kofi-stack-template-generator 2.1.52 → 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 (30) hide show
  1. package/.turbo/turbo-build.log +6 -6
  2. package/dist/index.js +1560 -0
  3. package/package.json +2 -2
  4. package/src/generator.ts +9 -0
  5. package/src/templates.generated.ts +27 -2
  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
@@ -0,0 +1,102 @@
1
+ ---
2
+ import { Check } from "lucide-astro"
3
+
4
+ interface Props {
5
+ label?: string
6
+ headline: string
7
+ description: string
8
+ features?: { text: string }[]
9
+ link?: {
10
+ label: string
11
+ href: string
12
+ }
13
+ imagePosition?: "left" | "right"
14
+ }
15
+
16
+ const {
17
+ label,
18
+ headline,
19
+ description,
20
+ features = [],
21
+ link,
22
+ imagePosition = "right",
23
+ } = Astro.props
24
+ ---
25
+
26
+ <section class="py-16 md:py-24">
27
+ <div class="container mx-auto px-4">
28
+ <div class:list={[
29
+ "grid md:grid-cols-2 gap-12 lg:gap-16 items-center",
30
+ imagePosition === "left" && "md:grid-flow-dense"
31
+ ]}>
32
+ <!-- Content -->
33
+ <div class:list={[imagePosition === "left" && "md:col-start-2"]}>
34
+ {label && (
35
+ <span class="inline-block text-sm font-medium text-primary mb-4">
36
+ {label}
37
+ </span>
38
+ )}
39
+ <h2 class="text-3xl md:text-4xl font-bold tracking-tight mb-4">
40
+ {headline}
41
+ </h2>
42
+ <p class="text-lg text-muted-foreground mb-6">
43
+ {description}
44
+ </p>
45
+
46
+ {features.length > 0 && (
47
+ <ul class="space-y-3 mb-8">
48
+ {features.map((feature) => (
49
+ <li class="flex items-center gap-3">
50
+ <div class="flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-primary/10">
51
+ <Check class="h-3 w-3 text-primary" />
52
+ </div>
53
+ <span class="text-sm text-muted-foreground">
54
+ {feature.text}
55
+ </span>
56
+ </li>
57
+ ))}
58
+ </ul>
59
+ )}
60
+
61
+ {link && (
62
+ <a
63
+ href={link.href}
64
+ class="inline-flex items-center gap-2 text-sm font-medium text-primary hover:underline"
65
+ >
66
+ {link.label}
67
+ <span aria-hidden="true">&rarr;</span>
68
+ </a>
69
+ )}
70
+ </div>
71
+
72
+ <!-- Image Placeholder -->
73
+ <div class:list={[
74
+ "relative aspect-[4/3] rounded-2xl bg-muted overflow-hidden",
75
+ imagePosition === "left" && "md:col-start-1 md:row-start-1"
76
+ ]}>
77
+ <div class="absolute inset-0 flex items-center justify-center">
78
+ <div class="text-center">
79
+ <div class="w-16 h-16 mx-auto mb-4 rounded-xl bg-primary/10 flex items-center justify-center">
80
+ <svg
81
+ class="w-8 h-8 text-primary"
82
+ fill="none"
83
+ stroke="currentColor"
84
+ viewBox="0 0 24 24"
85
+ >
86
+ <path
87
+ stroke-linecap="round"
88
+ stroke-linejoin="round"
89
+ stroke-width="1.5"
90
+ 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"
91
+ />
92
+ </svg>
93
+ </div>
94
+ <p class="text-sm text-muted-foreground">
95
+ Feature illustration
96
+ </p>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ </div>
101
+ </div>
102
+ </section>
@@ -0,0 +1,82 @@
1
+ ---
2
+ interface FinalCTALink {
3
+ label: string
4
+ href: string
5
+ variant: "default" | "outline"
6
+ }
7
+
8
+ interface Props {
9
+ headline?: string
10
+ subheading?: string
11
+ links?: FinalCTALink[]
12
+ style?: "dark" | "light" | "gradient"
13
+ }
14
+
15
+ const {
16
+ headline = "Ready to transform how your team works?",
17
+ subheading = "Join thousands of teams who chose the smarter way to work. Start free, upgrade as you grow.",
18
+ links = [
19
+ { label: "Start free trial", href: "/sign-up", variant: "outline" },
20
+ { label: "Book a demo", href: "/contact", variant: "default" },
21
+ ],
22
+ style = "dark",
23
+ } = Astro.props
24
+
25
+ const bgClasses = {
26
+ dark: "bg-foreground text-background",
27
+ light: "bg-muted text-foreground",
28
+ gradient: "bg-gradient-to-br from-primary to-primary/80 text-primary-foreground",
29
+ }
30
+
31
+ const buttonClasses = {
32
+ dark: {
33
+ default: "bg-background text-foreground hover:bg-background/90",
34
+ outline: "border border-background/30 text-background hover:bg-background/10",
35
+ },
36
+ light: {
37
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
38
+ outline: "border border-border hover:bg-background",
39
+ },
40
+ gradient: {
41
+ default: "bg-background text-foreground hover:bg-background/90",
42
+ outline: "border border-primary-foreground/30 text-primary-foreground hover:bg-primary-foreground/10",
43
+ },
44
+ }
45
+
46
+ const subtextClasses = {
47
+ dark: "text-background/80",
48
+ light: "text-muted-foreground",
49
+ gradient: "text-primary-foreground/80",
50
+ }
51
+ ---
52
+
53
+ <section class:list={["py-16 md:py-24", bgClasses[style]]}>
54
+ <div class="container mx-auto px-4">
55
+ <div class="max-w-3xl mx-auto text-center">
56
+ <h2 class="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight mb-6">
57
+ {headline}
58
+ </h2>
59
+ {subheading && (
60
+ <p class:list={["text-lg md:text-xl mb-8", subtextClasses[style]]}>
61
+ {subheading}
62
+ </p>
63
+ )}
64
+
65
+ {links && links.length > 0 && (
66
+ <div class="flex flex-wrap gap-4 justify-center">
67
+ {links.map((link) => (
68
+ <a
69
+ href={link.href}
70
+ class:list={[
71
+ "inline-flex items-center justify-center px-6 py-3 text-sm font-medium rounded-md transition-colors",
72
+ buttonClasses[style][link.variant]
73
+ ]}
74
+ >
75
+ {link.label}
76
+ </a>
77
+ ))}
78
+ </div>
79
+ )}
80
+ </div>
81
+ </div>
82
+ </section>
@@ -0,0 +1,177 @@
1
+ ---
2
+ interface Tab {
3
+ name: string
4
+ stat: string
5
+ statLabel: string
6
+ description: string
7
+ link?: {
8
+ label: string
9
+ href: string
10
+ }
11
+ }
12
+
13
+ interface Props {
14
+ heading?: string
15
+ subheading?: string
16
+ tabs?: Tab[]
17
+ }
18
+
19
+ const defaultTabs: Tab[] = [
20
+ {
21
+ name: "Sales Teams",
22
+ stat: "40%",
23
+ statLabel: "Faster deal cycles with smart pipeline tools",
24
+ description: "Close deals faster with intelligent pipeline management, automated follow-ups, and real-time insights that help your team hit quota every quarter.",
25
+ link: { label: "Solutions for sales", href: "/use-cases/sales" },
26
+ },
27
+ {
28
+ name: "Marketing Teams",
29
+ stat: "3x",
30
+ statLabel: "Campaign velocity with streamlined workflows",
31
+ description: "Launch campaigns that convert with collaborative planning, asset management, and performance analytics all in one place.",
32
+ link: { label: "Solutions for marketing", href: "/use-cases/marketing" },
33
+ },
34
+ {
35
+ name: "Product Teams",
36
+ stat: "50%",
37
+ statLabel: "Faster shipping with better prioritization",
38
+ description: "Ship features users love with roadmap planning, feedback collection, and release management that keeps everyone aligned.",
39
+ link: { label: "Solutions for product", href: "/use-cases/product" },
40
+ },
41
+ {
42
+ name: "Operations",
43
+ stat: "60%",
44
+ statLabel: "Time saved with process automation",
45
+ description: "Scale your operations without the chaos. Automate processes, manage resources, and get visibility across your entire organization.",
46
+ link: { label: "Solutions for ops", href: "/use-cases/operations" },
47
+ },
48
+ ]
49
+
50
+ const {
51
+ heading = "Solutions that deliver real results",
52
+ subheading = "Whether you're in sales, marketing, or product, SaaSify adapts to how your team works.",
53
+ tabs = defaultTabs,
54
+ } = Astro.props
55
+
56
+ const displayTabs = tabs.length > 0 ? tabs : defaultTabs
57
+ ---
58
+
59
+ <section class="py-16 md:py-24 bg-muted/30">
60
+ <div class="container mx-auto px-4">
61
+ <!-- Header -->
62
+ {(heading || subheading) && (
63
+ <div class="text-center mb-12 md:mb-16 max-w-3xl mx-auto">
64
+ {heading && (
65
+ <h2 class="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight mb-4">
66
+ {heading}
67
+ </h2>
68
+ )}
69
+ {subheading && (
70
+ <p class="text-lg md:text-xl text-muted-foreground">
71
+ {subheading}
72
+ </p>
73
+ )}
74
+ </div>
75
+ )}
76
+
77
+ <!-- Tabs -->
78
+ <div class="flex flex-wrap justify-center gap-2 mb-12" id="industry-tabs">
79
+ {displayTabs.map((tab, index) => (
80
+ <button
81
+ type="button"
82
+ data-tab-index={index}
83
+ class:list={[
84
+ "industry-tab px-4 py-2 text-sm font-medium rounded-full transition-colors",
85
+ index === 0
86
+ ? "bg-primary text-primary-foreground"
87
+ : "bg-background border border-border hover:bg-muted"
88
+ ]}
89
+ >
90
+ {tab.name}
91
+ </button>
92
+ ))}
93
+ </div>
94
+
95
+ <!-- Content -->
96
+ <div class="grid md:grid-cols-2 gap-12 lg:gap-16 items-center max-w-5xl mx-auto">
97
+ {displayTabs.map((tab, index) => (
98
+ <div
99
+ data-tab-content={index}
100
+ class:list={["tab-content text-center md:text-left", index !== 0 && "hidden"]}
101
+ >
102
+ <div class="text-7xl md:text-8xl lg:text-9xl font-bold text-primary mb-2">
103
+ {tab.stat}
104
+ </div>
105
+ <p class="text-xl md:text-2xl font-medium text-foreground">
106
+ {tab.statLabel}
107
+ </p>
108
+ </div>
109
+ ))}
110
+
111
+ {displayTabs.map((tab, index) => (
112
+ <div
113
+ data-tab-description={index}
114
+ class:list={["tab-description", index !== 0 && "hidden"]}
115
+ >
116
+ <p class="text-lg text-muted-foreground mb-6">
117
+ {tab.description}
118
+ </p>
119
+ {tab.link && (
120
+ <a
121
+ href={tab.link.href}
122
+ 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"
123
+ >
124
+ {tab.link.label}
125
+ <span aria-hidden="true">&rarr;</span>
126
+ </a>
127
+ )}
128
+ </div>
129
+ ))}
130
+ </div>
131
+ </div>
132
+ </section>
133
+
134
+ <script>
135
+ function initIndustryTabs() {
136
+ const tabsContainer = document.getElementById('industry-tabs')
137
+ if (!tabsContainer) return
138
+
139
+ const tabs = tabsContainer.querySelectorAll('.industry-tab')
140
+ const contents = document.querySelectorAll('.tab-content')
141
+ const descriptions = document.querySelectorAll('.tab-description')
142
+
143
+ tabs.forEach((tab) => {
144
+ tab.addEventListener('click', () => {
145
+ const index = tab.getAttribute('data-tab-index')
146
+
147
+ // Update tab styles
148
+ tabs.forEach((t) => {
149
+ t.classList.remove('bg-primary', 'text-primary-foreground')
150
+ t.classList.add('bg-background', 'border', 'border-border', 'hover:bg-muted')
151
+ })
152
+ tab.classList.add('bg-primary', 'text-primary-foreground')
153
+ tab.classList.remove('bg-background', 'border', 'border-border', 'hover:bg-muted')
154
+
155
+ // Update content visibility
156
+ contents.forEach((content) => {
157
+ if (content.getAttribute('data-tab-content') === index) {
158
+ content.classList.remove('hidden')
159
+ } else {
160
+ content.classList.add('hidden')
161
+ }
162
+ })
163
+
164
+ descriptions.forEach((desc) => {
165
+ if (desc.getAttribute('data-tab-description') === index) {
166
+ desc.classList.remove('hidden')
167
+ } else {
168
+ desc.classList.add('hidden')
169
+ }
170
+ })
171
+ })
172
+ })
173
+ }
174
+
175
+ initIndustryTabs()
176
+ document.addEventListener('astro:after-swap', initIndustryTabs)
177
+ </script>
@@ -0,0 +1,95 @@
1
+ ---
2
+ interface Logo {
3
+ name: string
4
+ initials?: string
5
+ }
6
+
7
+ interface Props {
8
+ heading?: string
9
+ logos?: Logo[]
10
+ style?: "scroll" | "grid"
11
+ }
12
+
13
+ const defaultLogos: Logo[] = [
14
+ { name: "TechFlow Inc", initials: "TF" },
15
+ { name: "Acme Corp", initials: "AC" },
16
+ { name: "Evergreen HQ", initials: "EH" },
17
+ { name: "Atlas Network", initials: "AN" },
18
+ { name: "Beacon Digital", initials: "BD" },
19
+ { name: "Cascade Systems", initials: "CS" },
20
+ ]
21
+
22
+ const {
23
+ heading = "Trusted by fast-growing companies everywhere",
24
+ logos = defaultLogos,
25
+ style = "scroll",
26
+ } = Astro.props
27
+
28
+ const displayLogos = logos.length > 0 ? logos : defaultLogos
29
+ ---
30
+
31
+ <section class="py-12 md:py-16 border-y border-border/50">
32
+ <div class="container mx-auto px-4">
33
+ {heading && (
34
+ <p class="text-center text-sm text-muted-foreground mb-8 uppercase tracking-wider">
35
+ {heading}
36
+ </p>
37
+ )}
38
+
39
+ {style === "scroll" ? (
40
+ <div class="logo-scroll-container">
41
+ <div class="logo-scroll-track">
42
+ {[...displayLogos, ...displayLogos].map((logo, index) => (
43
+ <div class="logo-item flex items-center justify-center px-6 md:px-8 grayscale hover:grayscale-0 transition-all duration-300">
44
+ <div class="flex items-center gap-2">
45
+ <span class="w-8 h-8 rounded bg-muted flex items-center justify-center text-xs font-bold text-foreground">
46
+ {logo.initials || logo.name.slice(0, 2).toUpperCase()}
47
+ </span>
48
+ <span class="text-sm font-medium text-muted-foreground hidden md:block">
49
+ {logo.name}
50
+ </span>
51
+ </div>
52
+ </div>
53
+ ))}
54
+ </div>
55
+ </div>
56
+ ) : (
57
+ <div class="grid grid-cols-3 md:grid-cols-6 gap-8 items-center justify-items-center">
58
+ {displayLogos.map((logo) => (
59
+ <div class="logo-item flex items-center justify-center px-6 md:px-8 grayscale hover:grayscale-0 transition-all duration-300">
60
+ <div class="flex items-center gap-2">
61
+ <span class="w-8 h-8 rounded bg-muted flex items-center justify-center text-xs font-bold text-foreground">
62
+ {logo.initials || logo.name.slice(0, 2).toUpperCase()}
63
+ </span>
64
+ <span class="text-sm font-medium text-muted-foreground hidden md:block">
65
+ {logo.name}
66
+ </span>
67
+ </div>
68
+ </div>
69
+ ))}
70
+ </div>
71
+ )}
72
+ </div>
73
+ </section>
74
+
75
+ <style>
76
+ .logo-scroll-container {
77
+ overflow: hidden;
78
+ mask-image: linear-gradient(to right, transparent, black 10%, black 90%, transparent);
79
+ }
80
+
81
+ .logo-scroll-track {
82
+ display: flex;
83
+ animation: scroll 30s linear infinite;
84
+ width: max-content;
85
+ }
86
+
87
+ @keyframes scroll {
88
+ 0% { transform: translateX(0); }
89
+ 100% { transform: translateX(-50%); }
90
+ }
91
+
92
+ .logo-scroll-container:hover .logo-scroll-track {
93
+ animation-play-state: paused;
94
+ }
95
+ </style>
@@ -0,0 +1,176 @@
1
+ ---
2
+ import { Check, X } from "lucide-astro"
3
+
4
+ interface PricingFeature {
5
+ feature: string
6
+ included: boolean
7
+ }
8
+
9
+ interface PricingPlan {
10
+ name: string
11
+ price: string
12
+ description: string
13
+ featured?: boolean
14
+ features: PricingFeature[]
15
+ link: {
16
+ label: string
17
+ href: string
18
+ variant: "default" | "outline"
19
+ }
20
+ }
21
+
22
+ interface Props {
23
+ heading?: string
24
+ subheading?: string
25
+ plans?: PricingPlan[]
26
+ }
27
+
28
+ const defaultPlans: PricingPlan[] = [
29
+ {
30
+ name: "Free",
31
+ price: "$0/mo",
32
+ description: "Perfect for trying SaaSify.",
33
+ features: [
34
+ { feature: "Up to 3 users", included: true },
35
+ { feature: "Basic features", included: true },
36
+ { feature: "Community support", included: true },
37
+ ],
38
+ link: { label: "Get started free", href: "/sign-up", variant: "outline" },
39
+ },
40
+ {
41
+ name: "Pro",
42
+ price: "$29/mo",
43
+ description: "For small teams getting started.",
44
+ featured: true,
45
+ features: [
46
+ { feature: "Up to 10 users", included: true },
47
+ { feature: "Advanced features", included: true },
48
+ { feature: "Integrations", included: true },
49
+ { feature: "Priority support", included: true },
50
+ ],
51
+ link: { label: "Get Pro", href: "/sign-up", variant: "default" },
52
+ },
53
+ {
54
+ name: "Business",
55
+ price: "$99/mo",
56
+ description: "For teams ready to scale.",
57
+ features: [
58
+ { feature: "Unlimited users", included: true },
59
+ { feature: "All features", included: true },
60
+ { feature: "API access", included: true },
61
+ { feature: "Dedicated support", included: true },
62
+ ],
63
+ link: { label: "Get Business", href: "/sign-up", variant: "outline" },
64
+ },
65
+ ]
66
+
67
+ const {
68
+ heading = "Simple, transparent pricing",
69
+ subheading = "Start free, upgrade as your team grows. No hidden fees.",
70
+ plans = defaultPlans,
71
+ } = Astro.props
72
+
73
+ const displayPlans = plans.length > 0 ? plans : defaultPlans
74
+ ---
75
+
76
+ <section class="py-16 md:py-24">
77
+ <div class="container mx-auto px-4">
78
+ <!-- Header -->
79
+ {(heading || subheading) && (
80
+ <div class="text-center mb-12 md:mb-16 max-w-3xl mx-auto">
81
+ {heading && (
82
+ <h2 class="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight mb-4">
83
+ {heading}
84
+ </h2>
85
+ )}
86
+ {subheading && (
87
+ <p class="text-lg md:text-xl text-muted-foreground">
88
+ {subheading}
89
+ </p>
90
+ )}
91
+ </div>
92
+ )}
93
+
94
+ <!-- Pricing Cards -->
95
+ <div class="grid md:grid-cols-3 gap-6 lg:gap-8 max-w-5xl mx-auto">
96
+ {displayPlans.map((plan) => (
97
+ <div
98
+ class:list={[
99
+ "relative rounded-2xl p-6 md:p-8 flex flex-col",
100
+ plan.featured
101
+ ? "bg-primary text-primary-foreground border-2 border-primary"
102
+ : "bg-card border border-border"
103
+ ]}
104
+ >
105
+ {plan.featured && (
106
+ <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">
107
+ Most Popular
108
+ </span>
109
+ )}
110
+
111
+ <!-- Plan header -->
112
+ <div class="mb-6">
113
+ <h3 class:list={["text-lg font-semibold mb-2", plan.featured ? "text-primary-foreground" : "text-foreground"]}>
114
+ {plan.name}
115
+ </h3>
116
+ <div class:list={["text-4xl font-bold mb-2", plan.featured ? "text-primary-foreground" : "text-foreground"]}>
117
+ {plan.price}
118
+ </div>
119
+ <p class:list={["text-sm", plan.featured ? "text-primary-foreground/80" : "text-muted-foreground"]}>
120
+ {plan.description}
121
+ </p>
122
+ </div>
123
+
124
+ <!-- Features -->
125
+ <ul class="space-y-3 mb-8 flex-1">
126
+ {plan.features.map((feature) => (
127
+ <li class="flex items-center gap-3">
128
+ {feature.included ? (
129
+ <Check class:list={["h-4 w-4", plan.featured ? "text-primary-foreground" : "text-primary"]} />
130
+ ) : (
131
+ <X class:list={["h-4 w-4", plan.featured ? "text-primary-foreground/50" : "text-muted-foreground"]} />
132
+ )}
133
+ <span
134
+ class:list={[
135
+ "text-sm",
136
+ plan.featured
137
+ ? feature.included ? "text-primary-foreground" : "text-primary-foreground/50"
138
+ : feature.included ? "text-foreground" : "text-muted-foreground"
139
+ ]}
140
+ >
141
+ {feature.feature}
142
+ </span>
143
+ </li>
144
+ ))}
145
+ </ul>
146
+
147
+ <!-- CTA -->
148
+ <a
149
+ href={plan.link.href}
150
+ class:list={[
151
+ "w-full inline-flex items-center justify-center px-6 py-3 text-sm font-medium rounded-md transition-colors",
152
+ plan.featured
153
+ ? "bg-background text-foreground hover:bg-background/90"
154
+ : plan.link.variant === "default"
155
+ ? "bg-primary text-primary-foreground hover:bg-primary/90"
156
+ : "border border-border bg-background hover:bg-muted"
157
+ ]}
158
+ >
159
+ {plan.link.label}
160
+ </a>
161
+ </div>
162
+ ))}
163
+ </div>
164
+
165
+ <!-- View all link -->
166
+ <div class="text-center mt-8">
167
+ <a
168
+ href="/pricing"
169
+ class="inline-flex items-center gap-2 text-sm font-medium text-primary hover:underline"
170
+ >
171
+ View full comparison
172
+ <span aria-hidden="true">&rarr;</span>
173
+ </a>
174
+ </div>
175
+ </div>
176
+ </section>
@@ -0,0 +1,56 @@
1
+ ---
2
+ interface ProofBannerLink {
3
+ label: string
4
+ href: string
5
+ variant: "default" | "outline"
6
+ }
7
+
8
+ interface Props {
9
+ headline?: string
10
+ subtext?: string
11
+ links?: ProofBannerLink[]
12
+ style?: "centered" | "left"
13
+ }
14
+
15
+ const {
16
+ headline = "Transform how your team works, collaborates, and grows",
17
+ subtext = "Every interaction feeds into a powerful platform that powers personalized experiences, seamless collaboration, and intelligent automation across every touchpoint.",
18
+ links = [
19
+ { label: "Start free trial", href: "/sign-up", variant: "default" },
20
+ { label: "Book a demo", href: "/contact", variant: "outline" },
21
+ ],
22
+ style = "centered",
23
+ } = Astro.props
24
+ ---
25
+
26
+ <section class="py-16 md:py-24">
27
+ <div class="container mx-auto px-4">
28
+ <div class:list={["max-w-4xl", style === "centered" ? "mx-auto text-center" : ""]}>
29
+ <h2 class="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight mb-6">
30
+ {headline}
31
+ </h2>
32
+ {subtext && (
33
+ <p class="text-lg md:text-xl text-muted-foreground mb-8 max-w-3xl mx-auto">
34
+ {subtext}
35
+ </p>
36
+ )}
37
+ {links && links.length > 0 && (
38
+ <div class:list={["flex flex-wrap gap-4", style === "centered" ? "justify-center" : ""]}>
39
+ {links.map((link) => (
40
+ <a
41
+ href={link.href}
42
+ class:list={[
43
+ "inline-flex items-center justify-center px-6 py-3 text-sm font-medium rounded-md transition-colors",
44
+ link.variant === "default"
45
+ ? "bg-primary text-primary-foreground hover:bg-primary/90"
46
+ : "border border-border bg-background hover:bg-muted"
47
+ ]}
48
+ >
49
+ {link.label}
50
+ </a>
51
+ ))}
52
+ </div>
53
+ )}
54
+ </div>
55
+ </div>
56
+ </section>