From b7afb5aa1e03ee0ebdbb1808e98aeb30b86a9ba2 Mon Sep 17 00:00:00 2001 From: shadcn Date: Mon, 17 Mar 2025 15:00:23 +0400 Subject: [PATCH] feat(v4): dashboard 02 (#6950) * feat(v4): dashboard 02 * fix: lint --- .../dashboard-02/components/app-sidebar.tsx | 169 ++++ .../dashboard-02/components/data-table.tsx | 756 ++++++++++++++++++ .../dashboard-02/components/nav-clouds.tsx | 74 ++ .../dashboard-02/components/nav-documents.tsx | 89 +++ .../dashboard-02/components/nav-main.tsx | 56 ++ .../dashboard-02/components/nav-secondary.tsx | 71 ++ .../dashboard-02/components/nav-user.tsx | 110 +++ apps/v4/app/(examples)/dashboard-02/data.json | 614 ++++++++++++++ .../v4/app/(examples)/dashboard-02/layout.tsx | 62 ++ apps/v4/app/(examples)/dashboard-02/page.tsx | 79 ++ apps/v4/app/(examples)/dashboard-02/theme.css | 23 + apps/v4/package.json | 8 +- pnpm-lock.yaml | 101 ++- 13 files changed, 2210 insertions(+), 2 deletions(-) create mode 100644 apps/v4/app/(examples)/dashboard-02/components/app-sidebar.tsx create mode 100644 apps/v4/app/(examples)/dashboard-02/components/data-table.tsx create mode 100644 apps/v4/app/(examples)/dashboard-02/components/nav-clouds.tsx create mode 100644 apps/v4/app/(examples)/dashboard-02/components/nav-documents.tsx create mode 100644 apps/v4/app/(examples)/dashboard-02/components/nav-main.tsx create mode 100644 apps/v4/app/(examples)/dashboard-02/components/nav-secondary.tsx create mode 100644 apps/v4/app/(examples)/dashboard-02/components/nav-user.tsx create mode 100644 apps/v4/app/(examples)/dashboard-02/data.json create mode 100644 apps/v4/app/(examples)/dashboard-02/layout.tsx create mode 100644 apps/v4/app/(examples)/dashboard-02/page.tsx create mode 100644 apps/v4/app/(examples)/dashboard-02/theme.css diff --git a/apps/v4/app/(examples)/dashboard-02/components/app-sidebar.tsx b/apps/v4/app/(examples)/dashboard-02/components/app-sidebar.tsx new file mode 100644 index 0000000000..0f242895d0 --- /dev/null +++ b/apps/v4/app/(examples)/dashboard-02/components/app-sidebar.tsx @@ -0,0 +1,169 @@ +"use client" + +import * as React from "react" +import { + IconCloud, + IconDashboard, + IconDatabase, + IconFileWord, + IconHelp, + IconInnerShadowTop, + IconListDetails, + IconReport, + IconSearch, + IconSettings, +} from "@tabler/icons-react" + +import { + Sidebar, + SidebarContent, + SidebarFooter, + SidebarHeader, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, +} from "@/registry/new-york-v4/ui/sidebar" +import { NavClouds } from "@/app/(examples)/dashboard-02/components/nav-clouds" +import { NavDocuments } from "@/app/(examples)/dashboard-02/components/nav-documents" +import { NavMain } from "@/app/(examples)/dashboard-02/components/nav-main" +import { NavSecondary } from "@/app/(examples)/dashboard-02/components/nav-secondary" +import { NavUser } from "@/app/(examples)/dashboard-02/components/nav-user" + +const data = { + user: { + name: "shadcn", + email: "m@example.com", + avatar: "/avatars/shadcn.jpg", + }, + navMain: [ + { + title: "Dashboard", + url: "#", + icon: IconDashboard, + }, + { + title: "Lifecycle", + url: "#", + icon: IconListDetails, + }, + ], + navClouds: [ + { + title: "Capture", + icon: IconCloud, + iconClassName: + "fill-amber-500 text-amber-500 dark:fill-amber-400 dark:text-amber-400", + isActive: true, + url: "#", + items: [ + { + title: "Active Proposals", + url: "#", + }, + { + title: "Archived", + url: "#", + }, + ], + }, + { + title: "Proposal", + icon: IconCloud, + iconClassName: + "fill-blue-500 text-blue-500 dark:fill-blue-400 dark:text-blue-400", + url: "#", + items: [ + { + title: "Active Proposals", + url: "#", + }, + { + title: "Archived", + url: "#", + }, + ], + }, + { + title: "Contract", + icon: IconCloud, + iconClassName: + "fill-teal-500 text-teal-500 dark:fill-teal-400 dark:text-teal-400", + url: "#", + items: [ + { + title: "Active Proposals", + url: "#", + }, + { + title: "Archived", + url: "#", + }, + ], + }, + ], + navSecondary: [ + { + title: "Settings", + url: "#", + icon: IconSettings, + }, + { + title: "Get Help", + url: "#", + icon: IconHelp, + }, + { + title: "Search", + url: "#", + icon: IconSearch, + }, + ], + documents: [ + { + name: "Data Library", + url: "#", + icon: IconDatabase, + }, + { + name: "Reports", + url: "#", + icon: IconReport, + }, + { + name: "Word Assistant", + url: "#", + icon: IconFileWord, + }, + ], +} + +export function AppSidebar({ ...props }: React.ComponentProps) { + return ( + + + + + + + + Acme Inc. + + + + + + + + + + + + + + + + ) +} diff --git a/apps/v4/app/(examples)/dashboard-02/components/data-table.tsx b/apps/v4/app/(examples)/dashboard-02/components/data-table.tsx new file mode 100644 index 0000000000..2ee5917462 --- /dev/null +++ b/apps/v4/app/(examples)/dashboard-02/components/data-table.tsx @@ -0,0 +1,756 @@ +"use client" + +import * as React from "react" +import { + DndContext, + KeyboardSensor, + MouseSensor, + TouchSensor, + closestCenter, + useSensor, + useSensors, + type DragEndEvent, + type UniqueIdentifier, +} from "@dnd-kit/core" +import { restrictToVerticalAxis } from "@dnd-kit/modifiers" +import { + SortableContext, + arrayMove, + useSortable, + verticalListSortingStrategy, +} from "@dnd-kit/sortable" +import { CSS } from "@dnd-kit/utilities" +import { + IconChevronDown, + IconChevronLeft, + IconChevronRight, + IconChevronsLeft, + IconChevronsRight, + IconCircleCheckFilled, + IconDotsVertical, + IconGripVertical, + IconLayoutColumns, + IconLoader, + IconPlus, + IconTrendingUp, +} from "@tabler/icons-react" +import { + ColumnDef, + ColumnFiltersState, + Row, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFacetedRowModel, + getFacetedUniqueValues, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table" +import { Area, AreaChart, CartesianGrid, XAxis } from "recharts" +import { toast } from "sonner" +import { z } from "zod" + +import { useIsMobile } from "@/registry/new-york-v4/hooks/use-mobile" +import { Badge } from "@/registry/new-york-v4/ui/badge" +import { Button } from "@/registry/new-york-v4/ui/button" +import { + ChartConfig, + ChartContainer, + ChartTooltip, + ChartTooltipContent, +} from "@/registry/new-york-v4/ui/chart" +import { Checkbox } from "@/registry/new-york-v4/ui/checkbox" +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from "@/registry/new-york-v4/ui/drawer" +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/registry/new-york-v4/ui/dropdown-menu" +import { Input } from "@/registry/new-york-v4/ui/input" +import { Label } from "@/registry/new-york-v4/ui/label" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/registry/new-york-v4/ui/select" +import { Separator } from "@/registry/new-york-v4/ui/separator" +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/registry/new-york-v4/ui/table" +import { Tabs, TabsList, TabsTrigger } from "@/registry/new-york-v4/ui/tabs" + +export const schema = z.object({ + id: z.number(), + header: z.string(), + type: z.string(), + status: z.string(), + target: z.string(), + limit: z.string(), + reviewer: z.string(), +}) + +// Create a separate component for the drag handle +function DragHandle({ id }: { id: number }) { + const { attributes, listeners } = useSortable({ + id, + }) + + return ( + + ) +} + +const columns: ColumnDef>[] = [ + { + id: "drag", + header: () => null, + cell: ({ row }) => , + }, + { + id: "select", + header: ({ table }) => ( +
+ table.toggleAllPageRowsSelected(!!value)} + aria-label="Select all" + /> +
+ ), + cell: ({ row }) => ( +
+ row.toggleSelected(!!value)} + aria-label="Select row" + /> +
+ ), + enableSorting: false, + enableHiding: false, + }, + { + accessorKey: "header", + header: "Header", + cell: ({ row }) => { + return + }, + enableHiding: false, + }, + { + accessorKey: "type", + header: "Section Type", + cell: ({ row }) => ( +
+ + {row.original.type} + +
+ ), + }, + { + accessorKey: "status", + header: "Status", + cell: ({ row }) => ( + + {row.original.status === "Done" ? ( + + ) : ( + + )} + {row.original.status} + + ), + }, + { + accessorKey: "target", + header: () =>
Target
, + cell: ({ row }) => ( +
{ + e.preventDefault() + toast.promise(new Promise((resolve) => setTimeout(resolve, 1000)), { + loading: `Saving ${row.original.header}`, + success: "Done", + error: "Error", + }) + }} + > + +
+ ), + }, + { + accessorKey: "limit", + header: () =>
Limit
, + cell: ({ row }) => ( +
{ + e.preventDefault() + toast.promise(new Promise((resolve) => setTimeout(resolve, 1000)), { + loading: `Saving ${row.original.header}`, + success: "Done", + error: "Error", + }) + }} + > + +
+ ), + }, + { + accessorKey: "reviewer", + header: "Reviewer", + cell: ({ row }) => { + const isAssigned = row.original.reviewer !== "Assign reviewer" + + if (isAssigned) { + return row.original.reviewer + } + + return ( + + ) + }, + }, + { + id: "actions", + cell: () => ( + + + + + + Edit + Make a copy + Favorite + + Delete + + + ), + }, +] + +function DraggableRow({ row }: { row: Row> }) { + const { transform, transition, setNodeRef, isDragging } = useSortable({ + id: row.original.id, + }) + + return ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + ) +} + +export function DataTable({ + data: initialData, +}: { + data: z.infer[] +}) { + const [data, setData] = React.useState(() => initialData) + const [rowSelection, setRowSelection] = React.useState({}) + const [columnVisibility, setColumnVisibility] = + React.useState({}) + const [columnFilters, setColumnFilters] = React.useState( + [] + ) + const [sorting, setSorting] = React.useState([]) + const [pagination, setPagination] = React.useState({ + pageIndex: 0, + pageSize: 10, + }) + const sortableId = React.useId() + const sensors = useSensors( + useSensor(MouseSensor, {}), + useSensor(TouchSensor, {}), + useSensor(KeyboardSensor, {}) + ) + + const dataIds = React.useMemo( + () => data?.map(({ id }) => id) || [], + [data] + ) + + const table = useReactTable({ + data, + columns, + state: { + sorting, + columnVisibility, + rowSelection, + columnFilters, + pagination, + }, + getRowId: (row) => row.id.toString(), + enableRowSelection: true, + onRowSelectionChange: setRowSelection, + onSortingChange: setSorting, + onColumnFiltersChange: setColumnFilters, + onColumnVisibilityChange: setColumnVisibility, + onPaginationChange: setPagination, + getCoreRowModel: getCoreRowModel(), + getFilteredRowModel: getFilteredRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getFacetedRowModel: getFacetedRowModel(), + getFacetedUniqueValues: getFacetedUniqueValues(), + }) + + function handleDragEnd(event: DragEndEvent) { + const { active, over } = event + if (active && over && active.id !== over.id) { + setData((data) => { + const oldIndex = dataIds.indexOf(active.id) + const newIndex = dataIds.indexOf(over.id) + return arrayMove(data, oldIndex, newIndex) + }) + } + } + + return ( +
+
+ + + + Outline + + Past Performance 3 + + + Key Personnel 2 + + Focus Documents + + +
+ + + + + + {table + .getAllColumns() + .filter( + (column) => + typeof column.accessorFn !== "undefined" && + column.getCanHide() + ) + .map((column) => { + return ( + + column.toggleVisibility(!!value) + } + > + {column.id} + + ) + })} + + + +
+
+
+ + + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ) + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + + {table.getRowModel().rows.map((row) => ( + + ))} + + ) : ( + + + No results. + + + )} + +
+
+
+
+ {table.getFilteredSelectedRowModel().rows.length} of{" "} + {table.getFilteredRowModel().rows.length} row(s) selected. +
+
+
+

