summaryrefslogtreecommitdiffhomepage
path: root/packages/desktop/src
diff options
context:
space:
mode:
authorAdam <[email protected]>2025-11-06 09:48:46 -0600
committerAdam <[email protected]>2025-11-06 09:48:51 -0600
commit6ba7c54baba355e3788e371374d26e58b60feb0d (patch)
treea69448dcdcd8e1935b2bc3c7d2344ad78f8ced75 /packages/desktop/src
parent146bae82cb584c253a42ed4565d423d9cded93a6 (diff)
downloadopencode-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.tsx1
-rw-r--r--packages/desktop/src/context/local.tsx35
-rw-r--r--packages/desktop/src/pages/layout.tsx62
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>