import type { ReactNode } from "react"; import { Box, Group, Paper, Stack, Text } from "@mantine/core"; import type { LucideIcon } from "lucide-react"; import { MapPin } from "lucide-react"; import { MiniRing, MiniSparkline } from "@/components/common/MiniGraph"; import type { OverviewAccent } from "@/components/overview/overview.styles"; import { freightBrand } from "@/theme/freight-brand"; /** Mini-graph variants a StatTile can render at its bottom. */ export type StatTileGraph = "area" | "line" | "ring" | "none"; /** * Shared visual building blocks for the Train Scheduling V2 surfaces. * Everything keys off the freight brand green so the list + detail pages * read as one cohesive, premium product. */ export const scheduleBrand = { /** Deep green → emerald hero wash used across scheduling surfaces. */ heroGradient: `linear-gradient(135deg, ${freightBrand.primaryDark} 0%, ${freightBrand.primary} 48%, ${freightBrand.primaryLight} 120%)`, /** Soft tinted surface for cards on white backgrounds. */ softSurface: `linear-gradient(135deg, ${freightBrand.mutedBg} 0%, #ffffff 60%, var(--mantine-color-gray-0) 100%)`, ring: freightBrand.ring, shadow: freightBrand.shadow, shadowSm: freightBrand.shadowSm, mutedBorder: freightBrand.mutedBorder, } as const; const STATUS_META: Record< string, { color: string; dot: string; label?: string } > = { DRAFT: { color: "gray", dot: "var(--mantine-color-gray-5)" }, SCHEDULED: { color: "green", dot: freightBrand.primary }, DISPATCHED: { color: "teal", dot: "var(--mantine-color-teal-6)" }, ARRIVED: { color: "blue", dot: "var(--mantine-color-blue-6)" }, CANCELLED: { color: "red", dot: "var(--mantine-color-red-6)" }, }; export function statusMeta(status: string) { return STATUS_META[status] ?? STATUS_META.DRAFT; } /** * Status pill with a leading status dot — clearer at a glance than a plain * badge and consistent everywhere a schedule status appears. */ export function StatusPill({ status, size = "sm", }: { status: string; size?: "sm" | "md"; }) { const meta = statusMeta(status); const isMd = size === "md"; return ( {meta.label ?? status} ); } /** * Compact metric tile used in hero strips. `onDark` flips colors for use on * the green hero gradient. */ export function StatTile({ icon: Icon, label, value, hint, onDark = false, accent = freightBrand.primary, graph = "none", graphAccent = "emerald", graphPct, }: { icon?: LucideIcon; label: string; value: ReactNode; hint?: ReactNode; onDark?: boolean; accent?: string; /** Optional decorative mini-graph at the bottom (ignored on dark tiles). */ graph?: StatTileGraph; graphAccent?: OverviewAccent; /** Percentage 0..100 for the ring variant. */ graphPct?: number | null; }) { // Mini-graphs only render on light tiles (the gradient reads poorly on dark). const showGraph = graph !== "none" && !onDark; return ( {Icon ? ( ) : null} {value} {label} {hint ? · {hint} : null} {showGraph && graph === "ring" ? ( {Math.round(graphPct ?? 0)}% ) : null} {showGraph && graph !== "ring" ? ( ) : null} ); } /** * Origin → destination corridor visual: two anchored stops joined by a rail * line. `variant="compact"` is for dense table rows; `default` for cards. */ export function RouteCorridor({ origin, destination, variant = "default", onDark = false, }: { origin?: string | null; destination?: string | null; variant?: "default" | "compact"; onDark?: boolean; }) { const compact = variant === "compact"; const dim = onDark ? "rgba(255,255,255,0.7)" : "var(--mantine-color-gray-5)"; const strong = onDark ? "white" : "var(--mantine-color-gray-8)"; const lineColor = onDark ? "rgba(255,255,255,0.4)" : "var(--mantine-color-gray-3)"; const accent = onDark ? "white" : freightBrand.primary; return ( {origin ?? "—"} {destination ?? "—"} ); }