openvibers/openvibe.deals Commits
The editors' pick band reads on light themes (WCAG AA) (#183)
Changes
@@@ -26,6 +26,9 @@.dl-band { padding: 2px 8px; border-radius: 999px; font-size: .7rem; font-weight: 800; letter-spacing: .02em; white-space: nowrap; }/* Half the hue, half the theme's text: it held on dark themes only (Daylight contrast probe, 2026-11-01). */.dl-band--pick { color: color-mix(in srgb, #f5b301 55%, var(--text-primary, #e8eef8)); background: color-mix(in srgb, #f5b301 16%, transparent); }++/* On light themes that mix lands on #926e15 (4.24:1 on the band). A deeper gold reads 5.7:1; dark themes keep the++ mix above, so their look is unchanged. */++[data-theme-mode="light"] .dl-band--pick { color: #7c5a0f; }.dl-band--popular { color: var(--accent-light, #60a5fa); background: color-mix(in srgb, var(--accent, #3b82f6) 16%, transparent); }.dl-band--new { color: var(--text-secondary, #96a7c2); background: color-mix(in srgb, var(--text-primary, #e8eef8) 7%, transparent); }@media (max-width: 600px) {@@@ -6,8 +6,20 @@* own line: active deals, prices seen in 24 hours, and an alert prefilled for it.*/const assert = require('assert');++const fs = require('fs');++const path = require('path');const { boot, check, done, HOUR } = require('./helpers/boot');++const css = fs.readFileSync(path.join(__dirname, '..', 'public', 'css', 'deal-cards.css'), 'utf8');++const lum = (hex) => [1, 3, 5]++ .map((i) => parseInt(hex.slice(i, i + 2), 16) / 255)++ .map((c) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4))++ .reduce((sum, c, i) => sum + [0.2126, 0.7152, 0.0722][i] * c, 0);++const ratio = (a, b) => {++ const [hi, lo] = [lum(a), lum(b)].sort((x, y) => y - x);++ return (hi + 0.05) / (lo + 0.05);++};++(async () => {const t = await boot();const [alice, bob, cara] = ['alice', 'bob', 'cara'].map((n) => t.network.addUser(n));@@@ -60,6 +72,13 @@ const { boot, check, done, HOUR } = require('./helpers/boot');assert.match(card((await t.get('/s/shop.example')).text, 'Desk lamp'), /dl-band--pick">Editors' pick|dl-band--pick">Editors' pick/);});++ await check('the pick band reads on light themes; dark themes keep the mix', async () => {++ assert.ok(css.includes('[data-theme-mode="light"] .dl-band--pick { color: #7c5a0f; }'), 'light themes use the deeper gold');++ assert.ok(css.includes('.dl-band--pick { color: color-mix(in srgb, #f5b301 55%, var(--text-primary, #e8eef8));'), 'dark themes keep the mix');++ const r = ratio('#7c5a0f', '#fdf3d6');++ assert.ok(r >= 4.5, `#7c5a0f on #fdf3d6 is ${r.toFixed(2)}:1`);++ });++await check('the shop: its line, its active deals, prices seen in 24 hours, an alert prefilled for it', async () => {const r = await t.get('/s/shop.example');assert.match(r.text, /<header class="dl-shop">/);
@@ -26,6 +26,9 @@
@@ -26,6 +26,9 @@
.dl-band { padding: 2px 8px; border-radius: 999px; font-size: .7rem; font-weight: 800; letter-spacing: .02em; white-space: nowrap; }
.dl-band { padding: 2px 8px; border-radius: 999px; font-size: .7rem; font-weight: 800; letter-spacing: .02em; white-space: nowrap; }
/* Half the hue, half the theme's text: it held on dark themes only (Daylight contrast probe, 2026-11-01). */
/* Half the hue, half the theme's text: it held on dark themes only (Daylight contrast probe, 2026-11-01). */
.dl-band--pick { color: color-mix(in srgb, #f5b301 55%, var(--text-primary, #e8eef8)); background: color-mix(in srgb, #f5b301 16%, transparent); }
.dl-band--pick { color: color-mix(in srgb, #f5b301 55%, var(--text-primary, #e8eef8)); background: color-mix(in srgb, #f5b301 16%, transparent); }
+/* On light themes that mix lands on #926e15 (4.24:1 on the band). A deeper gold reads 5.7:1; dark themes keep the
+ mix above, so their look is unchanged. */
+[data-theme-mode="light"] .dl-band--pick { color: #7c5a0f; }
.dl-band--popular { color: var(--accent-light, #60a5fa); background: color-mix(in srgb, var(--accent, #3b82f6) 16%, transparent); }
.dl-band--popular { color: var(--accent-light, #60a5fa); background: color-mix(in srgb, var(--accent, #3b82f6) 16%, transparent); }
.dl-band--new { color: var(--text-secondary, #96a7c2); background: color-mix(in srgb, var(--text-primary, #e8eef8) 7%, transparent); }
.dl-band--new { color: var(--text-secondary, #96a7c2); background: color-mix(in srgb, var(--text-primary, #e8eef8) 7%, transparent); }
@media (max-width: 600px) {
@media (max-width: 600px) {
@@ -6,8 +6,20 @@
@@ -6,8 +6,20 @@
* own line: active deals, prices seen in 24 hours, and an alert prefilled for it.
* own line: active deals, prices seen in 24 hours, and an alert prefilled for it.
*/
*/
const assert = require('assert');
const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
const { boot, check, done, HOUR } = require('./helpers/boot');
const { boot, check, done, HOUR } = require('./helpers/boot');
+const css = fs.readFileSync(path.join(__dirname, '..', 'public', 'css', 'deal-cards.css'), 'utf8');
+const lum = (hex) => [1, 3, 5]
+ .map((i) => parseInt(hex.slice(i, i + 2), 16) / 255)
+ .map((c) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4))
+ .reduce((sum, c, i) => sum + [0.2126, 0.7152, 0.0722][i] * c, 0);
+const ratio = (a, b) => {
+ const [hi, lo] = [lum(a), lum(b)].sort((x, y) => y - x);
+ return (hi + 0.05) / (lo + 0.05);
+};
+
(async () => {
(async () => {
const t = await boot();
const t = await boot();
const [alice, bob, cara] = ['alice', 'bob', 'cara'].map((n) => t.network.addUser(n));
const [alice, bob, cara] = ['alice', 'bob', 'cara'].map((n) => t.network.addUser(n));
@@ -60,6 +72,13 @@ const { boot, check, done, HOUR } = require('./helpers/boot');
@@ -60,6 +72,13 @@ const { boot, check, done, HOUR } = require('./helpers/boot');
assert.match(card((await t.get('/s/shop.example')).text, 'Desk lamp'), /dl-band--pick">Editors' pick|dl-band--pick">Editors' pick/);
assert.match(card((await t.get('/s/shop.example')).text, 'Desk lamp'), /dl-band--pick">Editors' pick|dl-band--pick">Editors' pick/);
});
});
+ await check('the pick band reads on light themes; dark themes keep the mix', async () => {
+ assert.ok(css.includes('[data-theme-mode="light"] .dl-band--pick { color: #7c5a0f; }'), 'light themes use the deeper gold');
+ assert.ok(css.includes('.dl-band--pick { color: color-mix(in srgb, #f5b301 55%, var(--text-primary, #e8eef8));'), 'dark themes keep the mix');
+ const r = ratio('#7c5a0f', '#fdf3d6');
+ assert.ok(r >= 4.5, `#7c5a0f on #fdf3d6 is ${r.toFixed(2)}:1`);
+ });
+
await check('the shop: its line, its active deals, prices seen in 24 hours, an alert prefilled for it', async () => {
await check('the shop: its line, its active deals, prices seen in 24 hours, an alert prefilled for it', async () => {
const r = await t.get('/s/shop.example');
const r = await t.get('/s/shop.example');
assert.match(r.text, /<header class="dl-shop">/);
assert.match(r.text, /<header class="dl-shop">/);