Skip to content

Instantly share code, notes, and snippets.

@shricodev
Created March 11, 2026 14:16
Show Gist options
  • Select an option

  • Save shricodev/f6edd67c32037c0a69def1b10985855d to your computer and use it in GitHub Desktop.

Select an option

Save shricodev/f6edd67c32037c0a69def1b10985855d to your computer and use it in GitHub Desktop.
OpenAI GPT-5.4 - Code Changes (git patch)
diff --git a/app/globals.css b/app/globals.css
index a2dc41e..5d5d471 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -2,25 +2,56 @@
:root {
--background: #ffffff;
- --foreground: #171717;
+ --foreground: #000000;
+ --dashboard-bg: #ffffff;
+ --text-primary: #000000;
+ --text-secondary: #7c8db5;
+ --border: #e6edff;
+ --accent: #347ae2;
+ --danger: #ff3b30;
+ --chart-grid: #dde5f6;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
- --font-sans: var(--font-geist-sans);
- --font-mono: var(--font-geist-mono);
+ --font-sans: "Poppins", "Segoe UI", Arial, sans-serif;
+ --font-mono: "SFMono-Regular", "Consolas", "Liberation Mono", monospace;
}
-@media (prefers-color-scheme: dark) {
- :root {
- --background: #0a0a0a;
- --foreground: #ededed;
- }
+* {
+ box-sizing: border-box;
+}
+
+html {
+ background: var(--background);
}
body {
+ margin: 0;
background: var(--background);
color: var(--foreground);
- font-family: Arial, Helvetica, sans-serif;
+ font-family: "Poppins", "Segoe UI", Arial, sans-serif;
+}
+
+button,
+input,
+select,
+textarea {
+ font: inherit;
+}
+
+img,
+svg {
+ display: block;
+}
+
+table {
+ border-collapse: separate;
+}
+
+@media (max-width: 1279px) {
+ body {
+ min-width: 360px;
+ }
}
diff --git a/app/layout.tsx b/app/layout.tsx
index f7fa87e..0250a29 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,20 +1,9 @@
import type { Metadata } from "next";
-import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
-const geistSans = Geist({
- variable: "--font-geist-sans",
- subsets: ["latin"],
-});
-
-const geistMono = Geist_Mono({
- variable: "--font-geist-mono",
- subsets: ["latin"],
-});
-
export const metadata: Metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
+ title: "Aeon Dashboard",
+ description: "Pixel-accurate dashboard clone built from the provided Figma frame",
};
export default function RootLayout({
@@ -24,11 +13,7 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
- <body
- className={`${geistSans.variable} ${geistMono.variable} antialiased`}
- >
- {children}
- </body>
+ <body>{children}</body>
</html>
);
}
diff --git a/app/page.tsx b/app/page.tsx
index 295f8fd..03a5565 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -1,65 +1,770 @@
-import Image from "next/image";
+type NavItem = {
+ label: string;
+ icon: keyof typeof navIcons;
+ active?: boolean;
+ hasChevron?: boolean;
+ badge?: string;
+ danger?: boolean;
+};
+
+type StatCard = {
+ value: string;
+ label: string;
+ delta: string;
+ note: string;
+ trend: "up" | "down";
+ icon: keyof typeof statIcons;
+};
+
+type Order = {
+ no: string;
+ id: string;
+ date: string;
+ customer: string;
+ location: string;
+ amount: string;
+ status: "New Order" | "On Delivery";
+};
+
+const primaryNav: NavItem[] = [
+ { label: "Overview", icon: "overview", active: true },
+ { label: "Product", icon: "product", hasChevron: true },
+ { label: "Orders", icon: "orders", hasChevron: true },
+ { label: "Checkout", icon: "checkout", badge: "2" },
+ { label: "Setting", icon: "settings" },
+];
+
+const secondaryNav: NavItem[] = [
+ { label: "Help Centre", icon: "help" },
+ { label: "Contact us", icon: "contact" },
+ { label: "Log out", icon: "logout", danger: true },
+];
+
+const stats: StatCard[] = [
+ {
+ value: "89,935",
+ label: "Total users",
+ delta: "10.2",
+ note: "+1.01% this week",
+ trend: "up",
+ icon: "users",
+ },
+ {
+ value: "23,283.5",
+ label: "Total products",
+ delta: "3.1",
+ note: "+0.49% this week",
+ trend: "up",
+ icon: "bag",
+ },
+ {
+ value: "46,827",
+ label: "Total users",
+ delta: "2.56",
+ note: "-0.91% this week",
+ trend: "down",
+ icon: "check",
+ },
+ {
+ value: "124,854",
+ label: "Refunded",
+ delta: "7.2",
+ note: "+1.51% this week",
+ trend: "up",
+ icon: "refund",
+ },
+];
+
+const orders: Order[] = [
+ {
+ no: "1",
+ id: "#12594",
+ date: "Dec 1, 2021",
+ customer: "Frank Murlo",
+ location: "312 S Wilmette Ave",
+ amount: "$847.69",
+ status: "New Order",
+ },
+ {
+ no: "2",
+ id: "#12490",
+ date: "Nov 15, 2021",
+ customer: "Thomas Bleir",
+ location: "Lathrop Ave, Harvey",
+ amount: "$477.14",
+ status: "On Delivery",
+ },
+ {
+ no: "3",
+ id: "#12306",
+ date: "Nov 02, 2021",
+ customer: "Bill Norton",
+ location: "5685 Bruce Ave, Portage",
+ amount: "$477.14",
+ status: "On Delivery",
+ },
+];
+
+const chartMonths = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"];
+const offlinePath =
+ "M 0 139 C 18 120, 36 107, 54 114 C 72 121, 90 127, 108 123 C 126 118, 144 91, 162 94 C 180 97, 198 105, 216 101 C 234 97, 252 67, 270 70 C 288 73, 306 90, 324 85 C 342 80, 360 72, 378 76 C 396 81, 414 111, 432 104 C 450 97, 468 82, 486 88 C 504 94, 522 105, 540 102 C 558 99, 576 95, 594 98 C 612 101, 630 108, 648 101 C 666 94, 684 68, 694 65";
+const onlinePath =
+ "M 0 123 C 18 126, 36 142, 54 133 C 72 124, 90 114, 108 118 C 126 122, 144 92, 162 96 C 180 100, 198 95, 216 82 C 234 69, 252 79, 270 65 C 288 51, 306 55, 324 57 C 342 59, 360 44, 378 53 C 396 62, 414 70, 432 65 C 450 60, 468 58, 486 61 C 504 64, 522 76, 540 69 C 558 62, 576 68, 594 63 C 612 58, 630 48, 648 82 C 666 116, 684 93, 694 100";
+
+const ringLegend = [
+ { label: "Offline", color: "#55C78A" },
+ { label: "Online", color: "#F49B14" },
+ { label: "Trade", color: "#3D7CE4" },
+];
export default function Home() {
return (
- <div className="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">
- <main className="flex min-h-screen w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
- <Image
- className="dark:invert"
- src="/next.svg"
- alt="Next.js logo"
- width={100}
- height={20}
- priority
- />
- <div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
- <h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
- To get started, edit the page.tsx file.
- </h1>
- <p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
- Looking for a starting point or more instructions? Head over to{" "}
- <a
- href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
- className="font-medium text-zinc-950 dark:text-zinc-50"
- >
- Templates
- </a>{" "}
- or the{" "}
- <a
- href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
- className="font-medium text-zinc-950 dark:text-zinc-50"
+ <div className="min-h-screen bg-[var(--dashboard-bg)] text-[var(--text-primary)]">
+ <div className="mx-auto min-h-screen max-w-[1440px] lg:flex">
+ <Sidebar />
+ <main className="flex-1 px-5 py-6 sm:px-8 lg:px-[40px] lg:pb-[56px] lg:pr-[56px] lg:pt-[60px]">
+ <Header />
+ <StatsSection />
+ <AnalyticsSection />
+ <OrdersSection />
+ </main>
+ </div>
+ </div>
+ );
+}
+
+function Sidebar() {
+ return (
+ <aside className="relative border-b border-[var(--border)] bg-white px-5 py-6 lg:min-h-screen lg:w-[285px] lg:border-b-0 lg:border-r lg:px-0 lg:py-0">
+ <Logo />
+ <div className="mt-8 flex gap-8 overflow-x-auto pb-1 lg:mt-[72px] lg:block lg:overflow-visible lg:pb-0">
+ <nav aria-label="Primary navigation" className="min-w-[193px] lg:ml-[56px]">
+ <ul className="space-y-[28px]">
+ {primaryNav.map((item) => (
+ <li key={item.label}>
+ <NavLink item={item} />
+ </li>
+ ))}
+ </ul>
+ </nav>
+ <nav
+ aria-label="Secondary navigation"
+ className="min-w-[193px] lg:absolute lg:bottom-[72px] lg:left-[56px]"
+ >
+ <ul className="space-y-[28px]">
+ {secondaryNav.map((item) => (
+ <li key={item.label}>
+ <NavLink item={item} />
+ </li>
+ ))}
+ </ul>
+ </nav>
+ </div>
+ <span className="absolute right-0 top-[158px] hidden h-6 w-1 rounded-l-[2px] bg-[var(--accent)] lg:block" />
+ </aside>
+ );
+}
+
+function Logo() {
+ return (
+ <div className="flex items-center gap-1 lg:ml-[51px] lg:mt-[60px]">
+ <span className="grid h-[30px] w-[30px] grid-cols-2 gap-[4px] rounded-[8px] bg-[#F4F7FF] p-[6px]">
+ <span className="rounded-full bg-[#347AE2]" />
+ <span className="rounded-full bg-[#8BB3FF]" />
+ <span className="rounded-full bg-[#8BB3FF]" />
+ <span className="rounded-full bg-[#347AE2]" />
+ </span>
+ <span className="text-[20px] font-bold leading-[30px] tracking-[0.01em]">
+ Aeon
+ </span>
+ </div>
+ );
+}
+
+function NavLink({ item }: { item: NavItem }) {
+ const Icon = navIcons[item.icon];
+ const textColor = item.active
+ ? "text-[var(--accent)]"
+ : item.danger
+ ? "text-[var(--danger)]"
+ : "text-[var(--text-secondary)]";
+
+ return (
+ <div className="flex w-[193px] items-center justify-between">
+ <div className="flex items-center gap-3">
+ <Icon className={textColor} />
+ <span className={`text-[16px] font-bold leading-6 ${textColor}`}>
+ {item.label}
+ </span>
+ </div>
+ {item.badge ? (
+ <span className="flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-[var(--danger)] px-[5px] text-center text-[12px] font-bold leading-[18px] text-white">
+ {item.badge}
+ </span>
+ ) : item.hasChevron ? (
+ <ChevronDown className="text-[var(--text-secondary)]" size={24} />
+ ) : null}
+ </div>
+ );
+}
+
+function Header() {
+ return (
+ <header className="flex flex-col gap-6 lg:flex-row lg:items-start lg:justify-between">
+ <div>
+ <h1 className="text-[28px] font-bold leading-[42px]">Welcome Back, Marci</h1>
+ <p className="text-[16px] font-bold leading-6 text-[var(--text-secondary)]">
+ Here is the information about all your orders
+ </p>
+ </div>
+ <div className="flex items-center gap-8 self-start lg:pt-0.5">
+ <div className="flex items-center gap-6 text-black">
+ <SearchIcon className="text-black" />
+ <div className="relative">
+ <BellIcon className="text-black" />
+ <span className="absolute right-0 top-0 h-1 w-1 rounded-full bg-[var(--danger)]" />
+ </div>
+ </div>
+ <button className="flex items-center gap-3" type="button" aria-label="Profile menu">
+ <span className="flex h-8 w-8 items-center justify-center rounded-full bg-[radial-gradient(circle_at_35%_30%,#9cbcff_12%,#5f81e5_50%,#d9a5a0_51%,#b76f67_100%)] text-[11px] font-semibold text-white shadow-[0_3px_10px_rgba(124,141,181,0.22)]">
+ MF
+ </span>
+ <span className="flex items-center gap-2">
+ <span className="text-[16px] font-bold leading-6">Marci Fumons</span>
+ <ChevronDown className="text-[var(--text-secondary)]" size={24} />
+ </span>
+ </button>
+ </div>
+ </header>
+ );
+}
+
+function StatsSection() {
+ return (
+ <section className="mt-8 rounded-[12px] border border-[var(--border)] bg-white px-5 py-[21px] lg:mt-8 lg:w-full lg:px-5">
+ <div className="grid gap-6 lg:grid-cols-[repeat(4,minmax(0,1fr))] lg:gap-0">
+ {stats.map((card, index) => (
+ <article
+ key={card.value}
+ className={`flex flex-col gap-3 ${index < stats.length - 1 ? "lg:border-r lg:border-[var(--border)] lg:pr-9" : ""} ${index > 0 ? "lg:pl-[26px]" : ""}`}
+ >
+ <div className="flex items-start justify-between">
+ <div>
+ <strong className="block text-[28px] font-semibold leading-[42px]">
+ {card.value}
+ </strong>
+ <p className="text-[16px] font-bold leading-6">{card.label}</p>
+ </div>
+ <span className="flex h-11 w-11 items-center justify-center rounded-[12px] bg-white shadow-[0_2px_10px_rgba(124,141,181,0.12)]">
+ {statIcons[card.icon]()}
+ </span>
+ </div>
+ <div className="flex items-center gap-3">
+ <span className="flex items-center gap-2 text-[14px] font-bold leading-[21px] text-[var(--text-secondary)]">
+ <TrendArrow trend={card.trend} />
+ {card.delta}
+ </span>
+ <span className="text-[14px] font-bold leading-[21px] text-[var(--text-secondary)]">
+ {card.note}
+ </span>
+ </div>
+ </article>
+ ))}
+ </div>
+ </section>
+ );
+}
+
+function AnalyticsSection() {
+ return (
+ <section className="mt-8 grid gap-6 lg:grid-cols-[772px_256px] lg:gap-8">
+ <LineChartCard />
+ <EarningsCard />
+ </section>
+ );
+}
+
+function LineChartCard() {
+ return (
+ <section className="rounded-[12px] border border-[var(--border)] bg-white p-5">
+ <div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
+ <h2 className="text-[20px] font-bold leading-[30px]">Orders Analytics</h2>
+ <div className="flex flex-wrap items-center gap-5">
+ <LegendDot color="#3D7CE4" label="Offline orders" />
+ <LegendDot color="#F49B14" label="Online orders" />
+ <FilterButton />
+ </div>
+ </div>
+ <div className="relative mt-6 h-[250px]">
+ <div className="absolute inset-x-0 top-0 space-y-[19px]">
+ {[100, 80, 60, 40, 20, 0].map((label, index) => (
+ <div key={label} className={index === 0 ? "h-[42px]" : "h-[21px]"}>
+ <div className="flex items-center justify-between">
+ <span className={`w-[24px] text-right text-[14px] font-bold leading-[21px] text-[var(--text-secondary)] ${index === 0 ? "translate-y-[1px]" : ""}`}>
+ {label}
+ </span>
+ <span
+ className={`ml-4 block flex-1 border-t border-[var(--chart-grid)] ${
+ index === 0 ? "mt-0" : "mt-0"
+ }`}
+ />
+ </div>
+ {index < 5 ? <div className="h-[19px]" /> : null}
+ </div>
+ ))}
+ </div>
+ <div className="absolute bottom-0 left-[55px] right-[55px] flex justify-between">
+ {chartMonths.map((month) => (
+ <span
+ key={month}
+ className="text-[14px] font-bold leading-[21px] text-[var(--text-secondary)]"
>
- Learning
- </a>{" "}
- center.
- </p>
+ {month}
+ </span>
+ ))}
</div>
- <div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
- <a
- className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
- href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
- target="_blank"
- rel="noopener noreferrer"
+ <div className="absolute bottom-[32px] left-[40px] right-[1px] top-[64px]">
+ <div className="absolute left-[246px] top-0 z-20 w-[111px]">
+ <div className="rounded-[12px] bg-white px-3 py-3 shadow-[0_10px_28px_rgba(124,141,181,0.18)]">
+ <p className="text-[12px] font-bold leading-[18px] text-[var(--text-secondary)]">
+ 15 Aug 2022
+ </p>
+ <p className="text-[24px] font-bold leading-6">$59,492.10</p>
+ </div>
+ <div className="mx-auto h-0 w-0 border-x-[6px] border-t-[5px] border-x-transparent border-t-white" />
+ </div>
+ <div className="absolute left-[246px] top-[29px] h-[181px] w-[18px] rounded-[6px] bg-[rgba(52,122,226,0.18)]" />
+ <div className="absolute left-[290px] top-[87px] h-2 w-2 rounded-full border-2 border-white bg-[#3D7CE4] shadow-[0_0_0_3px_rgba(52,122,226,0.2)]" />
+ <svg
+ viewBox="0 0 694 178"
+ className="absolute inset-0 h-full w-full"
+ fill="none"
+ aria-hidden="true"
>
- <Image
- className="dark:invert"
- src="/vercel.svg"
- alt="Vercel logomark"
- width={16}
- height={16}
+ <path
+ d={offlinePath}
+ stroke="#3D7CE4"
+ strokeWidth="2"
+ strokeLinecap="round"
+ strokeLinejoin="round"
/>
- Deploy Now
- </a>
- <a
- className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
- href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
- target="_blank"
- rel="noopener noreferrer"
- >
- Documentation
- </a>
+ <path
+ d={onlinePath}
+ stroke="#F49B14"
+ strokeWidth="2"
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ />
+ </svg>
</div>
- </main>
- </div>
+ </div>
+ </section>
+ );
+}
+
+function EarningsCard() {
+ return (
+ <section className="rounded-[12px] border border-[var(--border)] bg-white p-5">
+ <div className="flex items-center justify-between">
+ <h2 className="text-[20px] font-bold leading-[30px]">Earnings</h2>
+ <MoreIcon />
+ </div>
+ <div className="mt-5 flex justify-center">
+ <RingChart />
+ </div>
+ <div className="mt-5 flex items-center justify-between px-[5px]">
+ {ringLegend.map((item) => (
+ <LegendDot key={item.label} color={item.color} label={item.label} compact />
+ ))}
+ </div>
+ </section>
);
}
+
+function RingChart() {
+ return (
+ <svg viewBox="0 0 216 216" className="h-[216px] w-[216px]" aria-hidden="true">
+ {[75, 57, 39].map((radius) => (
+ <circle
+ key={radius}
+ cx="108"
+ cy="108"
+ r={radius}
+ fill="none"
+ stroke="#DDE5F6"
+ strokeWidth="7"
+ />
+ ))}
+ <Ring radius={75} color="#3D7CE4" offset={14} length={0.56} />
+ <Ring radius={57} color="#F49B14" offset={23} length={0.49} />
+ <Ring radius={39} color="#55C78A" offset={31} length={0.44} />
+ <Ring radius={66} color="#E7C89A" offset={96} length={0.22} opacity={0.85} />
+ <Ring radius={48} color="#B9E6D0" offset={118} length={0.19} opacity={0.8} />
+ <Ring radius={84} color="#A8C0F1" offset={134} length={0.21} opacity={0.85} />
+ </svg>
+ );
+}
+
+function Ring({
+ radius,
+ color,
+ offset,
+ length,
+ opacity = 1,
+}: {
+ radius: number;
+ color: string;
+ offset: number;
+ length: number;
+ opacity?: number;
+}) {
+ const circumference = 2 * Math.PI * radius;
+ return (
+ <circle
+ cx="108"
+ cy="108"
+ r={radius}
+ fill="none"
+ stroke={color}
+ strokeWidth="7"
+ strokeLinecap="round"
+ strokeDasharray={`${circumference * length} ${circumference}`}
+ strokeDashoffset={offset}
+ opacity={opacity}
+ transform="rotate(-90 108 108)"
+ />
+ );
+}
+
+function OrdersSection() {
+ return (
+ <section className="mt-8 rounded-[10px] border border-[var(--border)] bg-white p-5">
+ <div className="flex items-center justify-between">
+ <h2 className="text-[20px] font-bold leading-[30px]">Order List</h2>
+ <FilterButton />
+ </div>
+ <div className="mt-3 overflow-x-auto">
+ <table className="min-w-[1019px] border-separate border-spacing-0">
+ <thead>
+ <tr className="text-left">
+ <TableHead className="w-[61px] pl-3">No</TableHead>
+ <TableHead className="w-[114px]">ID</TableHead>
+ <TableHead className="w-[139px]">Date</TableHead>
+ <TableHead className="w-[164px]">Customer Name</TableHead>
+ <TableHead className="w-[186px]">Location</TableHead>
+ <TableHead className="w-[125px]">Amount</TableHead>
+ <TableHead className="w-[167px]">Status Order</TableHead>
+ <TableHead className="w-[51px] pr-3 text-right">Action</TableHead>
+ </tr>
+ </thead>
+ <tbody>
+ {orders.map((order) => (
+ <tr key={order.id}>
+ <TableCell className="pl-3">{order.no}</TableCell>
+ <TableCell>{order.id}</TableCell>
+ <TableCell>{order.date}</TableCell>
+ <TableCell>{order.customer}</TableCell>
+ <TableCell>{order.location}</TableCell>
+ <TableCell>{order.amount}</TableCell>
+ <TableCell>
+ <OrderStatus status={order.status} />
+ </TableCell>
+ <TableCell className="pr-3 text-right">
+ <MoreIcon />
+ </TableCell>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ </div>
+ </section>
+ );
+}
+
+function TableHead({
+ children,
+ className = "",
+}: {
+ children: React.ReactNode;
+ className?: string;
+}) {
+ const sortable = children !== "No" && children !== "Date" && children !== "Location" && children !== "Action";
+
+ return (
+ <th
+ scope="col"
+ className={`border-b border-[var(--border)] py-[18px] text-[12px] font-bold leading-[18px] text-black ${className}`}
+ >
+ <span className={`inline-flex items-center gap-1 ${className.includes("text-right") ? "justify-end" : ""}`}>
+ {children}
+ {sortable ? <SortIcon /> : null}
+ </span>
+ </th>
+ );
+}
+
+function TableCell({
+ children,
+ className = "",
+}: {
+ children: React.ReactNode;
+ className?: string;
+}) {
+ return (
+ <td
+ className={`border-b border-[var(--border)] py-4 text-[12px] font-bold leading-[18px] text-black ${className}`}
+ >
+ {children}
+ </td>
+ );
+}
+
+function OrderStatus({ status }: { status: Order["status"] }) {
+ const isNew = status === "New Order";
+ return (
+ <span className="inline-flex items-center gap-2 rounded-[8px] bg-white px-3 py-1 shadow-[0_2px_10px_rgba(124,141,181,0.12)]">
+ <span
+ className={`h-2 w-2 rounded-full ${isNew ? "bg-[#55C78A]" : "bg-[#F49B14]"}`}
+ />
+ <span className="text-[12px] font-bold leading-[18px] text-black">{status}</span>
+ </span>
+ );
+}
+
+function FilterButton() {
+ return (
+ <button
+ type="button"
+ className="inline-flex items-center gap-1 rounded-[8px] bg-white py-1 pl-3 pr-2 text-[12px] font-bold leading-[18px] text-black shadow-[0_2px_10px_rgba(124,141,181,0.12)]"
+ >
+ Monthly
+ <ChevronDown className="text-[var(--text-secondary)]" size={16} />
+ </button>
+ );
+}
+
+function LegendDot({
+ color,
+ label,
+ compact = false,
+}: {
+ color: string;
+ label: string;
+ compact?: boolean;
+}) {
+ return (
+ <span className={`inline-flex items-center gap-2 ${compact ? "" : ""}`}>
+ <span className="h-2 w-2 rounded-full" style={{ backgroundColor: color }} />
+ <span className={`${compact ? "text-[12px]" : "text-[12px]"} font-bold leading-[18px] text-black`}>
+ {label}
+ </span>
+ </span>
+ );
+}
+
+function TrendArrow({ trend }: { trend: StatCard["trend"] }) {
+ const color = trend === "up" ? "#55C78A" : "#FF5B5B";
+ const rotate = trend === "up" ? "-rotate-45" : "rotate-135";
+
+ return (
+ <span className={`inline-flex ${rotate}`}>
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
+ <path
+ d="M2 12L12 2M12 2H5.6M12 2V8.4"
+ stroke={color}
+ strokeWidth="1.8"
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ />
+ </svg>
+ </span>
+ );
+}
+
+function IconBase({
+ className = "",
+ size = 24,
+ children,
+ strokeWidth = 1.7,
+}: {
+ className?: string;
+ size?: number;
+ children: React.ReactNode;
+ strokeWidth?: number;
+}) {
+ return (
+ <svg
+ width={size}
+ height={size}
+ viewBox="0 0 24 24"
+ fill="none"
+ className={className}
+ aria-hidden="true"
+ stroke="currentColor"
+ strokeWidth={strokeWidth}
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ >
+ {children}
+ </svg>
+ );
+}
+
+function SearchIcon({ className = "" }: { className?: string }) {
+ return (
+ <IconBase className={className}>
+ <circle cx="11" cy="11" r="5.2" />
+ <path d="M15.5 15.5L19 19" />
+ </IconBase>
+ );
+}
+
+function BellIcon({ className = "" }: { className?: string }) {
+ return (
+ <IconBase className={className}>
+ <path d="M8.5 17.5H15.5" />
+ <path d="M10 19C10.5 19.8 11.1 20.2 12 20.2C12.9 20.2 13.5 19.8 14 19" />
+ <path d="M6.8 16.7C7.6 15.9 8 14.8 8 13.6V10.9C8 8.5 9.6 6.5 12 6.5C14.4 6.5 16 8.5 16 10.9V13.6C16 14.8 16.4 15.9 17.2 16.7" />
+ </IconBase>
+ );
+}
+
+function ChevronDown({
+ className = "",
+ size = 24,
+}: {
+ className?: string;
+ size?: number;
+}) {
+ return (
+ <IconBase className={className} size={size}>
+ <path d="M7 10L12 15L17 10" />
+ </IconBase>
+ );
+}
+
+function MoreIcon() {
+ return (
+ <button type="button" className="inline-flex h-6 w-6 items-center justify-center text-black">
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" aria-hidden="true">
+ <circle cx="7" cy="12" r="1.5" fill="currentColor" />
+ <circle cx="12" cy="12" r="1.5" fill="currentColor" />
+ <circle cx="17" cy="12" r="1.5" fill="currentColor" />
+ </svg>
+ </button>
+ );
+}
+
+function SortIcon() {
+ return (
+ <svg width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true">
+ <path d="M4 2L2.5 3.7H5.5L4 2Z" fill="#7C8DB5" />
+ <path d="M8 10L9.5 8.3H6.5L8 10Z" fill="#7C8DB5" />
+ <path d="M4 3.7V9" stroke="#7C8DB5" strokeWidth="1.1" strokeLinecap="round" />
+ <path d="M8 8.3V3" stroke="#7C8DB5" strokeWidth="1.1" strokeLinecap="round" />
+ </svg>
+ );
+}
+
+const navIcons = {
+ overview: ({ className = "" }: { className?: string }) => (
+ <IconBase className={className}>
+ <path d="M6.5 17.5V10.5" />
+ <path d="M11.5 17.5V6.5" />
+ <path d="M16.5 17.5V3.5" />
+ <path d="M4 20H20" />
+ </IconBase>
+ ),
+ product: ({ className = "" }: { className?: string }) => (
+ <IconBase className={className}>
+ <path d="M6.5 8.5H17.5L18.5 13.5H5.5L6.5 8.5Z" />
+ <path d="M8.5 8.5C8.5 6.6 10 5 12 5C14 5 15.5 6.6 15.5 8.5" />
+ <path d="M8.8 17.5H9" />
+ <path d="M15 17.5H15.2" />
+ </IconBase>
+ ),
+ orders: ({ className = "" }: { className?: string }) => (
+ <IconBase className={className}>
+ <circle cx="12" cy="8" r="3.2" />
+ <path d="M6.5 18.5C7.6 15.8 9.5 14.5 12 14.5C14.5 14.5 16.4 15.8 17.5 18.5" />
+ </IconBase>
+ ),
+ checkout: ({ className = "" }: { className?: string }) => (
+ <IconBase className={className}>
+ <rect x="7" y="4" width="10" height="15" rx="1.8" />
+ <path d="M10 8H14" />
+ <path d="M10 12H14" />
+ <path d="M10 16H13" />
+ </IconBase>
+ ),
+ settings: ({ className = "" }: { className?: string }) => (
+ <IconBase className={className}>
+ <circle cx="12" cy="12" r="2.8" />
+ <path d="M12 4.8V6.3" />
+ <path d="M12 17.7V19.2" />
+ <path d="M19.2 12H17.7" />
+ <path d="M6.3 12H4.8" />
+ <path d="M17.1 6.9L16 8" />
+ <path d="M8 16L6.9 17.1" />
+ <path d="M17.1 17.1L16 16" />
+ <path d="M8 8L6.9 6.9" />
+ </IconBase>
+ ),
+ help: ({ className = "" }: { className?: string }) => (
+ <IconBase className={className}>
+ <circle cx="12" cy="12" r="7.2" />
+ <path d="M10.1 9.6C10.3 8.7 11.1 8 12.1 8C13.3 8 14.1 8.8 14.1 9.9C14.1 11.6 12.1 11.7 12.1 13.4" />
+ <path d="M12 16.2H12.1" />
+ </IconBase>
+ ),
+ contact: ({ className = "" }: { className?: string }) => (
+ <IconBase className={className}>
+ <path d="M6 8.5C6 7.1 7.1 6 8.5 6H15.5C16.9 6 18 7.1 18 8.5V13.5C18 14.9 16.9 16 15.5 16H10L7 18V16H8.5C7.1 16 6 14.9 6 13.5V8.5Z" />
+ <path d="M9 11.2H9.1" />
+ <path d="M12 11.2H12.1" />
+ <path d="M15 11.2H15.1" />
+ </IconBase>
+ ),
+ logout: ({ className = "" }: { className?: string }) => (
+ <IconBase className={className}>
+ <path d="M10 6H8.2C7 6 6 7 6 8.2V15.8C6 17 7 18 8.2 18H10" />
+ <path d="M13 8L17 12L13 16" />
+ <path d="M17 12H9" />
+ </IconBase>
+ ),
+};
+
+const statIcons = {
+ users: () => (
+ <IconBase className="text-[var(--accent)]" size={24}>
+ <circle cx="9" cy="10" r="2.2" />
+ <path d="M5.8 16.6C6.7 14.9 7.9 14 9.4 14C10.9 14 12.1 14.9 13 16.6" />
+ <circle cx="15.7" cy="9.2" r="1.8" />
+ <path d="M14 14.8C14.6 14 15.3 13.7 16.2 13.7C17.1 13.7 17.9 14.2 18.4 15.2" />
+ </IconBase>
+ ),
+ bag: () => (
+ <IconBase className="text-[var(--accent)]" size={24}>
+ <path d="M7 9H17L18 16.5C18.1 17.4 17.4 18.2 16.5 18.2H7.5C6.6 18.2 5.9 17.4 6 16.5L7 9Z" />
+ <path d="M9 9V8.2C9 6.6 10.3 5.3 12 5.3C13.7 5.3 15 6.6 15 8.2V9" />
+ <path d="M9.5 12.3H9.6" />
+ <path d="M14.4 12.3H14.5" />
+ </IconBase>
+ ),
+ check: () => (
+ <IconBase className="text-[var(--accent)]" size={24}>
+ <circle cx="12" cy="12" r="7" />
+ <path d="M9 12.2L11.1 14.3L15.2 10.1" />
+ </IconBase>
+ ),
+ refund: () => (
+ <IconBase className="text-[var(--accent)]" size={24}>
+ <path d="M8.5 7.5H16.5" />
+ <path d="M8.5 7.5L11 5" />
+ <path d="M8.5 7.5L11 10" />
+ <path d="M15.5 16.5H7.5" />
+ <path d="M15.5 16.5L13 14" />
+ <path d="M15.5 16.5L13 19" />
+ </IconBase>
+ ),
+};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment