fix(app): correct RTL layout interactions (#40410)

This commit is contained in:
Luke Parker
2026-08-04 21:39:32 +10:00
committed by GitHub
parent 6c97a46dae
commit de1bd36a47
21 changed files with 210 additions and 84 deletions
@@ -30,19 +30,19 @@
flex-shrink: 0;
min-height: 0;
overflow: hidden;
border-right: 1px solid var(--border-weaker-base, var(--v2-border-border-weak));
border-inline-end: 1px solid var(--border-weaker-base, var(--v2-border-border-weak));
background: var(--v2-background-bg-base);
}
[data-component="session-review-v2-sidebar-root"] [data-slot="session-review-v2-sidebar"][aria-hidden="true"] {
border-right-width: 0;
border-inline-end-width: 0;
}
[data-component="session-review-v2-sidebar-root"]
[data-slot="session-review-v2-sidebar"][data-transition]:not([data-resizing]) {
transition:
width 200ms cubic-bezier(0.22, 1, 0.36, 1),
border-right-width 200ms cubic-bezier(0.22, 1, 0.36, 1);
border-inline-end-width 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
[data-component="session-review-v2-sidebar-root"] [data-slot="session-review-v2-sidebar-resize"] {
@@ -63,7 +63,8 @@
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 12px 16px 12px 8px;
padding-block: 12px;
padding-inline: 8px 16px;
flex-shrink: 0;
}
@@ -79,7 +80,7 @@
[data-component="session-review-v2-sidebar-root"]
[data-slot="session-review-v2-sidebar-title"]:not(:has([data-component="select-v2-root"])) {
margin-left: 8px;
margin-inline-start: 8px;
}
[data-component="session-review-v2-sidebar-root"]
@@ -211,7 +212,7 @@
justify-content: space-between;
gap: 8px;
padding: 10px 12px;
padding-left: 8px;
padding-inline-start: 8px;
flex-shrink: 0;
border-bottom: 1px solid var(--border-weaker-base, var(--v2-border-border-weak));
}
@@ -231,7 +232,7 @@
align-items: center;
gap: 8px;
min-width: 0;
padding-right: 8px;
padding-inline-end: 8px;
}
[data-component="session-review-v2"] [data-slot="session-review-v2-toolbar-title"] {
@@ -331,7 +332,7 @@
[data-component="session-review-v2"] [data-slot="session-review-v2-file-diff"] {
position: relative;
flex-shrink: 0;
margin-left: auto;
margin-inline-start: auto;
background-color: var(--v2-background-bg-base);
&::before {
@@ -339,17 +340,22 @@
position: absolute;
top: -8px;
bottom: -8px;
right: 100%;
inset-inline-end: 100%;
width: 16px;
z-index: 1;
pointer-events: none;
background: linear-gradient(90deg, transparent, var(--v2-background-bg-base));
}
&:dir(rtl)::before {
background: linear-gradient(270deg, transparent, var(--v2-background-bg-base));
}
&::after {
content: "";
position: absolute;
inset: -8px -16px -8px 0;
inset-block: -8px;
inset-inline: 0 -16px;
z-index: 0;
pointer-events: none;
background-color: var(--v2-background-bg-base);
@@ -9,6 +9,7 @@ import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2"
import type { SessionReviewDiffStyle } from "../../components/session-review"
import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
import { ScrollView } from "@opencode-ai/ui/scroll-view"
import { useLocale } from "@kobalte/core/i18n"
import { makeEventListener } from "@solid-primitives/event-listener"
import { Show, createEffect, createMemo, createSignal, type JSX } from "solid-js"
import { getWorkerPool } from "../../pierre/worker"
@@ -149,6 +150,7 @@ export function SessionReviewV2Sidebar(props: SessionReviewV2SidebarProps) {
export function SessionReviewV2(props: SessionReviewV2Props) {
const i18n = useI18n()
const locale = useLocale()
createEffect(() => {
getWorkerPool(props.diffStyle)
@@ -175,6 +177,8 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
}
const canCycle = () => props.files.length > 0
const previousKey = () => (locale.direction() === "rtl" ? "ArrowRight" : "ArrowLeft")
const nextKey = () => (locale.direction() === "rtl" ? "ArrowLeft" : "ArrowRight")
const showCollapsedMeta = () => props.sidebarOpen === false
// Memoize slot getters so Show conditions do not instantiate throwaway elements.
const title = createMemo(() => props.title)
@@ -189,11 +193,11 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
// pane is mounted, but never while typing in an input or comment editor.
makeEventListener(document, "keydown", (event) => {
if (event.defaultPrevented || event.ctrlKey || event.metaKey || event.altKey) return
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return
if (event.key !== previousKey() && event.key !== nextKey()) return
const target = event.target
if (target instanceof HTMLElement && (target.isContentEditable || target.closest("input, textarea, select"))) return
if (!props.hasDiffs || !canCycle()) return
const file = event.key === "ArrowLeft" ? prev() : next()
const file = event.key === previousKey() ? prev() : next()
if (!file) return
event.preventDefault()
cycle(file)
@@ -221,7 +225,7 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
value={
<>
{i18n.t("ui.sessionReviewV2.previousFile")}
<KeybindV2 keys={["←"]} variant="neutral" />
<KeybindV2 keys={[locale.direction() === "rtl" ? "→" : "←"]} variant="neutral" />
</>
}
>
@@ -241,7 +245,7 @@ export function SessionReviewV2(props: SessionReviewV2Props) {
value={
<>
{i18n.t("ui.sessionReviewV2.nextFile")}
<KeybindV2 keys={["→"]} variant="neutral" />
<KeybindV2 keys={[locale.direction() === "rtl" ? "←" : "→"]} variant="neutral" />
</>
}
>