Compare commits
5 Commits
c75ec15554
...
0919d57e27
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0919d57e27 | ||
|
|
d3995d057d | ||
|
|
528b3e2d65 | ||
|
|
91e6735eb2 | ||
|
|
563ba4a37c |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
||||
*.so
|
||||
.superpowers/
|
||||
|
||||
1397
docs/superpowers/plans/2026-06-06-lcars-card-redesign.md
Normal file
1397
docs/superpowers/plans/2026-06-06-lcars-card-redesign.md
Normal file
File diff suppressed because it is too large
Load Diff
175
docs/superpowers/specs/2026-06-06-lcars-card-redesign-design.md
Normal file
175
docs/superpowers/specs/2026-06-06-lcars-card-redesign-design.md
Normal file
@ -0,0 +1,175 @@
|
||||
# LCARS Card Redesign
|
||||
|
||||
**Date:** 2026-06-06
|
||||
**Scope:** `~/src/blockninja/themes/lcars` theme plugin
|
||||
**Status:** Design
|
||||
|
||||
## Problem
|
||||
|
||||
The current LCARS theme has the outer page frame (elbows, sidebar, header) reading correctly, but its **in-content blocks are generic**:
|
||||
|
||||
- `lcars_panel` renders as a thin coloured left-border with a small pill and title bar — visually closer to a Bootstrap callout than to LCARS.
|
||||
- There is no way for adjacent panels to **share frame chrome** (the defining "L wrapping multiple readouts" pattern of canonical LCARS).
|
||||
- There is no small-tile equivalent for dashboard-style numeric readouts.
|
||||
- Existing CSS hardcodes `font-family: 'Antonio', sans-serif`, which now violates the project-wide font-token rule introduced in `themes/CLAUDE.md` (must go through `var(--font-heading|body|mono, <fallback>)`).
|
||||
|
||||
This spec redesigns the panel system so cards read as LCARS and so that grouped cards visually share a single L-frame.
|
||||
|
||||
## Visual outcome
|
||||
|
||||
The brainstorming session locked the following geometry (mockups in `.superpowers/brainstorm/3782075-1780722894/content/08-wider-bigger-curve.html`):
|
||||
|
||||
- **Outer page corners** of every framed block are rounded; the **inner L bend** stays a sharp 90° (the corner block has `border-top-left-radius` on its outer corner only).
|
||||
- **Column 1** (rail / corner) is **5.5rem** wide.
|
||||
- **Top bar / top corner row** is **4rem** tall; **bottom bar / bottom corner row** is **3rem** tall — deliberate asymmetric chrome weight, top heavier than bottom.
|
||||
- **Outer top corners** use **1.75rem** radius; **outer bottom corners** use **1.25rem** radius.
|
||||
- **Grid gap** between cells is **4px**, producing the slim dark separators between LCARS colour segments.
|
||||
- Identifier text in the corner blocks uses `padding: 0 1.25rem 0.85rem 1rem` (top, right, bottom, left) so it sits clear of all four edges.
|
||||
|
||||
## Three block additions / changes
|
||||
|
||||
### 1. `lcars_panel` — redesigned (existing key)
|
||||
|
||||
A single self-contained framed panel. **Replaces the current thin-left-border implementation.**
|
||||
|
||||
**Schema (`schemas/lcars_panel.schema.json`):**
|
||||
|
||||
| Property | Type | Default | Notes |
|
||||
|---|---|---|---|
|
||||
| `frame` | enum `"elbow" \| "strip"` | `"elbow"` | Renders mode A or mode B from the brainstorm |
|
||||
| `title` | text | `""` | Goes in the top bar |
|
||||
| `top_label` | text | `""` | Corner-block identifier (e.g. `RM-47-A`); placeholder shows an LCARSy default |
|
||||
| `bottom_label` | text | `""` | Bottom corner identifier (e.g. `28-301`) |
|
||||
| `top_meta` | text | `""` | Right-aligned bar-top text (e.g. `STARDATE 47634.4`) |
|
||||
| `bottom_meta` | text | `""` | Right-aligned bar-bot text |
|
||||
| `status` | enum `online \| standby \| alert \| offline` | none | Optional status dot in bar-top; reuses existing `.lcars-status-*` classes |
|
||||
| `accent_color` | enum `primary \| secondary \| accent \| muted` | `primary` | Picks which theme token drives the top L colour |
|
||||
| `bottom_accent_color` | enum (same) | `secondary` | Bottom L colour — defaults differ from top so the panel reads as two-tone |
|
||||
| `content` | richtext | `""` | Panel body |
|
||||
|
||||
**Render targets:**
|
||||
|
||||
- `frame="elbow"`: 2-column / 3-row CSS grid as locked in the mockup (see § Geometry).
|
||||
- `frame="strip"`: a single segmented colour bar header + bordered body. No corner blocks, no rail; the colour band carries the labels.
|
||||
|
||||
### 2. `lcars_rail` — new compound block
|
||||
|
||||
Multiple sibling content cells share a single L-frame. The defining "how cards interact with each other" answer.
|
||||
|
||||
**Architecture choice:** the rail is **not** a true container (`HasInternalSlot: true`). The CMS's `RenderSlot` pipeline returns all children as one concatenated HTML blob with no per-child wrappers, which makes it impossible to pair each child with its own rail segment in a single CSS grid. Instead, the rail is a compound block whose cells are defined inline in its own schema — each cell has the rail-segment colour/label AND the cell content together. This keeps v1 implementable and avoids inventing a per-child-wrapper extension to the SDK. A future iteration can add a true container variant if needed.
|
||||
|
||||
**Schema (`schemas/lcars_rail.schema.json`):**
|
||||
|
||||
| Property | Type | Default | Notes |
|
||||
|---|---|---|---|
|
||||
| `title` | text | `""` | Top-bar title |
|
||||
| `top_label` / `bottom_label` | text | `""` | Same role as on `lcars_panel` |
|
||||
| `top_accent_color` / `bottom_accent_color` | enum | `primary` / `primary` | Colour the top and bottom corner blocks |
|
||||
| `cells` | array of `{label, color, title, content}` | required, min 1 | Each entry renders one rail segment + one paired body cell. `color` enum maps to theme tokens; default rotates `mauve → gold → blue → mauve…` when user leaves it blank. `content` is richtext. |
|
||||
| `rail_side` | enum `left \| right` | `left` | Flips the L for right-handed layouts (schema field reserved; CSS implements `"left"` only) |
|
||||
|
||||
### 3. `lcars_readout` — new tile block
|
||||
|
||||
A small dashboard tile for numeric/status displays. Designed for grids of mini-readouts.
|
||||
|
||||
**Schema (`schemas/lcars_readout.schema.json`):**
|
||||
|
||||
| Property | Type | Default | Notes |
|
||||
|---|---|---|---|
|
||||
| `label` | text | required | Small uppercase label above the value |
|
||||
| `value` | text | required | Big numeric/text value |
|
||||
| `unit` | text | `""` | Smaller unit suffix (`%`, `LY`, etc.) |
|
||||
| `accent_color` | enum | `primary` | Colours the top border and the value text |
|
||||
| `pulse` | bool | `false` | If true, the value gets the existing `lcars-pulse` animation |
|
||||
|
||||
**Render target:** a `<div>` with a 4px coloured top border, `padding: 0.5rem 0.75rem`, label in muted small caps, big value, optional unit. Multiple readouts work in any standard grid (CSS grid, columns block, etc.) the user already has.
|
||||
|
||||
## Geometry (locked)
|
||||
|
||||
```css
|
||||
.lcars-elbow {
|
||||
display: grid;
|
||||
grid-template-columns: 5.5rem 1fr;
|
||||
grid-template-rows: 4rem 1fr 3rem;
|
||||
gap: 4px;
|
||||
background: hsl(var(--background));
|
||||
}
|
||||
.lcars-elbow__tl { grid-area: 1/1; border-top-left-radius: 1.75rem; }
|
||||
.lcars-elbow__bar-t { grid-area: 1/2; border-top-right-radius: 1.75rem; }
|
||||
.lcars-elbow__rail { grid-area: 2/1; }
|
||||
.lcars-elbow__body { grid-area: 2/2; background: hsl(var(--background)); }
|
||||
.lcars-elbow__bl { grid-area: 3/1; border-bottom-left-radius: 1.25rem; }
|
||||
.lcars-elbow__bar-b { grid-area: 3/2; border-bottom-right-radius: 1.25rem; }
|
||||
|
||||
/* Identifier text inside the corner blocks */
|
||||
.lcars-elbow__tl, .lcars-elbow__bl {
|
||||
display: flex; justify-content: flex-end;
|
||||
font: 800 0.75rem/1 var(--font-heading, 'Antonio', sans-serif);
|
||||
letter-spacing: 0.08em;
|
||||
color: hsl(var(--background));
|
||||
}
|
||||
.lcars-elbow__tl { align-items: flex-end; padding: 0 1.25rem 0.85rem 1rem; }
|
||||
.lcars-elbow__bl { align-items: flex-start; padding: 0.75rem 1.25rem 0 1rem; }
|
||||
```
|
||||
|
||||
The rail block reuses the same column/gap rules but the row template becomes `4rem repeat(N, var(--lcars-rail-row, 3.5rem)) 3rem`, with one paired (rail-segment, body-cell) per `cells[]` entry. Segment and cell are placed in the same row via explicit `grid-row` in the pongo `{% for %}` loop — no reliance on auto-flow.
|
||||
|
||||
## Refinements bundled in this spec
|
||||
|
||||
These are small but in-scope because the changes touch the same files:
|
||||
|
||||
1. **Font tokens.** All `font-family: 'Antonio', sans-serif` in `assets/style.css` rewritten as `font-family: var(--font-heading, 'Antonio', sans-serif)`. No bundled fonts change. `fonts.json` shipped as `[]` (per CLAUDE.md guidance) and a new `RECOMMENDED_FONTS.md` instructs admins to assign Antonio (or similar geometric sans) to `--font-heading`.
|
||||
2. **Palette expansion in `presets.json`.** Add the canonical LCARS roles beyond `primary/secondary/accent`: the file gains entries for `peach`, `mauve`, `gold`, `blue`, `red` so panel accent-colour pickers map to actual theme tokens rather than the generic three. Existing token names stay; the new ones are additive.
|
||||
3. **Outer page-frame refinement.** The existing page-template elbow widths and radii are re-tuned to the same 5.5rem column / 1.75rem outer radius vocabulary so the page outer chrome and the in-content panel chrome share visual language. Adds optional `stardate` and `identifier` slots on the existing `lcars_header` block (already partly there — just makes the chrome richer).
|
||||
4. **Sidebar identifier codes.** `lcars_sidebar` items gain an optional `code` field (e.g. `SCI 01`) rendered as small right-aligned text inside each button, so the sidebar visually rhymes with the new rail block.
|
||||
5. **`required_icon_packs` declaration.** `plugin.mod` gets `required_icon_packs = ["lucide"]` (forward-declared per CLAUDE.md). No icons are required for the new blocks today; this is staged for future status-indicator iconography.
|
||||
6. **`RECOMMENDED_ICONS.md`** added with one line (Lucide) for parity with `RECOMMENDED_FONTS.md`.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- `rail_side: "right"` rendering — schema field accepted, CSS only implements `"left"`.
|
||||
- SVG-based frames or arbitrarily large inner-bend curves — the locked design uses CSS border-radius and a sharp inner bend.
|
||||
- Icon rendering inside panels — staged via `required_icon_packs` but no panel uses an icon yet.
|
||||
- Touch / mobile rail-collapse behaviour — existing responsive rules in `style.css` already collapse the page sidebar at 768px; the new blocks inherit the same breakpoint via a single block of rules at the bottom of the stylesheet.
|
||||
- Changes to `gotham` or any other theme.
|
||||
|
||||
## File-by-file impact
|
||||
|
||||
| File | Change |
|
||||
|---|---|
|
||||
| `blocks.go` | Add `LCARSRailMeta`, `LCARSReadoutMeta`. Update `LCARSPanelMeta` description. New `headerDefaults` / `panelDefaults` updated. |
|
||||
| `register.go` | Register the two new blocks. Update `lcars_panel` registration to use the new template (`blocks/panel.html` rewritten). Schema load remains in place. |
|
||||
| `schemas/lcars_panel.schema.json` | Rewritten per § 1 above. |
|
||||
| `schemas/lcars_rail.schema.json` | **NEW.** |
|
||||
| `schemas/lcars_readout.schema.json` | **NEW.** |
|
||||
| `schemas/lcars_sidebar.schema.json` | Add optional `code` field on each item. |
|
||||
| `templates/blocks/panel.html` | Rewritten to render `frame="elbow"` and `frame="strip"` per the locked geometry. |
|
||||
| `templates/blocks/rail.html` | **NEW.** |
|
||||
| `templates/blocks/readout.html` | **NEW.** |
|
||||
| `templates/blocks/sidebar.html` | Render the new optional `code` field. |
|
||||
| `templates/blocks/header.html` | Minor refinement so it shares the new 5.5rem / 1.75rem vocabulary with panel chrome. |
|
||||
| `templates/default.html` | Re-tune outer-frame widths/radii to match. |
|
||||
| `assets/style.css` | Replace `'Antonio', sans-serif` with `var(--font-heading, 'Antonio', sans-serif)` throughout. Add `.lcars-elbow*`, `.lcars-strip*`, `.lcars-rail*`, `.lcars-readout*` rule blocks. Re-tune `.lcars-elbow-*` outer-frame rules to new dimensions. Delete the old `.lcars-panel*` rules. |
|
||||
| `presets.json` | Add `peach / mauve / gold / blue / red` colour roles to each preset; keep `primary / secondary / accent / background / foreground` etc. as the canonical tokens. |
|
||||
| `plugin.mod` | Add `required_icon_packs = ["lucide"]`. Bump `version` via `make bump-minor` after implementation (this is a feature). |
|
||||
| `fonts.json` | Set to `[]`. (Currently lists bundled woff2s; per new CLAUDE.md rule fonts should be admin-assigned.) |
|
||||
| `RECOMMENDED_FONTS.md` | **NEW.** Antonio for heading; system sans for body; system mono for mono. |
|
||||
| `RECOMMENDED_ICONS.md` | **NEW.** Lucide pack. |
|
||||
|
||||
## Validation
|
||||
|
||||
Before commit:
|
||||
|
||||
- `make` — compiles the `.so`.
|
||||
- `cd ~/src/blockninja/check-safety && go run . ~/src/blockninja/themes/lcars` — passes the import-boundary and schema-vs-block-key checks.
|
||||
- `make rebuild` against a dev CMS instance — visually confirm an `lcars_panel` with `frame="elbow"`, an `lcars_rail` with three `lcars_readout` children, and the existing page chrome all read as one consistent LCARS frame.
|
||||
|
||||
## Decisions made during brainstorming (for reference)
|
||||
|
||||
1. **Inner L bend is sharp, outer page corners are rounded.** Confirmed against the user's `Lcars_wallpaper.svg.png` reference and an explicit AskUserQuestion choice ("Curve at the page corner (outside the panel)").
|
||||
2. **Top bar 4rem, bottom bar 3rem, asymmetric.** Authentic LCARS chrome is top-heavy.
|
||||
3. **Curve ratio matches v1 mockups, not v6.** 1.75rem top / 1.25rem bottom on a 5.5rem column 1 — visible but not dominating the corner block.
|
||||
4. **`lcars_rail` is a separate block, not a panel variant.** It exists as its own block (not just an `lcars_panel` mode) because it has fundamentally different content shape: a list of paired (segment, body-cell) entries, vs. the panel's single body. One mode-switch would have over-loaded the schema with mutually-exclusive fields.
|
||||
5. **`lcars_rail` is a compound schema-driven block, not a `HasInternalSlot` container.** Investigated during spec self-review: pongo blocks have no per-child wrapper hook in `RenderSlot`, so children of a true container come back as one concatenated HTML blob — incompatible with the goal of pairing each child with its own rail segment in a single CSS grid. Inline `cells[]` in the schema sidesteps this. (`themes/CLAUDE.md` lists an `AllowedChildren []string` field on BlockMeta which does not exist in `core/blocks/types.go` — the actual field is `HasInternalSlot bool`; CLAUDE.md should be corrected separately.)
|
||||
6. **`lcars_readout` is a separate block, not a `lcars_panel` mode.** Readouts are meant to be tiled; panels are meant to stand alone. Conflating them would have forced one of those uses to dominate.
|
||||
7. **Font tokens, not bundled font, going forward.** Aligns with the project-wide rule introduced in `themes/CLAUDE.md` during this session.
|
||||
2
go.mod
2
go.mod
@ -2,7 +2,7 @@ module git.dev.alexdunmow.com/block/lcars
|
||||
|
||||
go 1.26.4
|
||||
|
||||
require git.dev.alexdunmow.com/block/core v0.11.1
|
||||
require git.dev.alexdunmow.com/block/core v0.12.4
|
||||
|
||||
require (
|
||||
connectrpc.com/connect v1.20.0 // indirect
|
||||
|
||||
2
go.sum
2
go.sum
@ -2,6 +2,8 @@ connectrpc.com/connect v1.20.0 h1:6TNDAB+WeNd2uolWNlYczB5E0KNNaVMNUEx8JEUsPmQ=
|
||||
connectrpc.com/connect v1.20.0/go.mod h1:A2ygJrukXwWy32vkCAAHNVguZrqZ+jeZ9rGRnGR4dN4=
|
||||
git.dev.alexdunmow.com/block/core v0.11.1 h1:5b3Ps9CLor2FGyxw/Qovt27AGZKR5Xi1JZGi/TfliTA=
|
||||
git.dev.alexdunmow.com/block/core v0.11.1/go.mod h1:ZwzEOxRDLDfrhQGqo6hLw01/C1z/aS4Dm9ljQMl0Bg4=
|
||||
git.dev.alexdunmow.com/block/core v0.12.4 h1:F/K4DkAuBlVQivcnWNECORfUQfct0E1JOfmg+61uLzw=
|
||||
git.dev.alexdunmow.com/block/core v0.12.4/go.mod h1:ZwzEOxRDLDfrhQGqo6hLw01/C1z/aS4Dm9ljQMl0Bg4=
|
||||
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
|
||||
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/a-h/templ v0.3.1020 h1:ypAT/L5ySWEnZ6Zft/5yfoWXYYkhFNvEFOeeqecg4tw=
|
||||
|
||||
@ -2,7 +2,11 @@
|
||||
name = "lcars"
|
||||
display_name = "LCARS"
|
||||
scope = "@themes"
|
||||
version = "0.2.6"
|
||||
version = "0.2.7"
|
||||
description = "Star Trek-inspired LCARS interface theme for BlockNinja — angular panels, bold accent colors, and the distinctive curved frame layout of the 24th-century starship computer."
|
||||
kind = "plugin"
|
||||
kind = "theme"
|
||||
categories = ["templates"]
|
||||
tags = ["retro-futurist", "scifi", "lcars", "demo", "showcase", "angular", "amber"]
|
||||
|
||||
[compatibility]
|
||||
block_core = ">=0.11.0 <0.12.0"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user