mirror of
https://github.com/PR0M3TH3AN/Artstr-Studio.git
synced 2026-10-27 08:40:39 +00:00
Draft slide-deck & presenter-mode feature plan
- docs/SLIDE_DECK_FEATURE.md: phased spec for Slide Designer (16:9 canvas + speaker notes), Deck Builder (embedded ordered slides, slide-sorter view, deck theme), and Presenter Mode (single-window v1, dual-window deferred to Phase E). Phases A-D with ship gates. - Select tool icon changed to a rotated arrowhead so it reads as a cursor, not a play button (distinct from the planned Present icon). Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
1 parent
c872b5210d
commit
06c5ab6768
2 files changed
+437
-1
No files matched your search
@@ -0,0 +1,436 @@
|
||||
# Slide Decks & Presenter Mode
|
||||
|
||||
## Goals
|
||||
|
||||
Add a presentation system to Artstr Studio: design individual **slides**,
|
||||
assemble them into an ordered **deck**, and run a **presenter mode** to show
|
||||
the deck — all Nostr-native, forkable, and driven entirely off JSON data.
|
||||
|
||||
### Product goals
|
||||
|
||||
1. A **Slide Designer** — a 16:9 design surface (a flat canvas, like Custom
|
||||
Art) with an added **speaker-notes** field. A slide is a first-class
|
||||
Nostr design: publishable, forkable, loadable.
|
||||
2. A **Deck Builder** — a container that holds an ordered, variable-length
|
||||
list of slides. The deck embeds its slides' full data inline, so it is a
|
||||
single self-contained file. Slides can be imported from published
|
||||
designs and extracted back out as standalone designs.
|
||||
3. A **deck-level theme** that overrides per-slide styling (fonts,
|
||||
background) across the whole deck — with a per-slide opt-out so an
|
||||
individual slide can keep its own look.
|
||||
4. A **Presenter Mode** that plays the deck full-screen with speaker notes
|
||||
and slide navigation.
|
||||
|
||||
### Non-goals (v1)
|
||||
|
||||
- **Dual-window presenter view** (audience window + a separate presenter
|
||||
window with notes on a second screen). This is the real presenting
|
||||
experience and is the explicit Phase E follow-up — v1 is single-window.
|
||||
- Slide **transitions / animations / builds** (step-by-step reveals).
|
||||
- A presenter **timer / rehearsal stats / laser pointer**. Phase E+.
|
||||
- **Rich-text** speaker notes — plain text for v1.
|
||||
- Importing PowerPoint / Keynote / PDF decks.
|
||||
- **Exporting** a deck to PDF or slideshow video. A natural future ask, but
|
||||
not v1 — Presenter Mode is the v1 way to show a deck. (Individual slides
|
||||
still export as images like any Custom Art design.)
|
||||
- A per-property theme matrix — v1 theme overrides a small fixed set
|
||||
(font family, background); per-property locking is future polish.
|
||||
|
||||
---
|
||||
|
||||
## Why this fits the repo
|
||||
|
||||
This is the **disc pattern generalized**. A disc-label *sheet*
|
||||
(`templateMode: 'disc'`) embeds the disc designs assigned to its slots and
|
||||
is self-contained for printing; disc *designs* (`appMode: 'designer'`) are
|
||||
also independently publishable and importable. A deck/slide pair works the
|
||||
same way:
|
||||
|
||||
- **Slide** ⇄ disc design — a standalone, publishable design.
|
||||
- **Deck** ⇄ disc-label sheet — a Template-tab container that embeds the
|
||||
designs it holds.
|
||||
|
||||
Everything a deck needs already exists in some form:
|
||||
|
||||
- The **canvas editor** edits a slide unchanged — a slide is mechanically a
|
||||
Custom Art canvas locked to 16:9. Layers, text, shapes, the pen tool,
|
||||
undo/redo, fit-to-view all apply for free.
|
||||
- The **persist/load-on-switch** pattern (`persistCurrentDiscDesign` /
|
||||
`loadCurrentDiscDesignLayers`) is exactly how editing one slide inside a
|
||||
deck will work — swap the editor's `state.layers` for the active slide,
|
||||
write back on switch.
|
||||
- The **import-a-design-into-a-slot** flow (disc design → disc slot) is the
|
||||
model for "add a published design as a slide."
|
||||
- **Publish / fork / community browser / Lightning** all reuse as-is.
|
||||
|
||||
The genuinely new surfaces are the **slide sorter** (the Deck Builder view)
|
||||
and the **presenter runtime**.
|
||||
|
||||
### Current-state facts the plan is built on
|
||||
|
||||
- `appMode`: `'template' | 'designer'`. `templateMode`:
|
||||
`'cover' | 'disc' | 'jewel' | 'customart'`.
|
||||
- The **Designer tab** is shown when `appMode === 'designer'` *or*
|
||||
`templateMode === 'customart'`. The **Template tab** otherwise.
|
||||
- Each tab has a Layout panel: `layoutFieldset` (Template — Case cover /
|
||||
Disc labels) and `designerLayoutFieldset` (Designer — Custom Art / Disc
|
||||
Design). `applyLayout()` maps a layout choice to the right
|
||||
`appMode`/`templateMode` and crosses app modes when needed.
|
||||
- Custom Art canvas state: `state.customArt = { width, height, background,
|
||||
preset }`, rendered on `#sheet`; payload via `customArtPayload()`.
|
||||
- Designs publish as kind-30078 parameterized replaceable events tagged
|
||||
`casewrap-<mode>`, with the `d`-tag mode-prefixed.
|
||||
- Save discriminator (`templateMode` in payloads): `cover`, `disc`,
|
||||
`jewel`, `customart`, `disc-design`.
|
||||
- All image references are remote URLs — never embedded binary. A deck is
|
||||
therefore N slides of *layer JSON*, not megabytes of image data.
|
||||
|
||||
---
|
||||
|
||||
## Framing within Template / Designer
|
||||
|
||||
Per the decision to keep the existing tab framing (even though a deck is a
|
||||
*sequence*, not a print artboard — the distinction stays intentionally
|
||||
muddy for now):
|
||||
|
||||
- **Slide Designer** — a new layout option in the **Designer tab** Layout
|
||||
panel, beside Custom Art and Disc Design. Runs as
|
||||
`appMode: 'template', templateMode: 'slide'`. The Designer-tab visibility
|
||||
test extends to `… || templateMode === 'slide'`.
|
||||
- **Deck Builder** — a new layout option in the **Template tab** Layout
|
||||
panel, beside Case cover and Disc labels. Runs as
|
||||
`appMode: 'template', templateMode: 'deck'`.
|
||||
|
||||
This mirrors disc design (Designer) vs disc-label sheet (Template): the
|
||||
standalone authored thing lives on the Designer side, the container that
|
||||
holds many of them lives on the Template side.
|
||||
|
||||
Two new `templateMode` values — `slide` and `deck` — are added to
|
||||
`applyLayout()`, `WORKFLOW_ORDER`, the layout panels, the body-class /
|
||||
visibility logic, and the save discriminator set.
|
||||
|
||||
---
|
||||
|
||||
## Data model
|
||||
|
||||
### Slide design (standalone — `templateMode: 'slide'`)
|
||||
|
||||
```js
|
||||
{
|
||||
version: SCHEMA_VERSION,
|
||||
templateMode: 'slide',
|
||||
templateType: 'slide',
|
||||
meta: { … }, // title / category / language, as usual
|
||||
slide: {
|
||||
width: 1920, height: 1080, // 16:9, fixed aspect
|
||||
background: '#ffffff',
|
||||
notes: '' // plain-text speaker notes
|
||||
},
|
||||
layers: [ … ] // standard layer array
|
||||
}
|
||||
```
|
||||
|
||||
A slide is a Custom Art canvas with a `slide` object instead of `customArt`,
|
||||
the addition being `notes`. Rendered on `#sheet`. The aspect is locked 16:9
|
||||
(width/height adjustable for resolution, but the ratio holds).
|
||||
|
||||
### Deck (`templateMode: 'deck'`)
|
||||
|
||||
```js
|
||||
{
|
||||
version: SCHEMA_VERSION,
|
||||
templateMode: 'deck',
|
||||
templateType: 'deck',
|
||||
meta: { … }, // deck title / category / language
|
||||
deck: {
|
||||
theme: {
|
||||
fontFamily: '', // '' = no override
|
||||
background: '', // '' = no override (color or image URL)
|
||||
// small fixed set for v1; extensible
|
||||
},
|
||||
slides: [
|
||||
{
|
||||
name: 'Intro', // optional label shown in the sorter
|
||||
slide: { width, height, background, notes },
|
||||
layers: [ … ],
|
||||
ignoreDeckTheme: false // true = this slide keeps its own look
|
||||
},
|
||||
… // ordered, variable length
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- The deck **embeds each slide's full data inline** — it is one
|
||||
self-contained file. Presenter mode and previews never depend on N
|
||||
external events resolving.
|
||||
- A slide object inside `deck.slides[]` is the same shape as a standalone
|
||||
slide design's `{ slide, layers }`, plus an optional `name` and
|
||||
`ignoreDeckTheme`. Embedded slides carry **no `meta`** of their own — the
|
||||
deck's `meta` covers the whole deck.
|
||||
- **Import** copies a published design's `{ slide?/customArt, layers }` into
|
||||
a new `deck.slides[]` entry (see surface #2 for cross-aspect handling).
|
||||
**Extract** lifts one entry back out into a standalone slide design for
|
||||
separate publishing.
|
||||
|
||||
### Nostr
|
||||
|
||||
- Slide: kind-30078, tag `casewrap-slide`, `d`-tag `slide:<title|id>`.
|
||||
- Deck: kind-30078, tag `casewrap-deck`, `d`-tag `deck:<title|id>`.
|
||||
- Both are forkable and editable-in-place via the existing NIP-33 flow.
|
||||
- Schema version bumps; `slide` / `deck` / `notes` / `ignoreDeckTheme` are
|
||||
additive — old clients ignore unknown payloads.
|
||||
|
||||
---
|
||||
|
||||
## The surfaces
|
||||
|
||||
### 1. Slide editor
|
||||
|
||||
The existing canvas editor, opened on a 16:9 slide. The Designer-tab Layout
|
||||
panel's "Slide Designer" option gives a Canvas-style panel (resolution
|
||||
presets — 1920×1080, 1280×720 — background) **plus a "Speaker notes"
|
||||
textarea**. Notes save into `slide.notes`. Nothing else changes — it is the
|
||||
Custom Art editor with a locked aspect and one extra field.
|
||||
|
||||
When a slide is opened **from within a deck**, the panel shows a small
|
||||
notice that the deck theme will restyle fonts/background in the deck and
|
||||
presenter views — so the un-themed editor view isn't a surprise.
|
||||
|
||||
### 2. Deck Builder (the slide sorter)
|
||||
|
||||
A new view for `templateMode === 'deck'`. The canvas area shows a
|
||||
**reorderable grid of slide thumbnails**; the sidebar holds deck title and
|
||||
theme controls.
|
||||
|
||||
- **Add slide** — new blank slide · import from a published design · import
|
||||
from the community browser. Imports land on a 16:9 slide: a 16:9 source
|
||||
(slide / Custom Art) fills it; any other aspect (cover, square, …) is
|
||||
scaled to fit and centered, letterboxed.
|
||||
- **Reorder** — drag thumbnails.
|
||||
- **Duplicate / Delete** a slide.
|
||||
- **Edit a slide** — clicking a thumbnail opens it in the canvas editor
|
||||
(surface #1). The deck tracks `state.deck.editingIndex`; entering edit
|
||||
loads that slide into editor state, and a "Back to deck" control persists
|
||||
it back — the `persistCurrentDiscDesign`/`loadCurrentDiscDesignLayers`
|
||||
pattern. The active slide is persisted before *any* save, publish,
|
||||
reorder, or present.
|
||||
- **Thumbnails** are mini-renders via the existing slide preview-DOM
|
||||
renderer + `fitMiniPreview`. Only the edited slide's thumbnail re-renders
|
||||
on write-back — not the whole grid.
|
||||
- **Canvas chrome** — in the sorter view the bottom zoom bar and the right
|
||||
tool-options panel are hidden (nothing to zoom or configure); the left
|
||||
tool palette shows just the **Present** (▶) action button (see surface
|
||||
#3). Full chrome returns when a slide is opened in the canvas editor.
|
||||
- **Undo** uses the app's single history stack: sorter operations
|
||||
(add / delete / reorder) and slide edits are ordinary entries; undoing an
|
||||
entry made in the other view switches to that view first.
|
||||
- The sorter is its own view; a Keynote-style always-visible filmstrip
|
||||
alongside the canvas is deferred polish.
|
||||
|
||||
### 3. Presenter Mode (v1 — single window)
|
||||
|
||||
**Entry points.** Presenter Mode launches from a **Present** button — a play
|
||||
glyph (`▶`) — used consistently in two places:
|
||||
|
||||
- **In the editor** — a button in the left **tool palette**, in the slot
|
||||
where the drawing tools normally sit. It is shown whenever a deck is
|
||||
active (the Deck Builder sorter, and while editing one of the deck's
|
||||
slides), so you can jump straight to presenting. It is an *action*, not a
|
||||
tool mode.
|
||||
- **In the template browser** — a **Start Presentation** button on a deck's
|
||||
full preview page (`openDesignPreview`), beside Use/Fork · Share · Save
|
||||
JSON, using the same `▶` icon. This lets anyone present a published deck
|
||||
straight from the browser without forking it first.
|
||||
|
||||
Both entry points run the same full-screen runtime (Fullscreen API):
|
||||
|
||||
- The current slide is drawn with the **existing slide / Custom-Art
|
||||
preview-DOM renderer**, scaled to fill the viewport (letterboxed to 16:9)
|
||||
— no new slide renderer is needed.
|
||||
- **Speaker notes** for the current slide in a side/bottom panel, with a
|
||||
toggle to hide them (e.g. when projecting this same window).
|
||||
- A **next-slide thumbnail** and a **slide counter** (`3 / 12`).
|
||||
- Navigation: on-screen prev/next, arrow keys / space, `Esc` to exit.
|
||||
Presenter mode **owns the keyboard** while active — the editor's tool and
|
||||
layer shortcuts (V/P/B, arrows, Delete, …) are suppressed until it exits.
|
||||
- The deck theme is composed in (see below) — presenter mode shows the
|
||||
fully themed slide.
|
||||
|
||||
v1 is single-window: good for rehearsal, review, and casual presenting.
|
||||
The true projector experience (audience window + separate presenter window
|
||||
with notes) is **Phase E**.
|
||||
|
||||
### 4. Deck in the community browser
|
||||
|
||||
A published deck is a normal kind-30078 event, so it appears in the feed
|
||||
like any design — which means it needs preview support:
|
||||
|
||||
- **Feed-card thumbnail** — the first slide's mini-render, with a
|
||||
slide-count badge (e.g. `12 slides`) so a deck reads as a deck at a
|
||||
glance.
|
||||
- **Publish-confirm preview** — likewise the first slide.
|
||||
- **Full preview page** (`openDesignPreview`) — carries the **Start
|
||||
Presentation** button (surface #3) alongside Use/Fork · Share · Save JSON.
|
||||
|
||||
These hook into the existing per-mode preview renderers and feed-card
|
||||
builder; `deck` joins `MODE_LABELS` and the community mode filters.
|
||||
|
||||
---
|
||||
|
||||
## Theme composition
|
||||
|
||||
The deck theme is applied at **render time**, non-destructively — the slide
|
||||
JSON is never mutated.
|
||||
|
||||
- `deck.theme` carries a small fixed set for v1: `fontFamily`, `background`.
|
||||
- When a slide is rendered **in a deck context** (deck thumbnails, presenter
|
||||
mode), each themed property resolves as:
|
||||
|
||||
```
|
||||
effective = slide.ignoreDeckTheme ? slideValue
|
||||
: (deck.theme.<prop> || slideValue)
|
||||
```
|
||||
|
||||
e.g. a text layer's font = the deck theme font unless the slide opts out
|
||||
or the theme leaves it blank.
|
||||
- The **slide editor shows the raw slide** (no theme) — the theme only
|
||||
exists in the deck. This keeps the editor simple and the slide reusable
|
||||
across decks with different themes. When the slide is opened from a deck,
|
||||
the editor shows a notice that the theme will restyle it elsewhere
|
||||
(surface #1) so the editor/presenter mismatch isn't surprising.
|
||||
- `ignoreDeckTheme` is a per-slide boolean for v1 (whole-slide opt-out).
|
||||
Per-property locking is a future refinement.
|
||||
|
||||
Because it is pure JSON composition, the same logic serves deck thumbnails,
|
||||
presenter mode, and any future export.
|
||||
|
||||
---
|
||||
|
||||
## Phased delivery
|
||||
|
||||
### Phase A — Slide format
|
||||
- `templateMode: 'slide'`; 16:9 canvas; `slide` object with `notes`.
|
||||
- Slide Designer option in the Designer-tab Layout panel.
|
||||
- Canvas panel with resolution presets + the Speaker notes textarea.
|
||||
- Save / load / publish / fork a standalone slide design (`casewrap-slide`).
|
||||
|
||||
**Ship gate:** create a 16:9 slide with notes, publish it, load it back —
|
||||
notes round-trip; it shows in the community browser.
|
||||
|
||||
> Note: a standalone slide is thin value on its own — a 16:9 graphic whose
|
||||
> notes don't pay off until Presenter Mode (Phase D). Phase A is
|
||||
> groundwork; **A + B together** are the minimum genuinely-useful unit.
|
||||
|
||||
### Phase B — Deck Builder
|
||||
- `templateMode: 'deck'`; the `deck` data model (embedded ordered slides).
|
||||
- Deck Builder option in the Template-tab Layout panel.
|
||||
- The slide-sorter view: add (blank / import, with cross-aspect
|
||||
letterboxing) · reorder · duplicate · delete; open a slide in the canvas
|
||||
editor and write back on switch; per-slide thumbnails.
|
||||
- Sorter-view canvas chrome (hidden zoom bar / options panel).
|
||||
- Save / load / publish / fork a deck (`casewrap-deck`), self-contained.
|
||||
- Deck feed-card thumbnail (first slide + slide-count badge) and
|
||||
publish-confirm preview; `deck` added to `MODE_LABELS` / mode filters.
|
||||
|
||||
**Ship gate:** build a 5-slide deck, reorder it, edit slide 3, save the
|
||||
deck, reload it — order and edits persist; the deck shows in the feed with
|
||||
its slide count.
|
||||
|
||||
### Phase C — Deck theme
|
||||
- `deck.theme` (font family, background) + theme controls in the sidebar.
|
||||
- Per-slide `ignoreDeckTheme` toggle.
|
||||
- Render-time theme composition for deck thumbnails.
|
||||
|
||||
**Ship gate:** set a deck font; all slides restyle in the thumbnails;
|
||||
toggle one slide's opt-out and it reverts to its own font.
|
||||
|
||||
### Phase D — Presenter Mode (single-window)
|
||||
- Full-screen runtime: current slide + notes + next thumbnail + counter.
|
||||
- Keyboard / on-screen navigation; notes toggle; `Esc` to exit.
|
||||
- Theme composed in.
|
||||
- Two `▶` Present entry points: a tool-palette button in the Deck Builder
|
||||
editor, and a "Start Presentation" button on a deck's template-browser
|
||||
preview page.
|
||||
|
||||
**Ship gate:** present a deck start to finish with the keyboard from both
|
||||
entry points; notes track the current slide.
|
||||
|
||||
### Phase E — Dual-window presenter (future)
|
||||
- Popped-out audience window (slide only) synced to a presenter window
|
||||
(current + next slide, notes, timer). Not built in this pass.
|
||||
|
||||
---
|
||||
|
||||
## Risks & tradeoffs
|
||||
|
||||
| Risk | Mitigation |
|
||||
|---|---|
|
||||
| A deck embeds N slides → large JSON / large Nostr event; relays may cap event size | Images are URLs, not binary, so size is bounded to layer JSON. Warn when the deck payload exceeds ~100 KB or ~25 slides. Escape hatch if this proves limiting: a future mode where the deck references slide `naddr`s instead of embedding them (Phase E). |
|
||||
| Slide-edit ⇄ deck round-trip can drop edits if write-back is missed | Reuse the proven `persist…/load…` pattern; persist on every view switch and before publish/save/reorder/present. |
|
||||
| Undo crossing the sorter ⇄ slide-editor boundary (one shared history stack) | Sorter ops and slide edits are ordinary stack entries; undoing an entry made in the other view switches to that view first, so undo always lands somewhere coherent. |
|
||||
| Template/Designer framing is conceptually muddy (a deck is a sequence, not a print artboard) | Accepted explicitly; documented. Deck = Template-tab by analogy to the disc sheet; revisit if the IA is ever reworked. |
|
||||
| Theme composition must not corrupt the slide's own data | Theme is applied purely at render time; slide JSON is never mutated; opt-out is a slide flag. |
|
||||
| Presenter fullscreen behaviour varies across browsers | Use the standard Fullscreen API with a graceful non-fullscreen fallback. |
|
||||
| The slide sorter is a brand-new editor surface | Isolated as Phase B with its own ship gate; the slide *editor* itself is the existing canvas, unchanged. |
|
||||
| Old clients loading a `deck`/`slide` payload | Additive schema; unknown `templateMode` falls back gracefully (the community browser already filters by mode). |
|
||||
|
||||
---
|
||||
|
||||
## Open questions
|
||||
|
||||
1. **Slide default resolution** — DECIDED: 1920×1080 default (matches the
|
||||
existing Custom Art 16:9 preset), 1280×720 offered as an alternate
|
||||
preset. Aspect locked 16:9.
|
||||
2. **Presenter scope** — DECIDED: start single-window (Phase D); dual-window
|
||||
presenter view is Phase E.
|
||||
2a. **Presenter entry points** — DECIDED: a `▶` Present button in the Deck
|
||||
Builder's tool palette, and a matching "Start Presentation" button (same
|
||||
icon) on a deck's preview page in the template browser.
|
||||
3. **Slide editing** — DECIDED: the existing canvas editor, unchanged — a
|
||||
slide is just a 16:9 canvas.
|
||||
4. **Deck theme** — DECIDED: a deck-level theme overrides per-slide styling
|
||||
(fonts, background); each slide has an opt-out (`ignoreDeckTheme`) so it
|
||||
can keep its own look. Render-time composition, JSON-driven.
|
||||
5. **Speaker notes** — plain text for v1; rich text is future.
|
||||
6. **Deck Builder canvas UI** — sorter-grid view that opens slides in the
|
||||
canvas editor for v1; an always-on filmstrip is deferred polish.
|
||||
7. **Schema bump** — increment `schemaVersion` when Phase A lands; `slide`,
|
||||
`deck`, `notes`, `ignoreDeckTheme`, slide `name` are additive.
|
||||
8. **Importing a non-16:9 design as a slide** — DECIDED: scale-to-fit,
|
||||
centered and letterboxed on the 16:9 slide; no cropping.
|
||||
9. **Deck in the community feed** — DECIDED: feed-card and publish-confirm
|
||||
previews show the first slide, with a slide-count badge on the card.
|
||||
10. **Deck → PDF / video export** — DECIDED: non-goal for v1; Presenter
|
||||
Mode is how you show a deck. A natural future phase.
|
||||
11. **Deck size limit** — soft warning past ~100 KB / ~25 slides; hard
|
||||
architectural fallback (reference slides by `naddr`) deferred to Phase E
|
||||
if it proves necessary.
|
||||
|
||||
---
|
||||
|
||||
## Acceptance summary
|
||||
|
||||
### Phase A
|
||||
- [ ] Slide Designer is a Designer-tab layout; canvas is 16:9.
|
||||
- [ ] Speaker-notes field saves into `slide.notes` and round-trips.
|
||||
- [ ] A slide publishes/loads/forks as a `casewrap-slide` design.
|
||||
|
||||
### Phase B
|
||||
- [ ] Deck Builder is a Template-tab layout with a working slide sorter.
|
||||
- [ ] Add / reorder / duplicate / delete slides; import a published design
|
||||
(a non-16:9 import lands letterboxed on the slide).
|
||||
- [ ] Editing a slide writes back into the deck; deck saves self-contained.
|
||||
- [ ] A published deck shows in the community feed with a slide-count badge.
|
||||
|
||||
### Phase C
|
||||
- [ ] A deck theme restyles every slide in the deck.
|
||||
- [ ] A slide's `ignoreDeckTheme` toggle reverts it to its own styling.
|
||||
|
||||
### Phase D
|
||||
- [ ] Presenter mode plays a deck full-screen with notes + navigation.
|
||||
- [ ] Notes follow the current slide; the theme is applied.
|
||||
- [ ] Presenter mode owns the keyboard — editor shortcuts don't fire.
|
||||
- [ ] A `▶` Present button launches it from the Deck Builder tool palette.
|
||||
- [ ] A "Start Presentation" button launches it from a deck's template-
|
||||
browser preview page.
|
||||
+1
-1
@@ -2908,7 +2908,7 @@
|
||||
</div>
|
||||
|
||||
<div class="toolPalette" id="toolPalette">
|
||||
<button type="button" class="toolPaletteBtn active" id="tool-select" data-tool="select" title="Select tool (V)" aria-label="Select tool">▸</button>
|
||||
<button type="button" class="toolPaletteBtn active" id="tool-select" data-tool="select" title="Select tool (V)" aria-label="Select tool"><span style="display:inline-block;transform:rotate(-135deg)">➤</span></button>
|
||||
<button type="button" class="toolPaletteBtn" id="tool-hand" data-tool="hand" title="Hand / pan tool (H)" aria-label="Hand tool">✋</button>
|
||||
<div class="toolPaletteDivider" aria-hidden="true"></div>
|
||||
<button type="button" class="toolPaletteBtn" id="tool-pen" data-tool="pen" title="Pen tool (P)" aria-label="Pen tool">✒</button>
|
||||
|
||||
Reference in new issue
Block a user