snapshot of https://github.com/shadcn-ui/ui.git (main, 2026-09-15; blobs > 131072B omitted)
All checks were successful
Release / Create Version PR or Publish Stable Release (push) Has been skipped
Release / Publish Prerelease to NPM (push) Has been skipped
Monitor Registries / Monitor registry health (push) Has been skipped

This commit is contained in:
upstream-mirror
2026-09-15 22:44:43 +05:00
commit 1416db152c
5727 changed files with 630238 additions and 0 deletions

View File

@@ -0,0 +1,281 @@
"use client"
import * as React from "react"
import { NavDocuments } from "@/registry/bases/aria/blocks/dashboard-01/components/nav-documents"
import { NavMain } from "@/registry/bases/aria/blocks/dashboard-01/components/nav-main"
import { NavSecondary } from "@/registry/bases/aria/blocks/dashboard-01/components/nav-secondary"
import { NavUser } from "@/registry/bases/aria/blocks/dashboard-01/components/nav-user"
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarHeader,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
} from "@/registry/bases/aria/ui/sidebar"
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
const data = {
user: {
name: "shadcn",
email: "m@example.com",
avatar: "/avatars/shadcn.jpg",
},
navMain: [
{
title: "Dashboard",
url: "#",
icon: (
<IconPlaceholder
lucide="LayoutDashboardIcon"
tabler="IconDashboard"
hugeicons="DashboardSquare01Icon"
phosphor="SquaresFourIcon"
remixicon="RiDashboardLine"
/>
),
},
{
title: "Lifecycle",
url: "#",
icon: (
<IconPlaceholder
lucide="ListIcon"
tabler="IconListDetails"
hugeicons="Menu01Icon"
phosphor="ListIcon"
remixicon="RiListUnordered"
/>
),
},
{
title: "Analytics",
url: "#",
icon: (
<IconPlaceholder
lucide="ChartBarIcon"
tabler="IconChartBar"
hugeicons="ChartHistogramIcon"
phosphor="ChartBarIcon"
remixicon="RiBarChartLine"
/>
),
},
{
title: "Projects",
url: "#",
icon: (
<IconPlaceholder
lucide="FolderIcon"
tabler="IconFolder"
hugeicons="Folder01Icon"
phosphor="FolderIcon"
remixicon="RiFolderLine"
/>
),
},
{
title: "Team",
url: "#",
icon: (
<IconPlaceholder
lucide="UsersIcon"
tabler="IconUsers"
hugeicons="UserGroupIcon"
phosphor="UsersIcon"
remixicon="RiGroupLine"
/>
),
},
],
navClouds: [
{
title: "Capture",
icon: (
<IconPlaceholder
lucide="CameraIcon"
tabler="IconCamera"
hugeicons="Camera01Icon"
phosphor="CameraIcon"
remixicon="RiCameraLine"
/>
),
isActive: true,
url: "#",
items: [
{
title: "Active Proposals",
url: "#",
},
{
title: "Archived",
url: "#",
},
],
},
{
title: "Proposal",
icon: (
<IconPlaceholder
lucide="FileTextIcon"
tabler="IconFileDescription"
hugeicons="File01Icon"
phosphor="FileTextIcon"
remixicon="RiFileTextLine"
/>
),
url: "#",
items: [
{
title: "Active Proposals",
url: "#",
},
{
title: "Archived",
url: "#",
},
],
},
{
title: "Prompts",
icon: (
<IconPlaceholder
lucide="FileTextIcon"
tabler="IconFileAi"
hugeicons="File01Icon"
phosphor="FileTextIcon"
remixicon="RiFileTextLine"
/>
),
url: "#",
items: [
{
title: "Active Proposals",
url: "#",
},
{
title: "Archived",
url: "#",
},
],
},
],
navSecondary: [
{
title: "Settings",
url: "#",
icon: (
<IconPlaceholder
lucide="Settings2Icon"
tabler="IconSettings"
hugeicons="Settings05Icon"
phosphor="GearIcon"
remixicon="RiSettingsLine"
/>
),
},
{
title: "Get Help",
url: "#",
icon: (
<IconPlaceholder
lucide="CircleHelpIcon"
tabler="IconHelp"
hugeicons="HelpCircleIcon"
phosphor="QuestionIcon"
remixicon="RiQuestionLine"
/>
),
},
{
title: "Search",
url: "#",
icon: (
<IconPlaceholder
lucide="SearchIcon"
tabler="IconSearch"
hugeicons="SearchIcon"
phosphor="MagnifyingGlassIcon"
remixicon="RiSearchLine"
/>
),
},
],
documents: [
{
name: "Data Library",
url: "#",
icon: (
<IconPlaceholder
lucide="DatabaseIcon"
tabler="IconDatabase"
hugeicons="Database01Icon"
phosphor="DatabaseIcon"
remixicon="RiDatabase2Line"
/>
),
},
{
name: "Reports",
url: "#",
icon: (
<IconPlaceholder
lucide="FileChartColumnIcon"
tabler="IconReport"
hugeicons="Analytics01Icon"
phosphor="ChartLineIcon"
remixicon="RiFileChartLine"
/>
),
},
{
name: "Word Assistant",
url: "#",
icon: (
<IconPlaceholder
lucide="FileIcon"
tabler="IconFileWord"
hugeicons="File01Icon"
phosphor="FileIcon"
remixicon="RiFileLine"
/>
),
},
],
}
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
return (
<Sidebar collapsible="offcanvas" {...props}>
<SidebarHeader>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton
href="#"
className="data-[slot=sidebar-menu-button]:p-1.5!"
>
<IconPlaceholder
lucide="CommandIcon"
tabler="IconInnerShadowTop"
hugeicons="CommandIcon"
phosphor="CommandIcon"
remixicon="RiCommandLine"
className="size-5!"
/>
<span className="text-base font-semibold">Acme Inc.</span>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
<SidebarContent>
<NavMain items={data.navMain} />
<NavDocuments items={data.documents} />
<NavSecondary items={data.navSecondary} className="mt-auto" />
</SidebarContent>
<SidebarFooter>
<NavUser user={data.user} />
</SidebarFooter>
</Sidebar>
)
}

View File

