@kitlangton/knobs 0.4.0-next.1 → 0.4.0-next.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 +63 -0
- package/dist/types/ui/index.d.ts +2 -2
- package/dist/types/ui/walkthrough-blocks.d.ts +43 -0
- package/dist/types/ui/walkthrough-media.d.ts +4 -0
- package/dist/types/ui/walkthrough-model.d.ts +237 -3
- package/dist/types/ui/walkthrough.d.ts +3 -1
- package/dist/ui-react.js +859 -101
- package/dist/ui-solid.js +859 -101
- package/dist/ui.js +860 -101
- package/package.json +1 -1
package/dist/ui-solid.js
CHANGED
|
@@ -16375,7 +16375,7 @@ var walkthroughCss = `
|
|
|
16375
16375
|
.knobs-walkthrough a{color:inherit;text-decoration:underline;text-decoration-color:color-mix(in srgb,currentColor 35%,transparent);text-underline-offset:2px;transition:text-decoration-color .15s}
|
|
16376
16376
|
.knobs-walkthrough a:hover{text-decoration-color:currentColor}
|
|
16377
16377
|
.knobs-walkthrough code,.knobs-wt-slot code{font:calc(1em - 1px) var(--_k-mono);padding:1px 5px;border-radius:5px;background:var(--_k-fill)}
|
|
16378
|
-
:where(.knobs-ui) :is(.knobs-wt-btn,.knobs-wt-pick,.knobs-wt-toc-step){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;
|
|
16378
|
+
:where(.knobs-ui) :is(.knobs-wt-btn,.knobs-wt-pick,.knobs-wt-toc-step,button.knobs-wt-stitle,.knobs-wt-chapter){all:revert;box-sizing:border-box;font:inherit;color:inherit;letter-spacing:inherit;
|
|
16379
16379
|
background:transparent;border:0;border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
16380
16380
|
|
|
16381
16381
|
/* ——— layout: the rail beside the column; one column where it's narrow ——— */
|
|
@@ -16434,9 +16434,9 @@ var walkthroughCss = `
|
|
|
16434
16434
|
.knobs-wt-fi-body{max-width:var(--kw-measure);color:var(--_k-fg)}
|
|
16435
16435
|
.knobs-wt-fi-q{color:var(--_k-fg-2)}
|
|
16436
16436
|
.knobs-wt-fi-q::before{content:"You asked: ";color:var(--_k-fg-3)}
|
|
16437
|
-
:where(.knobs-ui) .knobs-wt-fi-step{all:revert;box-sizing:border-box;font:var(--_k-weight) calc(var(--
|
|
16437
|
+
:where(.knobs-ui) :is(.knobs-wt-fi-step,.knobs-wt-steplink){all:revert;box-sizing:border-box;font:var(--_k-weight) calc(var(--k-walkthrough-text,14px) - 2.5px)/1 var(--_k-mono);color:var(--_k-fg-2);background:transparent;border:0;
|
|
16438
16438
|
padding:3px 6px;margin:0;border-radius:6px;cursor:pointer;outline:none;transition:background .15s,color .15s}
|
|
16439
|
-
.knobs-ui .knobs-wt-fi-step:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
16439
|
+
.knobs-ui :is(.knobs-wt-fi-step,.knobs-wt-steplink):is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
16440
16440
|
|
|
16441
16441
|
/* ——— a step's sent notes ——— */
|
|
16442
16442
|
.knobs-wt-notes{display:flex;flex-direction:column}
|
|
@@ -16572,7 +16572,8 @@ var walkthroughCss = `
|
|
|
16572
16572
|
}
|
|
16573
16573
|
|
|
16574
16574
|
/* ——— media slots ——— */
|
|
16575
|
-
.knobs-ui.knobs-wt-slot{position:relative;min-width:0;container:knobs-wt-slot / inline-size;color:var(--_k-fg);font:var(--_k-weight) var(--k-walkthrough-text,14px)/1.5 var(--_k-font)
|
|
16575
|
+
.knobs-ui.knobs-wt-slot{position:relative;min-width:0;container:knobs-wt-slot / inline-size;color:var(--_k-fg);font:var(--_k-weight) var(--k-walkthrough-text,14px)/1.5 var(--_k-font);
|
|
16576
|
+
--kw-good:var(--k-walkthrough-good,var(--_k-ok));--kw-info:var(--k-walkthrough-info,var(--_k-info))}
|
|
16576
16577
|
.knobs-wt-slot-label{display:block;margin:0 0 6px 2px;font:var(--_k-weight-label) calc(var(--k-walkthrough-text,14px) - 3px)/1.3 var(--_k-font);color:var(--_k-fg-2);letter-spacing:.04em;text-transform:uppercase}
|
|
16577
16578
|
/* A compare is exactly as tall as its pictures at this width, so there's no letterbox: the two
|
|
16578
16579
|
sides edge to edge (side) or one (overlaid), plus its mode bar, the timeline and their two gaps
|
|
@@ -16612,9 +16613,141 @@ var walkthroughCss = `
|
|
|
16612
16613
|
.knobs-wt-text{max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
16613
16614
|
.knobs-wt-hold{border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill)}
|
|
16614
16615
|
.knobs-wt-failed{display:flex;align-items:center;justify-content:center;min-height:80px;color:var(--_k-fg-3);font-size:calc(var(--k-walkthrough-text,14px) - 2px)}
|
|
16616
|
+
|
|
16617
|
+
/* ——— data blocks: history, stack, table, chapters. On the step's card, so no card of their own:
|
|
16618
|
+
hairlines and fills only. Tones read the status tokens; hover fades are the panel's own. ——— */
|
|
16619
|
+
:where(.knobs-wt-history,.knobs-wt-stack,.knobs-wt-table,.knobs-wt-chapters){--kw-t:var(--k-walkthrough-text,14px);--kw-line:calc(var(--kw-t) + 6px);--kw-rail:var(--_k-border-strong)}
|
|
16620
|
+
:where(.knobs-wt-slot) [data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
16621
|
+
:where(.knobs-wt-slot) [data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
16622
|
+
:where(.knobs-wt-slot) [data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
16623
|
+
:where(.knobs-wt-slot) [data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
16624
|
+
:where(.knobs-wt-slot) [data-tone="dim"]{--kw-tone:var(--_k-fg-3)}
|
|
16625
|
+
.knobs-wt-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
|
|
16626
|
+
.knobs-ui .knobs-wt-tag{display:inline-flex;align-items:center;height:20px;padding:0 6px;border-radius:5px;background:var(--_k-fill);color:var(--_k-fg-2);font:var(--_k-weight) calc(var(--kw-t) - 3px)/1 var(--_k-mono);
|
|
16627
|
+
text-decoration:none;white-space:nowrap;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
|
|
16628
|
+
.knobs-ui a.knobs-wt-tag:is(:hover,:focus-visible){background:var(--_k-fill-selected);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
16629
|
+
|
|
16630
|
+
/* A history: dates down the left, a spine of tone dots joined by a hairline (broken around each
|
|
16631
|
+
dot), the event beside it. Inferred events take a ring for a dot and a dashed tag. */
|
|
16632
|
+
.knobs-wt-history{--kw-hy:calc(5px + var(--kw-line) / 2);display:flex;flex-direction:column;gap:18px;font-size:calc(var(--kw-t) - 1px);line-height:var(--kw-line);color:var(--_k-fg)}
|
|
16633
|
+
.knobs-wt-hgroup{display:flex;flex-direction:column;gap:6px;min-width:0}
|
|
16634
|
+
.knobs-wt-hhead{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px}
|
|
16635
|
+
.knobs-ui .knobs-wt-hheading{margin:0;font:var(--_k-weight-label) calc(var(--kw-t) - 3px)/1.3 var(--_k-font);letter-spacing:.04em;text-transform:uppercase;color:var(--_k-fg-2)}
|
|
16636
|
+
.knobs-wt-hsum{color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 2px);font-variant-numeric:tabular-nums}
|
|
16637
|
+
.knobs-wt-hlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
|
|
16638
|
+
.knobs-wt-hev{display:grid;grid-template-columns:var(--kw-hw,11ch) 14px minmax(0,1fr);grid-template-areas:"when spine main";column-gap:10px;align-items:baseline;padding:5px 0}
|
|
16639
|
+
.knobs-wt-hwhen{grid-area:when;display:flex;flex-direction:column;min-width:0;font:var(--_k-weight) calc(var(--kw-t) - 2px)/var(--kw-line) var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-2)}
|
|
16640
|
+
.knobs-wt-hage{color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 3px);line-height:1.35}
|
|
16641
|
+
.knobs-wt-hspine{grid-area:spine;position:relative;align-self:stretch;margin-block:-5px}
|
|
16642
|
+
.knobs-wt-hspine::before,.knobs-wt-hspine::after{content:"";position:absolute;left:6.5px;width:1px;background:var(--kw-rail)}
|
|
16643
|
+
.knobs-wt-hspine::before{top:0;height:calc(var(--kw-hy) - 6px)}
|
|
16644
|
+
.knobs-wt-hspine::after{top:calc(var(--kw-hy) + 6px);bottom:0}
|
|
16645
|
+
.knobs-wt-hev:first-child .knobs-wt-hspine::before,.knobs-wt-hev:last-child .knobs-wt-hspine::after{content:none}
|
|
16646
|
+
.knobs-wt-hdot{position:absolute;left:3.5px;top:calc(var(--kw-hy) - 3.5px);width:7px;height:7px;border-radius:50%;background:var(--kw-tone,var(--_k-fg-3))}
|
|
16647
|
+
.knobs-wt-hev[data-type="release"] .knobs-wt-hdot{border-radius:1.5px;rotate:45deg;scale:.9}
|
|
16648
|
+
.knobs-wt-hev[data-type="audit"] .knobs-wt-hdot{border-radius:1.5px}
|
|
16649
|
+
.knobs-wt-hev[data-provenance="inferred"] .knobs-wt-hdot{background:transparent;box-shadow:inset 0 0 0 1.5px var(--kw-tone,var(--_k-fg-3))}
|
|
16650
|
+
.knobs-wt-hmain{grid-area:main;display:flex;flex-direction:column;gap:2px;min-width:0}
|
|
16651
|
+
.knobs-wt-htitle{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
|
|
16652
|
+
.knobs-wt-prov{padding:0 6px;border-radius:5px;background:var(--_k-fill);color:var(--_k-fg-3);font:var(--_k-weight) calc(var(--kw-t) - 3.5px)/18px var(--_k-mono);white-space:nowrap}
|
|
16653
|
+
.knobs-wt-hev[data-provenance="inferred"] .knobs-wt-prov{background:transparent;color:var(--_k-warn);outline:1px dashed color-mix(in oklch,var(--_k-warn) 50%,transparent);outline-offset:-1px}
|
|
16654
|
+
.knobs-ui .knobs-wt-hdetail{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
16655
|
+
@container knobs-wt-slot (max-width:520px){
|
|
16656
|
+
.knobs-wt-hev{grid-template-columns:14px minmax(0,1fr);grid-template-areas:"spine when" "spine main"}
|
|
16657
|
+
.knobs-wt-hwhen{flex-direction:row;flex-wrap:wrap;align-items:baseline;column-gap:8px}
|
|
16658
|
+
}
|
|
16659
|
+
|
|
16660
|
+
/* A stack: the trunk at the top, each PR hanging off the branch it merges into, rails drawn as a
|
|
16661
|
+
git graph (solid, so where two meet they don't darken). A PR with a step goes there on a click. */
|
|
16662
|
+
.knobs-wt-stack{--kw-spt:7px;--kw-spb:7px;--kw-sy:calc(var(--kw-spt) + var(--kw-line) / 2);display:flex;flex-direction:column;font-size:calc(var(--kw-t) - 1px);line-height:var(--kw-line);color:var(--_k-fg)}
|
|
16663
|
+
.knobs-wt-srow{display:grid;grid-template-columns:auto minmax(0,1fr) auto;column-gap:10px;align-items:start;margin:0 -8px;padding:var(--kw-spt) 8px var(--kw-spb);
|
|
16664
|
+
border-radius:max(0px,calc(var(--_k-radius-panel) - 8px));transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
16665
|
+
.knobs-wt-srow[data-trunk]{--kw-spb:0px;grid-template-columns:auto minmax(0,1fr)}
|
|
16666
|
+
.knobs-wt-srow[data-go]{cursor:pointer}
|
|
16667
|
+
.knobs-wt-srow[data-go]:hover{background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
16668
|
+
.knobs-wt-lanes{display:flex;align-self:stretch;margin-block:calc(var(--kw-spt) * -1) calc(var(--kw-spb) * -1)}
|
|
16669
|
+
.knobs-wt-lane{position:relative;flex:none;width:16px}
|
|
16670
|
+
.knobs-wt-lane:is([data-rail="pass"],[data-rail="tee"],[data-down])::before{content:"";position:absolute;left:7.5px;top:0;bottom:0;width:1px;background:var(--kw-rail)}
|
|
16671
|
+
.knobs-wt-lane[data-down]::before{top:calc(var(--kw-sy) + 3.5px)}
|
|
16672
|
+
.knobs-wt-lane:is([data-rail="tee"],[data-rail="end"])::after{content:"";position:absolute;left:7.5px;top:0;width:13px;height:calc(var(--kw-sy) + .5px);border:solid var(--kw-rail);border-width:0 0 1px 1px;border-bottom-left-radius:6px}
|
|
16673
|
+
.knobs-wt-lane[data-rail="node"]::after{content:"";position:absolute;left:4.5px;top:calc(var(--kw-sy) - 3.5px);width:7px;height:7px;border-radius:50%;background:var(--_k-fg-3)}
|
|
16674
|
+
.knobs-wt-srow[data-trunk] .knobs-wt-lane[data-rail="node"]::after{background:var(--_k-fg-2)}
|
|
16675
|
+
.knobs-wt-trunk{font:var(--_k-weight-label) calc(var(--kw-t) - 2px)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2)}
|
|
16676
|
+
.knobs-wt-smain{display:flex;flex-direction:column;gap:1px;min-width:0}
|
|
16677
|
+
.knobs-wt-sline{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 8px}
|
|
16678
|
+
.knobs-wt-sord{font:var(--_k-weight) calc(var(--kw-t) - 2px)/var(--kw-line) var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-3);white-space:nowrap}
|
|
16679
|
+
.knobs-ui .knobs-wt-spr{font:var(--_k-weight-label) calc(var(--kw-t) - 1.5px)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2);text-decoration:none;white-space:nowrap}
|
|
16680
|
+
.knobs-ui a.knobs-wt-spr:is(:hover,:focus-visible){color:var(--_k-fg);text-decoration:underline}
|
|
16681
|
+
.knobs-ui .knobs-wt-stitle{font-weight:var(--_k-weight-label);line-height:var(--kw-line);color:var(--_k-fg);text-align:left}
|
|
16682
|
+
.knobs-ui button.knobs-wt-stitle{cursor:pointer;text-decoration:underline;text-decoration-color:transparent;text-underline-offset:3px;transition:text-decoration-color calc(var(--_k-hover-out) * 1ms)}
|
|
16683
|
+
.knobs-ui :is(.knobs-wt-srow[data-go]:hover button.knobs-wt-stitle,button.knobs-wt-stitle:focus-visible){text-decoration-color:color-mix(in oklch,currentColor 45%,transparent);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
16684
|
+
.knobs-ui .knobs-wt-ssummary{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
16685
|
+
.knobs-wt-smeta{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 12px;font:var(--_k-weight) calc(var(--kw-t) - 2px)/var(--kw-line) var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-3)}
|
|
16686
|
+
.knobs-wt-delta{display:inline-flex;gap:6px}
|
|
16687
|
+
.knobs-wt-add{color:var(--_k-diff-add)}
|
|
16688
|
+
.knobs-wt-del{color:var(--_k-diff-del)}
|
|
16689
|
+
.knobs-wt-sstatus{margin-top:calc((var(--kw-line) - 20px) / 2)}
|
|
16690
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr) auto}
|
|
16691
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow+.knobs-wt-srow{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
16692
|
+
@container knobs-wt-slot (max-width:520px){
|
|
16693
|
+
.knobs-wt-srow:not([data-trunk]){grid-template-columns:auto minmax(0,1fr)}
|
|
16694
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr)}
|
|
16695
|
+
.knobs-wt-sstatus{grid-column:-2;justify-self:start;margin-top:4px}
|
|
16696
|
+
}
|
|
16697
|
+
|
|
16698
|
+
/* A table: a real one, its head stuck while it scrolls, both ways; edges fade where there's more
|
|
16699
|
+
(the top one under the head), and thin bars show on hover. */
|
|
16700
|
+
@property --kw-fade-l{syntax:"<number>";inherits:false;initial-value:1}
|
|
16701
|
+
@property --kw-fade-r{syntax:"<number>";inherits:false;initial-value:1}
|
|
16702
|
+
@keyframes kw-fade-l{from{--kw-fade-l:1}to{--kw-fade-l:0}}
|
|
16703
|
+
@keyframes kw-fade-r{from{--kw-fade-r:0}to{--kw-fade-r:1}}
|
|
16704
|
+
.knobs-wt-table{max-height:520px;overflow:auto;overscroll-behavior-x:contain;outline:none;scrollbar-width:thin;scrollbar-color:transparent transparent;
|
|
16705
|
+
transition:scrollbar-color calc(var(--_k-hover-out) * 1ms)}
|
|
16706
|
+
.knobs-wt-table:is(:hover,:focus-visible){scrollbar-color:color-mix(in oklch,var(--_k-fg) 28%,transparent) transparent;transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
16707
|
+
.knobs-wt-table:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus);border-radius:calc(var(--_k-radius-panel) - 4px)}
|
|
16708
|
+
@supports (animation-timeline:scroll()){
|
|
16709
|
+
.knobs-wt-table{animation:knobs-fade-a linear both,knobs-fade-b linear both,kw-fade-l linear both,kw-fade-r linear both;animation-duration:auto;
|
|
16710
|
+
animation-timeline:scroll(self block),scroll(self block),scroll(self inline),scroll(self inline);animation-range:0 24px,calc(100% - 24px) 100%,0 8px,calc(100% - 8px) 100%;
|
|
16711
|
+
--kw-table-mask-y:linear-gradient(to bottom,#000 var(--kw-thead,0px),rgb(0 0 0/var(--knobs-fade-a)) var(--kw-thead,0px),#000 calc(var(--kw-thead,0px) + 20px),#000 calc(100% - 20px),rgb(0 0 0/var(--knobs-fade-b)));
|
|
16712
|
+
--kw-table-mask-x:linear-gradient(to right,rgb(0 0 0/var(--kw-fade-l)),#000 24px,#000 calc(100% - 24px),rgb(0 0 0/var(--kw-fade-r)));
|
|
16713
|
+
-webkit-mask-image:var(--kw-table-mask-y),var(--kw-table-mask-x);mask-image:var(--kw-table-mask-y),var(--kw-table-mask-x);-webkit-mask-composite:source-in;mask-composite:intersect}
|
|
16714
|
+
}
|
|
16715
|
+
.knobs-wt-table table{width:100%;margin:0;border-collapse:separate;border-spacing:0;font-size:calc(var(--kw-t) - 1.5px);line-height:1.45;font-variant-numeric:tabular-nums;color:var(--_k-fg-2)}
|
|
16716
|
+
.knobs-wt-table caption{caption-side:bottom;padding-top:8px;text-align:left;color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 2px)}
|
|
16717
|
+
.knobs-wt-table th{position:sticky;top:0;padding:0 12px 7px;text-align:left;vertical-align:bottom;font-weight:var(--_k-weight-label);font-size:calc(var(--kw-t) - 2.5px);color:var(--_k-fg-3);white-space:nowrap;
|
|
16718
|
+
background:var(--_k-pane-bg);box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
16719
|
+
.knobs-wt-table td{padding:8px 12px;vertical-align:baseline;box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
16720
|
+
.knobs-wt-table tr:last-child td{box-shadow:none}
|
|
16721
|
+
.knobs-wt-table :is(th,td):first-child{padding-left:0}
|
|
16722
|
+
.knobs-wt-table :is(th,td):last-child{padding-right:0}
|
|
16723
|
+
.knobs-wt-table td:first-child{color:var(--_k-fg)}
|
|
16724
|
+
.knobs-wt-table [data-align="right"]{text-align:right}
|
|
16725
|
+
.knobs-wt-table [data-align="center"]{text-align:center}
|
|
16726
|
+
.knobs-wt-table td[data-mono]{font-family:var(--_k-mono);font-size:calc(var(--kw-t) - 2.5px);color:var(--_k-fg);white-space:nowrap}
|
|
16727
|
+
.knobs-wt-table td[data-long]{min-width:24ch}
|
|
16728
|
+
.knobs-wt-table td>.knobs-wt-steplink{margin-left:4px}
|
|
16729
|
+
.knobs-ui .knobs-wt-table a.knobs-wt-chip{text-decoration:none}
|
|
16730
|
+
.knobs-wt-ctone{color:var(--kw-tone)}
|
|
16731
|
+
|
|
16732
|
+
/* Chapters: timestamp pills under a video; one highlight springs to the one playing. */
|
|
16733
|
+
.knobs-wt-chapters{position:relative;display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}
|
|
16734
|
+
.knobs-wt-chapter-mark{position:absolute;left:0;top:0;width:0;border-radius:calc(var(--_k-radius) + 2px);background:var(--_k-fill-selected);opacity:0;pointer-events:none;will-change:transform;
|
|
16735
|
+
transition:opacity calc(var(--_k-motion-snappy-ms) * 1ms)}
|
|
16736
|
+
.knobs-wt-chapter-mark[data-on]{opacity:1}
|
|
16737
|
+
.knobs-ui .knobs-wt-chapter{position:relative;display:inline-flex;align-items:baseline;gap:6px;height:26px;padding:0 10px 0 8px;border-radius:calc(var(--_k-radius) + 2px);color:var(--_k-fg-2);
|
|
16738
|
+
font-size:calc(var(--kw-t) - 2px);line-height:26px;white-space:nowrap;cursor:pointer;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
|
|
16739
|
+
.knobs-ui .knobs-wt-chapter:hover{background:var(--_ku-wash);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
16740
|
+
.knobs-ui .knobs-wt-chapter[aria-current]{background:transparent;color:var(--_k-fg)}
|
|
16741
|
+
.knobs-ui .knobs-wt-chapter:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus)}
|
|
16742
|
+
.knobs-wt-chapter-time{font:var(--_k-weight) calc(var(--kw-t) - 3px)/1 var(--_k-mono);font-variant-numeric:tabular-nums;color:var(--_k-fg-3)}
|
|
16743
|
+
.knobs-wt-chapter[aria-current] .knobs-wt-chapter-time{color:var(--_k-fg-2)}
|
|
16615
16744
|
@media(prefers-reduced-motion:reduce){:is(.knobs-walkthrough,.knobs-wt-slot) :where(*,::before,::after){transition-duration:.15s!important;transition-property:opacity,background,color!important}}
|
|
16616
16745
|
`;
|
|
16617
16746
|
|
|
16747
|
+
// src/ui/walkthrough-blocks.ts
|
|
16748
|
+
init_motion();
|
|
16749
|
+
init_look();
|
|
16750
|
+
|
|
16618
16751
|
// src/ui/walkthrough-model.ts
|
|
16619
16752
|
var DEFAULT_VERDICTS = ["ship", "change", "unsure"];
|
|
16620
16753
|
function slug(text) {
|
|
@@ -16656,20 +16789,207 @@ function fillMedia(m, base) {
|
|
|
16656
16789
|
if (typeof m === "string")
|
|
16657
16790
|
return mediaOf(resolveSrc(m, base));
|
|
16658
16791
|
switch (m.kind) {
|
|
16659
|
-
case "compare":
|
|
16660
|
-
|
|
16661
|
-
case "video":
|
|
16792
|
+
case "compare": {
|
|
16793
|
+
const { chapters, ...rest } = m;
|
|
16662
16794
|
return {
|
|
16663
|
-
...
|
|
16795
|
+
...rest,
|
|
16796
|
+
before: source2(m.before, base),
|
|
16797
|
+
after: source2(m.after, base),
|
|
16798
|
+
...chapters?.length ? { chapters: fillChapters(chapters) } : {}
|
|
16799
|
+
};
|
|
16800
|
+
}
|
|
16801
|
+
case "video": {
|
|
16802
|
+
const { chapters, captionsSrc, captions, ...rest } = m;
|
|
16803
|
+
const vtt = captions ?? captionsSrc;
|
|
16804
|
+
return {
|
|
16805
|
+
...rest,
|
|
16664
16806
|
src: resolveSrc(m.src, base),
|
|
16665
|
-
...m.poster ? { poster: resolveSrc(m.poster, base) } : {}
|
|
16807
|
+
...m.poster ? { poster: resolveSrc(m.poster, base) } : {},
|
|
16808
|
+
...vtt ? { captions: resolveSrc(vtt, base) } : {},
|
|
16809
|
+
...chapters?.length ? { chapters: fillChapters(chapters) } : {}
|
|
16666
16810
|
};
|
|
16811
|
+
}
|
|
16667
16812
|
case "image":
|
|
16668
16813
|
return { ...m, src: resolveSrc(m.src, base) };
|
|
16814
|
+
case "history":
|
|
16815
|
+
return { kind: "history", groups: fillHistory(m) };
|
|
16816
|
+
case "stack":
|
|
16817
|
+
return {
|
|
16818
|
+
kind: "stack",
|
|
16819
|
+
...m.base ? { base: m.base } : {},
|
|
16820
|
+
items: m.items.map(fillStackItem)
|
|
16821
|
+
};
|
|
16822
|
+
case "table":
|
|
16823
|
+
return fillTable(m);
|
|
16669
16824
|
default:
|
|
16670
16825
|
return m;
|
|
16671
16826
|
}
|
|
16672
16827
|
}
|
|
16828
|
+
function fillHistory(m) {
|
|
16829
|
+
const groups = [];
|
|
16830
|
+
if (m.events?.length)
|
|
16831
|
+
groups.push({ events: m.events });
|
|
16832
|
+
for (const g of m.groups ?? [])
|
|
16833
|
+
groups.push({
|
|
16834
|
+
...g.heading ? { heading: g.heading } : {},
|
|
16835
|
+
...g.summary ? { summary: g.summary } : {},
|
|
16836
|
+
events: g.events ?? g.rows ?? []
|
|
16837
|
+
});
|
|
16838
|
+
return groups;
|
|
16839
|
+
}
|
|
16840
|
+
function parseBranch(branch) {
|
|
16841
|
+
if (!branch?.trim())
|
|
16842
|
+
return {};
|
|
16843
|
+
const [head, base] = branch.split(/\s*(?:→|->|=>|⇒)\s*/, 2).map((s) => s.trim());
|
|
16844
|
+
return { ...head ? { head } : {}, ...base ? { base } : {} };
|
|
16845
|
+
}
|
|
16846
|
+
function parseDelta(delta) {
|
|
16847
|
+
if (delta === undefined || typeof delta === "object")
|
|
16848
|
+
return delta;
|
|
16849
|
+
const m = /\+\s*([\d,_]+)[^\d+]*?[-−–]\s*([\d,_]+)/.exec(delta);
|
|
16850
|
+
if (!m)
|
|
16851
|
+
return delta.trim() || undefined;
|
|
16852
|
+
const n = (s) => Number(s.replace(/[,_]/g, ""));
|
|
16853
|
+
return { add: n(m[1]), del: n(m[2]) };
|
|
16854
|
+
}
|
|
16855
|
+
function fillStackItem(it) {
|
|
16856
|
+
const parsed = parseBranch(it.branch);
|
|
16857
|
+
const head = parsed.head ?? it.head;
|
|
16858
|
+
const base = parsed.base ?? it.base;
|
|
16859
|
+
const delta = parseDelta(it.delta);
|
|
16860
|
+
const step = it.step ?? it.stepId;
|
|
16861
|
+
const pr = String(it.pr).trim();
|
|
16862
|
+
return {
|
|
16863
|
+
pr: /^\d+$/.test(pr) ? `#${pr}` : pr,
|
|
16864
|
+
...it.href ? { href: it.href } : {},
|
|
16865
|
+
title: it.title,
|
|
16866
|
+
...head ? { head } : {},
|
|
16867
|
+
...base ? { base } : {},
|
|
16868
|
+
...delta !== undefined ? { delta } : {},
|
|
16869
|
+
...it.status ? { status: it.status } : {},
|
|
16870
|
+
...it.tone ? { tone: it.tone } : {},
|
|
16871
|
+
...it.summary ? { summary: it.summary } : {},
|
|
16872
|
+
...step ? { step } : {},
|
|
16873
|
+
...it.order !== undefined && it.order !== "" ? { order: String(it.order) } : {}
|
|
16874
|
+
};
|
|
16875
|
+
}
|
|
16876
|
+
function stackLayout(m) {
|
|
16877
|
+
const items = m.items;
|
|
16878
|
+
const byHead = new Map;
|
|
16879
|
+
items.forEach((it, i) => it.head && !byHead.has(it.head) && byHead.set(it.head, i));
|
|
16880
|
+
let trunk = m.base ?? null;
|
|
16881
|
+
if (!trunk) {
|
|
16882
|
+
const tally = new Map;
|
|
16883
|
+
for (const it of items)
|
|
16884
|
+
if (it.base && !byHead.has(it.base))
|
|
16885
|
+
tally.set(it.base, (tally.get(it.base) ?? 0) + 1);
|
|
16886
|
+
let best = 0;
|
|
16887
|
+
for (const [b, n] of tally)
|
|
16888
|
+
if (n > best)
|
|
16889
|
+
[trunk, best] = [b, n];
|
|
16890
|
+
}
|
|
16891
|
+
const parentOf = items.map((it, i) => {
|
|
16892
|
+
const p = it.base === undefined ? undefined : byHead.get(it.base);
|
|
16893
|
+
return p === undefined || p === i ? null : p;
|
|
16894
|
+
});
|
|
16895
|
+
items.forEach((_, i) => {
|
|
16896
|
+
const seen = new Set;
|
|
16897
|
+
for (let n = i;n !== null; n = parentOf[n]) {
|
|
16898
|
+
if (seen.has(n)) {
|
|
16899
|
+
const loop = [n];
|
|
16900
|
+
for (let k = parentOf[n];k !== n && k !== null; k = parentOf[k])
|
|
16901
|
+
loop.push(k);
|
|
16902
|
+
parentOf[Math.min(...loop)] = null;
|
|
16903
|
+
break;
|
|
16904
|
+
}
|
|
16905
|
+
seen.add(n);
|
|
16906
|
+
}
|
|
16907
|
+
});
|
|
16908
|
+
const kids = items.map(() => []);
|
|
16909
|
+
const roots = [];
|
|
16910
|
+
parentOf.forEach((p, i) => (p === null ? roots : kids[p]).push(i));
|
|
16911
|
+
const rows = [];
|
|
16912
|
+
const walk = (list, depth, rails) => list.forEach((i, n) => {
|
|
16913
|
+
const it = items[i];
|
|
16914
|
+
const last = n === list.length - 1;
|
|
16915
|
+
const off = parentOf[i] === null && it.base && it.base !== trunk ? it.base : undefined;
|
|
16916
|
+
rows.push({
|
|
16917
|
+
item: it,
|
|
16918
|
+
index: i,
|
|
16919
|
+
depth,
|
|
16920
|
+
parent: parentOf[i],
|
|
16921
|
+
last,
|
|
16922
|
+
rails,
|
|
16923
|
+
children: kids[i].length,
|
|
16924
|
+
...off ? { offBase: off } : {}
|
|
16925
|
+
});
|
|
16926
|
+
walk(kids[i], depth + 1, [...rails, !last]);
|
|
16927
|
+
});
|
|
16928
|
+
walk(roots, 0, []);
|
|
16929
|
+
return { trunk, rows, flat: !trunk && rows.every((r) => r.depth === 0 && !r.children) };
|
|
16930
|
+
}
|
|
16931
|
+
var isNum = (c) => typeof c === "number" || typeof c === "object" && typeof c.text === "number";
|
|
16932
|
+
function fillCell(c) {
|
|
16933
|
+
if (typeof c !== "object")
|
|
16934
|
+
return { text: String(c) };
|
|
16935
|
+
return { ...c, text: String(c.text) };
|
|
16936
|
+
}
|
|
16937
|
+
function fillTable(m) {
|
|
16938
|
+
const wrapped = !m.columns.some((c) => c.key === "cells");
|
|
16939
|
+
const raw = m.rows.map((r) => {
|
|
16940
|
+
const keys = Object.keys(r);
|
|
16941
|
+
const cells = r.cells;
|
|
16942
|
+
return wrapped && keys.length === 1 && keys[0] === "cells" && cells && typeof cells === "object" ? cells : r;
|
|
16943
|
+
});
|
|
16944
|
+
const columns = m.columns.map((c) => {
|
|
16945
|
+
const present = raw.map((r) => r[c.key]).filter((v) => v !== undefined && v !== "");
|
|
16946
|
+
const numeric = present.length > 0 && present.every(isNum);
|
|
16947
|
+
return { ...c, align: c.align ?? (numeric ? "right" : "left") };
|
|
16948
|
+
});
|
|
16949
|
+
const rows = raw.map((r) => {
|
|
16950
|
+
const out = {};
|
|
16951
|
+
for (const [k, v] of Object.entries(r))
|
|
16952
|
+
if (v !== undefined && v !== null)
|
|
16953
|
+
out[k] = fillCell(v);
|
|
16954
|
+
return out;
|
|
16955
|
+
});
|
|
16956
|
+
return { kind: "table", columns, rows, ...m.caption ? { caption: m.caption } : {} };
|
|
16957
|
+
}
|
|
16958
|
+
function fillChapters(chapters) {
|
|
16959
|
+
const id = uniqueIds();
|
|
16960
|
+
const starts = chapters.map((c) => c.start).sort((a, b) => a - b);
|
|
16961
|
+
return chapters.map((c) => {
|
|
16962
|
+
const next = starts.find((s) => s > c.start);
|
|
16963
|
+
const end = c.end ?? (c.duration !== undefined ? Math.round((c.start + c.duration) * 1000) / 1000 : next);
|
|
16964
|
+
return {
|
|
16965
|
+
id: id(c.id ?? slug(c.label)),
|
|
16966
|
+
label: c.label,
|
|
16967
|
+
start: c.start,
|
|
16968
|
+
...end !== undefined && end > c.start ? { end } : {}
|
|
16969
|
+
};
|
|
16970
|
+
});
|
|
16971
|
+
}
|
|
16972
|
+
function chapterAt(chapters, time) {
|
|
16973
|
+
let at = -1;
|
|
16974
|
+
chapters.forEach((c, i) => {
|
|
16975
|
+
if (time >= c.start && time < (c.end ?? Infinity) && (at < 0 || c.start >= chapters[at].start))
|
|
16976
|
+
at = i;
|
|
16977
|
+
});
|
|
16978
|
+
return at;
|
|
16979
|
+
}
|
|
16980
|
+
function clock(seconds) {
|
|
16981
|
+
const t = Math.max(0, Math.floor(seconds));
|
|
16982
|
+
const h = Math.floor(t / 3600);
|
|
16983
|
+
const m = Math.floor(t % 3600 / 60);
|
|
16984
|
+
const s = String(t % 60).padStart(2, "0");
|
|
16985
|
+
return h ? `${h}:${String(m).padStart(2, "0")}:${s}` : `${m}:${s}`;
|
|
16986
|
+
}
|
|
16987
|
+
function findStep(steps, ref) {
|
|
16988
|
+
if (ref === undefined)
|
|
16989
|
+
return;
|
|
16990
|
+
const r = ref.trim().replace(/^#/, "");
|
|
16991
|
+
return steps.find((s) => s.key === r || s.id === r || s.number === r);
|
|
16992
|
+
}
|
|
16673
16993
|
function linkLabel(href) {
|
|
16674
16994
|
const pr = /\/(?:pull|issues)\/(\d+)/.exec(href);
|
|
16675
16995
|
if (pr)
|
|
@@ -16726,7 +17046,7 @@ function normalizeWalkthrough(doc) {
|
|
|
16726
17046
|
label: k,
|
|
16727
17047
|
value
|
|
16728
17048
|
}));
|
|
16729
|
-
const stepRef = (ref) =>
|
|
17049
|
+
const stepRef = (ref) => findStep(steps, ref)?.key ?? null;
|
|
16730
17050
|
const feed = sortFeed([
|
|
16731
17051
|
...(doc.updates ?? []).map((u) => ({ kind: "update", at: parseAt(u.at), text: u.text, step: stepRef(u.step) })),
|
|
16732
17052
|
...(doc.qa ?? []).map((x) => ({
|
|
@@ -16893,6 +17213,8 @@ function describeMedia(m) {
|
|
|
16893
17213
|
parts.push(`${m.kind} at ${formatTime(m.time)}`);
|
|
16894
17214
|
else
|
|
16895
17215
|
parts.push(m.kind);
|
|
17216
|
+
if (m.chapter)
|
|
17217
|
+
parts[0] += ` in “${m.chapter}”`;
|
|
16896
17218
|
if (m.loop)
|
|
16897
17219
|
parts.push(`loop ${formatTime(m.loop.start)}–${formatTime(m.loop.end)}`);
|
|
16898
17220
|
if (m.zoom)
|
|
@@ -17052,6 +17374,388 @@ function inlineMarkdown(text) {
|
|
|
17052
17374
|
return s.replace(/\u0000(\d+)\u0000/g, (_, i) => `<code>${escapeHtml(codes[Number(i)])}</code>`);
|
|
17053
17375
|
}
|
|
17054
17376
|
|
|
17377
|
+
// src/ui/walkthrough-blocks.ts
|
|
17378
|
+
var el = (doc, tag, cls) => {
|
|
17379
|
+
const n = doc.createElement(tag);
|
|
17380
|
+
if (cls)
|
|
17381
|
+
n.className = cls;
|
|
17382
|
+
return n;
|
|
17383
|
+
};
|
|
17384
|
+
var text = (doc, tag, cls, value) => {
|
|
17385
|
+
const n = el(doc, tag, cls);
|
|
17386
|
+
n.textContent = value;
|
|
17387
|
+
return n;
|
|
17388
|
+
};
|
|
17389
|
+
var prose = (doc, tag, cls, value) => {
|
|
17390
|
+
const n = el(doc, tag, cls);
|
|
17391
|
+
n.innerHTML = inlineMarkdown(value);
|
|
17392
|
+
return n;
|
|
17393
|
+
};
|
|
17394
|
+
var link = (doc, cls, label, href) => {
|
|
17395
|
+
if (!href)
|
|
17396
|
+
return text(doc, "span", cls, label);
|
|
17397
|
+
const a = text(doc, "a", cls, label);
|
|
17398
|
+
a.href = href;
|
|
17399
|
+
a.target = "_blank";
|
|
17400
|
+
a.rel = "noreferrer";
|
|
17401
|
+
return a;
|
|
17402
|
+
};
|
|
17403
|
+
function stepButton(doc, ref, steps) {
|
|
17404
|
+
const s = ref && steps?.find(ref);
|
|
17405
|
+
if (!s || !steps)
|
|
17406
|
+
return null;
|
|
17407
|
+
const b = text(doc, "button", "knobs-wt-steplink", s.number);
|
|
17408
|
+
b.type = "button";
|
|
17409
|
+
b.title = `Go to ${s.number} ${s.title}`;
|
|
17410
|
+
b.setAttribute("aria-label", b.title);
|
|
17411
|
+
b.addEventListener("click", (e) => {
|
|
17412
|
+
e.stopPropagation();
|
|
17413
|
+
steps.go(s.key);
|
|
17414
|
+
});
|
|
17415
|
+
return b;
|
|
17416
|
+
}
|
|
17417
|
+
var tags = (doc, list) => {
|
|
17418
|
+
if (!list?.length)
|
|
17419
|
+
return null;
|
|
17420
|
+
const row = el(doc, "div", "knobs-wt-tags");
|
|
17421
|
+
for (const e of list)
|
|
17422
|
+
row.append(link(doc, "knobs-wt-tag", e.label, e.href));
|
|
17423
|
+
return row;
|
|
17424
|
+
};
|
|
17425
|
+
function mountHistory(host, m, steps) {
|
|
17426
|
+
const doc = host.ownerDocument;
|
|
17427
|
+
const root = el(doc, "div", "knobs-wt-history");
|
|
17428
|
+
const longest = Math.max(6, ...m.groups.flatMap((g) => g.events.flatMap((e) => [e.date.length, e.age?.length ?? 0])));
|
|
17429
|
+
root.style.setProperty("--kw-hw", `${Math.min(16, longest + 1)}ch`);
|
|
17430
|
+
for (const g of m.groups) {
|
|
17431
|
+
const group = el(doc, "section", "knobs-wt-hgroup");
|
|
17432
|
+
if (g.heading || g.summary) {
|
|
17433
|
+
const head = el(doc, "header", "knobs-wt-hhead");
|
|
17434
|
+
if (g.heading)
|
|
17435
|
+
head.append(text(doc, "h4", "knobs-wt-hheading", g.heading));
|
|
17436
|
+
if (g.summary)
|
|
17437
|
+
head.append(text(doc, "span", "knobs-wt-hsum", g.summary));
|
|
17438
|
+
group.append(head);
|
|
17439
|
+
}
|
|
17440
|
+
const list = el(doc, "ol", "knobs-wt-hlist");
|
|
17441
|
+
for (const e of g.events)
|
|
17442
|
+
list.append(historyEvent(doc, e, steps));
|
|
17443
|
+
group.append(list);
|
|
17444
|
+
root.append(group);
|
|
17445
|
+
}
|
|
17446
|
+
host.append(root);
|
|
17447
|
+
return { dispose: () => root.remove(), context: () => ({ kind: "history" }) };
|
|
17448
|
+
}
|
|
17449
|
+
function historyEvent(doc, e, steps) {
|
|
17450
|
+
const li = el(doc, "li", "knobs-wt-hev");
|
|
17451
|
+
if (e.tone)
|
|
17452
|
+
li.dataset.tone = e.tone;
|
|
17453
|
+
if (e.type)
|
|
17454
|
+
li.dataset.type = e.type;
|
|
17455
|
+
if (e.provenance)
|
|
17456
|
+
li.dataset.provenance = e.provenance;
|
|
17457
|
+
const when = el(doc, "div", "knobs-wt-hwhen");
|
|
17458
|
+
when.append(text(doc, "time", "knobs-wt-hdate", e.date));
|
|
17459
|
+
if (e.age)
|
|
17460
|
+
when.append(text(doc, "span", "knobs-wt-hage", e.age));
|
|
17461
|
+
const spine = el(doc, "span", "knobs-wt-hspine");
|
|
17462
|
+
spine.setAttribute("aria-hidden", "true");
|
|
17463
|
+
spine.append(el(doc, "span", "knobs-wt-hdot"));
|
|
17464
|
+
const main = el(doc, "div", "knobs-wt-hmain");
|
|
17465
|
+
const title = el(doc, "div", "knobs-wt-htitle");
|
|
17466
|
+
title.append(text(doc, "span", "knobs-wt-htext", e.title));
|
|
17467
|
+
if (e.provenance || e.source) {
|
|
17468
|
+
const p = text(doc, "span", "knobs-wt-prov", [e.provenance, e.source].filter(Boolean).join(" · "));
|
|
17469
|
+
if (e.provenance === "inferred")
|
|
17470
|
+
p.title = "Inferred from behaviour, not seen in the record";
|
|
17471
|
+
else if (e.provenance === "verified")
|
|
17472
|
+
p.title = "Seen in the record";
|
|
17473
|
+
title.append(p);
|
|
17474
|
+
}
|
|
17475
|
+
const go = stepButton(doc, e.step, steps);
|
|
17476
|
+
if (go)
|
|
17477
|
+
title.append(go);
|
|
17478
|
+
main.append(title);
|
|
17479
|
+
if (e.detail)
|
|
17480
|
+
main.append(prose(doc, "p", "knobs-wt-hdetail", e.detail));
|
|
17481
|
+
const t = tags(doc, e.evidence);
|
|
17482
|
+
if (t)
|
|
17483
|
+
main.append(t);
|
|
17484
|
+
li.append(when, spine, main);
|
|
17485
|
+
return li;
|
|
17486
|
+
}
|
|
17487
|
+
function mountStack(host, m, steps) {
|
|
17488
|
+
const doc = host.ownerDocument;
|
|
17489
|
+
const layout = stackLayout(m);
|
|
17490
|
+
const root = el(doc, "div", "knobs-wt-stack");
|
|
17491
|
+
root.toggleAttribute("data-flat", layout.flat);
|
|
17492
|
+
const lane = (kind) => {
|
|
17493
|
+
const s = el(doc, "span", "knobs-wt-lane");
|
|
17494
|
+
s.dataset.rail = kind;
|
|
17495
|
+
return s;
|
|
17496
|
+
};
|
|
17497
|
+
const node = (down) => {
|
|
17498
|
+
const s = lane("node");
|
|
17499
|
+
s.toggleAttribute("data-down", down);
|
|
17500
|
+
return s;
|
|
17501
|
+
};
|
|
17502
|
+
const from = layout.trunk ? 0 : 1;
|
|
17503
|
+
if (layout.trunk && layout.rows.length) {
|
|
17504
|
+
const row = el(doc, "div", "knobs-wt-srow");
|
|
17505
|
+
row.dataset.trunk = "";
|
|
17506
|
+
const lanes = el(doc, "span", "knobs-wt-lanes");
|
|
17507
|
+
lanes.setAttribute("aria-hidden", "true");
|
|
17508
|
+
lanes.append(node(true));
|
|
17509
|
+
row.append(lanes, text(doc, "span", "knobs-wt-trunk", layout.trunk));
|
|
17510
|
+
root.append(row);
|
|
17511
|
+
}
|
|
17512
|
+
for (const r of layout.rows) {
|
|
17513
|
+
const it = r.item;
|
|
17514
|
+
const row = el(doc, "div", "knobs-wt-srow");
|
|
17515
|
+
if (!layout.flat) {
|
|
17516
|
+
const lanes = el(doc, "span", "knobs-wt-lanes");
|
|
17517
|
+
lanes.setAttribute("aria-hidden", "true");
|
|
17518
|
+
for (let k = from;k < r.depth; k++)
|
|
17519
|
+
lanes.append(lane(r.rails[k] ? "pass" : "none"));
|
|
17520
|
+
if (r.depth >= from)
|
|
17521
|
+
lanes.append(lane(r.last ? "end" : "tee"));
|
|
17522
|
+
lanes.append(node(r.children > 0));
|
|
17523
|
+
row.append(lanes);
|
|
17524
|
+
}
|
|
17525
|
+
const main = el(doc, "div", "knobs-wt-smain");
|
|
17526
|
+
const line = el(doc, "div", "knobs-wt-sline");
|
|
17527
|
+
if (it.order)
|
|
17528
|
+
line.append(text(doc, "span", "knobs-wt-sord", it.order));
|
|
17529
|
+
line.append(link(doc, "knobs-wt-spr", it.pr, it.href));
|
|
17530
|
+
const target = it.step ? steps?.find(it.step) : null;
|
|
17531
|
+
if (target && steps) {
|
|
17532
|
+
const title = text(doc, "button", "knobs-wt-stitle", it.title);
|
|
17533
|
+
title.type = "button";
|
|
17534
|
+
title.title = `Go to ${target.number} ${target.title}`;
|
|
17535
|
+
title.addEventListener("click", (e) => {
|
|
17536
|
+
e.stopPropagation();
|
|
17537
|
+
steps.go(target.key);
|
|
17538
|
+
});
|
|
17539
|
+
line.append(title);
|
|
17540
|
+
const go = stepButton(doc, it.step, steps);
|
|
17541
|
+
if (go)
|
|
17542
|
+
line.append(go);
|
|
17543
|
+
row.dataset.go = "";
|
|
17544
|
+
row.addEventListener("click", (e) => {
|
|
17545
|
+
const t = e.target;
|
|
17546
|
+
if (t?.closest("a,button"))
|
|
17547
|
+
return;
|
|
17548
|
+
if (doc.getSelection()?.toString())
|
|
17549
|
+
return;
|
|
17550
|
+
steps.go(target.key);
|
|
17551
|
+
});
|
|
17552
|
+
} else
|
|
17553
|
+
line.append(text(doc, "span", "knobs-wt-stitle", it.title));
|
|
17554
|
+
main.append(line);
|
|
17555
|
+
if (it.summary)
|
|
17556
|
+
main.append(prose(doc, "p", "knobs-wt-ssummary", it.summary));
|
|
17557
|
+
const meta = el(doc, "div", "knobs-wt-smeta");
|
|
17558
|
+
if (it.head) {
|
|
17559
|
+
const branch = r.offBase ? `${it.head} → ${r.offBase}` : it.head;
|
|
17560
|
+
meta.append(text(doc, "span", "knobs-wt-sbranch", branch));
|
|
17561
|
+
}
|
|
17562
|
+
if (it.delta !== undefined)
|
|
17563
|
+
meta.append(delta(doc, it.delta));
|
|
17564
|
+
if (meta.childNodes.length)
|
|
17565
|
+
main.append(meta);
|
|
17566
|
+
row.append(main);
|
|
17567
|
+
if (it.status) {
|
|
17568
|
+
const chip = text(doc, "span", "knobs-wt-chip knobs-wt-sstatus", it.status);
|
|
17569
|
+
chip.dataset.tone = it.tone ?? "dim";
|
|
17570
|
+
row.append(chip);
|
|
17571
|
+
}
|
|
17572
|
+
root.append(row);
|
|
17573
|
+
}
|
|
17574
|
+
host.append(root);
|
|
17575
|
+
return { dispose: () => root.remove(), context: () => ({ kind: "stack" }) };
|
|
17576
|
+
}
|
|
17577
|
+
function delta(doc, d) {
|
|
17578
|
+
const s = el(doc, "span", "knobs-wt-delta");
|
|
17579
|
+
if (typeof d === "string") {
|
|
17580
|
+
s.textContent = d;
|
|
17581
|
+
return s;
|
|
17582
|
+
}
|
|
17583
|
+
const n = (v) => v.toLocaleString("en-US");
|
|
17584
|
+
s.append(text(doc, "span", "knobs-wt-add", `+${n(d.add)}`));
|
|
17585
|
+
s.append(text(doc, "span", "knobs-wt-del", `−${n(d.del)}`));
|
|
17586
|
+
s.setAttribute("aria-label", `${d.add} added, ${d.del} removed`);
|
|
17587
|
+
return s;
|
|
17588
|
+
}
|
|
17589
|
+
function mountTable(host, m, steps) {
|
|
17590
|
+
const doc = host.ownerDocument;
|
|
17591
|
+
const win = doc.defaultView;
|
|
17592
|
+
const scroller = el(doc, "div", "knobs-wt-table");
|
|
17593
|
+
const table = el(doc, "table");
|
|
17594
|
+
if (m.caption)
|
|
17595
|
+
table.append(text(doc, "caption", "", m.caption));
|
|
17596
|
+
const head = el(doc, "thead");
|
|
17597
|
+
const hr = el(doc, "tr");
|
|
17598
|
+
for (const c of m.columns) {
|
|
17599
|
+
const th = text(doc, "th", "", c.label);
|
|
17600
|
+
th.scope = "col";
|
|
17601
|
+
th.dataset.align = c.align;
|
|
17602
|
+
hr.append(th);
|
|
17603
|
+
}
|
|
17604
|
+
head.append(hr);
|
|
17605
|
+
const body = el(doc, "tbody");
|
|
17606
|
+
for (const r of m.rows) {
|
|
17607
|
+
const tr = el(doc, "tr");
|
|
17608
|
+
for (const c of m.columns) {
|
|
17609
|
+
const td = el(doc, "td");
|
|
17610
|
+
td.dataset.align = c.align;
|
|
17611
|
+
if (c.mono)
|
|
17612
|
+
td.dataset.mono = "";
|
|
17613
|
+
const cell = r[c.key];
|
|
17614
|
+
if (cell) {
|
|
17615
|
+
if (cell.text.length > 40 && !c.mono && !cell.code)
|
|
17616
|
+
td.dataset.long = "";
|
|
17617
|
+
let content;
|
|
17618
|
+
if (cell.badge) {
|
|
17619
|
+
content = link(doc, "knobs-wt-chip", cell.text, cell.href);
|
|
17620
|
+
content.dataset.tone = cell.badge;
|
|
17621
|
+
} else {
|
|
17622
|
+
const inner = cell.code ? text(doc, "code", "", cell.text) : null;
|
|
17623
|
+
if (cell.href) {
|
|
17624
|
+
content = link(doc, "knobs-wt-clink", inner ? "" : cell.text, cell.href);
|
|
17625
|
+
if (inner)
|
|
17626
|
+
content.append(inner);
|
|
17627
|
+
} else
|
|
17628
|
+
content = inner ?? text(doc, "span", "", cell.text);
|
|
17629
|
+
if (cell.tone) {
|
|
17630
|
+
content.classList.add("knobs-wt-ctone");
|
|
17631
|
+
content.dataset.tone = cell.tone;
|
|
17632
|
+
}
|
|
17633
|
+
}
|
|
17634
|
+
td.append(content);
|
|
17635
|
+
const go = stepButton(doc, cell.step, steps);
|
|
17636
|
+
if (go)
|
|
17637
|
+
td.append(go);
|
|
17638
|
+
}
|
|
17639
|
+
tr.append(td);
|
|
17640
|
+
}
|
|
17641
|
+
body.append(tr);
|
|
17642
|
+
}
|
|
17643
|
+
table.append(head, body);
|
|
17644
|
+
scroller.append(table);
|
|
17645
|
+
host.append(scroller);
|
|
17646
|
+
const measure = () => {
|
|
17647
|
+
scroller.style.setProperty("--kw-thead", `${head.offsetHeight}px`);
|
|
17648
|
+
const scrolls = scroller.scrollWidth > scroller.clientWidth + 1 || scroller.scrollHeight > scroller.clientHeight + 1;
|
|
17649
|
+
if (scrolls) {
|
|
17650
|
+
scroller.tabIndex = 0;
|
|
17651
|
+
scroller.setAttribute("role", "region");
|
|
17652
|
+
scroller.setAttribute("aria-label", m.caption ?? "Table");
|
|
17653
|
+
} else {
|
|
17654
|
+
scroller.removeAttribute("tabindex");
|
|
17655
|
+
scroller.removeAttribute("role");
|
|
17656
|
+
scroller.removeAttribute("aria-label");
|
|
17657
|
+
}
|
|
17658
|
+
};
|
|
17659
|
+
const ro = win && "ResizeObserver" in win ? new win.ResizeObserver(measure) : null;
|
|
17660
|
+
ro?.observe(scroller);
|
|
17661
|
+
measure();
|
|
17662
|
+
return {
|
|
17663
|
+
dispose: () => {
|
|
17664
|
+
ro?.disconnect();
|
|
17665
|
+
scroller.remove();
|
|
17666
|
+
},
|
|
17667
|
+
context: () => ({ kind: "table" })
|
|
17668
|
+
};
|
|
17669
|
+
}
|
|
17670
|
+
var grid = (v) => Math.round(v * 64) / 64;
|
|
17671
|
+
function chapterPills(host, chapters, io) {
|
|
17672
|
+
const doc = host.ownerDocument;
|
|
17673
|
+
const win = doc.defaultView;
|
|
17674
|
+
const bar = el(doc, "div", "knobs-wt-chapters");
|
|
17675
|
+
bar.setAttribute("role", "group");
|
|
17676
|
+
bar.setAttribute("aria-label", "Chapters");
|
|
17677
|
+
const mark = el(doc, "span", "knobs-wt-chapter-mark");
|
|
17678
|
+
mark.setAttribute("aria-hidden", "true");
|
|
17679
|
+
bar.append(mark);
|
|
17680
|
+
const pills = chapters.map((c) => {
|
|
17681
|
+
const b = el(doc, "button", "knobs-wt-chapter");
|
|
17682
|
+
b.type = "button";
|
|
17683
|
+
b.append(text(doc, "span", "knobs-wt-chapter-time", clock(c.start)));
|
|
17684
|
+
b.append(text(doc, "span", "knobs-wt-chapter-label", c.label));
|
|
17685
|
+
b.addEventListener("click", () => {
|
|
17686
|
+
io.onEvent?.({ what: "seek", time: Math.round(c.start * 100) / 100, detail: c.label });
|
|
17687
|
+
io.seek(c.start);
|
|
17688
|
+
sync();
|
|
17689
|
+
});
|
|
17690
|
+
bar.append(b);
|
|
17691
|
+
return b;
|
|
17692
|
+
});
|
|
17693
|
+
host.append(bar);
|
|
17694
|
+
const x = new Spring(0, MOTION.calm.omega, MOTION.calm.zeta, 0.25);
|
|
17695
|
+
const y = new Spring(0, MOTION.calm.omega, MOTION.calm.zeta, 0.25);
|
|
17696
|
+
const w = new Spring(0, MOTION.calm.omega, MOTION.calm.zeta, 0.25);
|
|
17697
|
+
const draw = () => {
|
|
17698
|
+
const left = grid(x.x);
|
|
17699
|
+
mark.style.transform = `translate(${left}px,${grid(y.x)}px)`;
|
|
17700
|
+
mark.style.width = `${grid(x.x + w.x) - left}px`;
|
|
17701
|
+
};
|
|
17702
|
+
const loop = frameLoop(win, (dt) => {
|
|
17703
|
+
x.step(dt);
|
|
17704
|
+
y.step(dt);
|
|
17705
|
+
w.step(dt);
|
|
17706
|
+
draw();
|
|
17707
|
+
return !x.resting || !y.resting || !w.resting;
|
|
17708
|
+
});
|
|
17709
|
+
let at = -2;
|
|
17710
|
+
let shown = false;
|
|
17711
|
+
const place = (snap) => {
|
|
17712
|
+
const p = pills[at];
|
|
17713
|
+
if (!p) {
|
|
17714
|
+
mark.removeAttribute("data-on");
|
|
17715
|
+
pills.forEach((b) => b.removeAttribute("aria-current"));
|
|
17716
|
+
shown = false;
|
|
17717
|
+
return;
|
|
17718
|
+
}
|
|
17719
|
+
pills.forEach((b, i) => i === at ? b.setAttribute("aria-current", "true") : b.removeAttribute("aria-current"));
|
|
17720
|
+
const to = [p.offsetLeft, p.offsetTop, p.offsetWidth];
|
|
17721
|
+
if (snap || !shown || reducedMotion(win)) {
|
|
17722
|
+
x.snap(to[0]);
|
|
17723
|
+
y.snap(to[1]);
|
|
17724
|
+
w.snap(to[2]);
|
|
17725
|
+
draw();
|
|
17726
|
+
} else {
|
|
17727
|
+
x.set(to[0]);
|
|
17728
|
+
y.set(to[1]);
|
|
17729
|
+
w.set(to[2]);
|
|
17730
|
+
loop.wake();
|
|
17731
|
+
}
|
|
17732
|
+
mark.style.height = `${p.offsetHeight}px`;
|
|
17733
|
+
mark.dataset.on = "";
|
|
17734
|
+
shown = true;
|
|
17735
|
+
};
|
|
17736
|
+
const sync = () => {
|
|
17737
|
+
const next = chapterAt(chapters, io.now());
|
|
17738
|
+
if (next === at)
|
|
17739
|
+
return;
|
|
17740
|
+
at = next;
|
|
17741
|
+
place(false);
|
|
17742
|
+
};
|
|
17743
|
+
sync();
|
|
17744
|
+
const ro = "ResizeObserver" in win ? new win.ResizeObserver(() => place(true)) : null;
|
|
17745
|
+
ro?.observe(bar);
|
|
17746
|
+
return {
|
|
17747
|
+
sync,
|
|
17748
|
+
get current() {
|
|
17749
|
+
return chapters[at] ?? null;
|
|
17750
|
+
},
|
|
17751
|
+
dispose() {
|
|
17752
|
+
loop.stop();
|
|
17753
|
+
ro?.disconnect();
|
|
17754
|
+
bar.remove();
|
|
17755
|
+
}
|
|
17756
|
+
};
|
|
17757
|
+
}
|
|
17758
|
+
|
|
17055
17759
|
// src/ui/walkthrough-media.ts
|
|
17056
17760
|
function injectWalkthroughStyles(doc) {
|
|
17057
17761
|
if (doc.querySelector("style[data-knobs-ui-walkthrough]"))
|
|
@@ -17184,8 +17888,25 @@ async function mountCompare(host, m, look, alive, onEvent) {
|
|
|
17184
17888
|
onEvent?.({ what: "loop", detail: lastLoop = loopKey });
|
|
17185
17889
|
}
|
|
17186
17890
|
});
|
|
17891
|
+
const chapters = m.chapters?.length ? m.chapters : null;
|
|
17892
|
+
if (chapters)
|
|
17893
|
+
c.timeline?.update({
|
|
17894
|
+
markers: chapters.map((ch) => ({ id: ch.id, time: ch.start, label: ch.label }))
|
|
17895
|
+
});
|
|
17896
|
+
const pills = chapters ? chapterPills(host, chapters, {
|
|
17897
|
+
now: () => c.time,
|
|
17898
|
+
seek: (t) => {
|
|
17899
|
+
c.seek(t);
|
|
17900
|
+
c.play();
|
|
17901
|
+
},
|
|
17902
|
+
onEvent
|
|
17903
|
+
}) : null;
|
|
17187
17904
|
const unlisten = c.timeline?.listen({
|
|
17188
|
-
onSeek: (time, source) =>
|
|
17905
|
+
onSeek: (time, source) => {
|
|
17906
|
+
pills?.sync();
|
|
17907
|
+
if (source !== "play")
|
|
17908
|
+
onEvent?.({ what: "seek", time: round2(time) });
|
|
17909
|
+
},
|
|
17189
17910
|
onPlay: (on) => onEvent?.({ what: on ? "play" : "pause", time: round2(c.time) })
|
|
17190
17911
|
});
|
|
17191
17912
|
requestAnimationFrame(() => requestAnimationFrame(() => fit.dataset.settled = ""));
|
|
@@ -17207,12 +17928,14 @@ async function mountCompare(host, m, look, alive, onEvent) {
|
|
|
17207
17928
|
duration: round2(c.duration),
|
|
17208
17929
|
playing: c.playing,
|
|
17209
17930
|
mode: c.mode,
|
|
17931
|
+
...pills?.current ? { chapter: pills.current.label } : {},
|
|
17210
17932
|
...loop ? { loop: { start: round2(loop.start), end: round2(loop.end) } } : {},
|
|
17211
17933
|
...zoom ? { zoom: { u: round2(zoom.u), v: round2(zoom.v), w: round2(zoom.w), h: round2(zoom.h) } } : {}
|
|
17212
17934
|
};
|
|
17213
17935
|
},
|
|
17214
17936
|
dispose: () => {
|
|
17215
17937
|
unlisten?.();
|
|
17938
|
+
pills?.dispose();
|
|
17216
17939
|
c.dispose();
|
|
17217
17940
|
fit.remove();
|
|
17218
17941
|
}
|
|
@@ -17236,6 +17959,15 @@ function mountVideo(host, m, onEvent) {
|
|
|
17236
17959
|
v.poster = m.poster;
|
|
17237
17960
|
if (!aspect)
|
|
17238
17961
|
v.addEventListener("loadedmetadata", () => v.videoWidth && frame.style.setProperty("--kw-aspect", String(v.videoWidth / v.videoHeight)), { once: true });
|
|
17962
|
+
if (m.captions) {
|
|
17963
|
+
const track = doc.createElement("track");
|
|
17964
|
+
track.kind = "captions";
|
|
17965
|
+
track.label = "Captions";
|
|
17966
|
+
track.srclang = doc.documentElement.lang || "en";
|
|
17967
|
+
track.default = true;
|
|
17968
|
+
track.src = m.captions;
|
|
17969
|
+
v.append(track);
|
|
17970
|
+
}
|
|
17239
17971
|
v.src = m.src;
|
|
17240
17972
|
v.addEventListener("play", () => onEvent?.({ what: "play", time: round2(v.currentTime) }));
|
|
17241
17973
|
v.addEventListener("pause", () => onEvent?.({ what: "pause", time: round2(v.currentTime) }));
|
|
@@ -17245,6 +17977,18 @@ function mountVideo(host, m, onEvent) {
|
|
|
17245
17977
|
});
|
|
17246
17978
|
frame.append(v);
|
|
17247
17979
|
host.append(frame);
|
|
17980
|
+
const pills = m.chapters?.length ? chapterPills(host, m.chapters, {
|
|
17981
|
+
now: () => v.currentTime,
|
|
17982
|
+
seek: (t) => {
|
|
17983
|
+
v.currentTime = t;
|
|
17984
|
+
v.play().catch(() => {});
|
|
17985
|
+
},
|
|
17986
|
+
onEvent
|
|
17987
|
+
}) : null;
|
|
17988
|
+
const sync = () => pills?.sync();
|
|
17989
|
+
if (pills)
|
|
17990
|
+
for (const type of ["timeupdate", "seeking", "seeked"])
|
|
17991
|
+
v.addEventListener(type, sync);
|
|
17248
17992
|
return {
|
|
17249
17993
|
pause: () => v.pause(),
|
|
17250
17994
|
seekBy: (d) => {
|
|
@@ -17254,9 +17998,11 @@ function mountVideo(host, m, onEvent) {
|
|
|
17254
17998
|
kind: "video",
|
|
17255
17999
|
time: round2(v.currentTime),
|
|
17256
18000
|
...Number.isFinite(v.duration) ? { duration: round2(v.duration) } : {},
|
|
17257
|
-
playing: !v.paused
|
|
18001
|
+
playing: !v.paused,
|
|
18002
|
+
...pills?.current ? { chapter: pills.current.label } : {}
|
|
17258
18003
|
}),
|
|
17259
18004
|
dispose: () => {
|
|
18005
|
+
pills?.dispose();
|
|
17260
18006
|
v.pause();
|
|
17261
18007
|
v.removeAttribute("src");
|
|
17262
18008
|
v.load();
|
|
@@ -17480,6 +18226,12 @@ function mediaSlot(container, options) {
|
|
|
17480
18226
|
case "callout":
|
|
17481
18227
|
case "text":
|
|
17482
18228
|
return done(mountProse(host, m));
|
|
18229
|
+
case "history":
|
|
18230
|
+
return done(mountHistory(host, m, options.steps));
|
|
18231
|
+
case "stack":
|
|
18232
|
+
return done(mountStack(host, m, options.steps));
|
|
18233
|
+
case "table":
|
|
18234
|
+
return done(mountTable(host, m, options.steps));
|
|
17483
18235
|
case "mount": {
|
|
17484
18236
|
const cleanup = m.mount(host);
|
|
17485
18237
|
return done({ dispose: () => cleanup ? cleanup() : host.textContent = "" });
|
|
@@ -17534,14 +18286,14 @@ function mediaSlot(container, options) {
|
|
|
17534
18286
|
var CHECK3 = svg('<path d="m3.5 8.4 3 3 6-6.6"/>');
|
|
17535
18287
|
|
|
17536
18288
|
// src/ui/walkthrough.ts
|
|
17537
|
-
var
|
|
18289
|
+
var el2 = (doc, tag, cls) => {
|
|
17538
18290
|
const n = doc.createElement(tag);
|
|
17539
18291
|
if (cls)
|
|
17540
18292
|
n.className = cls;
|
|
17541
18293
|
return n;
|
|
17542
18294
|
};
|
|
17543
|
-
var
|
|
17544
|
-
const n =
|
|
18295
|
+
var prose2 = (doc, tag, cls, text) => {
|
|
18296
|
+
const n = el2(doc, tag, cls);
|
|
17545
18297
|
n.innerHTML = inlineMarkdown(text);
|
|
17546
18298
|
return n;
|
|
17547
18299
|
};
|
|
@@ -17549,7 +18301,7 @@ var lookOf2 = (o) => ({
|
|
|
17549
18301
|
...o.preset ? { preset: o.preset } : {},
|
|
17550
18302
|
...o.theme ? { theme: o.theme } : {}
|
|
17551
18303
|
});
|
|
17552
|
-
var
|
|
18304
|
+
var grid2 = (v) => Math.round(v * 64) / 64;
|
|
17553
18305
|
var ICON = {
|
|
17554
18306
|
full: svg('<path d="M3 6.5V3h3.5M13 6.5V3H9.5M3 9.5V13h3.5M13 9.5V13H9.5"/>'),
|
|
17555
18307
|
exit: svg('<path d="M6.5 3v3.5H3M9.5 3v3.5H13M6.5 13V9.5H3M9.5 13V9.5H13"/>'),
|
|
@@ -17575,7 +18327,7 @@ function tasteTest(container, options) {
|
|
|
17575
18327
|
suggested: o.suggested === true
|
|
17576
18328
|
});
|
|
17577
18329
|
let picked = options.picked ?? null;
|
|
17578
|
-
const root =
|
|
18330
|
+
const root = el2(doc, "div", "knobs-wt-options");
|
|
17579
18331
|
root.setAttribute("role", "radiogroup");
|
|
17580
18332
|
root.setAttribute("aria-label", "Options");
|
|
17581
18333
|
root.style.setProperty("--kw-n", String(Math.min(list.length, 3)));
|
|
@@ -17583,28 +18335,28 @@ function tasteTest(container, options) {
|
|
|
17583
18335
|
applyLook2(root, options);
|
|
17584
18336
|
const slots = [];
|
|
17585
18337
|
const tiles = list.map((o, i) => {
|
|
17586
|
-
const tile =
|
|
17587
|
-
const pick =
|
|
18338
|
+
const tile = el2(doc, "div", "knobs-wt-option");
|
|
18339
|
+
const pick = el2(doc, "button", "knobs-wt-pick");
|
|
17588
18340
|
pick.type = "button";
|
|
17589
18341
|
pick.setAttribute("role", "radio");
|
|
17590
18342
|
if (i < 9)
|
|
17591
18343
|
pick.setAttribute("aria-keyshortcuts", String(i + 1));
|
|
17592
|
-
const letter =
|
|
18344
|
+
const letter = el2(doc, "span", "knobs-wt-letter");
|
|
17593
18345
|
letter.textContent = o.letter;
|
|
17594
|
-
const name =
|
|
18346
|
+
const name = el2(doc, "span", "knobs-wt-olabel");
|
|
17595
18347
|
name.textContent = o.label;
|
|
17596
18348
|
pick.append(letter, name);
|
|
17597
18349
|
if (o.suggested) {
|
|
17598
|
-
const s =
|
|
18350
|
+
const s = el2(doc, "span", "knobs-wt-suggested");
|
|
17599
18351
|
s.textContent = "Suggested";
|
|
17600
18352
|
pick.append(s);
|
|
17601
18353
|
}
|
|
17602
18354
|
if (i < 9) {
|
|
17603
|
-
const key =
|
|
18355
|
+
const key = el2(doc, "span", "knobs-wt-key");
|
|
17604
18356
|
key.textContent = String(i + 1);
|
|
17605
18357
|
pick.append(key);
|
|
17606
18358
|
}
|
|
17607
|
-
const check =
|
|
18359
|
+
const check = el2(doc, "span", "knobs-wt-check");
|
|
17608
18360
|
check.innerHTML = CHECK3;
|
|
17609
18361
|
pick.append(check);
|
|
17610
18362
|
pick.addEventListener("click", () => {
|
|
@@ -17617,10 +18369,11 @@ function tasteTest(container, options) {
|
|
|
17617
18369
|
slots.push(mediaSlot(tile, {
|
|
17618
18370
|
...look,
|
|
17619
18371
|
media: o.media,
|
|
17620
|
-
...options.lazy === false ? { lazy: false } : {}
|
|
18372
|
+
...options.lazy === false ? { lazy: false } : {},
|
|
18373
|
+
...options.steps ? { steps: options.steps } : {}
|
|
17621
18374
|
}));
|
|
17622
18375
|
if (o.caption)
|
|
17623
|
-
tile.append(
|
|
18376
|
+
tile.append(prose2(doc, "p", "knobs-wt-ocap", o.caption));
|
|
17624
18377
|
root.append(tile);
|
|
17625
18378
|
return { tile, pick };
|
|
17626
18379
|
});
|
|
@@ -17668,7 +18421,7 @@ function walkthrough(container, options) {
|
|
|
17668
18421
|
injectWalkthroughStyles(doc);
|
|
17669
18422
|
const look = lookOf2(options);
|
|
17670
18423
|
const storage = options.storage === undefined ? browserStorage() : options.storage;
|
|
17671
|
-
const root =
|
|
18424
|
+
const root = el2(doc, "div", "knobs-walkthrough");
|
|
17672
18425
|
applyLook2(root, options);
|
|
17673
18426
|
container.append(root);
|
|
17674
18427
|
let page = normalizeWalkthrough(options.doc);
|
|
@@ -17728,8 +18481,8 @@ function walkthrough(container, options) {
|
|
|
17728
18481
|
if (mark) {
|
|
17729
18482
|
pillY.step(dt);
|
|
17730
18483
|
pillH.step(dt);
|
|
17731
|
-
mark.style.transform = `translateY(${
|
|
17732
|
-
mark.style.height = `${
|
|
18484
|
+
mark.style.transform = `translateY(${grid2(pillY.x)}px)`;
|
|
18485
|
+
mark.style.height = `${grid2(pillY.x + pillH.x) - grid2(pillY.x)}px`;
|
|
17733
18486
|
more ||= !pillY.resting || !pillH.resting;
|
|
17734
18487
|
}
|
|
17735
18488
|
if (scroll.to && scroll.el) {
|
|
@@ -17864,6 +18617,10 @@ function walkthrough(container, options) {
|
|
|
17864
18617
|
scrollToCard(v);
|
|
17865
18618
|
v.card.focus({ preventScroll: true });
|
|
17866
18619
|
};
|
|
18620
|
+
const stepLinks = {
|
|
18621
|
+
find: (ref) => findStep(page.steps, ref) ?? null,
|
|
18622
|
+
go: (key) => go(key)
|
|
18623
|
+
};
|
|
17867
18624
|
const slotsOf = (v) => v ? [...v.slots, ...v.taste?.slots ?? []] : [];
|
|
17868
18625
|
const mediaContext = (v) => {
|
|
17869
18626
|
const slots = slotsOf(v);
|
|
@@ -17878,17 +18635,17 @@ function walkthrough(container, options) {
|
|
|
17878
18635
|
return true;
|
|
17879
18636
|
return false;
|
|
17880
18637
|
};
|
|
17881
|
-
const scrim =
|
|
18638
|
+
const scrim = el2(doc, "div", "knobs-wt-scrim");
|
|
17882
18639
|
scrim.addEventListener("click", () => setFull(false));
|
|
17883
18640
|
const fullRect = () => ({ x: 12, y: 12, w: win.innerWidth - 24, h: win.innerHeight - 24 });
|
|
17884
18641
|
const placeFull = (f) => {
|
|
17885
18642
|
const a = f.hold.getBoundingClientRect();
|
|
17886
18643
|
const b = fullRect();
|
|
17887
18644
|
const k = reduced() ? Math.round(f.p.target) : f.p.x;
|
|
17888
|
-
const left =
|
|
17889
|
-
const top =
|
|
17890
|
-
const right =
|
|
17891
|
-
const bottom =
|
|
18645
|
+
const left = grid2(a.left + (b.x - a.left) * k);
|
|
18646
|
+
const top = grid2(a.top + (b.y - a.top) * k);
|
|
18647
|
+
const right = grid2(a.right + (b.x + b.w - a.right) * k);
|
|
18648
|
+
const bottom = grid2(a.bottom + (b.y + b.h - a.bottom) * k);
|
|
17892
18649
|
const s = f.v.card.style;
|
|
17893
18650
|
s.left = `${left}px`;
|
|
17894
18651
|
s.top = `${top}px`;
|
|
@@ -17923,7 +18680,7 @@ function walkthrough(container, options) {
|
|
|
17923
18680
|
}
|
|
17924
18681
|
if (!full) {
|
|
17925
18682
|
const r = v.card.getBoundingClientRect();
|
|
17926
|
-
const hold =
|
|
18683
|
+
const hold = el2(doc, "div", "knobs-wt-hold-card");
|
|
17927
18684
|
hold.style.height = `${r.height}px`;
|
|
17928
18685
|
v.card.before(hold);
|
|
17929
18686
|
v.card.dataset.full = "";
|
|
@@ -18071,7 +18828,7 @@ function walkthrough(container, options) {
|
|
|
18071
18828
|
toast("Couldn't reach the microphone", { tone: "warn", look, doc });
|
|
18072
18829
|
}
|
|
18073
18830
|
};
|
|
18074
|
-
const backPill =
|
|
18831
|
+
const backPill = el2(doc, "button", "knobs-wt-back");
|
|
18075
18832
|
backPill.type = "button";
|
|
18076
18833
|
let backTo = null;
|
|
18077
18834
|
let backTimer = 0;
|
|
@@ -18096,16 +18853,16 @@ function walkthrough(container, options) {
|
|
|
18096
18853
|
backTimer = win.setTimeout(hideBack, BACK_MS);
|
|
18097
18854
|
};
|
|
18098
18855
|
const bar = (() => {
|
|
18099
|
-
const dock =
|
|
18100
|
-
const box =
|
|
18101
|
-
const on =
|
|
18102
|
-
const row =
|
|
18103
|
-
const input =
|
|
18856
|
+
const dock = el2(doc, "div", "knobs-wt-dock");
|
|
18857
|
+
const box = el2(doc, "div", "knobs-wt-notebar");
|
|
18858
|
+
const on = el2(doc, "div", "knobs-wt-on");
|
|
18859
|
+
const row = el2(doc, "div", "knobs-wt-row");
|
|
18860
|
+
const input = el2(doc, "textarea", "knobs-wt-input");
|
|
18104
18861
|
input.rows = 1;
|
|
18105
18862
|
input.setAttribute("aria-label", "Note");
|
|
18106
|
-
const attach =
|
|
18863
|
+
const attach = el2(doc, "div", "knobs-wt-attach");
|
|
18107
18864
|
const btn = (icon, label, run) => {
|
|
18108
|
-
const b =
|
|
18865
|
+
const b = el2(doc, "button", "knobs-wt-tool");
|
|
18109
18866
|
b.type = "button";
|
|
18110
18867
|
b.innerHTML = icon;
|
|
18111
18868
|
b.setAttribute("aria-label", label);
|
|
@@ -18116,7 +18873,7 @@ function walkthrough(container, options) {
|
|
|
18116
18873
|
const fullBtn = btn(ICON.full, "Full window · f", () => setFull(!full));
|
|
18117
18874
|
const penBtn = btn(ICON.pen, "Draw on the media", () => setInk(!ink.on));
|
|
18118
18875
|
const micBtn = btn(ICON.mic, "Record a voice note", () => void toggleVoice());
|
|
18119
|
-
const micTime =
|
|
18876
|
+
const micTime = el2(doc, "span", "knobs-wt-rec");
|
|
18120
18877
|
micBtn.append(micTime);
|
|
18121
18878
|
const sendBtn = btn(ICON.send, "Send · Enter", () => send());
|
|
18122
18879
|
sendBtn.dataset.send = "";
|
|
@@ -18142,9 +18899,9 @@ function walkthrough(container, options) {
|
|
|
18142
18899
|
}
|
|
18143
18900
|
});
|
|
18144
18901
|
const chip = (text, clear) => {
|
|
18145
|
-
const c =
|
|
18902
|
+
const c = el2(doc, "span", "knobs-wt-chip-a");
|
|
18146
18903
|
c.append(text);
|
|
18147
|
-
const x =
|
|
18904
|
+
const x = el2(doc, "button", "knobs-wt-x");
|
|
18148
18905
|
x.type = "button";
|
|
18149
18906
|
x.innerHTML = ICON.close;
|
|
18150
18907
|
x.setAttribute("aria-label", `Remove ${text}`);
|
|
@@ -18257,9 +19014,9 @@ function walkthrough(container, options) {
|
|
|
18257
19014
|
}
|
|
18258
19015
|
};
|
|
18259
19016
|
const renderNote = (v, n, entering = false) => {
|
|
18260
|
-
const row =
|
|
19017
|
+
const row = el2(doc, "div", "knobs-wt-n");
|
|
18261
19018
|
row.dataset.id = n.id;
|
|
18262
|
-
const meta =
|
|
19019
|
+
const meta = el2(doc, "span", "knobs-wt-n-meta");
|
|
18263
19020
|
const m = n.context.media;
|
|
18264
19021
|
meta.textContent = m?.time !== undefined ? formatTime(m.time) : m?.file ? m.file.split("/").pop() : "·";
|
|
18265
19022
|
if (m?.time !== undefined) {
|
|
@@ -18275,11 +19032,11 @@ function walkthrough(container, options) {
|
|
|
18275
19032
|
});
|
|
18276
19033
|
}
|
|
18277
19034
|
row.append(meta);
|
|
18278
|
-
const body =
|
|
19035
|
+
const body = el2(doc, "div", "knobs-wt-n-body");
|
|
18279
19036
|
if (n.text)
|
|
18280
|
-
body.append(
|
|
19037
|
+
body.append(prose2(doc, "p", "knobs-wt-n-text", n.text));
|
|
18281
19038
|
if (n.voice) {
|
|
18282
|
-
const a =
|
|
19039
|
+
const a = el2(doc, "audio", "knobs-wt-n-voice");
|
|
18283
19040
|
a.controls = true;
|
|
18284
19041
|
a.preload = "none";
|
|
18285
19042
|
a.src = n.voice.url;
|
|
@@ -18299,7 +19056,7 @@ function walkthrough(container, options) {
|
|
|
18299
19056
|
body.append(thumb);
|
|
18300
19057
|
}
|
|
18301
19058
|
row.append(body);
|
|
18302
|
-
const x =
|
|
19059
|
+
const x = el2(doc, "button", "knobs-wt-x");
|
|
18303
19060
|
x.type = "button";
|
|
18304
19061
|
x.innerHTML = ICON.close;
|
|
18305
19062
|
x.setAttribute("aria-label", "Delete this note");
|
|
@@ -18353,22 +19110,22 @@ function walkthrough(container, options) {
|
|
|
18353
19110
|
pillPlaced = false;
|
|
18354
19111
|
root.textContent = "";
|
|
18355
19112
|
root.removeAttribute("data-settled");
|
|
18356
|
-
const layout =
|
|
18357
|
-
const main =
|
|
18358
|
-
const head =
|
|
18359
|
-
const h1 =
|
|
19113
|
+
const layout = el2(doc, "div", "knobs-wt-layout");
|
|
19114
|
+
const main = el2(doc, "div", "knobs-wt-main");
|
|
19115
|
+
const head = el2(doc, "header", "knobs-wt-head");
|
|
19116
|
+
const h1 = el2(doc, "h1", "knobs-wt-title");
|
|
18360
19117
|
h1.textContent = page.title;
|
|
18361
19118
|
head.append(h1);
|
|
18362
19119
|
if (page.summary)
|
|
18363
|
-
head.append(
|
|
19120
|
+
head.append(prose2(doc, "p", "knobs-wt-summary", page.summary));
|
|
18364
19121
|
if (page.meta.length) {
|
|
18365
|
-
const meta =
|
|
19122
|
+
const meta = el2(doc, "div", "knobs-wt-meta");
|
|
18366
19123
|
for (const m of page.meta) {
|
|
18367
|
-
const s =
|
|
19124
|
+
const s = el2(doc, "span");
|
|
18368
19125
|
s.append(m.label);
|
|
18369
|
-
const b =
|
|
19126
|
+
const b = el2(doc, "b");
|
|
18370
19127
|
if (m.href) {
|
|
18371
|
-
const a =
|
|
19128
|
+
const a = el2(doc, "a");
|
|
18372
19129
|
a.href = m.href;
|
|
18373
19130
|
a.target = "_blank";
|
|
18374
19131
|
a.rel = "noreferrer";
|
|
@@ -18383,27 +19140,27 @@ function walkthrough(container, options) {
|
|
|
18383
19140
|
}
|
|
18384
19141
|
main.append(head);
|
|
18385
19142
|
if (page.feed.length) {
|
|
18386
|
-
const feed =
|
|
19143
|
+
const feed = el2(doc, "section", "knobs-wt-feed");
|
|
18387
19144
|
feed.setAttribute("aria-label", "Latest");
|
|
18388
|
-
const list =
|
|
19145
|
+
const list = el2(doc, "ol", "knobs-wt-feed-list knobs-scroll-fade");
|
|
18389
19146
|
const now = Date.now();
|
|
18390
19147
|
for (const f of page.feed) {
|
|
18391
|
-
const li =
|
|
19148
|
+
const li = el2(doc, "li", "knobs-wt-fi");
|
|
18392
19149
|
li.dataset.kind = f.kind;
|
|
18393
|
-
const when =
|
|
19150
|
+
const when = el2(doc, "span", "knobs-wt-fi-when");
|
|
18394
19151
|
when.textContent = f.at === null ? "" : ago(f.at, now);
|
|
18395
19152
|
if (f.at !== null)
|
|
18396
19153
|
when.title = new Date(f.at).toLocaleString();
|
|
18397
|
-
const kind =
|
|
19154
|
+
const kind = el2(doc, "span", "knobs-wt-fi-kind");
|
|
18398
19155
|
kind.textContent = f.kind === "qa" ? "Answer" : "Update";
|
|
18399
|
-
const body =
|
|
19156
|
+
const body = el2(doc, "div", "knobs-wt-fi-body");
|
|
18400
19157
|
if (f.q)
|
|
18401
|
-
body.append(
|
|
18402
|
-
body.append(
|
|
19158
|
+
body.append(prose2(doc, "p", "knobs-wt-fi-q", f.q));
|
|
19159
|
+
body.append(prose2(doc, "p", "knobs-wt-fi-text", f.text));
|
|
18403
19160
|
li.append(when, kind, body);
|
|
18404
19161
|
if (f.step) {
|
|
18405
19162
|
const target = f.step;
|
|
18406
|
-
const link =
|
|
19163
|
+
const link = el2(doc, "button", "knobs-wt-fi-step");
|
|
18407
19164
|
link.type = "button";
|
|
18408
19165
|
link.textContent = page.steps.find((s) => s.key === target)?.number ?? "";
|
|
18409
19166
|
link.title = "Go to the step";
|
|
@@ -18418,33 +19175,33 @@ function walkthrough(container, options) {
|
|
|
18418
19175
|
let rail = null;
|
|
18419
19176
|
count = fill = tocEl = mark = null;
|
|
18420
19177
|
if (options.rail !== false) {
|
|
18421
|
-
rail =
|
|
19178
|
+
rail = el2(doc, "aside", "knobs-wt-rail");
|
|
18422
19179
|
rail.setAttribute("aria-label", "Progress");
|
|
18423
|
-
const progress =
|
|
18424
|
-
count =
|
|
18425
|
-
const meter =
|
|
18426
|
-
fill =
|
|
19180
|
+
const progress = el2(doc, "div", "knobs-wt-progress");
|
|
19181
|
+
count = el2(doc, "div", "knobs-wt-count");
|
|
19182
|
+
const meter = el2(doc, "div", "knobs-wt-bar");
|
|
19183
|
+
fill = el2(doc, "div", "knobs-wt-fill");
|
|
18427
19184
|
meter.append(fill);
|
|
18428
19185
|
progress.append(count, meter);
|
|
18429
|
-
tocEl =
|
|
19186
|
+
tocEl = el2(doc, "nav", "knobs-wt-toc");
|
|
18430
19187
|
tocEl.setAttribute("aria-label", "Contents");
|
|
18431
|
-
mark =
|
|
19188
|
+
mark = el2(doc, "div", "knobs-wt-toc-mark");
|
|
18432
19189
|
tocEl.append(mark);
|
|
18433
19190
|
rail.append(progress, tocEl, actions(true));
|
|
18434
19191
|
if (options.keys !== false) {
|
|
18435
|
-
const keys =
|
|
19192
|
+
const keys = el2(doc, "div", "knobs-wt-keys");
|
|
18436
19193
|
keys.innerHTML = "<kbd>j</kbd> <kbd>k</kbd> steps · <kbd>←</kbd> <kbd>→</kbd> seek · <kbd>f</kbd> full · <kbd>n</kbd> note" + (page.steps.some((s) => s.ask === "pick") ? " · <kbd>1</kbd>–<kbd>9</kbd> pick" : "");
|
|
18437
19194
|
rail.append(keys);
|
|
18438
19195
|
}
|
|
18439
19196
|
}
|
|
18440
19197
|
for (const section of page.sections) {
|
|
18441
|
-
const sec =
|
|
19198
|
+
const sec = el2(doc, "section", "knobs-wt-section");
|
|
18442
19199
|
sec.id = `wt-${section.id}`;
|
|
18443
|
-
const sh =
|
|
19200
|
+
const sh = el2(doc, "header", "knobs-wt-shead");
|
|
18444
19201
|
if (section.link || section.status) {
|
|
18445
|
-
const kicker =
|
|
19202
|
+
const kicker = el2(doc, "div", "knobs-wt-kicker");
|
|
18446
19203
|
if (section.link) {
|
|
18447
|
-
const a =
|
|
19204
|
+
const a = el2(doc, "a");
|
|
18448
19205
|
a.href = section.link.href;
|
|
18449
19206
|
a.target = "_blank";
|
|
18450
19207
|
a.rel = "noreferrer";
|
|
@@ -18453,21 +19210,21 @@ function walkthrough(container, options) {
|
|
|
18453
19210
|
}
|
|
18454
19211
|
if (section.status) {
|
|
18455
19212
|
const s = statusLook(section.status);
|
|
18456
|
-
const chip =
|
|
19213
|
+
const chip = el2(doc, "span", "knobs-wt-chip");
|
|
18457
19214
|
chip.dataset.tone = s.tone;
|
|
18458
19215
|
chip.textContent = s.label;
|
|
18459
19216
|
kicker.append(chip);
|
|
18460
19217
|
}
|
|
18461
19218
|
sh.append(kicker);
|
|
18462
19219
|
}
|
|
18463
|
-
const h2 =
|
|
19220
|
+
const h2 = el2(doc, "h2", "knobs-wt-stitle");
|
|
18464
19221
|
h2.textContent = section.title;
|
|
18465
19222
|
sh.append(h2);
|
|
18466
19223
|
if (section.summary)
|
|
18467
|
-
sh.append(
|
|
19224
|
+
sh.append(prose2(doc, "p", "knobs-wt-ssum", section.summary));
|
|
18468
19225
|
sec.append(sh);
|
|
18469
19226
|
if (tocEl) {
|
|
18470
|
-
const t =
|
|
19227
|
+
const t = el2(doc, "div", "knobs-wt-toc-section");
|
|
18471
19228
|
t.textContent = section.link ? `${section.link.label} ${section.title}` : section.title;
|
|
18472
19229
|
t.title = section.title;
|
|
18473
19230
|
tocEl.append(t);
|
|
@@ -18500,9 +19257,9 @@ function walkthrough(container, options) {
|
|
|
18500
19257
|
}));
|
|
18501
19258
|
};
|
|
18502
19259
|
const actions = (rail) => {
|
|
18503
|
-
const row =
|
|
19260
|
+
const row = el2(doc, "div", "knobs-wt-actions");
|
|
18504
19261
|
const btn = (text, run, primary = false) => {
|
|
18505
|
-
const b =
|
|
19262
|
+
const b = el2(doc, "button", "knobs-wt-btn");
|
|
18506
19263
|
b.type = "button";
|
|
18507
19264
|
b.textContent = text;
|
|
18508
19265
|
if (primary)
|
|
@@ -18540,43 +19297,44 @@ function walkthrough(container, options) {
|
|
|
18540
19297
|
}
|
|
18541
19298
|
};
|
|
18542
19299
|
const stepView = (step) => {
|
|
18543
|
-
const card =
|
|
19300
|
+
const card = el2(doc, "article", "knobs-wt-step knobs-surface");
|
|
18544
19301
|
card.id = `wt-${step.key.replace("/", "--")}`;
|
|
18545
19302
|
card.tabIndex = -1;
|
|
18546
19303
|
card.dataset.key = step.key;
|
|
18547
19304
|
card.setAttribute("aria-label", `${step.number} ${step.title}`);
|
|
18548
|
-
const head =
|
|
18549
|
-
const num =
|
|
19305
|
+
const head = el2(doc, "header", "knobs-wt-step-head");
|
|
19306
|
+
const num = el2(doc, "span", "knobs-wt-num");
|
|
18550
19307
|
num.textContent = step.number;
|
|
18551
|
-
const h3 =
|
|
19308
|
+
const h3 = el2(doc, "h3", "knobs-wt-stepTitle");
|
|
18552
19309
|
h3.textContent = step.title;
|
|
18553
19310
|
head.append(num, h3);
|
|
18554
19311
|
card.append(head);
|
|
18555
19312
|
if (step.caption)
|
|
18556
|
-
card.append(
|
|
19313
|
+
card.append(prose2(doc, "p", "knobs-wt-caption", step.caption));
|
|
18557
19314
|
const slots = [];
|
|
18558
19315
|
const onEvent = (e) => record({ ...e, step: step.key });
|
|
18559
19316
|
let media = null;
|
|
18560
19317
|
if (step.media.length) {
|
|
18561
|
-
media =
|
|
19318
|
+
media = el2(doc, "div", "knobs-wt-media");
|
|
18562
19319
|
media.style.setProperty("--kw-n", String(Math.min(step.media.length, 3)));
|
|
18563
19320
|
for (const m of step.media)
|
|
18564
|
-
slots.push(mediaSlot(media, { ...look, media: m, onEvent }));
|
|
19321
|
+
slots.push(mediaSlot(media, { ...look, media: m, onEvent, steps: stepLinks }));
|
|
18565
19322
|
card.append(media);
|
|
18566
19323
|
}
|
|
18567
19324
|
let taste = null;
|
|
18568
19325
|
if (step.question)
|
|
18569
|
-
card.append(
|
|
19326
|
+
card.append(prose2(doc, "p", "knobs-wt-question", step.question));
|
|
18570
19327
|
if (step.ask === "pick") {
|
|
18571
19328
|
taste = tasteTest(card, {
|
|
18572
19329
|
...look,
|
|
18573
19330
|
options: step.options,
|
|
18574
19331
|
picked: state.steps[step.key]?.pick ?? null,
|
|
18575
|
-
onPick: (id) => pick(step.key, id)
|
|
19332
|
+
onPick: (id) => pick(step.key, id),
|
|
19333
|
+
steps: stepLinks
|
|
18576
19334
|
});
|
|
18577
19335
|
media ??= taste.element;
|
|
18578
19336
|
}
|
|
18579
|
-
const notes =
|
|
19337
|
+
const notes = el2(doc, "div", "knobs-wt-notes");
|
|
18580
19338
|
card.append(notes);
|
|
18581
19339
|
card.addEventListener("focusin", () => {
|
|
18582
19340
|
if (scroll.to)
|
|
@@ -18587,10 +19345,10 @@ function walkthrough(container, options) {
|
|
|
18587
19345
|
let toc = null;
|
|
18588
19346
|
let glyph = null;
|
|
18589
19347
|
if (tocEl) {
|
|
18590
|
-
toc =
|
|
19348
|
+
toc = el2(doc, "button", "knobs-wt-toc-step");
|
|
18591
19349
|
toc.type = "button";
|
|
18592
|
-
glyph =
|
|
18593
|
-
const label =
|
|
19350
|
+
glyph = el2(doc, "span", "knobs-wt-toc-glyph");
|
|
19351
|
+
const label = el2(doc, "span", "knobs-wt-toc-label");
|
|
18594
19352
|
label.textContent = step.title;
|
|
18595
19353
|
toc.title = `${step.number} ${step.title}`;
|
|
18596
19354
|
toc.append(glyph, label);
|