Files

Handoff: ChicoryTV — Channel Builder (+ admin design system)

Overview

The Channel Builder ("New Channel") is a ground-up replacement for ErsatzTV's four-editor channel-creation chain (Channel → Schedule → Schedule Items → Playout). It is one screen: browse your media library on the left, build the channel's lineup in the center, set friendly options + a Channel Template on the right, and hit Create Channel — which (in the real app) builds all the underlying entities atomically. It ships inside the ChicoryTV admin, a dark, dense, app-like console and its React component library.

About the design files

The files in this bundle are design references created in HTML/React — prototypes showing the intended look and behavior, not production code to ship directly. The task is to recreate these designs in the target codebase's environment using its established patterns. Per the redesign brief, the intended target is a React SPA over the ErsatzTV REST API (replacing Blazor/MudBlazor); if that app doesn't exist yet, scaffold it (Vite + React + TypeScript is a reasonable default) and implement there. Nothing here depends on Blazor.

The prototypes are built on a real design system (React primitives + CSS-custom-property tokens + three themes) that lives in the parent project — treat that as the component/token source of truth.

Fidelity

High-fidelity. Final colors, typography, spacing, radii, motion, and interactions are all resolved. Recreate pixel-for-pixel using the codebase's real component library (promoting these primitives into it, or mapping to existing equivalents). All values below are exact.


Screens / Views

New Channel — Channel Builder (primary deliverable)

Purpose: create a working channel by adding library items to a lineup and setting a few friendly options; technical config comes from a selectable Channel Template.

Layout: full-height column. A builder toolbar (fixed, 12px×20px padding, hairline bottom border): accent icon tile + "New Channel" title + live summary (N in lineup · total duration) on the left; Cancel (ghost) and Create Channel (primary, right) — Create is disabled until there's a name + ≥1 lineup item, tooltip below. Below the toolbar, a 3-column grid, full height: grid-template-columns: minmax(0,1.2fr) minmax(0,1fr) 304px (columns shrink, never overflow; the 304px rail is fixed). Each column scrolls independently.

Column 1 — Library browser (overflow:hidden section):

  • Header: a Segmented source toggle Library / Collections (sliding highlight), a spacer, and a grid/compact density Segmented. Then a search input (Search shows & movies… / Search collections…). Then, in Library mode only, pill filter chips (All, Cartoons, Movies, TV Shows, Music Videos, Documentaries) — active chip uses accent-soft bg + accent text.
  • Body (scrolls): poster grid repeat(auto-fill, minmax(104px,1fr)), gap 10 — each poster is a 2:3 tinted, diagonally-striped placeholder (deterministic hue from title) with a bottom gradient scrim, title (12px semibold) + mono meta, and a type icon top-left (Tv/Film/Music/Radio, or Layers/Sparkles/FolderTree/Repeat for collection kinds). Compact mode is a 30×40 thumb + title + type · meta row. Double-click or drag to add; added cards show an accent ring + a pop-in check badge (top-right).

