ship-create 1.0.0

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 (56) hide show
  1. package/README.md +39 -0
  2. package/create.mjs +301 -0
  3. package/package.json +25 -0
  4. package/templates/.cursorrules +51 -0
  5. package/templates/.windsurfrules +51 -0
  6. package/templates/AGENTS.md +51 -0
  7. package/templates/CLAUDE.md +51 -0
  8. package/templates/docs/HUMAN_FLOW.md +205 -0
  9. package/templates/docs/PROJECT.md +154 -0
  10. package/templates/docs/PROMPTS.md +246 -0
  11. package/templates/docs/product-types/CRM_TEMPLATE.md +78 -0
  12. package/templates/docs/product-types/DASHBOARD_TEMPLATE.md +78 -0
  13. package/templates/docs/product-types/DIRECTORY_TEMPLATE.md +75 -0
  14. package/templates/docs/product-types/INTERNAL_TOOL_TEMPLATE.md +77 -0
  15. package/templates/docs/product-types/LEADGEN_TEMPLATE.md +78 -0
  16. package/templates/docs/product-types/MARKETPLACE_TEMPLATE.md +81 -0
  17. package/templates/docs/product-types/MEMBERSHIP_TEMPLATE.md +80 -0
  18. package/templates/docs/product-types/SAAS_TEMPLATE.md +79 -0
  19. package/templates/starter-kit/README.md +64 -0
  20. package/templates/starter-kit/app/backoffice/content/page.tsx +93 -0
  21. package/templates/starter-kit/app/backoffice/layout.tsx +105 -0
  22. package/templates/starter-kit/app/backoffice/page.tsx +165 -0
  23. package/templates/starter-kit/app/backoffice/settings/page.tsx +145 -0
  24. package/templates/starter-kit/app/backoffice/users/page.tsx +134 -0
  25. package/templates/starter-kit/app/globals.css +141 -0
  26. package/templates/starter-kit/app/layout.tsx +43 -0
  27. package/templates/starter-kit/app/member/(app)/billing/page.tsx +137 -0
  28. package/templates/starter-kit/app/member/(app)/content/page.tsx +111 -0
  29. package/templates/starter-kit/app/member/(app)/dashboard/page.tsx +129 -0
  30. package/templates/starter-kit/app/member/(app)/layout.tsx +130 -0
  31. package/templates/starter-kit/app/member/(app)/settings/page.tsx +96 -0
  32. package/templates/starter-kit/app/member/login/page.tsx +106 -0
  33. package/templates/starter-kit/app/member/signup/page.tsx +120 -0
  34. package/templates/starter-kit/app/page.tsx +82 -0
  35. package/templates/starter-kit/app/sale/_components/cta-footer.tsx +66 -0
  36. package/templates/starter-kit/app/sale/_components/faq.tsx +107 -0
  37. package/templates/starter-kit/app/sale/_components/features.tsx +95 -0
  38. package/templates/starter-kit/app/sale/_components/hero.tsx +106 -0
  39. package/templates/starter-kit/app/sale/_components/pricing.tsx +133 -0
  40. package/templates/starter-kit/app/sale/_components/problem.tsx +59 -0
  41. package/templates/starter-kit/app/sale/_components/testimonials.tsx +100 -0
  42. package/templates/starter-kit/app/sale/page.tsx +21 -0
  43. package/templates/starter-kit/components/ui/avatar.tsx +50 -0
  44. package/templates/starter-kit/components/ui/badge.tsx +36 -0
  45. package/templates/starter-kit/components/ui/button.tsx +56 -0
  46. package/templates/starter-kit/components/ui/card.tsx +78 -0
  47. package/templates/starter-kit/components/ui/input.tsx +24 -0
  48. package/templates/starter-kit/components/ui/table.tsx +88 -0
  49. package/templates/starter-kit/components/ui/tabs.tsx +55 -0
  50. package/templates/starter-kit/lib/mock-data.ts +118 -0
  51. package/templates/starter-kit/lib/utils.ts +6 -0
  52. package/templates/starter-kit/next.config.mjs +6 -0
  53. package/templates/starter-kit/package.json +36 -0
  54. package/templates/starter-kit/postcss.config.mjs +9 -0
  55. package/templates/starter-kit/tailwind.config.ts +83 -0
  56. package/templates/starter-kit/tsconfig.json +41 -0
