11import type { Impact } from '../../shared/protocol.ts'
2+ import { Show } from 'solid-js'
23import { Summary } from './Summary.tsx'
34import { Switch } from './Switch.tsx'
45
@@ -10,25 +11,35 @@ interface SummaryBarProps {
1011 totalNodes : number
1112 totalRules : number
1213 routeCount : number
14+ /** Number of violations currently selected. */
15+ selectedCount : number
16+ /** Whether every currently-visible violation is selected. */
17+ allSelected : boolean
18+ /** Select all visible violations, or unselect them when all are selected. */
19+ onToggleSelectAll : ( ) => void
20+ /** Clear the entire selection (including any hidden by the filter). */
21+ onClearSelection : ( ) => void
1322 autoScan : boolean
1423 onToggleAutoScan : ( enabled : boolean ) => void
1524 showBestPractice : boolean
1625 onToggleBestPractice : ( show : boolean ) => void
1726 onClearAll : ( ) => void
1827}
1928
29+ const ACTION = 'inline-flex items-center gap-1.5 text-xs color-muted bg-secondary border border-base rounded-md px-2.5 py-1 cursor-pointer transition hover:bg-active outline-none focus-visible:ring-2 focus-visible:ring-primary-500/40 disabled:op-40 disabled:cursor-default'
30+
2031/**
2132 * The compact, sticky summary band that heads the single-page panel: the
22- * severity chips (doubling as the impact filter), a one-line count, and the
23- * scan / best-practice / clear controls.
33+ * severity chips (doubling as the impact filter), a one-line count, bulk
34+ * selection actions, and the scan / best-practice / clear controls.
2435 */
2536export function SummaryBar ( props : SummaryBarProps ) {
2637 const plural = ( n : number , one : string ) => `${ n } ${ n === 1 ? one : `${ one } s` } `
2738 return (
2839 < div class = "flex flex-col gap-2 pt-3 pb-2.5 sticky top-0 z-[2] bg-base" >
2940 < Summary counts = { props . counts } active = { props . filter } onToggle = { props . onToggleFilter } onHover = { props . onHoverImpact } />
3041
31- < div class = "flex items-center gap-3 flex-wrap" >
42+ < div class = "flex items-center gap-2 flex-wrap" >
3243 < span class = "text-[11.5px] color-muted tabular-nums" >
3344 { plural ( props . totalNodes , 'issue' ) }
3445 { ' · ' }
@@ -37,6 +48,29 @@ export function SummaryBar(props: SummaryBarProps) {
3748 { plural ( props . routeCount , 'route' ) }
3849 </ span >
3950
51+ < button
52+ type = "button"
53+ class = { ACTION }
54+ onClick = { ( ) => props . onToggleSelectAll ( ) }
55+ title = { props . allSelected ? 'Unselect all visible violations' : 'Select all visible violations' }
56+ >
57+ < span aria-hidden class = { `shrink-0 ${ props . allSelected ? 'i-ph-check-square-duotone' : 'i-ph-square-duotone' } ` } />
58+ { props . allSelected ? 'Unselect all' : 'Select all' }
59+ </ button >
60+
61+ < Show when = { props . selectedCount > 0 } >
62+ < button
63+ type = "button"
64+ class = { ACTION }
65+ onClick = { ( ) => props . onClearSelection ( ) }
66+ title = "Clear the whole selection"
67+ >
68+ < span aria-hidden class = "i-ph-x shrink-0" />
69+ Clear selection
70+ < span class = "inline-flex items-center justify-center min-w-4 h-4 px-1 rounded-full bg-active text-[10px] font-bold tabular-nums" > { props . selectedCount } </ span >
71+ </ button >
72+ </ Show >
73+
4074 < span class = "flex-1" />
4175
4276 < Switch label = "Best-practice" checked = { props . showBestPractice } onChange = { props . onToggleBestPractice } />
0 commit comments