From af1c35e66fd79e3f6cb210023a069b81192ab10a Mon Sep 17 00:00:00 2001 From: Xaxis Date: Mon, 25 May 2026 09:56:52 -0800 Subject: [PATCH] feat(design): add Badge `brand` variant (0.5.0) oc-vote-web uses (brand-soft tinted badge). Adding it as a canonical Badge variant (bg-brand-soft text-brand border-brand-soft, all existing --brand utilities) so vote converges without losing its brand badge. Story updated. Co-Authored-By: Claude Opus 4.7 (1M context) --- design/package.json | 2 +- design/scripts/verify-live-ui.mjs | 46 +++++++++++++++++++++++++ design/scripts/verify-stamp.mjs | 2 +- design/src/primitives/badge.stories.tsx | 1 + design/src/primitives/badge.tsx | 1 + 5 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 design/scripts/verify-live-ui.mjs diff --git a/design/package.json b/design/package.json index d5a746f..e625c81 100644 --- a/design/package.json +++ b/design/package.json @@ -1,6 +1,6 @@ { "name": "@orangecheck/design", - "version": "0.4.0", + "version": "0.5.0", "description": "OrangeCheck design system — multi-theme tokens, primitives, and family composites for the .ochk.io sub-sites. Tailwind 4 + Next.js Pages Router. Not for third-party integration.", "keywords": [ "orangecheck", diff --git a/design/scripts/verify-live-ui.mjs b/design/scripts/verify-live-ui.mjs new file mode 100644 index 0000000..708e24d --- /dev/null +++ b/design/scripts/verify-live-ui.mjs @@ -0,0 +1,46 @@ +/* Honest live-UI check: does the deployed site actually render OcAppearanceMenu + * and does clicking a theme switch + persist it? Catches "tokens work but the + * control is missing/crashing" — which token-parity checks miss. + * Usage: SITES="https://a,https://b" node scripts/verify-live-ui.mjs */ +import { chromium } from '@playwright/test'; + +const SITES = (process.env.SITES || '').split(',').map((s) => s.trim()).filter(Boolean); +const browser = await chromium.launch(); + +for (const url of SITES) { + const page = await browser.newPage({ viewport: { width: 1280, height: 900 } }); + const errors = []; + page.on('console', (m) => m.type() === 'error' && errors.push(m.text())); + page.on('pageerror', (e) => errors.push('PAGEERROR: ' + e.message)); + const out = { url, menu: false, opened: false, switched: false, persisted: false, errors: [] }; + try { + await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 45000 }); + await page.waitForTimeout(2500); + const trigger = page.locator('button[aria-label="appearance settings"]'); + out.menu = (await trigger.count()) > 0; + if (out.menu) { + await trigger.first().click(); + await page.waitForTimeout(300); + const goldItem = page.locator('[role="menuitemradio"]', { hasText: 'gold' }); + out.opened = (await page.locator('[role="menu"]').count()) > 0 && (await goldItem.count()) > 0; + if (out.opened) { + await goldItem.first().click(); + await page.waitForTimeout(400); + out.switched = + (await page.evaluate(() => document.documentElement.getAttribute('data-oc-theme'))) === + 'gold'; + out.persisted = await page.evaluate(() => /oc_skin=gold/.test(document.cookie)); + } + } + } catch (e) { + out.errors.push('NAV: ' + e.message); + } + out.errors.push(...errors.filter((e) => !/favicon|plausible|404|Failed to load resource|net::ERR/i.test(e))); + await page.close(); + const ok = out.menu && out.opened && out.switched && out.persisted && out.errors.length === 0; + console.log( + `${ok ? '✅' : '❌'} ${url} menu=${out.menu} open=${out.opened} switch=${out.switched} persist=${out.persisted}` + + (out.errors.length ? ` ERR: ${out.errors.slice(0, 2).join(' | ')}` : '') + ); +} +await browser.close(); diff --git a/design/scripts/verify-stamp.mjs b/design/scripts/verify-stamp.mjs index 3a049c3..4925d02 100644 --- a/design/scripts/verify-stamp.mjs +++ b/design/scripts/verify-stamp.mjs @@ -4,7 +4,7 @@ import { chromium } from '@playwright/test'; const LOCAL = process.env.LOCAL_URL || 'http://localhost:3100'; -const PROD = 'https://stamp.ochk.io'; +const PROD = process.env.PROD_URL || 'https://stamp.ochk.io'; const browser = await chromium.launch(); diff --git a/design/src/primitives/badge.stories.tsx b/design/src/primitives/badge.stories.tsx index 536f035..948954b 100644 --- a/design/src/primitives/badge.stories.tsx +++ b/design/src/primitives/badge.stories.tsx @@ -10,6 +10,7 @@ const VARIANTS = [ 'warning', 'success', 'info', + 'brand', ] as const; const meta = { diff --git a/design/src/primitives/badge.tsx b/design/src/primitives/badge.tsx index 5aeb33b..46a1d2d 100644 --- a/design/src/primitives/badge.tsx +++ b/design/src/primitives/badge.tsx @@ -22,6 +22,7 @@ const badgeVariants = cva( success: 'bg-success text-success-foreground [a&]:hover:bg-success/90 border-transparent', info: 'bg-info text-info-foreground [a&]:hover:bg-info/90 border-transparent', + brand: 'bg-brand-soft text-brand border-brand-soft', outline: 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground', }, },