@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.js
CHANGED
|
@@ -18970,7 +18970,7 @@ var walkthroughCss = `
|
|
|
18970
18970
|
.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}
|
|
18971
18971
|
.knobs-walkthrough a:hover{text-decoration-color:currentColor}
|
|
18972
18972
|
.knobs-walkthrough code,.knobs-wt-slot code{font:calc(1em - 1px) var(--_k-mono);padding:1px 5px;border-radius:5px;background:var(--_k-fill)}
|
|
18973
|
-
: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;
|
|
18973
|
+
: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;
|
|
18974
18974
|
background:transparent;border:0;border-radius:0;margin:0;padding:0;min-width:0;box-shadow:none;outline:none}
|
|
18975
18975
|
|
|
18976
18976
|
/* ——— layout: the rail beside the column; one column where it's narrow ——— */
|
|
@@ -19029,9 +19029,9 @@ var walkthroughCss = `
|
|
|
19029
19029
|
.knobs-wt-fi-body{max-width:var(--kw-measure);color:var(--_k-fg)}
|
|
19030
19030
|
.knobs-wt-fi-q{color:var(--_k-fg-2)}
|
|
19031
19031
|
.knobs-wt-fi-q::before{content:"You asked: ";color:var(--_k-fg-3)}
|
|
19032
|
-
:where(.knobs-ui) .knobs-wt-fi-step{all:revert;box-sizing:border-box;font:var(--_k-weight) calc(var(--
|
|
19032
|
+
: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;
|
|
19033
19033
|
padding:3px 6px;margin:0;border-radius:6px;cursor:pointer;outline:none;transition:background .15s,color .15s}
|
|
19034
|
-
.knobs-ui .knobs-wt-fi-step:is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
19034
|
+
.knobs-ui :is(.knobs-wt-fi-step,.knobs-wt-steplink):is(:hover,:focus-visible){background:var(--_ku-wash-hi);color:var(--_k-fg)}
|
|
19035
19035
|
|
|
19036
19036
|
/* ——— a step's sent notes ——— */
|
|
19037
19037
|
.knobs-wt-notes{display:flex;flex-direction:column}
|
|
@@ -19167,7 +19167,8 @@ var walkthroughCss = `
|
|
|
19167
19167
|
}
|
|
19168
19168
|
|
|
19169
19169
|
/* ——— media slots ——— */
|
|
19170
|
-
.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)
|
|
19170
|
+
.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);
|
|
19171
|
+
--kw-good:var(--k-walkthrough-good,var(--_k-ok));--kw-info:var(--k-walkthrough-info,var(--_k-info))}
|
|
19171
19172
|
.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}
|
|
19172
19173
|
/* A compare is exactly as tall as its pictures at this width, so there's no letterbox: the two
|
|
19173
19174
|
sides edge to edge (side) or one (overlaid), plus its mode bar, the timeline and their two gaps
|
|
@@ -19207,9 +19208,141 @@ var walkthroughCss = `
|
|
|
19207
19208
|
.knobs-wt-text{max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
19208
19209
|
.knobs-wt-hold{border-radius:calc(var(--_k-radius-panel) - 4px);background:var(--_k-fill)}
|
|
19209
19210
|
.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)}
|
|
19211
|
+
|
|
19212
|
+
/* ——— data blocks: history, stack, table, chapters. On the step's card, so no card of their own:
|
|
19213
|
+
hairlines and fills only. Tones read the status tokens; hover fades are the panel's own. ——— */
|
|
19214
|
+
: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)}
|
|
19215
|
+
:where(.knobs-wt-slot) [data-tone="good"]{--kw-tone:var(--kw-good)}
|
|
19216
|
+
:where(.knobs-wt-slot) [data-tone="warn"]{--kw-tone:var(--_k-warn)}
|
|
19217
|
+
:where(.knobs-wt-slot) [data-tone="bad"]{--kw-tone:var(--_k-danger)}
|
|
19218
|
+
:where(.knobs-wt-slot) [data-tone="info"]{--kw-tone:var(--kw-info)}
|
|
19219
|
+
:where(.knobs-wt-slot) [data-tone="dim"]{--kw-tone:var(--_k-fg-3)}
|
|
19220
|
+
.knobs-wt-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
|
|
19221
|
+
.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);
|
|
19222
|
+
text-decoration:none;white-space:nowrap;transition:background calc(var(--_k-hover-out) * 1ms),color calc(var(--_k-hover-out) * 1ms)}
|
|
19223
|
+
.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)}
|
|
19224
|
+
|
|
19225
|
+
/* A history: dates down the left, a spine of tone dots joined by a hairline (broken around each
|
|
19226
|
+
dot), the event beside it. Inferred events take a ring for a dot and a dashed tag. */
|
|
19227
|
+
.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)}
|
|
19228
|
+
.knobs-wt-hgroup{display:flex;flex-direction:column;gap:6px;min-width:0}
|
|
19229
|
+
.knobs-wt-hhead{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px}
|
|
19230
|
+
.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)}
|
|
19231
|
+
.knobs-wt-hsum{color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 2px);font-variant-numeric:tabular-nums}
|
|
19232
|
+
.knobs-wt-hlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
|
|
19233
|
+
.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}
|
|
19234
|
+
.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)}
|
|
19235
|
+
.knobs-wt-hage{color:var(--_k-fg-3);font-size:calc(var(--kw-t) - 3px);line-height:1.35}
|
|
19236
|
+
.knobs-wt-hspine{grid-area:spine;position:relative;align-self:stretch;margin-block:-5px}
|
|
19237
|
+
.knobs-wt-hspine::before,.knobs-wt-hspine::after{content:"";position:absolute;left:6.5px;width:1px;background:var(--kw-rail)}
|
|
19238
|
+
.knobs-wt-hspine::before{top:0;height:calc(var(--kw-hy) - 6px)}
|
|
19239
|
+
.knobs-wt-hspine::after{top:calc(var(--kw-hy) + 6px);bottom:0}
|
|
19240
|
+
.knobs-wt-hev:first-child .knobs-wt-hspine::before,.knobs-wt-hev:last-child .knobs-wt-hspine::after{content:none}
|
|
19241
|
+
.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))}
|
|
19242
|
+
.knobs-wt-hev[data-type="release"] .knobs-wt-hdot{border-radius:1.5px;rotate:45deg;scale:.9}
|
|
19243
|
+
.knobs-wt-hev[data-type="audit"] .knobs-wt-hdot{border-radius:1.5px}
|
|
19244
|
+
.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))}
|
|
19245
|
+
.knobs-wt-hmain{grid-area:main;display:flex;flex-direction:column;gap:2px;min-width:0}
|
|
19246
|
+
.knobs-wt-htitle{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;font-weight:var(--_k-weight-label);color:var(--_k-fg)}
|
|
19247
|
+
.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}
|
|
19248
|
+
.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}
|
|
19249
|
+
.knobs-ui .knobs-wt-hdetail{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
19250
|
+
@container knobs-wt-slot (max-width:520px){
|
|
19251
|
+
.knobs-wt-hev{grid-template-columns:14px minmax(0,1fr);grid-template-areas:"spine when" "spine main"}
|
|
19252
|
+
.knobs-wt-hwhen{flex-direction:row;flex-wrap:wrap;align-items:baseline;column-gap:8px}
|
|
19253
|
+
}
|
|
19254
|
+
|
|
19255
|
+
/* A stack: the trunk at the top, each PR hanging off the branch it merges into, rails drawn as a
|
|
19256
|
+
git graph (solid, so where two meet they don't darken). A PR with a step goes there on a click. */
|
|
19257
|
+
.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)}
|
|
19258
|
+
.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);
|
|
19259
|
+
border-radius:max(0px,calc(var(--_k-radius-panel) - 8px));transition:background calc(var(--_k-hover-out) * 1ms)}
|
|
19260
|
+
.knobs-wt-srow[data-trunk]{--kw-spb:0px;grid-template-columns:auto minmax(0,1fr)}
|
|
19261
|
+
.knobs-wt-srow[data-go]{cursor:pointer}
|
|
19262
|
+
.knobs-wt-srow[data-go]:hover{background:var(--_ku-wash);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
19263
|
+
.knobs-wt-lanes{display:flex;align-self:stretch;margin-block:calc(var(--kw-spt) * -1) calc(var(--kw-spb) * -1)}
|
|
19264
|
+
.knobs-wt-lane{position:relative;flex:none;width:16px}
|
|
19265
|
+
.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)}
|
|
19266
|
+
.knobs-wt-lane[data-down]::before{top:calc(var(--kw-sy) + 3.5px)}
|
|
19267
|
+
.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}
|
|
19268
|
+
.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)}
|
|
19269
|
+
.knobs-wt-srow[data-trunk] .knobs-wt-lane[data-rail="node"]::after{background:var(--_k-fg-2)}
|
|
19270
|
+
.knobs-wt-trunk{font:var(--_k-weight-label) calc(var(--kw-t) - 2px)/var(--kw-line) var(--_k-mono);color:var(--_k-fg-2)}
|
|
19271
|
+
.knobs-wt-smain{display:flex;flex-direction:column;gap:1px;min-width:0}
|
|
19272
|
+
.knobs-wt-sline{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 8px}
|
|
19273
|
+
.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}
|
|
19274
|
+
.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}
|
|
19275
|
+
.knobs-ui a.knobs-wt-spr:is(:hover,:focus-visible){color:var(--_k-fg);text-decoration:underline}
|
|
19276
|
+
.knobs-ui .knobs-wt-stitle{font-weight:var(--_k-weight-label);line-height:var(--kw-line);color:var(--_k-fg);text-align:left}
|
|
19277
|
+
.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)}
|
|
19278
|
+
.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)}
|
|
19279
|
+
.knobs-ui .knobs-wt-ssummary{margin:0;max-width:var(--k-walkthrough-measure,68ch);color:var(--_k-fg-2)}
|
|
19280
|
+
.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)}
|
|
19281
|
+
.knobs-wt-delta{display:inline-flex;gap:6px}
|
|
19282
|
+
.knobs-wt-add{color:var(--_k-diff-add)}
|
|
19283
|
+
.knobs-wt-del{color:var(--_k-diff-del)}
|
|
19284
|
+
.knobs-wt-sstatus{margin-top:calc((var(--kw-line) - 20px) / 2)}
|
|
19285
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr) auto}
|
|
19286
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow+.knobs-wt-srow{box-shadow:inset 0 1px 0 var(--_k-border)}
|
|
19287
|
+
@container knobs-wt-slot (max-width:520px){
|
|
19288
|
+
.knobs-wt-srow:not([data-trunk]){grid-template-columns:auto minmax(0,1fr)}
|
|
19289
|
+
.knobs-wt-stack[data-flat] .knobs-wt-srow{grid-template-columns:minmax(0,1fr)}
|
|
19290
|
+
.knobs-wt-sstatus{grid-column:-2;justify-self:start;margin-top:4px}
|
|
19291
|
+
}
|
|
19292
|
+
|
|
19293
|
+
/* A table: a real one, its head stuck while it scrolls, both ways; edges fade where there's more
|
|
19294
|
+
(the top one under the head), and thin bars show on hover. */
|
|
19295
|
+
@property --kw-fade-l{syntax:"<number>";inherits:false;initial-value:1}
|
|
19296
|
+
@property --kw-fade-r{syntax:"<number>";inherits:false;initial-value:1}
|
|
19297
|
+
@keyframes kw-fade-l{from{--kw-fade-l:1}to{--kw-fade-l:0}}
|
|
19298
|
+
@keyframes kw-fade-r{from{--kw-fade-r:0}to{--kw-fade-r:1}}
|
|
19299
|
+
.knobs-wt-table{max-height:520px;overflow:auto;overscroll-behavior-x:contain;outline:none;scrollbar-width:thin;scrollbar-color:transparent transparent;
|
|
19300
|
+
transition:scrollbar-color calc(var(--_k-hover-out) * 1ms)}
|
|
19301
|
+
.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)}
|
|
19302
|
+
.knobs-wt-table:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus);border-radius:calc(var(--_k-radius-panel) - 4px)}
|
|
19303
|
+
@supports (animation-timeline:scroll()){
|
|
19304
|
+
.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;
|
|
19305
|
+
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%;
|
|
19306
|
+
--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)));
|
|
19307
|
+
--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)));
|
|
19308
|
+
-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}
|
|
19309
|
+
}
|
|
19310
|
+
.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)}
|
|
19311
|
+
.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)}
|
|
19312
|
+
.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;
|
|
19313
|
+
background:var(--_k-pane-bg);box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
19314
|
+
.knobs-wt-table td{padding:8px 12px;vertical-align:baseline;box-shadow:inset 0 -1px 0 var(--_k-border)}
|
|
19315
|
+
.knobs-wt-table tr:last-child td{box-shadow:none}
|
|
19316
|
+
.knobs-wt-table :is(th,td):first-child{padding-left:0}
|
|
19317
|
+
.knobs-wt-table :is(th,td):last-child{padding-right:0}
|
|
19318
|
+
.knobs-wt-table td:first-child{color:var(--_k-fg)}
|
|
19319
|
+
.knobs-wt-table [data-align="right"]{text-align:right}
|
|
19320
|
+
.knobs-wt-table [data-align="center"]{text-align:center}
|
|
19321
|
+
.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}
|
|
19322
|
+
.knobs-wt-table td[data-long]{min-width:24ch}
|
|
19323
|
+
.knobs-wt-table td>.knobs-wt-steplink{margin-left:4px}
|
|
19324
|
+
.knobs-ui .knobs-wt-table a.knobs-wt-chip{text-decoration:none}
|
|
19325
|
+
.knobs-wt-ctone{color:var(--kw-tone)}
|
|
19326
|
+
|
|
19327
|
+
/* Chapters: timestamp pills under a video; one highlight springs to the one playing. */
|
|
19328
|
+
.knobs-wt-chapters{position:relative;display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}
|
|
19329
|
+
.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;
|
|
19330
|
+
transition:opacity calc(var(--_k-motion-snappy-ms) * 1ms)}
|
|
19331
|
+
.knobs-wt-chapter-mark[data-on]{opacity:1}
|
|
19332
|
+
.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);
|
|
19333
|
+
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)}
|
|
19334
|
+
.knobs-ui .knobs-wt-chapter:hover{background:var(--_ku-wash);color:var(--_k-fg);transition-duration:calc(var(--_k-hover-in) * 1ms)}
|
|
19335
|
+
.knobs-ui .knobs-wt-chapter[aria-current]{background:transparent;color:var(--_k-fg)}
|
|
19336
|
+
.knobs-ui .knobs-wt-chapter:focus-visible{box-shadow:inset 0 0 0 2px var(--_k-focus)}
|
|
19337
|
+
.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)}
|
|
19338
|
+
.knobs-wt-chapter[aria-current] .knobs-wt-chapter-time{color:var(--_k-fg-2)}
|
|
19210
19339
|
@media(prefers-reduced-motion:reduce){:is(.knobs-walkthrough,.knobs-wt-slot) :where(*,::before,::after){transition-duration:.15s!important;transition-property:opacity,background,color!important}}
|
|
19211
19340
|
`;
|
|
19212
19341
|
|
|
19342
|
+
// src/ui/walkthrough-blocks.ts
|
|
19343
|
+
init_motion();
|
|
19344
|
+
init_look();
|
|
19345
|
+
|
|
19213
19346
|
// src/ui/walkthrough-model.ts
|
|
19214
19347
|
var DEFAULT_VERDICTS = ["ship", "change", "unsure"];
|
|
19215
19348
|
function slug(text) {
|
|
@@ -19251,20 +19384,207 @@ function fillMedia(m, base) {
|
|
|
19251
19384
|
if (typeof m === "string")
|
|
19252
19385
|
return mediaOf(resolveSrc(m, base));
|
|
19253
19386
|
switch (m.kind) {
|
|
19254
|
-
case "compare":
|
|
19255
|
-
|
|
19256
|
-
case "video":
|
|
19387
|
+
case "compare": {
|
|
19388
|
+
const { chapters, ...rest } = m;
|
|
19257
19389
|
return {
|
|
19258
|
-
...
|
|
19390
|
+
...rest,
|
|
19391
|
+
before: source2(m.before, base),
|
|
19392
|
+
after: source2(m.after, base),
|
|
19393
|
+
...chapters?.length ? { chapters: fillChapters(chapters) } : {}
|
|
19394
|
+
};
|
|
19395
|
+
}
|
|
19396
|
+
case "video": {
|
|
19397
|
+
const { chapters, captionsSrc, captions, ...rest } = m;
|
|
19398
|
+
const vtt = captions ?? captionsSrc;
|
|
19399
|
+
return {
|
|
19400
|
+
...rest,
|
|
19259
19401
|
src: resolveSrc(m.src, base),
|
|
19260
|
-
...m.poster ? { poster: resolveSrc(m.poster, base) } : {}
|
|
19402
|
+
...m.poster ? { poster: resolveSrc(m.poster, base) } : {},
|
|
19403
|
+
...vtt ? { captions: resolveSrc(vtt, base) } : {},
|
|
19404
|
+
...chapters?.length ? { chapters: fillChapters(chapters) } : {}
|
|
19261
19405
|
};
|
|
19406
|
+
}
|
|
19262
19407
|
case "image":
|
|
19263
19408
|
return { ...m, src: resolveSrc(m.src, base) };
|
|
19409
|
+
case "history":
|
|
19410
|
+
return { kind: "history", groups: fillHistory(m) };
|
|
19411
|
+
case "stack":
|
|
19412
|
+
return {
|
|
19413
|
+
kind: "stack",
|
|
19414
|
+
...m.base ? { base: m.base } : {},
|
|
19415
|
+
items: m.items.map(fillStackItem)
|
|
19416
|
+
};
|
|
19417
|
+
case "table":
|
|
19418
|
+
return fillTable(m);
|
|
19264
19419
|
default:
|
|
19265
19420
|
return m;
|
|
19266
19421
|
}
|
|
19267
19422
|
}
|
|
19423
|
+
function fillHistory(m) {
|
|
19424
|
+
const groups = [];
|
|
19425
|
+
if (m.events?.length)
|
|
19426
|
+
groups.push({ events: m.events });
|
|
19427
|
+
for (const g of m.groups ?? [])
|
|
19428
|
+
groups.push({
|
|
19429
|
+
...g.heading ? { heading: g.heading } : {},
|
|
19430
|
+
...g.summary ? { summary: g.summary } : {},
|
|
19431
|
+
events: g.events ?? g.rows ?? []
|
|
19432
|
+
});
|
|
19433
|
+
return groups;
|
|
19434
|
+
}
|
|
19435
|
+
function parseBranch(branch) {
|
|
19436
|
+
if (!branch?.trim())
|
|
19437
|
+
return {};
|
|
19438
|
+
const [head, base] = branch.split(/\s*(?:→|->|=>|⇒)\s*/, 2).map((s) => s.trim());
|
|
19439
|
+
return { ...head ? { head } : {}, ...base ? { base } : {} };
|
|
19440
|
+
}
|
|
19441
|
+
function parseDelta(delta) {
|
|
19442
|
+
if (delta === undefined || typeof delta === "object")
|
|
19443
|
+
return delta;
|
|
19444
|
+
const m = /\+\s*([\d,_]+)[^\d+]*?[-−–]\s*([\d,_]+)/.exec(delta);
|
|
19445
|
+
if (!m)
|
|
19446
|
+
return delta.trim() || undefined;
|
|
19447
|
+
const n = (s) => Number(s.replace(/[,_]/g, ""));
|
|
19448
|
+
return { add: n(m[1]), del: n(m[2]) };
|
|
19449
|
+
}
|
|
19450
|
+
function fillStackItem(it) {
|
|
19451
|
+
const parsed = parseBranch(it.branch);
|
|
19452
|
+
const head = parsed.head ?? it.head;
|
|
19453
|
+
const base = parsed.base ?? it.base;
|
|
19454
|
+
const delta = parseDelta(it.delta);
|
|
19455
|
+
const step = it.step ?? it.stepId;
|
|
19456
|
+
const pr = String(it.pr).trim();
|
|
19457
|
+
return {
|
|
19458
|
+
pr: /^\d+$/.test(pr) ? `#${pr}` : pr,
|
|
19459
|
+
...it.href ? { href: it.href } : {},
|
|
19460
|
+
title: it.title,
|
|
19461
|
+
...head ? { head } : {},
|
|
19462
|
+
...base ? { base } : {},
|
|
19463
|
+
...delta !== undefined ? { delta } : {},
|
|
19464
|
+
...it.status ? { status: it.status } : {},
|
|
19465
|
+
...it.tone ? { tone: it.tone } : {},
|
|
19466
|
+
...it.summary ? { summary: it.summary } : {},
|
|
19467
|
+
...step ? { step } : {},
|
|
19468
|
+
...it.order !== undefined && it.order !== "" ? { order: String(it.order) } : {}
|
|
19469
|
+
};
|
|
19470
|
+
}
|
|
19471
|
+
function stackLayout(m) {
|
|
19472
|
+
const items = m.items;
|
|
19473
|
+
const byHead = new Map;
|
|
19474
|
+
items.forEach((it, i) => it.head && !byHead.has(it.head) && byHead.set(it.head, i));
|
|
19475
|
+
let trunk = m.base ?? null;
|
|
19476
|
+
if (!trunk) {
|
|
19477
|
+
const tally = new Map;
|
|
19478
|
+
for (const it of items)
|
|
19479
|
+
if (it.base && !byHead.has(it.base))
|
|
19480
|
+
tally.set(it.base, (tally.get(it.base) ?? 0) + 1);
|
|
19481
|
+
let best = 0;
|
|
19482
|
+
for (const [b, n] of tally)
|
|
19483
|
+
if (n > best)
|
|
19484
|
+
[trunk, best] = [b, n];
|
|
19485
|
+
}
|
|
19486
|
+
const parentOf = items.map((it, i) => {
|
|
19487
|
+
const p = it.base === undefined ? undefined : byHead.get(it.base);
|
|
19488
|
+
return p === undefined || p === i ? null : p;
|
|
19489
|
+
});
|
|
19490
|
+
items.forEach((_, i) => {
|
|
19491
|
+
const seen = new Set;
|
|
19492
|
+
for (let n = i;n !== null; n = parentOf[n]) {
|
|
19493
|
+
if (seen.has(n)) {
|
|
19494
|
+
const loop = [n];
|
|
19495
|
+
for (let k = parentOf[n];k !== n && k !== null; k = parentOf[k])
|
|
19496
|
+
loop.push(k);
|
|
19497
|
+
parentOf[Math.min(...loop)] = null;
|
|
19498
|
+
break;
|
|
19499
|
+
}
|
|
19500
|
+
seen.add(n);
|
|
19501
|
+
}
|
|
19502
|
+
});
|
|
19503
|
+
const kids = items.map(() => []);
|
|
19504
|
+
const roots = [];
|
|
19505
|
+
parentOf.forEach((p, i) => (p === null ? roots : kids[p]).push(i));
|
|
19506
|
+
const rows = [];
|
|
19507
|
+
const walk = (list, depth, rails) => list.forEach((i, n) => {
|
|
19508
|
+
const it = items[i];
|
|
19509
|
+
const last = n === list.length - 1;
|
|
19510
|
+
const off = parentOf[i] === null && it.base && it.base !== trunk ? it.base : undefined;
|
|
19511
|
+
rows.push({
|
|
19512
|
+
item: it,
|
|
19513
|
+
index: i,
|
|
19514
|
+
depth,
|
|
19515
|
+
parent: parentOf[i],
|
|
19516
|
+
last,
|
|
19517
|
+
rails,
|
|
19518
|
+
children: kids[i].length,
|
|
19519
|
+
...off ? { offBase: off } : {}
|
|
19520
|
+
});
|
|
19521
|
+
walk(kids[i], depth + 1, [...rails, !last]);
|
|
19522
|
+
});
|
|
19523
|
+
walk(roots, 0, []);
|
|
19524
|
+
return { trunk, rows, flat: !trunk && rows.every((r) => r.depth === 0 && !r.children) };
|
|
19525
|
+
}
|
|
19526
|
+
var isNum = (c) => typeof c === "number" || typeof c === "object" && typeof c.text === "number";
|
|
19527
|
+
function fillCell(c) {
|
|
19528
|
+
if (typeof c !== "object")
|
|
19529
|
+
return { text: String(c) };
|
|
19530
|
+
return { ...c, text: String(c.text) };
|
|
19531
|
+
}
|
|
19532
|
+
function fillTable(m) {
|
|
19533
|
+
const wrapped = !m.columns.some((c) => c.key === "cells");
|
|
19534
|
+
const raw = m.rows.map((r) => {
|
|
19535
|
+
const keys = Object.keys(r);
|
|
19536
|
+
const cells = r.cells;
|
|
19537
|
+
return wrapped && keys.length === 1 && keys[0] === "cells" && cells && typeof cells === "object" ? cells : r;
|
|
19538
|
+
});
|
|
19539
|
+
const columns = m.columns.map((c) => {
|
|
19540
|
+
const present = raw.map((r) => r[c.key]).filter((v) => v !== undefined && v !== "");
|
|
19541
|
+
const numeric = present.length > 0 && present.every(isNum);
|
|
19542
|
+
return { ...c, align: c.align ?? (numeric ? "right" : "left") };
|
|
19543
|
+
});
|
|
19544
|
+
const rows = raw.map((r) => {
|
|
19545
|
+
const out = {};
|
|
19546
|
+
for (const [k, v] of Object.entries(r))
|
|
19547
|
+
if (v !== undefined && v !== null)
|
|
19548
|
+
out[k] = fillCell(v);
|
|
19549
|
+
return out;
|
|
19550
|
+
});
|
|
19551
|
+
return { kind: "table", columns, rows, ...m.caption ? { caption: m.caption } : {} };
|
|
19552
|
+
}
|
|
19553
|
+
function fillChapters(chapters) {
|
|
19554
|
+
const id = uniqueIds();
|
|
19555
|
+
const starts = chapters.map((c) => c.start).sort((a, b) => a - b);
|
|
19556
|
+
return chapters.map((c) => {
|
|
19557
|
+
const next = starts.find((s) => s > c.start);
|
|
19558
|
+
const end = c.end ?? (c.duration !== undefined ? Math.round((c.start + c.duration) * 1000) / 1000 : next);
|
|
19559
|
+
return {
|
|
19560
|
+
id: id(c.id ?? slug(c.label)),
|
|
19561
|
+
label: c.label,
|
|
19562
|
+
start: c.start,
|
|
19563
|
+
...end !== undefined && end > c.start ? { end } : {}
|
|
19564
|
+
};
|
|
19565
|
+
});
|
|
19566
|
+
}
|
|
19567
|
+
function chapterAt(chapters, time) {
|
|
19568
|
+
let at = -1;
|
|
19569
|
+
chapters.forEach((c, i) => {
|
|
19570
|
+
if (time >= c.start && time < (c.end ?? Infinity) && (at < 0 || c.start >= chapters[at].start))
|
|
19571
|
+
at = i;
|
|
19572
|
+
});
|
|
19573
|
+
return at;
|
|
19574
|
+
}
|
|
19575
|
+
function clock(seconds) {
|
|
19576
|
+
const t = Math.max(0, Math.floor(seconds));
|
|
19577
|
+
const h = Math.floor(t / 3600);
|
|
19578
|
+
const m = Math.floor(t % 3600 / 60);
|
|
19579
|
+
const s = String(t % 60).padStart(2, "0");
|
|
19580
|
+
return h ? `${h}:${String(m).padStart(2, "0")}:${s}` : `${m}:${s}`;
|
|
19581
|
+
}
|
|
19582
|
+
function findStep(steps, ref) {
|
|
19583
|
+
if (ref === undefined)
|
|
19584
|
+
return;
|
|
19585
|
+
const r = ref.trim().replace(/^#/, "");
|
|
19586
|
+
return steps.find((s) => s.key === r || s.id === r || s.number === r);
|
|
19587
|
+
}
|
|
19268
19588
|
function linkLabel(href) {
|
|
19269
19589
|
const pr = /\/(?:pull|issues)\/(\d+)/.exec(href);
|
|
19270
19590
|
if (pr)
|
|
@@ -19321,7 +19641,7 @@ function normalizeWalkthrough(doc) {
|
|
|
19321
19641
|
label: k,
|
|
19322
19642
|
value
|
|
19323
19643
|
}));
|
|
19324
|
-
const stepRef = (ref) =>
|
|
19644
|
+
const stepRef = (ref) => findStep(steps, ref)?.key ?? null;
|
|
19325
19645
|
const feed = sortFeed([
|
|
19326
19646
|
...(doc.updates ?? []).map((u) => ({ kind: "update", at: parseAt(u.at), text: u.text, step: stepRef(u.step) })),
|
|
19327
19647
|
...(doc.qa ?? []).map((x) => ({
|
|
@@ -19488,6 +19808,8 @@ function describeMedia(m) {
|
|
|
19488
19808
|
parts.push(`${m.kind} at ${formatTime(m.time)}`);
|
|
19489
19809
|
else
|
|
19490
19810
|
parts.push(m.kind);
|
|
19811
|
+
if (m.chapter)
|
|
19812
|
+
parts[0] += ` in “${m.chapter}”`;
|
|
19491
19813
|
if (m.loop)
|
|
19492
19814
|
parts.push(`loop ${formatTime(m.loop.start)}–${formatTime(m.loop.end)}`);
|
|
19493
19815
|
if (m.zoom)
|
|
@@ -19647,6 +19969,388 @@ function inlineMarkdown(text) {
|
|
|
19647
19969
|
return s.replace(/\u0000(\d+)\u0000/g, (_, i) => `<code>${escapeHtml(codes[Number(i)])}</code>`);
|
|
19648
19970
|
}
|
|
19649
19971
|
|
|
19972
|
+
// src/ui/walkthrough-blocks.ts
|
|
19973
|
+
var el = (doc, tag, cls) => {
|
|
19974
|
+
const n = doc.createElement(tag);
|
|
19975
|
+
if (cls)
|
|
19976
|
+
n.className = cls;
|
|
19977
|
+
return n;
|
|
19978
|
+
};
|
|
19979
|
+
var text = (doc, tag, cls, value) => {
|
|
19980
|
+
const n = el(doc, tag, cls);
|
|
19981
|
+
n.textContent = value;
|
|
19982
|
+
return n;
|
|
19983
|
+
};
|
|
19984
|
+
var prose = (doc, tag, cls, value) => {
|
|
19985
|
+
const n = el(doc, tag, cls);
|
|
19986
|
+
n.innerHTML = inlineMarkdown(value);
|
|
19987
|
+
return n;
|
|
19988
|
+
};
|
|
19989
|
+
var link = (doc, cls, label, href) => {
|
|
19990
|
+
if (!href)
|
|
19991
|
+
return text(doc, "span", cls, label);
|
|
19992
|
+
const a = text(doc, "a", cls, label);
|
|
19993
|
+
a.href = href;
|
|
19994
|
+
a.target = "_blank";
|
|
19995
|
+
a.rel = "noreferrer";
|
|
19996
|
+
return a;
|
|
19997
|
+
};
|
|
19998
|
+
function stepButton(doc, ref, steps) {
|
|
19999
|
+
const s = ref && steps?.find(ref);
|
|
20000
|
+
if (!s || !steps)
|
|
20001
|
+
return null;
|
|
20002
|
+
const b = text(doc, "button", "knobs-wt-steplink", s.number);
|
|
20003
|
+
b.type = "button";
|
|
20004
|
+
b.title = `Go to ${s.number} ${s.title}`;
|
|
20005
|
+
b.setAttribute("aria-label", b.title);
|
|
20006
|
+
b.addEventListener("click", (e) => {
|
|
20007
|
+
e.stopPropagation();
|
|
20008
|
+
steps.go(s.key);
|
|
20009
|
+
});
|
|
20010
|
+
return b;
|
|
20011
|
+
}
|
|
20012
|
+
var tags = (doc, list) => {
|
|
20013
|
+
if (!list?.length)
|
|
20014
|
+
return null;
|
|
20015
|
+
const row = el(doc, "div", "knobs-wt-tags");
|
|
20016
|
+
for (const e of list)
|
|
20017
|
+
row.append(link(doc, "knobs-wt-tag", e.label, e.href));
|
|
20018
|
+
return row;
|
|
20019
|
+
};
|
|
20020
|
+
function mountHistory(host, m, steps) {
|
|
20021
|
+
const doc = host.ownerDocument;
|
|
20022
|
+
const root = el(doc, "div", "knobs-wt-history");
|
|
20023
|
+
const longest = Math.max(6, ...m.groups.flatMap((g) => g.events.flatMap((e) => [e.date.length, e.age?.length ?? 0])));
|
|
20024
|
+
root.style.setProperty("--kw-hw", `${Math.min(16, longest + 1)}ch`);
|
|
20025
|
+
for (const g of m.groups) {
|
|
20026
|
+
const group = el(doc, "section", "knobs-wt-hgroup");
|
|
20027
|
+
if (g.heading || g.summary) {
|
|
20028
|
+
const head = el(doc, "header", "knobs-wt-hhead");
|
|
20029
|
+
if (g.heading)
|
|
20030
|
+
head.append(text(doc, "h4", "knobs-wt-hheading", g.heading));
|
|
20031
|
+
if (g.summary)
|
|
20032
|
+
head.append(text(doc, "span", "knobs-wt-hsum", g.summary));
|
|
20033
|
+
group.append(head);
|
|
20034
|
+
}
|
|
20035
|
+
const list = el(doc, "ol", "knobs-wt-hlist");
|
|
20036
|
+
for (const e of g.events)
|
|
20037
|
+
list.append(historyEvent(doc, e, steps));
|
|
20038
|
+
group.append(list);
|
|
20039
|
+
root.append(group);
|
|
20040
|
+
}
|
|
20041
|
+
host.append(root);
|
|
20042
|
+
return { dispose: () => root.remove(), context: () => ({ kind: "history" }) };
|
|
20043
|
+
}
|
|
20044
|
+
function historyEvent(doc, e, steps) {
|
|
20045
|
+
const li = el(doc, "li", "knobs-wt-hev");
|
|
20046
|
+
if (e.tone)
|
|
20047
|
+
li.dataset.tone = e.tone;
|
|
20048
|
+
if (e.type)
|
|
20049
|
+
li.dataset.type = e.type;
|
|
20050
|
+
if (e.provenance)
|
|
20051
|
+
li.dataset.provenance = e.provenance;
|
|
20052
|
+
const when = el(doc, "div", "knobs-wt-hwhen");
|
|
20053
|
+
when.append(text(doc, "time", "knobs-wt-hdate", e.date));
|
|
20054
|
+
if (e.age)
|
|
20055
|
+
when.append(text(doc, "span", "knobs-wt-hage", e.age));
|
|
20056
|
+
const spine = el(doc, "span", "knobs-wt-hspine");
|
|
20057
|
+
spine.setAttribute("aria-hidden", "true");
|
|
20058
|
+
spine.append(el(doc, "span", "knobs-wt-hdot"));
|
|
20059
|
+
const main = el(doc, "div", "knobs-wt-hmain");
|
|
20060
|
+
const title = el(doc, "div", "knobs-wt-htitle");
|
|
20061
|
+
title.append(text(doc, "span", "knobs-wt-htext", e.title));
|
|
20062
|
+
if (e.provenance || e.source) {
|
|
20063
|
+
const p = text(doc, "span", "knobs-wt-prov", [e.provenance, e.source].filter(Boolean).join(" · "));
|
|
20064
|
+
if (e.provenance === "inferred")
|
|
20065
|
+
p.title = "Inferred from behaviour, not seen in the record";
|
|
20066
|
+
else if (e.provenance === "verified")
|
|
20067
|
+
p.title = "Seen in the record";
|
|
20068
|
+
title.append(p);
|
|
20069
|
+
}
|
|
20070
|
+
const go = stepButton(doc, e.step, steps);
|
|
20071
|
+
if (go)
|
|
20072
|
+
title.append(go);
|
|
20073
|
+
main.append(title);
|
|
20074
|
+
if (e.detail)
|
|
20075
|
+
main.append(prose(doc, "p", "knobs-wt-hdetail", e.detail));
|
|
20076
|
+
const t = tags(doc, e.evidence);
|
|
20077
|
+
if (t)
|
|
20078
|
+
main.append(t);
|
|
20079
|
+
li.append(when, spine, main);
|
|
20080
|
+
return li;
|
|
20081
|
+
}
|
|
20082
|
+
function mountStack(host, m, steps) {
|
|
20083
|
+
const doc = host.ownerDocument;
|
|
20084
|
+
const layout = stackLayout(m);
|
|
20085
|
+
const root = el(doc, "div", "knobs-wt-stack");
|
|
20086
|
+
root.toggleAttribute("data-flat", layout.flat);
|
|
20087
|
+
const lane = (kind) => {
|
|
20088
|
+
const s = el(doc, "span", "knobs-wt-lane");
|
|
20089
|
+
s.dataset.rail = kind;
|
|
20090
|
+
return s;
|
|
20091
|
+
};
|
|
20092
|
+
const node = (down) => {
|
|
20093
|
+
const s = lane("node");
|
|
20094
|
+
s.toggleAttribute("data-down", down);
|
|
20095
|
+
return s;
|
|
20096
|
+
};
|
|
20097
|
+
const from = layout.trunk ? 0 : 1;
|
|
20098
|
+
if (layout.trunk && layout.rows.length) {
|
|
20099
|
+
const row = el(doc, "div", "knobs-wt-srow");
|
|
20100
|
+
row.dataset.trunk = "";
|
|
20101
|
+
const lanes = el(doc, "span", "knobs-wt-lanes");
|
|
20102
|
+
lanes.setAttribute("aria-hidden", "true");
|
|
20103
|
+
lanes.append(node(true));
|
|
20104
|
+
row.append(lanes, text(doc, "span", "knobs-wt-trunk", layout.trunk));
|
|
20105
|
+
root.append(row);
|
|
20106
|
+
}
|
|
20107
|
+
for (const r of layout.rows) {
|
|
20108
|
+
const it = r.item;
|
|
20109
|
+
const row = el(doc, "div", "knobs-wt-srow");
|
|
20110
|
+
if (!layout.flat) {
|
|
20111
|
+
const lanes = el(doc, "span", "knobs-wt-lanes");
|
|
20112
|
+
lanes.setAttribute("aria-hidden", "true");
|
|
20113
|
+
for (let k = from;k < r.depth; k++)
|
|
20114
|
+
lanes.append(lane(r.rails[k] ? "pass" : "none"));
|
|
20115
|
+
if (r.depth >= from)
|
|
20116
|
+
lanes.append(lane(r.last ? "end" : "tee"));
|
|
20117
|
+
lanes.append(node(r.children > 0));
|
|
20118
|
+
row.append(lanes);
|
|
20119
|
+
}
|
|
20120
|
+
const main = el(doc, "div", "knobs-wt-smain");
|
|
20121
|
+
const line = el(doc, "div", "knobs-wt-sline");
|
|
20122
|
+
if (it.order)
|
|
20123
|
+
line.append(text(doc, "span", "knobs-wt-sord", it.order));
|
|
20124
|
+
line.append(link(doc, "knobs-wt-spr", it.pr, it.href));
|
|
20125
|
+
const target = it.step ? steps?.find(it.step) : null;
|
|
20126
|
+
if (target && steps) {
|
|
20127
|
+
const title = text(doc, "button", "knobs-wt-stitle", it.title);
|
|
20128
|
+
title.type = "button";
|
|
20129
|
+
title.title = `Go to ${target.number} ${target.title}`;
|
|
20130
|
+
title.addEventListener("click", (e) => {
|
|
20131
|
+
e.stopPropagation();
|
|
20132
|
+
steps.go(target.key);
|
|
20133
|
+
});
|
|
20134
|
+
line.append(title);
|
|
20135
|
+
const go = stepButton(doc, it.step, steps);
|
|
20136
|
+
if (go)
|
|
20137
|
+
line.append(go);
|
|
20138
|
+
row.dataset.go = "";
|
|
20139
|
+
row.addEventListener("click", (e) => {
|
|
20140
|
+
const t = e.target;
|
|
20141
|
+
if (t?.closest("a,button"))
|
|
20142
|
+
return;
|
|
20143
|
+
if (doc.getSelection()?.toString())
|
|
20144
|
+
return;
|
|
20145
|
+
steps.go(target.key);
|
|
20146
|
+
});
|
|
20147
|
+
} else
|
|
20148
|
+
line.append(text(doc, "span", "knobs-wt-stitle", it.title));
|
|
20149
|
+
main.append(line);
|
|
20150
|
+
if (it.summary)
|
|
20151
|
+
main.append(prose(doc, "p", "knobs-wt-ssummary", it.summary));
|
|
20152
|
+
const meta = el(doc, "div", "knobs-wt-smeta");
|
|
20153
|
+
if (it.head) {
|
|
20154
|
+
const branch = r.offBase ? `${it.head} → ${r.offBase}` : it.head;
|
|
20155
|
+
meta.append(text(doc, "span", "knobs-wt-sbranch", branch));
|
|
20156
|
+
}
|
|
20157
|
+
if (it.delta !== undefined)
|
|
20158
|
+
meta.append(delta(doc, it.delta));
|
|
20159
|
+
if (meta.childNodes.length)
|
|
20160
|
+
main.append(meta);
|
|
20161
|
+
row.append(main);
|
|
20162
|
+
if (it.status) {
|
|
20163
|
+
const chip = text(doc, "span", "knobs-wt-chip knobs-wt-sstatus", it.status);
|
|
20164
|
+
chip.dataset.tone = it.tone ?? "dim";
|
|
20165
|
+
row.append(chip);
|
|
20166
|
+
}
|
|
20167
|
+
root.append(row);
|
|
20168
|
+
}
|
|
20169
|
+
host.append(root);
|
|
20170
|
+
return { dispose: () => root.remove(), context: () => ({ kind: "stack" }) };
|
|
20171
|
+
}
|
|
20172
|
+
function delta(doc, d) {
|
|
20173
|
+
const s = el(doc, "span", "knobs-wt-delta");
|
|
20174
|
+
if (typeof d === "string") {
|
|
20175
|
+
s.textContent = d;
|
|
20176
|
+
return s;
|
|
20177
|
+
}
|
|
20178
|
+
const n = (v) => v.toLocaleString("en-US");
|
|
20179
|
+
s.append(text(doc, "span", "knobs-wt-add", `+${n(d.add)}`));
|
|
20180
|
+
s.append(text(doc, "span", "knobs-wt-del", `−${n(d.del)}`));
|
|
20181
|
+
s.setAttribute("aria-label", `${d.add} added, ${d.del} removed`);
|
|
20182
|
+
return s;
|
|
20183
|
+
}
|
|
20184
|
+
function mountTable(host, m, steps) {
|
|
20185
|
+
const doc = host.ownerDocument;
|
|
20186
|
+
const win = doc.defaultView;
|
|
20187
|
+
const scroller = el(doc, "div", "knobs-wt-table");
|
|
20188
|
+
const table = el(doc, "table");
|
|
20189
|
+
if (m.caption)
|
|
20190
|
+
table.append(text(doc, "caption", "", m.caption));
|
|
20191
|
+
const head = el(doc, "thead");
|
|
20192
|
+
const hr = el(doc, "tr");
|
|
20193
|
+
for (const c of m.columns) {
|
|
20194
|
+
const th = text(doc, "th", "", c.label);
|
|
20195
|
+
th.scope = "col";
|
|
20196
|
+
th.dataset.align = c.align;
|
|
20197
|
+
hr.append(th);
|
|
20198
|
+
}
|
|
20199
|
+
head.append(hr);
|
|
20200
|
+
const body = el(doc, "tbody");
|
|
20201
|
+
for (const r of m.rows) {
|
|
20202
|
+
const tr = el(doc, "tr");
|
|
20203
|
+
for (const c of m.columns) {
|
|
20204
|
+
const td = el(doc, "td");
|
|
20205
|
+
td.dataset.align = c.align;
|
|
20206
|
+
if (c.mono)
|
|
20207
|
+
td.dataset.mono = "";
|
|
20208
|
+
const cell = r[c.key];
|
|
20209
|
+
if (cell) {
|
|
20210
|
+
if (cell.text.length > 40 && !c.mono && !cell.code)
|
|
20211
|
+
td.dataset.long = "";
|
|
20212
|
+
let content;
|
|
20213
|
+
if (cell.badge) {
|
|
20214
|
+
content = link(doc, "knobs-wt-chip", cell.text, cell.href);
|
|
20215
|
+
content.dataset.tone = cell.badge;
|
|
20216
|
+
} else {
|
|
20217
|
+
const inner = cell.code ? text(doc, "code", "", cell.text) : null;
|
|
20218
|
+
if (cell.href) {
|
|
20219
|
+
content = link(doc, "knobs-wt-clink", inner ? "" : cell.text, cell.href);
|
|
20220
|
+
if (inner)
|
|
20221
|
+
content.append(inner);
|
|
20222
|
+
} else
|
|
20223
|
+
content = inner ?? text(doc, "span", "", cell.text);
|
|
20224
|
+
if (cell.tone) {
|
|
20225
|
+
content.classList.add("knobs-wt-ctone");
|
|
20226
|
+
content.dataset.tone = cell.tone;
|
|
20227
|
+
}
|
|
20228
|
+
}
|
|
20229
|
+
td.append(content);
|
|
20230
|
+
const go = stepButton(doc, cell.step, steps);
|
|
20231
|
+
if (go)
|
|
20232
|
+
td.append(go);
|
|
20233
|
+
}
|
|
20234
|
+
tr.append(td);
|
|
20235
|
+
}
|
|
20236
|
+
body.append(tr);
|
|
20237
|
+
}
|
|
20238
|
+
table.append(head, body);
|
|
20239
|
+
scroller.append(table);
|
|
20240
|
+
host.append(scroller);
|
|
20241
|
+
const measure = () => {
|
|
20242
|
+
scroller.style.setProperty("--kw-thead", `${head.offsetHeight}px`);
|
|
20243
|
+
const scrolls = scroller.scrollWidth > scroller.clientWidth + 1 || scroller.scrollHeight > scroller.clientHeight + 1;
|
|
20244
|
+
if (scrolls) {
|
|
20245
|
+
scroller.tabIndex = 0;
|
|
20246
|
+
scroller.setAttribute("role", "region");
|
|
20247
|
+
scroller.setAttribute("aria-label", m.caption ?? "Table");
|
|
20248
|
+
} else {
|
|
20249
|
+
scroller.removeAttribute("tabindex");
|
|
20250
|
+
scroller.removeAttribute("role");
|
|
20251
|
+
scroller.removeAttribute("aria-label");
|
|
20252
|
+
}
|
|
20253
|
+
};
|
|
20254
|
+
const ro = win && "ResizeObserver" in win ? new win.ResizeObserver(measure) : null;
|
|
20255
|
+
ro?.observe(scroller);
|
|
20256
|
+
measure();
|
|
20257
|
+
return {
|
|
20258
|
+
dispose: () => {
|
|
20259
|
+
ro?.disconnect();
|
|
20260
|
+
scroller.remove();
|
|
20261
|
+
},
|
|
20262
|
+
context: () => ({ kind: "table" })
|
|
20263
|
+
};
|
|
20264
|
+
}
|
|
20265
|
+
var grid = (v) => Math.round(v * 64) / 64;
|
|
20266
|
+
function chapterPills(host, chapters, io) {
|
|
20267
|
+
const doc = host.ownerDocument;
|
|
20268
|
+
const win = doc.defaultView;
|
|
20269
|
+
const bar = el(doc, "div", "knobs-wt-chapters");
|
|
20270
|
+
bar.setAttribute("role", "group");
|
|
20271
|
+
bar.setAttribute("aria-label", "Chapters");
|
|
20272
|
+
const mark = el(doc, "span", "knobs-wt-chapter-mark");
|
|
20273
|
+
mark.setAttribute("aria-hidden", "true");
|
|
20274
|
+
bar.append(mark);
|
|
20275
|
+
const pills = chapters.map((c) => {
|
|
20276
|
+
const b = el(doc, "button", "knobs-wt-chapter");
|
|
20277
|
+
b.type = "button";
|
|
20278
|
+
b.append(text(doc, "span", "knobs-wt-chapter-time", clock(c.start)));
|
|
20279
|
+
b.append(text(doc, "span", "knobs-wt-chapter-label", c.label));
|
|
20280
|
+
b.addEventListener("click", () => {
|
|
20281
|
+
io.onEvent?.({ what: "seek", time: Math.round(c.start * 100) / 100, detail: c.label });
|
|
20282
|
+
io.seek(c.start);
|
|
20283
|
+
sync();
|
|
20284
|
+
});
|
|
20285
|
+
bar.append(b);
|
|
20286
|
+
return b;
|
|
20287
|
+
});
|
|
20288
|
+
host.append(bar);
|
|
20289
|
+
const x = new Spring(0, MOTION.calm.omega, MOTION.calm.zeta, 0.25);
|
|
20290
|
+
const y = new Spring(0, MOTION.calm.omega, MOTION.calm.zeta, 0.25);
|
|
20291
|
+
const w = new Spring(0, MOTION.calm.omega, MOTION.calm.zeta, 0.25);
|
|
20292
|
+
const draw = () => {
|
|
20293
|
+
const left = grid(x.x);
|
|
20294
|
+
mark.style.transform = `translate(${left}px,${grid(y.x)}px)`;
|
|
20295
|
+
mark.style.width = `${grid(x.x + w.x) - left}px`;
|
|
20296
|
+
};
|
|
20297
|
+
const loop = frameLoop(win, (dt) => {
|
|
20298
|
+
x.step(dt);
|
|
20299
|
+
y.step(dt);
|
|
20300
|
+
w.step(dt);
|
|
20301
|
+
draw();
|
|
20302
|
+
return !x.resting || !y.resting || !w.resting;
|
|
20303
|
+
});
|
|
20304
|
+
let at = -2;
|
|
20305
|
+
let shown = false;
|
|
20306
|
+
const place = (snap) => {
|
|
20307
|
+
const p = pills[at];
|
|
20308
|
+
if (!p) {
|
|
20309
|
+
mark.removeAttribute("data-on");
|
|
20310
|
+
pills.forEach((b) => b.removeAttribute("aria-current"));
|
|
20311
|
+
shown = false;
|
|
20312
|
+
return;
|
|
20313
|
+
}
|
|
20314
|
+
pills.forEach((b, i) => i === at ? b.setAttribute("aria-current", "true") : b.removeAttribute("aria-current"));
|
|
20315
|
+
const to = [p.offsetLeft, p.offsetTop, p.offsetWidth];
|
|
20316
|
+
if (snap || !shown || reducedMotion(win)) {
|
|
20317
|
+
x.snap(to[0]);
|
|
20318
|
+
y.snap(to[1]);
|
|
20319
|
+
w.snap(to[2]);
|
|
20320
|
+
draw();
|
|
20321
|
+
} else {
|
|
20322
|
+
x.set(to[0]);
|
|
20323
|
+
y.set(to[1]);
|
|
20324
|
+
w.set(to[2]);
|
|
20325
|
+
loop.wake();
|
|
20326
|
+
}
|
|
20327
|
+
mark.style.height = `${p.offsetHeight}px`;
|
|
20328
|
+
mark.dataset.on = "";
|
|
20329
|
+
shown = true;
|
|
20330
|
+
};
|
|
20331
|
+
const sync = () => {
|
|
20332
|
+
const next = chapterAt(chapters, io.now());
|
|
20333
|
+
if (next === at)
|
|
20334
|
+
return;
|
|
20335
|
+
at = next;
|
|
20336
|
+
place(false);
|
|
20337
|
+
};
|
|
20338
|
+
sync();
|
|
20339
|
+
const ro = "ResizeObserver" in win ? new win.ResizeObserver(() => place(true)) : null;
|
|
20340
|
+
ro?.observe(bar);
|
|
20341
|
+
return {
|
|
20342
|
+
sync,
|
|
20343
|
+
get current() {
|
|
20344
|
+
return chapters[at] ?? null;
|
|
20345
|
+
},
|
|
20346
|
+
dispose() {
|
|
20347
|
+
loop.stop();
|
|
20348
|
+
ro?.disconnect();
|
|
20349
|
+
bar.remove();
|
|
20350
|
+
}
|
|
20351
|
+
};
|
|
20352
|
+
}
|
|
20353
|
+
|
|
19650
20354
|
// src/ui/walkthrough-media.ts
|
|
19651
20355
|
function injectWalkthroughStyles(doc) {
|
|
19652
20356
|
if (doc.querySelector("style[data-knobs-ui-walkthrough]"))
|
|
@@ -19779,8 +20483,25 @@ async function mountCompare(host, m, look, alive, onEvent) {
|
|
|
19779
20483
|
onEvent?.({ what: "loop", detail: lastLoop = loopKey });
|
|
19780
20484
|
}
|
|
19781
20485
|
});
|
|
20486
|
+
const chapters = m.chapters?.length ? m.chapters : null;
|
|
20487
|
+
if (chapters)
|
|
20488
|
+
c.timeline?.update({
|
|
20489
|
+
markers: chapters.map((ch) => ({ id: ch.id, time: ch.start, label: ch.label }))
|
|
20490
|
+
});
|
|
20491
|
+
const pills = chapters ? chapterPills(host, chapters, {
|
|
20492
|
+
now: () => c.time,
|
|
20493
|
+
seek: (t) => {
|
|
20494
|
+
c.seek(t);
|
|
20495
|
+
c.play();
|
|
20496
|
+
},
|
|
20497
|
+
onEvent
|
|
20498
|
+
}) : null;
|
|
19782
20499
|
const unlisten = c.timeline?.listen({
|
|
19783
|
-
onSeek: (time, source) =>
|
|
20500
|
+
onSeek: (time, source) => {
|
|
20501
|
+
pills?.sync();
|
|
20502
|
+
if (source !== "play")
|
|
20503
|
+
onEvent?.({ what: "seek", time: round2(time) });
|
|
20504
|
+
},
|
|
19784
20505
|
onPlay: (on) => onEvent?.({ what: on ? "play" : "pause", time: round2(c.time) })
|
|
19785
20506
|
});
|
|
19786
20507
|
requestAnimationFrame(() => requestAnimationFrame(() => fit.dataset.settled = ""));
|
|
@@ -19802,12 +20523,14 @@ async function mountCompare(host, m, look, alive, onEvent) {
|
|
|
19802
20523
|
duration: round2(c.duration),
|
|
19803
20524
|
playing: c.playing,
|
|
19804
20525
|
mode: c.mode,
|
|
20526
|
+
...pills?.current ? { chapter: pills.current.label } : {},
|
|
19805
20527
|
...loop ? { loop: { start: round2(loop.start), end: round2(loop.end) } } : {},
|
|
19806
20528
|
...zoom ? { zoom: { u: round2(zoom.u), v: round2(zoom.v), w: round2(zoom.w), h: round2(zoom.h) } } : {}
|
|
19807
20529
|
};
|
|
19808
20530
|
},
|
|
19809
20531
|
dispose: () => {
|
|
19810
20532
|
unlisten?.();
|
|
20533
|
+
pills?.dispose();
|
|
19811
20534
|
c.dispose();
|
|
19812
20535
|
fit.remove();
|
|
19813
20536
|
}
|
|
@@ -19831,6 +20554,15 @@ function mountVideo(host, m, onEvent) {
|
|
|
19831
20554
|
v.poster = m.poster;
|
|
19832
20555
|
if (!aspect)
|
|
19833
20556
|
v.addEventListener("loadedmetadata", () => v.videoWidth && frame.style.setProperty("--kw-aspect", String(v.videoWidth / v.videoHeight)), { once: true });
|
|
20557
|
+
if (m.captions) {
|
|
20558
|
+
const track = doc.createElement("track");
|
|
20559
|
+
track.kind = "captions";
|
|
20560
|
+
track.label = "Captions";
|
|
20561
|
+
track.srclang = doc.documentElement.lang || "en";
|
|
20562
|
+
track.default = true;
|
|
20563
|
+
track.src = m.captions;
|
|
20564
|
+
v.append(track);
|
|
20565
|
+
}
|
|
19834
20566
|
v.src = m.src;
|
|
19835
20567
|
v.addEventListener("play", () => onEvent?.({ what: "play", time: round2(v.currentTime) }));
|
|
19836
20568
|
v.addEventListener("pause", () => onEvent?.({ what: "pause", time: round2(v.currentTime) }));
|
|
@@ -19840,6 +20572,18 @@ function mountVideo(host, m, onEvent) {
|
|
|
19840
20572
|
});
|
|
19841
20573
|
frame.append(v);
|
|
19842
20574
|
host.append(frame);
|
|
20575
|
+
const pills = m.chapters?.length ? chapterPills(host, m.chapters, {
|
|
20576
|
+
now: () => v.currentTime,
|
|
20577
|
+
seek: (t) => {
|
|
20578
|
+
v.currentTime = t;
|
|
20579
|
+
v.play().catch(() => {});
|
|
20580
|
+
},
|
|
20581
|
+
onEvent
|
|
20582
|
+
}) : null;
|
|
20583
|
+
const sync = () => pills?.sync();
|
|
20584
|
+
if (pills)
|
|
20585
|
+
for (const type of ["timeupdate", "seeking", "seeked"])
|
|
20586
|
+
v.addEventListener(type, sync);
|
|
19843
20587
|
return {
|
|
19844
20588
|
pause: () => v.pause(),
|
|
19845
20589
|
seekBy: (d) => {
|
|
@@ -19849,9 +20593,11 @@ function mountVideo(host, m, onEvent) {
|
|
|
19849
20593
|
kind: "video",
|
|
19850
20594
|
time: round2(v.currentTime),
|
|
19851
20595
|
...Number.isFinite(v.duration) ? { duration: round2(v.duration) } : {},
|
|
19852
|
-
playing: !v.paused
|
|
20596
|
+
playing: !v.paused,
|
|
20597
|
+
...pills?.current ? { chapter: pills.current.label } : {}
|
|
19853
20598
|
}),
|
|
19854
20599
|
dispose: () => {
|
|
20600
|
+
pills?.dispose();
|
|
19855
20601
|
v.pause();
|
|
19856
20602
|
v.removeAttribute("src");
|
|
19857
20603
|
v.load();
|
|
@@ -20075,6 +20821,12 @@ function mediaSlot(container, options) {
|
|
|
20075
20821
|
case "callout":
|
|
20076
20822
|
case "text":
|
|
20077
20823
|
return done(mountProse(host, m));
|
|
20824
|
+
case "history":
|
|
20825
|
+
return done(mountHistory(host, m, options.steps));
|
|
20826
|
+
case "stack":
|
|
20827
|
+
return done(mountStack(host, m, options.steps));
|
|
20828
|
+
case "table":
|
|
20829
|
+
return done(mountTable(host, m, options.steps));
|
|
20078
20830
|
case "mount": {
|
|
20079
20831
|
const cleanup = m.mount(host);
|
|
20080
20832
|
return done({ dispose: () => cleanup ? cleanup() : host.textContent = "" });
|
|
@@ -20129,14 +20881,14 @@ function mediaSlot(container, options) {
|
|
|
20129
20881
|
var CHECK3 = svg('<path d="m3.5 8.4 3 3 6-6.6"/>');
|
|
20130
20882
|
|
|
20131
20883
|
// src/ui/walkthrough.ts
|
|
20132
|
-
var
|
|
20884
|
+
var el2 = (doc, tag, cls) => {
|
|
20133
20885
|
const n = doc.createElement(tag);
|
|
20134
20886
|
if (cls)
|
|
20135
20887
|
n.className = cls;
|
|
20136
20888
|
return n;
|
|
20137
20889
|
};
|
|
20138
|
-
var
|
|
20139
|
-
const n =
|
|
20890
|
+
var prose2 = (doc, tag, cls, text) => {
|
|
20891
|
+
const n = el2(doc, tag, cls);
|
|
20140
20892
|
n.innerHTML = inlineMarkdown(text);
|
|
20141
20893
|
return n;
|
|
20142
20894
|
};
|
|
@@ -20144,7 +20896,7 @@ var lookOf2 = (o) => ({
|
|
|
20144
20896
|
...o.preset ? { preset: o.preset } : {},
|
|
20145
20897
|
...o.theme ? { theme: o.theme } : {}
|
|
20146
20898
|
});
|
|
20147
|
-
var
|
|
20899
|
+
var grid2 = (v) => Math.round(v * 64) / 64;
|
|
20148
20900
|
var ICON = {
|
|
20149
20901
|
full: svg('<path d="M3 6.5V3h3.5M13 6.5V3H9.5M3 9.5V13h3.5M13 9.5V13H9.5"/>'),
|
|
20150
20902
|
exit: svg('<path d="M6.5 3v3.5H3M9.5 3v3.5H13M6.5 13V9.5H3M9.5 13V9.5H13"/>'),
|
|
@@ -20170,7 +20922,7 @@ function tasteTest(container, options) {
|
|
|
20170
20922
|
suggested: o.suggested === true
|
|
20171
20923
|
});
|
|
20172
20924
|
let picked = options.picked ?? null;
|
|
20173
|
-
const root =
|
|
20925
|
+
const root = el2(doc, "div", "knobs-wt-options");
|
|
20174
20926
|
root.setAttribute("role", "radiogroup");
|
|
20175
20927
|
root.setAttribute("aria-label", "Options");
|
|
20176
20928
|
root.style.setProperty("--kw-n", String(Math.min(list.length, 3)));
|
|
@@ -20178,28 +20930,28 @@ function tasteTest(container, options) {
|
|
|
20178
20930
|
applyLook2(root, options);
|
|
20179
20931
|
const slots = [];
|
|
20180
20932
|
const tiles = list.map((o, i) => {
|
|
20181
|
-
const tile =
|
|
20182
|
-
const pick =
|
|
20933
|
+
const tile = el2(doc, "div", "knobs-wt-option");
|
|
20934
|
+
const pick = el2(doc, "button", "knobs-wt-pick");
|
|
20183
20935
|
pick.type = "button";
|
|
20184
20936
|
pick.setAttribute("role", "radio");
|
|
20185
20937
|
if (i < 9)
|
|
20186
20938
|
pick.setAttribute("aria-keyshortcuts", String(i + 1));
|
|
20187
|
-
const letter =
|
|
20939
|
+
const letter = el2(doc, "span", "knobs-wt-letter");
|
|
20188
20940
|
letter.textContent = o.letter;
|
|
20189
|
-
const name =
|
|
20941
|
+
const name = el2(doc, "span", "knobs-wt-olabel");
|
|
20190
20942
|
name.textContent = o.label;
|
|
20191
20943
|
pick.append(letter, name);
|
|
20192
20944
|
if (o.suggested) {
|
|
20193
|
-
const s =
|
|
20945
|
+
const s = el2(doc, "span", "knobs-wt-suggested");
|
|
20194
20946
|
s.textContent = "Suggested";
|
|
20195
20947
|
pick.append(s);
|
|
20196
20948
|
}
|
|
20197
20949
|
if (i < 9) {
|
|
20198
|
-
const key =
|
|
20950
|
+
const key = el2(doc, "span", "knobs-wt-key");
|
|
20199
20951
|
key.textContent = String(i + 1);
|
|
20200
20952
|
pick.append(key);
|
|
20201
20953
|
}
|
|
20202
|
-
const check =
|
|
20954
|
+
const check = el2(doc, "span", "knobs-wt-check");
|
|
20203
20955
|
check.innerHTML = CHECK3;
|
|
20204
20956
|
pick.append(check);
|
|
20205
20957
|
pick.addEventListener("click", () => {
|
|
@@ -20212,10 +20964,11 @@ function tasteTest(container, options) {
|
|
|
20212
20964
|
slots.push(mediaSlot(tile, {
|
|
20213
20965
|
...look,
|
|
20214
20966
|
media: o.media,
|
|
20215
|
-
...options.lazy === false ? { lazy: false } : {}
|
|
20967
|
+
...options.lazy === false ? { lazy: false } : {},
|
|
20968
|
+
...options.steps ? { steps: options.steps } : {}
|
|
20216
20969
|
}));
|
|
20217
20970
|
if (o.caption)
|
|
20218
|
-
tile.append(
|
|
20971
|
+
tile.append(prose2(doc, "p", "knobs-wt-ocap", o.caption));
|
|
20219
20972
|
root.append(tile);
|
|
20220
20973
|
return { tile, pick };
|
|
20221
20974
|
});
|
|
@@ -20263,7 +21016,7 @@ function walkthrough(container, options) {
|
|
|
20263
21016
|
injectWalkthroughStyles(doc);
|
|
20264
21017
|
const look = lookOf2(options);
|
|
20265
21018
|
const storage = options.storage === undefined ? browserStorage() : options.storage;
|
|
20266
|
-
const root =
|
|
21019
|
+
const root = el2(doc, "div", "knobs-walkthrough");
|
|
20267
21020
|
applyLook2(root, options);
|
|
20268
21021
|
container.append(root);
|
|
20269
21022
|
let page = normalizeWalkthrough(options.doc);
|
|
@@ -20323,8 +21076,8 @@ function walkthrough(container, options) {
|
|
|
20323
21076
|
if (mark) {
|
|
20324
21077
|
pillY.step(dt);
|
|
20325
21078
|
pillH.step(dt);
|
|
20326
|
-
mark.style.transform = `translateY(${
|
|
20327
|
-
mark.style.height = `${
|
|
21079
|
+
mark.style.transform = `translateY(${grid2(pillY.x)}px)`;
|
|
21080
|
+
mark.style.height = `${grid2(pillY.x + pillH.x) - grid2(pillY.x)}px`;
|
|
20328
21081
|
more ||= !pillY.resting || !pillH.resting;
|
|
20329
21082
|
}
|
|
20330
21083
|
if (scroll.to && scroll.el) {
|
|
@@ -20459,6 +21212,10 @@ function walkthrough(container, options) {
|
|
|
20459
21212
|
scrollToCard(v);
|
|
20460
21213
|
v.card.focus({ preventScroll: true });
|
|
20461
21214
|
};
|
|
21215
|
+
const stepLinks = {
|
|
21216
|
+
find: (ref) => findStep(page.steps, ref) ?? null,
|
|
21217
|
+
go: (key) => go(key)
|
|
21218
|
+
};
|
|
20462
21219
|
const slotsOf = (v) => v ? [...v.slots, ...v.taste?.slots ?? []] : [];
|
|
20463
21220
|
const mediaContext = (v) => {
|
|
20464
21221
|
const slots = slotsOf(v);
|
|
@@ -20473,17 +21230,17 @@ function walkthrough(container, options) {
|
|
|
20473
21230
|
return true;
|
|
20474
21231
|
return false;
|
|
20475
21232
|
};
|
|
20476
|
-
const scrim =
|
|
21233
|
+
const scrim = el2(doc, "div", "knobs-wt-scrim");
|
|
20477
21234
|
scrim.addEventListener("click", () => setFull(false));
|
|
20478
21235
|
const fullRect = () => ({ x: 12, y: 12, w: win.innerWidth - 24, h: win.innerHeight - 24 });
|
|
20479
21236
|
const placeFull = (f) => {
|
|
20480
21237
|
const a = f.hold.getBoundingClientRect();
|
|
20481
21238
|
const b = fullRect();
|
|
20482
21239
|
const k = reduced() ? Math.round(f.p.target) : f.p.x;
|
|
20483
|
-
const left =
|
|
20484
|
-
const top =
|
|
20485
|
-
const right =
|
|
20486
|
-
const bottom =
|
|
21240
|
+
const left = grid2(a.left + (b.x - a.left) * k);
|
|
21241
|
+
const top = grid2(a.top + (b.y - a.top) * k);
|
|
21242
|
+
const right = grid2(a.right + (b.x + b.w - a.right) * k);
|
|
21243
|
+
const bottom = grid2(a.bottom + (b.y + b.h - a.bottom) * k);
|
|
20487
21244
|
const s = f.v.card.style;
|
|
20488
21245
|
s.left = `${left}px`;
|
|
20489
21246
|
s.top = `${top}px`;
|
|
@@ -20518,7 +21275,7 @@ function walkthrough(container, options) {
|
|
|
20518
21275
|
}
|
|
20519
21276
|
if (!full) {
|
|
20520
21277
|
const r = v.card.getBoundingClientRect();
|
|
20521
|
-
const hold =
|
|
21278
|
+
const hold = el2(doc, "div", "knobs-wt-hold-card");
|
|
20522
21279
|
hold.style.height = `${r.height}px`;
|
|
20523
21280
|
v.card.before(hold);
|
|
20524
21281
|
v.card.dataset.full = "";
|
|
@@ -20666,7 +21423,7 @@ function walkthrough(container, options) {
|
|
|
20666
21423
|
toast("Couldn't reach the microphone", { tone: "warn", look, doc });
|
|
20667
21424
|
}
|
|
20668
21425
|
};
|
|
20669
|
-
const backPill =
|
|
21426
|
+
const backPill = el2(doc, "button", "knobs-wt-back");
|
|
20670
21427
|
backPill.type = "button";
|
|
20671
21428
|
let backTo = null;
|
|
20672
21429
|
let backTimer = 0;
|
|
@@ -20691,16 +21448,16 @@ function walkthrough(container, options) {
|
|
|
20691
21448
|
backTimer = win.setTimeout(hideBack, BACK_MS);
|
|
20692
21449
|
};
|
|
20693
21450
|
const bar = (() => {
|
|
20694
|
-
const dock =
|
|
20695
|
-
const box =
|
|
20696
|
-
const on =
|
|
20697
|
-
const row =
|
|
20698
|
-
const input =
|
|
21451
|
+
const dock = el2(doc, "div", "knobs-wt-dock");
|
|
21452
|
+
const box = el2(doc, "div", "knobs-wt-notebar");
|
|
21453
|
+
const on = el2(doc, "div", "knobs-wt-on");
|
|
21454
|
+
const row = el2(doc, "div", "knobs-wt-row");
|
|
21455
|
+
const input = el2(doc, "textarea", "knobs-wt-input");
|
|
20699
21456
|
input.rows = 1;
|
|
20700
21457
|
input.setAttribute("aria-label", "Note");
|
|
20701
|
-
const attach =
|
|
21458
|
+
const attach = el2(doc, "div", "knobs-wt-attach");
|
|
20702
21459
|
const btn = (icon, label, run) => {
|
|
20703
|
-
const b =
|
|
21460
|
+
const b = el2(doc, "button", "knobs-wt-tool");
|
|
20704
21461
|
b.type = "button";
|
|
20705
21462
|
b.innerHTML = icon;
|
|
20706
21463
|
b.setAttribute("aria-label", label);
|
|
@@ -20711,7 +21468,7 @@ function walkthrough(container, options) {
|
|
|
20711
21468
|
const fullBtn = btn(ICON.full, "Full window · f", () => setFull(!full));
|
|
20712
21469
|
const penBtn = btn(ICON.pen, "Draw on the media", () => setInk(!ink.on));
|
|
20713
21470
|
const micBtn = btn(ICON.mic, "Record a voice note", () => void toggleVoice());
|
|
20714
|
-
const micTime =
|
|
21471
|
+
const micTime = el2(doc, "span", "knobs-wt-rec");
|
|
20715
21472
|
micBtn.append(micTime);
|
|
20716
21473
|
const sendBtn = btn(ICON.send, "Send · Enter", () => send());
|
|
20717
21474
|
sendBtn.dataset.send = "";
|
|
@@ -20737,9 +21494,9 @@ function walkthrough(container, options) {
|
|
|
20737
21494
|
}
|
|
20738
21495
|
});
|
|
20739
21496
|
const chip = (text, clear) => {
|
|
20740
|
-
const c =
|
|
21497
|
+
const c = el2(doc, "span", "knobs-wt-chip-a");
|
|
20741
21498
|
c.append(text);
|
|
20742
|
-
const x =
|
|
21499
|
+
const x = el2(doc, "button", "knobs-wt-x");
|
|
20743
21500
|
x.type = "button";
|
|
20744
21501
|
x.innerHTML = ICON.close;
|
|
20745
21502
|
x.setAttribute("aria-label", `Remove ${text}`);
|
|
@@ -20852,9 +21609,9 @@ function walkthrough(container, options) {
|
|
|
20852
21609
|
}
|
|
20853
21610
|
};
|
|
20854
21611
|
const renderNote = (v, n, entering = false) => {
|
|
20855
|
-
const row =
|
|
21612
|
+
const row = el2(doc, "div", "knobs-wt-n");
|
|
20856
21613
|
row.dataset.id = n.id;
|
|
20857
|
-
const meta =
|
|
21614
|
+
const meta = el2(doc, "span", "knobs-wt-n-meta");
|
|
20858
21615
|
const m = n.context.media;
|
|
20859
21616
|
meta.textContent = m?.time !== undefined ? formatTime(m.time) : m?.file ? m.file.split("/").pop() : "·";
|
|
20860
21617
|
if (m?.time !== undefined) {
|
|
@@ -20870,11 +21627,11 @@ function walkthrough(container, options) {
|
|
|
20870
21627
|
});
|
|
20871
21628
|
}
|
|
20872
21629
|
row.append(meta);
|
|
20873
|
-
const body =
|
|
21630
|
+
const body = el2(doc, "div", "knobs-wt-n-body");
|
|
20874
21631
|
if (n.text)
|
|
20875
|
-
body.append(
|
|
21632
|
+
body.append(prose2(doc, "p", "knobs-wt-n-text", n.text));
|
|
20876
21633
|
if (n.voice) {
|
|
20877
|
-
const a =
|
|
21634
|
+
const a = el2(doc, "audio", "knobs-wt-n-voice");
|
|
20878
21635
|
a.controls = true;
|
|
20879
21636
|
a.preload = "none";
|
|
20880
21637
|
a.src = n.voice.url;
|
|
@@ -20894,7 +21651,7 @@ function walkthrough(container, options) {
|
|
|
20894
21651
|
body.append(thumb);
|
|
20895
21652
|
}
|
|
20896
21653
|
row.append(body);
|
|
20897
|
-
const x =
|
|
21654
|
+
const x = el2(doc, "button", "knobs-wt-x");
|
|
20898
21655
|
x.type = "button";
|
|
20899
21656
|
x.innerHTML = ICON.close;
|
|
20900
21657
|
x.setAttribute("aria-label", "Delete this note");
|
|
@@ -20948,22 +21705,22 @@ function walkthrough(container, options) {
|
|
|
20948
21705
|
pillPlaced = false;
|
|
20949
21706
|
root.textContent = "";
|
|
20950
21707
|
root.removeAttribute("data-settled");
|
|
20951
|
-
const layout =
|
|
20952
|
-
const main =
|
|
20953
|
-
const head =
|
|
20954
|
-
const h1 =
|
|
21708
|
+
const layout = el2(doc, "div", "knobs-wt-layout");
|
|
21709
|
+
const main = el2(doc, "div", "knobs-wt-main");
|
|
21710
|
+
const head = el2(doc, "header", "knobs-wt-head");
|
|
21711
|
+
const h1 = el2(doc, "h1", "knobs-wt-title");
|
|
20955
21712
|
h1.textContent = page.title;
|
|
20956
21713
|
head.append(h1);
|
|
20957
21714
|
if (page.summary)
|
|
20958
|
-
head.append(
|
|
21715
|
+
head.append(prose2(doc, "p", "knobs-wt-summary", page.summary));
|
|
20959
21716
|
if (page.meta.length) {
|
|
20960
|
-
const meta =
|
|
21717
|
+
const meta = el2(doc, "div", "knobs-wt-meta");
|
|
20961
21718
|
for (const m of page.meta) {
|
|
20962
|
-
const s =
|
|
21719
|
+
const s = el2(doc, "span");
|
|
20963
21720
|
s.append(m.label);
|
|
20964
|
-
const b =
|
|
21721
|
+
const b = el2(doc, "b");
|
|
20965
21722
|
if (m.href) {
|
|
20966
|
-
const a =
|
|
21723
|
+
const a = el2(doc, "a");
|
|
20967
21724
|
a.href = m.href;
|
|
20968
21725
|
a.target = "_blank";
|
|
20969
21726
|
a.rel = "noreferrer";
|
|
@@ -20978,27 +21735,27 @@ function walkthrough(container, options) {
|
|
|
20978
21735
|
}
|
|
20979
21736
|
main.append(head);
|
|
20980
21737
|
if (page.feed.length) {
|
|
20981
|
-
const feed =
|
|
21738
|
+
const feed = el2(doc, "section", "knobs-wt-feed");
|
|
20982
21739
|
feed.setAttribute("aria-label", "Latest");
|
|
20983
|
-
const list =
|
|
21740
|
+
const list = el2(doc, "ol", "knobs-wt-feed-list knobs-scroll-fade");
|
|
20984
21741
|
const now = Date.now();
|
|
20985
21742
|
for (const f of page.feed) {
|
|
20986
|
-
const li =
|
|
21743
|
+
const li = el2(doc, "li", "knobs-wt-fi");
|
|
20987
21744
|
li.dataset.kind = f.kind;
|
|
20988
|
-
const when =
|
|
21745
|
+
const when = el2(doc, "span", "knobs-wt-fi-when");
|
|
20989
21746
|
when.textContent = f.at === null ? "" : ago(f.at, now);
|
|
20990
21747
|
if (f.at !== null)
|
|
20991
21748
|
when.title = new Date(f.at).toLocaleString();
|
|
20992
|
-
const kind =
|
|
21749
|
+
const kind = el2(doc, "span", "knobs-wt-fi-kind");
|
|
20993
21750
|
kind.textContent = f.kind === "qa" ? "Answer" : "Update";
|
|
20994
|
-
const body =
|
|
21751
|
+
const body = el2(doc, "div", "knobs-wt-fi-body");
|
|
20995
21752
|
if (f.q)
|
|
20996
|
-
body.append(
|
|
20997
|
-
body.append(
|
|
21753
|
+
body.append(prose2(doc, "p", "knobs-wt-fi-q", f.q));
|
|
21754
|
+
body.append(prose2(doc, "p", "knobs-wt-fi-text", f.text));
|
|
20998
21755
|
li.append(when, kind, body);
|
|
20999
21756
|
if (f.step) {
|
|
21000
21757
|
const target = f.step;
|
|
21001
|
-
const link =
|
|
21758
|
+
const link = el2(doc, "button", "knobs-wt-fi-step");
|
|
21002
21759
|
link.type = "button";
|
|
21003
21760
|
link.textContent = page.steps.find((s) => s.key === target)?.number ?? "";
|
|
21004
21761
|
link.title = "Go to the step";
|
|
@@ -21013,33 +21770,33 @@ function walkthrough(container, options) {
|
|
|
21013
21770
|
let rail = null;
|
|
21014
21771
|
count = fill = tocEl = mark = null;
|
|
21015
21772
|
if (options.rail !== false) {
|
|
21016
|
-
rail =
|
|
21773
|
+
rail = el2(doc, "aside", "knobs-wt-rail");
|
|
21017
21774
|
rail.setAttribute("aria-label", "Progress");
|
|
21018
|
-
const progress =
|
|
21019
|
-
count =
|
|
21020
|
-
const meter =
|
|
21021
|
-
fill =
|
|
21775
|
+
const progress = el2(doc, "div", "knobs-wt-progress");
|
|
21776
|
+
count = el2(doc, "div", "knobs-wt-count");
|
|
21777
|
+
const meter = el2(doc, "div", "knobs-wt-bar");
|
|
21778
|
+
fill = el2(doc, "div", "knobs-wt-fill");
|
|
21022
21779
|
meter.append(fill);
|
|
21023
21780
|
progress.append(count, meter);
|
|
21024
|
-
tocEl =
|
|
21781
|
+
tocEl = el2(doc, "nav", "knobs-wt-toc");
|
|
21025
21782
|
tocEl.setAttribute("aria-label", "Contents");
|
|
21026
|
-
mark =
|
|
21783
|
+
mark = el2(doc, "div", "knobs-wt-toc-mark");
|
|
21027
21784
|
tocEl.append(mark);
|
|
21028
21785
|
rail.append(progress, tocEl, actions(true));
|
|
21029
21786
|
if (options.keys !== false) {
|
|
21030
|
-
const keys =
|
|
21787
|
+
const keys = el2(doc, "div", "knobs-wt-keys");
|
|
21031
21788
|
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" : "");
|
|
21032
21789
|
rail.append(keys);
|
|
21033
21790
|
}
|
|
21034
21791
|
}
|
|
21035
21792
|
for (const section of page.sections) {
|
|
21036
|
-
const sec =
|
|
21793
|
+
const sec = el2(doc, "section", "knobs-wt-section");
|
|
21037
21794
|
sec.id = `wt-${section.id}`;
|
|
21038
|
-
const sh =
|
|
21795
|
+
const sh = el2(doc, "header", "knobs-wt-shead");
|
|
21039
21796
|
if (section.link || section.status) {
|
|
21040
|
-
const kicker =
|
|
21797
|
+
const kicker = el2(doc, "div", "knobs-wt-kicker");
|
|
21041
21798
|
if (section.link) {
|
|
21042
|
-
const a =
|
|
21799
|
+
const a = el2(doc, "a");
|
|
21043
21800
|
a.href = section.link.href;
|
|
21044
21801
|
a.target = "_blank";
|
|
21045
21802
|
a.rel = "noreferrer";
|
|
@@ -21048,21 +21805,21 @@ function walkthrough(container, options) {
|
|
|
21048
21805
|
}
|
|
21049
21806
|
if (section.status) {
|
|
21050
21807
|
const s = statusLook(section.status);
|
|
21051
|
-
const chip =
|
|
21808
|
+
const chip = el2(doc, "span", "knobs-wt-chip");
|
|
21052
21809
|
chip.dataset.tone = s.tone;
|
|
21053
21810
|
chip.textContent = s.label;
|
|
21054
21811
|
kicker.append(chip);
|
|
21055
21812
|
}
|
|
21056
21813
|
sh.append(kicker);
|
|
21057
21814
|
}
|
|
21058
|
-
const h2 =
|
|
21815
|
+
const h2 = el2(doc, "h2", "knobs-wt-stitle");
|
|
21059
21816
|
h2.textContent = section.title;
|
|
21060
21817
|
sh.append(h2);
|
|
21061
21818
|
if (section.summary)
|
|
21062
|
-
sh.append(
|
|
21819
|
+
sh.append(prose2(doc, "p", "knobs-wt-ssum", section.summary));
|
|
21063
21820
|
sec.append(sh);
|
|
21064
21821
|
if (tocEl) {
|
|
21065
|
-
const t =
|
|
21822
|
+
const t = el2(doc, "div", "knobs-wt-toc-section");
|
|
21066
21823
|
t.textContent = section.link ? `${section.link.label} ${section.title}` : section.title;
|
|
21067
21824
|
t.title = section.title;
|
|
21068
21825
|
tocEl.append(t);
|
|
@@ -21095,9 +21852,9 @@ function walkthrough(container, options) {
|
|
|
21095
21852
|
}));
|
|
21096
21853
|
};
|
|
21097
21854
|
const actions = (rail) => {
|
|
21098
|
-
const row =
|
|
21855
|
+
const row = el2(doc, "div", "knobs-wt-actions");
|
|
21099
21856
|
const btn = (text, run, primary = false) => {
|
|
21100
|
-
const b =
|
|
21857
|
+
const b = el2(doc, "button", "knobs-wt-btn");
|
|
21101
21858
|
b.type = "button";
|
|
21102
21859
|
b.textContent = text;
|
|
21103
21860
|
if (primary)
|
|
@@ -21135,43 +21892,44 @@ function walkthrough(container, options) {
|
|
|
21135
21892
|
}
|
|
21136
21893
|
};
|
|
21137
21894
|
const stepView = (step) => {
|
|
21138
|
-
const card =
|
|
21895
|
+
const card = el2(doc, "article", "knobs-wt-step knobs-surface");
|
|
21139
21896
|
card.id = `wt-${step.key.replace("/", "--")}`;
|
|
21140
21897
|
card.tabIndex = -1;
|
|
21141
21898
|
card.dataset.key = step.key;
|
|
21142
21899
|
card.setAttribute("aria-label", `${step.number} ${step.title}`);
|
|
21143
|
-
const head =
|
|
21144
|
-
const num =
|
|
21900
|
+
const head = el2(doc, "header", "knobs-wt-step-head");
|
|
21901
|
+
const num = el2(doc, "span", "knobs-wt-num");
|
|
21145
21902
|
num.textContent = step.number;
|
|
21146
|
-
const h3 =
|
|
21903
|
+
const h3 = el2(doc, "h3", "knobs-wt-stepTitle");
|
|
21147
21904
|
h3.textContent = step.title;
|
|
21148
21905
|
head.append(num, h3);
|
|
21149
21906
|
card.append(head);
|
|
21150
21907
|
if (step.caption)
|
|
21151
|
-
card.append(
|
|
21908
|
+
card.append(prose2(doc, "p", "knobs-wt-caption", step.caption));
|
|
21152
21909
|
const slots = [];
|
|
21153
21910
|
const onEvent = (e) => record({ ...e, step: step.key });
|
|
21154
21911
|
let media = null;
|
|
21155
21912
|
if (step.media.length) {
|
|
21156
|
-
media =
|
|
21913
|
+
media = el2(doc, "div", "knobs-wt-media");
|
|
21157
21914
|
media.style.setProperty("--kw-n", String(Math.min(step.media.length, 3)));
|
|
21158
21915
|
for (const m of step.media)
|
|
21159
|
-
slots.push(mediaSlot(media, { ...look, media: m, onEvent }));
|
|
21916
|
+
slots.push(mediaSlot(media, { ...look, media: m, onEvent, steps: stepLinks }));
|
|
21160
21917
|
card.append(media);
|
|
21161
21918
|
}
|
|
21162
21919
|
let taste = null;
|
|
21163
21920
|
if (step.question)
|
|
21164
|
-
card.append(
|
|
21921
|
+
card.append(prose2(doc, "p", "knobs-wt-question", step.question));
|
|
21165
21922
|
if (step.ask === "pick") {
|
|
21166
21923
|
taste = tasteTest(card, {
|
|
21167
21924
|
...look,
|
|
21168
21925
|
options: step.options,
|
|
21169
21926
|
picked: state.steps[step.key]?.pick ?? null,
|
|
21170
|
-
onPick: (id) => pick(step.key, id)
|
|
21927
|
+
onPick: (id) => pick(step.key, id),
|
|
21928
|
+
steps: stepLinks
|
|
21171
21929
|
});
|
|
21172
21930
|
media ??= taste.element;
|
|
21173
21931
|
}
|
|
21174
|
-
const notes =
|
|
21932
|
+
const notes = el2(doc, "div", "knobs-wt-notes");
|
|
21175
21933
|
card.append(notes);
|
|
21176
21934
|
card.addEventListener("focusin", () => {
|
|
21177
21935
|
if (scroll.to)
|
|
@@ -21182,10 +21940,10 @@ function walkthrough(container, options) {
|
|
|
21182
21940
|
let toc = null;
|
|
21183
21941
|
let glyph = null;
|
|
21184
21942
|
if (tocEl) {
|
|
21185
|
-
toc =
|
|
21943
|
+
toc = el2(doc, "button", "knobs-wt-toc-step");
|
|
21186
21944
|
toc.type = "button";
|
|
21187
|
-
glyph =
|
|
21188
|
-
const label =
|
|
21945
|
+
glyph = el2(doc, "span", "knobs-wt-toc-glyph");
|
|
21946
|
+
const label = el2(doc, "span", "knobs-wt-toc-label");
|
|
21189
21947
|
label.textContent = step.title;
|
|
21190
21948
|
toc.title = `${step.number} ${step.title}`;
|
|
21191
21949
|
toc.append(glyph, label);
|
|
@@ -21445,6 +22203,7 @@ export {
|
|
|
21445
22203
|
solve2 as solveSplit,
|
|
21446
22204
|
split,
|
|
21447
22205
|
splitPath,
|
|
22206
|
+
stackLayout,
|
|
21448
22207
|
stackRows,
|
|
21449
22208
|
stepFile,
|
|
21450
22209
|
stepItem,
|