kofi-stack-template-generator 2.1.28 → 2.1.36

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 (44) hide show
  1. package/.turbo/turbo-build.log +6 -6
  2. package/.turbo/turbo-typecheck.log +1 -1
  3. package/dist/index.js +1023 -4
  4. package/package.json +1 -1
  5. package/src/generator.ts +57 -0
  6. package/src/templates.generated.ts +40 -6
  7. package/templates/admin/next.config.ts.hbs +7 -0
  8. package/templates/admin/package.json.hbs +38 -0
  9. package/templates/admin/postcss.config.mjs.hbs +7 -0
  10. package/templates/admin/src/app/analytics/page.tsx.hbs +39 -0
  11. package/templates/admin/src/app/globals.css.hbs +2 -0
  12. package/templates/admin/src/app/layout.tsx.hbs +33 -0
  13. package/templates/admin/src/app/page.tsx.hbs +47 -0
  14. package/templates/admin/src/app/settings/page.tsx.hbs +74 -0
  15. package/templates/admin/src/app/users/page.tsx.hbs +16 -0
  16. package/templates/admin/src/components/admin-sidebar.tsx.hbs +51 -0
  17. package/templates/admin/src/components/stats-cards.tsx.hbs +28 -0
  18. package/templates/admin/src/components/user-table.tsx.hbs +65 -0
  19. package/templates/admin/tsconfig.json.hbs +15 -0
  20. package/templates/design-system/next.config.ts.hbs +7 -0
  21. package/templates/design-system/package.json.hbs +35 -0
  22. package/templates/design-system/postcss.config.mjs.hbs +7 -0
  23. package/templates/design-system/src/app/blocks/page.tsx.hbs +140 -0
  24. package/templates/design-system/src/app/colors/page.tsx.hbs +34 -0
  25. package/templates/design-system/src/app/components/page.tsx.hbs +110 -0
  26. package/templates/design-system/src/app/globals.css.hbs +2 -0
  27. package/templates/design-system/src/app/layout.tsx.hbs +46 -0
  28. package/templates/design-system/src/app/page.tsx.hbs +65 -0
  29. package/templates/design-system/src/app/typography/page.tsx.hbs +112 -0
  30. package/templates/design-system/src/components/color-palette.tsx.hbs +117 -0
  31. package/templates/design-system/tsconfig.json.hbs +13 -0
  32. package/templates/marketing/nextjs/package.json.hbs +1 -1
  33. package/templates/marketing/payload/package.json.hbs +1 -1
  34. package/templates/mobile/app.json.hbs +39 -0
  35. package/templates/mobile/babel.config.js.hbs +6 -0
  36. package/templates/mobile/package.json.hbs +30 -0
  37. package/templates/mobile/src/app/(tabs)/_layout.tsx.hbs +27 -0
  38. package/templates/mobile/src/app/(tabs)/index.tsx.hbs +28 -0
  39. package/templates/mobile/src/app/(tabs)/profile.tsx.hbs +44 -0
  40. package/templates/mobile/src/app/_layout.tsx.hbs +13 -0
  41. package/templates/mobile/src/app/index.tsx.hbs +5 -0
  42. package/templates/mobile/tsconfig.json.hbs +10 -0
  43. package/templates/monorepo/package.json.hbs +4 -1
  44. package/templates/web/package.json.hbs +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kofi-stack-template-generator",
3
- "version": "2.1.28",
3
+ "version": "2.1.36",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
package/src/generator.ts CHANGED
@@ -37,6 +37,17 @@ export async function generateVirtualProject(
37
37
  } else if (config.marketingSite === 'nextjs') {
38
38
  await processMarketingTemplates(vfs, config)
39
39
  }
40
+
41
+ // Optional apps (monorepo only)
42
+ if (config.optionalApps?.includes('design-system')) {
43
+ await processDesignSystemTemplates(vfs, config)
44
+ }
45
+ if (config.optionalApps?.includes('mobile')) {
46
+ await processMobileTemplates(vfs, config)
47
+ }
48
+ if (config.optionalApps?.includes('admin')) {
49
+ await processAdminTemplates(vfs, config)
50
+ }
40
51
  }
41
52
 
42
53
  await processIntegrationTemplates(vfs, config)
@@ -154,6 +165,27 @@ async function processMarketingTemplates(
154
165
  processTemplatesFromPrefix(vfs, 'marketing/nextjs/', '/apps/marketing', config)
155
166
  }
156
167
 
