diff options
| author | OpeOginni <[email protected]> | 2025-11-05 18:33:30 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-05 11:33:30 -0600 |
| commit | 69a499f80786b2656121cee4469f39df2e6c40e7 (patch) | |
| tree | aec00083c25ae0afd780332add4d32ff9f08c707 | |
| parent | 37e564139fc1b46a66f916280a3baf3e3e399bf2 (diff) | |
| download | opencode-69a499f80786b2656121cee4469f39df2e6c40e7.tar.gz opencode-69a499f80786b2656121cee4469f39df2e6c40e7.zip | |
fix(tui): restructure Sidebar component to be scrollable (#3946)
| -rw-r--r-- | packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx | 242 |
1 files changed, 122 insertions, 120 deletions
diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx index c63297db2..2f1451a5f 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx @@ -40,136 +40,138 @@ export function Sidebar(props: { sessionID: string }) { return ( <Show when={session()}> - <box flexShrink={0} gap={1} width={40}> - <box> - <text fg={theme.text}> - <b>{session().title}</b> - </text> - <Show when={session().share?.url}> - <text fg={theme.textMuted}>{session().share!.url}</text> - </Show> - </box> - <box> - <text fg={theme.text}> - <b>Context</b> - </text> - <text fg={theme.textMuted}>{context()?.tokens ?? 0} tokens</text> - <text fg={theme.textMuted}>{context()?.percentage ?? 0}% used</text> - <text fg={theme.textMuted}>{cost()} spent</text> - </box> - <Show when={Object.keys(sync.data.mcp).length > 0}> + <scrollbox width={40}> + <box flexShrink={0} gap={1} paddingRight={1}> <box> <text fg={theme.text}> - <b>MCP</b> + <b>{session().title}</b> </text> - <For each={Object.entries(sync.data.mcp)}> - {([key, item]) => ( - <box flexDirection="row" gap={1}> - <text - flexShrink={0} - style={{ - fg: { - connected: theme.success, - failed: theme.error, - disabled: theme.textMuted, - }[item.status], - }} - > - • - </text> - <text fg={theme.text} wrapMode="word"> - {key}{" "} - <span style={{ fg: theme.textMuted }}> - <Switch> - <Match when={item.status === "connected"}>Connected</Match> - <Match when={item.status === "failed" && item}> - {(val) => <i>{val().error}</i>} - </Match> - <Match when={item.status === "disabled"}>Disabled in configuration</Match> - </Switch> - </span> - </text> - </box> - )} - </For> + <Show when={session().share?.url}> + <text fg={theme.textMuted}>{session().share!.url}</text> + </Show> </box> - </Show> - <Show when={sync.data.lsp.length > 0}> <box> <text fg={theme.text}> - <b>LSP</b> + <b>Context</b> </text> - <For each={sync.data.lsp}> - {(item) => ( - <box flexDirection="row" gap={1}> - <text - flexShrink={0} - style={{ - fg: { - connected: theme.success, - error: theme.error, - }[item.status], - }} - > - • - </text> - <text fg={theme.textMuted}> - {item.id} {item.root} - </text> - </box> - )} - </For> + <text fg={theme.textMuted}>{context()?.tokens ?? 0} tokens</text> + <text fg={theme.textMuted}>{context()?.percentage ?? 0}% used</text> + <text fg={theme.textMuted}>{cost()} spent</text> </box> - </Show> - <Show when={session().summary?.diffs}> - <box> - <text fg={theme.text}> - <b>Modified Files</b> - </text> - <For each={session().summary?.diffs || []}> - {(item) => { - const file = createMemo(() => { - const splits = item.file.split(path.sep).filter(Boolean) - const last = splits.at(-1)! - const rest = splits.slice(0, -1).join(path.sep) - return Locale.truncateMiddle(rest, 30 - last.length) + "/" + last - }) - return ( - <box flexDirection="row" gap={1} justifyContent="space-between"> - <text fg={theme.textMuted} wrapMode="char"> - {file()} + <Show when={Object.keys(sync.data.mcp).length > 0}> + <box> + <text fg={theme.text}> + <b>MCP</b> + </text> + <For each={Object.entries(sync.data.mcp)}> + {([key, item]) => ( + <box flexDirection="row" gap={1}> + <text + flexShrink={0} + style={{ + fg: { + connected: theme.success, + failed: theme.error, + disabled: theme.textMuted, + }[item.status], + }} + > + • + </text> + <text fg={theme.text} wrapMode="word"> + {key}{" "} + <span style={{ fg: theme.textMuted }}> + <Switch> + <Match when={item.status === "connected"}>Connected</Match> + <Match when={item.status === "failed" && item}> + {(val) => <i>{val().error}</i>} + </Match> + <Match when={item.status === "disabled"}>Disabled in configuration</Match> + </Switch> + </span> </text> - <box flexDirection="row" gap={1} flexShrink={0}> - <Show when={item.additions}> - <text fg={theme.diffAdded}>+{item.additions}</text> - </Show> - <Show when={item.deletions}> - <text fg={theme.diffRemoved}>-{item.deletions}</text> - </Show> - </box> </box> - ) - }} - </For> - </box> - </Show> - <Show when={todo().length > 0}> - <box> - <text fg={theme.text}> - <b>Todo</b> - </text> - <For each={todo()}> - {(todo) => ( - <text - style={{ fg: todo.status === "in_progress" ? theme.success : theme.textMuted }} - > - [{todo.status === "completed" ? "✓" : " "}] {todo.content} - </text> - )} - </For> - </box> - </Show> - </box> + )} + </For> + </box> + </Show> + <Show when={sync.data.lsp.length > 0}> + <box> + <text fg={theme.text}> + <b>LSP</b> + </text> + <For each={sync.data.lsp}> + {(item) => ( + <box flexDirection="row" gap={1}> + <text + flexShrink={0} + style={{ + fg: { + connected: theme.success, + error: theme.error, + }[item.status], + }} + > + • + </text> + <text fg={theme.textMuted}> + {item.id} {item.root} + </text> + </box> + )} + </For> + </box> + </Show> + <Show when={session().summary?.diffs}> + <box> + <text fg={theme.text}> + <b>Modified Files</b> + </text> + <For each={session().summary?.diffs || []}> + {(item) => { + const file = createMemo(() => { + const splits = item.file.split(path.sep).filter(Boolean) + const last = splits.at(-1)! + const rest = splits.slice(0, -1).join(path.sep) + return Locale.truncateMiddle(rest, 30 - last.length) + "/" + last + }) + return ( + <box flexDirection="row" gap={1} justifyContent="space-between"> + <text fg={theme.textMuted} wrapMode="char"> + {file()} + </text> + <box flexDirection="row" gap={1} flexShrink={0}> + <Show when={item.additions}> + <text fg={theme.diffAdded}>+{item.additions}</text> + </Show> + <Show when={item.deletions}> + <text fg={theme.diffRemoved}>-{item.deletions}</text> + </Show> + </box> + </box> + ) + }} + </For> + </box> + </Show> + <Show when={todo().length > 0}> + <box> + <text fg={theme.text}> + <b>Todo</b> + </text> + <For each={todo()}> + {(todo) => ( + <text + style={{ fg: todo.status === "in_progress" ? theme.success : theme.textMuted }} + > + [{todo.status === "completed" ? "✓" : " "}] {todo.content} + </text> + )} + </For> + </box> + </Show> + </box> + </scrollbox> </Show> ) } |
