create-lumen 2.0.0-alpha.1 → 2.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +15 -7
  2. package/bin/cli.js +1 -0
  3. package/package.json +2 -2
  4. package/schema/fixtures/v2/invalid/shadcn-without-tailwind.json +1 -1
  5. package/schema/fixtures/v2/valid/react-vite-type-based.json +1 -1
  6. package/schema/lumen.config.v2.json +0 -1
  7. package/src/cli-args.js +65 -3
  8. package/src/configure.js +4 -0
  9. package/src/css.js +14 -30
  10. package/src/dependencies.js +28 -18
  11. package/src/engine/capabilities.js +174 -4
  12. package/src/engine/composition.js +644 -0
  13. package/src/engine/index.js +1 -0
  14. package/src/injector.js +294 -446
  15. package/src/main.js +6 -7
  16. package/src/manifest/schema.js +1 -1
  17. package/src/prompts.js +459 -247
  18. package/src/readme.js +23 -2
  19. package/src/scaffold.js +17 -0
  20. package/templates/architectures/hybrid/main.jsx +10 -0
  21. package/templates/architectures/hybrid/main.tsx +10 -0
  22. package/templates/architectures/hybrid/src/App.jsx +20 -0
  23. package/templates/architectures/hybrid/src/App.tsx +20 -0
  24. package/templates/architectures/hybrid/src/shared/components/ui/Button.jsx +31 -0
  25. package/templates/architectures/hybrid/src/shared/components/ui/Button.tsx +36 -0
  26. package/templates/architectures/hybrid/src/shared/components/ui/index.js +1 -0
  27. package/templates/architectures/hybrid/src/shared/components/ui/index.ts +1 -0
  28. package/templates/architectures/hybrid/src/shared/hooks/useLocalStorage.jsx +28 -0
  29. package/templates/architectures/hybrid/src/shared/hooks/useLocalStorage.ts +28 -0
  30. package/templates/architectures/hybrid/src/shared/layouts/.gitkeep +0 -0
  31. package/templates/architectures/hybrid/src/shared/stores/.gitkeep +0 -0
  32. package/templates/architectures/hybrid/src/shared/styles/.gitkeep +0 -0
  33. package/templates/architectures/hybrid/src/shared/types/index.js +20 -0
  34. package/templates/architectures/hybrid/src/shared/types/index.ts +16 -0
  35. package/templates/architectures/hybrid/src/shared/utils/cn.jsx +3 -0
  36. package/templates/architectures/hybrid/src/shared/utils/cn.ts +5 -0
  37. package/templates/architectures/none/main.jsx +10 -0
  38. package/templates/architectures/none/main.tsx +10 -0
  39. package/templates/architectures/none/src/App.jsx +15 -0
  40. package/templates/architectures/none/src/App.tsx +15 -0
  41. package/templates/architectures/none/src/styles/.gitkeep +1 -0
  42. package/templates/architectures/none/src/types/index.js +20 -0
  43. package/templates/architectures/none/src/types/index.ts +16 -0
  44. package/templates/conditional/testing/jest/hybrid/src/__tests__/App.test.jsx +11 -0
  45. package/templates/conditional/testing/jest/hybrid/src/__tests__/App.test.tsx +11 -0
  46. package/templates/conditional/testing/jest/none/src/__tests__/App.test.jsx +11 -0
  47. package/templates/conditional/testing/jest/none/src/__tests__/App.test.tsx +11 -0
  48. package/templates/conditional/testing/vitest/hybrid/src/__tests__/App.test.jsx +10 -0
  49. package/templates/conditional/testing/vitest/hybrid/src/__tests__/App.test.tsx +10 -0
  50. package/templates/conditional/testing/vitest/none/src/__tests__/App.test.jsx +10 -0
  51. package/templates/conditional/testing/vitest/none/src/__tests__/App.test.tsx +10 -0
  52. package/templates/css/tailwind/src/globals.css +10 -0
  53. package/templates/css/tailwind/src/themes.css +86 -4
  54. package/templates/ui/shadcn/lib/utils.js +6 -0
  55. package/templates/ui/shadcn/lib/utils.ts +6 -0
  56. package/templates/ui/shadcn/primitives/Button.jsx +48 -0
  57. package/templates/ui/shadcn/primitives/Button.tsx +59 -0
  58. package/templates/ui/shadcn/primitives/Card.jsx +55 -0
  59. package/templates/ui/shadcn/primitives/Card.tsx +73 -0
  60. package/templates/ui/shadcn/primitives/index.js +9 -0
  61. package/templates/ui/shadcn/primitives/index.ts +9 -0
  62. package/templates/css/bootstrap/src/themes.css +0 -14
  63. /package/templates/{css/bootstrap/src/globals.css → architectures/hybrid/src/features/.gitkeep} +0 -0
