SPB Git forge

spb/cancerindex

Public
37commits 1branches 0releases
2.9 MBsize
maindefault branch
10 days agolast push
TypeScript 97.2% SQL 1.5% CSS 0.6% JavaScript 0.5%
2.2 KB · 56 lines tsx
Raw Blame History
1/**2 * Loading skeletons for route-level loading.tsx files. Neutral blocks only (no fake numbers, no3 * placeholder text that could be mistaken for data — CLAUDE.md §281). `aria-busy` + a visually4 * hidden status line announce the loading state to assistive technology.5 */6export function Skeleton({ className = '', w, h = 14 }: { className?: string; w?: string | number; h?: number }) {7  return <span aria-hidden className={`ci-skeleton block ${className}`} style={{ width: w ?? '100%', height: h }} />;8}910export function SkeletonText({ lines = 3, className = '' }: { lines?: number; className?: string }) {11  return (12    <div className={`space-y-2 ${className}`} aria-hidden>13      {Array.from({ length: lines }, (_, i) => (14        <Skeleton key={i} w={i === lines - 1 ? '62%' : '100%'} />15      ))}16    </div>17  );18}1920export function SkeletonTable({ rows = 8, cols = 6, className = '' }: { rows?: number; cols?: number; className?: string }) {21  return (22    <div className={`ci-table-wrap ${className}`} aria-hidden>23      <div className="grid gap-x-3 gap-y-0 px-2" style={{ gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))` }}>24        {Array.from({ length: cols }, (_, i) => (25          <Skeleton key={`h${i}`} h={10} className="my-3" w="60%" />26        ))}27        {Array.from({ length: rows * cols }, (_, i) => (28          <Skeleton key={i} h={12} className="my-[9px]" w={`${55 + ((i * 17) % 40)}%`} />29        ))}30      </div>31    </div>32  );33}3435export function PageSkeleton({ title = 'Loading', tabs = 0, table = true }: { title?: string; tabs?: number; table?: boolean }) {36  return (37    <div aria-busy="true" className="pt-6">38      <p className="sr-only" role="status">39        {title}…40      </p>41      <Skeleton h={10} w={120} className="mb-3" />42      <Skeleton h={34} w="55%" className="mb-3" />43      <Skeleton h={12} w="35%" className="mb-6" />44      {tabs > 0 ? (45        <div className="mb-6 flex gap-5 border-b border-rule pb-2" aria-hidden>46          {Array.from({ length: tabs }, (_, i) => (47            <Skeleton key={i} h={12} w={64 + ((i * 23) % 40)} />48          ))}49        </div>50      ) : null}51      <SkeletonText lines={2} className="mb-6 max-w-2xl" />52      {table ? <SkeletonTable /> : null}53    </div>54  );55}56