@rasensio/aidlc 1.77.0 → 1.79.0
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 +7 -3
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/menu.d.ts +5 -8
- package/dist/commands/menu.d.ts.map +1 -1
- package/dist/commands/menu.js +12 -13
- package/dist/commands/menu.js.map +1 -1
- package/dist/commands/status.d.ts +9 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +24 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/console/autopilot-view.d.ts +50 -0
- package/dist/console/autopilot-view.d.ts.map +1 -0
- package/dist/console/autopilot-view.js +99 -0
- package/dist/console/autopilot-view.js.map +1 -0
- package/dist/console/harness.d.ts +84 -0
- package/dist/console/harness.d.ts.map +1 -0
- package/dist/console/harness.js +191 -0
- package/dist/console/harness.js.map +1 -0
- package/dist/console/index.d.ts +28 -0
- package/dist/console/index.d.ts.map +1 -0
- package/dist/console/index.js +154 -0
- package/dist/console/index.js.map +1 -0
- package/dist/console/route.d.ts +45 -0
- package/dist/console/route.d.ts.map +1 -0
- package/dist/console/route.js +118 -0
- package/dist/console/route.js.map +1 -0
- package/dist/console/session.d.ts +92 -0
- package/dist/console/session.d.ts.map +1 -0
- package/dist/console/session.js +337 -0
- package/dist/console/session.js.map +1 -0
- package/dist/console/standing.d.ts +44 -0
- package/dist/console/standing.d.ts.map +1 -0
- package/dist/console/standing.js +96 -0
- package/dist/console/standing.js.map +1 -0
- package/dist/console/terminal.d.ts +31 -0
- package/dist/console/terminal.d.ts.map +1 -0
- package/dist/console/terminal.js +216 -0
- package/dist/console/terminal.js.map +1 -0
- package/dist/menu/index.d.ts +7 -24
- package/dist/menu/index.d.ts.map +1 -1
- package/dist/menu/index.js +6 -86
- package/dist/menu/index.js.map +1 -1
- package/dist/roadmap/graph.d.ts +53 -3
- package/dist/roadmap/graph.d.ts.map +1 -1
- package/dist/roadmap/graph.js +126 -54
- package/dist/roadmap/graph.js.map +1 -1
- package/dist/roadmap/view-assets.d.ts +5 -0
- package/dist/roadmap/view-assets.d.ts.map +1 -1
- package/dist/roadmap/view-assets.js +302 -91
- package/dist/roadmap/view-assets.js.map +1 -1
- package/dist/roadmap/view-html.d.ts +11 -1
- package/dist/roadmap/view-html.d.ts.map +1 -1
- package/dist/roadmap/view-html.js +166 -35
- package/dist/roadmap/view-html.js.map +1 -1
- package/dist/roadmap/view-model.js +1 -1
- package/dist/roadmap/view-model.js.map +1 -1
- package/package.json +2 -2
|
@@ -11,84 +11,136 @@
|
|
|
11
11
|
* plain ES2020 without template literals so `String.raw` can hold it unescaped; a test
|
|
12
12
|
* fails it if it grows past 16 KB or ever contains `</script`.
|
|
13
13
|
*
|
|
14
|
+
* roadmap-view-revamp added the tabs, per-tab filters kept in the URL hash, the theme,
|
|
15
|
+
* shortcuts and copy buttons. Visibility is still CSS: the script sets classes and
|
|
16
|
+
* attributes, the stylesheet hides. Every colour is a token on `:root` and
|
|
17
|
+
* `:root[data-theme="dark"]`, which the contrast test reads (roadmap-view-revamp/AC-24).
|
|
18
|
+
*
|
|
14
19
|
* @module
|
|
15
20
|
*/
|
|
16
21
|
export const VIEW_STYLE = String.raw `
|
|
17
|
-
:root { color-scheme: light; --
|
|
22
|
+
:root { color-scheme: light; --bg: #ffffff; --bg-2: #f6f7f9; --card: #ffffff; --ink: #1b1d22; --muted: #5b616e; --line: #e1e4e8; --line-2: #c4c9d1;
|
|
23
|
+
--link: #3e4ab8; --accent-ink: #3e4ab8; --chip-on: #e8eafb; --focus: #5e6ad2; --unmet: #c9252d; --shade: rgba(15, 17, 20, .12);
|
|
24
|
+
--st-inbox: #6b7280; --st-backlog: #6b7280; --st-in-progress: #b06d0b; --st-done: #5e6ad2; --st-hold: #6b7280;
|
|
25
|
+
--ready-bg: #e2f4e7; --ready-ink: #17643a; --blocked-bg: #fde7e7; --blocked-ink: #ae1f28; }
|
|
26
|
+
:root[data-theme="dark"] { color-scheme: dark; --bg: #101113; --bg-2: #16171a; --card: #1c1d21; --ink: #e8e9ec; --muted: #a0a5ae; --line: #2c2e34; --line-2: #464a53;
|
|
27
|
+
--link: #a9b0f6; --accent-ink: #a9b0f6; --chip-on: #2b2e4c; --focus: #8f98f4; --unmet: #ff6b6b; --shade: rgba(0, 0, 0, .5);
|
|
28
|
+
--st-inbox: #9aa0aa; --st-backlog: #9aa0aa; --st-in-progress: #e3a33b; --st-done: #8f98f4; --st-hold: #9aa0aa;
|
|
29
|
+
--ready-bg: #12301f; --ready-ink: #74dc9e; --blocked-bg: #3b1719; --blocked-ink: #ff9d9d; }
|
|
18
30
|
* { box-sizing: border-box; }
|
|
19
|
-
body { margin: 0; color: var(--ink); background:
|
|
31
|
+
body { margin: 0; color: var(--ink); background: var(--bg); font: .875rem/1.5 Inter, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; }
|
|
20
32
|
[hidden] { display: none !important; }
|
|
21
33
|
a { color: var(--link); }
|
|
22
|
-
code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
.
|
|
30
|
-
.
|
|
31
|
-
|
|
32
|
-
.
|
|
33
|
-
.
|
|
34
|
-
|
|
35
|
-
.
|
|
36
|
-
.
|
|
37
|
-
.
|
|
38
|
-
.
|
|
39
|
-
.
|
|
40
|
-
.
|
|
41
|
-
.
|
|
42
|
-
.
|
|
43
|
-
.
|
|
34
|
+
code, kbd { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .8125rem; }
|
|
35
|
+
kbd { padding: 0 .3rem; border: 1px solid var(--line-2); border-radius: .25rem; background: var(--bg-2); }
|
|
36
|
+
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
|
|
37
|
+
button { font: inherit; color: var(--ink); background: var(--bg); border: 1px solid var(--line); border-radius: .375rem; padding: .2rem .6rem; min-height: 1.75rem; min-width: 1.75rem; cursor: pointer; }
|
|
38
|
+
button:hover { border-color: var(--line-2); }
|
|
39
|
+
button[aria-pressed="true"] { background: var(--chip-on); border-color: var(--focus); }
|
|
40
|
+
@media (pointer: coarse) { button, .search input { min-height: 2.75rem; min-width: 2.75rem; } }
|
|
41
|
+
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
|
|
42
|
+
header.top { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1.5rem; padding: .75rem 1.5rem; border-bottom: 1px solid var(--line); }
|
|
43
|
+
h1 { margin: 0; font-size: 1rem; font-weight: 600; }
|
|
44
|
+
.generated, .search, .search-status, .keys { margin: 0; color: var(--muted); }
|
|
45
|
+
.search input { font: inherit; color: var(--ink); background: var(--bg); padding: .2rem .6rem; min-height: 1.75rem; min-width: 16rem; border: 1px solid var(--line-2); border-radius: .375rem; }
|
|
46
|
+
#theme { margin-left: auto; }
|
|
47
|
+
.tabs { display: flex; gap: .25rem; padding: 0 1.5rem; border-bottom: 1px solid var(--line); }
|
|
48
|
+
.tabs [role="tab"] { border: 0; border-bottom: 2px solid transparent; border-radius: 0; background: none; padding: .5rem .75rem; color: var(--muted); font-weight: 500; }
|
|
49
|
+
.tabs [role="tab"][aria-selected="true"] { color: var(--ink); border-bottom-color: var(--focus); }
|
|
50
|
+
.n { color: var(--muted); font-weight: 400; margin-left: .25rem; }
|
|
51
|
+
.view { padding: .75rem 1.5rem 0; }
|
|
52
|
+
.filters { display: flex; flex-wrap: wrap; gap: .5rem 1.25rem; margin-bottom: .75rem; }
|
|
53
|
+
.group { display: flex; flex-wrap: wrap; gap: .25rem; }
|
|
54
|
+
.chip, .preset, .only, #open-chains { border-radius: 999px; font-size: .8125rem; }
|
|
55
|
+
.ring { display: inline-block; position: relative; width: .75rem; height: .75rem; margin-right: .4rem; vertical-align: -.1rem; border: 1.5px solid var(--rc); border-radius: 50%; flex: none; }
|
|
56
|
+
.r-inbox { --rc: var(--st-inbox); border-style: dashed; }
|
|
57
|
+
.r-backlog { --rc: var(--st-backlog); }
|
|
58
|
+
.r-in-progress { --rc: var(--st-in-progress); background: linear-gradient(90deg, var(--rc) 50%, transparent 50%); }
|
|
59
|
+
.r-done { --rc: var(--st-done); background: var(--rc); }
|
|
60
|
+
.r-done::after { content: ""; position: absolute; left: .19rem; top: .06rem; width: .15rem; height: .3rem; border: solid var(--bg); border-width: 0 1.5px 1.5px 0; transform: rotate(45deg); }
|
|
61
|
+
.r-hold { --rc: var(--st-hold); }
|
|
62
|
+
.r-hold::after { content: ""; position: absolute; left: .15rem; right: .15rem; top: calc(50% - .75px); height: 1.5px; background: var(--rc); }
|
|
63
|
+
.board { display: flex; gap: .75rem; overflow-x: auto; align-items: flex-start; padding-bottom: 1rem; }
|
|
64
|
+
.col { flex: 1 1 16rem; min-width: 16rem; }
|
|
65
|
+
.col > .rail, .col.off > .body { display: none; }
|
|
66
|
+
.col.off { flex: 0 0 2.75rem; min-width: 2.75rem; }
|
|
67
|
+
.col.off > .rail { display: flex; align-items: center; gap: .4rem; width: 2.75rem; min-height: 14rem; padding: .6rem 0; writing-mode: vertical-rl; background: var(--bg-2); color: var(--muted); }
|
|
68
|
+
.col h3 { display: flex; align-items: center; margin: 0 0 .5rem; padding: .25rem .25rem; font-size: .8125rem; font-weight: 600; }
|
|
69
|
+
.count { font-weight: 400; color: var(--muted); margin-left: .4rem; }
|
|
70
|
+
.cards { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .375rem; }
|
|
71
|
+
.card { background: var(--card); border: 1px solid var(--line); border-radius: .375rem; padding: .5rem .625rem; cursor: pointer; }
|
|
72
|
+
.card:hover { border-color: var(--line-2); box-shadow: 0 1px 2px var(--shade); }
|
|
73
|
+
.card p { margin: .2rem 0 0; }
|
|
74
|
+
.card .title { display: flex; align-items: baseline; margin: 0; }
|
|
75
|
+
.card .open { border: 0; background: none; padding: 0; min-height: 0; text-align: left; font-weight: 500; line-height: 1.4; }
|
|
76
|
+
.rank { color: var(--muted); font-weight: 600; }
|
|
77
|
+
.badge { display: inline-block; margin-right: .35rem; padding: 0 .45rem; border-radius: 999px; font-size: .75rem; font-weight: 600; }
|
|
78
|
+
.badge.ready { background: var(--ready-bg); color: var(--ready-ink); }
|
|
79
|
+
.badge.blocked { background: var(--blocked-bg); color: var(--blocked-ink); }
|
|
80
|
+
.age, .links, .hold { font-size: .75rem; }
|
|
81
|
+
.age, .hold { color: var(--muted); }
|
|
44
82
|
.board:not(.searching) .col:not(.expanded) .capped { display: none; }
|
|
45
|
-
.show-all { margin: .5rem
|
|
46
|
-
.
|
|
47
|
-
.
|
|
48
|
-
.
|
|
49
|
-
|
|
50
|
-
.
|
|
51
|
-
.map-controls, .legend, .empty { margin: 0 1.5rem .75rem; }
|
|
52
|
-
.map-controls button { margin-right: .5rem; }
|
|
53
|
-
.sw { display: inline-block; width: .9rem; height: .9rem; margin: 0 .3rem 0 .9rem; border: 1.5px solid; border-radius: .2rem; vertical-align: -.1rem; }
|
|
54
|
-
.sw.missing { background: #fee2e2; border-color: #dc2626; border-style: dashed; }
|
|
55
|
-
.map-wrap { padding: 0 1.5rem; }
|
|
56
|
-
#map { display: block; width: 100%; height: 70vh; border: 1px solid var(--line); border-radius: .5rem; background: #fff; touch-action: none; cursor: grab; }
|
|
57
|
-
#map text { fill: var(--ink); font-size: 13px; }
|
|
58
|
-
#map .sub { fill: var(--muted); font-size: 11px; }
|
|
83
|
+
.show-all { margin: .5rem 0; }
|
|
84
|
+
.map-controls, .legend, .empty { margin: 0 0 .5rem; }
|
|
85
|
+
.legend { color: var(--muted); font-size: .8125rem; }
|
|
86
|
+
#map { display: block; width: 100%; height: calc(100vh - 12.5rem); min-height: 24rem; border: 1px solid var(--line); border-radius: .5rem; background: var(--bg-2); touch-action: none; cursor: grab; }
|
|
87
|
+
#map text { fill: var(--ink); font-size: 14px; }
|
|
88
|
+
#map .sub, #map .clabel { fill: var(--muted); font-size: 12px; }
|
|
59
89
|
#map .node { cursor: pointer; }
|
|
60
|
-
#map .node rect { stroke-width: 1.5; }
|
|
90
|
+
#map .node rect { fill: var(--card); stroke: var(--line-2); stroke-width: 1.5; }
|
|
61
91
|
#map .node:focus { outline: none; }
|
|
62
92
|
#map .node:focus-visible rect, #map .toggle:focus-visible circle { stroke: var(--focus); stroke-width: 3; }
|
|
63
|
-
#map .s-inbox rect {
|
|
64
|
-
#map .s-
|
|
65
|
-
#map .s-
|
|
66
|
-
#map .
|
|
67
|
-
#map .
|
|
68
|
-
#map .
|
|
69
|
-
#map .edge {
|
|
70
|
-
#map .edge.dashed { stroke-dasharray: 6 4; }
|
|
93
|
+
#map .s-inbox rect { stroke: var(--st-inbox); stroke-dasharray: 4 3; }
|
|
94
|
+
#map .s-in-progress rect { stroke: var(--st-in-progress); }
|
|
95
|
+
#map .s-done rect { stroke: var(--st-done); }
|
|
96
|
+
#map .missing rect { fill: var(--blocked-bg); stroke: var(--unmet); stroke-dasharray: 6 3; }
|
|
97
|
+
#map .edge { fill: none; stroke: var(--st-hold); stroke-width: 1.5; }
|
|
98
|
+
#map .edge.further { stroke-dasharray: 2 4; }
|
|
99
|
+
#map .edge.unmet { stroke: var(--unmet); stroke-dasharray: 6 4; }
|
|
71
100
|
#map .toggle { cursor: pointer; }
|
|
72
|
-
#map .toggle circle { fill:
|
|
101
|
+
#map .toggle circle { fill: var(--card); stroke: var(--muted); stroke-width: 1.5; }
|
|
73
102
|
#map .toggle text { text-anchor: middle; font-weight: 700; font-size: 15px; }
|
|
74
103
|
#map .off { display: none; }
|
|
75
|
-
#map
|
|
76
|
-
#map.focus .
|
|
104
|
+
#map .dim { opacity: .25; }
|
|
105
|
+
#map.focus .node:not(.hl) { opacity: .25; }
|
|
106
|
+
#map.focus .edge:not(.hl) { opacity: .12; }
|
|
77
107
|
#map .node.hl rect { stroke-width: 3; }
|
|
78
|
-
#map .edge.hl { stroke
|
|
79
|
-
.panel { position: fixed; top: 0; right: 0; bottom: 0; width: min(34rem, 100%); overflow-y: auto; padding: 1rem 1.25rem; background:
|
|
80
|
-
.panel h2 { margin: .25rem 3rem .5rem 0; font-size:
|
|
81
|
-
.panel h3 { margin: 1rem 0 .35rem; font-size:
|
|
108
|
+
#map .edge.hl { stroke-width: 2.5; opacity: 1; }
|
|
109
|
+
.panel { position: fixed; top: 0; right: 0; bottom: 0; width: min(34rem, 100%); overflow-y: auto; padding: 1rem 1.25rem; color: var(--ink); background: var(--bg); border-left: 1px solid var(--line); box-shadow: -4px 0 16px var(--shade); }
|
|
110
|
+
.panel h2 { margin: .25rem 3rem .5rem 0; font-size: 1rem; font-weight: 600; }
|
|
111
|
+
.panel h3 { margin: 1rem 0 .35rem; font-size: .8125rem; font-weight: 600; color: var(--muted); }
|
|
112
|
+
.panel .meta { display: flex; align-items: center; flex-wrap: wrap; gap: .25rem; color: var(--muted); }
|
|
82
113
|
.panel .close { float: right; }
|
|
83
|
-
|
|
114
|
+
.cmds { list-style: none; margin: 0; padding: 0; display: grid; gap: .4rem; }
|
|
115
|
+
.cmds li { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .5rem; }
|
|
116
|
+
.cmd-label { flex-basis: 100%; color: var(--muted); font-size: .75rem; }
|
|
117
|
+
.cmds code { flex: 1; padding: .2rem .45rem; border-radius: .25rem; background: var(--bg-2); overflow-wrap: anywhere; }
|
|
118
|
+
.keys { padding: 1rem 1.5rem 0; font-size: .75rem; }
|
|
119
|
+
footer { margin-top: 1rem; padding: .75rem 1.5rem; border-top: 1px solid var(--line); color: var(--muted); font-size: .75rem; }
|
|
84
120
|
`;
|
|
85
121
|
export const VIEW_SCRIPT = String.raw `
|
|
86
122
|
(function () {
|
|
87
123
|
'use strict';
|
|
88
124
|
var doc = document;
|
|
89
|
-
|
|
90
|
-
function
|
|
125
|
+
var root = doc.documentElement;
|
|
126
|
+
function one(sel, r) { return (r || doc).querySelector(sel); }
|
|
127
|
+
function all(sel, r) { return Array.prototype.slice.call((r || doc).querySelectorAll(sel)); }
|
|
91
128
|
function refs(el, name) { var v = el ? el.getAttribute(name) : ''; return v ? v.split(' ') : []; }
|
|
129
|
+
function attr(el, name, v) { el.setAttribute(name, String(v)); }
|
|
130
|
+
|
|
131
|
+
// The theme lives in the browser, so regenerating the page keeps it; storage may throw.
|
|
132
|
+
var KEY = 'aidlc-roadmap-theme';
|
|
133
|
+
var themeBtn = one('#theme');
|
|
134
|
+
function setTheme(dark) {
|
|
135
|
+
if (dark) root.setAttribute('data-theme', 'dark'); else root.removeAttribute('data-theme');
|
|
136
|
+
attr(themeBtn, 'aria-pressed', dark);
|
|
137
|
+
}
|
|
138
|
+
try { setTheme(localStorage.getItem(KEY) === 'dark'); } catch (e) { setTheme(false); }
|
|
139
|
+
themeBtn.addEventListener('click', function () {
|
|
140
|
+
var dark = root.getAttribute('data-theme') !== 'dark';
|
|
141
|
+
setTheme(dark);
|
|
142
|
+
try { localStorage.setItem(KEY, dark ? 'dark' : 'light'); } catch (e) { /* this visit only */ }
|
|
143
|
+
});
|
|
92
144
|
|
|
93
145
|
// Ages are worked out here, not by the generator, so the file's bytes do not change from
|
|
94
146
|
// one day to the next.
|
|
@@ -102,21 +154,135 @@ export const VIEW_SCRIPT = String.raw `
|
|
|
102
154
|
t.setAttribute('title', 'created ' + t.getAttribute('datetime'));
|
|
103
155
|
});
|
|
104
156
|
|
|
105
|
-
|
|
157
|
+
// View state. Each tab keeps its own filters; all of it round-trips through the hash.
|
|
158
|
+
var ALL = ['inbox', 'backlog', 'in-progress', 'done', 'hold'];
|
|
159
|
+
var ONLY = ['ready', 'blocked'];
|
|
160
|
+
var S = { tab: 'board', open: true, board: { s: ALL.slice(0, 3), o: [] }, deps: { s: ALL.slice(), o: [] } };
|
|
161
|
+
function listOf(v, known) {
|
|
162
|
+
if (v === '') return [];
|
|
163
|
+
var out = v.split('.');
|
|
164
|
+
for (var i = 0; i < out.length; i++) if (known.indexOf(out[i]) < 0) return null;
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
// The hash is untrusted: it is only ever compared against the constants above.
|
|
168
|
+
function readHash() {
|
|
169
|
+
location.hash.replace(/^#/, '').split('&').forEach(function (part) {
|
|
170
|
+
var at = part.indexOf('=');
|
|
171
|
+
if (at < 0) return;
|
|
172
|
+
var k = part.slice(0, at), v = part.slice(at + 1), list;
|
|
173
|
+
if (k === 'tab' && (v === 'board' || v === 'deps')) S.tab = v;
|
|
174
|
+
else if (k === 'open' && (v === '0' || v === '1')) S.open = v === '1';
|
|
175
|
+
else if (k === 'board' || k === 'deps') { list = listOf(v, ALL); if (list) S[k].s = list; }
|
|
176
|
+
else if (k === 'board-only' || k === 'deps-only') { list = listOf(v, ONLY); if (list) S[k.slice(0, -5)].o = list; }
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
var live = false;
|
|
180
|
+
function writeHash() {
|
|
181
|
+
if (!live) return;
|
|
182
|
+
var h = 'tab=' + S.tab + '&board=' + S.board.s.join('.') + '&board-only=' + S.board.o.join('.') +
|
|
183
|
+
'&deps=' + S.deps.s.join('.') + '&deps-only=' + S.deps.o.join('.') + '&open=' + (S.open ? 1 : 0);
|
|
184
|
+
try { history.replaceState(null, '', '#' + h); } catch (e) { /* the view still works */ }
|
|
185
|
+
}
|
|
186
|
+
function toggled(list, v, order) {
|
|
187
|
+
var on = list.indexOf(v) < 0;
|
|
188
|
+
return order.filter(function (x) { return x === v ? on : list.indexOf(x) >= 0; });
|
|
189
|
+
}
|
|
190
|
+
function same(a, b) { return a.length === b.length && a.every(function (x) { return b.indexOf(x) >= 0; }); }
|
|
191
|
+
|
|
106
192
|
var search = one('#q');
|
|
107
|
-
var
|
|
108
|
-
function
|
|
109
|
-
var
|
|
193
|
+
var q = '';
|
|
194
|
+
function match(el, f) {
|
|
195
|
+
var st = el.getAttribute('data-status');
|
|
196
|
+
if (st !== 'missing' && f.s.indexOf(st) < 0) return false;
|
|
197
|
+
if (f.o.length && !f.o.some(function (o) { return el.classList.contains(o); })) return false;
|
|
198
|
+
return q === '' || el.getAttribute('data-search').indexOf(q) !== -1;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
var tabs = all('[role="tab"]');
|
|
202
|
+
var board = one('.board');
|
|
203
|
+
var svg = one('#map');
|
|
204
|
+
var viewport = one('#viewport', svg);
|
|
205
|
+
var unlinked = one('.unlinked', svg);
|
|
206
|
+
var openBtn = one('#open-chains');
|
|
207
|
+
function place(g) {
|
|
208
|
+
if (!g) return;
|
|
209
|
+
var p = g.getAttribute(S.open ? 'data-open' : 'data-all') || g.getAttribute('data-all');
|
|
210
|
+
g.setAttribute('transform', 'translate(' + p + ')');
|
|
211
|
+
}
|
|
212
|
+
function render() {
|
|
213
|
+
tabs.forEach(function (t) {
|
|
214
|
+
var on = t.getAttribute('data-tab') === S.tab;
|
|
215
|
+
attr(t, 'aria-selected', on);
|
|
216
|
+
attr(t, 'tabindex', on ? 0 : -1);
|
|
217
|
+
doc.getElementById(t.getAttribute('aria-controls')).hidden = !on;
|
|
218
|
+
});
|
|
219
|
+
all('.filters').forEach(function (bar) {
|
|
220
|
+
var f = S[bar.getAttribute('data-for')];
|
|
221
|
+
all('.chip', bar).forEach(function (c) { attr(c, 'aria-pressed', f.s.indexOf(c.getAttribute('data-status')) >= 0); });
|
|
222
|
+
all('.only', bar).forEach(function (c) { attr(c, 'aria-pressed', f.o.indexOf(c.getAttribute('data-only')) >= 0); });
|
|
223
|
+
all('.preset', bar).forEach(function (c) { attr(c, 'aria-pressed', !f.o.length && same(refs(c, 'data-set'), f.s)); });
|
|
224
|
+
});
|
|
225
|
+
all('.col').forEach(function (c) { c.classList.toggle('off', S.board.s.indexOf(c.getAttribute('data-status')) < 0); });
|
|
226
|
+
var shown = 0, lit = 0, inDeps = 0, dim = {};
|
|
227
|
+
all('.card').forEach(function (c) { var m = match(c, S.board); c.hidden = !m; if (m) shown++; });
|
|
110
228
|
board.classList.toggle('searching', q !== '');
|
|
111
|
-
|
|
112
|
-
all('.
|
|
113
|
-
var
|
|
114
|
-
|
|
115
|
-
|
|
229
|
+
if (openBtn) attr(openBtn, 'aria-pressed', S.open);
|
|
230
|
+
all('.cluster', svg).forEach(function (c) {
|
|
231
|
+
var off = S.open && c.classList.contains('closed');
|
|
232
|
+
c.classList.toggle('off', off);
|
|
233
|
+
place(c);
|
|
234
|
+
if (!off) inDeps += +c.getAttribute('data-n');
|
|
235
|
+
});
|
|
236
|
+
place(unlinked);
|
|
237
|
+
all('.node', svg).forEach(function (n) {
|
|
238
|
+
var d = !match(n, S.deps);
|
|
239
|
+
n.classList.toggle('dim', d);
|
|
240
|
+
if (d) dim[n.getAttribute('data-ref')] = 1; else if (!n.closest('.off')) lit++;
|
|
116
241
|
});
|
|
117
|
-
|
|
242
|
+
all('.edge', svg).forEach(function (e) { e.classList.toggle('dim', !!(dim[e.getAttribute('data-from')] || dim[e.getAttribute('data-to')])); });
|
|
243
|
+
one('#n-board').textContent = shown;
|
|
244
|
+
one('#n-deps').textContent = inDeps;
|
|
245
|
+
var n = S.tab === 'board' ? shown : lit;
|
|
246
|
+
one('#search-status').textContent = q === '' ? '' : n === 1 ? '1 item matches' : n + ' items match';
|
|
247
|
+
writeHash();
|
|
118
248
|
}
|
|
119
|
-
|
|
249
|
+
|
|
250
|
+
var fitted = false;
|
|
251
|
+
function selectTab(name, focus) {
|
|
252
|
+
S.tab = name;
|
|
253
|
+
render();
|
|
254
|
+
if (name === 'deps' && !fitted) { fitted = true; fit(); }
|
|
255
|
+
if (focus) doc.getElementById('tab-' + name).focus();
|
|
256
|
+
}
|
|
257
|
+
tabs.forEach(function (t) {
|
|
258
|
+
t.addEventListener('click', function () { selectTab(t.getAttribute('data-tab')); });
|
|
259
|
+
t.addEventListener('keydown', function (e) {
|
|
260
|
+
if (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') return;
|
|
261
|
+
e.preventDefault();
|
|
262
|
+
selectTab(S.tab === 'board' ? 'deps' : 'board', true);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
all('.filters').forEach(function (bar) {
|
|
266
|
+
var f = S[bar.getAttribute('data-for')];
|
|
267
|
+
bar.addEventListener('click', function (e) {
|
|
268
|
+
var b = e.target.closest('button');
|
|
269
|
+
if (!b) return;
|
|
270
|
+
if (b.hasAttribute('data-status')) f.s = toggled(f.s, b.getAttribute('data-status'), ALL);
|
|
271
|
+
else if (b.hasAttribute('data-only')) f.o = toggled(f.o, b.getAttribute('data-only'), ONLY);
|
|
272
|
+
else if (b.hasAttribute('data-set')) { f.s = refs(b, 'data-set'); f.o = []; }
|
|
273
|
+
render();
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
// A rail brings its column back, so a hidden status is one click away.
|
|
277
|
+
all('.rail').forEach(function (r) {
|
|
278
|
+
r.addEventListener('click', function () {
|
|
279
|
+
var st = r.getAttribute('data-show');
|
|
280
|
+
if (S.board.s.indexOf(st) < 0) S.board.s = toggled(S.board.s, st, ALL);
|
|
281
|
+
render();
|
|
282
|
+
one('.filters[data-for="board"] .chip[data-status="' + st + '"]').focus();
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
search.addEventListener('input', function () { q = search.value.trim().toLowerCase(); render(); });
|
|
120
286
|
|
|
121
287
|
all('.show-all').forEach(function (btn) {
|
|
122
288
|
btn.addEventListener('click', function () {
|
|
@@ -131,11 +297,13 @@ export const VIEW_SCRIPT = String.raw `
|
|
|
131
297
|
var panel = one('#panel');
|
|
132
298
|
var panelBody = one('#panel-body');
|
|
133
299
|
var closeBtn = one('#panel-close');
|
|
300
|
+
var say = one('#live');
|
|
134
301
|
var opener = null;
|
|
135
302
|
function openPanel(ref, from) {
|
|
136
303
|
var tpl = doc.getElementById('detail-' + ref);
|
|
137
304
|
if (!tpl) return;
|
|
138
305
|
panelBody.replaceChildren(tpl.content.cloneNode(true));
|
|
306
|
+
say.textContent = '';
|
|
139
307
|
panel.hidden = false;
|
|
140
308
|
opener = from || null;
|
|
141
309
|
closeBtn.focus();
|
|
@@ -151,13 +319,31 @@ export const VIEW_SCRIPT = String.raw `
|
|
|
151
319
|
function gotoCard(ref) {
|
|
152
320
|
var card = doc.getElementById('card-' + ref);
|
|
153
321
|
if (!card) { openPanel(ref, null); return; }
|
|
154
|
-
|
|
322
|
+
var st = card.getAttribute('data-status');
|
|
323
|
+
if (S.board.s.indexOf(st) < 0) S.board.s = toggled(S.board.s, st, ALL);
|
|
324
|
+
if (!match(card, S.board)) { S.board.o = []; search.value = ''; q = ''; }
|
|
325
|
+
S.tab = 'board';
|
|
326
|
+
render();
|
|
155
327
|
var col = card.closest('.col');
|
|
156
328
|
if (card.classList.contains('capped') && !col.classList.contains('expanded')) one('.show-all', col).click();
|
|
157
329
|
if (card.scrollIntoView) card.scrollIntoView({ block: 'center' });
|
|
158
330
|
openPanel(ref, one('.open', card));
|
|
159
331
|
}
|
|
332
|
+
// The page runs nothing: it puts the command on the clipboard, or selects it to copy by hand.
|
|
333
|
+
function copy(btn) {
|
|
334
|
+
var code = doc.getElementById(btn.getAttribute('data-code'));
|
|
335
|
+
function byHand() {
|
|
336
|
+
var sel = window.getSelection ? window.getSelection() : null;
|
|
337
|
+
if (sel) sel.selectAllChildren(code);
|
|
338
|
+
say.textContent = 'Selected — press Ctrl+C or ⌘C to copy';
|
|
339
|
+
}
|
|
340
|
+
var cb = navigator.clipboard;
|
|
341
|
+
if (!cb || !cb.writeText) { byHand(); return; }
|
|
342
|
+
cb.writeText(btn.getAttribute('data-cmd')).then(function () { say.textContent = 'Copied'; }, byHand);
|
|
343
|
+
}
|
|
160
344
|
panelBody.addEventListener('click', function (e) {
|
|
345
|
+
var c = e.target.closest('.copy');
|
|
346
|
+
if (c) { copy(c); return; }
|
|
161
347
|
var a = e.target.closest('a[data-goto]');
|
|
162
348
|
if (!a) return;
|
|
163
349
|
e.preventDefault();
|
|
@@ -170,26 +356,49 @@ export const VIEW_SCRIPT = String.raw `
|
|
|
170
356
|
});
|
|
171
357
|
});
|
|
172
358
|
|
|
173
|
-
var
|
|
174
|
-
function
|
|
175
|
-
if (!svg) return;
|
|
359
|
+
var pinned = null;
|
|
360
|
+
function unlight() {
|
|
176
361
|
svg.classList.remove('focus');
|
|
177
362
|
all('.hl', svg).forEach(function (el) { el.classList.remove('hl'); });
|
|
178
363
|
}
|
|
364
|
+
function light(node) {
|
|
365
|
+
var lit = {};
|
|
366
|
+
lit[node.getAttribute('data-ref')] = true;
|
|
367
|
+
refs(node, 'data-chain').forEach(function (r) { lit[r] = true; });
|
|
368
|
+
svg.classList.add('focus');
|
|
369
|
+
all('.node', svg).forEach(function (n) { n.classList.toggle('hl', !!lit[n.getAttribute('data-ref')]); });
|
|
370
|
+
all('.edge', svg).forEach(function (ed) { ed.classList.toggle('hl', !!lit[ed.getAttribute('data-from')] && !!lit[ed.getAttribute('data-to')]); });
|
|
371
|
+
}
|
|
372
|
+
function clearFocus() { pinned = null; unlight(); }
|
|
373
|
+
function nodeOf(e) { return e.target.closest ? e.target.closest('.node') : null; }
|
|
374
|
+
function enter(e) { var n = nodeOf(e); if (n && !pinned) light(n); }
|
|
375
|
+
function leave(e) { var n = nodeOf(e); if (n && !pinned && !(e.relatedTarget && n.contains(e.relatedTarget))) unlight(); }
|
|
376
|
+
svg.addEventListener('mouseover', enter);
|
|
377
|
+
svg.addEventListener('focusin', enter);
|
|
378
|
+
svg.addEventListener('mouseout', leave);
|
|
379
|
+
svg.addEventListener('focusout', leave);
|
|
380
|
+
|
|
179
381
|
doc.addEventListener('keydown', function (e) {
|
|
180
|
-
if (e.
|
|
382
|
+
if (e.ctrlKey || e.metaKey || e.altKey) return;
|
|
383
|
+
if (e.key === 'Escape') {
|
|
384
|
+
if (!panel.hidden) closePanel();
|
|
385
|
+
else if (search.value !== '') { search.value = ''; q = ''; render(); }
|
|
386
|
+
clearFocus();
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
if (/^(INPUT|TEXTAREA|SELECT)$/.test(e.target.tagName || '')) return;
|
|
390
|
+
if (e.key === '/') { e.preventDefault(); search.focus(); }
|
|
391
|
+
else if (e.key === '1' || e.key === '2') selectTab(e.key === '1' ? 'board' : 'deps', true);
|
|
181
392
|
});
|
|
182
|
-
if (!svg) return;
|
|
183
393
|
|
|
184
|
-
var viewport = one('#viewport', svg);
|
|
185
|
-
var unlinked = one('.unlinked', svg);
|
|
186
394
|
var k = 1, tx = 0, ty = 0;
|
|
187
395
|
function r3(n) { return Math.round(n * 1000) / 1000; }
|
|
188
396
|
function apply() { viewport.setAttribute('transform', 'translate(' + r3(tx) + ' ' + r3(ty) + ') scale(' + r3(k) + ')'); }
|
|
189
397
|
function frame() { return { w: svg.clientWidth || 1000, h: svg.clientHeight || 600 }; }
|
|
190
398
|
function extent() {
|
|
191
399
|
var full = unlinked && !unlinked.classList.contains('off');
|
|
192
|
-
|
|
400
|
+
var pre = 'data-' + (S.open ? 'open' : 'all') + '-' + (full ? 'full' : 'linked') + '-';
|
|
401
|
+
return { w: +svg.getAttribute(pre + 'w'), h: +svg.getAttribute(pre + 'h') };
|
|
193
402
|
}
|
|
194
403
|
function fit() {
|
|
195
404
|
var f = frame(), s = extent();
|
|
@@ -242,19 +451,16 @@ export const VIEW_SCRIPT = String.raw `
|
|
|
242
451
|
svg.addEventListener('pointercancel', release);
|
|
243
452
|
svg.addEventListener('click', function (e) { if (!onControl(e) && !dragged) clearFocus(); });
|
|
244
453
|
|
|
454
|
+
// Node offsets are relative to their cluster, so centring adds the cluster's current place.
|
|
245
455
|
function activate(node) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
refs(node, 'data-chain').forEach(function (r) { lit[r] = true; });
|
|
250
|
-
svg.classList.add('focus');
|
|
251
|
-
all('.node', svg).forEach(function (n) { n.classList.toggle('hl', !!lit[n.getAttribute('data-ref')]); });
|
|
252
|
-
all('.edge', svg).forEach(function (ed) { ed.classList.toggle('hl', !!lit[ed.getAttribute('data-from')] && !!lit[ed.getAttribute('data-to')]); });
|
|
456
|
+
pinned = node;
|
|
457
|
+
light(node);
|
|
458
|
+
var m = /translate\(([-\d.]+) ([-\d.]+)\)/.exec(node.parentNode.getAttribute('transform') || '');
|
|
253
459
|
var f = frame();
|
|
254
|
-
tx = f.w / 2 - (+node.getAttribute('data-x') + +node.getAttribute('data-cx')) * k;
|
|
255
|
-
ty = f.h / 2 - (+node.getAttribute('data-y') + +node.getAttribute('data-cy')) * k;
|
|
460
|
+
tx = f.w / 2 - ((m ? +m[1] : 0) + +node.getAttribute('data-x') + +node.getAttribute('data-cx')) * k;
|
|
461
|
+
ty = f.h / 2 - ((m ? +m[2] : 0) + +node.getAttribute('data-y') + +node.getAttribute('data-cy')) * k;
|
|
256
462
|
apply();
|
|
257
|
-
openPanel(ref, node);
|
|
463
|
+
openPanel(node.getAttribute('data-ref'), node);
|
|
258
464
|
}
|
|
259
465
|
|
|
260
466
|
var collapsed = {};
|
|
@@ -263,7 +469,7 @@ export const VIEW_SCRIPT = String.raw `
|
|
|
263
469
|
Object.keys(collapsed).forEach(function (r) {
|
|
264
470
|
refs(doc.getElementById('node-' + r), 'data-sub').forEach(function (s) { hidden[s] = true; });
|
|
265
471
|
});
|
|
266
|
-
all('.
|
|
472
|
+
all('.cluster .node', svg).forEach(function (n) { n.classList.toggle('off', !!hidden[n.getAttribute('data-ref')]); });
|
|
267
473
|
all('.toggle', svg).forEach(function (t) { t.classList.toggle('off', !!hidden[t.getAttribute('data-toggle')]); });
|
|
268
474
|
all('.edge', svg).forEach(function (ed) { ed.classList.toggle('off', !!hidden[ed.getAttribute('data-from')] || !!hidden[ed.getAttribute('data-to')]); });
|
|
269
475
|
}
|
|
@@ -285,7 +491,7 @@ export const VIEW_SCRIPT = String.raw `
|
|
|
285
491
|
all('.toggle', svg).forEach(function (t) { onActivate(t, toggle); });
|
|
286
492
|
|
|
287
493
|
var unlinkedBtn = one('#unlinked-toggle');
|
|
288
|
-
if (unlinkedBtn
|
|
494
|
+
if (unlinkedBtn) {
|
|
289
495
|
unlinkedBtn.addEventListener('click', function () {
|
|
290
496
|
var show = unlinked.classList.contains('off');
|
|
291
497
|
unlinked.classList.toggle('off', !show);
|
|
@@ -294,8 +500,13 @@ export const VIEW_SCRIPT = String.raw `
|
|
|
294
500
|
fit();
|
|
295
501
|
});
|
|
296
502
|
}
|
|
503
|
+
if (openBtn) openBtn.addEventListener('click', function () { S.open = !S.open; render(); fit(); });
|
|
297
504
|
one('#fit').addEventListener('click', fit);
|
|
298
|
-
|
|
505
|
+
|
|
506
|
+
readHash();
|
|
507
|
+
render();
|
|
508
|
+
live = true;
|
|
509
|
+
if (S.tab === 'deps') { fitted = true; fit(); }
|
|
299
510
|
})();
|
|
300
|
-
|
|
511
|
+
`.replace(/^ +/gm, ''); // Indentation is for reading here; the page ships without it (AC-34).
|
|
301
512
|
//# sourceMappingURL=view-assets.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view-assets.js","sourceRoot":"","sources":["../../src/roadmap/view-assets.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"view-assets.js","sourceRoot":"","sources":["../../src/roadmap/view-assets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmGnC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsYpC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,sEAAsE"}
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
*
|
|
16
16
|
* @module
|
|
17
17
|
*/
|
|
18
|
-
import type
|
|
18
|
+
import { type RoadmapStatus } from './paths.js';
|
|
19
|
+
import type { RoadmapView, ViewItem } from './view-model.js';
|
|
19
20
|
/** Done cards shown before "show all" (AC-18). */
|
|
20
21
|
export declare const DONE_VISIBLE = 20;
|
|
21
22
|
/** Escape text for HTML text and double-quoted attribute values alike. */
|
|
@@ -32,6 +33,15 @@ export declare function contentSecurityPolicy(): string;
|
|
|
32
33
|
* library would be the first dependency the page grows.
|
|
33
34
|
*/
|
|
34
35
|
export declare function renderSummary(markdown: string): string;
|
|
36
|
+
/** Statuses the Board shows when the URL names none (AC-1). */
|
|
37
|
+
export declare const BOARD_DEFAULT: readonly RoadmapStatus[];
|
|
38
|
+
/** The five presets every tab offers, in order (AC-6). */
|
|
39
|
+
export declare const PRESETS: readonly {
|
|
40
|
+
name: string;
|
|
41
|
+
statuses: readonly RoadmapStatus[];
|
|
42
|
+
}[];
|
|
43
|
+
/** The commands that apply to an item, as `[label, command]`; the page runs none (AC-29). */
|
|
44
|
+
export declare function commandsFor(v: ViewItem): [string, string][];
|
|
35
45
|
/** Render the page. Pure. */
|
|
36
46
|
export declare function renderView(view: RoadmapView): string;
|
|
37
47
|
//# sourceMappingURL=view-html.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view-html.d.ts","sourceRoot":"","sources":["../../src/roadmap/view-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;
|
|
1
|
+
{"version":3,"file":"view-html.d.ts","sourceRoot":"","sources":["../../src/roadmap/view-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAElE,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7D,kDAAkD;AAClD,eAAO,MAAM,YAAY,KAAK,CAAC;AA8B/B,0EAA0E;AAC1E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,0CAA0C;AAC1C,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,iGAAiG;AACjG,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAcD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgCtD;AA8DD,+DAA+D;AAC/D,eAAO,MAAM,aAAa,EAAE,SAAS,aAAa,EAAwC,CAAC;AAuB3F,0DAA0D;AAC1D,eAAO,MAAM,OAAO,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAA;CAAE,EAMlF,CAAC;AAwKF,6FAA6F;AAC7F,wBAAgB,WAAW,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAmB3D;AAgDD,6BAA6B;AAC7B,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAiDpD"}
|