fb-slides 0.4.1 → 0.4.3
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/README.md +4 -4
- package/package.json +1 -1
- package/runtime/annotate.js +11 -17
- package/runtime/pointer.js +5 -5
- package/runtime/spotlight.js +22 -20
- package/runtime/theme.base.css +17 -0
package/README.md
CHANGED
|
@@ -128,10 +128,10 @@ Note: a bad description is the most common reason a tool never gets used.
|
|
|
128
128
|
| Key | |
|
|
129
129
|
| --- | --- |
|
|
130
130
|
| `→` / `Space` | next step (fragments included) |
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
131
|
+
| `Q` | the pen — draw on the slide, the ink fades on its own |
|
|
132
|
+
| `W` | the arrow — click the tail, then the tip; same colours as the pen |
|
|
133
|
+
| `E` | the spotlight — drag a rectangle, the rest of the slide dims and blurs |
|
|
134
|
+
| `R` | the pointer — replaces the cursor: a glowing halo, a dart aimed at the centre, or the normal mouse |
|
|
135
135
|
| `S` | speaker view — notes, timer, next slide |
|
|
136
136
|
| `Esc` / `O` | overview — the slides as a grid |
|
|
137
137
|
| `V` | the vertical navigator — every slide by title, down the left edge |
|
package/package.json
CHANGED
package/runtime/annotate.js
CHANGED
|
@@ -14,8 +14,6 @@
|
|
|
14
14
|
// pointer, not the slide's coordinate space.
|
|
15
15
|
// ---------------------------------------------------------------------------
|
|
16
16
|
|
|
17
|
-
import { unlistShortcut } from './shortcuts.js';
|
|
18
|
-
|
|
19
17
|
// The pen's palette. It lives here rather than in theme.css because it is a
|
|
20
18
|
// list the toolbar has to enumerate, not a token the theme swaps: `glow` is the
|
|
21
19
|
// halo, `core` the bright thread down the middle of it. JS hands the selected
|
|
@@ -73,14 +71,11 @@ const MAX_WIDTH = WIDTH * Math.max(...LAYERS.flatMap((l) => l.passes.map((p) =>
|
|
|
73
71
|
// narrow band the erase front is crossing.
|
|
74
72
|
const QUANTA = 24;
|
|
75
73
|
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const PEN_KEY_CODE = 80;
|
|
82
|
-
const ARROW_KEY_CODE = 65;
|
|
83
|
-
const HELP_TAKEN_FROM = { key: 'P', from: /previous/i };
|
|
74
|
+
// The tools live on the QWER row — four keys under the left hand, in the
|
|
75
|
+
// toolbar's own order, and none of them is reveal's: its handler answers
|
|
76
|
+
// nothing between Q and R (P, H/J/K/L, B, V, F, G, A, C, O are all elsewhere).
|
|
77
|
+
const PEN_KEY_CODE = 81; // Q
|
|
78
|
+
const ARROW_KEY_CODE = 87; // W
|
|
84
79
|
|
|
85
80
|
const PEN_ICON = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"
|
|
86
81
|
stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
@@ -144,9 +139,11 @@ const RevealAnnotate = () => ({
|
|
|
144
139
|
toolbar.setAttribute('aria-label', 'Slide tools');
|
|
145
140
|
toolbar.innerHTML = `
|
|
146
141
|
<button id="tool-pen" class="deck-tool" type="button" aria-pressed="false"
|
|
147
|
-
title="Pen — draw on the slide (
|
|
142
|
+
title="Pen — draw on the slide (Q)" aria-label="Pen">${PEN_ICON}<span
|
|
143
|
+
class="deck-key" aria-hidden="true">Q</span></button>
|
|
148
144
|
<button id="tool-arrow" class="deck-tool" type="button" aria-pressed="false"
|
|
149
|
-
title="Arrow — click the tail, then the tip (
|
|
145
|
+
title="Arrow — click the tail, then the tip (W)" aria-label="Arrow">${ARROW_ICON}<span
|
|
146
|
+
class="deck-key" aria-hidden="true">W</span></button>
|
|
150
147
|
<div id="deck-swatches" role="radiogroup" aria-label="Ink colour" hidden>
|
|
151
148
|
${COLOURS.map(
|
|
152
149
|
(colour, i) => `<button class="deck-swatch" type="button" role="radio"
|
|
@@ -574,10 +571,10 @@ const RevealAnnotate = () => ({
|
|
|
574
571
|
|
|
575
572
|
// `addKeyBinding` with a descriptor binds the key and lists it in reveal's
|
|
576
573
|
// own help overlay, which `registerKeyboardShortcut` alone would not do.
|
|
577
|
-
deck.addKeyBinding({ keyCode: PEN_KEY_CODE, key: '
|
|
574
|
+
deck.addKeyBinding({ keyCode: PEN_KEY_CODE, key: 'Q', description: 'Toggle the pen' }, () =>
|
|
578
575
|
toggleTool('pen'),
|
|
579
576
|
);
|
|
580
|
-
deck.addKeyBinding({ keyCode: ARROW_KEY_CODE, key: '
|
|
577
|
+
deck.addKeyBinding({ keyCode: ARROW_KEY_CODE, key: 'W', description: 'Toggle the arrow' }, () =>
|
|
581
578
|
toggleTool('arrow'),
|
|
582
579
|
);
|
|
583
580
|
// Keys the tools borrow only while one is armed, taken in capture phase so
|
|
@@ -601,9 +598,6 @@ const RevealAnnotate = () => ({
|
|
|
601
598
|
true,
|
|
602
599
|
);
|
|
603
600
|
|
|
604
|
-
// Only once reveal has configured itself is there a row to correct.
|
|
605
|
-
deck.on('ready', () => unlistShortcut(deck, HELP_TAKEN_FROM));
|
|
606
|
-
|
|
607
601
|
// A new slide is a clean sheet — including a line still under the pointer.
|
|
608
602
|
deck.on('slidechanged', clear);
|
|
609
603
|
// The overview is a different surface; drawing over it would annotate nothing.
|
package/runtime/pointer.js
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
// cursor now, not a mark on one slide.
|
|
20
20
|
// ---------------------------------------------------------------------------
|
|
21
21
|
|
|
22
|
-
const KEY_CODE =
|
|
22
|
+
const KEY_CODE = 82; // R — the last stop on the tools' QWER row
|
|
23
23
|
|
|
24
24
|
const KINDS = [
|
|
25
25
|
{
|
|
@@ -94,9 +94,9 @@ const RevealPointer = () => ({
|
|
|
94
94
|
button.className = 'deck-tool';
|
|
95
95
|
button.type = 'button';
|
|
96
96
|
button.setAttribute('aria-pressed', 'false');
|
|
97
|
-
button.title = 'Pointer — replace the cursor (
|
|
97
|
+
button.title = 'Pointer — replace the cursor (R)';
|
|
98
98
|
button.setAttribute('aria-label', 'Pointer');
|
|
99
|
-
button.innerHTML = POINTER_ICON
|
|
99
|
+
button.innerHTML = `${POINTER_ICON}<span class="deck-key" aria-hidden="true">R</span>`;
|
|
100
100
|
toolbar.append(button);
|
|
101
101
|
|
|
102
102
|
// The kind picker, hanging under the toolbar exactly like the pen's
|
|
@@ -217,8 +217,8 @@ const RevealPointer = () => ({
|
|
|
217
217
|
});
|
|
218
218
|
|
|
219
219
|
// `addKeyBinding` with a descriptor binds the key and lists it in reveal's
|
|
220
|
-
// own help overlay. `
|
|
221
|
-
deck.addKeyBinding({ keyCode: KEY_CODE, key: '
|
|
220
|
+
// own help overlay. `R` is unclaimed by reveal.
|
|
221
|
+
deck.addKeyBinding({ keyCode: KEY_CODE, key: 'R', description: 'Toggle the pointer' }, () =>
|
|
222
222
|
setPointer(!armed),
|
|
223
223
|
);
|
|
224
224
|
// While armed: Escape stands it down, the number row picks the kind — the
|
package/runtime/spotlight.js
CHANGED
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
// scales slides with.
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
// `E` sits between the pen's Q/W and the pointer's R: the four tools walk the
|
|
17
|
+
// QWER row in the toolbar's own order, and reveal answers none of those keys.
|
|
18
|
+
const KEY_CODE = 69;
|
|
17
19
|
|
|
18
20
|
const RADIUS = 10; // px, the hole's corner rounding
|
|
19
21
|
const MIN_DRAG = 6; // px in either axis before a press counts as a drag
|
|
@@ -89,9 +91,9 @@ const RevealSpotlight = () => ({
|
|
|
89
91
|
button.className = 'deck-tool';
|
|
90
92
|
button.type = 'button';
|
|
91
93
|
button.setAttribute('aria-pressed', 'false');
|
|
92
|
-
button.title = 'Spotlight — drag to light up part of the slide (
|
|
94
|
+
button.title = 'Spotlight — drag to light up part of the slide (E)';
|
|
93
95
|
button.setAttribute('aria-label', 'Spotlight');
|
|
94
|
-
button.innerHTML = SPOT_ICON
|
|
96
|
+
button.innerHTML = `${SPOT_ICON}<span class="deck-key" aria-hidden="true">E</span>`;
|
|
95
97
|
toolbar.append(button);
|
|
96
98
|
|
|
97
99
|
// ---- state ----------------------------------------------------------
|
|
@@ -100,6 +102,7 @@ const RevealSpotlight = () => ({
|
|
|
100
102
|
let rect = null; // {x, y, w, h} in screen px, or null when the veil is clear
|
|
101
103
|
let press = null; // where the current drag started, or null
|
|
102
104
|
let grab = null; // the pointer's offset into a rectangle being moved, or null
|
|
105
|
+
let ghostTimer = 0; // closes the old hole once the veil has faded out
|
|
103
106
|
|
|
104
107
|
const layout = () => {
|
|
105
108
|
if (!rect) return;
|
|
@@ -118,7 +121,11 @@ const RevealSpotlight = () => ({
|
|
|
118
121
|
};
|
|
119
122
|
|
|
120
123
|
// The clip-path stays as it was, so the hole holds its place while the
|
|
121
|
-
// veil fades out around it.
|
|
124
|
+
// veil fades out around it — but only for as long as the fade runs. The
|
|
125
|
+
// clip cuts hit-testing along with paint, so a ghost hole left on an
|
|
126
|
+
// armed veil would keep handing the pointer to the slide underneath:
|
|
127
|
+
// right where the light last was, a drag would select text instead of
|
|
128
|
+
// drawing the next rectangle.
|
|
122
129
|
const clear = () => {
|
|
123
130
|
rect = null;
|
|
124
131
|
press = null;
|
|
@@ -126,12 +133,19 @@ const RevealSpotlight = () => ({
|
|
|
126
133
|
veil.classList.remove('has-hole');
|
|
127
134
|
ring.classList.remove('has-hole', 'is-live');
|
|
128
135
|
ring.style.cursor = '';
|
|
136
|
+
clearTimeout(ghostTimer);
|
|
137
|
+
ghostTimer = setTimeout(() => {
|
|
138
|
+
if (!rect) veil.style.clipPath = '';
|
|
139
|
+
}, 320); // just past the 0.3s fade
|
|
129
140
|
};
|
|
130
141
|
|
|
131
142
|
const setSpot = (on) => {
|
|
132
143
|
armed = on;
|
|
133
144
|
button.setAttribute('aria-pressed', String(on));
|
|
134
145
|
toolbar.classList.toggle('is-armed', on);
|
|
146
|
+
// Arming must start from a whole veil: a hole still mid-fade from last
|
|
147
|
+
// time would leak the pointer through (see clear above).
|
|
148
|
+
if (on) veil.style.clipPath = '';
|
|
135
149
|
// Only an armed veil takes the pointer; the rest of the time clicks fall
|
|
136
150
|
// through to the slide underneath — same contract as the pen's canvas.
|
|
137
151
|
veil.classList.toggle('is-live', on);
|
|
@@ -250,22 +264,10 @@ const RevealSpotlight = () => ({
|
|
|
250
264
|
|
|
251
265
|
button.addEventListener('click', () => setSpot(!armed));
|
|
252
266
|
|
|
253
|
-
//
|
|
254
|
-
//
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
// Shift was there as a modifier.
|
|
258
|
-
let shiftTap = false;
|
|
259
|
-
document.addEventListener('keydown', (event) => {
|
|
260
|
-
shiftTap = event.key === 'Shift' && !event.repeat;
|
|
261
|
-
});
|
|
262
|
-
document.addEventListener('keyup', (event) => {
|
|
263
|
-
if (event.key === 'Shift' && shiftTap) setSpot(!armed);
|
|
264
|
-
});
|
|
265
|
-
// Hand-rolled keys are invisible to reveal's help overlay; shortcuts.js
|
|
266
|
-
// writes the row the binding above cannot.
|
|
267
|
-
deck.on('ready', () =>
|
|
268
|
-
listShortcutAfter(deck, { key: 'SHIFT', action: 'Toggle the spotlight', after: /overview/i }),
|
|
267
|
+
// `addKeyBinding` with a descriptor binds the key and lists it in reveal's
|
|
268
|
+
// own help overlay, exactly as the pen's Q and W do.
|
|
269
|
+
deck.addKeyBinding({ keyCode: KEY_CODE, key: 'E', description: 'Toggle the spotlight' }, () =>
|
|
270
|
+
setSpot(!armed),
|
|
269
271
|
);
|
|
270
272
|
// Escape is reveal's overview toggle; take it back only while armed, in the
|
|
271
273
|
// capture phase, exactly as the pen does.
|
package/runtime/theme.base.css
CHANGED
|
@@ -472,6 +472,7 @@ html[data-reveal-theme] .reveal strong { color: var(--r-heading-color, var(--tex
|
|
|
472
472
|
#deck-tools.is-armed { opacity: 1; }
|
|
473
473
|
|
|
474
474
|
.deck-tool {
|
|
475
|
+
position: relative;
|
|
475
476
|
display: grid;
|
|
476
477
|
place-items: center;
|
|
477
478
|
width: 34px;
|
|
@@ -488,6 +489,22 @@ html[data-reveal-theme] .reveal strong { color: var(--r-heading-color, var(--tex
|
|
|
488
489
|
display: block;
|
|
489
490
|
width: 19px;
|
|
490
491
|
height: 19px;
|
|
492
|
+
/* Lifted a touch to leave the bottom of the chip to the shortcut letter. */
|
|
493
|
+
transform: translateY(-2.5px);
|
|
494
|
+
}
|
|
495
|
+
/* The tool's key, worn small along the chip's bottom edge — nobody should
|
|
496
|
+
have to open the help overlay to remember which letter arms which tool. */
|
|
497
|
+
.deck-key {
|
|
498
|
+
position: absolute;
|
|
499
|
+
left: 0;
|
|
500
|
+
right: 0;
|
|
501
|
+
bottom: 1.5px;
|
|
502
|
+
font: 700 7.5px/1 var(--sans);
|
|
503
|
+
letter-spacing: 0.02em;
|
|
504
|
+
text-align: center;
|
|
505
|
+
color: currentColor;
|
|
506
|
+
opacity: 0.65;
|
|
507
|
+
pointer-events: none;
|
|
491
508
|
}
|
|
492
509
|
.deck-tool:hover {
|
|
493
510
|
background: color-mix(in srgb, var(--text) 10%, transparent);
|