diff --git a/.env b/.env
new file mode 100644
index 0000000..979796c
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+NEXT_PUBLIC_API_URL=https://newgarage.yslootahtech.com
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index e6ce5a4..8655a4c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,9 @@
# testing
/coverage
+/cypress/videos
+/cypress/screenshots
+/cypress/downloads
# next.js
/.next/
diff --git a/.vscode/mcp.json b/.vscode/mcp.json
new file mode 100644
index 0000000..6716ff9
--- /dev/null
+++ b/.vscode/mcp.json
@@ -0,0 +1,11 @@
+{
+ "servers": {
+ "shadcn": {
+ "command": "npx",
+ "args": [
+ "shadcn@latest",
+ "mcp"
+ ]
+ }
+ }
+}
diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx
new file mode 100644
index 0000000..1817e2f
--- /dev/null
+++ b/app/(auth)/login/page.tsx
@@ -0,0 +1,12 @@
+import { LoginForm } from "@/modules/auth/login-form";
+
+
+export default function Page() {
+ return (
+
+ )
+}
diff --git a/app/(authenticated)/layout.tsx b/app/(authenticated)/layout.tsx
new file mode 100644
index 0000000..e19769f
--- /dev/null
+++ b/app/(authenticated)/layout.tsx
@@ -0,0 +1,218 @@
+"use client"
+
+import type { NavGroup } from "@/base/types/navigation"
+import {
+ AlarmClockIcon,
+ AwardIcon,
+ BanknoteArrowDownIcon,
+ BarChart3Icon,
+ BellRingIcon,
+ BookIcon,
+ BriefcaseBusinessIcon,
+ Building2Icon,
+ CalendarCheck2Icon,
+ CalendarDaysIcon,
+ LayoutDashboardIcon,
+ ClipboardListIcon,
+ UsersIcon,
+ CalendarIcon,
+ CarIcon,
+ ClipboardCheckIcon,
+ Clock3Icon,
+ ClockIcon,
+ GemIcon,
+ GitBranchIcon,
+ HandCoinsIcon,
+ ListIcon,
+ ListTodoIcon,
+ MegaphoneIcon,
+ PackageIcon,
+ PhoneCallIcon,
+ PlugZapIcon,
+ ReceiptIcon,
+ ReceiptTextIcon,
+ SettingsIcon,
+ ShoppingBasketIcon,
+ CircleDollarSign,
+ StarIcon,
+ StoreIcon,
+ TimerIcon,
+ UserCogIcon,
+ WalletIcon,
+ WrenchIcon,
+ ShoppingCartIcon,
+} from "lucide-react"
+import Image from "next/image"
+import { DashboardLayout } from "@/base/components/layout/dashboard"
+import { useAuth } from "@/shared/hooks/use-auth"
+
+const navGroups: NavGroup[] = [
+ {
+ items: [
+ {
+ title: "Dashboard",
+ href: "/",
+ icon: ,
+ },
+ {
+ title: "Job Cards",
+ href: "/sales/workorder/list",
+ icon: ,
+ },
+ {
+ title: "Customer & Vehicles",
+ href: "/customer_vehicles",
+ icon: ,
+ },
+ {
+ title: "Reports",
+ href: "/reports",
+ icon: ,
+ },
+ ],
+ },
+ {
+ label: "Management",
+ items: [
+ {
+ title: "Calendars",
+ href: "/calendars",
+ icon: ,
+ items: [
+ { title: "Work Schedule", href: "/calendar/work_schedule/list", icon: },
+ { title: "Appointments", href: "/calendar/appointment/list", icon: },
+ ],
+ },
+ {
+ title: "Sales",
+ href: "/sales",
+ icon: ,
+ items: [
+ { title: "Customers", href: "/sales/customers", icon: },
+ { title: "Vehicles", href: "/sales/vehicles", icon: },
+ { title: "Inspections", href: "/sales/inspections", icon: },
+ { title: "Estimates", href: "/sales/estimate", icon: },
+ { title: "Job Cards", href: "/sales/workorder/list", icon: },
+ { title: "Invoices", href: "/sales/invoice", icon: },
+ { title: "Payments Received", href: "/sales/payment_received", icon: },
+ { title: "Credit Notes", href: "/sales/credit_notes", icon: },
+ ],
+ },
+ {
+ title: "Purchases",
+ href: "/purchases",
+ icon: ,
+ items: [
+ { title: "Vendors", href: "/purchase/vendor", icon: },
+ { title: "Expenses", href: "/purchase/expense", icon: },
+ { title: "Purchase Orders", href: "/purchase/purchase_order", icon: },
+ { title: "Bills", href: "/purchase/bill", icon: },
+ { title: "Payments Made", href: "/purchase/payments_made", icon: },
+ { title: "Vendor Credits", href: "/purchase/vendor_credit", icon: },
+ ],
+ },
+ {
+ title: "CRM",
+ href: "/crm",
+ icon: ,
+ items: [
+ { title: "Leads", href: "/crm/leads/list", icon: },
+ { title: "Calls", href: "/crm/calls_follow_up/list", icon: },
+ { title: "Tasks", href: "/crm/tasks/list", icon: },
+ ],
+ },
+ {
+ title: "Marketing",
+ href: "/marketing",
+ icon: ,
+ items: [
+ { title: "Service Reminders", href: "/marketing/service_reminder/list", icon: },
+ { title: "Rating & Reviews", href: "/marketing/rating_review", icon: },
+ { title: "Google Business Reviews", href: "/marketing/google_rating_review", icon: },
+ ],
+ },
+ {
+ title: "Accountants",
+ href: "/accountants",
+ icon: ,
+ items: [
+ { title: "Manual Journals", href: "/accountants/manual_journal", icon: },
+ { title: "Chart of Accounts", href: "/accountants/chart_of_account", icon: },
+ ],
+ },
+ {
+ title: "Employees",
+ href: "/productivity",
+ icon: ,
+ items: [
+ { title: "Employees", href: "/productivity/employees", icon: },
+ { title: "Time Clocks", href: "/productivity/time_clocks", icon: },
+ { title: "Time Sheets", href: "/productivity/timesheet", icon: },
+ { title: "Payroll", href: "/productivity/payroll", icon: },
+ { title: "Payments Made", href: "/productivity/employee_payments_made", icon: },
+ { title: "Shop Calendars", href: "/productivity/shop_calendars", icon: },
+ { title: "Shop Timing", href: "/productivity/shop_timings", icon: },
+ { title: "Holidays", href: "/productivity/holidays", icon: },
+ ],
+ },
+ {
+ title: "Items",
+ href: "/items",
+ icon: ,
+ items: [
+ { title: "Services", href: "/items/services", icon: },
+ { title: "Parts", href: "/items/parts", icon: },
+ { title: "Expense Item", href: "/items/expense_item", icon: },
+ { title: "Service Group", href: "/items/service_group", icon: },
+ { title: "Inspections", href: "/items/inspection", icon: },
+ { title: "Inventory Adjustments", href: "/items/adjustment", icon: },
+ ],
+ },
+ {
+ title: "Settings",
+ href: "/setting",
+ icon: ,
+ items: [
+ { title: "Company", href: "/setting/company", icon: },
+ { title: "Shop Types", href: "/setting/shop_type", icon: },
+ { title: "Tax & Rates", href: "/setting/tax_rates", icon: },
+ { title: "Configurations", href: "/setting/configurations/preferences/sales", icon: },
+ { title: "Templates", href: "/setting/templates", icon: },
+ { title: "Integrations", href: "/setting/integrations/providers", icon: },
+ { title: "Master", href: "/setting/master/body_type", icon: },
+ ],
+ },
+ ],
+ },
+]
+
+function Logo() {
+ return (
+
+
+
+ )
+}
+
+export default function AuthenticatedLayout({
+ children,
+}: {
+ children: React.ReactNode
+}) {
+ const { user } = useAuth()
+
+ const userInfo = user
+ ? {
+ name: user.name,
+ email: user.email,
+ initials: user.name.charAt(0).toUpperCase(),
+ }
+ : undefined
+
+ return (
+ } user={userInfo}>
+ {children}
+
+ )
+}
+
diff --git a/app/(authenticated)/page.tsx b/app/(authenticated)/page.tsx
new file mode 100644
index 0000000..69396b0
--- /dev/null
+++ b/app/(authenticated)/page.tsx
@@ -0,0 +1,14 @@
+import { DashboardHeader } from "@/base/components/layout/dashboard";
+import DashboardPage from "@/base/components/layout/dashboard/dashboard-page";
+export default function page() {
+ return (
+ } >
+
+
Dashboard
+
+ Welcome to your dashboard. Select an item from the sidebar to get started.
+
+
+
+ )
+}
diff --git a/app/(authenticated)/sales/customers/page.tsx b/app/(authenticated)/sales/customers/page.tsx
new file mode 100644
index 0000000..637fdd5
--- /dev/null
+++ b/app/(authenticated)/sales/customers/page.tsx
@@ -0,0 +1,54 @@
+"use client"
+
+import { ResourcePage } from '@/shared/data-view/resource-page'
+import { ColumnHeader } from '@/shared/data-view/table-view'
+import { CustomerForm } from '@/modules/customers/customer-form'
+import { CUSTOMER_ROUTES } from '@repo/api'
+import type { CustomersClient } from '@repo/api'
+import { Building2Icon, UserIcon } from 'lucide-react'
+
+export default function CustomersPage() {
+ return (
+
+ pageTitle='Customers'
+ title="Customer"
+ routeKey={CUSTOMER_ROUTES.INDEX}
+ getClient={(api) => api.customers}
+ columns={({ actionsColumn }) => [
+
+ {
+ accessorKey: "first_name",
+ header: ({ column }) => ,
+ cell: ({ row }) => {
+ const customerName = row.original.first_name
+ const isCompany = row.original.customer_type?.name?.toLocaleLowerCase() === "company";
+ const companyName = row.original.company_name
+ const name = isCompany && companyName ? `${customerName} (${row.original.last_name})` : customerName
+
+ return (
+ {isCompany ? : }
+ {name}
+
+ )
+ },
+ },
+ {
+ accessorKey: "email",
+ header: ({ column }) => ,
+ },
+ {
+ accessorKey: "phone",
+ header: ({ column }) => ,
+ },
+ actionsColumn(),
+ ]}
+ renderForm={({ resourceId, initialData, onSuccess }) => (
+
+ )}
+ />
+ )
+}
\ No newline at end of file
diff --git a/app/(authenticated)/sales/vehicles/page.tsx b/app/(authenticated)/sales/vehicles/page.tsx
new file mode 100644
index 0000000..e7e16d8
--- /dev/null
+++ b/app/(authenticated)/sales/vehicles/page.tsx
@@ -0,0 +1,58 @@
+"use client"
+
+import { ResourcePage } from '@/shared/data-view/resource-page'
+import { ColumnHeader } from '@/shared/data-view/table-view'
+import { VehicleForm } from '@/modules/vehicles/vehicle-form'
+import { VEHICLE_ROUTES } from '@repo/api'
+import type { VehiclesClient } from '@repo/api'
+import { CarIcon } from 'lucide-react'
+
+export default function VehiclesPage() {
+ return (
+
+ pageTitle="Vehicles"
+ title="Vehicle"
+ routeKey={VEHICLE_ROUTES.INDEX}
+ getClient={(api) => api.vehicles}
+ columns={({ actionsColumn }) => [
+ {
+ accessorKey: "name",
+ header: ({ column }) => ,
+ cell: ({ row }) => {
+ const r = row.original as any
+ const display = r.name || `${r.make ?? ""} ${r.model ?? ""}`.trim() || "—"
+ return (
+
+
+ {display}
+
+ )
+ },
+ },
+ {
+ accessorKey: "year",
+ header: ({ column }) => ,
+ cell: ({ row }) => (row.original as any).year ?? "—",
+ },
+ {
+ accessorKey: "license_plate",
+ header: ({ column }) => ,
+ cell: ({ row }) => (row.original as any).license_plate ?? "—",
+ },
+ {
+ accessorKey: "mileage",
+ header: ({ column }) => ,
+ cell: ({ row }) => (row.original as any).mileage ?? "—",
+ },
+ actionsColumn(),
+ ]}
+ renderForm={({ resourceId, initialData, onSuccess }) => (
+
+ )}
+ />
+ )
+}
\ No newline at end of file
diff --git a/app/(authenticated)/setting/shop_type/page.tsx b/app/(authenticated)/setting/shop_type/page.tsx
new file mode 100644
index 0000000..4e4c958
--- /dev/null
+++ b/app/(authenticated)/setting/shop_type/page.tsx
@@ -0,0 +1,54 @@
+"use client"
+
+import { ResourcePage } from "@/shared/data-view/resource-page"
+import { ColumnHeader } from "@/shared/data-view/table-view"
+import { ShopTypeForm } from "@/modules/settings/shop-type/shop-type-form"
+import { SHOP_TYPE_ROUTES } from "@repo/api"
+import type { ShopTypesClient } from "@repo/api"
+import { CheckIcon, XIcon } from "lucide-react"
+
+export default function ShopTypesPage() {
+ return (
+
+ pageTitle="Shop Types"
+ title="Shop Type"
+ routeKey={SHOP_TYPE_ROUTES.INDEX}
+ getClient={(api) => api.shopTypes}
+ columns={({ actionsColumn }) => [
+ {
+ accessorKey: "title",
+ header: ({ column }) => ,
+ },
+ {
+ accessorKey: "shop_type",
+ header: ({ column }) => ,
+ },
+ {
+ accessorKey: "note",
+ header: ({ column }) => ,
+ cell: ({ row }) => (
+
+ {(row.original as any).note ?? "—"}
+
+ ),
+ },
+ {
+ accessorKey: "is_default",
+ header: ({ column }) => ,
+ cell: ({ row }) =>
+ (row.original as any).is_default
+ ?
+ : ,
+ },
+ actionsColumn(),
+ ]}
+ renderForm={({ resourceId, initialData, onSuccess }) => (
+
+ )}
+ />
+ )
+}
diff --git a/app/globals.css b/app/globals.css
index 446b465..d4cf055 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -5,125 +5,175 @@
@custom-variant dark (&:is(.dark *));
@theme inline {
- --font-heading: var(--font-sans);
- --font-sans: var(--font-sans);
- --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);
- --color-foreground: var(--foreground);
- --color-background: var(--background);
- --radius-sm: calc(var(--radius) * 0.6);
- --radius-md: calc(var(--radius) * 0.8);
- --radius-lg: var(--radius);
- --radius-xl: calc(var(--radius) * 1.4);
- --radius-2xl: calc(var(--radius) * 1.8);
- --radius-3xl: calc(var(--radius) * 2.2);
- --radius-4xl: calc(var(--radius) * 2.6);
+ --font-heading: var(--font-sans);
+ --font-sans: var(--font-sans);
+ --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);
+ --color-foreground: var(--foreground);
+ --color-background: var(--background);
+ --radius-sm: calc(var(--radius) * 0.6);
+ --radius-md: calc(var(--radius) * 0.8);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) * 1.4);
+ --radius-2xl: calc(var(--radius) * 1.8);
+ --radius-3xl: calc(var(--radius) * 2.2);
+ --radius-4xl: calc(var(--radius) * 2.6);
+
+ --shadow-glow : 0 0 10px var(--primary);
}
:root {
- --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.87 0 0);
- --chart-2: oklch(0.556 0 0);
- --chart-3: oklch(0.439 0 0);
- --chart-4: oklch(0.371 0 0);
- --chart-5: oklch(0.269 0 0);
- --radius: 0.625rem;
- --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(96.416% 0.00011 271.152);
+ --foreground: oklch(0.062 0 0);
+ --card: oklch(0.975 0 0);
+ --card-foreground: oklch(0.281 0 0);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.145 0 0);
+ --primary: oklch(0.577 0.245 27.325);
+ --primary-foreground: oklch(0.985 0 0);
+ --secondary: oklch(0.97 0 0);
+ --secondary-foreground: oklch(0.205 0 0);
+ --muted: oklch(0.949 0 0);
+ --muted-foreground: oklch(0.6 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.87 0 0);
+ --chart-2: oklch(0.556 0 0);
+ --chart-3: oklch(0.439 0 0);
+ --chart-4: oklch(0.371 0 0);
+ --chart-5: oklch(0.269 0 0);
+ --radius: 0.625rem;
+ --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);
}
.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.87 0 0);
- --chart-2: oklch(0.556 0 0);
- --chart-3: oklch(0.439 0 0);
- --chart-4: oklch(0.371 0 0);
- --chart-5: oklch(0.269 0 0);
- --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(75.417% 0.14818 18.15);
+ --primary-foreground: oklch(0.985 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.87 0 0);
+ --chart-2: oklch(0.556 0 0);
+ --chart-3: oklch(0.439 0 0);
+ --chart-4: oklch(0.371 0 0);
+ --chart-5: oklch(0.269 0 0);
+ --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);
}
@layer base {
* {
@apply border-border outline-ring/50;
- }
+ }
+
body {
@apply bg-background text-foreground;
- }
+ }
+
html {
@apply font-sans;
- }
+ }
+}
+
+
+@layer utilities {
+ .dashboard-nav-item {
+ @apply
+ relative
+ overflow-hidden
+ data-active:bg-primary/10
+ data-active:text-primary
+ data-active:hover:text-primary
+ data-active:hover:bg-primary/15
+ transition-all
+ duration-300;
+ }
+
+ /* Accent bar — only in expanded mode */
+ /* .dashboard-nav-item:not([data-collapsed="true"])::after {
+ content: "";
+ position: absolute;
+ inset-inline-end: 0.25rem;
+ height: 80%;
+ border-radius: var(--radius-md);
+ z-index: 10;
+ box-shadow: 0 0 6px var(--primary);
+ }
+
+ .dashboard-nav-item:not([data-collapsed="true"])[data-active="true"]::after {
+ width: 0.25rem;
+ background-color: var(--primary);
+ } */
+
+ /* Collapsed mode: icon centered, no bar */
+ .dashboard-nav-item[data-collapsed="true"] {
+ @apply justify-center;
+ }
+
+ .dashboard-nav-sub-item {
+ @apply
+ transition-colors
+ duration-200
+ data-active:text-primary
+ data-active:font-medium
+ data-active:bg-primary/5
+ hover:text-primary/80;
+ }
}
\ No newline at end of file
diff --git a/app/layout.tsx b/app/layout.tsx
index a4c7321..326b949 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,10 +1,14 @@
-import { Geist, Geist_Mono, Inter } from "next/font/google"
+import { Geist_Mono, Inter } from "next/font/google"
import "./globals.css"
-import { ThemeProvider } from "@/components/theme-provider"
-import { cn } from "@/lib/utils";
+import { QueryProvider } from "@/shared/components/query-provider"
+import { ThemeProvider } from "@/shared/components/theme-provider"
+import { Toaster } from "@/shared/components/ui/sonner"
+import { ConfirmDialog } from "@/shared/components/confirm-dialog"
+import { NuqsAdapter } from "nuqs/adapters/next/app"
+import { cn } from "@/shared/lib/utils"
-const inter = Inter({subsets:['latin'],variable:'--font-sans'})
+const inter = Inter({ subsets: ["latin"], variable: "--font-sans" })
const fontMono = Geist_Mono({
subsets: ["latin"],
@@ -23,7 +27,13 @@ export default function RootLayout({
className={cn("antialiased", fontMono.variable, "font-sans", inter.variable)}
>
- {children}
+
+
+ {children}
+
+
+
+