shipd 0.1.2 → 0.1.4
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/base-package/app/globals.css +126 -0
- package/base-package/app/layout.tsx +53 -0
- package/base-package/app/page.tsx +15 -0
- package/base-package/base.config.json +57 -0
- package/base-package/components/ui/avatar.tsx +53 -0
- package/base-package/components/ui/badge.tsx +46 -0
- package/base-package/components/ui/button.tsx +59 -0
- package/base-package/components/ui/card.tsx +92 -0
- package/base-package/components/ui/chart.tsx +353 -0
- package/base-package/components/ui/checkbox.tsx +32 -0
- package/base-package/components/ui/dialog.tsx +135 -0
- package/base-package/components/ui/dropdown-menu.tsx +257 -0
- package/base-package/components/ui/form.tsx +167 -0
- package/base-package/components/ui/input.tsx +21 -0
- package/base-package/components/ui/label.tsx +24 -0
- package/base-package/components/ui/progress.tsx +31 -0
- package/base-package/components/ui/resizable.tsx +56 -0
- package/base-package/components/ui/select.tsx +185 -0
- package/base-package/components/ui/separator.tsx +28 -0
- package/base-package/components/ui/sheet.tsx +139 -0
- package/base-package/components/ui/skeleton.tsx +13 -0
- package/base-package/components/ui/sonner.tsx +25 -0
- package/base-package/components/ui/switch.tsx +31 -0
- package/base-package/components/ui/tabs.tsx +66 -0
- package/base-package/components/ui/textarea.tsx +18 -0
- package/base-package/components/ui/toggle-group.tsx +73 -0
- package/base-package/components/ui/toggle.tsx +47 -0
- package/base-package/components/ui/tooltip.tsx +61 -0
- package/base-package/components.json +21 -0
- package/base-package/eslint.config.mjs +16 -0
- package/base-package/lib/utils.ts +6 -0
- package/base-package/middleware.ts +12 -0
- package/base-package/next.config.ts +27 -0
- package/base-package/package.json +49 -0
- package/base-package/postcss.config.mjs +5 -0
- package/base-package/public/favicon.svg +4 -0
- package/base-package/tailwind.config.ts +89 -0
- package/base-package/tsconfig.json +27 -0
- package/dist/index.js +1862 -948
- package/features/ai-chat/README.md +258 -0
- package/features/ai-chat/app/api/chat/route.ts +16 -0
- package/features/ai-chat/app/dashboard/_components/chatbot.tsx +39 -0
- package/features/ai-chat/app/dashboard/chat/page.tsx +73 -0
- package/features/ai-chat/feature.config.json +22 -0
- package/features/analytics/README.md +308 -0
- package/features/analytics/feature.config.json +20 -0
- package/features/analytics/lib/posthog.ts +36 -0
- package/features/auth/README.md +336 -0
- package/features/auth/app/api/auth/[...all]/route.ts +4 -0
- package/features/auth/app/dashboard/layout.tsx +15 -0
- package/features/auth/app/dashboard/page.tsx +140 -0
- package/features/auth/app/sign-in/page.tsx +228 -0
- package/features/auth/app/sign-up/page.tsx +243 -0
- package/features/auth/auth-schema.ts +47 -0
- package/features/auth/components/auth/setup-instructions.tsx +123 -0
- package/features/auth/feature.config.json +33 -0
- package/features/auth/lib/auth-client.ts +8 -0
- package/features/auth/lib/auth.ts +295 -0
- package/features/auth/lib/email-stub.ts +55 -0
- package/features/auth/lib/email.ts +47 -0
- package/features/auth/middleware.patch.ts +43 -0
- package/features/database/README.md +256 -0
- package/features/database/db/drizzle.ts +48 -0
- package/features/database/db/schema.ts +21 -0
- package/features/database/drizzle.config.ts +13 -0
- package/features/database/feature.config.json +30 -0
- package/features/email/README.md +282 -0
- package/features/email/emails/components/layout.tsx +181 -0
- package/features/email/emails/password-reset.tsx +67 -0
- package/features/email/emails/payment-failed.tsx +167 -0
- package/features/email/emails/subscription-confirmation.tsx +129 -0
- package/features/email/emails/welcome.tsx +100 -0
- package/features/email/feature.config.json +22 -0
- package/features/email/lib/email.ts +118 -0
- package/features/file-upload/README.md +271 -0
- package/features/file-upload/app/api/upload-image/route.ts +64 -0
- package/features/file-upload/app/dashboard/upload/page.tsx +324 -0
- package/features/file-upload/feature.config.json +23 -0
- package/features/file-upload/lib/upload-image.ts +28 -0
- package/features/marketing-landing/README.md +266 -0
- package/features/marketing-landing/app/page.tsx +25 -0
- package/features/marketing-landing/components/homepage/cli-workflow-section.tsx +231 -0
- package/features/marketing-landing/components/homepage/features-section.tsx +152 -0
- package/features/marketing-landing/components/homepage/footer.tsx +53 -0
- package/features/marketing-landing/components/homepage/hero-section.tsx +112 -0
- package/features/marketing-landing/components/homepage/integrations.tsx +124 -0
- package/features/marketing-landing/components/homepage/navigation.tsx +116 -0
- package/features/marketing-landing/components/homepage/news-section.tsx +82 -0
- package/features/marketing-landing/components/homepage/pricing-section.tsx +98 -0
- package/features/marketing-landing/components/homepage/testimonials-section.tsx +34 -0
- package/features/marketing-landing/components/logos/BetterAuth.tsx +21 -0
- package/features/marketing-landing/components/logos/NeonPostgres.tsx +41 -0
- package/features/marketing-landing/components/logos/Nextjs.tsx +72 -0
- package/features/marketing-landing/components/logos/Polar.tsx +7 -0
- package/features/marketing-landing/components/logos/TailwindCSS.tsx +27 -0
- package/features/marketing-landing/components/logos/index.ts +6 -0
- package/features/marketing-landing/components/logos/shadcnui.tsx +8 -0
- package/features/marketing-landing/feature.config.json +23 -0
- package/features/payments/README.md +306 -0
- package/features/payments/app/api/subscription/route.ts +25 -0
- package/features/payments/app/dashboard/payment/_components/manage-subscription.tsx +22 -0
- package/features/payments/app/dashboard/payment/page.tsx +126 -0
- package/features/payments/app/success/page.tsx +123 -0
- package/features/payments/feature.config.json +31 -0
- package/features/payments/lib/polar-products.ts +49 -0
- package/features/payments/lib/subscription.ts +148 -0
- package/features/payments/payments-schema.ts +30 -0
- package/features/seo/README.md +244 -0
- package/features/seo/app/blog/[slug]/page.tsx +314 -0
- package/features/seo/app/blog/page.tsx +107 -0
- package/features/seo/app/robots.txt +13 -0
- package/features/seo/app/sitemap.ts +70 -0
- package/features/seo/feature.config.json +19 -0
- package/features/seo/lib/seo-utils.ts +163 -0
- package/package.json +3 -1
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@import "tw-animate-css";
|
|
3
|
+
|
|
4
|
+
@custom-variant dark (&:is(.dark *));
|
|
5
|
+
|
|
6
|
+
@theme inline {
|
|
7
|
+
--color-background: var(--background);
|
|
8
|
+
--color-foreground: var(--foreground);
|
|
9
|
+
--font-sans: var(--font-apple-system);
|
|
10
|
+
--font-mono: var(--font-sf-mono);
|
|
11
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
12
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
13
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
14
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
15
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
16
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
17
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
18
|
+
--color-sidebar: var(--sidebar);
|
|
19
|
+
--color-chart-5: var(--chart-5);
|
|
20
|
+
--color-chart-4: var(--chart-4);
|
|
21
|
+
--color-chart-3: var(--chart-3);
|
|
22
|
+
--color-chart-2: var(--chart-2);
|
|
23
|
+
--color-chart-1: var(--chart-1);
|
|
24
|
+
--color-ring: var(--ring);
|
|
25
|
+
--color-input: var(--input);
|
|
26
|
+
--color-border: var(--border);
|
|
27
|
+
--color-destructive: var(--destructive);
|
|
28
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
29
|
+
--color-accent: var(--accent);
|
|
30
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
31
|
+
--color-muted: var(--muted);
|
|
32
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
33
|
+
--color-secondary: var(--secondary);
|
|
34
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
35
|
+
--color-primary: var(--primary);
|
|
36
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
37
|
+
--color-popover: var(--popover);
|
|
38
|
+
--color-card-foreground: var(--card-foreground);
|
|
39
|
+
--color-card: var(--card);
|
|
40
|
+
--radius-sm: 8px;
|
|
41
|
+
--radius-md: 10px;
|
|
42
|
+
--radius-lg: 12px;
|
|
43
|
+
--radius-xl: 20px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
:root {
|
|
47
|
+
/* Dark Theme with Sunset Orange */
|
|
48
|
+
--background: #000000; /* Pure black */
|
|
49
|
+
--foreground: #ffffff;
|
|
50
|
+
--card: #0a0a0a; /* Slightly lighter than black */
|
|
51
|
+
--card-foreground: #ffffff;
|
|
52
|
+
--popover: #0a0a0a;
|
|
53
|
+
--popover-foreground: #ffffff;
|
|
54
|
+
--primary: #ff5722; /* Deep sunset orange */
|
|
55
|
+
--primary-foreground: #ffffff;
|
|
56
|
+
--secondary: #1a1a1a; /* Dark gray */
|
|
57
|
+
--secondary-foreground: #ffffff;
|
|
58
|
+
--muted: #1a1a1a;
|
|
59
|
+
--muted-foreground: #a1a1a1;
|
|
60
|
+
--accent: #ff5722; /* Sunset orange */
|
|
61
|
+
--accent-foreground: #ffffff;
|
|
62
|
+
--destructive: #ff3b30;
|
|
63
|
+
--destructive-foreground: #ffffff;
|
|
64
|
+
--border: #2a2a2a; /* Subtle dark border */
|
|
65
|
+
--input: #1a1a1a;
|
|
66
|
+
--ring: #ff5722;
|
|
67
|
+
--chart-1: #ff5722; /* Sunset orange */
|
|
68
|
+
--chart-2: #ff7043; /* Lighter orange */
|
|
69
|
+
--chart-3: #ff8a65; /* Even lighter orange */
|
|
70
|
+
--chart-4: #ffab91; /* Peachy orange */
|
|
71
|
+
--chart-5: #d84315; /* Deep burnt orange */
|
|
72
|
+
--sidebar: #0a0a0a;
|
|
73
|
+
--sidebar-foreground: #ffffff;
|
|
74
|
+
--sidebar-primary: #ff5722;
|
|
75
|
+
--sidebar-primary-foreground: #ffffff;
|
|
76
|
+
--sidebar-accent: #1a1a1a;
|
|
77
|
+
--sidebar-accent-foreground: #ffffff;
|
|
78
|
+
--sidebar-border: #2a2a2a;
|
|
79
|
+
--sidebar-ring: #ff5722;
|
|
80
|
+
/* Fonts */
|
|
81
|
+
--font-apple-system:
|
|
82
|
+
-apple-system, BlinkMacSystemFont, "San Francisco", "Helvetica Neue",
|
|
83
|
+
Helvetica, sans-serif;
|
|
84
|
+
--font-sf-mono: "SF Mono", Menlo, monospace;
|
|
85
|
+
--font-sans: var(--font-apple-system);
|
|
86
|
+
--font-serif: "New York", Georgia, serif;
|
|
87
|
+
--font-mono: var(--font-sf-mono);
|
|
88
|
+
--radius: 10px;
|
|
89
|
+
/* Dark theme shadows with orange glow */
|
|
90
|
+
--shadow-2xs: 0px 1px 2px rgba(255, 87, 34, 0.05);
|
|
91
|
+
--shadow-xs: 0px 1px 3px rgba(255, 87, 34, 0.1);
|
|
92
|
+
--shadow-sm: 0px 2px 4px rgba(255, 87, 34, 0.1);
|
|
93
|
+
--shadow: 0px 2px 6px rgba(255, 87, 34, 0.1);
|
|
94
|
+
--shadow-md: 0px 4px 8px rgba(255, 87, 34, 0.15);
|
|
95
|
+
--shadow-lg: 0px 8px 16px rgba(255, 87, 34, 0.2);
|
|
96
|
+
--shadow-xl: 0px 12px 24px rgba(255, 87, 34, 0.25);
|
|
97
|
+
--shadow-2xl: 0px 16px 32px rgba(255, 87, 34, 0.3);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@layer base {
|
|
101
|
+
* {
|
|
102
|
+
@apply border-border outline-ring/50;
|
|
103
|
+
}
|
|
104
|
+
body {
|
|
105
|
+
@apply bg-background text-foreground font-sans;
|
|
106
|
+
-webkit-font-smoothing: antialiased;
|
|
107
|
+
-moz-osx-font-smoothing: grayscale;
|
|
108
|
+
}
|
|
109
|
+
button,
|
|
110
|
+
input,
|
|
111
|
+
select,
|
|
112
|
+
textarea {
|
|
113
|
+
@apply focus:outline-none focus:ring-2 focus:ring-primary/50 transition-all duration-200;
|
|
114
|
+
}
|
|
115
|
+
button {
|
|
116
|
+
@apply hover:cursor-pointer;
|
|
117
|
+
}
|
|
118
|
+
h1,
|
|
119
|
+
h2,
|
|
120
|
+
h3,
|
|
121
|
+
h4,
|
|
122
|
+
h5,
|
|
123
|
+
h6 {
|
|
124
|
+
@apply font-medium tracking-tight;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import "./globals.css";
|
|
3
|
+
|
|
4
|
+
const siteConfig = {
|
|
5
|
+
name: "{{PROJECT_NAME}}",
|
|
6
|
+
description: "{{PROJECT_DESCRIPTION}}",
|
|
7
|
+
url: "{{APP_URL}}",
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const metadata: Metadata = {
|
|
11
|
+
metadataBase: new URL(siteConfig.url),
|
|
12
|
+
title: {
|
|
13
|
+
default: siteConfig.name,
|
|
14
|
+
template: `%s | ${siteConfig.name}`,
|
|
15
|
+
},
|
|
16
|
+
description: siteConfig.description,
|
|
17
|
+
keywords: ["SaaS", "Next.js", "React", "TypeScript", "Tailwind CSS"],
|
|
18
|
+
authors: [
|
|
19
|
+
{
|
|
20
|
+
name: siteConfig.name,
|
|
21
|
+
url: siteConfig.url,
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
creator: siteConfig.name,
|
|
25
|
+
openGraph: {
|
|
26
|
+
type: "website",
|
|
27
|
+
locale: "en_US",
|
|
28
|
+
url: siteConfig.url,
|
|
29
|
+
title: siteConfig.name,
|
|
30
|
+
description: siteConfig.description,
|
|
31
|
+
siteName: siteConfig.name,
|
|
32
|
+
},
|
|
33
|
+
icons: {
|
|
34
|
+
icon: "/favicon.svg",
|
|
35
|
+
shortcut: "/favicon.svg",
|
|
36
|
+
apple: "/favicon.svg",
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default function RootLayout({
|
|
41
|
+
children,
|
|
42
|
+
}: Readonly<{
|
|
43
|
+
children: React.ReactNode;
|
|
44
|
+
}>) {
|
|
45
|
+
return (
|
|
46
|
+
<html lang="en" suppressHydrationWarning>
|
|
47
|
+
<body className="antialiased">
|
|
48
|
+
{children}
|
|
49
|
+
</body>
|
|
50
|
+
</html>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export default function Home() {
|
|
2
|
+
return (
|
|
3
|
+
<main className="flex min-h-screen flex-col items-center justify-center p-24">
|
|
4
|
+
<div className="z-10 max-w-5xl w-full items-center justify-center font-mono text-sm">
|
|
5
|
+
<h1 className="text-4xl font-bold text-center mb-4">
|
|
6
|
+
Welcome to {{PROJECT_NAME}}
|
|
7
|
+
</h1>
|
|
8
|
+
<p className="text-center text-muted-foreground">
|
|
9
|
+
{{PROJECT_DESCRIPTION}}
|
|
10
|
+
</p>
|
|
11
|
+
</div>
|
|
12
|
+
</main>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "base",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Base Next.js package with UI components and core infrastructure",
|
|
5
|
+
"files": [
|
|
6
|
+
"next.config.ts",
|
|
7
|
+
"tailwind.config.ts",
|
|
8
|
+
"tsconfig.json",
|
|
9
|
+
"postcss.config.mjs",
|
|
10
|
+
"components.json",
|
|
11
|
+
"eslint.config.mjs",
|
|
12
|
+
"package.json",
|
|
13
|
+
"middleware.ts",
|
|
14
|
+
"app/layout.tsx",
|
|
15
|
+
"app/page.tsx",
|
|
16
|
+
"app/globals.css",
|
|
17
|
+
"components/ui/**/*",
|
|
18
|
+
"lib/utils.ts"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"next": "15.3.8",
|
|
22
|
+
"react": "^19.0.0",
|
|
23
|
+
"react-dom": "^19.0.0",
|
|
24
|
+
"@radix-ui/react-avatar": "^1.1.7",
|
|
25
|
+
"@radix-ui/react-checkbox": "^1.3.2",
|
|
26
|
+
"@radix-ui/react-dialog": "^1.1.11",
|
|
27
|
+
"@radix-ui/react-dropdown-menu": "^2.1.12",
|
|
28
|
+
"@radix-ui/react-label": "^2.1.6",
|
|
29
|
+
"@radix-ui/react-progress": "^1.1.4",
|
|
30
|
+
"@radix-ui/react-select": "^2.2.2",
|
|
31
|
+
"@radix-ui/react-separator": "^1.1.4",
|
|
32
|
+
"@radix-ui/react-slider": "^1.3.2",
|
|
33
|
+
"@radix-ui/react-slot": "^1.2.3",
|
|
34
|
+
"@radix-ui/react-switch": "^1.2.2",
|
|
35
|
+
"@radix-ui/react-tabs": "^1.1.9",
|
|
36
|
+
"@radix-ui/react-toggle": "^1.1.9",
|
|
37
|
+
"@radix-ui/react-toggle-group": "^1.1.10",
|
|
38
|
+
"@radix-ui/react-tooltip": "^1.2.7",
|
|
39
|
+
"class-variance-authority": "^0.7.1",
|
|
40
|
+
"clsx": "^2.1.1",
|
|
41
|
+
"tailwind-merge": "^3.2.0",
|
|
42
|
+
"lucide-react": "^0.503.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@eslint/eslintrc": "^3",
|
|
46
|
+
"@tailwindcss/postcss": "^4",
|
|
47
|
+
"@types/node": "^20.17.31",
|
|
48
|
+
"@types/react": "^19",
|
|
49
|
+
"@types/react-dom": "^19",
|
|
50
|
+
"eslint": "^9",
|
|
51
|
+
"eslint-config-next": "15.3.1",
|
|
52
|
+
"tailwindcss": "^4.1.7",
|
|
53
|
+
"tw-animate-css": "^1.3.0",
|
|
54
|
+
"typescript": "^5"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as AvatarPrimitive from "@radix-ui/react-avatar"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
|
|
8
|
+
function Avatar({
|
|
9
|
+
className,
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof AvatarPrimitive.Root>) {
|
|
12
|
+
return (
|
|
13
|
+
<AvatarPrimitive.Root
|
|
14
|
+
data-slot="avatar"
|
|
15
|
+
className={cn(
|
|
16
|
+
"relative flex size-8 shrink-0 overflow-hidden rounded-full",
|
|
17
|
+
className
|
|
18
|
+
)}
|
|
19
|
+
{...props}
|
|
20
|
+
/>
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function AvatarImage({
|
|
25
|
+
className,
|
|
26
|
+
...props
|
|
27
|
+
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
|
|
28
|
+
return (
|
|
29
|
+
<AvatarPrimitive.Image
|
|
30
|
+
data-slot="avatar-image"
|
|
31
|
+
className={cn("aspect-square size-full", className)}
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function AvatarFallback({
|
|
38
|
+
className,
|
|
39
|
+
...props
|
|
40
|
+
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
|
|
41
|
+
return (
|
|
42
|
+
<AvatarPrimitive.Fallback
|
|
43
|
+
data-slot="avatar-fallback"
|
|
44
|
+
className={cn(
|
|
45
|
+
"bg-muted flex size-full items-center justify-center rounded-full",
|
|
46
|
+
className
|
|
47
|
+
)}
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { Avatar, AvatarImage, AvatarFallback }
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
6
|
+
|
|
7
|
+
const badgeVariants = cva(
|
|
8
|
+
"inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default:
|
|
13
|
+
"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
|
|
14
|
+
secondary:
|
|
15
|
+
"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
|
|
16
|
+
destructive:
|
|
17
|
+
"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
18
|
+
outline:
|
|
19
|
+
"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
defaultVariants: {
|
|
23
|
+
variant: "default",
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
function Badge({
|
|
29
|
+
className,
|
|
30
|
+
variant,
|
|
31
|
+
asChild = false,
|
|
32
|
+
...props
|
|
33
|
+
}: React.ComponentProps<"span"> &
|
|
34
|
+
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
|
|
35
|
+
const Comp = asChild ? Slot : "span"
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Comp
|
|
39
|
+
data-slot="badge"
|
|
40
|
+
className={cn(badgeVariants({ variant }), className)}
|
|
41
|
+
{...props}
|
|
42
|
+
/>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { Badge, badgeVariants }
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
6
|
+
|
|
7
|
+
const buttonVariants = cva(
|
|
8
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default:
|
|
13
|
+
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
14
|
+
destructive:
|
|
15
|
+
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
16
|
+
outline:
|
|
17
|
+
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
|
18
|
+
secondary:
|
|
19
|
+
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
|
20
|
+
ghost:
|
|
21
|
+
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
22
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
23
|
+
},
|
|
24
|
+
size: {
|
|
25
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
26
|
+
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
27
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
28
|
+
icon: "size-9",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
defaultVariants: {
|
|
32
|
+
variant: "default",
|
|
33
|
+
size: "default",
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
function Button({
|
|
39
|
+
className,
|
|
40
|
+
variant,
|
|
41
|
+
size,
|
|
42
|
+
asChild = false,
|
|
43
|
+
...props
|
|
44
|
+
}: React.ComponentProps<"button"> &
|
|
45
|
+
VariantProps<typeof buttonVariants> & {
|
|
46
|
+
asChild?: boolean
|
|
47
|
+
}) {
|
|
48
|
+
const Comp = asChild ? Slot : "button"
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<Comp
|
|
52
|
+
data-slot="button"
|
|
53
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { Button, buttonVariants }
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils"
|
|
4
|
+
|
|
5
|
+
function Card({ className, ...props }: React.ComponentProps<"div">) {
|
|
6
|
+
return (
|
|
7
|
+
<div
|
|
8
|
+
data-slot="card"
|
|
9
|
+
className={cn(
|
|
10
|
+
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
|
|
11
|
+
className
|
|
12
|
+
)}
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
19
|
+
return (
|
|
20
|
+
<div
|
|
21
|
+
data-slot="card-header"
|
|
22
|
+
className={cn(
|
|
23
|
+
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
|
24
|
+
className
|
|
25
|
+
)}
|
|
26
|
+
{...props}
|
|
27
|
+
/>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
32
|
+
return (
|
|
33
|
+
<div
|
|
34
|
+
data-slot="card-title"
|
|
35
|
+
className={cn("leading-none font-semibold", className)}
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
|
42
|
+
return (
|
|
43
|
+
<div
|
|
44
|
+
data-slot="card-description"
|
|
45
|
+
className={cn("text-muted-foreground text-sm", className)}
|
|
46
|
+
{...props}
|
|
47
|
+
/>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
|
|
52
|
+
return (
|
|
53
|
+
<div
|
|
54
|
+
data-slot="card-action"
|
|
55
|
+
className={cn(
|
|
56
|
+
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
|
57
|
+
className
|
|
58
|
+
)}
|
|
59
|
+
{...props}
|
|
60
|
+
/>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
65
|
+
return (
|
|
66
|
+
<div
|
|
67
|
+
data-slot="card-content"
|
|
68
|
+
className={cn("px-6", className)}
|
|
69
|
+
{...props}
|
|
70
|
+
/>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
75
|
+
return (
|
|
76
|
+
<div
|
|
77
|
+
data-slot="card-footer"
|
|
78
|
+
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
|
|
79
|
+
{...props}
|
|
80
|
+
/>
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export {
|
|
85
|
+
Card,
|
|
86
|
+
CardHeader,
|
|
87
|
+
CardFooter,
|
|
88
|
+
CardTitle,
|
|
89
|
+
CardAction,
|
|
90
|
+
CardDescription,
|
|
91
|
+
CardContent,
|
|
92
|
+
}
|