diff options
| author | Adam <[email protected]> | 2025-11-13 14:47:25 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2025-11-13 14:47:29 -0600 |
| commit | a8836c5615f620321cc7aa2670767e0c9586d27b (patch) | |
| tree | 4af1b0f7397d2dceac6e0c9ba734049f41d7c326 /packages/desktop/src/components | |
| parent | 779a27693a9d37ae212c27af353414ff4de07ea4 (diff) | |
| download | opencode-a8836c5615f620321cc7aa2670767e0c9586d27b.tar.gz opencode-a8836c5615f620321cc7aa2670767e0c9586d27b.zip | |
wip(desktop): layout improvements
Diffstat (limited to 'packages/desktop/src/components')
| -rw-r--r-- | packages/desktop/src/components/prompt-input.tsx | 12 | ||||
| -rw-r--r-- | packages/desktop/src/components/session-review.tsx | 104 | ||||
| -rw-r--r-- | packages/desktop/src/components/sticky-accordion-header.tsx | 17 |
3 files changed, 127 insertions, 6 deletions
diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx index b2022cf30..2ae5f87fc 100644 --- a/packages/desktop/src/components/prompt-input.tsx +++ b/packages/desktop/src/components/prompt-input.tsx @@ -347,7 +347,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { <Show when={store.popoverIsOpen}> <div class="absolute inset-x-0 -top-3 -translate-y-full origin-bottom-left max-h-[252px] min-h-10 - overflow-auto no-scrollbar flex flex-col p-2 pb-0 rounded-2xl + overflow-auto no-scrollbar flex flex-col p-2 pb-0 rounded-md border border-border-base bg-surface-raised-stronger-non-alpha shadow-md" > <Show when={flat().length > 0} fallback={<div class="text-text-weak px-2">No matching files</div>}> @@ -382,7 +382,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { onSubmit={handleSubmit} classList={{ "bg-surface-raised-stronger-non-alpha border border-border-strong-base": true, - "rounded-2xl overflow-clip focus-within:border-transparent focus-within:shadow-xs-border-select": true, + "rounded-md overflow-clip focus-within:border-transparent focus-within:shadow-xs-border-select": true, [props.class ?? ""]: !!props.class, }} > @@ -396,17 +396,17 @@ export const PromptInput: Component<PromptInputProps> = (props) => { onInput={handleInput} onKeyDown={handleKeyDown} classList={{ - "w-full p-3 text-14-regular text-text-strong focus:outline-none whitespace-pre-wrap": true, + "w-full px-5 py-3 text-14-regular text-text-strong focus:outline-none whitespace-pre-wrap": true, "[&>[data-type=file]]:text-icon-info-active": true, }} /> <Show when={!session.prompt.dirty()}> - <div class="absolute top-0 left-0 p-3 text-14-regular text-text-weak pointer-events-none"> + <div class="absolute top-0 left-0 px-5 py-3 text-14-regular text-text-weak pointer-events-none"> Plan and build anything </div> </Show> </div> - <div class="p-3 flex items-center justify-between"> + <div class="relative p-3 flex items-center justify-between"> <div class="flex items-center justify-start gap-1"> <Select options={local.agent.list().map((agent) => agent.name)} @@ -489,7 +489,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { disabled={!session.prompt.dirty() && !session.working()} icon={session.working() ? "stop" : "arrow-up"} variant="primary" - class="rounded-full" + class="h-10 w-8 absolute right-2 bottom-2" /> </Tooltip> </div> diff --git a/packages/desktop/src/components/session-review.tsx b/packages/desktop/src/components/session-review.tsx new file mode 100644 index 000000000..8aefbbd46 --- /dev/null +++ b/packages/desktop/src/components/session-review.tsx @@ -0,0 +1,104 @@ +import { useLocal } from "@/context/local" +import { useSession } from "@/context/session" +import { FileIcon } from "@/ui" +import { getDirectory, getFilename } from "@/utils" +import { Accordion, Button, Diff, DiffChanges, Icon, IconButton, Tooltip } from "@opencode-ai/ui" +import { For, Match, Show, Switch } from "solid-js" +import { StickyAccordionHeader } from "./sticky-accordion-header" +import { createStore } from "solid-js/store" + +export const SessionReview = (props: { split?: boolean; class?: string; hideExpand?: boolean }) => { + const local = useLocal() + const session = useSession() + const [store, setStore] = createStore({ + open: session.diffs().map((d) => d.file), + }) + + const handleChange = (open: string[]) => { + setStore("open", open) + } + + const handleExpandOrCollapseAll = () => { + if (store.open.length > 0) { + setStore("open", []) + } else { + setStore( + "open", + session.diffs().map((d) => d.file), + ) + } + } + + return ( + <div + classList={{ + "flex flex-col gap-3 h-full overflow-y-auto no-scrollbar": true, + [props.class ?? ""]: !!props.class, + }} + > + <div class="sticky top-0 z-20 bg-background-stronger h-8 shrink-0 flex justify-between items-center self-stretch"> + <div class="text-14-medium text-text-strong">Session changes</div> + <div class="flex items-center gap-x-4 pr-px"> + <Button size="normal" icon="chevron-grabber-vertical" onClick={handleExpandOrCollapseAll}> + <Switch> + <Match when={store.open.length > 0}>Collapse all</Match> + <Match when={true}>Expand all</Match> + </Switch> + </Button> + <Show when={!props.hideExpand}> + <Tooltip value="Open in tab"> + <IconButton + icon="expand" + variant="ghost" + onClick={() => { + local.layout.review.tab() + session.layout.setActiveTab("review") + }} + /> + </Tooltip> + </Show> + </div> + </div> + <Accordion multiple value={store.open} onChange={handleChange}> + <For each={session.diffs()}> + {(diff) => ( + <Accordion.Item value={diff.file}> + <StickyAccordionHeader class="top-11 data-expanded:before:-top-11"> + <Accordion.Trigger class="bg-background-stronger"> + <div class="flex items-center justify-between w-full gap-5"> + <div class="grow flex items-center gap-5 min-w-0"> + <FileIcon node={{ path: diff.file, type: "file" }} class="shrink-0 size-4" /> + <div class="flex grow min-w-0"> + <Show when={diff.file.includes("/")}> + <span class="text-text-base truncate-start">{getDirectory(diff.file)}‎</span> + </Show> + <span class="text-text-strong shrink-0">{getFilename(diff.file)}</span> + </div> + </div> + <div class="shrink-0 flex gap-4 items-center justify-end"> + <DiffChanges changes={diff} /> + <Icon name="chevron-grabber-vertical" size="small" /> + </div> + </div> + </Accordion.Trigger> + </StickyAccordionHeader> + <Accordion.Content> + <Diff + diffStyle={props.split ? "split" : "unified"} + before={{ + name: diff.file!, + contents: diff.before!, + }} + after={{ + name: diff.file!, + contents: diff.after!, + }} + /> + </Accordion.Content> + </Accordion.Item> + )} + </For> + </Accordion> + </div> + ) +} diff --git a/packages/desktop/src/components/sticky-accordion-header.tsx b/packages/desktop/src/components/sticky-accordion-header.tsx new file mode 100644 index 000000000..cb3f0d5eb --- /dev/null +++ b/packages/desktop/src/components/sticky-accordion-header.tsx @@ -0,0 +1,17 @@ +import { Accordion } from "@opencode-ai/ui" +import { ParentProps } from "solid-js" + +export function StickyAccordionHeader(props: ParentProps<{ class?: string }>) { + return ( + <Accordion.Header + classList={{ + "sticky top-0 data-expanded:z-10": true, + "data-expanded:before:content-[''] data-expanded:before:z-[-10]": true, + "data-expanded:before:absolute data-expanded:before:inset-0 data-expanded:before:bg-background-stronger": true, + [props.class ?? ""]: !!props.class, + }} + > + {props.children} + </Accordion.Header> + ) +} |
