g1t/apps/web/app/components/workspace-skeletons.tsx
Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Navigation: the workspace's own page with tabs, pins and recent in the sidebar | 1 | /** |
| 2 | * The shapes of a workspace's tabs while they load: the same layout as | |
| 3 | * the real thing, so nothing moves when it arrives (components/ui/skeleton.tsx). | |
| 4 | */ | |
| 5 | import type { WorkspaceTabKey } from "../lib/workspace-nav"; | |
| 6 | import { Skeleton, SkeletonRows, SkeletonText } from "./ui/skeleton"; | |
| 7 | ||
| 8 | /** A project card, as the Overview and the Projects grid show them. */ | |
| 9 | export function ProjectCardSkeleton() { | |
| 10 | return ( | |
| 11 | <li aria-hidden="true" className="flex flex-col rounded-2xl border border-line bg-surface p-5"> | |
| 12 | <div className="flex items-start gap-3"> | |
| 13 | <Skeleton className="size-9 shrink-0 rounded-lg" /> | |
| 14 | <div className="grow space-y-2 pt-1"> | |
| 15 | <Skeleton className="h-3.5 w-32" /> | |
| 16 | <Skeleton className="h-3 w-48" /> | |
| 17 | </div> | |
| 18 | </div> | |
| 19 | <div className="mt-8 flex gap-4 border-t border-line pt-3"> | |
| 20 | <Skeleton className="h-3 w-12" /> | |
| 21 | <Skeleton className="h-3 w-8" /> | |
| 22 | <Skeleton className="h-3 w-8" /> | |
| 23 | </div> | |
| 24 | </li> | |
| 25 | ); | |
| 26 | } | |
| 27 | ||
| 28 | /** The Projects page's rows. */ | |
| 29 | export function ProjectRowsSkeleton({ rows = 8 }: { rows?: number }) { | |
| 30 | return ( | |
| 31 | <div aria-hidden="true" className="overflow-hidden rounded-xl border border-line bg-surface"> | |
| 32 | {Array.from({ length: rows }, (_, index) => ( | |
| 33 | <div key={index} className="flex items-center gap-3 border-b border-line px-4 py-3.5 last:border-b-0"> | |
| 34 | <Skeleton className="size-8 shrink-0 rounded-md" /> | |
| 35 | <div className="grow space-y-2"> | |
| 36 | <Skeleton className="h-3.5" style={{ width: `${30 + ((index * 13) % 25)}%` }} /> | |
| 37 | <Skeleton className="h-3" style={{ width: `${45 + ((index * 7) % 30)}%` }} /> | |
| 38 | </div> | |
| 39 | <Skeleton className="hidden h-3 w-16 sm:block" /> | |
| 40 | <Skeleton className="size-8 shrink-0 rounded-md" /> | |
| 41 | </div> | |
| 42 | ))} | |
| 43 | </div> | |
| 44 | ); | |
| 45 | } | |
| 46 | ||
| 47 | /** The Projects page: its search and filters, then rows. */ | |
| 48 | export function ProjectsSkeleton() { | |
| 49 | return ( | |
| 50 | <div aria-busy="true" aria-label="Loading projects" className="space-y-4"> | |
| 51 | <div className="flex flex-wrap gap-2"> | |
| 52 | <Skeleton className="h-9 w-full rounded-md sm:w-72" /> | |
| 53 | <Skeleton className="h-9 w-28 rounded-md" /> | |
| 54 | <Skeleton className="h-9 w-28 rounded-md" /> | |
| 55 | <Skeleton className="h-9 w-36 rounded-md" /> | |
| 56 | </div> | |
| 57 | <ProjectRowsSkeleton /> | |
| 58 | </div> | |
| 59 | ); | |
| 60 | } | |
| 61 | ||
| 62 | /** The Overview: pinned cards, then recent ones beside the aside. */ | |
| 63 | export function OverviewSkeleton() { | |
| 64 | return ( | |
| 65 | <div aria-busy="true" aria-label="Loading" className="grid gap-10 lg:grid-cols-[1fr_18rem]"> | |
| 66 | <div className="space-y-10"> | |
| 67 | <div> | |
| 68 | <Skeleton className="h-3.5 w-20" /> | |
| 69 | <ul className="mt-3 grid gap-4 sm:grid-cols-2"> | |
| 70 | {Array.from({ length: 4 }, (_, index) => ( | |
| 71 | <ProjectCardSkeleton key={index} /> | |
| 72 | ))} | |
| 73 | </ul> | |
| 74 | </div> | |
| 75 | <div> | |
| 76 | <Skeleton className="h-3.5 w-28" /> | |
| 77 | <SkeletonRows rows={4} className="mt-3 rounded-xl border border-line bg-surface" /> | |
| 78 | </div> | |
| 79 | </div> | |
| 80 | <div className="space-y-4"> | |
| 81 | <Skeleton className="h-40 rounded-xl" /> | |
| 82 | <SkeletonText lines={4} /> | |
| 83 | </div> | |
| 84 | </div> | |
| 85 | ); | |
| 86 | } | |
| 87 | ||
| 88 | /** Whichever tab is on its way. */ | |
| 89 | export function WorkspaceTabSkeleton({ tab }: { tab: WorkspaceTabKey }) { | |
| 90 | if (tab === "overview") return <OverviewSkeleton />; | |
| 91 | if (tab === "projects") return <ProjectsSkeleton />; | |
| 92 | return ( | |
| 93 | <div aria-busy="true" aria-label="Loading" className="space-y-4"> | |
| 94 | <Skeleton className="h-3.5 w-2/3 max-w-xl" /> | |
| 95 | <SkeletonRows rows={6} className="rounded-xl border border-line bg-surface" /> | |
| 96 | </div> | |
| 97 | ); | |
| 98 | } |