55 lines
1.2 KiB
TypeScript
55 lines
1.2 KiB
TypeScript
'use client'
|
||
import React from 'react'
|
||
|
||
interface ProgressBarProps {
|
||
value: number // 0–100
|
||
label?: string
|
||
color?: string
|
||
}
|
||
|
||
export function ProgressBar({ value, label, color = 'var(--accent)' }: ProgressBarProps) {
|
||
const clamped = Math.min(100, Math.max(0, value))
|
||
|
||
return (
|
||
<div style={{ width: '100%' }}>
|
||
{label && (
|
||
<div
|
||
style={{
|
||
display: 'flex',
|
||
justifyContent: 'space-between',
|
||
marginBottom: 'var(--s-1)',
|
||
fontSize: 'var(--t-small)',
|
||
color: 'var(--fg-muted)',
|
||
}}
|
||
>
|
||
<span>{label}</span>
|
||
<span>{clamped}%</span>
|
||
</div>
|
||
)}
|
||
<div
|
||
style={{
|
||
width: '100%',
|
||
height: '8px',
|
||
background: 'var(--bg-warm)',
|
||
borderRadius: 'var(--r-pill)',
|
||
overflow: 'hidden',
|
||
}}
|
||
role="progressbar"
|
||
aria-valuenow={clamped}
|
||
aria-valuemin={0}
|
||
aria-valuemax={100}
|
||
>
|
||
<div
|
||
style={{
|
||
width: `${clamped}%`,
|
||
height: '100%',
|
||
background: color,
|
||
borderRadius: 'var(--r-pill)',
|
||
transition: 'width 400ms ease',
|
||
}}
|
||
/>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|