Data Display
Data display patterns prioritize scan speed. Tables, summary cards, and grouped values should remain clear across themes and viewport widths.
Source files: styles/base.css, styles/components/card.css
Summary Cards
$83.97
Current monthly spend
$1,007.64
Projected annual spend
<div class="wm-card card">
<h3>$83.97</h3>
<p>Current monthly spend</p>
</div>
Table
| Merchant | Amount | Frequency | Status |
|---|---|---|---|
| Netflix | $18.99 | Monthly | Confirmed |
| Figma | $15.00 | Monthly | Pending Cancel |
| Adobe | $239.99 | Annual | Detected |
<table>
<thead>
<tr>
<th>Merchant</th>
<th>Amount</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Netflix</td>
<td>$18.99</td>
<td>Confirmed</td>
</tr>
</tbody>
</table>
Stat Cards — .stats-grid / .stat-card
Compact metric display. Use .stats-grid as a responsive wrapper and
.stat-card for each cell. Inner .stat-value and
.stat-label position the number and descriptor.
Source: styles/components/stat-card.css
<div class="stats-grid">
<div class="stat-card">
<div class="stat-value">$214</div>
<div class="stat-label">Monthly spend</div>
</div>
<div class="stat-card stat-card-success">
<div class="stat-value">$48</div>
<div class="stat-label">Savings realized</div>
</div>
<div class="stat-card stat-card-warning">
<div class="stat-value">$24</div>
<div class="stat-label">Projected savings</div>
</div>
</div>
Chart Container — .chart-container
Card wrapper for any chart library (Recharts, Chart.js, D3, etc.). Provides consistent surface, border, padding, and a heading slot. The CSS is intentionally minimal — chart rendering is handled by the library.
Source: styles/components/chart.css
Monthly Subscription Spend & Savings
Token → Chart color mapping
Read tokens at runtime in React via useCssVar("--wm-color-accent", fallback),
then pass the value as a fill prop on the Recharts <Bar> component.
| Token | Chart role |
|---|---|
--wm-color-accent |
Primary data series (spending) |
--wm-color-success |
Positive / realized savings series |
--wm-color-success-border |
Projected / muted positive series |
--wm-color-warning |
Budget threshold / warning series |
--wm-color-danger |
Overage / alert series |
--wm-color-border |
CartesianGrid stroke |
--wm-color-text-muted |
Axis tick color |
--wm-color-surface-solid |
Tooltip background fill |
Empty state — .chart-empty
Monthly Spend
No chart data available.
// React + Recharts integration example
function useCssVar(varName, fallback) {
const [value, setValue] = useState(fallback);
useEffect(() => {
const v = getComputedStyle(document.documentElement)
.getPropertyValue(varName).trim();
if (v) setValue(v);
}, [varName]);
return value;
}
function SpendChart({ data }) {
const colorSpending = useCssVar("--wm-color-accent", "#1a73e8");
const colorRealized = useCssVar("--wm-color-success", "#34a853");
const colorProjected = useCssVar("--wm-color-success-border", "#8bc34a");
if (!data.length) {
return (
<div class="chart-container">
<h3>Monthly Spend</h3>
<p class="chart-empty">No chart data available.</p>
</div>
);
}
return (
<div class="chart-container">
<h3>Monthly Subscription Spend & Savings</h3>
<ResponsiveContainer width="100%" height={300}>
<BarChart data={data}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="month" />
<YAxis />
<Tooltip formatter={(v) => `$${v.toFixed(2)}`} />
<Legend />
<Bar dataKey="amount" name="Spending" fill={colorSpending} radius={[4,4,0,0]} />
<Bar dataKey="realizedSavings" name="Realized Savings" fill={colorRealized} radius={[4,4,0,0]} />
<Bar dataKey="projectedSavings" name="Projected Savings" fill={colorProjected} radius={[4,4,0,0]} />
</BarChart>
</ResponsiveContainer>
</div>
);
}
Gallery — .gallery
Responsive auto-fill image grid. Each .gallery-item clips its image to a 16:10
aspect ratio and lifts on hover. An optional .gallery-item-caption overlays as
a frosted label on hover.
<div class="gallery">
<div class="gallery-item">
<img src="screenshot.png" alt="Project screenshot" />
<span class="gallery-item-caption">Project screenshot</span>
</div>
<div class="gallery-item">
<img src="dashboard.png" alt="Dashboard view" />
</div>
</div>