feat(pagespeed): render audit sub-group headers in diagnostics
Group audits within each category by sub-group (e.g., "Names and Labels", "Contrast") with small uppercase headers, matching the pagespeed.web.dev layout.
This commit is contained in:
@@ -526,9 +526,7 @@ export default function PageSpeedPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{groupAudits.length > 0 && (
|
{groupAudits.length > 0 && (
|
||||||
<div className="divide-y divide-neutral-100 dark:divide-neutral-800">
|
<AuditsBySubGroup audits={groupAudits} />
|
||||||
{groupAudits.map(audit => <AuditRow key={audit.id} audit={audit} />)}
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{groupPassed.length > 0 && (
|
{groupPassed.length > 0 && (
|
||||||
@@ -550,6 +548,52 @@ export default function PageSpeedPage() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// * Group audits by sub-group within a category (e.g., "Names and Labels", "Contrast")
|
||||||
|
function AuditsBySubGroup({ audits }: { audits: AuditSummary[] }) {
|
||||||
|
// * Collect unique sub-groups in order of appearance
|
||||||
|
const subGroupOrder: string[] = []
|
||||||
|
const bySubGroup: Record<string, AuditSummary[]> = {}
|
||||||
|
|
||||||
|
for (const audit of audits) {
|
||||||
|
const key = audit.sub_group || '__none__'
|
||||||
|
if (!bySubGroup[key]) {
|
||||||
|
bySubGroup[key] = []
|
||||||
|
subGroupOrder.push(key)
|
||||||
|
}
|
||||||
|
bySubGroup[key].push(audit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// * If no sub-groups exist, render flat list
|
||||||
|
if (subGroupOrder.length === 1 && subGroupOrder[0] === '__none__') {
|
||||||
|
return (
|
||||||
|
<div className="divide-y divide-neutral-100 dark:divide-neutral-800">
|
||||||
|
{audits.map(audit => <AuditRow key={audit.id} audit={audit} />)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-5">
|
||||||
|
{subGroupOrder.map(key => {
|
||||||
|
const items = bySubGroup[key]
|
||||||
|
const title = items[0]?.sub_group_title
|
||||||
|
return (
|
||||||
|
<div key={key}>
|
||||||
|
{title && (
|
||||||
|
<h4 className="text-[11px] font-semibold text-neutral-400 dark:text-neutral-500 uppercase tracking-wider mb-2">
|
||||||
|
{title}
|
||||||
|
</h4>
|
||||||
|
)}
|
||||||
|
<div className="divide-y divide-neutral-100 dark:divide-neutral-800">
|
||||||
|
{items.map(audit => <AuditRow key={audit.id} audit={audit} />)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// * Severity indicator based on audit score (pagespeed.web.dev style)
|
// * Severity indicator based on audit score (pagespeed.web.dev style)
|
||||||
function AuditSeverityIcon({ score }: { score: number | null }) {
|
function AuditSeverityIcon({ score }: { score: number | null }) {
|
||||||
if (score === null) {
|
if (score === null) {
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ export interface AuditSummary {
|
|||||||
savings_ms?: number
|
savings_ms?: number
|
||||||
category: 'opportunity' | 'diagnostic' | 'passed'
|
category: 'opportunity' | 'diagnostic' | 'passed'
|
||||||
group?: string // "performance", "accessibility", "best-practices", "seo"
|
group?: string // "performance", "accessibility", "best-practices", "seo"
|
||||||
|
sub_group?: string // "a11y-names-labels", "a11y-contrast", etc.
|
||||||
|
sub_group_title?: string // "Names and Labels", "Contrast", etc.
|
||||||
details?: AuditDetailItem[]
|
details?: AuditDetailItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user