@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.
- package/package.json +1 -1
- package/src/commands/deploys.ts +95 -0
- package/src/commands/link.ts +8 -0
- package/src/commands/mcp.ts +179 -4
- package/src/commands/rollback.ts +53 -0
- package/src/commands/secrets.ts +3 -1
- package/src/commands/services.ts +11 -1
- package/src/commands/ship.ts +3 -1
- package/src/commands/tokens.ts +16 -1
- package/src/commands/whoami.ts +43 -8
- package/src/index.ts +16 -0
- package/src/lib/agent-files.ts +54 -4
- package/src/lib/agent-integration.ts +4 -166
- package/src/lib/claude-hooks-installer.ts +55 -0
- package/src/lib/control-plane.ts +78 -40
- package/src/lib/crypto.ts +84 -0
- package/src/lib/debug.ts +2 -1
- package/src/lib/deploy-upload.ts +13 -3
- package/src/lib/hooks.ts +4 -3
- package/src/lib/managed-deploy.ts +12 -9
- package/src/lib/project-link.ts +6 -0
- package/src/lib/project-operations.ts +92 -30
- package/src/lib/prompts.ts +2 -2
- package/src/lib/telemetry.ts +2 -0
- package/src/mcp/README.md +1 -1
- package/src/mcp/resources/index.ts +1 -16
- package/src/mcp/server.ts +23 -0
- package/src/mcp/tools/index.ts +133 -17
- package/src/mcp/types.ts +1 -0
- package/src/mcp/utils.ts +2 -1
- package/src/templates/index.ts +25 -73
- package/templates/CLAUDE.md +62 -0
- package/templates/ai-chat/.jack.json +10 -5
- package/templates/ai-chat/bun.lock +50 -1
- package/templates/ai-chat/package.json +5 -0
- package/templates/ai-chat/public/app.js +73 -0
- package/templates/ai-chat/public/index.html +14 -197
- package/templates/ai-chat/schema.sql +14 -0
- package/templates/ai-chat/src/index.ts +86 -102
- package/templates/ai-chat/wrangler.jsonc +8 -1
- package/templates/cron/.jack.json +66 -0
- package/templates/cron/bun.lock +23 -0
- package/templates/cron/package.json +16 -0
- package/templates/cron/schema.sql +24 -0
- package/templates/cron/src/index.ts +117 -0
- package/templates/cron/src/jobs.ts +139 -0
- package/templates/cron/src/webhooks.ts +95 -0
- package/templates/cron/tsconfig.json +17 -0
- package/templates/cron/wrangler.jsonc +11 -0
- package/templates/miniapp/.jack.json +1 -1
- package/templates/nextjs/.jack.json +1 -1
- package/templates/nextjs-auth/.jack.json +44 -0
- package/templates/nextjs-auth/app/api/auth/[...all]/route.ts +11 -0
- package/templates/nextjs-auth/app/dashboard/loading.tsx +53 -0
- package/templates/nextjs-auth/app/dashboard/page.tsx +73 -0
- package/templates/nextjs-auth/app/error.tsx +44 -0
- package/templates/nextjs-auth/app/globals.css +1 -0
- package/templates/nextjs-auth/app/health/route.ts +3 -0
- package/templates/nextjs-auth/app/layout.tsx +24 -0
- package/templates/nextjs-auth/app/login/page.tsx +10 -0
- package/templates/nextjs-auth/app/page.tsx +86 -0
- package/templates/nextjs-auth/app/signup/page.tsx +10 -0
- package/templates/nextjs-auth/bun.lock +1065 -0
- package/templates/nextjs-auth/cloudflare-env.d.ts +8 -0
- package/templates/nextjs-auth/components/auth-form.tsx +191 -0
- package/templates/nextjs-auth/components/header.tsx +50 -0
- package/templates/nextjs-auth/components/user-menu.tsx +23 -0
- package/templates/nextjs-auth/lib/auth-client.ts +3 -0
- package/templates/nextjs-auth/lib/auth.ts +43 -0
- package/templates/nextjs-auth/lib/utils.ts +6 -0
- package/templates/nextjs-auth/middleware.ts +33 -0
- package/templates/nextjs-auth/next.config.ts +8 -0
- package/templates/nextjs-auth/open-next.config.ts +6 -0
- package/templates/nextjs-auth/package.json +33 -0
- package/templates/nextjs-auth/postcss.config.mjs +8 -0
- package/templates/nextjs-auth/schema.sql +49 -0
- package/templates/nextjs-auth/tsconfig.json +28 -0
- package/templates/nextjs-auth/wrangler.jsonc +23 -0
- package/templates/nextjs-clerk/.jack.json +54 -0
- package/templates/nextjs-clerk/app/dashboard/page.tsx +69 -0
- package/templates/nextjs-clerk/app/globals.css +1 -0
- package/templates/nextjs-clerk/app/health/route.ts +3 -0
- package/templates/nextjs-clerk/app/layout.tsx +28 -0
- package/templates/nextjs-clerk/app/page.tsx +86 -0
- package/templates/nextjs-clerk/app/sign-in/[[...sign-in]]/page.tsx +9 -0
- package/templates/nextjs-clerk/app/sign-up/[[...sign-up]]/page.tsx +9 -0
- package/templates/nextjs-clerk/bun.lock +1055 -0
- package/templates/nextjs-clerk/cloudflare-env.d.ts +3 -0
- package/templates/nextjs-clerk/components/header.tsx +40 -0
- package/templates/nextjs-clerk/lib/utils.ts +6 -0
- package/templates/nextjs-clerk/middleware.ts +18 -0
- package/templates/nextjs-clerk/next.config.ts +8 -0
- package/templates/nextjs-clerk/open-next.config.ts +6 -0
- package/templates/nextjs-clerk/package.json +31 -0
- package/templates/nextjs-clerk/postcss.config.mjs +8 -0
- package/templates/nextjs-clerk/tsconfig.json +28 -0
- package/templates/nextjs-clerk/wrangler.jsonc +17 -0
- package/templates/nextjs-shadcn/.jack.json +34 -0
- package/templates/nextjs-shadcn/app/dashboard/data.json +614 -0
- package/templates/nextjs-shadcn/app/dashboard/page.tsx +55 -0
- package/templates/nextjs-shadcn/app/globals.css +126 -0
- package/templates/nextjs-shadcn/app/health/route.ts +3 -0
- package/templates/nextjs-shadcn/app/layout.tsx +24 -0
- package/templates/nextjs-shadcn/app/login/page.tsx +19 -0
- package/templates/nextjs-shadcn/app/page.tsx +180 -0
- package/templates/nextjs-shadcn/app/showcase.tsx +1262 -0
- package/templates/nextjs-shadcn/bun.lock +1789 -0
- package/templates/nextjs-shadcn/cloudflare-env.d.ts +4 -0
- package/templates/nextjs-shadcn/components/app-sidebar.tsx +175 -0
- package/templates/nextjs-shadcn/components/chart-area-interactive.tsx +291 -0
- package/templates/nextjs-shadcn/components/data-table.tsx +807 -0
- package/templates/nextjs-shadcn/components/login-form.tsx +95 -0
- package/templates/nextjs-shadcn/components/nav-documents.tsx +92 -0
- package/templates/nextjs-shadcn/components/nav-main.tsx +73 -0
- package/templates/nextjs-shadcn/components/nav-projects.tsx +89 -0
- package/templates/nextjs-shadcn/components/nav-secondary.tsx +42 -0
- package/templates/nextjs-shadcn/components/nav-user.tsx +114 -0
- package/templates/nextjs-shadcn/components/section-cards.tsx +102 -0
- package/templates/nextjs-shadcn/components/site-header.tsx +30 -0
- package/templates/nextjs-shadcn/components/team-switcher.tsx +91 -0
- package/templates/nextjs-shadcn/components/ui/accordion.tsx +66 -0
- package/templates/nextjs-shadcn/components/ui/alert-dialog.tsx +196 -0
- package/templates/nextjs-shadcn/components/ui/alert.tsx +66 -0
- package/templates/nextjs-shadcn/components/ui/aspect-ratio.tsx +11 -0
- package/templates/nextjs-shadcn/components/ui/avatar.tsx +109 -0
- package/templates/nextjs-shadcn/components/ui/badge.tsx +48 -0
- package/templates/nextjs-shadcn/components/ui/breadcrumb.tsx +109 -0
- package/templates/nextjs-shadcn/components/ui/button-group.tsx +83 -0
- package/templates/nextjs-shadcn/components/ui/button.tsx +64 -0
- package/templates/nextjs-shadcn/components/ui/calendar.tsx +220 -0
- package/templates/nextjs-shadcn/components/ui/card.tsx +92 -0
- package/templates/nextjs-shadcn/components/ui/carousel.tsx +241 -0
- package/templates/nextjs-shadcn/components/ui/chart.tsx +357 -0
- package/templates/nextjs-shadcn/components/ui/checkbox.tsx +32 -0
- package/templates/nextjs-shadcn/components/ui/collapsible.tsx +33 -0
- package/templates/nextjs-shadcn/components/ui/combobox.tsx +310 -0
- package/templates/nextjs-shadcn/components/ui/command.tsx +184 -0
- package/templates/nextjs-shadcn/components/ui/context-menu.tsx +252 -0
- package/templates/nextjs-shadcn/components/ui/dialog.tsx +158 -0
- package/templates/nextjs-shadcn/components/ui/direction.tsx +22 -0
- package/templates/nextjs-shadcn/components/ui/drawer.tsx +135 -0
- package/templates/nextjs-shadcn/components/ui/dropdown-menu.tsx +257 -0
- package/templates/nextjs-shadcn/components/ui/empty.tsx +104 -0
- package/templates/nextjs-shadcn/components/ui/field.tsx +248 -0
- package/templates/nextjs-shadcn/components/ui/form.tsx +167 -0
- package/templates/nextjs-shadcn/components/ui/hover-card.tsx +44 -0
- package/templates/nextjs-shadcn/components/ui/input-group.tsx +170 -0
- package/templates/nextjs-shadcn/components/ui/input-otp.tsx +77 -0
- package/templates/nextjs-shadcn/components/ui/input.tsx +21 -0
- package/templates/nextjs-shadcn/components/ui/item.tsx +193 -0
- package/templates/nextjs-shadcn/components/ui/kbd.tsx +28 -0
- package/templates/nextjs-shadcn/components/ui/label.tsx +24 -0
- package/templates/nextjs-shadcn/components/ui/menubar.tsx +276 -0
- package/templates/nextjs-shadcn/components/ui/native-select.tsx +53 -0
- package/templates/nextjs-shadcn/components/ui/navigation-menu.tsx +168 -0
- package/templates/nextjs-shadcn/components/ui/pagination.tsx +127 -0
- package/templates/nextjs-shadcn/components/ui/popover.tsx +89 -0
- package/templates/nextjs-shadcn/components/ui/progress.tsx +31 -0
- package/templates/nextjs-shadcn/components/ui/radio-group.tsx +45 -0
- package/templates/nextjs-shadcn/components/ui/resizable.tsx +53 -0
- package/templates/nextjs-shadcn/components/ui/scroll-area.tsx +58 -0
- package/templates/nextjs-shadcn/components/ui/select.tsx +190 -0
- package/templates/nextjs-shadcn/components/ui/separator.tsx +28 -0
- package/templates/nextjs-shadcn/components/ui/sheet.tsx +143 -0
- package/templates/nextjs-shadcn/components/ui/sidebar.tsx +726 -0
- package/templates/nextjs-shadcn/components/ui/skeleton.tsx +13 -0
- package/templates/nextjs-shadcn/components/ui/slider.tsx +63 -0
- package/templates/nextjs-shadcn/components/ui/sonner.tsx +40 -0
- package/templates/nextjs-shadcn/components/ui/spinner.tsx +16 -0
- package/templates/nextjs-shadcn/components/ui/switch.tsx +35 -0
- package/templates/nextjs-shadcn/components/ui/table.tsx +116 -0
- package/templates/nextjs-shadcn/components/ui/tabs.tsx +91 -0
- package/templates/nextjs-shadcn/components/ui/textarea.tsx +18 -0
- package/templates/nextjs-shadcn/components/ui/toggle-group.tsx +83 -0
- package/templates/nextjs-shadcn/components/ui/toggle.tsx +47 -0
- package/templates/nextjs-shadcn/components/ui/tooltip.tsx +57 -0
- package/templates/nextjs-shadcn/components.json +23 -0
- package/templates/nextjs-shadcn/hooks/use-mobile.ts +19 -0
- package/templates/nextjs-shadcn/lib/utils.ts +6 -0
- package/templates/nextjs-shadcn/next-env.d.ts +6 -0
- package/templates/nextjs-shadcn/next.config.ts +8 -0
- package/templates/nextjs-shadcn/open-next.config.ts +6 -0
- package/templates/nextjs-shadcn/package.json +55 -0
- package/templates/nextjs-shadcn/postcss.config.mjs +8 -0
- package/templates/nextjs-shadcn/tsconfig.json +28 -0
- package/templates/nextjs-shadcn/wrangler.jsonc +23 -0
- package/templates/resend/.jack.json +64 -0
- package/templates/resend/bun.lock +23 -0
- package/templates/resend/package.json +16 -0
- package/templates/resend/schema.sql +13 -0
- package/templates/resend/src/email.ts +165 -0
- package/templates/resend/src/index.ts +108 -0
- package/templates/resend/tsconfig.json +17 -0
- package/templates/resend/wrangler.jsonc +11 -0
- package/templates/saas/.jack.json +1 -1
- 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'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
|
+
}
|