summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
authorVinicius da Motta <[email protected]>2026-01-21 01:22:38 -0300
committerGitHub <[email protected]>2026-01-20 22:22:38 -0600
commitb93f33eaa4ea48f5096abe01af8bc5d9a6095fb9 (patch)
tree5bc5150d627d6e52fd97bd08fdaeaa16688fee2e /packages
parent34d473c0f5d617994cb00da8aa5e4d63eab9d2ea (diff)
downloadopencode-b93f33eaa4ea48f5096abe01af8bc5d9a6095fb9.tar.gz
opencode-b93f33eaa4ea48f5096abe01af8bc5d9a6095fb9.zip
fix(tui): responsive layout for narrow screens (#9703)
Diffstat (limited to 'packages')
-rw-r--r--packages/opencode/src/cli/cmd/tui/routes/session/header.tsx78
-rw-r--r--packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx20
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>