@honeydeck/honeydeck 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/docs/configuration.md +16 -4
- package/docs/deeper-dive.md +6 -3
- package/docs/index.json +11 -0
- package/docs/mobile.md +1 -1
- package/docs/presenter-mode.md +12 -6
- package/docs/transitions.md +126 -0
- package/package.json +1 -1
- package/src/cli/templates/SPEC.md +2 -1
- package/src/cli/templates/starter/deck.mdx +22 -0
- package/src/runtime/Deck.tsx +255 -36
- package/src/runtime/SPEC.md +10 -2
- package/src/runtime/presentationApi.ts +112 -6
- package/src/runtime/sync.ts +130 -12
- package/src/runtime/views/PresenterCastButton.tsx +17 -9
- package/src/runtime/views/PresenterView.tsx +247 -30
- package/src/runtime/views/SPEC.md +28 -5
- package/src/runtime/views/presenterTime.ts +15 -0
- package/src/theme/base.css +85 -0
- package/src/vite-plugin/SPEC.md +7 -2
- package/src/vite-plugin/splitter.ts +2 -0
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
- Navigation controls button
|
|
11
11
|
- Direct URL: `/#/presenter/1/0`
|
|
12
12
|
|
|
13
|
+
### Deactivation
|
|
14
|
+
|
|
15
|
+
- Keyboard shortcut `p` exits presenter mode back to audience slide view at the same slide/step.
|
|
16
|
+
- Keyboard shortcut `Escape` exits presenter mode back to audience slide view at the same slide/step.
|
|
17
|
+
|
|
13
18
|
### UI Layout
|
|
14
19
|
|
|
15
20
|
```txt
|
|
@@ -25,7 +30,7 @@
|
|
|
25
30
|
│ - Remember to demo the sparkle button │
|
|
26
31
|
│ - Mention PDF export │
|
|
27
32
|
│ │
|
|
28
|
-
│ Slide 3/12 · Step 2/4
|
|
33
|
+
│ Slide 3/12 · Step 2/4 12:34 Timer 1:23 [Open] │
|
|
29
34
|
└──────────────────────────────────────────┘
|
|
30
35
|
```
|
|
31
36
|
|
|
@@ -35,9 +40,12 @@ Includes:
|
|
|
35
40
|
- Speaker notes for current slide, with Markdown formatting from `<Notes>` rendered as compact presenter prose
|
|
36
41
|
- Slide/step counter
|
|
37
42
|
- Clock (wall clock)
|
|
43
|
+
- Elapsed presentation timer sits next to the slide/step counter on the left side of the bottom bar and has idle/running/paused states. Idle shows a start action. Running shows a prominent elapsed display plus pause action. Paused shows elapsed time plus continue, restart-from-zero, and close/reset actions.
|
|
38
44
|
- Button to open audience view in new tab, preserving the current slide/step and deck base path
|
|
39
|
-
-
|
|
40
|
-
-
|
|
45
|
+
- Color mode cycle button (system → light → dark → system). Presenter color mode changes also sync to BroadcastChannel audience views and Presentation API cast receivers.
|
|
46
|
+
- Blank screen toggle button and `b` keyboard shortcut. While blanked, the presenter sees a `Screen blanked (b)` indicator and audience/cast views see a black screen.
|
|
47
|
+
- Button to cast the audience view to a secondary display when the Presentation API is supported. Unsupported browsers keep a visibly disabled-looking control in the action row; it does not render extra inline feedback, and its hover title/accessible label explains that Presentation API casting is unavailable. Active casting can be stopped from the same control.
|
|
48
|
+
- Presenter navigation buttons provide previous/next timeline-step navigation and previous/next slide navigation on mobile presenter layouts. Desktop presenter layouts do not show navigation buttons. On mobile, the timeline-step buttons sit on the outside edges of the button group (previous step, previous slide, next slide, next step), because step navigation is the primary/default action. Timeline keyboard shortcuts (`→`/`←`/`↓`/`↑`, `d`/`a`/`s`/`w`) update the presenter route and keep the window in presenter mode.
|
|
41
49
|
- Presenter navigation uses the shared Honeydeck navigation command abstraction so button, keyboard, and touch inputs share the same semantics as audience view.
|
|
42
50
|
- Presenter notes are scroll-owned regions: wheel, trackpad, touch scroll, and swipe gestures that start in notes scroll notes and never navigate slides, even at scroll boundaries.
|
|
43
51
|
- On mobile presenter layouts, the Current preview may use tap zones and swipe navigation; speaker notes remain scroll-only. Pinch-to-zoom and pinch-to-overview are not required in presenter mode.
|
|
@@ -47,7 +55,22 @@ Includes:
|
|
|
47
55
|
|
|
48
56
|
### Presenter Responsiveness
|
|
49
57
|
|
|
50
|
-
Presenter mode uses a two-column preview area (`Current` larger, `Next` smaller), a notes panel, and a bottom status/action bar on desktop. On narrow/mobile screens it switches to a single-column layout and hides the Next preview.
|
|
58
|
+
Presenter mode uses a two-column preview area (`Current` larger, `Next` smaller), a notes panel, and a bottom status/action bar on desktop. On narrow/mobile screens it switches to a single-column layout and hides the Next preview. The navigation button group is the bottom-most element on mobile and uses larger touch targets than desktop.
|
|
59
|
+
|
|
60
|
+
### Presentation Timer
|
|
61
|
+
|
|
62
|
+
- Idle state shows a `Start timer` button.
|
|
63
|
+
- Starting changes to running state, displaying elapsed time as `MM:SS` or `H:MM:SS`.
|
|
64
|
+
- In running state, clicking the elapsed time or pause action pauses the timer.
|
|
65
|
+
- In paused state, controls let the presenter continue, restart from zero, or close/reset the timer back to idle.
|
|
66
|
+
|
|
67
|
+
### Blank Screen
|
|
68
|
+
|
|
69
|
+
- Pressing `b` toggles the audience screen to black; pressing `b` again restores the normal view.
|
|
70
|
+
- A blank screen button in the bottom action bar provides the same toggle.
|
|
71
|
+
- While blanked, the presenter sees a `Screen blanked (b)` indicator overlay.
|
|
72
|
+
- The blank-screen state is broadcast via both `BroadcastChannel` and the Presentation API cast connection as a `blank-screen` sync message with `mode: "black" | "off"`.
|
|
73
|
+
- When the presenter disconnects, audience windows automatically unblank.
|
|
51
74
|
|
|
52
75
|
### Audience Sync
|
|
53
76
|
|
|
@@ -55,7 +78,7 @@ Presenter mode and audience view synchronize via `BroadcastChannel` and the Pres
|
|
|
55
78
|
|
|
56
79
|
- Same browser/profile BroadcastChannel sync remains available when casting is unsupported or unavailable
|
|
57
80
|
- Presenter mode is the controller
|
|
58
|
-
- Audience view listens for navigation updates
|
|
81
|
+
- Audience view listens for navigation updates, presenter color mode changes, and blank-screen commands
|
|
59
82
|
- Late-opening audience tabs request the current presenter position via a `sync-request` / `sync-response` handshake as soon as a receiver connection is available, so they sync immediately instead of waiting for the next presenter move
|
|
60
83
|
- Presence messages (`presenter-connected` / `presenter-disconnected`) are broadcast
|
|
61
84
|
- When the Presentation API is supported, presenter mode can cast the audience view to a secondary display; the receiver asks for the current route when a connection becomes available and presenter replies with a `sync-response` so the cast audience resyncs even if it missed the first `navigate` message
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function formatPresenterElapsedTime(elapsedMs: number): string {
|
|
2
|
+
const totalSeconds = Math.max(0, Math.floor(elapsedMs / 1000));
|
|
3
|
+
const seconds = totalSeconds % 60;
|
|
4
|
+
const totalMinutes = Math.floor(totalSeconds / 60);
|
|
5
|
+
const minutes = totalMinutes % 60;
|
|
6
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
7
|
+
|
|
8
|
+
if (hours > 0) {
|
|
9
|
+
return `${hours}:${minutes.toString().padStart(2, "0")}:${seconds
|
|
10
|
+
.toString()
|
|
11
|
+
.padStart(2, "0")}`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return `${minutes}:${seconds.toString().padStart(2, "0")}`;
|
|
15
|
+
}
|
package/src/theme/base.css
CHANGED
|
@@ -531,6 +531,91 @@
|
|
|
531
531
|
font-size: var(--honeydeck-font-size-code);
|
|
532
532
|
}
|
|
533
533
|
|
|
534
|
+
/* ── Slide transitions ───────────────────────────────────────────────────── */
|
|
535
|
+
|
|
536
|
+
.honeydeck-slide-layer.honeydeck-transition-fade.honeydeck-transition-enter {
|
|
537
|
+
animation-name: honeydeck-transition-fade-enter;
|
|
538
|
+
animation-duration: var(--honeydeck-transition-duration, 200ms);
|
|
539
|
+
animation-timing-function: var(--honeydeck-transition-easing, ease);
|
|
540
|
+
animation-fill-mode: both;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
.honeydeck-slide-layer.honeydeck-transition-fade.honeydeck-transition-exit {
|
|
544
|
+
animation-name: honeydeck-transition-fade-exit;
|
|
545
|
+
animation-duration: var(--honeydeck-transition-duration, 200ms);
|
|
546
|
+
animation-timing-function: var(--honeydeck-transition-easing, ease);
|
|
547
|
+
animation-fill-mode: both;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
@keyframes honeydeck-transition-fade-enter {
|
|
551
|
+
from {
|
|
552
|
+
opacity: var(--honeydeck-transition-enter-from-opacity, 0);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
to {
|
|
556
|
+
opacity: 1;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
@keyframes honeydeck-transition-fade-exit {
|
|
561
|
+
from {
|
|
562
|
+
opacity: var(--honeydeck-transition-exit-from-opacity, 1);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
to {
|
|
566
|
+
opacity: 0;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
.honeydeck-slide-layer.honeydeck-transition-slide-left.honeydeck-transition-enter {
|
|
571
|
+
animation-name: honeydeck-transition-slide-left-enter;
|
|
572
|
+
animation-duration: var(--honeydeck-transition-duration, 200ms);
|
|
573
|
+
animation-timing-function: var(--honeydeck-transition-easing, ease);
|
|
574
|
+
animation-fill-mode: both;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
.honeydeck-slide-layer.honeydeck-transition-slide-left.honeydeck-transition-exit {
|
|
578
|
+
animation-name: honeydeck-transition-slide-left-exit;
|
|
579
|
+
animation-duration: var(--honeydeck-transition-duration, 200ms);
|
|
580
|
+
animation-timing-function: var(--honeydeck-transition-easing, ease);
|
|
581
|
+
animation-fill-mode: both;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
@keyframes honeydeck-transition-slide-left-enter {
|
|
585
|
+
from {
|
|
586
|
+
opacity: 1;
|
|
587
|
+
transform: translateX(
|
|
588
|
+
calc(100% * var(--honeydeck-transition-direction, 1))
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
to {
|
|
593
|
+
opacity: 1;
|
|
594
|
+
transform: translateX(0);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
@keyframes honeydeck-transition-slide-left-exit {
|
|
599
|
+
from {
|
|
600
|
+
opacity: 1;
|
|
601
|
+
transform: translateX(0);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
to {
|
|
605
|
+
opacity: 1;
|
|
606
|
+
transform: translateX(
|
|
607
|
+
calc(-100% * var(--honeydeck-transition-direction, 1))
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
@media (prefers-reduced-motion: reduce) {
|
|
613
|
+
.honeydeck-slide-layer.honeydeck-transition-enter,
|
|
614
|
+
.honeydeck-slide-layer.honeydeck-transition-exit {
|
|
615
|
+
animation: none;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
534
619
|
/* ── Documentation Markdown typography ──────────────────────────────────────
|
|
535
620
|
Rendered README/docs pages use plain MDX elements. Keep their typography
|
|
536
621
|
here instead of in DocsView so the React view stays structural. */
|
package/src/vite-plugin/SPEC.md
CHANGED
|
@@ -108,7 +108,9 @@ All settings use **camelCase**. No separate config file exists. Frontmatter pars
|
|
|
108
108
|
| `colorMode` | `"system" \| "light" \| "dark"` | `"system"` | Browser color mode |
|
|
109
109
|
| `pdfColorMode` | `"light" \| "dark"` | unset | Optional explicit PDF color mode; when unset, PDF falls back to pinned deck `colorMode`, then `light` |
|
|
110
110
|
| `pdfSteps` | `"final" \| "all"` | `"final"` | Whether PDF includes all steps or final state |
|
|
111
|
-
| `transition` | `boolean` | `
|
|
111
|
+
| `transition` | `string \| boolean` | `fade` | Default named slide transition (`fade`, `none`, `slide-left`, or a custom CSS name); legacy `true` maps to `fade` and `false` maps to `none` |
|
|
112
|
+
| `transitionDuration` | `number` | `200` | Default slide transition duration in milliseconds |
|
|
113
|
+
| `transitionEasing` | `string` | `ease` | Default slide transition timing function |
|
|
112
114
|
| `magicCodeDuration` | `number` | `800` | Default Magic Code animation duration in milliseconds |
|
|
113
115
|
| `layouts` | `string` | built-in `@honeydeck/honeydeck/layouts` | Layout map module path |
|
|
114
116
|
| `defaultLayout` | `string` | `"Default"` | Layout used when slide has no `layout:` |
|
|
@@ -119,6 +121,9 @@ All settings use **camelCase**. No separate config file exists. Frontmatter pars
|
|
|
119
121
|
| Property | Type | Default | Description |
|
|
120
122
|
|----------|------|---------|-------------|
|
|
121
123
|
| `layout` | `string` | (uses `defaultLayout`) | Layout map key to use (PascalCase by convention, not validated) |
|
|
124
|
+
| `transition` | `string \| boolean` | deck default | Named transition into this slide; legacy booleans map to `fade`/`none` |
|
|
125
|
+
| `transitionDuration` | `number` | deck default | Transition duration into this slide in milliseconds |
|
|
126
|
+
| `transitionEasing` | `string` | deck default | Transition easing into this slide |
|
|
122
127
|
| ...layout-specific props | varies | — | Any additional props the layout accepts |
|
|
123
128
|
|
|
124
129
|
### Root frontmatter semantics
|
|
@@ -127,6 +132,6 @@ The first frontmatter block in the deck entry file is parsed as deck config. Dec
|
|
|
127
132
|
|
|
128
133
|
Slide-level frontmatter is a frontmatter-only block after a slide separator and applies to the following slide. Imported MDX files are normal MDX modules and cannot set deck-level properties. `magicCodeDuration` is deck-level only; the same key in slide-level frontmatter is treated as a normal layout prop and does not configure Magic Code.
|
|
129
134
|
|
|
130
|
-
Invalid `aspectRatio`, `colorMode`, and `pdfSteps` values fall back to defaults. Invalid `pdfColorMode` is ignored as unset, allowing the pinned `colorMode` fallback. `showSlideNumbers` is enabled only by literal `true`;
|
|
135
|
+
Invalid `aspectRatio`, `colorMode`, and `pdfSteps` values fall back to defaults. Invalid `pdfColorMode` is ignored as unset, allowing the pinned `colorMode` fallback. `showSlideNumbers` is enabled only by literal `true`; slide transition values normalize at runtime, with non-empty strings treated as named built-ins or custom CSS hooks. Invalid explicit Magic Code block `duration` values are compile errors; invalid deck-level `magicCodeDuration` falls back to the default Magic Code duration.
|
|
131
136
|
|
|
132
137
|
During development, changes to deck-level frontmatter invalidate the virtual config and every compiled virtual slide module, because slide compilation can depend on deck settings such as `magicCodeDuration`. Layout-related virtual modules are invalidated as before so layout map and demo previews stay current.
|