feat: version 2.17.5 -- Panel: medidor y detalle en "Proyectos atrasados"

La tarjeta muestra un medidor semicircular (atrasados/activos) con el valor al
centro; al hacer clic, el bloque inferior lista los proyectos atrasados en vez
de mis actividades. Por ahora solo esta tarjeta.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Milton Gonzalez
2026-10-20 17:02:45 -05:00
parent 9231bd2c7a
commit 4583e3c456
10 changed files with 102 additions and 9 deletions
+32 -3
View File
@@ -1,7 +1,36 @@
export function KpiCard({ label, value }) {
// Medidor semicircular (tipo odometro): arco de fondo + arco relleno segun ratio (0..1), con el
// valor del KPI al centro. Sin libreria -- un SVG con stroke-dasharray sobre el semicirculo.
function Gauge({ ratio, color, value }) {
const r = 40;
const length = Math.PI * r;
const clamped = Math.max(0, Math.min(1, ratio || 0));
const arc = `M ${50 - r} 50 A ${r} ${r} 0 0 1 ${50 + r} 50`;
return (
<div className="kpi-card">
<div className="kpi-value">{value}</div>
<div className="kpi-gauge">
<svg viewBox="0 0 100 56" aria-hidden="true">
<path d={arc} fill="none" stroke="rgb(var(--line))" strokeWidth="9" strokeLinecap="round" />
<path
d={arc} fill="none" stroke={`rgb(var(--${color}))`} strokeWidth="9" strokeLinecap="round"
strokeDasharray={`${length * clamped} ${length}`}
style={{ transition: 'stroke-dasharray .6s ease' }}
/>
</svg>
<div className="kpi-gauge-value">{value}</div>
</div>
);
}
export function KpiCard({ label, value, gauge, onClick, selected }) {
const clickable = !!onClick;
return (
<div
className={`kpi-card ${clickable ? 'kpi-card-clickable' : ''} ${selected ? 'selected' : ''}`}
onClick={onClick}
role={clickable ? 'button' : undefined}
tabIndex={clickable ? 0 : undefined}
onKeyDown={clickable ? (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onClick(); } } : undefined}
>
{gauge ? <Gauge ratio={gauge.ratio} color={gauge.color} value={value} /> : <div className="kpi-value">{value}</div>}
<div className="kpi-label">{label}</div>
</div>
);