Documentation menu
Documentation / Blocks & themes / theme-saturday
Theme Saturday
npm install @wabbit/tome-theme-saturdayFirst install from our registry?
Get a registry token from your credentials page. You need a purchase that includes this package, or a Craft Library membership.
Add the registry and your token to the
.npmrcat the root of your project, with your token in place ofYOUR_TOKEN:@wabbit:registry=https://npm.wabbit.com/ //npm.wabbit.com/:_authToken=YOUR_TOKEN
Saturday, a Tome theme for indoor places people go to play (trampoline parks, rinks, bowling and arcades, climbing gyms, indoor sports complexes): pick your night. Whole bands carry the page, the first screen is a sun-yellow field holding the header, a who-is-coming choice, a photo panel and the session board, packages are the roundest object on the page, and every Book action lands on one planner. Unbounded and Figtree, four palettes (Bounce, Arcade, Rink and Court) with derived opposite modes, self-hosted OFL fonts, activated by data-tome-theme="saturday".
Overview
Saturday is a Tome theme for indoor places people go to play: trampoline parks, ice and roller rinks, bowling and arcade complexes, climbing gyms, laser tag, indoor sports complexes and kids' play cafes. Its line is "Pick your night": a visitor has a free evening or a birthday coming and is choosing between this place and three others, and the page answers what there is to do, whether it is open tonight, what it costs, whether the kids are old enough, and how to book a party without phoning. Its look is whole bands: the first screen is a sun-yellow field that holds the header, a choice of who is coming, a photo panel and the session board, and every band after it is one color, with the cards sitting inside the bands.
This package is a theme (a ThemeManifest of kind: 'theme'). It owns no blocks. It declares the token surface blocks read, self-hosts its two OFL font families, and restyles ten blocks and chrome through their public hooks: high-impact-hero (the split variant with its choice group), local-class-schedule (the board variant), slat-deck, event-list (the cards variant), stat (the sourced variant), local-price-list (the package variant), faq, the tome-forms planner (stepsDisplay: 'stacked'), local-logistics (the cards variant) and section-header (the ruled-split variant, as every band's opener).
Layer: ui · Family / tier: themes / addon · Versioning: independent.
Peer dependencies
| Peer | Range | Required |
|---|---|---|
@wabbit/tome-ui | >=0.22.0 <1.0.0 | yes |
@wabbit/tome-core | >=1.35.0 <2.0.0 | no (optional) |
@wabbit/tome-blocks-marketing-starter | >=0.50.0 <1.0.0 | no (optional): the hero's choice group and slat-deck |
@wabbit/tome-blocks-local-pack | >=0.14.0 <1.0.0 | no (optional): the board, package and cards variants |
@wabbit/tome-blocks-org-pack | >=0.11.0 <1.0.0 | no (optional): the event-list cards variant |
@wabbit/tome-blocks-agency-essentials | >=0.50.0 <1.0.0 | no (optional): the scoreboard's note hook |
@wabbit/tome-ui is a CSS-contract peer. Its tokens.css re-declares the var()-aliased Layer 2 under [data-tome-theme] and defines the fixed-band ink family this theme sets, and it ships the platform scroll reveal Saturday turns on. @wabbit/tome-core is needed only for the @wabbit/tome-theme-saturday/register subpath and the ThemeManifest type. The block packs are optional peers: each carries the hooks Saturday styles at the release listed, and a site that omits a pack simply never renders its blocks, so the rules for them match nothing. The theme is CSS and a manifest: it has no server or client components of its own, and importing it adds no client JavaScript.
Usage
Import the stylesheet once at the app root, after tome-ui's tokens, and activate the theme on <html>:
// app/layout.tsx
import '@wabbit/tome-ui/tokens.css'
import '@wabbit/tome-theme-saturday/styles.css'
import '@wabbit/tome-theme-saturday/fonts.css'<html data-tome-theme="saturday"> <!-- Bounce, light -->
<html data-tome-theme="saturday" data-tome-palette="rink"> <!-- Rink, light -->
<html data-tome-theme="saturday" data-tome-palette="court" data-theme="dark"> <!-- Court, derived dark -->
<html data-tome-theme="saturday" data-tome-palette="arcade" data-theme="dark"> <!-- Arcade, as designed -->With no data-tome-palette the theme renders Bounce. data-theme="dark" gives Bounce, Rink and Court their derived dark mode. Arcade's manifest entry carries defaultMode: 'dark', so the admin palette picker and themeConfigHtmlAttributes() open it dark; data-theme="light" is its derived light mode.
To have the admin ThemeSwitcher, createThemeConfig() and other registry readers list it, register it on the server before building the Payload config:
import '@wabbit/tome-theme-saturday/register'Recommended chrome: Navbar 1 with the header's two buttons (the waiver as an outline button, Book as the default) and the local pack's live status bar in the chrome announcementSlot, so the status strip sits above the logo row; below 1024px the header is the platform's phone bar and the waiver and Book ride the mobileActionBar. Footer 7, which the theme paints as its own full-width tonal zone. Section openers are section-header in its ruled-split variant. The starter's logo may use the theme's lockup hooks (data-saturday-lockup, data-saturday-mark, data-saturday-lockup-name).
Palettes
Four palettes, each light and dark, from the palette run in the spec workspace (scripts/palettes.mjs is the recipe, scripts/palette-roles.json its roles-only extract; the stylesheets in src/tokens/palettes/ are generated from it by scripts/generate-tokens.mjs, never retyped). Every judged role clears the 0.05 line against every shipped palette in its mode, every text pair clears 4.5:1, and every mark, outline and focus ring clears 3:1 in all eight modes. The test suite re-measures the contrast from the shipped declarations.
| Palette | Id | Character | Fits | Opens |
|---|---|---|---|---|
| Bounce (default) | bounce | warm white ground, sun-yellow field, hot pink action | trampoline parks, kids venues, play cafes | light |
| Arcade | arcade | violet-black ground, coral field, hot pink-red action; the one dark-led palette | bowling, arcades, laser tag, evening venues | dark |
| Rink | rink | cold white ground, near-black field with an ice-white accent, ultramarine action | ice and roller rinks, climbing gyms | light |
| Court | court | hardwood ground, team-purple field, gold accent | indoor sports complexes, leagues and open play | light |
The field is the band: the first screen's header strip, header, hero and board, and the packages. The sign fills the action and paints the "what's on" band. The wash paints the planner band and fills a preset field. The tint paints the logistics band and every question. The page ground carries the deck, the scoreboard card's surroundings and the footer's neighbor. Two roles are derived, not picked: the scoreboard's figure color (the first of the band, band accent, sign and accent text that clears 4.5:1 on the ink) and the sign pill's edge on the field (the sign where it clears 3:1 against the field, else the field's ink: Arcade dark's hot pink-red sits on a coral field at about 1.1:1, and Court's purple action sits on its purple field).
Status
Every status pairs a shape and words with its color. The board's chip says "On now, until 7:00" (a filled dot on the success tint), "Starts 7:30" (a hollow ring on the tint), "Sold out" (a square on the error tint) or "Finished" (a dash, dimmed); "Sold out" appears only from a real availability field. The header's status says "Open now, until 10 PM" with a filled dot, or a hollow ring when closed. Nothing is fake scarcity: no countdown, no "only 3 left", and no animation but the one reveal and the deck's widening.
What the treatments do
- The yellow first screen. The status strip (the announcement slot, right-aligned) and the header frame are the field color, and the hero and the board under them are the same band. The header is two rows from 1024px: the logo with the waiver (outline) and Book (the sign fill), then the nav as a row of white pills, the current page in the ink.
- The hero and its choice. Headline, intro and "Who's coming?" take the left 8 of 16 columns, the choices an even 2x2 that works with no script, each answering with one sentence and its own action. The photo panel takes the right 8, rounded, from the headline to the bottom of the choice; on phones it sits after the intro.
- The Session Board. Today's sessions as tickets: time, activity with age rule and notes, price, state chip. It renders nothing without a session today, and the hero then closes the gap.
- The Activity Deck. Full-height photo slats, the open one widening, the rest narrowing to vertical names on a dark scrim that is dark in every mode; they stack on phones, and every collapsed name reads in full.
- What's on, the scoreboard, the packages, the questions. Date-tile event cards on a sign band (a still strip, no marquee); a rounded ink card with four outlined cells and bright figures, inside the content width; packages as the roundest object on the page (36px) with price, headcount, extra price, length, inclusions and any deposit; tint-card questions ending in a "Still have a question?" card.
- The Planner, then the logistics. One enquiry for every bookable thing, as numbered groups on a wash band, preset from a card's
?type=link, with its reply time beside the submit; then four logistics cards on a tint band, with no CTA band under it. The footer is its own tonal zone.
Motion is one primitive, the platform scroll reveal (a rise of 18px over 600ms, played once), and the deck's widening, which the block owns. Reduced motion turns every transition and the reveal off and hides nothing. Interactive targets are at least 44px; fields are 48px.
Fonts
Two families ship inside the package as latin-subset woff2 files, each with its SIL OFL 1.1 license: Unbounded (display; variable wght 700 to 800; fonts/OFL-Unbounded.md) and Figtree (body and interface; variable wght 400 to 800, no italic; fonts/OFL-Figtree.md). The subset covers Basic Latin, Latin-1 and Latin Extended-A. There is no third-party font request by default. Three ways to deliver them:
import '@wabbit/tome-theme-saturday/fonts.css': the bundler resolves the files from this package.- Your own host: copy the files from
@wabbit/tome-theme-saturday/fonts/*and injectgetSaturdayFontStyles({ src }). next/font/local, using the files fromgetSaturdayFontFaces().
import { getSaturdayFontPreloads } from '@wabbit/tome-theme-saturday/fonts'
// in <head>: preload the display face and the interface face
{getSaturdayFontPreloads({ src: '/fonts/saturday/' }).map((l) => <link key={l.href} {...l} />)}Sources, recorded in scripts/subset-fonts.py (the build never runs it) and checked by SHA-256, all from google/fonts at commit 5bb28733cec313b63fbd415b574b5ae35c8aa8b8:
| Face | Source | SHA-256 |
|---|---|---|
| Unbounded | ofl/unbounded/Unbounded[wght].ttf | 323b511be380c8d474ef030686b71aedde501f8d9cd46da558b7c40454372c3f |
| Figtree | ofl/figtree/Figtree[wght].ttf | 26ad3db9b31ff7dde67a91ff515d022d2f495cd506590699cf264f0bfe6fb714 |
Both faces have tabular figures. Each keeps tnum and pnum in the shipped subset, each defaults to proportional figures, and the ten tnum figures share one advance (at every tested weight in the recipe's check, and at the default weight in the test suite's re-read of the shipped files). So session times, prices, dates, counts and phone numbers are set with font-variant-numeric: tabular-nums, on the whole document and again on every figure hook. Code falls back to the system monospace stack (the manifest has no mono slot).
Public API
| Export | Subpath | Purpose |
|---|---|---|
saturdayThemeManifest (ThemeManifest) | ., @wabbit/tome-theme-saturday/manifest | The theme's manifest: name saturday, kind: 'theme', tier addon, four palettes (Arcade with defaultMode: 'dark'), fonts and one pairing, recommended blocks and chrome (Navbar 1, footer 7), styledBlocks, requires.tomeUi. |
SATURDAY_PALETTE_IDS, SaturdayPaletteId | ., @wabbit/tome-theme-saturday/manifest | ['bounce', 'arcade', 'rink', 'court'], the data-tome-palette values. |
SATURDAY_PALETTE_DEFAULT_MODES | ., @wabbit/tome-theme-saturday/manifest | The mode each palette opens in: light for three, dark for Arcade. |
SATURDAY_STYLED_BLOCKS, SATURDAY_RECOMMENDED_BLOCKS | ., @wabbit/tome-theme-saturday/manifest | The block slugs the theme restyles, and the slugs its demos are composed from, in page order. |
ThemeManifest (type) | . | Re-exported from @wabbit/tome-core/registry/theme. |
getSaturdayFontFaces(), getSaturdayFontStyles({ src }), getSaturdayFontPreloads({ src }) | ., @wabbit/tome-theme-saturday/fonts | Font descriptors, @font-face CSS for a custom host, and preload links. |
SATURDAY_FONT_STACKS, SATURDAY_FONT_LICENSES, SATURDAY_LATIN_UNICODE_RANGE, SATURDAY_DISPLAY_WEIGHTS, SATURDAY_UI_WEIGHTS | ., @wabbit/tome-theme-saturday/fonts | The CSS stacks the tokens use, the license files, the subset range, and the weights used. |
SaturdayFontFace, SaturdayFontPreloadDescriptor, SaturdayFontStylesOptions (types) | ., @wabbit/tome-theme-saturday/fonts | The descriptor shapes. |
| side effect | @wabbit/tome-theme-saturday/register | Registers saturdayThemeManifest in tome-core's theme registry. |
| stylesheet | @wabbit/tome-theme-saturday/styles.css | Tokens and treatments. The file that does everything visual. |
| stylesheet | @wabbit/tome-theme-saturday/fonts.css | The @font-face rules. Optional. |
| font files | @wabbit/tome-theme-saturday/fonts/* | The woff2 files and their OFL licenses, for self-hosting. |
import { saturdayThemeManifest } from '@wabbit/tome-theme-saturday/manifest'
// saturdayThemeManifest.name === 'saturday'; .selector === '[data-tome-theme="saturday"]'Layout of the package
src/
styles.css entry: imports everything below, in order
fonts.css, fonts.ts the @font-face rules and the font descriptors
fonts/ the two woff2 files and their OFL licenses (verbatim)
manifest.ts the ThemeManifest
register.ts registers the manifest (a side-effect subpath)
tokens/palettes/ GENERATED, one file per palette: color only, light and dark
tokens/type.css font slots, the scale, the weights
tokens/rhythm.css radius, rhythm, the stage width, motion, the reveal
treatments/ one file per area, through public hooks only
scripts/
palettes.mjs the palette recipe (contrast and delta-E against every shipped palette)
extract-roles.mjs palettes.json -> palette-roles.json
generate-tokens.mjs palette-roles.json -> tokens/palettes/*.css
subset-fonts.py the font recipe (pinned sources, tabular-figure check)
copy-assets.mjs build step: copies the stylesheets and fonts to dist/
tests/ conformance, palettes, contrast, fonts, hooks, hook coverage, treatments, no color literals, manifestColor literals live only in tokens/; the test suite fails one anywhere else. Every treatment rule is scoped to [data-tome-theme="saturday"], reaches blocks through published data-* hooks (never a class name), and takes every color from a token.
Related
@wabbit/tome-theme-groundsis the neighbor: acreage, many spaces, a scheduled thing. Saturday is one building, many activities, and a visitor choosing what to do, often tonight.- The block packs listed under Install carry the hooks this theme styles; their READMEs publish them.
License
See LICENSE.md. The bundled fonts are under the SIL Open Font License 1.1 (src/fonts/OFL-*.md).
Exports
| Import path |
|---|
@wabbit/tome-theme-saturday |
@wabbit/tome-theme-saturday/manifest |
@wabbit/tome-theme-saturday/register |
@wabbit/tome-theme-saturday/fonts |
@wabbit/tome-theme-saturday/styles.css |
@wabbit/tome-theme-saturday/fonts.css |
@wabbit/tome-theme-saturday/fonts/* |
Changelog
0.1.xMinor
First release of Saturday, a Tome theme for indoor places people go to play, where whole bands carry the page.
It is made for trampoline parks, rinks, bowling and arcades, climbing gyms and indoor sports complexes, where a visitor is choosing what to do tonight: the first screen is a sun-yellow field that holds the header, a "Who's coming?" choice, a photo panel and the session board, and every band after it is one color with the cards sitting inside it.
Four palettes, each light and dark: Bounce (the default, a warm white ground, a sun-yellow field and a hot pink action), Arcade (a violet-black ground, a coral field and a hot pink-red action, which opens dark), Rink (a cold white ground, a near-black field with an ice-white accent and an ultramarine action) and Court (a hardwood ground, a team-purple field and a gold accent). Type is Unbounded for headings, figures and prices and Figtree for everything else; both are self-hosted, and both have tabular figures, so session times, prices and counts line up.
It styles the hero's split variant with its choice group and photo panel, the session board with its state chips in words, the activity deck, the what's-on cards, the scoreboard, the packages (the roundest object on the page), the questions with their closing card, the stacked planner, the logistics cards, every band's opener, the status strip, the pill-nav header with the waiver and Book, and the footer as its own zone. Motion is one reveal, played once, and reduced motion turns it off.
Every contrast pair clears 4.5:1 and every target is at least 44px.
2 fixes (0.1.1 – 0.1.2)
- 0.1.2
The questions and the planner sit beside their openers from 1024px, as in the approved mockup.
The theme also fixes four problems found on phones and from the keyboard.
- Split bands: the opener takes the left five content columns and its block the right ten, with one empty column between. The column is set through the wrapper's
--tome-block-column, because the wrapper writes its column inline. Under 1024px both bands stack as before. - Numbered lists in an opener count in sign-colored dots (the planner's three steps).
- The status strip on a phone is one compact line, not the live-status block's 124px block. The header lockup's name steps down a size, so the menu button stays on the logo's row at 375.
- The hero photo takes its whole column. WebKit left the panel 0 by 0 on phones, so the photo vanished.
- Date and time fields in the planner show the focus ring from the keyboard. Focus can sit on a segment inside the field, where only
:focus-withinmatches.
- Split bands: the opener takes the left five content columns and its block the right ten, with one empty column between. The column is set through the wrapper's
- 0.1.1
The scoreboard card, the footer and the What's on intro now render as designed.
- The scoreboard card stretches across its rows instead of collapsing to 0px.
- An opener's line inherits its band's ink (it stayed muted gray on the pink What's on band).
- The footer reaches the ink by pointing
--tome-color-surface-mutedat it, because Footer 7 writes its background pair inline. Set the footer tomuted.