168
+ async function processDesignSystemTemplates(
169
+ vfs: VirtualFileSystem,
170
+ config: ProjectConfig
171
+ ): Promise<void> {
172
+ processTemplatesFromPrefix(vfs, 'design-system/', '/apps/design-system', config)
173
+ }
174
+
175
+ async function processMobileTemplates(
176
+ vfs: VirtualFileSystem,
177
+ config: ProjectConfig
178
+ ): Promise<void> {
179
+ processTemplatesFromPrefix(vfs, 'mobile/', '/apps/mobile', config)
180
+ }
181
+
182
+ async function processAdminTemplates(
183
+ vfs: VirtualFileSystem,
184
+ config: ProjectConfig
185
+ ): Promise<void> {
186
+ processTemplatesFromPrefix(vfs, 'admin/', '/apps/admin', config)
187
+ }
188
+
157
189
  async function processIntegrationTemplates(
158
190
  vfs: VirtualFileSystem,
159
191
  config: ProjectConfig
@@ -210,6 +242,11 @@ function generateDevScript(
210
242
  const webAppDir = isMonorepo ? 'apps/web' : '.'
211
243
  const backendDir = isMonorepo ? 'packages/backend' : '.'
212
244
 
245
+ // Build dynamic ports array based on config
246
+ const ports = [3000, 3001] // marketing, web
247
+ if (config.optionalApps?.includes('design-system')) ports.push(3002)
248
+ if (config.optionalApps?.includes('admin')) ports.push(3003)
249
+
213
250
  const devScript = `#!/usr/bin/env node
214
251
  /**
215
252
  * Dev Script - Starts Next.js and Convex dev servers
@@ -225,6 +262,26 @@ const rootDir = resolve(__dirname, '..')
225
262
  const webAppDir = resolve(rootDir, '${webAppDir}')
226
263
  const backendDir = resolve(rootDir, '${backendDir}')
227
264
 
265
+ // Kill process on a given port
266
+ function killPort(port) {
267
+ try {
268
+ const platform = process.platform
269
+ if (platform === 'darwin' || platform === 'linux') {
270
+ execSync(\`lsof -ti:\${port} | xargs kill -9 2>/dev/null || true\`, { stdio: 'ignore' })
271
+ } else if (platform === 'win32') {
272
+ execSync(\`for /f "tokens=5" %a in ('netstat -ano ^| findstr :\${port} ^| findstr LISTENING') do taskkill /F /PID %a 2>nul\`, { stdio: 'ignore', shell: 'cmd' })
273
+ }
274
+ } catch (e) {
275
+ // Port not in use or already free
276
+ }
277
+ }
278
+
279
+ // Free up app ports before starting
280
+ const APP_PORTS = [${ports.join(', ')}]
281
+ console.log('Freeing ports...')
282
+ APP_PORTS.forEach(killPort)
283
+ console.log('')
284
+
228
285
  function loadEnvFile(dir) {
229
286
  const envPath = resolve(dir, '.env.local')
230
287
  if (!existsSync(envPath)) return {}
@@ -1,9 +1,22 @@
1
1
  // Auto-generated file. Do not edit manually.
2
2
  // Run 'pnpm prebuild' to regenerate.
3
- // Generated: 2026-01-15T14:51:08.245Z
4
- // Template count: 149
3
+ // Generated: 2026-01-15T23:49:19.160Z
4
+ // Template count: 183
5
5
 
6
6
  export const EMBEDDED_TEMPLATES: Record<string, string> = {
7
+ "admin/next.config.ts.hbs": "import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {\n transpilePackages: ['@repo/ui', '@repo/backend'],\n}\n\nexport default nextConfig\n",
8
+ "admin/package.json.hbs": "{\n \"name\": \"@repo/admin\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev --turbopack --port 3003\",\n \"build\": \"next build\",\n \"start\": \"next start\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"dependencies\": {\n \"@repo/ui\": \"workspace:*\",\n \"@repo/backend\": \"workspace:*\",\n \"next\": \"^16.0.0\",\n \"react\": \"^19.0.0\",\n \"react-dom\": \"^19.0.0\",\n \"next-themes\": \"^0.4.6\",\n \"convex\": \"^1.25.0\",\n \"better-auth\": \"1.4.9\",\n{{#if (eq shadcn.iconLibrary \"hugeicons\")}} \"@hugeicons/react\": \"^0.3.0\"\n{{/if}}{{#if (eq shadcn.iconLibrary \"lucide\")}} \"lucide-react\": \"^0.469.0\"\n{{/if}}{{#if (eq shadcn.iconLibrary \"tabler\")}} \"@tabler/icons-react\": \"^3.31.0\"\n{{/if}}{{#if (eq shadcn.iconLibrary \"phosphor\")}} \"@phosphor-icons/react\": \"^2.1.7\"\n{{/if}} },\n \"devDependencies\": {\n \"@repo/config-typescript\": \"workspace:*\",\n \"@types/node\": \"^20.0.0\",\n \"@types/react\": \"^19.0.0\",\n \"@types/react-dom\": \"^19.0.0\",\n \"tailwindcss\": \"^4.0.0\",\n \"@tailwindcss/postcss\": \"^4.0.0\",\n \"postcss\": \"^8.4.0\",\n \"typescript\": \"^5.0.0\"\n }\n}\n",
9
+ "admin/postcss.config.mjs.hbs": "const config = {\n plugins: {\n '@tailwindcss/postcss': {},\n },\n}\n\nexport default config\n",
10
+ "admin/src/app/analytics/page.tsx.hbs": "import { StatsCards } from '@/components/stats-cards'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@repo/ui/components/card'\n\nexport default function AnalyticsPage() {\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-3xl font-bold tracking-tight\">Analytics</h1>\n <p className=\"text-muted-foreground\">\n View detailed analytics and insights.\n </p>\n </div>\n\n <StatsCards />\n\n <div className=\"grid gap-6 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>User Growth</CardTitle>\n <CardDescription>New users over time</CardDescription>\n </CardHeader>\n <CardContent className=\"h-[300px] flex items-center justify-center\">\n <p className=\"text-sm text-muted-foreground\">Chart placeholder</p>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Session Duration</CardTitle>\n <CardDescription>Average session length</CardDescription>\n </CardHeader>\n <CardContent className=\"h-[300px] flex items-center justify-center\">\n <p className=\"text-sm text-muted-foreground\">Chart placeholder</p>\n </CardContent>\n </Card>\n </div>\n </div>\n )\n}\n",
11
+ "admin/src/app/globals.css.hbs": "@import \"tailwindcss\";\n@import \"@repo/ui/styles.css\";\n",
12
+ "admin/src/app/layout.tsx.hbs": "import type { Metadata } from 'next'\nimport { ThemeProvider } from 'next-themes'\nimport { AdminSidebar } from '@/components/admin-sidebar'\nimport './globals.css'\n\nexport const metadata: Metadata = {\n title: '{{projectName}} Admin',\n description: 'Admin dashboard for {{projectName}}',\n}\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode\n}) {\n return (\n <html lang=\"en\" suppressHydrationWarning>\n <body className=\"min-h-screen bg-background font-sans antialiased\">\n <ThemeProvider\n attribute=\"class\"\n defaultTheme=\"system\"\n enableSystem\n disableTransitionOnChange\n >\n <div className=\"flex min-h-screen\">\n <AdminSidebar />\n <main className=\"flex-1 p-8\">{children}</main>\n </div>\n </ThemeProvider>\n </body>\n </html>\n )\n}\n",
13
+ "admin/src/app/page.tsx.hbs": "import { StatsCards } from '@/components/stats-cards'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@repo/ui/components/card'\n\nexport default function AdminDashboard() {\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-3xl font-bold tracking-tight\">Dashboard</h1>\n <p className=\"text-muted-foreground\">\n Welcome to the {{projectName}} admin dashboard.\n </p>\n </div>\n\n <StatsCards />\n\n <div className=\"grid gap-6 md:grid-cols-2\">\n <Card>\n <CardHeader>\n <CardTitle>Recent Activity</CardTitle>\n <CardDescription>Latest user activity and events</CardDescription>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm text-muted-foreground\">No recent activity to display.</p>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Quick Actions</CardTitle>\n <CardDescription>Common administrative tasks</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-2\">\n <a href=\"/users\" className=\"block text-sm text-primary hover:underline\">\n Manage Users\n </a>\n <a href=\"/analytics\" className=\"block text-sm text-primary hover:underline\">\n View Analytics\n </a>\n <a href=\"/settings\" className=\"block text-sm text-primary hover:underline\">\n System Settings\n </a>\n </CardContent>\n </Card>\n </div>\n </div>\n )\n}\n",
14
+ "admin/src/app/settings/page.tsx.hbs": "import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@repo/ui/components/card'\nimport { Button } from '@repo/ui/components/button'\nimport { Input } from '@repo/ui/components/input'\nimport { Label } from '@repo/ui/components/label'\n\nexport default function SettingsPage() {\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-3xl font-bold tracking-tight\">Settings</h1>\n <p className=\"text-muted-foreground\">\n Configure application settings and preferences.\n </p>\n </div>\n\n <div className=\"grid gap-6\">\n <Card>\n <CardHeader>\n <CardTitle>General Settings</CardTitle>\n <CardDescription>Basic application configuration</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"app-name\">Application Name</Label>\n <Input id=\"app-name\" defaultValue=\"{{projectName}}\" />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"support-email\">Support Email</Label>\n <Input id=\"support-email\" type=\"email\" placeholder=\"support@example.com\" />\n </div>\n <Button>Save Changes</Button>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Security</CardTitle>\n <CardDescription>Security and authentication settings</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"font-medium\">Two-Factor Authentication</p>\n <p className=\"text-sm text-muted-foreground\">\n Require 2FA for all admin users\n </p>\n </div>\n <Button variant=\"outline\">Configure</Button>\n </div>\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"font-medium\">Session Timeout</p>\n <p className=\"text-sm text-muted-foreground\">\n Auto logout after inactivity\n </p>\n </div>\n <Button variant=\"outline\">Configure</Button>\n </div>\n </CardContent>\n </Card>\n\n <Card className=\"border-destructive\">\n <CardHeader>\n <CardTitle className=\"text-destructive\">Danger Zone</CardTitle>\n <CardDescription>Irreversible actions</CardDescription>\n </CardHeader>\n <CardContent>\n <Button variant=\"destructive\">Delete All Data</Button>\n </CardContent>\n </Card>\n </div>\n </div>\n )\n}\n",
15
+ "admin/src/app/users/page.tsx.hbs": "import { UserTable } from '@/components/user-table'\n\nexport default function UsersPage() {\n return (\n <div className=\"space-y-8\">\n <div>\n <h1 className=\"text-3xl font-bold tracking-tight\">Users</h1>\n <p className=\"text-muted-foreground\">\n Manage users, roles, and permissions.\n </p>\n </div>\n\n <UserTable />\n </div>\n )\n}\n",
16
+ "admin/src/components/admin-sidebar.tsx.hbs": "'use client'\n\nimport { cn } from '@repo/ui/lib/utils'\nimport Link from 'next/link'\nimport { usePathname } from 'next/navigation'\n\nconst navigation = [\n { name: 'Dashboard', href: '/' },\n { name: 'Users', href: '/users' },\n { name: 'Analytics', href: '/analytics' },\n { name: 'Settings', href: '/settings' },\n]\n\nexport function AdminSidebar() {\n const pathname = usePathname()\n\n return (\n <div className=\"flex h-screen w-64 flex-col border-r bg-card\">\n <div className=\"flex h-14 items-center border-b px-6\">\n <Link href=\"/\" className=\"flex items-center gap-2 font-semibold\">\n <span>{{projectName}} Admin</span>\n </Link>\n </div>\n <nav className=\"flex-1 space-y-1 p-4\">\n {navigation.map((item) => (\n <Link\n key={item.name}\n href={item.href}\n className={cn(\n 'flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors',\n pathname === item.href\n ? 'bg-primary text-primary-foreground'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground'\n )}\n >\n {item.name}\n </Link>\n ))}\n </nav>\n <div className=\"border-t p-4\">\n <Link\n href=\"http://localhost:3001\"\n target=\"_blank\"\n className=\"flex items-center rounded-md px-3 py-2 text-sm font-medium text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n Back to App\n </Link>\n </div>\n </div>\n )\n}\n",
17
+ "admin/src/components/stats-cards.tsx.hbs": "import { Card, CardContent, CardHeader, CardTitle } from '@repo/ui/components/card'\n\nconst stats = [\n { name: 'Total Users', value: '0', change: '+0%' },\n { name: 'Active Sessions', value: '0', change: '+0%' },\n { name: 'Total Revenue', value: '$0', change: '+0%' },\n { name: 'Conversion Rate', value: '0%', change: '+0%' },\n]\n\nexport function StatsCards() {\n return (\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-4\">\n {stats.map((stat) => (\n <Card key={stat.name}>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">{stat.name}</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold\">{stat.value}</div>\n <p className=\"text-xs text-muted-foreground\">\n {stat.change} from last month\n </p>\n </CardContent>\n </Card>\n ))}\n </div>\n )\n}\n",
18
+ "admin/src/components/user-table.tsx.hbs": "'use client'\n\nimport { Button } from '@repo/ui/components/button'\nimport { Card, CardContent, CardHeader, CardTitle } from '@repo/ui/components/card'\n\n// Placeholder user data\nconst users = [\n { id: '1', name: 'John Doe', email: 'john@example.com', role: 'admin', status: 'active' },\n { id: '2', name: 'Jane Smith', email: 'jane@example.com', role: 'user', status: 'active' },\n { id: '3', name: 'Bob Johnson', email: 'bob@example.com', role: 'user', status: 'inactive' },\n]\n\nexport function UserTable() {\n return (\n <Card>\n <CardHeader className=\"flex flex-row items-center justify-between\">\n <CardTitle>All Users</CardTitle>\n <Button size=\"sm\">Add User</Button>\n </CardHeader>\n <CardContent>\n <div className=\"relative overflow-x-auto\">\n <table className=\"w-full text-sm text-left\">\n <thead className=\"text-xs text-muted-foreground uppercase bg-muted/50\">\n <tr>\n <th className=\"px-6 py-3\">Name</th>\n <th className=\"px-6 py-3\">Email</th>\n <th className=\"px-6 py-3\">Role</th>\n <th className=\"px-6 py-3\">Status</th>\n <th className=\"px-6 py-3\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {users.map((user) => (\n <tr key={user.id} className=\"border-b\">\n <td className=\"px-6 py-4 font-medium\">{user.name}</td>\n <td className=\"px-6 py-4\">{user.email}</td>\n <td className=\"px-6 py-4\">\n <span className=\"capitalize\">{user.role}</span>\n </td>\n <td className=\"px-6 py-4\">\n <span\n className={`px-2 py-1 rounded-full text-xs ${\n user.status === 'active'\n ? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200'\n : 'bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-200'\n }`}\n >\n {user.status}\n </span>\n </td>\n <td className=\"px-6 py-4\">\n <div className=\"flex gap-2\">\n <Button variant=\"ghost\" size=\"sm\">Edit</Button>\n <Button variant=\"ghost\" size=\"sm\" className=\"text-destructive\">Ban</Button>\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )\n}\n",
19
+ "admin/tsconfig.json.hbs": "{\n \"extends\": \"@repo/config-typescript/nextjs.json\",\n \"compilerOptions\": {\n \"baseUrl\": \".\",\n \"paths\": {\n \"@/*\": [\"./src/*\"],\n \"@repo/ui\": [\"../../packages/ui/src\"],\n \"@repo/ui/*\": [\"../../packages/ui/src/*\"],\n \"@repo/backend\": [\"../../packages/backend\"],\n \"@repo/backend/*\": [\"../../packages/backend/*\"]\n }\n },\n \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\", \".next/types/**/*.ts\"],\n \"exclude\": [\"node_modules\"]\n}\n",
7
20
  "base/_gitignore.hbs": "# Dependencies\nnode_modules\n.pnpm-store\n\n# Build outputs\n.next\ndist\n.turbo\nout\n\n# Testing\ncoverage\nplaywright-report\ntest-results\n\n# Environment\n.env\n.env.local\n.env.*.local\n\n# IDE\n.idea\n.vscode\n*.swp\n*.swo\n.DS_Store\n\n# Convex\n.convex\n\n# Vercel\n.vercel\n\n# Debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n.pnpm-debug.log*\n\n# TypeScript\n*.tsbuildinfo\n\n# Misc\n*.pem\n.cache\n",
8
21
  "base/biome.json.hbs": "{\n \"$schema\": \"https://biomejs.dev/schemas/1.9.4/schema.json\",\n \"organizeImports\": {\n \"enabled\": true\n },\n \"linter\": {\n \"enabled\": true,\n \"rules\": {\n \"recommended\": true\n }\n },\n \"formatter\": {\n \"enabled\": true,\n \"indentStyle\": \"space\",\n \"indentWidth\": 2\n },\n \"javascript\": {\n \"formatter\": {\n \"quoteStyle\": \"single\",\n \"semicolons\": \"asNeeded\"\n }\n },\n \"files\": {\n \"ignore\": [\n \"node_modules\",\n \".next\",\n \"dist\",\n \".turbo\",\n \"coverage\",\n \".vercel\",\n \"_generated\"\n ]\n }\n}\n",
9
22
  "convex/_env.local.hbs": "# Convex\nCONVEX_DEPLOYMENT=\nNEXT_PUBLIC_CONVEX_URL=\nNEXT_PUBLIC_CONVEX_SITE_URL=\n\n# Site URL (used for auth redirects)\nSITE_URL=http://localhost:3000\nNEXT_PUBLIC_SITE_URL=http://localhost:3000\n\n# Better Auth Secret (generate with: openssl rand -base64 32)\nBETTER_AUTH_SECRET=\n\n# Auth - GitHub OAuth\nGITHUB_CLIENT_ID=\nGITHUB_CLIENT_SECRET=\n\n# Auth - Google OAuth\nGOOGLE_CLIENT_ID=\nGOOGLE_CLIENT_SECRET=\n\n# Email (Resend) - https://resend.com\nRESEND_API_KEY=\nRESEND_FROM_EMAIL=\n{{#if (eq integrations.analytics 'posthog')}}\n\n# PostHog\nNEXT_PUBLIC_POSTHOG_KEY=\nNEXT_PUBLIC_POSTHOG_HOST=https://app.posthog.com\n{{/if}}\n{{#if (eq integrations.uploads 'convex-fs')}}\n\n# Convex FS - Built-in file storage (no additional config needed)\n{{/if}}\n{{#if (eq integrations.uploads 'r2')}}\n\n# Cloudflare R2\nR2_ACCESS_KEY_ID=\nR2_SECRET_ACCESS_KEY=\nR2_BUCKET=\nR2_ENDPOINT=\n{{/if}}\n{{#if (eq integrations.uploads 'uploadthing')}}\n\n# UploadThing\nUPLOADTHING_TOKEN=\n{{/if}}\n{{#if (eq integrations.uploads 's3')}}\n\n# AWS S3\nAWS_ACCESS_KEY_ID=\nAWS_SECRET_ACCESS_KEY=\nAWS_REGION=\nAWS_S3_BUCKET=\n{{/if}}\n{{#if (eq integrations.uploads 'vercel-blob')}}\n\n# Vercel Blob\nBLOB_READ_WRITE_TOKEN=\n{{/if}}\n{{#if (eq integrations.payments 'stripe')}}\n\n# Stripe\nSTRIPE_SECRET_KEY=\nSTRIPE_WEBHOOK_SECRET=\nNEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=\n{{/if}}\n{{#if (eq integrations.payments 'polar')}}\n\n# Polar\nPOLAR_ACCESS_TOKEN=\nPOLAR_WEBHOOK_SECRET=\nPOLAR_ORGANIZATION_ID=\n{{/if}}\n{{#if (includes addons 'rate-limiting')}}\n\n# Convex Rate Limiter - No additional config needed (uses Convex backend)\n{{/if}}\n{{#if (includes addons 'monitoring')}}\n\n# Sentry\nSENTRY_DSN=\nSENTRY_AUTH_TOKEN=\n{{/if}}\n",
@@ -15,9 +28,21 @@ export const EMBEDDED_TEMPLATES: Record<string, string> = {
15
28
  "convex/convex/users.ts.hbs": "import { query } from './_generated/server'\nimport { authComponent } from './auth'\n\n// Get current user from Better Auth session\n// Returns null if not authenticated (instead of throwing)\nexport const current = query({\n args: {},\n handler: async (ctx) => {\n try {\n return await authComponent.getAuthUser(ctx)\n } catch {\n return null\n }\n },\n})\n\n// Alias for current user - used by dashboard components\n// Returns null if not authenticated (instead of throwing)\nexport const viewer = query({\n args: {},\n handler: async (ctx) => {\n try {\n return await authComponent.getAuthUser(ctx)\n } catch {\n return null\n }\n },\n})\n",
16
29
  "convex/package.json.hbs": "{{#if (eq structure 'monorepo')}}{\n \"name\": \"@repo/backend\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"type\": \"module\",\n \"main\": \"./convex/_generated/api.js\",\n \"types\": \"./convex/_generated/api.d.ts\",\n \"exports\": {\n \".\": {\n \"import\": \"./convex/_generated/api.js\",\n \"types\": \"./convex/_generated/api.d.ts\"\n }\n },\n \"scripts\": {\n \"dev\": \"convex dev\",\n \"dev:setup\": \"convex dev --configure --until-success\",\n \"deploy\": \"convex deploy\"\n },\n \"dependencies\": {\n \"convex\": \"^1.25.0\",\n \"@convex-dev/better-auth\": \"^0.10.0\",\n \"better-auth\": \"1.4.9\",\n \"@convex-dev/resend\": \"^0.2.0\"{{#if (eq integrations.uploads 'convex-fs')}},\n \"convex-fs\": \"^0.2.0\"{{/if}}{{#if (eq integrations.uploads 'r2')}},\n \"@convex-dev/r2\": \"^0.8.0\"{{/if}}{{#if (eq integrations.payments 'stripe')}},\n \"@convex-dev/stripe\": \"^0.1.0\"{{/if}}{{#if (eq integrations.payments 'polar')}},\n \"@convex-dev/polar\": \"^0.7.0\"{{/if}}{{#if (includes addons 'rate-limiting')}},\n \"@convex-dev/rate-limiter\": \"^0.3.0\"{{/if}}\n },\n \"devDependencies\": {\n \"@types/node\": \"^20.0.0\",\n \"typescript\": \"^5.0.0\"\n }\n}{{/if}}\n",
17
30
  "convex/tsconfig.json.hbs": "{{#if (eq structure 'monorepo')}}{\n \"compilerOptions\": {\n \"target\": \"ESNext\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true,\n \"noEmit\": true,\n \"outDir\": \"dist\"\n },\n \"include\": [\"convex/**/*.ts\"],\n \"exclude\": [\"node_modules\"]\n}{{/if}}\n",
31
+ "design-system/next.config.ts.hbs": "import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {\n transpilePackages: ['@repo/ui'],\n}\n\nexport default nextConfig\n",
32
+ "design-system/package.json.hbs": "{\n \"name\": \"@repo/design-system\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev --turbopack --port 3002\",\n \"build\": \"next build\",\n \"start\": \"next start\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"dependencies\": {\n \"@repo/ui\": \"workspace:*\",\n \"next\": \"^16.0.0\",\n \"react\": \"^19.0.0\",\n \"react-dom\": \"^19.0.0\",\n \"next-themes\": \"^0.4.6\",\n{{#if (eq shadcn.iconLibrary \"hugeicons\")}} \"@hugeicons/react\": \"^0.3.0\"\n{{/if}}{{#if (eq shadcn.iconLibrary \"lucide\")}} \"lucide-react\": \"^0.469.0\"\n{{/if}}{{#if (eq shadcn.iconLibrary \"tabler\")}} \"@tabler/icons-react\": \"^3.31.0\"\n{{/if}}{{#if (eq shadcn.iconLibrary \"phosphor\")}} \"@phosphor-icons/react\": \"^2.1.7\"\n{{/if}} },\n \"devDependencies\": {\n \"@repo/config-typescript\": \"workspace:*\",\n \"@types/node\": \"^20.0.0\",\n \"@types/react\": \"^19.0.0\",\n \"@types/react-dom\": \"^19.0.0\",\n \"tailwindcss\": \"^4.0.0\",\n \"@tailwindcss/postcss\": \"^4.0.0\",\n \"postcss\": \"^8.4.0\",\n \"typescript\": \"^5.0.0\"\n }\n}\n",
33
+ "design-system/postcss.config.mjs.hbs": "const config = {\n plugins: {\n '@tailwindcss/postcss': {},\n },\n}\n\nexport default config\n",
34
+ "design-system/src/app/blocks/page.tsx.hbs": "import { Button } from '@repo/ui/components/button'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@repo/ui/components/card'\n\nexport default function BlocksPage() {\n return (\n <div className=\"container mx-auto max-w-6xl px-6 py-10 space-y-16\">\n <div className=\"space-y-4\">\n <h1 className=\"text-4xl font-bold tracking-tight\">Blocks</h1>\n <p className=\"text-xl text-muted-foreground\">\n Pre-built marketing and application blocks.\n </p>\n </div>\n\n {/* Hero Block */}\n <section className=\"space-y-4\">\n <h2 className=\"text-2xl font-semibold border-b pb-2\">Hero Section</h2>\n <div className=\"rounded-lg border bg-gradient-to-b from-background to-muted p-12 text-center\">\n <h1 className=\"text-4xl font-bold tracking-tight sm:text-5xl md:text-6xl\">\n Build something amazing\n </h1>\n <p className=\"mt-6 text-lg text-muted-foreground max-w-2xl mx-auto\">\n Start your next project with our powerful starter kit. Built with\n the latest technologies and best practices.\n </p>\n <div className=\"mt-8 flex justify-center gap-4\">\n <Button size=\"lg\">Get Started</Button>\n <Button size=\"lg\" variant=\"outline\">Learn More</Button>\n </div>\n </div>\n </section>\n\n {/* Features Block */}\n <section className=\"space-y-4\">\n <h2 className=\"text-2xl font-semibold border-b pb-2\">Features Grid</h2>\n <div className=\"grid gap-6 md:grid-cols-2 lg:grid-cols-3\">\n <Card>\n <CardHeader>\n <CardTitle>Fast Development</CardTitle>\n <CardDescription>\n Get started quickly with pre-built components and templates.\n </CardDescription>\n </CardHeader>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>Type Safe</CardTitle>\n <CardDescription>\n Full TypeScript support with strict type checking enabled.\n </CardDescription>\n </CardHeader>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>Modern Stack</CardTitle>\n <CardDescription>\n Built with Next.js 16, React 19, and Tailwind CSS v4.\n </CardDescription>\n </CardHeader>\n </Card>\n </div>\n </section>\n\n {/* CTA Block */}\n <section className=\"space-y-4\">\n <h2 className=\"text-2xl font-semibold border-b pb-2\">Call to Action</h2>\n <div className=\"rounded-lg border bg-primary p-12 text-center text-primary-foreground\">\n <h2 className=\"text-3xl font-bold\">Ready to get started?</h2>\n <p className=\"mt-4 text-lg opacity-90\">\n Join thousands of developers building with our platform.\n </p>\n <div className=\"mt-8\">\n <Button size=\"lg\" variant=\"secondary\">\n Start Free Trial\n </Button>\n </div>\n </div>\n </section>\n\n {/* Pricing Block */}\n <section className=\"space-y-4\">\n <h2 className=\"text-2xl font-semibold border-b pb-2\">Pricing Cards</h2>\n <div className=\"grid gap-6 md:grid-cols-3\">\n <Card>\n <CardHeader>\n <CardTitle>Starter</CardTitle>\n <CardDescription>For individuals and small projects</CardDescription>\n <div className=\"mt-4\">\n <span className=\"text-4xl font-bold\">$0</span>\n <span className=\"text-muted-foreground\">/month</span>\n </div>\n </CardHeader>\n <CardContent>\n <ul className=\"space-y-2 text-sm\">\n <li>Up to 3 projects</li>\n <li>Basic analytics</li>\n <li>Community support</li>\n </ul>\n <Button className=\"mt-6 w-full\" variant=\"outline\">Get Started</Button>\n </CardContent>\n </Card>\n <Card className=\"border-primary\">\n <CardHeader>\n <CardTitle>Pro</CardTitle>\n <CardDescription>For growing teams</CardDescription>\n <div className=\"mt-4\">\n <span className=\"text-4xl font-bold\">$29</span>\n <span className=\"text-muted-foreground\">/month</span>\n </div>\n </CardHeader>\n <CardContent>\n <ul className=\"space-y-2 text-sm\">\n <li>Unlimited projects</li>\n <li>Advanced analytics</li>\n <li>Priority support</li>\n </ul>\n <Button className=\"mt-6 w-full\">Subscribe</Button>\n </CardContent>\n </Card>\n <Card>\n <CardHeader>\n <CardTitle>Enterprise</CardTitle>\n <CardDescription>For large organizations</CardDescription>\n <div className=\"mt-4\">\n <span className=\"text-4xl font-bold\">Custom</span>\n </div>\n </CardHeader>\n <CardContent>\n <ul className=\"space-y-2 text-sm\">\n <li>Custom limits</li>\n <li>Dedicated support</li>\n <li>SLA guarantee</li>\n </ul>\n <Button className=\"mt-6 w-full\" variant=\"outline\">Contact Sales</Button>\n </CardContent>\n </Card>\n </div>\n </section>\n </div>\n )\n}\n",
35
+ "design-system/src/app/colors/page.tsx.hbs": "import { ColorPalette } from '@/components/color-palette'\n\nexport default function ColorsPage() {\n return (\n <div className=\"container mx-auto max-w-6xl px-6 py-10 space-y-8\">\n <div className=\"space-y-4\">\n <h1 className=\"text-4xl font-bold tracking-tight\">Color Palette</h1>\n <p className=\"text-xl text-muted-foreground\">\n The color system for {{projectName}}. Click any swatch to copy the Tailwind class.\n </p>\n </div>\n\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"text-lg font-semibold mb-4\">Usage</h2>\n <p className=\"text-muted-foreground mb-4\">\n Colors are defined as CSS variables and mapped to Tailwind utility classes.\n Use semantic color names for consistency across themes.\n </p>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"rounded-md bg-muted p-4\">\n <p className=\"text-sm font-mono text-muted-foreground mb-2\">Background</p>\n <code className=\"text-sm\">className=&quot;bg-primary text-primary-foreground&quot;</code>\n </div>\n <div className=\"rounded-md bg-muted p-4\">\n <p className=\"text-sm font-mono text-muted-foreground mb-2\">Text</p>\n <code className=\"text-sm\">className=&quot;text-muted-foreground&quot;</code>\n </div>\n </div>\n </div>\n\n <ColorPalette />\n </div>\n )\n}\n",
36
+ "design-system/src/app/components/page.tsx.hbs": "import { Button } from '@repo/ui/components/button'\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@repo/ui/components/card'\nimport { Input } from '@repo/ui/components/input'\nimport { Label } from '@repo/ui/components/label'\nimport { Badge } from '@repo/ui/components/badge'\nimport { Separator } from '@repo/ui/components/separator'\n\nexport default function ComponentsPage() {\n return (\n <div className=\"container mx-auto max-w-6xl px-6 py-10 space-y-12\">\n <div className=\"space-y-4\">\n <h1 className=\"text-4xl font-bold tracking-tight\">Components</h1>\n <p className=\"text-xl text-muted-foreground\">\n UI components from the shared @repo/ui package.\n </p>\n </div>\n\n <section className=\"space-y-6\">\n <h2 className=\"text-2xl font-semibold border-b pb-2\">Buttons</h2>\n <div className=\"flex flex-wrap gap-4\">\n <Button>Default</Button>\n <Button variant=\"secondary\">Secondary</Button>\n <Button variant=\"destructive\">Destructive</Button>\n <Button variant=\"outline\">Outline</Button>\n <Button variant=\"ghost\">Ghost</Button>\n <Button variant=\"link\">Link</Button>\n </div>\n <div className=\"flex flex-wrap gap-4\">\n <Button size=\"sm\">Small</Button>\n <Button size=\"default\">Default</Button>\n <Button size=\"lg\">Large</Button>\n </div>\n </section>\n\n <Separator />\n\n <section className=\"space-y-6\">\n <h2 className=\"text-2xl font-semibold border-b pb-2\">Cards</h2>\n <div className=\"grid gap-6 md:grid-cols-2 lg:grid-cols-3\">\n <Card>\n <CardHeader>\n <CardTitle>Card Title</CardTitle>\n <CardDescription>Card description goes here.</CardDescription>\n </CardHeader>\n <CardContent>\n <p>Card content with some example text.</p>\n </CardContent>\n <CardFooter>\n <Button size=\"sm\">Action</Button>\n </CardFooter>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Another Card</CardTitle>\n <CardDescription>Different content example.</CardDescription>\n </CardHeader>\n <CardContent>\n <p>More card content here.</p>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Third Card</CardTitle>\n <CardDescription>Yet another card example.</CardDescription>\n </CardHeader>\n <CardContent>\n <p>Additional content for this card.</p>\n </CardContent>\n </Card>\n </div>\n </section>\n\n <Separator />\n\n <section className=\"space-y-6\">\n <h2 className=\"text-2xl font-semibold border-b pb-2\">Form Elements</h2>\n <div className=\"grid gap-6 md:grid-cols-2\">\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"email\">Email</Label>\n <Input id=\"email\" type=\"email\" placeholder=\"Enter your email\" />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"password\">Password</Label>\n <Input id=\"password\" type=\"password\" placeholder=\"Enter password\" />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"disabled\">Disabled Input</Label>\n <Input id=\"disabled\" disabled placeholder=\"Disabled input\" />\n </div>\n </div>\n </div>\n </section>\n\n <Separator />\n\n <section className=\"space-y-6\">\n <h2 className=\"text-2xl font-semibold border-b pb-2\">Badges</h2>\n <div className=\"flex flex-wrap gap-4\">\n <Badge>Default</Badge>\n <Badge variant=\"secondary\">Secondary</Badge>\n <Badge variant=\"destructive\">Destructive</Badge>\n <Badge variant=\"outline\">Outline</Badge>\n </div>\n </section>\n </div>\n )\n}\n",
37
+ "design-system/src/app/globals.css.hbs": "@import \"tailwindcss\";\n@import \"@repo/ui/styles.css\";\n",
38
+ "design-system/src/app/layout.tsx.hbs": "import type { Metadata } from 'next'\nimport { ThemeProvider } from 'next-themes'\nimport './globals.css'\n\nexport const metadata: Metadata = {\n title: '{{projectName}} Design System',\n description: 'Design system documentation and component showcase',\n}\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode\n}) {\n return (\n <html lang=\"en\" suppressHydrationWarning>\n <body className=\"min-h-screen bg-background font-sans antialiased\">\n <ThemeProvider\n attribute=\"class\"\n defaultTheme=\"system\"\n enableSystem\n disableTransitionOnChange\n >\n <div className=\"relative flex min-h-screen flex-col\">\n <header className=\"sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60\">\n <div className=\"container flex h-14 items-center\">\n <div className=\"mr-4 flex\">\n <a href=\"/\" className=\"mr-6 flex items-center space-x-2\">\n <span className=\"font-bold\">{{projectName}} Design System</span>\n </a>\n <nav className=\"flex items-center space-x-6 text-sm font-medium\">\n <a href=\"/colors\" className=\"transition-colors hover:text-foreground/80 text-foreground/60\">Colors</a>\n <a href=\"/typography\" className=\"transition-colors hover:text-foreground/80 text-foreground/60\">Typography</a>\n <a href=\"/components\" className=\"transition-colors hover:text-foreground/80 text-foreground/60\">Components</a>\n <a href=\"/blocks\" className=\"transition-colors hover:text-foreground/80 text-foreground/60\">Blocks</a>\n </nav>\n </div>\n </div>\n </header>\n <main className=\"flex-1\">{children}</main>\n </div>\n </ThemeProvider>\n </body>\n </html>\n )\n}\n",
39
+ "design-system/src/app/page.tsx.hbs": "import { Card, CardDescription, CardHeader, CardTitle } from '@repo/ui/components/card'\nimport { Separator } from '@repo/ui/components/separator'\n\nexport default function Home() {\n return (\n <main className=\"container mx-auto max-w-4xl px-6 py-16\">\n <header className=\"mb-12 text-center\">\n <h1 className=\"text-4xl font-bold tracking-tight text-foreground\">\n Design System & Blocks\n </h1>\n <p className=\"mt-4 text-lg text-muted-foreground max-w-2xl mx-auto\">\n Explore the component library and design tokens for {{projectName}}.\n </p>\n </header>\n\n <Separator className=\"mb-12\" />\n\n <div className=\"grid gap-6 md:grid-cols-2 lg:grid-cols-4\">\n <a href=\"/colors\" className=\"group\">\n <Card className=\"h-full transition-all hover:border-primary/50 hover:shadow-md\">\n <CardHeader>\n <CardTitle className=\"text-xl\">Colors</CardTitle>\n <CardDescription className=\"text-base\">\n View the color palette and brand colors.\n </CardDescription>\n </CardHeader>\n </Card>\n </a>\n\n <a href=\"/typography\" className=\"group\">\n <Card className=\"h-full transition-all hover:border-primary/50 hover:shadow-md\">\n <CardHeader>\n <CardTitle className=\"text-xl\">Typography</CardTitle>\n <CardDescription className=\"text-base\">\n Typography scale and font styles.\n </CardDescription>\n </CardHeader>\n </Card>\n </a>\n\n <a href=\"/components\" className=\"group\">\n <Card className=\"h-full transition-all hover:border-primary/50 hover:shadow-md\">\n <CardHeader>\n <CardTitle className=\"text-xl\">Components</CardTitle>\n <CardDescription className=\"text-base\">\n View all shadcn UI components.\n </CardDescription>\n </CardHeader>\n </Card>\n </a>\n\n <a href=\"/blocks\" className=\"group\">\n <Card className=\"h-full transition-all hover:border-primary/50 hover:shadow-md\">\n <CardHeader>\n <CardTitle className=\"text-xl\">Blocks</CardTitle>\n <CardDescription className=\"text-base\">\n Pre-built marketing blocks.\n </CardDescription>\n </CardHeader>\n </Card>\n </a>\n </div>\n </main>\n )\n}\n",
40
+ "design-system/src/app/typography/page.tsx.hbs": "export default function TypographyPage() {\n return (\n <div className=\"container mx-auto max-w-4xl px-6 py-10 space-y-12\">\n <div className=\"space-y-4\">\n <h1 className=\"text-4xl font-bold tracking-tight\">Typography</h1>\n <p className=\"text-xl text-muted-foreground\">\n Typography scale and text styles for {{projectName}}.\n </p>\n </div>\n\n <section className=\"space-y-6\">\n <h2 className=\"text-2xl font-semibold border-b pb-2\">Headings</h2>\n <div className=\"space-y-4\">\n <div className=\"flex items-baseline gap-4\">\n <span className=\"text-sm text-muted-foreground w-20\">h1</span>\n <h1 className=\"scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl\">\n Heading One\n </h1>\n </div>\n <div className=\"flex items-baseline gap-4\">\n <span className=\"text-sm text-muted-foreground w-20\">h2</span>\n <h2 className=\"scroll-m-20 text-3xl font-semibold tracking-tight\">\n Heading Two\n </h2>\n </div>\n <div className=\"flex items-baseline gap-4\">\n <span className=\"text-sm text-muted-foreground w-20\">h3</span>\n <h3 className=\"scroll-m-20 text-2xl font-semibold tracking-tight\">\n Heading Three\n </h3>\n </div>\n <div className=\"flex items-baseline gap-4\">\n <span className=\"text-sm text-muted-foreground w-20\">h4</span>\n <h4 className=\"scroll-m-20 text-xl font-semibold tracking-tight\">\n Heading Four\n </h4>\n </div>\n </div>\n </section>\n\n <section className=\"space-y-6\">\n <h2 className=\"text-2xl font-semibold border-b pb-2\">Body Text</h2>\n <div className=\"space-y-4\">\n <div>\n <span className=\"text-sm text-muted-foreground\">Large</span>\n <p className=\"text-lg text-muted-foreground\">\n The quick brown fox jumps over the lazy dog. This is large body text.\n </p>\n </div>\n <div>\n <span className=\"text-sm text-muted-foreground\">Default</span>\n <p className=\"leading-7\">\n The quick brown fox jumps over the lazy dog. This is default body text with proper line height for readability.\n </p>\n </div>\n <div>\n <span className=\"text-sm text-muted-foreground\">Small</span>\n <p className=\"text-sm text-muted-foreground\">\n The quick brown fox jumps over the lazy dog. This is small text.\n </p>\n </div>\n <div>\n <span className=\"text-sm text-muted-foreground\">Muted</span>\n <p className=\"text-sm text-muted-foreground\">\n The quick brown fox jumps over the lazy dog. This is muted text for secondary content.\n </p>\n </div>\n </div>\n </section>\n\n <section className=\"space-y-6\">\n <h2 className=\"text-2xl font-semibold border-b pb-2\">Inline Styles</h2>\n <div className=\"space-y-4\">\n <p>\n This is <strong>bold text</strong> for emphasis.\n </p>\n <p>\n This is <em>italic text</em> for emphasis.\n </p>\n <p>\n This is <code className=\"relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold\">inline code</code> for technical terms.\n </p>\n <p>\n This is a <a href=\"#\" className=\"font-medium text-primary underline underline-offset-4\">link</a> for navigation.\n </p>\n </div>\n </section>\n\n <section className=\"space-y-6\">\n <h2 className=\"text-2xl font-semibold border-b pb-2\">Lists</h2>\n <div className=\"grid gap-8 md:grid-cols-2\">\n <div>\n <span className=\"text-sm text-muted-foreground mb-2 block\">Unordered List</span>\n <ul className=\"my-6 ml-6 list-disc [&>li]:mt-2\">\n <li>First item in the list</li>\n <li>Second item in the list</li>\n <li>Third item in the list</li>\n </ul>\n </div>\n <div>\n <span className=\"text-sm text-muted-foreground mb-2 block\">Ordered List</span>\n <ol className=\"my-6 ml-6 list-decimal [&>li]:mt-2\">\n <li>First numbered item</li>\n <li>Second numbered item</li>\n <li>Third numbered item</li>\n </ol>\n </div>\n </div>\n </section>\n </div>\n )\n}\n",
41
+ "design-system/src/components/color-palette.tsx.hbs": "'use client'\n\nimport { cn } from '@repo/ui/lib/utils'\nimport { useState } from 'react'\n\ninterface ColorSwatchProps {\n name: string\n variable: string\n className: string\n textClassName?: string\n}\n\nfunction ColorSwatch({ name, variable, className, textClassName }: ColorSwatchProps) {\n const [copied, setCopied] = useState(false)\n\n const copyToClipboard = () => {\n navigator.clipboard.writeText(variable)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n }\n\n return (\n <button type=\"button\" onClick={copyToClipboard} className=\"group text-left w-full\">\n <div\n className={cn(\n 'h-20 rounded-lg border flex items-end justify-between p-3 transition-all group-hover:scale-[1.02] group-hover:shadow-md',\n className\n )}\n >\n <span className={cn('text-xs font-medium', textClassName)}>\n {copied ? 'Copied!' : name}\n </span>\n </div>\n <p className=\"mt-2 text-xs text-muted-foreground font-mono\">{variable}</p>\n </button>\n )\n}\n\ninterface ColorGroupProps {\n title: string\n colors: ColorSwatchProps[]\n}\n\nfunction ColorGroup({ title, colors }: ColorGroupProps) {\n return (\n <div className=\"space-y-4\">\n <h3 className=\"text-lg font-semibold\">{title}</h3>\n <div className=\"grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4\">\n {colors.map((color) => (\n <ColorSwatch key={color.variable} {...color} />\n ))}\n </div>\n </div>\n )\n}\n\nexport function ColorPalette() {\n const colorGroups: ColorGroupProps[] = [\n {\n title: 'Base Colors',\n colors: [\n { name: 'Background', variable: 'bg-background', className: 'bg-background', textClassName: 'text-foreground' },\n { name: 'Foreground', variable: 'bg-foreground', className: 'bg-foreground', textClassName: 'text-background' },\n { name: 'Card', variable: 'bg-card', className: 'bg-card', textClassName: 'text-card-foreground' },\n { name: 'Popover', variable: 'bg-popover', className: 'bg-popover', textClassName: 'text-popover-foreground' },\n ],\n },\n {\n title: 'Brand Colors',\n colors: [\n { name: 'Primary', variable: 'bg-primary', className: 'bg-primary', textClassName: 'text-primary-foreground' },\n { name: 'Primary FG', variable: 'bg-primary-foreground', className: 'bg-primary-foreground', textClassName: 'text-primary' },\n { name: 'Secondary', variable: 'bg-secondary', className: 'bg-secondary', textClassName: 'text-secondary-foreground' },\n { name: 'Secondary FG', variable: 'bg-secondary-foreground', className: 'bg-secondary-foreground', textClassName: 'text-secondary' },\n { name: 'Accent', variable: 'bg-accent', className: 'bg-accent', textClassName: 'text-accent-foreground' },\n ],\n },\n {\n title: 'Semantic Colors',\n colors: [\n { name: 'Muted', variable: 'bg-muted', className: 'bg-muted', textClassName: 'text-muted-foreground' },\n { name: 'Muted FG', variable: 'bg-muted-foreground', className: 'bg-muted-foreground', textClassName: 'text-muted' },\n { name: 'Destructive', variable: 'bg-destructive', className: 'bg-destructive', textClassName: 'text-destructive-foreground' },\n { name: 'Border', variable: 'bg-border', className: 'bg-border', textClassName: 'text-foreground' },\n { name: 'Ring', variable: 'bg-ring', className: 'bg-ring', textClassName: 'text-background' },\n ],\n },\n {\n title: 'Chart Colors',\n colors: [\n { name: 'Chart 1', variable: 'bg-chart-1', className: 'bg-chart-1', textClassName: 'text-white' },\n { name: 'Chart 2', variable: 'bg-chart-2', className: 'bg-chart-2', textClassName: 'text-white' },\n { name: 'Chart 3', variable: 'bg-chart-3', className: 'bg-chart-3', textClassName: 'text-white' },\n { name: 'Chart 4', variable: 'bg-chart-4', className: 'bg-chart-4', textClassName: 'text-foreground' },\n { name: 'Chart 5', variable: 'bg-chart-5', className: 'bg-chart-5', textClassName: 'text-foreground' },\n ],\n },\n {\n title: 'Sidebar Colors',\n colors: [\n { name: 'Sidebar', variable: 'bg-sidebar', className: 'bg-sidebar', textClassName: 'text-sidebar-foreground' },\n { name: 'Sidebar FG', variable: 'bg-sidebar-foreground', className: 'bg-sidebar-foreground', textClassName: 'text-sidebar' },\n { name: 'Sidebar Primary', variable: 'bg-sidebar-primary', className: 'bg-sidebar-primary', textClassName: 'text-sidebar-primary-foreground' },\n { name: 'Sidebar Accent', variable: 'bg-sidebar-accent', className: 'bg-sidebar-accent', textClassName: 'text-sidebar-accent-foreground' },\n { name: 'Sidebar Border', variable: 'bg-sidebar-border', className: 'bg-sidebar-border', textClassName: 'text-sidebar-foreground' },\n ],\n },\n ]\n\n return (\n <div className=\"space-y-12\">\n {colorGroups.map((group) => (\n <ColorGroup key={group.title} {...group} />\n ))}\n </div>\n )\n}\n",
42
+ "design-system/tsconfig.json.hbs": "{\n \"extends\": \"@repo/config-typescript/nextjs.json\",\n \"compilerOptions\": {\n \"baseUrl\": \".\",\n \"paths\": {\n \"@/*\": [\"./src/*\"],\n \"@repo/ui\": [\"../../packages/ui/src\"],\n \"@repo/ui/*\": [\"../../packages/ui/src/*\"]\n }\n },\n \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\", \".next/types/**/*.ts\"],\n \"exclude\": [\"node_modules\"]\n}\n",
18
43
  "integrations/posthog/src/components/providers/posthog-provider.tsx.hbs": "'use client'\n\nimport posthog from 'posthog-js'\nimport { PostHogProvider as PHProvider } from 'posthog-js/react'\nimport { useEffect } from 'react'\n\nexport function PostHogProvider({ children }: { children: React.ReactNode }) {\n useEffect(() => {\n posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {\n api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST || 'https://app.posthog.com',\n person_profiles: 'identified_only',\n capture_pageview: false, // We capture pageviews manually\n })\n }, [])\n\n return <PHProvider client={posthog}>{children}</PHProvider>\n}\n",
19
44
  "marketing/nextjs/next.config.ts.hbs": "import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {\n transpilePackages: ['@repo/ui'],\n}\n\nexport default nextConfig\n",
20
- "marketing/nextjs/package.json.hbs": "{\n \"name\": \"@repo/marketing\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"scripts\": {\n \"dev\": \"next dev --turbopack -p 3001\",\n \"build\": \"next build\",\n \"start\": \"next start\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"dependencies\": {\n \"next\": \"^16.0.0\",\n \"react\": \"^19.0.0\",\n \"react-dom\": \"^19.0.0\",\n \"@repo/ui\": \"workspace:*\"\n },\n \"devDependencies\": {\n \"@repo/config-typescript\": \"workspace:*\",\n \"@types/node\": \"^20.0.0\",\n \"@types/react\": \"^19.0.0\",\n \"@types/react-dom\": \"^19.0.0\",\n \"tailwindcss\": \"^4.0.0\",\n \"@tailwindcss/postcss\": \"^4.0.0\",\n \"postcss\": \"^8.4.0\",\n \"typescript\": \"^5.0.0\"\n }\n}\n",
45
+ "marketing/nextjs/package.json.hbs": "{\n \"name\": \"@repo/marketing\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"scripts\": {\n \"dev\": \"next dev --turbopack --port 3000\",\n \"build\": \"next build\",\n \"start\": \"next start\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"dependencies\": {\n \"next\": \"^16.0.0\",\n \"react\": \"^19.0.0\",\n \"react-dom\": \"^19.0.0\",\n \"@repo/ui\": \"workspace:*\"\n },\n \"devDependencies\": {\n \"@repo/config-typescript\": \"workspace:*\",\n \"@types/node\": \"^20.0.0\",\n \"@types/react\": \"^19.0.0\",\n \"@types/react-dom\": \"^19.0.0\",\n \"tailwindcss\": \"^4.0.0\",\n \"@tailwindcss/postcss\": \"^4.0.0\",\n \"postcss\": \"^8.4.0\",\n \"typescript\": \"^5.0.0\"\n }\n}\n",
21
46
  "marketing/nextjs/postcss.config.mjs.hbs": "export default {\n plugins: {\n '@tailwindcss/postcss': {},\n },\n}\n",
22
47
  "marketing/nextjs/src/app/globals.css.hbs": "@import \"tailwindcss\";\n\n:root {\n --background: #ffffff;\n --foreground: #171717;\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n --background: #0a0a0a;\n --foreground: #ededed;\n }\n}\n\nbody {\n color: var(--foreground);\n background: var(--background);\n}\n",
23
48
  "marketing/nextjs/src/app/layout.tsx.hbs": "import type { Metadata } from 'next'\nimport { Geist, Geist_Mono } from 'next/font/google'\nimport './globals.css'\n\nconst geistSans = Geist({\n variable: '--font-geist-sans',\n subsets: ['latin'],\n})\n\nconst geistMono = Geist_Mono({\n variable: '--font-geist-mono',\n subsets: ['latin'],\n})\n\nexport const metadata: Metadata = {\n title: '{{projectName}} - Marketing',\n description: 'Marketing site for {{projectName}}',\n}\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode\n}) {\n return (\n <html lang=\"en\">\n <body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>\n {children}\n </body>\n </html>\n )\n}\n",
@@ -26,7 +51,7 @@ export const EMBEDDED_TEMPLATES: Record<string, string> = {
26
51
  "marketing/payload/_env.example.hbs": "# Database (Supabase PostgreSQL)\nDATABASE_URL=\"postgresql://postgres:[PASSWORD]@db.[PROJECT].supabase.co:5432/postgres\"\n\n# Payload CMS\nPAYLOAD_SECRET=\"\" # Generate with: openssl rand -base64 32\n\n# Scheduled Jobs\nCRON_SECRET=\"\" # Generate with: openssl rand -base64 32\n\n# Draft Previews\nPREVIEW_SECRET=\"\" # Generate with: openssl rand -base64 32\n\n# Email (Resend)\nRESEND_API_KEY=\"\"\nRESEND_FROM_EMAIL=\"noreply@yourdomain.com\"\n\n{{#if (eq integrations.payloadStorage 's3')}}\n# S3 Storage\nS3_BUCKET=\"media\"\nS3_ACCESS_KEY_ID=\"\"\nS3_SECRET_ACCESS_KEY=\"\"\nS3_REGION=\"us-east-1\"\nS3_ENDPOINT=\"\" # Optional: For S3-compatible services\n{{/if}}\n{{#if (eq integrations.payloadStorage 'r2')}}\n# Cloudflare R2 Storage\nR2_BUCKET=\"\"\nR2_ACCESS_KEY_ID=\"\"\nR2_SECRET_ACCESS_KEY=\"\"\nR2_ENDPOINT=\"https://[ACCOUNT_ID].r2.cloudflarestorage.com\"\n{{/if}}\n{{#if (eq integrations.payloadStorage 'vercel-blob')}}\n# Vercel Blob Storage\nBLOB_READ_WRITE_TOKEN=\"\"\n{{/if}}\n{{#if (eq integrations.payloadStorage 'gcs')}}\n# Google Cloud Storage\nGCS_BUCKET=\"\"\nGCS_PROJECT_ID=\"\"\nGCS_CREDENTIALS=\"{}\" # JSON service account key\n{{/if}}\n{{#if (eq integrations.payloadStorage 'local')}}\n# Local Storage\n# Files are stored in the /media directory by default\n# No additional configuration required\n{{/if}}\n",
27
52
  "marketing/payload/_env.local.hbs": "# Database (Supabase PostgreSQL)\nDATABASE_URL=\n\n# Payload CMS\nPAYLOAD_SECRET=\n\n# Scheduled Jobs\nCRON_SECRET=\n\n# Draft Previews\nPREVIEW_SECRET=\n\n# Email (Resend)\nRESEND_API_KEY=\nRESEND_FROM_EMAIL=\n\n{{#if (eq integrations.payloadStorage 's3')}}\n# S3 Storage\nS3_BUCKET=media\nS3_ACCESS_KEY_ID=\nS3_SECRET_ACCESS_KEY=\nS3_REGION=us-east-1\nS3_ENDPOINT=\n{{/if}}\n{{#if (eq integrations.payloadStorage 'r2')}}\n# Cloudflare R2 Storage\nR2_BUCKET=\nR2_ACCESS_KEY_ID=\nR2_SECRET_ACCESS_KEY=\nR2_ENDPOINT=\n{{/if}}\n{{#if (eq integrations.payloadStorage 'vercel-blob')}}\n# Vercel Blob Storage\nBLOB_READ_WRITE_TOKEN=\n{{/if}}\n{{#if (eq integrations.payloadStorage 'gcs')}}\n# Google Cloud Storage\nGCS_BUCKET=\nGCS_PROJECT_ID=\nGCS_CREDENTIALS=\n{{/if}}\n",
28
53
  "marketing/payload/next.config.ts.hbs": "import { withPayload } from '@payloadcms/next/withPayload'\nimport type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {\n transpilePackages: ['@repo/ui'],\n}\n\nexport default withPayload(nextConfig)\n",
29
- "marketing/payload/package.json.hbs": "{\n \"name\": \"@repo/marketing\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"scripts\": {\n \"dev\": \"next dev -p 3001\",\n \"build\": \"next build\",\n \"start\": \"next start\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\",\n \"typecheck\": \"tsc --noEmit\",\n \"db:push\": \"payload migrate\",\n \"db:seed\": \"tsx src/seed.ts\"\n },\n \"dependencies\": {\n \"next\": \"^15.4.10\",\n \"react\": \"^19.0.0\",\n \"react-dom\": \"^19.0.0\",\n \"payload\": \"^3.70.0\",\n \"@payloadcms/db-postgres\": \"^3.0.0\",\n \"@payloadcms/next\": \"^3.0.0\",\n \"@payloadcms/richtext-lexical\": \"^3.0.0\",\n \"@payloadcms/email-resend\": \"^3.0.0\",\n \"@payloadcms/plugin-seo\": \"^3.0.0\",\n{{#if (eq integrations.payloadStorage 's3')}}\n \"@payloadcms/storage-s3\": \"^3.0.0\",\n{{/if}}\n{{#if (eq integrations.payloadStorage 'r2')}}\n \"@payloadcms/storage-s3\": \"^3.0.0\",\n{{/if}}\n{{#if (eq integrations.payloadStorage 'vercel-blob')}}\n \"@payloadcms/storage-vercel-blob\": \"^3.0.0\",\n{{/if}}\n{{#if (eq integrations.payloadStorage 'gcs')}}\n \"@payloadcms/storage-gcs\": \"^3.0.0\",\n{{/if}}\n \"sharp\": \"^0.33.0\",\n \"@repo/ui\": \"workspace:*\"\n },\n \"devDependencies\": {\n \"@repo/config-typescript\": \"workspace:*\",\n \"@types/node\": \"^20.0.0\",\n \"@types/react\": \"^19.0.0\",\n \"@types/react-dom\": \"^19.0.0\",\n \"tailwindcss\": \"^4.0.0\",\n \"@tailwindcss/postcss\": \"^4.0.0\",\n \"postcss\": \"^8.4.0\",\n \"sass\": \"^1.86.0\",\n \"typescript\": \"^5.0.0\",\n \"tsx\": \"^4.0.0\"\n }\n}\n",
54
+ "marketing/payload/package.json.hbs": "{\n \"name\": \"@repo/marketing\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"scripts\": {\n \"dev\": \"next dev --port 3000\",\n \"build\": \"next build\",\n \"start\": \"next start\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\",\n \"typecheck\": \"tsc --noEmit\",\n \"db:push\": \"payload migrate\",\n \"db:seed\": \"tsx src/seed.ts\"\n },\n \"dependencies\": {\n \"next\": \"^15.4.10\",\n \"react\": \"^19.0.0\",\n \"react-dom\": \"^19.0.0\",\n \"payload\": \"^3.70.0\",\n \"@payloadcms/db-postgres\": \"^3.0.0\",\n \"@payloadcms/next\": \"^3.0.0\",\n \"@payloadcms/richtext-lexical\": \"^3.0.0\",\n \"@payloadcms/email-resend\": \"^3.0.0\",\n \"@payloadcms/plugin-seo\": \"^3.0.0\",\n{{#if (eq integrations.payloadStorage 's3')}}\n \"@payloadcms/storage-s3\": \"^3.0.0\",\n{{/if}}\n{{#if (eq integrations.payloadStorage 'r2')}}\n \"@payloadcms/storage-s3\": \"^3.0.0\",\n{{/if}}\n{{#if (eq integrations.payloadStorage 'vercel-blob')}}\n \"@payloadcms/storage-vercel-blob\": \"^3.0.0\",\n{{/if}}\n{{#if (eq integrations.payloadStorage 'gcs')}}\n \"@payloadcms/storage-gcs\": \"^3.0.0\",\n{{/if}}\n \"sharp\": \"^0.33.0\",\n \"@repo/ui\": \"workspace:*\"\n },\n \"devDependencies\": {\n \"@repo/config-typescript\": \"workspace:*\",\n \"@types/node\": \"^20.0.0\",\n \"@types/react\": \"^19.0.0\",\n \"@types/react-dom\": \"^19.0.0\",\n \"tailwindcss\": \"^4.0.0\",\n \"@tailwindcss/postcss\": \"^4.0.0\",\n \"postcss\": \"^8.4.0\",\n \"sass\": \"^1.86.0\",\n \"typescript\": \"^5.0.0\",\n \"tsx\": \"^4.0.0\"\n }\n}\n",
30
55
  "marketing/payload/postcss.config.mjs.hbs": "export default {\n plugins: {\n '@tailwindcss/postcss': {},\n },\n}\n",
31
56
  "marketing/payload/src/Footer/config.ts.hbs": "import type { GlobalConfig } from \"payload\"\n\nimport { link } from \"@/fields/link\"\nimport { revalidateFooter } from \"./hooks/revalidateFooter\"\n\nexport const Footer: GlobalConfig = {\n slug: \"footer\",\n access: {\n read: () => true,\n },\n fields: [\n // Link Columns - organized groups of links\n {\n name: \"columns\",\n type: \"array\",\n label: \"Link Columns\",\n maxRows: 5,\n admin: {\n initCollapsed: true,\n description: \"Add columns of links (e.g., Solutions, Resources, Company)\",\n },\n fields: [\n {\n name: \"title\",\n type: \"text\",\n required: true,\n label: \"Column Title\",\n },\n {\n name: \"links\",\n type: \"array\",\n label: \"Links\",\n maxRows: 10,\n fields: [\n link({\n appearances: false,\n }),\n ],\n admin: {\n initCollapsed: true,\n },\n },\n ],\n },\n // Social Links\n {\n name: \"socialLinks\",\n type: \"group\",\n label: \"Social Links\",\n admin: {\n description: \"Add your social media profile URLs\",\n },\n fields: [\n {\n name: \"twitter\",\n type: \"text\",\n label: \"X (Twitter)\",\n admin: {\n placeholder: \"https://x.com/yourhandle\",\n },\n },\n {\n name: \"instagram\",\n type: \"text\",\n label: \"Instagram\",\n admin: {\n placeholder: \"https://instagram.com/yourhandle\",\n },\n },\n {\n name: \"linkedin\",\n type: \"text\",\n label: \"LinkedIn\",\n admin: {\n placeholder: \"https://linkedin.com/company/yourcompany\",\n },\n },\n {\n name: \"github\",\n type: \"text\",\n label: \"GitHub\",\n admin: {\n placeholder: \"https://github.com/yourorg\",\n },\n },\n {\n name: \"youtube\",\n type: \"text\",\n label: \"YouTube\",\n admin: {\n placeholder: \"https://youtube.com/@yourchannel\",\n },\n },\n ],\n },\n // Newsletter Section\n {\n name: \"newsletter\",\n type: \"group\",\n label: \"Newsletter\",\n admin: {\n description: \"Configure the newsletter signup section\",\n },\n fields: [\n {\n name: \"enabled\",\n type: \"checkbox\",\n label: \"Enable Newsletter Signup\",\n defaultValue: true,\n },\n {\n name: \"title\",\n type: \"text\",\n label: \"Title\",\n defaultValue: \"Newsletter\",\n admin: {\n condition: (_, siblingData) => siblingData?.enabled,\n },\n },\n {\n name: \"description\",\n type: \"textarea\",\n label: \"Description\",\n defaultValue: \"Stay up to date with the latest updates and news.\",\n admin: {\n condition: (_, siblingData) => siblingData?.enabled,\n },\n },\n {\n name: \"buttonText\",\n type: \"text\",\n label: \"Button Text\",\n defaultValue: \"Subscribe\",\n admin: {\n condition: (_, siblingData) => siblingData?.enabled,\n },\n },\n {\n name: \"placeholder\",\n type: \"text\",\n label: \"Email Placeholder\",\n defaultValue: \"Enter your email\",\n admin: {\n condition: (_, siblingData) => siblingData?.enabled,\n },\n },\n ],\n },\n // Copyright and Bottom Bar\n {\n name: \"copyrightText\",\n type: \"text\",\n label: \"Copyright Text\",\n defaultValue: \"{{projectName}}\",\n admin: {\n description: \"Company name for copyright (year is added automatically)\",\n },\n },\n {\n name: \"bottomLinks\",\n type: \"array\",\n label: \"Bottom Bar Links\",\n maxRows: 4,\n admin: {\n description: \"Links shown in the bottom bar (e.g., Contact Support, Privacy Policy)\",\n initCollapsed: true,\n },\n fields: [\n link({\n appearances: false,\n }),\n ],\n },\n ],\n hooks: {\n afterChange: [revalidateFooter],\n },\n}\n",
32
57
  "marketing/payload/src/Footer/hooks/revalidateFooter.ts.hbs": "import type { GlobalAfterChangeHook } from \"payload\"\n\nimport { revalidateTag } from \"next/cache\"\n\nexport const revalidateFooter: GlobalAfterChangeHook = ({ doc, req: { payload, context } }) => {\n if (!context.disableRevalidate) {\n payload.logger.info(\"Revalidating footer\")\n\n revalidateTag(\"global_footer\")\n }\n\n return doc\n}\n",
@@ -119,7 +144,16 @@ export const EMBEDDED_TEMPLATES: Record<string, string> = {
119
144
  "marketing/payload/src/utilities/index.ts.hbs": "export { default as deepMerge, isObject } from \"./deepMerge\"\nexport { default as canUseDOM } from \"./canUseDOM\"\nexport { getServerSideURL, getClientSideURL } from \"./getURL\"\nexport { generatePreviewPath } from \"./generatePreviewPath\"\nexport { mergeOpenGraph } from \"./mergeOpenGraph\"\nexport { generateMeta } from \"./generateMeta\"\nexport { formatAuthors } from \"./formatAuthors\"\nexport { formatDateTime } from \"./formatDateTime\"\n",
120
145
  "marketing/payload/src/utilities/mergeOpenGraph.ts.hbs": "import type { Metadata } from \"next\"\nimport { getServerSideURL } from \"./getURL\"\n\nconst defaultOpenGraph: Metadata[\"openGraph\"] = {\n type: \"website\",\n description:\n \"Welcome to {{projectName}}. Built with Payload CMS and Next.js.\",\n images: [\n {\n url: `${getServerSideURL()}/og-image.png`,\n width: 1200,\n height: 630,\n alt: \"{{projectName}}\",\n },\n ],\n siteName: \"{{projectName}}\",\n title: \"{{projectName}}\",\n}\n\nexport const mergeOpenGraph = (og?: Metadata[\"openGraph\"]): Metadata[\"openGraph\"] => {\n return {\n ...defaultOpenGraph,\n ...og,\n images: og?.images ? og.images : defaultOpenGraph.images,\n }\n}\n",
121
146
  "marketing/payload/tsconfig.json.hbs": "{\n \"compilerOptions\": {\n \"target\": \"ES2017\",\n \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n \"allowJs\": true,\n \"skipLibCheck\": true,\n \"strict\": true,\n \"noEmit\": true,\n \"esModuleInterop\": true,\n \"module\": \"esnext\",\n \"moduleResolution\": \"bundler\",\n \"resolveJsonModule\": true,\n \"isolatedModules\": true,\n \"jsx\": \"preserve\",\n \"incremental\": true,\n \"plugins\": [{ \"name\": \"next\" }],\n \"paths\": {\n \"@payload-config\": [\"./src/payload.config.ts\"],\n \"@/*\": [\"./src/*\"]\n }\n },\n \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\", \".next/types/**/*.ts\", \".next/dev/types/**/*.ts\"],\n \"exclude\": [\"node_modules\"]\n}\n",
122
- "monorepo/package.json.hbs": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"scripts\": {\n \"dev\": \"node scripts/dev.mjs\",\n \"dev:all\": \"turbo dev\",\n \"dev:web\": \"turbo -F @repo/web dev\",\n \"dev:backend\": \"turbo -F @repo/backend dev\",\n \"dev:setup\": \"pnpm --filter @repo/backend dev:setup\",\n \"build\": \"turbo build\",\n \"lint\": \"turbo lint\",\n \"lint:fix\": \"turbo lint:fix\",\n \"format\": \"turbo format\",\n \"typecheck\": \"turbo typecheck\",\n \"test\": \"turbo test\",\n \"test:e2e\": \"turbo test:e2e\",\n \"clean\": \"turbo clean && rm -rf node_modules\",\n \"prepare\": \"husky\"\n },\n \"devDependencies\": {\n \"turbo\": \"^2.0.0\",\n \"husky\": \"^9.0.0\",\n \"lint-staged\": \"^15.0.0\"\n },\n \"packageManager\": \"pnpm@9.0.0\",\n \"lint-staged\": {\n \"*.{js,ts,jsx,tsx}\": [\"biome check --apply\"],\n \"*.{json,md}\": [\"biome format --write\"]\n }\n}\n",
147
+ "mobile/app.json.hbs": "{\n \"expo\": {\n \"name\": \"{{projectName}}\",\n \"slug\": \"{{projectName}}-mobile\",\n \"version\": \"1.0.0\",\n \"orientation\": \"portrait\",\n \"icon\": \"./assets/icon.png\",\n \"scheme\": \"{{projectName}}\",\n \"userInterfaceStyle\": \"automatic\",\n \"newArchEnabled\": true,\n \"splash\": {\n \"image\": \"./assets/splash.png\",\n \"resizeMode\": \"contain\",\n \"backgroundColor\": \"#ffffff\"\n },\n \"ios\": {\n \"supportsTablet\": true,\n \"bundleIdentifier\": \"com.{{projectName}}.app\"\n },\n \"android\": {\n \"adaptiveIcon\": {\n \"foregroundImage\": \"./assets/adaptive-icon.png\",\n \"backgroundColor\": \"#ffffff\"\n },\n \"package\": \"com.{{projectName}}.app\"\n },\n \"web\": {\n \"bundler\": \"metro\",\n \"output\": \"static\",\n \"favicon\": \"./assets/favicon.png\"\n },\n \"plugins\": [\n \"expo-router\"\n ],\n \"experiments\": {\n \"typedRoutes\": true\n }\n }\n}\n",
148
+ "mobile/babel.config.js.hbs": "module.exports = function (api) {\n api.cache(true)\n return {\n presets: ['babel-preset-expo'],\n }\n}\n",
149
+ "mobile/package.json.hbs": "{\n \"name\": \"@repo/mobile\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"main\": \"expo-router/entry\",\n \"scripts\": {\n \"dev\": \"expo start\",\n \"android\": \"expo run:android\",\n \"ios\": \"expo run:ios\",\n \"web\": \"expo start --web\",\n \"lint\": \"expo lint\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"dependencies\": {\n \"expo\": \"~52.0.0\",\n \"expo-router\": \"~4.0.0\",\n \"expo-linking\": \"~7.0.0\",\n \"expo-status-bar\": \"~2.0.0\",\n \"expo-constants\": \"~17.0.0\",\n \"react\": \"^19.0.0\",\n \"react-native\": \"0.76.0\",\n \"react-native-safe-area-context\": \"4.14.0\",\n \"react-native-screens\": \"~4.4.0\"\n },\n \"devDependencies\": {\n \"@babel/core\": \"^7.25.0\",\n \"@types/react\": \"^19.0.0\",\n \"typescript\": \"^5.0.0\"\n }\n}\n",
150
+ "mobile/src/app/(tabs)/_layout.tsx.hbs": "import { Tabs } from 'expo-router'\n\nexport default function TabLayout() {\n return (\n <Tabs\n screenOptions=\\{{\n tabBarActiveTintColor: '#007AFF',\n headerShown: true,\n }}\n >\n <Tabs.Screen\n name=\"index\"\n options=\\{{\n title: 'Home',\n tabBarLabel: 'Home',\n }}\n />\n <Tabs.Screen\n name=\"profile\"\n options=\\{{\n title: 'Profile',\n tabBarLabel: 'Profile',\n }}\n />\n </Tabs>\n )\n}\n",
151
+ "mobile/src/app/(tabs)/index.tsx.hbs": "import { StyleSheet, Text, View } from 'react-native'\n\nexport default function HomeScreen() {\n return (\n <View style={styles.container}>\n <Text style={styles.title}>Welcome to {{projectName}}</Text>\n <Text style={styles.subtitle}>Your mobile app is ready!</Text>\n </View>\n )\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n alignItems: 'center',\n justifyContent: 'center',\n padding: 20,\n },\n title: {\n fontSize: 24,\n fontWeight: 'bold',\n marginBottom: 8,\n },\n subtitle: {\n fontSize: 16,\n color: '#666',\n },\n})\n",
152
+ "mobile/src/app/(tabs)/profile.tsx.hbs": "import { StyleSheet, Text, View } from 'react-native'\n\nexport default function ProfileScreen() {\n return (\n <View style={styles.container}>\n <View style={styles.avatar}>\n <Text style={styles.avatarText}>?</Text>\n </View>\n <Text style={styles.title}>Profile</Text>\n <Text style={styles.subtitle}>Sign in to view your profile</Text>\n </View>\n )\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n alignItems: 'center',\n justifyContent: 'center',\n padding: 20,\n },\n avatar: {\n width: 80,\n height: 80,\n borderRadius: 40,\n backgroundColor: '#E5E5E5',\n alignItems: 'center',\n justifyContent: 'center',\n marginBottom: 16,\n },\n avatarText: {\n fontSize: 32,\n color: '#999',\n },\n title: {\n fontSize: 24,\n fontWeight: 'bold',\n marginBottom: 8,\n },\n subtitle: {\n fontSize: 16,\n color: '#666',\n },\n})\n",
153
+ "mobile/src/app/_layout.tsx.hbs": "import { Stack } from 'expo-router'\nimport { StatusBar } from 'expo-status-bar'\n\nexport default function RootLayout() {\n return (\n <>\n <StatusBar style=\"auto\" />\n <Stack>\n <Stack.Screen name=\"(tabs)\" options=\\{{ headerShown: false }} />\n </Stack>\n </>\n )\n}\n",
154
+ "mobile/src/app/index.tsx.hbs": "import { Redirect } from 'expo-router'\n\nexport default function Index() {\n return <Redirect href=\"/(tabs)\" />\n}\n",
155
+ "mobile/tsconfig.json.hbs": "{\n \"extends\": \"expo/tsconfig.base\",\n \"compilerOptions\": {\n \"strict\": true,\n \"paths\": {\n \"@/*\": [\"./src/*\"]\n }\n },\n \"include\": [\"**/*.ts\", \"**/*.tsx\", \".expo/types/**/*.ts\", \"expo-env.d.ts\"]\n}\n",
156
+ "monorepo/package.json.hbs": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"scripts\": {\n \"dev\": \"node scripts/dev.mjs\",\n \"dev:all\": \"turbo dev\",\n \"dev:web\": \"turbo -F @repo/web dev\",\n \"dev:backend\": \"turbo -F @repo/backend dev\",\n{{#if (includes optionalApps 'design-system')}} \"dev:design-system\": \"turbo -F @repo/design-system dev\",\n{{/if}}{{#if (includes optionalApps 'mobile')}} \"dev:mobile\": \"turbo -F @repo/mobile dev\",\n{{/if}}{{#if (includes optionalApps 'admin')}} \"dev:admin\": \"turbo -F @repo/admin dev\",\n{{/if}} \"dev:setup\": \"pnpm --filter @repo/backend dev:setup\",\n \"build\": \"turbo build\",\n \"lint\": \"turbo lint\",\n \"lint:fix\": \"turbo lint:fix\",\n \"format\": \"turbo format\",\n \"typecheck\": \"turbo typecheck\",\n \"test\": \"turbo test\",\n \"test:e2e\": \"turbo test:e2e\",\n \"clean\": \"turbo clean && rm -rf node_modules\",\n \"prepare\": \"husky\"\n },\n \"devDependencies\": {\n \"turbo\": \"^2.0.0\",\n \"husky\": \"^9.0.0\",\n \"lint-staged\": \"^15.0.0\"\n },\n \"packageManager\": \"pnpm@9.0.0\",\n \"lint-staged\": {\n \"*.{js,ts,jsx,tsx}\": [\"biome check --apply\"],\n \"*.{json,md}\": [\"biome format --write\"]\n }\n}\n",
123
157
  "monorepo/pnpm-workspace.yaml.hbs": "packages:\n - \"apps/*\"\n - \"packages/*\"\n",
124
158
  "monorepo/turbo.json.hbs": "{\n \"$schema\": \"https://turbo.build/schema.json\",\n \"ui\": \"tui\",\n \"tasks\": {\n \"build\": {\n \"dependsOn\": [\"^build\"],\n \"inputs\": [\"$TURBO_DEFAULT$\", \".env*\"],\n \"outputs\": [\".next/**\", \"!.next/cache/**\", \"dist/**\"]\n },\n \"lint\": {\n \"dependsOn\": [\"^lint\"],\n \"inputs\": [\"$TURBO_DEFAULT$\"]\n },\n \"lint:fix\": {\n \"dependsOn\": [\"^lint:fix\"],\n \"inputs\": [\"$TURBO_DEFAULT$\"]\n },\n \"format\": {\n \"dependsOn\": [\"^format\"],\n \"inputs\": [\"$TURBO_DEFAULT$\"]\n },\n \"typecheck\": {\n \"dependsOn\": [\"^typecheck\"],\n \"inputs\": [\"$TURBO_DEFAULT$\"]\n },\n \"dev\": {\n \"cache\": false,\n \"persistent\": true\n },\n \"dev:setup\": {\n \"cache\": false,\n \"interactive\": true\n },\n \"test\": {\n \"dependsOn\": [\"^build\"],\n \"inputs\": [\"$TURBO_DEFAULT$\"]\n },\n \"test:e2e\": {\n \"dependsOn\": [\"build\"],\n \"inputs\": [\"$TURBO_DEFAULT$\"]\n },\n \"clean\": {\n \"cache\": false\n }\n }\n}\n",
125
159
  "packages/config-biome/biome.json.hbs": "{\n \"$schema\": \"https://biomejs.dev/schemas/1.9.4/schema.json\",\n \"extends\": [\"../../biome.json\"]\n}\n",
@@ -134,7 +168,7 @@ export const EMBEDDED_TEMPLATES: Record<string, string> = {
134
168
  "web/_env.local.hbs": "# Convex - These values are synced from packages/backend/.env.local after running convex dev\n# NEXT_PUBLIC_CONVEX_URL and NEXT_PUBLIC_CONVEX_SITE_URL are auto-synced by dev script\nNEXT_PUBLIC_CONVEX_URL=\nNEXT_PUBLIC_CONVEX_SITE_URL=\n\n# Site URL for auth (your frontend URL)\nNEXT_PUBLIC_SITE_URL=http://localhost:3000\n{{#if (eq integrations.analytics 'posthog')}}\n\n# PostHog\nNEXT_PUBLIC_POSTHOG_KEY=\nNEXT_PUBLIC_POSTHOG_HOST=https://app.posthog.com\n{{/if}}\n{{#if (eq integrations.payments 'stripe')}}\n\n# Stripe\nNEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=\n{{/if}}\n",
135
169
  "web/components.json.hbs": "{\n \"$schema\": \"https://ui.shadcn.com/schema.json\",\n \"style\": \"new-york\",\n \"rsc\": true,\n \"tsx\": true,\n \"tailwind\": {\n \"config\": \"\",\n \"css\": \"src/app/globals.css\",\n \"baseColor\": \"{{shadcn.baseColor}}\",\n \"cssVariables\": true,\n \"prefix\": \"\"\n },\n \"aliases\": {\n \"components\": \"@/components\",\n \"utils\": \"@/lib/utils\",\n \"ui\": \"@/components/ui\",\n \"lib\": \"@/lib\",\n \"hooks\": \"@/hooks\"\n },\n \"iconLibrary\": \"{{shadcn.iconLibrary}}\"\n}\n",
136
170
  "web/next.config.ts.hbs": "import type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {\n{{#if (eq structure 'monorepo')}}\n transpilePackages: ['@repo/ui', '@repo/backend'],\n{{/if}}\n}\n\nexport default nextConfig\n",
137
- "web/package.json.hbs": "{\n \"name\": \"{{#if (eq structure 'monorepo')}}@repo/web{{else}}{{projectName}}{{/if}}\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"{{#if (eq structure 'monorepo')}}next dev --turbopack{{else}}node scripts/dev.mjs{{/if}}\",\n \"dev:next\": \"next dev --turbopack\",\n{{#unless (eq structure 'monorepo')}} \"dev:setup\": \"npx convex dev --configure --until-success\",\n{{/unless}} \"build\": \"next build\",\n \"start\": \"next start\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:e2e\": \"playwright test\"\n },\n \"dependencies\": {\n{{#if (eq structure 'monorepo')}} \"@repo/backend\": \"workspace:*\",\n \"@repo/ui\": \"workspace:*\",\n{{/if}} \"next\": \"^16.0.0\",\n \"react\": \"^19.0.0\",\n \"react-dom\": \"^19.0.0\",\n \"convex\": \"^1.25.0\",\n \"@convex-dev/better-auth\": \"^0.10.0\",\n \"better-auth\": \"1.4.9\",\n{{#unless (eq structure 'monorepo')}}{{#if (eq shadcn.iconLibrary \"hugeicons\")}} \"@hugeicons/react\": \"^0.3.0\",\n{{/if}}{{#if (eq shadcn.iconLibrary \"lucide\")}} \"lucide-react\": \"^0.469.0\",\n{{/if}}{{#if (eq shadcn.iconLibrary \"tabler\")}} \"@tabler/icons-react\": \"^3.31.0\",\n{{/if}}{{#if (eq shadcn.iconLibrary \"phosphor\")}} \"@phosphor-icons/react\": \"^2.1.7\",\n{{/if}}{{/unless}} \"class-variance-authority\": \"^0.7.0\",\n \"clsx\": \"^2.1.0\",\n \"tailwind-merge\": \"^2.5.0\",\n \"tw-animate-css\": \"^1.3.0\",\n \"resend\": \"^4.0.0\",\n \"react-email\": \"^3.0.0\",\n \"@react-email/components\": \"^0.0.36\"{{#if (eq integrations.analytics 'posthog')}},\n \"posthog-js\": \"^1.200.0\",\n \"posthog-node\": \"^5.0.0\"{{/if}}{{#if (eq integrations.analytics 'vercel')}},\n \"@vercel/analytics\": \"^1.4.0\",\n \"@vercel/speed-insights\": \"^1.1.0\"{{/if}}{{#if (eq integrations.uploads 'uploadthing')}},\n \"uploadthing\": \"^7.0.0\",\n \"@uploadthing/react\": \"^7.0.0\"{{/if}}{{#if (eq integrations.uploads 's3')}},\n \"@aws-sdk/client-s3\": \"^3.700.0\",\n \"@aws-sdk/s3-request-presigner\": \"^3.700.0\"{{/if}}{{#if (eq integrations.uploads 'vercel-blob')}},\n \"@vercel/blob\": \"^2.0.0\"{{/if}}{{#if (includes addons 'rate-limiting')}},\n \"@arcjet/next\": \"^1.0.0-beta.16\"{{/if}}{{#if (includes addons 'monitoring')}},\n \"@sentry/nextjs\": \"^8.0.0\"{{/if}}\n },\n \"devDependencies\": {\n{{#if (eq structure 'monorepo')}} \"@repo/config-typescript\": \"workspace:*\",\n{{/if}} \"@types/node\": \"^20.0.0\",\n \"@types/react\": \"^19.0.0\",\n \"@types/react-dom\": \"^19.0.0\",\n \"tailwindcss\": \"^4.0.0\",\n \"@tailwindcss/postcss\": \"^4.0.0\",\n \"postcss\": \"^8.4.0\",\n \"typescript\": \"^5.0.0\",\n \"vitest\": \"^3.0.0\",\n \"@vitejs/plugin-react\": \"^4.3.0\",\n \"@testing-library/react\": \"^16.0.0\",\n \"jsdom\": \"^26.0.0\",\n \"playwright\": \"^1.50.0\",\n \"@playwright/test\": \"^1.50.0\"\n }\n}\n",
171
+ "web/package.json.hbs": "{\n \"name\": \"{{#if (eq structure 'monorepo')}}@repo/web{{else}}{{projectName}}{{/if}}\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"{{#if (eq structure 'monorepo')}}next dev --turbopack --port 3001{{else}}node scripts/dev.mjs{{/if}}\",\n \"dev:next\": \"next dev --turbopack\",\n{{#unless (eq structure 'monorepo')}} \"dev:setup\": \"npx convex dev --configure --until-success\",\n{{/unless}} \"build\": \"next build\",\n \"start\": \"next start\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:e2e\": \"playwright test\"\n },\n \"dependencies\": {\n{{#if (eq structure 'monorepo')}} \"@repo/backend\": \"workspace:*\",\n \"@repo/ui\": \"workspace:*\",\n{{/if}} \"next\": \"^16.0.0\",\n \"react\": \"^19.0.0\",\n \"react-dom\": \"^19.0.0\",\n \"convex\": \"^1.25.0\",\n \"@convex-dev/better-auth\": \"^0.10.0\",\n \"better-auth\": \"1.4.9\",\n{{#unless (eq structure 'monorepo')}}{{#if (eq shadcn.iconLibrary \"hugeicons\")}} \"@hugeicons/react\": \"^0.3.0\",\n{{/if}}{{#if (eq shadcn.iconLibrary \"lucide\")}} \"lucide-react\": \"^0.469.0\",\n{{/if}}{{#if (eq shadcn.iconLibrary \"tabler\")}} \"@tabler/icons-react\": \"^3.31.0\",\n{{/if}}{{#if (eq shadcn.iconLibrary \"phosphor\")}} \"@phosphor-icons/react\": \"^2.1.7\",\n{{/if}}{{/unless}} \"class-variance-authority\": \"^0.7.0\",\n \"clsx\": \"^2.1.0\",\n \"tailwind-merge\": \"^2.5.0\",\n \"tw-animate-css\": \"^1.3.0\",\n \"resend\": \"^4.0.0\",\n \"react-email\": \"^3.0.0\",\n \"@react-email/components\": \"^0.0.36\"{{#if (eq integrations.analytics 'posthog')}},\n \"posthog-js\": \"^1.200.0\",\n \"posthog-node\": \"^5.0.0\"{{/if}}{{#if (eq integrations.analytics 'vercel')}},\n \"@vercel/analytics\": \"^1.4.0\",\n \"@vercel/speed-insights\": \"^1.1.0\"{{/if}}{{#if (eq integrations.uploads 'uploadthing')}},\n \"uploadthing\": \"^7.0.0\",\n \"@uploadthing/react\": \"^7.0.0\"{{/if}}{{#if (eq integrations.uploads 's3')}},\n \"@aws-sdk/client-s3\": \"^3.700.0\",\n \"@aws-sdk/s3-request-presigner\": \"^3.700.0\"{{/if}}{{#if (eq integrations.uploads 'vercel-blob')}},\n \"@vercel/blob\": \"^2.0.0\"{{/if}}{{#if (includes addons 'rate-limiting')}},\n \"@arcjet/next\": \"^1.0.0-beta.16\"{{/if}}{{#if (includes addons 'monitoring')}},\n \"@sentry/nextjs\": \"^8.0.0\"{{/if}}\n },\n \"devDependencies\": {\n{{#if (eq structure 'monorepo')}} \"@repo/config-typescript\": \"workspace:*\",\n{{/if}} \"@types/node\": \"^20.0.0\",\n \"@types/react\": \"^19.0.0\",\n \"@types/react-dom\": \"^19.0.0\",\n \"tailwindcss\": \"^4.0.0\",\n \"@tailwindcss/postcss\": \"^4.0.0\",\n \"postcss\": \"^8.4.0\",\n \"typescript\": \"^5.0.0\",\n \"vitest\": \"^3.0.0\",\n \"@vitejs/plugin-react\": \"^4.3.0\",\n \"@testing-library/react\": \"^16.0.0\",\n \"jsdom\": \"^26.0.0\",\n \"playwright\": \"^1.50.0\",\n \"@playwright/test\": \"^1.50.0\"\n }\n}\n",
138
172
  "web/postcss.config.mjs.hbs": "export default {\n plugins: {\n '@tailwindcss/postcss': {},\n },\n}\n",
139
173
  "web/src/app/(auth)/layout.tsx.hbs": "export default function AuthLayout({\n children,\n}: {\n children: React.ReactNode\n}) {\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-muted/50 p-4\">\n <div className=\"w-full max-w-md\">\n {children}\n </div>\n </div>\n )\n}\n",
140
174
  "web/src/app/(auth)/sign-in/page.tsx.hbs": "import { SignInForm } from '@/components/auth/sign-in-form'\n\nexport default function SignInPage() {\n return <SignInForm />\n}\n",
@@ -0,0 +1,7 @@
1
+ import type { NextConfig } from 'next'
2
+
3
+ const nextConfig: NextConfig = {
4
+ transpilePackages: ['@repo/ui', '@repo/backend'],
5
+ }
6
+
7
+ export default nextConfig
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@repo/admin",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "next dev --turbopack --port 3003",
8
+ "build": "next build",
9
+ "start": "next start",
10
+ "lint": "biome check .",
11
+ "lint:fix": "biome check --write .",
12
+ "typecheck": "tsc --noEmit"
13
+ },
14
+ "dependencies": {
15
+ "@repo/ui": "workspace:*",
16
+ "@repo/backend": "workspace:*",
17
+ "next": "^16.0.0",
18
+ "react": "^19.0.0",
19
+ "react-dom": "^19.0.0",
20
+ "next-themes": "^0.4.6",
21
+ "convex": "^1.25.0",
22
+ "better-auth": "1.4.9",
23
+ {{#if (eq shadcn.iconLibrary "hugeicons")}} "@hugeicons/react": "^0.3.0"
24
+ {{/if}}{{#if (eq shadcn.iconLibrary "lucide")}} "lucide-react": "^0.469.0"
25
+ {{/if}}{{#if (eq shadcn.iconLibrary "tabler")}} "@tabler/icons-react": "^3.31.0"
26
+ {{/if}}{{#if (eq shadcn.iconLibrary "phosphor")}} "@phosphor-icons/react": "^2.1.7"
27
+ {{/if}} },
28
+ "devDependencies": {
29
+ "@repo/config-typescript": "workspace:*",
30
+ "@types/node": "^20.0.0",
31
+ "@types/react": "^19.0.0",
32
+ "@types/react-dom": "^19.0.0",
33
+ "tailwindcss": "^4.0.0",
34
+ "@tailwindcss/postcss": "^4.0.0",
35
+ "postcss": "^8.4.0",
36
+ "typescript": "^5.0.0"
37
+ }
38
+ }
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ '@tailwindcss/postcss': {},
4
+ },
5
+ }
6
+
7
+ export default config
@@ -0,0 +1,39 @@
1
+ import { StatsCards } from '@/components/stats-cards'
2
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@repo/ui/components/card'
3
+
4
+ export default function AnalyticsPage() {
5
+ return (
6
+ <div className="space-y-8">
7
+ <div>
8
+ <h1 className="text-3xl font-bold tracking-tight">Analytics</h1>
9
+ <p className="text-muted-foreground">
10
+ View detailed analytics and insights.
11
+ </p>
12
+ </div>
13
+
14
+ <StatsCards />
15
+
16
+ <div className="grid gap-6 md:grid-cols-2">
17
+ <Card>
18
+ <CardHeader>
19
+ <CardTitle>User Growth</CardTitle>
20
+ <CardDescription>New users over time</CardDescription>
21
+ </CardHeader>
22
+ <CardContent className="h-[300px] flex items-center justify-center">
23
+ <p className="text-sm text-muted-foreground">Chart placeholder</p>
24
+ </CardContent>
25
+ </Card>
26
+
27
+ <Card>
28
+ <CardHeader>
29
+ <CardTitle>Session Duration</CardTitle>
30
+ <CardDescription>Average session length</CardDescription>
31
+ </CardHeader>
32
+ <CardContent className="h-[300px] flex items-center justify-center">
33
+ <p className="text-sm text-muted-foreground">Chart placeholder</p>
34
+ </CardContent>
35
+ </Card>
36
+ </div>
37
+ </div>
38
+ )
39
+ }
@@ -0,0 +1,2 @@
1
+ @import "tailwindcss";
2
+ @import "@repo/ui/styles.css";
@@ -0,0 +1,33 @@
1
+ import type { Metadata } from 'next'
2
+ import { ThemeProvider } from 'next-themes'
3
+ import { AdminSidebar } from '@/components/admin-sidebar'
4
+ import './globals.css'
5
+
6
+ export const metadata: Metadata = {
7
+ title: '{{projectName}} Admin',
8
+ description: 'Admin dashboard for {{projectName}}',
9
+ }
10
+
11
+ export default function RootLayout({
12
+ children,
13
+ }: {
14
+ children: React.ReactNode
15
+ }) {
16
+ return (
17
+ <html lang="en" suppressHydrationWarning>
18
+ <body className="min-h-screen bg-background font-sans antialiased">
19
+ <ThemeProvider
20
+ attribute="class"
21
+ defaultTheme="system"
22
+ enableSystem
23
+ disableTransitionOnChange
24
+ >
25
+ <div className="flex min-h-screen">
26
+ <AdminSidebar />
27
+ <main className="flex-1 p-8">{children}</main>
28
+ </div>
29
+ </ThemeProvider>
30
+ </body>
31
+ </html>
32
+ )
33
+ }
@@ -0,0 +1,47 @@
1
+ import { StatsCards } from '@/components/stats-cards'
2
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@repo/ui/components/card'
3
+
4
+ export default function AdminDashboard() {
5
+ return (
6
+ <div className="space-y-8">
7
+ <div>
8
+ <h1 className="text-3xl font-bold tracking-tight">Dashboard</h1>
9
+ <p className="text-muted-foreground">
10
+ Welcome to the {{projectName}} admin dashboard.
11
+ </p>
12
+ </div>
13
+
14
+ <StatsCards />
15
+
16
+ <div className="grid gap-6 md:grid-cols-2">
17
+ <Card>
18
+ <CardHeader>
19
+ <CardTitle>Recent Activity</CardTitle>
20
+ <CardDescription>Latest user activity and events</CardDescription>
21
+ </CardHeader>
22
+ <CardContent>
23
+ <p className="text-sm text-muted-foreground">No recent activity to display.</p>
24
+ </CardContent>
25
+ </Card>
26
+
27
+ <Card>
28
+ <CardHeader>
29
+ <CardTitle>Quick Actions</CardTitle>
30
+ <CardDescription>Common administrative tasks</CardDescription>
31
+ </CardHeader>
32
+ <CardContent className="space-y-2">
33
+ <a href="/users" className="block text-sm text-primary hover:underline">
34
+ Manage Users
35
+ </a>
36
+ <a href="/analytics" className="block text-sm text-primary hover:underline">
37
+ View Analytics
38
+ </a>
39
+ <a href="/settings" className="block text-sm text-primary hover:underline">
40
+ System Settings
41
+ </a>
42
+ </CardContent>
43
+ </Card>
44
+ </div>
45
+ </div>
46
+ )
47
+ }