fix(rtl): fix resize direction, path alignment, and i18n gaps
- 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 <noreply@anthropic.com>
This commit is contained in:
committed by
Shantur Rathore
parent
a6cb70ed41
commit
eb77c06571
@@ -82,7 +82,7 @@ const InstanceInfo: Component<InstanceInfoProps> = (props) => {
|
|||||||
<div class="panel-body space-y-3">
|
<div class="panel-body space-y-3">
|
||||||
<div>
|
<div>
|
||||||
<div class="text-xs font-medium text-muted uppercase tracking-wide mb-1">{t("instanceInfo.labels.folder")}</div>
|
<div class="text-xs font-medium text-muted uppercase tracking-wide mb-1">{t("instanceInfo.labels.folder")}</div>
|
||||||
<div class="text-xs text-primary font-mono break-all px-2 py-1.5 rounded border bg-surface-secondary border-base">
|
<div dir="ltr" class="text-xs text-primary font-mono break-all px-2 py-1.5 rounded border bg-surface-secondary border-base">
|
||||||
{currentInstance().folder}
|
{currentInstance().folder}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -94,7 +94,7 @@ const InstanceInfo: Component<InstanceInfoProps> = (props) => {
|
|||||||
<div class="text-xs font-medium text-muted uppercase tracking-wide mb-1">
|
<div class="text-xs font-medium text-muted uppercase tracking-wide mb-1">
|
||||||
{t("instanceInfo.labels.project")}
|
{t("instanceInfo.labels.project")}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs font-mono px-2 py-1.5 rounded border truncate bg-surface-secondary border-base text-primary">
|
<div dir="ltr" class="text-xs font-mono px-2 py-1.5 rounded border truncate bg-surface-secondary border-base text-primary">
|
||||||
{project().id}
|
{project().id}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -137,7 +137,7 @@ const InstanceInfo: Component<InstanceInfoProps> = (props) => {
|
|||||||
<div class="text-xs font-medium text-muted uppercase tracking-wide mb-1">
|
<div class="text-xs font-medium text-muted uppercase tracking-wide mb-1">
|
||||||
{t("instanceInfo.labels.binaryPath")}
|
{t("instanceInfo.labels.binaryPath")}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs font-mono break-all px-2 py-1.5 rounded border bg-surface-secondary border-base text-primary">
|
<div dir="ltr" class="text-xs font-mono break-all px-2 py-1.5 rounded border bg-surface-secondary border-base text-primary">
|
||||||
{currentInstance().binaryPath}
|
{currentInstance().binaryPath}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -151,7 +151,7 @@ const InstanceInfo: Component<InstanceInfoProps> = (props) => {
|
|||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<For each={environmentEntries()}>
|
<For each={environmentEntries()}>
|
||||||
{([key, value]) => (
|
{([key, value]) => (
|
||||||
<div class="flex items-center gap-2 px-2 py-1.5 rounded border bg-surface-secondary border-base">
|
<div dir="ltr" class="flex items-center gap-2 px-2 py-1.5 rounded border bg-surface-secondary border-base">
|
||||||
<span class="text-xs font-mono font-medium flex-1 text-primary" title={key}>
|
<span class="text-xs font-mono font-medium flex-1 text-primary" title={key}>
|
||||||
{key}
|
{key}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -249,7 +249,8 @@ const RightPanel: Component<RightPanelProps> = (props) => {
|
|||||||
const mode = activeSplitResize()
|
const mode = activeSplitResize()
|
||||||
if (!mode) return
|
if (!mode) return
|
||||||
event.preventDefault()
|
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)
|
const next = clampSplitWidth(splitResizeStartWidth() + delta)
|
||||||
if (mode === "changes") setChangesSplitWidth(next)
|
if (mode === "changes") setChangesSplitWidth(next)
|
||||||
else if (mode === "git-changes") setGitChangesSplitWidth(next)
|
else if (mode === "git-changes") setGitChangesSplitWidth(next)
|
||||||
@@ -272,7 +273,8 @@ const RightPanel: Component<RightPanelProps> = (props) => {
|
|||||||
const touch = event.touches[0]
|
const touch = event.touches[0]
|
||||||
if (!touch) return
|
if (!touch) return
|
||||||
event.preventDefault()
|
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)
|
const next = clampSplitWidth(splitResizeStartWidth() + delta)
|
||||||
if (mode === "changes") setChangesSplitWidth(next)
|
if (mode === "changes") setChangesSplitWidth(next)
|
||||||
else if (mode === "git-changes") setGitChangesSplitWidth(next)
|
else if (mode === "git-changes") setGitChangesSplitWidth(next)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import type { Component } from "solid-js"
|
|||||||
|
|
||||||
import { AlignJustify, FoldVertical, Split, UnfoldVertical, WrapText } from "lucide-solid"
|
import { AlignJustify, FoldVertical, Split, UnfoldVertical, WrapText } from "lucide-solid"
|
||||||
|
|
||||||
|
import { useI18n } from "../../../../../lib/i18n"
|
||||||
import type { DiffContextMode, DiffViewMode, DiffWordWrapMode } from "../types"
|
import type { DiffContextMode, DiffViewMode, DiffWordWrapMode } from "../types"
|
||||||
|
|
||||||
interface DiffToolbarProps {
|
interface DiffToolbarProps {
|
||||||
@@ -14,14 +15,15 @@ interface DiffToolbarProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DiffToolbar: Component<DiffToolbarProps> = (props) => {
|
const DiffToolbar: Component<DiffToolbarProps> = (props) => {
|
||||||
|
const { t } = useI18n()
|
||||||
const nextViewMode = (): DiffViewMode => (props.viewMode === "split" ? "unified" : "split")
|
const nextViewMode = (): DiffViewMode => (props.viewMode === "split" ? "unified" : "split")
|
||||||
const nextContextMode = (): DiffContextMode => (props.contextMode === "collapsed" ? "expanded" : "collapsed")
|
const nextContextMode = (): DiffContextMode => (props.contextMode === "collapsed" ? "expanded" : "collapsed")
|
||||||
const nextWordWrapMode = (): DiffWordWrapMode => (props.wordWrapMode === "on" ? "off" : "on")
|
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 = () =>
|
const contextModeTitle = () =>
|
||||||
nextContextMode() === "collapsed" ? "Hide unchanged regions" : "Show full file"
|
nextContextMode() === "collapsed" ? t("instanceShell.diff.hideUnchanged") : t("instanceShell.diff.showFull")
|
||||||
const wordWrapTitle = () => (nextWordWrapMode() === "on" ? "Enable word wrap" : "Disable word wrap")
|
const wordWrapTitle = () => (nextWordWrapMode() === "on" ? t("instanceShell.diff.enableWordWrap") : t("instanceShell.diff.disableWordWrap"))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="file-viewer-toolbar">
|
<div class="file-viewer-toolbar">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Show, type Component, type JSX } from "solid-js"
|
import { Show, type Component, type JSX } from "solid-js"
|
||||||
|
|
||||||
|
import { useI18n } from "../../../../../lib/i18n"
|
||||||
import OverlayList from "./OverlayList"
|
import OverlayList from "./OverlayList"
|
||||||
|
|
||||||
type SplitFilePanelList = {
|
type SplitFilePanelList = {
|
||||||
@@ -24,12 +25,13 @@ interface SplitFilePanelProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const SplitFilePanel: Component<SplitFilePanelProps> = (props) => {
|
const SplitFilePanel: Component<SplitFilePanelProps> = (props) => {
|
||||||
|
const { t } = useI18n()
|
||||||
return (
|
return (
|
||||||
<div class="files-tab-container">
|
<div class="files-tab-container">
|
||||||
<div class="files-tab-header">
|
<div class="files-tab-header">
|
||||||
<div class="files-tab-header-row">
|
<div class="files-tab-header-row">
|
||||||
<button type="button" class="files-toggle-button" onClick={props.onToggleList}>
|
<button type="button" class="files-toggle-button" onClick={props.onToggleList}>
|
||||||
{props.listOpen ? "Hide files" : "Show files"}
|
{props.listOpen ? t("instanceShell.filesShell.hideFiles") : t("instanceShell.filesShell.showFiles")}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{props.header}
|
{props.header}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ const GitChangesTab: Component<GitChangesTabProps> = (props) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const emptyViewerMessage = createMemo(() => {
|
const emptyViewerMessage = createMemo(() => {
|
||||||
if (!hasSession()) return props.t("instanceShell.sessionChanges.noSessionSelected")
|
if (!hasSession()) return props.t("instanceShell.gitChanges.noSessionSelected")
|
||||||
const currentEntries = entries()
|
const currentEntries = entries()
|
||||||
if (currentEntries === null) return props.t("instanceShell.gitChanges.loading")
|
if (currentEntries === null) return props.t("instanceShell.gitChanges.loading")
|
||||||
if (nonDeleted().length === 0) return props.t("instanceShell.gitChanges.empty")
|
if (nonDeleted().length === 0) return props.t("instanceShell.gitChanges.empty")
|
||||||
|
|||||||
@@ -46,7 +46,9 @@ export function useDrawerResize(options: DrawerResizeOptions): DrawerResizeApi {
|
|||||||
if (!side) return
|
if (!side) return
|
||||||
const startWidth = resizeStartWidth()
|
const startWidth = resizeStartWidth()
|
||||||
const clamp = side === "left" ? options.clampLeft : options.clampRight
|
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)
|
const nextWidth = clamp(startWidth + delta)
|
||||||
applyDrawerWidth(side, nextWidth)
|
applyDrawerWidth(side, nextWidth)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
setWorktreeSlugForParentSession,
|
setWorktreeSlugForParentSession,
|
||||||
} from "../stores/worktrees"
|
} from "../stores/worktrees"
|
||||||
import { sessions } from "../stores/sessions"
|
import { sessions } from "../stores/sessions"
|
||||||
|
import { useI18n } from "../lib/i18n"
|
||||||
|
|
||||||
const log = getLogger("session")
|
const log = getLogger("session")
|
||||||
|
|
||||||
@@ -25,8 +26,6 @@ type WorktreeOption =
|
|||||||
| { kind: "action"; key: "__create__"; label: string }
|
| { kind: "action"; key: "__create__"; label: string }
|
||||||
| { kind: "worktree"; key: string; slug: string; directory: string; raw: WorktreeDescriptor }
|
| { 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) {
|
function preventSelectPress(event: PointerEvent | MouseEvent) {
|
||||||
// Prevent Select.Item from treating this as a selection.
|
// Prevent Select.Item from treating this as a selection.
|
||||||
// We intentionally prevent default to stop Kobalte's internal press handling.
|
// We intentionally prevent default to stop Kobalte's internal press handling.
|
||||||
@@ -71,6 +70,7 @@ interface WorktreeSelectorProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function WorktreeSelector(props: WorktreeSelectorProps) {
|
export default function WorktreeSelector(props: WorktreeSelectorProps) {
|
||||||
|
const { t } = useI18n()
|
||||||
const [isOpen, setIsOpen] = createSignal(false)
|
const [isOpen, setIsOpen] = createSignal(false)
|
||||||
const [createOpen, setCreateOpen] = createSignal(false)
|
const [createOpen, setCreateOpen] = createSignal(false)
|
||||||
const [createSlug, setCreateSlug] = createSignal("")
|
const [createSlug, setCreateSlug] = createSignal("")
|
||||||
@@ -99,7 +99,8 @@ export default function WorktreeSelector(props: WorktreeSelectorProps) {
|
|||||||
directory: wt.directory,
|
directory: wt.directory,
|
||||||
raw: wt,
|
raw: wt,
|
||||||
}))
|
}))
|
||||||
return [CREATE_OPTION, ...mapped]
|
const createOption: WorktreeOption = { kind: "action", key: "__create__", label: t("instanceShell.worktree.create") }
|
||||||
|
return [createOption, ...mapped]
|
||||||
})
|
})
|
||||||
|
|
||||||
const selectedOption = createMemo<WorktreeOption | undefined>(() => {
|
const selectedOption = createMemo<WorktreeOption | undefined>(() => {
|
||||||
|
|||||||
@@ -124,6 +124,18 @@ export const instanceMessages = {
|
|||||||
"instanceShell.filesShell.viewerTitle": "Change viewer",
|
"instanceShell.filesShell.viewerTitle": "Change viewer",
|
||||||
"instanceShell.filesShell.viewerPlaceholder": "Detailed change rendering will be added in the next step.",
|
"instanceShell.filesShell.viewerPlaceholder": "Detailed change rendering will be added in the next step.",
|
||||||
"instanceShell.filesShell.viewerEmpty": "No file selected.",
|
"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.noSessionSelected": "Select a session to view plan.",
|
||||||
"instanceShell.plan.empty": "Nothing planned yet.",
|
"instanceShell.plan.empty": "Nothing planned yet.",
|
||||||
|
|||||||
@@ -120,6 +120,18 @@ export const instanceMessages = {
|
|||||||
"instanceShell.filesShell.viewerTitle": "מציג שינויים",
|
"instanceShell.filesShell.viewerTitle": "מציג שינויים",
|
||||||
"instanceShell.filesShell.viewerPlaceholder": "תצוגת שינויים מפורטת תתווסף בשלב הבא.",
|
"instanceShell.filesShell.viewerPlaceholder": "תצוגת שינויים מפורטת תתווסף בשלב הבא.",
|
||||||
"instanceShell.filesShell.viewerEmpty": "לא נבחר קובץ.",
|
"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.noSessionSelected": "בחר סשן לצפייה בתוכנית.",
|
||||||
"instanceShell.plan.empty": "עדיין לא תוכנן דבר.",
|
"instanceShell.plan.empty": "עדיין לא תוכנן דבר.",
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const sessionMessages = {
|
|||||||
"sessionList.session.untitled": "ללא שם",
|
"sessionList.session.untitled": "ללא שם",
|
||||||
"sessionList.status.working": "עובד",
|
"sessionList.status.working": "עובד",
|
||||||
"sessionList.status.compacting": "מסכם",
|
"sessionList.status.compacting": "מסכם",
|
||||||
"sessionList.status.idle": "בסרלה",
|
"sessionList.status.idle": "מוכן",
|
||||||
"sessionList.status.needsPermission": "נדרש אישור",
|
"sessionList.status.needsPermission": "נדרש אישור",
|
||||||
"sessionList.status.needsInput": "נדרש קלט",
|
"sessionList.status.needsInput": "נדרש קלט",
|
||||||
"sessionList.expand.collapseAriaLabel": "כווץ סשן",
|
"sessionList.expand.collapseAriaLabel": "כווץ סשן",
|
||||||
|
|||||||
@@ -424,7 +424,7 @@
|
|||||||
padding: 0.25rem 0.6rem;
|
padding: 0.25rem 0.6rem;
|
||||||
font: inherit;
|
font: inherit;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
text-align: left;
|
text-align: start;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background-color 0.2s ease, box-shadow 0.2s ease;
|
transition: background-color 0.2s ease, box-shadow 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,7 +256,7 @@
|
|||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: calc(100% + 6px);
|
bottom: calc(100% + 6px);
|
||||||
left: 0;
|
inset-inline-start: 0;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
background-color: var(--surface-base);
|
background-color: var(--surface-base);
|
||||||
border: 1px solid var(--border-base);
|
border: 1px solid var(--border-base);
|
||||||
|
|||||||
@@ -257,7 +257,7 @@
|
|||||||
border: none;
|
border: none;
|
||||||
border-bottom: 1px solid var(--tool-call-border-color);
|
border-bottom: 1px solid var(--tool-call-border-color);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: left;
|
text-align: start;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
|
|||||||
Reference in New Issue
Block a user