@profpowell/vb-project-planning 0.1.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.
Files changed (106) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +93 -0
  3. package/dist/vb-project-planning.css +1603 -0
  4. package/dist/vb-project-planning.js +11138 -0
  5. package/dist/vb-project-planning.min.css +1 -0
  6. package/dist/vb-project-planning.min.js +3312 -0
  7. package/package.json +80 -0
  8. package/src/index.css +14 -0
  9. package/src/index.js +26 -0
  10. package/src/lib/bundle-registry.js +156 -0
  11. package/src/lib/diff-by-key.js +86 -0
  12. package/src/lib/portrait-url.js +87 -0
  13. package/src/lib/vb-collection.js +122 -0
  14. package/src/lib/vb-element.js +96 -0
  15. package/src/lib/vb-store.js +200 -0
  16. package/src/lib/vb-view-transition.js +44 -0
  17. package/src/utils/copy-init.js +287 -0
  18. package/src/web-components/_ux-base.js +106 -0
  19. package/src/web-components/adr-wc/README.md +77 -0
  20. package/src/web-components/adr-wc/api.json +26 -0
  21. package/src/web-components/adr-wc/logic.js +376 -0
  22. package/src/web-components/adr-wc/static.html +17 -0
  23. package/src/web-components/adr-wc/styles.js +338 -0
  24. package/src/web-components/burndown-chart/api.json +74 -0
  25. package/src/web-components/burndown-chart/logic.js +198 -0
  26. package/src/web-components/burndown-chart/static.html +31 -0
  27. package/src/web-components/burndown-chart/styles.css +59 -0
  28. package/src/web-components/capacity-plan/_capacity-utils.js +56 -0
  29. package/src/web-components/capacity-plan/api.json +20 -0
  30. package/src/web-components/capacity-plan/logic.js +222 -0
  31. package/src/web-components/capacity-plan/static.html +24 -0
  32. package/src/web-components/capacity-plan/styles.css +84 -0
  33. package/src/web-components/empathy-map/api.json +31 -0
  34. package/src/web-components/empathy-map/logic.js +502 -0
  35. package/src/web-components/empathy-map/static.html +32 -0
  36. package/src/web-components/empathy-map/styles.js +534 -0
  37. package/src/web-components/gantt-chart/README.md +91 -0
  38. package/src/web-components/gantt-chart/api.json +20 -0
  39. package/src/web-components/gantt-chart/logic.js +812 -0
  40. package/src/web-components/gantt-chart/static.html +60 -0
  41. package/src/web-components/gantt-chart/styles.css +391 -0
  42. package/src/web-components/impact-effort/api.json +21 -0
  43. package/src/web-components/impact-effort/logic.js +392 -0
  44. package/src/web-components/impact-effort/static.html +23 -0
  45. package/src/web-components/impact-effort/styles.css +193 -0
  46. package/src/web-components/iron-triangle/_capacity.js +83 -0
  47. package/src/web-components/iron-triangle/_triangle-geometry.js +322 -0
  48. package/src/web-components/iron-triangle/api.json +26 -0
  49. package/src/web-components/iron-triangle/logic.js +474 -0
  50. package/src/web-components/iron-triangle/static.html +28 -0
  51. package/src/web-components/iron-triangle/styles.css +158 -0
  52. package/src/web-components/kanban-board/api.json +24 -0
  53. package/src/web-components/kanban-board/logic.js +698 -0
  54. package/src/web-components/kanban-board/static.html +20 -0
  55. package/src/web-components/kanban-board/styles.css +242 -0
  56. package/src/web-components/product-roadmap/api.json +118 -0
  57. package/src/web-components/product-roadmap/logic.js +460 -0
  58. package/src/web-components/product-roadmap/static.html +44 -0
  59. package/src/web-components/product-roadmap/styles.css +158 -0
  60. package/src/web-components/quadrant-grid/api.json +125 -0
  61. package/src/web-components/quadrant-grid/logic.js +397 -0
  62. package/src/web-components/quadrant-grid/static.html +49 -0
  63. package/src/web-components/quadrant-grid/styles.css +184 -0
  64. package/src/web-components/quality-target/_quality-utils.js +460 -0
  65. package/src/web-components/quality-target/api.json +30 -0
  66. package/src/web-components/quality-target/logic.js +516 -0
  67. package/src/web-components/quality-target/static.html +22 -0
  68. package/src/web-components/quality-target/styles.css +203 -0
  69. package/src/web-components/requirement-card/api.json +25 -0
  70. package/src/web-components/requirement-card/logic.js +166 -0
  71. package/src/web-components/requirement-card/static.html +36 -0
  72. package/src/web-components/requirement-card/styles.js +114 -0
  73. package/src/web-components/review-surface/README.md +178 -0
  74. package/src/web-components/review-surface/api.json +30 -0
  75. package/src/web-components/review-surface/logic.js +807 -0
  76. package/src/web-components/review-surface/static.html +33 -0
  77. package/src/web-components/review-surface/styles.js +459 -0
  78. package/src/web-components/risk-register/api.json +47 -0
  79. package/src/web-components/risk-register/logic.js +180 -0
  80. package/src/web-components/risk-register/static.html +46 -0
  81. package/src/web-components/risk-register/styles.css +37 -0
  82. package/src/web-components/story-map/api.json +22 -0
  83. package/src/web-components/story-map/logic.js +445 -0
  84. package/src/web-components/story-map/static.html +35 -0
  85. package/src/web-components/story-map/styles.css +169 -0
  86. package/src/web-components/traceability-matrix/api.json +84 -0
  87. package/src/web-components/traceability-matrix/logic.js +243 -0
  88. package/src/web-components/traceability-matrix/static.html +41 -0
  89. package/src/web-components/traceability-matrix/styles.css +94 -0
  90. package/src/web-components/user-journey/api.json +84 -0
  91. package/src/web-components/user-journey/logic.js +368 -0
  92. package/src/web-components/user-journey/static.html +14 -0
  93. package/src/web-components/user-journey/styles.js +317 -0
  94. package/src/web-components/user-persona/api.json +35 -0
  95. package/src/web-components/user-persona/logic.js +502 -0
  96. package/src/web-components/user-persona/static.html +20 -0
  97. package/src/web-components/user-persona/styles.js +299 -0
  98. package/src/web-components/user-story/api.json +35 -0
  99. package/src/web-components/user-story/logic.js +567 -0
  100. package/src/web-components/user-story/static.html +27 -0
  101. package/src/web-components/user-story/styles.js +332 -0
  102. package/src/web-components/work-item/README.md +85 -0
  103. package/src/web-components/work-item/api.json +30 -0
  104. package/src/web-components/work-item/logic.js +414 -0
  105. package/src/web-components/work-item/static.html +24 -0
  106. package/src/web-components/work-item/styles.js +376 -0
