chore: setup shadcn 7afa918b
Steve · 2025-10-24 20:01 11 file(s) · +431 −35
bun.lock +21 −1
4 4
    "": {
5 5
      "name": "alcove",
6 6
      "dependencies": {
7 +
        "@radix-ui/react-slot": "^1.2.3",
7 8
        "@tailwindcss/vite": "^4.1.16",
9 +
        "class-variance-authority": "^0.7.1",
10 +
        "clsx": "^2.1.1",
11 +
        "lucide-react": "^0.548.0",
8 12
        "react": "^19.1.1",
9 13
        "react-dom": "^19.1.1",
14 +
        "tailwind-merge": "^3.3.1",
10 15
        "tailwindcss": "^4.1.16",
11 16
      },
12 17
      "devDependencies": {
13 18
        "@eslint/js": "^9.36.0",
14 -
        "@types/node": "^24.6.0",
19 +
        "@types/node": "^24.9.1",
15 20
        "@types/react": "^19.1.16",
16 21
        "@types/react-dom": "^19.1.9",
17 22
        "@vitejs/plugin-react": "^5.0.4",
19 24
        "eslint-plugin-react-hooks": "^5.2.0",
20 25
        "eslint-plugin-react-refresh": "^0.4.22",
21 26
        "globals": "^16.4.0",
27 +
        "tw-animate-css": "^1.4.0",
22 28
        "typescript": "~5.9.3",
23 29
        "typescript-eslint": "^8.45.0",
24 30
        "vite": "npm:rolldown-vite@7.1.14",
121 127
122 128
    "@oxc-project/types": ["@oxc-project/types@0.93.0", "", {}, "sha512-yNtwmWZIBtJsMr5TEfoZFDxIWV6OdScOpza/f5YxbqUMJk+j6QX3Cf3jgZShGEFYWQJ5j9mJ6jM0tZHu2J9Yrg=="],
123 129
130 +
    "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
131 +
132 +
    "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
133 +
124 134
    "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-beta.41", "", { "os": "android", "cpu": "arm64" }, "sha512-Edflndd9lU7JVhVIvJlZhdCj5DkhYDJPIRn4Dx0RUdfc8asP9xHOI5gMd8MesDDx+BJpdIT/uAmVTearteU/mQ=="],
125 135
126 136
    "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-beta.41", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XGCzqfjdk7550PlyZRTBKbypXrB7ATtXhw/+bjtxnklLQs0mKP/XkQVOKyn9qGKSlvH8I56JLYryVxl0PCvSNw=="],
250 260
    "caniuse-lite": ["caniuse-lite@1.0.30001751", "", {}, "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw=="],
251 261
252 262
    "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
263 +
264 +
    "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
265 +
266 +
    "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
253 267
254 268
    "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
255 269
397 411
398 412
    "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
399 413
414 +
    "lucide-react": ["lucide-react@0.548.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-63b16z63jM9yc1MwxajHeuu0FRZFsDtljtDjYm26Kd86UQ5HQzu9ksEtoUUw4RBuewodw/tGFmvipePvRsKeDA=="],
415 +
400 416
    "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
401 417
402 418
    "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
465 481
466 482
    "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
467 483
484 +
    "tailwind-merge": ["tailwind-merge@3.3.1", "", {}, "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g=="],
485 +
468 486
    "tailwindcss": ["tailwindcss@4.1.16", "", {}, "sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA=="],
469 487
470 488
    "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="],
476 494
    "ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="],
477 495
478 496
    "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
497 +
498 +
    "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="],
479 499
480 500
    "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
481 501
components.json (added) +22 −0
1 +
{
2 +
	"$schema": "https://ui.shadcn.com/schema.json",
3 +
	"style": "new-york",
4 +
	"rsc": false,
5 +
	"tsx": true,
6 +
	"tailwind": {
7 +
		"config": "",
8 +
		"css": "src/index.css",
9 +
		"baseColor": "zinc",
10 +
		"cssVariables": true,
11 +
		"prefix": ""
12 +
	},
13 +
	"iconLibrary": "lucide",
14 +
	"aliases": {
15 +
		"components": "@/components",
16 +
		"utils": "@/lib/utils",
17 +
		"ui": "@/components/ui",
18 +
		"lib": "@/lib",
19 +
		"hooks": "@/hooks"
20 +
	},
21 +
	"registries": {}
22 +
}
package.json +7 −1
10 10
    "preview": "vite preview"
11 11
  },
