diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 6eed5d3..1c50425 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -27,3 +27,4 @@ jobs: - run: pnpm test - run: pnpm build - run: pnpm check:size + - run: pnpm check:colors diff --git a/web/package.json b/web/package.json index be54783..3ad401b 100644 --- a/web/package.json +++ b/web/package.json @@ -14,6 +14,7 @@ "lint": "eslint .", "gen:api": "openapi-typescript http://localhost:8080/api-docs/openapi.json -o src/api/schema.d.ts", "check:size": "node scripts/check-bundle-size.mjs", + "check:colors": "node scripts/check-no-raw-colors.mjs", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build" }, diff --git a/web/scripts/check-no-raw-colors.mjs b/web/scripts/check-no-raw-colors.mjs new file mode 100644 index 0000000..e2bc9d6 --- /dev/null +++ b/web/scripts/check-no-raw-colors.mjs @@ -0,0 +1,42 @@ +// Fails if any raw Tailwind color utility appears outside src/components/ui/. +import { readdirSync, readFileSync } from "node:fs"; +import { join, relative } from "node:path"; + +const root = "src"; +const excludeDir = join("src", "components", "ui"); +const RAW_COLOR = + /(?:text|bg|border|ring|fill|stroke|from|to|via|decoration|outline|divide|placeholder)-(?:neutral|gray|slate|zinc|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950)\b/; + +function walk(dir) { + const files = []; + for (const entry of readdirSync(dir, { withFileTypes: true })) { + const path = join(dir, entry.name); + if (entry.isDirectory()) { + if (path === excludeDir) continue; + files.push(...walk(path)); + } else if (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) { + files.push(path); + } + } + return files; +} + +const files = walk(root); +const offenses = []; +for (const file of files) { + const lines = readFileSync(file, "utf8").split("\n"); + for (let i = 0; i < lines.length; i++) { + const match = RAW_COLOR.exec(lines[i]); + if (match) offenses.push(`${relative(".", file)}:${i + 1}: ${match[0]}`); + } +} + +if (offenses.length > 0) { + console.error( + `raw color utilities found outside components/ui/ (${offenses.length}):`, + ); + for (const offense of offenses) console.error(` ${offense}`); + process.exit(1); +} + +console.log(`no raw color utilities outside components/ui/ (${files.length} files scanned)`); diff --git a/web/src/app.tsx b/web/src/app.tsx index 54205c4..a5e58a9 100644 --- a/web/src/app.tsx +++ b/web/src/app.tsx @@ -26,7 +26,7 @@ const FieldsPage = lazy(() => ); function FormFallback() { - return
Loading…
; + return
Loading…
; } export function App() { diff --git a/web/src/auth/login-page.tsx b/web/src/auth/login-page.tsx index 32b9e18..6009685 100644 --- a/web/src/auth/login-page.tsx +++ b/web/src/auth/login-page.tsx @@ -53,7 +53,7 @@ export function LoginPage() { /> {errorKey && ( -

+

{t(errorKey)}

)} diff --git a/web/src/authorities/authorities-page.tsx b/web/src/authorities/authorities-page.tsx index 676f92c..b0696af 100644 --- a/web/src/authorities/authorities-page.tsx +++ b/web/src/authorities/authorities-page.tsx @@ -53,7 +53,7 @@ export function AuthoritiesPage() { role="tab" aria-selected={k === currentKind} className={({ isActive }) => - `rounded px-3 py-1 text-sm ${isActive ? "bg-neutral-800 text-white" : "border"}` + `rounded-md px-3 py-1 text-sm ${isActive ? "bg-primary text-primary-foreground" : "border"}` } > {t(`authorities.${k}`)} @@ -63,13 +63,13 @@ export function AuthoritiesPage() {