profileShare

rasmusjy / voicetask

Read-only snapshot

No repository description.

main default branch 105 files Expires Sep 13, 2026, 9:06 AM
CoveragePanel.tsx 2,288 bytes
1 import { CATEGORY_IDS, type Coverage, type CoverageLevel } from 'shared/types'
2 import { CATEGORY_LABELS } from '../labels'
3
4 interface CoveragePanelProps {
5 coverage: Coverage
6 }
7
8 const STATUS_LABELS: Record<CoverageLevel, string> = {
9 missing: 'To discuss',
10 partial: 'In progress',
11 clear: 'Ready',
12 }
13
14 export function CoveragePanel({ coverage }: CoveragePanelProps) {
15 const readyCount = CATEGORY_IDS.filter((category) => coverage[category] === 'clear').length
16 const activeCount = CATEGORY_IDS.filter((category) => coverage[category] === 'partial').length
17 const remainingCount = CATEGORY_IDS.length - readyCount - activeCount
18 const progress = (readyCount / CATEGORY_IDS.length) * 100
19
20 return (
21 <section className="coverage-card" aria-labelledby="coverage-title">
22 <div className="coverage-heading">
23 <div>
24 <p className="coverage-kicker">Your build brief</p>
25 <h2 id="coverage-title">
26 {readyCount} of {CATEGORY_IDS.length} topics ready
27 </h2>
28 </div>
29 <span className="coverage-fraction" aria-hidden="true">
30 {readyCount}/{CATEGORY_IDS.length}
31 </span>
32 </div>
33 <div
34 className="coverage-track"
35 role="progressbar"
36 aria-label="Build brief topics ready"
37 aria-valuemin={0}
38 aria-valuemax={CATEGORY_IDS.length}
39 aria-valuenow={readyCount}
40 >
41 <span style={{ width: `${progress}%` }} />
42 </div>
43 <p className="coverage-progress">
44 {readyCount} ready, {activeCount} in progress, {remainingCount} to discuss
45 </p>
46 <ul className="coverage-panel">
47 {CATEGORY_IDS.map((category) => (
48 <li
49 key={category}
50 className={`coverage-item coverage-${coverage[category]}`}
51 aria-label={`${CATEGORY_LABELS[category].label}: ${STATUS_LABELS[coverage[category]]}. ${CATEGORY_LABELS[category].description}`}
52 >
53 <span className="coverage-dot" aria-hidden="true" />
54 <span className="coverage-item-copy">
55 <span>{CATEGORY_LABELS[category].label}</span>
56 <span className="coverage-status">{STATUS_LABELS[coverage[category]]}</span>
57 </span>
58 </li>
59 ))}
60 </ul>
61 </section>
62 )
63 }
64