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
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from 'astro/config'
2
+ import tailwindcss from '@tailwindcss/postcss'
3
+
4
+ export default defineConfig({
5
+ vite: {
6
+ css: {
7
+ postcss: {
8
+ plugins: [tailwindcss()],
9
+ },
10
+ },
11
+ },
12
+ })
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@repo/marketing",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "astro dev --port 3000",
8
+ "build": "astro build",
9
+ "preview": "astro preview",
10
+ "astro": "astro",
11
+ "lint": "biome check .",
12
+ "lint:fix": "biome check --write .",
13
+ "typecheck": "astro check && tsc --noEmit"
14
+ },
15
+ "dependencies": {
16
+ "astro": "^5.1.6",
17
+ "lucide-astro": "^0.468.0",
18
+ "clsx": "^2.1.1",
19
+ "tailwind-merge": "^2.6.0"
20
+ },
21
+ "devDependencies": {
22
+ "@astrojs/check": "^0.9.4",
23
+ "@astrojs/tailwind": "^6.0.2",
24
+ "@repo/config-typescript": "workspace:*",
25
+ "@types/node": "^20.0.0",
26
+ "tailwindcss": "^4.0.0",
27
+ "@tailwindcss/postcss": "^4.0.0",
28
+ "postcss": "^8.4.0",
29
+ "typescript": "^5.0.0"
30
+ }
31
+ }
@@ -0,0 +1,5 @@
1
+ export default {
2
+ plugins: {
3
+ '@tailwindcss/postcss': {},
4
+ },
5
+ }
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
2
+ <rect width="32" height="32" rx="6" fill="#0a0a0a"/>
3
+ <path d="M17.33 5L9 18.67h8L16 27l9-12h-8l1-10z" fill="none" stroke="#fafafa" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
4
+ </svg>
@@ -0,0 +1 @@
1
+ placeholder
@@ -0,0 +1,167 @@
1
+ ---
2
+ import Logo from "./Logo.astro"
3
+ import ThemeSelector from "./ThemeSelector.astro"
4
+
5
+ const footerColumns = [
6
+ {
7
+ title: "Product",
8
+ links: [
9
+ { label: "Home", href: "/" },
10
+ { label: "Pricing", href: "/pricing" },
11
+ { label: "Integrations", href: "/features/integrations" },
12
+ ],
13
+ },
14
+ {
15
+ title: "Resources",
16
+ links: [
17
+ { label: "Blog", href: "/blog" },
18
+ { label: "Documentation", href: "/docs" },
19
+ ],
20
+ },
21
+ {
22
+ title: "Company",
23
+ links: [
24
+ { label: "About", href: "/about" },
25
+ ],
26
+ },
27
+ {
28
+ title: "Legal",
29
+ links: [
30
+ { label: "Privacy", href: "/privacy" },
31
+ { label: "Terms", href: "/terms" },
32
+ ],
33
+ },
34
+ ]
35
+
36
+ const socialLinks = {
37
+ twitter: "https://x.com/saasify",
38
+ linkedin: "https://linkedin.com/company/saasify",
39
+ github: "https://github.com/saasify",
40
+ }
41
+
42
+ const bottomLinks = [
43
+ { label: "Contact Support", href: "/support" },
44
+ ]
45
+
46
+ const currentYear = new Date().getFullYear()
47
+ ---
48
+
49
+ <footer class="mt-auto border-t border-border bg-background">
50
+ <!-- Main Footer Content -->
51
+ <div class="container mx-auto px-4 py-12 lg:py-16">
52
+ <div class="grid grid-cols-2 gap-8 md:grid-cols-3 lg:grid-cols-6">
53
+ <!-- Link Columns -->
54
+ {footerColumns.map((column) => (
55
+ <div class="col-span-1">
56
+ <h3 class="mb-4 text-sm font-medium text-foreground">
57
+ {column.title}
58
+ </h3>
59
+ <ul class="space-y-3">
60
+ {column.links.map((link) => (
61
+ <li>
62
+ <a
63
+ href={link.href}
64
+ class="text-sm text-muted-foreground transition-colors hover:text-foreground"
65
+ >
66
+ {link.label}
67
+ </a>
68
+ </li>
69
+ ))}
70
+ </ul>
71
+ </div>
72
+ ))}
73
+
74
+ <!-- Newsletter Column -->
75
+ <div class="col-span-2 md:col-span-3 lg:col-span-2">
76
+ <h3 class="mb-4 text-sm font-medium text-foreground">
77
+ Newsletter
78
+ </h3>
79
+ <p class="mb-4 text-sm text-muted-foreground">
80
+ Get product updates, tips, and insights delivered weekly.
81
+ </p>
82
+ <form class="flex gap-2">
83
+ <input
84
+ type="email"
85
+ placeholder="Enter your email"
86
+ 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"
87
+ />
88
+ <button
89
+ type="submit"
90
+ class="px-4 py-2 text-sm font-medium rounded-md bg-primary text-primary-foreground hover:bg-primary/90"
91
+ >
92
+ Subscribe
93
+ </button>
94
+ </form>
95
+ </div>
96
+ </div>
97
+
98
+ <!-- Social Links -->
99
+ <div class="mt-10 flex items-center gap-4 border-t border-border pt-8">
100
+ <a
101
+ href={socialLinks.twitter}
102
+ target="_blank"
103
+ rel="noopener noreferrer"
104
+ class="text-muted-foreground transition-colors hover:text-foreground"
105
+ aria-label="X (Twitter)"
106
+ >
107
+ <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
108
+ <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" />
109
+ </svg>
110
+ </a>
111
+ <a
112
+ href={socialLinks.linkedin}
113
+ target="_blank"
114
+ rel="noopener noreferrer"
115
+ class="text-muted-foreground transition-colors hover:text-foreground"
116
+ aria-label="LinkedIn"
117
+ >
118
+ <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
119
+ <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" />
120
+ </svg>
121
+ </a>
122
+ <a
123
+ href={socialLinks.github}
124
+ target="_blank"
125
+ rel="noopener noreferrer"
126
+ class="text-muted-foreground transition-colors hover:text-foreground"
127
+ aria-label="GitHub"
128
+ >
129
+ <svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
130
+ <path
131
+ fill-rule="evenodd"
132
+ 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"
133
+ clip-rule="evenodd"
134
+ />
135
+ </svg>
136
+ </a>
137
+ </div>
138
+ </div>
139
+
140
+ <!-- Bottom Bar -->
141
+ <div class="border-t border-border">
142
+ <div class="container mx-auto flex flex-col items-center justify-between gap-4 px-4 py-6 sm:flex-row">
143
+ <!-- Logo and Copyright -->
144
+ <div class="flex items-center gap-4">
145
+ <a href="/" class="flex items-center">
146
+ <Logo class="h-6 w-6" />
147
+ </a>
148
+ <p class="text-sm text-muted-foreground">
149
+ &copy; {currentYear} SaaSify
150
+ </p>
151
+ </div>
152
+
153
+ <!-- Bottom Links and Theme Selector -->
154
+ <div class="flex items-center gap-6">
155
+ {bottomLinks.map((link) => (
156
+ <a
157
+ href={link.href}
158
+ class="text-sm text-muted-foreground transition-colors hover:text-foreground"
159
+ >
160
+ {link.label}
161
+ </a>
162
+ ))}
163
+ <ThemeSelector />
164
+ </div>
165
+ </div>
166
+ </div>
167
+ </footer>
@@ -0,0 +1,378 @@
1
+ ---
2
+ import Logo from "./Logo.astro"
3
+ import { ChevronDown, Menu, X, Layout, BarChart3, Shield, Zap, Layers, Target, Rocket, Settings } from "lucide-astro"
4
+
5
+ // Navigation data structure matching SaaSify
6
+ const productMenu = {
7
+ label: "Product",
8
+ columns: [
9
+ {
10
+ title: "Core Features",
11
+ items: [
12
+ { label: "Integrations", description: "Connect with 100+ tools you already use", href: "/features/integrations", icon: "layout" },
13
+ { label: "Analytics", description: "Real-time insights and reporting dashboards", href: "/features/analytics", icon: "barChart" },
14
+ { label: "Security", description: "Enterprise-grade protection and compliance", href: "/features/security", icon: "shield" },
15
+ ],
16
+ },
17
+ {
18
+ title: "Productivity",
19
+ items: [
20
+ { label: "Dashboard", description: "Unified command center for your team", href: "/features/dashboard", icon: "layout" },
21
+ { label: "Automation", description: "Streamline repetitive tasks instantly", href: "/features/automation", icon: "zap" },
22
+ { label: "Workflows", description: "Build custom processes without code", href: "/features/workflows", icon: "layers" },
23
+ ],
24
+ },
25
+ ],
26
+ }
27
+
28
+ const solutionsMenu = {
29
+ label: "Solutions",
30
+ columns: [
31
+ {
32
+ title: "By Team",
33
+ items: [
34
+ { label: "Sales Teams", description: "Close deals faster with smart tools", href: "/use-cases/sales", icon: "target" },
35
+ { label: "Marketing Teams", description: "Launch campaigns that convert", href: "/use-cases/marketing", icon: "rocket" },
36
+ { label: "Product Teams", description: "Ship features users love", href: "/use-cases/product", icon: "layers" },
37
+ { label: "Operations", description: "Scale without the growing pains", href: "/use-cases/operations", icon: "settings" },
38
+ ],
39
+ },
40
+ ],
41
+ }
42
+
43
+ const navLinks = [
44
+ { label: "Pricing", href: "/pricing" },
45
+ { label: "Blog", href: "/blog" },
46
+ ]
47
+
48
+ const ctaLinks = [
49
+ { label: "Sign In", href: "/sign-in", variant: "ghost" },
50
+ { label: "Get Started", href: "/sign-up", variant: "default" },
51
+ ]
52
+ ---
53
+
54
+ <header class="sticky top-0 z-50 border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
55
+ <div class="container mx-auto px-4 h-16 flex justify-between items-center">
56
+ <!-- Left section: Logo + Nav -->
57
+ <div class="flex items-center gap-8">
58
+ <a href="/" class="flex items-center gap-2">
59
+ <Logo />
60
+ <span class="text-xl font-semibold hidden sm:inline">SaaSify</span>
61
+ </a>
62
+
63
+ <!-- Desktop navigation -->
64
+ <nav class="hidden lg:flex items-center gap-1">
65
+ <!-- Product Menu -->
66
+ <div class="mega-menu-trigger relative" data-menu="product">
67
+ <button
68
+ type="button"
69
+ class="flex items-center gap-1 px-4 py-2 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors"
70
+ >
71
+ {productMenu.label}
72
+ <ChevronDown class="h-4 w-4 transition-transform mega-chevron" />
73
+ </button>
74
+ <div class="mega-menu-dropdown absolute left-0 top-full pt-2 opacity-0 -translate-y-2 pointer-events-none transition-all">
75
+ <div class="bg-background border border-border rounded-lg shadow-lg p-6 min-w-[480px]">
76
+ <div class="grid gap-8 grid-cols-2">
77
+ {productMenu.columns.map((column) => (
78
+ <div>
79
+ <h3 class="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-4">
80
+ {column.title}
81
+ </h3>
82
+ <ul class="space-y-1">
83
+ {column.items.map((item) => (
84
+ <li>
85
+ <a
86
+ href={item.href}
87
+ class="flex items-start gap-3 p-3 rounded-lg hover:bg-muted transition-colors group"
88
+ >
89
+ <div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-md bg-muted group-hover:bg-background">
90
+ {item.icon === "layout" && <Layout class="h-5 w-5 text-primary" />}
91
+ {item.icon === "barChart" && <BarChart3 class="h-5 w-5 text-primary" />}
92
+ {item.icon === "shield" && <Shield class="h-5 w-5 text-primary" />}
93
+ {item.icon === "zap" && <Zap class="h-5 w-5 text-primary" />}
94
+ {item.icon === "layers" && <Layers class="h-5 w-5 text-primary" />}
95
+ </div>
96
+ <div>
97
+ <div class="text-sm font-medium text-foreground">{item.label}</div>
98
+ <div class="text-xs text-muted-foreground mt-0.5">{item.description}</div>
99
+ </div>
100
+ </a>
101
+ </li>
102
+ ))}
103
+ </ul>
104
+ </div>
105
+ ))}
106
+ </div>
107
+ </div>
108
+ </div>
109
+ </div>
110
+
111
+ <!-- Solutions Menu -->
112
+ <div class="mega-menu-trigger relative" data-menu="solutions">
113
+ <button
114
+ type="button"
115
+ class="flex items-center gap-1 px-4 py-2 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors"
116
+ >
117
+ {solutionsMenu.label}
118
+ <ChevronDown class="h-4 w-4 transition-transform mega-chevron" />
119
+ </button>
120
+ <div class="mega-menu-dropdown absolute left-0 top-full pt-2 opacity-0 -translate-y-2 pointer-events-none transition-all">
121
+ <div class="bg-background border border-border rounded-lg shadow-lg p-6 min-w-[320px]">
122
+ <div class="grid gap-8 grid-cols-1">
123
+ {solutionsMenu.columns.map((column) => (
124
+ <div>
125
+ <h3 class="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-4">
126
+ {column.title}
127
+ </h3>
128
+ <ul class="space-y-1">
129
+ {column.items.map((item) => (
130
+ <li>
131
+ <a
132
+ href={item.href}
133
+ class="flex items-start gap-3 p-3 rounded-lg hover:bg-muted transition-colors group"
134
+ >
135
+ <div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-md bg-muted group-hover:bg-background">
136
+ {item.icon === "target" && <Target class="h-5 w-5 text-primary" />}
137
+ {item.icon === "rocket" && <Rocket class="h-5 w-5 text-primary" />}
138
+ {item.icon === "layers" && <Layers class="h-5 w-5 text-primary" />}
139
+ {item.icon === "settings" && <Settings class="h-5 w-5 text-primary" />}
140
+ </div>
141
+ <div>
142
+ <div class="text-sm font-medium text-foreground">{item.label}</div>
143
+ <div class="text-xs text-muted-foreground mt-0.5">{item.description}</div>
144
+ </div>
145
+ </a>
146
+ </li>
147
+ ))}
148
+ </ul>
149
+ </div>
150
+ ))}
151
+ </div>
152
+ </div>
153
+ </div>
154
+ </div>
155
+
156
+ {navLinks.map((link) => (
157
+ <a
158
+ href={link.href}
159
+ class="px-4 py-2 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors"
160
+ >
161
+ {link.label}
162
+ </a>
163
+ ))}
164
+ </nav>
165
+ </div>
166
+
167
+ <!-- Right section: CTAs -->
168
+ <div class="flex items-center gap-3">
169
+ <!-- Desktop CTAs -->
170
+ <div class="hidden lg:flex items-center gap-3">
171
+ {ctaLinks.map((link) => (
172
+ <a
173
+ href={link.href}
174
+ class:list={[
175
+ "px-4 py-2 text-sm font-medium rounded-md transition-colors",
176
+ link.variant === "default"
177
+ ? "bg-primary text-primary-foreground hover:bg-primary/90"
178
+ : "text-muted-foreground hover:text-foreground"
179
+ ]}
180
+ >
181
+ {link.label}
182
+ </a>
183
+ ))}
184
+ </div>
185
+
186
+ <!-- Mobile: Primary CTA + Hamburger -->
187
+ <a
188
+ href="/sign-up"
189
+ class="lg:hidden px-4 py-2 text-sm font-medium rounded-md bg-primary text-primary-foreground hover:bg-primary/90"
190
+ >
191
+ Get Started
192
+ </a>
193
+
194
+ <button
195
+ type="button"
196
+ id="mobile-menu-toggle"
197
+ class="lg:hidden p-2 text-muted-foreground hover:text-foreground"
198
+ aria-label="Toggle menu"
199
+ >
200
+ <Menu class="h-6 w-6 menu-open-icon" />
201
+ <X class="h-6 w-6 menu-close-icon hidden" />
202
+ </button>
203
+ </div>
204
+ </div>
205
+ </header>
206
+
207
+ <!-- Mobile Menu Overlay -->
208
+ <div id="mobile-menu" class="fixed inset-0 top-16 z-50 bg-background hidden lg:hidden">
209
+ <nav class="overflow-y-auto max-h-[calc(100vh-4rem)]">
210
+ <!-- Product Section -->
211
+ <div class="mobile-section border-b border-border" data-section="product">
212
+ <button
213
+ type="button"
214
+ class="flex items-center justify-between w-full px-4 py-3 text-sm font-medium"
215
+ >
216
+ Product
217
+ <ChevronDown class="h-4 w-4 transition-transform section-chevron" />
218
+ </button>
219
+ <div class="mobile-section-content hidden px-4 pb-4 space-y-4">
220
+ {productMenu.columns.map((column) => (
221
+ <div>
222
+ <h4 class="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">
223
+ {column.title}
224
+ </h4>
225
+ <ul class="space-y-1">
226
+ {column.items.map((item) => (
227
+ <li>
228
+ <a href={item.href} class="flex items-center gap-3 p-2 rounded-lg hover:bg-muted">
229
+ {item.icon === "layout" && <Layout class="h-4 w-4 text-primary" />}
230
+ {item.icon === "barChart" && <BarChart3 class="h-4 w-4 text-primary" />}
231
+ {item.icon === "shield" && <Shield class="h-4 w-4 text-primary" />}
232
+ {item.icon === "zap" && <Zap class="h-4 w-4 text-primary" />}
233
+ {item.icon === "layers" && <Layers class="h-4 w-4 text-primary" />}
234
+ <span class="text-sm">{item.label}</span>
235
+ </a>
236
+ </li>
237
+ ))}
238
+ </ul>
239
+ </div>
240
+ ))}
241
+ </div>
242
+ </div>
243
+
244
+ <!-- Solutions Section -->
245
+ <div class="mobile-section border-b border-border" data-section="solutions">
246
+ <button
247
+ type="button"
248
+ class="flex items-center justify-between w-full px-4 py-3 text-sm font-medium"
249
+ >
250
+ Solutions
251
+ <ChevronDown class="h-4 w-4 transition-transform section-chevron" />
252
+ </button>
253
+ <div class="mobile-section-content hidden px-4 pb-4 space-y-4">
254
+ {solutionsMenu.columns.map((column) => (
255
+ <div>
256
+ <h4 class="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">
257
+ {column.title}
258
+ </h4>
259
+ <ul class="space-y-1">
260
+ {column.items.map((item) => (
261
+ <li>
262
+ <a href={item.href} class="flex items-center gap-3 p-2 rounded-lg hover:bg-muted">
263
+ {item.icon === "target" && <Target class="h-4 w-4 text-primary" />}
264
+ {item.icon === "rocket" && <Rocket class="h-4 w-4 text-primary" />}
265
+ {item.icon === "layers" && <Layers class="h-4 w-4 text-primary" />}
266
+ {item.icon === "settings" && <Settings class="h-4 w-4 text-primary" />}
267
+ <span class="text-sm">{item.label}</span>
268
+ </a>
269
+ </li>
270
+ ))}
271
+ </ul>
272
+ </div>
273
+ ))}
274
+ </div>
275
+ </div>
276
+
277
+ <!-- Simple nav links -->
278
+ {navLinks.map((link) => (
279
+ <a
280
+ href={link.href}
281
+ class="flex items-center px-4 py-3 text-sm font-medium border-b border-border hover:bg-muted"
282
+ >
283
+ {link.label}
284
+ </a>
285
+ ))}
286
+
287
+ <!-- CTA links -->
288
+ <div class="p-4 space-y-2">
289
+ {ctaLinks.map((link) => (
290
+ <a
291
+ href={link.href}
292
+ class:list={[
293
+ "flex items-center justify-center w-full px-4 py-3 text-sm font-medium rounded-md transition-colors",
294
+ link.variant === "default"
295
+ ? "bg-primary text-primary-foreground hover:bg-primary/90"
296
+ : "border border-border hover:bg-muted"
297
+ ]}
298
+ >
299
+ {link.label}
300
+ </a>
301
+ ))}
302
+ </div>
303
+ </nav>
304
+ </div>
305
+
306
+ <script>
307
+ function initHeader() {
308
+ // Desktop mega menu
309
+ const megaMenuTriggers = document.querySelectorAll('.mega-menu-trigger')
310
+ megaMenuTriggers.forEach((trigger) => {
311
+ const dropdown = trigger.querySelector('.mega-menu-dropdown')
312
+ const chevron = trigger.querySelector('.mega-chevron')
313
+
314
+ trigger.addEventListener('mouseenter', () => {
315
+ dropdown?.classList.remove('opacity-0', '-translate-y-2', 'pointer-events-none')
316
+ dropdown?.classList.add('opacity-100', 'translate-y-0', 'pointer-events-auto')
317
+ chevron?.classList.add('rotate-180')
318
+ })
319
+
320
+ trigger.addEventListener('mouseleave', () => {
321
+ dropdown?.classList.add('opacity-0', '-translate-y-2', 'pointer-events-none')
322
+ dropdown?.classList.remove('opacity-100', 'translate-y-0', 'pointer-events-auto')
323
+ chevron?.classList.remove('rotate-180')
324
+ })
325
+ })
326
+
327
+ // Mobile menu toggle
328
+ const mobileToggle = document.getElementById('mobile-menu-toggle')
329
+ const mobileMenu = document.getElementById('mobile-menu')
330
+ const openIcon = mobileToggle?.querySelector('.menu-open-icon')
331
+ const closeIcon = mobileToggle?.querySelector('.menu-close-icon')
332
+
333
+ mobileToggle?.addEventListener('click', () => {
334
+ const isOpen = !mobileMenu?.classList.contains('hidden')
335
+ if (isOpen) {
336
+ mobileMenu?.classList.add('hidden')
337
+ openIcon?.classList.remove('hidden')
338
+ closeIcon?.classList.add('hidden')
339
+ } else {
340
+ mobileMenu?.classList.remove('hidden')
341
+ openIcon?.classList.add('hidden')
342
+ closeIcon?.classList.remove('hidden')
343
+ }
344
+ })
345
+
346
+ // Mobile sections toggle
347
+ const mobileSections = document.querySelectorAll('.mobile-section')
348
+ mobileSections.forEach((section) => {
349
+ const button = section.querySelector('button')
350
+ const content = section.querySelector('.mobile-section-content')
351
+ const chevron = section.querySelector('.section-chevron')
352
+
353
+ button?.addEventListener('click', () => {
354
+ const isOpen = !content?.classList.contains('hidden')
355
+ if (isOpen) {
356
+ content?.classList.add('hidden')
357
+ chevron?.classList.remove('rotate-180')
358
+ } else {
359
+ content?.classList.remove('hidden')
360
+ chevron?.classList.add('rotate-180')
361
+ }
362
+ })
363
+ })
364
+
365
+ // Close mobile menu on link click
366
+ const mobileLinks = mobileMenu?.querySelectorAll('a')
367
+ mobileLinks?.forEach((link) => {
368
+ link.addEventListener('click', () => {
369
+ mobileMenu?.classList.add('hidden')
370
+ openIcon?.classList.remove('hidden')
371
+ closeIcon?.classList.add('hidden')
372
+ })
373
+ })
374
+ }
375
+
376
+ initHeader()
377
+ document.addEventListener('astro:after-swap', initHeader)
378
+ </script>
@@ -0,0 +1,30 @@
1
+ ---
2
+ interface Props {
3
+ class?: string
4
+ }
5
+
6
+ const { class: className } = Astro.props
7
+ ---
8
+
9
+ <div class:list={["flex h-8 w-8 items-center justify-center rounded-lg bg-foreground logo-container", className]}>
10
+ <svg
11
+ class="h-5 w-5 text-background"
12
+ viewBox="0 0 24 24"
13
+ fill="none"
14
+ stroke="currentColor"
15
+ stroke-width="2"
16
+ stroke-linecap="round"
17
+ stroke-linejoin="round"
18
+ >
19
+ <path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"></path>
20
+ </svg>
21
+ </div>
22
+
23
+ <style>
24
+ :global([data-theme="dark"]) .logo-container {
25
+ background-color: white;
26
+ }
27
+ :global([data-theme="dark"]) .logo-container svg {
28
+ color: #0a0a0a;
29
+ }
30
+ </style>