|
| 1 | +import { groupBy } from 'storybook/internal/common'; |
| 2 | + |
1 | 3 | import { dedent } from 'ts-dedent'; |
2 | 4 |
|
3 | 5 | import type { ComponentManifest, ComponentsManifest } from '../types'; |
@@ -35,6 +37,34 @@ export function renderManifestComponentsPage(manifest: ComponentsManifest) { |
35 | 37 |
|
36 | 38 | const grid = entries.map(([key, c], idx) => renderComponentCard(key, c, idx)).join(''); |
37 | 39 |
|
| 40 | + const errorGroups = Object.entries( |
| 41 | + groupBy( |
| 42 | + entries.map(([, it]) => it).filter((it) => it.error), |
| 43 | + (manifest) => manifest.error?.name ?? 'Error' |
| 44 | + ) |
| 45 | + ); |
| 46 | + |
| 47 | + const errorGroupsHTML = errorGroups |
| 48 | + .map(([error, grouped]) => { |
| 49 | + const id = error.toLowerCase().replace(/[^a-z0-9]+/g, '-'); |
| 50 | + const headerText = `${esc(error)}`; |
| 51 | + const cards = grouped |
| 52 | + .map((manifest, id) => renderComponentCard(manifest.id, manifest, id)) |
| 53 | + .join(''); |
| 54 | + return ` |
| 55 | + <section class="group"> |
| 56 | + <input id="${id}-toggle" class="group-tg" type="checkbox" hidden /> |
| 57 | + <label for="${id}-toggle" class="group-header"> |
| 58 | + <span class="caret">▸</span> |
| 59 | + <span class="group-title">${headerText}</span> |
| 60 | + <span class="group-count">${grouped.length}</span> |
| 61 | + </label> |
| 62 | + <div class="group-cards">${cards}</div> |
| 63 | + </section> |
| 64 | + `; |
| 65 | + }) |
| 66 | + .join(''); |
| 67 | + |
38 | 68 | return dedent`<!doctype html> |
39 | 69 | <html lang="en"> |
40 | 70 | <head> |
@@ -127,12 +157,34 @@ export function renderManifestComponentsPage(manifest: ComponentsManifest) { |
127 | 157 | .dot-err{background:var(--err)} |
128 | 158 | .ex-name{font-weight:600} |
129 | 159 |
|
| 160 | + /* Error groups (visible in errors filter) */ |
| 161 | + .error-groups{display:none; margin-bottom:16px;} |
| 162 | + .group{border:1px solid var(--border);background:var(--panel);border-radius:14px;overflow:hidden} |
| 163 | + .group + .group{margin-top:12px} |
| 164 | + .group-header{display:flex;align-items:center;gap:10px;padding:12px 14px;cursor:pointer;border-bottom:1px solid var(--border)} |
| 165 | + .group-header:hover{background:#141722} |
| 166 | + .group-title{font-weight:600;flex:1} |
| 167 | + .group-count{font-size:12px;color:var(--muted);} |
| 168 | + .group-cards{display:none;padding:12px} |
| 169 | + .group .card{margin:12px 0} |
| 170 | + .group .card:first-child{margin-top:0} |
| 171 | + .group .card:last-child{margin-bottom:0} |
| 172 | + /* caret rotation */ |
| 173 | + .group-tg:checked + label .caret{transform:rotate(90deg)} |
| 174 | + .caret{transition:transform .15s ease} |
| 175 | + /* toggle body */ |
| 176 | + .group-tg:checked ~ .group-cards{display:block} |
| 177 | +
|
130 | 178 | /* CSS-only filtering of cards via top pills */ |
131 | 179 | #filter-errors:target ~ main .card:not(.has-error):not(.has-example-error){display:none} |
132 | 180 | #filter-warnings:target ~ main .card:not(.has-warn){display:none} |
133 | 181 | #filter-example-errors:target ~ main .card:not(.has-example-error){display:none} |
134 | 182 | #filter-all:target ~ main .card{display:block} |
135 | | - |
| 183 | + /* In errors view, hide standalone component-error cards in the regular grid (they will appear in groups) */ |
| 184 | + #filter-errors:target ~ main .grid .card.has-error{display:none} |
| 185 | + /* Show grouped section only in errors view */ |
| 186 | + #filter-errors:target ~ main .error-groups{display:block} |
| 187 | +
|
136 | 188 | /* When a toggle is checked, show the corresponding panel */ |
137 | 189 | .card > .tg-err:checked ~ .panels .panel-err { display: grid; } |
138 | 190 | .card > .tg-warn:checked ~ .panels .panel-warn { display: grid; } |
@@ -173,6 +225,7 @@ export function renderManifestComponentsPage(manifest: ComponentsManifest) { |
173 | 225 | <div class="grid" role="list"> |
174 | 226 | ${grid || `<div class="card"><div class="head"><div class="hint">No components.</div></div></div>`} |
175 | 227 | </div> |
| 228 | + ${errorGroups.length ? `<div class="error-groups" role="region" aria-label="Error groups">${errorGroupsHTML}</div>` : ''} |
176 | 229 | </div> |
177 | 230 | </main> |
178 | 231 | </body> |
|
0 commit comments