Skip to content

Commit d970fc0

Browse files
committed
fix: add theme customization documentation and example CSS preset
1 parent 848113b commit d970fc0

5 files changed

Lines changed: 280 additions & 2 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ You will also need:
7575
- Git available on your system `PATH`
7676
- A Windows environment for the current primary development target
7777

78+
## Theming
79+
80+
Theme customization notes and a reference preset CSS file are available in [docs/theme-customization.md](docs/theme-customization.md).
81+
7882
## Tech Stack
7983

8084
- Tauri 2
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
Example UniGit theme preset.
3+
4+
This file is documentation and reference material.
5+
It is not loaded automatically by the app today.
6+
7+
Use it when:
8+
- adding a new built-in theme preset to src/styles.css
9+
- designing a theme that needs selector-level treatment beyond JSON variable overrides
10+
*/
11+
12+
:root[data-theme="aurora-glass"] {
13+
color-scheme: dark;
14+
--bg-0: #071018;
15+
--bg-1: rgba(13, 21, 32, 0.76);
16+
--bg-3: rgba(255, 255, 255, 0.08);
17+
--line: rgba(255, 255, 255, 0.14);
18+
--line-soft: rgba(255, 255, 255, 0.11);
19+
--line-softer: rgba(255, 255, 255, 0.08);
20+
--line-subtle: rgba(255, 255, 255, 0.1);
21+
--line-strong: rgba(143, 198, 255, 0.38);
22+
--text-1: #f2f7ff;
23+
--text-2: rgba(229, 238, 255, 0.78);
24+
--text-3: rgba(219, 232, 255, 0.56);
25+
--accent: #8fc6ff;
26+
--accent-2: #7ff5db;
27+
--app-background:
28+
radial-gradient(circle at 14% 10%, rgba(86, 150, 255, 0.18), transparent 22%),
29+
radial-gradient(circle at 82% 18%, rgba(68, 233, 202, 0.14), transparent 24%),
30+
radial-gradient(circle at 52% 76%, rgba(117, 94, 255, 0.12), transparent 30%),
31+
linear-gradient(180deg, #16232b 0%, #0c141d 42%, #071018 100%);
32+
--panel-bg-start: rgba(31, 42, 58, 0.54);
33+
--panel-bg-end: rgba(10, 17, 28, 0.28);
34+
--panel-shadow: 0 26px 84px rgba(0, 0, 0, 0.42), inset 0 1px 0 rgba(255, 255, 255, 0.16), inset 0 -1px 0 rgba(255, 255, 255, 0.04);
35+
--elevated-shadow: 0 16px 42px rgba(0, 0, 0, 0.36), inset 0 1px 0 rgba(255, 255, 255, 0.14);
36+
--surface-section: rgba(255, 255, 255, 0.08);
37+
--surface-row: rgba(255, 255, 255, 0.1);
38+
--surface-card: rgba(255, 255, 255, 0.1);
39+
--surface-muted: rgba(255, 255, 255, 0.14);
40+
--surface-input: rgba(10, 17, 28, 0.44);
41+
--surface-menu-start: rgba(32, 43, 58, 0.64);
42+
--surface-menu-end: rgba(10, 17, 28, 0.42);
43+
--surface-selection: rgba(143, 198, 255, 0.18);
44+
--surface-selection-soft: rgba(143, 198, 255, 0.14);
45+
--surface-selection-subtle: rgba(143, 198, 255, 0.1);
46+
--surface-overlay: rgba(4, 9, 15, 0.5);
47+
--surface-fullscreen-start: rgba(16, 24, 35, 0.72);
48+
--surface-fullscreen-end: rgba(7, 12, 18, 0.44);
49+
--surface-frame: rgba(9, 15, 24, 0.3);
50+
--surface-viewport:
51+
radial-gradient(circle at 18% 20%, rgba(143, 198, 255, 0.18), transparent 24%),
52+
radial-gradient(circle at 84% 74%, rgba(127, 245, 219, 0.12), transparent 24%),
53+
rgba(7, 12, 20, 0.34);
54+
--surface-tab-active: linear-gradient(180deg, rgba(143, 198, 255, 0.18), rgba(255, 255, 255, 0.06));
55+
--surface-chip: rgba(255, 255, 255, 0.1);
56+
--surface-chip-strong: rgba(255, 255, 255, 0.14);
57+
--surface-button: rgba(255, 255, 255, 0.12);
58+
--surface-button-strong: rgba(255, 255, 255, 0.18);
59+
--surface-button-active: rgba(143, 198, 255, 0.18);
60+
--text-inverse: #08121c;
61+
--text-code: #e4eeff;
62+
--scrollbar-thumb: rgba(143, 198, 255, 0.22);
63+
--scrollbar-thumb-strong: rgba(143, 198, 255, 0.34);
64+
--scrollbar-track: rgba(255, 255, 255, 0.08);
65+
--ref-pill-bg: rgba(255, 255, 255, 0.16);
66+
--ref-pill-text: #eef4ff;
67+
--ref-pill-primary: rgba(143, 198, 255, 0.22);
68+
--control-accent: #8fc6ff;
69+
--panel-backdrop-filter: blur(34px) saturate(180%);
70+
--surface-backdrop-filter: blur(28px) saturate(165%);
71+
--control-backdrop-filter: blur(22px) saturate(160%);
72+
--glass-surface-highlight: linear-gradient(180deg, rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0.05) 36%, rgba(255, 255, 255, 0.01) 62%, rgba(255, 255, 255, 0.03));
73+
--glass-control-highlight: linear-gradient(180deg, rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0.05) 48%, rgba(255, 255, 255, 0.02));
74+
--glass-surface-shadow: 0 18px 44px rgba(0, 0, 0, 0.22), inset 0 1px 0 rgba(255, 255, 255, 0.14), inset 0 -1px 0 rgba(255, 255, 255, 0.03);
75+
--glass-control-shadow: 0 12px 28px rgba(0, 0, 0, 0.24), inset 0 1px 0 rgba(255, 255, 255, 0.14);
76+
--glass-rim: rgba(255, 255, 255, 0.16);
77+
}
78+
79+
:root[data-theme="aurora-glass"] .panel,
80+
:root[data-theme="aurora-glass"] .repo-tab,
81+
:root[data-theme="aurora-glass"] .repo-manager-section,
82+
:root[data-theme="aurora-glass"] .repo-manager-row,
83+
:root[data-theme="aurora-glass"] .lane,
84+
:root[data-theme="aurora-glass"] .change-card,
85+
:root[data-theme="aurora-glass"] .selection-card,
86+
:root[data-theme="aurora-glass"] .commit-box,
87+
:root[data-theme="aurora-glass"] .preview-frame,
88+
:root[data-theme="aurora-glass"] .branch-panel,
89+
:root[data-theme="aurora-glass"] .branch-row,
90+
:root[data-theme="aurora-glass"] .graph-viewport {
91+
backdrop-filter: var(--surface-backdrop-filter);
92+
box-shadow: var(--glass-surface-shadow);
93+
border-color: var(--glass-rim);
94+
}
95+
96+
:root[data-theme="aurora-glass"] .icon-button,
97+
:root[data-theme="aurora-glass"] .ghost-button,
98+
:root[data-theme="aurora-glass"] .branch-chip,
99+
:root[data-theme="aurora-glass"] .sync-chip,
100+
:root[data-theme="aurora-glass"] .changes-filter,
101+
:root[data-theme="aurora-glass"] .changes-select,
102+
:root[data-theme="aurora-glass"] .commit-box__input,
103+
:root[data-theme="aurora-glass"] .history-filter,
104+
:root[data-theme="aurora-glass"] .history-ref-pill {
105+
backdrop-filter: var(--control-backdrop-filter);
106+
box-shadow: var(--glass-control-shadow);
107+
border-color: var(--glass-rim);
108+
}
109+
110+
:root[data-theme="aurora-glass"] .repo-tab--active,
111+
:root[data-theme="aurora-glass"] .change-card--selected,
112+
:root[data-theme="aurora-glass"] .branch-row--selected,
113+
:root[data-theme="aurora-glass"] .ghost-button--active {
114+
box-shadow: 0 16px 34px rgba(3, 6, 12, 0.28), inset 0 1px 0 rgba(255, 255, 255, 0.2);
115+
}

