kofi-stack-template-generator 2.1.51 → 2.1.53

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 (54) hide show
  1. package/.turbo/turbo-build.log +6 -6
  2. package/dist/index.js +1906 -146
  3. package/package.json +2 -2
  4. package/src/generator.ts +9 -0
  5. package/src/templates.generated.ts +51 -5
  6. package/templates/marketing/astro/astro.config.ts.hbs +12 -0
  7. package/templates/marketing/astro/package.json.hbs +31 -0
  8. package/templates/marketing/astro/postcss.config.mjs.hbs +5 -0
  9. package/templates/marketing/astro/public/favicon.svg +4 -0
  10. package/templates/marketing/astro/public/media/hero-bg.png +1 -0
  11. package/templates/marketing/astro/src/components/Footer.astro +167 -0
  12. package/templates/marketing/astro/src/components/Header.astro +378 -0
  13. package/templates/marketing/astro/src/components/Logo.astro +30 -0
  14. package/templates/marketing/astro/src/components/ThemeSelector.astro +64 -0
  15. package/templates/marketing/astro/src/components/blocks/BentoFeatures.astro +209 -0
  16. package/templates/marketing/astro/src/components/blocks/FeatureShowcase.astro +102 -0
  17. package/templates/marketing/astro/src/components/blocks/FinalCTA.astro +82 -0
  18. package/templates/marketing/astro/src/components/blocks/IndustryTabs.astro +177 -0
  19. package/templates/marketing/astro/src/components/blocks/LogoBanner.astro +95 -0
  20. package/templates/marketing/astro/src/components/blocks/PricingTable.astro +176 -0
  21. package/templates/marketing/astro/src/components/blocks/ProofBanner.astro +56 -0
  22. package/templates/marketing/astro/src/components/blocks/TestimonialsGrid.astro +106 -0
  23. package/templates/marketing/astro/src/components/blocks/TrustColumns.astro +88 -0
  24. package/templates/marketing/astro/src/components/heros/AnimatedMockup.astro +711 -0
  25. package/templates/marketing/astro/src/components/heros/ProductShowcaseHero.astro +111 -0
  26. package/templates/marketing/astro/src/layouts/Layout.astro +37 -0
  27. package/templates/marketing/astro/src/lib/utils.ts +6 -0
  28. package/templates/marketing/astro/src/pages/index.astro +163 -0
  29. package/templates/marketing/astro/src/styles/globals.css.hbs +353 -0
  30. package/templates/marketing/astro/tsconfig.json.hbs +11 -0
  31. package/templates/marketing/nextjs/package.json.hbs +6 -1
  32. package/templates/marketing/nextjs/src/app/layout.tsx.hbs +19 -5
  33. package/templates/marketing/nextjs/src/app/page.tsx.hbs +160 -164
  34. package/templates/marketing/nextjs/src/components/Footer/index.tsx +188 -0
  35. package/templates/marketing/nextjs/src/components/Header/MegaMenu.tsx +117 -0
  36. package/templates/marketing/nextjs/src/components/Header/MobileMenu.tsx +178 -0
  37. package/templates/marketing/nextjs/src/components/Header/index.tsx +172 -0
  38. package/templates/marketing/nextjs/src/components/Logo.tsx +46 -0
  39. package/templates/marketing/nextjs/src/components/ThemeProvider.tsx +8 -0
  40. package/templates/marketing/nextjs/src/components/ThemeSelector.tsx +69 -0
  41. package/templates/marketing/nextjs/src/components/blocks/BentoFeatures.tsx +249 -0
  42. package/templates/marketing/nextjs/src/components/blocks/FeatureShowcase.tsx +110 -0
  43. package/templates/marketing/nextjs/src/components/blocks/FinalCTA.tsx +91 -0
  44. package/templates/marketing/nextjs/src/components/blocks/IndustryTabs.tsx +137 -0
  45. package/templates/marketing/nextjs/src/components/blocks/LogoBanner.tsx +80 -0
  46. package/templates/marketing/nextjs/src/components/blocks/PricingTable.tsx +210 -0
  47. package/templates/marketing/nextjs/src/components/blocks/ProofBanner.tsx +72 -0
  48. package/templates/marketing/nextjs/src/components/blocks/TestimonialsGrid.tsx +119 -0
  49. package/templates/marketing/nextjs/src/components/blocks/TrustColumns.tsx +110 -0
  50. package/templates/marketing/nextjs/src/components/blocks/index.ts +9 -0
  51. package/templates/marketing/nextjs/src/components/heros/AnimatedMockup.tsx +242 -0
  52. package/templates/marketing/nextjs/src/components/heros/ProductShowcaseHero.tsx +84 -0
  53. package/templates/marketing/nextjs/src/components/heros/index.ts +2 -0
  54. package/templates/marketing/nextjs/src/lib/utils.ts +6 -0
