@cyberskill/design 1.2.0 → 1.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. package/DESIGN.md +11 -9
  2. package/README.md +28 -24
  3. package/SKILL.md +18 -9
  4. package/THIRD-PARTY-NOTICES.md +35 -0
  5. package/VERSION +1 -1
  6. package/_ds_bundle.js +701 -1342
  7. package/_esm/cs.mjs +2 -2
  8. package/_esm/react.mjs +6 -1
  9. package/_vendor/NOTICE.md +16 -0
  10. package/_vendor/babel/README.md +7 -0
  11. package/_vendor/babel/babel.min.js +4 -0
  12. package/_vendor/react/README.md +3 -0
  13. package/_vendor/react/react-dom.production.min.js +1 -0
  14. package/_vendor/react/react.production.min.js +1 -0
  15. package/assets/aurora-hoa.webp +0 -0
  16. package/assets/aurora-kim.webp +0 -0
  17. package/assets/aurora-moc.webp +0 -0
  18. package/assets/aurora-tho.webp +0 -0
  19. package/assets/aurora-thuy.webp +0 -0
  20. package/base/ai.css +8 -3
  21. package/base/collections.css +10 -4
  22. package/base/components.css +5 -2
  23. package/base/controls.css +58 -21
  24. package/base/data.css +1 -1
  25. package/base/feedback.css +9 -2
  26. package/base/forms.css +1 -1
  27. package/base/glass.css +1 -1
  28. package/base/interaction.css +6 -2
  29. package/base/navigation.css +1 -1
  30. package/base/reset.css +7 -1
  31. package/base/responsive.css +13 -12
  32. package/base/shell.css +8 -2
  33. package/components/_i18n/i18n.js +28 -3
  34. package/components/_i18n/strings.js +42 -24
  35. package/components/ai/ChatMessage.d.ts +2 -0
  36. package/components/ai/ChatMessage.jsx +8 -4
  37. package/components/ai/ConfidenceMeter.d.ts +2 -0
  38. package/components/ai/HumanReviewGate.d.ts +2 -0
  39. package/components/ai/PromptInput.d.ts +2 -0
  40. package/components/ai/TypingIndicator.d.ts +2 -0
  41. package/components/ai/ai-conversation.card.html +3 -3
  42. package/components/ai/ai-lumi.card.html +3 -3
  43. package/components/ai/ai.card.html +3 -3
  44. package/components/brand/brand.card.html +3 -3
  45. package/components/button/buttons.card.html +3 -3
  46. package/components/data/Image.jsx +18 -2
  47. package/components/data/Sortable.d.ts +5 -1
  48. package/components/data/Sortable.jsx +42 -9
  49. package/components/data/Sortable.prompt.md +4 -2
  50. package/components/data/Terminal.jsx +3 -2
  51. package/components/data/Tooltip.d.ts +2 -0
  52. package/components/data/Tooltip.jsx +6 -3
  53. package/components/data/Tree.d.ts +2 -1
  54. package/components/data/Tree.jsx +137 -16
  55. package/components/data/Tree.prompt.md +1 -1
  56. package/components/data/collections.card.html +3 -3
  57. package/components/data/data.card.html +3 -3
  58. package/components/datatable/DataTable.d.ts +24 -1
  59. package/components/datatable/DataTable.jsx +78 -5
  60. package/components/datatable/DataTable.prompt.md +2 -1
  61. package/components/datatable/datatable.card.html +20 -16
  62. package/components/dialog/dialog.card.html +3 -3
  63. package/components/feedback/Alert.d.ts +2 -0
  64. package/components/feedback/Alert.jsx +8 -2
  65. package/components/feedback/EmptyState.d.ts +2 -0
  66. package/components/feedback/EmptyState.jsx +6 -3
  67. package/components/feedback/ProgressBar.d.ts +2 -0
  68. package/components/feedback/ProgressBar.jsx +6 -3
  69. package/components/feedback/Toast.jsx +15 -1
  70. package/components/feedback/Toast.prompt.md +2 -1
  71. package/components/feedback/feedback-2.card.html +3 -3
  72. package/components/feedback/feedback.card.html +3 -3
  73. package/components/forms/Cascader.jsx +7 -2
  74. package/components/forms/FileUpload.d.ts +2 -0
  75. package/components/forms/Form.d.ts +3 -1
  76. package/components/forms/Form.jsx +9 -1
  77. package/components/forms/Form.prompt.md +1 -1
  78. package/components/forms/Mentions.d.ts +1 -1
  79. package/components/forms/Mentions.jsx +59 -7
  80. package/components/forms/Mentions.prompt.md +3 -1
  81. package/components/forms/Rating.d.ts +3 -2
  82. package/components/forms/Rating.jsx +34 -3
  83. package/components/forms/Rating.prompt.md +1 -1
  84. package/components/forms/Select.d.ts +2 -0
  85. package/components/forms/Select.jsx +6 -2
  86. package/components/forms/Slider.d.ts +2 -0
  87. package/components/forms/Slider.jsx +5 -2
  88. package/components/forms/Switch.d.ts +2 -0
  89. package/components/forms/Switch.jsx +7 -9
  90. package/components/forms/Toggle.d.ts +2 -0
  91. package/components/forms/Toggle.jsx +14 -2
  92. package/components/forms/forms-2.card.html +3 -3
  93. package/components/forms/forms.card.html +3 -3
  94. package/components/icon/Icon.d.ts +1 -1
  95. package/components/icon/Icon.prompt.md +1 -1
  96. package/components/icon/icon.card.html +3 -3
  97. package/components/logo/logo.card.html +3 -3
  98. package/components/navigation/CommandPalette.d.ts +2 -0
  99. package/components/navigation/Menu.d.ts +2 -0
  100. package/components/navigation/Menu.jsx +60 -6
  101. package/components/navigation/Steps.d.ts +2 -0
  102. package/components/navigation/Steps.jsx +6 -3
  103. package/components/navigation/Tabs.d.ts +2 -0
  104. package/components/navigation/Tabs.jsx +6 -3
  105. package/components/navigation/Toolbar.d.ts +3 -2
  106. package/components/navigation/Toolbar.jsx +117 -11
  107. package/components/navigation/Toolbar.prompt.md +1 -1
  108. package/components/navigation/navigation.card.html +3 -3
  109. package/components/navigation/shell.card.html +3 -3
  110. package/components/overlays/ContextMenu.d.ts +2 -0
  111. package/components/overlays/ContextMenu.jsx +6 -3
  112. package/components/overlays/Drawer.d.ts +2 -0
  113. package/components/overlays/alertdialog.card.html +3 -3
  114. package/components/overlays/overlays.card.html +3 -3
  115. package/components/textfield/textfield.card.html +3 -3
  116. package/dist/styles.min.css +312 -64
  117. package/docs/benchmark-rubric.md +2 -2
  118. package/docs/ci-cd.md +18 -13
  119. package/docs/consumer-grant.md +4 -1
  120. package/docs/consuming.md +16 -12
  121. package/docs/contrast-report.md +81 -1
  122. package/docs/conventions.md +18 -5
  123. package/docs/decisions.md +41 -3
  124. package/docs/deploy.md +19 -6
  125. package/docs/design-styles.md +2 -2
  126. package/docs/doctrine.md +51 -0
  127. package/docs/figma.md +2 -0
  128. package/docs/live-hub.md +3 -1
  129. package/docs/products.md +1 -1
  130. package/docs/quality-gates.md +24 -12
  131. package/docs/release-notes.md +1 -1
  132. package/docs/release-runbook.md +78 -0
  133. package/docs/storybook.md +3 -3
  134. package/docs/sync.md +8 -8
  135. package/docs/template-schema-v2.md +1 -1
  136. package/docs/vi/benchmark-rubric.md +2 -2
  137. package/docs/vi/ci-cd.md +17 -14
  138. package/docs/vi/consumer-grant.md +4 -1
  139. package/docs/vi/consuming.md +16 -12
  140. package/docs/vi/contrast-report.md +81 -1
  141. package/docs/vi/conventions.md +19 -6
  142. package/docs/vi/decisions.md +40 -3
  143. package/docs/vi/deploy.md +19 -6
  144. package/docs/vi/design-styles.md +1 -1
  145. package/docs/vi/doctrine.md +51 -0
  146. package/docs/vi/figma.md +2 -0
  147. package/docs/vi/live-hub.md +3 -1
  148. package/docs/vi/products.md +1 -1
  149. package/docs/vi/quality-gates.md +23 -12
  150. package/docs/vi/release-notes.md +1 -1
  151. package/docs/vi/release-runbook.md +78 -0
  152. package/docs/vi/storybook.md +3 -3
  153. package/docs/vi/sync.md +7 -7
  154. package/docs/vi/template-schema-v2.md +1 -1
  155. package/docs/viewer.html +16 -5
  156. package/fonts/OFL.txt +98 -0
  157. package/guidelines/atomic-view.html +2 -2
  158. package/guidelines/brand-imagery.html +1 -1
  159. package/guidelines/elements-variants.html +5 -5
  160. package/guidelines/spacing-breakpoints.html +2 -1
  161. package/guidelines/surfaces-glass.html +1 -1
  162. package/llms.txt +18 -11
  163. package/package.json +28 -8
  164. package/templates/app-shell/AppShell.dc.html +3 -3
  165. package/templates/app-shell/content-schema.json +7 -0
  166. package/templates/article/Article.dc.html +3 -3
  167. package/templates/article/content-schema.json +7 -0
  168. package/templates/auth/Auth.dc.html +26 -10
  169. package/templates/auth/content-schema.json +25 -0
  170. package/templates/dashboard/Dashboard.dc.html +4 -4
  171. package/templates/dashboard/content-schema.json +7 -0
  172. package/templates/delivery-change-note/DeliveryChangeNote.dc.html +2 -2
  173. package/templates/delivery-runbook/DeliveryRunbook.dc.html +2 -2
  174. package/templates/email-safe/email-announcement.html +2 -2
  175. package/templates/email-safe/email-dunning.html +2 -2
  176. package/templates/email-safe/email-investor.html +2 -2
  177. package/templates/email-safe/email-launch.html +2 -2
  178. package/templates/email-safe/email-newsletter.html +2 -2
  179. package/templates/email-safe/email-status.html +2 -2
  180. package/templates/email-safe/email-transactional.html +2 -2
  181. package/templates/finance-dunning-email/FinanceDunningEmail.dc.html +2 -2
  182. package/templates/finance-expense-report/FinanceExpenseReport.dc.html +2 -2
  183. package/templates/finance-invoice/FinanceInvoice.dc.html +2 -2
  184. package/templates/finance-quote/FinanceQuote.dc.html +4 -4
  185. package/templates/hr-interview-kit/HrInterviewKit.dc.html +1 -1
  186. package/templates/marketing-case-study/MarketingCaseStudy.dc.html +1 -1
  187. package/templates/marketing-page/MarketingPage.dc.html +3 -3
  188. package/templates/marketing-page/content-schema.json +1 -0
  189. package/templates/settings/Settings.dc.html +3 -3
  190. package/templates/settings/content-schema.json +7 -0
  191. package/tokens/element-seeds.json +2 -2
  192. package/tokens/elements.css +193 -19
  193. package/tokens/native/CSTokens.kt +3 -2
  194. package/tokens/native/CSTokens.swift +3 -2
  195. package/tokens/native/cs_tokens.dart +3 -2
  196. package/tokens/provenance.json +8 -8
  197. package/tokens/spacing.css +2 -1
  198. package/tokens/tokens.dtcg.json +19 -14
  199. package/tokens/tokens.js +16 -15
  200. package/tokens/tokens.json +15 -14
  201. package/ui_kits/deck/index.html +1 -1
  202. package/ui_kits/status-hub/StatusHub.jsx +1 -1
  203. package/ui_kits/status-hub/login.html +52 -10
  204. package/ui_kits/status-hub/project.html +1 -1
  205. package/ui_kits/status-hub/settings.html +1 -1
  206. package/ui_kits/website/Website.jsx +1 -1
  207. package/ui_kits/website/careers.html +2 -2
  208. package/ui_kits/website/chat.html +1 -1
  209. package/ui_kits/website/site.css +1 -1
  210. package/ui_kits/website/work.html +2 -2
  211. package/assets/aurora-hoa.png +0 -0
  212. package/assets/aurora-kim.png +0 -0
  213. package/assets/aurora-moc.png +0 -0
  214. package/assets/aurora-thuy.png +0 -0
  215. package/docs/decisions/container-query-migration.md +0 -18
  216. package/docs/decisions/overlay-manager-design.md +0 -101
  217. package/docs/plans/cyberskill-design-system-audit-and-12-month-evolution-plan.md +0 -1490
  218. package/docs/status/assets/favicon.svg +0 -5
  219. package/docs/status/assets/status-legacy.css +0 -399
  220. package/docs/status/assets/status-legacy.js +0 -505
  221. package/docs/status/assets/status.css +0 -644
  222. package/docs/status/assets/status.js +0 -1308
  223. package/docs/status/data/status-feed.json +0 -1
  224. package/docs/status/data/task/TASK-REL-001.js +0 -1
  225. package/docs/status/data/task/TASK-REL-002.js +0 -1
  226. package/docs/status/index.html +0 -46
  227. package/docs/status/roadmap.html +0 -4
  228. package/docs/status/status-legacy.html +0 -122
  229. package/docs/tasks/BACKLOG.md +0 -26
  230. package/docs/tasks/_state/commit-links.yaml +0 -14
  231. package/docs/tasks/release/TASK-REL-001-launch-1-1-0/spec.md +0 -55
  232. package/docs/tasks/release/TASK-REL-002-republish-1-1-1/spec.md +0 -54
