From f1dd9c6903d4d9030efe7bd61533db3fa21e68d8 Mon Sep 17 00:00:00 2001 From: shadcn Date: Thu, 13 Mar 2025 13:06:08 +0400 Subject: [PATCH] feat: update dark mode colors (#6903) * feat: update dark colors * feat(v4): update dark mode colors * fix * fix * fix: slate and stone mismatches * feat(v4): update skeleton and switch colors * feat(v4): add dashboard example * fix(v4): update dashboard components * fix: themes * feat: update sonner * feat(v4): update dashboard buttons * fix: test new colors * fix: build commands * feat(v4): more color updates * feat(v4): update theme selector * fix(v4): minor component fixes --- apps/v4/app/(app)/forms/page.tsx | 9 +- apps/v4/app/(app)/layout.tsx | 2 + apps/v4/app/(app)/login/page.tsx | 2 +- .../components/analytics-date-picker.tsx | 61 +++ .../dashboard/components/app-sidebar.tsx | 84 +++ .../dashboard/components/chart-revenue.tsx | 110 ++++ .../dashboard/components/chart-visitors.tsx | 189 +++++++ .../dashboard/components/mode-toggle.tsx | 28 + .../dashboard/components/nav-main.tsx | 91 ++++ .../dashboard/components/nav-secondary.tsx | 40 ++ .../dashboard/components/nav-user.tsx | 90 ++++ .../dashboard/components/products-table.tsx | 217 ++++++++ .../dashboard/components/search-form.tsx | 22 + .../dashboard/components/site-header.tsx | 103 ++++ .../(examples)/dashboard/customers/page.tsx | 8 + apps/v4/app/(examples)/dashboard/layout.tsx | 29 + apps/v4/app/(examples)/dashboard/page.tsx | 206 ++++++++ .../(examples)/dashboard/settings/page.tsx | 500 ++++++++++++++++++ apps/v4/app/globals.css | 102 +--- apps/v4/app/layout.tsx | 33 +- apps/v4/app/themes.css | 442 ++++++++++++++++ apps/v4/components.json | 2 +- apps/v4/components/active-theme.tsx | 62 +++ apps/v4/components/card-demo.tsx | 52 +- apps/v4/components/context-menu-demo.tsx | 2 +- apps/v4/components/drawer-demo.tsx | 2 +- apps/v4/components/forms-demo.tsx | 275 +++++----- apps/v4/components/mode-switcher.tsx | 5 +- apps/v4/components/nav-header.tsx | 2 +- apps/v4/components/sonner-demo.tsx | 138 ++++- apps/v4/components/theme-selector.tsx | 30 ++ apps/v4/lib/fonts.ts | 49 ++ apps/v4/lib/themes.ts | 75 +++ apps/v4/registry.json | 3 + .../blocks/login-03/components/login-form.tsx | 2 +- .../blocks/login-04/components/login-form.tsx | 2 +- .../sidebar-07/components/team-switcher.tsx | 6 +- .../registry/new-york-v4/ui/alert-dialog.tsx | 2 +- apps/v4/registry/new-york-v4/ui/alert.tsx | 4 +- apps/v4/registry/new-york-v4/ui/badge.tsx | 2 +- apps/v4/registry/new-york-v4/ui/button.tsx | 9 +- apps/v4/registry/new-york-v4/ui/card.tsx | 30 +- apps/v4/registry/new-york-v4/ui/checkbox.tsx | 2 +- .../registry/new-york-v4/ui/context-menu.tsx | 2 +- apps/v4/registry/new-york-v4/ui/dialog.tsx | 2 +- apps/v4/registry/new-york-v4/ui/drawer.tsx | 10 +- .../registry/new-york-v4/ui/dropdown-menu.tsx | 2 +- apps/v4/registry/new-york-v4/ui/form.tsx | 4 +- .../v4/registry/new-york-v4/ui/hover-card.tsx | 22 +- apps/v4/registry/new-york-v4/ui/input-otp.tsx | 2 +- apps/v4/registry/new-york-v4/ui/input.tsx | 2 +- apps/v4/registry/new-york-v4/ui/menubar.tsx | 2 +- .../registry/new-york-v4/ui/radio-group.tsx | 2 +- apps/v4/registry/new-york-v4/ui/select.tsx | 8 +- apps/v4/registry/new-york-v4/ui/sheet.tsx | 2 +- apps/v4/registry/new-york-v4/ui/sidebar.tsx | 5 +- apps/v4/registry/new-york-v4/ui/skeleton.tsx | 2 +- apps/v4/registry/new-york-v4/ui/sonner.tsx | 18 +- apps/v4/registry/new-york-v4/ui/switch.tsx | 4 +- apps/v4/registry/new-york-v4/ui/tabs.tsx | 4 +- apps/v4/registry/new-york-v4/ui/textarea.tsx | 2 +- apps/www/package.json | 1 + apps/www/public/r/colors/gray.json | 20 +- apps/www/public/r/colors/neutral.json | 20 +- apps/www/public/r/colors/slate.json | 20 +- apps/www/public/r/colors/stone.json | 16 +- apps/www/public/r/colors/zinc.json | 20 +- apps/www/public/r/index.json | 3 + apps/www/public/r/styles/default/badge.json | 3 + .../public/r/styles/default/sidebar-16.json | 2 +- .../r/styles/new-york-v4/alert-dialog.json | 2 +- .../public/r/styles/new-york-v4/alert.json | 2 +- .../public/r/styles/new-york-v4/badge.json | 5 +- .../public/r/styles/new-york-v4/button.json | 2 +- .../www/public/r/styles/new-york-v4/card.json | 2 +- .../public/r/styles/new-york-v4/checkbox.json | 2 +- .../r/styles/new-york-v4/context-menu.json | 2 +- .../public/r/styles/new-york-v4/dialog.json | 2 +- .../public/r/styles/new-york-v4/drawer.json | 2 +- .../r/styles/new-york-v4/dropdown-menu.json | 2 +- .../www/public/r/styles/new-york-v4/form.json | 2 +- .../r/styles/new-york-v4/hover-card.json | 2 +- .../r/styles/new-york-v4/input-otp.json | 2 +- .../public/r/styles/new-york-v4/input.json | 2 +- .../public/r/styles/new-york-v4/login-03.json | 2 +- .../public/r/styles/new-york-v4/login-04.json | 2 +- .../public/r/styles/new-york-v4/menubar.json | 2 +- .../r/styles/new-york-v4/radio-group.json | 2 +- .../public/r/styles/new-york-v4/select.json | 2 +- .../public/r/styles/new-york-v4/sheet.json | 2 +- .../r/styles/new-york-v4/sidebar-07.json | 2 +- .../public/r/styles/new-york-v4/sidebar.json | 2 +- .../public/r/styles/new-york-v4/skeleton.json | 2 +- .../public/r/styles/new-york-v4/sonner.json | 2 +- .../public/r/styles/new-york-v4/switch.json | 2 +- .../www/public/r/styles/new-york-v4/tabs.json | 2 +- .../public/r/styles/new-york-v4/textarea.json | 2 +- apps/www/public/r/styles/new-york/badge.json | 3 + .../public/r/styles/new-york/sidebar-16.json | 2 +- .../sidebar-16/components/site-header.tsx | 2 +- apps/www/registry/registry-base-colors.ts | 108 ++-- package.json | 5 +- packages/shadcn/src/registry/api.ts | 3 +- turbo.json | 4 + 104 files changed, 3006 insertions(+), 502 deletions(-) create mode 100644 apps/v4/app/(examples)/dashboard/components/analytics-date-picker.tsx create mode 100644 apps/v4/app/(examples)/dashboard/components/app-sidebar.tsx create mode 100644 apps/v4/app/(examples)/dashboard/components/chart-revenue.tsx create mode 100644 apps/v4/app/(examples)/dashboard/components/chart-visitors.tsx create mode 100644 apps/v4/app/(examples)/dashboard/components/mode-toggle.tsx create mode 100644 apps/v4/app/(examples)/dashboard/components/nav-main.tsx create mode 100644 apps/v4/app/(examples)/dashboard/components/nav-secondary.tsx create mode 100644 apps/v4/app/(examples)/dashboard/components/nav-user.tsx create mode 100644 apps/v4/app/(examples)/dashboard/components/products-table.tsx create mode 100644 apps/v4/app/(examples)/dashboard/components/search-form.tsx create mode 100644 apps/v4/app/(examples)/dashboard/components/site-header.tsx create mode 100644 apps/v4/app/(examples)/dashboard/customers/page.tsx create mode 100644 apps/v4/app/(examples)/dashboard/layout.tsx create mode 100644 apps/v4/app/(examples)/dashboard/page.tsx create mode 100644 apps/v4/app/(examples)/dashboard/settings/page.tsx create mode 100644 apps/v4/app/themes.css create mode 100644 apps/v4/components/active-theme.tsx create mode 100644 apps/v4/components/theme-selector.tsx create mode 100644 apps/v4/lib/fonts.ts create mode 100644 apps/v4/lib/themes.ts diff --git a/apps/v4/app/(app)/forms/page.tsx b/apps/v4/app/(app)/forms/page.tsx index 8d5b813236..2696ab80e4 100644 --- a/apps/v4/app/(app)/forms/page.tsx +++ b/apps/v4/app/(app)/forms/page.tsx @@ -2,8 +2,13 @@ import { FormsDemo } from "@/components/forms-demo" export default function FormsPage() { return ( -
- +
+
+ +
+
+ +
) } diff --git a/apps/v4/app/(app)/layout.tsx b/apps/v4/app/(app)/layout.tsx index fb8212dbb1..ce7bf7d600 100644 --- a/apps/v4/app/(app)/layout.tsx +++ b/apps/v4/app/(app)/layout.tsx @@ -3,6 +3,7 @@ import { cookies } from "next/headers" import { AppSidebar } from "@/components/app-sidebar" import { ModeSwitcher } from "@/components/mode-switcher" import { NavHeader } from "@/components/nav-header" +import { ThemeSelector } from "@/components/theme-selector" import { Separator } from "@/registry/new-york-v4/ui/separator" import { SidebarInset, @@ -31,6 +32,7 @@ export default async function AppLayout({ />
+
diff --git a/apps/v4/app/(app)/login/page.tsx b/apps/v4/app/(app)/login/page.tsx index cadf08d1ce..9331b1a76b 100644 --- a/apps/v4/app/(app)/login/page.tsx +++ b/apps/v4/app/(app)/login/page.tsx @@ -17,7 +17,7 @@ export default function LoginPage() { return (
({ + from: new Date(new Date().getFullYear(), 0, 20), + to: addDays(new Date(new Date().getFullYear(), 0, 20), 20), + }) + + return ( + + + + + + + + + ) +} diff --git a/apps/v4/app/(examples)/dashboard/components/app-sidebar.tsx b/apps/v4/app/(examples)/dashboard/components/app-sidebar.tsx new file mode 100644 index 0000000000..e05981f030 --- /dev/null +++ b/apps/v4/app/(examples)/dashboard/components/app-sidebar.tsx @@ -0,0 +1,84 @@ +"use client" + +import * as React from "react" +import { + ChartLineIcon, + FileIcon, + HomeIcon, + LifeBuoy, + Send, + Settings2Icon, + ShoppingBagIcon, + ShoppingCartIcon, + UserIcon, +} from "lucide-react" + +import { Sidebar, SidebarContent } from "@/registry/new-york-v4/ui/sidebar" +import { NavMain } from "@/app/(examples)/dashboard/components/nav-main" +import { NavSecondary } from "@/app/(examples)/dashboard/components/nav-secondary" + +const data = { + navMain: [ + { + title: "Dashboard", + url: "/dashboard", + icon: HomeIcon, + }, + { + title: "Analytics", + url: "/dashboard/analytics", + icon: ChartLineIcon, + }, + { + title: "Orders", + url: "/dashboard/orders", + icon: ShoppingBagIcon, + }, + { + title: "Products", + url: "/dashboard/products", + icon: ShoppingCartIcon, + }, + { + title: "Invoices", + url: "/dashboard/invoices", + icon: FileIcon, + }, + { + title: "Customers", + url: "/dashboard/customers", + icon: UserIcon, + }, + { + title: "Settings", + url: "/dashboard/settings", + icon: Settings2Icon, + }, + ], + navSecondary: [ + { + title: "Support", + url: "#", + icon: LifeBuoy, + }, + { + title: "Feedback", + url: "#", + icon: Send, + }, + ], +} + +export function AppSidebar({ ...props }: React.ComponentProps) { + return ( + + + + + + + ) +} diff --git a/apps/v4/app/(examples)/dashboard/components/chart-revenue.tsx b/apps/v4/app/(examples)/dashboard/components/chart-revenue.tsx new file mode 100644 index 0000000000..a1dce3cbed --- /dev/null +++ b/apps/v4/app/(examples)/dashboard/components/chart-revenue.tsx @@ -0,0 +1,110 @@ +"use client" + +import { TrendingUp } from "lucide-react" +import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from "recharts" + +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/registry/new-york-v4/ui/card" +import { + ChartConfig, + ChartContainer, + ChartTooltip, + ChartTooltipContent, +} from "@/registry/new-york-v4/ui/chart" + +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: 346, mobile: 140 }, + { month: "July", desktop: 321, mobile: 275 }, + { month: "August", desktop: 132, mobile: 95 }, + { month: "September", desktop: 189, mobile: 225 }, + { month: "October", desktop: 302, mobile: 248 }, + { month: "November", desktop: 342, mobile: 285 }, + { month: "December", desktop: 328, mobile: 290 }, +] + +const chartConfig = { + desktop: { + label: "Desktop", + color: "var(--chart-1)", + }, + mobile: { + label: "Mobile", + color: "var(--chart-2)", + }, +} satisfies ChartConfig + +export function ChartRevenue() { + return ( + + + January - June 2024 + + $45,231.89 + + + + + + + value.slice(0, 3)} + /> + value.toLocaleString()} + domain={[0, "dataMax"]} + /> + } + /> + + + + + + +
+ Trending up by 5.2% this month +
+
+ Showing total visitors for the last 6 months +
+
+
+ ) +} diff --git a/apps/v4/app/(examples)/dashboard/components/chart-visitors.tsx b/apps/v4/app/(examples)/dashboard/components/chart-visitors.tsx new file mode 100644 index 0000000000..2ae91cfee9 --- /dev/null +++ b/apps/v4/app/(examples)/dashboard/components/chart-visitors.tsx @@ -0,0 +1,189 @@ +"use client" + +import * as React from "react" +import { Label, Pie, PieChart, Sector } from "recharts" +import { PieSectorDataItem } from "recharts/types/polar/Pie" + +import { + Card, + CardAction, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/registry/new-york-v4/ui/card" +import { + ChartConfig, + ChartContainer, + ChartStyle, + ChartTooltip, + ChartTooltipContent, +} from "@/registry/new-york-v4/ui/chart" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/registry/new-york-v4/ui/select" + +const desktopData = [ + { month: "january", desktop: 186, fill: "var(--color-january)" }, + { month: "february", desktop: 305, fill: "var(--color-february)" }, + { month: "march", desktop: 237, fill: "var(--color-march)" }, + { month: "april", desktop: 173, fill: "var(--color-april)" }, + { month: "may", desktop: 209, fill: "var(--color-may)" }, +] + +const chartConfig = { + visitors: { + label: "Visitors", + }, + desktop: { + label: "Desktop", + }, + mobile: { + label: "Mobile", + }, + january: { + label: "January", + color: "var(--chart-1)", + }, + february: { + label: "February", + color: "var(--chart-2)", + }, + march: { + label: "March", + color: "var(--chart-3)", + }, + april: { + label: "April", + color: "var(--chart-4)", + }, + may: { + label: "May", + color: "var(--chart-5)", + }, +} satisfies ChartConfig + +export function ChartVisitors() { + const id = "pie-interactive" + const [activeMonth, setActiveMonth] = React.useState(desktopData[0].month) + + const activeIndex = React.useMemo( + () => desktopData.findIndex((item) => item.month === activeMonth), + [activeMonth] + ) + const months = React.useMemo(() => desktopData.map((item) => item.month), []) + + return ( + + + + January - June 2024 + 1,234 visitors + + + + + + + + } + /> + ( + + + + + )} + > + + + + + + ) +} diff --git a/apps/v4/app/(examples)/dashboard/components/mode-toggle.tsx b/apps/v4/app/(examples)/dashboard/components/mode-toggle.tsx new file mode 100644 index 0000000000..ca63bb877b --- /dev/null +++ b/apps/v4/app/(examples)/dashboard/components/mode-toggle.tsx @@ -0,0 +1,28 @@ +"use client" + +import * as React from "react" +import { MoonIcon, SunIcon } from "lucide-react" +import { useTheme } from "next-themes" + +import { Button } from "@/registry/new-york-v4/ui/button" + +export function ModeToggle() { + const { setTheme, resolvedTheme } = useTheme() + + const toggleTheme = React.useCallback(() => { + setTheme(resolvedTheme === "dark" ? "light" : "dark") + }, [resolvedTheme, setTheme]) + + return ( + + ) +} diff --git a/apps/v4/app/(examples)/dashboard/components/nav-main.tsx b/apps/v4/app/(examples)/dashboard/components/nav-main.tsx new file mode 100644 index 0000000000..e445bb29fe --- /dev/null +++ b/apps/v4/app/(examples)/dashboard/components/nav-main.tsx @@ -0,0 +1,91 @@ +"use client" + +import { usePathname } from "next/navigation" +import { ChevronRight, type LucideIcon } from "lucide-react" + +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "@/registry/new-york-v4/ui/collapsible" +import { + SidebarGroup, + SidebarGroupLabel, + SidebarMenu, + SidebarMenuAction, + SidebarMenuButton, + SidebarMenuItem, + SidebarMenuSub, + SidebarMenuSubButton, + SidebarMenuSubItem, +} from "@/registry/new-york-v4/ui/sidebar" + +export function NavMain({ + items, +}: { + items: { + title: string + url: string + icon: LucideIcon + isActive?: boolean + items?: { + title: string + url: string + }[] + disabled?: boolean + }[] +}) { + const pathname = usePathname() + + return ( + + Dashboard + + {items.map((item) => ( + + + + + + {item.title} + + + {item.items?.length ? ( + <> + + + + Toggle + + + + + {item.items?.map((subItem) => ( + + + + {subItem.title} + + + + ))} + + + + ) : null} + + + ))} + + + ) +} diff --git a/apps/v4/app/(examples)/dashboard/components/nav-secondary.tsx b/apps/v4/app/(examples)/dashboard/components/nav-secondary.tsx new file mode 100644 index 0000000000..66924a12dc --- /dev/null +++ b/apps/v4/app/(examples)/dashboard/components/nav-secondary.tsx @@ -0,0 +1,40 @@ +import * as React from "react" +import { type LucideIcon } from "lucide-react" + +import { + SidebarGroup, + SidebarGroupContent, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, +} from "@/registry/new-york-v4/ui/sidebar" + +export function NavSecondary({ + items, + ...props +}: { + items: { + title: string + url: string + icon: LucideIcon + }[] +} & React.ComponentPropsWithoutRef) { + return ( + + + + {items.map((item) => ( + + + + + {item.title} + + + + ))} + + + + ) +} diff --git a/apps/v4/app/(examples)/dashboard/components/nav-user.tsx b/apps/v4/app/(examples)/dashboard/components/nav-user.tsx new file mode 100644 index 0000000000..e3004c5948 --- /dev/null +++ b/apps/v4/app/(examples)/dashboard/components/nav-user.tsx @@ -0,0 +1,90 @@ +"use client" + +import { BadgeCheck, Bell, CreditCard, LogOut, Sparkles } from "lucide-react" + +import { + Avatar, + AvatarFallback, + AvatarImage, +} from "@/registry/new-york-v4/ui/avatar" +import { Button } from "@/registry/new-york-v4/ui/button" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/registry/new-york-v4/ui/dropdown-menu" + +export function NavUser({ + user, +}: { + user: { + name: string + email: string + avatar: string + } +}) { + return ( + + + + + + +
+ + + CN + +
+ {user.name} + + {user.email} + +
+
+
+ + + + + Upgrade to Pro + + + + + + + Account + + + + Billing + + + + Notifications + + + + + + Log out + +
+
+ ) +} diff --git a/apps/v4/app/(examples)/dashboard/components/products-table.tsx b/apps/v4/app/(examples)/dashboard/components/products-table.tsx new file mode 100644 index 0000000000..de20722e4d --- /dev/null +++ b/apps/v4/app/(examples)/dashboard/components/products-table.tsx @@ -0,0 +1,217 @@ +import { + ArrowUpDownIcon, + EllipsisVerticalIcon, + ListFilterIcon, + PlusIcon, +} from "lucide-react" + +import { Badge } from "@/registry/new-york-v4/ui/badge" +import { Button } from "@/registry/new-york-v4/ui/button" +import { + Card, + CardContent, + CardFooter, + CardHeader, +} from "@/registry/new-york-v4/ui/card" +import { Checkbox } from "@/registry/new-york-v4/ui/checkbox" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/registry/new-york-v4/ui/dropdown-menu" +import { + Pagination, + PaginationContent, + PaginationEllipsis, + PaginationItem, + PaginationLink, + PaginationNext, + PaginationPrevious, +} from "@/registry/new-york-v4/ui/pagination" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/registry/new-york-v4/ui/select" +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 function ProductsTable({ + products, +}: { + products: { + id: string + name: string + price: number + stock: number + dateAdded: string + status: string + }[] +}) { + return ( + + + + + All Products + In Stock + Low Stock + + + + + +
+ + + + + +
+
+ + + + + + + + Product + Price + Stock + Status + Date Added + + + + + {products.map((product) => ( + + + + + {product.name} + + ${product.price.toFixed(2)} + + {product.stock} + + + {product.status} + + + + {new Date(product.dateAdded).toLocaleDateString("en-US", { + month: "long", + day: "numeric", + year: "numeric", + })} + + + + + + + + Edit + + Delete + + + + + + ))} + +
+
+ +
+ Showing 1-10 of 100 products +
+ + + + + + + 1 + + + + 2 + + + + 3 + + + + + + + + + +
+
+ ) +} diff --git a/apps/v4/app/(examples)/dashboard/components/search-form.tsx b/apps/v4/app/(examples)/dashboard/components/search-form.tsx new file mode 100644 index 0000000000..0491880e4d --- /dev/null +++ b/apps/v4/app/(examples)/dashboard/components/search-form.tsx @@ -0,0 +1,22 @@ +import { Search } from "lucide-react" + +import { Label } from "@/registry/new-york-v4/ui/label" +import { SidebarInput } from "@/registry/new-york-v4/ui/sidebar" + +export function SearchForm({ ...props }: React.ComponentProps<"form">) { + return ( +
+
+ + + +
+
+ ) +} diff --git a/apps/v4/app/(examples)/dashboard/components/site-header.tsx b/apps/v4/app/(examples)/dashboard/components/site-header.tsx new file mode 100644 index 0000000000..18bde1be28 --- /dev/null +++ b/apps/v4/app/(examples)/dashboard/components/site-header.tsx @@ -0,0 +1,103 @@ +"use client" + +import { Fragment, useMemo } from "react" +import { usePathname } from "next/navigation" +import { SidebarIcon } from "lucide-react" + +import { ThemeSelector } from "@/components/theme-selector" +import { SearchForm } from "@/registry/new-york-v4/blocks/sidebar-16/components/search-form" +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from "@/registry/new-york-v4/ui/breadcrumb" +import { Button } from "@/registry/new-york-v4/ui/button" +import { Separator } from "@/registry/new-york-v4/ui/separator" +import { useSidebar } from "@/registry/new-york-v4/ui/sidebar" +import { ModeToggle } from "@/app/(examples)/dashboard/components/mode-toggle" +import { NavUser } from "@/app/(examples)/dashboard/components/nav-user" + +export function SiteHeader() { + const { toggleSidebar } = useSidebar() + const pathname = usePathname() + + // Faux breadcrumbs for demo. + const breadcrumbs = useMemo(() => { + return pathname + .split("/") + .filter((path) => path !== "") + .map((path, index, array) => ({ + label: path, + href: `/${array.slice(0, index + 1).join("/")}`, + })) + }, [pathname]) + + return ( +
+
+ + + + + + + Home + + + + {breadcrumbs.map((breadcrumb, index) => + index === breadcrumbs.length - 1 ? ( + + + {breadcrumb.label} + + + ) : ( + + + + {breadcrumb.label} + + + + + ) + )} + + +
+ + + + +
+
+
+ ) +} diff --git a/apps/v4/app/(examples)/dashboard/customers/page.tsx b/apps/v4/app/(examples)/dashboard/customers/page.tsx new file mode 100644 index 0000000000..512a007ea2 --- /dev/null +++ b/apps/v4/app/(examples)/dashboard/customers/page.tsx @@ -0,0 +1,8 @@ +export default function CustomersPage() { + return ( +
+
Input
+
Input 50
+
+ ) +} diff --git a/apps/v4/app/(examples)/dashboard/layout.tsx b/apps/v4/app/(examples)/dashboard/layout.tsx new file mode 100644 index 0000000000..6cc4a33160 --- /dev/null +++ b/apps/v4/app/(examples)/dashboard/layout.tsx @@ -0,0 +1,29 @@ +import { cookies } from "next/headers" + +import { + SidebarInset, + SidebarProvider, +} from "@/registry/new-york-v4/ui/sidebar" +import { AppSidebar } from "@/app/(examples)/dashboard/components/app-sidebar" +import { SiteHeader } from "@/app/(examples)/dashboard/components/site-header" + +export default async function DashboardLayout({ + children, +}: { + children: React.ReactNode +}) { + const cookieStore = await cookies() + const defaultOpen = cookieStore.get("sidebar_state")?.value === "true" + + return ( +
+ + +
+ + {children} +
+
+
+ ) +} diff --git a/apps/v4/app/(examples)/dashboard/page.tsx b/apps/v4/app/(examples)/dashboard/page.tsx new file mode 100644 index 0000000000..be505093f5 --- /dev/null +++ b/apps/v4/app/(examples)/dashboard/page.tsx @@ -0,0 +1,206 @@ +import { Metadata } from "next" +import { + DownloadIcon, + FilterIcon, + TrendingDownIcon, + TrendingUpIcon, +} from "lucide-react" + +import { Badge } from "@/registry/new-york-v4/ui/badge" +import { Button } from "@/registry/new-york-v4/ui/button" +import { + Card, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/registry/new-york-v4/ui/card" +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/registry/new-york-v4/ui/tabs" +import { AnalyticsDatePicker } from "@/app/(examples)/dashboard/components/analytics-date-picker" +import { ChartRevenue } from "@/app/(examples)/dashboard/components/chart-revenue" +import { ChartVisitors } from "@/app/(examples)/dashboard/components/chart-visitors" +import { ProductsTable } from "@/app/(examples)/dashboard/components/products-table" + +export const metadata: Metadata = { + title: "Dashboard", + description: "An example dashboard to test the new components.", +} + +// Load from database. +const products = [ + { + id: "1", + name: "BJÖRKSNÄS Dining Table", + price: 599.99, + stock: 12, + dateAdded: "2023-06-15", + status: "In Stock", + }, + { + id: "2", + name: "POÄNG Armchair", + price: 249.99, + stock: 28, + dateAdded: "2023-07-22", + status: "In Stock", + }, + { + id: "3", + name: "MALM Bed Frame", + price: 399.99, + stock: 15, + dateAdded: "2023-08-05", + status: "In Stock", + }, + { + id: "4", + name: "KALLAX Shelf Unit", + price: 179.99, + stock: 32, + dateAdded: "2023-09-12", + status: "In Stock", + }, + { + id: "5", + name: "STOCKHOLM Rug", + price: 299.99, + stock: 8, + dateAdded: "2023-10-18", + status: "Low Stock", + }, + { + id: "6", + name: "KIVIK Sofa", + price: 899.99, + stock: 6, + dateAdded: "2023-11-02", + status: "Low Stock", + }, + { + id: "7", + name: "LISABO Coffee Table", + price: 149.99, + stock: 22, + dateAdded: "2023-11-29", + status: "In Stock", + }, + { + id: "8", + name: "HEMNES Bookcase", + price: 249.99, + stock: 17, + dateAdded: "2023-12-10", + status: "In Stock", + }, + { + id: "9", + name: "EKEDALEN Dining Chairs (Set of 2)", + price: 199.99, + stock: 14, + dateAdded: "2024-01-05", + status: "In Stock", + }, + { + id: "10", + name: "FRIHETEN Sleeper Sofa", + price: 799.99, + stock: 9, + dateAdded: "2024-01-18", + status: "Low Stock", + }, +] + +export default function DashboardPage() { + return ( +
+ +
+ + Overview + Analytics + Reports + + Exports + + +
+ + + +
+
+ +
+ + + 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/settings/page.tsx b/apps/v4/app/(examples)/dashboard/settings/page.tsx new file mode 100644 index 0000000000..d679a7cca8 --- /dev/null +++ b/apps/v4/app/(examples)/dashboard/settings/page.tsx @@ -0,0 +1,500 @@ +import { Metadata } from "next" + +import { cn } from "@/lib/utils" +import { Button } from "@/registry/new-york-v4/ui/button" +import { + Card, + CardAction, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/registry/new-york-v4/ui/card" +import { Checkbox } from "@/registry/new-york-v4/ui/checkbox" +import { Input } from "@/registry/new-york-v4/ui/input" +import { Label } from "@/registry/new-york-v4/ui/label" +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectTrigger, + SelectValue, +} from "@/registry/new-york-v4/ui/select" +import { Switch } from "@/registry/new-york-v4/ui/switch" +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/registry/new-york-v4/ui/table" +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/registry/new-york-v4/ui/tabs" + +export const metadata: Metadata = { + title: "Settings", + description: "Manage your account settings", +} + +const timezones = [ + { + label: "Americas", + timezones: [ + { value: "America/New_York", label: "(GMT-5) New York" }, + { value: "America/Los_Angeles", label: "(GMT-8) Los Angeles" }, + { value: "America/Chicago", label: "(GMT-6) Chicago" }, + { value: "America/Toronto", label: "(GMT-5) Toronto" }, + { value: "America/Vancouver", label: "(GMT-8) Vancouver" }, + { value: "America/Sao_Paulo", label: "(GMT-3) São Paulo" }, + ], + }, + { + label: "Europe", + timezones: [ + { value: "Europe/London", label: "(GMT+0) London" }, + { value: "Europe/Paris", label: "(GMT+1) Paris" }, + { value: "Europe/Berlin", label: "(GMT+1) Berlin" }, + { value: "Europe/Rome", label: "(GMT+1) Rome" }, + { value: "Europe/Madrid", label: "(GMT+1) Madrid" }, + { value: "Europe/Amsterdam", label: "(GMT+1) Amsterdam" }, + ], + }, + { + label: "Asia/Pacific", + timezones: [ + { value: "Asia/Tokyo", label: "(GMT+9) Tokyo" }, + { value: "Asia/Shanghai", label: "(GMT+8) Shanghai" }, + { value: "Asia/Singapore", label: "(GMT+8) Singapore" }, + { value: "Asia/Dubai", label: "(GMT+4) Dubai" }, + { value: "Australia/Sydney", label: "(GMT+11) Sydney" }, + { value: "Asia/Seoul", label: "(GMT+9) Seoul" }, + ], + }, +] as const + +const loginHistory = [ + { + date: "2024-01-01", + ip: "192.168.1.1", + location: "New York, USA", + }, + { + date: "2023-12-29", + ip: "172.16.0.100", + location: "London, UK", + }, + { + date: "2023-12-28", + ip: "10.0.0.50", + location: "Toronto, Canada", + }, + { + date: "2023-12-25", + ip: "192.168.2.15", + location: "Sydney, Australia", + }, +] as const + +const activeSessions = [ + { + device: "MacBook Pro", + browser: "Chrome", + os: "macOS", + }, + { + device: "iPhone", + browser: "Safari", + os: "iOS", + }, + { + device: "iPad", + browser: "Safari", + os: "iOS", + }, + { + device: "Android Phone", + browser: "Chrome", + os: "Android", + }, +] as const + +export default function SettingsPage() { + return ( +
+ +
+ + Account + Security + Notifications + Privacy + +
+ + + + Account Settings + + Make changes to your account here. + + + +
+ + + + + + + + This is your public display name. + + + + + + + + + + + + + + + +
+
+ + + +
+ + + Notifications + + Manage how you receive notifications. + + + +
+ + + + +
+ + +
+
+ + +
+
+ + +
+
+ + Choose how you want to receive notifications. + +
+ + + +
+ + +
+
+ + +
+
+ + +
+
+ + Choose how you want to receive notifications. + +
+
+
+
+ + + +
+
+ + + + Security Settings + + Make changes to your security settings here. + + + +
+ + + + + + + + This is your current password. + + + + + + + + + + + + + + + + + + + + + This will add an extra layer of security to your account. + Make this an extra long description to test the layout. + + + +
+
+ + + +
+ + + Login History + + Recent login activities on your account. + + + + + + + Date + + IP + + Location + + + + {loginHistory.map((login) => ( + + +
+ {new Date(login.date).toLocaleDateString("en-US", { + year: "numeric", + month: "long", + day: "numeric", + })} + + {login.ip} + +
+
+ + {login.ip} + + {login.location} +
+ ))} +
+
+
+
+ + + Active Sessions + + Current active sessions on your account. + + + + + + + + + + Device + Browser + OS + + + + {activeSessions.map((session) => ( + + {session.device} + {session.browser} + {session.os} + + ))} + +
+
+
+
+
+
+ ) +} + +function FieldGroup({ children }: React.ComponentProps<"div">) { + return ( +
+ {children} +
+ ) +} + +function Field({ children, className, ...props }: React.ComponentProps<"div">) { + return ( +
+ {children} +
+ ) +} + +function FieldControl({ + children, + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ {children} +
+ ) +} + +function FieldDescription({ + children, + className, + ...props +}: React.ComponentProps<"p">) { + return ( +

+ {children} +

+ ) +} diff --git a/apps/v4/app/globals.css b/apps/v4/app/globals.css index 238c4b6ae4..e7f6248ae5 100644 --- a/apps/v4/app/globals.css +++ b/apps/v4/app/globals.css @@ -4,7 +4,10 @@ @custom-variant dark (&:is(.dark *)); +@import "./themes.css"; + :root { + --radius: 0.625rem; --background: oklch(1 0 0); --foreground: oklch(0.145 0 0); --card: oklch(1 0 0); @@ -20,7 +23,6 @@ --accent: oklch(0.97 0 0); --accent-foreground: oklch(0.205 0 0); --destructive: oklch(0.577 0.245 27.325); - --destructive-foreground: 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); @@ -29,7 +31,6 @@ --chart-3: oklch(0.398 0.07 227.392); --chart-4: oklch(0.828 0.189 84.429); --chart-5: oklch(0.769 0.188 70.08); - --radius: 0.625rem; --sidebar: oklch(0.985 0 0); --sidebar-foreground: oklch(0.145 0 0); --sidebar-primary: oklch(0.205 0 0); @@ -43,22 +44,21 @@ .dark { --background: oklch(0.145 0 0); --foreground: oklch(0.985 0 0); - --card: oklch(0.145 0 0); + --card: oklch(0.205 0 0); --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.145 0 0); + --popover: oklch(0.269 0 0); --popover-foreground: oklch(0.985 0 0); - --primary: 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: oklch(0.371 0 0); --accent-foreground: oklch(0.985 0 0); - --destructive: oklch(0.396 0.141 25.723); - --destructive-foreground: oklch(0.637 0.237 25.331); - --border: oklch(0.269 0 0); - --input: oklch(0.269 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); --ring: oklch(0.556 0 0); --chart-1: oklch(0.488 0.243 264.376); --chart-2: oklch(0.696 0.17 162.48); @@ -71,66 +71,15 @@ --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(0.269 0 0); + --sidebar-border: oklch(1 0 0 / 10%); --sidebar-ring: oklch(0.439 0 0); } -.theme-login-one { - --primary: #ce2a2d; - --primary-foreground: #fff; - --ring: #ce2a2d9c; - --radius: 0rem; +@theme inline { --radius-sm: calc(var(--radius) - 4px); --radius-md: calc(var(--radius) - 2px); --radius-lg: var(--radius); - - font-family: var(--font-sans); - - a { - color: var(--primary); - } - - [data-slot="card"] { - border-radius: 0rem; - box-shadow: none; - } -} - -.theme-login-two { - --primary: #035fa8; - --primary-foreground: #fff; - --ring: #035fa89c; - font-family: var(--font-serif); - - a { - color: var(--primary); - } -} - -.theme-login-three { - --primary: #22c55e; - --primary-foreground: #000; - --ring: #22c55e; - --radius: 1.5rem; - - font-family: var(--font-manrope); - - a { - color: var(--primary); - } - - [data-slot="card"] { - @apply shadow-xl; - } - - [data-slot="input"] { - @apply dark:bg-input; - } -} - -@theme inline { - --font-sans: var(--font-sans); - --font-mono: var(--font-mono); + --radius-xl: calc(var(--radius) + 4px); --color-background: var(--background); --color-foreground: var(--foreground); --color-card: var(--card); @@ -146,7 +95,6 @@ --color-accent: var(--accent); --color-accent-foreground: var(--accent-foreground); --color-destructive: var(--destructive); - --color-destructive-foreground: var(--destructive-foreground); --color-border: var(--border); --color-input: var(--input); --color-ring: var(--ring); @@ -155,10 +103,6 @@ --color-chart-3: var(--chart-3); --color-chart-4: var(--chart-4); --color-chart-5: var(--chart-5); - --radius-sm: calc(var(--radius) - 4px); - --radius-md: calc(var(--radius) - 2px); - --radius-lg: var(--radius); - --radius-xl: calc(var(--radius) + 4px); --color-sidebar: var(--sidebar); --color-sidebar-foreground: var(--sidebar-foreground); --color-sidebar-primary: var(--sidebar-primary); @@ -167,26 +111,6 @@ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-border: var(--sidebar-border); --color-sidebar-ring: var(--sidebar-ring); - --animate-accordion-down: accordion-down 0.2s ease-out; - --animate-accordion-up: accordion-up 0.2s ease-out; - - @keyframes accordion-down { - from { - height: 0; - } - to { - height: var(--radix-accordion-content-height); - } - } - - @keyframes accordion-up { - from { - height: var(--radix-accordion-content-height); - } - to { - height: 0; - } - } } @layer base { diff --git a/apps/v4/app/layout.tsx b/apps/v4/app/layout.tsx index 930c72e6e8..f58cadf1b5 100644 --- a/apps/v4/app/layout.tsx +++ b/apps/v4/app/layout.tsx @@ -1,23 +1,15 @@ import type { Metadata, Viewport } from "next" -import { Geist_Mono as FontMono, Inter as FontSans } from "next/font/google" +import { cookies } from "next/headers" -import { cn } from "@/lib/utils" +import { fontVariables } from "@/lib/fonts" import { Analytics } from "@/components/analytics" import { ThemeProvider } from "@/components/theme-provider" import { Toaster } from "@/registry/new-york-v4/ui/sonner" import { siteConfig } from "@/www/config/site" import "./globals.css" - -const fontSans = FontSans({ - subsets: ["latin"], - variable: "--font-sans", -}) - -const fontMono = FontMono({ - subsets: ["latin"], - variable: "--font-mono", -}) +import { cn } from "@/lib/utils" +import { ActiveThemeProvider } from "@/components/active-theme" const META_THEME_COLORS = { light: "#ffffff", @@ -80,11 +72,14 @@ export const viewport: Viewport = { themeColor: META_THEME_COLORS.light, } -export default function RootLayout({ +export default async function RootLayout({ children, }: Readonly<{ children: React.ReactNode }>) { + const cookieStore = await cookies() + const activeThemeValue = cookieStore.get("active_theme")?.value + return ( @@ -103,8 +98,8 @@ export default function RootLayout({ - {children} - - + + {children} + + + diff --git a/apps/v4/app/themes.css b/apps/v4/app/themes.css new file mode 100644 index 0000000000..92c5b5ac08 --- /dev/null +++ b/apps/v4/app/themes.css @@ -0,0 +1,442 @@ +.theme-stone { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.147 0.004 49.25); + --card: oklch(1 0 0); + --card-foreground: oklch(0.147 0.004 49.25); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.147 0.004 49.25); + --primary: oklch(0.216 0.006 56.043); + --primary-foreground: oklch(0.985 0.001 106.423); + --secondary: oklch(0.97 0.001 106.424); + --secondary-foreground: oklch(0.216 0.006 56.043); + --muted: oklch(0.97 0.001 106.424); + --muted-foreground: oklch(0.553 0.013 58.071); + --accent: oklch(0.97 0.001 106.424); + --accent-foreground: oklch(0.216 0.006 56.043); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.923 0.003 48.717); + --input: oklch(0.923 0.003 48.717); + --ring: oklch(0.709 0.01 56.259); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0.001 106.423); + --sidebar-foreground: oklch(0.147 0.004 49.25); + --sidebar-primary: oklch(0.216 0.006 56.043); + --sidebar-primary-foreground: oklch(0.985 0.001 106.423); + --sidebar-accent: oklch(0.97 0.001 106.424); + --sidebar-accent-foreground: oklch(0.216 0.006 56.043); + --sidebar-border: oklch(0.923 0.003 48.717); + --sidebar-ring: oklch(0.709 0.01 56.259); + + @variant dark { + --background: oklch(0.147 0.004 49.25); + --foreground: oklch(0.985 0.001 106.423); + --card: oklch(0.216 0.006 56.043); + --card-foreground: oklch(0.985 0.001 106.423); + --popover: oklch(0.216 0.006 56.043); + --popover-foreground: oklch(0.985 0.001 106.423); + --primary: oklch(0.923 0.003 48.717); + --primary-foreground: oklch(0.216 0.006 56.043); + --secondary: oklch(0.268 0.007 34.298); + --secondary-foreground: oklch(0.985 0.001 106.423); + --muted: oklch(0.268 0.007 34.298); + --muted-foreground: oklch(0.709 0.01 56.259); + --accent: oklch(0.268 0.007 34.298); + --accent-foreground: oklch(0.985 0.001 106.423); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.553 0.013 58.071); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.216 0.006 56.043); + --sidebar-foreground: oklch(0.985 0.001 106.423); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0.001 106.423); + --sidebar-accent: oklch(0.268 0.007 34.298); + --sidebar-accent-foreground: oklch(0.985 0.001 106.423); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.553 0.013 58.071); + } +} + +.theme-zinc { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.141 0.005 285.823); + --card: oklch(1 0 0); + --card-foreground: oklch(0.141 0.005 285.823); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.141 0.005 285.823); + --primary: oklch(0.21 0.006 285.885); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.967 0.001 286.375); + --secondary-foreground: oklch(0.21 0.006 285.885); + --muted: oklch(0.967 0.001 286.375); + --muted-foreground: oklch(0.552 0.016 285.938); + --accent: oklch(0.967 0.001 286.375); + --accent-foreground: oklch(0.21 0.006 285.885); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.92 0.004 286.32); + --input: oklch(0.92 0.004 286.32); + --ring: oklch(0.705 0.015 286.067); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.141 0.005 285.823); + --sidebar-primary: oklch(0.21 0.006 285.885); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.967 0.001 286.375); + --sidebar-accent-foreground: oklch(0.21 0.006 285.885); + --sidebar-border: oklch(0.92 0.004 286.32); + --sidebar-ring: oklch(0.705 0.015 286.067); + + @variant dark { + --background: oklch(0.141 0.005 285.823); + --foreground: oklch(0.985 0 0); + --card: oklch(0.21 0.006 285.885); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.21 0.006 285.885); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.92 0.004 286.32); + --primary-foreground: oklch(0.21 0.006 285.885); + --secondary: oklch(0.274 0.006 286.033); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.274 0.006 286.033); + --muted-foreground: oklch(0.705 0.015 286.067); + --accent: oklch(0.274 0.006 286.033); + --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.552 0.016 285.938); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.21 0.006 285.885); + --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.274 0.006 286.033); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.552 0.016 285.938); + } +} + +.theme-neutral { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); + + @variant dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); + } +} + +.theme-gray { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.13 0.028 261.692); + --card: oklch(1 0 0); + --card-foreground: oklch(0.13 0.028 261.692); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.13 0.028 261.692); + --primary: oklch(0.21 0.034 264.665); + --primary-foreground: oklch(0.985 0.002 247.839); + --secondary: oklch(0.967 0.003 264.542); + --secondary-foreground: oklch(0.21 0.034 264.665); + --muted: oklch(0.967 0.003 264.542); + --muted-foreground: oklch(0.551 0.027 264.364); + --accent: oklch(0.967 0.003 264.542); + --accent-foreground: oklch(0.21 0.034 264.665); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.928 0.006 264.531); + --input: oklch(0.928 0.006 264.531); + --ring: oklch(0.707 0.022 261.325); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0.002 247.839); + --sidebar-foreground: oklch(0.13 0.028 261.692); + --sidebar-primary: oklch(0.21 0.034 264.665); + --sidebar-primary-foreground: oklch(0.985 0.002 247.839); + --sidebar-accent: oklch(0.967 0.003 264.542); + --sidebar-accent-foreground: oklch(0.21 0.034 264.665); + --sidebar-border: oklch(0.928 0.006 264.531); + --sidebar-ring: oklch(0.707 0.022 261.325); + + @variant dark { + --background: oklch(0.13 0.028 261.692); + --foreground: oklch(0.985 0.002 247.839); + --card: oklch(0.21 0.034 264.665); + --card-foreground: oklch(0.985 0.002 247.839); + --popover: oklch(0.21 0.034 264.665); + --popover-foreground: oklch(0.985 0.002 247.839); + --primary: oklch(0.928 0.006 264.531); + --primary-foreground: oklch(0.21 0.034 264.665); + --secondary: oklch(0.278 0.033 256.848); + --secondary-foreground: oklch(0.985 0.002 247.839); + --muted: oklch(0.278 0.033 256.848); + --muted-foreground: oklch(0.707 0.022 261.325); + --accent: oklch(0.278 0.033 256.848); + --accent-foreground: oklch(0.985 0.002 247.839); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.551 0.027 264.364); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.21 0.034 264.665); + --sidebar-foreground: oklch(0.985 0.002 247.839); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0.002 247.839); + --sidebar-accent: oklch(0.278 0.033 256.848); + --sidebar-accent-foreground: oklch(0.985 0.002 247.839); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.551 0.027 264.364); + } +} + +.theme-slate { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.129 0.042 264.695); + --card: oklch(1 0 0); + --card-foreground: oklch(0.129 0.042 264.695); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.129 0.042 264.695); + --primary: oklch(0.208 0.042 265.755); + --primary-foreground: oklch(0.984 0.003 247.858); + --secondary: oklch(0.968 0.007 247.896); + --secondary-foreground: oklch(0.208 0.042 265.755); + --muted: oklch(0.968 0.007 247.896); + --muted-foreground: oklch(0.554 0.046 257.417); + --accent: oklch(0.968 0.007 247.896); + --accent-foreground: oklch(0.208 0.042 265.755); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.929 0.013 255.508); + --input: oklch(0.929 0.013 255.508); + --ring: oklch(0.704 0.04 256.788); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.984 0.003 247.858); + --sidebar-foreground: oklch(0.129 0.042 264.695); + --sidebar-primary: oklch(0.208 0.042 265.755); + --sidebar-primary-foreground: oklch(0.984 0.003 247.858); + --sidebar-accent: oklch(0.968 0.007 247.896); + --sidebar-accent-foreground: oklch(0.208 0.042 265.755); + --sidebar-border: oklch(0.929 0.013 255.508); + --sidebar-ring: oklch(0.704 0.04 256.788); + + @variant dark { + --background: oklch(0.129 0.042 264.695); + --foreground: oklch(0.984 0.003 247.858); + --card: oklch(0.208 0.042 265.755); + --card-foreground: oklch(0.984 0.003 247.858); + --popover: oklch(0.208 0.042 265.755); + --popover-foreground: oklch(0.984 0.003 247.858); + --primary: oklch(0.929 0.013 255.508); + --primary-foreground: oklch(0.208 0.042 265.755); + --secondary: oklch(0.279 0.041 260.031); + --secondary-foreground: oklch(0.984 0.003 247.858); + --muted: oklch(0.279 0.041 260.031); + --muted-foreground: oklch(0.704 0.04 256.788); + --accent: oklch(0.279 0.041 260.031); + --accent-foreground: oklch(0.984 0.003 247.858); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.551 0.027 264.364); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.208 0.042 265.755); + --sidebar-foreground: oklch(0.984 0.003 247.858); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.984 0.003 247.858); + --sidebar-accent: oklch(0.279 0.041 260.031); + --sidebar-accent-foreground: oklch(0.984 0.003 247.858); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.551 0.027 264.364); + } +} + +.theme-blue { + --font-sans: var(--font-inter); + --text-sm: 0.85rem; + --radius: 0rem; + --spacing: 0.222222rem; + --primary: var(--color-blue-600); + --primary-foreground: var(--color-blue-50); + --chart-1: var(--color-blue-800); + --chart-2: var(--color-blue-700); + --chart-3: var(--color-blue-600); + --chart-4: var(--color-blue-500); + --chart-5: var(--color-blue-400); + + [data-slot="chart"] { + --chart-1: var(--color-blue-800); + --chart-2: var(--color-blue-700); + --chart-3: var(--color-blue-600); + --chart-4: var(--color-blue-500); + --chart-5: var(--color-blue-400); + } + + .rounded-xl { + border-radius: var(--radius); + } + + .shadow-sm { + box-shadow: none; + } + + @variant dark { + --primary: var(--color-blue-600); + --primary-foreground: var(--color-blue-50); + --chart-1: var(--color-blue-800); + --chart-2: var(--color-blue-700); + --chart-3: var(--color-blue-600); + --chart-4: var(--color-blue-500); + --chart-5: var(--color-blue-400); + + [data-slot="chart"] { + --chart-1: var(--color-blue-800); + --chart-2: var(--color-blue-700); + --chart-3: var(--color-blue-600); + --chart-4: var(--color-blue-500); + --chart-5: var(--color-blue-400); + } + } +} + +.theme-lime { + --font-sans: var(--font-noto-mono); + --spacing: 0.225rem; + --primary: var(--color-lime-600); + --primary-foreground: var(--color-lime-50); + --chart-1: var(--color-lime-800); + --chart-2: var(--color-lime-700); + --chart-3: var(--color-lime-600); + --chart-4: var(--color-lime-500); + --chart-5: var(--color-lime-400); + + [data-slot="chart"] { + --chart-1: var(--color-lime-800); + --chart-2: var(--color-lime-700); + --chart-3: var(--color-lime-600); + --chart-4: var(--color-lime-500); + --chart-5: var(--color-lime-400); + } + + .shadow-sm { + box-shadow: none; + } + + @variant dark { + --primary: var(--color-lime-600); + --primary-foreground: var(--color-lime-50); + --chart-1: var(--color-lime-900); + --chart-2: var(--color-lime-800); + --chart-3: var(--color-lime-700); + --chart-4: var(--color-lime-600); + --chart-5: var(--color-lime-500); + + [data-slot="chart"] { + --chart-1: var(--color-lime-900); + --chart-2: var(--color-lime-800); + --chart-3: var(--color-lime-700); + --chart-4: var(--color-lime-600); + --chart-5: var(--color-lime-500); + } + } +} + +.theme-small { + --radius: 0.5rem; + --text-lg: 1.05rem; + --text-base: 0.85rem; + --text-sm: 0.75rem; + --spacing: 0.222222rem; +} diff --git a/apps/v4/components.json b/apps/v4/components.json index 50ef6160d0..72435ee18e 100644 --- a/apps/v4/components.json +++ b/apps/v4/components.json @@ -18,4 +18,4 @@ "hooks": "@/hooks" }, "iconLibrary": "lucide" -} +} \ No newline at end of file diff --git a/apps/v4/components/active-theme.tsx b/apps/v4/components/active-theme.tsx new file mode 100644 index 0000000000..44ca91ec7b --- /dev/null +++ b/apps/v4/components/active-theme.tsx @@ -0,0 +1,62 @@ +"use client" + +import { + ReactNode, + createContext, + useContext, + useEffect, + useState, +} from "react" + +const COOKIE_NAME = "active_theme" +const DEFAULT_THEME = "default" + +function setThemeCookie(theme: string) { + if (typeof window === "undefined") return + + document.cookie = `${COOKIE_NAME}=${theme}; path=/; max-age=31536000; SameSite=Lax; ${window.location.protocol === "https:" ? "Secure;" : ""}` +} + +type ThemeContextType = { + activeTheme: string + setActiveTheme: (theme: string) => void +} + +const ThemeContext = createContext(undefined) + +export function ActiveThemeProvider({ + children, + initialTheme, +}: { + children: ReactNode + initialTheme?: string +}) { + const [activeTheme, setActiveTheme] = useState( + () => initialTheme || DEFAULT_THEME + ) + + useEffect(() => { + setThemeCookie(activeTheme) + + document.body.classList.forEach((className) => { + if (className.startsWith("theme-")) { + document.body.classList.remove(className) + } + }) + document.body.classList.add(`theme-${activeTheme}`) + }, [activeTheme]) + + return ( + + {children} + + ) +} + +export function useThemeConfig() { + const context = useContext(ThemeContext) + if (context === undefined) { + throw new Error("useThemeConfig must be used within an ActiveThemeProvider") + } + return context +} diff --git a/apps/v4/components/card-demo.tsx b/apps/v4/components/card-demo.tsx index ce20e154c6..ff2f0063e7 100644 --- a/apps/v4/components/card-demo.tsx +++ b/apps/v4/components/card-demo.tsx @@ -22,15 +22,15 @@ import { Label } from "@/registry/new-york-v4/ui/label" export function CardDemo() { return (
-
- - - Login to your account - - Enter your email below to login to your account - - - + + + Login to your account + + Enter your email below to login to your account + + + +
@@ -54,23 +54,23 @@ export function CardDemo() {
-
- - - -
- Don't have an account?{" "} - - Sign up - -
-
-
- + +
+ + + +
+ Don't have an account?{" "} + + Sign up + +
+
+
Meeting Notes diff --git a/apps/v4/components/context-menu-demo.tsx b/apps/v4/components/context-menu-demo.tsx index 658d78dc82..d16e9c9d5e 100644 --- a/apps/v4/components/context-menu-demo.tsx +++ b/apps/v4/components/context-menu-demo.tsx @@ -39,7 +39,7 @@ export function ContextMenuDemo() { More Tools - Save Page As... + Save Page... ⇧⌘S diff --git a/apps/v4/components/drawer-demo.tsx b/apps/v4/components/drawer-demo.tsx index 5ba9e12d18..73890f2c81 100644 --- a/apps/v4/components/drawer-demo.tsx +++ b/apps/v4/components/drawer-demo.tsx @@ -124,7 +124,7 @@ function DrawerBottom() { dataKey="goal" style={ { - fill: "hsl(var(--foreground))", + fill: "var(--primary)", opacity: 0.9, } as React.CSSProperties } diff --git a/apps/v4/components/forms-demo.tsx b/apps/v4/components/forms-demo.tsx index 72fc370ebb..653db0ac3e 100644 --- a/apps/v4/components/forms-demo.tsx +++ b/apps/v4/components/forms-demo.tsx @@ -44,55 +44,52 @@ const plans = [ ] as const const themes = { - stone: { + neutral: { light: { - "--primary": "oklch(0.216 0.006 56.043)", // --color-stone-900 - "--primary-foreground": "oklch(0.985 0.001 106.423)", // --color-stone-50 - "--accent": "oklch(0.97 0.001 106.424)", // --color-stone-100 - "--ring": "oklch(0.869 0.005 56.366)", // --color-stone-300 + "--primary": "oklch(0.205 0 0)", + "--primary-foreground": "oklch(0.985 0 0)", + "--ring": "oklch(0.708 0 0)", }, dark: { - "--primary": "oklch(0.985 0.001 106.423)", // --color-stone-50 - "--primary-foreground": "oklch(0.216 0.006 56.043)", // --color-stone-900 - "--accent": "oklch(0.268 0.007 34.298)", // --color-stone-800 - "--accent-foreground": "oklch(0.985 0.001 106.423)", // --color-stone-50 - "--ring": "oklch(0.553 0.013 58.071)", // --color-stone-500 + "--primary": "oklch(0.922 0 0)", + "--primary-foreground": "oklch(0.205 0 0)", + "--ring": "oklch(0.556 0 0)", }, }, blue: { light: { - "--primary": "oklch(0.546 0.245 262.881)", // --color-blue-600 - "--primary-foreground": "oklch(0.985 0.001 106.423)", // --color-blue-50 - "--ring": "oklch(0.707 0.165 254.624)", // --color-blue-400 + "--primary": "oklch(0.546 0.245 262.881)", + "--primary-foreground": "oklch(0.985 0.001 106.423)", + "--ring": "oklch(0.546 0.245 262.881)", }, dark: { - "--primary": "oklch(0.546 0.245 262.881)", // --color-blue-600 - "--primary-foreground": "oklch(0.985 0.001 106.423)", // --color-blue-50 - "--ring": "oklch(0.379 0.146 265.522)", // --color-blue-400 + "--primary": "oklch(0.623 0.214 259.815)", + "--primary-foreground": "oklch(0.985 0.001 106.423)", + "--ring": "oklch(0.623 0.214 259.815)", }, }, amber: { light: { - "--primary": "oklch(0.769 0.188 70.08)", // --color-blue-600 - "--primary-foreground": "oklch(0.985 0.001 106.423)", // --color-blue-50 - "--ring": "oklch(0.82 0.13 92.25)", // --color-blue-400 + "--primary": "oklch(0.769 0.188 70.08)", + "--primary-foreground": "oklch(0.985 0.001 106.423)", + "--ring": "oklch(0.82 0.13 92.25)", }, dark: { - "--primary": "oklch(0.985 0.001 106.423)", // --color-stone-50 - "--primary-foreground": "oklch(0.216 0.006 56.043)", // --color-stone-900 - "--ring": "oklch(0.553 0.013 58.071)", // --color-stone-500 + "--primary": "oklch(0.769 0.188 70.08)", + "--primary-foreground": "oklch(0.216 0.006 56.043)", + "--ring": "oklch(0.666 0.179 58.318)", }, }, teal: { light: { - "--primary": "oklch(0.627 0.194 149.214)", // --color-blue-600 - "--primary-foreground": "oklch(0.985 0.001 106.423)", // --color-blue-50 - "--ring": "oklch(0.79 0.19 153.13)", // --color-blue-400 + "--primary": "oklch(0.627 0.194 149.214)", + "--primary-foreground": "oklch(0.985 0.001 106.423)", + "--ring": "oklch(0.79 0.19 153.13)", }, dark: { - "--primary": "oklch(0.985 0.001 106.423)", // --color-stone-50 - "--primary-foreground": "oklch(0.216 0.006 56.043)", // --color-stone-900 - "--ring": "oklch(0.553 0.013 58.071)", // --color-stone-500 + "--primary": "oklch(0.704 0.14 182.503)", + "--primary-foreground": "oklch(0.216 0.006 56.043)", + "--ring": "oklch(0.704 0.14 182.503)", }, }, } as const @@ -109,123 +106,129 @@ export function FormsDemo() { }, [theme, mode]) return ( -
- - - Upgrade your subscription - - You are currently on the free plan. Upgrade to the pro plan to get - access to all features. - - - -
-
-
- - +
+
+ + + Upgrade your subscription + + You are currently on the free plan. Upgrade to the pro plan to get + access to all features. + + + +
+
+
+ + +
+
+ + +
- - + +
+ + + +
-
-
- -
- - - +
+ +
-
-
- - -
-
- Plan -

- Select the plan that best fits your needs. -

- - {plans.map((plan) => ( -
+
+ +