ui improvement
This commit is contained in:
@@ -1,99 +1,89 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import { Card } from '@astryxdesign/core/Card';
|
||||
import { HStack } from '@astryxdesign/core/HStack';
|
||||
import { Text } from '@astryxdesign/core/Text';
|
||||
import { VStack } from '@astryxdesign/core/VStack';
|
||||
import './kpiCard.css';
|
||||
|
||||
/**
|
||||
* A KPI tile — the console's headline figure.
|
||||
*
|
||||
* ── There were two of these, and neither worked ─────────────────────────────
|
||||
*
|
||||
* This component put an icon inline with the label and CENTRED the value
|
||||
* underneath it, which is why a row of tiles never lined up: a centred number
|
||||
* sits in a different place in every tile depending on how long it is.
|
||||
* `console.css` had a second, unrelated implementation — `.kpi` — with a
|
||||
* brand-tinted icon tile on the left and the text stacked beside it. The two
|
||||
* appeared on the same screen. The second was the better design and this is
|
||||
* now that design, for both.
|
||||
*
|
||||
* ── `note` is rendered again, and that is the real change ───────────────────
|
||||
*
|
||||
* The line under the figure — "142 app · 38 counter", "12% of app orders" —
|
||||
* was removed from the tile at some point but never removed from the CALLERS:
|
||||
* 86 of them still compute and pass it, and it was being thrown away. That is
|
||||
* the half of a KPI that carries the meaning. A bare `0` under "Unsynced
|
||||
* bills" reads as "no data" when it means everything is in the books, and `42`
|
||||
* under "Total orders" says nothing about which channel they came through.
|
||||
*
|
||||
* ── `tone` does something now ───────────────────────────────────────────────
|
||||
*
|
||||
* All five tones used to map to `var(--color-brand)`, so the prop was
|
||||
* decorative — every tile was purple whether it reported takings or a failure.
|
||||
* The tone now colours the icon tile only: the figure itself stays in ink,
|
||||
* because a number that changes colour with its own value is hard to compare
|
||||
* against the tile beside it. Brand remains the default, so a tile that is
|
||||
* merely reporting is not shouting.
|
||||
*/
|
||||
|
||||
export type KpiTone = 'accent' | 'success' | 'warning' | 'error' | 'neutral';
|
||||
|
||||
const TONE_COLOR: Record<KpiTone, string> = {
|
||||
accent: 'var(--color-brand)',
|
||||
success: 'var(--color-brand)',
|
||||
warning: 'var(--color-brand)',
|
||||
error: 'var(--color-brand)',
|
||||
neutral: 'var(--color-brand)',
|
||||
};
|
||||
|
||||
export interface KpiCardProps {
|
||||
/** Small-caps label. Say what it is, not what it means. */
|
||||
label: string;
|
||||
value: string;
|
||||
/**
|
||||
* Accepted and ignored, like `fill` below.
|
||||
*
|
||||
* This was the sub-pill — where the number got its meaning, since "1 of 84
|
||||
* orders" says something "1.2%" does not. The pill was removed from the tile
|
||||
* deliberately; 87 call sites across 21 files still pass the text, so the
|
||||
* prop stays declared to keep them compiling and is not read.
|
||||
*
|
||||
* That means every one of those 87 strings is now written and never shown.
|
||||
* Either drop them from the callers or bring the pill back — right now it is
|
||||
* neither, and this comment is here so that is visible rather than a puzzle
|
||||
* for whoever next wonders where "84 orders" went.
|
||||
* The line under the figure — what the number is made of, or what it is a
|
||||
* share of. This is where a KPI gets its meaning; see the note above.
|
||||
*/
|
||||
note?: string;
|
||||
/**
|
||||
* Colours the icon tile. `neutral` and `accent` are both the brand — a tile
|
||||
* reports by default and only says more when something is actually wrong.
|
||||
*/
|
||||
tone?: KpiTone;
|
||||
icon?: ReactNode;
|
||||
/**
|
||||
* Accepted and ignored.
|
||||
*
|
||||
* The underline bar this used to drive was removed from the tile. Six call
|
||||
* sites still pass it, so the prop stays declared to keep them compiling —
|
||||
* it is not read. Either drop it from the callers or restore the bar; right
|
||||
* now it is neither, and this comment is here so that is visible.
|
||||
* The 2px underline bar this drove was removed from the tile deliberately —
|
||||
* a proportion bar under five tiles turned the strip into a chart. Six call
|
||||
* sites still pass it, so the prop stays declared to keep them compiling.
|
||||
* Drop it from those callers and this can go.
|
||||
*/
|
||||
fill?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A KPI tile.
|
||||
*
|
||||
* Label and icon, then a large tabular value. The sub-pill and the 2px tone
|
||||
* underline were both removed from the tile; `note` and `fill` still arrive
|
||||
* from the call sites and are ignored — see the props above. Sized to sit 4–6
|
||||
* across rather than 4 — a console is glanced at all day, not read once.
|
||||
*/
|
||||
export function KpiCard({ label, value, tone = 'neutral', icon }: KpiCardProps) {
|
||||
const color = TONE_COLOR[tone];
|
||||
|
||||
export function KpiCard({ label, value, note, tone = 'neutral', icon }: KpiCardProps) {
|
||||
return (
|
||||
<Card padding={0} elevation="low">
|
||||
<VStack gap={1} padding={2} style={{ minHeight: 108 }}>
|
||||
{/* Icon first, then the label; the pill sits opposite it. Both are
|
||||
fixed to this row so tiles line up whether or not they carry one. */}
|
||||
{/* A fixed height, so a label that wraps to two lines (a long note
|
||||
squeezes it) does not push that tile's value below its neighbours'. */}
|
||||
<HStack justify="between" align="center" gap={1} style={{ minHeight: 32 }}>
|
||||
<HStack gap={1} align="center" style={{ minWidth: 0 }}>
|
||||
{icon ? (
|
||||
<span style={{ color, display: 'flex', flex: 'none' }} aria-hidden>
|
||||
{icon}
|
||||
</span>
|
||||
) : null}
|
||||
<Text
|
||||
type="label"
|
||||
size="xsm"
|
||||
color="secondary"
|
||||
style={{ textTransform: 'uppercase', letterSpacing: '0.09em', lineHeight: 1.35 }}
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
</HStack>
|
||||
<div className="kpi-card" data-tone={tone}>
|
||||
{/* Label and icon share the top row; the figure gets the full width of
|
||||
the card underneath them.
|
||||
|
||||
{/* Note pill removed as requested */}
|
||||
</HStack>
|
||||
The icon used to sit in a column of its own to the LEFT, and at the
|
||||
width these tiles actually get — five across a 1,224px column, less
|
||||
340px whenever Nearle Buddy is open — a 40px tile plus its gutter
|
||||
left about 134px for the number. "₹1,24,500" does not fit in 134px at
|
||||
24px bold, so it wrapped, and it wrapped mid-figure: the first tile
|
||||
on the Console read "₹1,24,50" on one line and "0" on the next. */}
|
||||
<div className="kpi-card-head">
|
||||
<span className="kpi-card-label">{label}</span>
|
||||
{icon ? (
|
||||
<span className="kpi-card-icon" aria-hidden>
|
||||
{icon}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<HStack justify="center" align="center" style={{ flex: 1 }}>
|
||||
<Text
|
||||
as="div"
|
||||
hasTabularNumbers
|
||||
style={{ color, fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 24, lineHeight: 1.1 }}
|
||||
>
|
||||
{value}
|
||||
</Text>
|
||||
</HStack>
|
||||
</VStack>
|
||||
|
||||
</Card>
|
||||
<span className="kpi-card-value">{value}</span>
|
||||
{note ? <span className="kpi-card-note">{note}</span> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user