docs/theme-customization.md

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
# Theme Customization
2+
3+
UniGit supports theming in two layers:
4+
5+
1. End-user custom themes through the Appearance section in the app.
6+
2. Full built-in themes in code by adding a new preset to the stylesheet and theme settings.
7+
8+
The current implementation is centered around CSS variables applied to `document.documentElement`.
9+
10+
## Quick Start For Users
11+
12+
Open Repo Manager, then go to the `Appearance` section.
13+
14+
If you want a simple custom theme:
15+
16+
1. Select `Custom`.
17+
2. Pick a base preset such as `Dark`, `Light`, or `Liquid Glass`.
18+
3. Paste a JSON object with CSS variable overrides.
19+
20+
Example:
21+
22+
```json
23+
{
24+
"--accent": "#8cb6ff",
25+
"--accent-2": "#72f0df",
26+
"--surface-card": "rgba(255, 255, 255, 0.08)",
27+
"--surface-button": "rgba(255, 255, 255, 0.12)",
28+
"--line-strong": "rgba(140, 182, 255, 0.42)"
29+
}
30+
```
31+
32+
Important:
33+
34+
- Custom themes in the current UI override CSS variables only.
35+
- The JSON must be a flat object.
36+
- Keys must start with `--`.
37+
- Values must be strings or numbers.
38+
39+
## How The Theme System Works
40+
41+
### Runtime application
42+
43+
The app applies theme presets in [src/app/App.tsx](src/app/App.tsx) by:
44+
45+
- Setting `document.documentElement.dataset.theme`
46+
- Setting `document.documentElement.style.colorScheme`
47+
- Applying any custom variable overrides directly on the root element
48+
49+
### Theme settings and validation
50+
51+
Theme preset IDs, saved state, JSON parsing, and validation live in [src/app/utils/themeSettings.ts](src/app/utils/themeSettings.ts).
52+
53+
### CSS source of truth
54+
55+
All theme variables and theme-specific selector overrides live in [src/styles.css](src/styles.css).
56+
57+
The main pattern is:
58+
59+
```css
60+
:root[data-theme="my-theme"] {
61+
--accent: #8cb6ff;
62+
--surface-card: rgba(255, 255, 255, 0.08);
63+
}
64+
65+
:root[data-theme="my-theme"] .panel,
66+
:root[data-theme="my-theme"] .change-card {
67+
backdrop-filter: blur(28px) saturate(165%);
68+
}
69+
```
70+
71+
## Variables You Will Usually Override
72+
73+
These variables give the biggest visual change with the least work:
74+
75+
- `--app-background`
76+
- `--panel-bg-start`
77+
- `--panel-bg-end`
78+
- `--surface-section`
79+
- `--surface-row`
80+
- `--surface-card`
81+
- `--surface-input`
82+
- `--surface-button`
83+
- `--surface-button-strong`
84+
- `--surface-button-active`
85+
- `--surface-selection`
86+
- `--surface-selection-soft`
87+
- `--line`
88+
- `--line-strong`
89+
- `--text-1`
90+
- `--text-2`
91+
- `--text-3`
92+
- `--accent`
93+
- `--accent-2`
94+
- `--control-accent`
95+
96+
For glass-like themes, these extra variables matter as well:
97+
98+
- `--panel-backdrop-filter`
99+
- `--surface-backdrop-filter`
100+
- `--control-backdrop-filter`
101+
- `--glass-surface-highlight`
102+
- `--glass-control-highlight`
103+
- `--glass-surface-shadow`
104+
- `--glass-control-shadow`
105+
- `--glass-rim`
106+
107+
## Common Selectors For Theme-Specific Styling
108+
109+
If variables alone are not enough, these selectors are the main places to add extra treatment:
110+
111+
- `.panel`
112+
- `.repo-tab`
113+
- `.repo-manager-section`
114+
- `.repo-manager-row`
115+
- `.lane`
116+
- `.change-card`
117+
- `.selection-card`
118+
- `.commit-box`
119+
- `.preview-frame`
120+
- `.branch-panel`
121+
- `.branch-row`
122+
- `.graph-viewport`
123+
- `.icon-button`
124+
- `.ghost-button`
125+
- `.branch-chip`
126+
- `.sync-chip`
127+
- `.changes-filter`
128+
- `.changes-select`
129+
- `.commit-box__input`
130+
- `.history-filter`
131+
132+
The existing liquid-glass theme in [src/styles.css](src/styles.css) is a good example of using both variables and targeted selectors.
133+
134+
## Adding A New Built-In Theme
135+
136+
If you want a first-class theme preset instead of JSON overrides:
137+
138+
1. Add the new preset ID to [src/app/utils/themeSettings.ts](src/app/utils/themeSettings.ts).
139+
2. Add its label and description to `themeOptions`.
140+
3. Add a `:root[data-theme="your-theme"]` block in [src/styles.css](src/styles.css).
141+
4. Add any theme-specific selector rules below the shared button and panel styles.
142+
5. Make sure the runtime `colorScheme` in [src/app/App.tsx](src/app/App.tsx) matches the visual intent of the theme.
143+
144+
Use `dark` unless the theme is genuinely light, because native scrollbars and form controls follow that setting.
145+
146+
## Example CSS Preset
147+
148+
An example preset file is available at [docs/examples/aurora-glass-theme.css](docs/examples/aurora-glass-theme.css).
149+
150+
That file shows:
151+
152+
- A complete `:root[data-theme="aurora-glass"]` variable block
153+
- Shared glass variables
154+
- Theme-specific selector overrides for panels, cards, controls, and the graph viewport
155+
156+
Note:
157+
158+
- The example CSS file is for contributors adding a built-in theme or for future import tooling.
159+
- End users currently paste JSON variable overrides into the app, not raw CSS.

src/app/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ export function App() {
449449
const nextVariables = parseCustomThemeVariables(themeSettings);
450450

451451
root.dataset.theme = presetId;
452-
root.style.colorScheme = presetId === "dark" ? "dark" : "light";
452+
root.style.colorScheme = presetId === "light" ? "light" : "dark";
453453

454454
for (const key of appliedThemeVariableKeysRef.current) {
455455
if (!(key in nextVariables)) {

src/app/utils/themeSettings.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const themeOptions: ThemeOption[] = [
3030
{
3131
id: "liquid-glass",
3232
label: "Liquid Glass",
33-
description: "A translucent Apple-inspired glass treatment with bright, frosted surfaces.",
33+
description: "A dark, translucent glass theme with layered highlights and deeper frosted surfaces.",
3434
},
3535
{
3636
id: "custom",

0 commit comments

Comments
 (0)