mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 00:52:50 +00:00
style: update the overview style
This commit is contained in:
@@ -1,65 +1,36 @@
|
||||
import { Group, Paper, Text } from "@mantine/core";
|
||||
import { KpiStrip, type KpiItem } from "@/components/page";
|
||||
|
||||
import {
|
||||
OverviewKpiCard,
|
||||
type KpiGraphVariant,
|
||||
type OverviewKpiItem,
|
||||
} from "./OverviewKpiCard";
|
||||
import type { OverviewKpiItem } from "./OverviewKpiCard";
|
||||
|
||||
/** Rotate mini-graph types per card so each strip reads as a lively mix. */
|
||||
const VARIANT_CYCLE: KpiGraphVariant[] = ["area", "line", "ring"];
|
||||
|
||||
/** Cohesive accent rotation — gold-forward with an orange and neutral break. */
|
||||
const ACCENT_CYCLE: NonNullable<OverviewKpiItem["accent"]>[] = [
|
||||
"gold",
|
||||
"orange",
|
||||
"default",
|
||||
];
|
||||
/**
|
||||
* Map the overview accent vocabulary onto brand / Mantine palette colors so the
|
||||
* shared KpiStrip renders a flat tinted icon chip per cell — no gradients,
|
||||
* gauges or sparklines.
|
||||
*/
|
||||
const ACCENT_COLOR: Record<string, string> = {
|
||||
default: "edr-green",
|
||||
emerald: "edr-green",
|
||||
amber: "yellow",
|
||||
rose: "red",
|
||||
sky: "blue",
|
||||
violet: "violet",
|
||||
gold: "yellow",
|
||||
orange: "orange",
|
||||
};
|
||||
|
||||
interface OverviewKpiStripProps {
|
||||
title?: string;
|
||||
items: OverviewKpiItem[];
|
||||
}
|
||||
|
||||
/** Parse a numeric magnitude out of a KPI value (handles formatted currency strings). */
|
||||
function toNumber(value: number | string): number {
|
||||
if (typeof value === "number") return value;
|
||||
const parsed = Number(String(value).replace(/[^0-9.-]/g, ""));
|
||||
return Number.isFinite(parsed) ? parsed : 0;
|
||||
}
|
||||
/** Clean KPI strip for the overview tabs — delegates to the shared KpiStrip. */
|
||||
export function OverviewKpiStrip({ items }: OverviewKpiStripProps) {
|
||||
const kpiItems: KpiItem[] = items.map((item) => ({
|
||||
label: item.label,
|
||||
value: item.value,
|
||||
icon: item.icon,
|
||||
hint: item.hint,
|
||||
color: ACCENT_COLOR[item.accent ?? "default"] ?? "edr-green",
|
||||
}));
|
||||
|
||||
export function OverviewKpiStrip({ title, items }: OverviewKpiStripProps) {
|
||||
const max = Math.max(...items.map((item) => toNumber(item.value)), 0);
|
||||
|
||||
return (
|
||||
<Paper
|
||||
p="lg"
|
||||
radius="lg"
|
||||
withBorder
|
||||
style={{
|
||||
background: "#ffffff",
|
||||
border: "1px solid var(--mantine-color-gray-2)",
|
||||
}}
|
||||
>
|
||||
{title && (
|
||||
<Text size="sm" fw={600} mb="md" c="dimmed">
|
||||
{title}
|
||||
</Text>
|
||||
)}
|
||||
<Group gap="md" align="stretch" wrap="wrap">
|
||||
{items.map((item, index) => (
|
||||
<OverviewKpiCard
|
||||
key={item.label}
|
||||
item={{
|
||||
...item,
|
||||
accent: ACCENT_CYCLE[index % ACCENT_CYCLE.length],
|
||||
variant: item.variant ?? VARIANT_CYCLE[index % VARIANT_CYCLE.length],
|
||||
progress:
|
||||
item.progress ?? (max > 0 ? toNumber(item.value) / max : 0),
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Group>
|
||||
</Paper>
|
||||
);
|
||||
return <KpiStrip items={kpiItems} />;
|
||||
}
|
||||
|
||||
@@ -47,11 +47,11 @@ export function OverviewPageHeader({
|
||||
data={RANGE_OPTIONS}
|
||||
size="sm"
|
||||
radius="lg"
|
||||
color="green"
|
||||
color="edr-green"
|
||||
/>
|
||||
<ActionIcon
|
||||
variant="light"
|
||||
color="green"
|
||||
color="edr-green"
|
||||
size="lg"
|
||||
radius="lg"
|
||||
aria-label="Refresh dashboard"
|
||||
|
||||
@@ -78,7 +78,7 @@ export function OverviewTabContent({ tab, range }: OverviewTabContentProps) {
|
||||
<Stack gap="md" pos="relative">
|
||||
{isFetching && (
|
||||
<Center style={{ position: "absolute", top: 8, right: 8, zIndex: 2 }}>
|
||||
<Loader size="sm" color="green" />
|
||||
<Loader size="sm" color="edr-green" />
|
||||
</Center>
|
||||
)}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
.ov-seg-label[data-active] {
|
||||
color: #15805f;
|
||||
color: var(--mantine-color-edr-green-7);
|
||||
}
|
||||
|
||||
/* ---- Premium tab bar ---- */
|
||||
@@ -47,10 +47,8 @@
|
||||
box-shadow: 0 2px 10px -4px rgba(15, 23, 42, 0.18);
|
||||
}
|
||||
.ov-tab[data-active] {
|
||||
background: linear-gradient(135deg, #2dbf95 0%, #1b9e7a 100%) !important;
|
||||
background: var(--mantine-color-edr-green-5) !important;
|
||||
color: #ffffff !important;
|
||||
box-shadow: 0 10px 20px -8px rgba(27, 158, 122, 0.55);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.ov-tab[data-active]:hover {
|
||||
color: #ffffff;
|
||||
|
||||
@@ -132,7 +132,7 @@ const OverviewPage = () => {
|
||||
value={activeTab}
|
||||
onChange={(value) => setActiveTab((value as OverviewTabKey) ?? "bookings")}
|
||||
variant="pills"
|
||||
color="green"
|
||||
color="edr-green"
|
||||
keepMounted={false}
|
||||
classNames={{ list: "ov-tablist", tab: "ov-tab" }}
|
||||
>
|
||||
@@ -151,12 +151,7 @@ const OverviewPage = () => {
|
||||
size="sm"
|
||||
radius="sm"
|
||||
variant={isActive ? "white" : "light"}
|
||||
color={isActive ? "green" : "gray"}
|
||||
styles={
|
||||
isActive
|
||||
? { root: { background: "rgba(255,255,255,0.9)", color: "#15805f" } }
|
||||
: undefined
|
||||
}
|
||||
color={isActive ? "edr-green" : "gray"}
|
||||
>
|
||||
{getTabBadge(tab)}
|
||||
</Badge>
|
||||
|
||||
Reference in New Issue
Block a user