package/src/readme.js CHANGED
@@ -10,8 +10,6 @@ function buildBuiltWith(responses) {
10
10
 
11
11
  if (responses.cssFramework === "tailwind") {
12
12
  items.push("[Tailwind CSS](https://tailwindcss.com/)");
13
- } else if (responses.cssFramework === "bootstrap") {
14
- items.push("[Bootstrap](https://getbootstrap.com/)");
15
13
  }
16
14
 
17
15
  if (responses.router) {
@@ -119,6 +117,29 @@ ${nestedTree(appChildren)}
119
117
  ${nestedTree(shared)}`;
120
118
  }
121
119
 
120
+ if (responses.architecture === "hybrid") {
121
+ const shared = [
122
+ "components/ # Shared UI components",
123
+ "hooks/ # Shared custom hooks",
124
+ "layouts/ # High-level layout wrappers",
125
+ "stores/ # Global state stores",
126
+ `styles/ # ${responses.cssFramework === "none" ? "main.css (reset) + themes.css (CSS variables)" : "globals.css (framework directives) + themes.css"}`,
127
+ "types/ # Global type definitions",
128
+ "utils/ # Pure utility functions",
129
+ ];
130
+ return `src/
131
+ ├── features/ # Feature modules (domain boundaries)
132
+ └── shared/ # Reusable, business-agnostic resources
133
+ ${nestedTree(shared)}`;
134
+ }
135
+
136
+ if (responses.architecture === "none") {
137
+ return `src/
138
+ ├── App.${responses.language === "ts" ? "tsx" : "jsx"} # Root application component
139
+ ├── main.${responses.language === "ts" ? "tsx" : "jsx"} # Application entry point
140
+ └── styles/ # Stylesheets`;
141
+ }
142
+
122
143
  const rows = ["components/ # Reusable UI components (common, form)"];