@@ -0,0 +1,107 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import { Plus } from "lucide-react";
5
+
6
+ import { cn } from "@/lib/utils";
7
+
8
+ const faqs = [
9
+ {
10
+ question: "Can I try it before I pay?",
11
+ answer:
12
+ "Yes — every plan includes a free 14-day trial with full access to features. No credit card required to start.",
13
+ },
14
+ {
15
+ question: "Can I change plans later?",
16
+ answer:
17
+ "Absolutely. You can upgrade, downgrade, or cancel at any time from your account settings — changes apply immediately.",
18
+ },
19
+ {
20
+ question: "Is my data secure?",
21
+ answer:
22
+ "All data is encrypted in transit and at rest. Business plans also include SSO, audit logs, and role-based permissions.",
23
+ },
24
+ {
25
+ question: "Do you offer discounts for annual billing?",
26
+ answer:
27
+ "Yes, switching to annual billing saves roughly two months compared to paying monthly. You can switch from your billing page.",
28
+ },
29
+ {
30
+ question: "What kind of support do you provide?",
31
+ answer:
32
+ "Starter includes email support, Pro includes priority support, and Business includes a dedicated success manager.",
33
+ },
34
+ {
35
+ question: "Can I cancel anytime?",
36
+ answer:
37
+ "Yes, there are no long-term contracts. You can cancel from your account at any time and you won't be charged again.",
38
+ },
39
+ ];
40
+
41
+ export function Faq() {
42
+ const [openIndex, setOpenIndex] = useState<number | null>(0);
43
+
44
+ return (
45
+ <section className="container mx-auto px-4 py-28">
46
+ <div className="mx-auto mb-16 flex max-w-2xl flex-col items-center gap-3 text-center">
47
+ <p className="label-mono text-primary">FAQ</p>
48
+ <h2 className="font-display text-4xl font-medium tracking-tight sm:text-5xl">
49
+ Frequently asked{" "}
50
+ <span className="italic text-primary">questions</span>
51
+ </h2>
52
+ <p className="mt-2 text-muted-foreground">
53
+ Everything you need to know before you get started.
54
+ </p>
55
+ </div>
56
+ <div className="mx-auto max-w-2xl divide-y divide-border rounded-2xl border border-border">
57
+ {faqs.map((faq, index) => {
58
+ const isOpen = openIndex === index;
59
+ return (
60
+ <div key={faq.question}>
61
+ <button
62
+ type="button"
63
+ onClick={() => setOpenIndex(isOpen ? null : index)}
64
+ className="flex w-full items-center gap-4 px-6 py-5 text-left transition-colors hover:bg-muted/40"
65
+ aria-expanded={isOpen}
66
+ >
67
+ <span className="label-mono shrink-0 text-muted-foreground/50">
68
+ {String(index + 1).padStart(2, "0")}
69
+ </span>
70
+ <span
71
+ className={cn(
72
+ "flex-1 text-sm font-medium transition-colors",
73
+ isOpen && "text-primary"
74
+ )}
75
+ >
76
+ {faq.question}
77
+ </span>
78
+ <span
79
+ className={cn(
80
+ "flex h-7 w-7 shrink-0 items-center justify-center rounded-full border border-border text-muted-foreground transition-all duration-300",
81
+ isOpen && "rotate-45 border-primary/50 text-primary"
82
+ )}
83
+ >
84
+ <Plus className="h-3.5 w-3.5" />
85
+ </span>
86
+ </button>
87
+ <div
88
+ className={cn(
89
+ "grid overflow-hidden transition-all duration-300 ease-out",
90
+ isOpen
91
+ ? "grid-rows-[1fr] opacity-100"
92
+ : "grid-rows-[0fr] opacity-0"
93
+ )}
94
+ >
95
+ <div className="overflow-hidden">
96
+ <p className="px-6 pb-5 pl-16 text-sm leading-relaxed text-muted-foreground">
97
+ {faq.answer}
98
+ </p>
99
+ </div>
100
+ </div>
101
+ </div>
102
+ );
103
+ })}
104
+ </div>
105
+ </section>
106
+ );
107
+ }
@@ -0,0 +1,95 @@
1
+ import {
2
+ BarChart3,
3
+ Bell,
4
+ Layers,
5
+ Lock,
6
+ Workflow,
7
+ Zap,
8
+ } from "lucide-react";
9
+
10
+ import {
11
+ Card,
12
+ CardContent,
13
+ CardDescription,
14
+ CardHeader,
15
+ CardTitle,
16
+ } from "@/components/ui/card";
17
+
18
+ const features = [
19
+ {
20
+ icon: Workflow,
21
+ title: "Unified workflows",
22
+ description:
23
+ "Build pipelines that connect every step of your process, from intake to delivery, without switching tools.",
24
+ },
25
+ {
26
+ icon: BarChart3,
27
+ title: "Real-time analytics",
28
+ description:
29
+ "See what's working and what's not with dashboards that update the moment your data changes.",
30
+ },
31
+ {
32
+ icon: Bell,
33
+ title: "Smart notifications",
34
+ description:
35
+ "Only get pinged when it matters. Configurable alerts keep noise down and signal up.",
36
+ },
37
+ {
38
+ icon: Layers,
39
+ title: "Flexible templates",
40
+ description:
41
+ "Start from a proven template or build your own — every workspace adapts to how your team actually works.",
42
+ },
43
+ {
44
+ icon: Lock,
45
+ title: "Enterprise-grade security",
46
+ description:
47
+ "Role-based access, audit logs, and encryption at rest keep your data safe by default.",
48
+ },
49
+ {
50
+ icon: Zap,
51
+ title: "Built for speed",
52
+ description:
53
+ "A fast, responsive interface so your team spends time working, not waiting on spinners.",
54
+ },
55
+ ];
56
+
57
+ export function Features() {
58
+ return (
59
+ <section className="bg-grid relative py-28">
60
+ <div className="container relative mx-auto px-4">
61
+ <div className="mx-auto mb-16 flex max-w-2xl flex-col items-center gap-3 text-center">
62
+ <p className="label-mono text-primary">Capabilities</p>
63
+ <h2 className="font-display text-4xl font-medium tracking-tight sm:text-5xl">
64
+ Everything your team{" "}
65
+ <span className="italic text-primary">needs</span>
66
+ </h2>
67
+ <p className="mt-2 text-muted-foreground">
68
+ One platform, every workflow — no more duct-taping five tools
69
+ together.
70
+ </p>
71
+ </div>
72
+ <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
73
+ {features.map((feature) => {
74
+ const Icon = feature.icon;
75
+ return (
76
+ <Card
77
+ key={feature.title}
78
+ className="bg-card/90 backdrop-blur transition-transform duration-300 hover:-translate-y-1"
79
+ >
80
+ <CardHeader>
81
+ <div className="mb-3 flex h-11 w-11 items-center justify-center rounded-full bg-primary/15 text-primary">
82
+ <Icon className="h-5 w-5" />
83
+ </div>
84
+ <CardTitle>{feature.title}</CardTitle>
85
+ <CardDescription>{feature.description}</CardDescription>
86
+ </CardHeader>
87
+ <CardContent />
88
+ </Card>
89
+ );
90
+ })}
91
+ </div>
92
+ </div>
93
+ </section>
94
+ );
95
+ }
@@ -0,0 +1,106 @@
1
+ import { ArrowRight } from "lucide-react";
2
+
3
+ import { Button } from "@/components/ui/button";
4
+
5
+ export function Hero() {
6
+ return (
7
+ <section className="relative overflow-hidden pb-24 pt-28 md:pt-36">
8
+ {/* Decorative grid panel, off to the right, faded */}
9
+ <div className="bg-grid pointer-events-none absolute inset-y-0 right-0 hidden w-1/2 [mask-image:linear-gradient(to_left,black,transparent)] lg:block" />
10
+
11
+ {/* Soft ember glow blob behind the headline */}
12
+ <div className="pointer-events-none absolute -left-32 top-10 h-[28rem] w-[28rem] rounded-full bg-primary/20 blur-[110px]" />
13
+
14
+ {/* Giant faint serif numeral as a decorative mark */}
15
+ <span
16
+ aria-hidden
17
+ className="pointer-events-none absolute -right-6 top-4 select-none font-display text-[16rem] font-medium leading-none text-foreground/[0.04] sm:text-[22rem]"
18
+ >
19
+ 01
20
+ </span>
21
+
22
+ <div className="container relative mx-auto px-4">
23
+ <div className="grid items-end gap-12 lg:grid-cols-[1.15fr_0.85fr]">
24
+ <div className="flex flex-col items-start gap-7 text-left">
25
+ <span
26
+ className="label-mono animate-fade-up inline-flex items-center gap-2 text-primary"
27
+ style={{ animationDelay: "0s" }}
28
+ >
29
+ <span className="h-1.5 w-1.5 rounded-full bg-primary" />
30
+ Now in public beta
31
+ </span>
32
+
33
+ <h1
34
+ className="animate-fade-up max-w-2xl font-display text-5xl font-medium leading-[1.05] tracking-tight sm:text-6xl md:text-7xl"
35
+ style={{ animationDelay: "0.1s" }}
36
+ >
37
+ Manage your entire workflow{" "}
38
+ <span className="relative inline-block italic text-primary">
39
+ in one place
40
+ <svg
41
+ aria-hidden
42
+ viewBox="0 0 300 18"
43
+ className="absolute -bottom-2 left-0 h-3 w-full text-primary/70"
44
+ preserveAspectRatio="none"
45
+ >
46
+ <path
47
+ d="M2 13C58 4 130 2 178 7C220 11 262 13 298 6"
48
+ fill="none"
49
+ stroke="currentColor"
50
+ strokeWidth="4"
51
+ strokeLinecap="round"
52
+ />
53
+ </svg>
54
+ </span>
55
+ </h1>
56
+
57
+ <p
58
+ className="animate-fade-up max-w-md text-lg leading-relaxed text-muted-foreground"
59
+ style={{ animationDelay: "0.2s" }}
60
+ >
61
+ Replace your spreadsheets, sticky notes, and ten disconnected
62
+ tools with a single platform built for teams who want to move
63
+ faster.
64
+ </p>
65
+
66
+ <div
67
+ className="animate-fade-up flex flex-col gap-3 sm:flex-row"
68
+ style={{ animationDelay: "0.3s" }}
69
+ >
70
+ <Button size="lg" className="glow-primary gap-2">
71
+ Get Started
72
+ <ArrowRight className="h-4 w-4" />
73
+ </Button>
74
+ <Button size="lg" variant="outline">
75
+ See Pricing
76
+ </Button>
77
+ </div>
78
+
79
+ <p
80
+ className="label-mono animate-fade-up text-muted-foreground"
81
+ style={{ animationDelay: "0.4s" }}
82
+ >
83
+ No credit card required &middot; Free 14-day trial
84
+ </p>
85
+ </div>
86
+
87
+ <div
88
+ className="animate-fade-up relative"
89
+ style={{ animationDelay: "0.25s" }}
90
+ >
91
+ <div className="bg-grid relative aspect-[4/5] w-full overflow-hidden rounded-2xl border border-border bg-card shadow-soft">
92
+ <div className="absolute inset-0 bg-gradient-to-br from-primary/15 via-transparent to-transparent" />
93
+ <div className="absolute bottom-6 left-6 right-6 rounded-xl border border-border bg-background/80 p-4 backdrop-blur">
94
+ <p className="label-mono text-primary">Live workspace</p>
95
+ <p className="mt-1 font-display text-lg">
96
+ Everything in sync, automatically.
97
+ </p>
98
+ </div>
99
+ </div>
100
+ <div className="absolute -bottom-5 -left-5 hidden h-20 w-20 rounded-full border border-primary/40 bg-primary/20 blur-sm sm:block" />
101
+ </div>
102
+ </div>
103
+ </div>
104
+ </section>
105
+ );
106
+ }
@@ -0,0 +1,133 @@
1
+ import { Check } from "lucide-react";
2
+
3
+ import { Badge } from "@/components/ui/badge";
4
+ import { Button } from "@/components/ui/button";
5
+ import {
6
+ Card,
7
+ CardContent,
8
+ CardDescription,
9
+ CardFooter,
10
+ CardHeader,
11
+ CardTitle,
12
+ } from "@/components/ui/card";
13
+ import { cn } from "@/lib/utils";
14
+
15
+ const tiers = [
16
+ {
17
+ name: "Starter",
18
+ price: "$19",
19
+ period: "/mo",
20
+ description: "For individuals and small teams getting started.",
21
+ features: [
22
+ "Up to 3 workspaces",
23
+ "Basic analytics",
24
+ "Email support",
25
+ "1 GB storage",
26
+ ],
27
+ cta: "Start Free Trial",
28
+ highlighted: false,
29
+ },
30
+ {
31
+ name: "Pro",
32
+ price: "$49",
33
+ period: "/mo",
34
+ description: "For growing teams that need more power and automation.",
35
+ features: [
36
+ "Unlimited workspaces",
37
+ "Advanced analytics",
38
+ "Priority support",
39
+ "50 GB storage",
40
+ "Custom integrations",
41
+ ],
42
+ cta: "Start Free Trial",
43
+ highlighted: true,
44
+ },
45
+ {
46
+ name: "Business",
47
+ price: "$129",
48
+ period: "/mo",
49
+ description: "For organizations that need scale, security, and control.",
50
+ features: [
51
+ "Everything in Pro",
52
+ "SSO & advanced permissions",
53
+ "Dedicated success manager",
54
+ "Unlimited storage",
55
+ "SLA & audit logs",
56
+ ],
57
+ cta: "Contact Sales",
58
+ highlighted: false,
59
+ },
60
+ ];
61
+
62
+ export function Pricing() {
63
+ return (
64
+ <section className="container mx-auto px-4 py-28">
65
+ <div className="mx-auto mb-16 flex max-w-2xl flex-col items-center gap-3 text-center">
66
+ <p className="label-mono text-primary">Pricing</p>
67
+ <h2 className="font-display text-4xl font-medium tracking-tight sm:text-5xl">
68
+ Simple, <span className="italic text-primary">transparent</span>{" "}
69
+ pricing
70
+ </h2>
71
+ <p className="mt-2 text-muted-foreground">
72
+ Choose the plan that fits your team. Upgrade or downgrade anytime.
73
+ </p>
74
+ </div>
75
+ <div className="grid items-center gap-8 lg:grid-cols-3">
76
+ {tiers.map((tier) => (
77
+ <Card
78
+ key={tier.name}
79
+ className={cn(
80
+ "relative flex flex-col transition-transform duration-300",
81
+ tier.highlighted &&
82
+ "glow-primary z-10 border-primary/60 lg:scale-110"
83
+ )}
84
+ >
85
+ {tier.highlighted && (
86
+ <Badge className="absolute -top-3 left-1/2 -translate-x-1/2">
87
+ Most Popular
88
+ </Badge>
89
+ )}
90
+ <CardHeader>
91
+ <p className="label-mono text-muted-foreground">{tier.name}</p>
92
+ <CardTitle
93
+ className={cn(
94
+ "text-2xl",
95
+ tier.highlighted && "text-primary"
96
+ )}
97
+ >
98
+ {tier.description}
99
+ </CardTitle>
100
+ <div className="mt-4 flex items-baseline gap-1">
101
+ <span className="font-display text-5xl font-medium tracking-tight">
102
+ {tier.price}
103
+ </span>
104
+ <span className="text-sm text-muted-foreground">
105
+ {tier.period}
106
+ </span>
107
+ </div>
108
+ </CardHeader>
109
+ <CardContent className="flex-1">
110
+ <ul className="space-y-3">
111
+ {tier.features.map((feature) => (
112
+ <li key={feature} className="flex items-start gap-2 text-sm">
113
+ <Check className="mt-0.5 h-4 w-4 shrink-0 text-success" />
114
+ <span>{feature}</span>
115
+ </li>
116
+ ))}
117
+ </ul>
118
+ </CardContent>
119
+ <CardFooter>
120
+ <Button
121
+ className="w-full"
122
+ size={tier.highlighted ? "lg" : "default"}
123
+ variant={tier.highlighted ? "default" : "outline"}
124
+ >
125
+ {tier.cta}
126
+ </Button>
127
+ </CardFooter>
128
+ </Card>
129
+ ))}
130
+ </div>
131
+ </section>
132
+ );
133
+ }
@@ -0,0 +1,59 @@
1
+ import { AlertTriangle, Clock, FolderX } from "lucide-react";
2
+
3
+ const problems = [
4
+ {
5
+ icon: Clock,
6
+ title: "Hours lost to busywork",
7
+ description:
8
+ "Your team spends more time updating status docs than actually doing the work that moves the business forward.",
9
+ },
10
+ {
11
+ icon: FolderX,
12
+ title: "Context scattered everywhere",
13
+ description:
14
+ "Decisions live in chat threads, files live in five different drives, and nobody can find the latest version of anything.",
15
+ },
16
+ {
17
+ icon: AlertTriangle,
18
+ title: "No visibility until it's too late",
19
+ description:
20
+ "Problems surface in a status meeting instead of the moment they happen, so small issues turn into missed deadlines.",
21
+ },
22
+ ];
23
+
24
+ export function Problem() {
25
+ return (
26
+ <section className="container mx-auto px-4 py-28">
27
+ <div className="mb-16 grid gap-6 lg:grid-cols-[0.6fr_1fr] lg:items-end">
28
+ <p className="label-mono text-primary">The problem</p>
29
+ <h2 className="max-w-xl font-display text-4xl font-medium leading-tight tracking-tight sm:text-5xl">
30
+ Sound <span className="italic text-primary">familiar?</span>
31
+ </h2>
32
+ </div>
33
+ <div className="grid gap-px overflow-hidden rounded-2xl border border-border bg-border sm:grid-cols-3">
34
+ {problems.map((problem, index) => {
35
+ const Icon = problem.icon;
36
+ return (
37
+ <div
38
+ key={problem.title}
39
+ className="flex flex-col gap-5 bg-background p-8"
40
+ >
41
+ <span className="label-mono text-muted-foreground/60">
42
+ {String(index + 1).padStart(2, "0")}
43
+ </span>
44
+ <div className="flex h-12 w-12 items-center justify-center rounded-full bg-destructive/10 text-destructive">
45
+ <Icon className="h-5 w-5" />
46
+ </div>
47
+ <h3 className="font-display text-xl font-medium leading-snug">
48
+ {problem.title}
49
+ </h3>
50
+ <p className="text-sm leading-relaxed text-muted-foreground">
51
+ {problem.description}
52
+ </p>
53
+ </div>
54
+ );
55
+ })}
56
+ </div>
57
+ </section>
58
+ );
59
+ }
@@ -0,0 +1,100 @@
1
+ import { Avatar, AvatarFallback } from "@/components/ui/avatar";
2
+ import { Card, CardContent } from "@/components/ui/card";
3
+ import { cn } from "@/lib/utils";
4
+
5
+ const testimonials = [
6
+ {
7
+ name: "Jordan Mills",
8
+ role: "Operations Lead, Northwind Co.",
9
+ initials: "JM",
10
+ quote:
11
+ "We replaced four separate tools with this in under a month. Our team finally has one source of truth.",
12
+ featured: true,
13
+ },
14
+ {
15
+ name: "Priya Anand",
16
+ role: "Founder, Lattice Studio",
17
+ initials: "PA",
18
+ quote:
19
+ "The automation alone saved us about 10 hours a week. It paid for itself in the first quarter.",
20
+ featured: false,
21
+ },
22
+ {
23
+ name: "Marcus Webb",
24
+ role: "Head of Product, Brightline",
25
+ initials: "MW",
26
+ quote:
27
+ "Setup took an afternoon, not a quarter. Our team adopted it without any real onboarding pain.",
28
+ featured: false,
29
+ },
30
+ ];
31
+
32
+ export function Testimonials() {
33
+ const [featured, ...rest] = testimonials;
34
+
35
+ return (
36
+ <section className="bg-grid relative py-28">
37
+ <div className="container relative mx-auto px-4">
38
+ <div className="mb-16 grid gap-6 lg:grid-cols-[0.6fr_1fr] lg:items-end">
39
+ <p className="label-mono text-primary">Social proof</p>
40
+ <h2 className="max-w-xl font-display text-4xl font-medium leading-tight tracking-tight sm:text-5xl">
41
+ Loved by teams{" "}
42
+ <span className="italic text-primary">everywhere</span>
43
+ </h2>
44
+ </div>
45
+
46
+ <div className="grid gap-6 lg:grid-cols-5">
47
+ <Card className="bg-card/90 backdrop-blur lg:col-span-3 lg:row-span-2">
48
+ <CardContent className="flex h-full flex-col justify-between gap-8 p-8">
49
+ <p className="font-display text-2xl font-medium leading-snug sm:text-3xl">
50
+ &ldquo;{featured.quote}&rdquo;
51
+ </p>
52
+ <div className="flex items-center gap-3">
53
+ <Avatar className="h-12 w-12">
54
+ <AvatarFallback className="bg-primary/15 text-primary">
55
+ {featured.initials}
56
+ </AvatarFallback>
57
+ </Avatar>
58
+ <div>
59
+ <p className="text-sm font-semibold">{featured.name}</p>
60
+ <p className="label-mono text-muted-foreground">
61
+ {featured.role}
62
+ </p>
63
+ </div>
64
+ </div>
65
+ </CardContent>
66
+ </Card>
67
+
68
+ {rest.map((testimonial, index) => (
69
+ <Card
70
+ key={testimonial.name}
71
+ className={cn(
72
+ "bg-card/90 backdrop-blur lg:col-span-2",
73
+ index === 0 ? "lg:translate-y-6" : "lg:-translate-y-2"
74
+ )}
75
+ >
76
+ <CardContent className="flex flex-col gap-5 p-6">
77
+ <p className="text-sm leading-relaxed text-muted-foreground">
78
+ &ldquo;{testimonial.quote}&rdquo;
79
+ </p>
80
+ <div className="flex items-center gap-3">
81
+ <Avatar>
82
+ <AvatarFallback>{testimonial.initials}</AvatarFallback>
83
+ </Avatar>
84
+ <div>
85
+ <p className="text-sm font-semibold">
86
+ {testimonial.name}
87
+ </p>
88
+ <p className="text-xs text-muted-foreground">
89
+ {testimonial.role}
90
+ </p>
91
+ </div>
92
+ </div>
93
+ </CardContent>
94
+ </Card>
95
+ ))}
96
+ </div>
97
+ </div>
98
+ </section>
99
+ );
100
+ }
@@ -0,0 +1,21 @@
1
+ import { CtaFooter } from "./_components/cta-footer";
2
+ import { Faq } from "./_components/faq";
3
+ import { Features } from "./_components/features";
4
+ import { Hero } from "./_components/hero";
5
+ import { Pricing } from "./_components/pricing";
6
+ import { Problem } from "./_components/problem";
7
+ import { Testimonials } from "./_components/testimonials";
8
+
9
+ export default function SalePage() {
10
+ return (
11
+ <main className="flex flex-col">
12
+ <Hero />
13
+ <Problem />
14
+ <Features />
15
+ <Pricing />
16
+ <Testimonials />
17
+ <Faq />
18
+ <CtaFooter />
19
+ </main>
20
+ );
21
+ }
@@ -0,0 +1,50 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as AvatarPrimitive from "@radix-ui/react-avatar";
5
+
6
+ import { cn } from "@/lib/utils";
7
+
8
+ const Avatar = React.forwardRef<
9
+ React.ElementRef<typeof AvatarPrimitive.Root>,
10
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
11
+ >(({ className, ...props }, ref) => (
12
+ <AvatarPrimitive.Root
13
+ ref={ref}
14
+ className={cn(
15
+ "relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
16
+ className
17
+ )}
18
+ {...props}
19
+ />
20
+ ));
21
+ Avatar.displayName = AvatarPrimitive.Root.displayName;
22
+
23
+ const AvatarImage = React.forwardRef<
24
+ React.ElementRef<typeof AvatarPrimitive.Image>,
25
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
26
+ >(({ className, ...props }, ref) => (
27
+ <AvatarPrimitive.Image
28
+ ref={ref}
29
+ className={cn("aspect-square h-full w-full", className)}
30
+ {...props}
31
+ />
32
+ ));
33
+ AvatarImage.displayName = AvatarPrimitive.Image.displayName;
34
+
35
+ const AvatarFallback = React.forwardRef<
36
+ React.ElementRef<typeof AvatarPrimitive.Fallback>,
37
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
38
+ >(({ className, ...props }, ref) => (
39
+ <AvatarPrimitive.Fallback
40
+ ref={ref}
41
+ className={cn(
42
+ "flex h-full w-full items-center justify-center rounded-full bg-muted text-sm font-medium text-muted-foreground",
43
+ className
44
+ )}
45
+ {...props}
46
+ />
47
+ ));
48
+ AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
49
+
50
+ export { Avatar, AvatarImage, AvatarFallback };