detached 187bf45

refactor(styles): consolidate CSS files and clean up config UI

- Unified design-tokens.css, tailwind.css, lib/styles.css into single styles/app.css
- Removed unused --dynamic-* CSS variable indirection
- Removed obsolete toast/omnibox/findbar GTK4 migration styles
- Fixed ConfigPage.svelte: removed duplicate UI Scale from Search tab
- Removed redundant dumb://config heading for clarity
- Merged Shortcuts section into Search tab for better organization
commit
187bf4544255ed581f5651d0328cc3bfec99f1c9
author
bnema · · 2025-12-21 22:11 UTC
parent
cd2db31
signature
unsigned
6 files · +133 -468
D webui/src/lib/styles.css +0 -1
@@ -1,1 +0,0 @@
1-@import "../styles/tailwind.css";
@@ -1,1 +0,0 @@
1-@import "../styles/tailwind.css";
M webui/src/pages/ConfigPage.svelte +11 -23
@@ -244,16 +244,12 @@
244244 {:else if config}
245245 <Tabs.Root bind:value={activeTab} class="w-full">
246246 <div class="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
247- <div class="space-y-2">
248- <div class="text-xs font-semibold uppercase tracking-[0.3em] text-muted-foreground">
249- Config Workspace
250- </div>
251- <div class="text-2xl font-semibold text-foreground">dumb://config</div>
247+ <div class="text-xs font-semibold uppercase tracking-[0.3em] text-muted-foreground">
248+ Config Workspace
252249 </div>
253250 <Tabs.List class="bg-muted/60">
254251 <Tabs.Trigger value="appearance">Appearance</Tabs.Trigger>
255252 <Tabs.Trigger value="search">Search</Tabs.Trigger>
256- <Tabs.Trigger value="shortcuts">Shortcuts</Tabs.Trigger>
257253 </Tabs.List>
258254 </div>
259255
@@ -366,29 +362,21 @@
366362 <Card.Root class="rounded-none border-0 bg-transparent py-0 shadow-none">
367363 <Card.Header>
368364 <Card.Title>Search</Card.Title>
369- <Card.Description>Default engine and UI scaling.</Card.Description>
365+ <Card.Description>Default engine and shortcuts.</Card.Description>
370366 </Card.Header>
371- <Card.Content class="grid gap-6 md:grid-cols-2">
367+ <Card.Content class="space-y-8">
372368 <div class="space-y-2">
373369 <Label for="search_engine">Default Search Engine (use %s for query)</Label>
374370 <Input id="search_engine" bind:value={config.default_search_engine} />
375371 </div>
376- <div class="space-y-2">
377- <Label for="ui_scale_search">UI Scale</Label>
378- <Input id="ui_scale_search" type="number" step="0.1" bind:value={config.default_ui_scale} />
379- </div>
380- </Card.Content>
381- </Card.Root>
382- </Tabs.Content>
383372
384- <Tabs.Content value="shortcuts">
385- <Card.Root class="rounded-none border-0 bg-transparent py-0 shadow-none">
386- <Card.Header>
387- <Card.Title>Search Shortcuts</Card.Title>
388- <Card.Description>Map prefixes like g to URL templates.</Card.Description>
389- </Card.Header>
390- <Card.Content>
391- <ShortcutsTable shortcuts={config.search_shortcuts} onUpdate={updateShortcuts} />
373+ <div class="space-y-3">
374+ <div class="text-sm font-semibold uppercase tracking-[0.2em] text-muted-foreground">
375+ Search Shortcuts
376+ </div>
377+ <p class="text-sm text-muted-foreground">Map prefixes like g to URL templates.</p>
378+ <ShortcutsTable shortcuts={config.search_shortcuts} onUpdate={updateShortcuts} />
379+ </div>
392380 </Card.Content>
393381 </Card.Root>
394382 </Tabs.Content>
@@ -244,16 +244,12 @@
244 {:else if config}244 {:else if config}
245 <Tabs.Root bind:value={activeTab} class="w-full">245 <Tabs.Root bind:value={activeTab} class="w-full">
246 <div class="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">246 <div class="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
247- <div class="space-y-2">247+ <div class="text-xs font-semibold uppercase tracking-[0.3em] text-muted-foreground">
248- <div class="text-xs font-semibold uppercase tracking-[0.3em] text-muted-foreground">248+ Config Workspace
249- Config Workspace
250- </div>
251- <div class="text-2xl font-semibold text-foreground">dumb://config</div>
252 </div>249 </div>
253 <Tabs.List class="bg-muted/60">250 <Tabs.List class="bg-muted/60">
254 <Tabs.Trigger value="appearance">Appearance</Tabs.Trigger>251 <Tabs.Trigger value="appearance">Appearance</Tabs.Trigger>
255 <Tabs.Trigger value="search">Search</Tabs.Trigger>252 <Tabs.Trigger value="search">Search</Tabs.Trigger>
256- <Tabs.Trigger value="shortcuts">Shortcuts</Tabs.Trigger>
257 </Tabs.List>253 </Tabs.List>
258 </div>254 </div>
259 255
@@ -366,29 +362,21 @@
366 <Card.Root class="rounded-none border-0 bg-transparent py-0 shadow-none">362 <Card.Root class="rounded-none border-0 bg-transparent py-0 shadow-none">
367 <Card.Header>363 <Card.Header>
368 <Card.Title>Search</Card.Title>364 <Card.Title>Search</Card.Title>
369- <Card.Description>Default engine and UI scaling.</Card.Description>365+ <Card.Description>Default engine and shortcuts.</Card.Description>
370 </Card.Header>366 </Card.Header>
371- <Card.Content class="grid gap-6 md:grid-cols-2">367+ <Card.Content class="space-y-8">
372 <div class="space-y-2">368 <div class="space-y-2">
373 <Label for="search_engine">Default Search Engine (use %s for query)</Label>369 <Label for="search_engine">Default Search Engine (use %s for query)</Label>
374 <Input id="search_engine" bind:value={config.default_search_engine} />370 <Input id="search_engine" bind:value={config.default_search_engine} />
375 </div>371 </div>
376- <div class="space-y-2">
377- <Label for="ui_scale_search">UI Scale</Label>
378- <Input id="ui_scale_search" type="number" step="0.1" bind:value={config.default_ui_scale} />
379- </div>
380- </Card.Content>
381- </Card.Root>
382- </Tabs.Content>
383 372
384- <Tabs.Content value="shortcuts">373+ <div class="space-y-3">
385- <Card.Root class="rounded-none border-0 bg-transparent py-0 shadow-none">374+ <div class="text-sm font-semibold uppercase tracking-[0.2em] text-muted-foreground">
386- <Card.Header>375+ Search Shortcuts
387- <Card.Title>Search Shortcuts</Card.Title>376+ </div>
388- <Card.Description>Map prefixes like g to URL templates.</Card.Description>377+ <p class="text-sm text-muted-foreground">Map prefixes like g to URL templates.</p>
389- </Card.Header>378+ <ShortcutsTable shortcuts={config.search_shortcuts} onUpdate={updateShortcuts} />
390- <Card.Content>379+ </div>
391- <ShortcutsTable shortcuts={config.search_shortcuts} onUpdate={updateShortcuts} />
392 </Card.Content>380 </Card.Content>
393 </Card.Root>381 </Card.Root>
394 </Tabs.Content>382 </Tabs.Content>
M webui/src/pages/config.ts +1 -1
@@ -1,6 +1,6 @@
11 import { mount } from "svelte";
22 import ConfigPage from "./ConfigPage.svelte";
3-import "../lib/styles.css";
3+import "../styles/app.css";
44
55 // Mount the config page
66 const app = mount(ConfigPage, {
@@ -1,6 +1,6 @@
1 import { mount } from "svelte";1 import { mount } from "svelte";
2 import ConfigPage from "./ConfigPage.svelte";2 import ConfigPage from "./ConfigPage.svelte";
3-import "../lib/styles.css";3+import "../styles/app.css";
4 4
5 // Mount the config page5 // Mount the config page
6 const app = mount(ConfigPage, {6 const app = mount(ConfigPage, {
M webui/src/styles/app.css +121 -2
@@ -9,12 +9,18 @@
99 * - Sharp corners (--radius: 0)
1010 * - High contrast
1111 * - Vibrant green primary accent
12+ *
13+ * Theme Flow:
14+ * 1. TOML config defines appearance.light_palette / dark_palette
15+ * 2. Go ThemeManager converts to CSS variables via palette.ToWebCSSVars()
16+ * 3. ContentInjector injects <style data-dumber-theme-vars> into webviews
17+ * 4. These CSS values below serve as fallbacks when running outside the browser
1218 */
1319
1420 @custom-variant dark (&:is(.dark *));
1521
1622 /* ═══════════════════════════════════════════════════════════════
17- * LIGHT THEME
23+ * LIGHT THEME (fallback values - Go backend overrides at runtime)
1824 * ═══════════════════════════════════════════════════════════════ */
1925 :root {
2026 --radius: 0;
@@ -83,7 +89,7 @@
8389 }
8490
8591 /* ═══════════════════════════════════════════════════════════════
86- * DARK THEME
92+ * DARK THEME (fallback values - Go backend overrides at runtime)
8793 * ═══════════════════════════════════════════════════════════════ */
8894 .dark {
8995 /* Core surfaces - true black for maximum contrast */
@@ -209,5 +215,118 @@
209215 }
210216 body {
211217 @apply bg-background text-foreground;
218+ transition:
219+ background-color 200ms ease,
220+ color 200ms ease;
221+ }
222+}
223+
224+/* ═══════════════════════════════════════════════════════════════
225+ * BROWSER UI BASE
226+ * ═══════════════════════════════════════════════════════════════ */
227+
228+.browser-ui {
229+ background-color: var(--background);
230+ color: var(--foreground);
231+ border-color: var(--border);
232+ transition: colors 250ms;
233+}
234+
235+/* ═══════════════════════════════════════════════════════════════
236+ * ANIMATIONS
237+ * ═══════════════════════════════════════════════════════════════ */
238+
239+.slide-in-top {
240+ animation: slide-in-top 0.25s ease-out;
241+}
242+
243+.slide-out-top {
244+ animation: slide-out-top 0.25s ease-in;
245+}
246+
247+.fade-in {
248+ animation: fade-in 0.15s ease-out;
249+}
250+
251+.fade-out {
252+ animation: fade-out 0.15s ease-in;
253+}
254+
255+@keyframes slide-in-top {
256+ from {
257+ transform: translateY(-100%);
258+ opacity: 0;
259+ }
260+ to {
261+ transform: translateY(0);
262+ opacity: 1;
263+ }
264+}
265+
266+@keyframes slide-out-top {
267+ from {
268+ transform: translateY(0);
269+ opacity: 1;
270+ }
271+ to {
272+ transform: translateY(-100%);
273+ opacity: 0;
274+ }
275+}
276+
277+@keyframes fade-in {
278+ from {
279+ opacity: 0;
280+ }
281+ to {
282+ opacity: 1;
283+ }
284+}
285+
286+@keyframes fade-out {
287+ from {
288+ opacity: 1;
289+ }
290+ to {
291+ opacity: 0;
292+ }
293+}
294+
295+/* ═══════════════════════════════════════════════════════════════
296+ * FIND HIGHLIGHTING
297+ * Styles for in-page search highlights
298+ * ═══════════════════════════════════════════════════════════════ */
299+
300+.find-highlight {
301+ background-color: rgb(255 235 59); /* yellow-400 */
302+ color: rgb(0 0 0); /* black */
303+ padding: 0 0.125rem; /* px-0.5 */
304+ border-radius: 0.125rem; /* rounded-sm */
305+ box-shadow: 0 0 0 1px rgb(200 185 0) inset;
306+}
307+
308+.find-active {
309+ background-color: rgb(255 152 0) !important; /* orange-500 */
310+ color: rgb(0 0 0); /* black */
311+ box-shadow: 0 0 0 1px rgb(179 107 0) inset !important;
312+}
313+
314+/* ═══════════════════════════════════════════════════════════════
315+ * COMPONENT ISOLATION
316+ * For injecting browser UI into external pages
317+ * ═══════════════════════════════════════════════════════════════ */
318+
319+.browser-component-root {
320+ /* Reset any inherited styles from the website */
321+ all: initial;
322+ /* Apply our design system */
323+ font-family:
324+ Fira Sans,
325+ system-ui,
326+ -apple-system,
327+ sans-serif;
328+ box-sizing: border-box;
329+ * {
330+ box-sizing: border-box;
212331 }
213332 }
@@ -9,12 +9,18 @@
9 * - Sharp corners (--radius: 0)9 * - Sharp corners (--radius: 0)
10 * - High contrast10 * - High contrast
11 * - Vibrant green primary accent11 * - Vibrant green primary accent
12+ *
13+ * Theme Flow:
14+ * 1. TOML config defines appearance.light_palette / dark_palette
15+ * 2. Go ThemeManager converts to CSS variables via palette.ToWebCSSVars()
16+ * 3. ContentInjector injects <style data-dumber-theme-vars> into webviews
17+ * 4. These CSS values below serve as fallbacks when running outside the browser
12 */18 */
13 19
14 @custom-variant dark (&:is(.dark *));20 @custom-variant dark (&:is(.dark *));
15 21
16 /* ═══════════════════════════════════════════════════════════════22 /* ═══════════════════════════════════════════════════════════════
17- * LIGHT THEME23+ * LIGHT THEME (fallback values - Go backend overrides at runtime)
18 * ═══════════════════════════════════════════════════════════════ */24 * ═══════════════════════════════════════════════════════════════ */
19 :root {25 :root {
20 --radius: 0;26 --radius: 0;
@@ -83,7 +89,7 @@
83 }89 }
84 90
85 /* ═══════════════════════════════════════════════════════════════91 /* ═══════════════════════════════════════════════════════════════
86- * DARK THEME92+ * DARK THEME (fallback values - Go backend overrides at runtime)
87 * ═══════════════════════════════════════════════════════════════ */93 * ═══════════════════════════════════════════════════════════════ */
88 .dark {94 .dark {
89 /* Core surfaces - true black for maximum contrast */95 /* Core surfaces - true black for maximum contrast */
@@ -209,5 +215,118 @@
209 }215 }
210 body {216 body {
211 @apply bg-background text-foreground;217 @apply bg-background text-foreground;
218+ transition:
219+ background-color 200ms ease,
220+ color 200ms ease;
221+ }
222+}
223+
224+/* ═══════════════════════════════════════════════════════════════
225+ * BROWSER UI BASE
226+ * ═══════════════════════════════════════════════════════════════ */
227+
228+.browser-ui {
229+ background-color: var(--background);
230+ color: var(--foreground);
231+ border-color: var(--border);
232+ transition: colors 250ms;
233+}
234+
235+/* ═══════════════════════════════════════════════════════════════
236+ * ANIMATIONS
237+ * ═══════════════════════════════════════════════════════════════ */
238+
239+.slide-in-top {
240+ animation: slide-in-top 0.25s ease-out;
241+}
242+
243+.slide-out-top {
244+ animation: slide-out-top 0.25s ease-in;
245+}
246+
247+.fade-in {
248+ animation: fade-in 0.15s ease-out;
249+}
250+
251+.fade-out {
252+ animation: fade-out 0.15s ease-in;
253+}
254+
255+@keyframes slide-in-top {
256+ from {
257+ transform: translateY(-100%);
258+ opacity: 0;
259+ }
260+ to {
261+ transform: translateY(0);
262+ opacity: 1;
263+ }
264+}
265+
266+@keyframes slide-out-top {
267+ from {
268+ transform: translateY(0);
269+ opacity: 1;
270+ }
271+ to {
272+ transform: translateY(-100%);
273+ opacity: 0;
274+ }
275+}
276+
277+@keyframes fade-in {
278+ from {
279+ opacity: 0;
280+ }
281+ to {
282+ opacity: 1;
283+ }
284+}
285+
286+@keyframes fade-out {
287+ from {
288+ opacity: 1;
289+ }
290+ to {
291+ opacity: 0;
292+ }
293+}
294+
295+/* ═══════════════════════════════════════════════════════════════
296+ * FIND HIGHLIGHTING
297+ * Styles for in-page search highlights
298+ * ═══════════════════════════════════════════════════════════════ */
299+
300+.find-highlight {
301+ background-color: rgb(255 235 59); /* yellow-400 */
302+ color: rgb(0 0 0); /* black */
303+ padding: 0 0.125rem; /* px-0.5 */
304+ border-radius: 0.125rem; /* rounded-sm */
305+ box-shadow: 0 0 0 1px rgb(200 185 0) inset;
306+}
307+
308+.find-active {
309+ background-color: rgb(255 152 0) !important; /* orange-500 */
310+ color: rgb(0 0 0); /* black */
311+ box-shadow: 0 0 0 1px rgb(179 107 0) inset !important;
312+}
313+
314+/* ═══════════════════════════════════════════════════════════════
315+ * COMPONENT ISOLATION
316+ * For injecting browser UI into external pages
317+ * ═══════════════════════════════════════════════════════════════ */
318+
319+.browser-component-root {
320+ /* Reset any inherited styles from the website */
321+ all: initial;
322+ /* Apply our design system */
323+ font-family:
324+ Fira Sans,
325+ system-ui,
326+ -apple-system,
327+ sans-serif;
328+ box-sizing: border-box;
329+ * {
330+ box-sizing: border-box;
212 }331 }
213 }332 }
D webui/src/styles/design-tokens.css +0 -192
@@ -1,192 +0,0 @@
1-/*
2- * Design Tokens - shadcn-svelte inspired
3- *
4- * Uses OKLCH color space for perceptually uniform colors.
5- * These tokens define the visual language of the browser UI.
6- *
7- * Aesthetic: Industrial Terminal / Brutalist Minimal
8- * - Sharp corners (--radius: 0)
9- * - High contrast
10- * - Vibrant green primary accent
11- * - Cyan secondary accent
12- */
13-
14-:root {
15- /* Radius - sharp terminal aesthetic */
16- --radius: 0;
17- --radius-sm: 0;
18- --radius-md: 0;
19- --radius-lg: 0;
20- --radius-xl: 0;
21-
22- /* ═══════════════════════════════════════════════════════════════
23- * LIGHT THEME
24- * ═══════════════════════════════════════════════════════════════ */
25-
26- /* Core surfaces */
27- --background: oklch(0.985 0.002 260);
28- --foreground: oklch(0.145 0.02 260);
29-
30- /* Card/Panel surfaces */
31- --card: oklch(0.965 0.004 260);
32- --card-foreground: oklch(0.145 0.02 260);
33-
34- /* Popover/Dropdown */
35- --popover: oklch(0.985 0.002 260);
36- --popover-foreground: oklch(0.145 0.02 260);
37-
38- /* Primary - Vibrant Green */
39- --primary: oklch(0.55 0.20 145);
40- --primary-foreground: oklch(0.985 0 0);
41-
42- /* Secondary - Muted surfaces */
43- --secondary: oklch(0.94 0.008 260);
44- --secondary-foreground: oklch(0.20 0.02 260);
45-
46- /* Muted - Subdued content */
47- --muted: oklch(0.94 0.008 260);
48- --muted-foreground: oklch(0.48 0.02 260);
49-
50- /* Accent - Cyan for info/highlights */
51- --accent: oklch(0.58 0.14 200);
52- --accent-foreground: oklch(0.145 0.02 260);
53-
54- /* Destructive - Red for danger */
55- --destructive: oklch(0.55 0.22 25);
56- --destructive-foreground: oklch(0.985 0 0);
57-
58- /* Borders & Inputs */
59- --border: oklch(0.88 0.008 260);
60- --input: oklch(0.88 0.008 260);
61- --ring: var(--primary);
62-
63- /* Semantic colors - for status indicators */
64- --success: oklch(0.65 0.20 145);
65- --success-foreground: oklch(0.985 0 0);
66- --warning: oklch(0.75 0.18 85);
67- --warning-foreground: oklch(0.145 0.02 260);
68- --info: oklch(0.65 0.15 230);
69- --info-foreground: oklch(0.985 0 0);
70-
71- /* Chart colors for analytics */
72- --chart-1: oklch(0.58 0.18 145); /* Green */
73- --chart-2: oklch(0.56 0.14 200); /* Cyan */
74- --chart-3: oklch(0.66 0.15 70); /* Amber */
75- --chart-4: oklch(0.58 0.18 300); /* Purple */
76- --chart-5: oklch(0.60 0.18 25); /* Red-orange */
77-
78- /* Sidebar (if used) */
79- --sidebar: oklch(0.975 0.002 260);
80- --sidebar-foreground: oklch(0.145 0.02 260);
81- --sidebar-primary: oklch(0.55 0.20 145);
82- --sidebar-primary-foreground: oklch(0.985 0 0);
83- --sidebar-accent: oklch(0.94 0.008 260);
84- --sidebar-accent-foreground: oklch(0.20 0.02 260);
85- --sidebar-border: oklch(0.88 0.008 260);
86- --sidebar-ring: oklch(0.55 0.20 145);
87-}
88-
89-.dark {
90- /* ═══════════════════════════════════════════════════════════════
91- * DARK THEME - High Contrast
92- * ═══════════════════════════════════════════════════════════════ */
93-
94- /* Core surfaces - true black for maximum contrast */
95- --background: oklch(0.09 0.005 260);
96- --foreground: oklch(0.97 0 0);
97-
98- /* Card/Panel surfaces - slightly elevated */
99- --card: oklch(0.14 0.008 260);
100- --card-foreground: oklch(0.97 0 0);
101-
102- /* Popover/Dropdown */
103- --popover: oklch(0.16 0.008 260);
104- --popover-foreground: oklch(0.97 0 0);
105-
106- /* Primary - Bright Green */
107- --primary: oklch(0.75 0.19 145);
108- --primary-foreground: oklch(0.12 0.02 145);
109-
110- /* Secondary - Elevated surfaces */
111- --secondary: oklch(0.20 0.008 260);
112- --secondary-foreground: oklch(0.97 0 0);
113-
114- /* Muted - More visible subdued content */
115- --muted: oklch(0.22 0.008 260);
116- --muted-foreground: oklch(0.70 0.01 260);
117-
118- /* Accent - Cyan for info/highlights */
119- --accent: oklch(0.68 0.14 200);
120- --accent-foreground: oklch(0.97 0 0);
121-
122- /* Destructive - Red for danger */
123- --destructive: oklch(0.65 0.20 25);
124- --destructive-foreground: oklch(0.97 0 0);
125-
126- /* Borders & Inputs - more visible */
127- --border: oklch(0.35 0.01 260);
128- --input: oklch(0.35 0.01 260);
129- --ring: var(--primary);
130-
131- /* Semantic colors - brighter for dark bg */
132- --success: oklch(0.72 0.18 145);
133- --success-foreground: oklch(0.12 0.02 145);
134- --warning: oklch(0.80 0.16 85);
135- --warning-foreground: oklch(0.12 0.02 85);
136- --info: oklch(0.70 0.14 230);
137- --info-foreground: oklch(0.12 0.02 230);
138-
139- /* Chart colors for analytics - brighter for dark bg */
140- --chart-1: oklch(0.72 0.18 145); /* Green */
141- --chart-2: oklch(0.68 0.14 200); /* Cyan */
142- --chart-3: oklch(0.76 0.16 70); /* Amber */
143- --chart-4: oklch(0.66 0.18 300); /* Purple */
144- --chart-5: oklch(0.68 0.18 25); /* Red-orange */
145-
146- /* Sidebar (if used) */
147- --sidebar: oklch(0.12 0.008 260);
148- --sidebar-foreground: oklch(0.97 0 0);
149- --sidebar-primary: oklch(0.75 0.19 145);
150- --sidebar-primary-foreground: oklch(0.12 0.02 145);
151- --sidebar-accent: oklch(0.20 0.008 260);
152- --sidebar-accent-foreground: oklch(0.97 0 0);
153- --sidebar-border: oklch(0.35 0.01 260);
154- --sidebar-ring: oklch(0.75 0.19 145);
155-}
156-
157-/* ═══════════════════════════════════════════════════════════════
158- * TAILWIND THEME BRIDGE
159- * Maps design tokens to Tailwind's color system
160- * ═══════════════════════════════════════════════════════════════ */
161-@theme inline {
162- --color-background: var(--background);
163- --color-foreground: var(--foreground);
164- --color-card: var(--card);
165- --color-card-foreground: var(--card-foreground);
166- --color-popover: var(--popover);
167- --color-popover-foreground: var(--popover-foreground);
168- --color-primary: var(--primary);
169- --color-primary-foreground: var(--primary-foreground);
170- --color-secondary: var(--secondary);
171- --color-secondary-foreground: var(--secondary-foreground);
172- --color-muted: var(--muted);
173- --color-muted-foreground: var(--muted-foreground);
174- --color-accent: var(--accent);
175- --color-accent-foreground: var(--accent-foreground);
176- --color-destructive: var(--destructive);
177- --color-destructive-foreground: var(--destructive-foreground);
178- --color-success: var(--success);
179- --color-success-foreground: var(--success-foreground);
180- --color-warning: var(--warning);
181- --color-warning-foreground: var(--warning-foreground);
182- --color-info: var(--info);
183- --color-info-foreground: var(--info-foreground);
184- --color-border: var(--border);
185- --color-input: var(--input);
186- --color-ring: var(--ring);
187- --color-chart-1: var(--chart-1);
188- --color-chart-2: var(--chart-2);
189- --color-chart-3: var(--chart-3);
190- --color-chart-4: var(--chart-4);
191- --color-chart-5: var(--chart-5);
192-}
@@ -1,192 +0,0 @@
1-/*
2- * Design Tokens - shadcn-svelte inspired
3- *
4- * Uses OKLCH color space for perceptually uniform colors.
5- * These tokens define the visual language of the browser UI.
6- *
7- * Aesthetic: Industrial Terminal / Brutalist Minimal
8- * - Sharp corners (--radius: 0)
9- * - High contrast
10- * - Vibrant green primary accent
11- * - Cyan secondary accent
12- */
13-
14-:root {
15- /* Radius - sharp terminal aesthetic */
16- --radius: 0;
17- --radius-sm: 0;
18- --radius-md: 0;
19- --radius-lg: 0;
20- --radius-xl: 0;
21-
22- /* ═══════════════════════════════════════════════════════════════
23- * LIGHT THEME
24- * ═══════════════════════════════════════════════════════════════ */
25-
26- /* Core surfaces */
27- --background: oklch(0.985 0.002 260);
28- --foreground: oklch(0.145 0.02 260);
29-
30- /* Card/Panel surfaces */
31- --card: oklch(0.965 0.004 260);
32- --card-foreground: oklch(0.145 0.02 260);
33-
34- /* Popover/Dropdown */
35- --popover: oklch(0.985 0.002 260);
36- --popover-foreground: oklch(0.145 0.02 260);
37-
38- /* Primary - Vibrant Green */
39- --primary: oklch(0.55 0.20 145);
40- --primary-foreground: oklch(0.985 0 0);
41-
42- /* Secondary - Muted surfaces */
43- --secondary: oklch(0.94 0.008 260);
44- --secondary-foreground: oklch(0.20 0.02 260);
45-
46- /* Muted - Subdued content */
47- --muted: oklch(0.94 0.008 260);
48- --muted-foreground: oklch(0.48 0.02 260);
49-
50- /* Accent - Cyan for info/highlights */
51- --accent: oklch(0.58 0.14 200);
52- --accent-foreground: oklch(0.145 0.02 260);
53-
54- /* Destructive - Red for danger */
55- --destructive: oklch(0.55 0.22 25);
56- --destructive-foreground: oklch(0.985 0 0);
57-
58- /* Borders & Inputs */
59- --border: oklch(0.88 0.008 260);
60- --input: oklch(0.88 0.008 260);
61- --ring: var(--primary);
62-
63- /* Semantic colors - for status indicators */
64- --success: oklch(0.65 0.20 145);
65- --success-foreground: oklch(0.985 0 0);
66- --warning: oklch(0.75 0.18 85);
67- --warning-foreground: oklch(0.145 0.02 260);
68- --info: oklch(0.65 0.15 230);
69- --info-foreground: oklch(0.985 0 0);
70-
71- /* Chart colors for analytics */
72- --chart-1: oklch(0.58 0.18 145); /* Green */
73- --chart-2: oklch(0.56 0.14 200); /* Cyan */
74- --chart-3: oklch(0.66 0.15 70); /* Amber */
75- --chart-4: oklch(0.58 0.18 300); /* Purple */
76- --chart-5: oklch(0.60 0.18 25); /* Red-orange */
77-
78- /* Sidebar (if used) */
79- --sidebar: oklch(0.975 0.002 260);
80- --sidebar-foreground: oklch(0.145 0.02 260);
81- --sidebar-primary: oklch(0.55 0.20 145);
82- --sidebar-primary-foreground: oklch(0.985 0 0);
83- --sidebar-accent: oklch(0.94 0.008 260);
84- --sidebar-accent-foreground: oklch(0.20 0.02 260);
85- --sidebar-border: oklch(0.88 0.008 260);
86- --sidebar-ring: oklch(0.55 0.20 145);
87-}
88-
89-.dark {
90- /* ═══════════════════════════════════════════════════════════════
91- * DARK THEME - High Contrast
92- * ═══════════════════════════════════════════════════════════════ */
93-
94- /* Core surfaces - true black for maximum contrast */
95- --background: oklch(0.09 0.005 260);
96- --foreground: oklch(0.97 0 0);
97-
98- /* Card/Panel surfaces - slightly elevated */
99- --card: oklch(0.14 0.008 260);
100- --card-foreground: oklch(0.97 0 0);
101-
102- /* Popover/Dropdown */
103- --popover: oklch(0.16 0.008 260);
104- --popover-foreground: oklch(0.97 0 0);
105-
106- /* Primary - Bright Green */
107- --primary: oklch(0.75 0.19 145);
108- --primary-foreground: oklch(0.12 0.02 145);
109-
110- /* Secondary - Elevated surfaces */
111- --secondary: oklch(0.20 0.008 260);
112- --secondary-foreground: oklch(0.97 0 0);
113-
114- /* Muted - More visible subdued content */
115- --muted: oklch(0.22 0.008 260);
116- --muted-foreground: oklch(0.70 0.01 260);
117-
118- /* Accent - Cyan for info/highlights */
119- --accent: oklch(0.68 0.14 200);
120- --accent-foreground: oklch(0.97 0 0);
121-
122- /* Destructive - Red for danger */
123- --destructive: oklch(0.65 0.20 25);
124- --destructive-foreground: oklch(0.97 0 0);
125-
126- /* Borders & Inputs - more visible */
127- --border: oklch(0.35 0.01 260);
128- --input: oklch(0.35 0.01 260);
129- --ring: var(--primary);
130-
131- /* Semantic colors - brighter for dark bg */
132- --success: oklch(0.72 0.18 145);
133- --success-foreground: oklch(0.12 0.02 145);
134- --warning: oklch(0.80 0.16 85);
135- --warning-foreground: oklch(0.12 0.02 85);
136- --info: oklch(0.70 0.14 230);
137- --info-foreground: oklch(0.12 0.02 230);
138-
139- /* Chart colors for analytics - brighter for dark bg */
140- --chart-1: oklch(0.72 0.18 145); /* Green */
141- --chart-2: oklch(0.68 0.14 200); /* Cyan */
142- --chart-3: oklch(0.76 0.16 70); /* Amber */
143- --chart-4: oklch(0.66 0.18 300); /* Purple */
144- --chart-5: oklch(0.68 0.18 25); /* Red-orange */
145-
146- /* Sidebar (if used) */
147- --sidebar: oklch(0.12 0.008 260);
148- --sidebar-foreground: oklch(0.97 0 0);
149- --sidebar-primary: oklch(0.75 0.19 145);
150- --sidebar-primary-foreground: oklch(0.12 0.02 145);
151- --sidebar-accent: oklch(0.20 0.008 260);
152- --sidebar-accent-foreground: oklch(0.97 0 0);
153- --sidebar-border: oklch(0.35 0.01 260);
154- --sidebar-ring: oklch(0.75 0.19 145);
155-}
156-
157-/* ═══════════════════════════════════════════════════════════════
158- * TAILWIND THEME BRIDGE
159- * Maps design tokens to Tailwind's color system
160- * ═══════════════════════════════════════════════════════════════ */
161-@theme inline {
162- --color-background: var(--background);
163- --color-foreground: var(--foreground);
164- --color-card: var(--card);
165- --color-card-foreground: var(--card-foreground);
166- --color-popover: var(--popover);
167- --color-popover-foreground: var(--popover-foreground);
168- --color-primary: var(--primary);
169- --color-primary-foreground: var(--primary-foreground);
170- --color-secondary: var(--secondary);
171- --color-secondary-foreground: var(--secondary-foreground);
172- --color-muted: var(--muted);
173- --color-muted-foreground: var(--muted-foreground);
174- --color-accent: var(--accent);
175- --color-accent-foreground: var(--accent-foreground);
176- --color-destructive: var(--destructive);
177- --color-destructive-foreground: var(--destructive-foreground);
178- --color-success: var(--success);
179- --color-success-foreground: var(--success-foreground);
180- --color-warning: var(--warning);
181- --color-warning-foreground: var(--warning-foreground);
182- --color-info: var(--info);
183- --color-info-foreground: var(--info-foreground);
184- --color-border: var(--border);
185- --color-input: var(--input);
186- --color-ring: var(--ring);
187- --color-chart-1: var(--chart-1);
188- --color-chart-2: var(--chart-2);
189- --color-chart-3: var(--chart-3);
190- --color-chart-4: var(--chart-4);
191- --color-chart-5: var(--chart-5);
192-}
D webui/src/styles/tailwind.css +0 -249
@@ -1,249 +0,0 @@
1-@import "./design-tokens.css";
2-@import "tailwindcss";
3-
4-/* Dynamic theme switching via CSS variables
5- * These bridge between:
6- * 1. Backend palette (--color-browser-*) injected at runtime
7- * 2. Design tokens (--background, --primary, etc.) for static fallbacks
8- * 3. Component usage (shadcn-svelte variables: --background, --card, --foreground, etc.)
9- */
10-:root {
11- /* Primary bridge - uses backend palette when available, falls back to tokens */
12- --dynamic-bg: var(--color-browser-bg, var(--background));
13- --dynamic-surface: var(--color-browser-surface, var(--card));
14- --dynamic-surface-variant: var(--color-browser-surface-variant, var(--secondary));
15- --dynamic-text: var(--color-browser-text, var(--foreground));
16- --dynamic-muted: var(--color-browser-muted, var(--muted-foreground));
17- --dynamic-accent: var(--color-browser-accent, var(--primary));
18- /* Border: hardcoded to avoid nested var() issues in WebKitGTK */
19- --dynamic-border: var(--color-browser-border, rgba(0, 0, 0, 0.12));
20-
21- /* Extended semantic colors from design tokens */
22- --dynamic-primary: var(--primary);
23- --dynamic-primary-foreground: var(--primary-foreground);
24- --dynamic-secondary: var(--secondary);
25- --dynamic-destructive: var(--destructive);
26- --dynamic-ring: var(--ring);
27-
28- /* Semantic status colors - backend can override */
29- --dynamic-success: var(--color-browser-success, var(--success));
30- --dynamic-success-foreground: var(--success-foreground);
31- --dynamic-warning: var(--color-browser-warning, var(--warning));
32- --dynamic-warning-foreground: var(--warning-foreground);
33- --dynamic-info: var(--color-browser-info, var(--info));
34- --dynamic-info-foreground: var(--info-foreground);
35-}
36-
37-/* Dark mode border override */
38-.dark {
39- --dynamic-border: var(--color-browser-border, rgba(255, 255, 255, 0.15));
40-}
41-
42-/* Base styles for browser UI components */
43-.browser-ui {
44- background-color: var(--dynamic-bg);
45- color: var(--dynamic-text);
46- border-color: var(--dynamic-border);
47- transition: colors 250ms;
48-}
49-
50-/* Toast notification styles */
51-.toast-base {
52- border-radius: 0;
53- box-shadow:
54- 0 10px 15px -3px rgb(0 0 0 / 0.1),
55- 0 4px 6px -4px rgb(0 0 0 / 0.1);
56- padding: 0.25rem 0.5rem;
57- max-width: 24rem;
58- pointer-events: auto;
59- background-color: var(--dynamic-surface);
60- color: var(--dynamic-text);
61- border: 1px solid var(--dynamic-border);
62-}
63-
64-.toast-success {
65- background-color: var(--dynamic-success);
66- color: var(--dynamic-success-foreground);
67- border: 1px solid color-mix(in srgb, var(--dynamic-success) 50%, var(--dynamic-border) 50%);
68-}
69-
70-.toast-error {
71- background-color: var(--dynamic-destructive);
72- color: var(--destructive-foreground);
73- border: 1px solid color-mix(in srgb, var(--dynamic-destructive) 50%, var(--dynamic-border) 50%);
74-}
75-
76-.toast-info {
77- background-color: var(--dynamic-info);
78- color: var(--dynamic-info-foreground);
79- border: 1px solid color-mix(in srgb, var(--dynamic-info) 50%, var(--dynamic-border) 50%);
80-}
81-
82-.toast-warning {
83- background-color: var(--dynamic-warning);
84- color: var(--dynamic-warning-foreground);
85- border: 1px solid color-mix(in srgb, var(--dynamic-warning) 50%, var(--dynamic-border) 50%);
86-}
87-
88-/* Omnibox/Find bar styles */
89-.omnibox-base {
90- background-color: var(--dynamic-bg);
91- color: var(--dynamic-text);
92- border: 1px solid var(--dynamic-border);
93- box-shadow:
94- 0 4px 6px -1px rgb(0 0 0 / 0.1),
95- 0 2px 4px -2px rgb(0 0 0 / 0.1);
96- transition: all 150ms;
97-}
98-
99-.omnibox-base:focus-within {
100- border-color: var(--dynamic-accent);
101-}
102-
103-.omnibox-input {
104- width: 100%;
105- padding: 0.5rem 0.75rem;
106- background-color: transparent;
107- color: var(--dynamic-text);
108- outline: none;
109- font-size: 0.875rem;
110-}
111-
112-.omnibox-input::placeholder {
113- color: var(--dynamic-muted);
114-}
115-
116-/* Find bar specific styles */
117-.findbar {
118- display: flex;
119- align-items: center;
120- gap: 0.5rem;
121- padding: 0.5rem 0.75rem;
122-}
123-
124-.findbar-input {
125- flex: 1;
126- background-color: transparent;
127- color: var(--dynamic-text);
128- outline: none;
129- font-size: 0.875rem;
130-}
131-
132-.findbar-input::placeholder {
133- color: var(--dynamic-muted);
134-}
135-
136-.findbar-button {
137- padding: 0.25rem 0.5rem;
138- border-radius: 0;
139- color: var(--dynamic-muted);
140- transition: colors 150ms;
141- font-size: 0.875rem;
142-}
143-
144-.findbar-button:hover {
145- color: var(--dynamic-text);
146-}
147-
148-.findbar-count {
149- font-size: 0.75rem;
150- color: var(--dynamic-muted);
151- font-variant-numeric: tabular-nums;
152-}
153-
154-/* Animation utilities */
155-.slide-in-top {
156- animation: slide-in-top 0.25s ease-out;
157-}
158-
159-.slide-out-top {
160- animation: slide-out-top 0.25s ease-in;
161-}
162-
163-.fade-in {
164- animation: fade-in 0.15s ease-out;
165-}
166-
167-.fade-out {
168- animation: fade-out 0.15s ease-in;
169-}
170-
171-@keyframes slide-in-top {
172- from {
173- transform: translateY(-100%);
174- opacity: 0;
175- }
176- to {
177- transform: translateY(0);
178- opacity: 1;
179- }
180-}
181-
182-@keyframes slide-out-top {
183- from {
184- transform: translateY(0);
185- opacity: 1;
186- }
187- to {
188- transform: translateY(-100%);
189- opacity: 0;
190- }
191-}
192-
193-@keyframes fade-in {
194- from {
195- opacity: 0;
196- }
197- to {
198- opacity: 1;
199- }
200-}
201-
202-@keyframes fade-out {
203- from {
204- opacity: 1;
205- }
206- to {
207- opacity: 0;
208- }
209-}
210-
211-/* Find highlighting styles for in-page search */
212-.find-highlight {
213- background-color: rgb(255 235 59); /* yellow-400 */
214- color: rgb(0 0 0); /* black */
215- padding: 0 0.125rem; /* px-0.5 */
216- border-radius: 0.125rem; /* rounded-sm */
217- box-shadow: 0 0 0 1px rgb(200 185 0) inset;
218-}
219-
220-.find-active {
221- background-color: rgb(255 152 0) !important; /* orange-500 */
222- color: rgb(0 0 0); /* black */
223- box-shadow: 0 0 0 1px rgb(179 107 0) inset !important;
224-}
225-
226-/* Utility for isolating component styles */
227-.browser-component-root {
228- /* Reset any inherited styles from the website */
229- all: initial;
230- /* Apply our design system */
231- font-family:
232- Fira Sans,
233- system-ui,
234- -apple-system,
235- sans-serif;
236- box-sizing: border-box;
237- * {
238- box-sizing: border-box;
239- }
240-}
241-
242-/* Global body styles */
243-body {
244- background-color: var(--dynamic-bg);
245- color: var(--dynamic-text);
246- transition:
247- background-color 200ms ease,
248- color 200ms ease;
249-}
@@ -1,249 +0,0 @@
1-@import "./design-tokens.css";
2-@import "tailwindcss";
3-
4-/* Dynamic theme switching via CSS variables
5- * These bridge between:
6- * 1. Backend palette (--color-browser-*) injected at runtime
7- * 2. Design tokens (--background, --primary, etc.) for static fallbacks
8- * 3. Component usage (shadcn-svelte variables: --background, --card, --foreground, etc.)
9- */
10-:root {
11- /* Primary bridge - uses backend palette when available, falls back to tokens */
12- --dynamic-bg: var(--color-browser-bg, var(--background));
13- --dynamic-surface: var(--color-browser-surface, var(--card));
14- --dynamic-surface-variant: var(--color-browser-surface-variant, var(--secondary));
15- --dynamic-text: var(--color-browser-text, var(--foreground));
16- --dynamic-muted: var(--color-browser-muted, var(--muted-foreground));
17- --dynamic-accent: var(--color-browser-accent, var(--primary));
18- /* Border: hardcoded to avoid nested var() issues in WebKitGTK */
19- --dynamic-border: var(--color-browser-border, rgba(0, 0, 0, 0.12));
20-
21- /* Extended semantic colors from design tokens */
22- --dynamic-primary: var(--primary);
23- --dynamic-primary-foreground: var(--primary-foreground);
24- --dynamic-secondary: var(--secondary);
25- --dynamic-destructive: var(--destructive);
26- --dynamic-ring: var(--ring);
27-
28- /* Semantic status colors - backend can override */
29- --dynamic-success: var(--color-browser-success, var(--success));
30- --dynamic-success-foreground: var(--success-foreground);
31- --dynamic-warning: var(--color-browser-warning, var(--warning));
32- --dynamic-warning-foreground: var(--warning-foreground);
33- --dynamic-info: var(--color-browser-info, var(--info));
34- --dynamic-info-foreground: var(--info-foreground);
35-}
36-
37-/* Dark mode border override */
38-.dark {
39- --dynamic-border: var(--color-browser-border, rgba(255, 255, 255, 0.15));
40-}
41-
42-/* Base styles for browser UI components */
43-.browser-ui {
44- background-color: var(--dynamic-bg);
45- color: var(--dynamic-text);
46- border-color: var(--dynamic-border);
47- transition: colors 250ms;
48-}
49-
50-/* Toast notification styles */
51-.toast-base {
52- border-radius: 0;
53- box-shadow:
54- 0 10px 15px -3px rgb(0 0 0 / 0.1),
55- 0 4px 6px -4px rgb(0 0 0 / 0.1);
56- padding: 0.25rem 0.5rem;
57- max-width: 24rem;
58- pointer-events: auto;
59- background-color: var(--dynamic-surface);
60- color: var(--dynamic-text);
61- border: 1px solid var(--dynamic-border);
62-}
63-
64-.toast-success {
65- background-color: var(--dynamic-success);
66- color: var(--dynamic-success-foreground);
67- border: 1px solid color-mix(in srgb, var(--dynamic-success) 50%, var(--dynamic-border) 50%);
68-}
69-
70-.toast-error {
71- background-color: var(--dynamic-destructive);
72- color: var(--destructive-foreground);
73- border: 1px solid color-mix(in srgb, var(--dynamic-destructive) 50%, var(--dynamic-border) 50%);
74-}
75-
76-.toast-info {
77- background-color: var(--dynamic-info);
78- color: var(--dynamic-info-foreground);
79- border: 1px solid color-mix(in srgb, var(--dynamic-info) 50%, var(--dynamic-border) 50%);
80-}
81-
82-.toast-warning {
83- background-color: var(--dynamic-warning);
84- color: var(--dynamic-warning-foreground);
85- border: 1px solid color-mix(in srgb, var(--dynamic-warning) 50%, var(--dynamic-border) 50%);
86-}
87-
88-/* Omnibox/Find bar styles */
89-.omnibox-base {
90- background-color: var(--dynamic-bg);
91- color: var(--dynamic-text);
92- border: 1px solid var(--dynamic-border);
93- box-shadow:
94- 0 4px 6px -1px rgb(0 0 0 / 0.1),
95- 0 2px 4px -2px rgb(0 0 0 / 0.1);
96- transition: all 150ms;
97-}
98-
99-.omnibox-base:focus-within {
100- border-color: var(--dynamic-accent);
101-}
102-
103-.omnibox-input {
104- width: 100%;
105- padding: 0.5rem 0.75rem;
106- background-color: transparent;
107- color: var(--dynamic-text);
108- outline: none;
109- font-size: 0.875rem;
110-}
111-
112-.omnibox-input::placeholder {
113- color: var(--dynamic-muted);
114-}
115-
116-/* Find bar specific styles */
117-.findbar {
118- display: flex;
119- align-items: center;
120- gap: 0.5rem;
121- padding: 0.5rem 0.75rem;
122-}
123-
124-.findbar-input {
125- flex: 1;
126- background-color: transparent;
127- color: var(--dynamic-text);
128- outline: none;
129- font-size: 0.875rem;
130-}
131-
132-.findbar-input::placeholder {
133- color: var(--dynamic-muted);
134-}
135-
136-.findbar-button {
137- padding: 0.25rem 0.5rem;
138- border-radius: 0;
139- color: var(--dynamic-muted);
140- transition: colors 150ms;
141- font-size: 0.875rem;
142-}
143-
144-.findbar-button:hover {
145- color: var(--dynamic-text);
146-}
147-
148-.findbar-count {
149- font-size: 0.75rem;
150- color: var(--dynamic-muted);
151- font-variant-numeric: tabular-nums;
152-}
153-
154-/* Animation utilities */
155-.slide-in-top {
156- animation: slide-in-top 0.25s ease-out;
157-}
158-
159-.slide-out-top {
160- animation: slide-out-top 0.25s ease-in;
161-}
162-
163-.fade-in {
164- animation: fade-in 0.15s ease-out;
165-}
166-
167-.fade-out {
168- animation: fade-out 0.15s ease-in;
169-}
170-
171-@keyframes slide-in-top {
172- from {
173- transform: translateY(-100%);
174- opacity: 0;
175- }
176- to {
177- transform: translateY(0);
178- opacity: 1;
179- }
180-}
181-
182-@keyframes slide-out-top {
183- from {
184- transform: translateY(0);
185- opacity: 1;
186- }
187- to {
188- transform: translateY(-100%);
189- opacity: 0;
190- }
191-}
192-
193-@keyframes fade-in {
194- from {
195- opacity: 0;
196- }
197- to {
198- opacity: 1;
199- }
200-}
201-
202-@keyframes fade-out {
203- from {
204- opacity: 1;
205- }
206- to {
207- opacity: 0;
208- }
209-}
210-
211-/* Find highlighting styles for in-page search */
212-.find-highlight {
213- background-color: rgb(255 235 59); /* yellow-400 */
214- color: rgb(0 0 0); /* black */
215- padding: 0 0.125rem; /* px-0.5 */
216- border-radius: 0.125rem; /* rounded-sm */
217- box-shadow: 0 0 0 1px rgb(200 185 0) inset;
218-}
219-
220-.find-active {
221- background-color: rgb(255 152 0) !important; /* orange-500 */
222- color: rgb(0 0 0); /* black */
223- box-shadow: 0 0 0 1px rgb(179 107 0) inset !important;
224-}
225-
226-/* Utility for isolating component styles */
227-.browser-component-root {
228- /* Reset any inherited styles from the website */
229- all: initial;
230- /* Apply our design system */
231- font-family:
232- Fira Sans,
233- system-ui,
234- -apple-system,
235- sans-serif;
236- box-sizing: border-box;
237- * {
238- box-sizing: border-box;
239- }
240-}
241-
242-/* Global body styles */
243-body {
244- background-color: var(--dynamic-bg);
245- color: var(--dynamic-text);
246- transition:
247- background-color 200ms ease,
248- color 200ms ease;
249-}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close