Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/web/src/components/ChatMarkdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1338,6 +1338,7 @@ function ChatMarkdown({

return (
<div
dir="auto"
className={cn(
"chat-markdown w-full min-w-0 text-sm leading-relaxed text-foreground/80",
className,
Expand Down
3 changes: 2 additions & 1 deletion apps/web/src/components/ComposerPromptEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1609,8 +1609,9 @@ function ComposerPromptEditorInner({
<PlainTextPlugin
contentEditable={
<ContentEditable
dir="auto"
className={cn(
"block max-h-50 min-h-17.5 w-full overflow-y-auto whitespace-pre-wrap wrap-break-word bg-transparent text-[16px] leading-relaxed text-foreground focus:outline-none sm:text-[14px]",
"composer-editor-bidi block max-h-50 min-h-17.5 w-full overflow-y-auto whitespace-pre-wrap wrap-break-word bg-transparent text-[16px] leading-relaxed text-foreground focus:outline-none sm:text-[14px]",
className,
)}
data-testid="composer-editor"
Expand Down
10 changes: 7 additions & 3 deletions apps/web/src/components/PlanSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ const PlanSidebar = memo(function PlanSidebar({
<div className="p-3 space-y-4">
{/* Explanation */}
{activePlan?.explanation ? (
<p className="text-[13px] leading-relaxed text-muted-foreground/80">
<p dir="auto" className="text-[13px] leading-relaxed text-muted-foreground/80">
{activePlan.explanation}
</p>
) : null}
Expand All @@ -221,6 +221,7 @@ const PlanSidebar = memo(function PlanSidebar({
>
{stepStatusIcon(step.status)}
<p
dir="auto"
className={cn(
"text-[13px] leading-snug",
step.status === "completed"
Expand All @@ -242,15 +243,18 @@ const PlanSidebar = memo(function PlanSidebar({
<div className="space-y-2">
<button
type="button"
className="group flex w-full items-center gap-1.5 text-left"
className="group flex w-full items-center gap-1.5 text-start"
onClick={() => setProposedPlanExpanded((v) => !v)}
>
{proposedPlanExpanded ? (
<ChevronDownIcon className="size-3 shrink-0 text-muted-foreground/40 transition-transform" />
) : (
<ChevronRightIcon className="size-3 shrink-0 text-muted-foreground/40 transition-transform" />
)}
<span className="text-[10px] font-semibold tracking-widest text-muted-foreground/40 uppercase group-hover:text-muted-foreground/60">
<span
dir="auto"
className="text-[10px] font-semibold tracking-widest text-muted-foreground/40 uppercase group-hover:text-muted-foreground/60"
>
{planTitle ?? "Full Plan"}
</span>
</button>
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,7 @@ export const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThr
<TooltipTrigger
render={
<span
dir="auto"
className="min-w-0 flex-1 truncate text-xs"
data-testid={`thread-title-${thread.id}`}
>
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/components/chat/ChatHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export const ChatHeader = memo(function ChatHeader({
<TooltipTrigger
render={
<h2
dir="auto"
aria-label={activeThreadTitle}
className="min-w-0 flex-1 basis-40 truncate text-sm font-medium text-foreground"
>
Expand Down
18 changes: 13 additions & 5 deletions apps/web/src/components/chat/ComposerPendingUserInputPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,13 @@ const ComposerPendingUserInputCard = memo(function ComposerPendingUserInputCard(
</span>
) : null}
</div>
<p className="text-sm text-foreground/90">{activeQuestion.question}</p>
<p dir="auto" className="text-sm text-foreground/90">
{activeQuestion.question}
</p>
{activeQuestion.multiSelect ? (
<p className="mt-1 text-xs text-muted-foreground/65">Select one or more options.</p>
<p dir="auto" className="mt-1 text-xs text-muted-foreground/65">
Select one or more options.
</p>
) : null}
<div className="mt-3 space-y-1.5">
{activeQuestion.options.map((option, index) => {
Expand All @@ -178,7 +182,7 @@ const ComposerPendingUserInputCard = memo(function ComposerPendingUserInputCard(
(!customAnswerActive && progress.selectedOptionLabels.includes(option.label));
const shortcutKey = index < 9 ? index + 1 : null;
const className = cn(
"group flex w-full items-center gap-3 rounded-lg border px-3 py-2 text-left outline-none transition-all duration-150 focus-visible:border-primary/40 focus-visible:ring-1 focus-visible:ring-primary/25",
"group flex w-full items-center gap-3 rounded-lg border px-3 py-2 text-start outline-none transition-all duration-150 focus-visible:border-primary/40 focus-visible:ring-1 focus-visible:ring-primary/25",
isSelected
? "border-primary/30 bg-primary/8 text-foreground"
: "border-transparent bg-muted/22 text-foreground/85 hover:border-border/45 hover:bg-muted/34",
Expand All @@ -188,9 +192,13 @@ const ComposerPendingUserInputCard = memo(function ComposerPendingUserInputCard(
const content = (
<>
<div className="min-w-0 flex-1 flex flex-col gap-0.5">
<span className="text-sm font-medium">{option.label}</span>
<span dir="auto" className="text-sm font-medium">
{option.label}
</span>
{option.description && option.description !== option.label ? (
<span className="text-xs text-muted-foreground/50">{option.description}</span>
<span dir="auto" className="text-xs text-muted-foreground/50">
{option.description}
</span>
) : null}
</div>
{isSelected ? (
Expand Down
4 changes: 3 additions & 1 deletion apps/web/src/components/chat/ComposerPlanFollowUpBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ export const ComposerPlanFollowUpBanner = memo(function ComposerPlanFollowUpBann
Plan Ready
</Badge>
{planTitle ? (
<span className="min-w-0 flex-1 truncate text-sm font-medium">{planTitle}</span>
<span dir="auto" className="min-w-0 flex-1 truncate text-sm font-medium">
{planTitle}
</span>
) : null}
</div>
{/* <div className="mt-2 text-xs text-muted-foreground">
Expand Down
4 changes: 3 additions & 1 deletion apps/web/src/components/chat/ProposedPlanCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,9 @@ export const ProposedPlanCard = memo(function ProposedPlanCard({
<div className="flex flex-wrap items-center justify-between gap-3">
<div className="flex min-w-0 items-center gap-2">
<Badge variant="secondary">Plan</Badge>
<p className="truncate text-sm font-medium text-foreground">{title}</p>
<p dir="auto" className="truncate text-sm font-medium text-foreground">
{title}
</p>
</div>
<Menu>
<MenuTrigger
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/settings/SettingsPanels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1484,7 +1484,7 @@ export function ArchivedThreadsPanel() {
},
);
}}
title={thread.title}
title={<span dir="auto">{thread.title}</span>}
description={
<>
Archived {formatRelativeTimeLabel(thread.archivedAt ?? thread.createdAt)}
Expand Down
40 changes: 35 additions & 5 deletions apps/web/src/index.css

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium

.chat-markdown li.task-list-item {
list-style-type: none;
}
.chat-markdown li.task-list-item input[type="checkbox"] {
margin: 0 0.35em 0.15em -1.25rem;
vertical-align: middle;
}

The task list checkbox uses physical margin: 0 0.35em 0.15em -1.25rem, which pulls the checkbox left with negative margin. In RTL contexts (now enabled by unicode-bidi: plaintext on li elements), the checkbox misaligns because -1.25rem remains left-bound instead of following the inline-start direction. Use margin-inline-start: -1.25rem with separate inline-end and block margins so the negative margin adapts to text direction.

Suggested change
.chat-markdown li.task-list-item input[type="checkbox"] {
- margin: 0 0.35em 0.15em -1.25rem;
+ margin-block: 0 0.15em;
+ margin-inline: -1.25rem 0.35em;
vertical-align: middle;
}
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/index.css around lines 449-456:

The task list checkbox uses physical `margin: 0 0.35em 0.15em -1.25rem`, which pulls the checkbox left with negative margin. In RTL contexts (now enabled by `unicode-bidi: plaintext` on `li` elements), the checkbox misaligns because `-1.25rem` remains left-bound instead of following the inline-start direction. Use `margin-inline-start: -1.25rem` with separate inline-end and block margins so the negative margin adapts to text direction.

Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,36 @@ label:has(> select#reasoning-effort) select {
word-break: break-word;
}

/* Bidirectional text direction detection for mixed RTL/LTR content */
.chat-markdown p,
.chat-markdown li,
.chat-markdown td,
.chat-markdown th,
.chat-markdown h1,
.chat-markdown h2,
.chat-markdown h3,
.chat-markdown h4,
.chat-markdown h5,
.chat-markdown h6,
.chat-markdown blockquote {
unicode-bidi: plaintext;
}
Comment thread
cursor[bot] marked this conversation as resolved.

/* Code and tables remain LTR regardless of surrounding text direction */
.chat-markdown pre,
.chat-markdown code,
.chat-markdown table {
direction: ltr;
unicode-bidi: isolate;
}

/* Per-line direction detection for pre-wrap user messages and composer */
.user-message-text,
.composer-editor-bidi,
.composer-editor-bidi p {
unicode-bidi: plaintext;
}
Comment thread
darkyeg marked this conversation as resolved.

.chat-markdown > :first-child {
margin-top: 0;
}
Expand Down Expand Up @@ -386,12 +416,12 @@ label:has(> select#reasoning-effort) select {
}

.chat-markdown ul {
padding-left: 1.25rem;
padding-inline-start: 1.25rem;
list-style-type: disc;
}

.chat-markdown ol {
padding-left: 1.25rem;
padding-inline-start: 1.25rem;
list-style-type: decimal;
}

Expand Down Expand Up @@ -451,8 +481,8 @@ label:has(> select#reasoning-effort) select {
}

.chat-markdown blockquote {
border-left: 2px solid var(--border);
padding-left: 0.8rem;
border-inline-start: 2px solid var(--border);
padding-inline-start: 0.8rem;
color: var(--muted-foreground);
}

Expand Down Expand Up @@ -635,7 +665,7 @@ label:has(> select#reasoning-effort) select {
.chat-markdown th,
.chat-markdown td {
padding: 0.45rem 0.75rem;
text-align: left;
text-align: start;
}

.chat-markdown thead th {
Expand Down
Loading