v1.3.0
What's Changed
Added
-
Flexible color model (#71).
colors:palettes accept a freeswatches:list
(named colors, optional per-swatchcss_variable) alongside the existing Tailwind-style
shades:map — projects without a 50–950 scale finally render a sane overview. Both
shapes normalize through the newColorPalettes/ColorUtillayer; swatch text color
(light/dark) is now computed from the hex via WCAG relative luminance instead of the
hardcoded shade-name list, so dark 100s and light 700s stop guessing wrong. Foundations
markup adapts to small palettes (capped swatch tiles, wrapping strip, truncating labels).
All swatch data ishtml_attr-escaped into the Alpine attributes infoundations.twig
(autoescape is off in this package), so free-form swatch names carrying apostrophes or
quotes render safely. OKLCH values are computed from the hex when the yaml omits them and
are the preferred lightness basis. -
Contrast / a11y layer (#72). Every swatch on the overview now grades white/black
text against WCAG AA (4.5:1) — dot badges on the tile, exact ratios in the tooltip and
hero — and an expandable matrix grades every color × color pair (all palettes + white +
black) with AAA / AA / AA-large / fail verdicts. Computed server-side from the hex via
the #71 normalization layer; zero yaml changes needed (newlabels.contrast_matrix*
keys are optional with English defaults). -
Favicon audit section (#73). Foundations gains a
#faviconsection: the favicon
rendered in simulated contexts (browser tab light/dark, iOS home-screen icon, Android/PWA
maskable icon) plus a server-side audit checklist — file existence, real pixel dimensions
vs. expectations (png_9696×96,apple_touch180×180), parsed ICO contents, manifest
JSON validity with per-icon existence checks, and thetheme_colorswatch. Audited by the
newFaviconAuditclass, which runs entirely server-side againststatic_path; every
configured path (and every manifest iconsrc) is containment-checked to stay under
static_pathbefore any filesystem read. Checklist labels are overridable via optional
labels.favicon*keys, all with English defaults — no yaml changes are required beyond
the existingfavicon:block. -
OG image audit section (#74). Foundations gains an
#og-imagesection: the optional
og_image:yaml key renders as share-card mockups — Facebook/LinkedIn (1.91:1 crop),
X/Twitter summary_large_image (2:1 crop), and a Slack unfurl — plus a compact server-side
audit checklist covering existence, real pixel dimensions vs. the ≥ 1200×630 recommendation,
aspect ratio vs. the 1.91:1 convention, and file size against platform limits (warn > 1 MB,
error > 8 MB). Audited by the newOgImageAuditclass, which shares the containment-hardened
PathGuardhelper withFaviconAudit(#73) rather than duplicating its scheme-URI rejection
and realpath-under-static_pathchecks. The section always renders — an empty-state prompt
covers the unconfigured case, since an OG image is expected on every project. Checklist
labels are overridable via optionallabels.og_*keys, all with English defaults.
Changed
-
Foundations interactivity no longer requires the consumer to ship Alpine (#79).
templates/foundations.twigdrops all Alpine directives; swatch switching, copy-to-clipboard
and the contrast-matrix toggle now live in a package-shipped, dependency-free
dist/foundations.[hash].js, injected for foundations renders exactly like the existing
foundations CSS bundle. The hero server-renders the default swatch, so the no-JS view shows
real data. Consumer component demos inside the iframe are unaffected — they keep using
whatever the consumer bundles. -
|resizernow emits tuple-declared variants for real fixture images too, not only
placeholder()fakes (#70). Every tuple
becomes an entry reusing the ORIGINALsrc(no image pipeline — the browser downloads one
file) with the tuple's declaredwidth/height/media, so the styleguide<picture>DOM
mirrors the multi-source markup the CMS resizer emits in production — what DOM-structural
checks (tailwind-base'spicture.contract.jssharpness contract) assert against. With
real-content fixtures (thepicture.md"prefer real content" default) previously passing
through untouched, the contract silently skipped exactly the fixtures projects prefer.
Missing tuple axes derive from the fixture'swidth/heightmetadata; without metadata the
provided axis is kept and the other omitted (never invented)..giffixtures pass through
whole — parity with timber-kitResizer::$skip_animated(animation can't be cheaply proven
from a URL, and flattening an animated preview is the dangerous direction). Verified against
a real consumer (pm-a): 220 visual baselines unchanged, behavior picture-contract coverage
grew from 16 to 26 renders with no failures. -
Malformed metadata YAML now surfaces in
GET /styleguide/api/healthinstead of silently
dropping the component from the catalogue.ComponentParser::parseTwigComment()throws
ParseExceptionon invalid YAML (previously degraded tofalse); the existing resilience
paths inparse()/parseAll()catch it and record agetWarnings()entry, so the walk
continues and the broken file is named. Variant sibling annotations keep the old
fall-back-silently behaviour (caught at thediscoverVariants()call-site). Real-world
trigger: an unquoted{ padding-top: 0 }in a field description made two sloneek
components vanish with no trace. Behavioural note for directparseTwigComment()
consumers: wrap intry/catch (ParseException)if you relied on thefalsereturn. -
styleguide lintreportsmetadata-yaml-invalid(Error) for malformed metadata YAML instead
of crashing on the propagatedParseException— distinct fromunindexed(no metadata comment
at all), because the author DID write metadata and the component is guaranteed missing from the
catalogue.
Pull Requests
- #69 — fix(parser): malformed metadata YAML surfaces in health warnings instead of silently dropping the component
- #75 — feat(resizer): tuple varianty i pro reálné fixture obrázky — DOM parita s produkcí (#70)
Full Changelog: v1.2.0...v1.3.0