From 0796f3a96363c50c478baa156573f0f19d89fbe9 Mon Sep 17 00:00:00 2001 From: RISHII <93994298+RISHII7@users.noreply.github.com> Date: Thu, 2 Jul 2026 11:41:37 +0530 Subject: [PATCH] feat(web,ui): add dashboard module, sidebar layout, and expand UI library MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces the full DashboardLayout/DashboardSidebar module for apps/web and expands @workspace/ui from ~5 to 40+ shadcn/ui components. ## Dashboard module — apps/web/modules/dashboard/ - DashboardLayout: server component reading sidebar_state cookie for SSR-persisted collapse state; composes AuthGuard + OrganizationGuard + SidebarProvider + DashboardSidebar + main - DashboardSidebar: client component with three-section nav - Header: OrganizationSwitcher asChild with Clerk appearance tokens for sidebar-width and collapsible-icon states - Content: Customer Support (Conversations, Knowledge Base), Configuration (Widget Customization, Integrations, Voice Assistant), Account (Plans & Billing); active-route via usePathname - Footer: UserButton showName with Clerk appearance for icon-collapse - SidebarRail for drag-to-resize; collapsible=icon mode ## Dashboard pages — apps/web/app/(dashboard)/ Six stub pages scaffolded: /conversations, /files, /customization, /integrations, /plugins/vapi, /billing ## App router - app/(dashboard)/layout.tsx: replaced inline AuthGuard + OrganizationGuard with single DashboardLayout delegation ## UI library expansion — packages/ui 40+ shadcn/ui components added: accordion, alert-dialog, alert, aspect-ratio, avatar, badge, breadcrumb, calendar, card, carousel, chart, checkbox, collapsible, command, context-menu, dialog, drawer, dropdown-menu, empty, field, hover-card, input-group, input-otp, kbd, label, menubar, message, native-select, navigation-menu, pagination, popover, progress, radio-group, resizable, scroll-area, select, separator, sheet, sidebar, skeleton, slider, sonner, spinner, switch, table, tabs, textarea, toggle-group, toggle, tooltip New Radix UI primitives and peer deps: react-accordion, react-alert-dialog, react-aspect-ratio, react-avatar, react-checkbox, react-collapsible, react-context-menu, react-dialog, react-dropdown-menu, react-hover-card, react-label, react-menubar, react-navigation-menu, react-popover, react-progress, react-radio-group, react-scroll-area, react-select, react-separator, react-slider, react-switch, react-tabs, react-toggle, react-toggle-group, react-tooltip, cmdk, date-fns, embla-carousel-react, input-otp, react-day-picker, react-resizable-panels, recharts, sonner, vaul Core updates: button.tsx rewritten, input.tsx updated, globals.css expanded with sidebar/chart design tokens and Tailwind v4 layer ## Docs - CHANGELOG.md: v0.6.0 section with full technical detail - README.md: Dashboard Layout feature, architecture diagram updated, design system description updated --- CHANGELOG.md | 111 +- README.md | 12 +- apps/web/app/(dashboard)/billing/page.tsx | 5 + .../app/(dashboard)/conversations/page.tsx | 5 + .../app/(dashboard)/customization/page.tsx | 5 + apps/web/app/(dashboard)/files/page.tsx | 5 + .../web/app/(dashboard)/integrations/page.tsx | 5 + apps/web/app/(dashboard)/layout.tsx | 9 +- .../web/app/(dashboard)/plugins/vapi/page.tsx | 5 + .../ui/components/dashboard-sidebar/index.tsx | 203 + .../ui/layouts/dashboard-layout/index.tsx | 25 + apps/web/package.json | 13 +- packages/ui/package.json | 53 +- packages/ui/src/components/accordion.tsx | 66 + packages/ui/src/components/alert-dialog.tsx | 157 + packages/ui/src/components/alert.tsx | 76 + packages/ui/src/components/aspect-ratio.tsx | 22 + packages/ui/src/components/avatar.tsx | 53 + packages/ui/src/components/badge.tsx | 46 + packages/ui/src/components/breadcrumb.tsx | 109 + packages/ui/src/components/button.tsx | 47 +- packages/ui/src/components/calendar.tsx | 228 + packages/ui/src/components/card.tsx | 103 + packages/ui/src/components/carousel.tsx | 241 + packages/ui/src/components/chart.tsx | 353 ++ packages/ui/src/components/checkbox.tsx | 32 + packages/ui/src/components/collapsible.tsx | 33 + packages/ui/src/components/command.tsx | 196 + packages/ui/src/components/context-menu.tsx | 252 + packages/ui/src/components/dialog.tsx | 143 + packages/ui/src/components/drawer.tsx | 134 + packages/ui/src/components/dropdown-menu.tsx | 257 + packages/ui/src/components/empty.tsx | 104 + packages/ui/src/components/field.tsx | 238 + packages/ui/src/components/hover-card.tsx | 44 + packages/ui/src/components/input-group.tsx | 158 + packages/ui/src/components/input-otp.tsx | 86 + packages/ui/src/components/input.tsx | 7 +- packages/ui/src/components/kbd.tsx | 26 + packages/ui/src/components/label.tsx | 20 + packages/ui/src/components/menubar.tsx | 276 ++ packages/ui/src/components/message.tsx | 92 + packages/ui/src/components/native-select.tsx | 65 + .../ui/src/components/navigation-menu.tsx | 168 + packages/ui/src/components/pagination.tsx | 127 + packages/ui/src/components/popover.tsx | 48 + packages/ui/src/components/progress.tsx | 31 + packages/ui/src/components/radio-group.tsx | 45 + packages/ui/src/components/resizable.tsx | 56 + packages/ui/src/components/scroll-area.tsx | 58 + packages/ui/src/components/select.tsx | 185 + packages/ui/src/components/separator.tsx | 28 + packages/ui/src/components/sheet.tsx | 139 + packages/ui/src/components/sidebar.tsx | 726 +++ packages/ui/src/components/skeleton.tsx | 13 + packages/ui/src/components/slider.tsx | 63 + packages/ui/src/components/sonner.tsx | 45 + packages/ui/src/components/spinner.tsx | 16 + packages/ui/src/components/switch.tsx | 31 + packages/ui/src/components/table.tsx | 116 + packages/ui/src/components/tabs.tsx | 66 + packages/ui/src/components/textarea.tsx | 18 + packages/ui/src/components/toggle-group.tsx | 73 + packages/ui/src/components/toggle.tsx | 47 + packages/ui/src/components/tooltip.tsx | 61 + packages/ui/src/hooks/use-mobile.ts | 19 + packages/ui/src/styles/globals.css | 222 +- pnpm-lock.yaml | 4147 +++++++++-------- 68 files changed, 8673 insertions(+), 1995 deletions(-) create mode 100644 apps/web/app/(dashboard)/billing/page.tsx create mode 100644 apps/web/app/(dashboard)/conversations/page.tsx create mode 100644 apps/web/app/(dashboard)/customization/page.tsx create mode 100644 apps/web/app/(dashboard)/files/page.tsx create mode 100644 apps/web/app/(dashboard)/integrations/page.tsx create mode 100644 apps/web/app/(dashboard)/plugins/vapi/page.tsx create mode 100644 apps/web/modules/dashboard/ui/components/dashboard-sidebar/index.tsx create mode 100644 apps/web/modules/dashboard/ui/layouts/dashboard-layout/index.tsx create mode 100644 packages/ui/src/components/accordion.tsx create mode 100644 packages/ui/src/components/alert-dialog.tsx create mode 100644 packages/ui/src/components/alert.tsx create mode 100644 packages/ui/src/components/aspect-ratio.tsx create mode 100644 packages/ui/src/components/avatar.tsx create mode 100644 packages/ui/src/components/badge.tsx create mode 100644 packages/ui/src/components/breadcrumb.tsx create mode 100644 packages/ui/src/components/calendar.tsx create mode 100644 packages/ui/src/components/card.tsx create mode 100644 packages/ui/src/components/carousel.tsx create mode 100644 packages/ui/src/components/chart.tsx create mode 100644 packages/ui/src/components/checkbox.tsx create mode 100644 packages/ui/src/components/collapsible.tsx create mode 100644 packages/ui/src/components/command.tsx create mode 100644 packages/ui/src/components/context-menu.tsx create mode 100644 packages/ui/src/components/dialog.tsx create mode 100644 packages/ui/src/components/drawer.tsx create mode 100644 packages/ui/src/components/dropdown-menu.tsx create mode 100644 packages/ui/src/components/empty.tsx create mode 100644 packages/ui/src/components/field.tsx create mode 100644 packages/ui/src/components/hover-card.tsx create mode 100644 packages/ui/src/components/input-group.tsx create mode 100644 packages/ui/src/components/input-otp.tsx create mode 100644 packages/ui/src/components/kbd.tsx create mode 100644 packages/ui/src/components/label.tsx create mode 100644 packages/ui/src/components/menubar.tsx create mode 100644 packages/ui/src/components/message.tsx create mode 100644 packages/ui/src/components/native-select.tsx create mode 100644 packages/ui/src/components/navigation-menu.tsx create mode 100644 packages/ui/src/components/pagination.tsx create mode 100644 packages/ui/src/components/popover.tsx create mode 100644 packages/ui/src/components/progress.tsx create mode 100644 packages/ui/src/components/radio-group.tsx create mode 100644 packages/ui/src/components/resizable.tsx create mode 100644 packages/ui/src/components/scroll-area.tsx create mode 100644 packages/ui/src/components/select.tsx create mode 100644 packages/ui/src/components/separator.tsx create mode 100644 packages/ui/src/components/sheet.tsx create mode 100644 packages/ui/src/components/sidebar.tsx create mode 100644 packages/ui/src/components/skeleton.tsx create mode 100644 packages/ui/src/components/slider.tsx create mode 100644 packages/ui/src/components/sonner.tsx create mode 100644 packages/ui/src/components/spinner.tsx create mode 100644 packages/ui/src/components/switch.tsx create mode 100644 packages/ui/src/components/table.tsx create mode 100644 packages/ui/src/components/tabs.tsx create mode 100644 packages/ui/src/components/textarea.tsx create mode 100644 packages/ui/src/components/toggle-group.tsx create mode 100644 packages/ui/src/components/toggle.tsx create mode 100644 packages/ui/src/components/tooltip.tsx create mode 100644 packages/ui/src/hooks/use-mobile.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 540ff48..479acf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,113 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 --- +## [0.6.0] - 2026-07-02 + +### Overview + +This release introduces the **Dashboard module** — a full sidebar-driven layout with +Clerk-integrated navigation, six stub pages for the core product surfaces, and a +major expansion of the `@workspace/ui` component library to 40+ shadcn/ui components. + +--- + +### Added + +#### Dashboard module — `apps/web/modules/dashboard/` + +- **`ui/layouts/dashboard-layout/index.tsx`** — `DashboardLayout` server component; + reads `sidebar_state` cookie for SSR-persisted open/closed state, composes + `AuthGuard` + `OrganizationGuard` + `SidebarProvider` + `DashboardSidebar` + `main` + into a single reusable layout +- **`ui/components/dashboard-sidebar/index.tsx`** — `DashboardSidebar` client + component with full three-section nav: + - **Header** — `OrganizationSwitcher` inside `SidebarMenuButton asChild` with + custom Clerk `appearance` for sidebar-width and icon-collapse states + - **Content** — three `SidebarGroup` sections: Customer Support + (Conversations, Knowledge Base), Configuration (Widget Customization, + Integrations, Voice Assistant), Account (Plans & Billing); each item uses + `SidebarMenuButton asChild` wrapping a Next.js `` with active-state + detection via `usePathname` + - **Footer** — `UserButton showName` with custom Clerk `appearance` for + sidebar-width and icon-collapse layout + - **Rail** — `SidebarRail` for drag-to-resize; `collapsible="icon"` mode + +#### Dashboard pages — `apps/web/app/(dashboard)/` + +Six stub pages scaffolded for the core product surfaces: + +| Route | File | Section | +| ---------------- | ------------------------ | ---------------- | +| `/conversations` | `conversations/page.tsx` | Customer Support | +| `/files` | `files/page.tsx` | Knowledge Base | +| `/customization` | `customization/page.tsx` | Configuration | +| `/integrations` | `integrations/page.tsx` | Configuration | +| `/plugins/vapi` | `plugins/vapi/page.tsx` | Voice Assistant | +| `/billing` | `billing/page.tsx` | Account | + +#### UI component library expansion — `packages/ui` + +40+ new shadcn/ui components added to `@workspace/ui`: + +`accordion` · `alert-dialog` · `alert` · `aspect-ratio` · `avatar` · `badge` · +`breadcrumb` · `calendar` · `card` · `carousel` · `chart` · `checkbox` · +`collapsible` · `command` · `context-menu` · `dialog` · `drawer` · +`dropdown-menu` · `empty` · `field` · `hover-card` · `input-group` · `input-otp` · +`kbd` · `label` · `menubar` · `message` · `native-select` · `navigation-menu` · +`pagination` · `popover` · `progress` · `radio-group` · `resizable` · +`scroll-area` · `select` · `separator` · `sheet` · `sidebar` · `skeleton` · +`slider` · `sonner` · `spinner` · `switch` · `table` · `tabs` · `textarea` · +`toggle-group` · `toggle` · `tooltip` + +Also added: `hooks/use-mobile.ts` — `useIsMobile` hook used by the sidebar for +tooltip/collapse behaviour. + +New Radix UI primitives added to `packages/ui`: +`react-accordion`, `react-alert-dialog`, `react-aspect-ratio`, `react-avatar`, +`react-checkbox`, `react-collapsible`, `react-context-menu`, `react-dialog`, +`react-dropdown-menu`, `react-hover-card`, `react-label`, `react-menubar`, +`react-navigation-menu`, `react-popover`, `react-progress`, `react-radio-group`, +`react-scroll-area`, `react-select`, `react-separator`, `react-slider`, +`react-switch`, `react-tabs`, `react-toggle`, `react-toggle-group`, `react-tooltip` + +New peer dependencies added to `apps/web`: +`@base-ui/react`, `@shadcn/react`, `cmdk`, `date-fns`, `embla-carousel-react`, +`input-otp`, `react-day-picker`, `react-resizable-panels`, `recharts`, `sonner`, `vaul` + +--- + +### Changed + +#### App router — `apps/web/app/(dashboard)/layout.tsx` + +- Replaced inline `AuthGuard` + `OrganizationGuard` composition with a single + `` import, moving all layout concerns into the dashboard module. + The app route file is now a thin delegation wrapper. + +#### Core UI — `packages/ui` + +- **`button.tsx`** — rewritten with updated variant/size tokens and class structure + matching the expanded design system +- **`input.tsx`** — updated to align with new design token naming +- **`styles/globals.css`** — major update: new CSS custom property design tokens for + sidebar, chart palette, and extended color scales; Tailwind v4 layer structure + +--- + +### Technical Decisions + +- **Module-based architecture for dashboard** — `DashboardLayout` and + `DashboardSidebar` live under `modules/dashboard/ui/` rather than in `app/`, keeping + the app directory as a thin routing layer and making both components independently + testable and reusable. +- **Cookie-persisted sidebar state** — `sidebar_state` is read server-side in + `DashboardLayout` so the sidebar open/closed state survives hard refreshes without + layout shift. +- **Stub pages** — all six dashboard routes are scaffolded as minimal stubs; content + will be filled in by subsequent feature releases. + +--- + ## [0.5.0] - 2026-07-01 ### Overview @@ -511,7 +618,9 @@ Initial release of **Echo** — an enterprise-grade full-stack monorepo platform --- -[Unreleased]: https://github.com/RISHII7/echo/compare/v0.5.0...HEAD +[Unreleased]: https://github.com/RISHII7/echo/compare/v0.6.0...HEAD +[0.6.0]: https://github.com/RISHII7/echo/compare/v0.5.1...v0.6.0 +[0.5.1]: https://github.com/RISHII7/echo/compare/v0.5.0...v0.5.1 [0.5.0]: https://github.com/RISHII7/echo/compare/v0.4.1...v0.5.0 [0.4.1]: https://github.com/RISHII7/echo/compare/v0.4.0...v0.4.1 [0.4.0]: https://github.com/RISHII7/echo/compare/v0.3.0...v0.4.0 diff --git a/README.md b/README.md index e426ea9..8e656bc 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,9 @@ Echo is a production-ready, full-stack monorepo platform engineered for enterpri - **Authentication** — Clerk with hosted sign-in/sign-up UI, session management, and middleware-level route protection - **Organizations** — Clerk multi-tenant organizations with org-selection flow, guard-based enforcement, and `OrganizationSwitcher` - **Real-Time Backend** — Convex reactive database with live queries and server mutations, bridged to Clerk sessions +- **Dashboard Layout** — Sidebar-driven layout with cookie-persisted collapse state, Clerk `OrganizationSwitcher` / `UserButton`, icon-collapse mode, and active-route detection - **Type Safety** — End-to-end TypeScript with strict mode and generated API types across all packages -- **Design System** — Shared UI component library built on shadcn/ui and Radix primitives +- **Design System** — Shared UI component library with 40+ shadcn/ui components built on Radix primitives - **Performance** — Next.js Turbopack, React Server Components, and Tailwind CSS v4 - **Code Quality** — ESLint 9, Prettier, and TypeScript strict checks enforced on every commit - **Error Monitoring** — Sentry across client, server, and edge runtimes with session replay and tracing @@ -80,8 +81,11 @@ echo/ ├── apps/ │ ├── web/ # Primary Next.js application │ │ └── modules/ -│ │ └── auth/ # Auth feature module (views, layouts, guards) -│ └── widget/ # Embeddable widget application +│ │ ├── auth/ # Auth feature module (views, layouts, guards) +│ │ └── dashboard/ # Dashboard feature module (layout, sidebar) +│ └── widget/ # Embeddable widget application (Vapi AI voice) +│ └── modules/ +│ └── widget/ # Widget feature module (hooks) ├── packages/ │ ├── backend/ # Convex real-time backend (schema + server functions) │ ├── ui/ # Shared component library @@ -90,7 +94,7 @@ echo/ │ └── typescript-config/ # Shared TypeScript configuration ``` -The monorepo uses a **workspace dependency graph** where apps consume packages, and packages can depend on other packages. Turborepo ensures tasks run in topological order with caching at every layer. The `@workspace/backend` package provides a shared Convex client that both apps import for real-time data access. Feature modules under `apps/web/modules/` isolate domain logic (views, layouts, guards) from the Next.js app directory routing layer. +The monorepo uses a **workspace dependency graph** where apps consume packages, and packages can depend on other packages. Turborepo ensures tasks run in topological order with caching at every layer. The `@workspace/backend` package provides a shared Convex client that both apps import for real-time data access. Feature modules under `apps/web/modules/` and `apps/widget/modules/` isolate domain logic (views, layouts, guards, hooks) from the Next.js app directory routing layer. --- diff --git a/apps/web/app/(dashboard)/billing/page.tsx b/apps/web/app/(dashboard)/billing/page.tsx new file mode 100644 index 0000000..e88041c --- /dev/null +++ b/apps/web/app/(dashboard)/billing/page.tsx @@ -0,0 +1,5 @@ +const Page = () => { + return
Billing
+} + +export default Page diff --git a/apps/web/app/(dashboard)/conversations/page.tsx b/apps/web/app/(dashboard)/conversations/page.tsx new file mode 100644 index 0000000..401d528 --- /dev/null +++ b/apps/web/app/(dashboard)/conversations/page.tsx @@ -0,0 +1,5 @@ +const Page = () => { + return
Conversations
+} + +export default Page diff --git a/apps/web/app/(dashboard)/customization/page.tsx b/apps/web/app/(dashboard)/customization/page.tsx new file mode 100644 index 0000000..e226cce --- /dev/null +++ b/apps/web/app/(dashboard)/customization/page.tsx @@ -0,0 +1,5 @@ +const Page = () => { + return
Customization
+} + +export default Page diff --git a/apps/web/app/(dashboard)/files/page.tsx b/apps/web/app/(dashboard)/files/page.tsx new file mode 100644 index 0000000..9d9862e --- /dev/null +++ b/apps/web/app/(dashboard)/files/page.tsx @@ -0,0 +1,5 @@ +const Page = () => { + return
Files
+} + +export default Page diff --git a/apps/web/app/(dashboard)/integrations/page.tsx b/apps/web/app/(dashboard)/integrations/page.tsx new file mode 100644 index 0000000..0f135e1 --- /dev/null +++ b/apps/web/app/(dashboard)/integrations/page.tsx @@ -0,0 +1,5 @@ +const Page = () => { + return
Integrations
+} + +export default Page diff --git a/apps/web/app/(dashboard)/layout.tsx b/apps/web/app/(dashboard)/layout.tsx index d4c4dc0..5830508 100644 --- a/apps/web/app/(dashboard)/layout.tsx +++ b/apps/web/app/(dashboard)/layout.tsx @@ -1,12 +1,7 @@ -import { AuthGuard } from "@/modules/auth/ui/components/auth-guard" -import { OrganizationGuard } from "@/modules/auth/ui/components/organization-guard" +import { DashboardLayout } from "@/modules/dashboard/ui/layouts/dashboard-layout" const Layout = ({ children }: { children: React.ReactNode }) => { - return ( - - {children} - - ) + return {children} } export default Layout diff --git a/apps/web/app/(dashboard)/plugins/vapi/page.tsx b/apps/web/app/(dashboard)/plugins/vapi/page.tsx new file mode 100644 index 0000000..75b8218 --- /dev/null +++ b/apps/web/app/(dashboard)/plugins/vapi/page.tsx @@ -0,0 +1,5 @@ +const Page = () => { + return

Vapi Plugin

+} + +export default Page diff --git a/apps/web/modules/dashboard/ui/components/dashboard-sidebar/index.tsx b/apps/web/modules/dashboard/ui/components/dashboard-sidebar/index.tsx new file mode 100644 index 0000000..502b915 --- /dev/null +++ b/apps/web/modules/dashboard/ui/components/dashboard-sidebar/index.tsx @@ -0,0 +1,203 @@ +"use client" + +import Link from "next/link" +import { + CreditCardIcon, + InboxIcon, + LayoutDashboardIcon, + LibraryBigIcon, + Mic, + PaletteIcon, +} from "lucide-react" +import { usePathname } from "next/navigation" + +import { OrganizationSwitcher, UserButton } from "@clerk/nextjs" + +import { + Sidebar, + SidebarContent, + SidebarFooter, + SidebarGroup, + SidebarGroupContent, + SidebarGroupLabel, + SidebarHeader, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + SidebarRail, +} from "@workspace/ui/components/sidebar" + +const customerSupportItems = [ + { + title: "Conversations", + url: "/conversations", + icon: InboxIcon, + }, + { + title: "Knowldge Base", + url: "/files", + icon: LibraryBigIcon, + }, +] + +const configurationItems = [ + { + title: "Widget Customization", + url: "/customization", + icon: PaletteIcon, + }, + { + title: "Integrations", + url: "/integrations", + icon: LayoutDashboardIcon, + }, + { + title: "Voice Assistant", + url: "/plugins/vapi", + icon: Mic, + }, +] + +const accountItems = [ + { + title: "Plans & Billing", + url: "/billing", + icon: CreditCardIcon, + }, +] + +export const DashboardSidebar = () => { + const pathname = usePathname() + + const isActive = (url: string) => { + if (url === "/") { + return pathname === "/" + } + + return pathname.startsWith(url) + } + + return ( + + + + + + + + + + + + + {/* Customer Support */} + + Customer Support + + + {customerSupportItems.map((item) => ( + + + + + {item.title} + + + + ))} + + + + + {/* Configuration Settings*/} + + Configuration + + + {configurationItems.map((item) => ( + + + + + {item.title} + + + + ))} + + + + + {/* Account */} + + Account + + + {accountItems.map((item) => ( + + + + + {item.title} + + + + ))} + + + + + + + + + + + + + + ) +} diff --git a/apps/web/modules/dashboard/ui/layouts/dashboard-layout/index.tsx b/apps/web/modules/dashboard/ui/layouts/dashboard-layout/index.tsx new file mode 100644 index 0000000..f77398e --- /dev/null +++ b/apps/web/modules/dashboard/ui/layouts/dashboard-layout/index.tsx @@ -0,0 +1,25 @@ +import { AuthGuard } from "@/modules/auth/ui/components/auth-guard" +import { OrganizationGuard } from "@/modules/auth/ui/components/organization-guard" +import { DashboardSidebar } from "@/modules/dashboard/ui/components/dashboard-sidebar" +import { SidebarProvider } from "@workspace/ui/components/sidebar" +import { cookies } from "next/headers" + +export const DashboardLayout = async ({ + children, +}: { + children: React.ReactNode +}) => { + const cookieStore = await cookies() + const defaultOpen = cookieStore.get("sidebar_state")?.value === "true" + + return ( + + + + +
{children}
+
+
+
+ ) +} diff --git a/apps/web/package.json b/apps/web/package.json index 0c79ef8..eeccf5d 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -12,17 +12,28 @@ "typecheck": "tsc --noEmit" }, "dependencies": { + "@base-ui/react": "^1.6.0", "@clerk/nextjs": "^7.5.9", "@sentry/nextjs": "^10.62.0", + "@shadcn/react": "^0.2.0", "@workspace/backend": "workspace:*", "@workspace/math": "workspace:*", "@workspace/ui": "workspace:*", + "cmdk": "^1.1.1", "convex": "^1.42.0", + "date-fns": "^4.4.0", + "embla-carousel-react": "^8.6.0", + "input-otp": "^1.4.2", "lucide-react": "^1.21.0", "next": "16.2.6", "next-themes": "^0.4.6", "react": "19.2.4", - "react-dom": "19.2.4" + "react-day-picker": "^10.0.1", + "react-dom": "19.2.4", + "react-resizable-panels": "^4.12.0", + "recharts": "3.8.0", + "sonner": "^2.0.7", + "vaul": "^1.1.2" }, "devDependencies": { "@tailwindcss/postcss": "^4", diff --git a/packages/ui/package.json b/packages/ui/package.json index ee0189b..5058394 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -9,17 +9,52 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@base-ui/react": "^1.6.0", + "@hookform/resolvers": "^5.2.0", + "@radix-ui/react-accordion": "^1.2.11", + "@radix-ui/react-alert-dialog": "^1.1.14", + "@radix-ui/react-aspect-ratio": "^1.1.7", + "@radix-ui/react-avatar": "^1.1.10", + "@radix-ui/react-checkbox": "^1.3.2", + "@radix-ui/react-collapsible": "^1.1.11", + "@radix-ui/react-context-menu": "^2.2.15", + "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-dropdown-menu": "^2.1.15", + "@radix-ui/react-hover-card": "^1.1.14", + "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-menubar": "^1.1.15", + "@radix-ui/react-navigation-menu": "^1.2.13", + "@radix-ui/react-popover": "^1.1.14", + "@radix-ui/react-progress": "^1.1.7", + "@radix-ui/react-radio-group": "^1.3.7", + "@radix-ui/react-scroll-area": "^1.2.9", + "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-separator": "^1.1.7", + "@radix-ui/react-slider": "^1.3.5", + "@radix-ui/react-slot": "^1.1.2", + "@radix-ui/react-switch": "^1.2.5", + "@radix-ui/react-tabs": "^1.1.12", + "@radix-ui/react-toggle": "^1.1.9", + "@radix-ui/react-toggle-group": "^1.1.10", + "@radix-ui/react-tooltip": "^1.2.7", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^1.21.0", - "next-themes": "^0.4.6", - "react": "19.2.4", - "react-dom": "19.2.4", - "shadcn": "^4.12.0", - "tailwind-merge": "^3.6.0", - "tw-animate-css": "^1.4.0", - "zod": "^4.4.3" + "cmdk": "^1.1.1", + "date-fns": "^4.1.0", + "embla-carousel-react": "^8.6.0", + "input-otp": "^1.4.2", + "lucide-react": "^0.475.0", + "next-themes": "^0.4.4", + "react": "^19.0.0", + "react-day-picker": "^9.8.1", + "react-dom": "^19.0.0", + "react-hook-form": "^7.61.1", + "react-resizable-panels": "^3.0.3", + "recharts": "2.15.4", + "sonner": "^2.0.6", + "tailwind-merge": "^3.0.1", + "tw-animate-css": "^1.2.4", + "vaul": "^1.1.2", + "zod": "^3.24.2" }, "devDependencies": { "@tailwindcss/postcss": "^4", diff --git a/packages/ui/src/components/accordion.tsx b/packages/ui/src/components/accordion.tsx new file mode 100644 index 0000000..a723153 --- /dev/null +++ b/packages/ui/src/components/accordion.tsx @@ -0,0 +1,66 @@ +"use client" + +import * as React from "react" +import * as AccordionPrimitive from "@radix-ui/react-accordion" +import { ChevronDownIcon } from "lucide-react" + +import { cn } from "@workspace/ui/lib/utils" + +function Accordion({ + ...props +}: React.ComponentProps) { + return +} + +function AccordionItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AccordionTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + svg]:rotate-180", + className + )} + {...props} + > + {children} + + + + ) +} + +function AccordionContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + +
{children}
+
+ ) +} + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/packages/ui/src/components/alert-dialog.tsx b/packages/ui/src/components/alert-dialog.tsx new file mode 100644 index 0000000..09d4f45 --- /dev/null +++ b/packages/ui/src/components/alert-dialog.tsx @@ -0,0 +1,157 @@ +"use client" + +import * as React from "react" +import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" + +import { cn } from "@workspace/ui/lib/utils" +import { buttonVariants } from "@workspace/ui/components/button" + +function AlertDialog({ + ...props +}: React.ComponentProps) { + return +} + +function AlertDialogTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogPortal({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + + ) +} + +function AlertDialogHeader({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogFooter({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogAction({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogCancel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, +} diff --git a/packages/ui/src/components/alert.tsx b/packages/ui/src/components/alert.tsx new file mode 100644 index 0000000..2d446dd --- /dev/null +++ b/packages/ui/src/components/alert.tsx @@ -0,0 +1,76 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@workspace/ui/lib/utils" + +const alertVariants = cva( + "group/alert relative grid w-full gap-0.5 rounded-lg border px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4", + { + variants: { + variant: { + default: "bg-card text-card-foreground", + destructive: + "bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Alert({ + className, + variant, + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
+ ) +} + +function AlertTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground", + className + )} + {...props} + /> + ) +} + +function AlertDescription({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertAction({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { Alert, AlertTitle, AlertDescription, AlertAction } diff --git a/packages/ui/src/components/aspect-ratio.tsx b/packages/ui/src/components/aspect-ratio.tsx new file mode 100644 index 0000000..d9a6f84 --- /dev/null +++ b/packages/ui/src/components/aspect-ratio.tsx @@ -0,0 +1,22 @@ +import { cn } from "@workspace/ui/lib/utils" + +function AspectRatio({ + ratio, + className, + ...props +}: React.ComponentProps<"div"> & { ratio: number }) { + return ( +
+ ) +} + +export { AspectRatio } diff --git a/packages/ui/src/components/avatar.tsx b/packages/ui/src/components/avatar.tsx new file mode 100644 index 0000000..3bb4080 --- /dev/null +++ b/packages/ui/src/components/avatar.tsx @@ -0,0 +1,53 @@ +"use client" + +import * as React from "react" +import * as AvatarPrimitive from "@radix-ui/react-avatar" + +import { cn } from "@workspace/ui/lib/utils" + +function Avatar({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarImage({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarFallback({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Avatar, AvatarImage, AvatarFallback } diff --git a/packages/ui/src/components/badge.tsx b/packages/ui/src/components/badge.tsx new file mode 100644 index 0000000..73268ae --- /dev/null +++ b/packages/ui/src/components/badge.tsx @@ -0,0 +1,46 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@workspace/ui/lib/utils" + +const badgeVariants = cva( + "inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-md border px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", + secondary: + "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + destructive: + "border-transparent bg-destructive text-white focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/90", + outline: + "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<"span"> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : "span" + + return ( + + ) +} + +export { Badge, badgeVariants } diff --git a/packages/ui/src/components/breadcrumb.tsx b/packages/ui/src/components/breadcrumb.tsx new file mode 100644 index 0000000..56209ab --- /dev/null +++ b/packages/ui/src/components/breadcrumb.tsx @@ -0,0 +1,109 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { ChevronRight, MoreHorizontal } from "lucide-react" + +import { cn } from "@workspace/ui/lib/utils" + +function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { + return