lovable-stack 1.0.3 → 1.1.0

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/README.md CHANGED
@@ -0,0 +1,113 @@
1
+
2
+ Lovable-Stack
3
+ Build Lovable AI projects locally without configuration stress.
4
+ Lovable-Stack is a Bun powered project generator that recreates the working stack behind projects generated by Lovable AI, so you can run, edit, and fully own your code locally.
5
+ It does the heavy setup for you.
6
+ You focus on building.
7
+
8
+ Why Lovable-Stack?
9
+ AI builders are amazing for speed.
10
+ You can:
11
+ • Generate a full demo site in minutes
12
+ • Connect GitHub
13
+ • Ship ideas fast
14
+ But when you clone that project locally, you may face:
15
+ • Dependency issues
16
+ • Runtime conflicts
17
+ • TypeScript strict errors
18
+ • Missing configuration alignment
19
+ • Bun lock visible packages
20
+ Lovable-Stack fixes that.
21
+ It scaffolds a clean, aligned local environment so your project runs properly on your machine.
22
+
23
+ What You Get
24
+ Lovable-Stack creates a fully configured project using:
25
+ • Bun
26
+ • React-Vite
27
+ • TypeScript
28
+ • Tailwind CSS
29
+ • shadcn/ui
30
+ • Radix UI
31
+ Everything is preconfigured and version-aligned.
32
+ No manual wiring.
33
+ No rebuilding the stack from scratch.
34
+
35
+ Requirements
36
+ Before using Lovable-Stack, install:
37
+ • Bun (latest version)
38
+ • Basic knowledge of React & TypeScript
39
+ Install Bun MacOS/Linux
40
+ curl -fsSL https://bun.sh/install | bash
41
+
42
+ Install Bun Windows
43
+ powershell -c "irm bun.sh/install.ps1|iex"
44
+
45
+
46
+ YOU CAN AS WELL VISIT BUN WEBSITE:
47
+
48
+ https://bun.com/docs/installation
49
+
50
+ Quick Start
51
+ 1. Create a new project
52
+ bunx lovable-stack my-app
53
+ 2. Enter the project folder
54
+ cd my-app
55
+ 3. Install dependencies
56
+ bun install
57
+ 4. Start development server
58
+ bun run dev
59
+ Your app is now running locally.
60
+
61
+ How To Use With Lovable AI
62
+ 1. Generate your project using Lovable AI.
63
+ 2. Copy your generated components (e.g. header.tsx, hero.tsx).
64
+ 3. Paste them into /src/components inside your LovableStack project.
65
+ 4. Continue building locally.
66
+ Now you own your code and environment.
67
+
68
+ Project Structure
69
+ my-app/
70
+ ├── src/
71
+ │ ├── components/
72
+ │ ├── pages/
73
+ │ └── main.tsx
74
+ ├── public/
75
+ ├── tsconfig.json
76
+ ├── vite.config.ts
77
+ └── bun.lock
78
+ Everything is already wired together.
79
+ Common Errors & Fixes
80
+ TypeScript “must be imported as type” error
81
+ If you see an error about importing types incorrectly, use:
82
+ import { NavLink as RouterNavLink } from "react-router-dom";
83
+ import type { NavLinkProps } from "react-router-dom";
84
+ Instead of:
85
+ import { NavLinkProps } from "react-router-dom"";
86
+ This project uses strict TypeScript settings.
87
+
88
+ Reporting Issues
89
+ If you encounter an error not listed here:
90
+ 1. Open a GitHub Issue
91
+ 2. Include:
92
+ o Your OS
93
+ o Bun version
94
+ o Full error message
95
+ o Screenshot (if possible)
96
+ This helps improve Lovable-Stack for everyone.
97
+
98
+ Philosophy
99
+ AI helps you move fast.
100
+ Lovable-Stack helps you move correctly.
101
+ It’s built for developers who want:
102
+ • Speed without losing control
103
+ • AI assistance without dependency confusion
104
+ • A stable local development environment
105
+ This project is designed to work alongside Lovable AI projects.
106
+ It is not affiliated with or endorsed by Lovable.
107
+
108
+ Contributing
109
+ Contributions are welcome.
110
+ 1. Fork the repository
111
+ 2. Create a new branch
112
+ 3. Submit a pull request
113
+ If you’ve solved an issue or improved the developer experience, feel free to contribute.
package/bin/index.js CHANGED
@@ -1,13 +1,90 @@
1
1
  #!/usr/bin/env node
