wip: desktop work

This commit is contained in:
Adam
2025-10-29 16:04:30 -05:00
parent cdeb82e9ca
commit 3210df7428
2 changed files with 114 additions and 28 deletions

View File

@@ -36,6 +36,7 @@ import { ProgressCircle } from "@/components/progress-circle"
import { Message, Part } from "@/components/message"
import { type AssistantMessage as AssistantMessageType } from "@opencode-ai/sdk"
import { DiffChanges } from "@/components/diff-changes"
import { Markdown } from "@/components/markdown"
export default function Page() {
const local = useLocal()
@@ -491,8 +492,8 @@ export default function Page() {
</Show>
</div>
</div>
<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">
<Tabs.Content value="chat" class="@container select-text flex flex-col flex-1 min-h-0 overflow-y-hidden">
<div class="relative px-6 pt-12 max-w-2xl w-full mx-auto flex flex-col flex-1 min-h-0">
<Show
when={local.session.active()}
fallback={
@@ -519,9 +520,12 @@ export default function Page() {
>
{(activeSession) => (
<div class="pt-3 flex flex-col flex-1 min-h-0">
<div class="flex items-start gap-8 flex-1 min-h-0">
<div class="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">
<ul
role="list"
class="absolute right-full mr-8 hidden w-60 shrink-0 @7xl:flex flex-col items-start gap-1"
>
<For each={local.session.userMessages()}>
{(message) => {
const countLines = (text: string) => {
@@ -648,16 +652,12 @@ 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 working = createMemo(() => !summary())
return (
<div
data-message={message.id}
class="flex flex-col items-start self-stretch gap-8 min-h-[calc(100vh-15rem)]"
class="flex flex-col items-start self-stretch gap-8 min-h-screen"
>
{/* Title */}
<div class="py-2 flex flex-col items-start gap-2 self-stretch sticky top-0 bg-background-stronger">
@@ -675,7 +675,9 @@ export default function Page() {
<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>
<Show when={summary()}>
<Markdown text={summary()!} />
</Show>
</div>
<Accordion class="w-full" multiple>
<For each={message.summary?.diffs || []}>
@@ -729,14 +731,85 @@ export default function Page() {
<div class="w-full">
<Switch>
<Match when={working()}>
<div class="w-full flex flex-col-reverse items-start self-stretch gap-6 max-h-30 overflow-y-auto no-scrollbar pointer-events-none mask-alpha mask-y-from-66% mask-y-from-background-base mask-y-to-transparent">
<For each={assistantMessages()?.toReversed()}>
{(assistantMessage) => {
const parts = createMemo(() => sync.data.part[assistantMessage.id])
return <Message message={assistantMessage} parts={parts()} />
}}
</For>
</div>
{(_) => {
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>
)
}}
</Match>
<Match when={!working()}>
<Collapsible variant="ghost" open={expanded()} onOpenChange={setExpanded}>
@@ -752,7 +825,7 @@ export default function Page() {
</div>
</Collapsible.Trigger>
<Collapsible.Content>
<div class="w-full flex flex-col-reverse items-start self-stretch gap-8">
<div class="w-full flex flex-col items-start self-stretch gap-8">
<For each={assistantMessages()}>
{(assistantMessage) => {
const parts = createMemo(
@@ -807,14 +880,7 @@ export default function Page() {
})()}
</DragOverlay>
</DragDropProvider>
<div
classList={{
"absolute inset-x-0 px-6 max-w-[904px] flex flex-col justify-center items-center z-50 mx-auto": true,
"bottom-8": true,
// "bottom-8": !!local.session.active(),
// "bottom-1/2 translate-y-1/2": !local.session.active(),
}}
>
<div class="absolute inset-x-0 px-6 max-w-2xl flex flex-col justify-center items-center z-50 mx-auto bottom-8">
<PromptInput
ref={(el) => {
inputRef = el