rshow 0.0.0-stage → 0.0.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.
Files changed (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +50 -2
  3. package/dist/main.js +8500 -0
  4. package/package.json +48 -4
  5. package/skills/rshow/SKILL.md +144 -0
  6. package/skills/rshow/reference/cli.md +263 -0
  7. package/skills/rshow/reference/dashboard.md +122 -0
  8. package/skills/rshow/reference/mockups.md +113 -0
  9. package/skills/rshow/reference/page-contract.md +83 -0
  10. package/skills/rshow/reference/pages.md +174 -0
  11. package/skills/rshow/reference/poster.md +137 -0
  12. package/skills/rshow/reference/project-page.md +132 -0
  13. package/skills/rshow/reference/reports.md +158 -0
  14. package/skills/rshow/reference/sketch.md +78 -0
  15. package/skills/rshow/reference/terminal.md +148 -0
  16. package/skills/rshow/reference/themes.md +139 -0
  17. package/skills/rshow-implement/SKILL.md +112 -0
  18. package/skills/rshow-implement/reference/compare.md +156 -0
  19. package/skills/rshow-implement/reference/handoff.md +125 -0
  20. package/skills/rshow-implement/reference/map.md +151 -0
  21. package/skills/rshow-slides/SKILL.md +136 -0
  22. package/skills/rshow-slides/reference/layouts.md +251 -0
  23. package/themes/default/dashboard.css +521 -0
  24. package/themes/default/dashboard.js +1390 -0
  25. package/themes/default/deck.css +586 -0
  26. package/themes/default/deck.js +741 -0
  27. package/themes/default/example/capture.ans +1 -0
  28. package/themes/default/example/dashboard.html +106 -0
  29. package/themes/default/example/demo.cast +14 -0
  30. package/themes/default/example/drawing.excalidraw +377 -0
  31. package/themes/default/example/index.html +311 -0
  32. package/themes/default/example/mockup-desktop.html +331 -0
  33. package/themes/default/example/mockup-platforms.html +742 -0
  34. package/themes/default/example/mockup.html +416 -0
  35. package/themes/default/example/page.html +153 -0
  36. package/themes/default/example/poster-figure.svg +58 -0
  37. package/themes/default/example/poster.html +181 -0
  38. package/themes/default/example/project.html +229 -0
  39. package/themes/default/example/report.html +404 -0
  40. package/themes/default/example/results.csv +61 -0
  41. package/themes/default/example/sketch.html +178 -0
  42. package/themes/default/example/teaser.svg +66 -0
  43. package/themes/default/example/terminal.html +231 -0
  44. package/themes/default/example/tui.html +223 -0
  45. package/themes/default/fonts/IBMPlexMono-Regular-Latin1.woff2 +0 -0
  46. package/themes/default/fonts/IBMPlexSans-Light-Latin1.woff2 +0 -0
  47. package/themes/default/fonts/IBMPlexSans-Regular-Latin1.woff2 +0 -0
  48. package/themes/default/fonts/IBMPlexSans-SemiBold-Latin1.woff2 +0 -0
  49. package/themes/default/fonts/OFL.txt +93 -0
  50. package/themes/default/fonts.css +63 -0
  51. package/themes/default/index.html +573 -0
  52. package/themes/default/mockup.css +1078 -0
  53. package/themes/default/mockup.js +1433 -0
  54. package/themes/default/mode.js +242 -0
  55. package/themes/default/page.css +320 -0
  56. package/themes/default/poster.css +480 -0
  57. package/themes/default/poster.js +223 -0
  58. package/themes/default/project.css +482 -0
  59. package/themes/default/project.js +116 -0
  60. package/themes/default/report.css +776 -0
  61. package/themes/default/report.js +427 -0
  62. package/themes/default/sketch.css +166 -0
  63. package/themes/default/sketch.js +681 -0
  64. package/themes/default/skins/adwaita.css +669 -0
  65. package/themes/default/skins/custom.css +596 -0
  66. package/themes/default/skins/egui.css +639 -0
  67. package/themes/default/skins/fluent.css +1093 -0
  68. package/themes/default/skins/fluent.js +458 -0
  69. package/themes/default/skins/mac.css +647 -0
  70. package/themes/default/skins/material.css +692 -0
  71. package/themes/default/skins/sketch.css +436 -0
  72. package/themes/default/skins/sketch.js +494 -0
  73. package/themes/default/skins/wire.css +561 -0
  74. package/themes/default/terminal.css +292 -0
  75. package/themes/default/terminal.js +433 -0
  76. package/themes/default/theme.json +149 -0
  77. package/themes/default/tokens.css +255 -0
  78. package/themes/default/tui.css +703 -0
  79. package/themes/default/tui.js +472 -0
  80. package/worker/index.js +6918 -0
  81. package/worker/migrations/0001_init.sql +52 -0
  82. package/worker/migrations/0002_blobs.sql +5 -0
  83. package/worker/migrations/0003_projects.sql +31 -0
  84. package/worker/migrations/0004_page_data_blob.sql +19 -0
@@ -0,0 +1,458 @@
1
+ /*
2
+ * rshow theme "default": the fluent skin, the real components.
3
+ *
4
+ * skins/fluent.css draws the whole kit with Fluent-like tokens, so the skin
5
+ * reads as Windows 11 with no network at all. This file goes one step further
6
+ * while the fluent skin is active: it upgrades the six controls that a design
7
+ * review actually argues about into the real Microsoft Fluent UI Web Components
8
+ * v3, so a wf-button is a fluent-button, a wf-input is a fluent-field around a
9
+ * fluent-text-input, and so on. The component and the drawn kit agree because
10
+ * they read the same token values out of fluent.css.
11
+ *
12
+ * Pinned version. @fluentui/web-components 3.1.3, the newest 3.x on npm when
13
+ * this file was written, fetched as one bundled ES module from jsdelivr:
14
+ *
15
+ * https://cdn.jsdelivr.net/npm/@fluentui/web-components@3.1.3/dist/web-components.min.js
16
+ *
17
+ * It is a single self contained module: no import map, no bundler, no bare
18
+ * specifier. The module registers its custom elements in a task after it
19
+ * evaluates, so this file waits on customElements.whenDefined before it builds
20
+ * anything.
21
+ *
22
+ * Fallback. A mockup is a drawing and must be readable on a plane: if the
23
+ * module does not load, or a browser without custom elements reaches this file,
24
+ * nothing is upgraded and fluent.css alone draws every control. A half upgraded
25
+ * screen is worse than a plain one, so a failure reverts what this file built.
26
+ *
27
+ * Switching skins away from fluent puts every original wf-* element back where
28
+ * it was, so wire, sketch and custom see the kit they expect.
29
+ *
30
+ * Markup stays the kit's markup. data-goto, href, data-state and inline styles
31
+ * move onto the upgraded element, which is why a hotspot or a state still works
32
+ * after the upgrade.
33
+ */
34
+ (function () {
35
+ 'use strict';
36
+
37
+ var main = document.querySelector('.mockup');
38
+ if (!main) {
39
+ return;
40
+ }
41
+
42
+ var MODULE_URL = 'https://cdn.jsdelivr.net/npm/@fluentui/web-components@3.1.3/dist/web-components.min.js';
43
+ var WAIT_LIMIT = 8000;
44
+
45
+ var SELECTOR = ['.wf-button', '.wf-input', '.wf-select', '.wf-checkbox', '.wf-toggle', '.wf-tabs'].join(', ');
46
+ var SKIP_CLASS = ['primary', 'ghost', 'on', 'is-active', 'wf-button', 'wf-input', 'wf-select', 'wf-checkbox', 'wf-toggle', 'wf-tabs'];
47
+
48
+ var phase = 'idle';
49
+ var waiting = [];
50
+ var built = [];
51
+ var loadTimer = null;
52
+ var debounce = null;
53
+ var tabSeq = 0;
54
+
55
+ // The skin of a screen is the nearest data-skin above it, so a page that pins
56
+ // one skin per screen and carries its own elsewhere still upgrades the right
57
+ // screens, and only those.
58
+ function skinOf(node) {
59
+ var host = node.closest ? node.closest('[data-skin]') : null;
60
+ return host ? host.getAttribute('data-skin') : '';
61
+ }
62
+
63
+ function fluentScreens() {
64
+ var screens = main.querySelectorAll('.mk-screen');
65
+ var active = [];
66
+ for (var i = 0; i < screens.length; i += 1) {
67
+ if (skinOf(screens[i]) === 'fluent') {
68
+ active.push(screens[i]);
69
+ }
70
+ }
71
+ return active;
72
+ }
73
+
74
+ function isFluent() {
75
+ return fluentScreens().length > 0;
76
+ }
77
+
78
+ function warn(message) {
79
+ if (window.console && window.console.warn) {
80
+ window.console.warn('[rshow fluent skin] ' + message);
81
+ }
82
+ }
83
+
84
+ // ---------------------------------------------------------------- load --
85
+
86
+ function settle(ok) {
87
+ phase = ok ? 'ready' : 'failed';
88
+ main.setAttribute('data-fluent-upgrade', ok ? 'components' : 'css-only');
89
+ var callbacks = waiting;
90
+ waiting = [];
91
+ for (var i = 0; i < callbacks.length; i += 1) {
92
+ callbacks[i](ok);
93
+ }
94
+ }
95
+
96
+ function ensure(done) {
97
+ if (phase === 'ready' || phase === 'failed') {
98
+ done(phase === 'ready');
99
+ return;
100
+ }
101
+ waiting.push(done);
102
+ if (phase === 'loading') {
103
+ return;
104
+ }
105
+ phase = 'loading';
106
+ if (typeof window.customElements === 'undefined' || typeof window.customElements.whenDefined !== 'function') {
107
+ warn('custom elements are not supported: fluent.css draws the controls');
108
+ settle(false);
109
+ return;
110
+ }
111
+ window.clearTimeout(loadTimer);
112
+ loadTimer = window.setTimeout(function () {
113
+ if (phase === 'loading') {
114
+ warn('the Fluent module did not answer in time: fluent.css draws the controls');
115
+ settle(false);
116
+ }
117
+ }, WAIT_LIMIT);
118
+ // A dynamic import of a URL is the browser's own module loader: no build
119
+ // step, no import map, and the pinned version is in the URL.
120
+ import(MODULE_URL)
121
+ .then(function () {
122
+ return window.customElements.whenDefined('fluent-button');
123
+ })
124
+ .then(function () {
125
+ window.clearTimeout(loadTimer);
126
+ if (phase !== 'loading') {
127
+ return;
128
+ }
129
+ var all = ['fluent-button', 'fluent-text-input', 'fluent-listbox', 'fluent-dropdown', 'fluent-checkbox', 'fluent-switch', 'fluent-tablist'];
130
+ for (var i = 0; i < all.length; i += 1) {
131
+ if (!window.customElements.get(all[i])) {
132
+ warn('the Fluent module did not define ' + all[i] + ': fluent.css draws the controls');
133
+ settle(false);
134
+ return;
135
+ }
136
+ }
137
+ settle(true);
138
+ })
139
+ .catch(function (err) {
140
+ window.clearTimeout(loadTimer);
141
+ warn('the Fluent module could not be loaded (' + (err && err.message ? err.message : err) + '): fluent.css draws the controls');
142
+ settle(false);
143
+ });
144
+ }
145
+
146
+ // -------------------------------------------------------------- shapes --
147
+
148
+ function copy(node, target) {
149
+ var attrs = node.attributes;
150
+ var i;
151
+ for (i = 0; i < attrs.length; i += 1) {
152
+ var name = attrs[i].name;
153
+ if (name === 'class' || name.indexOf('data-') === 0) {
154
+ continue;
155
+ }
156
+ if (name === 'aria-selected' || name === 'checked') {
157
+ continue;
158
+ }
159
+ target.setAttribute(name, attrs[i].value);
160
+ }
161
+ for (i = 0; i < attrs.length; i += 1) {
162
+ if (attrs[i].name.indexOf('data-') === 0) {
163
+ target.setAttribute(attrs[i].name, attrs[i].value);
164
+ }
165
+ }
166
+ var classes = (node.className || '').split(/\s+/);
167
+ for (i = 0; i < classes.length; i += 1) {
168
+ var name2 = classes[i];
169
+ if (name2 !== '' && SKIP_CLASS.indexOf(name2) < 0) {
170
+ target.classList.add(name2);
171
+ }
172
+ }
173
+ if (node.getAttribute('style')) {
174
+ target.setAttribute('style', node.getAttribute('style'));
175
+ }
176
+ return target;
177
+ }
178
+
179
+ function text(node) {
180
+ return String(node.textContent || '').replace(/\s+/g, ' ').trim();
181
+ }
182
+
183
+ // The kit labels a field in the notch on its border, so an upgraded control is
184
+ // wrapped in the kit's field: the label is ours, the control is Fluent's.
185
+ function labelled(node, control) {
186
+ var field = document.createElement('span');
187
+ field.className = 'wf-field';
188
+ var label = node.getAttribute('data-label');
189
+ if (label) {
190
+ var caption = document.createElement('span');
191
+ caption.className = 'wf-label';
192
+ caption.textContent = label;
193
+ field.appendChild(caption);
194
+ }
195
+ field.appendChild(control);
196
+ copy(node, field);
197
+ return field;
198
+ }
199
+
200
+ function upgradeButton(node) {
201
+ var primary = node.classList.contains('primary');
202
+ var ghost = node.classList.contains('ghost');
203
+ var link = node.tagName === 'A' && node.getAttribute('href');
204
+ var el = document.createElement(link ? 'fluent-anchor-button' : 'fluent-button');
205
+ el.setAttribute('appearance', primary ? 'primary' : ghost ? 'subtle' : 'secondary');
206
+ if (link) {
207
+ el.setAttribute('href', node.getAttribute('href'));
208
+ }
209
+ if (node.hasAttribute('disabled')) {
210
+ el.setAttribute('disabled', '');
211
+ }
212
+ var label = text(node);
213
+ if (label !== '') {
214
+ el.textContent = label;
215
+ }
216
+ copy(node, el);
217
+ return el;
218
+ }
219
+
220
+ // A text field is a fluent-text-input; the label is the kit's, kept because
221
+ // the library's own label needs a fluent-field wrapper and a slot per part,
222
+ // and the drawing wants the label in the notch on the border like the rest of
223
+ // the kit.
224
+ function upgradeInput(node) {
225
+ var input = document.createElement('fluent-text-input');
226
+ var value = text(node);
227
+ if (value !== '') {
228
+ input.setAttribute('value', value);
229
+ }
230
+ var placeholder = node.getAttribute('data-placeholder');
231
+ if (placeholder) {
232
+ input.setAttribute('placeholder', placeholder);
233
+ }
234
+ if (node.getAttribute('aria-label')) {
235
+ input.setAttribute('aria-label', node.getAttribute('aria-label'));
236
+ } else if (node.getAttribute('data-label')) {
237
+ input.setAttribute('aria-label', node.getAttribute('data-label'));
238
+ }
239
+ return labelled(node, input);
240
+ }
241
+
242
+ function optionsOf(node) {
243
+ var found = [];
244
+ var children = node.querySelectorAll('.wf-option');
245
+ var i;
246
+ for (i = 0; i < children.length; i += 1) {
247
+ found.push(text(children[i]));
248
+ }
249
+ if (found.length === 0 && node.getAttribute('data-options')) {
250
+ found = node.getAttribute('data-options').split('|');
251
+ for (i = 0; i < found.length; i += 1) {
252
+ found[i] = found[i].trim();
253
+ }
254
+ }
255
+ if (found.length === 0) {
256
+ var only = text(node);
257
+ found.push(only === '' ? 'Select' : only);
258
+ }
259
+ return found;
260
+ }
261
+
262
+ // The dropdown reads its options out of a slotted fluent-listbox, so the
263
+ // options are built into one: without it the control has nothing to show.
264
+ function upgradeSelect(node) {
265
+ var dropdown = document.createElement('fluent-dropdown');
266
+ var listbox = document.createElement('fluent-listbox');
267
+ var values = optionsOf(node);
268
+ var current = node.getAttribute('data-value') || values[0];
269
+ for (var i = 0; i < values.length; i += 1) {
270
+ var option = document.createElement('fluent-option');
271
+ option.textContent = values[i];
272
+ if (values[i] === current) {
273
+ option.setAttribute('selected', '');
274
+ }
275
+ listbox.appendChild(option);
276
+ }
277
+ dropdown.appendChild(listbox);
278
+ return labelled(node, dropdown);
279
+ }
280
+
281
+ function upgradeCheckbox(node) {
282
+ var box = document.createElement('fluent-checkbox');
283
+ if (node.getAttribute('data-checked') === 'true') {
284
+ box.setAttribute('checked', '');
285
+ }
286
+ if (node.getAttribute('data-label')) {
287
+ box.textContent = node.getAttribute('data-label');
288
+ }
289
+ copy(node, box);
290
+ return box;
291
+ }
292
+
293
+ function upgradeToggle(node) {
294
+ var control = document.createElement('fluent-switch');
295
+ if (node.classList.contains('on') || node.getAttribute('data-checked') === 'true') {
296
+ control.setAttribute('checked', '');
297
+ }
298
+ if (node.getAttribute('data-label')) {
299
+ control.textContent = node.getAttribute('data-label');
300
+ }
301
+ copy(node, control);
302
+ return control;
303
+ }
304
+
305
+ function upgradeTabs(node) {
306
+ var list = document.createElement('fluent-tablist');
307
+ var active = '';
308
+ var children = node.children;
309
+ for (var i = 0; i < children.length; i += 1) {
310
+ var child = children[i];
311
+ var tab = document.createElement('fluent-tab');
312
+ tabSeq += 1;
313
+ tab.setAttribute('id', 'mk-fluent-tab-' + tabSeq);
314
+ tab.textContent = text(child);
315
+ copyTabs(child, tab);
316
+ if (child.classList.contains('is-active') || child.getAttribute('aria-selected') === 'true') {
317
+ active = tab.getAttribute('id');
318
+ }
319
+ list.appendChild(tab);
320
+ }
321
+ if (list.children.length > 0) {
322
+ list.setAttribute('activeid', active !== '' ? active : list.children[0].getAttribute('id'));
323
+ }
324
+ copy(node, list);
325
+ return list;
326
+ }
327
+
328
+ function copyTabs(child, tab) {
329
+ var attrs = child.attributes;
330
+ for (var i = 0; i < attrs.length; i += 1) {
331
+ if (attrs[i].name.indexOf('data-') === 0) {
332
+ tab.setAttribute(attrs[i].name, attrs[i].value);
333
+ }
334
+ }
335
+ }
336
+
337
+ var BUILDERS = {
338
+ 'wf-button': upgradeButton,
339
+ 'wf-input': upgradeInput,
340
+ 'wf-select': upgradeSelect,
341
+ 'wf-checkbox': upgradeCheckbox,
342
+ 'wf-toggle': upgradeToggle,
343
+ 'wf-tabs': upgradeTabs
344
+ };
345
+
346
+ // ------------------------------------------------------------- upgrade --
347
+
348
+ function build(node) {
349
+ var keys = Object.keys(BUILDERS);
350
+ for (var i = 0; i < keys.length; i += 1) {
351
+ if (!node.classList.contains(keys[i])) {
352
+ continue;
353
+ }
354
+ var replacement;
355
+ try {
356
+ replacement = BUILDERS[keys[i]](node);
357
+ } catch (err) {
358
+ warn('could not upgrade ' + keys[i] + ': ' + (err && err.message ? err.message : err));
359
+ return;
360
+ }
361
+ var parent = node.parentNode;
362
+ if (!parent) {
363
+ return;
364
+ }
365
+ parent.replaceChild(replacement, node);
366
+ built.push({ original: node, upgraded: replacement });
367
+ return;
368
+ }
369
+ }
370
+
371
+ function upgrade() {
372
+ var screens = fluentScreens();
373
+ forget(screens);
374
+ if (screens.length === 0) {
375
+ return;
376
+ }
377
+ ensure(function (ok) {
378
+ if (!ok) {
379
+ restore();
380
+ return;
381
+ }
382
+ for (var s = 0; s < screens.length; s += 1) {
383
+ if (skinOf(screens[s]) !== 'fluent') {
384
+ continue;
385
+ }
386
+ var nodes = screens[s].querySelectorAll(SELECTOR);
387
+ for (var i = 0; i < nodes.length; i += 1) {
388
+ build(nodes[i]);
389
+ }
390
+ }
391
+ });
392
+ }
393
+
394
+ // A screen that stopped being fluent goes back to the kit's own controls,
395
+ // while the screens that are still fluent keep their real components.
396
+ function forget(screens) {
397
+ var stale = [];
398
+ for (var i = 0; i < built.length; i += 1) {
399
+ var host = built[i].upgraded.closest ? built[i].upgraded.closest('.mk-screen') : null;
400
+ if (screens.indexOf(host) < 0) {
401
+ stale.push(host);
402
+ }
403
+ }
404
+ for (var s = 0; s < stale.length; s += 1) {
405
+ restore(stale[s]);
406
+ }
407
+ }
408
+
409
+ function restore(screen) {
410
+ for (var i = built.length - 1; i >= 0; i -= 1) {
411
+ var record = built[i];
412
+ if (screen !== undefined) {
413
+ var host = record.upgraded.closest ? record.upgraded.closest('.mk-screen') : null;
414
+ if (host !== screen) {
415
+ continue;
416
+ }
417
+ }
418
+ var parent = record.upgraded.parentNode;
419
+ if (parent) {
420
+ parent.replaceChild(record.original, record.upgraded);
421
+ }
422
+ built.splice(i, 1);
423
+ }
424
+ }
425
+
426
+ // --------------------------------------------------------------- wiring --
427
+
428
+ function schedule(delay) {
429
+ if (debounce !== null) {
430
+ window.clearTimeout(debounce);
431
+ }
432
+ debounce = window.setTimeout(function () {
433
+ debounce = null;
434
+ upgrade();
435
+ }, delay === undefined ? 40 : delay);
436
+ }
437
+
438
+ document.addEventListener('mkchange', function () {
439
+ schedule(60);
440
+ });
441
+
442
+ // The components paint from the tokens of the active mode, so a mode change
443
+ // is a repaint and nothing more: the same upgrade pass keeps both modes and
444
+ // the toolbar's skin switch in one code path.
445
+ document.addEventListener('rshowmodechange', function () {
446
+ if (isFluent()) {
447
+ schedule(20);
448
+ }
449
+ });
450
+
451
+ if (document.readyState === 'loading') {
452
+ document.addEventListener('DOMContentLoaded', function () {
453
+ schedule(0);
454
+ });
455
+ } else {
456
+ schedule(0);
457
+ }
458
+ }());