create-strayl-app 1.0.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 ADDED
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env node
2
+
3
+
4
+ // src/index.ts
5
+ import { Command } from "commander";
6
+ import pc from "picocolors";
7
+ import { cpSync, existsSync, readFileSync, renameSync, writeFileSync } from "fs";
8
+ import { resolve, dirname, join } from "path";
9
+ import { fileURLToPath } from "url";
10
+ var __dirname = dirname(fileURLToPath(import.meta.url));
11
+ var templateDir = resolve(__dirname, "..", "template");
12
+ var program = new Command();
13
+ program.name("create-strayl-app").description("Scaffold a new Strayl web application").requiredOption("--name <name>", "Name of the new project").action((opts) => {
14
+ const name = opts.name.trim();
15
+ if (!name) {
16
+ console.error(pc.red("Error: --name must not be empty."));
17
+ process.exit(1);
18
+ }
19
+ if (!/^[a-zA-Z0-9_@\/-][a-zA-Z0-9_.\-@\/]*$/.test(name)) {
20
+ console.error(
21
+ pc.red(
22
+ "Error: Invalid project name. Use only alphanumeric characters, hyphens, underscores, dots, and slashes."
23
+ )
24
+ );
25
+ process.exit(1);
26
+ }
27
+ const targetDir = resolve(process.cwd(), name);
28
+ if (existsSync(targetDir)) {
29
+ console.error(
30
+ pc.red(`Error: Directory "${name}" already exists.`)
31
+ );
32
+ process.exit(1);
33
+ }
34
+ if (!existsSync(templateDir)) {
35
+ console.error(
36
+ pc.red("Error: Template directory not found. The package may be corrupted.")
37
+ );
38
+ process.exit(1);
39
+ }
40
+ console.log(pc.cyan(`Creating project "${name}"...`));
41
+ cpSync(templateDir, targetDir, { recursive: true });
42
+ const gitignorePath = join(targetDir, "gitignore");
43
+ if (existsSync(gitignorePath)) {
44
+ renameSync(gitignorePath, join(targetDir, ".gitignore"));
45
+ }
46
+ const pkgJsonPath = join(targetDir, "package.json");
47
+ if (existsSync(pkgJsonPath)) {
48
+ const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
49
+ pkgJson.name = name;
50
+ writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2) + "\n");
51
+ }
52
+ console.log(pc.green(`
53
+ Project "${name}" created successfully!
54
+ `));
55
+ console.log("Next steps:");
56
+ console.log(pc.cyan(` cd ${name}`));
57
+ console.log(pc.cyan(" npm install"));
58
+ console.log(pc.cyan(" npm run dev"));
59
+ console.log();
60
+ });
61
+ program.parse();
62
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { cpSync, existsSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { resolve, dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst templateDir = resolve(__dirname, \"..\", \"template\");\n\nconst program = new Command();\n\nprogram\n .name(\"create-strayl-app\")\n .description(\"Scaffold a new Strayl web application\")\n .requiredOption(\"--name <name>\", \"Name of the new project\")\n .action((opts: { name: string }) => {\n const name = opts.name.trim();\n\n if (!name) {\n console.error(pc.red(\"Error: --name must not be empty.\"));\n process.exit(1);\n }\n\n if (!/^[a-zA-Z0-9_@\\/-][a-zA-Z0-9_.\\-@\\/]*$/.test(name)) {\n console.error(\n pc.red(\n \"Error: Invalid project name. Use only alphanumeric characters, hyphens, underscores, dots, and slashes.\"\n )\n );\n process.exit(1);\n }\n\n const targetDir = resolve(process.cwd(), name);\n\n if (existsSync(targetDir)) {\n console.error(\n pc.red(`Error: Directory \"${name}\" already exists.`)\n );\n process.exit(1);\n }\n\n if (!existsSync(templateDir)) {\n console.error(\n pc.red(\"Error: Template directory not found. The package may be corrupted.\")\n );\n process.exit(1);\n }\n\n console.log(pc.cyan(`Creating project \"${name}\"...`));\n\n cpSync(templateDir, targetDir, { recursive: true });\n\n // npm publish strips .gitignore, so we ship it as \"gitignore\" and rename here\n const gitignorePath = join(targetDir, \"gitignore\");\n if (existsSync(gitignorePath)) {\n renameSync(gitignorePath, join(targetDir, \".gitignore\"));\n }\n\n const pkgJsonPath = join(targetDir, \"package.json\");\n if (existsSync(pkgJsonPath)) {\n const pkgJson = JSON.parse(readFileSync(pkgJsonPath, \"utf-8\"));\n pkgJson.name = name;\n writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2) + \"\\n\");\n }\n\n console.log(pc.green(`\\nProject \"${name}\" created successfully!\\n`));\n console.log(\"Next steps:\");\n console.log(pc.cyan(` cd ${name}`));\n console.log(pc.cyan(\" npm install\"));\n console.log(pc.cyan(\" npm run dev\"));\n console.log();\n });\n\nprogram.parse();\n"],"mappings":";;;;AAAA,SAAS,eAAe;AACxB,OAAO,QAAQ;AACf,SAAS,QAAQ,YAAY,cAAc,YAAY,qBAAqB;AAC5E,SAAS,SAAS,SAAS,YAAY;AACvC,SAAS,qBAAqB;AAE9B,IAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AACxD,IAAM,cAAc,QAAQ,WAAW,MAAM,UAAU;AAEvD,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,mBAAmB,EACxB,YAAY,uCAAuC,EACnD,eAAe,iBAAiB,yBAAyB,EACzD,OAAO,CAAC,SAA2B;AAClC,QAAM,OAAO,KAAK,KAAK,KAAK;AAE5B,MAAI,CAAC,MAAM;AACT,YAAQ,MAAM,GAAG,IAAI,kCAAkC,CAAC;AACxD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,CAAC,wCAAwC,KAAK,IAAI,GAAG;AACvD,YAAQ;AAAA,MACN,GAAG;AAAA,QACD;AAAA,MACF;AAAA,IACF;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,YAAY,QAAQ,QAAQ,IAAI,GAAG,IAAI;AAE7C,MAAI,WAAW,SAAS,GAAG;AACzB,YAAQ;AAAA,MACN,GAAG,IAAI,qBAAqB,IAAI,mBAAmB;AAAA,IACrD;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,CAAC,WAAW,WAAW,GAAG;AAC5B,YAAQ;AAAA,MACN,GAAG,IAAI,oEAAoE;AAAA,IAC7E;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,UAAQ,IAAI,GAAG,KAAK,qBAAqB,IAAI,MAAM,CAAC;AAEpD,SAAO,aAAa,WAAW,EAAE,WAAW,KAAK,CAAC;AAGlD,QAAM,gBAAgB,KAAK,WAAW,WAAW;AACjD,MAAI,WAAW,aAAa,GAAG;AAC7B,eAAW,eAAe,KAAK,WAAW,YAAY,CAAC;AAAA,EACzD;AAEA,QAAM,cAAc,KAAK,WAAW,cAAc;AAClD,MAAI,WAAW,WAAW,GAAG;AAC3B,UAAM,UAAU,KAAK,MAAM,aAAa,aAAa,OAAO,CAAC;AAC7D,YAAQ,OAAO;AACf,kBAAc,aAAa,KAAK,UAAU,SAAS,MAAM,CAAC,IAAI,IAAI;AAAA,EACpE;AAEA,UAAQ,IAAI,GAAG,MAAM;AAAA,WAAc,IAAI;AAAA,CAA2B,CAAC;AACnE,UAAQ,IAAI,aAAa;AACzB,UAAQ,IAAI,GAAG,KAAK,QAAQ,IAAI,EAAE,CAAC;AACnC,UAAQ,IAAI,GAAG,KAAK,eAAe,CAAC;AACpC,UAAQ,IAAI,GAAG,KAAK,eAAe,CAAC;AACpC,UAAQ,IAAI;AACd,CAAC;AAEH,QAAQ,MAAM;","names":[]}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "create-strayl-app",
3
+ "version": "1.0.1",
4
+ "description": "Scaffold a new Strayl web application",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-strayl-app": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "template"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsup",
15
+ "dev": "tsup --watch",
16
+ "typecheck": "tsc --noEmit",
17
+ "prepublishOnly": "npm run build"
18
+ },
19
+ "dependencies": {
20
+ "commander": "^12.1.0",
21
+ "picocolors": "^1.1.1"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^22.10.0",
25
+ "tsup": "^8.3.5",
26
+ "typescript": "^5.7.3"
27
+ },
28
+ "engines": {
29
+ "node": ">=18"
30
+ },
31
+ "keywords": [
32
+ "strayl",
33
+ "create",
34
+ "app",
35
+ "scaffold"
36
+ ],
37
+ "author": "Strayl Inc",
38
+ "license": "MIT"
39
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "new-york",
4
+ "rsc": false,
5
+ "tsx": true,
6
+ "aliases": {
7
+ "components": "@/components",
8
+ "utils": "@/lib/utils",
9
+ "ui": "@/components/ui",
10
+ "lib": "@/lib",
11
+ "hooks": "@/hooks"
12
+ },
13
+ "iconLibrary": "lucide",
14
+ "tailwind": {
15
+ "config": "",
16
+ "css": "src/styles.css",
17
+ "baseColor": "neutral",
18
+ "cssVariables": true,
19
+ "prefix": ""
20
+ }
21
+ }
@@ -0,0 +1,10 @@
1
+ node_modules
2
+ dist
3
+ .output
4
+ .vinxi
5
+ .nitro
6
+ .wrangler
7
+ *.local
8
+ .env
9
+ .env.*
10
+ !.env.example
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "my-app",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vite dev --port 3000",
7
+ "build": "vite build",
8
+ "start": "node .output/server/index.mjs"
9
+ },
10
+ "dependencies": {
11
+ "@base-ui/react": "^1.5.0",
12
+ "@fontsource-variable/geist": "^5.1.1",
13
+ "@radix-ui/react-slot": "^1.2.0",
14
+ "@tailwindcss/vite": "^4.1.4",
15
+ "@tanstack/react-router": "^1.159.5",
16
+ "@tanstack/react-start": "^1.159.5",
17
+ "@tanstack/router-plugin": "^1.159.5",
18
+ "class-variance-authority": "^0.7.1",
19
+ "clsx": "^2.1.1",
20
+ "lucide-react": "^0.475.0",
21
+ "next-themes": "^0.4.6",
22
+ "react": "^19.1.0",
23
+ "react-dom": "^19.1.0",
24
+ "tailwind-merge": "^3.0.2",
25
+ "tailwindcss": "^4.1.4",
26
+ "tw-animate-css": "^1.2.9",
27
+ "vite-tsconfig-paths": "^4.3.2"
28
+ },
29
+ "devDependencies": {
30
+ "@types/react": "^19.1.2",
31
+ "@types/react-dom": "^19.1.2",
32
+ "@vitejs/plugin-react": "^4.4.1",
33
+ "typescript": "^5.7.3",
34
+ "vite": "^7.0.0",
35
+ "vite-plugin-nitro": "^0.0.0-nightly-20250327-0404e32"
36
+ }
37
+ }
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,21 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { ThemeProvider as NextThemesProvider } from "next-themes"
5
+
6
+ export function ThemeProvider({
7
+ children,
8
+ }: {
9
+ children: React.ReactNode
10
+ }) {
11
+ return (
12
+ <NextThemesProvider
13
+ attribute="class"
14
+ defaultTheme="system"
15
+ enableSystem
16
+ disableTransitionOnChange
17
+ >
18
+ {children}
19
+ </NextThemesProvider>
20
+ )
21
+ }
@@ -0,0 +1,60 @@
1
+ "use client";
2
+
3
+ import { mergeProps } from "@base-ui/react/merge-props";
4
+ import { useRender } from "@base-ui/react/use-render";
5
+ import { cva, type VariantProps } from "class-variance-authority";
6
+
7
+ import { cn } from "@/lib/utils";
8
+
9
+ const badgeVariants = cva(
10
+ "relative inline-flex shrink-0 items-center justify-center gap-1 whitespace-nowrap rounded-sm border border-transparent font-medium outline-none transition-shadow focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-3.5 sm:[&_svg:not([class*='size-'])]:size-3 [&_svg]:pointer-events-none [&_svg]:shrink-0 [button,a&]:cursor-pointer [button,a&]:pointer-coarse:after:absolute [button,a&]:pointer-coarse:after:size-full [button,a&]:pointer-coarse:after:min-h-11 [button,a&]:pointer-coarse:after:min-w-11",
11
+ {
12
+ defaultVariants: {
13
+ size: "default",
14
+ variant: "default",
15
+ },
16
+ variants: {
17
+ size: {
18
+ default:
19
+ "h-5.5 min-w-5.5 px-[calc(--spacing(1)-1px)] text-sm sm:h-4.5 sm:min-w-4.5 sm:text-xs",
20
+ lg: "h-6.5 min-w-6.5 px-[calc(--spacing(1.5)-1px)] text-base sm:h-5.5 sm:min-w-5.5 sm:text-sm",
21
+ sm: "h-5 min-w-5 rounded-[calc(var(--radius-sm)-2px)] px-[calc(--spacing(1)-1px)] text-xs sm:h-4 sm:min-w-4 sm:text-[.625rem]",
22
+ },
23
+ variant: {
24
+ default:
25
+ "bg-primary text-primary-foreground [button,a&]:hover:bg-primary/90",
26
+ destructive:
27
+ "bg-destructive text-white [button,a&]:hover:bg-destructive/90",
28
+ error:
29
+ "bg-destructive/8 text-destructive-foreground dark:bg-destructive/16",
30
+ info: "bg-info/8 text-info-foreground dark:bg-info/16",
31
+ outline:
32
+ "border-input bg-background text-foreground dark:bg-input/32 [button,a&]:hover:bg-accent/50 dark:[button,a&]:hover:bg-input/48",
33
+ secondary:
34
+ "bg-secondary text-secondary-foreground [button,a&]:hover:bg-secondary/90",
35
+ success: "bg-success/8 text-success-foreground dark:bg-success/16",
36
+ warning: "bg-warning/8 text-warning-foreground dark:bg-warning/16",
37
+ },
38
+ },
39
+ },
40
+ );
41
+
42
+ interface BadgeProps extends useRender.ComponentProps<"span"> {
43
+ variant?: VariantProps<typeof badgeVariants>["variant"];
44
+ size?: VariantProps<typeof badgeVariants>["size"];
45
+ }
46
+
47
+ function Badge({ className, variant, size, render, ...props }: BadgeProps) {
48
+ const defaultProps = {
49
+ className: cn(badgeVariants({ className, size, variant })),
50
+ "data-slot": "badge",
51
+ };
52
+
53
+ return useRender({
54
+ defaultTagName: "span",
55
+ props: mergeProps<"span">(defaultProps, props),
56
+ render,
57
+ });
58
+ }
59
+
60
+ export { Badge, badgeVariants };
@@ -0,0 +1,73 @@
1
+ "use client";
2
+
3
+ import { mergeProps } from "@base-ui/react/merge-props";
4
+ import { useRender } from "@base-ui/react/use-render";
5
+ import { cva, type VariantProps } from "class-variance-authority";
6
+ import type * as React from "react";
7
+
8
+ import { cn } from "@/lib/utils";
9
+
10
+ const buttonVariants = cva(
11
+ "[&_svg]:-mx-0.5 relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-lg border font-medium text-base outline-none transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 sm:text-sm [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
12
+ {
13
+ defaultVariants: {
14
+ size: "default",
15
+ variant: "default",
16
+ },
17
+ variants: {
18
+ size: {
19
+ default: "h-9 px-[calc(--spacing(3)-1px)] sm:h-8",
20
+ icon: "size-9 sm:size-8",
21
+ "icon-lg": "size-10 sm:size-9",
22
+ "icon-sm": "size-8 sm:size-7",
23
+ "icon-xl":
24
+ "size-11 sm:size-10 [&_svg:not([class*='size-'])]:size-5 sm:[&_svg:not([class*='size-'])]:size-4.5",
25
+ "icon-xs":
26
+ "size-7 rounded-md before:rounded-[calc(var(--radius-md)-1px)] sm:size-6 not-in-data-[slot=input-group]:[&_svg:not([class*='size-'])]:size-4 sm:not-in-data-[slot=input-group]:[&_svg:not([class*='size-'])]:size-3.5",
27
+ lg: "h-10 px-[calc(--spacing(3.5)-1px)] sm:h-9",
28
+ sm: "h-8 gap-1.5 px-[calc(--spacing(2.5)-1px)] sm:h-7",
29
+ xl: "h-11 px-[calc(--spacing(4)-1px)] text-lg sm:h-10 sm:text-base [&_svg:not([class*='size-'])]:size-5 sm:[&_svg:not([class*='size-'])]:size-4.5",
30
+ xs: "h-7 gap-1 rounded-md px-[calc(--spacing(2)-1px)] text-sm before:rounded-[calc(var(--radius-md)-1px)] sm:h-6 sm:text-xs [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5",
31
+ },
32
+ variant: {
33
+ default:
34
+ "not-disabled:inset-shadow-[0_1px_--theme(--color-white/16%)] border-primary bg-primary text-primary-foreground shadow-primary/24 shadow-xs [:active,[data-pressed]]:inset-shadow-[0_1px_--theme(--color-black/8%)] [:disabled,:active,[data-pressed]]:shadow-none [:hover,[data-pressed]]:bg-primary/90",
35
+ destructive:
36
+ "not-disabled:inset-shadow-[0_1px_--theme(--color-white/16%)] border-destructive bg-destructive text-white shadow-destructive/24 shadow-xs [:active,[data-pressed]]:inset-shadow-[0_1px_--theme(--color-black/8%)] [:disabled,:active,[data-pressed]]:shadow-none [:hover,[data-pressed]]:bg-destructive/90",
37
+ "destructive-outline":
38
+ "border-input bg-transparent not-dark:bg-clip-padding text-destructive-foreground shadow-xs/5 not-disabled:not-active:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/6%)] dark:bg-input/32 dark:not-disabled:before:shadow-[0_-1px_--theme(--color-white/2%)] dark:not-disabled:not-active:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] [:disabled,:active,[data-pressed]]:shadow-none [:hover,[data-pressed]]:border-destructive/32 [:hover,[data-pressed]]:bg-destructive/4",
39
+ ghost:
40
+ "border-transparent text-foreground data-pressed:bg-accent [:hover,[data-pressed]]:bg-accent",
41
+ link: "border-transparent underline-offset-4 [:hover,[data-pressed]]:underline",
42
+ outline:
43
+ "border-input bg-background not-dark:bg-clip-padding text-foreground shadow-xs/5 not-disabled:not-active:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/6%)] dark:bg-input/32 dark:not-disabled:before:shadow-[0_-1px_--theme(--color-white/2%)] dark:not-disabled:not-active:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] [:disabled,:active,[data-pressed]]:shadow-none [:hover,[data-pressed]]:bg-accent/50 dark:[:hover,[data-pressed]]:bg-input/64",
44
+ secondary:
45
+ "border-transparent bg-secondary text-secondary-foreground [:active,[data-pressed]]:bg-secondary/80 [:hover,[data-pressed]]:bg-secondary/90",
46
+ },
47
+ },
48
+ },
49
+ );
50
+
51
+ interface ButtonProps extends useRender.ComponentProps<"button"> {
52
+ variant?: VariantProps<typeof buttonVariants>["variant"];
53
+ size?: VariantProps<typeof buttonVariants>["size"];
54
+ }
55
+
56
+ function Button({ className, variant, size, render, ...props }: ButtonProps) {
57
+ const typeValue: React.ButtonHTMLAttributes<HTMLButtonElement>["type"] =
58
+ render ? undefined : "button";
59
+
60
+ const defaultProps = {
61
+ className: cn(buttonVariants({ className, size, variant })),
62
+ "data-slot": "button",
63
+ type: typeValue,
64
+ };
65
+
66
+ return useRender({
67
+ defaultTagName: "button",
68
+ props: mergeProps<"button">(defaultProps, props),
69
+ render,
70
+ });
71
+ }
72
+
73
+ export { Button, buttonVariants };
@@ -0,0 +1,244 @@
1
+ "use client";
2
+
3
+ import { mergeProps } from "@base-ui/react/merge-props";
4
+ import { useRender } from "@base-ui/react/use-render";
5
+
6
+ import { cn } from "@/lib/utils";
7
+
8
+ function Card({
9
+ className,
10
+ render,
11
+ ...props
12
+ }: useRender.ComponentProps<"div">) {
13
+ const defaultProps = {
14
+ className: cn(
15
+ "relative flex flex-col rounded-lg border bg-card text-card-foreground",
16
+ className,
17
+ ),
18
+ "data-slot": "card",
19
+ };
20
+
21
+ return useRender({
22
+ defaultTagName: "div",
23
+ props: mergeProps<"div">(defaultProps, props),
24
+ render,
25
+ });
26
+ }
27
+
28
+ function CardFrame({
29
+ className,
30
+ render,
31
+ ...props
32
+ }: useRender.ComponentProps<"div">) {
33
+ const defaultProps = {
34
+ className: cn(
35
+ "flex flex-col relative rounded-2xl border bg-background before:absolute before:inset-0 before:rounded-[inherit] before:bg-muted/72 before:pointer-events-none not-dark:bg-clip-padding text-card-foreground shadow-xs/5 before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-2xl)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] dark:before:shadow-[0_-1px_--theme(--color-white/6%)] *:data-[slot=card]:-m-px *:not-last:data-[slot=card]:rounded-b-lg *:not-last:data-[slot=card]:before:rounded-b-[calc(var(--radius-lg)-1px)] *:not-first:data-[slot=card]:rounded-t-lg *:not-first:data-[slot=card]:before:rounded-t-[calc(var(--radius-lg)-1px)] *:data-[slot=card]:[clip-path:inset(-1rem_1px)] *:data-[slot=card]:first:[clip-path:inset(1px_1px_-1rem_1px_round_calc(var(--radius-2xl)-1px))] *:data-[slot=card]:last:[clip-path:inset(-1rem_1px_1px_1px_round_calc(var(--radius-2xl)-1px))] *:data-[slot=card]:shadow-none *:data-[slot=card]:before:hidden *:data-[slot=card]:bg-clip-padding",
36
+ className,
37
+ ),
38
+ "data-slot": "card-frame",
39
+ };
40
+
41
+ return useRender({
42
+ defaultTagName: "div",
43
+ props: mergeProps<"div">(defaultProps, props),
44
+ render,
45
+ });
46
+ }
47
+
48
+ function CardFrameHeader({
49
+ className,
50
+ render,
51
+ ...props
52
+ }: useRender.ComponentProps<"div">) {
53
+ const defaultProps = {
54
+ className: cn("flex flex-col px-6 py-4", className),
55
+ "data-slot": "card-frame-header",
56
+ };
57
+
58
+ return useRender({
59
+ defaultTagName: "div",
60
+ props: mergeProps<"div">(defaultProps, props),
61
+ render,
62
+ });
63
+ }
64
+
65
+ function CardFrameTitle({
66
+ className,
67
+ render,
68
+ ...props
69
+ }: useRender.ComponentProps<"div">) {
70
+ const defaultProps = {
71
+ className: cn("font-semibold text-sm", className),
72
+ "data-slot": "card-frame-title",
73
+ };
74
+
75
+ return useRender({
76
+ defaultTagName: "div",
77
+ props: mergeProps<"div">(defaultProps, props),
78
+ render,
79
+ });
80
+ }
81
+
82
+ function CardFrameDescription({
83
+ className,
84
+ render,
85
+ ...props
86
+ }: useRender.ComponentProps<"div">) {
87
+ const defaultProps = {
88
+ className: cn("text-muted-foreground text-sm", className),
89
+ "data-slot": "card-frame-description",
90
+ };
91
+
92
+ return useRender({
93
+ defaultTagName: "div",
94
+ props: mergeProps<"div">(defaultProps, props),
95
+ render,
96
+ });
97
+ }
98
+
99
+ function CardFrameFooter({
100
+ className,
101
+ render,
102
+ ...props
103
+ }: useRender.ComponentProps<"div">) {
104
+ const defaultProps = {
105
+ className: cn("px-6 py-4", className),
106
+ "data-slot": "card-frame-footer",
107
+ };
108
+
109
+ return useRender({
110
+ defaultTagName: "div",
111
+ props: mergeProps<"div">(defaultProps, props),
112
+ render,
113
+ });
114
+ }
115
+
116
+ function CardHeader({
117
+ className,
118
+ render,
119
+ ...props
120
+ }: useRender.ComponentProps<"div">) {
121
+ const defaultProps = {
122
+ className: cn(
123
+ "grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 p-6 in-[[data-slot=card]:has(>[data-slot=card-panel])]:pb-4 has-data-[slot=card-action]:grid-cols-[1fr_auto]",
124
+ className,
125
+ ),
126
+ "data-slot": "card-header",
127
+ };
128
+
129
+ return useRender({
130
+ defaultTagName: "div",
131
+ props: mergeProps<"div">(defaultProps, props),
132
+ render,
133
+ });
134
+ }
135
+
136
+ function CardTitle({
137
+ className,
138
+ render,
139
+ ...props
140
+ }: useRender.ComponentProps<"div">) {
141
+ const defaultProps = {
142
+ className: cn("font-medium text-lg leading-none", className),
143
+ "data-slot": "card-title",
144
+ };
145
+
146
+ return useRender({
147
+ defaultTagName: "div",
148
+ props: mergeProps<"div">(defaultProps, props),
149
+ render,
150
+ });
151
+ }
152
+
153
+ function CardDescription({
154
+ className,
155
+ render,
156
+ ...props
157
+ }: useRender.ComponentProps<"div">) {
158
+ const defaultProps = {
159
+ className: cn("text-muted-foreground text-sm", className),
160
+ "data-slot": "card-description",
161
+ };
162
+
163
+ return useRender({
164
+ defaultTagName: "div",
165
+ props: mergeProps<"div">(defaultProps, props),
166
+ render,
167
+ });
168
+ }
169
+
170
+ function CardAction({
171
+ className,
172
+ render,
173
+ ...props
174
+ }: useRender.ComponentProps<"div">) {
175
+ const defaultProps = {
176
+ className: cn(
177
+ "col-start-2 row-span-2 row-start-1 self-start justify-self-end inline-flex",
178
+ className,
179
+ ),
180
+ "data-slot": "card-action",
181
+ };
182
+
183
+ return useRender({
184
+ defaultTagName: "div",
185
+ props: mergeProps<"div">(defaultProps, props),
186
+ render,
187
+ });
188
+ }
189
+
190
+ function CardPanel({
191
+ className,
192
+ render,
193
+ ...props
194
+ }: useRender.ComponentProps<"div">) {
195
+ const defaultProps = {
196
+ className: cn(
197
+ "flex-1 p-6 in-[[data-slot=card]:has(>[data-slot=card-header]:not(.border-b))]:pt-0 in-[[data-slot=card]:has(>[data-slot=card-footer]:not(.border-t))]:pb-0",
198
+ className,
199
+ ),
200
+ "data-slot": "card-panel",
201
+ };
202
+
203
+ return useRender({
204
+ defaultTagName: "div",
205
+ props: mergeProps<"div">(defaultProps, props),
206
+ render,
207
+ });
208
+ }
209
+
210
+ function CardFooter({
211
+ className,
212
+ render,
213
+ ...props
214
+ }: useRender.ComponentProps<"div">) {
215
+ const defaultProps = {
216
+ className: cn(
217
+ "flex items-center p-6 in-[[data-slot=card]:has(>[data-slot=card-panel])]:pt-4",
218
+ className,
219
+ ),
220
+ "data-slot": "card-footer",
221
+ };
222
+
223
+ return useRender({
224
+ defaultTagName: "div",
225
+ props: mergeProps<"div">(defaultProps, props),
226
+ render,
227
+ });
228
+ }
229
+
230
+ export {
231
+ Card,
232
+ CardFrame,
233
+ CardFrameHeader,
234
+ CardFrameTitle,
235
+ CardFrameDescription,
236
+ CardFrameFooter,
237
+ CardAction,
238
+ CardDescription,
239
+ CardFooter,
240
+ CardHeader,
241
+ CardPanel,
242
+ CardPanel as CardContent,
243
+ CardTitle,
244
+ };