{"slug":"greenroom","name":"Greenroom — Events Calendar Dashboard","version":"1.0.0","category":"dashboard","priceCents":3900,"description":"An events calendar dashboard template for scheduling and venue-operations products, built on a calendar you can operate from the keyboard. Seven routes ship: a month overview with tonight's run order beside it, a week view with an hour grid, a booking detail, a holds work queue, a booking form, a programme settings page, and a living component styleguide. The month grid is an ARIA grid with one tab stop and the cell-entry pattern the specification writes: arrows walk days and weeks, PageUp and PageDown walk months, Enter steps into a day and moves focus to its first booking, Escape steps back out, and walking off the end of the month pages it. Minimum and maximum dates disable paging and arrow movement. Its signature is the occupancy tail: every public booking shows the hours the room is committed for, load-in to strike, so a 19:30 show reads as the 13:30 commitment it creates. In the week view that is a block whose height is the hold with the public hours banded inside it; on the detail page it is a four-mark ledger. Six programme strands carry the calendar's colour. A cancelled booking is struck through, a pencilled one has a dotted edge, and every strand has a dot and a name. The state layer includes filters that preserve themselves and tell a no-result from a first use, a form that validates on submit, focuses an error summary, keeps valid values and leaves a durable receipt rather than a toast, and a permission boundary explained in words instead of a dead disabled button. Every figure on every route derives from one fixture file, so no two pages can disagree about the same show. The palette has 128 tokens per mode, with its structural ramp authored in OKLCH on one neutral hue. Every pair is computed against its contrast tier, and the receipt reads the shipped stylesheet. Self-hosted Nunito, Figtree and Azeret Mono. Built for Tailwind v4, Next.js 15 and React 19; every colour lives in theme.css.","summary":"An events calendar dashboard template with month, week and agenda views, a keyboard-complete calendar, and 7 routes over one fixture spine.","tags":["events calendar dashboard template","react calendar dashboard template","nextjs scheduling dashboard template","tailwind event management template","venue booking dashboard template","tailwind-v4"],"palette":{"bg":"#f9e3f7","surface":"#fffcff","accent":"#7e4d8a","text":"#291927","line":"#dccbda"},"accent_mode":"second-hue","darkMode":true,"pages":[{"path":"/","title":"August at Quarry Hall","sections":["app-shell","schedule","today-rail"]},{"path":"/week","title":"This week, hour by hour","sections":["app-shell","schedule"]},{"path":"/event","title":"Hollow Bell","sections":["app-shell","event-detail","hold-ledger"]},{"path":"/holds","title":"Holds waiting on a decision","sections":["app-shell","holds-queue"]},{"path":"/new","title":"Can we take this on?","sections":["app-shell","booking-form"]},{"path":"/programme","title":"Strands and rooms","sections":["app-shell","strand-list"]},{"path":"/components","title":"The parts","sections":["app-shell"]}],"components":[{"name":"app-shell","file":"src/components/app-shell.tsx","renders":"Sidebar navigation, strand legend, page heading and footer"},{"name":"booking-dialog","file":"src/components/booking-dialog.tsx","renders":"A modal booking entry that reuses the complete form state layer"},{"name":"booking-form","file":"src/components/booking-form.tsx","renders":"The place-a-booking form and its whole state layer"},{"name":"event-detail","file":"src/components/event-detail.tsx","renders":"One show: status, capacity, promoter and what is missing"},{"name":"event-panel","file":"src/components/event-panel.tsx","renders":"A right-hand event sheet combining booking facts with the hold ledger"},{"name":"hold-ledger","file":"src/components/hold-ledger.tsx","renders":"One event's holds as rows — load-in, doors, curfew, strike"},{"name":"holds-queue","file":"src/components/holds-queue.tsx","renders":"The date-ordered pencil queue with strand filters and recovery states"},{"name":"load-chart","file":"src/components/load-chart.tsx","renders":"Held room hours by week and strand, with a matching data table"},{"name":"schedule","file":"src/components/schedule.tsx","renders":"The season in month, week or agenda view, with every hold drawn"},{"name":"strand-list","file":"src/components/strand-list.tsx","renders":"The six programme strands, their counts and their rooms"},{"name":"today-rail","file":"src/components/today-rail.tsx","renders":"Tonight's run order: doors, room, sold, and the hours held"},{"name":"ui/accordion-disclosure","file":"src/components/ui/accordion-disclosure.tsx","renders":"Greenroom's programme and mobile-navigation disclosure recipe"},{"name":"ui/chart","file":"src/components/ui/chart.tsx","renders":"Chart frame, strand patterns and accessible table helpers"},{"name":"ui/dashboard-layout","file":"src/components/ui/dashboard-layout.tsx","renders":"Shell geometry: sidebar, rail, topbar, header, footer"},{"name":"ui/dates","file":"src/components/ui/dates.ts","renders":"The theme's date and time words — no Intl, no clock"},{"name":"ui/dialog","file":"src/components/ui/dialog.tsx","renders":"Greenroom's modal recipe for booking entry and hold release"},{"name":"ui/event-calendar","file":"src/components/ui/event-calendar.tsx","renders":"tt-ui event calendar — month, week and agenda"},{"name":"ui/sheet-drawer","file":"src/components/ui/sheet-drawer.tsx","renders":"Greenroom's right-edge recipe for calendar event inspection"},{"name":"ui/strand-icon","file":"src/components/ui/strand-icon.tsx","renders":"The six programme strands mapped to named Lucide icons"},{"name":"ui/ui.config","file":"src/components/ui/ui.config.ts","renders":"Layer host, density, motion and focus decisions shared by library recipes"}],"tokens":{"--background":"#f9e3f7","--foreground":"#291927","--card":"#fffcff","--card-foreground":"#291927","--surface-sunken":"#f0d6ed","--surface-raised":"#ffffff","--surface-overlay":"#ffffff","--overlay-border":"#91808f","--muted":"#f8ecf6","--muted-foreground":"#6b5a69","--secondary":"#f8ecf7","--secondary-foreground":"#392637","--secondary-hover":"#f1e0ef","--secondary-active":"#e9d8e7","--border":"#d7c6d5","--border-strong":"#91808f","--shadow-color":"#3a1f37","--scrim":"#2a1628","--nav":"#f9f0f8","--nav-foreground":"#291927","--nav-muted":"#6b5a69","--nav-hover":"#f5e6f3","--nav-selected":"#ffffff","--nav-selected-foreground":"#712482","--nav-border":"#dccbda","--primary":"#7e4d8a","--primary-foreground":"#fefafe","--primary-hover":"#713d7c","--primary-active":"#632d6f","--primary-soft":"#f9e5fe","--primary-border":"#eacbf1","--primary-ink":"#7c298e","--accent":"#e39a07","--accent-foreground":"#2d1b00","--accent-hover":"#efac44","--accent-active":"#f8bf6c","--accent-soft":"#ffedd6","--accent-border":"#f3d6af","--field":"#f6f1f5","--field-border":"#e5d2e3","--control":"#fceffa","--control-border":"#d6c4d4","--control-hover":"#f5e6f3","--control-active":"#edddeb","--ring":"#a23db8","--selection":"#f8daff","--selection-foreground":"#3a1941","--selection-border":"#b774c7","--link":"#794db6","--link-hover":"#5c2f95","--link-visited":"#775386","--info":"#0465af","--info-foreground":"#fafcfe","--info-soft":"#e3f0fe","--info-border":"#bddbfb","--info-fill":"#0465af","--positive":"#067132","--positive-foreground":"#f7fef8","--positive-soft":"#dff6e2","--positive-border":"#bfe2c5","--positive-fill":"#067132","--warning":"#8a5601","--warning-foreground":"#fffbf7","--warning-soft":"#feebd6","--warning-border":"#f0d2b1","--warning-fill":"#8a5601","--critical":"#ac262a","--critical-foreground":"#fefbfa","--critical-soft":"#fee9e6","--critical-border":"#facac5","--critical-fill":"#ac262a","--strand-live":"#ffd2ca","--strand-live-ink":"#902014","--strand-live-mark":"#c13e2e","--strand-workshop":"#fcd89d","--strand-workshop-ink":"#694900","--strand-workshop-mark":"#946900","--strand-matinee":"#c1edb7","--strand-matinee-ink":"#196100","--strand-matinee-mark":"#2d8810","--strand-community":"#98f0ef","--strand-community-ink":"#015c5c","--strand-community-mark":"#058282","--strand-rehearsal":"#c3e2fe","--strand-rehearsal-ink":"#005486","--strand-rehearsal-mark":"#0177bc","--strand-hire":"#ddd9fe","--strand-hire-ink":"#523a9a","--strand-hire-mark":"#735acc","--hold-line":"#917d8f","--hold-field":"#fdeefb","--radius-sm":"0.375rem","--radius":"1rem","--radius-lg":"1.25rem","--radius-xl":"1.75rem","--radius-pill":"999px","--shadow-raised":"0 1px 2px -1px color-mix(in oklab, var(--shadow-color) 14%, transparent), 0 3px 8px -2px color-mix(in oklab, var(--shadow-color) 10%, transparent)","--shadow-overlay":"0 8px 24px -6px color-mix(in oklab, var(--shadow-color) 22%, transparent), 0 2px 6px -2px color-mix(in oklab, var(--shadow-color) 14%, transparent)","--text-caption":"0.75rem","--leading-caption":"1.4","--text-small":"0.875rem","--leading-small":"1.45","--text-body":"1rem","--leading-body":"1.55","--text-lead":"1.125rem","--leading-lead":"1.6","--text-d1":"1.5rem","--leading-d1":"1.25","--text-d2":"2rem","--leading-d2":"1.2","--text-d3":"clamp(2rem, 1.42rem + 2.46vw, 2.664rem)","--leading-d3":"1.15","--text-d4":"clamp(2.664rem, 1.56rem + 4.71vw, 3.551rem)","--leading-d4":"1.1","--tracking-d1":"-0.010em","--tracking-d2":"-0.016em","--tracking-d3":"-0.020em","--tracking-d4":"-0.024em","--tracking-label":"0.06em","--font-display":"var(--font-greenroom-display), ui-sans-serif, system-ui, sans-serif","--font-text":"var(--font-greenroom-text), ui-sans-serif, system-ui, sans-serif","--font-sans":"var(--font-text)","--font-mono":"var(--font-greenroom-mono), ui-monospace, monospace","--display-weight":"700","--duration-quick":"120ms","--duration-settle":"180ms","--ease-buoyant":"cubic-bezier(0.34, 1.4, 0.5, 1)","--ease-standard":"cubic-bezier(0.2, 0, 0, 1)"},"tokensDark":{"--background":"#1d111c","--foreground":"#f6edf5","--card":"#291b27","--card-foreground":"#f6edf5","--surface-sunken":"#150a14","--surface-raised":"#332432","--surface-overlay":"#3c2b3a","--overlay-border":"#7f6e7d","--muted":"#30222f","--muted-foreground":"#b2a4b1","--secondary":"#352633","--secondary-foreground":"#f2e7f0","--secondary-hover":"#3c2f3b","--secondary-active":"#443743","--border":"#443542","--border-strong":"#7f6e7d","--shadow-color":"#000000","--scrim":"#0d0710","--nav":"#261924","--nav-foreground":"#f6edf5","--nav-muted":"#b2a4b1","--nav-hover":"#312630","--nav-selected":"#3d2d3b","--nav-selected-foreground":"#f2b9ff","--nav-border":"#433542","--primary":"#925d9e","--primary-foreground":"#fefafe","--primary-hover":"#834e8f","--primary-active":"#753e81","--primary-soft":"#3e2843","--primary-border":"#563d5c","--primary-ink":"#f2b9ff","--accent":"#feb43a","--accent-foreground":"#281600","--accent-hover":"#ffca80","--accent-active":"#ffdbab","--accent-soft":"#3c2a0e","--accent-border":"#5b4320","--field":"#170c16","--field-border":"#473745","--control":"#312830","--control-border":"#51424f","--control-hover":"#3a2f39","--control-active":"#433641","--ring":"#e98dfe","--selection":"#492a50","--selection-foreground":"#f8e8fb","--selection-border":"#ab68ba","--link":"#c4a3ff","--link-hover":"#dbcafe","--link-visited":"#c49dd5","--info":"#6ab3fd","--info-foreground":"#0a0e11","--info-soft":"#192d41","--info-border":"#304a64","--info-fill":"#6ab3fd","--positive":"#6fd087","--positive-foreground":"#0a0f0b","--positive-soft":"#1a321f","--positive-border":"#315038","--positive-fill":"#6fd087","--warning":"#ffb250","--warning-foreground":"#100d09","--warning-soft":"#3a2710","--warning-border":"#5b4225","--warning-fill":"#ffb250","--critical":"#fd736d","--critical-foreground":"#110c0b","--critical-soft":"#3f2220","--critical-border":"#623c39","--critical-fill":"#fd736d","--strand-live":"#602018","--strand-live-ink":"#febfb4","--strand-live-mark":"#ff806d","--strand-workshop":"#4b3300","--strand-workshop-ink":"#ffc763","--strand-workshop-mark":"#dc9e08","--strand-matinee":"#18430d","--strand-matinee-ink":"#9ee78e","--strand-matinee-mark":"#70c35d","--strand-community":"#004141","--strand-community-ink":"#2eeded","--strand-community-mark":"#0cc3c3","--strand-rehearsal":"#003b61","--strand-rehearsal-ink":"#a9d7fe","--strand-rehearsal-mark":"#51b3fe","--strand-hire":"#382d65","--strand-hire-ink":"#d0cafe","--strand-hire-mark":"#aa9afe","--hold-line":"#9f8b9d","--hold-field":"#221821","--radius-sm":"0.375rem","--radius":"1rem","--radius-lg":"1.25rem","--radius-xl":"1.75rem","--radius-pill":"999px","--shadow-raised":"0 1px 2px -1px color-mix(in oklab, var(--shadow-color) 14%, transparent), 0 3px 8px -2px color-mix(in oklab, var(--shadow-color) 10%, transparent)","--shadow-overlay":"0 8px 24px -6px color-mix(in oklab, var(--shadow-color) 22%, transparent), 0 2px 6px -2px color-mix(in oklab, var(--shadow-color) 14%, transparent)","--text-caption":"0.75rem","--leading-caption":"1.4","--text-small":"0.875rem","--leading-small":"1.45","--text-body":"1rem","--leading-body":"1.55","--text-lead":"1.125rem","--leading-lead":"1.6","--text-d1":"1.5rem","--leading-d1":"1.25","--text-d2":"2rem","--leading-d2":"1.2","--text-d3":"clamp(2rem, 1.42rem + 2.46vw, 2.664rem)","--leading-d3":"1.15","--text-d4":"clamp(2.664rem, 1.56rem + 4.71vw, 3.551rem)","--leading-d4":"1.1","--tracking-d1":"-0.010em","--tracking-d2":"-0.016em","--tracking-d3":"-0.020em","--tracking-d4":"-0.024em","--tracking-label":"0.06em","--font-display":"var(--font-greenroom-display), ui-sans-serif, system-ui, sans-serif","--font-text":"var(--font-greenroom-text), ui-sans-serif, system-ui, sans-serif","--font-sans":"var(--font-text)","--font-mono":"var(--font-greenroom-mono), ui-monospace, monospace","--display-weight":"700","--duration-quick":"120ms","--duration-settle":"180ms","--ease-buoyant":"cubic-bezier(0.34, 1.4, 0.5, 1)","--ease-standard":"cubic-bezier(0.2, 0, 0, 1)"},"compatibility":{"next":">=15","react":">=19","tailwind":">=4"},"dependencies":["lucide-react","recharts"],"editions":{"react":{"source":"src","runtime":"react"},"html":{"source":"html/src","output":"html/dist","engine":"nunjucks","runtime":"vanilla","buildRequired":false}},"ui_library":{"version":"1.4.0","files":["html/src/js/_tt/accordion-disclosure.js","html/src/js/_tt/dialog.js","html/src/js/_tt/event-calendar.js","html/src/js/_tt/focusables.js","html/src/js/_tt/layer.js","html/src/js/_tt/mode.js","html/src/js/_tt/presence.js","html/src/js/_tt/reduced-motion.js","html/src/js/_tt/roving.js","html/src/js/_tt/sheet-drawer.js","src/components/ui/_tt/accordion-disclosure.axes.ts","src/components/ui/_tt/accordion-disclosure.fixtures.ts","src/components/ui/_tt/accordion-disclosure.tsx","src/components/ui/_tt/calendar.ts","src/components/ui/_tt/dialog.axes.ts","src/components/ui/_tt/dialog.fixtures.ts","src/components/ui/_tt/dialog.tsx","src/components/ui/_tt/event-calendar.axes.ts","src/components/ui/_tt/event-calendar.fixtures.ts","src/components/ui/_tt/event-calendar.tsx","src/components/ui/_tt/focusables.ts","src/components/ui/_tt/host.ts","src/components/ui/_tt/ids.ts","src/components/ui/_tt/layer.ts","src/components/ui/_tt/presence.ts","src/components/ui/_tt/recipe.ts","src/components/ui/_tt/reduced-motion.ts","src/components/ui/_tt/schedule.ts","src/components/ui/_tt/sheet-drawer.axes.ts","src/components/ui/_tt/sheet-drawer.fixtures.ts","src/components/ui/_tt/sheet-drawer.tsx"]},"license":"standard","design":{"typefaces":{"display":"Nunito","text":"Figtree","mono":"Azeret Mono"},"typeRatio":1.333,"signature":"The occupancy tail: every public booking draws the hours the room is genuinely held — load-in to strike — around the solid band of its public hours. In the week view the block's whole height is the hold, with the public hours banded inside the hatched field; on a month chip it is a doubled leading edge; on /event it is a four-mark ledger of load-in, doors, curfew and strike. holdFor() computes all three from the booking's own minutes and throws on one that claims a hold with no public hours to hang it off, so an uncited hold cannot be published."}}