← Commit history

1.12.0: newbie panel is two columns with a prompts TABLE; header numbers (edge to edge, 18px mark, 15px name); copy/send/play action icons shipped

John Lauer ·ba5b497e12 ·1mo ago ·parent bcd0043
6 files changed +191−125
assets/icons/action-copy.svgadded+8
@@ -0,0 +1,8 @@+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"+     fill="none" stroke="currentColor" stroke-width="1.8"+     stroke-linecap="round" stroke-linejoin="round">+  <!-- Adom action icon: COPY. Two offset sheets. Inline this into markup, where+       currentColor inherits; if you load it as a file, swap to #e6edf3. -->+  <rect x="9" y="9" width="12" height="12" rx="2.5"/>+  <path d="M6 15H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v1"/>+</svg>
assets/icons/action-play.svgadded+6
@@ -0,0 +1,6 @@+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"+     fill="none" stroke="currentColor" stroke-width="1.8"+     stroke-linecap="round" stroke-linejoin="round">+  <!-- Adom action icon: PLAY (the demo button's glyph). Outline triangle, never filled. -->+  <path d="M7 4.8v14.4a.6.6 0 0 0 .92.5l11.3-7.2a.6.6 0 0 0 0-1l-11.3-7.2a.6.6 0 0 0-.92.5z"/>+</svg>
assets/icons/action-send.svgadded+8
@@ -0,0 +1,8 @@+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"+     fill="none" stroke="currentColor" stroke-width="1.8"+     stroke-linecap="round" stroke-linejoin="round">+  <!-- Adom action icon: SEND TO AI. A paper plane leaving. Inline this into markup,+       where currentColor inherits; if you load it as a file, swap to #e6edf3. -->+  <path d="M21.5 2.5 10.5 13.5"/>+  <path d="M21.5 2.5 14.8 21.5l-4.3-8-8-4.3z"/>+</svg>
package.json+5−2
@@ -1,6 +1,6 @@ {   "slug": "adom-ui-design",-  "version": "1.11.1",+  "version": "1.12.0",   "type": "skill",   "description": "The Adom UI Design System plus a bundle of focused UI skills (tooltips, floating-windows, toasts, responsive-ui, app-shell, ai-driven-apps, clickable-paths, dark-default, input-feedback, settings-layout). One install drops the whole set of skill files onto your container, plus shared icon assets (the settings cog) so every Adom app draws the same glyph.",   "dependencies": {},@@ -31,7 +31,10 @@     "skills/status-leds/SKILL.md",     "skills/dash-demo/SKILL.md",     "skills/icons/SKILL.md",-    "skills/newbie-panel/SKILL.md"+    "skills/newbie-panel/SKILL.md",+    "assets/icons/action-copy.svg",+    "assets/icons/action-send.svg",+    "assets/icons/action-play.svg"   ],   "scripts": {     "install": "./install.sh",
skills/dash-header/SKILL.md+50−3
@@ -38,13 +38,60 @@ This skill adds the dashboard-specific rulings the 2026-08-24 audit showed being   Same spot on every app so a user's eye learns it once. A full app served in-container   that cannot learn the box name (ab's cross-origin /status projection does not carry it   yet) says `target: this machine` honestly rather than guessing or hiding the chip.-- **The app mark and the tab favicon are the SAME line-drawing SVG**, per the **icons**+- **The app mark and the tab favicon are the SAME line-drawing SVG file**, per the **icons**   sub-skill: white or currentColor strokes on transparent, never the wrapped vendor's logo-  and never a filled colored badge. This is what the user sees at 16px in ah's tab strip,-  so a brand-colored plate there breaks the fleet look faster than anything on the page.+  and never a filled colored badge. Exact sizes and weights are in the numbers below. - **The ? lives left of the gear** and recalls the newbie scaffolding - see   **newbie-graduation**. Gear opens settings per **settings-layout**. +## The numbers (John's ruling, 2026-08-24, after pup and adom-lbr diverged)++Every dashboard header was drifting on size, weight, color and inset. These are the values.++**The bar itself**+- Height **44px**, and it runs **EDGE TO EDGE**. No left, top or right margin, no rounded+  corners, no gap above it: the header is the top of the window, not a card floating in it.+  (pup shipped with a margin on three sides; that is the defect this rule names.)+- `background: var(--surface)`, a single `1px solid var(--line)` bottom border, nothing else.+- Horizontal padding **16px** inside the bar. The bar is flush; its CONTENTS are inset.++**The app mark**+- **18x18**, and it is the SAME FILE as your `webview.favicon`, so the tab icon and the+  header icon are visibly one mark. A filled brand tile in the header beside a line icon in+  the tab strip is the inconsistency this rule kills.+- Line drawing per the **icons** skill. Inline it and let it inherit, or paint `#e6edf3`.+- `stroke-width: 1.8` at 24 viewBox units, so it matches the weight of the action icons.+  A mark drawn at 2.4 reads BOLD next to everyone else (adom-lbr shipped this way; pup's+  weight is the reference).++**The app name**+- Familjen Grotesk **600**, **15px**, `color: var(--text)`, `letter-spacing: -.01em`.+- Not teal, not the accent, not uppercase, not monospace. The name is text, not branding.+- The human name only: `Pup`, `Adom LBR`, `Chip Fetcher`. Never the slug.++**The subtitle**+- **13px**, `color: var(--muted)`, `font-weight: 400`, sitting **8px** after the name on the+  same baseline. Two to four plain words: `AI browser control`, `the KiCad bridge`.+- Hides below 720px, per **responsive-ui**.++**Right-hand controls**+- Icon buttons only, **18px** glyphs in **28x28** ghost buttons, `gap: 6px`,+  `margin-left: auto`. `var(--muted)` at rest, `var(--teal)` on hover.+- Order, left to right: the `target:` chip, then **?** (restores the newbie panel), then the+  settings cog. Same order on every app so the eye learns it once.+- The cog is `assets/icons/settings-cog-outline.svg` from this pack, unmodified. Do not+  substitute another gear: the whole point is that every Adom cog is the same cog.++**The target chip**+- Mono **12px**, `var(--muted)` label with the box name in `var(--text)`, an 8px LED dot+  inside, `border: 1px solid var(--line)`, `border-radius: 999px`, `padding: 3px 10px`.+- A full app served in-container that cannot learn the box name says `target: this machine`+  rather than guessing or hiding the chip.++**Ralph-test the header**: screenshot two apps' headers at the same width and overlay them.+The bar height, the icon size and weight, the name's size and color, the control order and+the cog must be indistinguishable. If you can tell which app is which from anything other+than the mark, the name and the subtitle, something is off-spec. ## Subtitle  Two to four words that say what the page is, in plain language: "the KiCad bridge",
skills/newbie-panel/SKILL.md+114−120
@@ -2,143 +2,137 @@ name: newbie-panel user-invocable: true description: >--  THE newbie panel every dock dashboard renders: one FULL-WIDTH band across the top of the-  page (never a narrow column squeezed beside the app's own UI), holding the sample AI-  prompts and the demo button. Defines when it shows, the X that hides it, the ? in the-  header that brings it back, where the demo button sits and what it looks like, how prompt-  rows are laid out, and the two ICON buttons on every prompt (copy, send to AI) with-  tooltips and toasts instead of text labels. Read BEFORE building or restyling the-  prompts/demo area of any dashboard. Trigger words: newbie panel, sample prompts panel,-  prompts area, say it panel, demo button, copy button, send to ai button, prompt row,-  dismiss panel, bring back help, onboarding panel, getting started panel.+  THE newbie panel every dock dashboard renders: ONE full-width, edge-to-edge band at the+  top of the page, split into TWO COLUMNS - the demo button on the left, the sample AI+  prompts on the right as a quiet TABLE (never pills, which go ragged when phrases differ in+  length). Prescribes every dimension so seven apps look identical: column widths, row+  height, type sizes and colors, the 16px line icons for copy and send (shipped as assets in+  this pack), tooltips, toasts, the single X that collapses it and the ? that restores it.+  Read BEFORE building or restyling the prompts/demo area of any dashboard. Trigger words:+  newbie panel, sample prompts panel, prompts table, say it panel, demo button, copy button,+  send to ai button, prompt row, dismiss panel, bring back help, onboarding panel. --- -Parent skill: **adom-ui-design** (layout partner to **say-strip**, **dash-demo**,-**newbie-graduation**, **icons**, **toasts**)+Parent skill: **adom-ui-design** (works with **dash-header**, **dash-demo**,+**newbie-graduation**, **icons**, **toasts**, **tooltips**)  # The newbie panel -John, 2026-08-24, looking at a dashboard that squeezed the prompts into a narrow left-column beside the app's own two-column UI:+John's ruling, 2026-08-24, reviewing pup and chip-fetcher side by side: -> "this looks not great. it seems to me the right column should not be showing and the-> whole width of the screen should have the newbie panel that has the sample ai prompts-> and the demo button."+> "one panel at the top of the page with 2 columns. the left column is the demo button. the+> right column is the sample ai prompts. the sample prompts should probably just be in a+> table layout since the pills are kinda ugly cuz the prompts are different lengths, so it+> gets too noisy." -The panel is a BAND, not a column. Text wrapping mid-phrase at 200px, six stacked rows-pushing the app off screen, buttons wider than the prompt they belong to: all of that is-the panel being asked to live in a column it was never designed for.+Pills were the mistake. Six phrases of different lengths in rounded chips, each trailed by+two buttons, produce a ragged staircase that reads as noise however good the copy is. A+table has one left edge, one right edge, and one row height, so the eye reads the PHRASES+instead of the boxes around them. -## Layout law--- **Full page width.** The panel spans the dashboard's content width, top of the page,-  above everything the app itself renders. It is never placed inside a sidebar, a split-  pane, or one column of the app's own grid.-- **While the panel is open, the app's own columns yield.** On a full app (chip-fetcher,-  lbr, parts-search) the panel pushes the app's UI DOWN; it does not sit beside it and it-  does not overlay it. A user in the fresh state is reading the panel, not the app.-- **Prompts flow, they do not stack.** Chips wrap left-to-right across the full width,-  three or four per row at desktop width, one per row only on a phone. A phrase must never-  wrap inside itself at desktop width; if it does, the panel is too narrow, which means it-  is in the wrong place.-- **Max width for readability:** cap the panel's inner content at about 1100px and center-  it on very wide screens, so phrases stay scannable.+## Anatomy  ```-┌──────────────────────────────────────────────────────────────────────────┐-│ Say it                                                                 ✕ │-│ You never need this page's buttons: just tell your AI, using the word cf.│-│                                                                          │-│  ▶ Play the 2-minute demo                                                │-│                                                                          │-│  "get me the files for the STM32H757 with cf"        ⧉  ➤                │-│  "plan a batch for my BOM with cf"                   ⧉  ➤                │-│  "find a 3.3V LDO in stock at mouser with cf"        ⧉  ➤                │-└──────────────────────────────────────────────────────────────────────────┘-        the app's own UI starts here, full width, below the panel+┌ panel: full content width, one card ────────────────────────────────────────────┐+│  Say it                                                                       ✕ │+│  You never need this page's buttons: just tell your AI, using the word pup.     │+│ ┌ left col, 220px ─┬ right col, flex ──────────────────────────────────────────┐│+│ │                  │  "open your dashboard in pup"                    ⧉    ➤   ││+│ │   ▶  Play the    │ ─────────────────────────────────────────────────────────  ││+│ │      demo        │  "open my wiki page in pup"                      ⧉    ➤   ││+│ │                  │ ─────────────────────────────────────────────────────────  ││+│ │   2 minutes      │  "screenshot this site in pup"                   ⧉    ➤   ││+│ └──────────────────┴───────────────────────────────────────────────────────────┘│+└─────────────────────────────────────────────────────────────────────────────────┘ ``` -## Two traps that make a full-width panel stay a column--Found the hard way by chip-fetcher, the first app to convert:--1. **The panel must be a SIBLING of the app body, outside the app's grid.** If it lives-   inside your `.app-grid` / two-column layout, it inherits a column and stays a column-   however wide you style it. `.newbie` and `.app-body` are siblings; the app body's top-   should measure equal to the panel's bottom.-2. **The demo button must fold WITH the panel.** It is part of the newbie surface, so a-   dismissed panel that leaves a stray demo button behind is half-collapsed and looks like-   a bug.--Measure rather than eyeball: at a wide viewport, assert panel width equals the content-width, inner content is capped near 1100, `appBody.top === panel.bottom`, and no chip is-taller than one line. At 390px, one chip per row and the icon buttons still in a 44px-target.--## The demo button--- **One button, inside the panel, directly under the explainer line and ABOVE the prompts.**-  The demo is the fastest path to understanding, so it comes before the reading material.-- Label: `Play the demo`, or with the real duration when you know it-  (`Play the 2-minute demo`). Never "Tour", "Walkthrough", "Start", or an emoji.-- Look: the panel's only PRIMARY button. Teal fill `--teal`, `--on-accent` text, radius 8,-  padding 9px 16px, with a small play glyph (line icon, per **icons**) to its left.-  Everything else in the panel is quiet, so the one filled button reads as the invitation.-- While the demo runs the panel stays put and the player toolbar appears per **dash-demo**;-  the button becomes a disabled "Demo running" state rather than vanishing.--## Prompt rows+## The numbers (copy them, do not re-derive them)++**Panel**+- Full content width, a SIBLING of the app body (never inside the app's grid, or it stays a+  column however wide you style it). The app's own UI begins below it.+- `background: var(--surface)`, `border: 1px solid var(--line)`,+  `border-left: 3px solid var(--teal)`, `border-radius: 12px`.+- `padding: 18px 20px 20px`. Outer margin `16px 0 20px`.+- Inner content `max-width: 1180px`, centered, so phrases stay scannable on a 32in monitor.++**Panel heading and explainer**+- Heading: the literal `Say it`, Familjen Grotesk 600, **15px**, `var(--text)`.+- Explainer: **13.5px**, `var(--muted)`, one sentence, `max-width: 70ch`, the app's noun in+  `var(--teal)` and bold.+- The `✕` sits top-right of the panel, 28x28 ghost button, `var(--muted)`, teal on hover.++**Columns**+- `display: grid; grid-template-columns: 220px 1fr; gap: 24px; align-items: start;`+- A `1px` vertical hairline (`var(--line)`) between the columns, drawn as a+  `border-left` on the right column, so the split reads without a heavy divider.+- Below **760px**: `grid-template-columns: 1fr`, demo button first, full width, hairline+  becomes a `border-top`.++**Left column: the demo button**+- The panel's ONLY filled button: `background: var(--teal)`, `color: var(--on-accent)`,+  `border-radius: 8px`, `padding: 10px 18px`, Familjen Grotesk 600 **14px**,+  `display: inline-flex; align-items: center; gap: 8px;`.+- Glyph: `action-play.svg` from this pack, **16px**, stroke 1.8, inherits the button color.+- Label `Play the demo`, or with the real duration `Play the 2-minute demo`. Never "Tour",+  "Walkthrough", "Start", never an emoji.+- Optional second line under the button: duration or step count, **12px**, `var(--muted)`.+- While the demo runs it becomes a disabled `Demo running` in the same footprint; it never+  disappears, and it folds WITH the panel when the panel collapses.++**Right column: the prompts table**+- A real table structure (`<table>` or `role="table"` rows), not a chip flow.+- Row: `height: 40px`, `border-bottom: 1px solid var(--line)`, none on the last row.+- Row hover: `background: rgba(255,255,255,.03)`, cursor pointer (the whole row copies).+- Phrase cell: **14px** body face, `var(--text)`, in curly quotes, the noun in `var(--teal)`,+  `white-space: nowrap; overflow: hidden; text-overflow: ellipsis;` so a long phrase+  truncates rather than wrapping and breaking the row rhythm. Full text in its `title`.+- Action cell: fixed **72px**, right-aligned, holding the two icon buttons with `gap: 6px`.+- 3 to 6 rows. More than six is a menu, not an invitation.++**The two icon buttons**+- Files: `assets/icons/action-copy.svg` and `assets/icons/action-send.svg` from THIS pack.+  Inline them (so `currentColor` inherits); do not draw your own.+- Icon **16px**, stroke 1.8, inside a **28x28** ghost button, `border-radius: 6px`,+  `border: 1px solid transparent`.+- Rest `color: var(--muted)`. Hover `color: var(--teal); border-color: var(--line);+  background: rgba(0,184,177,.08)`. Focus-visible: 2px teal outline.+- Touch: keep the 28px button inside a 44px hit area with padding, per **responsive-ui**.+- **Icon + tooltip + toast is one contract, never ship one without the other two:**+  - `action-copy`: tooltip and `aria-label` `Copy this prompt to your clipboard`; on click,+    copy then the success toast `Copied to clipboard. Paste it into any AI thread.`+  - `action-send`: tooltip and `aria-label` `Send this prompt to a new AI thread`; on click,+    open a NEW thread and submit, then `Sent to a new AI thread.` On failure, error toast+    plus the copy fallback (see **say-strip**). Currently PARKED fleet-wide: the backend+    refuses before any control-API call and the button falls back to copy.+- Tooltips follow the **tooltips** skill: 600ms delay, body-appended fixed div, clamped to+  the viewport. -Each row is the phrase, then its two buttons, right-aligned in a fixed column so the-buttons form a clean vertical pair down the panel:--- Phrase in curly quotes, body face, never monospace, with the app's noun in `--teal`-  (see **say-strip** for the wording rules).-- Clicking the PHRASE itself copies, same as the copy button. Largest target, safest action.-- The two buttons are **ICONS, not words** (John's ruling): text labels like "Copy" and-  "Send to AI" repeated six times eat the width the phrases need. Icons keep the row to one-  line and let the panel breathe.--## The two icon buttons--Both are line icons per the **icons** skill: 16px, `fill="none"`,-`stroke="currentColor"` (they are inlined into your markup, so inheritance works),-stroke-width 1.8, in a 28x28 ghost button, `--muted` at rest and `--teal` on hover.--| Button | Glyph | Tooltip | On click |-|---|---|---|---|-| **Copy** | two offset rounded rectangles | `Copy this prompt to your clipboard` | Copy, then the success toast `Copied to clipboard. Paste it into any AI thread.` |-| **Send to AI** | a paper-plane / arrow leaving a line | `Send this prompt to a new AI thread` | Open a NEW thread and submit, then `Sent to a new AI thread.` On failure: error toast plus the copy fallback (see **say-strip**) |+## Showing, hiding, bringing back -Rules that make icon buttons legible rather than cryptic:+- Fresh dashboards show the panel expanded (**newbie-graduation** State 1).+- ONE `✕`, top-right of the panel, collapses the WHOLE panel (heading, explainer, demo,+  table) to a single quiet line: `Say it: 6 phrases`, tappable to expand for the session.+  Never an X per section.+- The `?` in the header, left of the settings cog, restores the Fresh panel for the session.+- The collapsed one-liner never disappears entirely: it is the user's thread back to+  "you can just say it".+- Auto-graduation folds it the same way a dismissal does; the localStorage key MUST be+  namespaced with your app slug. -- **Every icon button carries a tooltip** (600ms, per the **tooltips** skill) AND an-  `aria-label` with the same words. An icon with no tooltip is a guessing game.-- **Every click answers with a toast** (see **toasts**), because an icon gives no built-in-  confirmation the way a labelled button does. Icon + tooltip + toast is one contract:-  never ship the icon without the other two.-- On touch, where hover cannot happen, the tooltip text is reachable by long-press and the-  toast does the explaining. Keep the 28px button inside a 44px touch target.+## Two traps that keep a full-width panel a column -## Showing, hiding, bringing back+Found by chip-fetcher, the first app to convert: -- **Shows** on a fresh dashboard, expanded, per **newbie-graduation**'s Fresh state.-- **Hidden** by ONE `✕` at the panel's top-right, which collapses the WHOLE panel (prompts,-  demo, explainer) to a single quiet line: `Say it: 6 phrases`, tappable to expand for the-  session. One X for the whole panel is the sanctioned shape, not an X per section.-- **Brought back** by the `?` in the app header, left of the settings cog (see-  **dash-header**). It restores the Fresh panel for the current session; the user's-  dismissal is remembered across reloads until they ask for it again.-- The collapsed one-liner NEVER disappears entirely: it is the user's thread back to-  "you can just say it", which is the whole point of the dashboard.-- Auto-graduation (3 green launches, first AI-driven action) folds the panel the same way a-  dismissal does. See **newbie-graduation** for the triggers and the localStorage key,-  which MUST be namespaced with your app slug.+1. **The panel must be a SIBLING of the app body**, outside the app's grid, or it inherits a+   column however wide you style it. Assert `appBody.top === panel.bottom`.+2. **The demo button must fold WITH the panel.** A dismissed panel that leaves a stray demo+   button behind looks like a bug.  ## Ralph-test -Open the dashboard at 1400px and at 390px and LOOK: the panel spans the full width, no-phrase wraps inside itself, the demo button is the only filled button, and the app's own UI-starts below the panel rather than beside it. Hover both icon buttons and read the-tooltips. Click each and watch for the toast. Press ✕, confirm the one-liner, reload,-confirm it stayed collapsed, press ?, confirm Fresh returns.+At 1400px: panel spans the content width, two columns with the hairline between them, every+row exactly 40px, phrases truncating rather than wrapping, one filled button on the page.+At 390px: one column, demo first, icons still in a 44px target. Hover both icons and read+the tooltips; click each and watch for the toast. Press `✕`, confirm the one-liner, reload,+confirm it stayed collapsed, press `?`, confirm Fresh returns.