lovable-stack 1.0.3 → 1.1.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/README.md CHANGED
@@ -0,0 +1,173 @@
1
+ # Lovable Stack
2
+
3
+ Build Lovable AI projects locally without configuration stress.
4
+
5
+ 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. It does the heavy setup for you — you focus on building.
6
+
7
+ ---
8
+
9
+ ## Quick Start
10
+
11
+ 1. Create a new project:
12
+
13
+ ```bash
14
+ bunx lovable-stack my-app
15
+
16
+ Enter the project folder:
17
+
18
+ cd my-app
19
+
20
+ Install dependencies:
21
+
22
+ bun install
23
+
24
+ Start the development server:
25
+
26
+ bun run dev
27
+
28
+ Your app is now running locally.
29
+
30
+ Why Lovable Stack?
31
+
32
+ AI builders are amazing for speed. You can:
33
+
34
+ Generate a full demo site in minutes
35
+
36
+ Connect GitHub
37
+
38
+ Ship ideas fast
39
+
40
+ But when you clone that project locally, you may face:
41
+
42
+ Dependency issues
43
+
44
+ Runtime conflicts
45
+
46
+ TypeScript strict errors
47
+
48
+ Missing configuration alignment
49
+
50
+ Bun lock visible packages
51
+
52
+ Lovable Stack fixes that. It scaffolds a clean, aligned local environment so your project runs properly on your machine.
53
+
54
+ What You Get
55
+
56
+ Lovable Stack creates a fully configured project using:
57
+
58
+ Bun
59
+
60
+ React + Vite
61
+
62
+ TypeScript
63
+
64
+ Tailwind CSS
65
+
66
+ shadcn/ui
67
+
68
+ Radix UI
69
+
70
+ Everything is preconfigured and version-aligned. No manual wiring. No rebuilding the stack from scratch.
71
+
72
+ Requirements
73
+
74
+ Before using Lovable Stack, install:
75
+
76
+ Bun (latest version)
77
+
78
+ Basic knowledge of React & TypeScript
79
+
80
+ Install Bun (MacOS/Linux):
81
+
82
+ curl -fsSL https://bun.sh/install | bash
83
+
84
+ Install Bun (Windows):
85
+
86
+ powershell -c "irm bun.sh/install.ps1|iex"
87
+
88
+ Visit Bun website: https://bun.com/docs/installation
89
+
90
+ How To Use With Lovable AI
91
+
92
+ Generate your project using Lovable AI.
93
+
94
+ Copy your generated components (e.g., header.tsx, hero.tsx).
95
+
96
+ Paste them into /src/components inside your Lovable Stack project.
97
+
98
+ Continue building locally.
99
+
100
+ Now you own your code and environment.
101
+
102
+ Project Structure
103
+ my-app/
104
+ ├── src/
105
+ │ ├── components/
106
+ │ ├── pages/
107
+ │ └── main.tsx
108
+ ├── public/
109
+ ├── tsconfig.json
110
+ ├── vite.config.ts
111
+ └── bun.lock
112
+
113
+ Everything is already wired together.
114
+
115
+ Common Errors & Fixes
116
+
117
+ TypeScript “must be imported as type” error
118
+
119
+ If you see an error about importing types incorrectly, use:
120
+
121
+ import { NavLink as RouterNavLink } from "react-router-dom";
122
+ import type { NavLinkProps } from "react-router-dom";
123
+
124
+ Instead of:
125
+
126
+ import { NavLinkProps } from "react-router-dom";
127
+
128
+ This project uses strict TypeScript settings.
129
+
130
+ Reporting Issues
131
+
132
+ If you encounter an error not listed here:
133
+
134
+ Open a GitHub Issue
135
+
136
+ Include:
137
+
138
+ Your OS
139
+
140
+ Bun version
141
+
142
+ Full error message
143
+
144
+ Screenshot (if possible)
145
+
146
+ This helps improve Lovable Stack for everyone.
147
+
148
+ Philosophy
149
+
150
+ AI helps you move fast. Lovable Stack helps you move correctly.
151
+
152
+ It’s built for developers who want:
153
+
154
+ Speed without losing control
155
+
156
+ AI assistance without dependency confusion
157
+
158
+ A stable local development environment
159
+
160
+ This project is designed to work alongside Lovable AI projects.
161
+ It is not affiliated with or endorsed by Lovable.
162
+
163
+ Contributing
164
+
165
+ Contributions are welcome:
166
+
167
+ Fork the repository
168
+
169
+ Create a new branch
170
+
171
+ Submit a pull request
172
+
173
+ 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.1",
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;