@cogito.ai/cli 0.3.5 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +20 -1
- package/dist/templates/web-nextjs/apps/docs/.source/browser.ts +1 -1
- package/dist/templates/web-nextjs/apps/docs/.source/server.ts +3 -2
- package/dist/templates/web-nextjs/apps/docs/content/docs/decisions/meta.json +1 -1
- package/dist/templates/web-nextjs/apps/docs/content/docs/decisions/turbo-package-manager.mdx +70 -0
- package/dist/templates/web-nextjs/apps/docs/package.json +1 -1
- package/dist/templates/web-nextjs/apps/web/messages/en.json +5 -1
- package/dist/templates/web-nextjs/apps/web/messages/zh.json +5 -1
- package/dist/templates/web-nextjs/apps/web/package.json +27 -0
- package/dist/templates/web-nextjs/apps/web/postcss.config.mjs +8 -0
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(auth)/login/page.tsx +87 -93
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(auth)/signup/page.tsx +116 -98
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(protected)/dashboard/page.tsx +38 -29
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(protected)/layout.tsx +2 -5
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/layout.tsx +4 -7
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/privacy/page.tsx +23 -0
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/terms/page.tsx +23 -0
- package/dist/templates/web-nextjs/apps/web/src/app/route.ts +13 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/app-sidebar.tsx +188 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/chart-area-interactive.tsx +291 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/data-table.tsx +807 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/data.json +614 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-documents.tsx +92 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-main.tsx +58 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-secondary.tsx +42 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-user.tsx +118 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/page.tsx +40 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/section-cards.tsx +102 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/site-header.tsx +30 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/alert-dialog.tsx +196 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/avatar.tsx +109 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/badge.tsx +48 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/breadcrumb.tsx +109 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/button.tsx +14 -2
- package/dist/templates/web-nextjs/apps/web/src/components/ui/card.tsx +92 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/chart.tsx +374 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/checkbox.tsx +32 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/collapsible.tsx +33 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/command.tsx +184 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/dialog.tsx +158 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/drawer.tsx +135 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/dropdown-menu.tsx +257 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/field.tsx +248 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/input-otp.tsx +77 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/pagination.tsx +127 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/popover.tsx +89 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/progress.tsx +31 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/radio-group.tsx +45 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/scroll-area.tsx +58 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/select.tsx +190 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/separator.tsx +29 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/sheet.tsx +143 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/sidebar.tsx +726 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/skeleton.tsx +13 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/slider.tsx +63 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/sonner.tsx +11 -25
- package/dist/templates/web-nextjs/apps/web/src/components/ui/switch.tsx +35 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/table.tsx +116 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/tabs.tsx +91 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/textarea.tsx +18 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/toggle-group.tsx +83 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/toggle.tsx +47 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/tooltip.tsx +57 -0
- package/dist/templates/web-nextjs/apps/web/src/features/auth/server.ts +15 -0
- package/dist/templates/web-nextjs/apps/web/src/hooks/use-mobile.ts +21 -0
- package/dist/templates/web-nextjs/package.json +10 -0
- package/dist/templates/web-nextjs/packages/openspec-docs-sync/package.json +0 -3
- package/dist/templates/web-nextjs/pnpm-lock.yaml +1561 -96
- package/dist/templates/web-nextjs/pnpm-workspace.yaml +15 -0
- package/dist/templates/web-nextjs/turbo.json +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { IconCirclePlusFilled, IconMail, type Icon } from "@tabler/icons-react"
|
|
4
|
+
|
|
5
|
+
import { Button } from "@/components/ui/button"
|
|
6
|
+
import {
|
|
7
|
+
SidebarGroup,
|
|
8
|
+
SidebarGroupContent,
|
|
9
|
+
SidebarMenu,
|
|
10
|
+
SidebarMenuButton,
|
|
11
|
+
SidebarMenuItem,
|
|
12
|
+
} from "@/components/ui/sidebar"
|
|
13
|
+
|
|
14
|
+
export function NavMain({
|
|
15
|
+
items,
|
|
16
|
+
}: {
|
|
17
|
+
items: {
|
|
18
|
+
title: string
|
|
19
|
+
url: string
|
|
20
|
+
icon?: Icon
|
|
21
|
+
}[]
|
|
22
|
+
}) {
|
|
23
|
+
return (
|
|
24
|
+
<SidebarGroup>
|
|
25
|
+
<SidebarGroupContent className="flex flex-col gap-2">
|
|
26
|
+
<SidebarMenu>
|
|
27
|
+
<SidebarMenuItem className="flex items-center gap-2">
|
|
28
|
+
<SidebarMenuButton
|
|
29
|
+
tooltip="Quick Create"
|
|
30
|
+
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"
|
|
31
|
+
>
|
|
32
|
+
<IconCirclePlusFilled />
|
|
33
|
+
<span>Quick Create</span>
|
|
34
|
+
</SidebarMenuButton>
|
|
35
|
+
<Button
|
|
36
|
+
size="icon"
|
|
37
|
+
className="size-8 group-data-[collapsible=icon]:opacity-0"
|
|
38
|
+
variant="outline"
|
|
39
|
+
>
|
|
40
|
+
<IconMail />
|
|
41
|
+
<span className="sr-only">Inbox</span>
|
|
42
|
+
</Button>
|
|
43
|
+
</SidebarMenuItem>
|
|
44
|
+
</SidebarMenu>
|
|
45
|
+
<SidebarMenu>
|
|
46
|
+
{items.map((item) => (
|
|
47
|
+
<SidebarMenuItem key={item.title}>
|
|
48
|
+
<SidebarMenuButton tooltip={item.title}>
|
|
49
|
+
{item.icon && <item.icon />}
|
|
50
|
+
<span>{item.title}</span>
|
|
51
|
+
</SidebarMenuButton>
|
|
52
|
+
</SidebarMenuItem>
|
|
53
|
+
))}
|
|
54
|
+
</SidebarMenu>
|
|
55
|
+
</SidebarGroupContent>
|
|
56
|
+
</SidebarGroup>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { type Icon } from "@tabler/icons-react"
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
SidebarGroup,
|
|
8
|
+
SidebarGroupContent,
|
|
9
|
+
SidebarMenu,
|
|
10
|
+
SidebarMenuButton,
|
|
11
|
+
SidebarMenuItem,
|
|
12
|
+
} from "@/components/ui/sidebar"
|
|
13
|
+
|
|
14
|
+
export function NavSecondary({
|
|
15
|
+
items,
|
|
16
|
+
...props
|
|
17
|
+
}: {
|
|
18
|
+
items: {
|
|
19
|
+
title: string
|
|
20
|
+
url: string
|
|
21
|
+
icon: Icon
|
|
22
|
+
}[]
|
|
23
|
+
} & React.ComponentPropsWithoutRef<typeof SidebarGroup>) {
|
|
24
|
+
return (
|
|
25
|
+
<SidebarGroup {...props}>
|
|
26
|
+
<SidebarGroupContent>
|
|
27
|
+
<SidebarMenu>
|
|
28
|
+
{items.map((item) => (
|
|
29
|
+
<SidebarMenuItem key={item.title}>
|
|
30
|
+
<SidebarMenuButton asChild>
|
|
31
|
+
<a href={item.url}>
|
|
32
|
+
<item.icon />
|
|
33
|
+
<span>{item.title}</span>
|
|
34
|
+
</a>
|
|
35
|
+
</SidebarMenuButton>
|
|
36
|
+
</SidebarMenuItem>
|
|
37
|
+
))}
|
|
38
|
+
</SidebarMenu>
|
|
39
|
+
</SidebarGroupContent>
|
|
40
|
+
</SidebarGroup>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
IconCreditCard,
|
|
5
|
+
IconDotsVertical,
|
|
6
|
+
IconLogout,
|
|
7
|
+
IconNotification,
|
|
8
|
+
IconUserCircle,
|
|
9
|
+
} from "@tabler/icons-react"
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
Avatar,
|
|
13
|
+
AvatarFallback,
|
|
14
|
+
AvatarImage,
|
|
15
|
+
} from "@/components/ui/avatar"
|
|
16
|
+
import {
|
|
17
|
+
DropdownMenu,
|
|
18
|
+
DropdownMenuContent,
|
|
19
|
+
DropdownMenuGroup,
|
|
20
|
+
DropdownMenuItem,
|
|
21
|
+
DropdownMenuLabel,
|
|
22
|
+
DropdownMenuSeparator,
|
|
23
|
+
DropdownMenuTrigger,
|
|
24
|
+
} from "@/components/ui/dropdown-menu"
|
|
25
|
+
import {
|
|
26
|
+
SidebarMenu,
|
|
27
|
+
SidebarMenuButton,
|
|
28
|
+
SidebarMenuItem,
|
|
29
|
+
useSidebar,
|
|
30
|
+
} from "@/components/ui/sidebar"
|
|
31
|
+
import { signOut } from '@/features/auth'
|
|
32
|
+
|
|
33
|
+
export function NavUser({
|
|
34
|
+
user,
|
|
35
|
+
locale,
|
|
36
|
+
}: {
|
|
37
|
+
user: {
|
|
38
|
+
name: string
|
|
39
|
+
email: string
|
|
40
|
+
avatar: string
|
|
41
|
+
}
|
|
42
|
+
locale: string
|
|
43
|
+
}) {
|
|
44
|
+
const { isMobile } = useSidebar()
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<SidebarMenu>
|
|
48
|
+
<SidebarMenuItem>
|
|
49
|
+
<DropdownMenu>
|
|
50
|
+
<DropdownMenuTrigger asChild>
|
|
51
|
+
<SidebarMenuButton
|
|
52
|
+
size="lg"
|
|
53
|
+
className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
|
|
54
|
+
>
|
|
55
|
+
<Avatar className="h-8 w-8 rounded-lg grayscale">
|
|
56
|
+
<AvatarImage src={user.avatar} alt={user.name} />
|
|
57
|
+
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
|
|
58
|
+
</Avatar>
|
|
59
|
+
<div className="grid flex-1 text-left text-sm leading-tight">
|
|
60
|
+
<span className="truncate font-medium">{user.name}</span>
|
|
61
|
+
<span className="truncate text-xs text-muted-foreground">
|
|
62
|
+
{user.email}
|
|
63
|
+
</span>
|
|
64
|
+
</div>
|
|
65
|
+
<IconDotsVertical className="ml-auto size-4" />
|
|
66
|
+
</SidebarMenuButton>
|
|
67
|
+
</DropdownMenuTrigger>
|
|
68
|
+
<DropdownMenuContent
|
|
69
|
+
className="w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg"
|
|
70
|
+
side={isMobile ? "bottom" : "right"}
|
|
71
|
+
align="end"
|
|
72
|
+
sideOffset={4}
|
|
73
|
+
>
|
|
74
|
+
<DropdownMenuLabel className="p-0 font-normal">
|
|
75
|
+
<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
|
|
76
|
+
<Avatar className="h-8 w-8 rounded-lg">
|
|
77
|
+
<AvatarImage src={user.avatar} alt={user.name} />
|
|
78
|
+
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
|
|
79
|
+
</Avatar>
|
|
80
|
+
<div className="grid flex-1 text-left text-sm leading-tight">
|
|
81
|
+
<span className="truncate font-medium">{user.name}</span>
|
|
82
|
+
<span className="truncate text-xs text-muted-foreground">
|
|
83
|
+
{user.email}
|
|
84
|
+
</span>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
</DropdownMenuLabel>
|
|
88
|
+
<DropdownMenuSeparator />
|
|
89
|
+
<DropdownMenuGroup>
|
|
90
|
+
<DropdownMenuItem>
|
|
91
|
+
<IconUserCircle />
|
|
92
|
+
Account
|
|
93
|
+
</DropdownMenuItem>
|
|
94
|
+
<DropdownMenuItem>
|
|
95
|
+
<IconCreditCard />
|
|
96
|
+
Billing
|
|
97
|
+
</DropdownMenuItem>
|
|
98
|
+
<DropdownMenuItem>
|
|
99
|
+
<IconNotification />
|
|
100
|
+
Notifications
|
|
101
|
+
</DropdownMenuItem>
|
|
102
|
+
</DropdownMenuGroup>
|
|
103
|
+
<DropdownMenuSeparator />
|
|
104
|
+
<DropdownMenuItem asChild>
|
|
105
|
+
<form action={signOut}>
|
|
106
|
+
<input type="hidden" name="locale" value={locale} />
|
|
107
|
+
<button type="submit" className="flex w-full items-center gap-2">
|
|
108
|
+
<IconLogout />
|
|
109
|
+
Log out
|
|
110
|
+
</button>
|
|
111
|
+
</form>
|
|
112
|
+
</DropdownMenuItem>
|
|
113
|
+
</DropdownMenuContent>
|
|
114
|
+
</DropdownMenu>
|
|
115
|
+
</SidebarMenuItem>
|
|
116
|
+
</SidebarMenu>
|
|
117
|
+
)
|
|
118
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { AppSidebar } from "@/components/dashboard/app-sidebar"
|
|
2
|
+
import { ChartAreaInteractive } from "@/components/dashboard/chart-area-interactive"
|
|
3
|
+
import { DataTable } from "@/components/dashboard/data-table"
|
|
4
|
+
import { SectionCards } from "@/components/dashboard/section-cards"
|
|
5
|
+
import { SiteHeader } from "@/components/dashboard/site-header"
|
|
6
|
+
import {
|
|
7
|
+
SidebarInset,
|
|
8
|
+
SidebarProvider,
|
|
9
|
+
} from "@/components/ui/sidebar"
|
|
10
|
+
|
|
11
|
+
import data from "./data.json"
|
|
12
|
+
|
|
13
|
+
export default function Page() {
|
|
14
|
+
return (
|
|
15
|
+
<SidebarProvider
|
|
16
|
+
style={
|
|
17
|
+
{
|
|
18
|
+
"--sidebar-width": "calc(var(--spacing) * 72)",
|
|
19
|
+
"--header-height": "calc(var(--spacing) * 12)",
|
|
20
|
+
} as React.CSSProperties
|
|
21
|
+
}
|
|
22
|
+
>
|
|
23
|
+
<AppSidebar variant="inset" user={{ name: "User", email: "", avatar: "" }} locale="en" />
|
|
24
|
+
<SidebarInset>
|
|
25
|
+
<SiteHeader />
|
|
26
|
+
<div className="flex flex-1 flex-col">
|
|
27
|
+
<div className="@container/main flex flex-1 flex-col gap-2">
|
|
28
|
+
<div className="flex flex-col gap-4 py-4 md:gap-6 md:py-6">
|
|
29
|
+
<SectionCards />
|
|
30
|
+
<div className="px-4 lg:px-6">
|
|
31
|
+
<ChartAreaInteractive />
|
|
32
|
+
</div>
|
|
33
|
+
<DataTable data={data} />
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</SidebarInset>
|
|
38
|
+
</SidebarProvider>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { IconTrendingDown, IconTrendingUp } from "@tabler/icons-react"
|
|
2
|
+
|
|
3
|
+
import { Badge } from "@/components/ui/badge"
|
|
4
|
+
import {
|
|
5
|
+
Card,
|
|
6
|
+
CardAction,
|
|
7
|
+
CardDescription,
|
|
8
|
+
CardFooter,
|
|
9
|
+
CardHeader,
|
|
10
|
+
CardTitle,
|
|
11
|
+
} from "@/components/ui/card"
|
|
12
|
+
|
|
13
|
+
export function SectionCards() {
|
|
14
|
+
return (
|
|
15
|
+
<div className="grid grid-cols-1 gap-4 px-4 *:data-[slot=card]:bg-gradient-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">
|
|
16
|
+
<Card className="@container/card">
|
|
17
|
+
<CardHeader>
|
|
18
|
+
<CardDescription>Total Revenue</CardDescription>
|
|
19
|
+
<CardTitle className="text-2xl font-semibold tabular-nums @[250px]/card:text-3xl">
|
|
20
|
+
$1,250.00
|
|
21
|
+
</CardTitle>
|
|
22
|
+
<CardAction>
|
|
23
|
+
<Badge variant="outline">
|
|
24
|
+
<IconTrendingUp />
|
|
25
|
+
+12.5%
|
|
26
|
+
</Badge>
|
|
27
|
+
</CardAction>
|
|
28
|
+
</CardHeader>
|
|
29
|
+
<CardFooter className="flex-col items-start gap-1.5 text-sm">
|
|
30
|
+
<div className="line-clamp-1 flex gap-2 font-medium">
|
|
31
|
+
Trending up this month <IconTrendingUp className="size-4" />
|
|
32
|
+
</div>
|
|
33
|
+
<div className="text-muted-foreground">
|
|
34
|
+
Visitors for the last 6 months
|
|
35
|
+
</div>
|
|
36
|
+
</CardFooter>
|
|
37
|
+
</Card>
|
|
38
|
+
<Card className="@container/card">
|
|
39
|
+
<CardHeader>
|
|
40
|
+
<CardDescription>New Customers</CardDescription>
|
|
41
|
+
<CardTitle className="text-2xl font-semibold tabular-nums @[250px]/card:text-3xl">
|
|
42
|
+
1,234
|
|
43
|
+
</CardTitle>
|
|
44
|
+
<CardAction>
|
|
45
|
+
<Badge variant="outline">
|
|
46
|
+
<IconTrendingDown />
|
|
47
|
+
-20%
|
|
48
|
+
</Badge>
|
|
49
|
+
</CardAction>
|
|
50
|
+
</CardHeader>
|
|
51
|
+
<CardFooter className="flex-col items-start gap-1.5 text-sm">
|
|
52
|
+
<div className="line-clamp-1 flex gap-2 font-medium">
|
|
53
|
+
Down 20% this period <IconTrendingDown className="size-4" />
|
|
54
|
+
</div>
|
|
55
|
+
<div className="text-muted-foreground">
|
|
56
|
+
Acquisition needs attention
|
|
57
|
+
</div>
|
|
58
|
+
</CardFooter>
|
|
59
|
+
</Card>
|
|
60
|
+
<Card className="@container/card">
|
|
61
|
+
<CardHeader>
|
|
62
|
+
<CardDescription>Active Accounts</CardDescription>
|
|
63
|
+
<CardTitle className="text-2xl font-semibold tabular-nums @[250px]/card:text-3xl">
|
|
64
|
+
45,678
|
|
65
|
+
</CardTitle>
|
|
66
|
+
<CardAction>
|
|
67
|
+
<Badge variant="outline">
|
|
68
|
+
<IconTrendingUp />
|
|
69
|
+
+12.5%
|
|
70
|
+
</Badge>
|
|
71
|
+
</CardAction>
|
|
72
|
+
</CardHeader>
|
|
73
|
+
<CardFooter className="flex-col items-start gap-1.5 text-sm">
|
|
74
|
+
<div className="line-clamp-1 flex gap-2 font-medium">
|
|
75
|
+
Strong user retention <IconTrendingUp className="size-4" />
|
|
76
|
+
</div>
|
|
77
|
+
<div className="text-muted-foreground">Engagement exceed targets</div>
|
|
78
|
+
</CardFooter>
|
|
79
|
+
</Card>
|
|
80
|
+
<Card className="@container/card">
|
|
81
|
+
<CardHeader>
|
|
82
|
+
<CardDescription>Growth Rate</CardDescription>
|
|
83
|
+
<CardTitle className="text-2xl font-semibold tabular-nums @[250px]/card:text-3xl">
|
|
84
|
+
4.5%
|
|
85
|
+
</CardTitle>
|
|
86
|
+
<CardAction>
|
|
87
|
+
<Badge variant="outline">
|
|
88
|
+
<IconTrendingUp />
|
|
89
|
+
+4.5%
|
|
90
|
+
</Badge>
|
|
91
|
+
</CardAction>
|
|
92
|
+
</CardHeader>
|
|
93
|
+
<CardFooter className="flex-col items-start gap-1.5 text-sm">
|
|
94
|
+
<div className="line-clamp-1 flex gap-2 font-medium">
|
|
95
|
+
Steady performance increase <IconTrendingUp className="size-4" />
|
|
96
|
+
</div>
|
|
97
|
+
<div className="text-muted-foreground">Meets growth projections</div>
|
|
98
|
+
</CardFooter>
|
|
99
|
+
</Card>
|
|
100
|
+
</div>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Button } from "@/components/ui/button"
|
|
2
|
+
import { Separator } from "@/components/ui/separator"
|
|
3
|
+
import { SidebarTrigger } from "@/components/ui/sidebar"
|
|
4
|
+
|
|
5
|
+
export function SiteHeader() {
|
|
6
|
+
return (
|
|
7
|
+
<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)">
|
|
8
|
+
<div className="flex w-full items-center gap-1 px-4 lg:gap-2 lg:px-6">
|
|
9
|
+
<SidebarTrigger className="-ml-1" />
|
|
10
|
+
<Separator
|
|
11
|
+
orientation="vertical"
|
|
12
|
+
className="mx-2 data-[orientation=vertical]:h-4"
|
|
13
|
+
/>
|
|
14
|
+
<h1 className="text-base font-medium">Documents</h1>
|
|
15
|
+
<div className="ml-auto flex items-center gap-2">
|
|
16
|
+
<Button variant="ghost" asChild size="sm" className="hidden sm:flex">
|
|
17
|
+
<a
|
|
18
|
+
href="https://github.com/shadcn-ui/ui/tree/main/apps/v4/app/(examples)/dashboard"
|
|
19
|
+
rel="noopener noreferrer"
|
|
20
|
+
target="_blank"
|
|
21
|
+
className="dark:text-foreground"
|
|
22
|
+
>
|
|
23
|
+
GitHub
|
|
24
|
+
</a>
|
|
25
|
+
</Button>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</header>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { AlertDialog as AlertDialogPrimitive } from "radix-ui"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
import { Button } from "@/components/ui/button"
|
|
8
|
+
|
|
9
|
+
function AlertDialog({
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
|
|
12
|
+
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function AlertDialogTrigger({
|
|
16
|
+
...props
|
|
17
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
|
|
18
|
+
return (
|
|
19
|
+
<AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function AlertDialogPortal({
|
|
24
|
+
...props
|
|
25
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
|
|
26
|
+
return (
|
|
27
|
+
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function AlertDialogOverlay({
|
|
32
|
+
className,
|
|
33
|
+
...props
|
|
34
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
|
|
35
|
+
return (
|
|
36
|
+
<AlertDialogPrimitive.Overlay
|
|
37
|
+
data-slot="alert-dialog-overlay"
|
|
38
|
+
className={cn(
|
|
39
|
+
"fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",
|
|
40
|
+
className
|
|
41
|
+
)}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function AlertDialogContent({
|
|
48
|
+
className,
|
|
49
|
+
size = "default",
|
|
50
|
+
...props
|
|
51
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Content> & {
|
|
52
|
+
size?: "default" | "sm"
|
|
53
|
+
}) {
|
|
54
|
+
return (
|
|
55
|
+
<AlertDialogPortal>
|
|
56
|
+
<AlertDialogOverlay />
|
|
57
|
+
<AlertDialogPrimitive.Content
|
|
58
|
+
data-slot="alert-dialog-content"
|
|
59
|
+
data-size={size}
|
|
60
|
+
className={cn(
|
|
61
|
+
"group/alert-dialog-content fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg duration-200 data-[size=sm]:max-w-xs data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[size=default]:sm:max-w-lg",
|
|
62
|
+
className
|
|
63
|
+
)}
|
|
64
|
+
{...props}
|
|
65
|
+
/>
|
|
66
|
+
</AlertDialogPortal>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function AlertDialogHeader({
|
|
71
|
+
className,
|
|
72
|
+
...props
|
|
73
|
+
}: React.ComponentProps<"div">) {
|
|
74
|
+
return (
|
|
75
|
+
<div
|
|
76
|
+
data-slot="alert-dialog-header"
|
|
77
|
+
className={cn(
|
|
78
|
+
"grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]",
|
|
79
|
+
className
|
|
80
|
+
)}
|
|
81
|
+
{...props}
|
|
82
|
+
/>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function AlertDialogFooter({
|
|
87
|
+
className,
|
|
88
|
+
...props
|
|
89
|
+
}: React.ComponentProps<"div">) {
|
|
90
|
+
return (
|
|
91
|
+
<div
|
|
92
|
+
data-slot="alert-dialog-footer"
|
|
93
|
+
className={cn(
|
|
94
|
+
"flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end",
|
|
95
|
+
className
|
|
96
|
+
)}
|
|
97
|
+
{...props}
|
|
98
|
+
/>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function AlertDialogTitle({
|
|
103
|
+
className,
|
|
104
|
+
...props
|
|
105
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
|
|
106
|
+
return (
|
|
107
|
+
<AlertDialogPrimitive.Title
|
|
108
|
+
data-slot="alert-dialog-title"
|
|
109
|
+
className={cn(
|
|
110
|
+
"text-lg font-semibold sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2",
|
|
111
|
+
className
|
|
112
|
+
)}
|
|
113
|
+
{...props}
|
|
114
|
+
/>
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function AlertDialogDescription({
|
|
119
|
+
className,
|
|
120
|
+
...props
|
|
121
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
|
|
122
|
+
return (
|
|
123
|
+
<AlertDialogPrimitive.Description
|
|
124
|
+
data-slot="alert-dialog-description"
|
|
125
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
126
|
+
{...props}
|
|
127
|
+
/>
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function AlertDialogMedia({
|
|
132
|
+
className,
|
|
133
|
+
...props
|
|
134
|
+
}: React.ComponentProps<"div">) {
|
|
135
|
+
return (
|
|
136
|
+
<div
|
|
137
|
+
data-slot="alert-dialog-media"
|
|
138
|
+
className={cn(
|
|
139
|
+
"mb-2 inline-flex size-16 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-8",
|
|
140
|
+
className
|
|
141
|
+
)}
|
|
142
|
+
{...props}
|
|
143
|
+
/>
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function AlertDialogAction({
|
|
148
|
+
className,
|
|
149
|
+
variant = "default",
|
|
150
|
+
size = "default",
|
|
151
|
+
...props
|
|
152
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Action> &
|
|
153
|
+
Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
|
|
154
|
+
return (
|
|
155
|
+
<Button variant={variant} size={size} asChild>
|
|
156
|
+
<AlertDialogPrimitive.Action
|
|
157
|
+
data-slot="alert-dialog-action"
|
|
158
|
+
className={cn(className)}
|
|
159
|
+
{...props}
|
|
160
|
+
/>
|
|
161
|
+
</Button>
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function AlertDialogCancel({
|
|
166
|
+
className,
|
|
167
|
+
variant = "outline",
|
|
168
|
+
size = "default",
|
|
169
|
+
...props
|
|
170
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel> &
|
|
171
|
+
Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
|
|
172
|
+
return (
|
|
173
|
+
<Button variant={variant} size={size} asChild>
|
|
174
|
+
<AlertDialogPrimitive.Cancel
|
|
175
|
+
data-slot="alert-dialog-cancel"
|
|
176
|
+
className={cn(className)}
|
|
177
|
+
{...props}
|
|
178
|
+
/>
|
|
179
|
+
</Button>
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export {
|
|
184
|
+
AlertDialog,
|
|
185
|
+
AlertDialogAction,
|
|
186
|
+
AlertDialogCancel,
|
|
187
|
+
AlertDialogContent,
|
|
188
|
+
AlertDialogDescription,
|
|
189
|
+
AlertDialogFooter,
|
|
190
|
+
AlertDialogHeader,
|
|
191
|
+
AlertDialogMedia,
|
|
192
|
+
AlertDialogOverlay,
|
|
193
|
+
AlertDialogPortal,
|
|
194
|
+
AlertDialogTitle,
|
|
195
|
+
AlertDialogTrigger,
|
|
196
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { Avatar as AvatarPrimitive } from "radix-ui"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
|
|
8
|
+
function Avatar({
|
|
9
|
+
className,
|
|
10
|
+
size = "default",
|
|
11
|
+
...props
|
|
12
|
+
}: React.ComponentProps<typeof AvatarPrimitive.Root> & {
|
|
13
|
+
size?: "default" | "sm" | "lg"
|
|
14
|
+
}) {
|
|
15
|
+
return (
|
|
16
|
+
<AvatarPrimitive.Root
|
|
17
|
+
data-slot="avatar"
|
|
18
|
+
data-size={size}
|
|
19
|
+
className={cn(
|
|
20
|
+
"group/avatar relative flex size-8 shrink-0 overflow-hidden rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6",
|
|
21
|
+
className
|
|
22
|
+
)}
|
|
23
|
+
{...props}
|
|
24
|
+
/>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function AvatarImage({
|
|
29
|
+
className,
|
|
30
|
+
...props
|
|
31
|
+
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
|
|
32
|
+
return (
|
|
33
|
+
<AvatarPrimitive.Image
|
|
34
|
+
data-slot="avatar-image"
|
|
35
|
+
className={cn("aspect-square size-full", className)}
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function AvatarFallback({
|
|
42
|
+
className,
|
|
43
|
+
...props
|
|
44
|
+
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
|
|
45
|
+
return (
|
|
46
|
+
<AvatarPrimitive.Fallback
|
|
47
|
+
data-slot="avatar-fallback"
|
|
48
|
+
className={cn(
|
|
49
|
+
"flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=sm]/avatar:text-xs",
|
|
50
|
+
className
|
|
51
|
+
)}
|
|
52
|
+
{...props}
|
|
53
|
+
/>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) {
|
|
58
|
+
return (
|
|
59
|
+
<span
|
|
60
|
+
data-slot="avatar-badge"
|
|
61
|
+
className={cn(
|
|
62
|
+
"absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground ring-2 ring-background select-none",
|
|
63
|
+
"group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden",
|
|
64
|
+
"group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2",
|
|
65
|
+
"group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2",
|
|
66
|
+
className
|
|
67
|
+
)}
|
|
68
|
+
{...props}
|
|
69
|
+
/>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
74
|
+
return (
|
|
75
|
+
<div
|
|
76
|
+
data-slot="avatar-group"
|
|
77
|
+
className={cn(
|
|
78
|
+
"group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background",
|
|
79
|
+
className
|
|
80
|
+
)}
|
|
81
|
+
{...props}
|
|
82
|
+
/>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function AvatarGroupCount({
|
|
87
|
+
className,
|
|
88
|
+
...props
|
|
89
|
+
}: React.ComponentProps<"div">) {
|
|
90
|
+
return (
|
|
91
|
+
<div
|
|
92
|
+
data-slot="avatar-group-count"
|
|
93
|
+
className={cn(
|
|
94
|
+
"relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3",
|
|
95
|
+
className
|
|
96
|
+
)}
|
|
97
|
+
{...props}
|
|
98
|
+
/>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export {
|
|
103
|
+
Avatar,
|
|
104
|
+
AvatarImage,
|
|
105
|
+
AvatarFallback,
|
|
106
|
+
AvatarBadge,
|
|
107
|
+
AvatarGroup,
|
|
108
|
+
AvatarGroupCount,
|
|
109
|
+
}
|