Column 2 — Lineup (the channel's content, overflow:hidden section, accepts drops):

  • Header: "LINEUP" eyebrow, a Sequential / Shuffled status badge (icon, informational — the real control is the Shuffle toggle in the rail), a spacer, a Clear ghost button.
  • Body (scrolls): ordered rows, gap 7. Each row: grip handle, order number (mono) when Sequential or a shuffle glyph when Shuffled, a 34×46 poster thumb, title (14px semibold) + type · library, mono duration, and a remove (×) button. Drag-to-reorder (HTML5 DnD; a 0 -2px 0 accent top-border marks the drop target; dragged row drops to 0.35 opacity). Empty state = dashed dropzone. A trailing dashed "double-click or drag more titles to add" hint.

Column 3 — Settings rail (fixed 304px, background: surface-card, scrolls via an overlay scrollbar — hidden native bar so no reflow, subtle fading thumb):

  • Channel name input; Number input with an AUTO mono chip trailing.
  • Channel image: a dashed dropzone (drop or click → file input; live FileReader preview). Below, two preview tiles — Guide logo (logo + name + "listing") and On-screen bug (logo bottom-right over a striped "video frame"). A "Set logo & bug separately" disclosure reveals two image buttons. Default: the one image drives both.
  • Shuffle toggle (label + "Plays in a random order." / "Plays in sequence (chronological)."). Shows an "overrides template" tag when it differs from the selected template's default.
  • Always playing toggle — the live-TV concept. Rendered in the live color (--ctv-live) with a tinted row + a "● LIVE" pill when on. Helper: "Like live TV — advances on schedule even when nobody is watching." Also shows the "overrides template" tag when diverging. (Backend gap #68 — still needs confirmation.)
  • Channel Template picker: a button showing the current template (name + one-line desc + Custom badge). Opens a list of built-ins + custom, each with a radio, name, desc; a "Save current settings as template…" action. Selecting a template applies its Shuffle + Always-playing defaults and shows its config as chips (e.g. 1080p H.264, HLS Segmenter, Sequential, Always on, Pre + post filler).
  • Advanced disclosure: a SlidersHorizontal header + N fields · <template>. Two buttons — Override settings (one click → editable fields, active-orange in dual theme) and View defaults (read-only chips). Clicking the active one collapses. The field region animates via max-height. ~24 fields grouped Streaming / Filler / Playback / Behavior.

Other admin screens (context; already in the design system)

  • Dashboard — on-air cards, stat tiles, condensed health panel, activity feed, release notes.
  • Channels — dense table, bulk-select, (D)/(H) markers, streaming-mode badges, inline actions.
  • Guide / EPG — dark channels×time grid, "now" marker, live focal color, jump-to-now.
  • Schedule editor — two-pane, drag-to-reorder items + tabbed inspector.
  • Playouts — now/next monitor (live preview, up-next, timeline strip, upcoming list).
  • Libraries — Local/Plex/Jellyfin/Emby source cards with scan status.
  • App shell: 232px left sidebar (nav + health), 52px top bar (search, Connect menu). Primary "big" button is top-right on every screen.

Interactions & behavior

  • Add to lineup: double-click a library card OR drag it onto the lineup. Dedupes by id; added cards show a check.
  • Reorder lineup: native drag-and-drop; drop-target top-border indicator; source dims to 0.35.
  • Shuffle vs Sequential: rail toggle; lineup order display switches (numbers vs shuffle glyph).
  • Channel image: drop/select → FileReader.readAsDataURL → live logo + bug preview; falls back to a generated initials chip (deterministic color from the name) when empty.
  • Template selection: applies the template's shuffle + always-playing defaults; toggles then show "overrides template" if the user changes them.
  • Advanced: one-click Override (editable) / View defaults (read-only); max-height collapse animation; on expand, the panel smooth-scrolls just enough to bring the Advanced header to the top.
  • Create Channel: enabled only with a name + ≥1 item.
  • Themes: data-theme on <html> = "" (warm, default) / cool / dual. In dual, the focal warm hue drives primary actions, active nav, and selection via --action-primary.

Motion (iOS/macOS-subtle; respect prefers-reduced-motion)

  • Durations 90 / 140 / 220–340ms. Standard ease cubic-bezier(0.2,0,0,1); entrance/settle cubic-bezier(0.16,1,0.3,1).
  • Segmented control: highlight slides (transform, ~300ms). Cards: hover-lift (translateY(-2px)
    • shadow). Buttons/rows: press-scale (scale(0.96), ~150ms). Selection check: pop-in (scale + fade). Advanced: max-height accordion. Switches slide. Live status dot pings.

State management

Per Channel Builder instance: search, libraryFilter, source (library|collections), compact, lineup[] (ordered items), drag ids (dragLib, dragRow, overRow), name, number, shuffle, always, logoSrc (dataURL|null), selected template id, tplOpen, and Advanced mode (closed|view|override) + edited field values. Derived: addedIds, filtered pool, total duration, canCreate. Real app: replace mock arrays with the library browse/search API (#65), Channel Templates entity (#64), and the composite create endpoint (#63).

Design tokens (exact)

Surfaces: app #0F1115 · sunken #0B0D11 · card #171A21 · raised #1C2029 · selected #222732. Borders: hairline #262B36 · control #333A48. Text: primary #E6E9EF · muted #9AA4B2 · faint #626B7A. Accent: warm chicory #E08A3C (default) · cool periwinkle #5B7CFA · soft = accent @14%. Semantic alias: --action-primary = accent (warm/cool) or --ctv-live in dual. Status: ok #3FB984 · warn #E0A83D · error #E5484D · live #E08A3C (warm) / #F0663F (dual), each with a ~14–16% soft tint. Radii: chips 3px · buttons/inputs 5px · cards/rows/menus 7px · dialogs 10px · pills full. Type: Geist (UI) + Geist Mono (numerics, tabular figures). Base 13px; scale 11·12·13·14·16·20·26·34; weights 400/500/600. Eyebrows 11px/600 uppercase, 0.06em tracking. Spacing: 4px grid. Fixed chrome: sidebar 232 · top bar 52 · rows 44 · controls 34 (sm 28). Elevation: border + subtle shadow (sm 0 1px 2px/.40, md 0 4px 12px/.45, pop 0 8px 28px/.55, dialog 0 16px 40px/.55); live elements get a small accent glow.

Assets

  • Icons: Lucide (2px stroke), via CDN in the prototypes; use your icon lib's Lucide set. Glyphs used: Plus, Check, X, Search, Library, FolderTree, LayoutGrid, Rows3, GripVertical, Shuffle, ListOrdered, Radio, Film, Tv, Music, Layers, Sparkles, Repeat, Image, SlidersHorizontal, SquarePen, Eye, CircleCheck, Circle, Save, ChevronDown/Up/Right.
  • Brand mark: assets/chicory-mark.svg (periwinkle chicory flower) — do not redraw; reference it.
  • Posters/artwork: placeholders only (striped, tinted). Real artwork comes from the library API (#65).
  • No other raster assets.

Files

In the parent project (download it alongside this folder):

  • templates/chicorytv-admin/ChannelBuilder.jsx — the Channel Builder (also copied into this folder).
  • templates/chicorytv-admin/{Shell,Dashboard,Channels,Epg,ScheduleEditor,Playouts,ScheduleLibrary}.jsx, data.js, icons.jsx, app.html, ds-base.js — the admin shell + other screens.
  • components/ — the React component library (.jsx + .d.ts per component; namespace window.ChicoryTVDesignSystem_eb3b61).
  • tokens/ + styles.css — design tokens and the three themes (tokens/themes.css).
  • readme.md — full design-system documentation.
  • docs/superpowers/specs/2026-07-01-chicorytv-ui-redesign-design.md — the redesign brief; §6 is the Channel Builder spec, §8 records exactly what was built + backend gaps (#62/#63–#68).

To view the whole admin: open templates/chicorytv-admin/app.html and click New Channel.