2
- const fs = require("fs-extra");
3
- const path = require("path");
4
2
 
5
- const args = process.argv.slice(2);
6
- const projectName = args[0] || "my-new-project";
3
+ import fs from "fs-extra";
4
+ import path from "path";
5
+ import inquirer from "inquirer";
6
+ import chalk from "chalk";
7
+ import ora from "ora";
8
+ import { fileURLToPath } from "url";
7
9
 
8
- const templatePath = path.join(__dirname, "../template");
9
- const targetPath = path.join(process.cwd(), projectName);
10
+ /**
11
+ * Recreate __dirname in ESM (cross-platform safe)
12
+ */
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = path.dirname(__filename);
10
15
 
11
- fs.copySync(templatePath, targetPath);
16
+ async function run() {
17
+ const args = process.argv.slice(2);
18
+ let projectName = args[0];
12
19
 
13
- console.log(`✅ Project "${projectName}" created from lovable-stack template.`);
20
+ // 1️⃣ Ask for project name if missing
21
+ if (!projectName) {
22
+ const answers = await inquirer.prompt([
23
+ {
24
+ type: "input",
25
+ name: "projectName",
26
+ message: "What is your project name?",
27
+ default: "my-new-project",
28
+ },
29
+ ]);
30
+
31
+ projectName = answers.projectName.trim();
32
+ }
33
+
34
+ if (!projectName) {
35
+ console.log(chalk.red("Project name cannot be empty."));
36
+ process.exit(1);
37
+ }
38
+
39
+ const templatePath = path.resolve(__dirname, "../template");
40
+ const targetPath = path.resolve(process.cwd(), projectName);
41
+
42
+ // Safety check: template must exist
43
+ if (!fs.existsSync(templatePath)) {
44
+ console.log(chalk.red("Template folder not found."));
45
+ process.exit(1);
46
+ }
47
+
48
+ // 2️⃣ Check if folder exists
49
+ if (fs.existsSync(targetPath)) {
50
+ const { overwrite } = await inquirer.prompt([
51
+ {
52
+ type: "confirm",
53
+ name: "overwrite",
54
+ message: `Folder "${projectName}" already exists. Overwrite?`,
55
+ default: false,
56
+ },
57
+ ]);
58
+
59
+ if (!overwrite) {
60
+ console.log(chalk.yellow("Operation cancelled."));
61
+ process.exit(0);
62
+ }
63
+
64
+ await fs.remove(targetPath);
65
+ }
66
+
67
+ // 3️⃣ Spinner while copying
68
+ const spinner = ora("Creating project...").start();
69
+
70
+ try {
71
+ await fs.copy(templatePath, targetPath);
72
+ spinner.succeed("Project created successfully!");
73
+ } catch (err) {
74
+ spinner.fail("Failed to create project.");
75
+ console.error(err);
76
+ process.exit(1);
77
+ }
78
+
79
+ // 4️⃣ Final message
80
+ console.log(`
81
+ ${chalk.green("Success!")} Your project is ready.
82
+
83
+ Next steps:
84
+ cd ${projectName}
85
+ bun install
86
+ bun run dev
87
+ `);
88
+ }
89
+
90
+ run();
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "lovable-stack",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
+ "type": "module",
4
5
  "bin": {
5
- "lovable-stack": "bin/index.js"
6
+ "lovable-stack": "bin/index.mjs"
6
7
  },
7
8
  "files": [
8
9
  "bin/",
@@ -10,6 +11,9 @@
10
11
  "README.md"
11
12
  ],
