diff options
| author | Adam <[email protected]> | 2025-11-05 16:32:05 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2025-11-05 16:32:08 -0600 |
| commit | e006e3355cff3de25e023edcee0b59985e7db66b (patch) | |
| tree | 97d54c28fe10801fadfdb28adce18d1c68c4c0ea | |
| parent | d7e31f76c480be81985590dfabcca353be8442bc (diff) | |
| download | opencode-e006e3355cff3de25e023edcee0b59985e7db66b.tar.gz opencode-e006e3355cff3de25e023edcee0b59985e7db66b.zip | |
feat(desktop): incrementally load sessions in side nav
| -rw-r--r-- | packages/desktop/src/context/sync.tsx | 22 | ||||
| -rw-r--r-- | packages/desktop/src/pages/layout.tsx | 95 |
2 files changed, 70 insertions, 47 deletions
diff --git a/packages/desktop/src/context/sync.tsx b/packages/desktop/src/context/sync.tsx index c60206b0b..1e960397b 100644 --- a/packages/desktop/src/context/sync.tsx +++ b/packages/desktop/src/context/sync.tsx @@ -16,6 +16,8 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ config: Config path: Path session: Session[] + limit: number + more: boolean message: { [sessionID: string]: Message[] } @@ -32,6 +34,8 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ agent: [], provider: [], session: [], + limit: 10, + more: false, message: {}, part: {}, node: [], @@ -106,12 +110,14 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ path: () => sdk.client.path.get().then((x) => setStore("path", x.data!)), agent: () => sdk.client.app.agents().then((x) => setStore("agent", x.data ?? [])), session: () => - sdk.client.session.list().then((x) => - setStore( - "session", - (x.data ?? []).slice().sort((a, b) => a.id.localeCompare(b.id)), - ), - ), + sdk.client.session.list().then((x) => { + const sessions = (x.data ?? []) + .slice() + .sort((a, b) => a.id.localeCompare(b.id)) + .slice(0, store.limit) + setStore("session", sessions) + setStore("more", sessions.length === store.limit) + }), config: () => sdk.client.config.get().then((x) => setStore("config", x.data!)), changes: () => sdk.client.file.status().then((x) => setStore("changes", x.data!)), node: () => sdk.client.file.list({ query: { path: "/" } }).then((x) => setStore("node", x.data!)), @@ -184,6 +190,10 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ }), ) }, + fetch: async (count = 10) => { + setStore("limit", (x) => x + count) + await load.session() + }, }, load, absolute, diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 22f0a50de..1d9669604 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -1,5 +1,5 @@ import { Button, Tooltip, DiffChanges } from "@opencode-ai/ui" -import { createMemo, ParentProps, Show } from "solid-js" +import { createMemo, For, ParentProps, Show } from "solid-js" import { getFilename } from "@/utils" import { DateTime } from "luxon" import { useSync } from "@/context/sync" @@ -9,61 +9,74 @@ import { A, useParams } from "@solidjs/router" export default function Layout(props: ParentProps) { const params = useParams() const sync = useSync() + 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"> <div class="w-70 shrink-0 bg-background-weak border-r border-border-weak-base flex flex-col items-start"> - <div class="h-10 flex items-center self-stretch px-5 border-b border-border-weak-base"> + <div class="h-10 shrink-0 flex items-center self-stretch px-5 border-b border-border-weak-base"> <span class="text-14-regular overflow-hidden text-ellipsis">{getFilename(sync.data.path.directory)}</span> </div> - <div class="flex flex-col items-start gap-4 self-stretch flex-1 py-4 px-3"> + <div class="flex flex-col items-start gap-4 self-stretch flex-1 py-4 px-3 overflow-hidden"> <A href="/session" class="w-full"> <Button class="w-full" size="large" icon="edit-small-2"> New Session </Button> </A> - <VList data={sync.data.session} class="no-scrollbar"> - {(session) => { - const updated = createMemo(() => DateTime.fromMillis(session.time.updated)) - return ( - <A - data-active={session.id === params.id} - href={`/session/${session.id}`} - class="group/session focus:outline-none" - > - <Tooltip placement="right" value={session.title}> - <div - class="w-full mb-1.5 px-3 py-1 rounded-md + <div class="w-full h-full overflow-y-auto no-scrollbar flex flex-col flex-1"> + <nav class="w-full"> + <For each={sync.data.session}> + {(session) => { + const updated = createMemo(() => DateTime.fromMillis(session.time.updated)) + return ( + <A + data-active={session.id === params.id} + href={`/session/${session.id}`} + class="group/session focus:outline-none" + > + <Tooltip placement="right" value={session.title}> + <div + class="w-full mb-1.5 px-3 py-1 rounded-md group-data-[active=true]/session:bg-surface-raised-base-hover group-hover/session:bg-surface-raised-base-hover group-focus/session:bg-surface-raised-base-hover" - > - <div class="flex items-center self-stretch gap-6 justify-between"> - <span class="text-14-regular text-text-strong overflow-hidden text-ellipsis truncate"> - {session.title} - </span> - <span class="text-12-regular text-text-weak text-right whitespace-nowrap"> - {Math.abs(updated().diffNow().as("seconds")) < 60 - ? "Now" - : updated() - .toRelative({ style: "short", unit: ["days", "hours", "minutes"] }) - ?.replace(" ago", "") - ?.replace(/ days?/, "d") - ?.replace(" min.", "m") - ?.replace(" hr.", "h")} - </span> - </div> - <div class="flex justify-between items-center self-stretch"> - <span class="text-12-regular text-text-weak">{`${session.summary?.files || "No"} file${session.summary?.files !== 1 ? "s" : ""} changed`}</span> - <Show when={session.summary}>{(summary) => <DiffChanges changes={summary()} />}</Show> - </div> - </div> - </Tooltip> - </A> - ) - }} - </VList> + > + <div class="flex items-center self-stretch gap-6 justify-between"> + <span class="text-14-regular text-text-strong overflow-hidden text-ellipsis truncate"> + {session.title} + </span> + <span class="text-12-regular text-text-weak text-right whitespace-nowrap"> + {Math.abs(updated().diffNow().as("seconds")) < 60 + ? "Now" + : updated() + .toRelative({ style: "short", unit: ["days", "hours", "minutes"] }) + ?.replace(" ago", "") + ?.replace(/ days?/, "d") + ?.replace(" min.", "m") + ?.replace(" hr.", "h")} + </span> + </div> + <div class="flex justify-between items-center self-stretch"> + <span class="text-12-regular text-text-weak">{`${session.summary?.files || "No"} file${session.summary?.files !== 1 ? "s" : ""} changed`}</span> + <Show when={session.summary}>{(summary) => <DiffChanges changes={summary()} />}</Show> + </div> + </div> + </Tooltip> + </A> + ) + }} + </For> + </nav> + <Show when={sync.data.more}> + <button + class="shrink-0 self-start p-3 text-12-medium text-text-weak hover:text-text-strong" + onClick={() => sync.session.fetch()} + > + Show more + </button> + </Show> + </div> </div> </div> <main class="size-full overflow-x-hidden">{props.children}</main> |
