Move JavaScript style objects from home page components into reusable CSS classes in App.css. This follows the existing pattern (intel-button, intel-card, intel-input) and consolidates all visual styling in one place. New CSS classes added: - .panel-card (--accent, --warning, --teal) — sidebar panels - .section-heading (--accent, --warning, --teal) — monospace headings - .stat-card modifiers (--clickable, --active, --warning, --danger) - .stat-card__label / .stat-card__value (--accent, --neutral, etc.) - .severity-badge (--critical, --high, --medium, --low) - .glow-dot (--critical, --high, --medium, --low) - .sidebar-ticket — compact ticket cards - .workflow-item — Ivanti workflow entries - .workflow-state-badge — teal state pill - .ticket-status-badge — small status indicator - .archive-item (--active, --resolved) — finding archive entries - .big-counter (--warning, --teal) — large centered stat numbers Benefits: - 578 fewer lines of JavaScript across components - Styles are browser-cached separately from JS bundle - Single source of truth for the design system - Easier to update colors/spacing project-wide
59 lines
1.6 KiB
JavaScript
59 lines
1.6 KiB
JavaScript
import React from 'react';
|
|
|
|
function StatCard({ label, value, color = 'accent', variant, onClick, active }) {
|
|
const cardClasses = [
|
|
'stat-card',
|
|
onClick && 'stat-card--clickable',
|
|
active && 'stat-card--active',
|
|
variant && `stat-card--${variant}`,
|
|
].filter(Boolean).join(' ');
|
|
|
|
const valueClass = `stat-card__value stat-card__value--${color}`;
|
|
|
|
return (
|
|
<div
|
|
className={cardClasses}
|
|
onClick={onClick}
|
|
role={onClick ? 'button' : undefined}
|
|
tabIndex={onClick ? 0 : undefined}
|
|
aria-label={`${label}: ${value}`}
|
|
>
|
|
<div className="stat-card__label">{label}</div>
|
|
<div className={valueClass}>{value}</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default function StatsBar({ totalCVEs, vendorEntries, openTickets, criticalCount, onFilterSeverity, activeSeverity }) {
|
|
return (
|
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
|
<StatCard
|
|
label="Total CVEs"
|
|
value={totalCVEs}
|
|
color="accent"
|
|
onClick={() => onFilterSeverity && onFilterSeverity('All Severities')}
|
|
active={activeSeverity === 'All Severities'}
|
|
/>
|
|
<StatCard
|
|
label="Vendor Entries"
|
|
value={vendorEntries}
|
|
color="neutral"
|
|
/>
|
|
<StatCard
|
|
label="Open Tickets"
|
|
value={openTickets}
|
|
color="warning"
|
|
variant="warning"
|
|
/>
|
|
<StatCard
|
|
label="Critical"
|
|
value={criticalCount}
|
|
color="danger"
|
|
variant="danger"
|
|
onClick={() => onFilterSeverity && onFilterSeverity(activeSeverity === 'Critical' ? 'All Severities' : 'Critical')}
|
|
active={activeSeverity === 'Critical'}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|