12
13
  "dependencies": {
13
- "fs-extra": "^11.1.1"
14
+ "chalk": "^5.6.2",
15
+ "fs-extra": "^11.3.3",
16
+ "inquirer": "^13.3.0",
17
+ "ora": "6"
14
18
  }
15
- }
19
+ }
package/template/bun.lock CHANGED
@@ -3,7 +3,7 @@
3
3
  "configVersion": 1,
4
4
  "workspaces": {
5
5
  "": {
6
- "name": "my-app",
6
+ "name": "lovable-stack",
7
7
  "dependencies": {
8
8
  "@hookform/resolvers": "^5.2.2",
9
9
  "@radix-ui/react-accordion": "^1.2.12",
@@ -0,0 +1,42 @@
1
+ #root {
2
+ max-width: 1280px;
3
+ margin: 0 auto;
4
+ padding: 2rem;
5
+ text-align: center;
6
+ }
7
+
8
+ .logo {
9
+ height: 6em;
10
+ padding: 1.5em;
11
+ will-change: filter;
12
+ transition: filter 300ms;
13
+ }
14
+ .logo:hover {
15
+ filter: drop-shadow(0 0 2em #646cffaa);
16
+ }
17
+ .logo.react:hover {
18
+ filter: drop-shadow(0 0 2em #61dafbaa);
19
+ }
20
+
21
+ @keyframes logo-spin {
22
+ from {
23
+ transform: rotate(0deg);
24
+ }
25
+ to {
26
+ transform: rotate(360deg);
27
+ }
28
+ }
29
+
30
+ @media (prefers-reduced-motion: no-preference) {
31
+ a:nth-of-type(2) .logo {
32
+ animation: logo-spin infinite 20s linear;
33
+ }
34
+ }
35
+
36
+ .card {
37
+ padding: 2em;
38
+ }
39
+
40
+ .read-the-docs {
41
+ color: #888;
42
+ }
@@ -3,14 +3,25 @@ import { Toaster as Sonner } from "@/components/ui/sonner";
3
3
  import { TooltipProvider } from "@/components/ui/tooltip";
4
4
  import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
5
5
  import { BrowserRouter, Routes, Route } from "react-router-dom";
6
-
6
+ import Index from "./pages/Index";
7
+ import NotFound from "./pages/NotFound";
7
8
 
8
9
  const queryClient = new QueryClient();
9
10
 
10
11
  const App = () => (
11
- <>
12
- hello
13
- </>
12
+ <QueryClientProvider client={queryClient}>
13
+ <TooltipProvider>
14
+ <Toaster />
15
+ <Sonner />
16
+ <BrowserRouter>
17
+ <Routes>
18
+ <Route path="/" element={<Index />} />
19
+ {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
20
+ <Route path="*" element={<NotFound />} />
21
+ </Routes>
22
+ </BrowserRouter>
23
+ </TooltipProvider>
24
+ </QueryClientProvider>
14
25
  );
15
26
 
16
27
  export default App;
@@ -0,0 +1,29 @@
1
+ import { NavLink as RouterNavLink } from "react-router-dom";
2
+ import type { NavLinkProps } from "react-router-dom";
3
+ import { forwardRef } from "react";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ interface NavLinkCompatProps extends Omit<NavLinkProps, "className"> {
7
+ className?: string;
8
+ activeClassName?: string;
9
+ pendingClassName?: string;
10
+ }
11
+
12
+ const NavLink = forwardRef<HTMLAnchorElement, NavLinkCompatProps>(
13
+ ({ className, activeClassName, pendingClassName, to, ...props }, ref) => {
14
+ return (
15
+ <RouterNavLink
16
+ ref={ref}
17
+ to={to}
18
+ className={({ isActive, isPending }) =>
19
+ cn(className, isActive && activeClassName, isPending && pendingClassName)
20
+ }
21
+ {...props}
22
+ />
23
+ );
24
+ },
25
+ );
26
+
27
+ NavLink.displayName = "NavLink";
28
+
29
+ export { NavLink };
@@ -1,43 +1,139 @@
1
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
1
2
  @tailwind base;
2
3
  @tailwind components;
3
4
  @tailwind utilities;
4
5
 
5
- /* Minimal resets only - no custom themes per requirements */
6
+
7
+ @layer base {
8
+ :root {
9
+ --background: 240 20% 97%;
10
+ --foreground: 230 25% 18%;
11
+
12
+ --card: 0 0% 100%;
13
+ --card-foreground: 230 25% 18%;
14
+
15
+ --popover: 0 0% 100%;
16
+ --popover-foreground: 230 25% 18%;
17
+
18
+ --primary: 340 65% 60%;
19
+ --primary-foreground: 0 0% 100%;
20
+
21
+ --secondary: 240 15% 93%;
22
+ --secondary-foreground: 230 25% 18%;
23
+
24
+ --muted: 240 12% 92%;
25
+ --muted-foreground: 230 10% 46%;
26
+
27
+ --accent: 260 30% 94%;
28
+ --accent-foreground: 230 25% 18%;
29
+
30
+ --destructive: 0 84.2% 60.2%;
31
+ --destructive-foreground: 210 40% 98%;
32
+
33
+ --border: 240 12% 90%;
34
+ --input: 240 12% 90%;
35
+ --ring: 340 65% 60%;
36
+
37
+ --radius: 0.75rem;
38
+
39
+ --gradient-hero: linear-gradient(135deg, hsl(240 20% 97%) 0%, hsl(330 30% 95%) 50%, hsl(260 25% 95%) 100%);
40
+ --shadow-soft: 0 4px 24px -4px hsl(230 25% 18% / 0.06);
41
+ --shadow-card: 0 1px 12px -2px hsl(230 25% 18% / 0.05);
42
+
43
+ --sidebar-background: 0 0% 98%;
44
+ --sidebar-foreground: 240 5.3% 26.1%;
45
+ --sidebar-primary: 240 5.9% 10%;
46
+ --sidebar-primary-foreground: 0 0% 98%;
47
+ --sidebar-accent: 240 4.8% 95.9%;
48
+ --sidebar-accent-foreground: 240 5.9% 10%;
49
+ --sidebar-border: 220 13% 91%;
50
+ --sidebar-ring: 217.2 91.2% 59.8%;
51
+ }
52
+
53
+ .dark {
54
+ --background: 230 20% 8%;
55
+ --foreground: 220 20% 92%;
56
+ --card: 230 18% 12%;
57
+ --card-foreground: 220 20% 92%;
58
+ --popover: 230 18% 12%;
59
+ --popover-foreground: 220 20% 92%;
60
+ --primary: 340 65% 60%;
61
+ --primary-foreground: 0 0% 100%;
62
+ --secondary: 230 15% 16%;
63
+ --secondary-foreground: 220 20% 92%;
64
+ --muted: 230 12% 18%;
65
+ --muted-foreground: 220 10% 55%;
66
+ --accent: 260 20% 18%;
67
+ --accent-foreground: 220 20% 92%;
68
+ --destructive: 0 62.8% 30.6%;
69
+ --destructive-foreground: 210 40% 98%;
70
+ --border: 230 12% 20%;
71
+ --input: 230 12% 20%;
72
+ --ring: 340 65% 60%;
73
+ --gradient-hero: linear-gradient(135deg, hsl(230 20% 8%) 0%, hsl(330 15% 12%) 50%, hsl(260 15% 12%) 100%);
74
+ --shadow-soft: 0 4px 24px -4px hsl(0 0% 0% / 0.3);
75
+ --shadow-card: 0 1px 12px -2px hsl(0 0% 0% / 0.2);
76
+ --sidebar-background: 240 5.9% 10%;
77
+ --sidebar-foreground: 240 4.8% 95.9%;
78
+ --sidebar-primary: 224.3 76.3% 48%;
79
+ --sidebar-primary-foreground: 0 0% 100%;
80
+ --sidebar-accent: 240 3.7% 15.9%;
81
+ --sidebar-accent-foreground: 240 4.8% 95.9%;
82
+ --sidebar-border: 240 3.7% 15.9%;
83
+ --sidebar-ring: 217.2 91.2% 59.8%;
84
+ }
85
+ }
86
+
6
87
  @layer base {
7
88
  * {
8
- scroll-behavior: smooth;
89
+ @apply border-border;
9
90
  }
10
-
11
91
  body {
12
- font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
92
+ @apply bg-background text-foreground;
93
+ font-family: 'Inter', system-ui, sans-serif;
13
94
  }
14
95
  }
15
96
 
16
- @layer utilities {
17
- .animate-fade-in {
18
- animation: fadeIn 0.5s ease-out forwards;
97
+ @keyframes glow-pulse {
98
+ 0%, 100% {
99
+ filter: drop-shadow(0 0 8px hsl(340 65% 60% / 0.6)) drop-shadow(0 0 20px hsl(340 65% 60% / 0.3));
100
+ transform: scale(1);
19
101
  }
20
-
21
- .animate-slide-up {
22
- animation: slideUp 0.6s ease-out forwards;
23
- }
24
-
25
- .animate-pulse-soft {
26
- animation: pulseSoft 2s ease-in-out infinite;
102
+ 50% {
103
+ filter: drop-shadow(0 0 16px hsl(340 65% 60% / 0.8)) drop-shadow(0 0 40px hsl(340 65% 60% / 0.5));
104
+ transform: scale(1.1);
27
105
  }
28
106
  }
29
107
 
30
- @keyframes fadeIn {
31
- from { opacity: 0; }
32
- to { opacity: 1; }
108
+ .glow-heart {
109
+ display: inline-block;
110
+ animation: glow-pulse 2s ease-in-out infinite;
111
+ }
112
+
113
+ @keyframes typing {
114
+ from { width: 0; }
115
+ to { width: 100%; }
116
+ }
117
+
118
+ @keyframes blink-caret {
119
+ from, to { border-color: transparent; }
120
+ 50% { border-color: hsl(var(--primary)); }
33
121
  }
34
122
 
35
- @keyframes slideUp {
36
- from { opacity: 0; transform: translateY(20px); }
37
- to { opacity: 1; transform: translateY(0); }
123
+ .typing-text {
124
+ display: inline-block;
125
+ overflow: hidden;
126
+ white-space: nowrap;
127
+ border-right: 2px solid hsl(var(--primary));
128
+ width: 0;
129
+ animation:
130
+ typing-loop 7s steps(26, end) infinite,
131
+ blink-caret 0.75s step-end infinite;
38
132
  }
39
133
 
40
- @keyframes pulseSoft {
41
- 0%, 100% { opacity: 1; }
42
- 50% { opacity: 0.7; }
134
+ @keyframes typing-loop {
135
+ 0% { width: 0; }
136
+ 28% { width: 100%; } /* typed by ~2s */
137
+ 86% { width: 100%; } /* hold until ~6s */
138
+ 100% { width: 0; } /* reset */
43
139
  }
@@ -0,0 +1,97 @@
1
+ const steps = [
2
+ { num: "1️⃣", text: "Go to Lovable AI" },
3
+ { num: "2️⃣", text: "Generate your UI" },
4
+ { num: "3️⃣", text: "Copy the generated source files" },
5
+ { num: "4️⃣", text: "Replace the matching files in your local project" },
6
+ { num: "5️⃣", text: "Run the project again" },
7
+ ];
8
+
9
+ const editableFiles = [
10
+ "src/components/*",
11
+ "src/pages/*",
12
+ "src/App.tsx",
13
+ "src/App.css",
14
+ "src/index.css",
15
+ "index.html",
16
+ "tailwind.config.ts",
17
+ "package.json (name only)",
18
+ ];
19
+
20
+ const Index = () => {
21
+ return (
22
+ <div className="min-h-screen" style={{ background: "var(--gradient-hero)" }}>
23
+ <div className="mx-auto max-w-3xl px-6 py-20 space-y-16">
24
+
25
+ {/* Hero */}
26
+ <section className="text-center space-y-5 pt-12 pb-4">
27
+ <div className="text-4xl sm:text-5xl font-bold tracking-tight text-foreground">
28
+ <span className="glow-heart text-5xl sm:text-6xl">💖</span>
29
+ <h1 className="typing-text text-4xl sm:text-5xl font-bold tracking-tight text-foreground mx-auto mt-3" style={{ maxWidth: 'max-content' }}>
30
+ Welcome to Lovable Stack
31
+ </h1>
32
+ </div>
33
+ <p className="text-lg text-muted-foreground font-medium">
34
+ AI-assisted building, fully editable by you.
35
+ </p>
36
+ <p className="text-sm text-muted-foreground leading-relaxed max-w-md mx-auto">
37
+ Lovable AI generated your initial layout.
38
+ <br />
39
+ Now it's yours to shape.
40
+ </p>
41
+ </section>
42
+
43
+ {/* How It Works */}
44
+ <section className="rounded-2xl bg-card p-8 sm:p-10 space-y-6" style={{ boxShadow: "var(--shadow-soft)" }}>
45
+ <h2 className="text-2xl font-semibold text-foreground">
46
+ 💖 How Lovable AI Works With Your Project
47
+ </h2>
48
+ <p className="text-sm text-muted-foreground">
49
+ Lovable Stack ships with a starter demo template. When you generate a project using Lovable AI:
50
+ </p>
51
+ <ol className="space-y-3">
52
+ {steps.map((s) => (
53
+ <li key={s.num} className="flex items-start gap-3 text-sm text-foreground">
54
+ <span className="shrink-0 text-base">{s.num}</span>
55
+ <span>{s.text}</span>
56
+ </li>
57
+ ))}
58
+ </ol>
59
+ <p className="text-sm font-medium text-primary">Done.</p>
60
+ </section>
61
+
62
+ {/* Editable Files */}
63
+ <section className="rounded-2xl bg-card p-8 sm:p-10 space-y-6" style={{ boxShadow: "var(--shadow-soft)" }}>
64
+ <h2 className="text-2xl font-semibold text-foreground">
65
+ 🧩 Editable Files
66
+ </h2>
67
+ <p className="text-sm text-muted-foreground">
68
+ Only these files should be replaced when updating from Lovable AI:
69
+ </p>
70
+ <ul className="grid gap-2">
71
+ {editableFiles.map((f) => (
72
+ <li key={f} className="rounded-lg bg-secondary px-4 py-2.5 text-sm font-mono text-secondary-foreground">
73
+ {f}
74
+ </li>
75
+ ))}
76
+ </ul>
77
+ <div className="rounded-xl bg-muted p-5 space-y-2 mt-4">
78
+ <p className="text-sm text-foreground font-medium">Architecture note</p>
79
+ <p className="text-sm text-muted-foreground leading-relaxed">
80
+ The base template handles tooling, configuration, and environment setup.
81
+ Lovable AI only replaces UI and layout logic.
82
+ This separation keeps your project stable.
83
+ </p>
84
+ </div>
85
+ </section>
86
+
87
+ <footer className="text-center pb-8">
88
+ <p className="text-xs text-muted-foreground">
89
+ Built with Lovable Stack
90
+ </p>
91
+ </footer>
92
+ </div>
93
+ </div>
94
+ );
95
+ };
96
+
97
+ export default Index;
@@ -0,0 +1,24 @@
1
+ import { useLocation } from "react-router-dom";
2
+ import { useEffect } from "react";
3
+
4
+ const NotFound = () => {
5
+ const location = useLocation();
6
+
7
+ useEffect(() => {
8
+ console.error("404 Error: User attempted to access non-existent route:", location.pathname);
9
+ }, [location.pathname]);
10
+
11
+ return (
12
+ <div className="flex min-h-screen items-center justify-center bg-muted">
13
+ <div className="text-center">
14
+ <h1 className="mb-4 text-4xl font-bold">404</h1>
15
+ <p className="mb-4 text-xl text-muted-foreground">Oops! Page not found</p>
16
+ <a href="/" className="text-primary underline hover:text-primary/90">
17
+ Return to Home
18
+ </a>
19
+ </div>
20
+ </div>
21
+ );
22
+ };
23
+
24
+ export default NotFound;
@@ -0,0 +1,91 @@
1
+ import type { Config } from "tailwindcss";
2
+
3
+ export default {
4
+ darkMode: ["class"],
5
+ content: ["./pages/**/*.{ts,tsx}", "./components/**/*.{ts,tsx}", "./app/**/*.{ts,tsx}", "./src/**/*.{ts,tsx}"],
6
+ prefix: "",
7
+ theme: {
8
+ container: {
9
+ center: true,
10
+ padding: "2rem",
11
+ screens: {
12
+ "2xl": "1400px",
13
+ },
14
+ },
15
+ extend: {
16
+ colors: {
17
+ border: "hsl(var(--border))",
18
+ input: "hsl(var(--input))",
19
+ ring: "hsl(var(--ring))",
20
+ background: "hsl(var(--background))",
21
+ foreground: "hsl(var(--foreground))",
22
+ primary: {
23
+ DEFAULT: "hsl(var(--primary))",
24
+ foreground: "hsl(var(--primary-foreground))",
25
+ },
26
+ secondary: {
27
+ DEFAULT: "hsl(var(--secondary))",
28
+ foreground: "hsl(var(--secondary-foreground))",
29
+ },
30
+ destructive: {
31
+ DEFAULT: "hsl(var(--destructive))",
32
+ foreground: "hsl(var(--destructive-foreground))",
33
+ },
34
+ muted: {
35
+ DEFAULT: "hsl(var(--muted))",
36
+ foreground: "hsl(var(--muted-foreground))",
37
+ },
38
+ accent: {
39
+ DEFAULT: "hsl(var(--accent))",
40
+ foreground: "hsl(var(--accent-foreground))",
41
+ },
42
+ popover: {
43
+ DEFAULT: "hsl(var(--popover))",
44
+ foreground: "hsl(var(--popover-foreground))",
45
+ },
46
+ card: {
47
+ DEFAULT: "hsl(var(--card))",
48
+ foreground: "hsl(var(--card-foreground))",
49
+ },
50
+ sidebar: {
51
+ DEFAULT: "hsl(var(--sidebar-background))",
52
+ foreground: "hsl(var(--sidebar-foreground))",
53
+ primary: "hsl(var(--sidebar-primary))",
54
+ "primary-foreground": "hsl(var(--sidebar-primary-foreground))",
55
+ accent: "hsl(var(--sidebar-accent))",
56
+ "accent-foreground": "hsl(var(--sidebar-accent-foreground))",
57
+ border: "hsl(var(--sidebar-border))",
58
+ ring: "hsl(var(--sidebar-ring))",
59
+ },
60
+ },
61
+ borderRadius: {
62
+ lg: "var(--radius)",
63
+ md: "calc(var(--radius) - 2px)",
64
+ sm: "calc(var(--radius) - 4px)",
65
+ },
66
+ keyframes: {
67
+ "accordion-down": {
68
+ from: {
69
+ height: "0",
70
+ },
71
+ to: {
72
+ height: "var(--radix-accordion-content-height)",
73
+ },
74
+ },
75
+ "accordion-up": {
76
+ from: {
77
+ height: "var(--radix-accordion-content-height)",
78
+ },
79
+ to: {
80
+ height: "0",
81
+ },
82
+ },
83
+ },
84
+ animation: {
85
+ "accordion-down": "accordion-down 0.2s ease-out",
86
+ "accordion-up": "accordion-up 0.2s ease-out",
87
+ },
88
+ },
89
+ },
90
+ plugins: [require("tailwindcss-animate")],
91
+ } satisfies Config;