@getjack/jack 0.1.32 → 0.1.34

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.
Files changed (196) hide show
  1. package/package.json +1 -1
  2. package/src/commands/deploys.ts +95 -0
  3. package/src/commands/link.ts +8 -0
  4. package/src/commands/mcp.ts +179 -4
  5. package/src/commands/rollback.ts +53 -0
  6. package/src/commands/secrets.ts +3 -1
  7. package/src/commands/services.ts +11 -1
  8. package/src/commands/ship.ts +3 -1
  9. package/src/commands/tokens.ts +16 -1
  10. package/src/commands/whoami.ts +43 -8
  11. package/src/index.ts +16 -0
  12. package/src/lib/agent-files.ts +54 -4
  13. package/src/lib/agent-integration.ts +4 -166
  14. package/src/lib/claude-hooks-installer.ts +55 -0
  15. package/src/lib/control-plane.ts +78 -40
  16. package/src/lib/crypto.ts +84 -0
  17. package/src/lib/debug.ts +2 -1
  18. package/src/lib/deploy-upload.ts +13 -3
  19. package/src/lib/hooks.ts +4 -3
  20. package/src/lib/managed-deploy.ts +12 -9
  21. package/src/lib/project-link.ts +6 -0
  22. package/src/lib/project-operations.ts +92 -30
  23. package/src/lib/prompts.ts +2 -2
  24. package/src/lib/telemetry.ts +2 -0
  25. package/src/mcp/README.md +1 -1
  26. package/src/mcp/resources/index.ts +1 -16
  27. package/src/mcp/server.ts +23 -0
  28. package/src/mcp/tools/index.ts +133 -17
  29. package/src/mcp/types.ts +1 -0
  30. package/src/mcp/utils.ts +2 -1
  31. package/src/templates/index.ts +25 -73
  32. package/templates/CLAUDE.md +62 -0
  33. package/templates/ai-chat/.jack.json +10 -5
  34. package/templates/ai-chat/bun.lock +50 -1
  35. package/templates/ai-chat/package.json +5 -0
  36. package/templates/ai-chat/public/app.js +73 -0
  37. package/templates/ai-chat/public/index.html +14 -197
  38. package/templates/ai-chat/schema.sql +14 -0
  39. package/templates/ai-chat/src/index.ts +86 -102
  40. package/templates/ai-chat/wrangler.jsonc +8 -1
  41. package/templates/cron/.jack.json +66 -0
  42. package/templates/cron/bun.lock +23 -0
  43. package/templates/cron/package.json +16 -0
  44. package/templates/cron/schema.sql +24 -0
  45. package/templates/cron/src/index.ts +117 -0
  46. package/templates/cron/src/jobs.ts +139 -0
  47. package/templates/cron/src/webhooks.ts +95 -0
  48. package/templates/cron/tsconfig.json +17 -0
  49. package/templates/cron/wrangler.jsonc +11 -0
  50. package/templates/miniapp/.jack.json +1 -1
  51. package/templates/nextjs/.jack.json +1 -1
  52. package/templates/nextjs-auth/.jack.json +44 -0
  53. package/templates/nextjs-auth/app/api/auth/[...all]/route.ts +11 -0
  54. package/templates/nextjs-auth/app/dashboard/loading.tsx +53 -0
  55. package/templates/nextjs-auth/app/dashboard/page.tsx +73 -0
  56. package/templates/nextjs-auth/app/error.tsx +44 -0
  57. package/templates/nextjs-auth/app/globals.css +1 -0
  58. package/templates/nextjs-auth/app/health/route.ts +3 -0
  59. package/templates/nextjs-auth/app/layout.tsx +24 -0
  60. package/templates/nextjs-auth/app/login/page.tsx +10 -0
  61. package/templates/nextjs-auth/app/page.tsx +86 -0
  62. package/templates/nextjs-auth/app/signup/page.tsx +10 -0
  63. package/templates/nextjs-auth/bun.lock +1065 -0
  64. package/templates/nextjs-auth/cloudflare-env.d.ts +8 -0
  65. package/templates/nextjs-auth/components/auth-form.tsx +191 -0
  66. package/templates/nextjs-auth/components/header.tsx +50 -0
  67. package/templates/nextjs-auth/components/user-menu.tsx +23 -0
  68. package/templates/nextjs-auth/lib/auth-client.ts +3 -0
  69. package/templates/nextjs-auth/lib/auth.ts +43 -0
  70. package/templates/nextjs-auth/lib/utils.ts +6 -0
  71. package/templates/nextjs-auth/middleware.ts +33 -0
  72. package/templates/nextjs-auth/next.config.ts +8 -0
  73. package/templates/nextjs-auth/open-next.config.ts +6 -0
  74. package/templates/nextjs-auth/package.json +33 -0
  75. package/templates/nextjs-auth/postcss.config.mjs +8 -0
  76. package/templates/nextjs-auth/schema.sql +49 -0
  77. package/templates/nextjs-auth/tsconfig.json +28 -0
  78. package/templates/nextjs-auth/wrangler.jsonc +23 -0
  79. package/templates/nextjs-clerk/.jack.json +54 -0
  80. package/templates/nextjs-clerk/app/dashboard/page.tsx +69 -0
  81. package/templates/nextjs-clerk/app/globals.css +1 -0
  82. package/templates/nextjs-clerk/app/health/route.ts +3 -0
  83. package/templates/nextjs-clerk/app/layout.tsx +28 -0
  84. package/templates/nextjs-clerk/app/page.tsx +86 -0
  85. package/templates/nextjs-clerk/app/sign-in/[[...sign-in]]/page.tsx +9 -0
  86. package/templates/nextjs-clerk/app/sign-up/[[...sign-up]]/page.tsx +9 -0
  87. package/templates/nextjs-clerk/bun.lock +1055 -0
  88. package/templates/nextjs-clerk/cloudflare-env.d.ts +3 -0
  89. package/templates/nextjs-clerk/components/header.tsx +40 -0
  90. package/templates/nextjs-clerk/lib/utils.ts +6 -0
  91. package/templates/nextjs-clerk/middleware.ts +18 -0
  92. package/templates/nextjs-clerk/next.config.ts +8 -0
  93. package/templates/nextjs-clerk/open-next.config.ts +6 -0
  94. package/templates/nextjs-clerk/package.json +31 -0
  95. package/templates/nextjs-clerk/postcss.config.mjs +8 -0
  96. package/templates/nextjs-clerk/tsconfig.json +28 -0
  97. package/templates/nextjs-clerk/wrangler.jsonc +17 -0
  98. package/templates/nextjs-shadcn/.jack.json +34 -0
  99. package/templates/nextjs-shadcn/app/dashboard/data.json +614 -0
  100. package/templates/nextjs-shadcn/app/dashboard/page.tsx +55 -0
  101. package/templates/nextjs-shadcn/app/globals.css +126 -0
  102. package/templates/nextjs-shadcn/app/health/route.ts +3 -0
  103. package/templates/nextjs-shadcn/app/layout.tsx +24 -0
  104. package/templates/nextjs-shadcn/app/login/page.tsx +19 -0
  105. package/templates/nextjs-shadcn/app/page.tsx +180 -0
  106. package/templates/nextjs-shadcn/app/showcase.tsx +1262 -0
  107. package/templates/nextjs-shadcn/bun.lock +1789 -0
  108. package/templates/nextjs-shadcn/cloudflare-env.d.ts +4 -0
  109. package/templates/nextjs-shadcn/components/app-sidebar.tsx +175 -0
  110. package/templates/nextjs-shadcn/components/chart-area-interactive.tsx +291 -0
  111. package/templates/nextjs-shadcn/components/data-table.tsx +807 -0
  112. package/templates/nextjs-shadcn/components/login-form.tsx +95 -0
  113. package/templates/nextjs-shadcn/components/nav-documents.tsx +92 -0
  114. package/templates/nextjs-shadcn/components/nav-main.tsx +73 -0
  115. package/templates/nextjs-shadcn/components/nav-projects.tsx +89 -0
  116. package/templates/nextjs-shadcn/components/nav-secondary.tsx +42 -0
  117. package/templates/nextjs-shadcn/components/nav-user.tsx +114 -0
  118. package/templates/nextjs-shadcn/components/section-cards.tsx +102 -0
  119. package/templates/nextjs-shadcn/components/site-header.tsx +30 -0
  120. package/templates/nextjs-shadcn/components/team-switcher.tsx +91 -0
  121. package/templates/nextjs-shadcn/components/ui/accordion.tsx +66 -0
  122. package/templates/nextjs-shadcn/components/ui/alert-dialog.tsx +196 -0
  123. package/templates/nextjs-shadcn/components/ui/alert.tsx +66 -0
  124. package/templates/nextjs-shadcn/components/ui/aspect-ratio.tsx +11 -0
  125. package/templates/nextjs-shadcn/components/ui/avatar.tsx +109 -0
  126. package/templates/nextjs-shadcn/components/ui/badge.tsx +48 -0
  127. package/templates/nextjs-shadcn/components/ui/breadcrumb.tsx +109 -0
  128. package/templates/nextjs-shadcn/components/ui/button-group.tsx +83 -0
  129. package/templates/nextjs-shadcn/components/ui/button.tsx +64 -0
  130. package/templates/nextjs-shadcn/components/ui/calendar.tsx +220 -0
  131. package/templates/nextjs-shadcn/components/ui/card.tsx +92 -0
  132. package/templates/nextjs-shadcn/components/ui/carousel.tsx +241 -0
  133. package/templates/nextjs-shadcn/components/ui/chart.tsx +357 -0
  134. package/templates/nextjs-shadcn/components/ui/checkbox.tsx +32 -0
  135. package/templates/nextjs-shadcn/components/ui/collapsible.tsx +33 -0
  136. package/templates/nextjs-shadcn/components/ui/combobox.tsx +310 -0
  137. package/templates/nextjs-shadcn/components/ui/command.tsx +184 -0
  138. package/templates/nextjs-shadcn/components/ui/context-menu.tsx +252 -0
  139. package/templates/nextjs-shadcn/components/ui/dialog.tsx +158 -0
  140. package/templates/nextjs-shadcn/components/ui/direction.tsx +22 -0
  141. package/templates/nextjs-shadcn/components/ui/drawer.tsx +135 -0
  142. package/templates/nextjs-shadcn/components/ui/dropdown-menu.tsx +257 -0
  143. package/templates/nextjs-shadcn/components/ui/empty.tsx +104 -0
  144. package/templates/nextjs-shadcn/components/ui/field.tsx +248 -0
  145. package/templates/nextjs-shadcn/components/ui/form.tsx +167 -0
  146. package/templates/nextjs-shadcn/components/ui/hover-card.tsx +44 -0
  147. package/templates/nextjs-shadcn/components/ui/input-group.tsx +170 -0
  148. package/templates/nextjs-shadcn/components/ui/input-otp.tsx +77 -0
  149. package/templates/nextjs-shadcn/components/ui/input.tsx +21 -0
  150. package/templates/nextjs-shadcn/components/ui/item.tsx +193 -0
  151. package/templates/nextjs-shadcn/components/ui/kbd.tsx +28 -0
  152. package/templates/nextjs-shadcn/components/ui/label.tsx +24 -0
  153. package/templates/nextjs-shadcn/components/ui/menubar.tsx +276 -0
  154. package/templates/nextjs-shadcn/components/ui/native-select.tsx +53 -0
  155. package/templates/nextjs-shadcn/components/ui/navigation-menu.tsx +168 -0
  156. package/templates/nextjs-shadcn/components/ui/pagination.tsx +127 -0
  157. package/templates/nextjs-shadcn/components/ui/popover.tsx +89 -0
  158. package/templates/nextjs-shadcn/components/ui/progress.tsx +31 -0
  159. package/templates/nextjs-shadcn/components/ui/radio-group.tsx +45 -0
  160. package/templates/nextjs-shadcn/components/ui/resizable.tsx +53 -0
  161. package/templates/nextjs-shadcn/components/ui/scroll-area.tsx +58 -0
  162. package/templates/nextjs-shadcn/components/ui/select.tsx +190 -0
  163. package/templates/nextjs-shadcn/components/ui/separator.tsx +28 -0
  164. package/templates/nextjs-shadcn/components/ui/sheet.tsx +143 -0
  165. package/templates/nextjs-shadcn/components/ui/sidebar.tsx +726 -0
  166. package/templates/nextjs-shadcn/components/ui/skeleton.tsx +13 -0
  167. package/templates/nextjs-shadcn/components/ui/slider.tsx +63 -0
  168. package/templates/nextjs-shadcn/components/ui/sonner.tsx +40 -0
  169. package/templates/nextjs-shadcn/components/ui/spinner.tsx +16 -0
  170. package/templates/nextjs-shadcn/components/ui/switch.tsx +35 -0
  171. package/templates/nextjs-shadcn/components/ui/table.tsx +116 -0
  172. package/templates/nextjs-shadcn/components/ui/tabs.tsx +91 -0
  173. package/templates/nextjs-shadcn/components/ui/textarea.tsx +18 -0
  174. package/templates/nextjs-shadcn/components/ui/toggle-group.tsx +83 -0
  175. package/templates/nextjs-shadcn/components/ui/toggle.tsx +47 -0
  176. package/templates/nextjs-shadcn/components/ui/tooltip.tsx +57 -0
  177. package/templates/nextjs-shadcn/components.json +23 -0
  178. package/templates/nextjs-shadcn/hooks/use-mobile.ts +19 -0
  179. package/templates/nextjs-shadcn/lib/utils.ts +6 -0
  180. package/templates/nextjs-shadcn/next-env.d.ts +6 -0
  181. package/templates/nextjs-shadcn/next.config.ts +8 -0
  182. package/templates/nextjs-shadcn/open-next.config.ts +6 -0
  183. package/templates/nextjs-shadcn/package.json +55 -0
  184. package/templates/nextjs-shadcn/postcss.config.mjs +8 -0
  185. package/templates/nextjs-shadcn/tsconfig.json +28 -0
  186. package/templates/nextjs-shadcn/wrangler.jsonc +23 -0
  187. package/templates/resend/.jack.json +64 -0
  188. package/templates/resend/bun.lock +23 -0
  189. package/templates/resend/package.json +16 -0
  190. package/templates/resend/schema.sql +13 -0
  191. package/templates/resend/src/email.ts +165 -0
  192. package/templates/resend/src/index.ts +108 -0
  193. package/templates/resend/tsconfig.json +17 -0
  194. package/templates/resend/wrangler.jsonc +11 -0
  195. package/templates/saas/.jack.json +1 -1
  196. package/templates/ai-chat/public/chat.js +0 -149