@@ -0,0 +1,300 @@
"use client"
import * as React from "react"
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts"
import { useIsMobile } from "@/registry/bases/aria/hooks/use-mobile"
import {
Card,
CardAction,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/registry/bases/aria/ui/card"
import {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
type ChartConfig,
} from "@/registry/bases/aria/ui/chart"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/registry/bases/aria/ui/select"
import {
ToggleGroup,
ToggleGroupItem,
} from "@/registry/bases/aria/ui/toggle-group"
export const description = "An interactive area chart"
const chartData = [
{ date: "2024-04-01", desktop: 222, mobile: 150 },
{ date: "2024-04-02", desktop: 97, mobile: 180 },
{ date: "2024-04-03", desktop: 167, mobile: 120 },
{ date: "2024-04-04", desktop: 242, mobile: 260 },
{ date: "2024-04-05", desktop: 373, mobile: 290 },
{ date: "2024-04-06", desktop: 301, mobile: 340 },
{ date: "2024-04-07", desktop: 245, mobile: 180 },
{ date: "2024-04-08", desktop: 409, mobile: 320 },
{ date: "2024-04-09", desktop: 59, mobile: 110 },
{ date: "2024-04-10", desktop: 261, mobile: 190 },
{ date: "2024-04-11", desktop: 327, mobile: 350 },
{ date: "2024-04-12", desktop: 292, mobile: 210 },
{ date: "2024-04-13", desktop: 342, mobile: 380 },
{ date: "2024-04-14", desktop: 137, mobile: 220 },
{ date: "2024-04-15", desktop: 120, mobile: 170 },
{ date: "2024-04-16", desktop: 138, mobile: 190 },
{ date: "2024-04-17", desktop: 446, mobile: 360 },
{ date: "2024-04-18", desktop: 364, mobile: 410 },
{ date: "2024-04-19", desktop: 243, mobile: 180 },
{ date: "2024-04-20", desktop: 89, mobile: 150 },
{ date: "2024-04-21", desktop: 137, mobile: 200 },
{ date: "2024-04-22", desktop: 224, mobile: 170 },
{ date: "2024-04-23", desktop: 138, mobile: 230 },
{ date: "2024-04-24", desktop: 387, mobile: 290 },
{ date: "2024-04-25", desktop: 215, mobile: 250 },
{ date: "2024-04-26", desktop: 75, mobile: 130 },
{ date: "2024-04-27", desktop: 383, mobile: 420 },
{ date: "2024-04-28", desktop: 122, mobile: 180 },
{ date: "2024-04-29", desktop: 315, mobile: 240 },
{ date: "2024-04-30", desktop: 454, mobile: 380 },
{ date: "2024-05-01", desktop: 165, mobile: 220 },
{ date: "2024-05-02", desktop: 293, mobile: 310 },
{ date: "2024-05-03", desktop: 247, mobile: 190 },
{ date: "2024-05-04", desktop: 385, mobile: 420 },
{ date: "2024-05-05", desktop: 481, mobile: 390 },
{ date: "2024-05-06", desktop: 498, mobile: 520 },
{ date: "2024-05-07", desktop: 388, mobile: 300 },
{ date: "2024-05-08", desktop: 149, mobile: 210 },
{ date: "2024-05-09", desktop: 227, mobile: 180 },
{ date: "2024-05-10", desktop: 293, mobile: 330 },
{ date: "2024-05-11", desktop: 335, mobile: 270 },
{ date: "2024-05-12", desktop: 197, mobile: 240 },
{ date: "2024-05-13", desktop: 197, mobile: 160 },
{ date: "2024-05-14", desktop: 448, mobile: 490 },
{ date: "2024-05-15", desktop: 473, mobile: 380 },
{ date: "2024-05-16", desktop: 338, mobile: 400 },
{ date: "2024-05-17", desktop: 499, mobile: 420 },
{ date: "2024-05-18", desktop: 315, mobile: 350 },
{ date: "2024-05-19", desktop: 235, mobile: 180 },
{ date: "2024-05-20", desktop: 177, mobile: 230 },
{ date: "2024-05-21", desktop: 82, mobile: 140 },
{ date: "2024-05-22", desktop: 81, mobile: 120 },
{ date: "2024-05-23", desktop: 252, mobile: 290 },
{ date: "2024-05-24", desktop: 294, mobile: 220 },
{ date: "2024-05-25", desktop: 201, mobile: 250 },
{ date: "2024-05-26", desktop: 213, mobile: 170 },
{ date: "2024-05-27", desktop: 420, mobile: 460 },
{ date: "2024-05-28", desktop: 233, mobile: 190 },
{ date: "2024-05-29", desktop: 78, mobile: 130 },
{ date: "2024-05-30", desktop: 340, mobile: 280 },
{ date: "2024-05-31", desktop: 178, mobile: 230 },
{ date: "2024-06-01", desktop: 178, mobile: 200 },
{ date: "2024-06-02", desktop: 470, mobile: 410 },
{ date: "2024-06-03", desktop: 103, mobile: 160 },
{ date: "2024-06-04", desktop: 439, mobile: 380 },
{ date: "2024-06-05", desktop: 88, mobile: 140 },
{ date: "2024-06-06", desktop: 294, mobile: 250 },
{ date: "2024-06-07", desktop: 323, mobile: 370 },
{ date: "2024-06-08", desktop: 385, mobile: 320 },
{ date: "2024-06-09", desktop: 438, mobile: 480 },
{ date: "2024-06-10", desktop: 155, mobile: 200 },
{ date: "2024-06-11", desktop: 92, mobile: 150 },
{ date: "2024-06-12", desktop: 492, mobile: 420 },
{ date: "2024-06-13", desktop: 81, mobile: 130 },
{ date: "2024-06-14", desktop: 426, mobile: 380 },
{ date: "2024-06-15", desktop: 307, mobile: 350 },
{ date: "2024-06-16", desktop: 371, mobile: 310 },
{ date: "2024-06-17", desktop: 475, mobile: 520 },
{ date: "2024-06-18", desktop: 107, mobile: 170 },
{ date: "2024-06-19", desktop: 341, mobile: 290 },
{ date: "2024-06-20", desktop: 408, mobile: 450 },
{ date: "2024-06-21", desktop: 169, mobile: 210 },
{ date: "2024-06-22", desktop: 317, mobile: 270 },
{ date: "2024-06-23", desktop: 480, mobile: 530 },
{ date: "2024-06-24", desktop: 132, mobile: 180 },
{ date: "2024-06-25", desktop: 141, mobile: 190 },
{ date: "2024-06-26", desktop: 434, mobile: 380 },
{ date: "2024-06-27", desktop: 448, mobile: 490 },
{ date: "2024-06-28", desktop: 149, mobile: 200 },
{ date: "2024-06-29", desktop: 103, mobile: 160 },
{ date: "2024-06-30", desktop: 446, mobile: 400 },
]
const chartConfig = {
visitors: {
label: "Visitors",
},
desktop: {
label: "Desktop",
color: "var(--primary)",
},
mobile: {
label: "Mobile",
color: "var(--primary)",
},
} satisfies ChartConfig
export function ChartAreaInteractive() {
const isMobile = useIsMobile()
const [timeRange, setTimeRange] = React.useState("90d")
React.useEffect(() => {
if (isMobile) {
setTimeRange("7d")
}
}, [isMobile])
const filteredData = chartData.filter((item) => {
const date = new Date(item.date)
const referenceDate = new Date("2024-06-30")
let daysToSubtract = 90
if (timeRange === "30d") {
daysToSubtract = 30
} else if (timeRange === "7d") {
daysToSubtract = 7
}
const startDate = new Date(referenceDate)
startDate.setDate(startDate.getDate() - daysToSubtract)
return date >= startDate
})
return (
<Card className="@container/card">
<CardHeader>
<CardTitle>Total Visitors</CardTitle>
<CardDescription>
<span className="hidden @[540px]/card:block">
Total for the last 3 months
</span>
<span className="@[540px]/card:hidden">Last 3 months</span>
</CardDescription>
<CardAction>
<ToggleGroup
selectionMode="single"
selectedKeys={timeRange ? [timeRange] : []}
onSelectionChange={(value) => {
setTimeRange((Array.from(value)[0] as string) ?? "90d")
}}
variant="outline"
className="hidden *:data-[slot=toggle-group-item]:px-4! @[767px]/card:flex"
>
<ToggleGroupItem id="90d">Last 3 months</ToggleGroupItem>
<ToggleGroupItem id="30d">Last 30 days</ToggleGroupItem>
<ToggleGroupItem id="7d">Last 7 days</ToggleGroupItem>
</ToggleGroup>
<Select
aria-label="Select a value"
value={timeRange}
onChange={(value) => {
if (value !== null) {
setTimeRange(String(value))
}
}}
>
<SelectTrigger
className="flex w-40 **:data-[slot=select-value]:block **:data-[slot=select-value]:truncate @[767px]/card:hidden"
size="sm"
>
<SelectValue />
</SelectTrigger>
<SelectContent className="rounded-xl">
<SelectItem id="90d" className="rounded-lg">
Last 3 months
</SelectItem>
<SelectItem id="30d" className="rounded-lg">
Last 30 days
</SelectItem>
<SelectItem id="7d" className="rounded-lg">
Last 7 days
</SelectItem>
</SelectContent>
</Select>
</CardAction>
</CardHeader>
<CardContent className="px-2 pt-4 sm:px-6 sm:pt-6">
<ChartContainer
config={chartConfig}
className="aspect-auto h-[250px] w-full"
>
<AreaChart data={filteredData}>
<defs>
<linearGradient id="fillDesktop" x1="0" y1="0" x2="0" y2="1">
<stop
offset="5%"
stopColor="var(--color-desktop)"
stopOpacity={1.0}
/>
<stop
offset="95%"
stopColor="var(--color-desktop)"
stopOpacity={0.1}
/>
</linearGradient>
<linearGradient id="fillMobile" x1="0" y1="0" x2="0" y2="1">
<stop
offset="5%"
stopColor="var(--color-mobile)"
stopOpacity={0.8}
/>
<stop
offset="95%"
stopColor="var(--color-mobile)"
stopOpacity={0.1}
/>
</linearGradient>
</defs>
<CartesianGrid vertical={false} />
<XAxis
dataKey="date"
tickLine={false}
axisLine={false}
tickMargin={8}
minTickGap={32}
tickFormatter={(value) => {
const date = new Date(value)
return date.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
})
}}
/>
<ChartTooltip
cursor={false}
content={
<ChartTooltipContent
labelFormatter={(value) => {
return new Date(value).toLocaleDateString("en-US", {
month: "short",
day: "numeric",
})
}}
indicator="dot"
/>
}
/>
<Area
dataKey="mobile"
type="natural"
fill="url(#fillMobile)"
stroke="var(--color-mobile)"
stackId="a"
/>
<Area
dataKey="desktop"
type="natural"
fill="url(#fillDesktop)"
stroke="var(--color-desktop)"
stackId="a"
/>
</AreaChart>
</ChartContainer>
</CardContent>
</Card>
)
}

