From 4b67a171cf9d8157e3a3554bb5f84244e6c5d4e6 Mon Sep 17 00:00:00 2001 From: inkko44 Date: Tue, 14 Jul 2026 11:05:34 -0400 Subject: [PATCH] feat(bolt-slides): sidebar icon, grid view, mobile dock restack, auto deck title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BOU-2200: the dock's rail toggle used a 2x2 grid icon that read as a grid view — it now uses a proper sidebar icon, and the grid icon opens a real full-screen grid view of all slides (G). Sidebar moves to S, annotate to A. BOU-2201: shared decks kept the placeholder tab title. The skill now sets the title + emoji favicon unprompted, index.html ships a placeholder favicon, and the Deck derives a title from the cover heading as a runtime safety net. Also from review feedback: thumbnails measure pre-paint (useLayoutEffect) so the grid opens without a resize snap; on phones the dock restacks with nav floating above the tools pill, and the annotation toolbar becomes a single scrollable row with mouse drag-to-scroll. Co-Authored-By: Claude Fable 5 --- bolt-slides/.bolt/skills/slides/SKILL.md | 9 +- bolt-slides/README.md | 2 +- bolt-slides/index.html | 5 + bolt-slides/src/deck/Annotator.tsx | 43 ++++++- bolt-slides/src/deck/Deck.tsx | 146 +++++++++++++++++------ bolt-slides/src/deck/icons.tsx | 7 ++ bolt-slides/src/styles/base.css | 101 ++++++++++++++-- 7 files changed, 269 insertions(+), 44 deletions(-) diff --git a/bolt-slides/.bolt/skills/slides/SKILL.md b/bolt-slides/.bolt/skills/slides/SKILL.md index 29a0328..99b6e5b 100644 --- a/bolt-slides/.bolt/skills/slides/SKILL.md +++ b/bolt-slides/.bolt/skills/slides/SKILL.md @@ -92,6 +92,11 @@ Dark vs light: set `html { color-scheme }` in base.css and pick `--bg`/`--fg` accordingly. Set fonts in `--font-head`/`--font-body` and the `@import` at the top of `base.css`. Derive from the brand when given. +**Tab title + icon — always, unprompted.** Shared decks show the browser tab, so +never leave the `index.html` placeholders: set `` to the deck's real title +(e.g. "Acme — Series A") and swap the emoji in the favicon `<link>` to one that +fits the topic. Do this for every deck without being asked. + --- ## Step 3 — Author slides (each child of `<Deck>` is one slide) @@ -288,12 +293,14 @@ trigger or that it exists — just deliver the demo. - [ ] The engine + chrome in `src/deck/` are **left untouched**; the dock + thumbnail rail appear, arrow keys advance AND step back through builds, - fullscreen / overview work, annotation (D) has full tools and + fullscreen / sidebar (S) / grid view (G) work, annotation (A) has full tools and persists per slide, presenter (P) opens a synced new tab, `H` hides the UI, and the URL hash tracks the slide. - [ ] The deck is **authored, not reskinned** — topic, structure, copy, names are the user's, with no starter leftovers (no "Title"/"Northwind"). - [ ] If a brand/URL was given, `--primary`, fonts, and logo come from that brand. +- [ ] `index.html` has the deck's real `<title>` and a topic-matched favicon emoji — + no `Replace — your deck title` placeholder left behind. - [ ] Only the `:root` block was edited for the theme; editing `--primary` recolors everything incl. the dock. - [ ] Slides compose like web sections (full-bleed/asymmetric/bento/split), not diff --git a/bolt-slides/README.md b/bolt-slides/README.md index 3d42c45..14ff16d 100644 --- a/bolt-slides/README.md +++ b/bolt-slides/README.md @@ -2,7 +2,7 @@ A Bolt skill that builds a premium, **responsive React presentation deck** — classic paged slides you present one at a time, with a Slidev-style floating dock + thumbnail -rail, click-builds, annotation, and presenter mode — but each slide is a +rail, grid overview, click-builds, annotation, and presenter mode — but each slide is a responsive web layout (no fixed canvas, no clipping) built from a rich component library. diff --git a/bolt-slides/index.html b/bolt-slides/index.html index 56383bc..fb4074a 100644 --- a/bolt-slides/index.html +++ b/bolt-slides/index.html @@ -3,7 +3,12 @@ <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <!-- Always replace the title + favicon emoji to match the deck topic --> <title>Replace — your deck title + diff --git a/bolt-slides/src/deck/Annotator.tsx b/bolt-slides/src/deck/Annotator.tsx index 0e4eb09..c37e1e3 100644 --- a/bolt-slides/src/deck/Annotator.tsx +++ b/bolt-slides/src/deck/Annotator.tsx @@ -370,6 +370,39 @@ export default function Annotator({ redraw(); } + // drag-to-scroll for the bar when it overflows (phones scroll natively by + // touch; this covers mouse users). A 4px threshold keeps clicks working, + // and a capture-phase click handler swallows the click after a real drag. + const barRef = useRef(null); + const barDrag = useRef({ down: false, moved: false, x: 0, left: 0 }); + function barDown(e: React.PointerEvent) { + if (e.pointerType !== 'mouse' || !barRef.current) return; + barDrag.current = { + down: true, + moved: false, + x: e.clientX, + left: barRef.current.scrollLeft, + }; + } + function barMove(e: React.PointerEvent) { + const d = barDrag.current; + if (!d.down || !barRef.current) return; + const dx = e.clientX - d.x; + if (!d.moved && Math.abs(dx) < 4) return; + d.moved = true; + barRef.current.scrollLeft = d.left - dx; + } + function barUp() { + barDrag.current.down = false; + } + function barClickCapture(e: React.MouseEvent) { + if (barDrag.current.moved) { + e.preventDefault(); + e.stopPropagation(); + barDrag.current.moved = false; + } + } + return ( <> {active && ( -
+
{TOOLS.map((t) => ( +
+ {slide + 1} + / {total} +
+ + + ); + return (
@@ -370,6 +428,36 @@ export default function Deck({ children }: { children: ReactNode }) {
+ {gridOpen && ( +
+
+ All slides + +
+
+ {slides.map((s, i) => ( + + ))} +
+
+ )} + {isPresenter && (
@@ -397,39 +485,29 @@ export default function Deck({ children }: { children: ReactNode }) { )}
+ {/* phones: nav floats bare above the tools pill (see base.css) */} +
{navCluster}
- - -
- {slide + 1} - / {total} -
+
{navCluster}
+