← Commit history

1.13.0: panel fully closes with a header TOGGLE; demo toolbar lives in the panel and never uses monospace; never ship title plus a custom tooltip

John Lauer ·e9a4c0ae12 ·1mo ago ·parent 7f64219
5 files changed +68−22
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "adom-ui-design",-  "version": "1.12.1",+  "version": "1.13.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": {},
skills/dash-demo/SKILL.md+19−4
@@ -65,12 +65,26 @@ A demo is a JSON list of steps. Everything else (player, audio, captions) is gen  ## The player toolbar -Visible whenever the demo is running, hidden otherwise:+**It lives INSIDE the newbie panel, directly below the "Play the demo" button, in the left+column** (John's ruling, 2026-08-24). Not floating bottom-centre, not docked to the window,+not overlaying the page. The demo is launched from that button, so its transport belongs in+the same block: the user's eye never leaves the place they started.++Visible whenever the demo is running, absent otherwise (the button above it becomes the+disabled `Demo running` state, per **newbie-panel**):  ```-[ ⏮ prev ] [ ⏯ play/pause ] [ ⏭ next ] | [ 🔊 mute ] | step 3/8 | [ ✕ exit ]+[ ⏮ ] [ ⏯ ] [ ⏭ ]   [ 🔇 ]   step 3/8   [ ✕ ] ``` +**Typography, and this is not optional: NEVER a monospace or Courier face anywhere in the+demo UI.** Pup shipped its toolbar and step counter in Courier and it read as a terminal+bolted onto a designed page. The toolbar uses the body face at **12.5px** for the step+counter (`var(--muted)`, `font-variant-numeric: tabular-nums` so `3/8` does not jitter as it+counts), and the controls are 16px line glyphs in 28x28 ghost buttons, the same buttons as+everywhere else. Monospace is reserved for genuine machine text (versions, paths, IDs), and a+step counter is not machine text.+ - **play/pause**: pause freezes the action where safe, pauses audio mid-word, keeps the   caption up. Resume continues the same step. - **prev/next**: jump step boundaries. Audio for the old step stops instantly; the new@@ -78,8 +92,9 @@ Visible whenever the demo is running, hidden otherwise: - **exit**: stop everything, clear the ab caption, stop audio, restore whatever the demo   moved (windows, tabs, state), return the dashboard to rest. Exit must be safe at ANY   step - ralph-test it from the middle of the most destructive step.-- Toolbar style: house tokens, fixed bottom-center of the dashboard, small; it is a-  remote control, not a feature. Buttons follow the input-feedback skill.+- Toolbar style: house tokens, in the panel's left column under the demo button, small; it+  is a remote control, not a feature. Buttons follow the input-feedback skill, and every one+  of them carries a tooltip and an aria-label like any other icon button.  ## Where the demo lives on the page 
skills/newbie-graduation/SKILL.md+8−7
@@ -29,11 +29,11 @@ dashboard's newbie job is to hand the user to their AI.  1. **Fresh** (default on first visit): say strip expanded, getting-started panel open,    demo buttons prominent. The dashboard teaches.-2. **Graduated**: each scaffold collapses to a single quiet line ("Say it - 6 phrases",-   one row, tap to expand once). Getting-started and demo sections fold to their headings.-   The app's real content moves up.-3. **Recallable**: the header's **?** (left of the gear, see dash-header) restores Fresh-   for the current session, then the page folds back. Nothing is ever unreachable.+2. **Graduated**: the newbie panel CLOSES completely (no one-liner, no stub) and the app's+   real content moves up to fill the space. The header toggle is how it comes back.+3. **Recallable**: the header TOGGLE (left of the gear, see dash-header) brings the panel+   back, and pressing it again closes it. It is a true toggle with a visible pressed state,+   not a one-way restore. Nothing is ever unreachable.  ## Graduation triggers (any one graduates that scaffold) @@ -78,8 +78,9 @@ when storage is empty or unreadable - the safe default is teaching.  - The status LED row (see status-leds): health is not scaffolding. - The header, the gear, the ?.-- The say strip's collapsed one-liner: even a graduated page keeps one visible thread back-  to "you can just say it".+- The header toggle: even a fully-closed panel leaves one visible, labelled way back to+  "you can just say it". That control is the thread back, which is why the panel itself may+  close completely.  ## Ralph-test 
skills/newbie-panel/SKILL.md+20−10
@@ -111,14 +111,23 @@ instead of the boxes around them. ## Showing, hiding, bringing back  - 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.+- ONE `✕`, top-right of the panel. It **FULLY CLOSES the panel: no residual one-liner, no+  stub, nothing left behind** (John's ruling, 2026-08-24: "when i close the newbie panel, i+  think it should fully close"). The app's own UI moves up to fill the space. An earlier+  version of this skill said it collapsed to a `Say it: 6 phrases` line; that is retired.+- **The header carries a TOGGLE that brings it back, and it behaves like a toggle**, not a+  one-way "show" button (John, same ruling: "if a header is going to have this button, which+  i like, it needs to act as a toggle button"). Requirements:+  - It sits left of the settings cog, 18px line glyph in a 28x28 ghost button.+  - It reflects state in at least TWO ways, per the **input-feedback** skill: `aria-pressed`+    true/false plus a visible difference (teal glyph and a subtle inset background when the+    panel is open, muted when closed). A toggle that looks identical in both states is a lie.+  - Its tooltip and `aria-label` change with state: `Hide the prompts panel` when open,+    `Show the prompts panel` when closed.+  - Pressing it when the panel is open closes it, exactly as the `✕` does. Both controls+    drive the same state; they never drift apart.+- The choice persists across reloads (namespaced localStorage, see **newbie-graduation**),+  and auto-graduation closes it the same way a dismissal does.  ## Two traps that keep a full-width panel a column @@ -134,5 +143,6 @@ Found by chip-fetcher, the first app to convert: 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.+the tooltips; click each and watch for the toast. Press `✕`, confirm the panel is GONE with no stub and the app UI moves up, reload, confirm+it stayed closed, press the header toggle, confirm the panel returns AND the toggle's own+appearance changed, press it again, confirm it closes.
skills/tooltips/SKILL.md+20
@@ -27,6 +27,26 @@ thing you are trying to read, or shouting in all caps. This skill is the one cor > tiered to the owner HUD) are plausible-sounding ideas that keep getting reinvented and keep > breaking. Use the body-appended fixed-div renderer below and nothing else. +## ⚠ NEVER ship `title` AND a custom tooltip on the same element++Found live on 2026-08-24: hovering a Send-to-AI button produced TWO tooltips, the styled+Adom one and the browser's own native yellow box, overlapping each other.++The cause is always the same: the element carries a `title` attribute AND a custom tooltip+(`data-tooltip`, a JS handler, a component wrapper). The browser renders `title` natively+after its own delay, on top of yours, in its own style, at its own position, and it cannot+be styled or suppressed once it fires.++- **Pick ONE.** In an Adom app that is the custom tooltip, because it obeys the 600ms delay,+  the house styling, the z-index ladder and the viewport clamp.+- **Use `aria-label` for the accessible name**, never `title`, so screen readers get the text+  without the browser painting a second box.+- If a component library adds `title` for you, strip it (`el.removeAttribute('title')` after+  mount, or pass the prop that disables it).+- Audit before shipping: `document.querySelectorAll('[title][data-tooltip]')` must return+  zero, and hover every icon button once and count the boxes. Two is a bug.++ ## 1. Every interactive element gets a descriptive tooltip  Buttons, icon-only controls, labels with jargon, and any non-obvious widget MUST carry a