package/dist/index.js CHANGED
@@ -1191,180 +1191,1935 @@ export function ColorPalette() {
1191
1191
  `,
1192
1192
  "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',
1193
1193
  "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 const key = process.env.NEXT_PUBLIC_POSTHOG_KEY\n if (!key) return\n\n posthog.init(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",
1194
- "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",
1195
- "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',
1196
- "marketing/nextjs/postcss.config.mjs.hbs": "export default {\n plugins: {\n '@tailwindcss/postcss': {},\n },\n}\n",
1197
- "marketing/nextjs/src/app/globals.css.hbs": '@import "tailwindcss";\n@import "tw-animate-css";\n\n@custom-variant dark (&:is(.dark *));\n\n@theme inline {\n /* Colors */\n --color-background: var(--background);\n --color-foreground: var(--foreground);\n\n --color-card: var(--card);\n --color-card-foreground: var(--card-foreground);\n\n --color-popover: var(--popover);\n --color-popover-foreground: var(--popover-foreground);\n\n --color-primary: var(--primary);\n --color-primary-foreground: var(--primary-foreground);\n\n --color-secondary: var(--secondary);\n --color-secondary-foreground: var(--secondary-foreground);\n\n --color-muted: var(--muted);\n --color-muted-foreground: var(--muted-foreground);\n\n --color-accent: var(--accent);\n --color-accent-foreground: var(--accent-foreground);\n\n --color-destructive: var(--destructive);\n\n --color-border: var(--border);\n --color-input: var(--input);\n --color-ring: var(--ring);\n\n --color-chart-1: var(--chart-1);\n --color-chart-2: var(--chart-2);\n --color-chart-3: var(--chart-3);\n --color-chart-4: var(--chart-4);\n --color-chart-5: var(--chart-5);\n\n /* Border radius */\n --radius-sm: calc(var(--radius) - 4px);\n --radius-md: calc(var(--radius) - 2px);\n --radius-lg: var(--radius);\n --radius-xl: calc(var(--radius) + 4px);\n\n /* Fonts */\n --font-sans: var(--font-geist-sans), system-ui, sans-serif;\n --font-mono: var(--font-geist-mono), monospace;\n\n /* Container */\n --container-sm: 40rem;\n --container-md: 48rem;\n --container-lg: 64rem;\n --container-xl: 80rem;\n --container-2xl: 96rem;\n\n /* Animations */\n --animate-accordion-down: accordion-down 0.2s ease-out;\n --animate-accordion-up: accordion-up 0.2s ease-out;\n}\n\n@keyframes accordion-down {\n from {\n height: 0;\n }\n to {\n height: var(--radix-accordion-content-height);\n }\n}\n\n@keyframes accordion-up {\n from {\n height: var(--radix-accordion-content-height);\n }\n to {\n height: 0;\n }\n}\n\n/* ========================================\n THEME COLOR VARIABLES\n ======================================== */\n\n:root {\n --radius: 0.625rem;\n --background: oklch(1 0 0);\n --foreground: oklch(0.145 0 0);\n --card: oklch(1 0 0);\n --card-foreground: oklch(0.145 0 0);\n --popover: oklch(1 0 0);\n --popover-foreground: oklch(0.145 0 0);\n --secondary: oklch(0.97 0 0);\n --secondary-foreground: oklch(0.205 0 0);\n --muted: oklch(0.97 0 0);\n --muted-foreground: oklch(0.556 0 0);\n --accent: oklch(0.97 0 0);\n --accent-foreground: oklch(0.205 0 0);\n --destructive: oklch(0.577 0.245 27.325);\n --border: oklch(0.922 0 0);\n --input: oklch(0.922 0 0);\n\n{{#if (eq shadcn.themeColor "neutral")}}\n --primary: oklch(0.205 0 0);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.708 0 0);\n --chart-1: oklch(0.646 0.222 41.116);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "blue")}}\n --primary: oklch(0.546 0.245 262.881);\n --primary-foreground: oklch(0.985 0.002 247.858);\n --ring: oklch(0.546 0.245 262.881);\n --chart-1: oklch(0.546 0.245 262.881);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "green")}}\n --primary: oklch(0.596 0.145 163.225);\n --primary-foreground: oklch(0.982 0.018 155.826);\n --ring: oklch(0.596 0.145 163.225);\n --chart-1: oklch(0.596 0.145 163.225);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "purple")}}\n --primary: oklch(0.627 0.265 303.9);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.627 0.265 303.9);\n --chart-1: oklch(0.627 0.265 303.9);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "red")}}\n --primary: oklch(0.637 0.237 25.331);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.637 0.237 25.331);\n --chart-1: oklch(0.637 0.237 25.331);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "orange")}}\n --primary: oklch(0.705 0.191 47.604);\n --primary-foreground: oklch(0.216 0.006 56.043);\n --ring: oklch(0.705 0.191 47.604);\n --chart-1: oklch(0.705 0.191 47.604);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "amber")}}\n --primary: oklch(0.769 0.188 70.08);\n --primary-foreground: oklch(0.216 0.006 56.043);\n --ring: oklch(0.769 0.188 70.08);\n --chart-1: oklch(0.769 0.188 70.08);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.646 0.222 41.116);\n{{else if (eq shadcn.themeColor "cyan")}}\n --primary: oklch(0.715 0.143 215.221);\n --primary-foreground: oklch(0.216 0.006 56.043);\n --ring: oklch(0.715 0.143 215.221);\n --chart-1: oklch(0.715 0.143 215.221);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "emerald")}}\n --primary: oklch(0.696 0.17 162.48);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.696 0.17 162.48);\n --chart-1: oklch(0.696 0.17 162.48);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "fuchsia")}}\n --primary: oklch(0.667 0.295 322.15);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.667 0.295 322.15);\n --chart-1: oklch(0.667 0.295 322.15);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "indigo")}}\n --primary: oklch(0.585 0.233 277.117);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.585 0.233 277.117);\n --chart-1: oklch(0.585 0.233 277.117);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "lime")}}\n --primary: oklch(0.768 0.233 130.85);\n --primary-foreground: oklch(0.216 0.006 56.043);\n --ring: oklch(0.768 0.233 130.85);\n --chart-1: oklch(0.768 0.233 130.85);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "pink")}}\n --primary: oklch(0.718 0.202 349.761);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.718 0.202 349.761);\n --chart-1: oklch(0.718 0.202 349.761);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "rose")}}\n --primary: oklch(0.645 0.246 16.439);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.645 0.246 16.439);\n --chart-1: oklch(0.645 0.246 16.439);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "sky")}}\n --primary: oklch(0.685 0.169 237.323);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.685 0.169 237.323);\n --chart-1: oklch(0.685 0.169 237.323);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "teal")}}\n --primary: oklch(0.704 0.14 182.503);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.704 0.14 182.503);\n --chart-1: oklch(0.704 0.14 182.503);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "violet")}}\n --primary: oklch(0.606 0.25 292.717);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.606 0.25 292.717);\n --chart-1: oklch(0.606 0.25 292.717);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "yellow")}}\n --primary: oklch(0.795 0.184 86.047);\n --primary-foreground: oklch(0.216 0.006 56.043);\n --ring: oklch(0.795 0.184 86.047);\n --chart-1: oklch(0.795 0.184 86.047);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.646 0.222 41.116);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else}}\n --primary: oklch(0.205 0 0);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.708 0 0);\n --chart-1: oklch(0.646 0.222 41.116);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{/if}}\n}\n\n.dark {\n --background: oklch(0.145 0 0);\n --foreground: oklch(0.985 0 0);\n --card: oklch(0.205 0 0);\n --card-foreground: oklch(0.985 0 0);\n --popover: oklch(0.269 0 0);\n --popover-foreground: oklch(0.985 0 0);\n --secondary: oklch(0.269 0 0);\n --secondary-foreground: oklch(0.985 0 0);\n --muted: oklch(0.269 0 0);\n --muted-foreground: oklch(0.708 0 0);\n --accent: oklch(0.371 0 0);\n --accent-foreground: oklch(0.985 0 0);\n --destructive: oklch(0.704 0.191 22.216);\n --border: oklch(1 0 0 / 10%);\n --input: oklch(1 0 0 / 15%);\n\n{{#if (eq shadcn.themeColor "neutral")}}\n --primary: oklch(0.922 0 0);\n --primary-foreground: oklch(0.205 0 0);\n --ring: oklch(0.556 0 0);\n --chart-1: oklch(0.488 0.243 264.376);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "blue")}}\n --primary: oklch(0.623 0.214 262.881);\n --primary-foreground: oklch(0.273 0.033 256.848);\n --ring: oklch(0.623 0.214 262.881);\n --chart-1: oklch(0.623 0.214 262.881);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "green")}}\n --primary: oklch(0.696 0.17 162.48);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.696 0.17 162.48);\n --chart-1: oklch(0.696 0.17 162.48);\n --chart-2: oklch(0.488 0.243 264.376);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "purple")}}\n --primary: oklch(0.714 0.203 305.504);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.714 0.203 305.504);\n --chart-1: oklch(0.714 0.203 305.504);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.488 0.243 264.376);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "red")}}\n --primary: oklch(0.704 0.191 22.216);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.704 0.191 22.216);\n --chart-1: oklch(0.704 0.191 22.216);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.488 0.243 264.376);\n{{else if (eq shadcn.themeColor "orange")}}\n --primary: oklch(0.792 0.17 52.615);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.792 0.17 52.615);\n --chart-1: oklch(0.792 0.17 52.615);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "amber")}}\n --primary: oklch(0.828 0.189 84.429);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.828 0.189 84.429);\n --chart-1: oklch(0.828 0.189 84.429);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.488 0.243 264.376);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "cyan")}}\n --primary: oklch(0.789 0.154 211.53);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.789 0.154 211.53);\n --chart-1: oklch(0.789 0.154 211.53);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "emerald")}}\n --primary: oklch(0.765 0.166 160.391);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.765 0.166 160.391);\n --chart-1: oklch(0.765 0.166 160.391);\n --chart-2: oklch(0.488 0.243 264.376);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "fuchsia")}}\n --primary: oklch(0.74 0.238 322.16);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.74 0.238 322.16);\n --chart-1: oklch(0.74 0.238 322.16);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.488 0.243 264.376);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "indigo")}}\n --primary: oklch(0.673 0.182 276.935);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.673 0.182 276.935);\n --chart-1: oklch(0.673 0.182 276.935);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "lime")}}\n --primary: oklch(0.841 0.238 128.85);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.841 0.238 128.85);\n --chart-1: oklch(0.841 0.238 128.85);\n --chart-2: oklch(0.488 0.243 264.376);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "pink")}}\n --primary: oklch(0.775 0.181 349.761);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.775 0.181 349.761);\n --chart-1: oklch(0.775 0.181 349.761);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.488 0.243 264.376);\n{{else if (eq shadcn.themeColor "rose")}}\n --primary: oklch(0.712 0.194 13.428);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.712 0.194 13.428);\n --chart-1: oklch(0.712 0.194 13.428);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.488 0.243 264.376);\n{{else if (eq shadcn.themeColor "sky")}}\n --primary: oklch(0.756 0.143 232.661);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.756 0.143 232.661);\n --chart-1: oklch(0.756 0.143 232.661);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "teal")}}\n --primary: oklch(0.777 0.152 181.912);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.777 0.152 181.912);\n --chart-1: oklch(0.777 0.152 181.912);\n --chart-2: oklch(0.488 0.243 264.376);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "violet")}}\n --primary: oklch(0.702 0.183 293.541);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.702 0.183 293.541);\n --chart-1: oklch(0.702 0.183 293.541);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.488 0.243 264.376);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "yellow")}}\n --primary: oklch(0.852 0.199 91.936);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.852 0.199 91.936);\n --chart-1: oklch(0.852 0.199 91.936);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.488 0.243 264.376);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else}}\n --primary: oklch(0.922 0 0);\n --primary-foreground: oklch(0.205 0 0);\n --ring: oklch(0.556 0 0);\n --chart-1: oklch(0.488 0.243 264.376);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{/if}}\n}\n\n/* ========================================\n BASE STYLES\n ======================================== */\n\n@layer base {\n * {\n @apply border-border outline-ring/50;\n }\n body {\n @apply bg-background text-foreground;\n }\n}\n\n/* Container utility */\n.container {\n width: 100%;\n margin-left: auto;\n margin-right: auto;\n padding-left: 1rem;\n padding-right: 1rem;\n max-width: 96rem;\n}\n\n@media (min-width: 640px) {\n .container {\n padding-left: 1.5rem;\n padding-right: 1.5rem;\n }\n}\n\n@media (min-width: 1024px) {\n .container {\n padding-left: 2rem;\n padding-right: 2rem;\n }\n}\n',
1198
- "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",
1199
- "marketing/nextjs/src/app/page.tsx.hbs": `export default function HomePage() {
1200
- return (
1201
- <main className="min-h-screen">
1202
- {/* Navigation */}
1203
- <nav className="sticky top-0 z-50 w-full border-b border-gray-200 dark:border-gray-800 bg-white/80 dark:bg-gray-900/80 backdrop-blur-sm">
1204
- <div className="container mx-auto px-4">
1205
- <div className="flex h-16 items-center justify-between">
1206
- <div className="flex items-center gap-2">
1207
- <div className="flex h-8 w-8 items-center justify-center rounded-lg bg-gray-900 dark:bg-white">
1208
- <svg className="h-4 w-4 text-white dark:text-gray-900" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1209
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
1210
- </svg>
1194
+ "marketing/astro/astro.config.ts.hbs": "import { defineConfig } from 'astro/config'\nimport tailwindcss from '@tailwindcss/postcss'\n\nexport default defineConfig({\n vite: {\n css: {\n postcss: {\n plugins: [tailwindcss()],\n },\n },\n },\n})\n",
1195
+ "marketing/astro/package.json.hbs": '{\n "name": "@repo/marketing",\n "version": "0.1.0",\n "private": true,\n "type": "module",\n "scripts": {\n "dev": "astro dev --port 3000",\n "build": "astro build",\n "preview": "astro preview",\n "astro": "astro",\n "lint": "biome check .",\n "lint:fix": "biome check --write .",\n "typecheck": "astro check && tsc --noEmit"\n },\n "dependencies": {\n "astro": "^5.1.6",\n "lucide-astro": "^0.468.0",\n "clsx": "^2.1.1",\n "tailwind-merge": "^2.6.0"\n },\n "devDependencies": {\n "@astrojs/check": "^0.9.4",\n "@astrojs/tailwind": "^6.0.2",\n "@repo/config-typescript": "workspace:*",\n "@types/node": "^20.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',
1196
+ "marketing/astro/postcss.config.mjs.hbs": "export default {\n plugins: {\n '@tailwindcss/postcss': {},\n },\n}\n",
1197
+ "marketing/astro/public/favicon.svg": "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIj4KICA8cmVjdCB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHJ4PSI2IiBmaWxsPSIjMGEwYTBhIi8+CiAgPHBhdGggZD0iTTE3LjMzIDVMOSAxOC42N2g4TDE2IDI3bDktMTJoLThsMS0xMHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2ZhZmFmYSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPC9zdmc+Cg==",
1198
+ "marketing/astro/public/media/hero-bg.png": "cGxhY2Vob2xkZXI=",
1199
+ "marketing/astro/src/components/Footer.astro": '---\nimport Logo from "./Logo.astro"\nimport ThemeSelector from "./ThemeSelector.astro"\n\nconst footerColumns = [\n {\n title: "Product",\n links: [\n { label: "Home", href: "/" },\n { label: "Pricing", href: "/pricing" },\n { label: "Integrations", href: "/features/integrations" },\n ],\n },\n {\n title: "Resources",\n links: [\n { label: "Blog", href: "/blog" },\n { label: "Documentation", href: "/docs" },\n ],\n },\n {\n title: "Company",\n links: [\n { label: "About", href: "/about" },\n ],\n },\n {\n title: "Legal",\n links: [\n { label: "Privacy", href: "/privacy" },\n { label: "Terms", href: "/terms" },\n ],\n },\n]\n\nconst socialLinks = {\n twitter: "https://x.com/saasify",\n linkedin: "https://linkedin.com/company/saasify",\n github: "https://github.com/saasify",\n}\n\nconst bottomLinks = [\n { label: "Contact Support", href: "/support" },\n]\n\nconst currentYear = new Date().getFullYear()\n---\n\n<footer class="mt-auto border-t border-border bg-background">\n <!-- Main Footer Content -->\n <div class="container mx-auto px-4 py-12 lg:py-16">\n <div class="grid grid-cols-2 gap-8 md:grid-cols-3 lg:grid-cols-6">\n <!-- Link Columns -->\n {footerColumns.map((column) => (\n <div class="col-span-1">\n <h3 class="mb-4 text-sm font-medium text-foreground">\n {column.title}\n </h3>\n <ul class="space-y-3">\n {column.links.map((link) => (\n <li>\n <a\n href={link.href}\n class="text-sm text-muted-foreground transition-colors hover:text-foreground"\n >\n {link.label}\n </a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n\n <!-- Newsletter Column -->\n <div class="col-span-2 md:col-span-3 lg:col-span-2">\n <h3 class="mb-4 text-sm font-medium text-foreground">\n Newsletter\n </h3>\n <p class="mb-4 text-sm text-muted-foreground">\n Get product updates, tips, and insights delivered weekly.\n </p>\n <form class="flex gap-2">\n <input\n type="email"\n placeholder="Enter your email"\n class="flex-1 px-3 py-2 text-sm rounded-md border border-input bg-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"\n />\n <button\n type="submit"\n class="px-4 py-2 text-sm font-medium rounded-md bg-primary text-primary-foreground hover:bg-primary/90"\n >\n Subscribe\n </button>\n </form>\n </div>\n </div>\n\n <!-- Social Links -->\n <div class="mt-10 flex items-center gap-4 border-t border-border pt-8">\n <a\n href={socialLinks.twitter}\n target="_blank"\n rel="noopener noreferrer"\n class="text-muted-foreground transition-colors hover:text-foreground"\n aria-label="X (Twitter)"\n >\n <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">\n <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />\n </svg>\n </a>\n <a\n href={socialLinks.linkedin}\n target="_blank"\n rel="noopener noreferrer"\n class="text-muted-foreground transition-colors hover:text-foreground"\n aria-label="LinkedIn"\n >\n <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">\n <path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />\n </svg>\n </a>\n <a\n href={socialLinks.github}\n target="_blank"\n rel="noopener noreferrer"\n class="text-muted-foreground transition-colors hover:text-foreground"\n aria-label="GitHub"\n >\n <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">\n <path\n fill-rule="evenodd"\n d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"\n clip-rule="evenodd"\n />\n </svg>\n </a>\n </div>\n </div>\n\n <!-- Bottom Bar -->\n <div class="border-t border-border">\n <div class="container mx-auto flex flex-col items-center justify-between gap-4 px-4 py-6 sm:flex-row">\n <!-- Logo and Copyright -->\n <div class="flex items-center gap-4">\n <a href="/" class="flex items-center">\n <Logo class="h-6 w-6" />\n </a>\n <p class="text-sm text-muted-foreground">\n &copy; {currentYear} SaaSify\n </p>\n </div>\n\n <!-- Bottom Links and Theme Selector -->\n <div class="flex items-center gap-6">\n {bottomLinks.map((link) => (\n <a\n href={link.href}\n class="text-sm text-muted-foreground transition-colors hover:text-foreground"\n >\n {link.label}\n </a>\n ))}\n <ThemeSelector />\n </div>\n </div>\n </div>\n</footer>\n',
1200
+ "marketing/astro/src/components/Header.astro": `---
1201
+ import Logo from "./Logo.astro"
1202
+ import { ChevronDown, Menu, X, Layout, BarChart3, Shield, Zap, Layers, Target, Rocket, Settings } from "lucide-astro"
1203
+
1204
+ // Navigation data structure matching SaaSify
1205
+ const productMenu = {
1206
+ label: "Product",
1207
+ columns: [
1208
+ {
1209
+ title: "Core Features",
1210
+ items: [
1211
+ { label: "Integrations", description: "Connect with 100+ tools you already use", href: "/features/integrations", icon: "layout" },
1212
+ { label: "Analytics", description: "Real-time insights and reporting dashboards", href: "/features/analytics", icon: "barChart" },
1213
+ { label: "Security", description: "Enterprise-grade protection and compliance", href: "/features/security", icon: "shield" },
1214
+ ],
1215
+ },
1216
+ {
1217
+ title: "Productivity",
1218
+ items: [
1219
+ { label: "Dashboard", description: "Unified command center for your team", href: "/features/dashboard", icon: "layout" },
1220
+ { label: "Automation", description: "Streamline repetitive tasks instantly", href: "/features/automation", icon: "zap" },
1221
+ { label: "Workflows", description: "Build custom processes without code", href: "/features/workflows", icon: "layers" },
1222
+ ],
1223
+ },
1224
+ ],
1225
+ }
1226
+
1227
+ const solutionsMenu = {
1228
+ label: "Solutions",
1229
+ columns: [
1230
+ {
1231
+ title: "By Team",
1232
+ items: [
1233
+ { label: "Sales Teams", description: "Close deals faster with smart tools", href: "/use-cases/sales", icon: "target" },
1234
+ { label: "Marketing Teams", description: "Launch campaigns that convert", href: "/use-cases/marketing", icon: "rocket" },
1235
+ { label: "Product Teams", description: "Ship features users love", href: "/use-cases/product", icon: "layers" },
1236
+ { label: "Operations", description: "Scale without the growing pains", href: "/use-cases/operations", icon: "settings" },
1237
+ ],
1238
+ },
1239
+ ],
1240
+ }
1241
+
1242
+ const navLinks = [
1243
+ { label: "Pricing", href: "/pricing" },
1244
+ { label: "Blog", href: "/blog" },
1245
+ ]
1246
+
1247
+ const ctaLinks = [
1248
+ { label: "Sign In", href: "/sign-in", variant: "ghost" },
1249
+ { label: "Get Started", href: "/sign-up", variant: "default" },
1250
+ ]
1251
+ ---
1252
+
1253
+ <header class="sticky top-0 z-50 border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
1254
+ <div class="container mx-auto px-4 h-16 flex justify-between items-center">
1255
+ <!-- Left section: Logo + Nav -->
1256
+ <div class="flex items-center gap-8">
1257
+ <a href="/" class="flex items-center gap-2">
1258
+ <Logo />
1259
+ <span class="text-xl font-semibold hidden sm:inline">SaaSify</span>
1260
+ </a>
1261
+
1262
+ <!-- Desktop navigation -->
1263
+ <nav class="hidden lg:flex items-center gap-1">
1264
+ <!-- Product Menu -->
1265
+ <div class="mega-menu-trigger relative" data-menu="product">
1266
+ <button
1267
+ type="button"
1268
+ class="flex items-center gap-1 px-4 py-2 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors"
1269
+ >
1270
+ {productMenu.label}
1271
+ <ChevronDown class="h-4 w-4 transition-transform mega-chevron" />
1272
+ </button>
1273
+ <div class="mega-menu-dropdown absolute left-0 top-full pt-2 opacity-0 -translate-y-2 pointer-events-none transition-all">
1274
+ <div class="bg-background border border-border rounded-lg shadow-lg p-6 min-w-[480px]">
1275
+ <div class="grid gap-8 grid-cols-2">
1276
+ {productMenu.columns.map((column) => (
1277
+ <div>
1278
+ <h3 class="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-4">
1279
+ {column.title}
1280
+ </h3>
1281
+ <ul class="space-y-1">
1282
+ {column.items.map((item) => (
1283
+ <li>
1284
+ <a
1285
+ href={item.href}
1286
+ class="flex items-start gap-3 p-3 rounded-lg hover:bg-muted transition-colors group"
1287
+ >
1288
+ <div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-md bg-muted group-hover:bg-background">
1289
+ {item.icon === "layout" && <Layout class="h-5 w-5 text-primary" />}
1290
+ {item.icon === "barChart" && <BarChart3 class="h-5 w-5 text-primary" />}
1291
+ {item.icon === "shield" && <Shield class="h-5 w-5 text-primary" />}
1292
+ {item.icon === "zap" && <Zap class="h-5 w-5 text-primary" />}
1293
+ {item.icon === "layers" && <Layers class="h-5 w-5 text-primary" />}
1294
+ </div>
1295
+ <div>
1296
+ <div class="text-sm font-medium text-foreground">{item.label}</div>
1297
+ <div class="text-xs text-muted-foreground mt-0.5">{item.description}</div>
1298
+ </div>
1299
+ </a>
1300
+ </li>
1301
+ ))}
1302
+ </ul>
1303
+ </div>
1304
+ ))}
1211
1305
  </div>
1212
- <span className="font-semibold text-gray-900 dark:text-white">{{projectName}}</span>
1213
1306
  </div>
1214
- <div className="hidden md:flex items-center gap-6">
1215
- <a href="#features" className="text-sm text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white transition-colors">
1216
- Features
1217
- </a>
1218
- <a href="#" className="text-sm text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white transition-colors">
1219
- Pricing
1220
- </a>
1221
- <a href="#" className="text-sm text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white transition-colors">
1222
- Docs
1223
- </a>
1224
- </div>
1225
- <div className="flex items-center gap-4">
1226
- <a
1227
- href="/sign-in"
1228
- className="text-sm font-medium text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white transition-colors"
1229
- >
1230
- Sign in
1231
- </a>
1232
- <a
1233
- href="/sign-up"
1234
- className="rounded-lg bg-gray-900 dark:bg-white px-4 py-2 text-sm font-medium text-white dark:text-gray-900 hover:opacity-90 transition-opacity"
1235
- >
1236
- Get Started
1237
- </a>
1307
+ </div>
1308
+ </div>
1309
+
1310
+ <!-- Solutions Menu -->
1311
+ <div class="mega-menu-trigger relative" data-menu="solutions">
1312
+ <button
1313
+ type="button"
1314
+ class="flex items-center gap-1 px-4 py-2 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors"
1315
+ >
1316
+ {solutionsMenu.label}
1317
+ <ChevronDown class="h-4 w-4 transition-transform mega-chevron" />
1318
+ </button>
1319
+ <div class="mega-menu-dropdown absolute left-0 top-full pt-2 opacity-0 -translate-y-2 pointer-events-none transition-all">
1320
+ <div class="bg-background border border-border rounded-lg shadow-lg p-6 min-w-[320px]">
1321
+ <div class="grid gap-8 grid-cols-1">
1322
+ {solutionsMenu.columns.map((column) => (
1323
+ <div>
1324
+ <h3 class="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-4">
1325
+ {column.title}
1326
+ </h3>
1327
+ <ul class="space-y-1">
1328
+ {column.items.map((item) => (
1329
+ <li>
1330
+ <a
1331
+ href={item.href}
1332
+ class="flex items-start gap-3 p-3 rounded-lg hover:bg-muted transition-colors group"
1333
+ >
1334
+ <div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-md bg-muted group-hover:bg-background">
1335
+ {item.icon === "target" && <Target class="h-5 w-5 text-primary" />}
1336
+ {item.icon === "rocket" && <Rocket class="h-5 w-5 text-primary" />}
1337
+ {item.icon === "layers" && <Layers class="h-5 w-5 text-primary" />}
1338
+ {item.icon === "settings" && <Settings class="h-5 w-5 text-primary" />}
1339
+ </div>
1340
+ <div>
1341
+ <div class="text-sm font-medium text-foreground">{item.label}</div>
1342
+ <div class="text-xs text-muted-foreground mt-0.5">{item.description}</div>
1343
+ </div>
1344
+ </a>
1345
+ </li>
1346
+ ))}
1347
+ </ul>
1348
+ </div>
1349
+ ))}
1350
+ </div>
1238
1351
  </div>
1239
1352
  </div>
1240
1353
  </div>
1354
+
1355
+ {navLinks.map((link) => (
1356
+ <a
1357
+ href={link.href}
1358
+ class="px-4 py-2 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors"
1359
+ >
1360
+ {link.label}
1361
+ </a>
1362
+ ))}
1241
1363
  </nav>
1364
+ </div>
1242
1365
 
1243
- {/* Hero Section */}
1244
- <section className="relative overflow-hidden bg-gradient-to-b from-gray-50 to-white dark:from-gray-900 dark:to-gray-800">
1245
- <div className="container mx-auto px-4 py-24 sm:py-32">
1246
- <div className="text-center">
1247
- <h1 className="text-4xl font-bold tracking-tight text-gray-900 dark:text-white sm:text-6xl">
1248
- Welcome to {{projectName}}
1249
- </h1>
1250
- <p className="mt-6 text-lg leading-8 text-gray-600 dark:text-gray-300 max-w-2xl mx-auto">
1251
- A modern full-stack application built with Next.js, Convex, and Better-Auth.
1252
- </p>
1253
- <div className="mt-10 flex items-center justify-center gap-x-6">
1254
- <a
1255
- href="/app"
1256
- className="rounded-lg bg-gray-900 dark:bg-white px-6 py-3 text-sm font-semibold text-white dark:text-gray-900 shadow-sm hover:opacity-90 transition-opacity"
1257
- >
1258
- Get Started
1259
- </a>
1260
- <a
1261
- href="#features"
1262
- className="text-sm font-semibold leading-6 text-gray-900 dark:text-white"
1263
- >
1264
- Learn more <span aria-hidden="true">\u2192</span>
1265
- </a>
1266
- </div>
1366
+ <!-- Right section: CTAs -->
1367
+ <div class="flex items-center gap-3">
1368
+ <!-- Desktop CTAs -->
1369
+ <div class="hidden lg:flex items-center gap-3">
1370
+ {ctaLinks.map((link) => (
1371
+ <a
1372
+ href={link.href}
1373
+ class:list={[
1374
+ "px-4 py-2 text-sm font-medium rounded-md transition-colors",
1375
+ link.variant === "default"
1376
+ ? "bg-primary text-primary-foreground hover:bg-primary/90"
1377
+ : "text-muted-foreground hover:text-foreground"
1378
+ ]}
1379
+ >
1380
+ {link.label}
1381
+ </a>
1382
+ ))}
1383
+ </div>
1384
+
1385
+ <!-- Mobile: Primary CTA + Hamburger -->
1386
+ <a
1387
+ href="/sign-up"
1388
+ class="lg:hidden px-4 py-2 text-sm font-medium rounded-md bg-primary text-primary-foreground hover:bg-primary/90"
1389
+ >
1390
+ Get Started
1391
+ </a>
1392
+
1393
+ <button
1394
+ type="button"
1395
+ id="mobile-menu-toggle"
1396
+ class="lg:hidden p-2 text-muted-foreground hover:text-foreground"
1397
+ aria-label="Toggle menu"
1398
+ >
1399
+ <Menu class="h-6 w-6 menu-open-icon" />
1400
+ <X class="h-6 w-6 menu-close-icon hidden" />
1401
+ </button>
1402
+ </div>
1403
+ </div>
1404
+ </header>
1405
+
1406
+ <!-- Mobile Menu Overlay -->
1407
+ <div id="mobile-menu" class="fixed inset-0 top-16 z-50 bg-background hidden lg:hidden">
1408
+ <nav class="overflow-y-auto max-h-[calc(100vh-4rem)]">
1409
+ <!-- Product Section -->
1410
+ <div class="mobile-section border-b border-border" data-section="product">
1411
+ <button
1412
+ type="button"
1413
+ class="flex items-center justify-between w-full px-4 py-3 text-sm font-medium"
1414
+ >
1415
+ Product
1416
+ <ChevronDown class="h-4 w-4 transition-transform section-chevron" />
1417
+ </button>
1418
+ <div class="mobile-section-content hidden px-4 pb-4 space-y-4">
1419
+ {productMenu.columns.map((column) => (
1420
+ <div>
1421
+ <h4 class="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">
1422
+ {column.title}
1423
+ </h4>
1424
+ <ul class="space-y-1">
1425
+ {column.items.map((item) => (
1426
+ <li>
1427
+ <a href={item.href} class="flex items-center gap-3 p-2 rounded-lg hover:bg-muted">
1428
+ {item.icon === "layout" && <Layout class="h-4 w-4 text-primary" />}
1429
+ {item.icon === "barChart" && <BarChart3 class="h-4 w-4 text-primary" />}
1430
+ {item.icon === "shield" && <Shield class="h-4 w-4 text-primary" />}
1431
+ {item.icon === "zap" && <Zap class="h-4 w-4 text-primary" />}
1432
+ {item.icon === "layers" && <Layers class="h-4 w-4 text-primary" />}
1433
+ <span class="text-sm">{item.label}</span>
1434
+ </a>
1435
+ </li>
1436
+ ))}
1437
+ </ul>
1438
+ </div>
1439
+ ))}
1440
+ </div>
1441
+ </div>
1442
+
1443
+ <!-- Solutions Section -->
1444
+ <div class="mobile-section border-b border-border" data-section="solutions">
1445
+ <button
1446
+ type="button"
1447
+ class="flex items-center justify-between w-full px-4 py-3 text-sm font-medium"
1448
+ >
1449
+ Solutions
1450
+ <ChevronDown class="h-4 w-4 transition-transform section-chevron" />
1451
+ </button>
1452
+ <div class="mobile-section-content hidden px-4 pb-4 space-y-4">
1453
+ {solutionsMenu.columns.map((column) => (
1454
+ <div>
1455
+ <h4 class="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">
1456
+ {column.title}
1457
+ </h4>
1458
+ <ul class="space-y-1">
1459
+ {column.items.map((item) => (
1460
+ <li>
1461
+ <a href={item.href} class="flex items-center gap-3 p-2 rounded-lg hover:bg-muted">
1462
+ {item.icon === "target" && <Target class="h-4 w-4 text-primary" />}
1463
+ {item.icon === "rocket" && <Rocket class="h-4 w-4 text-primary" />}
1464
+ {item.icon === "layers" && <Layers class="h-4 w-4 text-primary" />}
1465
+ {item.icon === "settings" && <Settings class="h-4 w-4 text-primary" />}
1466
+ <span class="text-sm">{item.label}</span>
1467
+ </a>
1468
+ </li>
1469
+ ))}
1470
+ </ul>
1471
+ </div>
1472
+ ))}
1473
+ </div>
1474
+ </div>
1475
+
1476
+ <!-- Simple nav links -->
1477
+ {navLinks.map((link) => (
1478
+ <a
1479
+ href={link.href}
1480
+ class="flex items-center px-4 py-3 text-sm font-medium border-b border-border hover:bg-muted"
1481
+ >
1482
+ {link.label}
1483
+ </a>
1484
+ ))}
1485
+
1486
+ <!-- CTA links -->
1487
+ <div class="p-4 space-y-2">
1488
+ {ctaLinks.map((link) => (
1489
+ <a
1490
+ href={link.href}
1491
+ class:list={[
1492
+ "flex items-center justify-center w-full px-4 py-3 text-sm font-medium rounded-md transition-colors",
1493
+ link.variant === "default"
1494
+ ? "bg-primary text-primary-foreground hover:bg-primary/90"
1495
+ : "border border-border hover:bg-muted"
1496
+ ]}
1497
+ >
1498
+ {link.label}
1499
+ </a>
1500
+ ))}
1501
+ </div>
1502
+ </nav>
1503
+ </div>
1504
+
1505
+ <script>
1506
+ function initHeader() {
1507
+ // Desktop mega menu
1508
+ const megaMenuTriggers = document.querySelectorAll('.mega-menu-trigger')
1509
+ megaMenuTriggers.forEach((trigger) => {
1510
+ const dropdown = trigger.querySelector('.mega-menu-dropdown')
1511
+ const chevron = trigger.querySelector('.mega-chevron')
1512
+
1513
+ trigger.addEventListener('mouseenter', () => {
1514
+ dropdown?.classList.remove('opacity-0', '-translate-y-2', 'pointer-events-none')
1515
+ dropdown?.classList.add('opacity-100', 'translate-y-0', 'pointer-events-auto')
1516
+ chevron?.classList.add('rotate-180')
1517
+ })
1518
+
1519
+ trigger.addEventListener('mouseleave', () => {
1520
+ dropdown?.classList.add('opacity-0', '-translate-y-2', 'pointer-events-none')
1521
+ dropdown?.classList.remove('opacity-100', 'translate-y-0', 'pointer-events-auto')
1522
+ chevron?.classList.remove('rotate-180')
1523
+ })
1524
+ })
1525
+
1526
+ // Mobile menu toggle
1527
+ const mobileToggle = document.getElementById('mobile-menu-toggle')
1528
+ const mobileMenu = document.getElementById('mobile-menu')
1529
+ const openIcon = mobileToggle?.querySelector('.menu-open-icon')
1530
+ const closeIcon = mobileToggle?.querySelector('.menu-close-icon')
1531
+
1532
+ mobileToggle?.addEventListener('click', () => {
1533
+ const isOpen = !mobileMenu?.classList.contains('hidden')
1534
+ if (isOpen) {
1535
+ mobileMenu?.classList.add('hidden')
1536
+ openIcon?.classList.remove('hidden')
1537
+ closeIcon?.classList.add('hidden')
1538
+ } else {
1539
+ mobileMenu?.classList.remove('hidden')
1540
+ openIcon?.classList.add('hidden')
1541
+ closeIcon?.classList.remove('hidden')
1542
+ }
1543
+ })
1544
+
1545
+ // Mobile sections toggle
1546
+ const mobileSections = document.querySelectorAll('.mobile-section')
1547
+ mobileSections.forEach((section) => {
1548
+ const button = section.querySelector('button')
1549
+ const content = section.querySelector('.mobile-section-content')
1550
+ const chevron = section.querySelector('.section-chevron')
1551
+
1552
+ button?.addEventListener('click', () => {
1553
+ const isOpen = !content?.classList.contains('hidden')
1554
+ if (isOpen) {
1555
+ content?.classList.add('hidden')
1556
+ chevron?.classList.remove('rotate-180')
1557
+ } else {
1558
+ content?.classList.remove('hidden')
1559
+ chevron?.classList.add('rotate-180')
1560
+ }
1561
+ })
1562
+ })
1563
+
1564
+ // Close mobile menu on link click
1565
+ const mobileLinks = mobileMenu?.querySelectorAll('a')
1566
+ mobileLinks?.forEach((link) => {
1567
+ link.addEventListener('click', () => {
1568
+ mobileMenu?.classList.add('hidden')
1569
+ openIcon?.classList.remove('hidden')
1570
+ closeIcon?.classList.add('hidden')
1571
+ })
1572
+ })
1573
+ }
1574
+
1575
+ initHeader()
1576
+ document.addEventListener('astro:after-swap', initHeader)
1577
+ </script>
1578
+ `,
1579
+ "marketing/astro/src/components/Logo.astro": '---\ninterface Props {\n class?: string\n}\n\nconst { class: className } = Astro.props\n---\n\n<div class:list={["flex h-8 w-8 items-center justify-center rounded-lg bg-foreground logo-container", className]}>\n <svg\n class="h-5 w-5 text-background"\n viewBox="0 0 24 24"\n fill="none"\n stroke="currentColor"\n stroke-width="2"\n stroke-linecap="round"\n stroke-linejoin="round"\n >\n <path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"></path>\n </svg>\n</div>\n\n<style>\n :global([data-theme="dark"]) .logo-container {\n background-color: white;\n }\n :global([data-theme="dark"]) .logo-container svg {\n color: #0a0a0a;\n }\n</style>\n',
1580
+ "marketing/astro/src/components/ThemeSelector.astro": `---
1581
+ ---
1582
+
1583
+ <div class="theme-selector relative">
1584
+ <button
1585
+ type="button"
1586
+ id="theme-toggle"
1587
+ class="flex items-center gap-2 px-3 py-1.5 text-sm rounded-md border border-border bg-background hover:bg-muted transition-colors"
1588
+ aria-label="Toggle theme"
1589
+ >
1590
+ <svg id="sun-icon" class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1591
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path>
1592
+ </svg>
1593
+ <svg id="moon-icon" class="h-4 w-4 hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1594
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path>
1595
+ </svg>
1596
+ <span id="theme-label">Light</span>
1597
+ </button>
1598
+ </div>
1599
+
1600
+ <script>
1601
+ function initTheme() {
1602
+ const toggle = document.getElementById('theme-toggle')
1603
+ const sunIcon = document.getElementById('sun-icon')
1604
+ const moonIcon = document.getElementById('moon-icon')
1605
+ const label = document.getElementById('theme-label')
1606
+
1607
+ function getTheme() {
1608
+ if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
1609
+ return localStorage.getItem('theme')
1610
+ }
1611
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
1612
+ }
1613
+
1614
+ function setTheme(theme: string) {
1615
+ if (theme === 'dark') {
1616
+ document.documentElement.setAttribute('data-theme', 'dark')
1617
+ sunIcon?.classList.add('hidden')
1618
+ moonIcon?.classList.remove('hidden')
1619
+ if (label) label.textContent = 'Dark'
1620
+ } else {
1621
+ document.documentElement.removeAttribute('data-theme')
1622
+ sunIcon?.classList.remove('hidden')
1623
+ moonIcon?.classList.add('hidden')
1624
+ if (label) label.textContent = 'Light'
1625
+ }
1626
+ localStorage.setItem('theme', theme)
1627
+ }
1628
+
1629
+ // Set initial theme
1630
+ setTheme(getTheme() || 'light')
1631
+
1632
+ toggle?.addEventListener('click', () => {
1633
+ const current = getTheme()
1634
+ setTheme(current === 'dark' ? 'light' : 'dark')
1635
+ })
1636
+ }
1637
+
1638
+ // Run on initial load
1639
+ initTheme()
1640
+
1641
+ // Re-run on page navigation (for View Transitions)
1642
+ document.addEventListener('astro:after-swap', initTheme)
1643
+ </script>
1644
+ `,
1645
+ "marketing/astro/src/components/blocks/BentoFeatures.astro": '---\nimport { Rocket, Zap, Layers, Shield, Globe, Settings, BarChart3 } from "lucide-astro"\n\ninterface Feature {\n size?: "small" | "tall"\n style?: "default" | "primary" | "accent" | "gradient"\n icon?: string\n stat?: string\n title: string\n description: string\n}\n\ninterface Props {\n heading?: string\n subheading?: string\n features?: Feature[]\n}\n\nconst defaultFeatures: Feature[] = [\n {\n size: "small",\n style: "gradient",\n icon: "zap",\n stat: "5x",\n title: "Faster onboarding",\n description: "Get your team up and running in hours, not weeks.",\n },\n {\n size: "small",\n style: "accent",\n icon: "rocket",\n title: "Quick setup",\n description: "Configure your workspace, invite your team, and start collaborating.",\n },\n {\n size: "small",\n style: "default",\n icon: "layers",\n title: "Powerful integrations",\n description: "Connect with 100+ tools you already use.",\n },\n {\n size: "tall",\n style: "primary",\n icon: "shield",\n title: "Enterprise security",\n description: "SOC 2 compliant with end-to-end encryption and complete audit trails for peace of mind.",\n },\n {\n size: "small",\n style: "default",\n icon: "globe",\n stat: "99.9%",\n title: "Uptime",\n description: "Reliable infrastructure you can count on.",\n },\n {\n size: "small",\n style: "default",\n icon: "globe",\n title: "Global scale",\n description: "Multi-region with custom domains.",\n },\n {\n size: "small",\n style: "default",\n icon: "settings",\n title: "Smart automation",\n description: "Automate repetitive tasks and workflows.",\n },\n {\n size: "small",\n style: "default",\n icon: "layers",\n title: "Flexible workflows",\n description: "Build custom processes for any use case.",\n },\n]\n\nconst {\n heading = "Discover what SaaSify can do",\n subheading = "Everything you need to work smarter and scale faster",\n features = defaultFeatures,\n} = Astro.props\n\nconst displayFeatures = features.length > 0 ? features : defaultFeatures\n\nconst gridPositions = [\n "md:col-span-1 md:row-span-1",\n "md:col-span-1 md:row-span-1",\n "md:col-span-1 md:row-span-1",\n "md:col-span-1 md:row-span-2",\n "md:col-span-1 md:row-span-1",\n "md:col-span-1 md:row-span-1",\n "md:col-span-1 md:row-span-1",\n "md:col-span-1 md:row-span-1",\n]\n\nconst styleClasses = {\n default: {\n bg: "bg-card border border-border/50 hover:border-border",\n text: "text-foreground",\n icon: "bg-primary/10 text-primary",\n statText: "text-primary",\n descText: "text-muted-foreground",\n },\n primary: {\n bg: "bg-primary hover:bg-primary/95",\n text: "text-primary-foreground",\n icon: "bg-white/20 text-white",\n statText: "text-white",\n descText: "text-white/80",\n },\n accent: {\n bg: "bg-gradient-to-br from-teal-500 to-teal-600 hover:from-teal-500/95 hover:to-teal-600/95",\n text: "text-white",\n icon: "bg-white/20 text-white",\n statText: "text-white",\n descText: "text-white/80",\n },\n gradient: {\n bg: "bg-gradient-to-br from-primary via-primary/90 to-secondary hover:from-primary/95",\n text: "text-white",\n icon: "bg-white/20 text-white",\n statText: "text-white",\n descText: "text-white/80",\n },\n}\n---\n\n<section class="py-16 md:py-24">\n <div class="container mx-auto px-4">\n <!-- Header -->\n {(heading || subheading) && (\n <div class="text-center mb-12 md:mb-16 max-w-3xl mx-auto">\n {heading && (\n <h2 class="text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight mb-6">\n {heading}\n </h2>\n )}\n {subheading && (\n <p class="text-xl md:text-2xl text-muted-foreground">{subheading}</p>\n )}\n </div>\n )}\n\n <!-- Bento Grid -->\n <div class="grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-5 md:grid-rows-[repeat(3,minmax(140px,160px))]">\n {displayFeatures.map((feature, index) => {\n const style = feature.style || "default"\n const styleConfig = styleClasses[style] || styleClasses.default\n const gridPosition = gridPositions[index] || "md:col-span-1 md:row-span-1"\n\n return (\n <div\n class:list={[\n "relative rounded-2xl overflow-hidden p-5 md:p-6 flex flex-col transition-all duration-300 group",\n "hover:shadow-lg hover:-translate-y-0.5",\n "col-span-1 row-span-1",\n gridPosition,\n styleConfig.bg,\n ]}\n >\n {/* Decorative elements */}\n {feature.size === "tall" && (\n <div class="absolute -right-6 -bottom-6 w-24 h-24 md:w-32 md:h-32 rounded-full bg-white/10 blur-xl" />\n )}\n\n {/* Content */}\n <div class="relative z-10 flex flex-col h-full">\n {/* Icon */}\n {feature.icon && (\n <div class:list={["w-10 h-10 md:w-11 md:h-11 rounded-xl flex items-center justify-center mb-auto", styleConfig.icon]}>\n {feature.icon === "rocket" && <Rocket class="w-5 h-5" />}\n {feature.icon === "zap" && <Zap class="w-5 h-5" />}\n {feature.icon === "layers" && <Layers class="w-5 h-5" />}\n {feature.icon === "shield" && <Shield class="w-5 h-5" />}\n {feature.icon === "globe" && <Globe class="w-5 h-5" />}\n {feature.icon === "settings" && <Settings class="w-5 h-5" />}\n {feature.icon === "barChart" && <BarChart3 class="w-5 h-5" />}\n </div>\n )}\n\n {/* Spacer */}\n <div class="flex-1 min-h-2" />\n\n {/* Stat */}\n {feature.stat && (\n <div class:list={["font-bold mb-0.5 leading-none text-3xl md:text-4xl", styleConfig.statText]}>\n {feature.stat}\n </div>\n )}\n\n {/* Title */}\n <h3 class:list={["font-semibold mb-1 text-base md:text-lg", styleConfig.text]}>\n {feature.title}\n </h3>\n\n {/* Description */}\n <p class:list={["leading-snug text-xs md:text-sm", styleConfig.descText]}>\n {feature.description}\n </p>\n </div>\n </div>\n )\n })}\n </div>\n </div>\n</section>\n',
1646
+ "marketing/astro/src/components/blocks/FeatureShowcase.astro": '---\nimport { Check } from "lucide-astro"\n\ninterface Props {\n label?: string\n headline: string\n description: string\n features?: { text: string }[]\n link?: {\n label: string\n href: string\n }\n imagePosition?: "left" | "right"\n}\n\nconst {\n label,\n headline,\n description,\n features = [],\n link,\n imagePosition = "right",\n} = Astro.props\n---\n\n<section class="py-16 md:py-24">\n <div class="container mx-auto px-4">\n <div class:list={[\n "grid md:grid-cols-2 gap-12 lg:gap-16 items-center",\n imagePosition === "left" && "md:grid-flow-dense"\n ]}>\n <!-- Content -->\n <div class:list={[imagePosition === "left" && "md:col-start-2"]}>\n {label && (\n <span class="inline-block text-sm font-medium text-primary mb-4">\n {label}\n </span>\n )}\n <h2 class="text-3xl md:text-4xl font-bold tracking-tight mb-4">\n {headline}\n </h2>\n <p class="text-lg text-muted-foreground mb-6">\n {description}\n </p>\n\n {features.length > 0 && (\n <ul class="space-y-3 mb-8">\n {features.map((feature) => (\n <li class="flex items-center gap-3">\n <div class="flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-primary/10">\n <Check class="h-3 w-3 text-primary" />\n </div>\n <span class="text-sm text-muted-foreground">\n {feature.text}\n </span>\n </li>\n ))}\n </ul>\n )}\n\n {link && (\n <a\n href={link.href}\n class="inline-flex items-center gap-2 text-sm font-medium text-primary hover:underline"\n >\n {link.label}\n <span aria-hidden="true">&rarr;</span>\n </a>\n )}\n </div>\n\n <!-- Image Placeholder -->\n <div class:list={[\n "relative aspect-[4/3] rounded-2xl bg-muted overflow-hidden",\n imagePosition === "left" && "md:col-start-1 md:row-start-1"\n ]}>\n <div class="absolute inset-0 flex items-center justify-center">\n <div class="text-center">\n <div class="w-16 h-16 mx-auto mb-4 rounded-xl bg-primary/10 flex items-center justify-center">\n <svg\n class="w-8 h-8 text-primary"\n fill="none"\n stroke="currentColor"\n viewBox="0 0 24 24"\n >\n <path\n stroke-linecap="round"\n stroke-linejoin="round"\n stroke-width="1.5"\n d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"\n />\n </svg>\n </div>\n <p class="text-sm text-muted-foreground">\n Feature illustration\n </p>\n </div>\n </div>\n </div>\n </div>\n </div>\n</section>\n',
1647
+ "marketing/astro/src/components/blocks/FinalCTA.astro": '---\ninterface FinalCTALink {\n label: string\n href: string\n variant: "default" | "outline"\n}\n\ninterface Props {\n headline?: string\n subheading?: string\n links?: FinalCTALink[]\n style?: "dark" | "light" | "gradient"\n}\n\nconst {\n headline = "Ready to transform how your team works?",\n subheading = "Join thousands of teams who chose the smarter way to work. Start free, upgrade as you grow.",\n links = [\n { label: "Start free trial", href: "/sign-up", variant: "outline" },\n { label: "Book a demo", href: "/contact", variant: "default" },\n ],\n style = "dark",\n} = Astro.props\n\nconst bgClasses = {\n dark: "bg-foreground text-background",\n light: "bg-muted text-foreground",\n gradient: "bg-gradient-to-br from-primary to-primary/80 text-primary-foreground",\n}\n\nconst buttonClasses = {\n dark: {\n default: "bg-background text-foreground hover:bg-background/90",\n outline: "border border-background/30 text-background hover:bg-background/10",\n },\n light: {\n default: "bg-primary text-primary-foreground hover:bg-primary/90",\n outline: "border border-border hover:bg-background",\n },\n gradient: {\n default: "bg-background text-foreground hover:bg-background/90",\n outline: "border border-primary-foreground/30 text-primary-foreground hover:bg-primary-foreground/10",\n },\n}\n\nconst subtextClasses = {\n dark: "text-background/80",\n light: "text-muted-foreground",\n gradient: "text-primary-foreground/80",\n}\n---\n\n<section class:list={["py-16 md:py-24", bgClasses[style]]}>\n <div class="container mx-auto px-4">\n <div class="max-w-3xl mx-auto text-center">\n <h2 class="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight mb-6">\n {headline}\n </h2>\n {subheading && (\n <p class:list={["text-lg md:text-xl mb-8", subtextClasses[style]]}>\n {subheading}\n </p>\n )}\n\n {links && links.length > 0 && (\n <div class="flex flex-wrap gap-4 justify-center">\n {links.map((link) => (\n <a\n href={link.href}\n class:list={[\n "inline-flex items-center justify-center px-6 py-3 text-sm font-medium rounded-md transition-colors",\n buttonClasses[style][link.variant]\n ]}\n >\n {link.label}\n </a>\n ))}\n </div>\n )}\n </div>\n </div>\n</section>\n',
1648
+ "marketing/astro/src/components/blocks/IndustryTabs.astro": `---
1649
+ interface Tab {
1650
+ name: string
1651
+ stat: string
1652
+ statLabel: string
1653
+ description: string
1654
+ link?: {
1655
+ label: string
1656
+ href: string
1657
+ }
1658
+ }
1659
+
1660
+ interface Props {
1661
+ heading?: string
1662
+ subheading?: string
1663
+ tabs?: Tab[]
1664
+ }
1665
+
1666
+ const defaultTabs: Tab[] = [
1667
+ {
1668
+ name: "Sales Teams",
1669
+ stat: "40%",
1670
+ statLabel: "Faster deal cycles with smart pipeline tools",
1671
+ description: "Close deals faster with intelligent pipeline management, automated follow-ups, and real-time insights that help your team hit quota every quarter.",
1672
+ link: { label: "Solutions for sales", href: "/use-cases/sales" },
1673
+ },
1674
+ {
1675
+ name: "Marketing Teams",
1676
+ stat: "3x",
1677
+ statLabel: "Campaign velocity with streamlined workflows",
1678
+ description: "Launch campaigns that convert with collaborative planning, asset management, and performance analytics all in one place.",
1679
+ link: { label: "Solutions for marketing", href: "/use-cases/marketing" },
1680
+ },
1681
+ {
1682
+ name: "Product Teams",
1683
+ stat: "50%",
1684
+ statLabel: "Faster shipping with better prioritization",
1685
+ description: "Ship features users love with roadmap planning, feedback collection, and release management that keeps everyone aligned.",
1686
+ link: { label: "Solutions for product", href: "/use-cases/product" },
1687
+ },
1688
+ {
1689
+ name: "Operations",
1690
+ stat: "60%",
1691
+ statLabel: "Time saved with process automation",
1692
+ description: "Scale your operations without the chaos. Automate processes, manage resources, and get visibility across your entire organization.",
1693
+ link: { label: "Solutions for ops", href: "/use-cases/operations" },
1694
+ },
1695
+ ]
1696
+
1697
+ const {
1698
+ heading = "Solutions that deliver real results",
1699
+ subheading = "Whether you're in sales, marketing, or product, SaaSify adapts to how your team works.",
1700
+ tabs = defaultTabs,
1701
+ } = Astro.props
1702
+
1703
+ const displayTabs = tabs.length > 0 ? tabs : defaultTabs
1704
+ ---
1705
+
1706
+ <section class="py-16 md:py-24 bg-muted/30">
1707
+ <div class="container mx-auto px-4">
1708
+ <!-- Header -->
1709
+ {(heading || subheading) && (
1710
+ <div class="text-center mb-12 md:mb-16 max-w-3xl mx-auto">
1711
+ {heading && (
1712
+ <h2 class="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight mb-4">
1713
+ {heading}
1714
+ </h2>
1715
+ )}
1716
+ {subheading && (
1717
+ <p class="text-lg md:text-xl text-muted-foreground">
1718
+ {subheading}
1719
+ </p>
1720
+ )}
1721
+ </div>
1722
+ )}
1723
+
1724
+ <!-- Tabs -->
1725
+ <div class="flex flex-wrap justify-center gap-2 mb-12" id="industry-tabs">
1726
+ {displayTabs.map((tab, index) => (
1727
+ <button
1728
+ type="button"
1729
+ data-tab-index={index}
1730
+ class:list={[
1731
+ "industry-tab px-4 py-2 text-sm font-medium rounded-full transition-colors",
1732
+ index === 0
1733
+ ? "bg-primary text-primary-foreground"
1734
+ : "bg-background border border-border hover:bg-muted"
1735
+ ]}
1736
+ >
1737
+ {tab.name}
1738
+ </button>
1739
+ ))}
1740
+ </div>
1741
+
1742
+ <!-- Content -->
1743
+ <div class="grid md:grid-cols-2 gap-12 lg:gap-16 items-center max-w-5xl mx-auto">
1744
+ {displayTabs.map((tab, index) => (
1745
+ <div
1746
+ data-tab-content={index}
1747
+ class:list={["tab-content text-center md:text-left", index !== 0 && "hidden"]}
1748
+ >
1749
+ <div class="text-7xl md:text-8xl lg:text-9xl font-bold text-primary mb-2">
1750
+ {tab.stat}
1267
1751
  </div>
1752
+ <p class="text-xl md:text-2xl font-medium text-foreground">
1753
+ {tab.statLabel}
1754
+ </p>
1268
1755
  </div>
1269
- </section>
1756
+ ))}
1270
1757
 
1271
- {/* Features Section */}
1272
- <section id="features" className="py-24 sm:py-32">
1273
- <div className="container mx-auto px-4">
1274
- <div className="text-center mb-16">
1275
- <h2 className="text-3xl font-bold tracking-tight text-gray-900 dark:text-white sm:text-4xl">
1276
- Everything you need
1277
- </h2>
1278
- <p className="mt-4 text-lg text-gray-600 dark:text-gray-300">
1279
- Built with the best tools for modern web development
1280
- </p>
1758
+ {displayTabs.map((tab, index) => (
1759
+ <div
1760
+ data-tab-description={index}
1761
+ class:list={["tab-description", index !== 0 && "hidden"]}
1762
+ >
1763
+ <p class="text-lg text-muted-foreground mb-6">
1764
+ {tab.description}
1765
+ </p>
1766
+ {tab.link && (
1767
+ <a
1768
+ href={tab.link.href}
1769
+ class="inline-flex items-center gap-2 px-6 py-3 text-sm font-medium rounded-md bg-primary text-primary-foreground hover:bg-primary/90 transition-colors"
1770
+ >
1771
+ {tab.link.label}
1772
+ <span aria-hidden="true">&rarr;</span>
1773
+ </a>
1774
+ )}
1775
+ </div>
1776
+ ))}
1777
+ </div>
1778
+ </div>
1779
+ </section>
1780
+
1781
+ <script>
1782
+ function initIndustryTabs() {
1783
+ const tabsContainer = document.getElementById('industry-tabs')
1784
+ if (!tabsContainer) return
1785
+
1786
+ const tabs = tabsContainer.querySelectorAll('.industry-tab')
1787
+ const contents = document.querySelectorAll('.tab-content')
1788
+ const descriptions = document.querySelectorAll('.tab-description')
1789
+
1790
+ tabs.forEach((tab) => {
1791
+ tab.addEventListener('click', () => {
1792
+ const index = tab.getAttribute('data-tab-index')
1793
+
1794
+ // Update tab styles
1795
+ tabs.forEach((t) => {
1796
+ t.classList.remove('bg-primary', 'text-primary-foreground')
1797
+ t.classList.add('bg-background', 'border', 'border-border', 'hover:bg-muted')
1798
+ })
1799
+ tab.classList.add('bg-primary', 'text-primary-foreground')
1800
+ tab.classList.remove('bg-background', 'border', 'border-border', 'hover:bg-muted')
1801
+
1802
+ // Update content visibility
1803
+ contents.forEach((content) => {
1804
+ if (content.getAttribute('data-tab-content') === index) {
1805
+ content.classList.remove('hidden')
1806
+ } else {
1807
+ content.classList.add('hidden')
1808
+ }
1809
+ })
1810
+
1811
+ descriptions.forEach((desc) => {
1812
+ if (desc.getAttribute('data-tab-description') === index) {
1813
+ desc.classList.remove('hidden')
1814
+ } else {
1815
+ desc.classList.add('hidden')
1816
+ }
1817
+ })
1818
+ })
1819
+ })
1820
+ }
1821
+
1822
+ initIndustryTabs()
1823
+ document.addEventListener('astro:after-swap', initIndustryTabs)
1824
+ </script>
1825
+ `,
1826
+ "marketing/astro/src/components/blocks/LogoBanner.astro": '---\ninterface Logo {\n name: string\n initials?: string\n}\n\ninterface Props {\n heading?: string\n logos?: Logo[]\n style?: "scroll" | "grid"\n}\n\nconst defaultLogos: Logo[] = [\n { name: "TechFlow Inc", initials: "TF" },\n { name: "Acme Corp", initials: "AC" },\n { name: "Evergreen HQ", initials: "EH" },\n { name: "Atlas Network", initials: "AN" },\n { name: "Beacon Digital", initials: "BD" },\n { name: "Cascade Systems", initials: "CS" },\n]\n\nconst {\n heading = "Trusted by fast-growing companies everywhere",\n logos = defaultLogos,\n style = "scroll",\n} = Astro.props\n\nconst displayLogos = logos.length > 0 ? logos : defaultLogos\n---\n\n<section class="py-12 md:py-16 border-y border-border/50">\n <div class="container mx-auto px-4">\n {heading && (\n <p class="text-center text-sm text-muted-foreground mb-8 uppercase tracking-wider">\n {heading}\n </p>\n )}\n\n {style === "scroll" ? (\n <div class="logo-scroll-container">\n <div class="logo-scroll-track">\n {[...displayLogos, ...displayLogos].map((logo, index) => (\n <div class="logo-item flex items-center justify-center px-6 md:px-8 grayscale hover:grayscale-0 transition-all duration-300">\n <div class="flex items-center gap-2">\n <span class="w-8 h-8 rounded bg-muted flex items-center justify-center text-xs font-bold text-foreground">\n {logo.initials || logo.name.slice(0, 2).toUpperCase()}\n </span>\n <span class="text-sm font-medium text-muted-foreground hidden md:block">\n {logo.name}\n </span>\n </div>\n </div>\n ))}\n </div>\n </div>\n ) : (\n <div class="grid grid-cols-3 md:grid-cols-6 gap-8 items-center justify-items-center">\n {displayLogos.map((logo) => (\n <div class="logo-item flex items-center justify-center px-6 md:px-8 grayscale hover:grayscale-0 transition-all duration-300">\n <div class="flex items-center gap-2">\n <span class="w-8 h-8 rounded bg-muted flex items-center justify-center text-xs font-bold text-foreground">\n {logo.initials || logo.name.slice(0, 2).toUpperCase()}\n </span>\n <span class="text-sm font-medium text-muted-foreground hidden md:block">\n {logo.name}\n </span>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n</section>\n\n<style>\n .logo-scroll-container {\n overflow: hidden;\n mask-image: linear-gradient(to right, transparent, black 10%, black 90%, transparent);\n }\n\n .logo-scroll-track {\n display: flex;\n animation: scroll 30s linear infinite;\n width: max-content;\n }\n\n @keyframes scroll {\n 0% { transform: translateX(0); }\n 100% { transform: translateX(-50%); }\n }\n\n .logo-scroll-container:hover .logo-scroll-track {\n animation-play-state: paused;\n }\n</style>\n',
1827
+ "marketing/astro/src/components/blocks/PricingTable.astro": '---\nimport { Check, X } from "lucide-astro"\n\ninterface PricingFeature {\n feature: string\n included: boolean\n}\n\ninterface PricingPlan {\n name: string\n price: string\n description: string\n featured?: boolean\n features: PricingFeature[]\n link: {\n label: string\n href: string\n variant: "default" | "outline"\n }\n}\n\ninterface Props {\n heading?: string\n subheading?: string\n plans?: PricingPlan[]\n}\n\nconst defaultPlans: PricingPlan[] = [\n {\n name: "Free",\n price: "$0/mo",\n description: "Perfect for trying SaaSify.",\n features: [\n { feature: "Up to 3 users", included: true },\n { feature: "Basic features", included: true },\n { feature: "Community support", included: true },\n ],\n link: { label: "Get started free", href: "/sign-up", variant: "outline" },\n },\n {\n name: "Pro",\n price: "$29/mo",\n description: "For small teams getting started.",\n featured: true,\n features: [\n { feature: "Up to 10 users", included: true },\n { feature: "Advanced features", included: true },\n { feature: "Integrations", included: true },\n { feature: "Priority support", included: true },\n ],\n link: { label: "Get Pro", href: "/sign-up", variant: "default" },\n },\n {\n name: "Business",\n price: "$99/mo",\n description: "For teams ready to scale.",\n features: [\n { feature: "Unlimited users", included: true },\n { feature: "All features", included: true },\n { feature: "API access", included: true },\n { feature: "Dedicated support", included: true },\n ],\n link: { label: "Get Business", href: "/sign-up", variant: "outline" },\n },\n]\n\nconst {\n heading = "Simple, transparent pricing",\n subheading = "Start free, upgrade as your team grows. No hidden fees.",\n plans = defaultPlans,\n} = Astro.props\n\nconst displayPlans = plans.length > 0 ? plans : defaultPlans\n---\n\n<section class="py-16 md:py-24">\n <div class="container mx-auto px-4">\n <!-- Header -->\n {(heading || subheading) && (\n <div class="text-center mb-12 md:mb-16 max-w-3xl mx-auto">\n {heading && (\n <h2 class="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight mb-4">\n {heading}\n </h2>\n )}\n {subheading && (\n <p class="text-lg md:text-xl text-muted-foreground">\n {subheading}\n </p>\n )}\n </div>\n )}\n\n <!-- Pricing Cards -->\n <div class="grid md:grid-cols-3 gap-6 lg:gap-8 max-w-5xl mx-auto">\n {displayPlans.map((plan) => (\n <div\n class:list={[\n "relative rounded-2xl p-6 md:p-8 flex flex-col",\n plan.featured\n ? "bg-primary text-primary-foreground border-2 border-primary"\n : "bg-card border border-border"\n ]}\n >\n {plan.featured && (\n <span class="absolute -top-3 left-1/2 -translate-x-1/2 px-3 py-1 text-xs font-medium rounded-full bg-background text-foreground">\n Most Popular\n </span>\n )}\n\n <!-- Plan header -->\n <div class="mb-6">\n <h3 class:list={["text-lg font-semibold mb-2", plan.featured ? "text-primary-foreground" : "text-foreground"]}>\n {plan.name}\n </h3>\n <div class:list={["text-4xl font-bold mb-2", plan.featured ? "text-primary-foreground" : "text-foreground"]}>\n {plan.price}\n </div>\n <p class:list={["text-sm", plan.featured ? "text-primary-foreground/80" : "text-muted-foreground"]}>\n {plan.description}\n </p>\n </div>\n\n <!-- Features -->\n <ul class="space-y-3 mb-8 flex-1">\n {plan.features.map((feature) => (\n <li class="flex items-center gap-3">\n {feature.included ? (\n <Check class:list={["h-4 w-4", plan.featured ? "text-primary-foreground" : "text-primary"]} />\n ) : (\n <X class:list={["h-4 w-4", plan.featured ? "text-primary-foreground/50" : "text-muted-foreground"]} />\n )}\n <span\n class:list={[\n "text-sm",\n plan.featured\n ? feature.included ? "text-primary-foreground" : "text-primary-foreground/50"\n : feature.included ? "text-foreground" : "text-muted-foreground"\n ]}\n >\n {feature.feature}\n </span>\n </li>\n ))}\n </ul>\n\n <!-- CTA -->\n <a\n href={plan.link.href}\n class:list={[\n "w-full inline-flex items-center justify-center px-6 py-3 text-sm font-medium rounded-md transition-colors",\n plan.featured\n ? "bg-background text-foreground hover:bg-background/90"\n : plan.link.variant === "default"\n ? "bg-primary text-primary-foreground hover:bg-primary/90"\n : "border border-border bg-background hover:bg-muted"\n ]}\n >\n {plan.link.label}\n </a>\n </div>\n ))}\n </div>\n\n <!-- View all link -->\n <div class="text-center mt-8">\n <a\n href="/pricing"\n class="inline-flex items-center gap-2 text-sm font-medium text-primary hover:underline"\n >\n View full comparison\n <span aria-hidden="true">&rarr;</span>\n </a>\n </div>\n </div>\n</section>\n',
1828
+ "marketing/astro/src/components/blocks/ProofBanner.astro": '---\ninterface ProofBannerLink {\n label: string\n href: string\n variant: "default" | "outline"\n}\n\ninterface Props {\n headline?: string\n subtext?: string\n links?: ProofBannerLink[]\n style?: "centered" | "left"\n}\n\nconst {\n headline = "Transform how your team works, collaborates, and grows",\n subtext = "Every interaction feeds into a powerful platform that powers personalized experiences, seamless collaboration, and intelligent automation across every touchpoint.",\n links = [\n { label: "Start free trial", href: "/sign-up", variant: "default" },\n { label: "Book a demo", href: "/contact", variant: "outline" },\n ],\n style = "centered",\n} = Astro.props\n---\n\n<section class="py-16 md:py-24">\n <div class="container mx-auto px-4">\n <div class:list={["max-w-4xl", style === "centered" ? "mx-auto text-center" : ""]}>\n <h2 class="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight mb-6">\n {headline}\n </h2>\n {subtext && (\n <p class="text-lg md:text-xl text-muted-foreground mb-8 max-w-3xl mx-auto">\n {subtext}\n </p>\n )}\n {links && links.length > 0 && (\n <div class:list={["flex flex-wrap gap-4", style === "centered" ? "justify-center" : ""]}>\n {links.map((link) => (\n <a\n href={link.href}\n class:list={[\n "inline-flex items-center justify-center px-6 py-3 text-sm font-medium rounded-md transition-colors",\n link.variant === "default"\n ? "bg-primary text-primary-foreground hover:bg-primary/90"\n : "border border-border bg-background hover:bg-muted"\n ]}\n >\n {link.label}\n </a>\n ))}\n </div>\n )}\n </div>\n </div>\n</section>\n',
1829
+ "marketing/astro/src/components/blocks/TestimonialsGrid.astro": '---\ninterface Testimonial {\n stat: string\n statLabel: string\n quote: string\n author: string\n company: string\n}\n\ninterface Props {\n heading?: string\n subheading?: string\n testimonials?: Testimonial[]\n}\n\nconst defaultTestimonials: Testimonial[] = [\n {\n stat: "94%",\n statLabel: "Faster onboarding",\n quote: "We got our entire team onboarded in under a day. The intuitive interface and powerful integrations saved us weeks of setup time.",\n author: "Sarah Chen",\n company: "TechFlow Inc",\n },\n {\n stat: "3x",\n statLabel: "Productivity",\n quote: "Our team is shipping features faster than ever. The automation tools eliminated hours of manual work every week.",\n author: "Marcus Rivera",\n company: "Beacon Digital",\n },\n {\n stat: "40%",\n statLabel: "Cost reduction",\n quote: "We consolidated five different tools into SaaSify. The ROI was immediate and our team loves having everything in one place.",\n author: "David Kim",\n company: "Cascade Systems",\n },\n]\n\nconst {\n heading = "Loved by teams at companies of all sizes",\n subheading = "See how leading teams use SaaSify to drive growth and productivity.",\n testimonials = defaultTestimonials,\n} = Astro.props\n\nconst displayTestimonials = testimonials.length > 0 ? testimonials : defaultTestimonials\n---\n\n<section class="py-16 md:py-24">\n <div class="container mx-auto px-4">\n <!-- Header -->\n {(heading || subheading) && (\n <div class="text-center mb-12 md:mb-16 max-w-3xl mx-auto">\n {heading && (\n <h2 class="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight mb-4">\n {heading}\n </h2>\n )}\n {subheading && (\n <p class="text-lg md:text-xl text-muted-foreground">\n {subheading}\n </p>\n )}\n </div>\n )}\n\n <!-- Testimonials Grid -->\n <div class="grid md:grid-cols-3 gap-6 lg:gap-8">\n {displayTestimonials.map((testimonial) => (\n <div class="relative bg-card border border-border rounded-2xl p-6 md:p-8">\n <!-- Stat -->\n <div class="mb-6">\n <div class="text-4xl md:text-5xl font-bold text-primary mb-1">\n {testimonial.stat}\n </div>\n <p class="text-sm font-medium text-muted-foreground">\n {testimonial.statLabel}\n </p>\n </div>\n\n <!-- Quote -->\n <blockquote class="text-foreground mb-6">\n "{testimonial.quote}"\n </blockquote>\n\n <!-- Author -->\n <div class="flex items-center gap-3">\n <div class="w-10 h-10 rounded-full bg-muted flex items-center justify-center">\n <span class="text-sm font-medium">\n {testimonial.author.split(" ").map((n) => n[0]).join("")}\n </span>\n </div>\n <div>\n <p class="text-sm font-medium text-foreground">\n {testimonial.author}\n </p>\n <p class="text-sm text-muted-foreground">\n {testimonial.company}\n </p>\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n</section>\n',
1830
+ "marketing/astro/src/components/blocks/TrustColumns.astro": '---\nimport { Zap, Plug, Database, Cloud, Shield, Lock, Award, Globe } from "lucide-astro"\n\ninterface TrustItem {\n icon: string\n text: string\n}\n\ninterface TrustColumn {\n label: string\n heading: string\n description: string\n items: TrustItem[]\n}\n\ninterface Props {\n columns?: TrustColumn[]\n}\n\nconst defaultColumns: TrustColumn[] = [\n {\n label: "Integrations",\n heading: "Connect anywhere",\n description: "Plug in and get started immediately with pre-built connectors for every major platform.",\n items: [\n { icon: "zap", text: "Go live in minutes" },\n { icon: "plug", text: "Pre-built connectors" },\n { icon: "database", text: "Complete data sync" },\n { icon: "cloud", text: "Cloud-native infrastructure" },\n ],\n },\n {\n label: "Security & Compliance",\n heading: "Enterprise-level security",\n description: "Keep your data safe with encryption, granular access control, and compliance-ready infrastructure.",\n items: [\n { icon: "shield", text: "SOC 2 Type II certified" },\n { icon: "lock", text: "End-to-end encryption" },\n { icon: "award", text: "Complete audit trails" },\n { icon: "globe", text: "GDPR compliant" },\n ],\n },\n]\n\nconst { columns = defaultColumns } = Astro.props\n\nconst displayColumns = columns.length > 0 ? columns : defaultColumns\n---\n\n<section class="py-16 md:py-24">\n <div class="container mx-auto px-4">\n <div class="grid md:grid-cols-2 gap-12 lg:gap-16">\n {displayColumns.map((column) => (\n <div>\n <span class="inline-block text-sm font-medium text-primary mb-4">\n {column.label}\n </span>\n <h2 class="text-2xl md:text-3xl font-bold tracking-tight mb-4">\n {column.heading}\n </h2>\n <p class="text-muted-foreground mb-8">\n {column.description}\n </p>\n\n <ul class="space-y-4">\n {column.items.map((item) => (\n <li class="flex items-center gap-3">\n <div class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary/10">\n {item.icon === "zap" && <Zap class="h-4 w-4 text-primary" />}\n {item.icon === "plug" && <Plug class="h-4 w-4 text-primary" />}\n {item.icon === "database" && <Database class="h-4 w-4 text-primary" />}\n {item.icon === "cloud" && <Cloud class="h-4 w-4 text-primary" />}\n {item.icon === "shield" && <Shield class="h-4 w-4 text-primary" />}\n {item.icon === "lock" && <Lock class="h-4 w-4 text-primary" />}\n {item.icon === "award" && <Award class="h-4 w-4 text-primary" />}\n {item.icon === "globe" && <Globe class="h-4 w-4 text-primary" />}\n </div>\n <span class="text-sm font-medium">\n {item.text}\n </span>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n </div>\n</section>\n',
1831
+ "marketing/astro/src/components/heros/AnimatedMockup.astro": `---
1832
+ interface MockupState {
1833
+ id: number
1834
+ label: string
1835
+ sidebarActive: string
1836
+ previewTitle: string
1837
+ previewDescription: string
1838
+ previewCategory: string
1839
+ previewStatus: "draft" | "published" | "featured"
1840
+ previewUrl?: string
1841
+ }
1842
+
1843
+ const mockupStates: MockupState[] = [
1844
+ {
1845
+ id: 1,
1846
+ label: "Setup & styling",
1847
+ sidebarActive: "templates",
1848
+ previewTitle: "Atlas Directory",
1849
+ previewDescription: "Apply your brand, typography, and layout in minutes.",
1850
+ previewCategory: "Design systems",
1851
+ previewStatus: "draft",
1852
+ previewUrl: "atlas.directory/home",
1853
+ },
1854
+ {
1855
+ id: 2,
1856
+ label: "Plans & pricing",
1857
+ sidebarActive: "billing",
1858
+ previewTitle: "Pro Listing Plan",
1859
+ previewDescription: "Recurring billing, featured placements, and add-ons configured.",
1860
+ previewCategory: "Monetization",
1861
+ previewStatus: "draft",
1862
+ previewUrl: "atlas.directory/billing",
1863
+ },
1864
+ {
1865
+ id: 3,
1866
+ label: "SEO & publishing",
1867
+ sidebarActive: "seo",
1868
+ previewTitle: "Atlas Directory",
1869
+ previewDescription: "Schema, sitemap, and custom domain are ready to publish.",
1870
+ previewCategory: "SEO & domains",
1871
+ previewStatus: "published",
1872
+ previewUrl: "atlas.directory/launch",
1873
+ },
1874
+ {
1875
+ id: 4,
1876
+ label: "Payouts live",
1877
+ sidebarActive: "overview",
1878
+ previewTitle: "Atlas Directory",
1879
+ previewDescription: "Subscribers active, payouts scheduled to Stripe, featured slots sold.",
1880
+ previewCategory: "Revenue",
1881
+ previewStatus: "featured",
1882
+ previewUrl: "atlas.directory/analytics",
1883
+ },
1884
+ ]
1885
+
1886
+ const initialState = mockupStates[0]
1887
+ ---
1888
+
1889
+ <div class="mockup-wrapper" id="animated-mockup">
1890
+ <!-- Browser Chrome -->
1891
+ <div class="mockup-chrome">
1892
+ <div class="mockup-chrome-dots">
1893
+ <span class="dot dot-red"></span>
1894
+ <span class="dot dot-yellow"></span>
1895
+ <span class="dot dot-green"></span>
1896
+ </div>
1897
+ <div class="mockup-chrome-title">SaaSify</div>
1898
+ <div class="mockup-chrome-actions"></div>
1899
+ </div>
1900
+
1901
+ <!-- App Content -->
1902
+ <div class="mockup-content">
1903
+ <!-- Sidebar -->
1904
+ <div class="mockup-sidebar">
1905
+ <div class="sidebar-header">
1906
+ <div class="sidebar-logo">
1907
+ <span class="logo-icon">D</span>
1908
+ <span class="logo-text">My Directory</span>
1909
+ </div>
1910
+ </div>
1911
+ <nav class="sidebar-nav">
1912
+ <div class="sidebar-item" data-nav="overview">
1913
+ <span class="sidebar-icon">\u{1F4CA}</span>
1914
+ <span class="sidebar-label">Overview</span>
1915
+ </div>
1916
+ <div class="sidebar-item sidebar-item--active" data-nav="templates">
1917
+ <span class="sidebar-icon">\u{1F5BC}\uFE0F</span>
1918
+ <span class="sidebar-label">Templates</span>
1919
+ </div>
1920
+ <div class="sidebar-item" data-nav="listings">
1921
+ <span class="sidebar-icon">\u{1F4CB}</span>
1922
+ <span class="sidebar-label">Listings</span>
1923
+ <span class="sidebar-badge">24</span>
1924
+ </div>
1925
+ <div class="sidebar-item" data-nav="billing">
1926
+ <span class="sidebar-icon">\u{1F4B3}</span>
1927
+ <span class="sidebar-label">Plans & Billing</span>
1928
+ </div>
1929
+ <div class="sidebar-item" data-nav="automations">
1930
+ <span class="sidebar-icon">\u26A1</span>
1931
+ <span class="sidebar-label">Automations</span>
1932
+ </div>
1933
+ <div class="sidebar-item" data-nav="seo">
1934
+ <span class="sidebar-icon">\u{1F50E}</span>
1935
+ <span class="sidebar-label">SEO</span>
1936
+ </div>
1937
+ <div class="sidebar-item" data-nav="settings">
1938
+ <span class="sidebar-icon">\u2699\uFE0F</span>
1939
+ <span class="sidebar-label">Settings</span>
1940
+ </div>
1941
+ </nav>
1942
+ </div>
1943
+
1944
+ <!-- Main Content Area -->
1945
+ <div class="mockup-main">
1946
+ <!-- Header -->
1947
+ <div class="main-header">
1948
+ <div class="header-title">
1949
+ <h2 id="mockup-label">{initialState.label}</h2>
1950
+ <span class="header-breadcrumb">SaaSify / <span id="mockup-breadcrumb">{initialState.previewTitle}</span></span>
1951
+ </div>
1952
+ <div class="header-actions">
1953
+ <button type="button" class="action-btn" id="mockup-action-btn">
1954
+ Save Draft
1955
+ </button>
1956
+ </div>
1957
+ </div>
1958
+
1959
+ <!-- Split View: Editor + Preview -->
1960
+ <div class="main-split">
1961
+ <!-- Editor Panel -->
1962
+ <div class="editor-panel">
1963
+ <div class="editor-section">
1964
+ <span class="editor-label">Listing Name</span>
1965
+ <div class="editor-input">
1966
+ <span class="input-text" id="mockup-title">{initialState.previewTitle}</span>
1967
+ <span class="input-cursor"></span>
1968
+ </div>
1281
1969
  </div>
1282
- <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
1283
- <div className="p-6 rounded-xl border border-gray-200 dark:border-gray-700">
1284
- <div className="w-12 h-12 bg-gray-100 dark:bg-gray-800 rounded-lg flex items-center justify-center mb-4">
1285
- <svg className="w-6 h-6 text-gray-900 dark:text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1286
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
1287
- </svg>
1288
- </div>
1289
- <h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
1290
- Lightning Fast
1291
- </h3>
1292
- <p className="text-gray-600 dark:text-gray-300">
1293
- Built on Next.js with Turbopack for instant hot reload and optimized production builds.
1294
- </p>
1970
+ <div class="editor-section">
1971
+ <span class="editor-label">Category</span>
1972
+ <div class="editor-select">
1973
+ <span id="mockup-category">{initialState.previewCategory}</span>
1974
+ <span class="select-arrow">\u25BC</span>
1295
1975
  </div>
1296
- <div className="p-6 rounded-xl border border-gray-200 dark:border-gray-700">
1297
- <div className="w-12 h-12 bg-gray-100 dark:bg-gray-800 rounded-lg flex items-center justify-center mb-4">
1298
- <svg className="w-6 h-6 text-gray-900 dark:text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1299
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4" />
1300
- </svg>
1976
+ </div>
1977
+ <div class="editor-section">
1978
+ <span class="editor-label">Description</span>
1979
+ <div class="editor-textarea">
1980
+ <span class="textarea-text" id="mockup-description">{initialState.previewDescription}</span>
1981
+ </div>
1982
+ </div>
1983
+ </div>
1984
+
1985
+ <!-- Preview Panel -->
1986
+ <div class="preview-panel">
1987
+ <div class="preview-header">
1988
+ <span class="preview-label">Live Preview</span>
1989
+ <span class="preview-url" id="mockup-url">{initialState.previewUrl}</span>
1990
+ </div>
1991
+ <div class="preview-card">
1992
+ <div class="preview-badge hidden" id="mockup-badge">\u2B50 Featured</div>
1993
+ <div class="preview-image">
1994
+ <div class="preview-image-placeholder">
1995
+ <span>\u{1F3E2}</span>
1301
1996
  </div>
1302
- <h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
1303
- Real-time Database
1304
- </h3>
1305
- <p className="text-gray-600 dark:text-gray-300">
1306
- Powered by Convex for automatic real-time sync and type-safe queries.
1307
- </p>
1308
1997
  </div>
1309
- <div className="p-6 rounded-xl border border-gray-200 dark:border-gray-700">
1310
- <div className="w-12 h-12 bg-gray-100 dark:bg-gray-800 rounded-lg flex items-center justify-center mb-4">
1311
- <svg className="w-6 h-6 text-gray-900 dark:text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1312
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
1313
- </svg>
1998
+ <div class="preview-content">
1999
+ <span class="preview-category-tag" id="mockup-preview-category">{initialState.previewCategory}</span>
2000
+ <h3 class="preview-title" id="mockup-preview-title">{initialState.previewTitle}</h3>
2001
+ <p class="preview-description" id="mockup-preview-description">{initialState.previewDescription}</p>
2002
+ <div class="preview-meta">
2003
+ <span class="meta-rating">\u2605\u2605\u2605\u2605\u2605</span>
2004
+ <span class="meta-reviews">24 reviews</span>
1314
2005
  </div>
1315
- <h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
1316
- Secure Auth
1317
- </h3>
1318
- <p className="text-gray-600 dark:text-gray-300">
1319
- Better-Auth provides secure, flexible authentication with social login support.
1320
- </p>
1321
2006
  </div>
1322
2007
  </div>
1323
2008
  </div>
1324
- </section>
2009
+ </div>
2010
+ </div>
2011
+ </div>
2012
+
2013
+ <!-- State Indicator -->
2014
+ <div class="mockup-indicators">
2015
+ {mockupStates.map((s, i) => (
2016
+ <button
2017
+ type="button"
2018
+ data-state-index={i}
2019
+ class:list={["indicator", i === 0 && "indicator--active"]}
2020
+ >
2021
+ <span class="indicator-dot"></span>
2022
+ <span class="indicator-label">{s.label}</span>
2023
+ </button>
2024
+ ))}
2025
+ </div>
2026
+ </div>
2027
+
2028
+ <script define:vars={{ mockupStates }}>
2029
+ function initMockup() {
2030
+ const mockup = document.getElementById('animated-mockup')
2031
+ if (!mockup) return
2032
+
2033
+ let currentState = 0
2034
+ let isPaused = false
2035
+ let interval
2036
+
2037
+ const elements = {
2038
+ label: document.getElementById('mockup-label'),
2039
+ breadcrumb: document.getElementById('mockup-breadcrumb'),
2040
+ title: document.getElementById('mockup-title'),
2041
+ category: document.getElementById('mockup-category'),
2042
+ description: document.getElementById('mockup-description'),
2043
+ url: document.getElementById('mockup-url'),
2044
+ badge: document.getElementById('mockup-badge'),
2045
+ previewCategory: document.getElementById('mockup-preview-category'),
2046
+ previewTitle: document.getElementById('mockup-preview-title'),
2047
+ previewDescription: document.getElementById('mockup-preview-description'),
2048
+ actionBtn: document.getElementById('mockup-action-btn'),
2049
+ }
1325
2050
 
1326
- {/* CTA Section */}
1327
- <section className="py-24 sm:py-32 bg-gray-900 dark:bg-gray-800">
1328
- <div className="container mx-auto px-4 text-center">
1329
- <h2 className="text-3xl font-bold tracking-tight text-white sm:text-4xl">
1330
- Ready to get started?
1331
- </h2>
1332
- <p className="mt-4 text-lg text-gray-300 max-w-2xl mx-auto">
1333
- Start building your next project with our full-stack template.
1334
- </p>
1335
- <div className="mt-10">
1336
- <a
1337
- href="/app"
1338
- className="rounded-lg bg-white px-6 py-3 text-sm font-semibold text-gray-900 shadow-sm hover:opacity-90 transition-opacity"
1339
- >
1340
- Launch App
1341
- </a>
2051
+ function updateMockup(stateIndex) {
2052
+ const state = mockupStates[stateIndex]
2053
+ if (!state) return
2054
+
2055
+ // Update content
2056
+ if (elements.label) elements.label.textContent = state.label
2057
+ if (elements.breadcrumb) elements.breadcrumb.textContent = state.previewTitle
2058
+ if (elements.title) elements.title.textContent = state.previewTitle
2059
+ if (elements.category) elements.category.textContent = state.previewCategory
2060
+ if (elements.description) elements.description.textContent = state.previewDescription
2061
+ if (elements.url) elements.url.textContent = state.previewUrl || 'saasify.app/live'
2062
+ if (elements.previewCategory) elements.previewCategory.textContent = state.previewCategory
2063
+ if (elements.previewTitle) elements.previewTitle.textContent = state.previewTitle
2064
+ if (elements.previewDescription) elements.previewDescription.textContent = state.previewDescription
2065
+
2066
+ // Update badge
2067
+ if (elements.badge) {
2068
+ if (state.previewStatus === 'featured') {
2069
+ elements.badge.classList.remove('hidden')
2070
+ } else {
2071
+ elements.badge.classList.add('hidden')
2072
+ }
2073
+ }
2074
+
2075
+ // Update action button
2076
+ if (elements.actionBtn) {
2077
+ elements.actionBtn.classList.remove('action-btn--success', 'action-btn--featured')
2078
+ if (state.previewStatus === 'draft') {
2079
+ elements.actionBtn.textContent = 'Save Draft'
2080
+ } else if (state.previewStatus === 'published') {
2081
+ elements.actionBtn.textContent = '\u2713 Published'
2082
+ elements.actionBtn.classList.add('action-btn--success')
2083
+ } else if (state.previewStatus === 'featured') {
2084
+ elements.actionBtn.textContent = '\u2B50 Featured'
2085
+ elements.actionBtn.classList.add('action-btn--featured')
2086
+ }
2087
+ }
2088
+
2089
+ // Update sidebar active state
2090
+ const sidebarItems = mockup.querySelectorAll('.sidebar-item')
2091
+ sidebarItems.forEach(item => {
2092
+ item.classList.remove('sidebar-item--active')
2093
+ if (item.getAttribute('data-nav') === state.sidebarActive) {
2094
+ item.classList.add('sidebar-item--active')
2095
+ }
2096
+ })
2097
+
2098
+ // Update indicators
2099
+ const indicators = mockup.querySelectorAll('.indicator')
2100
+ indicators.forEach((ind, i) => {
2101
+ ind.classList.toggle('indicator--active', i === stateIndex)
2102
+ })
2103
+ }
2104
+
2105
+ function nextState() {
2106
+ if (isPaused) return
2107
+ currentState = (currentState + 1) % mockupStates.length
2108
+ updateMockup(currentState)
2109
+ }
2110
+
2111
+ // Auto-advance
2112
+ interval = setInterval(nextState, 3000)
2113
+
2114
+ // Pause on hover
2115
+ mockup.addEventListener('mouseenter', () => {
2116
+ isPaused = true
2117
+ })
2118
+ mockup.addEventListener('mouseleave', () => {
2119
+ isPaused = false
2120
+ })
2121
+
2122
+ // Manual state selection
2123
+ const indicators = mockup.querySelectorAll('.indicator')
2124
+ indicators.forEach((indicator) => {
2125
+ indicator.addEventListener('click', () => {
2126
+ const index = parseInt(indicator.getAttribute('data-state-index') || '0', 10)
2127
+ currentState = index
2128
+ updateMockup(currentState)
2129
+ })
2130
+ })
2131
+ }
2132
+
2133
+ initMockup()
2134
+ document.addEventListener('astro:after-swap', initMockup)
2135
+ </script>
2136
+
2137
+ <style>
2138
+ .mockup-wrapper {
2139
+ width: 100%;
2140
+ max-width: 900px;
2141
+ margin: 0 auto;
2142
+ background: var(--background);
2143
+ border-radius: 0.75rem;
2144
+ overflow: hidden;
2145
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
2146
+ }
2147
+
2148
+ .mockup-chrome {
2149
+ display: flex;
2150
+ align-items: center;
2151
+ gap: 0.5rem;
2152
+ padding: 0.75rem 1rem;
2153
+ background: var(--muted);
2154
+ border-bottom: 1px solid var(--border);
2155
+ }
2156
+
2157
+ .mockup-chrome-dots {
2158
+ display: flex;
2159
+ gap: 0.375rem;
2160
+ }
2161
+
2162
+ .dot {
2163
+ width: 0.75rem;
2164
+ height: 0.75rem;
2165
+ border-radius: 50%;
2166
+ }
2167
+
2168
+ .dot-red { background: #ff5f56; }
2169
+ .dot-yellow { background: #ffbd2e; }
2170
+ .dot-green { background: #27ca40; }
2171
+
2172
+ .mockup-chrome-title {
2173
+ flex: 1;
2174
+ text-align: center;
2175
+ font-size: 0.75rem;
2176
+ color: var(--muted-foreground);
2177
+ }
2178
+
2179
+ .mockup-chrome-actions {
2180
+ width: 3rem;
2181
+ }
2182
+
2183
+ .mockup-content {
2184
+ display: flex;
2185
+ min-height: 300px;
2186
+ }
2187
+
2188
+ .mockup-sidebar {
2189
+ width: 180px;
2190
+ background: var(--card);
2191
+ border-right: 1px solid var(--border);
2192
+ padding: 1rem 0;
2193
+ display: none;
2194
+ }
2195
+
2196
+ @media (min-width: 768px) {
2197
+ .mockup-sidebar {
2198
+ display: block;
2199
+ }
2200
+ .mockup-content {
2201
+ min-height: 350px;
2202
+ }
2203
+ }
2204
+
2205
+ .sidebar-header {
2206
+ padding: 0 1rem 1rem;
2207
+ border-bottom: 1px solid var(--border);
2208
+ margin-bottom: 0.5rem;
2209
+ }
2210
+
2211
+ .sidebar-logo {
2212
+ display: flex;
2213
+ align-items: center;
2214
+ gap: 0.5rem;
2215
+ }
2216
+
2217
+ .logo-icon {
2218
+ width: 1.5rem;
2219
+ height: 1.5rem;
2220
+ background: var(--primary);
2221
+ color: var(--primary-foreground);
2222
+ border-radius: 0.25rem;
2223
+ display: flex;
2224
+ align-items: center;
2225
+ justify-content: center;
2226
+ font-size: 0.75rem;
2227
+ font-weight: 600;
2228
+ }
2229
+
2230
+ .logo-text {
2231
+ font-size: 0.75rem;
2232
+ font-weight: 600;
2233
+ color: var(--foreground);
2234
+ }
2235
+
2236
+ .sidebar-nav {
2237
+ padding: 0 0.5rem;
2238
+ }
2239
+
2240
+ .sidebar-item {
2241
+ display: flex;
2242
+ align-items: center;
2243
+ gap: 0.5rem;
2244
+ padding: 0.5rem;
2245
+ border-radius: 0.375rem;
2246
+ cursor: pointer;
2247
+ transition: background 0.15s;
2248
+ }
2249
+
2250
+ .sidebar-item:hover {
2251
+ background: var(--muted);
2252
+ }
2253
+
2254
+ .sidebar-item--active {
2255
+ background: var(--primary);
2256
+ color: var(--primary-foreground);
2257
+ }
2258
+
2259
+ .sidebar-icon {
2260
+ font-size: 0.875rem;
2261
+ }
2262
+
2263
+ .sidebar-label {
2264
+ font-size: 0.75rem;
2265
+ flex: 1;
2266
+ }
2267
+
2268
+ .sidebar-badge {
2269
+ font-size: 0.625rem;
2270
+ background: var(--muted);
2271
+ padding: 0.125rem 0.375rem;
2272
+ border-radius: 9999px;
2273
+ }
2274
+
2275
+ .sidebar-item--active .sidebar-badge {
2276
+ background: rgba(255, 255, 255, 0.2);
2277
+ }
2278
+
2279
+ .mockup-main {
2280
+ flex: 1;
2281
+ display: flex;
2282
+ flex-direction: column;
2283
+ min-width: 0;
2284
+ }
2285
+
2286
+ .main-header {
2287
+ display: flex;
2288
+ justify-content: space-between;
2289
+ align-items: center;
2290
+ padding: 0.75rem 1rem;
2291
+ border-bottom: 1px solid var(--border);
2292
+ }
2293
+
2294
+ .header-title h2 {
2295
+ font-size: 0.875rem;
2296
+ font-weight: 600;
2297
+ color: var(--foreground);
2298
+ margin: 0;
2299
+ }
2300
+
2301
+ .header-breadcrumb {
2302
+ font-size: 0.625rem;
2303
+ color: var(--muted-foreground);
2304
+ }
2305
+
2306
+ .action-btn {
2307
+ font-size: 0.625rem;
2308
+ padding: 0.375rem 0.75rem;
2309
+ background: var(--primary);
2310
+ color: var(--primary-foreground);
2311
+ border: none;
2312
+ border-radius: 0.25rem;
2313
+ cursor: pointer;
2314
+ }
2315
+
2316
+ .action-btn--success {
2317
+ background: #22c55e;
2318
+ }
2319
+
2320
+ .action-btn--featured {
2321
+ background: #f59e0b;
2322
+ }
2323
+
2324
+ .main-split {
2325
+ display: flex;
2326
+ flex: 1;
2327
+ min-height: 0;
2328
+ }
2329
+
2330
+ .editor-panel {
2331
+ flex: 1;
2332
+ padding: 1rem;
2333
+ border-right: 1px solid var(--border);
2334
+ display: none;
2335
+ }
2336
+
2337
+ @media (min-width: 640px) {
2338
+ .editor-panel {
2339
+ display: block;
2340
+ }
2341
+ }
2342
+
2343
+ .editor-section {
2344
+ margin-bottom: 0.75rem;
2345
+ }
2346
+
2347
+ .editor-label {
2348
+ display: block;
2349
+ font-size: 0.625rem;
2350
+ color: var(--muted-foreground);
2351
+ margin-bottom: 0.25rem;
2352
+ }
2353
+
2354
+ .editor-input,
2355
+ .editor-select,
2356
+ .editor-textarea {
2357
+ background: var(--muted);
2358
+ border: 1px solid var(--border);
2359
+ border-radius: 0.25rem;
2360
+ padding: 0.5rem;
2361
+ font-size: 0.75rem;
2362
+ color: var(--foreground);
2363
+ }
2364
+
2365
+ .editor-input {
2366
+ display: flex;
2367
+ align-items: center;
2368
+ }
2369
+
2370
+ .input-cursor {
2371
+ width: 1px;
2372
+ height: 1em;
2373
+ background: var(--primary);
2374
+ animation: blink 1s infinite;
2375
+ }
2376
+
2377
+ @keyframes blink {
2378
+ 50% { opacity: 0; }
2379
+ }
2380
+
2381
+ .editor-select {
2382
+ display: flex;
2383
+ justify-content: space-between;
2384
+ align-items: center;
2385
+ }
2386
+
2387
+ .select-arrow {
2388
+ font-size: 0.5rem;
2389
+ color: var(--muted-foreground);
2390
+ }
2391
+
2392
+ .editor-textarea {
2393
+ min-height: 60px;
2394
+ }
2395
+
2396
+ .preview-panel {
2397
+ flex: 1;
2398
+ padding: 1rem;
2399
+ background: var(--muted);
2400
+ }
2401
+
2402
+ .preview-header {
2403
+ display: flex;
2404
+ justify-content: space-between;
2405
+ margin-bottom: 0.75rem;
2406
+ }
2407
+
2408
+ .preview-label {
2409
+ font-size: 0.625rem;
2410
+ font-weight: 500;
2411
+ color: var(--muted-foreground);
2412
+ }
2413
+
2414
+ .preview-url {
2415
+ font-size: 0.625rem;
2416
+ color: var(--primary);
2417
+ }
2418
+
2419
+ .preview-card {
2420
+ background: var(--background);
2421
+ border-radius: 0.5rem;
2422
+ overflow: hidden;
2423
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
2424
+ position: relative;
2425
+ }
2426
+
2427
+ .preview-badge {
2428
+ position: absolute;
2429
+ top: 0.5rem;
2430
+ right: 0.5rem;
2431
+ background: #f59e0b;
2432
+ color: white;
2433
+ font-size: 0.5rem;
2434
+ padding: 0.25rem 0.5rem;
2435
+ border-radius: 9999px;
2436
+ font-weight: 500;
2437
+ }
2438
+
2439
+ .preview-image {
2440
+ aspect-ratio: 16/9;
2441
+ background: var(--muted);
2442
+ }
2443
+
2444
+ .preview-image-placeholder {
2445
+ width: 100%;
2446
+ height: 100%;
2447
+ display: flex;
2448
+ align-items: center;
2449
+ justify-content: center;
2450
+ font-size: 2rem;
2451
+ }
2452
+
2453
+ .preview-content {
2454
+ padding: 0.75rem;
2455
+ }
2456
+
2457
+ .preview-category-tag {
2458
+ display: inline-block;
2459
+ font-size: 0.5rem;
2460
+ color: var(--primary);
2461
+ background: color-mix(in oklch, var(--primary) 10%, transparent);
2462
+ padding: 0.125rem 0.375rem;
2463
+ border-radius: 9999px;
2464
+ margin-bottom: 0.25rem;
2465
+ }
2466
+
2467
+ .preview-title {
2468
+ font-size: 0.75rem;
2469
+ font-weight: 600;
2470
+ color: var(--foreground);
2471
+ margin: 0 0 0.25rem;
2472
+ }
2473
+
2474
+ .preview-description {
2475
+ font-size: 0.625rem;
2476
+ color: var(--muted-foreground);
2477
+ margin: 0 0 0.5rem;
2478
+ line-height: 1.4;
2479
+ }
2480
+
2481
+ .preview-meta {
2482
+ display: flex;
2483
+ gap: 0.5rem;
2484
+ font-size: 0.5rem;
2485
+ color: var(--muted-foreground);
2486
+ }
2487
+
2488
+ .meta-rating {
2489
+ color: #f59e0b;
2490
+ }
2491
+
2492
+ .mockup-indicators {
2493
+ display: flex;
2494
+ justify-content: center;
2495
+ gap: 0.5rem;
2496
+ padding: 0.75rem;
2497
+ background: var(--card);
2498
+ border-top: 1px solid var(--border);
2499
+ }
2500
+
2501
+ .indicator {
2502
+ display: flex;
2503
+ align-items: center;
2504
+ gap: 0.375rem;
2505
+ padding: 0.375rem 0.75rem;
2506
+ background: transparent;
2507
+ border: 1px solid var(--border);
2508
+ border-radius: 9999px;
2509
+ cursor: pointer;
2510
+ transition: all 0.15s;
2511
+ }
2512
+
2513
+ .indicator:hover {
2514
+ border-color: var(--primary);
2515
+ }
2516
+
2517
+ .indicator--active {
2518
+ background: var(--primary);
2519
+ border-color: var(--primary);
2520
+ color: var(--primary-foreground);
2521
+ }
2522
+
2523
+ .indicator-dot {
2524
+ width: 0.375rem;
2525
+ height: 0.375rem;
2526
+ border-radius: 50%;
2527
+ background: currentColor;
2528
+ }
2529
+
2530
+ .indicator-label {
2531
+ font-size: 0.625rem;
2532
+ font-weight: 500;
2533
+ display: none;
2534
+ }
2535
+
2536
+ @media (min-width: 640px) {
2537
+ .indicator-label {
2538
+ display: inline;
2539
+ }
2540
+ }
2541
+ </style>
2542
+ `,
2543
+ "marketing/astro/src/components/heros/ProductShowcaseHero.astro": '---\nimport AnimatedMockup from "./AnimatedMockup.astro"\n\ninterface HeroLink {\n label: string\n href: string\n variant: "default" | "outline"\n}\n\ninterface Props {\n headline?: string\n description?: string\n links?: HeroLink[]\n}\n\nconst {\n headline = "The modern platform for growing teams",\n description = "Streamline workflows, boost productivity, and scale your business with one powerful platform.",\n links = [\n { label: "Start free trial", href: "/sign-up", variant: "default" },\n { label: "Watch demo", href: "/demo", variant: "outline" },\n ],\n} = Astro.props\n---\n\n<div class="relative overflow-hidden">\n <!-- Hero Content - Left Aligned -->\n <div class="container mx-auto px-4 pt-8 pb-16 md:pt-16 md:pb-24">\n <div class="max-w-2xl">\n <h1 class="text-4xl font-bold tracking-tight text-foreground sm:text-5xl md:text-6xl">\n {headline}\n </h1>\n <p class="mt-6 text-lg text-muted-foreground md:text-xl">\n {description}\n </p>\n {links && links.length > 0 && (\n <div class="mt-8 flex flex-wrap gap-4">\n {links.map((link) => (\n <a\n href={link.href}\n class:list={[\n "inline-flex items-center justify-center px-6 py-3 text-sm font-medium rounded-md transition-colors",\n link.variant === "default"\n ? "bg-primary text-primary-foreground hover:bg-primary/90"\n : "border border-border bg-background hover:bg-muted"\n ]}\n >\n {link.label}\n </a>\n ))}\n </div>\n )}\n </div>\n </div>\n\n <!-- Product Mockup Section -->\n <div class="container mx-auto px-4">\n <div class="hero-showcase">\n <!-- Background Image -->\n <div class="hero-bg-image">\n <img\n src="/media/hero-bg.png"\n alt=""\n class="w-full h-full object-cover"\n />\n </div>\n\n <!-- Mockup - centered within background -->\n <div class="hero-mockup-centered">\n <AnimatedMockup />\n </div>\n </div>\n </div>\n</div>\n\n<style>\n .hero-showcase {\n position: relative;\n width: 100%;\n max-width: 1200px;\n margin: 0 auto;\n border-radius: 1rem;\n overflow: hidden;\n background: linear-gradient(135deg, var(--primary) 0%, color-mix(in oklch, var(--primary) 70%, black) 100%);\n min-height: 400px;\n }\n\n .hero-bg-image {\n position: absolute;\n inset: 0;\n opacity: 0.1;\n }\n\n .hero-mockup-centered {\n position: relative;\n z-index: 10;\n padding: 2rem;\n display: flex;\n justify-content: center;\n align-items: center;\n }\n\n @media (min-width: 768px) {\n .hero-showcase {\n min-height: 500px;\n }\n .hero-mockup-centered {\n padding: 3rem;\n }\n }\n</style>\n',
2544
+ "marketing/astro/src/layouts/Layout.astro": `---
2545
+ import "../styles/globals.css"
2546
+
2547
+ interface Props {
2548
+ title?: string
2549
+ description?: string
2550
+ }
2551
+
2552
+ const {
2553
+ title = "SaaSify - The modern platform for growing teams",
2554
+ description = "Transform your workflow with our all-in-one platform. Streamline operations, boost productivity, and scale your business with powerful tools designed for modern teams.",
2555
+ } = Astro.props
2556
+ ---
2557
+
2558
+ <!doctype html>
2559
+ <html lang="en">
2560
+ <head>
2561
+ <meta charset="UTF-8" />
2562
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
2563
+ <meta name="description" content={description} />
2564
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
2565
+ <title>{title}</title>
2566
+ <!-- Prevent flash of wrong theme -->
2567
+ <script is:inline>
2568
+ (function() {
2569
+ const theme = localStorage.getItem('theme') ||
2570
+ (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
2571
+ if (theme === 'dark') {
2572
+ document.documentElement.setAttribute('data-theme', 'dark')
2573
+ }
2574
+ })()
2575
+ </script>
2576
+ </head>
2577
+ <body class="min-h-screen bg-background text-foreground antialiased">
2578
+ <slot />
2579
+ </body>
2580
+ </html>
2581
+ `,
2582
+ "marketing/astro/src/lib/utils.ts": 'import { type ClassValue, clsx } from "clsx"\nimport { twMerge } from "tailwind-merge"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n',
2583
+ "marketing/astro/src/pages/index.astro": `---
2584
+ import Layout from "../layouts/Layout.astro"
2585
+ import Header from "../components/Header.astro"
2586
+ import Footer from "../components/Footer.astro"
2587
+ import ProductShowcaseHero from "../components/heros/ProductShowcaseHero.astro"
2588
+ import LogoBanner from "../components/blocks/LogoBanner.astro"
2589
+ import ProofBanner from "../components/blocks/ProofBanner.astro"
2590
+ import BentoFeatures from "../components/blocks/BentoFeatures.astro"
2591
+ import FeatureShowcase from "../components/blocks/FeatureShowcase.astro"
2592
+ import IndustryTabs from "../components/blocks/IndustryTabs.astro"
2593
+ import TestimonialsGrid from "../components/blocks/TestimonialsGrid.astro"
2594
+ import TrustColumns from "../components/blocks/TrustColumns.astro"
2595
+ import PricingTable from "../components/blocks/PricingTable.astro"
2596
+ import FinalCTA from "../components/blocks/FinalCTA.astro"
2597
+ ---
2598
+
2599
+ <Layout>
2600
+ <div class="min-h-screen flex flex-col">
2601
+ <Header />
2602
+
2603
+ <main class="flex-1">
2604
+ <!-- Hero Section -->
2605
+ <ProductShowcaseHero
2606
+ headline="The modern platform for growing teams"
2607
+ description="Streamline workflows, boost productivity, and scale your business with one powerful platform."
2608
+ links={[
2609
+ { label: "Start free trial", href: "/sign-up", variant: "default" },
2610
+ { label: "Watch demo", href: "/demo", variant: "outline" },
2611
+ ]}
2612
+ />
2613
+
2614
+ <!-- Logo Banner - Social proof -->
2615
+ <LogoBanner
2616
+ heading="Trusted by fast-growing companies everywhere"
2617
+ style="scroll"
2618
+ />
2619
+
2620
+ <!-- Value Proposition -->
2621
+ <ProofBanner
2622
+ headline="Transform how your team works, collaborates, and grows"
2623
+ subtext="Every interaction feeds into a powerful platform that powers personalized experiences, seamless collaboration, and intelligent automation across every touchpoint."
2624
+ links={[
2625
+ { label: "Start free trial", href: "/sign-up", variant: "default" },
2626
+ { label: "Book a demo", href: "/contact", variant: "outline" },
2627
+ ]}
2628
+ />
2629
+
2630
+ <!-- Bento Features -->
2631
+ <BentoFeatures
2632
+ heading="Discover what SaaSify can do"
2633
+ subheading="Everything you need to work smarter and scale faster"
2634
+ />
2635
+
2636
+ <!-- Feature Showcase: Integrations -->
2637
+ <FeatureShowcase
2638
+ label="Seamless Integrations"
2639
+ headline="Connect everything your team uses in one place"
2640
+ description="Integrate with 100+ popular tools including Slack, Salesforce, HubSpot, and more. Two-way sync keeps everything up to date automatically."
2641
+ features={[
2642
+ { text: "100+ native integrations" },
2643
+ { text: "Two-way data sync" },
2644
+ { text: "Custom webhooks" },
2645
+ { text: "API access included" },
2646
+ ]}
2647
+ link={{ label: "Explore integrations", href: "/features/integrations" }}
2648
+ imagePosition="right"
2649
+ />
2650
+
2651
+ <!-- Feature Showcase: Analytics -->
2652
+ <FeatureShowcase
2653
+ label="Actionable Analytics"
2654
+ headline="Make decisions backed by real-time data"
2655
+ description="Track every metric that matters. From team performance to customer insights, get the visibility you need to drive growth."
2656
+ features={[
2657
+ { text: "Real-time dashboards" },
2658
+ { text: "Custom reports" },
2659
+ { text: "Team performance metrics" },
2660
+ { text: "Automated insights" },
2661
+ ]}
2662
+ link={{ label: "Learn about analytics", href: "/features/analytics" }}
2663
+ imagePosition="left"
2664
+ />
2665
+
2666
+ <!-- Feature Showcase: Automation -->
2667
+ <FeatureShowcase
2668
+ label="Workflow Automation"
2669
+ headline="Eliminate busywork with smart automation"
2670
+ description="Build powerful workflows without code. Automate approvals, notifications, data entry, and more to focus on what matters."
2671
+ features={[
2672
+ { text: "Visual workflow builder" },
2673
+ { text: "Conditional logic" },
2674
+ { text: "Scheduled triggers" },
2675
+ { text: "Cross-app automation" },
2676
+ ]}
2677
+ link={{ label: "See automation features", href: "/features/automation" }}
2678
+ imagePosition="right"
2679
+ />
2680
+
2681
+ <!-- Feature Showcase: Collaboration -->
2682
+ <FeatureShowcase
2683
+ label="Team Collaboration"
2684
+ headline="Work together seamlessly, from anywhere"
2685
+ description="Real-time collaboration features keep everyone aligned. Share workspaces, leave comments, and track activity across your entire team."
2686
+ features={[
2687
+ { text: "Real-time collaboration" },
2688
+ { text: "Shared workspaces" },
2689
+ { text: "Comments and mentions" },
2690
+ { text: "Activity tracking" },
2691
+ ]}
2692
+ link={{ label: "Explore collaboration", href: "/features" }}
2693
+ imagePosition="left"
2694
+ />
2695
+
2696
+ <!-- Industry Tabs -->
2697
+ <IndustryTabs
2698
+ heading="Solutions that deliver real results"
2699
+ subheading="Whether you're in sales, marketing, or product, SaaSify adapts to how your team works."
2700
+ />
2701
+
2702
+ <!-- Testimonials -->
2703
+ <TestimonialsGrid
2704
+ heading="Loved by teams at companies of all sizes"
2705
+ subheading="See how leading teams use SaaSify to drive growth and productivity."
2706
+ />
2707
+
2708
+ <!-- Trust Columns -->
2709
+ <TrustColumns />
2710
+
2711
+ <!-- Second Logo Banner - Integrations -->
2712
+ <LogoBanner
2713
+ heading="Integrates with your favorite tools"
2714
+ style="grid"
2715
+ logos={[
2716
+ { name: "Slack", initials: "SL" },
2717
+ { name: "Salesforce", initials: "SF" },
2718
+ { name: "HubSpot", initials: "HS" },
2719
+ { name: "Google Workspace", initials: "GW" },
2720
+ { name: "Zapier", initials: "ZP" },
2721
+ { name: "Jira", initials: "JI" },
2722
+ ]}
2723
+ />
2724
+
2725
+ <!-- Pricing -->
2726
+ <PricingTable
2727
+ heading="Simple, transparent pricing"
2728
+ subheading="Start free, upgrade as your team grows. No hidden fees."
2729
+ />
2730
+
2731
+ <!-- Final CTA -->
2732
+ <FinalCTA
2733
+ headline="Ready to transform how your team works?"
2734
+ subheading="Join thousands of teams who chose the smarter way to work. Start free, upgrade as you grow."
2735
+ style="dark"
2736
+ links={[
2737
+ { label: "Start free trial", href: "/sign-up", variant: "outline" },
2738
+ { label: "Book a demo", href: "/contact", variant: "default" },
2739
+ ]}
2740
+ />
2741
+ </main>
2742
+
2743
+ <Footer />
2744
+ </div>
2745
+ </Layout>
2746
+ `,
2747
+ "marketing/astro/src/styles/globals.css.hbs": '@import "tailwindcss";\n\n@theme inline {\n --color-background: var(--background);\n --color-foreground: var(--foreground);\n --color-card: var(--card);\n --color-card-foreground: var(--card-foreground);\n --color-popover: var(--popover);\n --color-popover-foreground: var(--popover-foreground);\n --color-primary: var(--primary);\n --color-primary-foreground: var(--primary-foreground);\n --color-secondary: var(--secondary);\n --color-secondary-foreground: var(--secondary-foreground);\n --color-muted: var(--muted);\n --color-muted-foreground: var(--muted-foreground);\n --color-accent: var(--accent);\n --color-accent-foreground: var(--accent-foreground);\n --color-destructive: var(--destructive);\n --color-border: var(--border);\n --color-input: var(--input);\n --color-ring: var(--ring);\n --color-chart-1: var(--chart-1);\n --color-chart-2: var(--chart-2);\n --color-chart-3: var(--chart-3);\n --color-chart-4: var(--chart-4);\n --color-chart-5: var(--chart-5);\n --radius-sm: calc(var(--radius) - 4px);\n --radius-md: calc(var(--radius) - 2px);\n --radius-lg: var(--radius);\n --radius-xl: calc(var(--radius) + 4px);\n --font-sans: system-ui, sans-serif;\n --font-mono: monospace;\n}\n\n:root {\n --radius: 0.625rem;\n --background: oklch(1 0 0);\n --foreground: oklch(0.145 0 0);\n --card: oklch(1 0 0);\n --card-foreground: oklch(0.145 0 0);\n --popover: oklch(1 0 0);\n --popover-foreground: oklch(0.145 0 0);\n --secondary: oklch(0.97 0 0);\n --secondary-foreground: oklch(0.205 0 0);\n --muted: oklch(0.97 0 0);\n --muted-foreground: oklch(0.556 0 0);\n --accent: oklch(0.97 0 0);\n --accent-foreground: oklch(0.205 0 0);\n --destructive: oklch(0.577 0.245 27.325);\n --border: oklch(0.922 0 0);\n --input: oklch(0.922 0 0);\n\n{{#if (eq shadcn.themeColor "neutral")}}\n --primary: oklch(0.205 0 0);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.708 0 0);\n --chart-1: oklch(0.646 0.222 41.116);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "blue")}}\n --primary: oklch(0.546 0.245 262.881);\n --primary-foreground: oklch(0.985 0.002 247.858);\n --ring: oklch(0.546 0.245 262.881);\n --chart-1: oklch(0.546 0.245 262.881);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "green")}}\n --primary: oklch(0.596 0.145 163.225);\n --primary-foreground: oklch(0.982 0.018 155.826);\n --ring: oklch(0.596 0.145 163.225);\n --chart-1: oklch(0.596 0.145 163.225);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "purple")}}\n --primary: oklch(0.627 0.265 303.9);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.627 0.265 303.9);\n --chart-1: oklch(0.627 0.265 303.9);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "red")}}\n --primary: oklch(0.637 0.237 25.331);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.637 0.237 25.331);\n --chart-1: oklch(0.637 0.237 25.331);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "orange")}}\n --primary: oklch(0.705 0.191 47.604);\n --primary-foreground: oklch(0.216 0.006 56.043);\n --ring: oklch(0.705 0.191 47.604);\n --chart-1: oklch(0.705 0.191 47.604);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "amber")}}\n --primary: oklch(0.769 0.188 70.08);\n --primary-foreground: oklch(0.216 0.006 56.043);\n --ring: oklch(0.769 0.188 70.08);\n --chart-1: oklch(0.769 0.188 70.08);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.646 0.222 41.116);\n{{else if (eq shadcn.themeColor "cyan")}}\n --primary: oklch(0.715 0.143 215.221);\n --primary-foreground: oklch(0.216 0.006 56.043);\n --ring: oklch(0.715 0.143 215.221);\n --chart-1: oklch(0.715 0.143 215.221);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "emerald")}}\n --primary: oklch(0.696 0.17 162.48);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.696 0.17 162.48);\n --chart-1: oklch(0.696 0.17 162.48);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "fuchsia")}}\n --primary: oklch(0.667 0.295 322.15);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.667 0.295 322.15);\n --chart-1: oklch(0.667 0.295 322.15);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "indigo")}}\n --primary: oklch(0.585 0.233 277.117);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.585 0.233 277.117);\n --chart-1: oklch(0.585 0.233 277.117);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "lime")}}\n --primary: oklch(0.768 0.233 130.85);\n --primary-foreground: oklch(0.216 0.006 56.043);\n --ring: oklch(0.768 0.233 130.85);\n --chart-1: oklch(0.768 0.233 130.85);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "pink")}}\n --primary: oklch(0.718 0.202 349.761);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.718 0.202 349.761);\n --chart-1: oklch(0.718 0.202 349.761);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "rose")}}\n --primary: oklch(0.645 0.246 16.439);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.645 0.246 16.439);\n --chart-1: oklch(0.645 0.246 16.439);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "sky")}}\n --primary: oklch(0.685 0.169 237.323);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.685 0.169 237.323);\n --chart-1: oklch(0.685 0.169 237.323);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "teal")}}\n --primary: oklch(0.704 0.14 182.503);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.704 0.14 182.503);\n --chart-1: oklch(0.704 0.14 182.503);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "violet")}}\n --primary: oklch(0.606 0.25 292.717);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.606 0.25 292.717);\n --chart-1: oklch(0.606 0.25 292.717);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "yellow")}}\n --primary: oklch(0.795 0.184 86.047);\n --primary-foreground: oklch(0.216 0.006 56.043);\n --ring: oklch(0.795 0.184 86.047);\n --chart-1: oklch(0.795 0.184 86.047);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.646 0.222 41.116);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else}}\n --primary: oklch(0.205 0 0);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.708 0 0);\n --chart-1: oklch(0.646 0.222 41.116);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{/if}}\n}\n\n.dark {\n --background: oklch(0.145 0 0);\n --foreground: oklch(0.985 0 0);\n --card: oklch(0.205 0 0);\n --card-foreground: oklch(0.985 0 0);\n --popover: oklch(0.269 0 0);\n --popover-foreground: oklch(0.985 0 0);\n --secondary: oklch(0.269 0 0);\n --secondary-foreground: oklch(0.985 0 0);\n --muted: oklch(0.269 0 0);\n --muted-foreground: oklch(0.708 0 0);\n --accent: oklch(0.371 0 0);\n --accent-foreground: oklch(0.985 0 0);\n --destructive: oklch(0.704 0.191 22.216);\n --border: oklch(1 0 0 / 10%);\n --input: oklch(1 0 0 / 15%);\n\n{{#if (eq shadcn.themeColor "neutral")}}\n --primary: oklch(0.922 0 0);\n --primary-foreground: oklch(0.205 0 0);\n --ring: oklch(0.556 0 0);\n{{else if (eq shadcn.themeColor "blue")}}\n --primary: oklch(0.623 0.214 262.881);\n --primary-foreground: oklch(0.273 0.033 256.848);\n --ring: oklch(0.623 0.214 262.881);\n{{else if (eq shadcn.themeColor "green")}}\n --primary: oklch(0.696 0.17 162.48);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.696 0.17 162.48);\n{{else if (eq shadcn.themeColor "purple")}}\n --primary: oklch(0.714 0.203 305.504);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.714 0.203 305.504);\n{{else if (eq shadcn.themeColor "red")}}\n --primary: oklch(0.704 0.191 22.216);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.704 0.191 22.216);\n{{else if (eq shadcn.themeColor "orange")}}\n --primary: oklch(0.792 0.17 52.615);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.792 0.17 52.615);\n{{else if (eq shadcn.themeColor "amber")}}\n --primary: oklch(0.828 0.189 84.429);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.828 0.189 84.429);\n{{else if (eq shadcn.themeColor "cyan")}}\n --primary: oklch(0.789 0.154 211.53);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.789 0.154 211.53);\n{{else if (eq shadcn.themeColor "emerald")}}\n --primary: oklch(0.765 0.166 160.391);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.765 0.166 160.391);\n{{else if (eq shadcn.themeColor "fuchsia")}}\n --primary: oklch(0.74 0.238 322.16);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.74 0.238 322.16);\n{{else if (eq shadcn.themeColor "indigo")}}\n --primary: oklch(0.673 0.182 276.935);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.673 0.182 276.935);\n{{else if (eq shadcn.themeColor "lime")}}\n --primary: oklch(0.841 0.238 128.85);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.841 0.238 128.85);\n{{else if (eq shadcn.themeColor "pink")}}\n --primary: oklch(0.775 0.181 349.761);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.775 0.181 349.761);\n{{else if (eq shadcn.themeColor "rose")}}\n --primary: oklch(0.712 0.194 13.428);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.712 0.194 13.428);\n{{else if (eq shadcn.themeColor "sky")}}\n --primary: oklch(0.756 0.143 232.661);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.756 0.143 232.661);\n{{else if (eq shadcn.themeColor "teal")}}\n --primary: oklch(0.777 0.152 181.912);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.777 0.152 181.912);\n{{else if (eq shadcn.themeColor "violet")}}\n --primary: oklch(0.702 0.183 293.541);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.702 0.183 293.541);\n{{else if (eq shadcn.themeColor "yellow")}}\n --primary: oklch(0.852 0.199 91.936);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.852 0.199 91.936);\n{{else}}\n --primary: oklch(0.922 0 0);\n --primary-foreground: oklch(0.205 0 0);\n --ring: oklch(0.556 0 0);\n{{/if}}\n}\n\n@layer base {\n * {\n @apply border-border outline-ring/50;\n }\n body {\n @apply bg-background text-foreground;\n }\n}\n\n.container {\n width: 100%;\n margin-left: auto;\n margin-right: auto;\n padding-left: 1rem;\n padding-right: 1rem;\n max-width: 96rem;\n}\n\n@media (min-width: 640px) {\n .container {\n padding-left: 1.5rem;\n padding-right: 1.5rem;\n }\n}\n\n@media (min-width: 1024px) {\n .container {\n padding-left: 2rem;\n padding-right: 2rem;\n }\n}\n',
2748
+ "marketing/astro/tsconfig.json.hbs": '{\n "extends": "astro/tsconfigs/strict",\n "compilerOptions": {\n "baseUrl": ".",\n "paths": {\n "@/*": ["./src/*"]\n }\n },\n "include": ["src/**/*", ".astro/types.d.ts"],\n "exclude": ["node_modules", "dist"]\n}\n',
2749
+ "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",
2750
+ "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 "lucide-react": "^0.468.0",\n "next-themes": "^0.4.4",\n "clsx": "^2.1.1",\n "tailwind-merge": "^2.6.0",\n "class-variance-authority": "^0.7.1"\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',
2751
+ "marketing/nextjs/postcss.config.mjs.hbs": "export default {\n plugins: {\n '@tailwindcss/postcss': {},\n },\n}\n",
2752
+ "marketing/nextjs/src/app/globals.css.hbs": '@import "tailwindcss";\n@import "tw-animate-css";\n\n@custom-variant dark (&:is(.dark *));\n\n@theme inline {\n /* Colors */\n --color-background: var(--background);\n --color-foreground: var(--foreground);\n\n --color-card: var(--card);\n --color-card-foreground: var(--card-foreground);\n\n --color-popover: var(--popover);\n --color-popover-foreground: var(--popover-foreground);\n\n --color-primary: var(--primary);\n --color-primary-foreground: var(--primary-foreground);\n\n --color-secondary: var(--secondary);\n --color-secondary-foreground: var(--secondary-foreground);\n\n --color-muted: var(--muted);\n --color-muted-foreground: var(--muted-foreground);\n\n --color-accent: var(--accent);\n --color-accent-foreground: var(--accent-foreground);\n\n --color-destructive: var(--destructive);\n\n --color-border: var(--border);\n --color-input: var(--input);\n --color-ring: var(--ring);\n\n --color-chart-1: var(--chart-1);\n --color-chart-2: var(--chart-2);\n --color-chart-3: var(--chart-3);\n --color-chart-4: var(--chart-4);\n --color-chart-5: var(--chart-5);\n\n /* Border radius */\n --radius-sm: calc(var(--radius) - 4px);\n --radius-md: calc(var(--radius) - 2px);\n --radius-lg: var(--radius);\n --radius-xl: calc(var(--radius) + 4px);\n\n /* Fonts */\n --font-sans: var(--font-geist-sans), system-ui, sans-serif;\n --font-mono: var(--font-geist-mono), monospace;\n\n /* Container */\n --container-sm: 40rem;\n --container-md: 48rem;\n --container-lg: 64rem;\n --container-xl: 80rem;\n --container-2xl: 96rem;\n\n /* Animations */\n --animate-accordion-down: accordion-down 0.2s ease-out;\n --animate-accordion-up: accordion-up 0.2s ease-out;\n}\n\n@keyframes accordion-down {\n from {\n height: 0;\n }\n to {\n height: var(--radix-accordion-content-height);\n }\n}\n\n@keyframes accordion-up {\n from {\n height: var(--radix-accordion-content-height);\n }\n to {\n height: 0;\n }\n}\n\n/* ========================================\n THEME COLOR VARIABLES\n ======================================== */\n\n:root {\n --radius: 0.625rem;\n --background: oklch(1 0 0);\n --foreground: oklch(0.145 0 0);\n --card: oklch(1 0 0);\n --card-foreground: oklch(0.145 0 0);\n --popover: oklch(1 0 0);\n --popover-foreground: oklch(0.145 0 0);\n --secondary: oklch(0.97 0 0);\n --secondary-foreground: oklch(0.205 0 0);\n --muted: oklch(0.97 0 0);\n --muted-foreground: oklch(0.556 0 0);\n --accent: oklch(0.97 0 0);\n --accent-foreground: oklch(0.205 0 0);\n --destructive: oklch(0.577 0.245 27.325);\n --border: oklch(0.922 0 0);\n --input: oklch(0.922 0 0);\n\n{{#if (eq shadcn.themeColor "neutral")}}\n --primary: oklch(0.205 0 0);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.708 0 0);\n --chart-1: oklch(0.646 0.222 41.116);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "blue")}}\n --primary: oklch(0.546 0.245 262.881);\n --primary-foreground: oklch(0.985 0.002 247.858);\n --ring: oklch(0.546 0.245 262.881);\n --chart-1: oklch(0.546 0.245 262.881);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "green")}}\n --primary: oklch(0.596 0.145 163.225);\n --primary-foreground: oklch(0.982 0.018 155.826);\n --ring: oklch(0.596 0.145 163.225);\n --chart-1: oklch(0.596 0.145 163.225);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "purple")}}\n --primary: oklch(0.627 0.265 303.9);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.627 0.265 303.9);\n --chart-1: oklch(0.627 0.265 303.9);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "red")}}\n --primary: oklch(0.637 0.237 25.331);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.637 0.237 25.331);\n --chart-1: oklch(0.637 0.237 25.331);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "orange")}}\n --primary: oklch(0.705 0.191 47.604);\n --primary-foreground: oklch(0.216 0.006 56.043);\n --ring: oklch(0.705 0.191 47.604);\n --chart-1: oklch(0.705 0.191 47.604);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "amber")}}\n --primary: oklch(0.769 0.188 70.08);\n --primary-foreground: oklch(0.216 0.006 56.043);\n --ring: oklch(0.769 0.188 70.08);\n --chart-1: oklch(0.769 0.188 70.08);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.646 0.222 41.116);\n{{else if (eq shadcn.themeColor "cyan")}}\n --primary: oklch(0.715 0.143 215.221);\n --primary-foreground: oklch(0.216 0.006 56.043);\n --ring: oklch(0.715 0.143 215.221);\n --chart-1: oklch(0.715 0.143 215.221);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "emerald")}}\n --primary: oklch(0.696 0.17 162.48);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.696 0.17 162.48);\n --chart-1: oklch(0.696 0.17 162.48);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "fuchsia")}}\n --primary: oklch(0.667 0.295 322.15);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.667 0.295 322.15);\n --chart-1: oklch(0.667 0.295 322.15);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "indigo")}}\n --primary: oklch(0.585 0.233 277.117);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.585 0.233 277.117);\n --chart-1: oklch(0.585 0.233 277.117);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "lime")}}\n --primary: oklch(0.768 0.233 130.85);\n --primary-foreground: oklch(0.216 0.006 56.043);\n --ring: oklch(0.768 0.233 130.85);\n --chart-1: oklch(0.768 0.233 130.85);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "pink")}}\n --primary: oklch(0.718 0.202 349.761);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.718 0.202 349.761);\n --chart-1: oklch(0.718 0.202 349.761);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "rose")}}\n --primary: oklch(0.645 0.246 16.439);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.645 0.246 16.439);\n --chart-1: oklch(0.645 0.246 16.439);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "sky")}}\n --primary: oklch(0.685 0.169 237.323);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.685 0.169 237.323);\n --chart-1: oklch(0.685 0.169 237.323);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "teal")}}\n --primary: oklch(0.704 0.14 182.503);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.704 0.14 182.503);\n --chart-1: oklch(0.704 0.14 182.503);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "violet")}}\n --primary: oklch(0.606 0.25 292.717);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.606 0.25 292.717);\n --chart-1: oklch(0.606 0.25 292.717);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else if (eq shadcn.themeColor "yellow")}}\n --primary: oklch(0.795 0.184 86.047);\n --primary-foreground: oklch(0.216 0.006 56.043);\n --ring: oklch(0.795 0.184 86.047);\n --chart-1: oklch(0.795 0.184 86.047);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.646 0.222 41.116);\n --chart-5: oklch(0.769 0.188 70.08);\n{{else}}\n --primary: oklch(0.205 0 0);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.708 0 0);\n --chart-1: oklch(0.646 0.222 41.116);\n --chart-2: oklch(0.6 0.118 184.704);\n --chart-3: oklch(0.398 0.07 227.392);\n --chart-4: oklch(0.828 0.189 84.429);\n --chart-5: oklch(0.769 0.188 70.08);\n{{/if}}\n}\n\n.dark {\n --background: oklch(0.145 0 0);\n --foreground: oklch(0.985 0 0);\n --card: oklch(0.205 0 0);\n --card-foreground: oklch(0.985 0 0);\n --popover: oklch(0.269 0 0);\n --popover-foreground: oklch(0.985 0 0);\n --secondary: oklch(0.269 0 0);\n --secondary-foreground: oklch(0.985 0 0);\n --muted: oklch(0.269 0 0);\n --muted-foreground: oklch(0.708 0 0);\n --accent: oklch(0.371 0 0);\n --accent-foreground: oklch(0.985 0 0);\n --destructive: oklch(0.704 0.191 22.216);\n --border: oklch(1 0 0 / 10%);\n --input: oklch(1 0 0 / 15%);\n\n{{#if (eq shadcn.themeColor "neutral")}}\n --primary: oklch(0.922 0 0);\n --primary-foreground: oklch(0.205 0 0);\n --ring: oklch(0.556 0 0);\n --chart-1: oklch(0.488 0.243 264.376);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "blue")}}\n --primary: oklch(0.623 0.214 262.881);\n --primary-foreground: oklch(0.273 0.033 256.848);\n --ring: oklch(0.623 0.214 262.881);\n --chart-1: oklch(0.623 0.214 262.881);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "green")}}\n --primary: oklch(0.696 0.17 162.48);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.696 0.17 162.48);\n --chart-1: oklch(0.696 0.17 162.48);\n --chart-2: oklch(0.488 0.243 264.376);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "purple")}}\n --primary: oklch(0.714 0.203 305.504);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.714 0.203 305.504);\n --chart-1: oklch(0.714 0.203 305.504);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.488 0.243 264.376);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "red")}}\n --primary: oklch(0.704 0.191 22.216);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.704 0.191 22.216);\n --chart-1: oklch(0.704 0.191 22.216);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.488 0.243 264.376);\n{{else if (eq shadcn.themeColor "orange")}}\n --primary: oklch(0.792 0.17 52.615);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.792 0.17 52.615);\n --chart-1: oklch(0.792 0.17 52.615);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "amber")}}\n --primary: oklch(0.828 0.189 84.429);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.828 0.189 84.429);\n --chart-1: oklch(0.828 0.189 84.429);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.488 0.243 264.376);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "cyan")}}\n --primary: oklch(0.789 0.154 211.53);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.789 0.154 211.53);\n --chart-1: oklch(0.789 0.154 211.53);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "emerald")}}\n --primary: oklch(0.765 0.166 160.391);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.765 0.166 160.391);\n --chart-1: oklch(0.765 0.166 160.391);\n --chart-2: oklch(0.488 0.243 264.376);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "fuchsia")}}\n --primary: oklch(0.74 0.238 322.16);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.74 0.238 322.16);\n --chart-1: oklch(0.74 0.238 322.16);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.488 0.243 264.376);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "indigo")}}\n --primary: oklch(0.673 0.182 276.935);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.673 0.182 276.935);\n --chart-1: oklch(0.673 0.182 276.935);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "lime")}}\n --primary: oklch(0.841 0.238 128.85);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.841 0.238 128.85);\n --chart-1: oklch(0.841 0.238 128.85);\n --chart-2: oklch(0.488 0.243 264.376);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "pink")}}\n --primary: oklch(0.775 0.181 349.761);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.775 0.181 349.761);\n --chart-1: oklch(0.775 0.181 349.761);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.488 0.243 264.376);\n{{else if (eq shadcn.themeColor "rose")}}\n --primary: oklch(0.712 0.194 13.428);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.712 0.194 13.428);\n --chart-1: oklch(0.712 0.194 13.428);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.488 0.243 264.376);\n{{else if (eq shadcn.themeColor "sky")}}\n --primary: oklch(0.756 0.143 232.661);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.756 0.143 232.661);\n --chart-1: oklch(0.756 0.143 232.661);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "teal")}}\n --primary: oklch(0.777 0.152 181.912);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.777 0.152 181.912);\n --chart-1: oklch(0.777 0.152 181.912);\n --chart-2: oklch(0.488 0.243 264.376);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "violet")}}\n --primary: oklch(0.702 0.183 293.541);\n --primary-foreground: oklch(0.985 0 0);\n --ring: oklch(0.702 0.183 293.541);\n --chart-1: oklch(0.702 0.183 293.541);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.488 0.243 264.376);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else if (eq shadcn.themeColor "yellow")}}\n --primary: oklch(0.852 0.199 91.936);\n --primary-foreground: oklch(0.15 0 0);\n --ring: oklch(0.852 0.199 91.936);\n --chart-1: oklch(0.852 0.199 91.936);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.488 0.243 264.376);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{else}}\n --primary: oklch(0.922 0 0);\n --primary-foreground: oklch(0.205 0 0);\n --ring: oklch(0.556 0 0);\n --chart-1: oklch(0.488 0.243 264.376);\n --chart-2: oklch(0.696 0.17 162.48);\n --chart-3: oklch(0.769 0.188 70.08);\n --chart-4: oklch(0.627 0.265 303.9);\n --chart-5: oklch(0.645 0.246 16.439);\n{{/if}}\n}\n\n/* ========================================\n BASE STYLES\n ======================================== */\n\n@layer base {\n * {\n @apply border-border outline-ring/50;\n }\n body {\n @apply bg-background text-foreground;\n }\n}\n\n/* Container utility */\n.container {\n width: 100%;\n margin-left: auto;\n margin-right: auto;\n padding-left: 1rem;\n padding-right: 1rem;\n max-width: 96rem;\n}\n\n@media (min-width: 640px) {\n .container {\n padding-left: 1.5rem;\n padding-right: 1.5rem;\n }\n}\n\n@media (min-width: 1024px) {\n .container {\n padding-left: 2rem;\n padding-right: 2rem;\n }\n}\n',
2753
+ "marketing/nextjs/src/app/layout.tsx.hbs": `import type { Metadata } from 'next'
2754
+ import { Geist, Geist_Mono } from 'next/font/google'
2755
+ import { ThemeProvider } from '@/components/ThemeProvider'
2756
+ import './globals.css'
2757
+
2758
+ const geistSans = Geist({
2759
+ variable: '--font-geist-sans',
2760
+ subsets: ['latin'],
2761
+ })
2762
+
2763
+ const geistMono = Geist_Mono({
2764
+ variable: '--font-geist-mono',
2765
+ subsets: ['latin'],
2766
+ })
2767
+
2768
+ export const metadata: Metadata = {
2769
+ title: 'SaaSify - The modern platform for growing teams',
2770
+ description: 'Transform your workflow with our all-in-one platform. Streamline operations, boost productivity, and scale your business with powerful tools designed for modern teams.',
2771
+ keywords: ['SaaS', 'productivity', 'workflow', 'automation', 'team collaboration'],
2772
+ openGraph: {
2773
+ title: 'SaaSify - The modern platform for growing teams',
2774
+ description: 'Transform your workflow with our all-in-one platform.',
2775
+ type: 'website',
2776
+ },
2777
+ }
2778
+
2779
+ export default function RootLayout({
2780
+ children,
2781
+ }: {
2782
+ children: React.ReactNode
2783
+ }) {
2784
+ return (
2785
+ <html lang="en" suppressHydrationWarning>
2786
+ <body className={\`\${geistSans.variable} \${geistMono.variable} font-sans antialiased\`}>
2787
+ <ThemeProvider
2788
+ attribute="class"
2789
+ defaultTheme="system"
2790
+ enableSystem
2791
+ disableTransitionOnChange
2792
+ >
2793
+ {children}
2794
+ </ThemeProvider>
2795
+ </body>
2796
+ </html>
2797
+ )
2798
+ }
2799
+ `,
2800
+ "marketing/nextjs/src/app/page.tsx.hbs": `import { Header } from "@/components/Header"
2801
+ import { Footer } from "@/components/Footer"
2802
+ import { ProductShowcaseHero } from "@/components/heros"
2803
+ import {
2804
+ LogoBanner,
2805
+ ProofBanner,
2806
+ BentoFeatures,
2807
+ FeatureShowcase,
2808
+ IndustryTabs,
2809
+ TestimonialsGrid,
2810
+ TrustColumns,
2811
+ PricingTable,
2812
+ FinalCTA,
2813
+ } from "@/components/blocks"
2814
+
2815
+ export default function HomePage() {
2816
+ return (
2817
+ <div className="min-h-screen flex flex-col">
2818
+ <Header />
2819
+
2820
+ <main className="flex-1">
2821
+ {/* Hero Section */}
2822
+ <ProductShowcaseHero
2823
+ headline="The modern platform for growing teams"
2824
+ description="Streamline workflows, boost productivity, and scale your business with one powerful platform."
2825
+ links={[
2826
+ { label: "Start free trial", href: "/sign-up", variant: "default" },
2827
+ { label: "Watch demo", href: "/demo", variant: "outline" },
2828
+ ]}
2829
+ />
2830
+
2831
+ {/* Logo Banner - Social proof */}
2832
+ <LogoBanner
2833
+ heading="Trusted by fast-growing companies everywhere"
2834
+ style="scroll"
2835
+ />
2836
+
2837
+ {/* Value Proposition */}
2838
+ <ProofBanner
2839
+ headline="Transform how your team works, collaborates, and grows"
2840
+ subtext="Every interaction feeds into a powerful platform that powers personalized experiences, seamless collaboration, and intelligent automation across every touchpoint."
2841
+ links={[
2842
+ { label: "Start free trial", href: "/sign-up", variant: "default" },
2843
+ { label: "Book a demo", href: "/contact", variant: "outline" },
2844
+ ]}
2845
+ />
2846
+
2847
+ {/* Bento Features */}
2848
+ <BentoFeatures
2849
+ heading="Discover what SaaSify can do"
2850
+ subheading="Everything you need to work smarter and scale faster"
2851
+ />
2852
+
2853
+ {/* Feature Showcase: Integrations */}
2854
+ <FeatureShowcase
2855
+ label="Seamless Integrations"
2856
+ headline="Connect everything your team uses in one place"
2857
+ description="Integrate with 100+ popular tools including Slack, Salesforce, HubSpot, and more. Two-way sync keeps everything up to date automatically."
2858
+ features={[
2859
+ { text: "100+ native integrations" },
2860
+ { text: "Two-way data sync" },
2861
+ { text: "Custom webhooks" },
2862
+ { text: "API access included" },
2863
+ ]}
2864
+ link={{ label: "Explore integrations", href: "/features/integrations" }}
2865
+ imagePosition="right"
2866
+ />
2867
+
2868
+ {/* Feature Showcase: Analytics */}
2869
+ <FeatureShowcase
2870
+ label="Actionable Analytics"
2871
+ headline="Make decisions backed by real-time data"
2872
+ description="Track every metric that matters. From team performance to customer insights, get the visibility you need to drive growth."
2873
+ features={[
2874
+ { text: "Real-time dashboards" },
2875
+ { text: "Custom reports" },
2876
+ { text: "Team performance metrics" },
2877
+ { text: "Automated insights" },
2878
+ ]}
2879
+ link={{ label: "Learn about analytics", href: "/features/analytics" }}
2880
+ imagePosition="left"
2881
+ />
2882
+
2883
+ {/* Feature Showcase: Automation */}
2884
+ <FeatureShowcase
2885
+ label="Workflow Automation"
2886
+ headline="Eliminate busywork with smart automation"
2887
+ description="Build powerful workflows without code. Automate approvals, notifications, data entry, and more to focus on what matters."
2888
+ features={[
2889
+ { text: "Visual workflow builder" },
2890
+ { text: "Conditional logic" },
2891
+ { text: "Scheduled triggers" },
2892
+ { text: "Cross-app automation" },
2893
+ ]}
2894
+ link={{ label: "See automation features", href: "/features/automation" }}
2895
+ imagePosition="right"
2896
+ />
2897
+
2898
+ {/* Feature Showcase: Collaboration */}
2899
+ <FeatureShowcase
2900
+ label="Team Collaboration"
2901
+ headline="Work together seamlessly, from anywhere"
2902
+ description="Real-time collaboration features keep everyone aligned. Share workspaces, leave comments, and track activity across your entire team."
2903
+ features={[
2904
+ { text: "Real-time collaboration" },
2905
+ { text: "Shared workspaces" },
2906
+ { text: "Comments and mentions" },
2907
+ { text: "Activity tracking" },
2908
+ ]}
2909
+ link={{ label: "Explore collaboration", href: "/features" }}
2910
+ imagePosition="left"
2911
+ />
2912
+
2913
+ {/* Industry Tabs */}
2914
+ <IndustryTabs
2915
+ heading="Solutions that deliver real results"
2916
+ subheading="Whether you're in sales, marketing, or product, SaaSify adapts to how your team works."
2917
+ />
2918
+
2919
+ {/* Testimonials */}
2920
+ <TestimonialsGrid
2921
+ heading="Loved by teams at companies of all sizes"
2922
+ subheading="See how leading teams use SaaSify to drive growth and productivity."
2923
+ />
2924
+
2925
+ {/* Trust Columns */}
2926
+ <TrustColumns />
2927
+
2928
+ {/* Second Logo Banner - Integrations */}
2929
+ <LogoBanner
2930
+ heading="Integrates with your favorite tools"
2931
+ style="grid"
2932
+ logos={[
2933
+ { name: "Slack", initials: "SL" },
2934
+ { name: "Salesforce", initials: "SF" },
2935
+ { name: "HubSpot", initials: "HS" },
2936
+ { name: "Google Workspace", initials: "GW" },
2937
+ { name: "Zapier", initials: "ZP" },
2938
+ { name: "Jira", initials: "JI" },
2939
+ ]}
2940
+ />
2941
+
2942
+ {/* Pricing */}
2943
+ <PricingTable
2944
+ heading="Simple, transparent pricing"
2945
+ subheading="Start free, upgrade as your team grows. No hidden fees."
2946
+ />
2947
+
2948
+ {/* Final CTA */}
2949
+ <FinalCTA
2950
+ headline="Ready to transform how your team works?"
2951
+ subheading="Join thousands of teams who chose the smarter way to work. Start free, upgrade as you grow."
2952
+ style="dark"
2953
+ links={[
2954
+ { label: "Start free trial", href: "/sign-up", variant: "outline" },
2955
+ { label: "Book a demo", href: "/contact", variant: "default" },
2956
+ ]}
2957
+ />
2958
+ </main>
2959
+
2960
+ <Footer />
2961
+ </div>
2962
+ )
2963
+ }
2964
+ `,
2965
+ "marketing/nextjs/src/components/Footer/index.tsx": '"use client"\n\nimport Link from "next/link"\nimport { Logo } from "@/components/Logo"\nimport { ThemeSelector } from "@/components/ThemeSelector"\nimport { cn } from "@/lib/utils"\n\n// Footer navigation structure matching SaaSify\nconst footerColumns = [\n {\n title: "Product",\n links: [\n { label: "Home", href: "/" },\n { label: "Pricing", href: "/pricing" },\n { label: "Integrations", href: "/features/integrations" },\n ],\n },\n {\n title: "Resources",\n links: [\n { label: "Blog", href: "/blog" },\n { label: "Documentation", href: "/docs" },\n ],\n },\n {\n title: "Company",\n links: [\n { label: "About", href: "/about" },\n ],\n },\n {\n title: "Legal",\n links: [\n { label: "Privacy", href: "/privacy" },\n { label: "Terms", href: "/terms" },\n ],\n },\n]\n\nconst socialLinks = {\n twitter: "https://x.com/saasify",\n linkedin: "https://linkedin.com/company/saasify",\n github: "https://github.com/saasify",\n}\n\nconst bottomLinks = [\n { label: "Contact Support", href: "/support" },\n]\n\n// Social icons as inline SVGs\nconst SocialIcons = {\n twitter: (\n <svg className="h-5 w-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">\n <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />\n </svg>\n ),\n linkedin: (\n <svg className="h-5 w-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">\n <path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />\n </svg>\n ),\n github: (\n <svg className="h-5 w-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">\n <path\n fillRule="evenodd"\n d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"\n clipRule="evenodd"\n />\n </svg>\n ),\n}\n\nexport function Footer() {\n const currentYear = new Date().getFullYear()\n\n return (\n <footer className="mt-auto border-t border-border bg-background">\n {/* Main Footer Content */}\n <div className="container mx-auto px-4 py-12 lg:py-16">\n <div className="grid grid-cols-2 gap-8 md:grid-cols-3 lg:grid-cols-6">\n {/* Link Columns */}\n {footerColumns.map((column) => (\n <div key={column.title} className="col-span-1">\n <h3 className="mb-4 text-sm font-medium text-foreground">\n {column.title}\n </h3>\n <ul className="space-y-3">\n {column.links.map((link) => (\n <li key={link.href}>\n <Link\n href={link.href}\n className="text-sm text-muted-foreground transition-colors hover:text-foreground"\n >\n {link.label}\n </Link>\n </li>\n ))}\n </ul>\n </div>\n ))}\n\n {/* Newsletter Column */}\n <div className="col-span-2 md:col-span-3 lg:col-span-2">\n <h3 className="mb-4 text-sm font-medium text-foreground">\n Newsletter\n </h3>\n <p className="mb-4 text-sm text-muted-foreground">\n Get product updates, tips, and insights delivered weekly.\n </p>\n <form className="flex gap-2">\n <input\n type="email"\n placeholder="Enter your email"\n className="flex-1 px-3 py-2 text-sm rounded-md border border-input bg-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"\n />\n <button\n type="submit"\n className="px-4 py-2 text-sm font-medium rounded-md bg-primary text-primary-foreground hover:bg-primary/90"\n >\n Subscribe\n </button>\n </form>\n </div>\n </div>\n\n {/* Social Links */}\n <div className="mt-10 flex items-center gap-4 border-t border-border pt-8">\n <a\n href={socialLinks.twitter}\n target="_blank"\n rel="noopener noreferrer"\n className="text-muted-foreground transition-colors hover:text-foreground"\n aria-label="X (Twitter)"\n >\n {SocialIcons.twitter}\n </a>\n <a\n href={socialLinks.linkedin}\n target="_blank"\n rel="noopener noreferrer"\n className="text-muted-foreground transition-colors hover:text-foreground"\n aria-label="LinkedIn"\n >\n {SocialIcons.linkedin}\n </a>\n <a\n href={socialLinks.github}\n target="_blank"\n rel="noopener noreferrer"\n className="text-muted-foreground transition-colors hover:text-foreground"\n aria-label="GitHub"\n >\n {SocialIcons.github}\n </a>\n </div>\n </div>\n\n {/* Bottom Bar */}\n <div className="border-t border-border">\n <div className="container mx-auto flex flex-col items-center justify-between gap-4 px-4 py-6 sm:flex-row">\n {/* Logo and Copyright */}\n <div className="flex items-center gap-4">\n <Link href="/" className="flex items-center">\n <Logo className="h-6 w-6" />\n </Link>\n <p className="text-sm text-muted-foreground">\n \xA9 {currentYear} SaaSify\n </p>\n </div>\n\n {/* Bottom Links and Theme Selector */}\n <div className="flex items-center gap-6">\n {bottomLinks.map((link) => (\n <Link\n key={link.href}\n href={link.href}\n className="text-sm text-muted-foreground transition-colors hover:text-foreground"\n >\n {link.label}\n </Link>\n ))}\n <ThemeSelector />\n </div>\n </div>\n </div>\n </footer>\n )\n}\n',
2966
+ "marketing/nextjs/src/components/Header/MegaMenu.tsx": '"use client"\n\nimport { useState } from "react"\nimport Link from "next/link"\nimport { ChevronDown, Layout, BarChart3, Shield, Zap, Layers, Target, Rocket, Settings } from "lucide-react"\nimport { cn } from "@/lib/utils"\n\ninterface MenuItem {\n label: string\n description: string\n href: string\n icon: string\n}\n\ninterface MenuColumn {\n title: string\n items: MenuItem[]\n}\n\ninterface MegaMenuProps {\n menu: {\n label: string\n columns: MenuColumn[]\n }\n}\n\nconst iconMap: Record<string, React.ComponentType<{ className?: string }>> = {\n layout: Layout,\n barChart: BarChart3,\n shield: Shield,\n zap: Zap,\n layers: Layers,\n target: Target,\n rocket: Rocket,\n settings: Settings,\n}\n\nexport function MegaMenu({ menu }: MegaMenuProps) {\n const [isOpen, setIsOpen] = useState(false)\n\n return (\n <div\n className="relative"\n onMouseEnter={() => setIsOpen(true)}\n onMouseLeave={() => setIsOpen(false)}\n >\n <button\n type="button"\n className={cn(\n "flex items-center gap-1 px-4 py-2 text-sm font-medium transition-colors",\n isOpen ? "text-foreground" : "text-muted-foreground hover:text-foreground"\n )}\n onClick={() => setIsOpen(!isOpen)}\n aria-expanded={isOpen}\n >\n {menu.label}\n <ChevronDown\n className={cn(\n "h-4 w-4 transition-transform",\n isOpen && "rotate-180"\n )}\n />\n </button>\n\n {/* Dropdown */}\n <div\n className={cn(\n "absolute left-0 top-full pt-2 transition-all",\n isOpen\n ? "opacity-100 translate-y-0 pointer-events-auto"\n : "opacity-0 -translate-y-2 pointer-events-none"\n )}\n >\n <div className="bg-background border border-border rounded-lg shadow-lg p-6 min-w-[480px]">\n <div className={cn(\n "grid gap-8",\n menu.columns.length === 1 ? "grid-cols-1" : "grid-cols-2"\n )}>\n {menu.columns.map((column) => (\n <div key={column.title}>\n <h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-4">\n {column.title}\n </h3>\n <ul className="space-y-1">\n {column.items.map((item) => {\n const Icon = iconMap[item.icon] || Layout\n return (\n <li key={item.href}>\n <Link\n href={item.href}\n className="flex items-start gap-3 p-3 rounded-lg hover:bg-muted transition-colors group"\n onClick={() => setIsOpen(false)}\n >\n <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-md bg-muted group-hover:bg-background">\n <Icon className="h-5 w-5 text-primary" />\n </div>\n <div>\n <div className="text-sm font-medium text-foreground">\n {item.label}\n </div>\n <div className="text-xs text-muted-foreground mt-0.5">\n {item.description}\n </div>\n </div>\n </Link>\n </li>\n )\n })}\n </ul>\n </div>\n ))}\n </div>\n </div>\n </div>\n </div>\n )\n}\n',
2967
+ "marketing/nextjs/src/components/Header/MobileMenu.tsx": '"use client"\n\nimport { useState } from "react"\nimport Link from "next/link"\nimport { Menu, X, ChevronDown, Layout, BarChart3, Shield, Zap, Layers, Target, Rocket, Settings } from "lucide-react"\nimport { cn } from "@/lib/utils"\n\ninterface MenuItem {\n label: string\n description: string\n href: string\n icon: string\n}\n\ninterface MenuColumn {\n title: string\n items: MenuItem[]\n}\n\ninterface MobileMenuProps {\n productMenu: {\n label: string\n columns: MenuColumn[]\n }\n solutionsMenu: {\n label: string\n columns: MenuColumn[]\n }\n navLinks: { label: string; href: string }[]\n ctaLinks: { label: string; href: string; variant: "default" | "ghost" }[]\n}\n\nconst iconMap: Record<string, React.ComponentType<{ className?: string }>> = {\n layout: Layout,\n barChart: BarChart3,\n shield: Shield,\n zap: Zap,\n layers: Layers,\n target: Target,\n rocket: Rocket,\n settings: Settings,\n}\n\nfunction MobileMenuSection({\n menu,\n isOpen,\n onToggle,\n onClose,\n}: {\n menu: { label: string; columns: MenuColumn[] }\n isOpen: boolean\n onToggle: () => void\n onClose: () => void\n}) {\n return (\n <div className="border-b border-border">\n <button\n type="button"\n className="flex items-center justify-between w-full px-4 py-3 text-sm font-medium"\n onClick={onToggle}\n >\n {menu.label}\n <ChevronDown\n className={cn(\n "h-4 w-4 transition-transform",\n isOpen && "rotate-180"\n )}\n />\n </button>\n {isOpen && (\n <div className="px-4 pb-4 space-y-4">\n {menu.columns.map((column) => (\n <div key={column.title}>\n <h4 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">\n {column.title}\n </h4>\n <ul className="space-y-1">\n {column.items.map((item) => {\n const Icon = iconMap[item.icon] || Layout\n return (\n <li key={item.href}>\n <Link\n href={item.href}\n className="flex items-center gap-3 p-2 rounded-lg hover:bg-muted"\n onClick={onClose}\n >\n <Icon className="h-4 w-4 text-primary" />\n <span className="text-sm">{item.label}</span>\n </Link>\n </li>\n )\n })}\n </ul>\n </div>\n ))}\n </div>\n )}\n </div>\n )\n}\n\nexport function MobileMenu({ productMenu, solutionsMenu, navLinks, ctaLinks }: MobileMenuProps) {\n const [isOpen, setIsOpen] = useState(false)\n const [openSection, setOpenSection] = useState<string | null>(null)\n\n const handleClose = () => {\n setIsOpen(false)\n setOpenSection(null)\n }\n\n return (\n <div className="lg:hidden">\n <button\n type="button"\n className="p-2 text-muted-foreground hover:text-foreground"\n onClick={() => setIsOpen(!isOpen)}\n aria-label={isOpen ? "Close menu" : "Open menu"}\n >\n {isOpen ? <X className="h-6 w-6" /> : <Menu className="h-6 w-6" />}\n </button>\n\n {/* Mobile menu overlay */}\n {isOpen && (\n <div className="fixed inset-0 top-16 z-50 bg-background">\n <nav className="overflow-y-auto max-h-[calc(100vh-4rem)]">\n <MobileMenuSection\n menu={productMenu}\n isOpen={openSection === "product"}\n onToggle={() =>\n setOpenSection(openSection === "product" ? null : "product")\n }\n onClose={handleClose}\n />\n <MobileMenuSection\n menu={solutionsMenu}\n isOpen={openSection === "solutions"}\n onToggle={() =>\n setOpenSection(openSection === "solutions" ? null : "solutions")\n }\n onClose={handleClose}\n />\n\n {/* Simple nav links */}\n {navLinks.map((link) => (\n <Link\n key={link.href}\n href={link.href}\n className="flex items-center px-4 py-3 text-sm font-medium border-b border-border hover:bg-muted"\n onClick={handleClose}\n >\n {link.label}\n </Link>\n ))}\n\n {/* CTA links */}\n <div className="p-4 space-y-2">\n {ctaLinks.map((link) => (\n <Link\n key={link.href}\n href={link.href}\n className={cn(\n "flex items-center justify-center w-full px-4 py-3 text-sm font-medium rounded-md transition-colors",\n link.variant === "default"\n ? "bg-primary text-primary-foreground hover:bg-primary/90"\n : "border border-border hover:bg-muted"\n )}\n onClick={handleClose}\n >\n {link.label}\n </Link>\n ))}\n </div>\n </nav>\n </div>\n )}\n </div>\n )\n}\n',
2968
+ "marketing/nextjs/src/components/Header/index.tsx": '"use client"\n\nimport Link from "next/link"\nimport { Logo } from "@/components/Logo"\nimport { MegaMenu } from "./MegaMenu"\nimport { MobileMenu } from "./MobileMenu"\nimport { cn } from "@/lib/utils"\n\n// Navigation data structure matching SaaSify\nconst productMenu = {\n label: "Product",\n columns: [\n {\n title: "Core Features",\n items: [\n {\n label: "Integrations",\n description: "Connect with 100+ tools you already use",\n href: "/features/integrations",\n icon: "layout",\n },\n {\n label: "Analytics",\n description: "Real-time insights and reporting dashboards",\n href: "/features/analytics",\n icon: "barChart",\n },\n {\n label: "Security",\n description: "Enterprise-grade protection and compliance",\n href: "/features/security",\n icon: "shield",\n },\n ],\n },\n {\n title: "Productivity",\n items: [\n {\n label: "Dashboard",\n description: "Unified command center for your team",\n href: "/features/dashboard",\n icon: "layout",\n },\n {\n label: "Automation",\n description: "Streamline repetitive tasks instantly",\n href: "/features/automation",\n icon: "zap",\n },\n {\n label: "Workflows",\n description: "Build custom processes without code",\n href: "/features/workflows",\n icon: "layers",\n },\n ],\n },\n ],\n}\n\nconst solutionsMenu = {\n label: "Solutions",\n columns: [\n {\n title: "By Team",\n items: [\n {\n label: "Sales Teams",\n description: "Close deals faster with smart tools",\n href: "/use-cases/sales",\n icon: "target",\n },\n {\n label: "Marketing Teams",\n description: "Launch campaigns that convert",\n href: "/use-cases/marketing",\n icon: "rocket",\n },\n {\n label: "Product Teams",\n description: "Ship features users love",\n href: "/use-cases/product",\n icon: "layers",\n },\n {\n label: "Operations",\n description: "Scale without the growing pains",\n href: "/use-cases/operations",\n icon: "settings",\n },\n ],\n },\n ],\n}\n\nconst navLinks = [\n { label: "Pricing", href: "/pricing" },\n { label: "Blog", href: "/blog" },\n]\n\nconst ctaLinks = [\n { label: "Sign In", href: "/sign-in", variant: "ghost" as const },\n { label: "Get Started", href: "/sign-up", variant: "default" as const },\n]\n\nexport function Header() {\n return (\n <header className="sticky top-0 z-50 border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">\n <div className="container mx-auto px-4 h-16 flex justify-between items-center">\n {/* Left section: Logo + Nav */}\n <div className="flex items-center gap-8">\n <Link href="/" className="flex items-center gap-2">\n <Logo />\n <span className="text-xl font-semibold hidden sm:inline">SaaSify</span>\n </Link>\n\n {/* Desktop navigation */}\n <nav className="hidden lg:flex items-center gap-1">\n <MegaMenu menu={productMenu} />\n <MegaMenu menu={solutionsMenu} />\n {navLinks.map((link) => (\n <Link\n key={link.href}\n href={link.href}\n className="px-4 py-2 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors"\n >\n {link.label}\n </Link>\n ))}\n </nav>\n </div>\n\n {/* Right section: CTAs */}\n <div className="flex items-center gap-3">\n {/* Desktop CTAs */}\n <div className="hidden lg:flex items-center gap-3">\n {ctaLinks.map((link) => (\n <Link\n key={link.href}\n href={link.href}\n className={cn(\n "px-4 py-2 text-sm font-medium rounded-md transition-colors",\n link.variant === "default"\n ? "bg-primary text-primary-foreground hover:bg-primary/90"\n : "text-muted-foreground hover:text-foreground"\n )}\n >\n {link.label}\n </Link>\n ))}\n </div>\n\n {/* Mobile: Primary CTA + Hamburger */}\n <Link\n href="/sign-up"\n className="lg:hidden px-4 py-2 text-sm font-medium rounded-md bg-primary text-primary-foreground hover:bg-primary/90"\n >\n Get Started\n </Link>\n\n <MobileMenu\n productMenu={productMenu}\n solutionsMenu={solutionsMenu}\n navLinks={navLinks}\n ctaLinks={ctaLinks}\n />\n </div>\n </div>\n </header>\n )\n}\n',
2969
+ "marketing/nextjs/src/components/Logo.tsx": '"use client"\n\nimport { useTheme } from "next-themes"\nimport { useEffect, useState } from "react"\nimport { cn } from "@/lib/utils"\n\ninterface LogoProps {\n className?: string\n variant?: "light" | "dark" | "auto"\n}\n\nexport function Logo({ className, variant = "auto" }: LogoProps) {\n const { resolvedTheme } = useTheme()\n const [mounted, setMounted] = useState(false)\n\n useEffect(() => {\n setMounted(true)\n }, [])\n\n // Determine which variant to show\n const showDark =\n variant === "dark" ||\n (variant === "auto" && mounted && resolvedTheme === "dark")\n\n return (\n <div\n className={cn(\n "flex h-8 w-8 items-center justify-center rounded-lg",\n showDark ? "bg-white" : "bg-foreground",\n className\n )}\n >\n <svg\n className={cn("h-5 w-5", showDark ? "text-gray-900" : "text-background")}\n viewBox="0 0 24 24"\n fill="none"\n stroke="currentColor"\n strokeWidth={2}\n strokeLinecap="round"\n strokeLinejoin="round"\n >\n <path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" />\n </svg>\n </div>\n )\n}\n',
2970
+ "marketing/nextjs/src/components/ThemeProvider.tsx": '"use client"\n\nimport { ThemeProvider as NextThemesProvider } from "next-themes"\nimport type { ThemeProviderProps } from "next-themes"\n\nexport function ThemeProvider({ children, ...props }: ThemeProviderProps) {\n return <NextThemesProvider {...props}>{children}</NextThemesProvider>\n}\n',
2971
+ "marketing/nextjs/src/components/ThemeSelector.tsx": '"use client"\n\nimport { Moon, Sun, Monitor } from "lucide-react"\nimport { useTheme } from "next-themes"\nimport { useEffect, useState } from "react"\nimport { cn } from "@/lib/utils"\n\nexport function ThemeSelector() {\n const { theme, setTheme } = useTheme()\n const [mounted, setMounted] = useState(false)\n\n useEffect(() => {\n setMounted(true)\n }, [])\n\n if (!mounted) {\n return (\n <div className="flex items-center gap-1 rounded-full border border-border bg-background/50 p-1">\n <div className="h-7 w-7 rounded-full" />\n <div className="h-7 w-7 rounded-full" />\n <div className="h-7 w-7 rounded-full" />\n </div>\n )\n }\n\n return (\n <div className="flex items-center gap-1 rounded-full border border-border bg-background/50 p-1">\n <button\n type="button"\n onClick={() => setTheme("light")}\n className={cn(\n "flex h-7 w-7 items-center justify-center rounded-full transition-colors",\n theme === "light"\n ? "bg-foreground text-background"\n : "text-muted-foreground hover:text-foreground"\n )}\n aria-label="Light mode"\n >\n <Sun className="h-4 w-4" />\n </button>\n <button\n type="button"\n onClick={() => setTheme("dark")}\n className={cn(\n "flex h-7 w-7 items-center justify-center rounded-full transition-colors",\n theme === "dark"\n ? "bg-foreground text-background"\n : "text-muted-foreground hover:text-foreground"\n )}\n aria-label="Dark mode"\n >\n <Moon className="h-4 w-4" />\n </button>\n <button\n type="button"\n onClick={() => setTheme("system")}\n className={cn(\n "flex h-7 w-7 items-center justify-center rounded-full transition-colors",\n theme === "system"\n ? "bg-foreground text-background"\n : "text-muted-foreground hover:text-foreground"\n )}\n aria-label="System theme"\n >\n <Monitor className="h-4 w-4" />\n </button>\n </div>\n )\n}\n',
2972
+ "marketing/nextjs/src/components/blocks/BentoFeatures.tsx": '"use client"\n\nimport {\n BarChart3,\n Globe,\n Layers,\n type LucideIcon,\n Rocket,\n Settings,\n Shield,\n Zap,\n} from "lucide-react"\nimport { cn } from "@/lib/utils"\n\ninterface Feature {\n size?: "small" | "tall"\n style?: "default" | "primary" | "accent" | "gradient"\n icon?: string\n stat?: string\n title: string\n description: string\n}\n\ninterface BentoFeaturesProps {\n heading?: string\n subheading?: string\n features?: Feature[]\n}\n\nconst iconMap: Record<string, LucideIcon> = {\n rocket: Rocket,\n zap: Zap,\n layers: Layers,\n shield: Shield,\n globe: Globe,\n settings: Settings,\n barChart: BarChart3,\n}\n\nconst gridPositions = [\n "md:col-span-1 md:row-span-1",\n "md:col-span-1 md:row-span-1",\n "md:col-span-1 md:row-span-1",\n "md:col-span-1 md:row-span-2",\n "md:col-span-1 md:row-span-1",\n "md:col-span-1 md:row-span-1",\n "md:col-span-1 md:row-span-1",\n "md:col-span-1 md:row-span-1",\n]\n\nconst styleClasses: Record<string, { bg: string; text: string; icon: string; statText: string }> = {\n default: {\n bg: "bg-card border border-border/50 hover:border-border",\n text: "text-foreground",\n icon: "bg-primary/10 text-primary",\n statText: "text-primary",\n },\n primary: {\n bg: "bg-primary hover:bg-primary/95",\n text: "text-primary-foreground",\n icon: "bg-white/20 text-white",\n statText: "text-white",\n },\n accent: {\n bg: "bg-gradient-to-br from-teal-500 to-teal-600 hover:from-teal-500/95 hover:to-teal-600/95",\n text: "text-white",\n icon: "bg-white/20 text-white",\n statText: "text-white",\n },\n gradient: {\n bg: "bg-gradient-to-br from-primary via-primary/90 to-secondary hover:from-primary/95",\n text: "text-white",\n icon: "bg-white/20 text-white",\n statText: "text-white",\n },\n}\n\nconst defaultFeatures: Feature[] = [\n {\n size: "small",\n style: "gradient",\n icon: "zap",\n stat: "5x",\n title: "Faster onboarding",\n description: "Get your team up and running in hours, not weeks.",\n },\n {\n size: "small",\n style: "accent",\n icon: "rocket",\n title: "Quick setup",\n description: "Configure your workspace, invite your team, and start collaborating.",\n },\n {\n size: "small",\n style: "default",\n icon: "layers",\n title: "Powerful integrations",\n description: "Connect with 100+ tools you already use.",\n },\n {\n size: "tall",\n style: "primary",\n icon: "shield",\n title: "Enterprise security",\n description: "SOC 2 compliant with end-to-end encryption and complete audit trails for peace of mind.",\n },\n {\n size: "small",\n style: "default",\n icon: "globe",\n stat: "99.9%",\n title: "Uptime",\n description: "Reliable infrastructure you can count on.",\n },\n {\n size: "small",\n style: "default",\n icon: "globe",\n title: "Global scale",\n description: "Multi-region with custom domains.",\n },\n {\n size: "small",\n style: "default",\n icon: "settings",\n title: "Smart automation",\n description: "Automate repetitive tasks and workflows.",\n },\n {\n size: "small",\n style: "default",\n icon: "layers",\n title: "Flexible workflows",\n description: "Build custom processes for any use case.",\n },\n]\n\nexport function BentoFeatures({\n heading = "Discover what SaaSify can do",\n subheading = "Everything you need to work smarter and scale faster",\n features = defaultFeatures,\n}: BentoFeaturesProps) {\n const displayFeatures = features.length > 0 ? features : defaultFeatures\n\n return (\n <section className="py-16 md:py-24">\n <div className="container mx-auto px-4">\n {/* Header */}\n {(heading || subheading) && (\n <div className="text-center mb-12 md:mb-16 max-w-3xl mx-auto">\n {heading && (\n <h2 className="text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight mb-6">\n {heading}\n </h2>\n )}\n {subheading && (\n <p className="text-xl md:text-2xl text-muted-foreground">{subheading}</p>\n )}\n </div>\n )}\n\n {/* Bento Grid */}\n <div className="grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-5 md:grid-rows-[repeat(3,minmax(140px,160px))]">\n {displayFeatures.map((feature, index) => {\n const style = feature.style || "default"\n const iconKey = feature.icon\n const Icon = iconKey && iconKey in iconMap ? iconMap[iconKey] : null\n const styleConfig = styleClasses[style] || styleClasses.default\n const gridPosition = gridPositions[index] || "md:col-span-1 md:row-span-1"\n const isLarge =\n gridPosition.includes("col-span-2") && gridPosition.includes("row-span-2")\n\n return (\n <div\n key={feature.title}\n className={cn(\n "relative rounded-2xl overflow-hidden p-5 md:p-6 flex flex-col transition-all duration-300 group",\n "hover:shadow-lg hover:-translate-y-0.5",\n "col-span-1 row-span-1",\n gridPosition,\n styleConfig.bg\n )}\n >\n {/* Decorative elements */}\n {!isLarge && feature.size === "tall" && (\n <div className="absolute -right-6 -bottom-6 w-24 h-24 md:w-32 md:h-32 rounded-full bg-white/10 blur-xl" />\n )}\n\n {/* Content */}\n <div className="relative z-10 flex flex-col h-full">\n {/* Icon */}\n {Icon && (\n <div\n className={cn(\n "w-10 h-10 md:w-11 md:h-11 rounded-xl flex items-center justify-center mb-auto",\n styleConfig.icon\n )}\n >\n <Icon className="w-5 h-5 md:w-5 md:h-5" />\n </div>\n )}\n\n {/* Spacer */}\n <div className="flex-1 min-h-2" />\n\n {/* Stat */}\n {feature.stat && (\n <div\n className={cn(\n "font-bold mb-0.5 leading-none",\n isLarge ? "text-5xl md:text-6xl" : "text-3xl md:text-4xl",\n styleConfig.statText\n )}\n >\n {feature.stat}\n </div>\n )}\n\n {/* Title */}\n <h3\n className={cn(\n "font-semibold mb-1",\n isLarge ? "text-lg md:text-xl" : "text-base md:text-lg",\n styleConfig.text\n )}\n >\n {feature.title}\n </h3>\n\n {/* Description */}\n <p\n className={cn(\n "leading-snug",\n isLarge ? "text-sm md:text-base" : "text-xs md:text-sm",\n style === "default" ? "text-muted-foreground" : "text-white/80"\n )}\n >\n {feature.description}\n </p>\n </div>\n </div>\n )\n })}\n </div>\n </div>\n </section>\n )\n}\n',
2973
+ "marketing/nextjs/src/components/blocks/FeatureShowcase.tsx": '"use client"\n\nimport Link from "next/link"\nimport { Check } from "lucide-react"\nimport { cn } from "@/lib/utils"\n\ninterface FeatureShowcaseProps {\n label?: string\n headline: string\n description: string\n features?: { text: string }[]\n link?: {\n label: string\n href: string\n }\n imagePosition?: "left" | "right"\n}\n\nexport function FeatureShowcase({\n label,\n headline,\n description,\n features = [],\n link,\n imagePosition = "right",\n}: FeatureShowcaseProps) {\n return (\n <section className="py-16 md:py-24">\n <div className="container mx-auto px-4">\n <div\n className={cn(\n "grid md:grid-cols-2 gap-12 lg:gap-16 items-center",\n imagePosition === "left" && "md:grid-flow-dense"\n )}\n >\n {/* Content */}\n <div className={cn(imagePosition === "left" && "md:col-start-2")}>\n {label && (\n <span className="inline-block text-sm font-medium text-primary mb-4">\n {label}\n </span>\n )}\n <h2 className="text-3xl md:text-4xl font-bold tracking-tight mb-4">\n {headline}\n </h2>\n <p className="text-lg text-muted-foreground mb-6">\n {description}\n </p>\n\n {features.length > 0 && (\n <ul className="space-y-3 mb-8">\n {features.map((feature) => (\n <li key={feature.text} className="flex items-center gap-3">\n <div className="flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-primary/10">\n <Check className="h-3 w-3 text-primary" />\n </div>\n <span className="text-sm text-muted-foreground">\n {feature.text}\n </span>\n </li>\n ))}\n </ul>\n )}\n\n {link && (\n <Link\n href={link.href}\n className="inline-flex items-center gap-2 text-sm font-medium text-primary hover:underline"\n >\n {link.label}\n <span aria-hidden="true">\u2192</span>\n </Link>\n )}\n </div>\n\n {/* Image Placeholder */}\n <div\n className={cn(\n "relative aspect-[4/3] rounded-2xl bg-muted overflow-hidden",\n imagePosition === "left" && "md:col-start-1 md:row-start-1"\n )}\n >\n <div className="absolute inset-0 flex items-center justify-center">\n <div className="text-center">\n <div className="w-16 h-16 mx-auto mb-4 rounded-xl bg-primary/10 flex items-center justify-center">\n <svg\n className="w-8 h-8 text-primary"\n fill="none"\n stroke="currentColor"\n viewBox="0 0 24 24"\n >\n <path\n strokeLinecap="round"\n strokeLinejoin="round"\n strokeWidth={1.5}\n d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"\n />\n </svg>\n </div>\n <p className="text-sm text-muted-foreground">\n Feature illustration\n </p>\n </div>\n </div>\n </div>\n </div>\n </div>\n </section>\n )\n}\n',
2974
+ "marketing/nextjs/src/components/blocks/FinalCTA.tsx": '"use client"\n\nimport Link from "next/link"\nimport { cn } from "@/lib/utils"\n\ninterface FinalCTALink {\n label: string\n href: string\n variant: "default" | "outline"\n}\n\ninterface FinalCTAProps {\n headline?: string\n subheading?: string\n links?: FinalCTALink[]\n style?: "dark" | "light" | "gradient"\n}\n\nexport function FinalCTA({\n headline = "Ready to transform how your team works?",\n subheading = "Join thousands of teams who chose the smarter way to work. Start free, upgrade as you grow.",\n links = [\n { label: "Start free trial", href: "/sign-up", variant: "outline" },\n { label: "Book a demo", href: "/contact", variant: "default" },\n ],\n style = "dark",\n}: FinalCTAProps) {\n const bgClasses = {\n dark: "bg-foreground text-background",\n light: "bg-muted text-foreground",\n gradient: "bg-gradient-to-br from-primary to-primary/80 text-primary-foreground",\n }\n\n const buttonClasses = {\n dark: {\n default: "bg-background text-foreground hover:bg-background/90",\n outline: "border border-background/30 text-background hover:bg-background/10",\n },\n light: {\n default: "bg-primary text-primary-foreground hover:bg-primary/90",\n outline: "border border-border hover:bg-background",\n },\n gradient: {\n default: "bg-background text-foreground hover:bg-background/90",\n outline: "border border-primary-foreground/30 text-primary-foreground hover:bg-primary-foreground/10",\n },\n }\n\n return (\n <section className={cn("py-16 md:py-24", bgClasses[style])}>\n <div className="container mx-auto px-4">\n <div className="max-w-3xl mx-auto text-center">\n <h2 className="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight mb-6">\n {headline}\n </h2>\n {subheading && (\n <p\n className={cn(\n "text-lg md:text-xl mb-8",\n style === "dark"\n ? "text-background/80"\n : style === "gradient"\n ? "text-primary-foreground/80"\n : "text-muted-foreground"\n )}\n >\n {subheading}\n </p>\n )}\n\n {links && links.length > 0 && (\n <div className="flex flex-wrap gap-4 justify-center">\n {links.map((link) => (\n <Link\n key={link.href}\n href={link.href}\n className={cn(\n "inline-flex items-center justify-center px-6 py-3 text-sm font-medium rounded-md transition-colors",\n buttonClasses[style][link.variant]\n )}\n >\n {link.label}\n </Link>\n ))}\n </div>\n )}\n </div>\n </div>\n </section>\n )\n}\n',
2975
+ "marketing/nextjs/src/components/blocks/IndustryTabs.tsx": `"use client"
2976
+
2977
+ import { useState } from "react"
2978
+ import Link from "next/link"
2979
+ import { cn } from "@/lib/utils"
2980
+
2981
+ interface Tab {
2982
+ name: string
2983
+ stat: string
2984
+ statLabel: string
2985
+ description: string
2986
+ link?: {
2987
+ label: string
2988
+ href: string
2989
+ }
2990
+ }
2991
+
2992
+ interface IndustryTabsProps {
2993
+ heading?: string
2994
+ subheading?: string
2995
+ tabs?: Tab[]
2996
+ }
2997
+
2998
+ const defaultTabs: Tab[] = [
2999
+ {
3000
+ name: "Sales Teams",
3001
+ stat: "40%",
3002
+ statLabel: "Faster deal cycles with smart pipeline tools",
3003
+ description:
3004
+ "Close deals faster with intelligent pipeline management, automated follow-ups, and real-time insights that help your team hit quota every quarter.",
3005
+ link: { label: "Solutions for sales", href: "/use-cases/sales" },
3006
+ },
3007
+ {
3008
+ name: "Marketing Teams",
3009
+ stat: "3x",
3010
+ statLabel: "Campaign velocity with streamlined workflows",
3011
+ description:
3012
+ "Launch campaigns that convert with collaborative planning, asset management, and performance analytics all in one place.",
3013
+ link: { label: "Solutions for marketing", href: "/use-cases/marketing" },
3014
+ },
3015
+ {
3016
+ name: "Product Teams",
3017
+ stat: "50%",
3018
+ statLabel: "Faster shipping with better prioritization",
3019
+ description:
3020
+ "Ship features users love with roadmap planning, feedback collection, and release management that keeps everyone aligned.",
3021
+ link: { label: "Solutions for product", href: "/use-cases/product" },
3022
+ },
3023
+ {
3024
+ name: "Operations",
3025
+ stat: "60%",
3026
+ statLabel: "Time saved with process automation",
3027
+ description:
3028
+ "Scale your operations without the chaos. Automate processes, manage resources, and get visibility across your entire organization.",
3029
+ link: { label: "Solutions for ops", href: "/use-cases/operations" },
3030
+ },
3031
+ ]
3032
+
3033
+ export function IndustryTabs({
3034
+ heading = "Solutions that deliver real results",
3035
+ subheading = "Whether you're in sales, marketing, or product, SaaSify adapts to how your team works.",
3036
+ tabs = defaultTabs,
3037
+ }: IndustryTabsProps) {
3038
+ const [activeTab, setActiveTab] = useState(0)
3039
+ const displayTabs = tabs.length > 0 ? tabs : defaultTabs
3040
+ const activeContent = displayTabs[activeTab]
3041
+
3042
+ return (
3043
+ <section className="py-16 md:py-24 bg-muted/30">
3044
+ <div className="container mx-auto px-4">
3045
+ {/* Header */}
3046
+ {(heading || subheading) && (
3047
+ <div className="text-center mb-12 md:mb-16 max-w-3xl mx-auto">
3048
+ {heading && (
3049
+ <h2 className="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight mb-4">
3050
+ {heading}
3051
+ </h2>
3052
+ )}
3053
+ {subheading && (
3054
+ <p className="text-lg md:text-xl text-muted-foreground">
3055
+ {subheading}
3056
+ </p>
3057
+ )}
1342
3058
  </div>
3059
+ )}
3060
+
3061
+ {/* Tabs */}
3062
+ <div className="flex flex-wrap justify-center gap-2 mb-12">
3063
+ {displayTabs.map((tab, index) => (
3064
+ <button
3065
+ key={tab.name}
3066
+ type="button"
3067
+ onClick={() => setActiveTab(index)}
3068
+ className={cn(
3069
+ "px-4 py-2 text-sm font-medium rounded-full transition-colors",
3070
+ activeTab === index
3071
+ ? "bg-primary text-primary-foreground"
3072
+ : "bg-background border border-border hover:bg-muted"
3073
+ )}
3074
+ >
3075
+ {tab.name}
3076
+ </button>
3077
+ ))}
1343
3078
  </div>
1344
- </section>
1345
3079
 
1346
- {/* Footer */}
1347
- <footer className="border-t border-gray-200 dark:border-gray-700">
1348
- <div className="container mx-auto px-4 py-12">
1349
- <div className="text-center text-gray-600 dark:text-gray-300">
1350
- <p>
1351
- Built with{' '}
1352
- <a
1353
- href="https://github.com/theodenanyoh11/create-kofi-stack"
1354
- className="text-gray-900 dark:text-white hover:underline"
1355
- target="_blank"
1356
- rel="noopener noreferrer"
1357
- >
1358
- create-kofi-stack
1359
- </a>
3080
+ {/* Content */}
3081
+ <div className="grid md:grid-cols-2 gap-12 lg:gap-16 items-center max-w-5xl mx-auto">
3082
+ {/* Stats side */}
3083
+ <div className="text-center md:text-left">
3084
+ <div className="text-7xl md:text-8xl lg:text-9xl font-bold text-primary mb-2">
3085
+ {activeContent.stat}
3086
+ </div>
3087
+ <p className="text-xl md:text-2xl font-medium text-foreground">
3088
+ {activeContent.statLabel}
3089
+ </p>
3090
+ </div>
3091
+
3092
+ {/* Description side */}
3093
+ <div>
3094
+ <p className="text-lg text-muted-foreground mb-6">
3095
+ {activeContent.description}
1360
3096
  </p>
3097
+ {activeContent.link && (
3098
+ <Link
3099
+ href={activeContent.link.href}
3100
+ className="inline-flex items-center gap-2 px-6 py-3 text-sm font-medium rounded-md bg-primary text-primary-foreground hover:bg-primary/90 transition-colors"
3101
+ >
3102
+ {activeContent.link.label}
3103
+ <span aria-hidden="true">\u2192</span>
3104
+ </Link>
3105
+ )}
1361
3106
  </div>
1362
3107
  </div>
1363
- </footer>
1364
- </main>
3108
+ </div>
3109
+ </section>
1365
3110
  )
1366
3111
  }
1367
3112
  `,
3113
+ "marketing/nextjs/src/components/blocks/LogoBanner.tsx": '"use client"\n\nimport { cn } from "@/lib/utils"\n\ninterface Logo {\n name: string\n initials?: string\n}\n\ninterface LogoBannerProps {\n heading?: string\n logos?: Logo[]\n style?: "scroll" | "grid"\n}\n\nconst defaultLogos: Logo[] = [\n { name: "TechFlow Inc", initials: "TF" },\n { name: "Acme Corp", initials: "AC" },\n { name: "Evergreen HQ", initials: "EH" },\n { name: "Atlas Network", initials: "AN" },\n { name: "Beacon Digital", initials: "BD" },\n { name: "Cascade Systems", initials: "CS" },\n]\n\nfunction LogoItem({ logo }: { logo: Logo }) {\n return (\n <div\n className={cn(\n "logo-item flex items-center justify-center px-6 md:px-8",\n "grayscale hover:grayscale-0 transition-all duration-300"\n )}\n >\n <div className="flex items-center gap-2">\n <span className="w-8 h-8 rounded bg-muted flex items-center justify-center text-xs font-bold text-foreground">\n {logo.initials || logo.name.slice(0, 2).toUpperCase()}\n </span>\n <span className="text-sm font-medium text-muted-foreground hidden md:block">\n {logo.name}\n </span>\n </div>\n </div>\n )\n}\n\nexport function LogoBanner({\n heading = "Trusted by fast-growing companies everywhere",\n logos = defaultLogos,\n style = "scroll",\n}: LogoBannerProps) {\n const displayLogos = logos.length > 0 ? logos : defaultLogos\n\n return (\n <section className="py-12 md:py-16 border-y border-border/50">\n <div className="container mx-auto px-4">\n {heading && (\n <p className="text-center text-sm text-muted-foreground mb-8 uppercase tracking-wider">\n {heading}\n </p>\n )}\n\n {style === "scroll" ? (\n <div className="logo-scroll-container">\n <div className="logo-scroll-track">\n {/* Double the logos for seamless loop */}\n {[...displayLogos, ...displayLogos].map((logo, index) => (\n <LogoItem key={`${logo.name}-${index}`} logo={logo} />\n ))}\n </div>\n </div>\n ) : (\n <div className="grid grid-cols-3 md:grid-cols-6 gap-8 items-center justify-items-center">\n {displayLogos.map((logo) => (\n <LogoItem key={logo.name} logo={logo} />\n ))}\n </div>\n )}\n </div>\n </section>\n )\n}\n',
3114
+ "marketing/nextjs/src/components/blocks/PricingTable.tsx": '"use client"\n\nimport Link from "next/link"\nimport { Check, X } from "lucide-react"\nimport { cn } from "@/lib/utils"\n\ninterface PricingFeature {\n feature: string\n included: boolean\n}\n\ninterface PricingPlan {\n name: string\n price: string\n description: string\n featured?: boolean\n features: PricingFeature[]\n link: {\n label: string\n href: string\n variant: "default" | "outline"\n }\n}\n\ninterface PricingTableProps {\n heading?: string\n subheading?: string\n plans?: PricingPlan[]\n}\n\nconst defaultPlans: PricingPlan[] = [\n {\n name: "Free",\n price: "$0/mo",\n description: "Perfect for trying SaaSify.",\n features: [\n { feature: "Up to 3 users", included: true },\n { feature: "Basic features", included: true },\n { feature: "Community support", included: true },\n ],\n link: { label: "Get started free", href: "/sign-up", variant: "outline" },\n },\n {\n name: "Pro",\n price: "$29/mo",\n description: "For small teams getting started.",\n featured: true,\n features: [\n { feature: "Up to 10 users", included: true },\n { feature: "Advanced features", included: true },\n { feature: "Integrations", included: true },\n { feature: "Priority support", included: true },\n ],\n link: { label: "Get Pro", href: "/sign-up", variant: "default" },\n },\n {\n name: "Business",\n price: "$99/mo",\n description: "For teams ready to scale.",\n features: [\n { feature: "Unlimited users", included: true },\n { feature: "All features", included: true },\n { feature: "API access", included: true },\n { feature: "Dedicated support", included: true },\n ],\n link: { label: "Get Business", href: "/sign-up", variant: "outline" },\n },\n]\n\nexport function PricingTable({\n heading = "Simple, transparent pricing",\n subheading = "Start free, upgrade as your team grows. No hidden fees.",\n plans = defaultPlans,\n}: PricingTableProps) {\n const displayPlans = plans.length > 0 ? plans : defaultPlans\n\n return (\n <section className="py-16 md:py-24">\n <div className="container mx-auto px-4">\n {/* Header */}\n {(heading || subheading) && (\n <div className="text-center mb-12 md:mb-16 max-w-3xl mx-auto">\n {heading && (\n <h2 className="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight mb-4">\n {heading}\n </h2>\n )}\n {subheading && (\n <p className="text-lg md:text-xl text-muted-foreground">\n {subheading}\n </p>\n )}\n </div>\n )}\n\n {/* Pricing Cards */}\n <div className="grid md:grid-cols-3 gap-6 lg:gap-8 max-w-5xl mx-auto">\n {displayPlans.map((plan) => (\n <div\n key={plan.name}\n className={cn(\n "relative rounded-2xl p-6 md:p-8 flex flex-col",\n plan.featured\n ? "bg-primary text-primary-foreground border-2 border-primary"\n : "bg-card border border-border"\n )}\n >\n {plan.featured && (\n <span className="absolute -top-3 left-1/2 -translate-x-1/2 px-3 py-1 text-xs font-medium rounded-full bg-background text-foreground">\n Most Popular\n </span>\n )}\n\n {/* Plan header */}\n <div className="mb-6">\n <h3\n className={cn(\n "text-lg font-semibold mb-2",\n plan.featured ? "text-primary-foreground" : "text-foreground"\n )}\n >\n {plan.name}\n </h3>\n <div\n className={cn(\n "text-4xl font-bold mb-2",\n plan.featured ? "text-primary-foreground" : "text-foreground"\n )}\n >\n {plan.price}\n </div>\n <p\n className={cn(\n "text-sm",\n plan.featured ? "text-primary-foreground/80" : "text-muted-foreground"\n )}\n >\n {plan.description}\n </p>\n </div>\n\n {/* Features */}\n <ul className="space-y-3 mb-8 flex-1">\n {plan.features.map((feature) => (\n <li key={feature.feature} className="flex items-center gap-3">\n {feature.included ? (\n <Check\n className={cn(\n "h-4 w-4",\n plan.featured ? "text-primary-foreground" : "text-primary"\n )}\n />\n ) : (\n <X\n className={cn(\n "h-4 w-4",\n plan.featured ? "text-primary-foreground/50" : "text-muted-foreground"\n )}\n />\n )}\n <span\n className={cn(\n "text-sm",\n plan.featured\n ? feature.included\n ? "text-primary-foreground"\n : "text-primary-foreground/50"\n : feature.included\n ? "text-foreground"\n : "text-muted-foreground"\n )}\n >\n {feature.feature}\n </span>\n </li>\n ))}\n </ul>\n\n {/* CTA */}\n <Link\n href={plan.link.href}\n className={cn(\n "w-full inline-flex items-center justify-center px-6 py-3 text-sm font-medium rounded-md transition-colors",\n plan.featured\n ? "bg-background text-foreground hover:bg-background/90"\n : plan.link.variant === "default"\n ? "bg-primary text-primary-foreground hover:bg-primary/90"\n : "border border-border bg-background hover:bg-muted"\n )}\n >\n {plan.link.label}\n </Link>\n </div>\n ))}\n </div>\n\n {/* View all link */}\n <div className="text-center mt-8">\n <Link\n href="/pricing"\n className="inline-flex items-center gap-2 text-sm font-medium text-primary hover:underline"\n >\n View full comparison\n <span aria-hidden="true">\u2192</span>\n </Link>\n </div>\n </div>\n </section>\n )\n}\n',
3115
+ "marketing/nextjs/src/components/blocks/ProofBanner.tsx": '"use client"\n\nimport Link from "next/link"\nimport { cn } from "@/lib/utils"\n\ninterface ProofBannerLink {\n label: string\n href: string\n variant: "default" | "outline"\n}\n\ninterface ProofBannerProps {\n headline?: string\n subtext?: string\n links?: ProofBannerLink[]\n style?: "centered" | "left"\n}\n\nexport function ProofBanner({\n headline = "Transform how your team works, collaborates, and grows",\n subtext = "Every interaction feeds into a powerful platform that powers personalized experiences, seamless collaboration, and intelligent automation across every touchpoint.",\n links = [\n { label: "Start free trial", href: "/sign-up", variant: "default" },\n { label: "Book a demo", href: "/contact", variant: "outline" },\n ],\n style = "centered",\n}: ProofBannerProps) {\n return (\n <section className="py-16 md:py-24">\n <div className="container mx-auto px-4">\n <div\n className={cn(\n "max-w-4xl",\n style === "centered" ? "mx-auto text-center" : ""\n )}\n >\n <h2 className="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight mb-6">\n {headline}\n </h2>\n {subtext && (\n <p className="text-lg md:text-xl text-muted-foreground mb-8 max-w-3xl mx-auto">\n {subtext}\n </p>\n )}\n {links && links.length > 0 && (\n <div\n className={cn(\n "flex flex-wrap gap-4",\n style === "centered" ? "justify-center" : ""\n )}\n >\n {links.map((link) => (\n <Link\n key={link.href}\n href={link.href}\n className={cn(\n "inline-flex items-center justify-center px-6 py-3 text-sm font-medium rounded-md transition-colors",\n link.variant === "default"\n ? "bg-primary text-primary-foreground hover:bg-primary/90"\n : "border border-border bg-background hover:bg-muted"\n )}\n >\n {link.label}\n </Link>\n ))}\n </div>\n )}\n </div>\n </div>\n </section>\n )\n}\n',
3116
+ "marketing/nextjs/src/components/blocks/TestimonialsGrid.tsx": '"use client"\n\nimport { cn } from "@/lib/utils"\n\ninterface Testimonial {\n stat: string\n statLabel: string\n quote: string\n author: string\n company: string\n}\n\ninterface TestimonialsGridProps {\n heading?: string\n subheading?: string\n testimonials?: Testimonial[]\n}\n\nconst defaultTestimonials: Testimonial[] = [\n {\n stat: "94%",\n statLabel: "Faster onboarding",\n quote:\n "We got our entire team onboarded in under a day. The intuitive interface and powerful integrations saved us weeks of setup time.",\n author: "Sarah Chen",\n company: "TechFlow Inc",\n },\n {\n stat: "3x",\n statLabel: "Productivity",\n quote:\n "Our team is shipping features faster than ever. The automation tools eliminated hours of manual work every week.",\n author: "Marcus Rivera",\n company: "Beacon Digital",\n },\n {\n stat: "40%",\n statLabel: "Cost reduction",\n quote:\n "We consolidated five different tools into SaaSify. The ROI was immediate and our team loves having everything in one place.",\n author: "David Kim",\n company: "Cascade Systems",\n },\n]\n\nexport function TestimonialsGrid({\n heading = "Loved by teams at companies of all sizes",\n subheading = "See how leading teams use SaaSify to drive growth and productivity.",\n testimonials = defaultTestimonials,\n}: TestimonialsGridProps) {\n const displayTestimonials = testimonials.length > 0 ? testimonials : defaultTestimonials\n\n return (\n <section className="py-16 md:py-24">\n <div className="container mx-auto px-4">\n {/* Header */}\n {(heading || subheading) && (\n <div className="text-center mb-12 md:mb-16 max-w-3xl mx-auto">\n {heading && (\n <h2 className="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight mb-4">\n {heading}\n </h2>\n )}\n {subheading && (\n <p className="text-lg md:text-xl text-muted-foreground">\n {subheading}\n </p>\n )}\n </div>\n )}\n\n {/* Testimonials Grid */}\n <div className="grid md:grid-cols-3 gap-6 lg:gap-8">\n {displayTestimonials.map((testimonial) => (\n <div\n key={testimonial.author}\n className="relative bg-card border border-border rounded-2xl p-6 md:p-8"\n >\n {/* Stat */}\n <div className="mb-6">\n <div className="text-4xl md:text-5xl font-bold text-primary mb-1">\n {testimonial.stat}\n </div>\n <p className="text-sm font-medium text-muted-foreground">\n {testimonial.statLabel}\n </p>\n </div>\n\n {/* Quote */}\n <blockquote className="text-foreground mb-6">\n "{testimonial.quote}"\n </blockquote>\n\n {/* Author */}\n <div className="flex items-center gap-3">\n <div className="w-10 h-10 rounded-full bg-muted flex items-center justify-center">\n <span className="text-sm font-medium">\n {testimonial.author\n .split(" ")\n .map((n) => n[0])\n .join("")}\n </span>\n </div>\n <div>\n <p className="text-sm font-medium text-foreground">\n {testimonial.author}\n </p>\n <p className="text-sm text-muted-foreground">\n {testimonial.company}\n </p>\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n </section>\n )\n}\n',
3117
+ "marketing/nextjs/src/components/blocks/TrustColumns.tsx": '"use client"\n\nimport {\n Award,\n Cloud,\n Database,\n Globe,\n Lock,\n Plug,\n Shield,\n Zap,\n type LucideIcon,\n} from "lucide-react"\nimport { cn } from "@/lib/utils"\n\ninterface TrustItem {\n icon: string\n text: string\n}\n\ninterface TrustColumn {\n label: string\n heading: string\n description: string\n items: TrustItem[]\n}\n\ninterface TrustColumnsProps {\n columns?: TrustColumn[]\n}\n\nconst iconMap: Record<string, LucideIcon> = {\n zap: Zap,\n plug: Plug,\n database: Database,\n cloud: Cloud,\n shield: Shield,\n lock: Lock,\n award: Award,\n globe: Globe,\n}\n\nconst defaultColumns: TrustColumn[] = [\n {\n label: "Integrations",\n heading: "Connect anywhere",\n description:\n "Plug in and get started immediately with pre-built connectors for every major platform.",\n items: [\n { icon: "zap", text: "Go live in minutes" },\n { icon: "plug", text: "Pre-built connectors" },\n { icon: "database", text: "Complete data sync" },\n { icon: "cloud", text: "Cloud-native infrastructure" },\n ],\n },\n {\n label: "Security & Compliance",\n heading: "Enterprise-level security",\n description:\n "Keep your data safe with encryption, granular access control, and compliance-ready infrastructure.",\n items: [\n { icon: "shield", text: "SOC 2 Type II certified" },\n { icon: "lock", text: "End-to-end encryption" },\n { icon: "award", text: "Complete audit trails" },\n { icon: "globe", text: "GDPR compliant" },\n ],\n },\n]\n\nexport function TrustColumns({ columns = defaultColumns }: TrustColumnsProps) {\n const displayColumns = columns.length > 0 ? columns : defaultColumns\n\n return (\n <section className="py-16 md:py-24">\n <div className="container mx-auto px-4">\n <div className="grid md:grid-cols-2 gap-12 lg:gap-16">\n {displayColumns.map((column) => (\n <div key={column.label}>\n <span className="inline-block text-sm font-medium text-primary mb-4">\n {column.label}\n </span>\n <h2 className="text-2xl md:text-3xl font-bold tracking-tight mb-4">\n {column.heading}\n </h2>\n <p className="text-muted-foreground mb-8">\n {column.description}\n </p>\n\n <ul className="space-y-4">\n {column.items.map((item) => {\n const Icon = iconMap[item.icon] || Shield\n return (\n <li key={item.text} className="flex items-center gap-3">\n <div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary/10">\n <Icon className="h-4 w-4 text-primary" />\n </div>\n <span className="text-sm font-medium">\n {item.text}\n </span>\n </li>\n )\n })}\n </ul>\n </div>\n ))}\n </div>\n </div>\n </section>\n )\n}\n',
3118
+ "marketing/nextjs/src/components/blocks/index.ts": 'export { LogoBanner } from "./LogoBanner"\nexport { ProofBanner } from "./ProofBanner"\nexport { BentoFeatures } from "./BentoFeatures"\nexport { FeatureShowcase } from "./FeatureShowcase"\nexport { IndustryTabs } from "./IndustryTabs"\nexport { TestimonialsGrid } from "./TestimonialsGrid"\nexport { TrustColumns } from "./TrustColumns"\nexport { PricingTable } from "./PricingTable"\nexport { FinalCTA } from "./FinalCTA"\n',
3119
+ "marketing/nextjs/src/components/heros/AnimatedMockup.tsx": '"use client"\n\nimport { useEffect, useState } from "react"\nimport { cn } from "@/lib/utils"\n\ninterface MockupState {\n id: number\n label: string\n sidebarActive: string\n previewTitle: string\n previewDescription: string\n previewCategory: string\n previewStatus: "draft" | "published" | "featured"\n previewUrl?: string\n}\n\nconst mockupStates: MockupState[] = [\n {\n id: 1,\n label: "Setup & styling",\n sidebarActive: "templates",\n previewTitle: "Atlas Directory",\n previewDescription: "Apply your brand, typography, and layout in minutes.",\n previewCategory: "Design systems",\n previewStatus: "draft",\n previewUrl: "atlas.directory/home",\n },\n {\n id: 2,\n label: "Plans & pricing",\n sidebarActive: "billing",\n previewTitle: "Pro Listing Plan",\n previewDescription: "Recurring billing, featured placements, and add-ons configured.",\n previewCategory: "Monetization",\n previewStatus: "draft",\n previewUrl: "atlas.directory/billing",\n },\n {\n id: 3,\n label: "SEO & publishing",\n sidebarActive: "seo",\n previewTitle: "Atlas Directory",\n previewDescription: "Schema, sitemap, and custom domain are ready to publish.",\n previewCategory: "SEO & domains",\n previewStatus: "published",\n previewUrl: "atlas.directory/launch",\n },\n {\n id: 4,\n label: "Payouts live",\n sidebarActive: "overview",\n previewTitle: "Atlas Directory",\n previewDescription: "Subscribers active, payouts scheduled to Stripe, featured slots sold.",\n previewCategory: "Revenue",\n previewStatus: "featured",\n previewUrl: "atlas.directory/analytics",\n },\n]\n\ninterface SidebarItemProps {\n icon: string\n label: string\n active?: boolean\n badge?: number\n}\n\nfunction SidebarItem({ icon, label, active, badge }: SidebarItemProps) {\n return (\n <div className={cn("sidebar-item", active && "sidebar-item--active")}>\n <span className="sidebar-icon">{icon}</span>\n <span className="sidebar-label">{label}</span>\n {badge && <span className="sidebar-badge">{badge}</span>}\n </div>\n )\n}\n\nexport function AnimatedMockup() {\n const [currentState, setCurrentState] = useState(0)\n const [isPaused, setIsPaused] = useState(false)\n\n useEffect(() => {\n if (isPaused) return\n\n const interval = setInterval(() => {\n setCurrentState((prev) => (prev + 1) % mockupStates.length)\n }, 3000)\n\n return () => clearInterval(interval)\n }, [isPaused])\n\n const state = mockupStates[currentState]\n\n return (\n <div\n className="mockup-wrapper"\n onMouseEnter={() => setIsPaused(true)}\n onMouseLeave={() => setIsPaused(false)}\n >\n {/* Browser Chrome */}\n <div className="mockup-chrome">\n <div className="mockup-chrome-dots">\n <span className="dot dot-red" />\n <span className="dot dot-yellow" />\n <span className="dot dot-green" />\n </div>\n <div className="mockup-chrome-title">SaaSify</div>\n <div className="mockup-chrome-actions" />\n </div>\n\n {/* App Content */}\n <div className="mockup-content">\n {/* Sidebar */}\n <div className="mockup-sidebar">\n <div className="sidebar-header">\n <div className="sidebar-logo">\n <span className="logo-icon">D</span>\n <span className="logo-text">My Directory</span>\n </div>\n </div>\n <nav className="sidebar-nav">\n <SidebarItem icon="\u{1F4CA}" label="Overview" active={state.sidebarActive === "overview"} />\n <SidebarItem icon="\u{1F5BC}\uFE0F" label="Templates" active={state.sidebarActive === "templates"} />\n <SidebarItem\n icon="\u{1F4CB}"\n label="Listings"\n active={state.sidebarActive === "listings"}\n badge={24}\n />\n <SidebarItem\n icon="\u{1F4B3}"\n label="Plans & Billing"\n active={state.sidebarActive === "billing"}\n />\n <SidebarItem\n icon="\u26A1"\n label="Automations"\n active={state.sidebarActive === "automations"}\n />\n <SidebarItem icon="\u{1F50E}" label="SEO" active={state.sidebarActive === "seo"} />\n <SidebarItem icon="\u2699\uFE0F" label="Settings" active={state.sidebarActive === "settings"} />\n </nav>\n </div>\n\n {/* Main Content Area */}\n <div className="mockup-main">\n {/* Header */}\n <div className="main-header">\n <div className="header-title">\n <h2>{state.label}</h2>\n <span className="header-breadcrumb">SaaSify / {state.previewTitle}</span>\n </div>\n <div className="header-actions">\n <button\n type="button"\n className={cn(\n "action-btn",\n state.previewStatus === "published" && "action-btn--success",\n state.previewStatus === "featured" && "action-btn--featured"\n )}\n >\n {state.previewStatus === "draft" && "Save Draft"}\n {state.previewStatus === "published" && "\u2713 Published"}\n {state.previewStatus === "featured" && "\u2B50 Featured"}\n </button>\n </div>\n </div>\n\n {/* Split View: Editor + Preview */}\n <div className="main-split">\n {/* Editor Panel */}\n <div className="editor-panel">\n <div className="editor-section">\n <span className="editor-label">Listing Name</span>\n <div className="editor-input">\n <span className="input-text">{state.previewTitle}</span>\n <span className="input-cursor" />\n </div>\n </div>\n <div className="editor-section">\n <span className="editor-label">Category</span>\n <div className="editor-select">\n <span>{state.previewCategory}</span>\n <span className="select-arrow">\u25BC</span>\n </div>\n </div>\n <div className="editor-section">\n <span className="editor-label">Description</span>\n <div className="editor-textarea">\n <span className={cn("textarea-text", state.id >= 2 && "textarea-text--complete")}>\n {state.previewDescription}\n </span>\n </div>\n </div>\n </div>\n\n {/* Preview Panel */}\n <div className="preview-panel">\n <div className="preview-header">\n <span className="preview-label">Live Preview</span>\n <span className="preview-url">{state.previewUrl ?? "saasify.app/live"}</span>\n </div>\n <div className="preview-card">\n {state.previewStatus === "featured" && (\n <div className="preview-badge">\u2B50 Featured</div>\n )}\n <div className="preview-image">\n <div className="preview-image-placeholder">\n <span>\u{1F3E2}</span>\n </div>\n </div>\n <div className="preview-content">\n <span className="preview-category-tag">{state.previewCategory}</span>\n <h3 className="preview-title">{state.previewTitle}</h3>\n <p className="preview-description">{state.previewDescription}</p>\n <div className="preview-meta">\n <span className="meta-rating">\u2605\u2605\u2605\u2605\u2605</span>\n <span className="meta-reviews">24 reviews</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n {/* State Indicator */}\n <div className="mockup-indicators">\n {mockupStates.map((s, i) => (\n <button\n type="button"\n key={s.id}\n onClick={() => setCurrentState(i)}\n className={cn("indicator", i === currentState && "indicator--active")}\n >\n <span className="indicator-dot" />\n <span className="indicator-label">{s.label}</span>\n </button>\n ))}\n </div>\n </div>\n )\n}\n',
3120
+ "marketing/nextjs/src/components/heros/ProductShowcaseHero.tsx": '"use client"\n\nimport Link from "next/link"\nimport Image from "next/image"\nimport { AnimatedMockup } from "./AnimatedMockup"\nimport { cn } from "@/lib/utils"\n\ninterface HeroLink {\n label: string\n href: string\n variant: "default" | "outline"\n}\n\ninterface ProductShowcaseHeroProps {\n headline: string\n description: string\n links?: HeroLink[]\n}\n\nexport function ProductShowcaseHero({\n headline = "The modern platform for growing teams",\n description = "Streamline workflows, boost productivity, and scale your business with one powerful platform.",\n links = [\n { label: "Start free trial", href: "/sign-up", variant: "default" },\n { label: "Watch demo", href: "/demo", variant: "outline" },\n ],\n}: ProductShowcaseHeroProps) {\n return (\n <div className="relative overflow-hidden">\n {/* Hero Content - Left Aligned */}\n <div className="container mx-auto px-4 pt-8 pb-16 md:pt-16 md:pb-24">\n <div className="max-w-2xl">\n <h1 className="text-4xl font-bold tracking-tight text-foreground sm:text-5xl md:text-6xl">\n {headline}\n </h1>\n <p className="mt-6 text-lg text-muted-foreground md:text-xl">\n {description}\n </p>\n {links && links.length > 0 && (\n <div className="mt-8 flex flex-wrap gap-4">\n {links.map((link) => (\n <Link\n key={link.href}\n href={link.href}\n className={cn(\n "inline-flex items-center justify-center px-6 py-3 text-sm font-medium rounded-md transition-colors",\n link.variant === "default"\n ? "bg-primary text-primary-foreground hover:bg-primary/90"\n : "border border-border bg-background hover:bg-muted"\n )}\n >\n {link.label}\n </Link>\n ))}\n </div>\n )}\n </div>\n </div>\n\n {/* Product Mockup Section */}\n <div className="container mx-auto px-4">\n <div className="hero-showcase">\n {/* Background Image */}\n <div className="hero-bg-image">\n <Image\n src="/media/hero-bg.png"\n alt=""\n fill\n sizes="(max-width: 1280px) 100vw, 1280px"\n className="object-cover"\n priority\n quality={75}\n />\n </div>\n\n {/* Mockup - centered within background */}\n <div className="hero-mockup-centered">\n <AnimatedMockup />\n </div>\n </div>\n </div>\n </div>\n )\n}\n',
3121
+ "marketing/nextjs/src/components/heros/index.ts": 'export { ProductShowcaseHero } from "./ProductShowcaseHero"\nexport { AnimatedMockup } from "./AnimatedMockup"\n',
3122
+ "marketing/nextjs/src/lib/utils.ts": 'import { type ClassValue, clsx } from "clsx"\nimport { twMerge } from "tailwind-merge"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n',
1368
3123
  "marketing/nextjs/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": "react-jsx",\n "incremental": true,\n "plugins": [{ "name": "next" }],\n "paths": {\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',
1369
3124
  "marketing/payload/_env.example.hbs": `# Database (Supabase PostgreSQL)
1370
3125
  DATABASE_URL="postgresql://postgres:[PASSWORD]@db.[PROJECT].supabase.co:5432/postgres"
@@ -10534,6 +12289,8 @@ async function generateVirtualProject(config) {
10534
12289
  await processPayloadTemplates(vfs, config);
10535
12290
  } else if (config.marketingSite === "nextjs") {
10536
12291
  await processMarketingTemplates(vfs, config);
12292
+ } else if (config.marketingSite === "astro") {
12293
+ await processAstroMarketingTemplates(vfs, config);
10537
12294
  }
10538
12295
  if (config.optionalApps?.includes("design-system")) {
10539
12296
  await processDesignSystemTemplates(vfs, config);
@@ -10611,6 +12368,9 @@ async function processPayloadTemplates(vfs, config) {
10611
12368
  async function processMarketingTemplates(vfs, config) {
10612
12369
  processTemplatesFromPrefix(vfs, "marketing/nextjs/", "/apps/marketing", config);
10613
12370
  }
12371
+ async function processAstroMarketingTemplates(vfs, config) {
12372
+ processTemplatesFromPrefix(vfs, "marketing/astro/", "/apps/marketing", config);
12373
+ }
10614
12374
  async function processDesignSystemTemplates(vfs, config) {
10615
12375
  processTemplatesFromPrefix(vfs, "design-system/", "/apps/design-system", config);
10616
12376
  }