Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ GitHub. The full reasoning and the measurements behind each change are in [ROADM
theme changes. The window opens in the theme's background, so a light theme does not flash
dark first.
- **Readability is tested, not assumed.**
- Every theme is checked against 128 contrast rules: 4.5:1 for text on every surface, button
- Every theme is checked against 143 contrast rules: 4.5:1 for text on every surface, button
text in the middle of the gradient, the code editors, focus rings and switch knobs at 3:1.
- Every rule in the panel's CSS that sets both a text colour and a background is measured in
every theme.
Expand Down Expand Up @@ -61,7 +61,12 @@ GitHub. The full reasoning and the measurements behind each change are in [ROADM
- A test checks every text in a cell, in every state, on white, black, grey and the six primary
and secondary colours. The self-test now measures clip cells too and reads `color-mix()`
backgrounds. Before, it skipped them and measured the text against the card underneath.
Only cells that show a scene preview are left out, because their text sits on a picture.
- In a cell that shows a scene preview or an image, the name, info line and countdown now sit on
their own card-coloured backing. The preview stays visible around them. On a white scene
the text used to fall below 3:1, and the info line was drawn underneath the preview.
- **The selected scene's info line** was 3.9:1 in Light and 4.1–4.4:1
in Midnight and CaYaDev. On the selected row's accent tint it now uses the secondary text
colour, and the contrast rules cover body and secondary text on selected rows.
- **Two labels were unreadable in every theme.** The empty side of the A/B crossfader and the
"built-in" tag in Studio's list were dimmed with opacity to 2.9:1 and 3.7:1. They now use the
secondary text colour. The decorative "·" separators in status lines are hidden from screen
Expand Down
6 changes: 4 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -3607,14 +3607,16 @@ The panel had one look. It now has seven themes and Device default, chosen under
- A slot with no source was faded with opacity, which brought its name to 3.3:1.
- The tint is now 10% (12% on hover), the countdowns use `--warn-text`, and the sourceless slot is dimmed with colour instead of opacity.
- A test measures every text in a cell, in every state, against nine extreme slot colours, and forbids opacity on the cell.
- The self-test also read `color-mix()` backgrounds (`color(srgb …)`) as nothing and measured the text against the card underneath. It now parses them and measures clip cells. Only cells with a scene preview are skipped.
- The self-test also read `color-mix()` backgrounds (`color(srgb …)`) as nothing and measured the text against the card underneath. It now parses them and measures every clip cell.
- A cell with a scene preview or an image puts its texts on their own `--card` backing. On a white scene the text was below 3:1, and `.cd-meta` was not positioned, so the preview was drawn over it.
- **Profile with content.** Running the audit through every category with scenes, preview cells, a lyric file and open folds found the selected scene's info line (`--muted2` on `accent-soft`) at 3.90:1 in Light. The self-test missed it because it loads its own settings with no saved scenes. That row now uses `--muted`, and the rules cover `--text` and `--muted` on `--accent-rgb .16`. After the fix, every category in every theme measured 2,966–3,005 texts, none below the threshold.
- **Tests that fail on misuse.**
- Every theme defines exactly the token set.
- `:root` equals the CaYaDev table.
- No colour literal outside `:root`.
- Every `var()` is defined, and channel tokens are used only as channels.
- Panel scripts carry no colour outside the content list, and the list cannot go stale.
- 128 contrast rules per theme.
- 143 contrast rules per theme.
- Every CSS rule with both a text colour and a background is measured in every theme. This caught the "Live" pill in Light and Sepia at 4.17:1.
- The head script was tested in a fake DOM.
- **Self-test.** Every theme is picked from the panel's own picker, every category is scrolled through, and the colour Chromium draws for each visible text is measured against its composited background.
Expand Down
16 changes: 15 additions & 1 deletion src/admin/admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,8 @@ video.logo-lib-thumb { pointer-events: none; }
}
.scene-name:focus { background: var(--card); border-bottom: 1px solid var(--accent); }
.scene-meta { font-size: 9.5px; color: var(--muted2); padding-left: 3px; }
/* Seçili satırın vurgu zemininde --muted2 Aydınlık'ta 3.9:1'e iniyordu (#770) */
.scene-item.active .scene-meta { color: var(--muted); }
.scene-acts { display: flex; gap: 4px; flex-shrink: 0; }
.scene-toolbar { display: flex; gap: 6px; margin-top: 10px; flex-shrink: 0; }
.scene-toolbar .btn { flex: 1; }
Expand Down Expand Up @@ -1445,9 +1447,21 @@ input[type=color].tl-swatch.big { width: 34px; height: 24px; }
.cd-thumb, .perf-thumb {
position: absolute; inset: 0; opacity: .40; pointer-events: none; border-radius: inherit;
}
.cd-name, .perf-name { position: relative; z-index: 1; }
.cd-name, .cd-meta, .perf-name { position: relative; z-index: 1; }
.cd-count, .perf-count { z-index: 2; }
.perf-cell.filled .perf-thumb { opacity: .32; }
/* Önizleme kullanıcının sahne rengi ya da görseli: beyaz bir sahnede yazı
3:1'in altına iniyordu. Önizlemeli hücrede yazılar kendi kart zeminiyle
durur; önizleme etraflarında görünmeye devam eder (#770). */
.cd-cell:has(> .cd-thumb) > .cd-name,
.cd-cell:has(> .cd-thumb) > .cd-meta,
.cd-cell:has(> .cd-thumb) > .cd-count:not(:empty),
.perf-cell:has(> .perf-thumb) > .perf-name,
.perf-cell:has(> .perf-thumb) > .perf-count:not(:empty) {
background: var(--card); border-radius: 4px; padding: 0 4px;
}
.cd-cell:has(> .cd-thumb) > .cd-name,
.cd-cell:has(> .cd-thumb) > .cd-meta { align-self: flex-start; max-width: 100%; }

/* Çakışma uyarısı — engellemiyoruz ama görünür olmalı. */
.settings-io-note.warn { color: var(--warn-text); border-left: 2px solid var(--warn); padding-left: 8px; }
Expand Down
8 changes: 4 additions & 4 deletions src/shared/ui-contrast-audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@
const SKIP = [
'.preview-stage', '.studio-preview', '.md-thumb-box', '.logo-lib-thumb', '.img-thumb',
'.scene-thumb', '.layer-preview', '.md-cell .md-fav', '.preset', '.up-swatch',
/* Klip hücreleri ölçülür (zemin kullanıcının rengiyle boyalı ama oran
her renkte yetecek kadar düşük); yalnız sahne önizlemesi taşıyanlar
görüntü üstünde sayılır. */
'.tpl-swatch', '.tl-swatch', '.cd-cell:has(> .cd-thumb)', '.perf-cell:has(> .perf-thumb)', '[aria-hidden="true"]',
/* Klip hücreleri ölçülür: zemin kullanıcının rengiyle boyalı ama oran
her renkte yetecek kadar düşük; önizlemeli hücrede yazılar kendi kart
zeminiyle duruyor. */
'.tpl-swatch', '.tl-swatch', '[aria-hidden="true"]',
'.ui-theme-preview',
].join(',');

Expand Down
4 changes: 3 additions & 1 deletion src/shared/ui-theme-contrast.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@
['--ok-text', '--ok-rgb', 0.14], ['--warn-text', '--warn-rgb', 0.16],
['--danger-text', '--danger-rgb', 0.14], ['--danger-text', '--danger-rgb', 0.22],
['--ok', '--ok-rgb', 0.14], ['--text-strong', '--accent-rgb', 0.3],
['--text', '--sel-rgb', 0.22], ['--text', '--fg-rgb', 0.08]].forEach(([fg, rgb, a]) => {
['--text', '--sel-rgb', 0.22], ['--text', '--fg-rgb', 0.08],
// Seçili satır (accent-soft, arama sonucu): gövde ve ikincil yazı. --muted2 burada yetmez
['--text', '--accent-rgb', 0.16], ['--muted', '--accent-rgb', 0.16]].forEach(([fg, rgb, a]) => {
['--bg2', '--card', '--card2'].forEach((base) => {
out.push({ fg, on: { tint: rgb, alpha: a, base }, min: 'text', why: fg + ' / ' + rgb + ' ' + a + ' / ' + base });
});
Expand Down
16 changes: 16 additions & 0 deletions tests/ui-themes.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,15 @@ test('klip hücreleri: içindeki yazılar her yuva renginde ve her durumda okunu
{ bg: ['.perf-cell.armed'], fg: ['.perf-cell.filled', '.perf-count'] },
{ bg: ['.perf-cell.active'], fg: ['.perf-cell.active', '.perf-count'] },
{ bg: ['.cd-cell.filled.noref'], fg: ['.cd-cell.filled.noref', '.cd-meta', '.cd-count'] },
// Önizlemeli hücre: yazı sahnenin resminin değil kendi zemininin üstünde
{
bg: ['.cd-cell:has(> .cd-thumb) > .cd-name', '.cd-cell:has(> .cd-thumb) > .cd-meta', '.cd-cell:has(> .cd-thumb) > .cd-count:not(:empty)'],
fg: ['.cd-cell.filled', '.cd-meta', '.cd-count'],
},
{
bg: ['.perf-cell:has(> .perf-thumb) > .perf-name', '.perf-cell:has(> .perf-thumb) > .perf-count:not(:empty)'],
fg: ['.perf-cell.filled', '.perf-cell.active', '.perf-count'],
},
];
const fails = [];
let checked = 0;
Expand All @@ -231,6 +240,13 @@ test('klip hücreleri: içindeki yazılar her yuva renginde ve her durumda okunu
// Soluk gösterim opaklıkla değil renkle: opaklık yazıyı da soldurur
rules.filter((r) => r.sel.split(',').some((x) => /\.(cd|perf)-cell[\w.:-]*$/.test(x.trim())) && r.decls.some((d) => d.prop === 'opacity'))
.forEach((r) => fails.push(r.sel + ' { opacity }'));
/* Önizleme konumlu ve yazıların üstüne çizilir: yazı konumlu değilse
önizlemenin altında kalır (.cd-meta öyleydi). */
['.cd-name', '.cd-meta', '.perf-name'].forEach((sel) => {
if (prop(sel, 'position') !== 'relative') fails.push(sel + ' önizlemenin altında kalıyor');
});
// Tarama önizlemeli hücreleri artık atlamıyor
assert.doesNotMatch(read('src/shared/ui-contrast-audit.js'), /(cd|perf)-(thumb|cell)/);
assert.deepStrictEqual(fails, []);
});

Expand Down
Loading