12 12
  "dependencies": {
13 +
    "@radix-ui/react-slot": "^1.2.3",
13 14
    "@tailwindcss/vite": "^4.1.16",
15 +
    "class-variance-authority": "^0.7.1",
16 +
    "clsx": "^2.1.1",
17 +
    "lucide-react": "^0.548.0",
14 18
    "react": "^19.1.1",
15 19
    "react-dom": "^19.1.1",
20 +
    "tailwind-merge": "^3.3.1",
16 21
    "tailwindcss": "^4.1.16"
17 22
  },
18 23
  "devDependencies": {
19 24
    "@eslint/js": "^9.36.0",
20 -
    "@types/node": "^24.6.0",
25 +
    "@types/node": "^24.9.1",
21 26
    "@types/react": "^19.1.16",
22 27
    "@types/react-dom": "^19.1.9",
23 28
    "@vitejs/plugin-react": "^5.0.4",
25 30
    "eslint-plugin-react-hooks": "^5.2.0",
26 31
    "eslint-plugin-react-refresh": "^0.4.22",
27 32
    "globals": "^16.4.0",
33 +
    "tw-animate-css": "^1.4.0",
28 34
    "typescript": "~5.9.3",
29 35
    "typescript-eslint": "^8.45.0",
30 36
    "vite": "npm:rolldown-vite@7.1.14"
src/App.tsx +8 −4
1 +
import { ThemeProvider } from "@/components/theme-provider";
2 +
1 3
function App() {
2 4
	return (
3 -
		<main className="min-h-screen w-full items-center justify-center flex-col flex bg-[#121113] text-white font-mono gap-2">
4 -
			<h1 className="text-6xl font-bold">ALCOVE</h1>
5 -
			<p className="text-lg">Coming soon</p>
6 -
		</main>
5 +
		<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
6 +
			<main className="min-h-screen w-full items-center justify-center flex-col flex gap-2">
7 +
				<h1 className="text-6xl font-bold">ALCOVE</h1>
8 +
				<p className="text-lg">Coming soon</p>
9 +
			</main>
10 +
		</ThemeProvider>
7 11
	);
8 12
}
9 13
src/components/theme-provider.tsx (added) +73 −0
1 +
import { createContext, useContext, useEffect, useState } from "react";
2 +
3 +
type Theme = "dark" | "light" | "system";
4 +
5 +
type ThemeProviderProps = {
6 +
	children: React.ReactNode;
7 +
	defaultTheme?: Theme;
8 +
	storageKey?: string;
9 +
};
10 +
11 +
type ThemeProviderState = {
12 +
	theme: Theme;
13 +
	setTheme: (theme: Theme) => void;
14 +
};
15 +
16 +
const initialState: ThemeProviderState = {
17 +
	theme: "system",
18 +
	setTheme: () => null,
19 +
};
20 +
21 +
const ThemeProviderContext = createContext<ThemeProviderState>(initialState);
22 +
23 +
export function ThemeProvider({
24 +
	children,
25 +
	defaultTheme = "system",
26 +
	storageKey = "vite-ui-theme",
27 +
	...props
28 +
}: ThemeProviderProps) {
29 +
	const [theme, setTheme] = useState<Theme>(
30 +
		() => (localStorage.getItem(storageKey) as Theme) || defaultTheme,
31 +
	);
32 +
33 +
	useEffect(() => {
34 +
		const root = window.document.documentElement;
35 +
36 +
		root.classList.remove("light", "dark");
37 +
38 +
		if (theme === "system") {
39 +
			const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
40 +
				.matches
41 +
				? "dark"
42 +
				: "light";
43 +
44 +
			root.classList.add(systemTheme);
45 +
			return;
46 +
		}
47 +
48 +
		root.classList.add(theme);
49 +
	}, [theme]);
50 +
51 +
	const value = {
52 +
		theme,
53 +
		setTheme: (theme: Theme) => {
54 +
			localStorage.setItem(storageKey, theme);
55 +
			setTheme(theme);
56 +
		},
57 +
	};
58 +
59 +
	return (
60 +
		<ThemeProviderContext.Provider {...props} value={value}>
61 +
			{children}
62 +
		</ThemeProviderContext.Provider>
63 +
	);
64 +
}
65 +
66 +
export const useTheme = () => {
67 +
	const context = useContext(ThemeProviderContext);
68 +
69 +
	if (context === undefined)
70 +
		throw new Error("useTheme must be used within a ThemeProvider");
71 +
72 +
	return context;
73 +
};
src/components/ui/button.tsx (added) +60 −0
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: "bg-primary text-primary-foreground hover:bg-primary/90",
13 +
        destructive:
14 +
          "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
15 +
        outline:
16 +
          "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
17 +
        secondary:
18 +
          "bg-secondary text-secondary-foreground hover:bg-secondary/80",
19 +
        ghost:
20 +
          "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
21 +
        link: "text-primary underline-offset-4 hover:underline",
22 +
      },
