diff options
| author | Adam <[email protected]> | 2025-10-28 15:29:11 -0500 |
|---|---|---|
| committer | Adam <[email protected]> | 2025-10-28 15:29:16 -0500 |
| commit | 545f34584847e3216ecf95ab493dacac282ec465 (patch) | |
| tree | 9bf9c1e8cd2d49ee63a155e4b4131b4e1960fc0f /packages/desktop/src/pages | |
| parent | 77ae0b527e4b1a8277b0391d0acbc7d82b08e4ea (diff) | |
| download | opencode-545f34584847e3216ecf95ab493dacac282ec465.tar.gz opencode-545f34584847e3216ecf95ab493dacac282ec465.zip | |
wip: desktop work
Diffstat (limited to 'packages/desktop/src/pages')
| -rw-r--r-- | packages/desktop/src/pages/index.tsx | 136 |
1 files changed, 68 insertions, 68 deletions
diff --git a/packages/desktop/src/pages/index.tsx b/packages/desktop/src/pages/index.tsx index b4bd36162..c1884b2c0 100644 --- a/packages/desktop/src/pages/index.tsx +++ b/packages/desktop/src/pages/index.tsx @@ -1,8 +1,19 @@ -import { Button, List, SelectDialog, Tooltip, IconButton, Tabs, Icon, Accordion, Diff } from "@opencode-ai/ui" +import { + Button, + List, + SelectDialog, + Tooltip, + IconButton, + Tabs, + Icon, + Accordion, + Diff, + Collapsible, +} from "@opencode-ai/ui" import { FileIcon } from "@/ui" import FileTree from "@/components/file-tree" import { For, onCleanup, onMount, Show, Match, Switch, createSignal, createEffect, createMemo } from "solid-js" -import { useLocal, type LocalFile, type TextSelection } from "@/context/local" +import { useLocal, type LocalFile } from "@/context/local" import { createStore } from "solid-js/store" import { getDirectory, getFilename } from "@/utils" import { ContentPart, PromptInput } from "@/components/prompt-input" @@ -185,42 +196,10 @@ export default function Page() { } if (!session) return - interface SubmissionAttachment { - path: string - selection?: TextSelection - label: string - } - - const createAttachmentKey = (path: string, selection?: TextSelection) => { - if (!selection) return path - return `${path}:${selection.startLine}:${selection.startChar}:${selection.endLine}:${selection.endChar}` - } - - const formatAttachmentLabel = (path: string, selection?: TextSelection) => { - if (!selection) return getFilename(path) - return `${getFilename(path)} (${selection.startLine}-${selection.endLine})` - } - const toAbsolutePath = (path: string) => (path.startsWith("/") ? path : sync.absolute(path)) const text = parts.map((part) => part.content).join("") - const attachments = new Map<string, SubmissionAttachment>() - - const registerAttachment = (path: string, selection: TextSelection | undefined, label?: string) => { - if (!path) return - const key = createAttachmentKey(path, selection) - if (attachments.has(key)) return - attachments.set(key, { - path, - selection, - label: label ?? formatAttachmentLabel(path, selection), - }) - } - - const promptAttachments = parts.filter((part) => part.type === "file") - for (const part of promptAttachments) { - registerAttachment(part.path, part.selection, part.content) - } + const attachments = parts.filter((part) => part.type === "file") // const activeFile = local.context.active() // if (activeFile) { @@ -239,7 +218,7 @@ export default function Page() { // ) // } - const attachmentParts = Array.from(attachments.values()).map((attachment) => { + const attachmentParts = attachments.map((attachment) => { const absolute = toAbsolutePath(attachment.path) const query = attachment.selection ? `?start=${attachment.selection.startLine}&end=${attachment.selection.endLine}` @@ -252,9 +231,9 @@ export default function Page() { source: { type: "file" as const, text: { - value: `@${attachment.label}`, - start: 0, - end: 0, + value: attachment.content, + start: attachment.start, + end: attachment.end, }, path: absolute, }, @@ -510,8 +489,8 @@ export default function Page() { </Show> </div> </div> - <Tabs.Content value="chat" class="select-text flex flex-col flex-1 min-h-0"> - <div class="p-6 pt-12 max-w-[904px] w-full mx-auto flex flex-col flex-1 min-h-0"> + <Tabs.Content value="chat" class="select-text flex flex-col flex-1 min-h-0 overflow-y-hidden"> + <div class="px-6 pt-12 max-w-[904px] w-full mx-auto flex flex-col flex-1 min-h-0"> <Show when={local.session.active()} fallback={ @@ -537,7 +516,7 @@ export default function Page() { } > {(activeSession) => ( - <div class="py-3 flex flex-col flex-1 min-h-0"> + <div class="pt-3 flex flex-col flex-1 min-h-0"> <div class="flex items-start gap-8 flex-1 min-h-0"> <Show when={local.session.userMessages().length > 1}> <ul role="list" class="w-60 shrink-0 flex flex-col items-start gap-1"> @@ -665,30 +644,65 @@ export default function Page() { (m) => m.role === "assistant" && m.parentID == message.id, ) as AssistantMessageType[] }) + const working = createMemo(() => { + const last = assistantMessages()[assistantMessages().length - 1] + if (!last) return false + return !last.time.completed + }) + const lastWithContent = createMemo(() => + assistantMessages().findLast((m) => { + const parts = sync.data.part[m.id] + return parts?.find((p) => p.type === "text" || p.type === "tool") + }), + ) return ( - <div - data-message={message.id} - class="flex flex-col items-start self-stretch gap-14 pt-1.5" - > + <div data-message={message.id} class="flex flex-col items-start self-stretch gap-8"> {/* Title */} - <div class="flex flex-col items-start gap-2 self-stretch"> + <div class="py-2 flex flex-col items-start gap-2 self-stretch sticky top-0 bg-background-stronger"> <h1 class="text-14-medium text-text-strong overflow-hidden text-ellipsis min-w-0"> {title() ?? prompt()} </h1> - <Show when={title}> - <div class="text-12-regular text-text-base">{prompt()}</div> + </div> + <Show when={title}> + <div class="-mt-5 text-12-regular text-text-base line-clamp-3">{prompt()}</div> + </Show> + {/* Response */} + <div class="w-full flex flex-col gap-2"> + <Collapsible variant="ghost"> + <Collapsible.Trigger class="text-text-weak hover:text-text-strong"> + <div class="flex items-center gap-1 self-stretch"> + <h2 class="text-12-medium">Show steps</h2> + <Collapsible.Arrow /> + </div> + </Collapsible.Trigger> + <Collapsible.Content> + <div class="w-full flex flex-col items-start self-stretch gap-8"> + <For each={assistantMessages()}> + {(assistantMessage) => { + const parts = createMemo(() => sync.data.part[assistantMessage.id]) + return <AssistantMessage message={assistantMessage} parts={parts()} /> + }} + </For> + </div> + </Collapsible.Content> + </Collapsible> + <Show when={working() && lastWithContent()}> + {(last) => { + const lastParts = createMemo(() => sync.data.part[last().id]) + return ( + <AssistantMessage lastToolOnly message={last()} parts={lastParts()} /> + ) + }} </Show> </div> {/* Summary */} - <div class="w-full flex flex-col gap-6 items-start self-stretch"> - <Show when={summary}> + <Show when={!working()}> + <div class="w-full flex flex-col gap-6 items-start self-stretch"> <div class="flex flex-col items-start gap-1 self-stretch"> <h2 class="text-12-medium text-text-weak">Summary</h2> <div class="text-14-regular text-text-base self-stretch">{summary()}</div> </div> - </Show> - <Show when={message.summary?.diffs.length}> <Accordion class="w-full" multiple> <For each={message.summary?.diffs || []}> {(diff) => ( @@ -735,22 +749,8 @@ export default function Page() { )} </For> </Accordion> - </Show> - </div> - {/* Response */} - <div data-todo="Response" class="w-full"> - <div class="flex flex-col items-start gap-1 self-stretch"> - <h2 class="text-12-medium text-text-weak">Response</h2> </div> - <div class="w-full flex flex-col items-start self-stretch gap-8"> - <For each={assistantMessages()}> - {(assistantMessage) => { - const parts = createMemo(() => sync.data.part[assistantMessage.id]) - return <AssistantMessage message={assistantMessage} parts={parts()} /> - }} - </For> - </div> - </div> + </Show> </div> ) }} |