@@ -1,505 +0,0 @@
1
- /* status-app.js - client for status-hub@2.
2
- One corpus, three lenses (board / table / releases) + a task detail drawer.
3
- No dependencies and no network calls except the on-demand per-task spec chunk
4
- (data/task/<ID>.js - a classic script, so it works over file:// too).
5
- The page stays readable without this file: <noscript> carries a static table
6
- of every task plus the full release list. */
7
- (function () {
8
- "use strict";
9
-
10
- var el = document.getElementById("cs-data");
11
- if (!el) return;
12
- var D = JSON.parse(el.textContent);
13
- // status.css already has a `.tasks` rule meaning something else, so renaming
14
- // the class would collide. Data key: renamed. CSS class: frozen.
15
- var TASKS = D.tasks;
16
- var BY = {};
17
- TASKS.forEach(function (f) { BY[f.i] = f; });
18
-
19
- var ACTIVE = { ready_to_implement: 1, implementing: 1, ready_to_review: 1,
20
- reviewing: 1, ready_to_test: 1, testing: 1 };
21
- // cannot_reproduce / duplicate are TERMINAL (added 2026-07-14 with `type: bug`).
22
- // Omit them here and they bucket as "todo" — the board would show closed bugs as
23
- // outstanding work forever, which is exactly the kind of quiet lie a status page
24
- // must not tell.
25
- var DONE = { done: 1, closed: 1, cannot_reproduce: 1, duplicate: 1 };
26
- function bucket(s) {
27
- return DONE[s] ? "done" : ACTIVE[s] ? "active" : s === "on_hold" ? "hold" : "todo";
28
- }
29
-
30
- var LENSES = { board: 1, table: 1, timeline: 1 };
31
- var LEGACY = { roadmap: "board", backlog: "table", changelog: "timeline" };
32
- var FKEYS = ["m", "s", "p", "c", "ph", "b"];
33
- var FFIELD = { m: "m", s: "s", p: "p", c: "c", ph: "ph" };
34
- var FLABEL = { m: "module", s: "status", p: "priority", c: "class", ph: "phase", b: "group" };
35
-
36
- var S = { lens: "board", q: "", f: {}, group: "m", sort: "i", dir: 1, task: null };
37
-
38
- /* ---- hash state ------------------------------------------------------- */
39
- function readHash() {
40
- var h = decodeURIComponent(location.hash.replace(/^#/, ""));
41
- if (!h) return;
42
- var parts = h.split("?");
43
- var path = parts[0];
44
- var qs = parts[1] || "";
45
- if (path.indexOf("task/") === 0) S.task = path.slice(5);
46
- else if (LENSES[path]) S.lens = path;
47
- else if (LEGACY[path]) S.lens = LEGACY[path];
48
- qs.split("&").forEach(function (kv) {
49
- if (!kv) return;
50
- var i = kv.indexOf("=");
51
- var k = i < 0 ? kv : kv.slice(0, i);
52
- var v = i < 0 ? "" : decodeURIComponent(kv.slice(i + 1));
53
- if (k === "q") S.q = v;
54
- else if (k === "g") S.group = v;
55
- else if (FKEYS.indexOf(k) >= 0 && v) S.f[k] = v;
56
- });
57
- }
58
- function writeHash(replace) {
59
- var q = [];
60
- if (S.q) q.push("q=" + encodeURIComponent(S.q));
61
- FKEYS.forEach(function (k) { if (S.f[k]) q.push(k + "=" + encodeURIComponent(S.f[k])); });
62
- if (S.lens === "board" && S.group !== "m") q.push("g=" + S.group);
63
- var h = "#" + (S.task ? "task/" + S.task : S.lens) + (q.length ? "?" + q.join("&") : "");
64
- if (h === location.hash) return;
65
- if (replace && history.replaceState) history.replaceState(null, "", h);
66
- else if (history.pushState) history.pushState(null, "", h);
67
- else location.hash = h;
68
- }
69
-
70
- /* ---- filtering -------------------------------------------------------- */
71
- function matches(f) {
72
- for (var k in FFIELD) if (S.f[k] && f[FFIELD[k]] !== S.f[k]) return false;
73
- if (S.f.b && bucket(f.s) !== S.f.b) return false;
74
- if (S.q) {
75
- var q = S.q.toLowerCase();
76
- var hay = (f.i + " " + f.t + " " + f.m + " " + (f.o || "") + " " +
77
- (f.ph || "") + " " + (f.sm || "")).toLowerCase();
78
- if (hay.indexOf(q) < 0) return false;
79
- }
80
- return true;
81
- }
82
- function view() { return TASKS.filter(matches); }
83
-
84
- /* ---- helpers ---------------------------------------------------------- */
85
- function esc(s) {
86
- return String(s == null ? "" : s).replace(/&/g, "&amp;").replace(/</g, "&lt;")
87
- .replace(/>/g, "&gt;").replace(/"/g, "&quot;");
88
- }
89
- function pct(n, d) { return d ? (100 * n / d).toFixed(1) : "0.0"; }
90
- function chip(f, ghost) {
91
- if (!f) return "";
92
- return '<button class="chip ' + bucket(f.s) + (ghost ? " ghost" : "") +
93
- '" data-task="' + esc(f.i) + '" title="' + esc(f.i + " — " + f.t + " [" + f.s + "]") +
94
- '">' + esc(f.i.replace(/^TASK-/, "")) + "</button>";
95
- }
96
- function chipId(id, ghost) {
97
- return BY[id] ? chip(BY[id], ghost)
98
- : '<span class="chip ghost" title="not in this corpus">' + esc(id.replace(/^TASK-/, "")) + "</span>";
99
- }
100
- function segs(rows) {
101
- var d = 0, a = 0, h = 0;
102
- rows.forEach(function (f) {
103
- var b = bucket(f.s);
104
- if (b === "done") d++; else if (b === "active") a++; else if (b === "hold") h++;
105
- });
106
- var n = rows.length;
107
- return '<div class="minibar"><i class="seg-done" style="width:' + pct(d, n) + '%"></i>' +
108
- '<i class="seg-active" style="width:' + pct(a, n) + '%"></i>' +
109
- '<i class="seg-hold" style="width:' + pct(h, n) + '%"></i></div>';
110
- }
111
-
112
- /* ---- lens: board ------------------------------------------------------ */
113
- function board(rows) {
114
- var g = S.group, keys = [], bag = {};
115
- rows.forEach(function (f) {
116
- var k = f[g] || "(unset)";
117
- if (!bag[k]) { bag[k] = []; keys.push(k); }
118
- bag[k].push(f);
119
- });
120
- if (g === "s") keys.sort(function (a, b) { return D.statuses.indexOf(a) - D.statuses.indexOf(b); });
121
- else keys.sort(function (a, b) {
122
- return bag[b].length - bag[a].length || String(a).localeCompare(String(b));
123
- });
124
- if (!keys.length) return '<p class="empty">No task matches these filters.</p>';
125
- return '<div class="grid">' + keys.map(function (k) {
126
- var rs = bag[k];
127
- var d = rs.filter(function (f) { return bucket(f.s) === "done"; }).length;
128
- var a = rs.filter(function (f) { return bucket(f.s) === "active"; }).length;
129
- return '<section class="card' + (a ? " hot" : "") + '">' +
130
- '<div class="card-h"><h3><span class="k">' + esc(k) + '</span> ' +
131
- '<span class="muted">· ' + rs.length + " tasks</span></h3>" +
132
- '<span class="pct">' + pct(d, rs.length) + "% done</span></div>" +
133
- segs(rs) + '<div class="task-chips">' +
134
- rs.map(function (f) { return chip(f); }).join("") + "</div></section>";
135
- }).join("") + "</div>";
136
- }
137
-
138
- /* ---- lens: table ------------------------------------------------------ */
139
- var COLS = [
140
- { k: "i", h: "id" }, { k: "t", h: "title" }, { k: "m", h: "module" },
141
- { k: "c", h: "class" }, { k: "p", h: "priority" }, { k: "ph", h: "phase" },
142
- { k: "e", h: "effort" }, { k: "s", h: "status" }
143
- ];
144
- function table(rows) {
145
- var k = S.sort, dir = S.dir;
146
- var sorted = rows.slice().sort(function (a, b) {
147
- var x = a[k], y = b[k];
148
- if (k === "s") { x = D.statuses.indexOf(x); y = D.statuses.indexOf(y); }
149
- else if (k === "e") { x = +x || 0; y = +y || 0; }
150
- else { x = x == null ? "" : x; y = y == null ? "" : y; }
151
- return (x > y ? 1 : x < y ? -1 : 0) * dir || String(a.i).localeCompare(String(b.i));
152
- });
153
- if (!sorted.length) return '<p class="empty">No task matches these filters.</p>';
154
- var head = COLS.map(function (c) {
155
- var s = S.sort === c.k ? (S.dir > 0 ? "ascending" : "descending") : "none";
156
- return '<th data-sort="' + c.k + '" aria-sort="' + s + '" scope="col">' + c.h + "</th>";
157
- }).join("");
158
- var body = sorted.map(function (f) {
159
- return '<tr data-task="' + esc(f.i) + '" tabindex="0">' +
160
- '<td class="code">' + esc(f.i) + "</td>" +
161
- '<td class="t">' + esc(f.t) + "</td>" +
162
- "<td>" + esc(f.m) + "</td><td>" + esc(f.c || "") + "</td>" +
163
- '<td class="pri ' + esc(f.p || "") + '">' + esc(f.p || "") + "</td>" +
164
- "<td>" + esc(f.ph || "") + "</td><td>" + esc(f.e || "") + "</td>" +
165
- '<td><span class="pill ' + bucket(f.s) + '">' + esc(f.s) + "</span></td></tr>";
166
- }).join("");
167
- return '<div class="tbl-wrap"><table><thead><tr>' + head +
168
- "</tr></thead><tbody>" + body + "</tbody></table></div>";
169
- }
170
-
171
- /* ---- lens: releases --------------------------------------------------- */
172
- var BOUND = {};
173
- (D.bound || []).forEach(function (id) { BOUND[id] = 1; });
174
-
175
- function timeline(rows) {
176
- var seen = {};
177
- rows.forEach(function (f) { seen[f.i] = 1; });
178
- // "unreleased" = in flight, plus anything already done that no release accounts for
179
- var moving = rows.filter(function (f) {
180
- var b = bucket(f.s);
181
- return b === "active" || (b === "done" && !BOUND[f.i]);
182
- });
183
- var out = [];
184
- if (moving.length) {
185
- var shipped = moving.filter(function (f) { return bucket(f.s) === "done"; }).length;
186
- out.push('<article class="rel now"><span class="tick">★</span><div>' +
187
- '<div class="rel-h"><b>unreleased</b><span class="muted">' + moving.length + " tasks</span></div>" +
188
- '<p class="relnote">No release accounts for these yet — ' +
189
- (moving.length - shipped) + " in flight (<code>ready_to_implement</code> → <code>testing</code>)" +
190
- (shipped ? ", " + shipped + " already <code>done</code> but not cut into a release" : "") +
191
- ".</p>" +
192
- '<div class="task-chips">' + moving.map(function (f) { return chip(f); }).join("") +
193
- "</div></div></article>");
194
- }
195
- D.releases.forEach(function (r, i) {
196
- var cited = r.cited.filter(function (id) { return !BY[id] || seen[id]; });
197
- var dated = r.dated.filter(function (id) { return seen[id]; });
198
- var secs = r.sec.map(function (s) {
199
- return '<div class="rel-sec"><h4>' + esc(s.h) + "</h4><ul>" +
200
- s.items.map(function (x) { return "<li>" + x + "</li>"; }).join("") + "</ul></div>";
201
- }).join("");
202
- var chips = cited.map(function (id) { return chipId(id); }).join("") +
203
- dated.map(function (id) { return chipId(id, true); }).join("");
204
- out.push('<article class="rel' + (i === 0 && !moving.length ? " now" : "") +
205
- '"><span class="tick">' + (i === 0 ? "★" : "✓") + "</span><div>" +
206
- '<div class="rel-h"><b>' + esc(r.vl) + "</b>" +
207
- (r.d ? '<span class="muted">' + esc(r.d) + "</span>" : "") +
208
- '<span class="muted">' + (cited.length + dated.length) + " tasks</span></div>" +
209
- (chips ? '<div class="task-chips">' + chips + "</div>"
210
- : '<p class="relnote">No task id cited in this entry.</p>') +
211
- (dated.length ? '<p class="relnote">Dashed chips were bound by <code>shipped:</code> date, ' +
212
- "not cited in the entry text.</p>" : "") +
213
- (r.intro.length || secs
214
- ? "<details><summary>Release notes</summary>" +
215
- r.intro.map(function (p) { return "<p>" + p + "</p>"; }).join("") + secs + "</details>"
216
- : "") +
217
- "</div></article>");
218
- });
219
- return '<div class="rels">' + out.join("") + "</div>";
220
- }
221
-
222
- /* ---- drawer ----------------------------------------------------------- */
223
- var drawer = document.getElementById("drawer");
224
- var scrim = document.getElementById("scrim");
225
- var dwTab = "overview";
226
- var lastFocus = null;
227
-
228
- // the markdown is only reachable when it ships next to the page (docs/status/ does; the
229
- // website build does not - there the rendered task page is the way in)
230
- function specHref(f) { return D.frBase ? D.frBase + f.dm + "/" + f.k + "/spec.md" : ""; }
231
- function srcLink(f, label) {
232
- var h = specHref(f);
233
- return h ? '<a href="' + esc(h) + '">' + label + "</a>"
234
- : (f.pg ? '<a href="' + esc(f.pg) + '">the task page</a>' : "");
235
- }
236
- function row(dt, dd) { return dd ? "<div><dt>" + esc(dt) + "</dt><dd>" + dd + "</dd></div>" : ""; }
237
-
238
- function drawerHtml(f) {
239
- var n = f.d.length + f.b.length + f.rl.length;
240
- var tabs = [["overview", "Overview"], ["spec", "Full spec"], ["links", "Links (" + n + ")"]];
241
- return '<div class="dw-h"><div class="row">' +
242
- '<span class="pill ' + bucket(f.s) + '">' + esc(f.s) + "</span>" +
243
- '<span class="code muted">' + esc(f.i) + "</span>" +
244
- '<span class="pri ' + esc(f.p || "") + '">' + esc(f.p || "") + "</span>" +
245
- '<button class="dw-x" type="button" aria-label="Close">×</button></div>' +
246
- '<h2 id="dw-title">' + esc(f.t) + "</h2></div>" +
247
- '<div class="dw-tabs" role="tablist">' + tabs.map(function (t) {
248
- return '<button class="dw-tab" role="tab" type="button" data-dwtab="' + t[0] +
249
- '" aria-selected="' + (dwTab === t[0]) + '">' + t[1] + "</button>";
250
- }).join("") + "</div><div class=\"dw-b\" id=\"dw-body\"></div>";
251
- }
252
-
253
- function overview(f) {
254
- var m = '<dl class="meta">' +
255
- row("module", esc(f.m)) + row("class", esc(f.c)) + row("phase", esc(f.ph)) +
256
- row("milestone", esc(f.ms)) + row("slice", esc(f.sl)) + row("owner", esc(f.o)) +
257
- row("effort", f.e ? esc(f.e) + " h" : "") + row("verify", esc(f.v)) +
258
- row("created", esc(f.cr)) + row("shipped", esc(f.sh)) + "</dl>";
259
- var s = "";
260
- if (f.sm) s += '<div class="sect"><h3>Summary</h3><p>' + esc(f.sm) + "</p></div>";
261
- if (f.st && f.st.length) {
262
- s += '<div class="sect"><h3>Sub-tasks (' + f.st.length + ')</h3><ul class="tasks">' +
263
- f.st.map(function (t) { return "<li>" + esc(t) + "</li>"; }).join("") + "</ul></div>";
264
- }
265
- if (f.r) s += '<div class="sect"><h3>Risk if skipped</h3><p class="risk">' + esc(f.r) + "</p></div>";
266
- return m + s;
267
- }
268
-
269
- function links(f) {
270
- function blk(title, ids, none) {
271
- return "<div><h3>" + esc(title) + " (" + ids.length + ")</h3>" +
272
- (ids.length ? '<div class="task-chips">' + ids.map(function (id) { return chipId(id); }).join("") + "</div>"
273
- : '<p class="muted">' + esc(none) + "</p>") + "</div>";
274
- }
275
- var srcs = [];
276
- if (f.pg) srcs.push('<a href="' + esc(f.pg) + '">Rendered task page</a>');
277
- if (specHref(f)) srcs.push('<a href="' + esc(specHref(f)) + '"><code>spec.md</code> — the record of truth</a>');
278
- if (!srcs.length) srcs.push('<span class="muted">Markdown is the record of truth: <code>' +
279
- esc("docs/tasks/" + f.dm + "/" + f.k + "/spec.md") + "</code></span>");
280
- return '<div class="rel-links">' +
281
- blk("Depends on", f.d, "Nothing blocks this task.") +
282
- blk("Blocks", f.b, "This task blocks nothing.") +
283
- blk("Related", f.rl, "No related tasks recorded.") + "</div>" +
284
- '<div class="sect"><h3>Sources</h3><p>' + srcs.join(" · ") + "</p></div>";
285
- }
286
-
287
- function specTab(f) {
288
- var body = document.getElementById("dw-body");
289
- if (!f.sp) {
290
- body.innerHTML = '<p class="load">No spec body was rendered into this page. ' +
291
- srcLink(f, "Open spec.md") + "</p>";
292
- return;
293
- }
294
- var W = window.CS_SPEC || (window.CS_SPEC = {});
295
- function paintSpec() {
296
- var tmp = document.createElement("div");
297
- tmp.innerHTML = W[f.i];
298
- var toc = [];
299
- Array.prototype.forEach.call(tmp.querySelectorAll("h2"), function (h, n) {
300
- var id = "s" + n;
301
- h.id = id;
302
- toc.push('<a href="#' + id + '" data-anchor="' + id + '">' + esc(h.textContent) + "</a>");
303
- });
304
- body.innerHTML = (toc.length ? '<nav class="toc">' + toc.join("") + "</nav>" : "") +
305
- '<div class="spec">' + tmp.innerHTML + "</div>";
306
- }
307
- if (W[f.i]) { paintSpec(); return; }
308
- body.innerHTML = '<p class="load">Loading the full spec …</p>';
309
- var sc = document.createElement("script");
310
- sc.src = D.specDir + "/" + f.i + ".js";
311
- sc.onerror = function () {
312
- body.innerHTML = '<p class="load">The spec chunk did not load. ' + srcLink(f, "Open spec.md") + "</p>";
313
- };
314
- sc.onload = function () { if (W[f.i]) paintSpec(); else sc.onerror(); };
315
- document.head.appendChild(sc);
316
- }
317
-
318
- function paintDrawer(f) {
319
- if (dwTab === "spec") specTab(f);
320
- else document.getElementById("dw-body").innerHTML = dwTab === "links" ? links(f) : overview(f);
321
- }
322
- function openTask(id, push) {
323
- var f = BY[id];
324
- if (!f) return;
325
- if (!S.task) lastFocus = document.activeElement;
326
- S.task = id;
327
- drawer.innerHTML = drawerHtml(f);
328
- drawer.hidden = false;
329
- scrim.hidden = false;
330
- document.body.style.overflow = "hidden";
331
- paintDrawer(f);
332
- drawer.querySelector(".dw-x").focus();
333
- if (push !== false) writeHash();
334
- }
335
- function closeFR() {
336
- if (!S.task) return;
337
- S.task = null;
338
- dwTab = "overview";
339
- drawer.hidden = true;
340
- scrim.hidden = true;
341
- drawer.innerHTML = "";
342
- document.body.style.overflow = "";
343
- writeHash();
344
- if (lastFocus && lastFocus.focus) lastFocus.focus();
345
- }
346
-
347
- /* ---- paint ------------------------------------------------------------ */
348
- var lensEl = document.getElementById("lens");
349
- var countEl = document.getElementById("count");
350
- var chipbar = document.getElementById("active-filters");
351
-
352
- function paint() {
353
- var rows = view();
354
- countEl.textContent = rows.length === TASKS.length
355
- ? TASKS.length + " tasks"
356
- : "showing " + rows.length + " of " + TASKS.length;
357
- lensEl.innerHTML = S.lens === "table" ? table(rows)
358
- : S.lens === "timeline" ? timeline(rows) : board(rows);
359
-
360
- Array.prototype.forEach.call(document.querySelectorAll(".ln"), function (b) {
361
- b.setAttribute("aria-selected", String(b.dataset.lens === S.lens));
362
- });
363
- var g = document.getElementById("f-g");
364
- if (g) g.parentNode.hidden = S.lens !== "board";
365
-
366
- var on = [];
367
- FKEYS.forEach(function (k) {
368
- if (S.f[k]) on.push('<span class="fchip">' + esc(FLABEL[k]) + ": " + esc(S.f[k]) +
369
- '<button type="button" data-drop="' + k + '" aria-label="Remove filter">×</button></span>');
370
- });
371
- if (S.q) on.push('<span class="fchip">search: ' + esc(S.q) +
372
- '<button type="button" data-drop="q" aria-label="Clear search">×</button></span>');
373
- chipbar.innerHTML = on.join("");
374
- chipbar.hidden = !on.length;
375
-
376
- Array.prototype.forEach.call(document.querySelectorAll(".kpi"), function (k) {
377
- k.dataset.on = S.f.b && S.f.b === k.dataset.bucket ? "1" : "0";
378
- });
379
- }
380
-
381
- function syncControls() {
382
- var q = document.getElementById("q");
383
- if (q) q.value = S.q;
384
- FKEYS.forEach(function (k) {
385
- var s = document.getElementById("f-" + k);
386
- if (s) s.value = S.f[k] || "";
387
- });
388
- var g = document.getElementById("f-g");
389
- if (g) g.value = S.group;
390
- }
391
-
392
- /* ---- events ----------------------------------------------------------- */
393
- document.addEventListener("click", function (e) {
394
- var t = e.target;
395
- if (!t.closest) return;
396
-
397
- if (t === scrim || t.closest(".dw-x")) { closeFR(); return; }
398
-
399
- var dt = t.closest("[data-dwtab]");
400
- if (dt && S.task) {
401
- dwTab = dt.dataset.dwtab;
402
- Array.prototype.forEach.call(drawer.querySelectorAll(".dw-tab"), function (b) {
403
- b.setAttribute("aria-selected", String(b.dataset.dwtab === dwTab));
404
- });
405
- paintDrawer(BY[S.task]);
406
- return;
407
- }
408
-
409
- var anchor = t.closest("[data-anchor]");
410
- if (anchor) {
411
- e.preventDefault();
412
- var target = document.getElementById(anchor.dataset.anchor);
413
- if (target) target.scrollIntoView({ block: "start" });
414
- return;
415
- }
416
-
417
- // branch never fired: clicking a task row on the status page did nothing, in every repo
418
- // that vendored this file. Renamed the declaration, left the target — again.
419
- var task = t.closest("[data-task]");
420
- if (task) { openTask(task.dataset.task); return; }
421
-
422
- var ln = t.closest(".ln");
423
- if (ln) { S.lens = ln.dataset.lens; writeHash(); paint(); return; }
424
-
425
- var drop = t.closest("[data-drop]");
426
- if (drop) {
427
- var dk = drop.dataset.drop;
428
- if (dk === "q") S.q = ""; else delete S.f[dk];
429
- syncControls(); writeHash(); paint();
430
- return;
431
- }
432
-
433
- var kpi = t.closest(".kpi");
434
- if (kpi && kpi.dataset.bucket) {
435
- if (S.f.b === kpi.dataset.bucket) delete S.f.b; else S.f.b = kpi.dataset.bucket;
436
- writeHash(); paint();
437
- return;
438
- }
439
-
440
- var th = t.closest("th[data-sort]");
441
- if (th) {
442
- if (S.sort === th.dataset.sort) S.dir = -S.dir;
443
- else { S.sort = th.dataset.sort; S.dir = 1; }
444
- paint();
445
- return;
446
- }
447
-
448
- if (t.closest("#clear")) { S.q = ""; S.f = {}; syncControls(); writeHash(); paint(); }
449
- });
450
-
451
- document.addEventListener("keydown", function (e) {
452
- if (e.key === "Escape" && S.task) { closeFR(); return; }
453
- if (e.key === "/" && document.activeElement.tagName !== "INPUT") {
454
- e.preventDefault();
455
- document.getElementById("q").focus();
456
- return;
457
- }
458
- if (e.key === "Enter" && e.target.dataset && e.target.dataset.task) openTask(e.target.dataset.task);
459
- });
460
-
461
- var qEl = document.getElementById("q");
462
- var timer;
463
- qEl.addEventListener("input", function () {
464
- clearTimeout(timer);
465
- timer = setTimeout(function () { S.q = qEl.value.trim(); writeHash(true); paint(); }, 120);
466
- });
467
-
468
- Array.prototype.forEach.call(document.querySelectorAll("#bar select"), function (s) {
469
- s.addEventListener("change", function () {
470
- var k = s.id.slice(2);
471
- if (k === "g") S.group = s.value;
472
- else if (s.value) S.f[k] = s.value;
473
- else delete S.f[k];
474
- writeHash();
475
- paint();
476
- });
477
- });
478
-
479
- document.getElementById("theme").addEventListener("click", function () {
480
- var next = document.documentElement.dataset.theme === "dark" ? "light" : "dark";
481
- document.documentElement.dataset.theme = next;
482
- try { window.localStorage.setItem("cs-theme", next); } catch (err) { /* private mode */ }
483
- });
484
-
485
- window.addEventListener("hashchange", function () {
486
- var was = S.task;
487
- S.task = null; S.q = ""; S.f = {};
488
- readHash();
489
- syncControls();
490
- if (S.task) { openTask(S.task, false); return; }
491
- if (was) closeFR();
492
- paint();
493
- });
494
-
495
- /* ---- boot ------------------------------------------------------------- */
496
- try {
497
- var saved = window.localStorage.getItem("cs-theme");
498
- if (saved) document.documentElement.dataset.theme = saved;
499
- } catch (err) { /* private mode */ }
500
-
501
- readHash();
502
- syncControls();
503
- paint();
504
- if (S.task) openTask(S.task, false);
505
- })();