diff options
| author | Adam <[email protected]> | 2026-01-15 17:57:56 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2026-01-15 17:59:25 -0600 |
| commit | 49939c4d8d4b7112273ab03779d4ec0c9ad2a175 (patch) | |
| tree | 8c95e9411f12d97e31951641ec7686578de2c333 | |
| parent | 529eb6e1477b985a61d9cdf4c279f81065d31300 (diff) | |
| download | opencode-49939c4d8d4b7112273ab03779d4ec0c9ad2a175.tar.gz opencode-49939c4d8d4b7112273ab03779d4ec0c9ad2a175.zip | |
feat(app): skeleton loader for sessions
| -rw-r--r-- | packages/app/src/pages/layout.tsx | 23 |
1 files changed, 21 insertions, 2 deletions
diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx index bbc9e9aa0..f2a777fd3 100644 --- a/packages/app/src/pages/layout.tsx +++ b/packages/app/src/pages/layout.tsx @@ -885,7 +885,7 @@ export default function Layout(props: ParentProps) { return ( <div data-session-id={props.session.id} - class="group/session relative w-full rounded-md cursor-default transition-colors pl-2 pr-3 + class="group/session relative w-full rounded-md cursor-default transition-colors px-3 hover:bg-surface-raised-base-hover focus-within:bg-surface-raised-base-hover has-[.active]:bg-surface-base-active" > <Tooltip placement={props.mobile ? "bottom" : "right"} value={props.session.title} gutter={16} openDelay={1000}> @@ -902,7 +902,7 @@ export default function Layout(props: ParentProps) { > <Switch> <Match when={isWorking()}> - <Spinner class="size-[15px] opacity-50" /> + <Spinner class="size-[15px]" /> </Match> <Match when={hasPermissions()}> <div class="size-1.5 rounded-full bg-surface-warning-strong" /> @@ -944,6 +944,17 @@ export default function Layout(props: ParentProps) { ) } + const SessionSkeleton = (props: { count?: number }): JSX.Element => { + const items = Array.from({ length: props.count ?? 4 }, (_, index) => index) + return ( + <div class="flex flex-col gap-1"> + <For each={items}> + {() => <div class="h-8 w-full rounded-md bg-surface-raised-base opacity-60 animate-pulse" />} + </For> + </div> + ) + } + const SortableProject = (props: { project: LocalProject; mobile?: boolean }): JSX.Element => { const sortable = createSortable(props.project.worktree) const selected = createMemo(() => { @@ -1105,6 +1116,7 @@ export default function Layout(props: ParentProps) { return `${kind} : ${name}` }) const open = createMemo(() => store.workspaceExpanded[props.directory] ?? true) + const loading = createMemo(() => open() && workspaceStore.status !== "complete" && sessions().length === 0) const hasMore = createMemo(() => local() && workspaceStore.sessionTotal > workspaceStore.session.length) const loadMore = async () => { if (!local()) return @@ -1166,6 +1178,9 @@ export default function Layout(props: ParentProps) { > New session </Button> + <Show when={loading()}> + <SessionSkeleton /> + </Show> <For each={sessions()}> {(session) => <SessionItem session={session} slug={slug()} mobile={props.mobile} />} </For> @@ -1200,6 +1215,7 @@ export default function Layout(props: ParentProps) { .filter((session) => !session.parentID) .toSorted(sortSessions), ) + const loading = createMemo(() => workspaceStore.status !== "complete" && sessions().length === 0) const hasMore = createMemo(() => workspaceStore.sessionTotal > workspaceStore.session.length) const loadMore = async () => { setWorkspaceStore("limit", (limit) => limit + 5) @@ -1214,6 +1230,9 @@ export default function Layout(props: ParentProps) { class="size-full flex flex-col py-2 overflow-y-auto no-scrollbar" > <nav class="flex flex-col gap-1 px-2"> + <Show when={loading()}> + <SessionSkeleton /> + </Show> <For each={sessions()}> {(session) => <SessionItem session={session} slug={slug()} mobile={props.mobile} />} </For> |
