From 2dc8878db7ef83039a89cc9ae2abcbb0df6f1b62 Mon Sep 17 00:00:00 2001 From: ianshaloom Date: Wed, 4 Mar 2026 19:41:52 +0300 Subject: [PATCH] =?UTF-8?q?feat(admin):=20implement=20navigation=20&=20lay?= =?UTF-8?q?out=20(Plan=2002,=20Phases=201=E2=80=933)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1 — Active route highlighting - NavMain derives isActive from usePathname() at render time - Flat links: exact match; collapsible groups: startsWith; sub-items: exact match - Removed hardcoded isActive fields from NAV_LINKS Phase 2 — Dynamic breadcrumbs - Added ROUTE_LABELS map to app.constants.ts - Created DynamicBreadcrumb component (pathname-driven, ShadCN primitives) - Wired DynamicBreadcrumb into dashboard layout header Phase 3 — Mobile shell (observation only, no structural changes needed) Icons — migrated all sidebar/breadcrumb icons from lucide-react to @hugeicons/react + @hugeicons/core-free-icons Infra - tsconfig.json: moduleResolution → bundler (required for hugeicons ESM exports) - Renamed middleware.ts → proxy.ts (Next.js 15.5 convention) - Added @hugeicons/mcp-server to .mcp.json Co-Authored-By: Claude Sonnet 4.6 --- .mcp.json | 18 ++ apps/admin/components.json | 8 +- apps/admin/next-env.d.ts | 2 +- apps/admin/package.json | 5 +- apps/admin/src/app/(dashboard)/layout.tsx | 2 + apps/admin/src/app/(dashboard)/page.tsx | 9 +- apps/admin/src/app/globals.css | 208 +++++++++--------- apps/admin/src/app/layout.tsx | 16 +- apps/admin/src/app/not-found.tsx | 4 +- .../components/layout/DynamicBreadcrumb.tsx | 69 ++++++ .../components/layout/sidebar/app-sidebar.tsx | 37 +--- .../components/layout/sidebar/nav-main.tsx | 95 ++++++-- .../shared/still_building_placeholder.tsx | 6 +- apps/admin/src/lib/constants/app.constants.ts | 74 +++---- apps/admin/src/{middleware.ts => proxy.ts} | 0 apps/admin/tsconfig.json | 11 +- package-lock.json | 170 ++++++++++---- package.json | 2 +- 18 files changed, 492 insertions(+), 244 deletions(-) create mode 100644 .mcp.json create mode 100644 apps/admin/src/components/layout/DynamicBreadcrumb.tsx rename apps/admin/src/{middleware.ts => proxy.ts} (100%) diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000..d3fd982 --- /dev/null +++ b/.mcp.json @@ -0,0 +1,18 @@ +{ + "mcpServers": { + "shadcn": { + "command": "npx", + "args": [ + "shadcn@latest", + "mcp" + ] + }, + "hugeicons": { + "command": "npx", + "args": [ + "-y", + "@hugeicons/mcp-server" + ] + } + } +} diff --git a/apps/admin/components.json b/apps/admin/components.json index 03909d9..5978e30 100644 --- a/apps/admin/components.json +++ b/apps/admin/components.json @@ -1,16 +1,16 @@ { "$schema": "https://ui.shadcn.com/schema.json", - "style": "new-york", + "style": "radix-nova", "rsc": true, "tsx": true, "tailwind": { "config": "", - "css": "src/app/globals.css", + "css": "app/globals.css", "baseColor": "neutral", "cssVariables": true, "prefix": "" }, - "iconLibrary": "lucide", + "iconLibrary": "hugeicons", "rtl": false, "aliases": { "components": "@/components", @@ -19,5 +19,7 @@ "lib": "@/lib", "hooks": "@/hooks" }, + "menuColor": "default", + "menuAccent": "subtle", "registries": {} } diff --git a/apps/admin/next-env.d.ts b/apps/admin/next-env.d.ts index 830fb59..c4b7818 100644 --- a/apps/admin/next-env.d.ts +++ b/apps/admin/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -/// +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/admin/package.json b/apps/admin/package.json index 7103ade..377431e 100644 --- a/apps/admin/package.json +++ b/apps/admin/package.json @@ -10,7 +10,10 @@ "type-check": "tsc --noEmit" }, "dependencies": { + "@base-ui/react": "^1.2.0", "@clerk/nextjs": "^6.38.2", + "@hugeicons/core-free-icons": "^3.3.0", + "@hugeicons/react": "^1.1.5", "@repo/convex": "*", "@repo/types": "*", "@repo/utils": "*", @@ -27,4 +30,4 @@ "tailwindcss": "^4.2.0", "tw-animate-css": "^1.4.0" } -} +} \ No newline at end of file diff --git a/apps/admin/src/app/(dashboard)/layout.tsx b/apps/admin/src/app/(dashboard)/layout.tsx index bbc250e..2346e80 100644 --- a/apps/admin/src/app/(dashboard)/layout.tsx +++ b/apps/admin/src/app/(dashboard)/layout.tsx @@ -1,6 +1,7 @@ import { AdminUserSync } from "../../components/auth/AdminUserSync"; import { AdminAuthGate } from "../../components/auth/AdminAuthGate"; import { AppSidebar } from "../../components/layout/sidebar/app-sidebar"; +import { DynamicBreadcrumb } from "../../components/layout/DynamicBreadcrumb"; import { SidebarInset, SidebarProvider, @@ -27,6 +28,7 @@ export default function DashboardLayout({ orientation="vertical" className="mr-2 data-[orientation=vertical]:h-4" /> +
diff --git a/apps/admin/src/app/(dashboard)/page.tsx b/apps/admin/src/app/(dashboard)/page.tsx index fa62daf..51a0807 100644 --- a/apps/admin/src/app/(dashboard)/page.tsx +++ b/apps/admin/src/app/(dashboard)/page.tsx @@ -1,7 +1,14 @@ export default function DashboardPage() { return (
-

Admin Dashboard

+
+
+
+
+
+
+
+
); } diff --git a/apps/admin/src/app/globals.css b/apps/admin/src/app/globals.css index db50c17..7d223ad 100644 --- a/apps/admin/src/app/globals.css +++ b/apps/admin/src/app/globals.css @@ -5,120 +5,122 @@ @custom-variant dark (&:is(.dark *)); @theme inline { - --radius-sm: calc(var(--radius) - 4px); - --radius-md: calc(var(--radius) - 2px); - --radius-lg: var(--radius); - --radius-xl: calc(var(--radius) + 4px); - --radius-2xl: calc(var(--radius) + 8px); - --radius-3xl: calc(var(--radius) + 12px); - --radius-4xl: calc(var(--radius) + 16px); - --color-background: var(--background); - --color-foreground: var(--foreground); - --color-card: var(--card); - --color-card-foreground: var(--card-foreground); - --color-popover: var(--popover); - --color-popover-foreground: var(--popover-foreground); - --color-primary: var(--primary); - --color-primary-foreground: var(--primary-foreground); - --color-secondary: var(--secondary); - --color-secondary-foreground: var(--secondary-foreground); - --color-muted: var(--muted); - --color-muted-foreground: var(--muted-foreground); - --color-accent: var(--accent); - --color-accent-foreground: var(--accent-foreground); - --color-destructive: var(--destructive); - --color-border: var(--border); - --color-input: var(--input); - --color-ring: var(--ring); - --color-chart-1: var(--chart-1); - --color-chart-2: var(--chart-2); - --color-chart-3: var(--chart-3); - --color-chart-4: var(--chart-4); - --color-chart-5: var(--chart-5); - --color-sidebar: var(--sidebar); - --color-sidebar-foreground: var(--sidebar-foreground); - --color-sidebar-primary: var(--sidebar-primary); - --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); - --color-sidebar-accent: var(--sidebar-accent); - --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); - --color-sidebar-border: var(--sidebar-border); - --color-sidebar-ring: var(--sidebar-ring); + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-sans); + --font-mono: var(--font-geist-mono); + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-ring: var(--ring); + --color-input: var(--input); + --color-border: var(--border); + --color-destructive: var(--destructive); + --color-accent-foreground: var(--accent-foreground); + --color-accent: var(--accent); + --color-muted-foreground: var(--muted-foreground); + --color-muted: var(--muted); + --color-secondary-foreground: var(--secondary-foreground); + --color-secondary: var(--secondary); + --color-primary-foreground: var(--primary-foreground); + --color-primary: var(--primary); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --color-card-foreground: var(--card-foreground); + --color-card: var(--card); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --radius-2xl: calc(var(--radius) + 8px); + --radius-3xl: calc(var(--radius) + 12px); + --radius-4xl: calc(var(--radius) + 16px); } :root { - --radius: 0.625rem; - --background: oklch(1 0 0); - --foreground: oklch(0.145 0 0); - --card: oklch(1 0 0); - --card-foreground: oklch(0.145 0 0); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.145 0 0); - --primary: oklch(0.205 0 0); - --primary-foreground: oklch(0.985 0 0); - --secondary: oklch(0.97 0 0); - --secondary-foreground: oklch(0.205 0 0); - --muted: oklch(0.97 0 0); - --muted-foreground: oklch(0.556 0 0); - --accent: oklch(0.97 0 0); - --accent-foreground: oklch(0.205 0 0); - --destructive: oklch(0.577 0.245 27.325); - --border: oklch(0.922 0 0); - --input: oklch(0.922 0 0); - --ring: oklch(0.708 0 0); - --chart-1: oklch(0.646 0.222 41.116); - --chart-2: oklch(0.6 0.118 184.704); - --chart-3: oklch(0.398 0.07 227.392); - --chart-4: oklch(0.828 0.189 84.429); - --chart-5: oklch(0.769 0.188 70.08); - --sidebar: oklch(0.985 0 0); - --sidebar-foreground: oklch(0.145 0 0); - --sidebar-primary: oklch(0.205 0 0); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.97 0 0); - --sidebar-accent-foreground: oklch(0.205 0 0); - --sidebar-border: oklch(0.922 0 0); - --sidebar-ring: oklch(0.708 0 0); + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.60 0.10 185); + --primary-foreground: oklch(0.98 0.01 181); + --secondary: oklch(0.967 0.001 286.375); + --secondary-foreground: oklch(0.21 0.006 285.885); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.58 0.22 27); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.85 0.13 181); + --chart-2: oklch(0.78 0.13 182); + --chart-3: oklch(0.70 0.12 183); + --chart-4: oklch(0.60 0.10 185); + --chart-5: oklch(0.51 0.09 186); + --radius: 0.45rem; + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.60 0.10 185); + --sidebar-primary-foreground: oklch(0.98 0.01 181); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); } .dark { - --background: oklch(0.145 0 0); - --foreground: oklch(0.985 0 0); - --card: oklch(0.205 0 0); - --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.205 0 0); - --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.922 0 0); - --primary-foreground: oklch(0.205 0 0); - --secondary: oklch(0.269 0 0); - --secondary-foreground: oklch(0.985 0 0); - --muted: oklch(0.269 0 0); - --muted-foreground: oklch(0.708 0 0); - --accent: oklch(0.269 0 0); - --accent-foreground: oklch(0.985 0 0); - --destructive: oklch(0.704 0.191 22.216); - --border: oklch(1 0 0 / 10%); - --input: oklch(1 0 0 / 15%); - --ring: oklch(0.556 0 0); - --chart-1: oklch(0.488 0.243 264.376); - --chart-2: oklch(0.696 0.17 162.48); - --chart-3: oklch(0.769 0.188 70.08); - --chart-4: oklch(0.627 0.265 303.9); - --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.205 0 0); - --sidebar-foreground: oklch(0.985 0 0); - --sidebar-primary: oklch(0.488 0.243 264.376); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.269 0 0); - --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.556 0 0); + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.70 0.12 183); + --primary-foreground: oklch(0.28 0.04 193); + --secondary: oklch(0.274 0.006 286.033); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.371 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.85 0.13 181); + --chart-2: oklch(0.78 0.13 182); + --chart-3: oklch(0.70 0.12 183); + --chart-4: oklch(0.60 0.10 185); + --chart-5: oklch(0.51 0.09 186); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.78 0.13 182); + --sidebar-primary-foreground: oklch(0.28 0.04 193); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); } @layer base { * { @apply border-border outline-ring/50; - } + } body { @apply bg-background text-foreground; - } + } } \ No newline at end of file diff --git a/apps/admin/src/app/layout.tsx b/apps/admin/src/app/layout.tsx index 3b52c39..6090305 100644 --- a/apps/admin/src/app/layout.tsx +++ b/apps/admin/src/app/layout.tsx @@ -1,10 +1,20 @@ import type { Metadata } from "next"; -import { Inter } from "next/font/google"; +import { DM_Sans, Geist, Geist_Mono } from "next/font/google"; import { ClerkProvider } from "@clerk/nextjs"; import { ConvexClientProvider } from "@repo/convex"; import "./globals.css"; -const inter = Inter({ subsets: ["latin"] }); +const dmSans = DM_Sans({subsets:['latin'],variable:'--font-sans'}); + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); export const metadata: Metadata = { title: { @@ -21,7 +31,7 @@ export default function RootLayout({ }) { return ( - + {children} diff --git a/apps/admin/src/app/not-found.tsx b/apps/admin/src/app/not-found.tsx index c906c06..ed72b22 100644 --- a/apps/admin/src/app/not-found.tsx +++ b/apps/admin/src/app/not-found.tsx @@ -6,8 +6,8 @@ export default function NotFound() {
-

- Page +

+ Page not found

diff --git a/apps/admin/src/components/layout/DynamicBreadcrumb.tsx b/apps/admin/src/components/layout/DynamicBreadcrumb.tsx new file mode 100644 index 0000000..c5e25a6 --- /dev/null +++ b/apps/admin/src/components/layout/DynamicBreadcrumb.tsx @@ -0,0 +1,69 @@ +"use client"; + +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import { HugeiconsIcon } from "@hugeicons/react"; +import { Home01Icon } from "@hugeicons/core-free-icons"; +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from "@/components/ui/breadcrumb"; +import { ROUTE_LABELS } from "@/lib/constants/app.constants"; + +export function DynamicBreadcrumb() { + const pathname = usePathname(); + const segments = pathname.split("/").filter(Boolean); + + // Root path — render "Dashboard" as a single page crumb + if (segments.length === 0) { + return ( + + + + Dashboard + + + + ); + } + + return ( + + + {/* Home icon link */} + + + + + + + + + {segments.map((segment, index) => { + const href = "/" + segments.slice(0, index + 1).join("/"); + const label = ROUTE_LABELS[segment] ?? segment; + const isLast = index === segments.length - 1; + + return ( + + + + {isLast ? ( + {label} + ) : ( + + {label} + + )} + + + ); + })} + + + ); +} diff --git a/apps/admin/src/components/layout/sidebar/app-sidebar.tsx b/apps/admin/src/components/layout/sidebar/app-sidebar.tsx index b7c7b86..5b681f6 100644 --- a/apps/admin/src/components/layout/sidebar/app-sidebar.tsx +++ b/apps/admin/src/components/layout/sidebar/app-sidebar.tsx @@ -1,16 +1,8 @@ "use client"; import * as React from "react"; -import { - LayoutDashboard, - ShoppingCart, - Package, - Users, - Tag, - Star, - Settings, - PawPrint, -} from "lucide-react"; +import { HugeiconsIcon } from "@hugeicons/react"; +import { Store01Icon } from "@hugeicons/core-free-icons"; import { Sidebar, SidebarContent, @@ -23,19 +15,8 @@ import { } from "@/components/ui/sidebar"; import { NavMain } from "./nav-main"; import { NavUser } from "./nav-user"; - -const navItems = [ - { title: "Dashboard", url: "/", icon: LayoutDashboard }, - { title: "Orders", url: "/orders", icon: ShoppingCart }, - { title: "Products", url: "/products", icon: Package }, - { title: "Customers", url: "/customers", icon: Users }, - { title: "Categories", url: "/categories", icon: Tag }, - { title: "Reviews", url: "/reviews", icon: Star }, -]; - -const settingsItems = [ - { title: "Settings", url: "/settings", icon: Settings }, -]; +import { NAV_LINKS } from "@/lib/constants/app.constants"; +import { PawPrint } from "lucide-react"; export function AppSidebar({ ...props }: React.ComponentProps) { return ( @@ -57,8 +38,14 @@ export function AppSidebar({ ...props }: React.ComponentProps) { - - + {/* dashboard */} + + + {/* Application */} + + + {/* Users */} + diff --git a/apps/admin/src/components/layout/sidebar/nav-main.tsx b/apps/admin/src/components/layout/sidebar/nav-main.tsx index c861409..6a4d083 100644 --- a/apps/admin/src/components/layout/sidebar/nav-main.tsx +++ b/apps/admin/src/components/layout/sidebar/nav-main.tsx @@ -1,39 +1,102 @@ "use client"; import Link from "next/link"; -import { type LucideIcon } from "lucide-react"; +import { usePathname } from "next/navigation"; +import { HugeiconsIcon, type IconSvgElement } from "@hugeicons/react"; +import { ArrowRight01Icon } from "@hugeicons/core-free-icons"; import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem, + SidebarMenuSub, + SidebarMenuSubButton, + SidebarMenuSubItem, } from "@/components/ui/sidebar"; +import { CollapsibleTrigger, CollapsibleContent, Collapsible } from "@/components/ui/collapsible"; export function NavMain({ - items, + overview, + isOverview, + navMain, }: { - items: { + overview: { title: string; url: string; - icon: LucideIcon; - isActive?: boolean; + icon: IconSvgElement; + }[]; + isOverview?: boolean; + navMain: { + title: string; + url: string; + icon: IconSvgElement; + items?: { + title: string; + url: string; + }[]; }[]; }) { + const pathname = usePathname(); + + if (isOverview) { + return ( + + Platform + + {overview.map((item) => ( + + + + + {item.title} + + + + ))} + + + ); + } + return ( - Platform + Application - {items.map((item) => ( - - - - - {item.title} - - - - ))} + {navMain.map((item) => { + const isGroupActive = pathname.startsWith(item.url); + return ( + + + + + + {item.title} + + + + + + {item.items?.map((subItem) => ( + + + + {subItem.title} + + + + ))} + + + + + ); + })} ); diff --git a/apps/admin/src/components/shared/still_building_placeholder.tsx b/apps/admin/src/components/shared/still_building_placeholder.tsx index 2023f4a..c2d330f 100644 --- a/apps/admin/src/components/shared/still_building_placeholder.tsx +++ b/apps/admin/src/components/shared/still_building_placeholder.tsx @@ -6,9 +6,9 @@ export default function StillBuildingPlaceholder() {
-

- Building - in progress +

+ Building + in Progress

diff --git a/apps/admin/src/lib/constants/app.constants.ts b/apps/admin/src/lib/constants/app.constants.ts index 06b2e31..c0fa211 100644 --- a/apps/admin/src/lib/constants/app.constants.ts +++ b/apps/admin/src/lib/constants/app.constants.ts @@ -1,30 +1,53 @@ -import { BookOpen, Bot, ShoppingCart, LayoutDashboard, Users } from "lucide-react"; +import { + DashboardSquare02Icon, + ShoppingCart01Icon, + PackageIcon, + UserMultipleIcon, +} from "@hugeicons/core-free-icons"; + +export const ROUTE_LABELS: Record = { + orders: "Orders", + products: "Products", + categories: "Categories", + images: "Images", + variants: "Variants", + customers: "Customers", + reviews: "Reviews", + messages: "Messages", + newsletter: "Newsletter", + users: "Users", + settings: "Settings", + returns: "Returns", +}; export const NAV_LINKS = { overview: [ { title: "Dashboard", url: "/", - icon: LayoutDashboard, + icon: DashboardSquare02Icon, }, ], navMain: [ { title: "Sales", url: "/orders", - icon: ShoppingCart, - isActive: true, + icon: ShoppingCart01Icon, items: [ { title: "Orders", url: "/orders", }, + { + title: "Returns", + url: "/returns", + }, ], }, { title: "Products", url: "/products", - icon: Bot, + icon: PackageIcon, items: [ { title: "Categories", @@ -32,7 +55,7 @@ export const NAV_LINKS = { }, { title: "Products", - url: "/products/products", + url: "/products", }, { title: "Images", @@ -44,54 +67,31 @@ export const NAV_LINKS = { }, ], }, - { - title: "Documentation", - url: "#", - icon: BookOpen, - items: [ - { - title: "Introduction", - url: "#", - }, - { - title: "Get Started", - url: "#", - }, - { - title: "Tutorials", - url: "#", - }, - { - title: "Changelog", - url: "#", - }, - ], - }, { title: "Customers", url: "/customers", - icon: Users, + icon: UserMultipleIcon, items: [ { title: "Reviews", - url: "#", + url: "/customers/reviews", }, { title: "Messages", - url: "#", + url: "/customers/messages", }, { title: "Newsletter", - url: "#", + url: "/customers/newsletter", }, ], }, ], - sales: [ + users: [ { - title: "Orders", - url: "/orders", - icon: ShoppingCart, + title: "Users", + url: "/users", + icon: UserMultipleIcon, }, ], }; diff --git a/apps/admin/src/middleware.ts b/apps/admin/src/proxy.ts similarity index 100% rename from apps/admin/src/middleware.ts rename to apps/admin/src/proxy.ts diff --git a/apps/admin/tsconfig.json b/apps/admin/tsconfig.json index fe63dae..207fe18 100644 --- a/apps/admin/tsconfig.json +++ b/apps/admin/tsconfig.json @@ -12,10 +12,10 @@ "incremental": true, "module": "esnext", "esModuleInterop": true, - "moduleResolution": "node", + "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "plugins": [ { "name": "next" @@ -23,14 +23,17 @@ ], "target": "ES2017", "paths": { - "@/*": ["./src/*"] + "@/*": [ + "./src/*" + ] } }, "include": [ "next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", - "**/*.tsx" + "**/*.tsx", + ".next/dev/types/**/*.ts" ], "exclude": [ "node_modules" diff --git a/package-lock.json b/package-lock.json index 3725f1c..0f31c04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@clerk/backend": "^2.32.1", "@tailwindcss/postcss": "^4.2.0", "convex": "^1.32.0", - "next": "^15.3.2", + "next": "16.1.6", "react": "^19.2.4", "react-dom": "^19.2.4", "stripe": "^20.4.0", @@ -45,7 +45,10 @@ "apps/admin": { "version": "0.0.1", "dependencies": { + "@base-ui/react": "^1.2.0", "@clerk/nextjs": "^6.38.2", + "@hugeicons/core-free-icons": "^3.3.0", + "@hugeicons/react": "^1.1.5", "@repo/convex": "*", "@repo/types": "*", "@repo/utils": "*", @@ -609,7 +612,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -663,6 +665,59 @@ "node": ">=6.9.0" } }, + "node_modules/@base-ui/react": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@base-ui/react/-/react-1.2.0.tgz", + "integrity": "sha512-O6aEQHcm+QyGTFY28xuwRD3SEJGZOBDpyjN2WvpfWYFVhg+3zfXPysAILqtM0C1kWC82MccOE/v1j+GHXE4qIw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.6", + "@base-ui/utils": "0.2.5", + "@floating-ui/react-dom": "^2.1.6", + "@floating-ui/utils": "^0.2.10", + "tabbable": "^6.4.0", + "use-sync-external-store": "^1.6.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17 || ^18 || ^19", + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@base-ui/utils": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@base-ui/utils/-/utils-0.2.5.tgz", + "integrity": "sha512-oYC7w0gp76RI5MxprlGLV0wze0SErZaRl3AAkeP3OnNB/UBMb6RqNf6ZSIlxOc9Qp68Ab3C2VOcJQyRs7Xc7Vw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.6", + "@floating-ui/utils": "^0.2.10", + "reselect": "^5.1.1", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "@types/react": "^17 || ^18 || ^19", + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@clerk/backend": { "version": "2.32.1", "resolved": "https://registry.npmjs.org/@clerk/backend/-/backend-2.32.1.tgz", @@ -1714,6 +1769,21 @@ "hono": "^4" } }, + "node_modules/@hugeicons/core-free-icons": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@hugeicons/core-free-icons/-/core-free-icons-3.3.0.tgz", + "integrity": "sha512-qYyr4JQ2eQIHTSTbITvnJvs6ERNK64D9gpwZnf2IyuG0exzqfyABLO/oTB71FB3RZPfu1GbwycdiGSo46apjMQ==", + "license": "MIT" + }, + "node_modules/@hugeicons/react": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@hugeicons/react/-/react-1.1.5.tgz", + "integrity": "sha512-JX/iDz3oO7hWdVqbjwFwRrAjHk8h2vI+mBkNzp4JcXG3t4idoupfjon73nLOA7cr27m0M8hrRC1Q2h6nEBGKVA==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.0.0" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -2498,9 +2568,9 @@ } }, "node_modules/@next/env": { - "version": "15.5.12", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.12.tgz", - "integrity": "sha512-pUvdJN1on574wQHjaBfNGDt9Mz5utDSZFsIIQkMzPgNS8ZvT4H2mwOrOIClwsQOb6EGx5M76/CZr6G8i6pSpLg==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz", + "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -2514,9 +2584,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "15.5.12", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.12.tgz", - "integrity": "sha512-RnRjBtH8S8eXCpUNkQ+543DUc7ys8y15VxmFU9HRqlo9BG3CcBUiwNtF8SNoi2xvGCVJq1vl2yYq+3oISBS0Zg==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz", + "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==", "cpu": [ "arm64" ], @@ -2530,9 +2600,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.5.12", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.12.tgz", - "integrity": "sha512-nqa9/7iQlboF1EFtNhWxQA0rQstmYRSBGxSM6g3GxvxHxcoeqVXfGNr9stJOme674m2V7r4E3+jEhhGvSQhJRA==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", + "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", "cpu": [ "x64" ], @@ -2546,9 +2616,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.5.12", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.12.tgz", - "integrity": "sha512-dCzAjqhDHwmoB2M4eYfVKqXs99QdQxNQVpftvP1eGVppamXh/OkDAwV737Zr0KPXEqRUMN4uCjh6mjO+XtF3Mw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", + "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", "cpu": [ "arm64" ], @@ -2562,9 +2632,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.5.12", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.12.tgz", - "integrity": "sha512-+fpGWvQiITgf7PUtbWY1H7qUSnBZsPPLyyq03QuAKpVoTy/QUx1JptEDTQMVvQhvizCEuNLEeghrQUyXQOekuw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", + "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", "cpu": [ "arm64" ], @@ -2578,9 +2648,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.5.12", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.12.tgz", - "integrity": "sha512-jSLvgdRRL/hrFAPqEjJf1fFguC719kmcptjNVDJl26BnJIpjL3KH5h6mzR4mAweociLQaqvt4UyzfbFjgAdDcw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", + "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", "cpu": [ "x64" ], @@ -2594,9 +2664,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "15.5.12", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.12.tgz", - "integrity": "sha512-/uaF0WfmYqQgLfPmN6BvULwxY0dufI2mlN2JbOKqqceZh1G4hjREyi7pg03zjfyS6eqNemHAZPSoP84x17vo6w==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", + "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", "cpu": [ "x64" ], @@ -2610,9 +2680,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.5.12", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.12.tgz", - "integrity": "sha512-xhsL1OvQSfGmlL5RbOmU+FV120urrgFpYLq+6U8C6KIym32gZT6XF/SDE92jKzzlPWskkbjOKCpqk5m4i8PEfg==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", + "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", "cpu": [ "arm64" ], @@ -2626,9 +2696,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.5.12", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.12.tgz", - "integrity": "sha512-Z1Dh6lhFkxvBDH1FoW6OU/L6prYwPSlwjLiZkExIAh8fbP6iI/M7iGTQAJPYJ9YFlWobCZ1PHbchFhFYb2ADkw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", + "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", "cpu": [ "x64" ], @@ -10110,7 +10180,6 @@ "version": "2.10.0", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", - "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -14337,14 +14406,15 @@ } }, "node_modules/next": { - "version": "15.5.12", - "resolved": "https://registry.npmjs.org/next/-/next-15.5.12.tgz", - "integrity": "sha512-Fi/wQ4Etlrn60rz78bebG1i1SR20QxvV8tVp6iJspjLUSHcZoeUXCt+vmWoEcza85ElZzExK/jJ/F6SvtGktjA==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", + "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==", "license": "MIT", "peer": true, "dependencies": { - "@next/env": "15.5.12", + "@next/env": "16.1.6", "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" @@ -14353,18 +14423,18 @@ "next": "dist/bin/next" }, "engines": { - "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.5.12", - "@next/swc-darwin-x64": "15.5.12", - "@next/swc-linux-arm64-gnu": "15.5.12", - "@next/swc-linux-arm64-musl": "15.5.12", - "@next/swc-linux-x64-gnu": "15.5.12", - "@next/swc-linux-x64-musl": "15.5.12", - "@next/swc-win32-arm64-msvc": "15.5.12", - "@next/swc-win32-x64-msvc": "15.5.12", - "sharp": "^0.34.3" + "@next/swc-darwin-arm64": "16.1.6", + "@next/swc-darwin-x64": "16.1.6", + "@next/swc-linux-arm64-gnu": "16.1.6", + "@next/swc-linux-arm64-musl": "16.1.6", + "@next/swc-linux-x64-gnu": "16.1.6", + "@next/swc-linux-x64-musl": "16.1.6", + "@next/swc-win32-arm64-msvc": "16.1.6", + "@next/swc-win32-x64-msvc": "16.1.6", + "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -15728,6 +15798,12 @@ "node": ">=0.10.0" } }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", @@ -16798,6 +16874,12 @@ "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/tabbable": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz", + "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", + "license": "MIT" + }, "node_modules/tagged-tag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", diff --git a/package.json b/package.json index dea6ead..7264e0b 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "@clerk/backend": "^2.32.1", "@tailwindcss/postcss": "^4.2.0", "convex": "^1.32.0", - "next": "^15.3.2", + "next": "16.1.6", "react": "^19.2.4", "react-dom": "^19.2.4", "stripe": "^20.4.0",