-
-
Save shricodev/f6edd67c32037c0a69def1b10985855d to your computer and use it in GitHub Desktop.
OpenAI GPT-5.4 - Code Changes (git patch)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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