chore: scaffold Next.js 16 admin app with ITA ITO design tokens

Set up the project skeleton for the ITA ITO opening-hours display admin:
Next.js 16 (App Router) with TypeScript in strict mode, Tailwind CSS 4,
Vitest, ESLint and a blocking CI workflow.

The design tokens are copied verbatim from the model_ita_ito project
(palette, Inter Variable + Source Serif 4, radii, dark theme) so the two
applications look like one family, as required by the spec.

ESLint is pinned to v9: eslint-config-next bundles a react plugin that
crashes on ESLint 10. The typed `consistent-type-imports` rule is left
out because `verbatimModuleSyntax` already enforces the same discipline
at compile time, without the cost of typed linting across the repo.

PLAN.md records the agreed architecture, including the decisions that
depart from the original spec — most importantly the move from BYOD to
a self-hosted BYOS server, which removes the TRMNL private plugin, the
Liquid template and the webhook entirely.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012cSY9pVhZmJUKNN7wf1Myd
This commit is contained in:
2026-09-20 17:30:19 +02:00
co-authored by Claude Opus 5
commit a9809f83ca
19 changed files with 12272 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
@import '@fontsource-variable/inter';
@import '@fontsource-variable/source-serif-4';
@import 'tailwindcss';
@import './tokens.css';
/* Tokens are the single source of truth; Tailwind utilities read them from here. */
@theme inline {
--color-canvas: var(--canvas);
--color-surface: var(--surface);
--color-surface-muted: var(--surface-muted);
--color-line: var(--line);
--color-line-strong: var(--line-strong);
--color-ink: var(--ink);
--color-ink-muted: var(--ink-muted);
--color-accent: var(--accent);
--color-accent-hover: var(--accent-hover);
--color-accent-tint: var(--accent-tint);
--color-accent-ink: var(--accent-ink);
--color-on-accent: var(--on-accent);
--color-danger: var(--danger);
--color-danger-tint: var(--danger-tint);
--color-success: var(--success);
--color-success-tint: var(--success-tint);
--radius-sm: var(--radius-sm);
--radius-md: var(--radius-md);
--radius-lg: var(--radius-lg);
--font-sans: var(--font-sans);
--font-serif: var(--font-serif);
}
@layer base {
html {
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
min-height: 100dvh;
background: var(--canvas);
color: var(--ink);
font-family: var(--font-sans);
font-feature-settings: 'cv11', 'ss01';
line-height: 1.55;
-webkit-font-smoothing: antialiased;
}
h1,
h2,
h3 {
font-family: var(--font-serif);
font-weight: 500;
letter-spacing: -0.01em;
}
:focus-visible {
outline: 2px solid var(--focus-ring);
outline-offset: 2px;
}
}
+187
View File
@@ -0,0 +1,187 @@
/*
* Design tokens. Values inspired by a warm, calm palette; checked for WCAG AA:
* - ink on canvas 17.9:1, ink-muted on canvas 6.4:1
* - accent (#B5552F) with white text 4.9:1; dark accent (#D97757) on dark canvas 4.9:1
*/
:root {
--canvas: #faf9f5;
--surface: #ffffff;
--surface-muted: #f3f1ea;
--line: #e8e6dc;
--line-strong: #d6d3c7;
--ink: #141413;
--ink-muted: #5e5d59;
--accent: #b5552f;
--accent-hover: #9e4827;
--accent-soft: #c96442;
--accent-tint: #f6e7df;
/* Accent text on the tinted background: 5.1:1. */
--accent-ink: #983f1e;
--on-accent: #ffffff;
--danger: #b42318;
--danger-tint: #fdecea;
--success: #3f6b4b;
--success-tint: #e7f0e9;
--observation: #c8102e;
--focus-ring: #c96442;
--radius-sm: 6px;
--radius-md: 8px;
--radius-lg: 12px;
--font-sans: 'Inter Variable', 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
--font-serif: 'Source Serif 4 Variable', 'Source Serif 4', Georgia, 'Times New Roman', serif;
--safe-top: env(safe-area-inset-top, 0px);
--safe-bottom: env(safe-area-inset-bottom, 0px);
color-scheme: light;
}
:root[data-theme='dark'] {
--canvas: #262624;
--surface: #30302e;
--surface-muted: #2b2b29;
--line: #3e3e3a;
--line-strong: #52524d;
--ink: #f5f4ee;
--ink-muted: #b7b5a9;
--accent: #d97757;
--accent-hover: #e38b6e;
--accent-soft: #d97757;
--accent-tint: #3d2e27;
--accent-ink: #f0b8a0;
--on-accent: #1a1a18;
--danger: #f08a7e;
--danger-tint: #3f2724;
--success: #8fbf9a;
--success-tint: #26352a;
--observation: #ff6b6b;
--focus-ring: #d97757;
color-scheme: dark;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme='light']) {
--canvas: #262624;
--surface: #30302e;
--surface-muted: #2b2b29;
--line: #3e3e3a;
--line-strong: #52524d;
--ink: #f5f4ee;
--ink-muted: #b7b5a9;
--accent: #d97757;
--accent-hover: #e38b6e;
--accent-soft: #d97757;
--accent-tint: #3d2e27;
--accent-ink: #f0b8a0;
--on-accent: #1a1a18;
--danger: #f08a7e;
--danger-tint: #3f2724;
--success: #8fbf9a;
--success-tint: #26352a;
--observation: #ff6b6b;
--focus-ring: #d97757;
color-scheme: dark;
}
}
/* Status / badge tones: soft backgrounds, text ≥ 4.5:1 on its background in both themes. */
:root {
--tone-neutral-bg: #efede6;
--tone-neutral-fg: #4a4944;
--tone-accent-bg: #f6e7df;
--tone-accent-fg: #8f3f20;
--tone-sand-bg: #f1eadb;
--tone-sand-fg: #6b5a36;
--tone-ochre-bg: #f3e6c8;
--tone-ochre-fg: #6f5310;
--tone-amber-bg: #f6e2c7;
--tone-amber-fg: #7a4a0e;
--tone-terracotta-bg: #f4ddd3;
--tone-terracotta-fg: #8a3a1d;
--tone-plum-bg: #ece0ea;
--tone-plum-fg: #6a3b61;
--tone-slate-bg: #e1e7ee;
--tone-slate-fg: #3b5068;
--tone-sage-bg: #e2ebdf;
--tone-sage-fg: #3d5a37;
--tone-olive-bg: #e8e8d3;
--tone-olive-fg: #555522;
--tone-gray-bg: #e8e7e3;
--tone-gray-fg: #54534e;
/* Grid ("hoja de pedidos") in the application look. */
--grid-header-bg: #efece2;
--grid-line: #ddd8ca;
--grid-block-line: #b9b3a2;
--grid-no-bg: #f3f1ea;
--grid-active: #c96442;
--grid-selection-bg: #f6e7df;
--tabbar-height: 0px;
}
:root[data-theme='dark'] {
--tone-neutral-bg: #3a3a37;
--tone-neutral-fg: #dedcd2;
--tone-accent-bg: #4a3128;
--tone-accent-fg: #f0b8a0;
--tone-sand-bg: #413a2c;
--tone-sand-fg: #e6d6b0;
--tone-ochre-bg: #443a22;
--tone-ochre-fg: #ecd18f;
--tone-amber-bg: #45351f;
--tone-amber-fg: #f0c48c;
--tone-terracotta-bg: #4a3027;
--tone-terracotta-fg: #f1b59c;
--tone-plum-bg: #40303e;
--tone-plum-fg: #e5bfdd;
--tone-slate-bg: #2f3945;
--tone-slate-fg: #bdd0e6;
--tone-sage-bg: #2f3b2d;
--tone-sage-fg: #c1dcb9;
--tone-olive-bg: #393a26;
--tone-olive-fg: #dcdca6;
--tone-gray-bg: #3a3a38;
--tone-gray-fg: #d6d4cc;
--grid-header-bg: #34342f;
--grid-line: #45443f;
--grid-block-line: #67655d;
--grid-no-bg: #2d2d2b;
--grid-active: #d97757;
--grid-selection-bg: #3d2e27;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme='light']) {
--tone-neutral-bg: #3a3a37;
--tone-neutral-fg: #dedcd2;
--tone-accent-bg: #4a3128;
--tone-accent-fg: #f0b8a0;
--tone-sand-bg: #413a2c;
--tone-sand-fg: #e6d6b0;
--tone-ochre-bg: #443a22;
--tone-ochre-fg: #ecd18f;
--tone-amber-bg: #45351f;
--tone-amber-fg: #f0c48c;
--tone-terracotta-bg: #4a3027;
--tone-terracotta-fg: #f1b59c;
--tone-plum-bg: #40303e;
--tone-plum-fg: #e5bfdd;
--tone-slate-bg: #2f3945;
--tone-slate-fg: #bdd0e6;
--tone-sage-bg: #2f3b2d;
--tone-sage-fg: #c1dcb9;
--tone-olive-bg: #393a26;
--tone-olive-fg: #dcdca6;
--tone-gray-bg: #3a3a38;
--tone-gray-fg: #d6d4cc;
--grid-header-bg: #34342f;
--grid-line: #45443f;
--grid-block-line: #67655d;
--grid-no-bg: #2d2d2b;
--grid-active: #d97757;
--grid-selection-bg: #3d2e27;
}
}