/** * Loading states specific to the pull request surface — the first list, a search under way, * and a detail panel opening — use bars in the geometry of the content they stand for, pulsing * on one composited layer. Diff loading uses the shared diff-panel skeleton instead. * * Deliberately not the app's shimmer skeleton. The sweep is a `transform` animation per bar — * compositor-safe, but a layer for every bar on screen — and its white highlight over the * near-white `muted` base all but disappears in light mode. Here one `animate-ghost-pulse` on the * container is a single opacity animation however many bars sit under it, and the bars take * their tone from `muted-foreground` at low alpha, which reads on both themes. */ import { cn } from "~/lib/utils"; function GhostBar({ className }: { className?: string | undefined }) { return
; } /** Widths cycle rather than randomize, so the ghost renders the same on every pass. */ const TITLE_WIDTHS = ["w-3/5", "w-2/5", "w-1/2", "w-2/3", "w-2/5", "w-3/5", "w-1/2"]; const META_WIDTHS = ["w-2/5", "w-1/3", "w-2/5", "w-1/4", "w-1/3", "w-2/5", "w-1/3"]; /** Rows in the list's own grid — glyph, title over meta, time over diffstat. */ export function PullRequestListGhost({ rows = 7, caption, }: { rows?: number; /** Said where the group headers speak, for the states with something to say — a search. */ caption?: string; }) { return ({caption}
) : null} {Array.from({ length: rows }, (_, index) => (