Workshop Kit · widget reference

Shipped

palette-picker

A three-swatch palette picker — accent, background (cream), ink — with curated starting palettes by cuisine and a live WCAG contrast guard. Writes to palette[] in MuntinContext; every other widget that subscribes (the live-preview rail, the L14 generator) repaints the operator's site in the new colors instantly.

Live demo

Three native color inputs side-by-side. Pick a suggested palette to start, then nudge any individual swatch. The contrast indicator below the pickers updates live with the accent-on-cream ratio (the most-visible text contrast in the operator's generated site). Save persists across reloads.

data-context-key="palette" (always — reads restaurantProfile.cuisine for the starting suggestions)

Current MuntinContext.palette (the three hex values in order) Pick a palette above…

Contract

The widget needs no data attributes beyond data-widget. It always writes to palette[] (positionally: index 0 = accent, 1 = cream, 2 = ink), and reads restaurantProfile.cuisine for the starting suggestions.

Attribute / behaviorNotes
data-widgetRequired Always "palette-picker".
Reads MuntinContext.restaurantProfile.cuisine If present, the cuisine string (case-insensitive substring match: "mexican", "italian", "japanese", "mediterranean", etc.) selects a curated set of three starting palettes appropriate to that cuisine. If absent or no match, a neutral fallback set ships.
Writes MuntinContext.palette An array of three uppercase #RRGGBB strings — [accent, cream, ink] — written on every change (debounced). Empty/invalid hex never reaches storage; the widget's color inputs are native <input type="color"> elements which only emit valid hex.
Live WCAG contrast guard Recomputes the WCAG 2.2 contrast ratio of accent ↔ cream on every change. Three severity tiers: ok (≥4.5), warn (3.0–4.5), fail (<3.0). The indicator below the pickers shows the ratio and tier in plain language.

Markup

<section class="course-widget" data-widget="palette-picker"></section>

That's the whole call site. The cuisine-aware suggestion logic, the three color inputs, the contrast guard, and the polite-region announcements all live in the widget renderer; the lesson author just drops the empty section into the page.

Why three swatches, not five

A common mistake in restaurant branding is treating the website like a brand kit — primary, secondary, tertiary, accent-1, accent-2. That's how brand consultants charge $8,000 for a logo lockup. For the operator who's actually shipping a site this week, three colors do the job: one accent for the CTA + brand chrome, one background, one ink. The L14 generator interpolates those three into the inline CSS of every generated page; no palette beyond the three ever needs to exist.

The contrast guard exists because operators consistently pick accent/cream pairs that look great in the picker (saturated coral on warm beige) but fail at body text. The widget catches this in the design moment, not after deploy.

Where it ships

Every subsequent lesson with a live-preview-frame in its rail picks up the new palette automatically — by L8 the menu page renders in the operator's accent color; by L14 the generator emits a stylesheet keyed to it.

Source

/tools/_shared/workshop/palette-picker.js — ~280 LOC. Exports { tag, contextKeys, mount, serialize } per the Workshop Kit widget contract. Cuisine → palette table at the top of the file; WCAG 2.2 contrast math in a small helper; the rest is wiring native <input type="color"> elements to the commit path.

contextKeys lists both 'palette' (it writes) and 'restaurantProfile' (it reads for cuisine). The engine uses contextKeys for tree-shaking + dependency tracking; widgets that don't declare their reads can miss re-renders when upstream context changes.

← Back to the Workshop Kit