View File

@@ -0,0 +1,892 @@
"use client"
import * as React from "react"
import {
columnFilteringFeature,
columnVisibilityFeature,
createColumnHelper,
createFilteredRowModel,
createPaginatedRowModel,
createSortedRowModel,
rowPaginationFeature,
rowSelectionFeature,
rowSortingFeature,
tableFeatures,
useTable,
type ColumnFiltersState,
type ColumnVisibilityState,
type SortingState,
} from "@tanstack/react-table"
import {
DropIndicator,
useDragAndDrop,
useListData,
} from "react-aria-components"
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts"
import { toast } from "sonner"
import { z } from "zod"
import { useIsMobile } from "@/registry/bases/aria/hooks/use-mobile"
import { Badge } from "@/registry/bases/aria/ui/badge"
import { Button } from "@/registry/bases/aria/ui/button"
import {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
type ChartConfig,
} from "@/registry/bases/aria/ui/chart"
import { Checkbox } from "@/registry/bases/aria/ui/checkbox"
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from "@/registry/bases/aria/ui/drawer"
import {
DropdownMenu,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/registry/bases/aria/ui/dropdown-menu"
import { Input } from "@/registry/bases/aria/ui/input"
import { Label } from "@/registry/bases/aria/ui/label"
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/registry/bases/aria/ui/select"
import { Separator } from "@/registry/bases/aria/ui/separator"
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/registry/bases/aria/ui/table"
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@/registry/bases/aria/ui/tabs"
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
// New in v9: declare the features this table uses — anything you don't
// register is tree-shaken out of the bundle.
const features = tableFeatures({
columnFilteringFeature,
columnVisibilityFeature,
rowPaginationFeature,
rowSelectionFeature,
rowSortingFeature,
filteredRowModel: createFilteredRowModel(),
paginatedRowModel: createPaginatedRowModel(),
sortedRowModel: createSortedRowModel(),
})
const columnHelper = createColumnHelper<
typeof features,
z.infer<typeof schema>
>()
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() {
return (
<Button
slot="drag"
variant="ghost"
size="icon"
className="size-7 text-muted-foreground hover:bg-transparent"
>
<IconPlaceholder
lucide="GripVerticalIcon"
tabler="IconGripVertical"
hugeicons="DragDropVerticalIcon"
phosphor="DotsSixVerticalIcon"
remixicon="RiDraggable"
className="size-3 text-muted-foreground"
/>
</Button>
)
}
const columns = columnHelper.columns([
columnHelper.display({
id: "drag",
header: () => null,
cell: ({ row }) => <DragHandle />,
}),
columnHelper.display({
id: "select",
header: () => (
<div className="flex items-center justify-center">
<Checkbox slot="selection" />
</div>
),
cell: () => (
<div className="flex items-center justify-center">
<Checkbox slot="selection" />
</div>
),
enableSorting: false,
enableHiding: false,
}),
columnHelper.accessor("header", {
header: "Header",
cell: ({ row }) => {
return <TableCellViewer item={row.original} />
},
enableHiding: false,
}),
columnHelper.accessor("type", {
header: "Section Type",
cell: ({ row }) => (
<div className="w-32">
<Badge variant="outline" className="px-1.5 text-muted-foreground">
{row.original.type}
</Badge>
</div>
),
}),
columnHelper.accessor("status", {
header: "Status",
cell: ({ row }) => (
<Badge variant="outline" className="px-1.5 text-muted-foreground">
{row.original.status === "Done" ? (
<IconPlaceholder
lucide="CircleCheckIcon"
tabler="IconCircleCheckFilled"
hugeicons="CheckmarkCircle01Icon"
phosphor="CheckCircleIcon"
remixicon="RiCheckboxCircleFill"
className="fill-green-500 dark:fill-green-400"
/>
) : (
<IconPlaceholder
lucide="LoaderIcon"
tabler="IconLoader"
hugeicons="Loading03Icon"
phosphor="SpinnerIcon"
remixicon="RiLoader4Line"
/>
)}
{row.original.status}
</Badge>
),
}),
columnHelper.accessor("target", {
header: () => <div className="w-full text-right">Target</div>,
cell: ({ row }) => (
<form
onSubmit={(e) => {
e.preventDefault()
toast.promise(new Promise((resolve) => setTimeout(resolve, 1000)), {
loading: `Saving ${row.original.header}`,
success: "Done",
error: "Error",
})
}}
>
<Label htmlFor={`${row.original.id}-target`} className="sr-only">
Target
</Label>
<Input
className="h-8 w-16 border-transparent bg-transparent text-right shadow-none hover:bg-input/30 focus-visible:border focus-visible:bg-background dark:bg-transparent dark:hover:bg-input/30 dark:focus-visible:bg-input/30"
defaultValue={row.original.target}
id={`${row.original.id}-target`}
/>
</form>
),
}),
columnHelper.accessor("limit", {
header: () => <div className="w-full text-right">Limit</div>,
cell: ({ row }) => (
<form
onSubmit={(e) => {
e.preventDefault()
toast.promise(new Promise((resolve) => setTimeout(resolve, 1000)), {
loading: `Saving ${row.original.header}`,
success: "Done",
error: "Error",
})
}}
>
<Label htmlFor={`${row.original.id}-limit`} className="sr-only">
Limit
</Label>
<Input
className="h-8 w-16 border-transparent bg-transparent text-right shadow-none hover:bg-input/30 focus-visible:border focus-visible:bg-background dark:bg-transparent dark:hover:bg-input/30 dark:focus-visible:bg-input/30"
defaultValue={row.original.limit}
id={`${row.original.id}-limit`}
/>
</form>
),
}),
columnHelper.accessor("reviewer", {
header: "Reviewer",
cell: ({ row }) => {
const isAssigned = row.original.reviewer !== "Assign reviewer"
if (isAssigned) {
return row.original.reviewer
}
return (
<>
<Label htmlFor={`${row.original.id}-reviewer`} className="sr-only">
Reviewer
</Label>
<Select placeholder="Assign reviewer">
<SelectTrigger
className="w-38 **:data-[slot=select-value]:block **:data-[slot=select-value]:truncate"
size="sm"
id={`${row.original.id}-reviewer`}
>
<SelectValue />
</SelectTrigger>
<SelectContent placement="bottom end">
<SelectGroup>
<SelectItem id="Eddie Lake">Eddie Lake</SelectItem>
<SelectItem id="Jamik Tashpulatov">
Jamik Tashpulatov
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</>
)
},
}),
columnHelper.display({
id: "actions",
cell: () => (
<DropdownMenuTrigger>
<Button
variant="ghost"
className="flex size-8 text-muted-foreground aria-expanded:bg-muted"
size="icon"
>
<IconPlaceholder
lucide="EllipsisVerticalIcon"
tabler="IconDotsVertical"
hugeicons="MoreVerticalCircle01Icon"
phosphor="DotsThreeVerticalIcon"
remixicon="RiMore2Line"
/>
<span className="sr-only">Open menu</span>
</Button>
<DropdownMenu placement="bottom end" className="w-32">
<DropdownMenuItem>Edit</DropdownMenuItem>
<DropdownMenuItem>Make a copy</DropdownMenuItem>
<DropdownMenuItem>Favorite</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem variant="destructive">Delete</DropdownMenuItem>
</DropdownMenu>
</DropdownMenuTrigger>
),
}),
])
export function DataTable({
data: initialData,
}: {
data: z.infer<typeof schema>[]
}) {
const list = useListData({
initialItems: initialData,
getKey: (item) => String(item.id),
})
const data = list.items
const [rowSelection, setRowSelection] = React.useState({})
const [columnVisibility, setColumnVisibility] =
React.useState<ColumnVisibilityState>({})
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
)
const [sorting, setSorting] = React.useState<SortingState>([])
const [pagination, setPagination] = React.useState({
pageIndex: 0,
pageSize: 10,
})
const table = useTable({
features,
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,
})
const { dragAndDropHooks } = useDragAndDrop({
getItems: (keys, items: z.infer<typeof schema>[]) =>
items.map((item) => ({
"text/plain": item.header,
})),
onReorder(e) {
if (e.target.dropPosition === "before") {
list.moveBefore(e.target.key, e.keys)
} else if (e.target.dropPosition === "after") {
list.moveAfter(e.target.key, e.keys)
}
},
renderDropIndicator(target) {
return (
<DropIndicator
target={target}
className="outline-blue-400 data-drop-target:outline-1"
/>
)
},
})
return (
<Tabs
defaultSelectedKey="outline"
className="w-full flex-col justify-start gap-6"
>
<div className="flex items-center justify-between px-4 lg:px-6">
<Label htmlFor="view-selector" className="sr-only">
View
</Label>
{/* <Select placeholder="Select a view" defaultValue="outline">
<SelectTrigger
className="flex w-fit @4xl/main:hidden"
size="sm"
id="view-selector"
>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem id="outline">Outline</SelectItem>
<SelectItem id="past-performance">Past Performance</SelectItem>
<SelectItem id="key-personnel">Key Personnel</SelectItem>
<SelectItem id="focus-documents">Focus Documents</SelectItem>
</SelectGroup>
</SelectContent>
</Select> */}
<TabsList className="hidden **:data-[slot=badge]:size-5 **:data-[slot=badge]:rounded-full **:data-[slot=badge]:bg-muted-foreground/30 **:data-[slot=badge]:px-1 @4xl/main:flex">
<TabsTrigger id="outline">Outline</TabsTrigger>
<TabsTrigger id="past-performance">
Past Performance <Badge variant="secondary">3</Badge>
</TabsTrigger>
<TabsTrigger id="key-personnel">
Key Personnel <Badge variant="secondary">2</Badge>
</TabsTrigger>
<TabsTrigger id="focus-documents">Focus Documents</TabsTrigger>
</TabsList>
<div className="flex items-center gap-2">
{/* <DropdownMenuTrigger>
<Button variant="outline" size="sm">
<IconPlaceholder
lucide="Columns3Icon"
tabler="IconLayoutColumns"
hugeicons="LeftToRightListBulletIcon"
phosphor="ColumnsIcon"
remixicon="RiLayoutColumnLine"
data-icon="inline-start"
/>
Columns
<IconPlaceholder
lucide="ChevronDownIcon"
tabler="IconChevronDown"
hugeicons="ArrowDown01Icon"
phosphor="CaretDownIcon"
remixicon="RiArrowDownSLine"
data-icon="inline-end"
/>
</Button>
<DropdownMenu
align="end"
className="w-32"
selectionMode="multiple"
selectedKeys={
table
.getVisibleFlatColumns()
.filter((column) => column.getCanHide())
.map(column => column.id)
}
onSelectionChange={(keys) => {
table.setColumnVisibility(
Object.fromEntries(
table
.getAllFlatColumns()
.map((c) => [
c.id,
!c.getCanHide() || keys === "all" || keys.has(c.id),
])
)
)
}}
>
{table
.getAllColumns()
.filter(
(column) =>
typeof column.accessorFn !== "undefined" &&
column.getCanHide()
)
.map((column) => {
return (
<DropdownMenuItem
key={column.id}
id={column.id}
className="capitalize"
>
{column.id}
</DropdownMenuItem>
)
})}
</DropdownMenu>
</DropdownMenuTrigger> */}
<Button variant="outline" size="sm">
<IconPlaceholder
lucide="PlusIcon"
tabler="IconPlus"
hugeicons="Add01Icon"
phosphor="PlusIcon"
remixicon="RiAddLine"
/>
<span className="hidden lg:inline">Add Section</span>
</Button>
</div>
</div>
<TabsContent
id="outline"
className="relative flex flex-col gap-4 overflow-auto px-4 lg:px-6"
>
<div className="overflow-hidden rounded-lg border">
<Table
aria-label="Tasks"
dragAndDropHooks={dragAndDropHooks}
selectionMode="multiple"
onSelectionChange={(selection) => {
if (selection === "all") {
table.toggleAllRowsSelected()
} else {
table.setRowSelection(
Object.fromEntries([...selection].map((key) => [key, true]))
)
}
}}
sortDescriptor={
sorting.length
? {
column: sorting[0].id,
direction: sorting[0].desc ? "descending" : "ascending",
}
: undefined
}
onSortChange={(sortDescriptor) => {
table.setSorting([
{
id: "" + sortDescriptor.column,
desc: sortDescriptor.direction === "descending",
},
])
}}
>
<TableHeader className="sticky top-0 z-10 bg-muted">
{table.getFlatHeaders().map((header) => (
<TableHead
key={header.id}
id={header.id}
isRowHeader={header.index === 1}
allowsSorting={header.column.getCanSort()}
>
{header.isPlaceholder ? null : (
<table.FlexRender header={header} />
)}
</TableHead>
))}
</TableHeader>
<TableBody
className="data-empty:h-24 data-empty:text-center **:data-[slot=table-cell]:first:w-8"
renderEmptyState={() => "No results."}
>
{table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
id={row.id}
value={row.original}
className="relative z-0 data-[dragging=true]:z-10 data-[dragging=true]:opacity-80"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
<table.FlexRender cell={cell} />
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</div>
<div className="flex items-center justify-between px-4">
<div className="hidden flex-1 text-sm text-muted-foreground lg:flex">
{table.getFilteredSelectedRowModel().rows.length} of{" "}
{table.getFilteredRowModel().rows.length} row(s) selected.
</div>
<div className="flex w-full items-center gap-8 lg:w-fit">
<div className="hidden items-center gap-2 lg:flex">
<Label htmlFor="rows-per-page" className="text-sm font-medium">
Rows per page
</Label>
<Select
aria-label="Rows per page"
placeholder={`${table.state.pagination.pageSize}`}
value={`${table.state.pagination.pageSize}`}
onChange={(value) => {
table.setPageSize(Number(value))
}}
>
<SelectTrigger size="sm" className="w-20" id="rows-per-page">
<SelectValue />
</SelectTrigger>
<SelectContent placement="top">
<SelectGroup>
{[10, 20, 30, 40, 50].map((pageSize) => (
<SelectItem key={pageSize} id={`${pageSize}`}>
{pageSize}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</div>
<div className="flex w-fit items-center justify-center text-sm font-medium">
Page {table.state.pagination.pageIndex + 1} of{" "}
{table.getPageCount()}
</div>
<div className="ml-auto flex items-center gap-2 lg:ml-0">
<Button
variant="outline"
className="hidden h-8 w-8 p-0 lg:flex"
onPress={() => table.setPageIndex(0)}
isDisabled={!table.getCanPreviousPage()}
>
<span className="sr-only">Go to first page</span>
<IconPlaceholder
lucide="ChevronsLeftIcon"
tabler="IconChevronsLeft"
hugeicons="ArrowLeftDoubleIcon"
phosphor="CaretDoubleLeftIcon"
remixicon="RiSkipLeftLine"
/>
</Button>
<Button
variant="outline"
className="size-8"
size="icon"
onPress={() => table.previousPage()}
isDisabled={!table.getCanPreviousPage()}
>
<span className="sr-only">Go to previous page</span>
<IconPlaceholder
lucide="ChevronLeftIcon"
tabler="IconChevronLeft"
hugeicons="ArrowLeft01Icon"
phosphor="CaretLeftIcon"
remixicon="RiArrowLeftSLine"
/>
</Button>
<Button
variant="outline"
className="size-8"
size="icon"
onPress={() => table.nextPage()}
isDisabled={!table.getCanNextPage()}
>
<span className="sr-only">Go to next page</span>
<IconPlaceholder
lucide="ChevronRightIcon"
tabler="IconChevronRight"
hugeicons="ArrowRight01Icon"
phosphor="CaretRightIcon"
remixicon="RiArrowRightSLine"
/>
</Button>
<Button
variant="outline"
className="hidden size-8 lg:flex"
size="icon"
onPress={() => table.setPageIndex(table.getPageCount() - 1)}
isDisabled={!table.getCanNextPage()}
>
<span className="sr-only">Go to last page</span>
<IconPlaceholder
lucide="ChevronsRightIcon"
tabler="IconChevronsRight"
hugeicons="ArrowRightDoubleIcon"
phosphor="CaretDoubleRightIcon"
remixicon="RiSkipRightLine"
/>
</Button>
</div>
</div>
</div>
</TabsContent>
<TabsContent id="past-performance" className="flex flex-col px-4 lg:px-6">
<div className="aspect-video w-full flex-1 rounded-lg border border-dashed"></div>
</TabsContent>
<TabsContent id="key-personnel" className="flex flex-col px-4 lg:px-6">
<div className="aspect-video w-full flex-1 rounded-lg border border-dashed"></div>
</TabsContent>
<TabsContent id="focus-documents" className="flex flex-col px-4 lg:px-6">
<div className="aspect-video w-full flex-1 rounded-lg border border-dashed"></div>
</TabsContent>
</Tabs>
)
}
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<typeof schema> }) {
const isMobile = useIsMobile()
return (
<Drawer swipeDirection={isMobile ? "down" : "right"}>
<DrawerTrigger
render={
<Button
variant="link"
className="w-fit px-0 text-left text-foreground"
/>
}
>
{item.header}
</DrawerTrigger>
<DrawerContent>
<DrawerHeader className="gap-1">
<DrawerTitle>{item.header}</DrawerTitle>
<DrawerDescription>
Showing total visitors for the last 6 months
</DrawerDescription>
</DrawerHeader>
<div className="flex flex-col gap-4 overflow-y-auto px-4 text-sm">
{!isMobile && (
<>
<ChartContainer config={chartConfig}>
<AreaChart
accessibilityLayer
data={chartData}
margin={{
left: 0,
right: 10,
}}
>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
axisLine={false}
tickMargin={8}
tickFormatter={(value) => value.slice(0, 3)}
hide
/>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent indicator="dot" />}
/>
<Area
dataKey="mobile"
type="natural"
fill="var(--color-mobile)"
fillOpacity={0.6}
stroke="var(--color-mobile)"
stackId="a"
/>
<Area
dataKey="desktop"
type="natural"
fill="var(--color-desktop)"
fillOpacity={0.4}
stroke="var(--color-desktop)"
stackId="a"
/>
</AreaChart>
</ChartContainer>
<Separator />
<div className="grid gap-2">
<div className="flex gap-2 leading-none font-medium">
Trending up by 5.2% this month{" "}
<IconPlaceholder
lucide="TrendingUpIcon"
tabler="IconTrendingUp"
hugeicons="ChartUpIcon"
phosphor="TrendUpIcon"
remixicon="RiArrowUpLine"
className="size-4"
/>
</div>
<div className="text-muted-foreground">
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.
</div>
</div>
<Separator />
</>
)}
<form className="flex flex-col gap-4">
<div className="flex flex-col gap-3">
<Label htmlFor="header">Header</Label>
<Input id="header" defaultValue={item.header} />
</div>
<div className="grid grid-cols-2 gap-4">
<div className="flex flex-col gap-3">
<Label htmlFor="type">Type</Label>
<Select
placeholder="Select a type"
aria-label="Type"
defaultValue={item.type}
>
<SelectTrigger id="type" className="w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem id="Table of Contents">
Table of Contents
</SelectItem>
<SelectItem id="Executive Summary">
Executive Summary
</SelectItem>
<SelectItem id="Technical Approach">
Technical Approach
</SelectItem>
<SelectItem id="Design">Design</SelectItem>
<SelectItem id="Capabilities">Capabilities</SelectItem>
<SelectItem id="Focus Documents">
Focus Documents
</SelectItem>
<SelectItem id="Narrative">Narrative</SelectItem>
<SelectItem id="Cover Page">Cover Page</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="status">Status</Label>
<Select
aria-label="Status"
placeholder="Select a status"
defaultValue={item.status}
>
<SelectTrigger id="status" className="w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem id="Done">Done</SelectItem>
<SelectItem id="In Progress">In Progress</SelectItem>
<SelectItem id="Not Started">Not Started</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="flex flex-col gap-3">
<Label htmlFor="target">Target</Label>
<Input id="target" defaultValue={item.target} />
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="limit">Limit</Label>
<Input id="limit" defaultValue={item.limit} />
</div>
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="reviewer">Reviewer</Label>
<Select
aria-label="Reviewer"
placeholder="Select a reviewer"
defaultValue={item.reviewer}
>
<SelectTrigger id="reviewer" className="w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem id="Eddie Lake">Eddie Lake</SelectItem>
<SelectItem id="Jamik Tashpulatov">
Jamik Tashpulatov
</SelectItem>
<SelectItem id="Emily Whalen">Emily Whalen</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
</form>
</div>
<DrawerFooter>
<Button>Submit</Button>
<DrawerClose render={<Button variant="outline" />}>Done</DrawerClose>
</DrawerFooter>
</DrawerContent>
</Drawer>
)
}

View File

@@ -0,0 +1,107 @@
"use client"
import {
DropdownMenu,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/registry/bases/aria/ui/dropdown-menu"
import {
SidebarGroup,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuAction,
SidebarMenuButton,
SidebarMenuItem,
useSidebar,
} from "@/registry/bases/aria/ui/sidebar"
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
export function NavDocuments({
items,
}: {
items: {
name: string
url: string
icon: React.ReactNode
}[]
}) {
const { isMobile } = useSidebar()
return (
<SidebarGroup className="group-data-[collapsible=icon]:hidden">
<SidebarGroupLabel>Documents</SidebarGroupLabel>
<SidebarMenu>
{items.map((item) => (
<SidebarMenuItem key={item.name}>
<SidebarMenuButton href={item.url}>
{item.icon}
<span>{item.name}</span>
</SidebarMenuButton>
<DropdownMenuTrigger>
<SidebarMenuAction showOnHover className="aria-expanded:bg-muted">
<IconPlaceholder
lucide="MoreHorizontalIcon"
tabler="IconDots"
hugeicons="MoreHorizontalCircle01Icon"
phosphor="DotsThreeOutlineIcon"
remixicon="RiMoreLine"
/>
<span className="sr-only">More</span>
</SidebarMenuAction>
<DropdownMenu
className="w-24"
placement={isMobile ? "bottom end" : "right top"}
>
<DropdownMenuItem>
<IconPlaceholder
lucide="FolderIcon"
tabler="IconFolder"
hugeicons="Folder01Icon"
phosphor="FolderIcon"
remixicon="RiFolderLine"
/>
<span>Open</span>
</DropdownMenuItem>
<DropdownMenuItem>
<IconPlaceholder
lucide="ShareIcon"
tabler="IconShare3"
hugeicons="Share01Icon"
phosphor="ShareIcon"
remixicon="RiShareLine"
/>
<span>Share</span>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem variant="destructive">
<IconPlaceholder
lucide="Trash2Icon"
tabler="IconTrash"
hugeicons="Delete02Icon"
phosphor="TrashIcon"
remixicon="RiDeleteBinLine"
/>
<span>Delete</span>
</DropdownMenuItem>
</DropdownMenu>
</DropdownMenuTrigger>
</SidebarMenuItem>
))}
<SidebarMenuItem>
<SidebarMenuButton className="text-sidebar-foreground/70">
<IconPlaceholder
lucide="MoreHorizontalIcon"
tabler="IconDots"
hugeicons="MoreHorizontalCircle01Icon"
phosphor="DotsThreeOutlineIcon"
remixicon="RiMoreLine"
className="text-sidebar-foreground/70"
/>
<span>More</span>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroup>
)
}

View File

@@ -0,0 +1,69 @@
"use client"
import { Button } from "@/registry/bases/aria/ui/button"
import {
SidebarGroup,
SidebarGroupContent,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
} from "@/registry/bases/aria/ui/sidebar"
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
export function NavMain({
items,
}: {
items: {
title: string
url: string
icon?: React.ReactNode
}[]
}) {
return (
<SidebarGroup>
<SidebarGroupContent className="flex flex-col gap-2">
<SidebarMenu>
<SidebarMenuItem className="flex items-center gap-2">
<SidebarMenuButton
tooltip="Quick Create"
className="min-w-8 bg-primary text-primary-foreground duration-200 ease-linear hover:bg-primary/90 hover:text-primary-foreground active:bg-primary/90 active:text-primary-foreground"
>
<IconPlaceholder
lucide="CirclePlusIcon"
tabler="IconCirclePlusFilled"
hugeicons="PlusSignCircleIcon"
phosphor="PlusCircleIcon"
remixicon="RiAddCircleFill"
/>
<span>Quick Create</span>
</SidebarMenuButton>
<Button
size="icon"
className="size-8 group-data-[collapsible=icon]:opacity-0"
variant="outline"
>
<IconPlaceholder
lucide="MailIcon"
tabler="IconMail"
hugeicons="Mail01Icon"
phosphor="EnvelopeIcon"
remixicon="RiMailLine"
/>
<span className="sr-only">Inbox</span>
</Button>
</SidebarMenuItem>
</SidebarMenu>
<SidebarMenu>
{items.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton tooltip={item.title}>
{item.icon}
<span>{item.title}</span>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
)
}

View File

@@ -0,0 +1,39 @@
"use client"
import * as React from "react"
import {
SidebarGroup,
SidebarGroupContent,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
} from "@/registry/bases/aria/ui/sidebar"
export function NavSecondary({
items,
...props
}: {
items: {
title: string
url: string
icon: React.ReactNode
}[]
} & React.ComponentPropsWithoutRef<typeof SidebarGroup>) {
return (
<SidebarGroup {...props}>
<SidebarGroupContent>
<SidebarMenu>
{items.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton href={item.url}>
{item.icon}
<span>{item.title}</span>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
)
}

View File

@@ -0,0 +1,128 @@
"use client"
import {
Avatar,
AvatarFallback,
AvatarImage,
} from "@/registry/bases/aria/ui/avatar"
import {
DropdownMenu,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/registry/bases/aria/ui/dropdown-menu"
import {
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
useSidebar,
} from "@/registry/bases/aria/ui/sidebar"
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
export function NavUser({
user,
}: {
user: {
name: string
email: string
avatar: string
}
}) {
const { isMobile } = useSidebar()
return (
<SidebarMenu>
<SidebarMenuItem>
<DropdownMenuTrigger>
<SidebarMenuButton size="lg" className="aria-expanded:bg-muted">
<Avatar className="size-8 rounded-lg grayscale">
<AvatarImage src={user.avatar} alt={user.name} />
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
</Avatar>
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-medium">{user.name}</span>
<span className="truncate text-xs text-foreground/70">
{user.email}
</span>
</div>
<IconPlaceholder
lucide="EllipsisVerticalIcon"
tabler="IconDotsVertical"
hugeicons="MoreVerticalCircle01Icon"
phosphor="DotsThreeVerticalIcon"
remixicon="RiMore2Line"
className="ml-auto size-4"
/>
</SidebarMenuButton>
<DropdownMenu
className="min-w-56"
placement={isMobile ? "bottom end" : "right bottom"}
offset={4}
>
<DropdownMenuGroup>
<DropdownMenuLabel className="p-0 font-normal">
<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
<Avatar className="size-8">
<AvatarImage src={user.avatar} alt={user.name} />
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
</Avatar>
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-medium">{user.name}</span>
<span className="truncate text-xs text-muted-foreground">
{user.email}
</span>
</div>
</div>
</DropdownMenuLabel>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
<IconPlaceholder
lucide="CircleUserRoundIcon"
tabler="IconUserCircle"
hugeicons="UserCircle02Icon"
phosphor="UserCircleIcon"
remixicon="RiUserLine"
/>
Account
</DropdownMenuItem>
<DropdownMenuItem>
<IconPlaceholder
lucide="CreditCardIcon"
tabler="IconCreditCard"
hugeicons="CreditCardIcon"
phosphor="CreditCardIcon"
remixicon="RiBankCardLine"
/>
Billing
</DropdownMenuItem>
<DropdownMenuItem>
<IconPlaceholder
lucide="BellIcon"
tabler="IconNotification"
hugeicons="Notification03Icon"
phosphor="BellIcon"
remixicon="RiNotification3Line"
/>
Notifications
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuItem>
<IconPlaceholder
lucide="LogOutIcon"
tabler="IconLogout"
hugeicons="Logout01Icon"
phosphor="SignOutIcon"
remixicon="RiLogoutBoxLine"
/>
Log out
</DropdownMenuItem>
</DropdownMenu>
</DropdownMenuTrigger>
</SidebarMenuItem>
</SidebarMenu>
)
}

View File

@@ -0,0 +1,159 @@
"use client"
import { Badge } from "@/registry/bases/aria/ui/badge"
import {
Card,
CardAction,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/registry/bases/aria/ui/card"
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
export function SectionCards() {
return (
<div className="grid grid-cols-1 gap-4 px-4 *:data-[slot=card]:bg-linear-to-t *:data-[slot=card]:from-primary/5 *:data-[slot=card]:to-card *:data-[slot=card]:shadow-xs lg:px-6 @xl/main:grid-cols-2 @5xl/main:grid-cols-4 dark:*:data-[slot=card]:bg-card">
<Card className="@container/card">
<CardHeader>
<CardDescription>Total Revenue</CardDescription>
<CardTitle className="text-2xl font-semibold tabular-nums @[250px]/card:text-3xl">
$1,250.00
</CardTitle>
<CardAction>
<Badge variant="outline">
<IconPlaceholder
lucide="TrendingUpIcon"
tabler="IconTrendingUp"
hugeicons="ChartUpIcon"
phosphor="TrendUpIcon"
remixicon="RiArrowUpLine"
/>
+12.5%
</Badge>
</CardAction>
</CardHeader>
<CardFooter className="flex-col items-start gap-1.5 text-sm">
<div className="line-clamp-1 flex gap-2 font-medium">
Trending up this month{" "}
<IconPlaceholder
lucide="TrendingUpIcon"
tabler="IconTrendingUp"
hugeicons="ChartUpIcon"
phosphor="TrendUpIcon"
remixicon="RiArrowUpLine"
className="size-4"
/>
</div>
<div className="text-muted-foreground">
Visitors for the last 6 months
</div>
</CardFooter>
</Card>
<Card className="@container/card">
<CardHeader>
<CardDescription>New Customers</CardDescription>
<CardTitle className="text-2xl font-semibold tabular-nums @[250px]/card:text-3xl">
1,234
</CardTitle>
<CardAction>
<Badge variant="outline">
<IconPlaceholder
lucide="TrendingDownIcon"
tabler="IconTrendingDown"
hugeicons="ChartDownIcon"
phosphor="TrendDownIcon"
remixicon="RiArrowDownLine"
/>
-20%
</Badge>
</CardAction>
</CardHeader>
<CardFooter className="flex-col items-start gap-1.5 text-sm">
<div className="line-clamp-1 flex gap-2 font-medium">
Down 20% this period{" "}
<IconPlaceholder
lucide="TrendingDownIcon"
tabler="IconTrendingDown"
hugeicons="ChartDownIcon"
phosphor="TrendDownIcon"
remixicon="RiArrowDownLine"
className="size-4"
/>
</div>
<div className="text-muted-foreground">
Acquisition needs attention
</div>
</CardFooter>
</Card>
<Card className="@container/card">
<CardHeader>
<CardDescription>Active Accounts</CardDescription>
<CardTitle className="text-2xl font-semibold tabular-nums @[250px]/card:text-3xl">
45,678
</CardTitle>
<CardAction>
<Badge variant="outline">
<IconPlaceholder
lucide="TrendingUpIcon"
tabler="IconTrendingUp"
hugeicons="ChartUpIcon"
phosphor="TrendUpIcon"
remixicon="RiArrowUpLine"
/>
+12.5%
</Badge>
</CardAction>
</CardHeader>
<CardFooter className="flex-col items-start gap-1.5 text-sm">
<div className="line-clamp-1 flex gap-2 font-medium">
Strong user retention{" "}
<IconPlaceholder
lucide="TrendingUpIcon"
tabler="IconTrendingUp"
hugeicons="ChartUpIcon"
phosphor="TrendUpIcon"
remixicon="RiArrowUpLine"
className="size-4"
/>
</div>
<div className="text-muted-foreground">Engagement exceed targets</div>
</CardFooter>
</Card>
<Card className="@container/card">
<CardHeader>
<CardDescription>Growth Rate</CardDescription>
<CardTitle className="text-2xl font-semibold tabular-nums @[250px]/card:text-3xl">
4.5%
</CardTitle>
<CardAction>
<Badge variant="outline">
<IconPlaceholder
lucide="TrendingUpIcon"
tabler="IconTrendingUp"
hugeicons="ChartUpIcon"
phosphor="TrendUpIcon"
remixicon="RiArrowUpLine"
/>
+4.5%
</Badge>
</CardAction>
</CardHeader>
<CardFooter className="flex-col items-start gap-1.5 text-sm">
<div className="line-clamp-1 flex gap-2 font-medium">
Steady performance increase{" "}
<IconPlaceholder
lucide="TrendingUpIcon"
tabler="IconTrendingUp"
hugeicons="ChartUpIcon"
phosphor="TrendUpIcon"
remixicon="RiArrowUpLine"
className="size-4"
/>
</div>
<div className="text-muted-foreground">Meets growth projections</div>
</CardFooter>
</Card>
</div>
)
}

View File

@@ -0,0 +1,17 @@
import { Separator } from "@/registry/bases/aria/ui/separator"
import { SidebarTrigger } from "@/registry/bases/aria/ui/sidebar"
export function SiteHeader() {
return (
<header className="flex h-(--header-height) shrink-0 items-center gap-2 border-b transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-(--header-height)">
<div className="flex w-full items-center gap-1 px-4 lg:gap-2 lg:px-6">
<SidebarTrigger className="-ml-1" />
<Separator
orientation="vertical"
className="mx-2 h-4 data-vertical:self-auto"
/>
<h1 className="text-base font-medium">Documents</h1>
</div>
</header>
)
}