From eb77c0657163ecfc2d658b1c8e35a0ec33091334 Mon Sep 17 00:00:00 2001 From: MusiCode Date: Wed, 18 Mar 2026 01:48:45 +0000 Subject: [PATCH] fix(rtl): fix resize direction, path alignment, and i18n gaps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Invert resize delta in RTL for drawer (useDrawerResize) and split panel (RightPanel) - Add dir="ltr" to path/code value elements in instance-info panel - Replace hardcoded English strings with i18n: Hide/Show files, No git changes yet, Hide unchanged regions / Show full file, diff toolbar titles, + Create worktree - Fix sessionList.status.idle: "בסרלה" → "מוכן" in session.ts - Fix text-align: left → start in message-reasoning-toggle and tool-call-io-toggle - Fix left: 0 → inset-inline-start: 0 in attachment-chip-preview Co-Authored-By: Claude Sonnet 4.6 --- packages/ui/src/components/instance-info.tsx | 8 ++++---- .../instance/shell/right-panel/RightPanel.tsx | 6 ++++-- .../shell/right-panel/components/DiffToolbar.tsx | 8 +++++--- .../shell/right-panel/components/SplitFilePanel.tsx | 4 +++- .../shell/right-panel/tabs/GitChangesTab.tsx | 2 +- .../src/components/instance/shell/useDrawerResize.ts | 4 +++- packages/ui/src/components/worktree-selector.tsx | 7 ++++--- packages/ui/src/lib/i18n/messages/en/instance.ts | 12 ++++++++++++ packages/ui/src/lib/i18n/messages/he/instance.ts | 12 ++++++++++++ packages/ui/src/lib/i18n/messages/he/session.ts | 2 +- packages/ui/src/styles/messaging/message-base.css | 2 +- packages/ui/src/styles/messaging/prompt-input.css | 2 +- packages/ui/src/styles/messaging/tool-call.css | 2 +- 13 files changed, 52 insertions(+), 19 deletions(-) diff --git a/packages/ui/src/components/instance-info.tsx b/packages/ui/src/components/instance-info.tsx index da54521b..31684cbe 100644 --- a/packages/ui/src/components/instance-info.tsx +++ b/packages/ui/src/components/instance-info.tsx @@ -82,7 +82,7 @@ const InstanceInfo: Component = (props) => {
{t("instanceInfo.labels.folder")}
-
+
{currentInstance().folder}
@@ -94,7 +94,7 @@ const InstanceInfo: Component = (props) => {
{t("instanceInfo.labels.project")}
-
+
{project().id}
@@ -137,7 +137,7 @@ const InstanceInfo: Component = (props) => {
{t("instanceInfo.labels.binaryPath")}
-
+
{currentInstance().binaryPath}
@@ -151,7 +151,7 @@ const InstanceInfo: Component = (props) => {
{([key, value]) => ( -
+
{key} diff --git a/packages/ui/src/components/instance/shell/right-panel/RightPanel.tsx b/packages/ui/src/components/instance/shell/right-panel/RightPanel.tsx index 10dba5d0..a57d11ed 100644 --- a/packages/ui/src/components/instance/shell/right-panel/RightPanel.tsx +++ b/packages/ui/src/components/instance/shell/right-panel/RightPanel.tsx @@ -249,7 +249,8 @@ const RightPanel: Component = (props) => { const mode = activeSplitResize() if (!mode) return event.preventDefault() - const delta = event.clientX - splitResizeStartX() + const isRtl = typeof document !== "undefined" && document.documentElement.dir === "rtl" + const delta = (event.clientX - splitResizeStartX()) * (isRtl ? -1 : 1) const next = clampSplitWidth(splitResizeStartWidth() + delta) if (mode === "changes") setChangesSplitWidth(next) else if (mode === "git-changes") setGitChangesSplitWidth(next) @@ -272,7 +273,8 @@ const RightPanel: Component = (props) => { const touch = event.touches[0] if (!touch) return event.preventDefault() - const delta = touch.clientX - splitResizeStartX() + const isRtl = typeof document !== "undefined" && document.documentElement.dir === "rtl" + const delta = (touch.clientX - splitResizeStartX()) * (isRtl ? -1 : 1) const next = clampSplitWidth(splitResizeStartWidth() + delta) if (mode === "changes") setChangesSplitWidth(next) else if (mode === "git-changes") setGitChangesSplitWidth(next) diff --git a/packages/ui/src/components/instance/shell/right-panel/components/DiffToolbar.tsx b/packages/ui/src/components/instance/shell/right-panel/components/DiffToolbar.tsx index 2e9e980b..798a061a 100644 --- a/packages/ui/src/components/instance/shell/right-panel/components/DiffToolbar.tsx +++ b/packages/ui/src/components/instance/shell/right-panel/components/DiffToolbar.tsx @@ -2,6 +2,7 @@ import type { Component } from "solid-js" import { AlignJustify, FoldVertical, Split, UnfoldVertical, WrapText } from "lucide-solid" +import { useI18n } from "../../../../../lib/i18n" import type { DiffContextMode, DiffViewMode, DiffWordWrapMode } from "../types" interface DiffToolbarProps { @@ -14,14 +15,15 @@ interface DiffToolbarProps { } const DiffToolbar: Component = (props) => { + const { t } = useI18n() const nextViewMode = (): DiffViewMode => (props.viewMode === "split" ? "unified" : "split") const nextContextMode = (): DiffContextMode => (props.contextMode === "collapsed" ? "expanded" : "collapsed") const nextWordWrapMode = (): DiffWordWrapMode => (props.wordWrapMode === "on" ? "off" : "on") - const viewModeTitle = () => (nextViewMode() === "split" ? "Switch to split view" : "Switch to unified view") + const viewModeTitle = () => (nextViewMode() === "split" ? t("instanceShell.diff.switchToSplit") : t("instanceShell.diff.switchToUnified")) const contextModeTitle = () => - nextContextMode() === "collapsed" ? "Hide unchanged regions" : "Show full file" - const wordWrapTitle = () => (nextWordWrapMode() === "on" ? "Enable word wrap" : "Disable word wrap") + nextContextMode() === "collapsed" ? t("instanceShell.diff.hideUnchanged") : t("instanceShell.diff.showFull") + const wordWrapTitle = () => (nextWordWrapMode() === "on" ? t("instanceShell.diff.enableWordWrap") : t("instanceShell.diff.disableWordWrap")) return (
diff --git a/packages/ui/src/components/instance/shell/right-panel/components/SplitFilePanel.tsx b/packages/ui/src/components/instance/shell/right-panel/components/SplitFilePanel.tsx index 56fd6211..ea96ed01 100644 --- a/packages/ui/src/components/instance/shell/right-panel/components/SplitFilePanel.tsx +++ b/packages/ui/src/components/instance/shell/right-panel/components/SplitFilePanel.tsx @@ -1,5 +1,6 @@ import { Show, type Component, type JSX } from "solid-js" +import { useI18n } from "../../../../../lib/i18n" import OverlayList from "./OverlayList" type SplitFilePanelList = { @@ -24,12 +25,13 @@ interface SplitFilePanelProps { } const SplitFilePanel: Component = (props) => { + const { t } = useI18n() return (
{props.header} diff --git a/packages/ui/src/components/instance/shell/right-panel/tabs/GitChangesTab.tsx b/packages/ui/src/components/instance/shell/right-panel/tabs/GitChangesTab.tsx index 5f83d9e6..019dce1d 100644 --- a/packages/ui/src/components/instance/shell/right-panel/tabs/GitChangesTab.tsx +++ b/packages/ui/src/components/instance/shell/right-panel/tabs/GitChangesTab.tsx @@ -82,7 +82,7 @@ const GitChangesTab: Component = (props) => { }) const emptyViewerMessage = createMemo(() => { - if (!hasSession()) return props.t("instanceShell.sessionChanges.noSessionSelected") + if (!hasSession()) return props.t("instanceShell.gitChanges.noSessionSelected") const currentEntries = entries() if (currentEntries === null) return props.t("instanceShell.gitChanges.loading") if (nonDeleted().length === 0) return props.t("instanceShell.gitChanges.empty") diff --git a/packages/ui/src/components/instance/shell/useDrawerResize.ts b/packages/ui/src/components/instance/shell/useDrawerResize.ts index d3a4f982..c07fc139 100644 --- a/packages/ui/src/components/instance/shell/useDrawerResize.ts +++ b/packages/ui/src/components/instance/shell/useDrawerResize.ts @@ -46,7 +46,9 @@ export function useDrawerResize(options: DrawerResizeOptions): DrawerResizeApi { if (!side) return const startWidth = resizeStartWidth() const clamp = side === "left" ? options.clampLeft : options.clampRight - const delta = side === "left" ? clientX - resizeStartX() : resizeStartX() - clientX + const isRtl = typeof document !== "undefined" && document.documentElement.dir === "rtl" + const rawDelta = side === "left" ? clientX - resizeStartX() : resizeStartX() - clientX + const delta = isRtl ? -rawDelta : rawDelta const nextWidth = clamp(startWidth + delta) applyDrawerWidth(side, nextWidth) } diff --git a/packages/ui/src/components/worktree-selector.tsx b/packages/ui/src/components/worktree-selector.tsx index 71773d86..52c7f7d7 100644 --- a/packages/ui/src/components/worktree-selector.tsx +++ b/packages/ui/src/components/worktree-selector.tsx @@ -18,6 +18,7 @@ import { setWorktreeSlugForParentSession, } from "../stores/worktrees" import { sessions } from "../stores/sessions" +import { useI18n } from "../lib/i18n" const log = getLogger("session") @@ -25,8 +26,6 @@ type WorktreeOption = | { kind: "action"; key: "__create__"; label: string } | { kind: "worktree"; key: string; slug: string; directory: string; raw: WorktreeDescriptor } -const CREATE_OPTION: WorktreeOption = { kind: "action", key: "__create__", label: "+ Create worktree" } - function preventSelectPress(event: PointerEvent | MouseEvent) { // Prevent Select.Item from treating this as a selection. // We intentionally prevent default to stop Kobalte's internal press handling. @@ -71,6 +70,7 @@ interface WorktreeSelectorProps { } export default function WorktreeSelector(props: WorktreeSelectorProps) { + const { t } = useI18n() const [isOpen, setIsOpen] = createSignal(false) const [createOpen, setCreateOpen] = createSignal(false) const [createSlug, setCreateSlug] = createSignal("") @@ -99,7 +99,8 @@ export default function WorktreeSelector(props: WorktreeSelectorProps) { directory: wt.directory, raw: wt, })) - return [CREATE_OPTION, ...mapped] + const createOption: WorktreeOption = { kind: "action", key: "__create__", label: t("instanceShell.worktree.create") } + return [createOption, ...mapped] }) const selectedOption = createMemo(() => { diff --git a/packages/ui/src/lib/i18n/messages/en/instance.ts b/packages/ui/src/lib/i18n/messages/en/instance.ts index 83af3eaf..16e96e01 100644 --- a/packages/ui/src/lib/i18n/messages/en/instance.ts +++ b/packages/ui/src/lib/i18n/messages/en/instance.ts @@ -124,6 +124,18 @@ export const instanceMessages = { "instanceShell.filesShell.viewerTitle": "Change viewer", "instanceShell.filesShell.viewerPlaceholder": "Detailed change rendering will be added in the next step.", "instanceShell.filesShell.viewerEmpty": "No file selected.", + "instanceShell.filesShell.hideFiles": "Hide files", + "instanceShell.filesShell.showFiles": "Show files", + "instanceShell.gitChanges.noSessionSelected": "Select a session to view git changes.", + "instanceShell.gitChanges.loading": "Loading git changes…", + "instanceShell.gitChanges.empty": "No git changes yet.", + "instanceShell.diff.hideUnchanged": "Hide unchanged regions", + "instanceShell.diff.showFull": "Show full file", + "instanceShell.diff.switchToSplit": "Switch to split view", + "instanceShell.diff.switchToUnified": "Switch to unified view", + "instanceShell.diff.enableWordWrap": "Enable word wrap", + "instanceShell.diff.disableWordWrap": "Disable word wrap", + "instanceShell.worktree.create": "+ Create worktree", "instanceShell.plan.noSessionSelected": "Select a session to view plan.", "instanceShell.plan.empty": "Nothing planned yet.", diff --git a/packages/ui/src/lib/i18n/messages/he/instance.ts b/packages/ui/src/lib/i18n/messages/he/instance.ts index 707f0073..6c8345fe 100644 --- a/packages/ui/src/lib/i18n/messages/he/instance.ts +++ b/packages/ui/src/lib/i18n/messages/he/instance.ts @@ -120,6 +120,18 @@ export const instanceMessages = { "instanceShell.filesShell.viewerTitle": "מציג שינויים", "instanceShell.filesShell.viewerPlaceholder": "תצוגת שינויים מפורטת תתווסף בשלב הבא.", "instanceShell.filesShell.viewerEmpty": "לא נבחר קובץ.", + "instanceShell.filesShell.hideFiles": "הסתר קבצים", + "instanceShell.filesShell.showFiles": "הצג קבצים", + "instanceShell.gitChanges.noSessionSelected": "בחר סשן לצפייה בשינויי Git.", + "instanceShell.gitChanges.loading": "טוען שינויי Git…", + "instanceShell.gitChanges.empty": "אין שינויי Git עדיין.", + "instanceShell.diff.hideUnchanged": "הסתר אזורים ללא שינוי", + "instanceShell.diff.showFull": "הצג קובץ מלא", + "instanceShell.diff.switchToSplit": "עבור לתצוגה מפוצלת", + "instanceShell.diff.switchToUnified": "עבור לתצוגה מאוחדת", + "instanceShell.diff.enableWordWrap": "הפעל גלישת מילים", + "instanceShell.diff.disableWordWrap": "כבה גלישת מילים", + "instanceShell.worktree.create": "+ צור worktree", "instanceShell.plan.noSessionSelected": "בחר סשן לצפייה בתוכנית.", "instanceShell.plan.empty": "עדיין לא תוכנן דבר.", diff --git a/packages/ui/src/lib/i18n/messages/he/session.ts b/packages/ui/src/lib/i18n/messages/he/session.ts index dd27896a..6ff5035a 100644 --- a/packages/ui/src/lib/i18n/messages/he/session.ts +++ b/packages/ui/src/lib/i18n/messages/he/session.ts @@ -14,7 +14,7 @@ export const sessionMessages = { "sessionList.session.untitled": "ללא שם", "sessionList.status.working": "עובד", "sessionList.status.compacting": "מסכם", - "sessionList.status.idle": "בסרלה", + "sessionList.status.idle": "מוכן", "sessionList.status.needsPermission": "נדרש אישור", "sessionList.status.needsInput": "נדרש קלט", "sessionList.expand.collapseAriaLabel": "כווץ סשן", diff --git a/packages/ui/src/styles/messaging/message-base.css b/packages/ui/src/styles/messaging/message-base.css index fa9614dd..79f3b9f0 100644 --- a/packages/ui/src/styles/messaging/message-base.css +++ b/packages/ui/src/styles/messaging/message-base.css @@ -424,7 +424,7 @@ padding: 0.25rem 0.6rem; font: inherit; color: inherit; - text-align: left; + text-align: start; cursor: pointer; transition: background-color 0.2s ease, box-shadow 0.2s ease; } diff --git a/packages/ui/src/styles/messaging/prompt-input.css b/packages/ui/src/styles/messaging/prompt-input.css index bd8df62c..fb12c9d5 100644 --- a/packages/ui/src/styles/messaging/prompt-input.css +++ b/packages/ui/src/styles/messaging/prompt-input.css @@ -256,7 +256,7 @@ display: none; position: absolute; bottom: calc(100% + 6px); - left: 0; + inset-inline-start: 0; padding: 8px; background-color: var(--surface-base); border: 1px solid var(--border-base); diff --git a/packages/ui/src/styles/messaging/tool-call.css b/packages/ui/src/styles/messaging/tool-call.css index 7c54fa36..859c7f4f 100644 --- a/packages/ui/src/styles/messaging/tool-call.css +++ b/packages/ui/src/styles/messaging/tool-call.css @@ -257,7 +257,7 @@ border: none; border-bottom: 1px solid var(--tool-call-border-color); width: 100%; - text-align: left; + text-align: start; font-size: 0.875rem; font-weight: normal; color: var(--text-primary);