fb-slides 0.4.0 → 0.4.2

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 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
- | `P` | the pen — draw on the slide, the ink fades on its own |
132
- | `A` | the arrow — click the tail, then the tip; same colours as the pen |
133
- | `C` | the pointerreplaces the cursor: a glowing halo, a dart aimed at the centre, or the normal mouse |
134
- | `Shift` (tap) | the spotlightdrag a rectangle, the rest of the slide dims and blurs |
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 spotlightdrag a rectangle, the rest of the slide dims and blurs |
134
+ | `R` | the pointerreplaces 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fb-slides",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "type": "module",
5
5
  "description": "Markdown-driven reveal.js decks: live demo embeds, annotation, mermaid, and a zero-config dev server",
6
6
  "keywords": [
@@ -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
@@ -52,7 +50,7 @@ const WIDTH = 3.4; // px, the bright core of the line
52
50
 
53
51
  // The arrow's head: how far back along the shaft the wings reach, and how far
54
52
  // they open off it. A short arrow shrinks its head rather than being all head.
55
- const HEAD_LEN = 48;
53
+ const HEAD_LEN = 56;
56
54
  const HEAD_SPREAD = 0.55; // radians
57
55
  // Under this, a press-and-release is a click placing the tail, not a whole
58
56
  // arrow: the tip then follows the pointer until the second click.
@@ -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
- // `P` is reveal's own previous-slide key, and a plugin binding wins over it
77
- // which is the point: on stage the pen is reached for far more often than a key
78
- // and Shift+Space already do. Reveal's own row in the help overlay still
79
- // lists it, though, so it has to be corrected. `A` is reveal's auto-slide
80
- // toggle, idle in a deck that does not auto-advance — the arrow takes it.
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 (P)" aria-label="Pen">${PEN_ICON}</button>
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 (A)" aria-label="Arrow">${ARROW_ICON}</button>
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"
@@ -254,8 +251,9 @@ const RevealAnnotate = () => ({
254
251
 
255
252
  // The slab of canvas a stroke can reach, clamped to the viewport. Padded by
256
253
  // half the widest pass, plus a little for the curve's overshoot between
257
- // points.
258
- const boundsOf = (points) => {
254
+ // points; `extra` widens it further for shapes whose paint reaches past
255
+ // the points themselves.
256
+ const boundsOf = (points, extra = 0) => {
259
257
  let minX = Infinity;
260
258
  let minY = Infinity;
261
259
  let maxX = -Infinity;
@@ -266,7 +264,7 @@ const RevealAnnotate = () => ({
266
264
  if (x > maxX) maxX = x;
267
265
  if (y > maxY) maxY = y;
268
266
  }
269
- const pad = MAX_WIDTH / 2 + 3;
267
+ const pad = MAX_WIDTH / 2 + 3 + extra;
270
268
  const x = Math.max(0, Math.floor(minX - pad));
271
269
  const y = Math.max(0, Math.floor(minY - pad));
272
270
  return {
@@ -317,8 +315,6 @@ const RevealAnnotate = () => ({
317
315
  const { from, to } = stroke;
318
316
  const length = Math.hypot(to.x - from.x, to.y - from.y);
319
317
  if (length < 1) return true;
320
- const box = boundsOf([from, to]);
321
- if (box.w <= 0 || box.h <= 0) return true;
322
318
 
323
319
  const fade = progress === null ? 1 : 1 - progress;
324
320
  const angle = Math.atan2(to.y - from.y, to.x - from.x);
@@ -332,6 +328,13 @@ const RevealAnnotate = () => ({
332
328
  y: to.y - head * 0.75 * Math.sin(angle),
333
329
  };
334
330
 
331
+ // The wings go into the bounds along with the line's own ends: an
332
+ // axis-aligned arrow has a razor-thin from-to box, and the head reaches
333
+ // further out of it sideways than the stroke padding covers. The extra
334
+ // head-width of pad keeps the glow well clear of the clip on every side.
335
+ const box = boundsOf([from, to, ...wings], head);
336
+ if (box.w <= 0 || box.h <= 0) return true;
337
+
335
338
  for (const { ink, passes } of LAYERS) {
336
339
  onLayer(box, stroke.ink[ink], (c) => {
337
340
  c.lineCap = 'round';
@@ -568,10 +571,10 @@ const RevealAnnotate = () => ({
568
571
 
569
572
  // `addKeyBinding` with a descriptor binds the key and lists it in reveal's
570
573
  // own help overlay, which `registerKeyboardShortcut` alone would not do.
571
- deck.addKeyBinding({ keyCode: PEN_KEY_CODE, key: 'P', description: 'Toggle the pen' }, () =>
574
+ deck.addKeyBinding({ keyCode: PEN_KEY_CODE, key: 'Q', description: 'Toggle the pen' }, () =>
572
575
  toggleTool('pen'),
573
576
  );
574
- deck.addKeyBinding({ keyCode: ARROW_KEY_CODE, key: 'A', description: 'Toggle the arrow' }, () =>
577
+ deck.addKeyBinding({ keyCode: ARROW_KEY_CODE, key: 'W', description: 'Toggle the arrow' }, () =>
575
578
  toggleTool('arrow'),
576
579
  );
577
580
  // Keys the tools borrow only while one is armed, taken in capture phase so
@@ -595,9 +598,6 @@ const RevealAnnotate = () => ({
595
598
  true,
596
599
  );
597
600
 
598
- // Only once reveal has configured itself is there a row to correct.
599
- deck.on('ready', () => unlistShortcut(deck, HELP_TAKEN_FROM));
600
-
601
601
  // A new slide is a clean sheet — including a line still under the pointer.
602
602
  deck.on('slidechanged', clear);
603
603
  // The overview is a different surface; drawing over it would annotate nothing.
@@ -19,7 +19,7 @@
19
19
  // cursor now, not a mark on one slide.
20
20
  // ---------------------------------------------------------------------------
21
21
 
22
- const KEY_CODE = 67; // C
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 (C)';
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. `C` is unclaimed by reveal.
221
- deck.addKeyBinding({ keyCode: KEY_CODE, key: 'C', description: 'Toggle the pointer' }, () =>
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
@@ -13,7 +13,9 @@
13
13
  // scales slides with.
14
14
  // ---------------------------------------------------------------------------
15
15
 
16
- import { listShortcutAfter } from './shortcuts.js';
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 (Shift)';
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 ----------------------------------------------------------
@@ -250,22 +252,10 @@ const RevealSpotlight = () => ({
250
252
 
251
253
  button.addEventListener('click', () => setSpot(!armed));
252
254
 
253
- // The shortcut is a tap of Shift on its own not through addKeyBinding,
254
- // which knows nothing of keyup. Toggling on the keydown would fire on
255
- // every Shift+Space and Shift+arrow reveal already answers, so the toggle
256
- // waits for the release, and stands down the moment any other key shows
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 }),
255
+ // `addKeyBinding` with a descriptor binds the key and lists it in reveal's
256
+ // own help overlay, exactly as the pen's Q and W do.
257
+ deck.addKeyBinding({ keyCode: KEY_CODE, key: 'E', description: 'Toggle the spotlight' }, () =>
258
+ setSpot(!armed),
269
259
  );
270
260
  // Escape is reveal's overview toggle; take it back only while armed, in the
271
261
  // capture phase, exactly as the pen does.
@@ -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);