123
144
  if (responses.apiClient !== "none") {
124
145
  rows.push("config/ # API configuration (axios/fetch)");
package/src/scaffold.js CHANGED
@@ -1,5 +1,7 @@
1
+ import { promises as fsp } from "fs";
1
2
  import path from "path";
2
3
  import { execa } from "execa";
4
+ import { copyDirRecursive } from "@/utils/fs.js";
3
5
  import { isYarnV1 } from "@/utils/yarn-v1.js";
4
6
 
5
7
  export async function runViteCreate(projectPath, projectName, pkg, language) {
@@ -27,3 +29,18 @@ export async function runBaseInstall(projectPath, pkg) {
27
29
  export async function runGitInit(projectPath) {
28
30
  await execa("git", ["init"], { stdio: "pipe", cwd: projectPath });
29
31
  }
32
+
33
+ export async function scaffoldBase(projectPath, provider, language, templatesDir) {
34
+ if (provider && typeof provider.getFilePlan === "function") {
35
+ const filePlan = provider.getFilePlan({ lang: language });
36
+ const baseDir = path.join(templatesDir, "..", filePlan);
37
+ try {
38
+ await fsp.access(baseDir);
39
+ await copyDirRecursive(baseDir, projectPath);
40
+ return true;
41
+ } catch {
42
+ // Base directory does not exist yet in templates/bases
43
+ }
44
+ }
45
+ return false;
46
+ }
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import ReactDOM from "react-dom/client";
3
+ import App from "./App";
4
+ import "./shared/styles/globals.css";
5
+
6
+ ReactDOM.createRoot(document.getElementById("root")).render(
7
+ <React.StrictMode>
8
+ <App />
9
+ </React.StrictMode>
10
+ );
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import ReactDOM from "react-dom/client";
3
+ import App from "./App";
4
+ import "./shared/styles/globals.css";
5
+
6
+ ReactDOM.createRoot(document.getElementById("root")!).render(
7
+ <React.StrictMode>
8
+ <App />
9
+ </React.StrictMode>
10
+ );
@@ -0,0 +1,20 @@
1
+ import { Button } from "@/shared/components/ui/Button";
2
+
3
+ export default function App() {
4
+ return (
5
+ <div
6
+ style={{
7
+ minHeight: "100vh",
8
+ display: "flex",
9
+ flexDirection: "column",
10
+ alignItems: "center",
11
+ justifyContent: "center",
12
+ backgroundColor: "var(--color-bg, #ffffff)",
13
+ }}
14
+ >
15
+ <h1>Welcome to Lumen</h1>
16
+ <p>Hybrid architecture (src/features + src/shared).</p>
17
+ <Button>Click me</Button>
18
+ </div>
19
+ );
20
+ }
@@ -0,0 +1,20 @@
1
+ import { Button } from "@/shared/components/ui/Button";
2
+
3
+ export default function App() {
4
+ return (
5
+ <div
6
+ style={{
7
+ minHeight: "100vh",
8
+ display: "flex",
9
+ flexDirection: "column",
10
+ alignItems: "center",
11
+ justifyContent: "center",
12
+ backgroundColor: "var(--color-bg, #ffffff)",
13
+ }}
14
+ >
15
+ <h1>Welcome to Lumen</h1>
16
+ <p>Hybrid architecture (src/features + src/shared).</p>
17
+ <Button>Click me</Button>
18
+ </div>
19
+ );
20
+ }
@@ -0,0 +1,31 @@
1
+ export function Button({
2
+ variant = "primary",
3
+ children,
4
+ className,
5
+ ...props
6
+ }) {
7
+ const styles = {
8
+ primary: { backgroundColor: "var(--color-primary)", color: "white" },
9
+ secondary: {
10
+ backgroundColor: "var(--color-border)",
11
+ color: "var(--color-fg)",
12
+ },
13
+ };
14
+
15
+ return (
16
+ <button
17
+ style={{
18
+ padding: "8px 16px",
19
+ borderRadius: "8px",
20
+ fontWeight: 500,
21
+ border: "none",
22
+ cursor: "pointer",
23
+ ...styles[variant],
24
+ }}
25
+ className={className}
26
+ {...props}
27
+ >
28
+ {children}
29
+ </button>
30
+ );
31
+ }
@@ -0,0 +1,36 @@
1
+ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
2
+ variant?: "primary" | "secondary";
3
+ children: React.ReactNode;
4
+ }
5
+
6
+ export function Button({
7
+ variant = "primary",
8
+ children,
9
+ className,
10
+ ...props
11
+ }: ButtonProps) {
12
+ const styles = {
13
+ primary: { backgroundColor: "var(--color-primary)", color: "white" },
14
+ secondary: {
15
+ backgroundColor: "var(--color-border)",
16
+ color: "var(--color-fg)",
17
+ },
18
+ };
19
+
20
+ return (
21
+ <button
22
+ style={{
23
+ padding: "8px 16px",
24
+ borderRadius: "8px",
25
+ fontWeight: 500,
26
+ border: "none",
27
+ cursor: "pointer",
28
+ ...styles[variant],
29
+ }}
30
+ className={className}
31
+ {...props}
32
+ >
33
+ {children}
34
+ </button>
35
+ );
36
+ }
@@ -0,0 +1 @@
1
+ export { Button } from "./Button";
@@ -0,0 +1 @@
1
+ export { Button } from "./Button";
@@ -0,0 +1,28 @@
1
+ import { useState, useCallback } from "react";
2
+
3
+ export function useLocalStorage(key, initialValue) {
4
+ const [storedValue, setStoredValue] = useState(() => {
5
+ try {
6
+ const item = window.localStorage.getItem(key);
7
+ return item ? JSON.parse(item) : initialValue;
8
+ } catch {
9
+ return initialValue;
10
+ }
11
+ });
12
+
13
+ const setValue = useCallback(
14
+ (value) => {
15
+ try {
16
+ const valueToStore =
17
+ value instanceof Function ? value(storedValue) : value;
18
+ setStoredValue(valueToStore);
19
+ window.localStorage.setItem(key, JSON.stringify(valueToStore));
20
+ } catch (error) {
21
+ console.error(error);
22
+ }
23
+ },
24
+ [key, storedValue]
25
+ );
26
+
27
+ return [storedValue, setValue];
28
+ }
@@ -0,0 +1,28 @@
1
+ import { useState, useCallback } from "react";
2
+
3
+ export function useLocalStorage<T>(key: string, initialValue: T) {
4
+ const [storedValue, setStoredValue] = useState<T>(() => {
5
+ try {
6
+ const item = window.localStorage.getItem(key);
7
+ return item ? (JSON.parse(item) as T) : initialValue;
8
+ } catch {
9
+ return initialValue;
10
+ }
11
+ });
12
+
13
+ const setValue = useCallback(
14
+ (value: T | ((prev: T) => T)) => {
15
+ try {
16
+ const valueToStore =
17
+ value instanceof Function ? value(storedValue) : value;
18
+ setStoredValue(valueToStore);
19
+ window.localStorage.setItem(key, JSON.stringify(valueToStore));
20
+ } catch (error) {
21
+ console.error(error);
22
+ }
23
+ },
24
+ [key, storedValue]
25
+ );
26
+
27
+ return [storedValue, setValue] as const;
28
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @typedef {Object} User
3
+ * @property {string} id
4
+ * @property {string} email
5
+ * @property {string} name
6
+ */
7
+
8
+ /**
9
+ * @typedef {Object} ApiResponse
10
+ * @property {*} data
11
+ * @property {string} message
12
+ * @property {boolean} success
13
+ */
14
+
15
+ /**
16
+ * @typedef {Object} CreateUserPayload
17
+ * @property {string} email
18
+ * @property {string} name
19
+ */
20
+ export {};
@@ -0,0 +1,16 @@
1
+ export interface User {
2
+ id: string;
3
+ email: string;
4
+ name: string;
5
+ }
6
+
7
+ export interface ApiResponse<T> {
8
+ data: T;
9
+ message: string;
10
+ success: boolean;
11
+ }
12
+
13
+ export interface CreateUserPayload {
14
+ email: string;
15
+ name: string;
16
+ }
@@ -0,0 +1,3 @@
1
+ export function cn(...inputs) {
2
+ return inputs.filter(Boolean).join(" ");
3
+ }
@@ -0,0 +1,5 @@
1
+ type ClassValue = string | false | null | undefined;
2
+
3
+ export function cn(...inputs: ClassValue[]): string {
4
+ return inputs.filter(Boolean).join(" ");
5
+ }
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import ReactDOM from "react-dom/client";
3
+ import App from "./App";
4
+ import "./styles/globals.css";
5
+
6
+ ReactDOM.createRoot(document.getElementById("root")).render(
7
+ <React.StrictMode>
8
+ <App />
9
+ </React.StrictMode>
10
+ );
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import ReactDOM from "react-dom/client";
3
+ import App from "./App";
4
+ import "./styles/globals.css";
5
+
6
+ ReactDOM.createRoot(document.getElementById("root")!).render(
7
+ <React.StrictMode>
8
+ <App />
9
+ </React.StrictMode>
10
+ );
@@ -0,0 +1,15 @@
1
+ export default function App() {
2
+ return (
3
+ <div
4
+ style={{
5
+ minHeight: "100vh",
6
+ display: "flex",
7
+ alignItems: "center",
8
+ justifyContent: "center",
9
+ backgroundColor: "var(--color-bg, #ffffff)",
10
+ }}
11
+ >
12
+ <h1>Welcome to Lumen</h1>
13
+ </div>
14
+ );
15
+ }
@@ -0,0 +1,15 @@
1
+ export default function App() {
2
+ return (
3
+ <div
4
+ style={{
5
+ minHeight: "100vh",
6
+ display: "flex",
7
+ alignItems: "center",
8
+ justifyContent: "center",
9
+ backgroundColor: "var(--color-bg, #ffffff)",
10
+ }}
11
+ >
12
+ <h1>Welcome to Lumen</h1>
13
+ </div>
14
+ );
15
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @typedef {Object} User
3
+ * @property {string} id
4
+ * @property {string} email
5
+ * @property {string} name
6
+ */
7
+
8
+ /**
9
+ * @typedef {Object} ApiResponse
10
+ * @property {*} data
11
+ * @property {string} message
12
+ * @property {boolean} success
13
+ */
14
+
15
+ /**
16
+ * @typedef {Object} CreateUserPayload
17
+ * @property {string} email
18
+ * @property {string} name
19
+ */
20
+ export {};
@@ -0,0 +1,16 @@
1
+ export interface User {
2
+ id: string;
3
+ email: string;
4
+ name: string;
5
+ }
6
+
7
+ export interface ApiResponse<T> {
8
+ data: T;
9
+ message: string;
10
+ success: boolean;
11
+ }
12
+
13
+ export interface CreateUserPayload {
14
+ email: string;
15
+ name: string;
16
+ }
@@ -0,0 +1,11 @@
1
+ import { describe, it, expect } from "@jest/globals";
2
+ import { render, screen } from "@testing-library/react";
3
+ import "@testing-library/jest-dom/jest-globals";
4
+ import App from "@/App";
5
+
6
+ describe("App", () => {
7
+ it("renders without crashing", () => {
8
+ render(<App />);
9
+ expect(screen.getByText(/Welcome/i)).toBeInTheDocument();
10
+ });
11
+ });
@@ -0,0 +1,11 @@
1
+ import { describe, it, expect } from "@jest/globals";
2
+ import { render, screen } from "@testing-library/react";
3
+ import "@testing-library/jest-dom/jest-globals";
4
+ import App from "@/App";
5
+
6
+ describe("App", () => {
7
+ it("renders without crashing", () => {
8
+ render(<App />);
9
+ expect(screen.getByText(/Welcome/i)).toBeInTheDocument();
10
+ });
11
+ });
@@ -0,0 +1,11 @@
1
+ import { describe, it, expect } from "@jest/globals";
2
+ import { render, screen } from "@testing-library/react";
3
+ import "@testing-library/jest-dom/jest-globals";
4
+ import App from "@/App";
5
+
6
+ describe("App", () => {
7
+ it("renders without crashing", () => {
8
+ render(<App />);
9
+ expect(screen.getByText(/Welcome/i)).toBeInTheDocument();
10
+ });
11
+ });
@@ -0,0 +1,11 @@
1
+ import { describe, it, expect } from "@jest/globals";
2
+ import { render, screen } from "@testing-library/react";
3
+ import "@testing-library/jest-dom/jest-globals";
4
+ import App from "@/App";
5
+
6
+ describe("App", () => {
7
+ it("renders without crashing", () => {
8
+ render(<App />);
9
+ expect(screen.getByText(/Welcome/i)).toBeInTheDocument();
10
+ });
11
+ });
@@ -0,0 +1,10 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import { describe, it, expect } from "vitest";
3
+ import App from "@/App";
4
+
5
+ describe("App", () => {
6
+ it("renders without crashing", () => {
7
+ render(<App />);
8
+ expect(screen.getByText(/Welcome/i)).toBeInTheDocument();
9
+ });
10
+ });
@@ -0,0 +1,10 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import { describe, it, expect } from "vitest";
3
+ import App from "@/App";
4
+
5
+ describe("App", () => {
6
+ it("renders without crashing", () => {
7
+ render(<App />);
8
+ expect(screen.getByText(/Welcome/i)).toBeInTheDocument();
9
+ });
10
+ });
@@ -0,0 +1,10 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import { describe, it, expect } from "vitest";
3
+ import App from "@/App";
4
+
5
+ describe("App", () => {
6
+ it("renders without crashing", () => {
7
+ render(<App />);
8
+ expect(screen.getByText(/Welcome/i)).toBeInTheDocument();
9
+ });
10
+ });
@@ -0,0 +1,10 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import { describe, it, expect } from "vitest";
3
+ import App from "@/App";
4
+
5
+ describe("App", () => {
6
+ it("renders without crashing", () => {
7
+ render(<App />);
8
+ expect(screen.getByText(/Welcome/i)).toBeInTheDocument();
9
+ });
10
+ });
@@ -1 +1,11 @@
1
1
  @import "tailwindcss";
2
+ @import "./themes.css";
3
+
4
+ @layer base {
5
+ * {
6
+ @apply border-border;
7
+ }
8
+ body {
9
+ @apply bg-background text-foreground;
10
+ }
11
+ }
@@ -1,9 +1,91 @@
1
1
  /* themes.css — Tailwind v4 theme tokens
2
2
  * Synced with ThemeProvider / AppProvider via
3
- * document.documentElement.dataset.theme.
3
+ * document.documentElement.dataset.theme and .dark class.
4
4
  */
5
- @custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
5
+ @custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *, .dark, .dark *));
6
6
 
7
- @theme {
8
- --color-primary: #6366f1;
7
+ @theme inline {
8
+ --color-background: var(--background);
9
+ --color-foreground: var(--foreground);
10
+ --color-card: var(--card);
11
+ --color-card-foreground: var(--card-foreground);
12
+ --color-popover: var(--popover);
13
+ --color-popover-foreground: var(--popover-foreground);
14
+ --color-primary: var(--primary);
15
+ --color-primary-foreground: var(--primary-foreground);
16
+ --color-secondary: var(--secondary);
17
+ --color-secondary-foreground: var(--secondary-foreground);
18
+ --color-muted: var(--muted);
19
+ --color-muted-foreground: var(--muted-foreground);
20
+ --color-accent: var(--accent);
21
+ --color-accent-foreground: var(--accent-foreground);
22
+ --color-destructive: var(--destructive);
23
+ --color-destructive-foreground: var(--destructive-foreground);
24
+ --color-border: var(--border);
25
+ --color-input: var(--input);
26
+ --color-ring: var(--ring);
27
+ --color-chart-1: var(--chart-1);
28
+ --color-chart-2: var(--chart-2);
29
+ --color-chart-3: var(--chart-3);
30
+ --color-chart-4: var(--chart-4);
31
+ --color-chart-5: var(--chart-5);
32
+ --radius-sm: calc(var(--radius) - 4px);
33
+ --radius-md: calc(var(--radius) - 2px);
34
+ --radius-lg: var(--radius);
35
+ --radius-xl: calc(var(--radius) + 4px);
36
+ }
37
+
38
+ :root {
39
+ --background: oklch(1 0 0);
40
+ --foreground: oklch(0.145 0 0);
41
+ --card: oklch(1 0 0);
42
+ --card-foreground: oklch(0.145 0 0);
43
+ --popover: oklch(1 0 0);
44
+ --popover-foreground: oklch(0.145 0 0);
45
+ --primary: oklch(0.205 0 0);
46
+ --primary-foreground: oklch(0.985 0 0);
47
+ --secondary: oklch(0.97 0 0);
48
+ --secondary-foreground: oklch(0.205 0 0);
49
+ --muted: oklch(0.97 0 0);
50
+ --muted-foreground: oklch(0.556 0 0);
51
+ --accent: oklch(0.97 0 0);
52
+ --accent-foreground: oklch(0.205 0 0);
53
+ --destructive: oklch(0.577 0.245 27.325);
54
+ --destructive-foreground: oklch(0.577 0.245 27.325);
55
+ --border: oklch(0.922 0 0);
56
+ --input: oklch(0.922 0 0);
57
+ --ring: oklch(0.708 0 0);
58
+ --chart-1: oklch(0.646 0.222 41.116);
59
+ --chart-2: oklch(0.6 0.118 184.704);
60
+ --chart-3: oklch(0.398 0.07 227.392);
61
+ --chart-4: oklch(0.828 0.189 84.429);
62
+ --chart-5: oklch(0.769 0.188 70.08);
63
+ --radius: 0.625rem;
64
+ }
65
+
66
+ [data-theme="dark"], .dark {
67
+ --background: oklch(0.145 0 0);
68
+ --foreground: oklch(0.985 0 0);
69
+ --card: oklch(0.145 0 0);
70
+ --card-foreground: oklch(0.985 0 0);
71
+ --popover: oklch(0.145 0 0);
72
+ --popover-foreground: oklch(0.985 0 0);
73
+ --primary: oklch(0.985 0 0);
74
+ --primary-foreground: oklch(0.205 0 0);
75
+ --secondary: oklch(0.269 0 0);
76
+ --secondary-foreground: oklch(0.985 0 0);
77
+ --muted: oklch(0.269 0 0);
78
+ --muted-foreground: oklch(0.708 0 0);
79
+ --accent: oklch(0.269 0 0);
80
+ --accent-foreground: oklch(0.985 0 0);
81
+ --destructive: oklch(0.396 0.141 25.723);
82
+ --destructive-foreground: oklch(0.637 0.237 25.331);
83
+ --border: oklch(0.269 0 0);
84
+ --input: oklch(0.269 0 0);
85
+ --ring: oklch(0.439 0 0);
86
+ --chart-1: oklch(0.488 0.243 264.376);
87
+ --chart-2: oklch(0.696 0.17 162.48);
88
+ --chart-3: oklch(0.769 0.188 70.08);
89
+ --chart-4: oklch(0.627 0.265 303.9);
90
+ --chart-5: oklch(0.645 0.246 16.439);
9
91
  }
@@ -0,0 +1,6 @@
1
+ import { clsx } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ export function cn(...inputs) {
5
+ return twMerge(clsx(inputs));
6
+ }
@@ -0,0 +1,6 @@
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
+ }