Skip to content

Commit 36b3408

Browse files
committed
Tooling/CSS: Enforce design tokens via Stylelint
- Ban `!important`, `cursor: pointer`, raw color functions (`rgba`/`rgb`/`hsl`/`hsla`), and hex colors in component files - Restrict `font-weight` to 400/500/600 and `opacity` to an approved set - Add `stylelint-declaration-block-no-ignored-properties` plugin to catch ineffective CSS - Migrate ~26 inline `rgba()` calls to `color-mix()` or new tokens (`--color-overlay`, `--color-tint-hover`, `--shadow-focus-contrast`, etc.) - Deduplicate `@keyframes spin` from 6 components (global definition in `app.css` suffices) - Fix pre-existing violations: `font-weight: bold` → `600`, `font-weight: 300` → `400`, `opacity: 0.85` → `0.8`
1 parent 777f9ec commit 36b3408

27 files changed

Lines changed: 94 additions & 121 deletions

apps/desktop/.stylelintrc.mjs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,20 @@ const __dirname = dirname(__filename)
66

77
export default {
88
extends: ['stylelint-config-standard'],
9-
plugins: ['stylelint-value-no-unknown-custom-properties'],
9+
plugins: ['stylelint-value-no-unknown-custom-properties', 'stylelint-declaration-block-no-ignored-properties'],
1010
customSyntax: 'postcss-html',
11+
overrides: [
12+
{
13+
files: ['**/app.css'],
14+
rules: {
15+
'color-no-hex': null,
16+
'function-disallowed-list': null,
17+
},
18+
},
19+
],
1120
rules: {
21+
'color-no-hex': true,
22+
'function-disallowed-list': ['rgba', 'rgb', 'hsl', 'hsla'],
1223
'csstools/value-no-unknown-custom-properties': [
1324
true,
1425
{
@@ -24,6 +35,12 @@ export default {
2435
'border-radius': ['/\\dpx/'],
2536
'z-index': ['/^\\d{2,}/'],
2637
'font-family': ['/^(?!var\\(|inherit|unset|initial)/'],
38+
cursor: ['pointer'],
39+
},
40+
'declaration-no-important': true,
41+
'declaration-property-value-allowed-list': {
42+
'font-weight': ['400', '500', '600', 'normal', 'inherit'],
43+
opacity: ['/^(0|0\\.3|0\\.4|0\\.5|0\\.6|0\\.7|0\\.8|1|inherit)$/'],
2744
},
2845
'custom-property-pattern': '^(color|spacing|font|radius|shadow|transition|z)-.+',
2946
'declaration-block-no-duplicate-custom-properties': true,
@@ -38,6 +55,7 @@ export default {
3855
'font-family-no-duplicate-names': null,
3956
'declaration-property-value-keyword-no-deprecated': null,
4057
'declaration-block-no-redundant-longhand-properties': null,
58+
'plugin/declaration-block-no-ignored-properties': true,
4159
'comment-empty-line-before': null,
4260
'color-function-alias-notation': null,
4361
'keyframes-name-pattern': null,

apps/desktop/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
"prettier-plugin-svelte": "^3.5.1",
7979
"stylelint": "^16.26.1",
8080
"stylelint-config-standard": "^39.0.1",
81+
"stylelint-declaration-block-no-ignored-properties": "2.8.0",
8182
"stylelint-value-no-unknown-custom-properties": "^6.1.1",
8283
"svelte": "^5.53.7",
8384
"svelte-check": "^4.4.4",

apps/desktop/src/app.css

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
--color-accent-hover: color-mix(in oklch, var(--color-accent), white 15%);
4949
--color-accent-subtle: color-mix(in oklch, var(--color-accent), transparent 85%);
5050
--color-cmdr-gold: #d4a006;
51+
--color-cmdr-blue: #4a9eff;
52+
--color-cmdr-purple: #7c3aed;
5153
--color-system-accent: #d4a006; /* Updated at runtime by accent-color.ts */
5254

5355
/* === Cursor (row highlight in file lists) === */
@@ -80,6 +82,19 @@
8082
/* === Selection === */
8183
--color-selection-fg: #c9a227;
8284

85+
/* === Overlays === */
86+
--color-overlay: color-mix(in srgb, black, transparent 50%);
87+
--color-overlay-light: color-mix(in srgb, black, transparent 60%);
88+
--color-overlay-heavy: color-mix(in srgb, black, transparent 40%);
89+
--color-drag-overlay-bg: #1e1e1e;
90+
91+
/* === Hover tints (subtle background shifts for interactive items) === */
92+
--color-tint-hover: color-mix(in srgb, black, transparent 96%);
93+
--color-tint-hover-strong: color-mix(in srgb, black, transparent 85%);
94+
95+
/* === Focus ring shadow === */
96+
--shadow-focus-contrast: 0 0 0 4px color-mix(in srgb, black, transparent 90%);
97+
8398
/* === Search Highlight === */
8499
--color-highlight: rgba(255, 213, 0, 0.4);
85100
--color-highlight-active: rgba(255, 150, 50, 0.6);
@@ -199,6 +214,18 @@
199214
--color-toast-success-stripe: #22c55e;
200215
--color-toast-success-bg: color-mix(in srgb, #22c55e 8%, var(--color-bg-secondary));
201216

217+
/* === Overlays === */
218+
--color-overlay: color-mix(in srgb, black, transparent 50%);
219+
--color-overlay-light: color-mix(in srgb, black, transparent 60%);
220+
--color-overlay-heavy: color-mix(in srgb, black, transparent 40%);
221+
222+
/* === Hover tints === */
223+
--color-tint-hover: color-mix(in srgb, white, transparent 94%);
224+
--color-tint-hover-strong: color-mix(in srgb, white, transparent 75%);
225+
226+
/* === Focus ring shadow === */
227+
--shadow-focus-contrast: 0 0 0 4px color-mix(in srgb, white, transparent 92%);
228+
202229
/* === Selection === */
203230
--color-selection-fg: #d4a82a;
204231

apps/desktop/src/lib/command-palette/CommandPalette.svelte

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@
200200
.palette-overlay {
201201
position: fixed;
202202
inset: 0;
203-
background: rgba(0, 0, 0, 0.5);
203+
background: var(--color-overlay);
204204
backdrop-filter: blur(2px);
205205
display: flex;
206206
justify-content: center;
@@ -258,7 +258,7 @@
258258
259259
/* Hover state - just a subtle overlay */
260260
.result-item.is-hovered {
261-
background: rgba(255, 255, 255, 0.06);
261+
background: var(--color-tint-hover);
262262
}
263263
264264
/* Cursor state - accent-tinted highlight */
@@ -279,7 +279,7 @@
279279
280280
/* Match highlight - macOS Spotlight-style with visible background */
281281
.match-highlight {
282-
background: rgba(255, 255, 255, 0.25);
282+
background: var(--color-tint-hover-strong);
283283
color: inherit;
284284
border-radius: var(--radius-sm);
285285
/* stylelint-disable-next-line declaration-property-value-disallowed-list */
@@ -290,7 +290,7 @@
290290
291291
/* When item is under cursor, make the match highlight even more visible */
292292
.result-item.is-under-cursor .match-highlight {
293-
background: rgba(255, 255, 255, 0.35);
293+
background: color-mix(in srgb, white, transparent 65%);
294294
}
295295
296296
.shortcuts {
@@ -300,18 +300,5 @@
300300
flex-shrink: 0;
301301
}
302302
303-
/* Support light mode */
304-
@media (prefers-color-scheme: light) {
305-
.result-item.is-hovered {
306-
background: rgba(0, 0, 0, 0.04);
307-
}
308-
309-
.match-highlight {
310-
background: rgba(0, 0, 0, 0.15);
311-
}
312-
313-
.result-item.is-under-cursor .match-highlight {
314-
background: rgba(255, 255, 255, 0.4);
315-
}
316-
}
303+
/* Light mode overrides handled by design tokens (--color-tint-hover, --color-tint-hover-strong) */
317304
</style>

apps/desktop/src/lib/file-explorer/drag/DragOverlay.svelte

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@
6262
max-width: 320px;
6363
padding: var(--spacing-md) var(--spacing-md);
6464
border-radius: var(--radius-lg);
65-
background: rgba(30, 30, 30, 0.9);
66-
color: rgba(255, 255, 255, 0.92);
65+
background: color-mix(in srgb, var(--color-drag-overlay-bg), transparent 10%);
66+
color: color-mix(in srgb, white, transparent 8%);
6767
font-family: var(--font-system), sans-serif;
6868
font-size: var(--font-size-xs);
6969
line-height: 1.5;
@@ -115,19 +115,19 @@
115115
}
116116
117117
.is-summary {
118-
color: rgba(255, 255, 255, 0.55);
118+
color: color-mix(in srgb, white, transparent 45%);
119119
font-style: italic;
120120
}
121121
122122
.action-line {
123123
margin-top: var(--spacing-sm);
124124
padding-top: var(--spacing-sm);
125-
border-top: 1px solid rgba(255, 255, 255, 0.15);
125+
border-top: 1px solid color-mix(in srgb, white, transparent 85%);
126126
font-weight: 500;
127127
color: var(--color-accent);
128128
}
129129
130130
.action-line.is-warning {
131-
color: rgba(255, 255, 255, 0.4);
131+
color: color-mix(in srgb, white, transparent 60%);
132132
}
133133
</style>

apps/desktop/src/lib/file-explorer/navigation/VolumeBreadcrumb.svelte

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -772,15 +772,6 @@
772772
animation: spin 0.8s linear infinite;
773773
}
774774
775-
@keyframes spin {
776-
from {
777-
transform: rotate(0deg);
778-
}
779-
to {
780-
transform: rotate(360deg);
781-
}
782-
}
783-
784775
/*noinspection CssUnusedSymbol*/
785776
.timeout-warning-row.retry-failed {
786777
animation: flash-warning 0.3s ease;

apps/desktop/src/lib/file-explorer/network/NetworkLoginForm.svelte

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -300,14 +300,12 @@
300300
align-items: center;
301301
gap: var(--spacing-sm);
302302
padding: var(--spacing-sm) 0;
303-
cursor: pointer;
304303
}
305304
306305
.radio-option input[type='radio'] {
307306
width: 16px;
308307
height: 16px;
309308
accent-color: var(--color-accent);
310-
cursor: pointer;
311309
}
312310
313311
.radio-label {
@@ -369,14 +367,12 @@
369367
align-items: center;
370368
gap: var(--spacing-sm);
371369
padding: var(--spacing-sm) 0;
372-
cursor: pointer;
373370
}
374371
375372
.checkbox-option input[type='checkbox'] {
376373
width: 16px;
377374
height: 16px;
378375
accent-color: var(--color-accent);
379-
cursor: pointer;
380376
}
381377
382378
.checkbox-label {
@@ -400,18 +396,12 @@
400396
.spinner {
401397
width: 14px;
402398
height: 14px;
403-
border: 2px solid rgba(255, 255, 255, 0.3);
399+
border: 2px solid color-mix(in srgb, white, transparent 70%);
404400
border-top-color: white;
405401
border-radius: var(--radius-full);
406402
animation: spin 0.8s linear infinite;
407403
}
408404
409-
@keyframes spin {
410-
to {
411-
transform: rotate(360deg);
412-
}
413-
}
414-
415405
/* Screen reader only */
416406
.sr-only {
417407
position: absolute;

apps/desktop/src/lib/file-explorer/network/ShareBrowser.svelte

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,6 @@
556556
background: none;
557557
border: 1px solid transparent;
558558
border-radius: var(--radius-sm);
559-
cursor: pointer;
560559
}
561560
562561
.forget-password-btn:hover {

apps/desktop/src/lib/file-explorer/tabs/TabBar.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@
210210
/* stylelint-disable-next-line declaration-property-value-disallowed-list */
211211
margin-bottom: -1px;
212212
z-index: 1;
213-
box-shadow: 0 0 4px rgba(0, 0, 0, 0.04);
213+
box-shadow: 0 0 4px color-mix(in srgb, black, transparent 96%);
214214
}
215215
216216
/* Accent top border on active tab */
@@ -229,7 +229,7 @@
229229
@media (prefers-color-scheme: dark) {
230230
.tab.active {
231231
background-color: color-mix(in oklch, var(--color-bg-primary), var(--color-accent) 7%);
232-
box-shadow: 0 0 4px rgba(0, 0, 0, 0.15);
232+
box-shadow: 0 0 4px color-mix(in srgb, black, transparent 85%);
233233
}
234234
}
235235
@@ -329,7 +329,7 @@
329329
background: none;
330330
color: var(--color-text-tertiary);
331331
font-size: var(--font-size-sm);
332-
font-weight: 300;
332+
font-weight: 400;
333333
cursor: default;
334334
transition:
335335
background-color var(--transition-fast),

apps/desktop/src/lib/file-operations/delete/DeleteDialog.svelte

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -439,16 +439,10 @@
439439
margin-left: var(--spacing-xs);
440440
}
441441
442-
@keyframes spin {
443-
to {
444-
transform: rotate(360deg);
445-
}
446-
}
447-
448442
.scan-checkmark {
449443
color: var(--color-allow);
450444
font-size: var(--font-size-md);
451-
font-weight: bold;
445+
font-weight: 600;
452446
margin-left: var(--spacing-xs);
453447
}
454448

0 commit comments

Comments
 (0)