23 +
      size: {
24 +
        default: "h-9 px-4 py-2 has-[>svg]:px-3",
25 +
        sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
26 +
        lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
27 +
        icon: "size-9",
28 +
        "icon-sm": "size-8",
29 +
        "icon-lg": "size-10",
30 +
      },
31 +
    },
32 +
    defaultVariants: {
33 +
      variant: "default",
34 +
      size: "default",
35 +
    },
36 +
  }
37 +
)
38 +
39 +
function Button({
40 +
  className,
41 +
  variant,
42 +
  size,
43 +
  asChild = false,
44 +
  ...props
45 +
}: React.ComponentProps<"button"> &
46 +
  VariantProps<typeof buttonVariants> & {
47 +
    asChild?: boolean
48 +
  }) {
49 +
  const Comp = asChild ? Slot : "button"
50 +
51 +
  return (
52 +
    <Comp
53 +
      data-slot="button"
54 +
      className={cn(buttonVariants({ variant, size, className }))}
55 +
      {...props}
56 +
    />
57 +
  )
58 +
}
59 +
60 +
export { Button, buttonVariants }
src/index.css +189 −0
1 1
@import "tailwindcss";
2 +
@import "tw-animate-css";
3 +
4 +
@custom-variant dark (&:is(.dark *));
5 +
6 +
@theme inline {
7 +
  --radius-sm: calc(var(--radius) - 4px);
8 +
  --radius-md: calc(var(--radius) - 2px);
9 +
  --radius-lg: var(--radius);
10 +
  --radius-xl: calc(var(--radius) + 4px);
11 +
  --color-background: var(--background);
12 +
  --color-foreground: var(--foreground);
13 +
  --color-card: var(--card);
14 +
  --color-card-foreground: var(--card-foreground);
15 +
  --color-popover: var(--popover);
16 +
  --color-popover-foreground: var(--popover-foreground);
17 +
  --color-primary: var(--primary);
18 +
  --color-primary-foreground: var(--primary-foreground);
19 +
  --color-secondary: var(--secondary);
20 +
  --color-secondary-foreground: var(--secondary-foreground);
21 +
  --color-muted: var(--muted);
22 +
  --color-muted-foreground: var(--muted-foreground);
23 +
  --color-accent: var(--accent);
24 +
  --color-accent-foreground: var(--accent-foreground);
25 +
  --color-destructive: var(--destructive);
26 +
  --color-border: var(--border);
27 +
  --color-input: var(--input);
28 +
  --color-ring: var(--ring);
29 +
  --color-chart-1: var(--chart-1);
30 +
  --color-chart-2: var(--chart-2);
31 +
  --color-chart-3: var(--chart-3);
32 +
  --color-chart-4: var(--chart-4);
33 +
  --color-chart-5: var(--chart-5);
34 +
  --color-sidebar: var(--sidebar);
35 +
  --color-sidebar-foreground: var(--sidebar-foreground);
36 +
  --color-sidebar-primary: var(--sidebar-primary);
37 +
  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
38 +
  --color-sidebar-accent: var(--sidebar-accent);
39 +
  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
40 +
  --color-sidebar-border: var(--sidebar-border);
41 +
  --color-sidebar-ring: var(--sidebar-ring);
42 +
  --font-sans: Geist Mono, ui-monospace, monospace;
43 +
  --font-mono: JetBrains Mono, monospace;
44 +
  --font-serif: serif;
45 +
  --radius: 0.75rem;
46 +
  --tracking-tighter: calc(var(--tracking-normal) - 0.05em);
47 +
  --tracking-tight: calc(var(--tracking-normal) - 0.025em);
48 +
  --tracking-wide: calc(var(--tracking-normal) + 0.025em);
49 +
  --tracking-wider: calc(var(--tracking-normal) + 0.05em);
50 +
  --tracking-widest: calc(var(--tracking-normal) + 0.1em);
51 +
  --tracking-normal: var(--tracking-normal);
52 +
  --shadow-2xl: var(--shadow-2xl);
53 +
  --shadow-xl: var(--shadow-xl);
54 +
  --shadow-lg: var(--shadow-lg);
55 +
  --shadow-md: var(--shadow-md);
56 +
  --shadow: var(--shadow);
57 +
  --shadow-sm: var(--shadow-sm);
58 +
  --shadow-xs: var(--shadow-xs);
59 +
  --shadow-2xs: var(--shadow-2xs);
60 +
  --spacing: var(--spacing);
61 +
  --letter-spacing: var(--letter-spacing);
62 +
  --shadow-offset-y: var(--shadow-offset-y);
63 +
  --shadow-offset-x: var(--shadow-offset-x);
64 +
  --shadow-spread: var(--shadow-spread);
65 +
  --shadow-blur: var(--shadow-blur);
66 +
  --shadow-opacity: var(--shadow-opacity);
67 +
  --color-shadow-color: var(--shadow-color);
68 +
  --color-destructive-foreground: var(--destructive-foreground);
69 +
}
70 +
71 +
:root {
72 +
  --radius: 0.75rem;
73 +
  --background: oklch(1.0000 0 0);
74 +
  --foreground: oklch(0.2101 0.0318 264.6645);
75 +
  --card: oklch(1.0000 0 0);
76 +
  --card-foreground: oklch(0.2101 0.0318 264.6645);
77 +
  --popover: oklch(1.0000 0 0);
78 +
  --popover-foreground: oklch(0.2101 0.0318 264.6645);
79 +
  --primary: oklch(0.6716 0.1368 48.5130);
80 +
  --primary-foreground: oklch(1.0000 0 0);
81 +
  --secondary: oklch(0.5360 0.0398 196.0280);
82 +
  --secondary-foreground: oklch(1.0000 0 0);
83 +
  --muted: oklch(0.9670 0.0029 264.5419);
84 +
  --muted-foreground: oklch(0.5510 0.0234 264.3637);
85 +
  --accent: oklch(0.9491 0 0);
86 +
  --accent-foreground: oklch(0.2101 0.0318 264.6645);
87 +
  --destructive: oklch(0.6368 0.2078 25.3313);
88 +
  --border: oklch(0.9276 0.0058 264.5313);
89 +
  --input: oklch(0.9276 0.0058 264.5313);
90 +
  --ring: oklch(0.6716 0.1368 48.5130);
91 +
  --chart-1: oklch(0.5940 0.0443 196.0233);
92 +
  --chart-2: oklch(0.7214 0.1337 49.9802);
93 +
  --chart-3: oklch(0.8721 0.0864 68.5474);
94 +
  --chart-4: oklch(0.6268 0 0);
95 +
  --chart-5: oklch(0.6830 0 0);
96 +
  --sidebar: oklch(0.9670 0.0029 264.5419);
97 +
  --sidebar-foreground: oklch(0.2101 0.0318 264.6645);
98 +
  --sidebar-primary: oklch(0.6716 0.1368 48.5130);
99 +
  --sidebar-primary-foreground: oklch(1.0000 0 0);
100 +
  --sidebar-accent: oklch(1.0000 0 0);
101 +
  --sidebar-accent-foreground: oklch(0.2101 0.0318 264.6645);
102 +
  --sidebar-border: oklch(0.9276 0.0058 264.5313);
103 +
  --sidebar-ring: oklch(0.6716 0.1368 48.5130);
104 +
  --destructive-foreground: oklch(0.9851 0 0);
105 +
  --font-sans: Geist Mono, ui-monospace, monospace;
106 +
  --font-serif: serif;
107 +
  --font-mono: JetBrains Mono, monospace;
108 +
  --shadow-color: #000000;
109 +
  --shadow-opacity: 0.05;
110 +
  --shadow-blur: 4px;
111 +
  --shadow-spread: 0px;
112 +
  --shadow-offset-x: 0px;
113 +
  --shadow-offset-y: 1px;
114 +
  --letter-spacing: 0rem;
115 +
  --spacing: 0.25rem;
116 +
  --shadow-2xs: 0px 1px 4px 0px hsl(0 0% 0% / 0.03);
117 +
  --shadow-xs: 0px 1px 4px 0px hsl(0 0% 0% / 0.03);
118 +
  --shadow-sm: 0px 1px 4px 0px hsl(0 0% 0% / 0.05), 0px 1px 2px -1px hsl(0 0% 0% / 0.05);
119 +
  --shadow: 0px 1px 4px 0px hsl(0 0% 0% / 0.05), 0px 1px 2px -1px hsl(0 0% 0% / 0.05);
120 +
  --shadow-md: 0px 1px 4px 0px hsl(0 0% 0% / 0.05), 0px 2px 4px -1px hsl(0 0% 0% / 0.05);
121 +
  --shadow-lg: 0px 1px 4px 0px hsl(0 0% 0% / 0.05), 0px 4px 6px -1px hsl(0 0% 0% / 0.05);
122 +
  --shadow-xl: 0px 1px 4px 0px hsl(0 0% 0% / 0.05), 0px 8px 10px -1px hsl(0 0% 0% / 0.05);
123 +
  --shadow-2xl: 0px 1px 4px 0px hsl(0 0% 0% / 0.13);
124 +
  --tracking-normal: 0rem;
125 +
}
126 +
127 +
.dark {
128 +
  --background: oklch(0.1797 0.0043 308.1928);
129 +
  --foreground: oklch(0.8109 0 0);
130 +
  --card: oklch(0.1822 0 0);
131 +
  --card-foreground: oklch(0.8109 0 0);
132 +
  --popover: oklch(0.1797 0.0043 308.1928);
133 +
  --popover-foreground: oklch(0.8109 0 0);
134 +
  --primary: oklch(0.7214 0.1337 49.9802);
135 +
  --primary-foreground: oklch(0.1797 0.0043 308.1928);
136 +
  --secondary: oklch(0.5940 0.0443 196.0233);
137 +
  --secondary-foreground: oklch(0.1797 0.0043 308.1928);
138 +
  --muted: oklch(0.2520 0 0);
139 +
  --muted-foreground: oklch(0.6268 0 0);
140 +
  --accent: oklch(0.3211 0 0);
141 +
  --accent-foreground: oklch(0.8109 0 0);
142 +
  --destructive: oklch(0.5940 0.0443 196.0233);
143 +
  --border: oklch(0.2520 0 0);
144 +
  --input: oklch(0.2520 0 0);
145 +
  --ring: oklch(0.7214 0.1337 49.9802);
146 +
  --chart-1: oklch(0.5940 0.0443 196.0233);
147 +
  --chart-2: oklch(0.7214 0.1337 49.9802);
148 +
  --chart-3: oklch(0.8721 0.0864 68.5474);
149 +
  --chart-4: oklch(0.6268 0 0);
150 +
  --chart-5: oklch(0.6830 0 0);
151 +
  --sidebar: oklch(0.1822 0 0);
152 +
  --sidebar-foreground: oklch(0.8109 0 0);
153 +
  --sidebar-primary: oklch(0.7214 0.1337 49.9802);
154 +
  --sidebar-primary-foreground: oklch(0.1797 0.0043 308.1928);
155 +
  --sidebar-accent: oklch(0.3211 0 0);
156 +
  --sidebar-accent-foreground: oklch(0.8109 0 0);
157 +
  --sidebar-border: oklch(0.2520 0 0);
158 +
  --sidebar-ring: oklch(0.7214 0.1337 49.9802);
159 +
  --destructive-foreground: oklch(0.1797 0.0043 308.1928);
160 +
  --radius: 0.75rem;
161 +
  --font-sans: Geist Mono, ui-monospace, monospace;
162 +
  --font-serif: serif;
163 +
  --font-mono: JetBrains Mono, monospace;
164 +
  --shadow-color: #000000;
165 +
  --shadow-opacity: 0.05;
166 +
  --shadow-blur: 4px;
167 +
  --shadow-spread: 0px;
168 +
  --shadow-offset-x: 0px;
169 +
  --shadow-offset-y: 1px;
170 +
  --letter-spacing: 0rem;
171 +
  --spacing: 0.25rem;
172 +
  --shadow-2xs: 0px 1px 4px 0px hsl(0 0% 0% / 0.03);
173 +
  --shadow-xs: 0px 1px 4px 0px hsl(0 0% 0% / 0.03);
174 +
  --shadow-sm: 0px 1px 4px 0px hsl(0 0% 0% / 0.05), 0px 1px 2px -1px hsl(0 0% 0% / 0.05);
175 +
  --shadow: 0px 1px 4px 0px hsl(0 0% 0% / 0.05), 0px 1px 2px -1px hsl(0 0% 0% / 0.05);
176 +
  --shadow-md: 0px 1px 4px 0px hsl(0 0% 0% / 0.05), 0px 2px 4px -1px hsl(0 0% 0% / 0.05);
177 +
  --shadow-lg: 0px 1px 4px 0px hsl(0 0% 0% / 0.05), 0px 4px 6px -1px hsl(0 0% 0% / 0.05);
178 +
  --shadow-xl: 0px 1px 4px 0px hsl(0 0% 0% / 0.05), 0px 8px 10px -1px hsl(0 0% 0% / 0.05);
179 +
  --shadow-2xl: 0px 1px 4px 0px hsl(0 0% 0% / 0.13);
180 +
}
181 +
182 +
@layer base {
183 +
  * {
184 +
    @apply border-border outline-ring/50;
185 +
  }
186 +
  body {
187 +
    @apply bg-background text-foreground;
188 +
    letter-spacing: var(--tracking-normal);
189 +
  }
190 +
}
src/lib/utils.ts (added) +6 −0
1 +
import { clsx, type ClassValue } from "clsx"
2 +
import { twMerge } from "tailwind-merge"
3 +
4 +
export function cn(...inputs: ClassValue[]) {
5 +
  return twMerge(clsx(inputs))
6 +
}
tsconfig.app.json +28 −24
1 1
{
2 -
  "compilerOptions": {
3 -
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4 -
    "target": "ES2022",
5 -
    "useDefineForClassFields": true,
6 -
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
7 -
    "module": "ESNext",
8 -
    "types": ["vite/client"],
9 -
    "skipLibCheck": true,
2 +
	"compilerOptions": {
3 +
		"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4 +
		"target": "ES2022",
5 +
		"useDefineForClassFields": true,
6 +
		"lib": ["ES2022", "DOM", "DOM.Iterable"],
7 +
		"module": "ESNext",
8 +
		"types": ["vite/client"],
9 +
		"skipLibCheck": true,
10 10
11 -
    /* Bundler mode */
12 -
    "moduleResolution": "bundler",
13 -
    "allowImportingTsExtensions": true,
14 -
    "verbatimModuleSyntax": true,
15 -
    "moduleDetection": "force",
16 -
    "noEmit": true,
17 -
    "jsx": "react-jsx",
11 +
		/* Bundler mode */
12 +
		"moduleResolution": "bundler",
13 +
		"allowImportingTsExtensions": true,
14 +
		"verbatimModuleSyntax": true,
15 +
		"moduleDetection": "force",
16 +
		"noEmit": true,
17 +
		"jsx": "react-jsx",
18 18
19 -
    /* Linting */
20 -
    "strict": true,
21 -
    "noUnusedLocals": true,
22 -
    "noUnusedParameters": true,
23 -
    "erasableSyntaxOnly": true,
24 -
    "noFallthroughCasesInSwitch": true,
25 -
    "noUncheckedSideEffectImports": true
26 -
  },
27 -
  "include": ["src"]
19 +
		/* Linting */
20 +
		"strict": true,
21 +
		"noUnusedLocals": true,
22 +
		"noUnusedParameters": true,
23 +
		"erasableSyntaxOnly": true,
24 +
		"noFallthroughCasesInSwitch": true,
25 +
		"noUncheckedSideEffectImports": true,
26 +
		"baseUrl": ".",
27 +
		"paths": {
28 +
			"@/*": ["./src/*"]
29 +
		}
30 +
	},
31 +
	"include": ["src"]
28 32
}
tsconfig.json +11 −5
1 1
{
2 -
  "files": [],
3 -
  "references": [
4 -
    { "path": "./tsconfig.app.json" },
5 -
    { "path": "./tsconfig.node.json" }
6 -
  ]
2 +
	"files": [],
3 +
	"references": [
4 +
		{ "path": "./tsconfig.app.json" },
5 +
		{ "path": "./tsconfig.node.json" }
6 +
	],
7 +
	"compilerOptions": {
8 +
		"baseUrl": ".",
9 +
		"paths": {
10 +
			"@/*": ["./src/*"]
11 +
		}
12 +
	}
7 13
}
vite.config.ts +6 −0
1 1
import { defineConfig } from "vite";
2 +
import path from "path";
2 3
import react from "@vitejs/plugin-react";
3 4
import tailwindcss from "@tailwindcss/vite";
4 5
5 6
// https://vite.dev/config/
6 7
export default defineConfig({
7 8
	plugins: [react(), tailwindcss()],
9 +
	resolve: {
10 +
		alias: {
11 +
			"@": path.resolve(__dirname, "./src"),
12 +
		},
13 +
	},
8 14
});