diff options
| author | Vinicius da Motta <[email protected]> | 2026-01-21 01:22:38 -0300 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-01-20 22:22:38 -0600 |
| commit | b93f33eaa4ea48f5096abe01af8bc5d9a6095fb9 (patch) | |
| tree | 5bc5150d627d6e52fd97bd08fdaeaa16688fee2e | |
| parent | 34d473c0f5d617994cb00da8aa5e4d63eab9d2ea (diff) | |
| download | opencode-b93f33eaa4ea48f5096abe01af8bc5d9a6095fb9.tar.gz opencode-b93f33eaa4ea48f5096abe01af8bc5d9a6095fb9.zip | |
fix(tui): responsive layout for narrow screens (#9703)
| -rw-r--r-- | packages/opencode/src/cli/cmd/tui/routes/session/header.tsx | 78 | ||||
| -rw-r--r-- | packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx | 20 |
2 files changed, 55 insertions, 43 deletions
diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/header.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/header.tsx index afcb2c611..5e814c3d2 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/header.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/header.tsx @@ -8,6 +8,7 @@ import type { AssistantMessage, Session } from "@opencode-ai/sdk/v2" import { useCommandDialog } from "@tui/component/dialog-command" import { useKeybind } from "../../context/keybind" import { Installation } from "@/installation" +import { useTerminalDimensions } from "@opentui/solid" const Title = (props: { session: Accessor<Session> }) => { const { theme } = useTheme() @@ -63,6 +64,8 @@ export function Header() { const keybind = useKeybind() const command = useCommandDialog() const [hover, setHover] = createSignal<"parent" | "prev" | "next" | null>(null) + const dimensions = useTerminalDimensions() + const narrow = createMemo(() => dimensions().width < 80) return ( <box flexShrink={0}> @@ -79,49 +82,52 @@ export function Header() { > <Switch> <Match when={session()?.parentID}> - <box flexDirection="row" gap={2}> - <text fg={theme.text}> - <b>Subagent session</b> - </text> - <box - onMouseOver={() => setHover("parent")} - onMouseOut={() => setHover(null)} - onMouseUp={() => command.trigger("session.parent")} - backgroundColor={hover() === "parent" ? theme.backgroundElement : theme.backgroundPanel} - > + <box flexDirection="column" gap={1}> + <box flexDirection={narrow() ? "column" : "row"} justifyContent="space-between" gap={narrow() ? 1 : 0}> <text fg={theme.text}> - Parent <span style={{ fg: theme.textMuted }}>{keybind.print("session_parent")}</span> + <b>Subagent session</b> </text> + <box flexDirection="row" gap={1} flexShrink={0}> + <ContextInfo context={context} cost={cost} /> + <text fg={theme.textMuted}>v{Installation.VERSION}</text> + </box> </box> - <box - onMouseOver={() => setHover("prev")} - onMouseOut={() => setHover(null)} - onMouseUp={() => command.trigger("session.child.previous")} - backgroundColor={hover() === "prev" ? theme.backgroundElement : theme.backgroundPanel} - > - <text fg={theme.text}> - Prev <span style={{ fg: theme.textMuted }}>{keybind.print("session_child_cycle_reverse")}</span> - </text> - </box> - <box - onMouseOver={() => setHover("next")} - onMouseOut={() => setHover(null)} - onMouseUp={() => command.trigger("session.child.next")} - backgroundColor={hover() === "next" ? theme.backgroundElement : theme.backgroundPanel} - > - <text fg={theme.text}> - Next <span style={{ fg: theme.textMuted }}>{keybind.print("session_child_cycle")}</span> - </text> - </box> - <box flexGrow={1} flexShrink={1} /> - <box flexDirection="row" gap={1} flexShrink={0}> - <ContextInfo context={context} cost={cost} /> - <text fg={theme.textMuted}>v{Installation.VERSION}</text> + <box flexDirection="row" gap={2}> + <box + onMouseOver={() => setHover("parent")} + onMouseOut={() => setHover(null)} + onMouseUp={() => command.trigger("session.parent")} + backgroundColor={hover() === "parent" ? theme.backgroundElement : theme.backgroundPanel} + > + <text fg={theme.text}> + Parent <span style={{ fg: theme.textMuted }}>{keybind.print("session_parent")}</span> + </text> + </box> + <box + onMouseOver={() => setHover("prev")} + onMouseOut={() => setHover(null)} + onMouseUp={() => command.trigger("session.child.previous")} + backgroundColor={hover() === "prev" ? theme.backgroundElement : theme.backgroundPanel} + > + <text fg={theme.text}> + Prev <span style={{ fg: theme.textMuted }}>{keybind.print("session_child_cycle_reverse")}</span> + </text> + </box> + <box + onMouseOver={() => setHover("next")} + onMouseOut={() => setHover(null)} + onMouseUp={() => command.trigger("session.child.next")} + backgroundColor={hover() === "next" ? theme.backgroundElement : theme.backgroundPanel} + > + <text fg={theme.text}> + Next <span style={{ fg: theme.textMuted }}>{keybind.print("session_child_cycle")}</span> + </text> + </box> </box> </box> </Match> <Match when={true}> - <box flexDirection="row" justifyContent="space-between" gap={1}> + <box flexDirection={narrow() ? "column" : "row"} justifyContent="space-between" gap={1}> <Title session={session} /> <box flexDirection="row" gap={1} flexShrink={0}> <ContextInfo context={context} cost={cost} /> diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx index c4ff4c04b..0414ec39b 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx @@ -302,6 +302,8 @@ function RejectPrompt(props: { onConfirm: (message: string) => void; onCancel: ( const { theme } = useTheme() const keybind = useKeybind() const textareaKeybindings = useTextareaKeybindings() + const dimensions = useTerminalDimensions() + const narrow = createMemo(() => dimensions().width < 80) useKeyboard((evt) => { if (evt.name === "escape" || keybind.match("app_exit", evt)) { @@ -332,14 +334,16 @@ function RejectPrompt(props: { onConfirm: (message: string) => void; onCancel: ( </box> </box> <box - flexDirection="row" + flexDirection={narrow() ? "column" : "row"} flexShrink={0} paddingTop={1} paddingLeft={2} paddingRight={3} paddingBottom={1} backgroundColor={theme.backgroundElement} - justifyContent="space-between" + justifyContent={narrow() ? "flex-start" : "space-between"} + alignItems={narrow() ? "flex-start" : "center"} + gap={1} > <textarea ref={(val: TextareaRenderable) => (input = val)} @@ -349,7 +353,7 @@ function RejectPrompt(props: { onConfirm: (message: string) => void; onCancel: ( cursorColor={theme.primary} keyBindings={textareaKeybindings()} /> - <box flexDirection="row" gap={2} flexShrink={0} marginLeft={1}> + <box flexDirection="row" gap={2} flexShrink={0}> <text fg={theme.text}> enter <span style={{ fg: theme.textMuted }}>confirm</span> </text> @@ -379,6 +383,7 @@ function Prompt<const T extends Record<string, string>>(props: { expanded: false, }) const diffKey = Keybind.parse("ctrl+f")[0] + const narrow = createMemo(() => dimensions().width < 80) useKeyboard((evt) => { if (evt.name === "left" || evt.name == "h") { @@ -440,7 +445,7 @@ function Prompt<const T extends Record<string, string>>(props: { {props.body} </box> <box - flexDirection="row" + flexDirection={narrow() ? "column" : "row"} flexShrink={0} gap={1} paddingTop={1} @@ -448,9 +453,10 @@ function Prompt<const T extends Record<string, string>>(props: { paddingRight={3} paddingBottom={1} backgroundColor={theme.backgroundElement} - justifyContent="space-between" + justifyContent={narrow() ? "flex-start" : "space-between"} + alignItems={narrow() ? "flex-start" : "center"} > - <box flexDirection="row" gap={1}> + <box flexDirection="row" gap={1} flexShrink={0}> <For each={keys}> {(option) => ( <box @@ -470,7 +476,7 @@ function Prompt<const T extends Record<string, string>>(props: { )} </For> </box> - <box flexDirection="row" gap={2}> + <box flexDirection="row" gap={2} flexShrink={0}> <Show when={props.fullscreen}> <text fg={theme.text}> {"ctrl+f"} <span style={{ fg: theme.textMuted }}>{hint()}</span> |
