@sienklogic/plan-build-run 2.29.0 → 2.30.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/CHANGELOG.md +18 -0
- package/dashboard/public/css/explorer.css +458 -0
- package/dashboard/src/components/Layout.tsx +1 -0
- package/dashboard/src/components/explorer/ExplorerPage.tsx +57 -0
- package/dashboard/src/components/explorer/tabs/AuditsTab.tsx +29 -0
- package/dashboard/src/components/explorer/tabs/MilestonesTab.tsx +84 -0
- package/dashboard/src/components/explorer/tabs/NotesTab.tsx +32 -0
- package/dashboard/src/components/explorer/tabs/PhasesTab.tsx +204 -0
- package/dashboard/src/components/explorer/tabs/QuickTab.tsx +40 -0
- package/dashboard/src/components/explorer/tabs/RequirementsTab.tsx +45 -0
- package/dashboard/src/components/explorer/tabs/ResearchTab.tsx +47 -0
- package/dashboard/src/components/explorer/tabs/TodosTab.tsx +161 -0
- package/dashboard/src/index.tsx +2 -0
- package/dashboard/src/routes/explorer.routes.tsx +226 -0
- package/dashboard/src/services/audit.service.d.ts +14 -0
- package/dashboard/src/services/milestone.service.d.ts +35 -0
- package/dashboard/src/services/notes.service.d.ts +14 -0
- package/dashboard/src/services/phase.service.d.ts +59 -0
- package/dashboard/src/services/quick.service.d.ts +15 -0
- package/dashboard/src/services/requirements.service.d.ts +19 -0
- package/dashboard/src/services/research.service.d.ts +27 -0
- package/dashboard/src/services/roadmap.service.d.ts +23 -0
- package/package.json +1 -1
- package/plugins/copilot-pbr/plugin.json +1 -1
- package/plugins/cursor-pbr/.cursor-plugin/plugin.json +1 -1
- package/plugins/pbr/.claude-plugin/plugin.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,24 @@ All notable changes to Plan-Build-Run will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.30.0](https://github.com/SienkLogic/plan-build-run/compare/plan-build-run-v2.29.0...plan-build-run-v2.30.0) (2026-02-24)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **40-01:** add Explorer view shell with phases tab and Alpine.js tabs ([f6d4fb3](https://github.com/SienkLogic/plan-build-run/commit/f6d4fb391cbd6eebe13ee6c381556404f4ad1faf))
|
|
14
|
+
* **40-02:** add MilestonesTab component and milestone.service type declarations ([420572b](https://github.com/SienkLogic/plan-build-run/commit/420572bb0009b52e0e761baf66097980758b981e))
|
|
15
|
+
* **40-02:** add TodosTab component with TodoListFragment and TodoCreateForm ([0cca669](https://github.com/SienkLogic/plan-build-run/commit/0cca669f39079a69fe5376d7460135a0fd496f07))
|
|
16
|
+
* **40-02:** wire todos and milestones routes into explorer.routes.tsx ([83e2963](https://github.com/SienkLogic/plan-build-run/commit/83e2963fc1d7bbc061df23c3f5c80c326bd2f16e))
|
|
17
|
+
* **40-03:** add NotesTab, AuditsTab, and QuickTab components ([e3edd64](https://github.com/SienkLogic/plan-build-run/commit/e3edd647a9db251527f50ed2264540acbc1974ff))
|
|
18
|
+
* **40-03:** add ResearchTab and RequirementsTab components with requirements CSS ([3102ff7](https://github.com/SienkLogic/plan-build-run/commit/3102ff735a0be217f013fa01199c1823cf2cfae5))
|
|
19
|
+
* **40-03:** wire research, requirements, notes, audits, quick routes; add service .d.ts files ([a45fcd9](https://github.com/SienkLogic/plan-build-run/commit/a45fcd906d06fc0da866ed6492c116bc9e80ab76))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Bug Fixes
|
|
23
|
+
|
|
24
|
+
* **40-02:** use JSX-compatible hx-on attribute syntax in TodoCreateForm ([70e6822](https://github.com/SienkLogic/plan-build-run/commit/70e6822c5ec72ef25ee290ba7453065637f3c828))
|
|
25
|
+
|
|
8
26
|
## [2.29.0](https://github.com/SienkLogic/plan-build-run/compare/plan-build-run-v2.28.0...plan-build-run-v2.29.0) (2026-02-24)
|
|
9
27
|
|
|
10
28
|
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
Explorer — Tab shell + Phase drill-down
|
|
3
|
+
Depends on: tokens.css, status-colors.css
|
|
4
|
+
============================================ */
|
|
5
|
+
|
|
6
|
+
/* x-cloak: hide elements controlled by Alpine.js before it initialises */
|
|
7
|
+
[x-cloak] { display: none !important; }
|
|
8
|
+
|
|
9
|
+
/* ---- Explorer shell ---- */
|
|
10
|
+
|
|
11
|
+
.explorer {
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
padding: var(--space-lg);
|
|
15
|
+
max-width: 1200px;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* ---- Tab bar ---- */
|
|
19
|
+
|
|
20
|
+
.explorer__tabs {
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: row;
|
|
23
|
+
gap: 0;
|
|
24
|
+
border-bottom: 1px solid var(--color-border);
|
|
25
|
+
margin-bottom: var(--space-lg);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.explorer__tab-btn {
|
|
29
|
+
padding: var(--space-sm) var(--space-md);
|
|
30
|
+
border: none;
|
|
31
|
+
border-bottom: 2px solid transparent;
|
|
32
|
+
background: none;
|
|
33
|
+
cursor: pointer;
|
|
34
|
+
color: var(--color-text-dim);
|
|
35
|
+
font-size: 0.9rem;
|
|
36
|
+
font-family: var(--font-sans);
|
|
37
|
+
transition: all 0.15s;
|
|
38
|
+
white-space: nowrap;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.explorer__tab-btn:hover {
|
|
42
|
+
color: var(--color-text);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.explorer__tab-btn[aria-selected="true"] {
|
|
46
|
+
color: var(--color-accent);
|
|
47
|
+
border-bottom-color: var(--color-accent);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* ---- Tab panels ---- */
|
|
51
|
+
|
|
52
|
+
.explorer__tab-content {
|
|
53
|
+
min-height: 400px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.explorer__loading {
|
|
57
|
+
display: flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
justify-content: center;
|
|
60
|
+
padding: var(--space-xl);
|
|
61
|
+
color: var(--color-text-dim);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* ---- Explorer list (phases, todos, etc.) ---- */
|
|
65
|
+
|
|
66
|
+
.explorer-list {
|
|
67
|
+
display: flex;
|
|
68
|
+
flex-direction: column;
|
|
69
|
+
gap: var(--space-sm);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* ---- Expandable item ---- */
|
|
73
|
+
|
|
74
|
+
.explorer-item {
|
|
75
|
+
background: var(--color-surface-raised);
|
|
76
|
+
border: 1px solid var(--color-border);
|
|
77
|
+
border-radius: var(--radius-md);
|
|
78
|
+
overflow: hidden;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.explorer-item__header {
|
|
82
|
+
display: flex;
|
|
83
|
+
align-items: center;
|
|
84
|
+
gap: var(--space-sm);
|
|
85
|
+
padding: var(--space-sm) var(--space-md);
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
user-select: none;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.explorer-item__header:hover {
|
|
91
|
+
background: var(--color-surface-hover);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.explorer-item__toggle {
|
|
95
|
+
font-size: 0.7rem;
|
|
96
|
+
color: var(--color-text-dim);
|
|
97
|
+
transition: transform 0.2s;
|
|
98
|
+
display: inline-block;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.explorer-item__toggle--open {
|
|
102
|
+
transform: rotate(90deg);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.explorer-item__title {
|
|
106
|
+
font-weight: 500;
|
|
107
|
+
font-size: 0.95rem;
|
|
108
|
+
flex: 1;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.explorer-item__meta {
|
|
112
|
+
font-size: 0.8rem;
|
|
113
|
+
color: var(--color-text-dim);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.explorer-item__body {
|
|
117
|
+
border-top: 1px solid var(--color-border);
|
|
118
|
+
padding: var(--space-md);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* ---- Plan list within phase detail ---- */
|
|
122
|
+
|
|
123
|
+
.explorer-item__plans {
|
|
124
|
+
display: flex;
|
|
125
|
+
flex-direction: column;
|
|
126
|
+
gap: var(--space-xs);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.explorer-plan-item {
|
|
130
|
+
border: 1px solid var(--color-border);
|
|
131
|
+
border-radius: var(--radius-sm);
|
|
132
|
+
overflow: hidden;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.explorer-plan-link {
|
|
136
|
+
display: flex;
|
|
137
|
+
align-items: center;
|
|
138
|
+
gap: var(--space-xs);
|
|
139
|
+
padding: var(--space-xs) var(--space-sm);
|
|
140
|
+
border-radius: var(--radius-sm);
|
|
141
|
+
cursor: pointer;
|
|
142
|
+
font-size: 0.9rem;
|
|
143
|
+
user-select: none;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.explorer-plan-link:hover {
|
|
147
|
+
background: var(--color-surface-hover);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* ---- Document viewer ---- */
|
|
151
|
+
|
|
152
|
+
.explorer-doc-viewer {
|
|
153
|
+
margin-top: var(--space-md);
|
|
154
|
+
background: var(--color-surface);
|
|
155
|
+
border: 1px solid var(--color-border);
|
|
156
|
+
border-radius: var(--radius-md);
|
|
157
|
+
padding: var(--space-md);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.explorer-doc-viewer__tabs {
|
|
161
|
+
display: flex;
|
|
162
|
+
gap: var(--space-xs);
|
|
163
|
+
margin-bottom: var(--space-md);
|
|
164
|
+
border-bottom: 1px solid var(--color-border);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.explorer-doc-viewer__tab {
|
|
168
|
+
padding: var(--space-xs) var(--space-sm);
|
|
169
|
+
font-size: 0.8rem;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* ---- Rendered document content ---- */
|
|
173
|
+
|
|
174
|
+
.explorer-doc-content {
|
|
175
|
+
font-size: 0.9rem;
|
|
176
|
+
line-height: 1.6;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.explorer-doc-content h1,
|
|
180
|
+
.explorer-doc-content h2,
|
|
181
|
+
.explorer-doc-content h3,
|
|
182
|
+
.explorer-doc-content h4 {
|
|
183
|
+
margin-top: var(--space-md);
|
|
184
|
+
margin-bottom: var(--space-xs);
|
|
185
|
+
font-weight: 600;
|
|
186
|
+
line-height: 1.3;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.explorer-doc-content h1 { font-size: 1.25rem; }
|
|
190
|
+
.explorer-doc-content h2 { font-size: 1.1rem; }
|
|
191
|
+
.explorer-doc-content h3 { font-size: 1rem; }
|
|
192
|
+
|
|
193
|
+
.explorer-doc-content p {
|
|
194
|
+
margin-bottom: var(--space-sm);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.explorer-doc-content ul,
|
|
198
|
+
.explorer-doc-content ol {
|
|
199
|
+
padding-left: var(--space-md);
|
|
200
|
+
margin-bottom: var(--space-sm);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.explorer-doc-content li {
|
|
204
|
+
margin-bottom: var(--space-xs);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.explorer-doc-content code {
|
|
208
|
+
font-family: var(--font-mono);
|
|
209
|
+
font-size: 0.85em;
|
|
210
|
+
background: var(--color-surface-raised);
|
|
211
|
+
padding: 0.1em 0.3em;
|
|
212
|
+
border-radius: var(--radius-sm);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.explorer-doc-content pre {
|
|
216
|
+
background: var(--color-surface-raised);
|
|
217
|
+
border: 1px solid var(--color-border);
|
|
218
|
+
border-radius: var(--radius-md);
|
|
219
|
+
padding: var(--space-md);
|
|
220
|
+
overflow-x: auto;
|
|
221
|
+
margin-bottom: var(--space-sm);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.explorer-doc-content pre code {
|
|
225
|
+
background: none;
|
|
226
|
+
padding: 0;
|
|
227
|
+
font-size: 0.85rem;
|
|
228
|
+
line-height: var(--line-height-mono);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.explorer-doc-content table {
|
|
232
|
+
width: 100%;
|
|
233
|
+
border-collapse: collapse;
|
|
234
|
+
font-size: 0.875rem;
|
|
235
|
+
margin-bottom: var(--space-sm);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.explorer-doc-content th,
|
|
239
|
+
.explorer-doc-content td {
|
|
240
|
+
padding: var(--space-xs) var(--space-sm);
|
|
241
|
+
border: 1px solid var(--color-border);
|
|
242
|
+
text-align: left;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.explorer-doc-content th {
|
|
246
|
+
background: var(--color-surface-raised);
|
|
247
|
+
font-weight: 600;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* ---- Status badges ---- */
|
|
251
|
+
|
|
252
|
+
.explorer-badge {
|
|
253
|
+
display: inline-flex;
|
|
254
|
+
align-items: center;
|
|
255
|
+
padding: 2px 8px;
|
|
256
|
+
border-radius: 999px;
|
|
257
|
+
font-size: 0.75rem;
|
|
258
|
+
font-weight: 500;
|
|
259
|
+
white-space: nowrap;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.explorer-badge--complete {
|
|
263
|
+
background: rgba(52, 211, 153, 0.12);
|
|
264
|
+
color: #6ee7b7;
|
|
265
|
+
border: 1px solid rgba(52, 211, 153, 0.2);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.explorer-badge--building,
|
|
269
|
+
.explorer-badge--in-progress {
|
|
270
|
+
background: rgba(251, 191, 36, 0.12);
|
|
271
|
+
color: #fcd34d;
|
|
272
|
+
border: 1px solid rgba(251, 191, 36, 0.2);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.explorer-badge--pending,
|
|
276
|
+
.explorer-badge--not-started {
|
|
277
|
+
background: rgba(107, 114, 128, 0.12);
|
|
278
|
+
color: #9ca3af;
|
|
279
|
+
border: 1px solid rgba(107, 114, 128, 0.2);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.explorer-badge--covered {
|
|
283
|
+
background: rgba(52, 211, 153, 0.12);
|
|
284
|
+
color: #6ee7b7;
|
|
285
|
+
border: 1px solid rgba(52, 211, 153, 0.2);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.explorer-badge--uncovered {
|
|
289
|
+
background: rgba(248, 113, 113, 0.12);
|
|
290
|
+
color: #fca5a5;
|
|
291
|
+
border: 1px solid rgba(248, 113, 113, 0.2);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/* ---- Todos + Milestones tab toolbar ---- */
|
|
295
|
+
|
|
296
|
+
.explorer-toolbar {
|
|
297
|
+
display: flex;
|
|
298
|
+
align-items: center;
|
|
299
|
+
gap: var(--space-sm);
|
|
300
|
+
margin-bottom: var(--space-md);
|
|
301
|
+
flex-wrap: wrap;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.explorer-search {
|
|
305
|
+
flex: 1;
|
|
306
|
+
min-width: 200px;
|
|
307
|
+
padding: var(--space-xs) var(--space-sm);
|
|
308
|
+
border: 1px solid var(--color-border);
|
|
309
|
+
border-radius: var(--radius-sm);
|
|
310
|
+
background: var(--color-surface);
|
|
311
|
+
color: var(--color-text);
|
|
312
|
+
font-size: 0.9rem;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.explorer-create-form {
|
|
316
|
+
background: var(--color-surface-raised);
|
|
317
|
+
border: 1px solid var(--color-border);
|
|
318
|
+
border-radius: var(--radius-md);
|
|
319
|
+
padding: var(--space-md);
|
|
320
|
+
margin-bottom: var(--space-md);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.explorer-section-title {
|
|
324
|
+
font-size: 0.85rem;
|
|
325
|
+
font-weight: 600;
|
|
326
|
+
color: var(--color-text-dim);
|
|
327
|
+
text-transform: uppercase;
|
|
328
|
+
letter-spacing: 0.05em;
|
|
329
|
+
margin: var(--space-md) 0 var(--space-sm);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/* ---- Button system ---- */
|
|
333
|
+
|
|
334
|
+
.btn {
|
|
335
|
+
display: inline-flex;
|
|
336
|
+
align-items: center;
|
|
337
|
+
gap: 4px;
|
|
338
|
+
padding: var(--space-xs) var(--space-sm);
|
|
339
|
+
border-radius: var(--radius-sm);
|
|
340
|
+
border: 1px solid transparent;
|
|
341
|
+
cursor: pointer;
|
|
342
|
+
font-size: 0.875rem;
|
|
343
|
+
font-weight: 500;
|
|
344
|
+
transition: all 0.15s;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.btn--primary {
|
|
348
|
+
background: var(--color-accent);
|
|
349
|
+
color: white;
|
|
350
|
+
border-color: var(--color-accent);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.btn--ghost {
|
|
354
|
+
background: none;
|
|
355
|
+
color: var(--color-text-dim);
|
|
356
|
+
border-color: var(--color-border);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.btn--sm {
|
|
360
|
+
padding: 2px var(--space-xs);
|
|
361
|
+
font-size: 0.8rem;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.btn--danger {
|
|
365
|
+
background: var(--color-error-bg);
|
|
366
|
+
color: var(--color-error);
|
|
367
|
+
border-color: var(--color-error);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/* ---- Priority badge modifiers ---- */
|
|
371
|
+
|
|
372
|
+
.explorer-badge--high {
|
|
373
|
+
background: var(--color-error-bg);
|
|
374
|
+
color: var(--color-error);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.explorer-badge--medium {
|
|
378
|
+
background: var(--color-warning-bg);
|
|
379
|
+
color: var(--color-warning);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.explorer-badge--low {
|
|
383
|
+
background: var(--color-surface-raised);
|
|
384
|
+
color: var(--color-text-dim);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/* ---- Create form ---- */
|
|
388
|
+
|
|
389
|
+
.explorer-form {
|
|
390
|
+
display: flex;
|
|
391
|
+
flex-direction: column;
|
|
392
|
+
gap: var(--space-sm);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.explorer-form__row {
|
|
396
|
+
display: flex;
|
|
397
|
+
flex-direction: column;
|
|
398
|
+
gap: 4px;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.explorer-form__label {
|
|
402
|
+
font-size: 0.8rem;
|
|
403
|
+
font-weight: 500;
|
|
404
|
+
color: var(--color-text-dim);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.explorer-form__actions {
|
|
408
|
+
display: flex;
|
|
409
|
+
gap: var(--space-sm);
|
|
410
|
+
padding-top: var(--space-sm);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/* ---- Milestone detail ---- */
|
|
414
|
+
|
|
415
|
+
.explorer-milestone-detail {
|
|
416
|
+
display: flex;
|
|
417
|
+
flex-direction: column;
|
|
418
|
+
gap: var(--space-md);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/* ---- Requirements traceability table ---- */
|
|
422
|
+
|
|
423
|
+
.explorer-req-section {
|
|
424
|
+
margin-bottom: var(--space-lg);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.explorer-req-table {
|
|
428
|
+
width: 100%;
|
|
429
|
+
border-collapse: collapse;
|
|
430
|
+
font-size: 0.875rem;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.explorer-req-table th {
|
|
434
|
+
text-align: left;
|
|
435
|
+
padding: var(--space-xs) var(--space-sm);
|
|
436
|
+
border-bottom: 2px solid var(--color-border);
|
|
437
|
+
font-weight: 600;
|
|
438
|
+
color: var(--color-text-dim);
|
|
439
|
+
font-size: 0.8rem;
|
|
440
|
+
text-transform: uppercase;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.explorer-req-table td {
|
|
444
|
+
padding: var(--space-xs) var(--space-sm);
|
|
445
|
+
border-bottom: 1px solid var(--color-border);
|
|
446
|
+
vertical-align: top;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.explorer-req-table tr:hover td {
|
|
450
|
+
background: var(--color-surface-hover);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.explorer-req-id {
|
|
454
|
+
font-family: var(--font-mono);
|
|
455
|
+
font-size: 0.8rem;
|
|
456
|
+
white-space: nowrap;
|
|
457
|
+
color: var(--color-text-dim);
|
|
458
|
+
}
|
|
@@ -35,6 +35,7 @@ export function Layout({ title, children, currentView }: LayoutProps) {
|
|
|
35
35
|
<link rel="stylesheet" href="/css/layout.css" />
|
|
36
36
|
<link rel="stylesheet" href="/css/status-colors.css" />
|
|
37
37
|
<link rel="stylesheet" href="/css/command-center.css" />
|
|
38
|
+
<link rel="stylesheet" href="/css/explorer.css" />
|
|
38
39
|
|
|
39
40
|
{/* Prevent flash of wrong theme */}
|
|
40
41
|
{html`<script>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const TABS = [
|
|
2
|
+
{ id: 'phases', label: 'Phases', api: '/api/explorer/phases' },
|
|
3
|
+
{ id: 'todos', label: 'Todos', api: '/api/explorer/todos' },
|
|
4
|
+
{ id: 'milestones', label: 'Milestones', api: '/api/explorer/milestones' },
|
|
5
|
+
{ id: 'research', label: 'Research', api: '/api/explorer/research' },
|
|
6
|
+
{ id: 'requirements', label: 'Requirements', api: '/api/explorer/requirements' },
|
|
7
|
+
{ id: 'notes', label: 'Notes', api: '/api/explorer/notes' },
|
|
8
|
+
{ id: 'audits', label: 'Audits', api: '/api/explorer/audits' },
|
|
9
|
+
{ id: 'quick', label: 'Quick Tasks', api: '/api/explorer/quick' },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
export function ExplorerPage() {
|
|
13
|
+
return (
|
|
14
|
+
<div
|
|
15
|
+
class="explorer"
|
|
16
|
+
x-data={`{
|
|
17
|
+
activeTab: 'phases',
|
|
18
|
+
loaded: {},
|
|
19
|
+
switchTab(id) {
|
|
20
|
+
this.activeTab = id;
|
|
21
|
+
}
|
|
22
|
+
}`}
|
|
23
|
+
>
|
|
24
|
+
<div class="explorer__tabs" role="tablist" aria-label="Explorer tabs">
|
|
25
|
+
{TABS.map(tab => (
|
|
26
|
+
<button
|
|
27
|
+
key={tab.id}
|
|
28
|
+
role="tab"
|
|
29
|
+
class="explorer__tab-btn"
|
|
30
|
+
x-bind:aria-selected={`activeTab === '${tab.id}'`}
|
|
31
|
+
x-on:click={`switchTab('${tab.id}')`}
|
|
32
|
+
id={`tab-${tab.id}`}
|
|
33
|
+
aria-controls={`panel-${tab.id}`}
|
|
34
|
+
>
|
|
35
|
+
{tab.label}
|
|
36
|
+
</button>
|
|
37
|
+
))}
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
{TABS.map(tab => (
|
|
41
|
+
<div
|
|
42
|
+
key={tab.id}
|
|
43
|
+
id={`panel-${tab.id}`}
|
|
44
|
+
role="tabpanel"
|
|
45
|
+
aria-labelledby={`tab-${tab.id}`}
|
|
46
|
+
class="explorer__tab-content"
|
|
47
|
+
x-show={`activeTab === '${tab.id}'`}
|
|
48
|
+
hx-get={tab.api}
|
|
49
|
+
hx-trigger="intersect once"
|
|
50
|
+
hx-swap="innerHTML"
|
|
51
|
+
>
|
|
52
|
+
<div class="explorer__loading">Loading...</div>
|
|
53
|
+
</div>
|
|
54
|
+
))}
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function auditDetailHtml(report: any): string {
|
|
2
|
+
if (!report) return '<p class="explorer__loading">Report not found.</p>';
|
|
3
|
+
return `<div class="explorer-doc-content">${report.html}</div>`;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function AuditsTab({ reports }: { reports: any[] }) {
|
|
7
|
+
return (
|
|
8
|
+
<div class="explorer-list">
|
|
9
|
+
{reports.length === 0 && <p class="explorer__loading">No audit reports.</p>}
|
|
10
|
+
{reports.map(report => (
|
|
11
|
+
<div class="explorer-item" x-data="{ open: false }" key={report.filename}>
|
|
12
|
+
<div class="explorer-item__header" x-on:click="open = !open">
|
|
13
|
+
<span class="explorer-item__toggle"
|
|
14
|
+
x-bind:class="open ? 'explorer-item__toggle--open' : ''">▶</span>
|
|
15
|
+
<span class="explorer-item__title">{report.title || report.filename}</span>
|
|
16
|
+
<span class="explorer-item__meta">{report.date}</span>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="explorer-item__body" x-show="open" x-cloak>
|
|
19
|
+
<div hx-get={`/api/explorer/audits/${encodeURIComponent(report.filename)}`}
|
|
20
|
+
hx-trigger="load"
|
|
21
|
+
hx-swap="innerHTML">
|
|
22
|
+
<span class="explorer__loading">Loading...</span>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
))}
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
interface Milestone {
|
|
2
|
+
version: string;
|
|
3
|
+
name?: string;
|
|
4
|
+
date?: string;
|
|
5
|
+
duration?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface MilestoneDetail {
|
|
9
|
+
version: string;
|
|
10
|
+
sections: Array<{ type: string; html: string }>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface MilestonesTabProps {
|
|
14
|
+
active: Milestone[];
|
|
15
|
+
archived: Milestone[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface MilestoneItemProps {
|
|
19
|
+
milestone: Milestone;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function MilestonesTab({ active, archived }: MilestonesTabProps) {
|
|
23
|
+
return (
|
|
24
|
+
<div>
|
|
25
|
+
{/* Active milestones section */}
|
|
26
|
+
<h3 class="explorer-section-title">Active</h3>
|
|
27
|
+
{active.length === 0 && <p class="explorer__loading">No active milestones.</p>}
|
|
28
|
+
<div class="explorer-list">
|
|
29
|
+
{active.map((ms) => (
|
|
30
|
+
<div class="explorer-item" key={ms.version}>
|
|
31
|
+
<div class="explorer-item__header">
|
|
32
|
+
<span class="explorer-item__title">v{ms.version}</span>
|
|
33
|
+
<span class="explorer-badge explorer-badge--building">active</span>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
))}
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
{/* Archived milestones section */}
|
|
40
|
+
<h3 class="explorer-section-title" style="margin-top: var(--space-lg)">
|
|
41
|
+
Archived
|
|
42
|
+
</h3>
|
|
43
|
+
{archived.length === 0 && <p class="explorer__loading">No archived milestones.</p>}
|
|
44
|
+
<div class="explorer-list">
|
|
45
|
+
{archived.map((ms) => (
|
|
46
|
+
<MilestoneItem key={ms.version} milestone={ms} />
|
|
47
|
+
))}
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function MilestoneItem({ milestone }: MilestoneItemProps) {
|
|
54
|
+
return (
|
|
55
|
+
<div class="explorer-item" x-data="{ open: false }">
|
|
56
|
+
<div class="explorer-item__header" x-on:click="open = !open">
|
|
57
|
+
<span
|
|
58
|
+
class="explorer-item__toggle"
|
|
59
|
+
x-bind:class="open ? 'explorer-item__toggle--open' : ''"
|
|
60
|
+
>
|
|
61
|
+
▶
|
|
62
|
+
</span>
|
|
63
|
+
<span class="explorer-item__title">v{milestone.version}</span>
|
|
64
|
+
<span class="explorer-badge explorer-badge--complete">archived</span>
|
|
65
|
+
</div>
|
|
66
|
+
<div class="explorer-item__body" x-show="open" x-cloak>
|
|
67
|
+
<div
|
|
68
|
+
hx-get={`/api/explorer/milestones/${milestone.version}`}
|
|
69
|
+
hx-trigger="load"
|
|
70
|
+
hx-swap="innerHTML"
|
|
71
|
+
>
|
|
72
|
+
<span class="explorer__loading">Loading...</span>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function milestoneDetailHtml(detail: MilestoneDetail | null): string {
|
|
80
|
+
if (!detail) return '<p class="explorer__loading">Not found.</p>';
|
|
81
|
+
return detail.sections
|
|
82
|
+
.map((s) => `<div class="explorer-doc-content">${s.html}</div>`)
|
|
83
|
+
.join('');
|
|
84
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function noteDetailHtml(note: any): string {
|
|
2
|
+
if (!note) return '<p class="explorer__loading">Note not found.</p>';
|
|
3
|
+
return `<div class="explorer-doc-content">${note.html}</div>`;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function NotesTab({ notes }: { notes: any[] }) {
|
|
7
|
+
return (
|
|
8
|
+
<div class="explorer-list">
|
|
9
|
+
{notes.length === 0 && <p class="explorer__loading">No notes.</p>}
|
|
10
|
+
{notes.map(note => (
|
|
11
|
+
<div class="explorer-item" x-data="{ open: false }" key={note.filename}>
|
|
12
|
+
<div class="explorer-item__header" x-on:click="open = !open">
|
|
13
|
+
<span class="explorer-item__toggle"
|
|
14
|
+
x-bind:class="open ? 'explorer-item__toggle--open' : ''">▶</span>
|
|
15
|
+
<span class="explorer-item__title">{note.title || note.filename}</span>
|
|
16
|
+
<span class="explorer-item__meta">{note.date}</span>
|
|
17
|
+
{note.promoted && (
|
|
18
|
+
<span class="explorer-badge explorer-badge--complete">promoted</span>
|
|
19
|
+
)}
|
|
20
|
+
</div>
|
|
21
|
+
<div class="explorer-item__body" x-show="open" x-cloak>
|
|
22
|
+
<div hx-get={`/api/explorer/notes/${encodeURIComponent(note.filename.replace(/\.md$/, ''))}`}
|
|
23
|
+
hx-trigger="load"
|
|
24
|
+
hx-swap="innerHTML">
|
|
25
|
+
<span class="explorer__loading">Loading...</span>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
))}
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|