diff options
| author | Adam <[email protected]> | 2025-11-06 09:48:46 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2025-11-06 09:48:51 -0600 |
| commit | 6ba7c54baba355e3788e371374d26e58b60feb0d (patch) | |
| tree | a69448dcdcd8e1935b2bc3c7d2344ad78f8ced75 /packages/desktop/src | |
| parent | 146bae82cb584c253a42ed4565d423d9cded93a6 (diff) | |
| download | opencode-6ba7c54baba355e3788e371374d26e58b60feb0d.tar.gz opencode-6ba7c54baba355e3788e371374d26e58b60feb0d.zip | |
feat(desktop): collapsible sidebar
Diffstat (limited to 'packages/desktop/src')
| -rw-r--r-- | packages/desktop/src/components/prompt-input.tsx | 1 | ||||
| -rw-r--r-- | packages/desktop/src/context/local.tsx | 35 | ||||
| -rw-r--r-- | packages/desktop/src/pages/layout.tsx | 62 |
3 files changed, 86 insertions, 12 deletions
diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx index cad1f2098..74443d6a5 100644 --- a/packages/desktop/src/components/prompt-input.tsx +++ b/packages/desktop/src/components/prompt-input.tsx @@ -543,6 +543,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { disabled={!session.prompt.dirty() && !session.working()} icon={session.working() ? "stop" : "arrow-up"} variant="primary" + class="rounded-full" /> </Tooltip> </div> diff --git a/packages/desktop/src/context/local.tsx b/packages/desktop/src/context/local.tsx index cef6c5555..9dacc7100 100644 --- a/packages/desktop/src/context/local.tsx +++ b/packages/desktop/src/context/local.tsx @@ -5,6 +5,7 @@ import type { FileContent, FileNode, Model, Provider, File as FileStatus } from import { createSimpleContext } from "./helper" import { useSDK } from "./sdk" import { useSync } from "./sync" +import { makePersisted } from "@solid-primitives/storage" export type LocalFile = FileNode & Partial<{ @@ -456,11 +457,45 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ } })() + const layout = (() => { + const [store, setStore] = makePersisted( + createStore({ + sidebar: { + opened: true, + width: 240, + }, + }), + { + name: "layout", + }, + ) + + return { + sidebar: { + opened: createMemo(() => store.sidebar.opened), + open() { + setStore("sidebar", "opened", true) + }, + close() { + setStore("sidebar", "opened", false) + }, + toggle() { + setStore("sidebar", "opened", (x) => !x) + }, + width: createMemo(() => store.sidebar.width), + resize(width: number) { + setStore("sidebar", "width", width) + }, + }, + } + })() + const result = { model, agent, file, context, + layout, } return result }, diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 85f55e8bd..e1560accb 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -1,27 +1,42 @@ -import { Button, Tooltip, DiffChanges } from "@opencode-ai/ui" +import { Button, Tooltip, DiffChanges, IconButton } from "@opencode-ai/ui" import { createMemo, For, ParentProps, Show } from "solid-js" -import { getFilename } from "@/utils" import { DateTime } from "luxon" import { useSync } from "@/context/sync" import { A, useParams } from "@solidjs/router" +import { useLocal } from "@/context/local" export default function Layout(props: ParentProps) { const params = useParams() const sync = useSync() + const local = useLocal() return ( <div class="relative h-screen flex flex-col"> <header class="hidden h-12 shrink-0 bg-background-strong border-b border-border-weak-base"></header> <div class="h-[calc(100vh-0rem)] flex"> - <div class="w-70 shrink-0 bg-background-weak border-r border-border-weak-base flex flex-col items-start"> - <div class="h-10 shrink-0 flex items-center self-stretch px-5 border-b border-border-weak-base"> - <span class="text-14-regular overflow-hidden text-ellipsis">{getFilename(sync.data.path.directory)}</span> - </div> - <div class="flex flex-col items-start gap-4 self-stretch flex-1 py-4 px-3 overflow-hidden"> - <Button as={A} href="/session" class="w-full" size="large" icon="edit-small-2"> - New Session - </Button> - <div class="w-full h-full overflow-y-auto no-scrollbar flex flex-col flex-1"> + <div + classList={{ + "@container w-16 pb-4 shrink-0 bg-background-weak": true, + "flex flex-col items-start self-stretch justify-between": true, + "border-r border-border-weak-base": true, + "w-70": local.layout.sidebar.opened(), + }} + > + <div class="flex flex-col justify-center items-start gap-4 self-stretch py-2 overflow-hidden mx-auto @[4rem]:mx-0"> + <div class="h-8 shrink-0 flex items-center self-stretch px-3"> + <Tooltip placement="right" value="Collapse sidebar"> + <IconButton icon="layout-left" variant="ghost" size="large" onClick={local.layout.sidebar.toggle} /> + </Tooltip> + </div> + <div class="w-full px-3"> + <Button as={A} href="/session" class="hidden @[4rem]:flex w-full" size="large" icon="edit-small-2"> + New Session + </Button> + <Tooltip placement="right" value="New session"> + <IconButton as={A} href="/session" icon="edit-small-2" size="large" class="@[4rem]:hidden" /> + </Tooltip> + </div> + <div class="hidden @[4rem]:flex size-full overflow-y-auto no-scrollbar flex-col flex-1 px-3"> <nav class="w-full"> <For each={sync.data.session}> {(session) => { @@ -30,7 +45,7 @@ export default function Layout(props: ParentProps) { <A data-active={session.id === params.id} href={`/session/${session.id}`} - class="group/session focus:outline-none" + class="group/session focus:outline-none cursor-default" > <Tooltip placement="right" value={session.title}> <div @@ -75,6 +90,29 @@ export default function Layout(props: ParentProps) { </Show> </div> </div> + <div class="flex flex-col items-start shrink-0 px-3 py-1 mx-auto @[4rem]:mx-0"> + <Button + as={"a"} + href="https://opencode.ai/desktop-feedback" + target="_blank" + class="hidden @[4rem]:flex w-full gap-2 text-12-medium text-text-base stroke-[1.5px]" + variant="ghost" + icon="speech-bubble" + > + Share feedback + </Button> + <Tooltip placement="right" value="Share feedback"> + <IconButton + as={"a"} + href="https://opencode.ai/desktop-feedback" + target="_blank" + icon="speech-bubble" + variant="ghost" + size="large" + class="@[4rem]:hidden stroke-[1.5px]" + /> + </Tooltip> + </div> </div> <main class="size-full overflow-x-hidden">{props.children}</main> </div> |