Rows per page

+ +
+
+ Page {table.getState().pagination.pageIndex + 1} of{" "} + {table.getPageCount()} +
+
+ + + + +
+
+
+
+
+ ) +} + +const chartData = [ + { month: "January", desktop: 186, mobile: 80 }, + { month: "February", desktop: 305, mobile: 200 }, + { month: "March", desktop: 237, mobile: 120 }, + { month: "April", desktop: 73, mobile: 190 }, + { month: "May", desktop: 209, mobile: 130 }, + { month: "June", desktop: 214, mobile: 140 }, +] + +const chartConfig = { + desktop: { + label: "Desktop", + color: "var(--primary)", + }, + mobile: { + label: "Mobile", + color: "var(--primary)", + }, +} satisfies ChartConfig + +function TableCellViewer({ item }: { item: z.infer }) { + const isMobile = useIsMobile() + + return ( + + + + + + + {item.header} + + Showing total visitors for the last 6 months + + +
+ {!isMobile && ( + <> + + + + value.slice(0, 3)} + hide + /> + } + /> + + + + + +
+
+ Trending up by 5.2% this month{" "} + +
+
+ Showing total visitors for the last 6 months. This is just + some random text to test the layout. It spans multiple lines + and should wrap around. +
+
+ + + )} +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+ + +
+
+
+ + + + + + +
+
+ ) +} diff --git a/apps/v4/app/(examples)/dashboard-02/components/nav-clouds.tsx b/apps/v4/app/(examples)/dashboard-02/components/nav-clouds.tsx new file mode 100644 index 0000000000..a361381260 --- /dev/null +++ b/apps/v4/app/(examples)/dashboard-02/components/nav-clouds.tsx @@ -0,0 +1,74 @@ +"use client" + +import { IconChevronRight, type Icon } from "@tabler/icons-react" + +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "@/registry/new-york-v4/ui/collapsible" +import { + SidebarGroup, + SidebarGroupLabel, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + SidebarMenuSub, + SidebarMenuSubButton, + SidebarMenuSubItem, +} from "@/registry/new-york-v4/ui/sidebar" + +export function NavClouds({ + items, +}: { + items: { + title: string + url: string + icon?: Icon + iconClassName?: string + isActive?: boolean + items?: { + title: string + url: string + }[] + }[] +}) { + return ( + + Clouds + + {items.map((item) => ( + + + + + {item.icon && } + {item.title} + + + + + + {item.items?.map((subItem) => ( + + + + {subItem.title} + + + + ))} + + + + + ))} + + + ) +} diff --git a/apps/v4/app/(examples)/dashboard-02/components/nav-documents.tsx b/apps/v4/app/(examples)/dashboard-02/components/nav-documents.tsx new file mode 100644 index 0000000000..4e3b277319 --- /dev/null +++ b/apps/v4/app/(examples)/dashboard-02/components/nav-documents.tsx @@ -0,0 +1,89 @@ +"use client" + +import { + IconDots, + IconFolder, + IconShare3, + IconTrash, + type Icon, +} from "@tabler/icons-react" + +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/registry/new-york-v4/ui/dropdown-menu" +import { + SidebarGroup, + SidebarGroupLabel, + SidebarMenu, + SidebarMenuAction, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from "@/registry/new-york-v4/ui/sidebar" + +export function NavDocuments({ + items, +}: { + items: { + name: string + url: string + icon: Icon + }[] +}) { + const { isMobile } = useSidebar() + + return ( + + Documents + + {items.map((item) => ( + + + + + {item.name} + + + + + + + More + + + + + + Open + + + + Share + + + + + Delete + + + + + ))} + + + + More + + + + + ) +} diff --git a/apps/v4/app/(examples)/dashboard-02/components/nav-main.tsx b/apps/v4/app/(examples)/dashboard-02/components/nav-main.tsx new file mode 100644 index 0000000000..dc2e6243f3 --- /dev/null +++ b/apps/v4/app/(examples)/dashboard-02/components/nav-main.tsx @@ -0,0 +1,56 @@ +"use client" + +import { IconCirclePlusFilled, IconMail, type Icon } from "@tabler/icons-react" + +import { Button } from "@/registry/new-york-v4/ui/button" +import { + SidebarGroup, + SidebarGroupContent, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, +} from "@/registry/new-york-v4/ui/sidebar" + +export function NavMain({ + items, +}: { + items: { + title: string + url: string + icon?: Icon + }[] +}) { + return ( + + + + + + + Quick Create + + + + + + {items.map((item) => ( + + {item.icon && } + {item.title} + + ))} + + + + ) +} diff --git a/apps/v4/app/(examples)/dashboard-02/components/nav-secondary.tsx b/apps/v4/app/(examples)/dashboard-02/components/nav-secondary.tsx new file mode 100644 index 0000000000..3cc90ef83a --- /dev/null +++ b/apps/v4/app/(examples)/dashboard-02/components/nav-secondary.tsx @@ -0,0 +1,71 @@ +"use client" + +import * as React from "react" +import { IconBrightness, type Icon } from "@tabler/icons-react" +import { useTheme } from "next-themes" + +import { + SidebarGroup, + SidebarGroupContent, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, +} from "@/registry/new-york-v4/ui/sidebar" +import { Skeleton } from "@/registry/new-york-v4/ui/skeleton" +import { Switch } from "@/registry/new-york-v4/ui/switch" + +export function NavSecondary({ + items, + ...props +}: { + items: { + title: string + url: string + icon: Icon + }[] +} & React.ComponentPropsWithoutRef) { + const { resolvedTheme, setTheme } = useTheme() + const [mounted, setMounted] = React.useState(false) + + React.useEffect(() => { + setMounted(true) + }, []) + + return ( + + + + {items.map((item) => ( + + + + + {item.title} + + + + ))} + + + + + + + + + ) +} diff --git a/apps/v4/app/(examples)/dashboard-02/components/nav-user.tsx b/apps/v4/app/(examples)/dashboard-02/components/nav-user.tsx new file mode 100644 index 0000000000..adca40fd0c --- /dev/null +++ b/apps/v4/app/(examples)/dashboard-02/components/nav-user.tsx @@ -0,0 +1,110 @@ +"use client" + +import { + IconCreditCard, + IconDotsVertical, + IconLogout, + IconNotification, + IconUserCircle, +} from "@tabler/icons-react" + +import { + Avatar, + AvatarFallback, + AvatarImage, +} from "@/registry/new-york-v4/ui/avatar" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/registry/new-york-v4/ui/dropdown-menu" +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, +} from "@/registry/new-york-v4/ui/sidebar" + +export function NavUser({ + user, +}: { + user: { + name: string + email: string + avatar: string + } +}) { + const { isMobile } = useSidebar() + + return ( + + + + + + + + CN + +
+ {user.name} + + {user.email} + +
+ +
+
+ + +
+ + + CN + +
+ {user.name} + + {user.email} + +
+
+
+ + + + + Account + + + + Billing + + + + Notifications + + + + + + Log out + +
+
+
+
+ ) +} diff --git a/apps/v4/app/(examples)/dashboard-02/data.json b/apps/v4/app/(examples)/dashboard-02/data.json new file mode 100644 index 0000000000..ec0873641b --- /dev/null +++ b/apps/v4/app/(examples)/dashboard-02/data.json @@ -0,0 +1,614 @@ +[ + { + "id": 1, + "header": "Cover page", + "type": "Cover page", + "status": "In Process", + "target": "18", + "limit": "5", + "reviewer": "Eddie Lake" + }, + { + "id": 2, + "header": "Table of contents", + "type": "Table of contents", + "status": "Done", + "target": "29", + "limit": "24", + "reviewer": "Eddie Lake" + }, + { + "id": 3, + "header": "Executive summary", + "type": "Narrative", + "status": "Done", + "target": "10", + "limit": "13", + "reviewer": "Eddie Lake" + }, + { + "id": 4, + "header": "Technical approach", + "type": "Narrative", + "status": "Done", + "target": "27", + "limit": "23", + "reviewer": "Jamik Tashpulatov" + }, + { + "id": 5, + "header": "Design", + "type": "Narrative", + "status": "In Process", + "target": "2", + "limit": "16", + "reviewer": "Jamik Tashpulatov" + }, + { + "id": 6, + "header": "Capabilities", + "type": "Narrative", + "status": "In Process", + "target": "20", + "limit": "8", + "reviewer": "Jamik Tashpulatov" + }, + { + "id": 7, + "header": "Integration with existing systems", + "type": "Narrative", + "status": "In Process", + "target": "19", + "limit": "21", + "reviewer": "Jamik Tashpulatov" + }, + { + "id": 8, + "header": "Innovation and Advantages", + "type": "Narrative", + "status": "Done", + "target": "25", + "limit": "26", + "reviewer": "Assign reviewer" + }, + { + "id": 9, + "header": "Overview of EMR's Innovative Solutions", + "type": "Technical content", + "status": "Done", + "target": "7", + "limit": "23", + "reviewer": "Assign reviewer" + }, + { + "id": 10, + "header": "Advanced Algorithms and Machine Learning", + "type": "Narrative", + "status": "Done", + "target": "30", + "limit": "28", + "reviewer": "Assign reviewer" + }, + { + "id": 11, + "header": "Adaptive Communication Protocols", + "type": "Narrative", + "status": "Done", + "target": "9", + "limit": "31", + "reviewer": "Assign reviewer" + }, + { + "id": 12, + "header": "Advantages Over Current Technologies", + "type": "Narrative", + "status": "Done", + "target": "12", + "limit": "0", + "reviewer": "Assign reviewer" + }, + { + "id": 13, + "header": "Past Performance", + "type": "Narrative", + "status": "Done", + "target": "22", + "limit": "33", + "reviewer": "Assign reviewer" + }, + { + "id": 14, + "header": "Customer Feedback and Satisfaction Levels", + "type": "Narrative", + "status": "Done", + "target": "15", + "limit": "34", + "reviewer": "Assign reviewer" + }, + { + "id": 15, + "header": "Implementation Challenges and Solutions", + "type": "Narrative", + "status": "Done", + "target": "3", + "limit": "35", + "reviewer": "Assign reviewer" + }, + { + "id": 16, + "header": "Security Measures and Data Protection Policies", + "type": "Narrative", + "status": "In Process", + "target": "6", + "limit": "36", + "reviewer": "Assign reviewer" + }, + { + "id": 17, + "header": "Scalability and Future Proofing", + "type": "Narrative", + "status": "Done", + "target": "4", + "limit": "37", + "reviewer": "Assign reviewer" + }, + { + "id": 18, + "header": "Cost-Benefit Analysis", + "type": "Plain language", + "status": "Done", + "target": "14", + "limit": "38", + "reviewer": "Assign reviewer" + }, + { + "id": 19, + "header": "User Training and Onboarding Experience", + "type": "Narrative", + "status": "Done", + "target": "17", + "limit": "39", + "reviewer": "Assign reviewer" + }, + { + "id": 20, + "header": "Future Development Roadmap", + "type": "Narrative", + "status": "Done", + "target": "11", + "limit": "40", + "reviewer": "Assign reviewer" + }, + { + "id": 21, + "header": "System Architecture Overview", + "type": "Technical content", + "status": "In Process", + "target": "24", + "limit": "18", + "reviewer": "Maya Johnson" + }, + { + "id": 22, + "header": "Risk Management Plan", + "type": "Narrative", + "status": "Done", + "target": "15", + "limit": "22", + "reviewer": "Carlos Rodriguez" + }, + { + "id": 23, + "header": "Compliance Documentation", + "type": "Legal", + "status": "In Process", + "target": "31", + "limit": "27", + "reviewer": "Sarah Chen" + }, + { + "id": 24, + "header": "API Documentation", + "type": "Technical content", + "status": "Done", + "target": "8", + "limit": "12", + "reviewer": "Raj Patel" + }, + { + "id": 25, + "header": "User Interface Mockups", + "type": "Visual", + "status": "In Process", + "target": "19", + "limit": "25", + "reviewer": "Leila Ahmadi" + }, + { + "id": 26, + "header": "Database Schema", + "type": "Technical content", + "status": "Done", + "target": "22", + "limit": "20", + "reviewer": "Thomas Wilson" + }, + { + "id": 27, + "header": "Testing Methodology", + "type": "Technical content", + "status": "In Process", + "target": "17", + "limit": "14", + "reviewer": "Assign reviewer" + }, + { + "id": 28, + "header": "Deployment Strategy", + "type": "Narrative", + "status": "Done", + "target": "26", + "limit": "30", + "reviewer": "Eddie Lake" + }, + { + "id": 29, + "header": "Budget Breakdown", + "type": "Financial", + "status": "In Process", + "target": "13", + "limit": "16", + "reviewer": "Jamik Tashpulatov" + }, + { + "id": 30, + "header": "Market Analysis", + "type": "Research", + "status": "Done", + "target": "29", + "limit": "32", + "reviewer": "Sophia Martinez" + }, + { + "id": 31, + "header": "Competitor Comparison", + "type": "Research", + "status": "In Process", + "target": "21", + "limit": "19", + "reviewer": "Assign reviewer" + }, + { + "id": 32, + "header": "Maintenance Plan", + "type": "Technical content", + "status": "Done", + "target": "16", + "limit": "23", + "reviewer": "Alex Thompson" + }, + { + "id": 33, + "header": "User Personas", + "type": "Research", + "status": "In Process", + "target": "27", + "limit": "24", + "reviewer": "Nina Patel" + }, + { + "id": 34, + "header": "Accessibility Compliance", + "type": "Legal", + "status": "Done", + "target": "18", + "limit": "21", + "reviewer": "Assign reviewer" + }, + { + "id": 35, + "header": "Performance Metrics", + "type": "Technical content", + "status": "In Process", + "target": "23", + "limit": "26", + "reviewer": "David Kim" + }, + { + "id": 36, + "header": "Disaster Recovery Plan", + "type": "Technical content", + "status": "Done", + "target": "14", + "limit": "17", + "reviewer": "Jamik Tashpulatov" + }, + { + "id": 37, + "header": "Third-party Integrations", + "type": "Technical content", + "status": "In Process", + "target": "25", + "limit": "28", + "reviewer": "Eddie Lake" + }, + { + "id": 38, + "header": "User Feedback Summary", + "type": "Research", + "status": "Done", + "target": "20", + "limit": "15", + "reviewer": "Assign reviewer" + }, + { + "id": 39, + "header": "Localization Strategy", + "type": "Narrative", + "status": "In Process", + "target": "12", + "limit": "19", + "reviewer": "Maria Garcia" + }, + { + "id": 40, + "header": "Mobile Compatibility", + "type": "Technical content", + "status": "Done", + "target": "28", + "limit": "31", + "reviewer": "James Wilson" + }, + { + "id": 41, + "header": "Data Migration Plan", + "type": "Technical content", + "status": "In Process", + "target": "19", + "limit": "22", + "reviewer": "Assign reviewer" + }, + { + "id": 42, + "header": "Quality Assurance Protocols", + "type": "Technical content", + "status": "Done", + "target": "30", + "limit": "33", + "reviewer": "Priya Singh" + }, + { + "id": 43, + "header": "Stakeholder Analysis", + "type": "Research", + "status": "In Process", + "target": "11", + "limit": "14", + "reviewer": "Eddie Lake" + }, + { + "id": 44, + "header": "Environmental Impact Assessment", + "type": "Research", + "status": "Done", + "target": "24", + "limit": "27", + "reviewer": "Assign reviewer" + }, + { + "id": 45, + "header": "Intellectual Property Rights", + "type": "Legal", + "status": "In Process", + "target": "17", + "limit": "20", + "reviewer": "Sarah Johnson" + }, + { + "id": 46, + "header": "Customer Support Framework", + "type": "Narrative", + "status": "Done", + "target": "22", + "limit": "25", + "reviewer": "Jamik Tashpulatov" + }, + { + "id": 47, + "header": "Version Control Strategy", + "type": "Technical content", + "status": "In Process", + "target": "15", + "limit": "18", + "reviewer": "Assign reviewer" + }, + { + "id": 48, + "header": "Continuous Integration Pipeline", + "type": "Technical content", + "status": "Done", + "target": "26", + "limit": "29", + "reviewer": "Michael Chen" + }, + { + "id": 49, + "header": "Regulatory Compliance", + "type": "Legal", + "status": "In Process", + "target": "13", + "limit": "16", + "reviewer": "Assign reviewer" + }, + { + "id": 50, + "header": "User Authentication System", + "type": "Technical content", + "status": "Done", + "target": "28", + "limit": "31", + "reviewer": "Eddie Lake" + }, + { + "id": 51, + "header": "Data Analytics Framework", + "type": "Technical content", + "status": "In Process", + "target": "21", + "limit": "24", + "reviewer": "Jamik Tashpulatov" + }, + { + "id": 52, + "header": "Cloud Infrastructure", + "type": "Technical content", + "status": "Done", + "target": "16", + "limit": "19", + "reviewer": "Assign reviewer" + }, + { + "id": 53, + "header": "Network Security Measures", + "type": "Technical content", + "status": "In Process", + "target": "29", + "limit": "32", + "reviewer": "Lisa Wong" + }, + { + "id": 54, + "header": "Project Timeline", + "type": "Planning", + "status": "Done", + "target": "14", + "limit": "17", + "reviewer": "Eddie Lake" + }, + { + "id": 55, + "header": "Resource Allocation", + "type": "Planning", + "status": "In Process", + "target": "27", + "limit": "30", + "reviewer": "Assign reviewer" + }, + { + "id": 56, + "header": "Team Structure and Roles", + "type": "Planning", + "status": "Done", + "target": "20", + "limit": "23", + "reviewer": "Jamik Tashpulatov" + }, + { + "id": 57, + "header": "Communication Protocols", + "type": "Planning", + "status": "In Process", + "target": "15", + "limit": "18", + "reviewer": "Assign reviewer" + }, + { + "id": 58, + "header": "Success Metrics", + "type": "Planning", + "status": "Done", + "target": "30", + "limit": "33", + "reviewer": "Eddie Lake" + }, + { + "id": 59, + "header": "Internationalization Support", + "type": "Technical content", + "status": "In Process", + "target": "23", + "limit": "26", + "reviewer": "Jamik Tashpulatov" + }, + { + "id": 60, + "header": "Backup and Recovery Procedures", + "type": "Technical content", + "status": "Done", + "target": "18", + "limit": "21", + "reviewer": "Assign reviewer" + }, + { + "id": 61, + "header": "Monitoring and Alerting System", + "type": "Technical content", + "status": "In Process", + "target": "25", + "limit": "28", + "reviewer": "Daniel Park" + }, + { + "id": 62, + "header": "Code Review Guidelines", + "type": "Technical content", + "status": "Done", + "target": "12", + "limit": "15", + "reviewer": "Eddie Lake" + }, + { + "id": 63, + "header": "Documentation Standards", + "type": "Technical content", + "status": "In Process", + "target": "27", + "limit": "30", + "reviewer": "Jamik Tashpulatov" + }, + { + "id": 64, + "header": "Release Management Process", + "type": "Planning", + "status": "Done", + "target": "22", + "limit": "25", + "reviewer": "Assign reviewer" + }, + { + "id": 65, + "header": "Feature Prioritization Matrix", + "type": "Planning", + "status": "In Process", + "target": "19", + "limit": "22", + "reviewer": "Emma Davis" + }, + { + "id": 66, + "header": "Technical Debt Assessment", + "type": "Technical content", + "status": "Done", + "target": "24", + "limit": "27", + "reviewer": "Eddie Lake" + }, + { + "id": 67, + "header": "Capacity Planning", + "type": "Planning", + "status": "In Process", + "target": "21", + "limit": "24", + "reviewer": "Jamik Tashpulatov" + }, + { + "id": 68, + "header": "Service Level Agreements", + "type": "Legal", + "status": "Done", + "target": "26", + "limit": "29", + "reviewer": "Assign reviewer" + } +] diff --git a/apps/v4/app/(examples)/dashboard-02/layout.tsx b/apps/v4/app/(examples)/dashboard-02/layout.tsx new file mode 100644 index 0000000000..64cf320fa9 --- /dev/null +++ b/apps/v4/app/(examples)/dashboard-02/layout.tsx @@ -0,0 +1,62 @@ +import { cookies } from "next/headers" + +import { Separator } from "@/registry/new-york-v4/ui/separator" +import { + SidebarInset, + SidebarProvider, + SidebarTrigger, +} from "@/registry/new-york-v4/ui/sidebar" +import { AppSidebar } from "@/app/(examples)/dashboard-02/components/app-sidebar" + +import "./theme.css" +import { IconExternalLink } from "@tabler/icons-react" + +import { Button } from "@/registry/new-york-v4/ui/button" + +export default async function DashboardLayout({ + children, +}: { + children: React.ReactNode +}) { + const cookieStore = await cookies() + const defaultOpen = cookieStore.get("sidebar_state")?.value === "true" + + return ( + + + +
+
+ + +

Documents

+ +
+
+
{children}
+
+
+ ) +} diff --git a/apps/v4/app/(examples)/dashboard-02/page.tsx b/apps/v4/app/(examples)/dashboard-02/page.tsx new file mode 100644 index 0000000000..e4c38b2ec2 --- /dev/null +++ b/apps/v4/app/(examples)/dashboard-02/page.tsx @@ -0,0 +1,79 @@ +import { Metadata } from "next" +import { IconTrendingDown, IconTrendingUp } from "@tabler/icons-react" + +import { Badge } from "@/registry/new-york-v4/ui/badge" +import { + Card, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/registry/new-york-v4/ui/card" +import { DataTable } from "@/app/(examples)/dashboard-02/components/data-table" + +import data from "./data.json" + +export const metadata: Metadata = { + title: "Dashboard", + description: "A dashboard with tabs, table and sidebar.", +} + +export default async function Dashboard02() { + return ( +
+
+
+ + + Total Revenue + $1,250.00 in the last 30 days + + + + + +12.5% + + + + + + New Customers + -12 customers from last month + + + + + -20% + + + + + + Active Accounts + +2,345 users from last month + + + + + +12.5% + + + + + + Growth Rate + +12.5% increase per month + + + + + +4.5% + + + +
+ +
+
+ ) +} diff --git a/apps/v4/app/(examples)/dashboard-02/theme.css b/apps/v4/app/(examples)/dashboard-02/theme.css new file mode 100644 index 0000000000..7cb9b2808a --- /dev/null +++ b/apps/v4/app/(examples)/dashboard-02/theme.css @@ -0,0 +1,23 @@ +:root, +.theme-custom { + --font-sans: var(--font-inter); + --header-height: calc(var(--spacing) * 12 + 1px); + --primary: oklch(0.546 0.245 262.881); + --primary-foreground: oklch(0.97 0.014 254.604); + + @media (min-width: 1024px) { + --radius: 0.6rem; + --text-lg: 1.05rem; + --text-base: 0.85rem; + --text-sm: 0.8rem; + --spacing: 0.222222rem; + } + + [data-slot="card"] { + --spacing: 0.16rem; + } +} + +.dark { + --primary: oklch(0.623 0.214 259.815); +} diff --git a/apps/v4/package.json b/apps/v4/package.json index 97f9795869..531ba09b1a 100644 --- a/apps/v4/package.json +++ b/apps/v4/package.json @@ -15,6 +15,10 @@ "registry:build": "tsx --tsconfig ./tsconfig.scripts.json ./scripts/build-registry.mts && prettier --log-level silent --write \"registry/**/*.{ts,tsx,json,mdx}\" --cache" }, "dependencies": { + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/modifiers": "^9.0.0", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", "@hookform/resolvers": "^3.10.0", "@radix-ui/react-accessible-icon": "^1.1.1", "@radix-ui/react-accordion": "^1.2.2", @@ -46,7 +50,9 @@ "@radix-ui/react-toggle": "^1.1.1", "@radix-ui/react-toggle-group": "^1.1.1", "@radix-ui/react-tooltip": "^1.1.7", + "@tabler/icons-react": "^3.31.0", "@tailwindcss/postcss": "^4.0.1", + "@tanstack/react-table": "^8.9.1", "@vercel/analytics": "^1.2.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -74,7 +80,7 @@ "tailwindcss-animate": "^1.0.7", "ts-morph": "^22.0.0", "vaul": "1.1.2", - "zod": "^3.21.4" + "zod": "^3.24.1" }, "devDependencies": { "@eslint/eslintrc": "^3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1ce0c11447..fae2e450c0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -108,6 +108,18 @@ importers: apps/v4: dependencies: + '@dnd-kit/core': + specifier: ^6.3.1 + version: 6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@dnd-kit/modifiers': + specifier: ^9.0.0 + version: 9.0.0(@dnd-kit/core@6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) + '@dnd-kit/sortable': + specifier: ^10.0.0 + version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) + '@dnd-kit/utilities': + specifier: ^3.2.2 + version: 3.2.2(react@19.0.0) '@hookform/resolvers': specifier: ^3.10.0 version: 3.10.0(react-hook-form@7.54.2(react@19.0.0)) @@ -201,9 +213,15 @@ importers: '@radix-ui/react-tooltip': specifier: ^1.1.7 version: 1.1.7(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@tabler/icons-react': + specifier: ^3.31.0 + version: 3.31.0(react@19.0.0) '@tailwindcss/postcss': specifier: ^4.0.1 version: 4.0.2 + '@tanstack/react-table': + specifier: ^8.9.1 + version: 8.20.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@vercel/analytics': specifier: ^1.2.2 version: 1.4.1(next@15.2.0-canary.33(@babel/core@7.26.7)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) @@ -286,7 +304,7 @@ importers: specifier: 1.1.2 version: 1.1.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) zod: - specifier: ^3.21.4 + specifier: ^3.24.1 version: 3.24.1 devDependencies: '@eslint/eslintrc': @@ -1031,6 +1049,34 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} + '@dnd-kit/accessibility@3.1.1': + resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} + peerDependencies: + react: '>=16.8.0' + + '@dnd-kit/core@6.3.1': + resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@dnd-kit/modifiers@9.0.0': + resolution: {integrity: sha512-ybiLc66qRGuZoC20wdSSG6pDXFikui/dCNGthxv4Ndy8ylErY0N3KVxY2bgo7AWwIbxDmXDg3ylAFmnrjcbVvw==} + peerDependencies: + '@dnd-kit/core': ^6.3.0 + react: '>=16.8.0' + + '@dnd-kit/sortable@10.0.0': + resolution: {integrity: sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==} + peerDependencies: + '@dnd-kit/core': ^6.3.0 + react: '>=16.8.0' + + '@dnd-kit/utilities@3.2.2': + resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} + peerDependencies: + react: '>=16.8.0' + '@effect-ts/core@0.60.5': resolution: {integrity: sha512-qi1WrtJA90XLMnj2hnUszW9Sx4dXP03ZJtCc5DiUBIOhF4Vw7plfb65/bdBySPoC9s7zy995TdUX1XBSxUkl5w==} @@ -2923,6 +2969,14 @@ packages: resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==} engines: {node: '>=6'} + '@tabler/icons-react@3.31.0': + resolution: {integrity: sha512-2rrCM5y/VnaVKnORpDdAua9SEGuJKVqPtWxeQ/vUVsgaUx30LDgBZph7/lterXxDY1IKR6NO//HDhWiifXTi3w==} + peerDependencies: + react: '>= 16' + + '@tabler/icons@3.31.0': + resolution: {integrity: sha512-dblAdeKY3+GA1U+Q9eziZ0ooVlZMHsE8dqP0RkwvRtEsAULoKOYaCUOcJ4oW1DjWegdxk++UAt2SlQVnmeHv+g==} + '@tailwindcss/node@4.0.2': resolution: {integrity: sha512-/q5HXvgEc5GaaAhoVj8oeAw1TPRlZtRAnzWz2ChpFdKsEAVoHUAW6EX/tDr3tkUfQ1VVSBpxeGUg0V0gPZSs1A==} @@ -8756,6 +8810,38 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 + '@dnd-kit/accessibility@3.1.1(react@19.0.0)': + dependencies: + react: 19.0.0 + tslib: 2.8.1 + + '@dnd-kit/core@6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@dnd-kit/accessibility': 3.1.1(react@19.0.0) + '@dnd-kit/utilities': 3.2.2(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + tslib: 2.8.1 + + '@dnd-kit/modifiers@9.0.0(@dnd-kit/core@6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)': + dependencies: + '@dnd-kit/core': 6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@dnd-kit/utilities': 3.2.2(react@19.0.0) + react: 19.0.0 + tslib: 2.8.1 + + '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)': + dependencies: + '@dnd-kit/core': 6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@dnd-kit/utilities': 3.2.2(react@19.0.0) + react: 19.0.0 + tslib: 2.8.1 + + '@dnd-kit/utilities@3.2.2(react@19.0.0)': + dependencies: + react: 19.0.0 + tslib: 2.8.1 + '@effect-ts/core@0.60.5': dependencies: '@effect-ts/system': 0.57.5 @@ -11211,6 +11297,13 @@ snapshots: dependencies: defer-to-connect: 1.1.3 + '@tabler/icons-react@3.31.0(react@19.0.0)': + dependencies: + '@tabler/icons': 3.31.0 + react: 19.0.0 + + '@tabler/icons@3.31.0': {} + '@tailwindcss/node@4.0.2': dependencies: enhanced-resolve: 5.18.0 @@ -11279,6 +11372,12 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + '@tanstack/react-table@8.20.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@tanstack/table-core': 8.20.5 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + '@tanstack/table-core@8.20.5': {} '@tootallnate/quickjs-emscripten@0.23.0': {}