@@ -0,0 +1,60 @@
1
+ <!--
2
+ gantt-chart — static (zero-JS) form
3
+ Without JS, the native table renders with progress bars and time elements.
4
+ -->
5
+ <gantt-chart title="Q2 Product Roadmap" show-today show-progress>
6
+ <table>
7
+ <thead>
8
+ <tr>
9
+ <th>Task</th>
10
+ <th>Start</th>
11
+ <th>End</th>
12
+ <th>Progress</th>
13
+ </tr>
14
+ </thead>
15
+ <tbody>
16
+ <tr data-task-id="research" data-group="Design" data-status="done">
17
+ <td>User research</td>
18
+ <td><time datetime="2026-04-01">Apr 1</time></td>
19
+ <td><time datetime="2026-04-07">Apr 7</time></td>
20
+ <td><progress value="100" max="100">100%</progress></td>
21
+ </tr>
22
+ <tr data-task-id="wireframes" data-group="Design" data-depends="research" data-status="done">
23
+ <td>Wireframes</td>
24
+ <td><time datetime="2026-04-07">Apr 7</time></td>
25
+ <td><time datetime="2026-04-14">Apr 14</time></td>
26
+ <td><progress value="100" max="100">100%</progress></td>
27
+ </tr>
28
+ <tr data-task-id="visual-design" data-group="Design" data-depends="wireframes" data-status="in-progress">
29
+ <td>Visual design</td>
30
+ <td><time datetime="2026-04-14">Apr 14</time></td>
31
+ <td><time datetime="2026-04-28">Apr 28</time></td>
32
+ <td><progress value="60" max="100">60%</progress></td>
33
+ </tr>
34
+ <tr data-task-id="api" data-group="Engineering" data-depends="wireframes" data-status="in-progress">
35
+ <td>API development</td>
36
+ <td><time datetime="2026-04-10">Apr 10</time></td>
37
+ <td><time datetime="2026-05-01">May 1</time></td>
38
+ <td><progress value="40" max="100">40%</progress></td>
39
+ </tr>
40
+ <tr data-task-id="frontend" data-group="Engineering" data-depends="visual-design,api" data-status="not-started">
41
+ <td>Frontend build</td>
42
+ <td><time datetime="2026-04-28">Apr 28</time></td>
43
+ <td><time datetime="2026-05-15">May 15</time></td>
44
+ <td><progress value="0" max="100">0%</progress></td>
45
+ </tr>
46
+ <tr data-task-id="testing" data-group="QA" data-depends="frontend" data-status="not-started">
47
+ <td>QA testing</td>
48
+ <td><time datetime="2026-05-12">May 12</time></td>
49
+ <td><time datetime="2026-05-22">May 22</time></td>
50
+ <td><progress value="0" max="100">0%</progress></td>
51
+ </tr>
52
+ <tr data-task-id="launch" data-group="Engineering" data-depends="testing" data-milestone data-status="not-started">
53
+ <td>Launch</td>
54
+ <td><time datetime="2026-05-25">May 25</time></td>
55
+ <td><time datetime="2026-05-25">May 25</time></td>
56
+ <td><progress value="0" max="100">0%</progress></td>
57
+ </tr>
58
+ </tbody>
59
+ </table>
60
+ </gantt-chart>
@@ -0,0 +1,391 @@
1
+ /**
2
+ * Light DOM styles for <gantt-chart>
3
+ *
4
+ * Layout: task-list (left) | timeline bars (right)
5
+ * Progressive: without JS, the native <table> renders normally.
6
+ */
7
+
8
+ /* ── Host ──────────────────────────────────────────── */
9
+ gantt-chart {
10
+ display: block;
11
+ container-type: inline-size;
12
+ font-family: var(--font-sans, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif);
13
+ line-height: 1.5;
14
+ color: var(--color-text, #1a1a1a);
15
+ }
16
+
17
+ /* Before upgrade, the table is visible normally */
18
+ gantt-chart:not([data-upgraded]) > table {
19
+ width: 100%;
20
+ }
21
+
22
+ /* ── Title ─────────────────────────────────────────── */
23
+ .gc-title {
24
+ font-size: var(--font-size-xl, 1.25rem);
25
+ font-weight: 700;
26
+ margin-block-end: var(--size-s, 0.75rem);
27
+ }
28
+
29
+ /* ── Container ─────────────────────────────────────── */
30
+ .gc-container {
31
+ border: 1px solid var(--color-border, #e0e0e0);
32
+ border-radius: var(--radius-m, 0.5rem);
33
+ overflow: hidden;
34
+ background: var(--color-surface, #ffffff);
35
+ }
36
+
37
+ /* ── Timeline header ───────────────────────────────── */
38
+ .gc-timeline-header {
39
+ display: flex;
40
+ position: relative;
41
+ border-block-end: 1px solid var(--color-border, #e0e0e0);
42
+ background: var(--color-surface-raised, #f8f9fa);
43
+ min-height: 32px;
44
+ }
45
+
46
+ .gc-timeline-spacer {
47
+ flex: 0 0 var(--gc-task-width, 180px);
48
+ border-inline-end: 1px solid var(--color-border, #e0e0e0);
49
+ }
50
+
51
+ .gc-timeline-dates {
52
+ flex: 1;
53
+ position: relative;
54
+ min-height: 32px;
55
+ }
56
+
57
+ .gc-date-label {
58
+ position: absolute;
59
+ top: 0;
60
+ bottom: 0;
61
+ display: flex;
62
+ align-items: center;
63
+ font-size: 11px;
64
+ font-weight: 600;
65
+ color: var(--color-text-muted, #666666);
66
+ padding-inline-start: 6px;
67
+ white-space: nowrap;
68
+ border-inline-start: 1px solid var(--color-border, #e0e0e0);
69
+ }
70
+
71
+ .gc-date-label:first-child {
72
+ border-inline-start: none;
73
+ }
74
+
75
+ /* ── Body layout ───────────────────────────────────── */
76
+ .gc-body {
77
+ display: flex;
78
+ min-height: 0;
79
+ }
80
+
81
+ /* ── Task list (left panel) ────────────────────────── */
82
+ .gc-task-list {
83
+ flex: 0 0 var(--gc-task-width, 180px);
84
+ border-inline-end: 1px solid var(--color-border, #e0e0e0);
85
+ overflow: hidden;
86
+ }
87
+
88
+ .gc-task-row {
89
+ display: flex;
90
+ align-items: center;
91
+ gap: 6px;
92
+ height: var(--gc-row-height, 36px);
93
+ padding-inline: 12px;
94
+ border-block-end: 1px solid color-mix(in srgb, var(--color-border, #e0e0e0) 50%, transparent);
95
+ font-size: var(--font-size-sm, 0.875rem);
96
+ white-space: nowrap;
97
+ overflow: hidden;
98
+ text-overflow: ellipsis;
99
+ }
100
+
101
+ .gc-task-row:last-child {
102
+ border-block-end: none;
103
+ }
104
+
105
+ .gc-task-name {
106
+ overflow: hidden;
107
+ text-overflow: ellipsis;
108
+ }
109
+
110
+ .gc-task-dates {
111
+ position: absolute;
112
+ width: 1px;
113
+ height: 1px;
114
+ overflow: hidden;
115
+ clip: rect(0, 0, 0, 0);
116
+ white-space: nowrap;
117
+ }
118
+
119
+ /* ── Group headers ─────────────────────────────────── */
120
+ .gc-group-header {
121
+ display: flex;
122
+ align-items: center;
123
+ height: 28px;
124
+ padding-inline: 12px;
125
+ background: var(--color-surface-raised, #f8f9fa);
126
+ border-block-end: 1px solid var(--color-border, #e0e0e0);
127
+ }
128
+
129
+ .gc-group-label {
130
+ font-size: 11px;
131
+ font-weight: 700;
132
+ text-transform: uppercase;
133
+ letter-spacing: 0.05em;
134
+ color: var(--color-text-muted, #666666);
135
+ }
136
+
137
+ .gc-group-spacer {
138
+ height: 28px;
139
+ background: var(--color-surface-raised, #f8f9fa);
140
+ border-block-end: 1px solid var(--color-border, #e0e0e0);
141
+ }
142
+
143
+ /* ── Bars panel (right panel) ──────────────────────── */
144
+ .gc-bars {
145
+ flex: 1;
146
+ position: relative;
147
+ min-width: 0;
148
+ overflow-x: auto;
149
+ }
150
+
151
+ /* ── Grid lines ────────────────────────────────────── */
152
+ .gc-grid-lines {
153
+ position: absolute;
154
+ inset: 0;
155
+ pointer-events: none;
156
+ }
157
+
158
+ .gc-grid-line {
159
+ position: absolute;
160
+ top: 0;
161
+ bottom: 0;
162
+ width: 1px;
163
+ background: color-mix(in srgb, var(--color-border, #e0e0e0) 50%, transparent);
164
+ }
165
+
166
+ /* ── Bar rows ──────────────────────────────────────── */
167
+ .gc-bar-row {
168
+ position: relative;
169
+ height: var(--gc-row-height, 36px);
170
+ border-block-end: 1px solid color-mix(in srgb, var(--color-border, #e0e0e0) 50%, transparent);
171
+ }
172
+
173
+ .gc-bar-row:last-child {
174
+ border-block-end: none;
175
+ }
176
+
177
+ /* ── Bars ──────────────────────────────────────────── */
178
+ .gc-bar {
179
+ position: absolute;
180
+ top: 6px;
181
+ bottom: 6px;
182
+ border-radius: var(--radius-s, 4px);
183
+ background: var(--gc-bar-color, var(--color-interactive, #0066cc));
184
+ cursor: pointer;
185
+ min-width: 4px;
186
+ display: flex;
187
+ align-items: center;
188
+ overflow: hidden;
189
+ transition: filter 150ms ease;
190
+ }
191
+
192
+ .gc-bar:hover {
193
+ filter: brightness(1.1);
194
+ }
195
+
196
+ .gc-bar:focus-visible {
197
+ outline: 2px solid var(--color-interactive, #0066cc);
198
+ outline-offset: 2px;
199
+ }
200
+
201
+ /* ── Bar fill (progress) ───────────────────────────── */
202
+ .gc-bar-fill {
203
+ height: 100%;
204
+ border-radius: inherit;
205
+ background: color-mix(in srgb, var(--gc-bar-color, var(--color-interactive, #0066cc)) 65%, white);
206
+ pointer-events: none;
207
+ }
208
+
209
+ /* ── Bar label ─────────────────────────────────────── */
210
+ .gc-bar-label {
211
+ position: absolute;
212
+ inset: 0;
213
+ display: flex;
214
+ align-items: center;
215
+ padding-inline: 6px;
216
+ font-size: 11px;
217
+ font-weight: 600;
218
+ color: #fff;
219
+ white-space: nowrap;
220
+ overflow: hidden;
221
+ text-overflow: ellipsis;
222
+ pointer-events: none;
223
+ }
224
+
225
+ /* ── Status colors ─────────────────────────────────── */
226
+ .gc-bar[data-status="done"] {
227
+ --gc-bar-color: var(--color-success, #16a34a);
228
+ }
229
+
230
+ .gc-bar[data-status="blocked"] {
231
+ --gc-bar-color: var(--color-error, #dc2626);
232
+ }
233
+
234
+ .gc-bar[data-status="not-started"] {
235
+ --gc-bar-color: var(--color-text-muted, #666666);
236
+ opacity: 0.6;
237
+ }
238
+
239
+ /* ── Milestone (diamond) ───────────────────────────── */
240
+ .gc-milestone {
241
+ position: absolute;
242
+ top: 50%;
243
+ width: 14px;
244
+ height: 14px;
245
+ transform: translate(-50%, -50%) rotate(45deg);
246
+ background: var(--gc-bar-color, var(--color-interactive, #0066cc));
247
+ border: 2px solid var(--color-surface, #ffffff);
248
+ cursor: pointer;
249
+ }
250
+
251
+ .gc-milestone:focus-visible {
252
+ outline: 2px solid var(--color-interactive, #0066cc);
253
+ outline-offset: 3px;
254
+ }
255
+
256
+ .gc-milestone[data-status="done"] {
257
+ --gc-bar-color: var(--color-success, #16a34a);
258
+ }
259
+
260
+ /* ── Today line ────────────────────────────────────── */
261
+ .gc-today-line {
262
+ position: absolute;
263
+ top: 0;
264
+ bottom: 0;
265
+ width: 2px;
266
+ background: var(--color-error, #dc2626);
267
+ z-index: 5;
268
+ pointer-events: none;
269
+ }
270
+
271
+ .gc-today-label {
272
+ position: absolute;
273
+ top: -22px;
274
+ left: 50%;
275
+ transform: translateX(-50%);
276
+ font-size: 10px;
277
+ font-weight: 700;
278
+ color: var(--color-error, #dc2626);
279
+ white-space: nowrap;
280
+ }
281
+
282
+ /* ── Dependency arrows ─────────────────────────────── */
283
+ .gc-deps {
284
+ position: absolute;
285
+ inset: 0;
286
+ pointer-events: none;
287
+ overflow: visible;
288
+ }
289
+
290
+ .gc-dep-line {
291
+ fill: none;
292
+ stroke: var(--color-text-muted, #666666);
293
+ stroke-width: 1.5;
294
+ marker-end: url(#gc-arrowhead);
295
+ }
296
+
297
+ /* ── Visually hidden (original table + live region) ── */
298
+ .gc-sr-only {
299
+ position: absolute;
300
+ width: 1px;
301
+ height: 1px;
302
+ padding: 0;
303
+ margin: -1px;
304
+ overflow: hidden;
305
+ clip: rect(0, 0, 0, 0);
306
+ white-space: nowrap;
307
+ border: 0;
308
+ }
309
+
310
+ /* ── Compact variant ───────────────────────────────── */
311
+ gantt-chart[compact] {
312
+ --gc-row-height: 28px;
313
+ --gc-task-width: 140px;
314
+ }
315
+
316
+ gantt-chart[compact] .gc-task-row {
317
+ font-size: 12px;
318
+ padding-inline: 8px;
319
+ }
320
+
321
+ gantt-chart[compact] .gc-bar {
322
+ top: 5px;
323
+ bottom: 5px;
324
+ }
325
+
326
+ gantt-chart[compact] .gc-group-header {
327
+ height: 24px;
328
+ }
329
+
330
+ gantt-chart[compact] .gc-group-spacer {
331
+ height: 24px;
332
+ }
333
+
334
+ /* ── Responsive ────────────────────────────────────── */
335
+ @container (max-width: 30rem) {
336
+ .gc-body {
337
+ flex-direction: column;
338
+ }
339
+
340
+ .gc-task-list {
341
+ flex: none;
342
+ border-inline-end: none;
343
+ border-block-end: 1px solid var(--color-border, #e0e0e0);
344
+ }
345
+
346
+ .gc-task-row {
347
+ height: auto;
348
+ padding-block: 4px;
349
+ }
350
+
351
+ .gc-timeline-spacer {
352
+ display: none;
353
+ }
354
+ }
355
+
356
+ /* ── Motion ────────────────────────────────────────── */
357
+ @media (prefers-reduced-motion: reduce) {
358
+ .gc-bar {
359
+ transition: none;
360
+ }
361
+ }
362
+
363
+ /* ── Print ─────────────────────────────────────────── */
364
+ @media print {
365
+ gantt-chart[data-upgraded] .gc-container,
366
+ gantt-chart[data-upgraded] .gc-title {
367
+ display: none;
368
+ }
369
+
370
+ gantt-chart[data-upgraded] .gc-sr-only {
371
+ position: static;
372
+ width: auto;
373
+ height: auto;
374
+ margin: 0;
375
+ overflow: visible;
376
+ clip: auto;
377
+ white-space: normal;
378
+ }
379
+ }
380
+
381
+ /*
382
+ * View Transition crossfade between rebuilds (theme/data/attribute changes).
383
+ * The component pins a unique view-transition-name on the host for the
384
+ * duration of each refresh so the browser captures only the gantt region
385
+ * and crossfades old → new in one frame budget.
386
+ */
387
+ ::view-transition-old(*),
388
+ ::view-transition-new(*) {
389
+ animation-duration: 220ms;
390
+ animation-timing-function: ease-out;
391
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "../../../schemas/api.schema.json",
3
+ "element": "impact-effort",
4
+ "type": "web-component",
5
+ "description": "2x2 prioritization matrix with drag-and-drop between quadrants (Quick Wins, Big Bets, Fill-Ins, Money Pit)",
6
+ "htmlvalidate": { "flow": true, "permittedContent": ["@flow"] },
7
+ "attributes": [
8
+ { "name": "src", "kind": "host-api", "purpose": "config", "type": "string", "description": "URL to JSON data for items" },
9
+ { "name": "title", "kind": "host-api", "purpose": "config", "type": "string", "description": "Optional heading above the matrix" },
10
+ { "name": "compact", "kind": "host-api", "purpose": "config", "type": "boolean", "description": "Reduced spacing variant" }
11
+ ],
12
+ "childAttributes": [
13
+ { "name": "data-quadrant", "on": "any child", "type": "enum", "values": ["quick-wins", "big-bets", "fill-ins", "money-pit"], "description": "Target quadrant for this item" },
14
+ { "name": "draggable", "on": "any child", "type": "boolean", "description": "Required for drag capability" },
15
+ { "name": "data-id", "on": "any child", "type": "string", "description": "Stable identifier for the item" }
16
+ ],
17
+ "events": [
18
+ { "name": "impact-effort:move", "detail": "{ itemId, from, to, item }", "description": "Fired when an item is dragged between quadrants" },
19
+ { "name": "impact-effort:ready", "detail": "{ quadrantCounts }", "description": "Fired after component initializes" }
20
+ ]
21
+ }