@@ -0,0 +1,95 @@
1
+ import { cn } from "@/lib/utils"
2
+ import { Button } from "@/components/ui/button"
3
+ import {
4
+ Card,
5
+ CardContent,
6
+ CardDescription,
7
+ CardHeader,
8
+ CardTitle,
9
+ } from "@/components/ui/card"
10
+ import {
11
+ Field,
12
+ FieldDescription,
13
+ FieldGroup,
14
+ FieldLabel,
15
+ FieldSeparator,
16
+ } from "@/components/ui/field"
17
+ import { Input } from "@/components/ui/input"
18
+
19
+ export function LoginForm({
20
+ className,
21
+ ...props
22
+ }: React.ComponentProps<"div">) {
23
+ return (
24
+ <div className={cn("flex flex-col gap-6", className)} {...props}>
25
+ <Card>
26
+ <CardHeader className="text-center">
27
+ <CardTitle className="text-xl">Welcome back</CardTitle>
28
+ <CardDescription>
29
+ Login with your Apple or Google account
30
+ </CardDescription>
31
+ </CardHeader>
32
+ <CardContent>
33
+ <form>
34
+ <FieldGroup>
35
+ <Field>
36
+ <Button variant="outline" type="button">
37
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
38
+ <path
39
+ d="M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701"
40
+ fill="currentColor"
41
+ />
42
+ </svg>
43
+ Login with Apple
44
+ </Button>
45
+ <Button variant="outline" type="button">
46
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
47
+ <path
48
+ d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
49
+ fill="currentColor"
50
+ />
51
+ </svg>
52
+ Login with Google
53
+ </Button>
54
+ </Field>
55
+ <FieldSeparator className="*:data-[slot=field-separator-content]:bg-card">
56
+ Or continue with
57
+ </FieldSeparator>
58
+ <Field>
59
+ <FieldLabel htmlFor="email">Email</FieldLabel>
60
+ <Input
61
+ id="email"
62
+ type="email"
63
+ placeholder="m@example.com"
64
+ required
65
+ />
66
+ </Field>
67
+ <Field>
68
+ <div className="flex items-center">
69
+ <FieldLabel htmlFor="password">Password</FieldLabel>
70
+ <a
71
+ href="#"
72
+ className="ml-auto text-sm underline-offset-4 hover:underline"
73
+ >
74
+ Forgot your password?
75
+ </a>
76
+ </div>
77
+ <Input id="password" type="password" required />
78
+ </Field>
79
+ <Field>
80
+ <Button type="submit">Login</Button>
81
+ <FieldDescription className="text-center">
82
+ Don&apos;t have an account? <a href="#">Sign up</a>
83
+ </FieldDescription>
84
+ </Field>
85
+ </FieldGroup>
86
+ </form>
87
+ </CardContent>
88
+ </Card>
89
+ <FieldDescription className="px-6 text-center">
90
+ By clicking continue, you agree to our <a href="#">Terms of Service</a>{" "}
91
+ and <a href="#">Privacy Policy</a>.
92
+ </FieldDescription>
93
+ </div>
94
+ )
95
+ }
@@ -0,0 +1,92 @@
1
+ "use client"
2
+
3
+ import {
4
+ IconDots,
5
+ IconFolder,
6
+ IconShare3,
7
+ IconTrash,
8
+ type Icon,
9
+ } from "@tabler/icons-react"
10
+
11
+ import {
12
+ DropdownMenu,
13
+ DropdownMenuContent,
14
+ DropdownMenuItem,
15
+ DropdownMenuSeparator,
16
+ DropdownMenuTrigger,
17
+ } from "@/components/ui/dropdown-menu"
18
+ import {
19
+ SidebarGroup,
20
+ SidebarGroupLabel,
21
+ SidebarMenu,
22
+ SidebarMenuAction,
23
+ SidebarMenuButton,
24
+ SidebarMenuItem,
25
+ useSidebar,
26
+ } from "@/components/ui/sidebar"
27
+
28
+ export function NavDocuments({
29
+ items,
30
+ }: {
31
+ items: {
32
+ name: string
33
+ url: string
34
+ icon: Icon
35
+ }[]
36
+ }) {
37
+ const { isMobile } = useSidebar()
38
+
39
+ return (
40
+ <SidebarGroup className="group-data-[collapsible=icon]:hidden">
41
+ <SidebarGroupLabel>Documents</SidebarGroupLabel>
42
+ <SidebarMenu>
43
+ {items.map((item) => (
44
+ <SidebarMenuItem key={item.name}>
45
+ <SidebarMenuButton asChild>
46
+ <a href={item.url}>
47
+ <item.icon />
48
+ <span>{item.name}</span>
49
+ </a>
50
+ </SidebarMenuButton>
51
+ <DropdownMenu>
52
+ <DropdownMenuTrigger asChild>
53
+ <SidebarMenuAction
54
+ showOnHover
55
+ className="data-[state=open]:bg-accent rounded-sm"
56
+ >
57
+ <IconDots />
58
+ <span className="sr-only">More</span>
59
+ </SidebarMenuAction>
60
+ </DropdownMenuTrigger>
61
+ <DropdownMenuContent
62
+ className="w-24 rounded-lg"
63
+ side={isMobile ? "bottom" : "right"}
64
+ align={isMobile ? "end" : "start"}
65
+ >
66
+ <DropdownMenuItem>
67
+ <IconFolder />
68
+ <span>Open</span>
69
+ </DropdownMenuItem>
70
+ <DropdownMenuItem>
71
+ <IconShare3 />
72
+ <span>Share</span>
73
+ </DropdownMenuItem>
74
+ <DropdownMenuSeparator />
75
+ <DropdownMenuItem variant="destructive">
76
+ <IconTrash />
77
+ <span>Delete</span>
78
+ </DropdownMenuItem>
79
+ </DropdownMenuContent>
80
+ </DropdownMenu>
81
+ </SidebarMenuItem>
82
+ ))}
83
+ <SidebarMenuItem>
84
+ <SidebarMenuButton className="text-sidebar-foreground/70">
85
+ <IconDots className="text-sidebar-foreground/70" />
86
+ <span>More</span>
87
+ </SidebarMenuButton>
88
+ </SidebarMenuItem>
89
+ </SidebarMenu>
90
+ </SidebarGroup>
91
+ )
92
+ }
@@ -0,0 +1,73 @@
1
+ "use client"
2
+
3
+ import { ChevronRight, type LucideIcon } from "lucide-react"
4
+
5
+ import {
6
+ Collapsible,
7
+ CollapsibleContent,
8
+ CollapsibleTrigger,
9
+ } from "@/components/ui/collapsible"
10
+ import {
11
+ SidebarGroup,
12
+ SidebarGroupLabel,
13
+ SidebarMenu,
14
+ SidebarMenuButton,
15
+ SidebarMenuItem,
16
+ SidebarMenuSub,
17
+ SidebarMenuSubButton,
18
+ SidebarMenuSubItem,
19
+ } from "@/components/ui/sidebar"
20
+
21
+ export function NavMain({
22
+ items,
23
+ }: {
24
+ items: {
25
+ title: string
26
+ url: string
27
+ icon?: LucideIcon
28
+ isActive?: boolean
29
+ items?: {
30
+ title: string
31
+ url: string
32
+ }[]
33
+ }[]
34
+ }) {
35
+ return (
36
+ <SidebarGroup>
37
+ <SidebarGroupLabel>Platform</SidebarGroupLabel>
38
+ <SidebarMenu>
39
+ {items.map((item) => (
40
+ <Collapsible
41
+ key={item.title}
42
+ asChild
43
+ defaultOpen={item.isActive}
44
+ className="group/collapsible"
45
+ >
46
+ <SidebarMenuItem>
47
+ <CollapsibleTrigger asChild>
48
+ <SidebarMenuButton tooltip={item.title}>
49
+ {item.icon && <item.icon />}
50
+ <span>{item.title}</span>
51
+ <ChevronRight className="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
52
+ </SidebarMenuButton>
53
+ </CollapsibleTrigger>
54
+ <CollapsibleContent>
55
+ <SidebarMenuSub>
56
+ {item.items?.map((subItem) => (
57
+ <SidebarMenuSubItem key={subItem.title}>
58
+ <SidebarMenuSubButton asChild>
59
+ <a href={subItem.url}>
60
+ <span>{subItem.title}</span>
61
+ </a>
62
+ </SidebarMenuSubButton>
63
+ </SidebarMenuSubItem>
64
+ ))}
65
+ </SidebarMenuSub>
66
+ </CollapsibleContent>
67
+ </SidebarMenuItem>
68
+ </Collapsible>
69
+ ))}
70
+ </SidebarMenu>
71
+ </SidebarGroup>
72
+ )
73
+ }
@@ -0,0 +1,89 @@
1
+ "use client"
2
+
3
+ import {
4
+ Folder,
5
+ Forward,
6
+ MoreHorizontal,
7
+ Trash2,
8
+ type LucideIcon,
9
+ } from "lucide-react"
10
+
11
+ import {
12
+ DropdownMenu,
13
+ DropdownMenuContent,
14
+ DropdownMenuItem,
15
+ DropdownMenuSeparator,
16
+ DropdownMenuTrigger,
17
+ } from "@/components/ui/dropdown-menu"
18
+ import {
19
+ SidebarGroup,
20
+ SidebarGroupLabel,
21
+ SidebarMenu,
22
+ SidebarMenuAction,
23
+ SidebarMenuButton,
24
+ SidebarMenuItem,
25
+ useSidebar,
26
+ } from "@/components/ui/sidebar"
27
+
28
+ export function NavProjects({
29
+ projects,
30
+ }: {
31
+ projects: {
32
+ name: string
33
+ url: string
34
+ icon: LucideIcon
35
+ }[]
36
+ }) {
37
+ const { isMobile } = useSidebar()
38
+
39
+ return (
40
+ <SidebarGroup className="group-data-[collapsible=icon]:hidden">
41
+ <SidebarGroupLabel>Projects</SidebarGroupLabel>
42
+ <SidebarMenu>
43
+ {projects.map((item) => (
44
+ <SidebarMenuItem key={item.name}>
45
+ <SidebarMenuButton asChild>
46
+ <a href={item.url}>
47
+ <item.icon />
48
+ <span>{item.name}</span>
49
+ </a>
50
+ </SidebarMenuButton>
51
+ <DropdownMenu>
52
+ <DropdownMenuTrigger asChild>
53
+ <SidebarMenuAction showOnHover>
54
+ <MoreHorizontal />
55
+ <span className="sr-only">More</span>
56
+ </SidebarMenuAction>
57
+ </DropdownMenuTrigger>
58
+ <DropdownMenuContent
59
+ className="w-48 rounded-lg"
60
+ side={isMobile ? "bottom" : "right"}
61
+ align={isMobile ? "end" : "start"}
62
+ >
63
+ <DropdownMenuItem>
64
+ <Folder className="text-muted-foreground" />
65
+ <span>View Project</span>
66
+ </DropdownMenuItem>
67
+ <DropdownMenuItem>
68
+ <Forward className="text-muted-foreground" />
69
+ <span>Share Project</span>
70
+ </DropdownMenuItem>
71
+ <DropdownMenuSeparator />
72
+ <DropdownMenuItem>
73
+ <Trash2 className="text-muted-foreground" />
74
+ <span>Delete Project</span>
75
+ </DropdownMenuItem>
76
+ </DropdownMenuContent>
77
+ </DropdownMenu>
78
+ </SidebarMenuItem>
79
+ ))}
80
+ <SidebarMenuItem>
81
+ <SidebarMenuButton className="text-sidebar-foreground/70">
82
+ <MoreHorizontal className="text-sidebar-foreground/70" />
83
+ <span>More</span>
84
+ </SidebarMenuButton>
85
+ </SidebarMenuItem>
86
+ </SidebarMenu>
87
+ </SidebarGroup>
88
+ )
89
+ }
@@ -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,114 @@
1
+ "use client"
2
+
3
+ import {
4
+ BadgeCheck,
5
+ Bell,
6
+ ChevronsUpDown,
7
+ CreditCard,
8
+ LogOut,
9
+ Sparkles,
10
+ } from "lucide-react"
11
+
12
+ import {
13
+ Avatar,
14
+ AvatarFallback,
15
+ AvatarImage,
16
+ } from "@/components/ui/avatar"
17
+ import {
18
+ DropdownMenu,
19
+ DropdownMenuContent,
20
+ DropdownMenuGroup,
21
+ DropdownMenuItem,
22
+ DropdownMenuLabel,
23
+ DropdownMenuSeparator,
24
+ DropdownMenuTrigger,
25
+ } from "@/components/ui/dropdown-menu"
26
+ import {
27
+ SidebarMenu,
28
+ SidebarMenuButton,
29
+ SidebarMenuItem,
30
+ useSidebar,
31
+ } from "@/components/ui/sidebar"
32
+
33
+ export function NavUser({
34
+ user,
35
+ }: {
36
+ user: {
37
+ name: string
38
+ email: string
39
+ avatar: string
40
+ }
41
+ }) {
42
+ const { isMobile } = useSidebar()
43
+
44
+ return (
45
+ <SidebarMenu>
46
+ <SidebarMenuItem>
47
+ <DropdownMenu>
48
+ <DropdownMenuTrigger asChild>
49
+ <SidebarMenuButton
50
+ size="lg"
51
+ className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
52
+ >
53
+ <Avatar className="h-8 w-8 rounded-lg">
54
+ <AvatarImage src={user.avatar} alt={user.name} />
55
+ <AvatarFallback className="rounded-lg">CN</AvatarFallback>
56
+ </Avatar>
57
+ <div className="grid flex-1 text-left text-sm leading-tight">
58
+ <span className="truncate font-medium">{user.name}</span>
59
+ <span className="truncate text-xs">{user.email}</span>
60
+ </div>
61
+ <ChevronsUpDown className="ml-auto size-4" />
62
+ </SidebarMenuButton>
63
+ </DropdownMenuTrigger>
64
+ <DropdownMenuContent
65
+ className="w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg"
66
+ side={isMobile ? "bottom" : "right"}
67
+ align="end"
68
+ sideOffset={4}
69
+ >
70
+ <DropdownMenuLabel className="p-0 font-normal">
71
+ <div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
72
+ <Avatar className="h-8 w-8 rounded-lg">
73
+ <AvatarImage src={user.avatar} alt={user.name} />
74
+ <AvatarFallback className="rounded-lg">CN</AvatarFallback>
75
+ </Avatar>
76
+ <div className="grid flex-1 text-left text-sm leading-tight">
77
+ <span className="truncate font-medium">{user.name}</span>
78
+ <span className="truncate text-xs">{user.email}</span>
79
+ </div>
80
+ </div>
81
+ </DropdownMenuLabel>
82
+ <DropdownMenuSeparator />
83
+ <DropdownMenuGroup>
84
+ <DropdownMenuItem>
85
+ <Sparkles />
86
+ Upgrade to Pro
87
+ </DropdownMenuItem>
88
+ </DropdownMenuGroup>
89
+ <DropdownMenuSeparator />
90
+ <DropdownMenuGroup>
91
+ <DropdownMenuItem>
92
+ <BadgeCheck />
93
+ Account
94
+ </DropdownMenuItem>
95
+ <DropdownMenuItem>
96
+ <CreditCard />
97
+ Billing
98
+ </DropdownMenuItem>
99
+ <DropdownMenuItem>
100
+ <Bell />
101
+ Notifications
102
+ </DropdownMenuItem>
103
+ </DropdownMenuGroup>
104
+ <DropdownMenuSeparator />
105
+ <DropdownMenuItem>
106
+ <LogOut />
107
+ Log out
108
+ </DropdownMenuItem>
109
+ </DropdownMenuContent>
110
+ </DropdownMenu>
111
+ </SidebarMenuItem>
112
+ </SidebarMenu>
113
+ )
114
+ }
@@ -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="*:data-[slot=card]:from-primary/5 *:data-[slot=card]:to-card dark:*:data-[slot=card]:bg-card grid grid-cols-1 gap-4 px-4 *:data-[slot=card]:bg-gradient-to-t *:data-[slot=card]:shadow-xs lg:px-6 @xl/main:grid-cols-2 @5xl/main:grid-cols-4">
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
+ }