spb/cancerindex
Public
TypeScript 97.2%
SQL 1.5%
CSS 0.6%
JavaScript 0.5%
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