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