summaryrefslogtreecommitdiffhomepage
path: root/packages/desktop/src/pages
diff options
context:
space:
mode:
authorAdam <[email protected]>2025-10-31 11:54:27 -0500
committerAdam <[email protected]>2025-10-31 12:00:44 -0500
commitffc889b99e61c6f21ce68985ee398c3031a5b19b (patch)
treeb4356c27d343f127265ae020b015e8224b658ba4 /packages/desktop/src/pages
parent36b48a44ac1f0c9593a4abdf1d21980a2bfaee22 (diff)
downloadopencode-ffc889b99e61c6f21ce68985ee398c3031a5b19b.tar.gz
opencode-ffc889b99e61c6f21ce68985ee398c3031a5b19b.zip
wip: desktop work
Diffstat (limited to 'packages/desktop/src/pages')
-rw-r--r--packages/desktop/src/pages/index.tsx130
1 files changed, 30 insertions, 100 deletions
diff --git a/packages/desktop/src/pages/index.tsx b/packages/desktop/src/pages/index.tsx
index 5b2f4ecc1..3eea97b6c 100644
--- a/packages/desktop/src/pages/index.tsx
+++ b/packages/desktop/src/pages/index.tsx
@@ -17,6 +17,7 @@ import {
} from "@opencode-ai/ui"
import { FileIcon } from "@/ui"
import FileTree from "@/components/file-tree"
+import { MessageProgress } from "@/components/message-progress"
import { For, onCleanup, onMount, Show, Match, Switch, createSignal, createEffect, createMemo } from "solid-js"
import { useLocal, type LocalFile } from "@/context/local"
import { createStore } from "solid-js/store"
@@ -39,6 +40,7 @@ import { useSync } from "@/context/sync"
import { useSDK } from "@/context/sdk"
import { type AssistantMessage as AssistantMessageType } from "@opencode-ai/sdk"
import { Markdown } from "@opencode-ai/ui"
+import { Spinner } from "@/components/spinner"
export default function Page() {
const local = useLocal()
@@ -546,21 +548,31 @@ export default function Page() {
<For each={local.session.userMessages()}>
{(message) => {
const diffs = createMemo(() => message.summary?.diffs ?? [])
+ const working = createMemo(() => !message.summary?.title)
return (
- <li
- class="group/li flex items-center gap-x-2 py-1 self-stretch cursor-default"
- onClick={() => local.session.setActiveMessage(message.id)}
- >
- <DiffChanges diff={diffs()} variant="bars" />
- <div
- data-active={local.session.activeMessage()?.id === message.id}
- classList={{
- "text-14-regular text-text-weak whitespace-nowrap truncate min-w-0": true,
- "text-text-weak data-[active=true]:text-text-strong group-hover/li:text-text-base": true,
- }}
+ <li class="group/li flex items-center self-stretch">
+ <button
+ class="flex items-center self-stretch w-full gap-x-2 py-1 cursor-default"
+ onClick={() => local.session.setActiveMessage(message.id)}
>
- {message.summary?.title ?? local.session.getMessageText(message)}
- </div>
+ <Switch>
+ <Match when={working()}>
+ <Spinner class="text-text-base shrink-0 w-[18px] aspect-square" />
+ </Match>
+ <Match when={true}>
+ <DiffChanges diff={diffs()} variant="bars" />
+ </Match>
+ </Switch>
+ <div
+ data-active={local.session.activeMessage()?.id === message.id}
+ classList={{
+ "text-14-regular text-text-weak whitespace-nowrap truncate min-w-0": true,
+ "text-text-weak data-[active=true]:text-text-strong group-hover/li:text-text-base": true,
+ }}
+ >
+ {message.summary?.title ?? local.session.getMessageText(message)}
+ </div>
+ </button>
</li>
)
}}
@@ -600,19 +612,15 @@ export default function Page() {
</Show>
</div>
</div>
- <Show when={title}>
- <div class="-mt-8">
- <Message message={message} parts={parts()} />
- </div>
- </Show>
+ <div class="-mt-8">
+ <Message message={message} parts={parts()} />
+ </div>
{/* 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>
- <Show when={summary()}>
- <Markdown text={summary()!} />
- </Show>
+ <Show when={summary()}>{(summary) => <Markdown text={summary()} />}</Show>
</div>
<Accordion class="w-full" multiple>
<For each={message.summary?.diffs || []}>
@@ -666,85 +674,7 @@ export default function Page() {
<div class="w-full">
<Switch>
<Match when={working()}>
- {(_) => {
- const items = createMemo(() =>
- assistantMessages().flatMap((m) => sync.data.part[m.id]),
- )
- const finishedItems = createMemo(() =>
- items().filter(
- (p) =>
- (p?.type === "text" && p.time?.end) ||
- (p?.type === "reasoning" && p.time?.end) ||
- (p?.type === "tool" && p.state.status === "completed"),
- ),
- )
-
- const MINIMUM_DELAY = 800
- const [visibleCount, setVisibleCount] = createSignal(1)
-
- createEffect(() => {
- const total = finishedItems().length
- if (total > visibleCount()) {
- const timer = setTimeout(() => {
- setVisibleCount((prev) => prev + 1)
- }, MINIMUM_DELAY)
- onCleanup(() => clearTimeout(timer))
- } else if (total < visibleCount()) {
- setVisibleCount(total)
- }
- })
-
- const translateY = createMemo(() => {
- const total = visibleCount()
- if (total < 2) return "0px"
- return `-${(total - 2) * 48 - 8}px`
- })
-
- return (
- <div class="flex flex-col gap-3">
- <div
- class="h-36 overflow-hidden pointer-events-none
- mask-alpha mask-y-from-66% mask-y-from-background-base mask-y-to-transparent"
- >
- <div
- class="w-full flex flex-col items-start self-stretch gap-2 py-10
- transform transition-transform duration-500 ease-[cubic-bezier(0.22,1,0.36,1)]"
- style={{ transform: `translateY(${translateY()})` }}
- >
- <For each={finishedItems()}>
- {(part) => {
- const message = createMemo(() =>
- sync.data.message[part.sessionID].find(
- (m) => m.id === part.messageID,
- ),
- )
- return (
- <div class="h-10 flex items-center w-full">
- <Switch>
- <Match when={part.type === "text" && part}>
- {(p) => (
- <div
- textContent={p().text}
- class="text-12-regular text-text-base whitespace-nowrap truncate w-full"
- />
- )}
- </Match>
- <Match when={part.type === "reasoning" && part}>
- {(p) => <Part message={message()!} part={p()} />}
- </Match>
- <Match when={part.type === "tool" && part}>
- {(p) => <Part message={message()!} part={p()} />}
- </Match>
- </Switch>
- </div>
- )
- }}
- </For>
- </div>
- </div>
- </div>
- )
- }}
+ <MessageProgress assistantMessages={assistantMessages} />
</Match>
<Match when={!working()}>
<Collapsible variant="ghost" open={expanded()} onOpenChange={setExpanded}>