diff options
| author | Adam <[email protected]> | 2025-11-14 12:38:52 -0600 |
|---|---|---|
| committer | opencode <[email protected]> | 2025-11-18 17:07:34 +0000 |
| commit | 4069999b782cc00d4e707f5eca32082bdfad45bc (patch) | |
| tree | d5c13cdd361fc79b14250b4b426a0a1195f7a01c /packages/desktop/src/pages | |
| parent | 5ba9b47b3c87dfb044c30857e56959c8eff0c8c1 (diff) | |
| download | opencode-4069999b782cc00d4e707f5eca32082bdfad45bc.tar.gz opencode-4069999b782cc00d4e707f5eca32082bdfad45bc.zip | |
wip(desktop): new layout work
Diffstat (limited to 'packages/desktop/src/pages')
| -rw-r--r-- | packages/desktop/src/pages/layout.tsx | 82 | ||||
| -rw-r--r-- | packages/desktop/src/pages/session-layout.tsx | 16 | ||||
| -rw-r--r-- | packages/desktop/src/pages/session.tsx | 49 |
3 files changed, 112 insertions, 35 deletions
diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index d88564007..6e0078a16 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -1,33 +1,85 @@ -import { Button, Tooltip, DiffChanges, IconButton } from "@opencode-ai/ui" -import { createMemo, For, ParentProps, Show } from "solid-js" +import { Button, Tooltip, DiffChanges, IconButton, Mark, Icon } from "@opencode-ai/ui" +import { createMemo, For, Match, ParentProps, Show, Switch } from "solid-js" import { DateTime } from "luxon" import { useSync } from "@/context/sync" import { A, useParams } from "@solidjs/router" -import { useLocal } from "@/context/local" +import { useLayout } from "@/context/layout" export default function Layout(props: ParentProps) { const params = useParams() const sync = useSync() - const local = useLocal() + const layout = useLayout() 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"> + <header class="h-12 shrink-0 bg-background-base border-b border-border-weak-base"> <div classList={{ - "@container w-14 pb-4 shrink-0 bg-background-weak": true, - "flex flex-col items-start self-stretch justify-between": true, + "w-12 shrink-0 px-4 py-3.5": true, + "flex items-center justify-start self-stretch": true, "border-r border-border-weak-base": true, - "w-70": local.layout.sidebar.opened(), }} + style={{ width: layout.sidebar.opened() ? `${layout.sidebar.width()}px` : undefined }} > - <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> + <Mark class="shrink-0" /> + </div> + </header> + <div class="h-[calc(100vh-3rem)] flex"> + <div + classList={{ + "@container w-12 pb-5 shrink-0 bg-background-base": true, + "flex flex-col gap-5.5 items-start self-stretch justify-between": true, + "border-r border-border-weak-base": true, + }} + style={{ width: layout.sidebar.opened() ? `${layout.sidebar.width()}px` : undefined }} + > + <div class="flex flex-col justify-center items-start gap-4 self-stretch p-2 overflow-hidden mx-auto @[4rem]:mx-0"> + <Switch> + <Match when={layout.sidebar.opened()}> + <Button + variant="ghost" + size="large" + class="group/sidebar-toggle w-full text-left justify-start" + onClick={layout.sidebar.toggle} + > + <div class="relative -ml-px flex items-center justify-center size-4 [&>*]:absolute [&>*]:inset-0"> + <Icon name="layout-left" size="small" class="group-hover/sidebar-toggle:hidden" /> + <Icon + name="layout-left-partial" + size="small" + class="hidden group-hover/sidebar-toggle:inline-block" + /> + <Icon + name="layout-left-full" + size="small" + class="hidden group-active/sidebar-toggle:inline-block" + /> + </div> + <div class="hidden group-hover/sidebar-toggle:block group-active/sidebar-toggle:block text-text-base"> + Toggle sidebar + </div> + </Button> + </Match> + <Match when={!layout.sidebar.opened()}> + <Tooltip placement="right" value="Toggle sidebar"> + <Button variant="ghost" size="large" class="group/sidebar-toggle" onClick={layout.sidebar.toggle}> + <div class="relative -ml-px flex items-center justify-center size-4 [&>*]:absolute [&>*]:inset-0"> + <Icon name="layout-right" size="small" class="group-hover/sidebar-toggle:hidden" /> + <Icon + name="layout-right-partial" + size="small" + class="hidden group-hover/sidebar-toggle:inline-block" + /> + <Icon + name="layout-right-full" + size="small" + class="hidden group-active/sidebar-toggle:inline-block" + /> + </div> + </Button> + </Tooltip> + </Match> + </Switch> <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 diff --git a/packages/desktop/src/pages/session-layout.tsx b/packages/desktop/src/pages/session-layout.tsx index 9a24608f0..7f355c9bc 100644 --- a/packages/desktop/src/pages/session-layout.tsx +++ b/packages/desktop/src/pages/session-layout.tsx @@ -1,12 +1,24 @@ import { Show, type ParentProps } from "solid-js" -import { SessionProvider } from "@/context/session" +import { SessionProvider, useSession } from "@/context/session" import { useParams } from "@solidjs/router" +import { SDKProvider, useSDK } from "@/context/sdk" +import { LocalProvider } from "@/context/local" export default function Layout(props: ParentProps) { const params = useParams() + const root = useSDK() return ( <Show when={params.id || true} keyed> - <SessionProvider sessionId={params.id}>{props.children}</SessionProvider> + <SessionProvider sessionId={params.id}> + {(() => { + const session = useSession() + return ( + <SDKProvider url={root.url} directory={session.info()?.directory}> + <LocalProvider>{props.children}</LocalProvider> + </SDKProvider> + ) + })()} + </SessionProvider> </Show> ) } diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 0e5eb1f3d..884d789b1 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -13,7 +13,6 @@ import { Code, Tooltip, ProgressCircle, - Button, } from "@opencode-ai/ui" import { FileIcon } from "@/ui" import { MessageProgress } from "@/components/message-progress" @@ -52,8 +51,10 @@ import { Spinner } from "@/components/spinner" import { useSession } from "@/context/session" import { StickyAccordionHeader } from "@/components/sticky-accordion-header" import { SessionReview } from "@/components/session-review" +import { useLayout } from "@/context/layout" export default function Page() { + const layout = useLayout() const local = useLocal() const sync = useSync() const session = useSession() @@ -176,10 +177,16 @@ export default function Page() { setStore("activeDraggable", undefined) } - const FileVisual = (props: { file: LocalFile }): JSX.Element => { + const FileVisual = (props: { file: LocalFile; active?: boolean }): JSX.Element => { return ( <div class="flex items-center gap-x-1.5"> - <FileIcon node={props.file} class="grayscale-100 group-data-[selected]/tab:grayscale-0" /> + <FileIcon + node={props.file} + classList={{ + "grayscale-100 group-data-[selected]/tab:grayscale-0": !props.active, + "grayscale-0": props.active, + }} + /> <span classList={{ "text-14-medium": true, @@ -300,11 +307,11 @@ export default function Page() { </Tooltip> </div> </Tabs.Trigger> - <Show when={local.layout.review.state() === "tab" && session.diffs().length}> + <Show when={layout.review.state() === "tab" && session.diffs().length}> <Tabs.Trigger value="review" closeButton={ - <IconButton icon="collapse" size="normal" variant="ghost" onClick={local.layout.review.pane} /> + <IconButton icon="collapse" size="normal" variant="ghost" onClick={layout.review.pane} /> } > <div class="flex items-center gap-3"> @@ -343,8 +350,8 @@ export default function Page() { <div classList={{ "w-full flex-1 min-h-0": true, - grid: local.layout.review.state() === "tab", - flex: local.layout.review.state() === "pane", + grid: layout.review.state() === "tab", + flex: layout.review.state() === "pane", }} > <div class="relative shrink-0 px-6 py-3 flex flex-col gap-6 flex-1 min-h-0 w-full max-w-xl mx-auto"> @@ -353,7 +360,7 @@ export default function Page() { <div classList={{ "flex-1 min-h-0 pb-20": true, - "flex items-start justify-start": local.layout.review.state() === "pane", + "flex items-start justify-start": layout.review.state() === "pane", }} > <Show when={session.messages.user().length > 1}> @@ -361,8 +368,8 @@ export default function Page() { role="list" classList={{ "mr-8 shrink-0 flex flex-col items-start": true, - "absolute right-full w-60 mt-3 @7xl:gap-2 @7xl:mt-1": local.layout.review.state() === "tab", - "mt-3": local.layout.review.state() === "pane", + "absolute right-full w-60 mt-3 @7xl:gap-2 @7xl:mt-1": layout.review.state() === "tab", + "mt-3": layout.review.state() === "pane", }} > <For each={session.messages.user()}> @@ -382,7 +389,7 @@ export default function Page() { <li classList={{ "group/li flex items-center self-stretch justify-end": true, - "@7xl:justify-start": local.layout.review.state() === "tab", + "@7xl:justify-start": layout.review.state() === "tab", }} > <Tooltip @@ -401,7 +408,7 @@ export default function Page() { classList={{ "group/tick flex items-center justify-start h-2 w-8 -mr-3": true, "data-[active=true]:[&>div]:bg-icon-strong-base data-[active=true]:[&>div]:w-full": true, - "@7xl:hidden": local.layout.review.state() === "tab", + "@7xl:hidden": layout.review.state() === "tab", }} > <div class="h-px w-5 bg-icon-base group-hover/tick:w-full group-hover/tick:bg-icon-strong-base" /> @@ -410,7 +417,7 @@ export default function Page() { <button classList={{ "hidden items-center self-stretch w-full gap-x-2 cursor-default": true, - "@7xl:flex": local.layout.review.state() === "tab", + "@7xl:flex": layout.review.state() === "tab", }} onClick={handleClick} > @@ -654,7 +661,7 @@ export default function Page() { /> </div> </div> - <Show when={local.layout.review.state() === "pane" && session.diffs().length}> + <Show when={layout.review.state() === "pane" && session.diffs().length}> <div classList={{ "relative grow px-6 py-3 flex-1 min-h-0 border-l border-border-weak-base": true, @@ -665,7 +672,7 @@ export default function Page() { </Show> </div> </Tabs.Content> - <Show when={local.layout.review.state() === "tab" && session.diffs().length}> + <Show when={layout.review.state() === "tab" && session.diffs().length}> <Tabs.Content value="review" class="select-text flex flex-col h-full overflow-hidden"> <div classList={{ @@ -718,8 +725,8 @@ export default function Page() { }, ) return ( - <div class="relative px-3 h-10 flex items-center bg-background-base border-x border-border-weak-base border-b border-b-transparent"> - <Show when={file()}>{(f) => <FileVisual file={f()} />}</Show> + <div class="relative px-6 h-12 flex items-center bg-background-stronger border-x border-border-weak-base border-b border-b-transparent"> + <Show when={file()}>{(f) => <FileVisual active file={f()} />}</Show> </div> ) }} @@ -769,7 +776,13 @@ export default function Page() { items={local.file.searchFiles} key={(x) => x} onOpenChange={(open) => setStore("fileSelectOpen", open)} - onSelect={(x) => (x ? session.layout.openTab("file://" + x) : undefined)} + onSelect={(x) => { + if (x) { + local.file.open(x) + return session.layout.openTab("file://" + x) + } + return undefined + }} > {(i) => ( <div |
