fix: show deck skeletons while loading connections

This commit is contained in:
2026-09-28 20:59:53 +09:00
parent 7a7bc983e6
commit f1914a5d0a
3 changed files with 54 additions and 13 deletions
+7
View File
@@ -1,6 +1,7 @@
import { Icon } from "#/components/icon";
import { Badge } from "#/components/ui/badge";
import { Button } from "#/components/ui/button";
import { Skeleton } from "#/components/ui/skeleton";
import {
DropdownMenu,
DropdownMenuContent,
@@ -22,6 +23,7 @@ import { describeSource } from "./source-description";
export function ResearchColumn({
column,
connectionLabel,
connectionLoading = false,
onEdit,
onRemove,
onMove,
@@ -32,6 +34,7 @@ export function ResearchColumn({
}: {
column: DeckColumn;
connectionLabel?: string;
connectionLoading?: boolean;
onEdit: () => void;
onRemove: () => void;
onMove: (direction: -1 | 1) => void;
@@ -112,9 +115,13 @@ export function ResearchColumn({
</DropdownMenu>
</div>
<div className="deck-column-label">
{connectionLoading ? (
<Skeleton className="h-3 w-24 shrink-0" aria-hidden="true" />
) : (
<span title={`Connection profile: ${connectionLabel ?? "Connection not found"}`}>
{connectionLabel ?? "Connection not found"}
</span>
)}
<Badge variant="outline" className="deck-source-label">
<Icon name={column.source.kind} />
{sourceDescription.label}
+13 -6
View File
@@ -15,6 +15,7 @@ import {
EmptyTitle,
} from "#/components/ui/empty";
import { Input } from "#/components/ui/input";
import { Skeleton } from "#/components/ui/skeleton";
import { loadConnections } from "#/features/connections/server-functions";
import { syncResearchDeck } from "#/features/research/research-deck-sync";
import { ResearchPanel } from "#/features/research/research-panel";
@@ -27,6 +28,7 @@ import { type ColumnRegistry, useColumnTools } from "./column-tools";
import { ResearchColumn } from "./deck-column";
import { DeckSwitcher } from "./deck-switcher";
import { type DeckColumn, MAX_COLUMNS, moveColumn } from "./model";
import { ResearchDeckSkeleton } from "./research-deck-skeleton";
import { useDeck } from "./use-deck";
import { useDeckTools } from "./webmcp-tools";
@@ -202,10 +204,19 @@ export function DeckPage() {
>
<div className="deck-heading">
<div>
{ready ? (
<>
<h1>{deck.title}</h1>
<span className="deck-count">
{deck.columns.length} / {MAX_COLUMNS} columns
</span>
</>
) : (
<div className="space-y-2" aria-hidden="true">
<Skeleton className="h-5 w-40" />
<Skeleton className="h-3 w-20" />
</div>
)}
</div>
<div className="deck-actions">
{deck.persisted ? (
@@ -260,11 +271,6 @@ export function DeckPage() {
</Button>
</p>
) : null}
{!ready ? (
<p className="deck-save-status" role="status">
Loading decks…
</p>
) : null}
{profiles.isError ? (
<p role="alert" className="deck-error">
Unable to load connection profiles.
@@ -288,7 +294,6 @@ export function DeckPage() {
{profiles.data.relayError}
</p>
) : null}
{profiles.isPending ? <p role="status">Loading connection profiles…</p> : null}
{!renaming && editing === null && !switcherEditing ? storageErrorNotice : null}
{renaming ? (
<Dialog title="Rename deck" onClose={() => setRenaming(false)}>
@@ -355,6 +360,7 @@ export function DeckPage() {
</Button>
</div>
) : null}
{!ready && !storageError ? <ResearchDeckSkeleton /> : null}
{ready && deck.columns.length === 0 && editing === null ? (
<Empty>
<EmptyHeader>
@@ -388,6 +394,7 @@ export function DeckPage() {
key={`${deck.id}:${column.id}`}
registry={registry}
column={column}
connectionLoading={profiles.isPending}
citation={
citationNavigation.target?.deckId === deck.id &&
citationNavigation.target.column.id === column.id &&
@@ -0,0 +1,27 @@
import { Skeleton } from "#/components/ui/skeleton";
import { ResearchPostSkeleton } from "./research-post-skeleton";
export function ResearchDeckSkeleton() {
return (
<div className="deck-board" role="status" aria-label="Loading research">
{["first", "second", "third"].map((column) => (
<div key={column} className="deck-column" aria-hidden="true">
<div className="deck-column-header space-y-3">
<div className="flex items-center gap-2">
<Skeleton className="size-4 shrink-0" />
<Skeleton className="h-4 w-32" />
</div>
<Skeleton className="h-3 w-24" />
<Skeleton className="h-3 w-40" />
<Skeleton className="h-3 w-20" />
</div>
<div className="deck-column-results">
<ResearchPostSkeleton />
<ResearchPostSkeleton />
<ResearchPostSkeleton />
</div>
</div>
))}
</div>
);
}