3.0 KB108 lines
Blame
1interface SkeletonProps {
2 className?: string;
3 width?: string;
4 height?: string;
5}
6
7export function Skeleton({ className = "", width, height = "0.875rem" }: SkeletonProps) {
8 return (
9 <div
10 className={`skeleton ${className}`}
11 style={{
12 width: width ?? "100%",
13 height,
14 minHeight: height,
15 }}
16 />
17 );
18}
19
20const FILE_WIDTHS = [120, 90, 140, 80, 110];
21
22/** A row skeleton that mimics a file tree row. */
23export function FileRowSkeleton({ index = 0 }: { index?: number }) {
24 return (
25 <div className="flex items-center gap-2 py-1.5 px-3">
26 <Skeleton width="16px" height="16px" />
27 <Skeleton width={`${FILE_WIDTHS[index % FILE_WIDTHS.length]}px`} height="0.875rem" />
28 </div>
29 );
30}
31
32/** A full page skeleton for repo/code views. */
33export function RepoSkeleton() {
34 return (
35 <div className="max-w-3xl mx-auto px-4 py-6">
36 <div
37 style={{ border: "1px solid var(--border-subtle)" }}
38 >
39 {Array.from({ length: 6 }).map((_, i) => (
40 <div
41 key={i}
42 style={{
43 borderTop: i > 0 ? "1px solid var(--divide)" : undefined,
44 }}
45 >
46 <FileRowSkeleton index={i} />
47 </div>
48 ))}
49 </div>
50 </div>
51 );
52}
53
54const CODE_WIDTHS = [280, 200, 320, 160, 240, 300, 180, 260, 140, 220, 290, 170];
55
56/** A skeleton for file/blob views (code viewer). */
57export function BlobSkeleton() {
58 return (
59 <div className="px-4 py-6">
60 <div style={{ border: "1px solid var(--border-subtle)" }}>
61 <div
62 className="flex items-center gap-4 px-3 py-2"
63 style={{
64 backgroundColor: "var(--bg-inset)",
65 borderBottom: "1px solid var(--border-subtle)",
66 }}
67 >
68 <Skeleton width="40px" height="0.75rem" />
69 <Skeleton width="55px" height="0.75rem" />
70 </div>
71 <div className="py-1">
72 {Array.from({ length: 12 }).map((_, i) => (
73 <div key={i} className="flex items-center gap-4 px-3 py-0.5">
74 <Skeleton width="20px" height="0.75rem" />
75 <Skeleton width={`${CODE_WIDTHS[i % CODE_WIDTHS.length]}px`} height="0.75rem" />
76 </div>
77 ))}
78 </div>
79 </div>
80 </div>
81 );
82}
83
84const LIST_WIDTHS = [200, 170, 230, 150];
85const LIST_SUB_WIDTHS = [100, 80, 120, 90];
86
87/** A skeleton for list pages (repos, commits, MRs). */
88export function ListSkeleton({ rows = 4 }: { rows?: number }) {
89 return (
90 <div
91 style={{ border: "1px solid var(--border-subtle)" }}
92 >
93 {Array.from({ length: rows }).map((_, i) => (
94 <div
95 key={i}
96 className="py-2.5 px-3"
97 style={{
98 borderTop: i > 0 ? "1px solid var(--divide)" : undefined,
99 }}
100 >
101 <Skeleton width={`${LIST_WIDTHS[i % LIST_WIDTHS.length]}px`} height="0.875rem" className="mb-1.5" />
102 <Skeleton width={`${LIST_SUB_WIDTHS[i % LIST_SUB_WIDTHS.length]}px`} height="0.65rem" />
103 </div>
104 ))}
105 </div>
106 );
107}
108