@plannotator/pi-extension 0.19.12 → 0.19.14
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/package.json +1 -1
- package/plannotator.html +2 -2
- package/review-editor.html +2 -2
- package/skills/plannotator-visual-explainer/SKILL.md +73 -86
- package/skills/plannotator-visual-explainer/references/design-system.md +560 -0
- package/skills/plannotator-visual-explainer/references/pr-components.md +717 -0
- package/skills/plannotator-visual-explainer/references/svg-patterns.md +368 -0
- package/skills/plannotator-visual-explainer/references/extended-patterns.md +0 -629
|
@@ -1,629 +0,0 @@
|
|
|
1
|
-
# Extended Patterns
|
|
2
|
-
|
|
3
|
-
Components that complement visual-explainer's toolkit. These use the same Plannotator theme tokens from `theme-override.md` and can be mixed freely with Nico's `.ve-card`, `.kpi-card`, `.pipeline` patterns.
|
|
4
|
-
|
|
5
|
-
## Timeline
|
|
6
|
-
|
|
7
|
-
Vertical timeline showing phases or sequence — without time estimates. Shows ordering and dependencies, not duration.
|
|
8
|
-
|
|
9
|
-
```html
|
|
10
|
-
<div class="timeline">
|
|
11
|
-
<div class="timeline-item">
|
|
12
|
-
<div class="timeline-label">Phase 1</div>
|
|
13
|
-
<div class="timeline-dot-col">
|
|
14
|
-
<div class="timeline-dot active"></div>
|
|
15
|
-
<div class="timeline-line"></div>
|
|
16
|
-
</div>
|
|
17
|
-
<div class="timeline-content">
|
|
18
|
-
<h4>Foundation</h4>
|
|
19
|
-
<p>Set up the core infrastructure and initial integrations.</p>
|
|
20
|
-
</div>
|
|
21
|
-
</div>
|
|
22
|
-
<!-- more items -->
|
|
23
|
-
</div>
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
```css
|
|
27
|
-
.timeline { display: flex; flex-direction: column; gap: 0; }
|
|
28
|
-
|
|
29
|
-
.timeline-item {
|
|
30
|
-
display: grid;
|
|
31
|
-
grid-template-columns: 100px 28px 1fr;
|
|
32
|
-
gap: 16px;
|
|
33
|
-
min-height: 80px;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.timeline-label {
|
|
37
|
-
font-family: var(--font-mono);
|
|
38
|
-
font-size: 0.75rem;
|
|
39
|
-
color: var(--muted-foreground);
|
|
40
|
-
text-align: right;
|
|
41
|
-
padding-top: 4px;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
.timeline-dot-col {
|
|
45
|
-
display: flex;
|
|
46
|
-
flex-direction: column;
|
|
47
|
-
align-items: center;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.timeline-dot {
|
|
51
|
-
width: 14px;
|
|
52
|
-
height: 14px;
|
|
53
|
-
border-radius: 50%;
|
|
54
|
-
background: var(--card);
|
|
55
|
-
border: 3px solid var(--primary);
|
|
56
|
-
flex-shrink: 0;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
.timeline-dot.active { background: var(--primary); }
|
|
60
|
-
|
|
61
|
-
.timeline-line {
|
|
62
|
-
width: 2px;
|
|
63
|
-
flex: 1;
|
|
64
|
-
background: var(--border);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.timeline-content { padding-bottom: 24px; }
|
|
68
|
-
|
|
69
|
-
.timeline-content h4 {
|
|
70
|
-
font-family: var(--font-display);
|
|
71
|
-
font-size: 1rem;
|
|
72
|
-
font-weight: 500;
|
|
73
|
-
margin-bottom: 4px;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
.timeline-content p {
|
|
77
|
-
font-size: 0.88rem;
|
|
78
|
-
color: var(--muted-foreground);
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
The last timeline item should hide the line: `style="background: transparent"` on the `.timeline-line`.
|
|
83
|
-
|
|
84
|
-
## Code Blocks with Syntax Highlighting
|
|
85
|
-
|
|
86
|
-
Dark-themed code panels showing key interfaces, schemas, or API signatures. Use sparingly — show the 5-10 lines that matter, not full files.
|
|
87
|
-
|
|
88
|
-
```html
|
|
89
|
-
<div class="code-panel">
|
|
90
|
-
<span class="code-file">src/api/handler.ts</span>
|
|
91
|
-
<pre><code><span class="kw">interface</span> <span class="fn">Config</span> {
|
|
92
|
-
<span class="fn">port</span>: <span class="kw">number</span>;
|
|
93
|
-
<span class="fn">host</span>: <span class="kw">string</span>;
|
|
94
|
-
}</code></pre>
|
|
95
|
-
</div>
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
```css
|
|
99
|
-
.code-panel {
|
|
100
|
-
background: var(--code-bg);
|
|
101
|
-
border: 1.5px solid var(--border);
|
|
102
|
-
border-radius: var(--radius);
|
|
103
|
-
padding: 20px 24px;
|
|
104
|
-
overflow-x: auto;
|
|
105
|
-
margin: 16px 0;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
.code-file {
|
|
109
|
-
font-family: var(--font-mono);
|
|
110
|
-
font-size: 0.7rem;
|
|
111
|
-
color: var(--muted-foreground);
|
|
112
|
-
display: block;
|
|
113
|
-
margin-bottom: 8px;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.code-panel pre {
|
|
117
|
-
margin: 0;
|
|
118
|
-
font-family: var(--font-mono);
|
|
119
|
-
font-size: 0.85rem;
|
|
120
|
-
line-height: 1.55;
|
|
121
|
-
color: var(--foreground);
|
|
122
|
-
white-space: pre-wrap;
|
|
123
|
-
word-break: break-word;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
.code-panel .kw { color: var(--primary); }
|
|
127
|
-
.code-panel .fn { color: var(--accent); }
|
|
128
|
-
.code-panel .str { color: var(--success); }
|
|
129
|
-
.code-panel .cm { color: var(--muted-foreground); font-style: italic; }
|
|
130
|
-
.code-panel .num { color: var(--warning); }
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
## Risk Table
|
|
134
|
-
|
|
135
|
-
Severity-graded risk assessment with colored badges.
|
|
136
|
-
|
|
137
|
-
```html
|
|
138
|
-
<div class="risk-grid">
|
|
139
|
-
<div class="risk-row">
|
|
140
|
-
<div class="risk-name">Database migration on live table</div>
|
|
141
|
-
<div><span class="risk-badge risk-high">HIGH</span></div>
|
|
142
|
-
<div class="risk-mitigation">Run during off-peak with online DDL</div>
|
|
143
|
-
</div>
|
|
144
|
-
</div>
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
```css
|
|
148
|
-
.risk-grid {
|
|
149
|
-
border: 1.5px solid var(--border);
|
|
150
|
-
border-radius: var(--radius);
|
|
151
|
-
overflow: hidden;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
.risk-row {
|
|
155
|
-
display: grid;
|
|
156
|
-
grid-template-columns: 1fr auto 1.5fr;
|
|
157
|
-
gap: 24px;
|
|
158
|
-
padding: 16px 24px;
|
|
159
|
-
align-items: center;
|
|
160
|
-
border-bottom: 1px solid var(--border);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
.risk-row:last-child { border-bottom: none; }
|
|
164
|
-
.risk-name { font-weight: 500; }
|
|
165
|
-
.risk-mitigation { font-size: 0.9rem; color: var(--muted-foreground); }
|
|
166
|
-
|
|
167
|
-
.risk-badge {
|
|
168
|
-
font-family: var(--font-mono);
|
|
169
|
-
font-size: 0.65rem;
|
|
170
|
-
font-weight: 600;
|
|
171
|
-
padding: 2px 8px;
|
|
172
|
-
border-radius: 4px;
|
|
173
|
-
text-transform: uppercase;
|
|
174
|
-
letter-spacing: 0.04em;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
.risk-high {
|
|
178
|
-
background: color-mix(in oklab, var(--destructive) 15%, transparent);
|
|
179
|
-
color: var(--destructive);
|
|
180
|
-
}
|
|
181
|
-
.risk-med {
|
|
182
|
-
background: color-mix(in oklab, var(--warning) 15%, transparent);
|
|
183
|
-
color: var(--warning);
|
|
184
|
-
}
|
|
185
|
-
.risk-low {
|
|
186
|
-
background: color-mix(in oklab, var(--success) 15%, transparent);
|
|
187
|
-
color: var(--success);
|
|
188
|
-
}
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
## Open Questions
|
|
192
|
-
|
|
193
|
-
Callout cards for unresolved decisions. Each names who can answer.
|
|
194
|
-
|
|
195
|
-
```html
|
|
196
|
-
<div class="question">
|
|
197
|
-
<h3>Should we use WebSockets or SSE?</h3>
|
|
198
|
-
<p>SSE is simpler but unidirectional. WebSockets add infrastructure complexity.</p>
|
|
199
|
-
<span class="question-owner">Decide with: infrastructure team</span>
|
|
200
|
-
</div>
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
```css
|
|
204
|
-
.question {
|
|
205
|
-
border-left: 3px solid var(--primary);
|
|
206
|
-
padding: 16px 24px;
|
|
207
|
-
margin: 16px 0;
|
|
208
|
-
background: var(--card);
|
|
209
|
-
border-radius: 0 var(--radius) var(--radius) 0;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
.question h3 {
|
|
213
|
-
font-family: var(--font-display);
|
|
214
|
-
font-size: 1.05rem;
|
|
215
|
-
font-weight: 500;
|
|
216
|
-
margin-bottom: 4px;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
.question p {
|
|
220
|
-
font-size: 0.9rem;
|
|
221
|
-
color: var(--muted-foreground);
|
|
222
|
-
line-height: 1.55;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
.question-owner {
|
|
226
|
-
font-family: var(--font-mono);
|
|
227
|
-
font-size: 0.72rem;
|
|
228
|
-
color: var(--primary);
|
|
229
|
-
font-weight: 500;
|
|
230
|
-
display: block;
|
|
231
|
-
margin-top: 8px;
|
|
232
|
-
}
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
## Inline SVG Diagrams
|
|
236
|
-
|
|
237
|
-
For architecture, data flow, and simple flowcharts where Mermaid is overkill (under 8 nodes, simple topology). These produce crisp, theme-aware vector diagrams drawn directly in the HTML. Use Mermaid for anything with complex edge routing (10+ nodes, many crossing connections).
|
|
238
|
-
|
|
239
|
-
### Container
|
|
240
|
-
|
|
241
|
-
```html
|
|
242
|
-
<div class="svg-panel">
|
|
243
|
-
<svg viewBox="0 0 720 280" xmlns="http://www.w3.org/2000/svg" style="width:100%">
|
|
244
|
-
<!-- diagram content -->
|
|
245
|
-
</svg>
|
|
246
|
-
<span class="svg-caption">Request flow through the API gateway</span>
|
|
247
|
-
</div>
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
```css
|
|
251
|
-
.svg-panel {
|
|
252
|
-
border: 1.5px solid var(--border);
|
|
253
|
-
border-radius: var(--radius);
|
|
254
|
-
padding: 24px;
|
|
255
|
-
margin: 24px 0;
|
|
256
|
-
background: var(--card);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
.svg-caption {
|
|
260
|
-
font-family: var(--font-mono);
|
|
261
|
-
font-size: 0.72rem;
|
|
262
|
-
color: var(--muted-foreground);
|
|
263
|
-
display: block;
|
|
264
|
-
margin-top: 8px;
|
|
265
|
-
text-align: center;
|
|
266
|
-
}
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### Arrow markers
|
|
270
|
-
|
|
271
|
-
Define in `<defs>`. Reference via `marker-end="url(#arrow)"`.
|
|
272
|
-
|
|
273
|
-
```svg
|
|
274
|
-
<defs>
|
|
275
|
-
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5"
|
|
276
|
-
markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
|
277
|
-
<path d="M0,0 L10,5 L0,10 z" fill="var(--muted-foreground)"/>
|
|
278
|
-
</marker>
|
|
279
|
-
<marker id="arrow-primary" viewBox="0 0 10 10" refX="9" refY="5"
|
|
280
|
-
markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
|
281
|
-
<path d="M0,0 L10,5 L0,10 z" fill="var(--primary)"/>
|
|
282
|
-
</marker>
|
|
283
|
-
<marker id="arrow-success" viewBox="0 0 10 10" refX="9" refY="5"
|
|
284
|
-
markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
|
285
|
-
<path d="M0,0 L10,5 L0,10 z" fill="var(--success)"/>
|
|
286
|
-
</marker>
|
|
287
|
-
<marker id="arrow-destructive" viewBox="0 0 10 10" refX="9" refY="5"
|
|
288
|
-
markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
|
289
|
-
<path d="M0,0 L10,5 L0,10 z" fill="var(--destructive)"/>
|
|
290
|
-
</marker>
|
|
291
|
-
</defs>
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
### Box node
|
|
295
|
-
|
|
296
|
-
```svg
|
|
297
|
-
<g transform="translate(100, 80)">
|
|
298
|
-
<rect width="140" height="56" rx="10" fill="var(--card)"
|
|
299
|
-
stroke="var(--border)" stroke-width="1.5"/>
|
|
300
|
-
<text x="70" y="24" text-anchor="middle"
|
|
301
|
-
font-family="var(--font-sans)" font-size="13" font-weight="600"
|
|
302
|
-
fill="var(--foreground)">API Server</text>
|
|
303
|
-
<text x="70" y="40" text-anchor="middle"
|
|
304
|
-
font-family="var(--font-mono)" font-size="10.5"
|
|
305
|
-
fill="var(--muted-foreground)">Express + middleware</text>
|
|
306
|
-
</g>
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
### Highlighted box (new or hot-path component)
|
|
310
|
-
|
|
311
|
-
```svg
|
|
312
|
-
<g transform="translate(100, 80)">
|
|
313
|
-
<rect width="140" height="56" rx="10"
|
|
314
|
-
fill="color-mix(in oklab, var(--primary) 8%, transparent)"
|
|
315
|
-
stroke="var(--primary)" stroke-width="1.5"/>
|
|
316
|
-
<text x="70" y="24" text-anchor="middle"
|
|
317
|
-
font-family="var(--font-sans)" font-size="13" font-weight="600"
|
|
318
|
-
fill="var(--foreground)">New Service</text>
|
|
319
|
-
<text x="70" y="40" text-anchor="middle"
|
|
320
|
-
font-family="var(--font-mono)" font-size="10.5"
|
|
321
|
-
fill="var(--primary)">to be created</text>
|
|
322
|
-
</g>
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
### Connecting arrows
|
|
326
|
-
|
|
327
|
-
```svg
|
|
328
|
-
<!-- Horizontal -->
|
|
329
|
-
<line x1="240" y1="108" x2="320" y2="108"
|
|
330
|
-
stroke="var(--muted-foreground)" stroke-width="1.5"
|
|
331
|
-
marker-end="url(#arrow)"/>
|
|
332
|
-
|
|
333
|
-
<!-- Vertical -->
|
|
334
|
-
<line x1="170" y1="136" x2="170" y2="200"
|
|
335
|
-
stroke="var(--muted-foreground)" stroke-width="1.5"
|
|
336
|
-
marker-end="url(#arrow)"/>
|
|
337
|
-
|
|
338
|
-
<!-- Dashed (async, optional, or secondary path) -->
|
|
339
|
-
<line x1="240" y1="108" x2="320" y2="108"
|
|
340
|
-
stroke="var(--primary)" stroke-width="1.5"
|
|
341
|
-
stroke-dasharray="5 4"
|
|
342
|
-
marker-end="url(#arrow-primary)"/>
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
### Edge labels
|
|
346
|
-
|
|
347
|
-
```svg
|
|
348
|
-
<text x="280" y="100" text-anchor="middle"
|
|
349
|
-
font-family="var(--font-mono)" font-size="9.5"
|
|
350
|
-
fill="var(--muted-foreground)">REST</text>
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
### Flowchart elements
|
|
354
|
-
|
|
355
|
-
```svg
|
|
356
|
-
<!-- Decision diamond -->
|
|
357
|
-
<path d="M310,262 L352,294 L310,326 L268,294 Z"
|
|
358
|
-
fill="var(--card)" stroke="var(--border)" stroke-width="1.5"/>
|
|
359
|
-
<text x="310" y="298" text-anchor="middle"
|
|
360
|
-
font-family="var(--font-sans)" font-size="11" font-weight="500"
|
|
361
|
-
fill="var(--foreground)">Valid?</text>
|
|
362
|
-
|
|
363
|
-
<!-- Terminal / pill node -->
|
|
364
|
-
<rect x="260" y="20" width="100" height="36" rx="18"
|
|
365
|
-
fill="var(--card)" stroke="var(--border)" stroke-width="1.5"/>
|
|
366
|
-
|
|
367
|
-
<!-- Success endpoint -->
|
|
368
|
-
<rect x="260" y="400" width="100" height="36" rx="18"
|
|
369
|
-
fill="color-mix(in oklab, var(--success) 12%, transparent)"
|
|
370
|
-
stroke="var(--success)" stroke-width="1.5"/>
|
|
371
|
-
|
|
372
|
-
<!-- Failure endpoint -->
|
|
373
|
-
<rect x="100" y="400" width="100" height="36" rx="18"
|
|
374
|
-
fill="color-mix(in oklab, var(--destructive) 12%, transparent)"
|
|
375
|
-
stroke="var(--destructive)" stroke-width="1.5"/>
|
|
376
|
-
|
|
377
|
-
<!-- Curved branch from decision to side -->
|
|
378
|
-
<path d="M268,294 C200,294 160,294 160,240"
|
|
379
|
-
fill="none" stroke="var(--destructive)" stroke-width="1.5"
|
|
380
|
-
marker-end="url(#arrow-destructive)"/>
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
### Data flow (request/response)
|
|
384
|
-
|
|
385
|
-
```svg
|
|
386
|
-
<!-- Request (solid) -->
|
|
387
|
-
<line x1="140" y1="100" x2="280" y2="100"
|
|
388
|
-
stroke="var(--muted-foreground)" stroke-width="1.5"
|
|
389
|
-
marker-end="url(#arrow)"/>
|
|
390
|
-
<text x="210" y="92" text-anchor="middle"
|
|
391
|
-
font-family="var(--font-mono)" font-size="9.5"
|
|
392
|
-
fill="var(--muted-foreground)">POST /api/plan</text>
|
|
393
|
-
|
|
394
|
-
<!-- Response (dashed) -->
|
|
395
|
-
<line x1="280" y1="116" x2="140" y2="116"
|
|
396
|
-
stroke="var(--primary)" stroke-width="1.5" stroke-dasharray="5 4"
|
|
397
|
-
marker-end="url(#arrow-primary)"/>
|
|
398
|
-
<text x="210" y="132" text-anchor="middle"
|
|
399
|
-
font-family="var(--font-mono)" font-size="9.5"
|
|
400
|
-
fill="var(--primary)">{ plan, status }</text>
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
### Fan-out pattern
|
|
404
|
-
|
|
405
|
-
```svg
|
|
406
|
-
<line x1="200" y1="100" x2="340" y2="60"
|
|
407
|
-
stroke="var(--muted-foreground)" stroke-width="1.5" marker-end="url(#arrow)"/>
|
|
408
|
-
<line x1="200" y1="100" x2="340" y2="100"
|
|
409
|
-
stroke="var(--muted-foreground)" stroke-width="1.5" marker-end="url(#arrow)"/>
|
|
410
|
-
<line x1="200" y1="100" x2="340" y2="140"
|
|
411
|
-
stroke="var(--muted-foreground)" stroke-width="1.5" marker-end="url(#arrow)"/>
|
|
412
|
-
```
|
|
413
|
-
|
|
414
|
-
### Bar chart
|
|
415
|
-
|
|
416
|
-
```svg
|
|
417
|
-
<svg viewBox="0 0 400 180" xmlns="http://www.w3.org/2000/svg"
|
|
418
|
-
style="width:100%;max-width:400px">
|
|
419
|
-
<!-- Gridlines -->
|
|
420
|
-
<line x1="40" y1="20" x2="380" y2="20" stroke="var(--border)" stroke-width="1" opacity="0.5"/>
|
|
421
|
-
<line x1="40" y1="60" x2="380" y2="60" stroke="var(--border)" stroke-width="1" opacity="0.5"/>
|
|
422
|
-
<line x1="40" y1="100" x2="380" y2="100" stroke="var(--border)" stroke-width="1" opacity="0.5"/>
|
|
423
|
-
<line x1="40" y1="140" x2="380" y2="140" stroke="var(--border)" stroke-width="1"/>
|
|
424
|
-
|
|
425
|
-
<!-- Bars (muted default, primary for peak) -->
|
|
426
|
-
<rect x="60" y="60" width="40" height="80" rx="4" fill="var(--muted)"/>
|
|
427
|
-
<rect x="120" y="40" width="40" height="100" rx="4" fill="var(--primary)"/>
|
|
428
|
-
<rect x="180" y="80" width="40" height="60" rx="4" fill="var(--muted)"/>
|
|
429
|
-
|
|
430
|
-
<!-- Value labels above bars -->
|
|
431
|
-
<text x="140" y="35" text-anchor="middle"
|
|
432
|
-
font-family="var(--font-mono)" font-size="10" font-weight="600"
|
|
433
|
-
fill="var(--primary)">25</text>
|
|
434
|
-
|
|
435
|
-
<!-- X-axis labels -->
|
|
436
|
-
<text x="80" y="158" text-anchor="middle"
|
|
437
|
-
font-family="var(--font-mono)" font-size="9"
|
|
438
|
-
fill="var(--muted-foreground)">Q1</text>
|
|
439
|
-
</svg>
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
### Using CSS classes in SVG
|
|
443
|
-
|
|
444
|
-
For cleaner markup, define reusable classes inside the SVG:
|
|
445
|
-
|
|
446
|
-
```svg
|
|
447
|
-
<svg viewBox="0 0 720 280" xmlns="http://www.w3.org/2000/svg">
|
|
448
|
-
<style>
|
|
449
|
-
.box { fill: var(--card); stroke: var(--border); stroke-width: 1.5; }
|
|
450
|
-
.new { fill: color-mix(in oklab, var(--primary) 8%, transparent);
|
|
451
|
-
stroke: var(--primary); stroke-width: 1.5; }
|
|
452
|
-
.title { font-family: var(--font-sans); font-size: 13px;
|
|
453
|
-
font-weight: 600; fill: var(--foreground); }
|
|
454
|
-
.sub { font-family: var(--font-mono); font-size: 10.5px;
|
|
455
|
-
fill: var(--muted-foreground); }
|
|
456
|
-
.conn { stroke: var(--muted-foreground); stroke-width: 1.5; }
|
|
457
|
-
</style>
|
|
458
|
-
</svg>
|
|
459
|
-
```
|
|
460
|
-
|
|
461
|
-
### Positioning rules
|
|
462
|
-
|
|
463
|
-
- `viewBox` with fixed coordinates + `style="width:100%;max-width:720px"` for responsive scaling
|
|
464
|
-
- Standard node: `120–160px` wide, `48–56px` tall
|
|
465
|
-
- Minimum gap: `60px` horizontal, `40px` vertical
|
|
466
|
-
- Arrow label offset: `8–12px` above the line
|
|
467
|
-
|
|
468
|
-
### Color roles in SVG
|
|
469
|
-
|
|
470
|
-
| Element | Token |
|
|
471
|
-
|---------|-------|
|
|
472
|
-
| Box background | `var(--card)` |
|
|
473
|
-
| Box stroke | `var(--border)` |
|
|
474
|
-
| Highlighted box | `var(--primary)` stroke, `color-mix(in oklab, var(--primary) 8%, transparent)` fill |
|
|
475
|
-
| Arrows / connectors | `var(--muted-foreground)` |
|
|
476
|
-
| Title text | `var(--foreground)` |
|
|
477
|
-
| Subtitle / labels | `var(--muted-foreground)` |
|
|
478
|
-
| Success path | `var(--success)` |
|
|
479
|
-
| Error path | `var(--destructive)` |
|
|
480
|
-
| Warning | `var(--warning)` |
|
|
481
|
-
|
|
482
|
-
## Section Headers
|
|
483
|
-
|
|
484
|
-
Numbered sections with display font headings:
|
|
485
|
-
|
|
486
|
-
```css
|
|
487
|
-
.section-header {
|
|
488
|
-
display: flex;
|
|
489
|
-
align-items: baseline;
|
|
490
|
-
gap: 14px;
|
|
491
|
-
margin-bottom: 24px;
|
|
492
|
-
padding-bottom: 8px;
|
|
493
|
-
border-bottom: 1.5px solid var(--border);
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
.section-num {
|
|
497
|
-
font-family: var(--font-mono);
|
|
498
|
-
font-size: 0.75rem;
|
|
499
|
-
font-weight: 600;
|
|
500
|
-
color: var(--primary);
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
.section-header h2 {
|
|
504
|
-
font-family: var(--font-display);
|
|
505
|
-
font-size: 1.35rem;
|
|
506
|
-
font-weight: 500;
|
|
507
|
-
}
|
|
508
|
-
```
|
|
509
|
-
|
|
510
|
-
## Tag Chips
|
|
511
|
-
|
|
512
|
-
Small inline labels for categorizing items:
|
|
513
|
-
|
|
514
|
-
```css
|
|
515
|
-
.tag {
|
|
516
|
-
font-family: var(--font-mono);
|
|
517
|
-
font-size: 0.68rem;
|
|
518
|
-
padding: 2px 8px;
|
|
519
|
-
border-radius: 4px;
|
|
520
|
-
background: var(--muted);
|
|
521
|
-
color: var(--muted-foreground);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
.tag-highlight {
|
|
525
|
-
background: color-mix(in oklab, var(--primary) 12%, transparent);
|
|
526
|
-
color: var(--primary);
|
|
527
|
-
}
|
|
528
|
-
```
|
|
529
|
-
|
|
530
|
-
## Diff Rendering (for PR reviews)
|
|
531
|
-
|
|
532
|
-
Use Pierre diffs via CDN for syntax-highlighted, theme-aware diff rendering. Pierre renders into shadow DOM (no style conflicts) and supports Plannotator theme tokens via CSS variable injection.
|
|
533
|
-
|
|
534
|
-
```html
|
|
535
|
-
<script type="module">
|
|
536
|
-
import { getSingularPatch, registerDiffsComponent } from 'https://cdn.jsdelivr.net/npm/@pierre/diffs@1.1.21/+esm';
|
|
537
|
-
|
|
538
|
-
registerDiffsComponent();
|
|
539
|
-
|
|
540
|
-
const patch = `--- a/src/handler.ts
|
|
541
|
-
+++ b/src/handler.ts
|
|
542
|
-
@@ -1,4 +1,6 @@
|
|
543
|
-
import { Router } from 'express';
|
|
544
|
-
+import { NotificationService } from './notifications';
|
|
545
|
-
-import { legacyPoll } from './polling';
|
|
546
|
-
|
|
547
|
-
export function createHandler() {`;
|
|
548
|
-
|
|
549
|
-
const fileDiff = getSingularPatch(patch);
|
|
550
|
-
|
|
551
|
-
const container = document.querySelector('diffs-container');
|
|
552
|
-
container.fileDiff = fileDiff;
|
|
553
|
-
container.options = {
|
|
554
|
-
themeType: window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light',
|
|
555
|
-
diffStyle: 'unified',
|
|
556
|
-
diffIndicators: 'bars',
|
|
557
|
-
lineDiffType: 'word-alt',
|
|
558
|
-
unsafeCSS: `
|
|
559
|
-
:host {
|
|
560
|
-
--diffs-bg: var(--background);
|
|
561
|
-
--diffs-fg: var(--foreground);
|
|
562
|
-
--diffs-dark-bg: var(--background);
|
|
563
|
-
--diffs-light-bg: var(--background);
|
|
564
|
-
--diffs-dark: var(--foreground);
|
|
565
|
-
--diffs-light: var(--foreground);
|
|
566
|
-
border-radius: var(--radius);
|
|
567
|
-
border: 1.5px solid var(--border);
|
|
568
|
-
overflow: hidden;
|
|
569
|
-
}
|
|
570
|
-
`,
|
|
571
|
-
};
|
|
572
|
-
</script>
|
|
573
|
-
|
|
574
|
-
<diffs-container></diffs-container>
|
|
575
|
-
```
|
|
576
|
-
|
|
577
|
-
Pierre handles syntax highlighting (via Shiki), line numbers, add/del coloring, word-level diffs, and split/unified views automatically. The `unsafeCSS` option injects Plannotator theme tokens into the shadow DOM.
|
|
578
|
-
|
|
579
|
-
For multiple diffs on one page, create one `<diffs-container>` per file and set `fileDiff` + `options` on each.
|
|
580
|
-
|
|
581
|
-
## Review Comment Bubbles (for PR reviews)
|
|
582
|
-
|
|
583
|
-
Speech bubbles with severity-coded left borders.
|
|
584
|
-
|
|
585
|
-
```css
|
|
586
|
-
.bubble {
|
|
587
|
-
position: relative;
|
|
588
|
-
background: var(--card);
|
|
589
|
-
border: 1.5px solid var(--border);
|
|
590
|
-
border-left-width: 4px;
|
|
591
|
-
border-radius: 8px;
|
|
592
|
-
padding: 12px 14px 12px 16px;
|
|
593
|
-
max-width: 680px;
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
.bubble.blocking { border-left-color: var(--primary); }
|
|
597
|
-
.bubble.nit { border-left-color: var(--border); }
|
|
598
|
-
.bubble.suggestion { border-left-color: var(--success); }
|
|
599
|
-
|
|
600
|
-
.bubble .severity {
|
|
601
|
-
font-family: var(--font-mono);
|
|
602
|
-
font-size: 0.65rem;
|
|
603
|
-
font-weight: 700;
|
|
604
|
-
text-transform: uppercase;
|
|
605
|
-
letter-spacing: 0.06em;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
.bubble.blocking .severity { color: var(--primary); }
|
|
609
|
-
.bubble.nit .severity { color: var(--muted-foreground); }
|
|
610
|
-
.bubble.suggestion .severity { color: var(--success); }
|
|
611
|
-
```
|
|
612
|
-
|
|
613
|
-
## File Badges (for PR reviews)
|
|
614
|
-
|
|
615
|
-
```css
|
|
616
|
-
.file-badge {
|
|
617
|
-
font-family: var(--font-mono);
|
|
618
|
-
font-size: 0.62rem;
|
|
619
|
-
font-weight: 700;
|
|
620
|
-
text-transform: uppercase;
|
|
621
|
-
letter-spacing: 0.04em;
|
|
622
|
-
padding: 2px 6px;
|
|
623
|
-
border-radius: 4px;
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
.file-badge.new { background: color-mix(in oklab, var(--success) 15%, transparent); color: var(--success); }
|
|
627
|
-
.file-badge.mod { background: color-mix(in oklab, var(--warning) 15%, transparent); color: var(--warning); }
|
|
628
|
-
.file-badge.del { background: color-mix(in oklab, var(--destructive) 15%, transparent); color: var(--destructive); }
|
|
629
|
-
```
|