Migration This is my new public git source viewer. Source coming soon. Please contact with concerns/bugs. Contact me

static/css/base.css

c0427d5fc7c0fcf8606c546071085e8af231fb81 · 11.8 KB · 466 lines raw

1 /* gsg — a quiet, text-first interface in the spirit of cgit: hairlines
2 instead of boxes, no shadows, no hover animation. The one indulgence is
3 a black-and-purple signal color -- used for links, hashes, and a thin
4 two-tone stripe at the very top of the page -- so the theme still reads
5 as its own thing rather than "yet another dark git UI".
6
7 Loaded on every page: design tokens, reset, nav, page chrome, and the
8 handful of components (cards, tables, chips, facts-bar, footer,
9 notices) shared by more than one view. View-specific rules live in the
10 other files under static/css/, linked only by the views that need
11 them. */
12
13 :root {
14 /* Base — near-black ink */
15 --bg: #0F111A;
16 --bg-elev: #141725;
17 --surface: #1C2032;
18 --surface-2: #24283C;
19 --line: #2A3045;
20 --line-soft: #2E354E;
21
22 /* Foreground */
23 --fg: #FFFFFF;
24 --fg-muted: #9AA0B3;
25 --fg-subtle: #6B7280;
26
27 /* Accent — one signal color, not a rainbow */
28 --accent: #A78BFA;
29 --accent-2: #7C3AED;
30 --accent-grad: linear-gradient(90deg, var(--accent), var(--accent-2));
31
32 /* Status colors */
33 --add: #10B981;
34 --add-bg: rgba(16, 185, 129, 0.15);
35 --del: #EF4444;
36 --del-bg: rgba(239, 68, 68, 0.15);
37
38 /* Counterpart to --accent -- tags and other "second kind of thing"
39 markers use this instead of a shade too close to the purple accent. */
40 --tag: #FAA78B;
41
42 /* Syntax highlighting -- deliberately just four colours (keyword,
43 string, number, name) plus a muted comment, not a full-spectrum
44 scheme. Blob view only; see static/css/blob.css. */
45 --syn-kw: #818CF8;
46 --syn-str: #34D399;
47 --syn-num: #FAA78B;
48 --syn-fn: #60A5FA;
49
50 /* Lane colors — spectrum for telling graph lanes apart, independent
51 of the brand accent above */
52 --lane-0: #818CF8;
53 --lane-1: #10B981;
54 --lane-2: #F59E0B;
55 --lane-3: #EC4899;
56 --lane-4: #3B82F6;
57 --lane-5: #84CC16;
58
59 /* Typography */
60 --mono: ui-monospace, "SFMono-Regular", "JetBrains Mono", "Cascadia Mono",
61 Menlo, Consolas, "Liberation Mono", monospace;
62 --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
63
64 /* Spacing & radius */
65 --r: 8px;
66 --r-sm: 4px;
67 --pad: clamp(.85rem, 2.5vw, 1.5rem);
68 }
69
70 @media (prefers-color-scheme: light) {
71 :root {
72 --bg: #F3F4F6;
73 --bg-elev: #FFFFFF;
74 --surface: #FFFFFF;
75 --surface-2: #F9FAFB;
76 --line: #E5E7EB;
77 --line-soft: #E5E7EB;
78 --fg: #111827;
79 --fg-muted: #6B7280;
80 --fg-subtle: #9CA3AF;
81 --accent: #7C3AED;
82 --accent-2: #5B21B6;
83 --add: #059669;
84 --del: #DC2626;
85 --tag: #B45309;
86 --syn-kw: #4F46E5;
87 --syn-str: #047857;
88 --syn-num: #B45309;
89 --syn-fn: #1D4ED8;
90 }
91 }
92
93 /* ---------------------------------------------------------------- reset & base */
94
95 *, *::before, *::after { box-sizing: border-box; }
96
97 html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
98
99 body {
100 margin: 0;
101 background: var(--bg);
102 color: var(--fg);
103 font-family: var(--mono);
104 font-size: 13px;
105 line-height: 1.55;
106 font-variant-ligatures: none;
107 -webkit-font-smoothing: antialiased;
108 }
109
110 /* The one graphic flourish: a thin two-tone stripe, always at the very
111 top of the viewport. Small enough to be quiet, present enough to be a
112 mark -- the rest of the page is just text and hairlines. */
113 body::before {
114 content: "";
115 position: fixed;
116 top: 0; left: 0; right: 0;
117 height: 3px;
118 background: var(--accent-grad);
119 z-index: 200;
120 }
121
122 a { color: var(--accent); text-decoration: none; }
123 a:hover { text-decoration: underline; }
124
125 /* Full viewport width, minus a small gutter -- no centered max-width
126 column. Anything wide (tables, diffs, the graph) scrolls inside its own
127 container instead of forcing the page to scroll horizontally. */
128 .wrap { width: 100%; margin: 0; padding-inline: var(--pad); }
129
130 /* ---------------------------------------------------------------- navigation */
131
132 .nav {
133 position: sticky; top: 3px; z-index: 100;
134 background: var(--bg-elev);
135 border-bottom: 1px solid var(--line);
136 }
137 .nav-inner {
138 display: grid;
139 grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
140 align-items: center;
141 gap: .75rem;
142 height: 3rem;
143 }
144
145 .nav-start {
146 display: flex; align-items: center; gap: .75rem;
147 grid-column: 1;
148 min-width: 0;
149 }
150
151 .nav-end {
152 grid-column: 3;
153 justify-self: end;
154 }
155
156 .brand {
157 display: flex; align-items: center; gap: .5rem;
158 color: var(--fg); font-weight: 700; font-size: .95rem;
159 letter-spacing: -.02em;
160 }
161 .brand .logo {
162 width: 22px; height: 22px;
163 background: var(--accent);
164 border-radius: var(--r-sm);
165 display: grid; place-items: center;
166 color: var(--bg); font-weight: 700; font-size: .78rem;
167 }
168 .brand:hover { color: var(--accent); text-decoration: none; }
169
170 .repo-name {
171 color: var(--fg); font-weight: 600;
172 margin-left: .5rem;
173 }
174 .nav-repo-name { color: var(--line); }
175 .nav-repo-name:hover { color: var(--accent); }
176
177 /* Tabs — plain text, an underline marks the current page */
178 .tabs {
179 display: flex; gap: 1rem;
180 grid-column: 2;
181 justify-self: center;
182 }
183 .tab {
184 padding: .2rem 0;
185 color: var(--fg-muted);
186 font-size: .78rem;
187 border-bottom: 2px solid transparent;
188 }
189 .tab:hover {
190 color: var(--fg);
191 text-decoration: none;
192 }
193 .tab.active {
194 color: var(--fg);
195 border-bottom-color: var(--accent);
196 }
197
198 /* Ref picker — plain, borderless select */
199 .refpicker {
200 position: relative;
201 }
202 .refpicker select {
203 font: inherit; font-size: .78rem;
204 color: var(--fg-muted);
205 background: none;
206 border: 1px solid var(--line);
207 border-radius: var(--r-sm);
208 padding: .25rem 1.75rem .25rem .6rem;
209 cursor: pointer;
210 appearance: none;
211 background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236B7280' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
212 background-repeat: no-repeat;
213 background-position: right .6rem center;
214 background-size: 10px 10px;
215 }
216 .refpicker select:hover { border-color: var(--accent); color: var(--fg); }
217 .refpicker select:focus-visible {
218 outline: 2px solid var(--accent);
219 outline-offset: -2px;
220 }
221
222 /* ---------------------------------------------------------------- page layout */
223
224 main.wrap { padding-top: 1.25rem; padding-bottom: 2rem; }
225
226 /* Hero: a plain text header with a hairline underneath -- no box, no
227 gradient. The page title carries the weight instead of a card. */
228 .hero {
229 margin-bottom: 1.25rem;
230 padding-bottom: .9rem;
231 border-bottom: 1px solid var(--line);
232 }
233
234 .page-title {
235 margin: 0;
236 font-size: 1.3rem;
237 font-weight: 700;
238 letter-spacing: -.02em;
239 line-height: 1.25;
240 }
241 .page-subtitle {
242 margin: .35rem 0 0;
243 color: var(--fg-muted);
244 font-size: .82rem;
245 }
246
247 .breadcrumbs {
248 display: flex; flex-wrap: wrap; gap: .4rem;
249 align-items: baseline;
250 margin-top: 1rem;
251 font-size: .9rem;
252 color: var(--fg-muted);
253 }
254 .breadcrumbs a { color: var(--accent); }
255 .breadcrumbs .here { color: var(--fg); }
256
257 /* ---------------------------------------------------------------- cards & containers */
258
259 /* Reserved for content that genuinely needs a boundary (a diff, a grouped
260 sub-section) -- a thin border, nothing else. Most pages don't use it. */
261 .card {
262 border: 1px solid var(--line);
263 border-radius: var(--r);
264 padding: .7rem .9rem;
265 margin-bottom: .75rem;
266 }
267
268 /* Facts bar — a plain line of label: value pairs, cgit-style, not a grid
269 of stat tiles. */
270 .facts-bar {
271 display: flex;
272 flex-wrap: wrap;
273 column-gap: 1.5rem;
274 row-gap: .3rem;
275 margin-bottom: 1rem;
276 font-size: .82rem;
277 }
278 .fact { display: flex; gap: .4rem; align-items: baseline; }
279 .fact-label {
280 color: var(--fg-subtle);
281 }
282 .fact-label::after { content: ":"; }
283 .fact-value {
284 color: var(--fg);
285 font-weight: 600;
286 }
287
288 /* ---------------------------------------------------------------- tables */
289
290 /* Borderless, hairline-separated rows -- like cgit's listings -- rather
291 than a bordered card. Tables can still be wider than the viewport (long
292 paths, many columns on mobile); scrolling lives on the table itself so
293 the page body never gains a horizontal scrollbar. */
294 .table-wrap { overflow-x: auto; }
295 .table {
296 width: 100%;
297 border-collapse: collapse;
298 }
299 .table th {
300 color: var(--fg-subtle);
301 font-size: .68rem;
302 text-transform: uppercase;
303 letter-spacing: .07em;
304 padding: .4rem .6rem;
305 text-align: left;
306 font-weight: 600;
307 border-bottom: 1px solid var(--line);
308 }
309 .table td {
310 padding: .4rem .6rem;
311 border-bottom: 1px solid var(--line-soft);
312 vertical-align: middle;
313 }
314 .table tr:hover td {
315 background: var(--surface-2);
316 }
317
318 /* ---------------------------------------------------------------- chips & badges */
319
320 .chips {
321 display: flex;
322 flex-wrap: wrap;
323 gap: .4rem;
324 list-style: none;
325 margin: 0;
326 padding: 0;
327 }
328 /* Plain bordered tags, not filled pill badges. */
329 .chip {
330 display: inline-flex;
331 align-items: center;
332 gap: .35rem;
333 font-size: .7rem;
334 padding: .2rem .5rem;
335 border: 1px solid var(--line);
336 border-radius: var(--r-sm);
337 color: var(--fg-muted);
338 background: none;
339 }
340 .chip:hover {
341 border-color: var(--accent);
342 color: var(--fg);
343 text-decoration: none;
344 }
345 .chip-tag:hover {
346 border-color: var(--tag);
347 }
348 .chip-branch { color: var(--accent); border-color: currentColor; }
349 .chip-tag { color: var(--tag); border-color: currentColor; }
350 .chip-ok { color: var(--add); border-color: currentColor; }
351 .chip-bad { color: var(--del); border-color: currentColor; }
352
353 /* ---------------------------------------------------------------- footer */
354
355 footer {
356 margin-top: 1.5rem;
357 padding: 1rem 0;
358 border-top: 1px solid var(--line);
359 display: flex;
360 justify-content: space-between;
361 align-items: center;
362 flex-wrap: wrap;
363 gap: .75rem;
364 font-size: .8rem;
365 }
366 footer .footer-left {
367 display: flex;
368 gap: .75rem;
369 align-items: center;
370 }
371 footer .footer-right {
372 color: var(--fg-subtle);
373 font-size: .75rem;
374 }
375 footer a { color: var(--accent); }
376
377 /* ---------------------------------------------------------------- notices */
378
379 .notice {
380 padding: .5rem .8rem;
381 border-left: 2px solid var(--accent);
382 color: var(--fg-muted);
383 font-size: .8rem;
384 margin: .75rem 0;
385 }
386
387 /* ---------------------------------------------------------------- error page */
388
389 .error-page { padding-top: 3rem; padding-bottom: 3rem; text-align: center; }
390 .error-code {
391 font-size: 3rem;
392 font-weight: 700;
393 color: var(--accent);
394 margin: 0;
395 letter-spacing: -.03em;
396 }
397 .error-page .page-title { margin-top: .25rem; }
398 .error-page .page-subtitle { margin-bottom: 1rem; }
399
400 /* ---------------------------------------------------------------- responsive */
401
402 @media (max-width: 640px) {
403 .nav-inner {
404 display: flex;
405 flex-wrap: wrap;
406 height: auto; padding-block: .5rem;
407 }
408 .nav-start { flex: 1 1 auto; }
409 .nav-end { margin-left: auto; }
410 .tabs {
411 justify-self: auto;
412 width: 100%;
413 order: 3;
414 gap: .75rem;
415 }
416 .facts-bar {
417 flex-direction: column;
418 gap: .25rem;
419 }
420 .hero { padding-bottom: .7rem; }
421 .page-title {
422 font-size: 1.1rem;
423 }
424 }
425
426 @media (prefers-reduced-motion: reduce) {
427 *, *::before, *::after {
428 animation: none !important;
429 transition: none !important;
430 }
431 }
432
433 /* ---------------------------------------------------------------- utilities */
434
435 .hidden { display: none !important; }
436 .muted { color: var(--fg-muted); }
437 .text-accent { color: var(--accent); }
438 .font-mono { font-family: var(--mono); }
439 .w-full { width: 100%; }
440 .text-right { text-align: right !important; }
441 .text-center { text-align: center !important; }
442 .text-sm { font-size: .85rem; }
443 .text-xs { font-size: .75rem; }
444
445 /* Focus states for accessibility */
446 :focus-visible {
447 outline: 2px solid var(--accent);
448 outline-offset: 2px;
449 }
450
451 /* Scrollbar styling */
452 ::-webkit-scrollbar {
453 height: 8px;
454 width: 8px;
455 }
456 ::-webkit-scrollbar-track {
457 background: var(--bg-elev);
458 border-radius: 4px;
459 }
460 ::-webkit-scrollbar-thumb {
461 background: var(--line);
462 border-radius: 4px;
463 }
464 ::-webkit-scrollbar-thumb:hover {
465 background: var(--fg-subtle);
466 }