diff --git a/.claude/launch.json b/.claude/launch.json new file mode 100644 index 0000000..ffa1c6e --- /dev/null +++ b/.claude/launch.json @@ -0,0 +1,14 @@ +{ + "version": "0.0.1", + "configurations": [ + { + "name": "start", + "runtimeExecutable": "npm", + "runtimeArgs": [ + "run", + "start" + ], + "port": 3000 + } + ] +} diff --git a/CLAUDE.md b/CLAUDE.md index ba8b906..655a735 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -37,6 +37,7 @@ title-bar controls). The rules that matter most: - Verify against the guide's testing section and resilience checklist. Mocks for the existing upstreams: `node tools/prodcom-mock.js` (ProdCom) and `node band-lineup-display/tmp/pp-mock.js 1599` (ProPresenter). + `node tools/slack-mock.js 24716` (Slack; run ProdDash with `SLACK_API_BASE=http://127.0.0.1:24716/api`). ## Reference code (read-only forks — don't develop these here) diff --git a/README.md b/README.md index 80696b3..8856226 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,10 @@ touching the shell (see [docs/MODULE-GUIDE.md](docs/MODULE-GUIDE.md)). 2. Discovers modules in `modules/` and serves each one's client at `/modules//`. 3. Mounts each enabled module's server routes under `/api/modules//` — - that's where module servers proxy ProdCom, poll ProPresenter, and stream - live updates over SSE, so browsers never talk to production gear - directly (no CORS, and API keys never leave the server). + that's where module servers follow ProdCom, poll ProPresenter, and stream + live updates over SSE — one upstream connection per module, however many + dashboards are open — so browsers never talk to production gear directly + (no CORS, and API keys never leave the server). 4. Stores server-wide module config and named layouts in a per-machine data directory outside the app folder, so updating ProdDash never loses them. @@ -99,6 +100,7 @@ with this machine's shell settings — the same keys as the checked-in | --- | --- | | `port` | Port ProdDash serves on (default `24500`). The macOS launcher writes this one, so the port it is set to holds however ProdDash is started. | | `adminPasscode` | If set, the admin page asks for this shared passcode. Leave `""` for none — it's a plain-HTTP LAN tool. | +| `theme` | The dashboard palette: `booth` (default), `harbor`, `graphite`, `ember` or `daylight`. The admin page's **Theme** section writes this one — see [Themes](#themes). | Environment variables override both files: `PORT`, `PRODDASH_PASSCODE`, and `PRODDASH_DATA_DIR` to put the data directory somewhere else (a relative path @@ -111,6 +113,22 @@ so and falls back to the app's `config/` folder. directory, so nothing has to be re-entered. The old files are left in place and ignored from then on. +### Themes + +The whole dashboard — every tile, on every browser — draws with one palette, +chosen in the admin page's **Theme** section and switched live: pick a swatch +and open dashboards change without a reload. Five presets ship: **Booth** +(the default dark, mint accent), **Harbor** (deep navy, cyan), **Graphite** +(neutral charcoal, electric blue), **Ember** (warm broadcast black, orange) +and **Daylight**, a light palette for a front-of-house desk in daytime. Each +keeps the status colours apart — the accent is never near the danger red or +the warning amber — and muted text readable in a dark booth. The choice is +stored as `theme` in the data directory's `proddash.json` (table above), so +it holds across restarts and updates; a browser remembers the last theme it +saw and applies it before the server answers, so nothing flashes. Modules +style with the shell's colour variables, which is why they follow; a colour +set on a tile itself (a PCO Plan header colour, say) is deliberately kept. + ## Installing modules and updating Everything below happens in the **admin page**; ProdDash talks to its GitHub diff --git a/docs/MODULE-GUIDE.md b/docs/MODULE-GUIDE.md index 64ca0c2..acaafe1 100644 --- a/docs/MODULE-GUIDE.md +++ b/docs/MODULE-GUIDE.md @@ -92,6 +92,7 @@ the app); its settings are kept for a later reinstall. | `proddash` | yes | The ProdDash versions this module works with: `">=1.1.0"`, `"^1.1.0"`, `">=1.1.0 <2.0.0"`, or `"*"`. A module whose requirement the running shell doesn't meet is listed in the admin page but never loaded, and can't be installed from the catalog. | | `description` | no | Shown in the admin page / picker. | | `permissions` | no | What macOS must allow before this module can work — see **Permissions macOS has to grant**. Ignored by the shell; read by the macOS launcher. | +| `provides` | no | Capabilities other modules can consume — `["timers"]` today. Forwarded in `/api/modules` so a consumer can find you. See **Working with other modules**. | | `client` | yes | Client entry file, loaded as an ES module. | | `server` | no | Server entry file (CommonJS), loaded with `require()`. | | `style` | no | A stylesheet the shell injects once per module. | @@ -103,7 +104,7 @@ the app); its settings are kept for a later reinstall. Both schemas map field names to specs: ``` -{ "type": "string" | "number" | "boolean" | "switch" | "select" | "color" | "password" | "endpoint", +{ "type": "string" | "text" | "number" | "boolean" | "switch" | "select" | "multiselect" | "template" | "color" | "password" | "endpoint", "label": "Shown next to the field", "default": , "group": "Section heading", // optional; see below @@ -115,10 +116,33 @@ Both schemas map field names to specs: } ``` -`boolean` renders as a checkbox; `switch` is the same true/false value shown -as a toggle (use it for a feature on/off that other fields depend on). +`boolean` and `switch` are the same true/false value. In a tile's gear popover +both render as a switch; in the admin page `switch` is the toggle and +`boolean` the plainer checkbox (use `switch` for a feature on/off that other +fields depend on). **Label a switch with the noun of what it turns on** — +"Seconds", "Top bar", "Section headers" — never "Show seconds": on means +shown or enabled, off means hidden or disabled, and the label shouldn't say +so twice. `color` renders a swatch picker and stores a `#rrggbb` string (give it a hex default; the tile applies it as a CSS custom property — see `pco-plan`). +`multiselect` is several picks from one list — the same `options` / +`optionsRoute` as `select`, rendered as one switch per option and stored as +an array of values. A saved value the list no longer offers stays checked and +marked, so nothing is dropped behind anyone's back. In a tile's gear popover +it also takes `columns` (2–4) and `allByDefault: true`: a tile that has never +chosen shows every option on and saves nothing until someone flips one, so +options that turn up later are on as well (give it no `default` then). +`select` and `multiselect` may use `optionsRoute` in `instanceSchema` too — +the popover GETs `/api/modules/` like the admin page does. + +`template` (tile settings) is a text with placeholders, built by dragging or +clicking the variables the module offers into it: `"variables": [ { "value": +"{series}", "label": "Series" }, … ]`. Keep `help` to the joining rules; the +chips carry the names. + +`text` is a multi-line string — a `