create-lacspace-app 1.12.2 → 1.14.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 (2) hide show
  1. package/dist/index.js +691 -43
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -430,6 +430,7 @@ function homePage(ctx) {
430
430
  import { LiveStats } from "@/components/live-stats";
431
431
  import { Aurora } from "@/components/aurora";
432
432
  import { HeroArt } from "@/components/hero-art";
433
+ import { StatBand, Steps, Testimonial } from "@/components/ui";
433
434
 
434
435
  // \u2728 Self-canonical home page \u2014 one line, full SEO (title, canonical, OG, Twitter).
435
436
  export const metadata = site.meta({ title: ${JSON.stringify(n)}, path: "/" });
@@ -442,6 +443,7 @@ export default function Home() {
442
443
  ${inner}
443
444
  ${showcaseSection(ctx)}
444
445
  ${marqueeSection(ctx)}
446
+ ${extraHomeSections(ctx)}
445
447
  ${faqSection(ctx)}
446
448
  ${builtWithSection(ctx)}
447
449
  </main>
@@ -669,32 +671,315 @@ export default function AppleIcon() {
669
671
  );
670
672
  }
671
673
  `;
672
- var aboutPage = (ctx) => `import type { Metadata } from "next";
673
- import Link from "next/link";
674
- import { site } from "@/lib/site";
675
-
676
- // \u2728 Per-page SEO, auto-generated: title template, canonical, Open Graph,
677
- // Twitter card and its OWN dynamic OG image \u2014 all from one line.
678
- export const metadata: Metadata = site.meta({
679
- title: "About",
680
- path: "/about",
681
- description: "Learn more about ${ctx.template.siteName}.",
674
+ var aboutPage = (ctx) => {
675
+ const r = richContent(ctx);
676
+ const n = ctx.template.siteName;
677
+ const story = r.process.map((p, i) => ({ date: ["Then", "Next", "Now", "Ahead"][i] ?? "", title: p.title, desc: p.desc }));
678
+ return pageFile({
679
+ title: "About",
680
+ path: "/about",
681
+ description: `The story, the team and the values behind ${n}.`,
682
+ cta: { title: "Let's build something together", subtitle: "We'd love to hear what you're working on.", label: "Get in touch", href: "/contact" },
683
+ body: ` <section className="mx-auto max-w-3xl px-6 py-24">
684
+ <Breadcrumbs items={[{ label: "Home", href: "/" }, { label: "About" }]} />
685
+ <h1 className="mt-6 text-4xl font-bold sm:text-5xl">About <span className="gradient-text">${n}</span></h1>
686
+ <p className="mt-4 text-lg text-muted">${n} exists to help you ship something you're proud of \u2014 faster, and with less fuss. Here's who we are and what we believe.</p>
687
+ </section>
688
+ <Section className="pt-0"><StatBand stats={${JSON.stringify(r.stats)}} /></Section>
689
+ <Section eyebrow="Our story" title="How we got here" className="pt-0">
690
+ <div className="mx-auto max-w-2xl"><Timeline items={${JSON.stringify(story)}} /></div>
691
+ </Section>
692
+ <Section eyebrow="What we value" title="Principles we won't compromise" className="pt-0">
693
+ <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
694
+ {${JSON.stringify(r.values)}.map((v) => <FeatureCard key={v.title} title={v.title} desc={v.desc} />)}
695
+ </div>
696
+ </Section>
697
+ <Section eyebrow="The team" title="The people behind ${n}" className="pt-0">
698
+ <TeamGrid members={${JSON.stringify(r.team)}} />
699
+ </Section>
700
+ <Section title="Frequently asked" className="pt-0"><FAQ items={${JSON.stringify(r.faqs.slice(0, 4))}} /></Section>`
701
+ });
702
+ };
703
+ var faqPage = (ctx) => {
704
+ const r = richContent(ctx);
705
+ const n = ctx.template.siteName;
706
+ return pageFile({
707
+ title: "FAQ",
708
+ path: "/faq",
709
+ description: `Answers to common questions about ${n}.`,
710
+ cta: { title: "Still have questions?", subtitle: "We're happy to help \u2014 reach out any time.", label: "Contact us", href: "/contact" },
711
+ body: ` <section className="mx-auto max-w-3xl px-6 py-24 text-center">
712
+ <Pill>FAQ</Pill>
713
+ <h1 className="mt-4 text-4xl font-bold sm:text-5xl">Frequently asked <span className="gradient-text">questions</span></h1>
714
+ <p className="mx-auto mt-4 max-w-xl text-lg text-muted">Everything you need to know about ${n}. Can't find an answer? Get in touch.</p>
715
+ </section>
716
+ <Section className="pt-0"><FAQ items={${JSON.stringify(r.faqs)}} /></Section>`
717
+ });
718
+ };
719
+ var integrationsPage = (ctx) => pageFile({
720
+ title: "Integrations",
721
+ path: "/integrations",
722
+ description: `Connect ${ctx.template.siteName} to the tools your team already uses.`,
723
+ cta: { title: "Don't see your tool?", subtitle: "We add integrations every month \u2014 tell us what you need.", label: "Request an integration", href: "/contact" },
724
+ body: ` <section className="mx-auto max-w-3xl px-6 py-24 text-center">
725
+ <Pill>Integrations</Pill>
726
+ <h1 className="mt-4 text-4xl font-bold sm:text-5xl">Works with your <span className="gradient-text">stack</span></h1>
727
+ <p className="mx-auto mt-4 max-w-xl text-lg text-muted">Plug ${ctx.template.siteName} into the tools you already love.</p>
728
+ </section>
729
+ <Section className="pt-0"><LogoCloud label="Popular integrations" names={["Slack", "Notion", "GitHub", "Figma", "Linear", "Stripe", "Zapier", "HubSpot"]} /></Section>
730
+ <Section eyebrow="Categories" title="Everything connects" className="pt-0">
731
+ <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
732
+ {[
733
+ { icon: "\u{1F4AC}", title: "Communication", desc: "Slack, Teams and email \u2014 never miss an update." },
734
+ { icon: "\u{1F4CA}", title: "Analytics", desc: "Pipe events to your warehouse or BI tool." },
735
+ { icon: "\u{1F517}", title: "Automation", desc: "Zapier and webhooks to connect anything." },
736
+ { icon: "\u{1F4B3}", title: "Payments", desc: "Stripe and PayPal, wired and ready." },
737
+ { icon: "\u{1F5C2}\uFE0F", title: "Productivity", desc: "Notion, Linear and Jira in two clicks." },
738
+ { icon: "\u{1F510}", title: "Identity", desc: "SSO, SAML and SCIM for teams." },
739
+ ].map((f) => <FeatureCard key={f.title} icon={f.icon} title={f.title} desc={f.desc} />)}
740
+ </div>
741
+ </Section>`
742
+ });
743
+ var changelogPage = (ctx) => pageFile({
744
+ title: "Changelog",
745
+ path: "/changelog",
746
+ description: `New features and improvements shipped to ${ctx.template.siteName}.`,
747
+ body: ` <section className="mx-auto max-w-3xl px-6 py-24 text-center">
748
+ <Pill>Changelog</Pill>
749
+ <h1 className="mt-4 text-4xl font-bold sm:text-5xl">What&rsquo;s <span className="gradient-text">new</span></h1>
750
+ <p className="mx-auto mt-4 max-w-xl text-lg text-muted">Every improvement we ship to ${ctx.template.siteName}, newest first.</p>
751
+ </section>
752
+ <Section className="pt-0">
753
+ <div className="mx-auto max-w-2xl">
754
+ <Timeline items={[
755
+ { date: "This week", title: "Dark mode everywhere", desc: "A no-flash theme system across every page." },
756
+ { date: "Last week", title: "Faster search", desc: "Command palette results now feel instant." },
757
+ { date: "Earlier", title: "Team roles", desc: "Invite teammates with granular permissions." },
758
+ { date: "Launch", title: "Hello, world \u{1F44B}", desc: "The first public release." },
759
+ ]} />
760
+ </div>
761
+ </Section>`
762
+ });
763
+ var galleryPage = (ctx) => pageFile({
764
+ title: "Gallery",
765
+ path: "/gallery",
766
+ description: `A look inside ${ctx.template.siteName}.`,
767
+ cta: { title: "Come see for yourself", subtitle: "Book a table and taste the difference.", label: "Reserve a table", href: "/reservations" },
768
+ body: ` <section className="mx-auto max-w-3xl px-6 py-24 text-center">
769
+ <Pill>Gallery</Pill>
770
+ <h1 className="mt-4 text-4xl font-bold sm:text-5xl">A look <span className="gradient-text">inside</span></h1>
771
+ <p className="mx-auto mt-4 max-w-xl text-lg text-muted">The room, the plates, the little details that make ${ctx.template.siteName}.</p>
772
+ </section>
773
+ <Section className="pt-0">
774
+ <Gallery items={[
775
+ { emoji: "\u{1F37D}\uFE0F", label: "The dining room" },
776
+ { emoji: "\u{1F958}", label: "Signature dish" },
777
+ { emoji: "\u{1F377}", label: "Cellar" },
778
+ { emoji: "\u{1F468}\u200D\u{1F373}", label: "The kitchen" },
779
+ { emoji: "\u{1F370}", label: "Desserts" },
780
+ { emoji: "\u{1F33F}", label: "Fresh daily" },
781
+ ]} />
782
+ </Section>`
783
+ });
784
+ var usesPage = (ctx) => pageFile({
785
+ title: "Uses",
786
+ path: "/uses",
787
+ description: `The gear, apps and tools ${ctx.template.siteName} uses every day.`,
788
+ body: ` <section className="mx-auto max-w-3xl px-6 py-24 text-center">
789
+ <Pill>Uses</Pill>
790
+ <h1 className="mt-4 text-4xl font-bold sm:text-5xl">What I <span className="gradient-text">use</span></h1>
791
+ <p className="mx-auto mt-4 max-w-xl text-lg text-muted">The gear and software behind the work.</p>
792
+ </section>
793
+ <Section title="Editor & tools" className="pt-0">
794
+ <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
795
+ {[
796
+ { icon: "\u{1F5A5}\uFE0F", title: "VS Code", desc: "My editor of choice, tuned to the bone." },
797
+ { icon: "\u26A1", title: "Next.js", desc: "The React framework behind everything I ship." },
798
+ { icon: "\u{1F3A8}", title: "Figma", desc: "Where every design starts." },
799
+ { icon: "\u2328\uFE0F", title: "Raycast", desc: "Launcher, clipboard history and snippets." },
800
+ { icon: "\u{1F9E0}", title: "Obsidian", desc: "Notes and a second brain." },
801
+ { icon: "\u{1F3A7}", title: "Focus playlist", desc: "Lo-fi, always." },
802
+ ].map((f) => <FeatureCard key={f.title} icon={f.icon} title={f.title} desc={f.desc} />)}
803
+ </div>
804
+ </Section>`
805
+ });
806
+ var richPage = (ctx, cfg) => {
807
+ const r = richContent(ctx);
808
+ const showcase = cfg.extra ?? `<Section eyebrow="Loved by teams" title="Don't just take our word for it" className="pt-0">
809
+ <div className="grid gap-6 md:grid-cols-3">
810
+ ${r.testimonials.map((t) => `<Testimonial quote={${JSON.stringify(t.quote)}} author={${JSON.stringify(t.author)}} role={${JSON.stringify(t.role ?? "")}} />`).join("\n ")}
811
+ </div>
812
+ </Section>`;
813
+ return pageFile({
814
+ title: cfg.title,
815
+ path: cfg.path,
816
+ description: cfg.description,
817
+ cta: cfg.cta,
818
+ body: ` <section className="mx-auto max-w-3xl px-6 py-24 text-center">
819
+ <Pill>${cfg.eyebrow}</Pill>
820
+ <h1 className="mt-4 text-4xl font-bold sm:text-5xl">${cfg.heading}</h1>
821
+ <p className="mx-auto mt-4 max-w-xl text-lg text-muted">${cfg.lead}</p>
822
+ </section>
823
+ <Section className="pt-0">
824
+ <FeatureSplit eyebrow=${JSON.stringify(cfg.split.eyebrow ?? "")} title=${JSON.stringify(cfg.split.title)} desc=${JSON.stringify(cfg.split.desc)} bullets={${JSON.stringify(cfg.split.bullets)}} media={<div className="grid h-52 place-items-center text-7xl">${cfg.split.emoji}</div>} />
825
+ </Section>
826
+ <Section className="pt-0"><StatBand stats={${JSON.stringify(r.stats)}} /></Section>
827
+ <Section eyebrow="Highlights" title="What you get" className="pt-0">
828
+ <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
829
+ {${JSON.stringify(cfg.features)}.map((f) => <FeatureCard key={f.title} icon={f.icon} title={f.title} desc={f.desc} />)}
830
+ </div>
831
+ </Section>
832
+ ${showcase}`
833
+ });
834
+ };
835
+ var careersPage = (ctx) => {
836
+ const n = ctx.template.siteName;
837
+ return richPage(ctx, {
838
+ title: "Careers",
839
+ path: "/careers",
840
+ eyebrow: "Careers",
841
+ description: `Join the team building ${n}.`,
842
+ heading: `Join the <span className="gradient-text">team</span>`,
843
+ lead: `We're a small team doing our best work. If that sounds like you, say hello.`,
844
+ split: { eyebrow: "Why us", title: "A place to do your best work", desc: "Small team, big ownership, and the support to grow.", bullets: ["Remote-first and async-friendly", "Real ownership from day one", "Learning budget and great gear"], emoji: "\u{1F680}" },
845
+ features: [
846
+ { icon: "\u{1F30D}", title: "Remote-first", desc: "Work from anywhere, on your schedule." },
847
+ { icon: "\u{1F4C8}", title: "Grow fast", desc: "Mentorship and a budget to level up." },
848
+ { icon: "\u{1F91D}", title: "Real ownership", desc: "Ship things that matter, end to end." },
849
+ { icon: "\u{1F3D6}\uFE0F", title: "Time to recharge", desc: "Generous, actually-used time off." },
850
+ { icon: "\u{1F499}", title: "Great people", desc: "Kind, sharp teammates who have your back." },
851
+ { icon: "\u{1F4B8}", title: "Fair pay", desc: "Transparent, competitive compensation." }
852
+ ],
853
+ extra: `<Section eyebrow="Open roles" title="We're hiring" className="pt-0">
854
+ <div className="mx-auto grid max-w-3xl gap-4">
855
+ {[
856
+ { role: "Senior Frontend Engineer", team: "Engineering", type: "Full-time \xB7 Remote" },
857
+ { role: "Product Designer", team: "Design", type: "Full-time \xB7 Remote" },
858
+ { role: "Developer Advocate", team: "Growth", type: "Full-time \xB7 Remote" },
859
+ ].map((j) => (
860
+ <div key={j.role} className="flex flex-wrap items-center justify-between gap-3 rounded-2xl border border-hairline bg-surface p-5">
861
+ <div><h3 className="font-semibold">{j.role}</h3><p className="text-sm text-muted">{j.team}</p></div>
862
+ <div className="flex items-center gap-3"><Badge>{j.type}</Badge><a href="/contact" className="rounded-full gradient-bg px-4 py-2 text-sm font-semibold text-black">Apply</a></div>
863
+ </div>
864
+ ))}
865
+ </div>
866
+ </Section>`,
867
+ cta: { title: "Don't see your role?", subtitle: "We're always keen to meet great people.", label: "Send an intro", href: "/contact" }
868
+ });
869
+ };
870
+ var collectionsPage = (ctx) => richPage(ctx, {
871
+ title: "Collections",
872
+ path: "/collections",
873
+ eyebrow: "Collections",
874
+ description: `Shop ${ctx.template.siteName} by collection.`,
875
+ heading: `Shop by <span className="gradient-text">collection</span>`,
876
+ lead: "Curated edits for every season and style.",
877
+ split: { eyebrow: "Featured", title: "This season's edit", desc: "Hand-picked pieces our team is loving right now.", bullets: ["Free shipping over $50", "30-day easy returns", "Ethically sourced"], emoji: "\u{1F6CD}\uFE0F" },
878
+ features: [
879
+ { icon: "\u{1F9E5}", title: "New arrivals", desc: "Fresh drops, added weekly." },
880
+ { icon: "\u{1F525}", title: "Best sellers", desc: "The pieces everyone's buying." },
881
+ { icon: "\u{1F331}", title: "Sustainable", desc: "Made to last, kind to the planet." },
882
+ { icon: "\u{1F381}", title: "Gifting", desc: "Thoughtful picks for everyone." },
883
+ { icon: "\u{1F48E}", title: "Premium", desc: "Elevated essentials worth the splurge." },
884
+ { icon: "\u{1F3F7}\uFE0F", title: "Sale", desc: "Up to 40% off, while stocks last." }
885
+ ],
886
+ extra: `<Section eyebrow="Browse" title="Explore the collections" className="pt-0">
887
+ <Gallery items={[
888
+ { emoji: "\u{1F9E5}", label: "Outerwear" }, { emoji: "\u{1F45F}", label: "Footwear" }, { emoji: "\u{1F45C}", label: "Bags" },
889
+ { emoji: "\u231A", label: "Accessories" }, { emoji: "\u{1F576}\uFE0F", label: "Eyewear" }, { emoji: "\u{1F9E2}", label: "Headwear" },
890
+ ]} />
891
+ </Section>`,
892
+ cta: { title: "Ready to shop?", subtitle: "Your next favourite thing is waiting.", label: "Browse the shop", href: "/shop" }
893
+ });
894
+ var businessWorkPage = (ctx) => richPage(ctx, {
895
+ title: "Work",
896
+ path: "/work",
897
+ eyebrow: "Case studies",
898
+ description: `Selected work from ${ctx.template.siteName}.`,
899
+ heading: `Work that <span className="gradient-text">performs</span>`,
900
+ lead: "A few recent projects and the outcomes they drove.",
901
+ split: { eyebrow: "How we work", title: "Outcomes, not just output", desc: "We measure success by the numbers that move your business.", bullets: ["Discovery-led, evidence-based", "Ship weekly, learn faster", "Own the result together"], emoji: "\u{1F4CA}" },
902
+ features: [
903
+ { icon: "\u{1F6D2}", title: "Northwind Commerce", desc: "+38% conversion after a full storefront rebuild." },
904
+ { icon: "\u{1F3E6}", title: "Globex Fintech", desc: "Onboarding time cut from 9 minutes to under 2." },
905
+ { icon: "\u{1F393}", title: "Initech Learning", desc: "2.4\xD7 course completions with a redesigned LMS." },
906
+ { icon: "\u{1F69A}", title: "Umbrella Logistics", desc: "Real-time tracking that cut support tickets 45%." },
907
+ { icon: "\u{1F3E5}", title: "Soylent Health", desc: "HIPAA-ready portal shipped in eight weeks." },
908
+ { icon: "\u{1F4F1}", title: "Hooli Mobile", desc: "A 4.9\u2605 app rebuilt from the ground up." }
909
+ ],
910
+ cta: { title: "Have a project in mind?", subtitle: "Tell us the outcome you're after \u2014 we'll map the path.", label: "Start a project", href: "/contact" }
911
+ });
912
+ var apiRefPage = (ctx) => richPage(ctx, {
913
+ title: "API Reference",
914
+ path: "/api-reference",
915
+ eyebrow: "API",
916
+ description: `The ${ctx.template.siteName} REST API reference.`,
917
+ heading: `The <span className="gradient-text">API</span> reference`,
918
+ lead: "A predictable, typed REST API with sensible defaults.",
919
+ split: { eyebrow: "Basics", title: "REST, done right", desc: "JSON everywhere, cursor pagination, and clear error codes.", bullets: ["Bearer-token auth", "Idempotent writes", "Webhooks for every event"], emoji: "\u{1F50C}" },
920
+ features: [
921
+ { icon: "\u{1F511}", title: "POST /auth/token", desc: "Exchange credentials for an access token." },
922
+ { icon: "\u{1F464}", title: "GET /users/:id", desc: "Fetch a single user by id." },
923
+ { icon: "\u{1F4E6}", title: "GET /resources", desc: "List resources with cursor pagination." },
924
+ { icon: "\u270F\uFE0F", title: "PATCH /resources/:id", desc: "Partially update a resource." },
925
+ { icon: "\u{1F5D1}\uFE0F", title: "DELETE /resources/:id", desc: "Remove a resource (idempotent)." },
926
+ { icon: "\u{1FA9D}", title: "POST /webhooks", desc: "Subscribe to real-time events." }
927
+ ],
928
+ extra: `<Section eyebrow="Examples" title="Common requests" className="pt-0">
929
+ <div className="mx-auto max-w-3xl"><Accordion items={[
930
+ { q: "Authenticate", a: "curl -X POST /auth/token -d '{ \\"key\\": \\"...\\" }' \u2014 returns a bearer token valid for 24h." },
931
+ { q: "List with pagination", a: "GET /resources?limit=20&cursor=... \u2014 responses include a next_cursor field." },
932
+ { q: "Handle errors", a: "Every error returns a JSON body with a code and message, plus the right HTTP status." },
933
+ ]} /></div>
934
+ </Section>`,
935
+ cta: { title: "Need a hand?", subtitle: "Our team is happy to help you integrate.", label: "Talk to us", href: "/contact" }
936
+ });
937
+ var reservationsPage = (ctx) => {
938
+ const n = ctx.template.siteName;
939
+ return richPage(ctx, {
940
+ title: "Reservations",
941
+ path: "/reservations",
942
+ eyebrow: "Reservations",
943
+ description: `Book your table at ${n}.`,
944
+ heading: `Reserve your <span className="gradient-text">table</span>`,
945
+ lead: `We can't wait to host you at ${n}. Book ahead \u2014 we fill up fast.`,
946
+ split: { eyebrow: "Good to know", title: "Everything for a perfect evening", desc: "Walk-ins welcome, but reservations are recommended, especially on weekends.", bullets: ["Parties up to 12 online", "Private dining available", "Dietary needs? Just ask"], emoji: "\u{1F37D}\uFE0F" },
947
+ features: [
948
+ { icon: "\u{1F570}\uFE0F", title: "Lunch", desc: "Tue\u2013Fri \xB7 12:00\u201315:00" },
949
+ { icon: "\u{1F319}", title: "Dinner", desc: "Tue\u2013Sun \xB7 18:00\u201323:00" },
950
+ { icon: "\u{1F942}", title: "Weekend brunch", desc: "Sat\u2013Sun \xB7 10:00\u201314:00" },
951
+ { icon: "\u{1F389}", title: "Private events", desc: "Book the whole room." },
952
+ { icon: "\u{1F697}", title: "Parking", desc: "Valet available on evenings." },
953
+ { icon: "\u267F", title: "Accessible", desc: "Step-free access throughout." }
954
+ ],
955
+ extra: `<Section className="pt-0">
956
+ <div className="mx-auto max-w-2xl rounded-3xl border border-hairline bg-surface p-8 text-center">
957
+ <h2 className="text-2xl font-bold">Book by phone or online</h2>
958
+ <p className="mt-3 text-muted">Call us on <span className="font-semibold text-fg">+1 (555) 012-3456</span> or reserve online in seconds.</p>
959
+ <a href="/contact" className="mt-6 inline-block rounded-full gradient-bg px-8 py-3 font-semibold text-black">Reserve a table</a>
960
+ </div>
961
+ </Section>`,
962
+ cta: { title: "Planning something special?", subtitle: "Ask us about private dining and set menus.", label: "Enquire now", href: "/contact" }
963
+ });
964
+ };
965
+ var eventsPage = (ctx) => richPage(ctx, {
966
+ title: "Private events",
967
+ path: "/events",
968
+ eyebrow: "Private events",
969
+ description: `Host your event at ${ctx.template.siteName}.`,
970
+ heading: `Your event, <span className="gradient-text">elevated</span>`,
971
+ lead: "From intimate dinners to full buy-outs \u2014 we'll make it unforgettable.",
972
+ split: { eyebrow: "Occasions", title: "Made for the moments that matter", desc: "Birthdays, launches, weddings and everything in between.", bullets: ["Bespoke set menus", "Dedicated event host", "AV and styling on request"], emoji: "\u{1F389}" },
973
+ features: [
974
+ { icon: "\u{1F382}", title: "Celebrations", desc: "Birthdays and anniversaries, done right." },
975
+ { icon: "\u{1F4BC}", title: "Corporate", desc: "Launches, offsites and client dinners." },
976
+ { icon: "\u{1F48D}", title: "Weddings", desc: "Rehearsal dinners and receptions." },
977
+ { icon: "\u{1F377}", title: "Tastings", desc: "Guided wine and menu pairings." },
978
+ { icon: "\u{1F465}", title: "Buy-outs", desc: "The whole space, just for you." },
979
+ { icon: "\u{1F3B6}", title: "Live music", desc: "We'll arrange the perfect soundtrack." }
980
+ ],
981
+ cta: { title: "Let's plan your event", subtitle: "Tell us the date and the vibe \u2014 we'll handle the rest.", label: "Start planning", href: "/contact" }
682
982
  });
683
-
684
- export default function AboutPage() {
685
- return (
686
- <main className="mx-auto max-w-3xl px-6 py-28">
687
- <Link href="/" className="text-sm text-muted hover:text-fg">\u2190 Back home</Link>
688
- <h1 className="mt-6 text-4xl font-black sm:text-5xl gradient-text">About</h1>
689
- <p className="mt-6 text-lg leading-relaxed text-muted">
690
- This page already has its own SEO \u2014 a unique title, canonical URL, Open Graph tags and a
691
- generated social image \u2014 from a single <code>site.meta()</code> call. Duplicate this file for
692
- any new route and it just works.
693
- </p>
694
- </main>
695
- );
696
- }
697
- `;
698
983
  var themeToggle = () => `"use client";
699
984
 
700
985
  import { useTheme } from "@lacspace/theme";
@@ -1476,13 +1761,13 @@ function buildFiles(ctx) {
1476
1761
  "WELCOME.md": welcomeMd(ctx)
1477
1762
  };
1478
1763
  const isDash = ctx.template.key === "dashboard";
1764
+ files["components/aurora.tsx"] = aurora();
1479
1765
  if (isDash) {
1480
1766
  files["components/dashboard-shell.tsx"] = dashboardShell(ctx);
1481
1767
  } else {
1482
1768
  files["components/site-header.tsx"] = siteHeader(ctx);
1483
1769
  files["components/site-footer.tsx"] = siteFooter(ctx);
1484
1770
  files["components/announcement-bar.tsx"] = announcementBar();
1485
- files["components/aurora.tsx"] = aurora();
1486
1771
  files["components/hero-art.tsx"] = heroArt(ctx);
1487
1772
  }
1488
1773
  for (const page of stubPages(ctx)) {
@@ -1523,7 +1808,8 @@ function pagesFor(ctx) {
1523
1808
  const common = [
1524
1809
  { path: "/about", label: "About", nav: true, group: "Company", real: true },
1525
1810
  { path: "/contact", label: "Contact", nav: true, group: "Company", real: true },
1526
- { path: "/careers", label: "Careers", group: "Company" },
1811
+ { path: "/careers", label: "Careers", group: "Company", real: true },
1812
+ { path: "/faq", label: "FAQ", group: "Resources", real: true },
1527
1813
  { path: "/privacy", label: "Privacy", group: "Resources" },
1528
1814
  { path: "/terms", label: "Terms", group: "Resources" }
1529
1815
  ];
@@ -1531,17 +1817,16 @@ function pagesFor(ctx) {
1531
1817
  personal: [
1532
1818
  { path: "/work", label: "Work", nav: true, group: "Product", real: true },
1533
1819
  { path: "/blog", label: "Blog", nav: true, group: "Product" },
1534
- { path: "/uses", label: "Uses", group: "Resources" }
1820
+ { path: "/uses", label: "Uses", group: "Resources", real: true }
1535
1821
  ],
1536
1822
  business: [
1537
1823
  { path: "/services", label: "Services", nav: true, group: "Product", real: true },
1538
- { path: "/work", label: "Work", nav: true, group: "Product" },
1539
- { path: "/pricing", label: "Pricing", nav: true, group: "Product", real: true },
1540
- { path: "/faq", label: "FAQ", group: "Resources" }
1824
+ { path: "/work", label: "Work", nav: true, group: "Product", real: true },
1825
+ { path: "/pricing", label: "Pricing", nav: true, group: "Product", real: true }
1541
1826
  ],
1542
1827
  ecommerce: [
1543
1828
  { path: "/shop", label: "Shop", nav: true, group: "Product", real: true },
1544
- { path: "/collections", label: "Collections", nav: true, group: "Product" },
1829
+ { path: "/collections", label: "Collections", nav: true, group: "Product", real: true },
1545
1830
  { path: "/cart", label: "Cart", group: "Product", real: true },
1546
1831
  { path: "/shipping", label: "Shipping", group: "Resources" },
1547
1832
  { path: "/returns", label: "Returns", group: "Resources" }
@@ -1549,8 +1834,8 @@ function pagesFor(ctx) {
1549
1834
  saas: [
1550
1835
  { path: "/features", label: "Features", nav: true, group: "Product", real: true },
1551
1836
  { path: "/pricing", label: "Pricing", nav: true, group: "Product", real: true },
1552
- { path: "/integrations", label: "Integrations", group: "Product" },
1553
- { path: "/changelog", label: "Changelog", group: "Resources" }
1837
+ { path: "/integrations", label: "Integrations", group: "Product", real: true },
1838
+ { path: "/changelog", label: "Changelog", group: "Resources", real: true }
1554
1839
  ],
1555
1840
  blog: [
1556
1841
  { path: "/blog", label: "Articles", nav: true, group: "Product", real: true },
@@ -1560,14 +1845,14 @@ function pagesFor(ctx) {
1560
1845
  docs: [
1561
1846
  { path: "/docs", label: "Docs", nav: true, group: "Product", real: true },
1562
1847
  { path: "/guides", label: "Guides", nav: true, group: "Product", real: true },
1563
- { path: "/api-reference", label: "API", nav: true, group: "Product" },
1564
- { path: "/changelog", label: "Changelog", group: "Resources" }
1848
+ { path: "/api-reference", label: "API", nav: true, group: "Product", real: true },
1849
+ { path: "/changelog", label: "Changelog", group: "Resources", real: true }
1565
1850
  ],
1566
1851
  restaurant: [
1567
1852
  { path: "/menu", label: "Menu", nav: true, group: "Product", real: true },
1568
- { path: "/reservations", label: "Reservations", nav: true, group: "Product" },
1569
- { path: "/gallery", label: "Gallery", nav: true, group: "Product" },
1570
- { path: "/events", label: "Private events", group: "Resources" }
1853
+ { path: "/reservations", label: "Reservations", nav: true, group: "Product", real: true },
1854
+ { path: "/gallery", label: "Gallery", nav: true, group: "Product", real: true },
1855
+ { path: "/events", label: "Private events", group: "Resources", real: true }
1571
1856
  ]
1572
1857
  };
1573
1858
  return [...specific[k] ?? [], ...common];
@@ -1946,7 +2231,7 @@ var pageFile = (o) => `import type { Metadata } from "next";
1946
2231
  import Link from "next/link";
1947
2232
  import { site } from "@/lib/site";
1948
2233
  import { Aurora } from "@/components/aurora";
1949
- import { Section, Pill, StatCard, FeatureCard, Testimonial, Steps, CTABand, Bento, AreaChart, Newsletter } from "@/components/ui";
2234
+ import { Section, Pill, StatCard, FeatureCard, Testimonial, Steps, CTABand, Bento, AreaChart, Newsletter, Badge, Callout, Accordion, FAQ, Tabs, Timeline, PricingTable, LogoCloud, StatBand, TeamGrid, FeatureSplit, Gallery, Rating, Progress, Breadcrumbs, Avatar, AvatarGroup } from "@/components/ui";
1950
2235
 
1951
2236
  export const metadata: Metadata = site.meta({ title: ${JSON.stringify(o.title)}, path: ${JSON.stringify(o.path)}, description: ${JSON.stringify(o.description)} });
1952
2237
 
@@ -2560,6 +2845,244 @@ export function Newsletter({ title = "Stay in the loop", subtitle = "Occasional
2560
2845
  </div>
2561
2846
  );
2562
2847
  }
2848
+ `,
2849
+ "components/ui/badge.tsx": `import type { ReactNode } from "react";
2850
+
2851
+ const tones = {
2852
+ default: "border-hairline bg-surface text-muted",
2853
+ accent: "border-transparent gradient-bg text-black",
2854
+ success: "border-emerald-500/30 bg-emerald-500/10 text-emerald-400",
2855
+ warning: "border-amber-500/30 bg-amber-500/10 text-amber-400",
2856
+ danger: "border-red-500/30 bg-red-500/10 text-red-400",
2857
+ } as const;
2858
+
2859
+ export function Badge({ children, tone = "default", className = "" }: { children: ReactNode; tone?: keyof typeof tones; className?: string }) {
2860
+ return <span className={"inline-flex items-center gap-1 rounded-full border px-2.5 py-0.5 text-xs font-semibold " + tones[tone] + " " + className}>{children}</span>;
2861
+ }
2862
+ `,
2863
+ "components/ui/callout.tsx": `import type { ReactNode } from "react";
2864
+
2865
+ const tones = {
2866
+ info: { c: "border-sky-500/30 bg-sky-500/10", i: "\u{1F4A1}" },
2867
+ success: { c: "border-emerald-500/30 bg-emerald-500/10", i: "\u2705" },
2868
+ warning: { c: "border-amber-500/30 bg-amber-500/10", i: "\u26A0\uFE0F" },
2869
+ danger: { c: "border-red-500/30 bg-red-500/10", i: "\u26D4" },
2870
+ } as const;
2871
+
2872
+ export function Callout({ children, title, tone = "info" }: { children: ReactNode; title?: string; tone?: keyof typeof tones }) {
2873
+ const t = tones[tone];
2874
+ return (
2875
+ <div className={"flex gap-3 rounded-2xl border p-4 " + t.c}>
2876
+ <div className="text-lg leading-none">{t.i}</div>
2877
+ <div className="text-sm">
2878
+ {title ? <p className="font-semibold">{title}</p> : null}
2879
+ <div className="text-muted">{children}</div>
2880
+ </div>
2881
+ </div>
2882
+ );
2883
+ }
2884
+ `,
2885
+ "components/ui/accordion.tsx": `export function Accordion({ items }: { items: { q: string; a: string }[] }) {
2886
+ return (
2887
+ <div className="overflow-hidden rounded-2xl border border-hairline bg-surface">
2888
+ {items.map((it, i) => (
2889
+ <details key={it.q} className={"group px-6 " + (i > 0 ? "border-t border-hairline" : "")}>
2890
+ <summary className="flex cursor-pointer list-none items-center justify-between py-4 font-medium">
2891
+ {it.q}
2892
+ <span className="ml-4 text-muted transition group-open:rotate-45">+</span>
2893
+ </summary>
2894
+ <p className="pb-5 text-sm leading-relaxed text-muted">{it.a}</p>
2895
+ </details>
2896
+ ))}
2897
+ </div>
2898
+ );
2899
+ }
2900
+ `,
2901
+ "components/ui/faq.tsx": `export function FAQ({ items, title }: { items: { q: string; a: string }[]; title?: string }) {
2902
+ return (
2903
+ <div className="mx-auto max-w-3xl">
2904
+ {title ? <h2 className="mb-8 text-center text-3xl font-bold sm:text-4xl">{title}</h2> : null}
2905
+ <div className="overflow-hidden rounded-2xl border border-hairline bg-surface">
2906
+ {items.map((it, i) => (
2907
+ <details key={it.q} className={"group px-6 " + (i > 0 ? "border-t border-hairline" : "")}>
2908
+ <summary className="flex cursor-pointer list-none items-center justify-between py-4 font-medium">{it.q}<span className="ml-4 text-muted transition group-open:rotate-45">+</span></summary>
2909
+ <p className="pb-5 text-sm leading-relaxed text-muted">{it.a}</p>
2910
+ </details>
2911
+ ))}
2912
+ </div>
2913
+ </div>
2914
+ );
2915
+ }
2916
+ `,
2917
+ "components/ui/tabs.tsx": `"use client";
2918
+
2919
+ import { useState, type ReactNode } from "react";
2920
+
2921
+ export function Tabs({ tabs }: { tabs: { label: string; content: ReactNode }[] }) {
2922
+ const [i, setI] = useState(0);
2923
+ return (
2924
+ <div>
2925
+ <div className="inline-flex flex-wrap gap-1 rounded-full border border-hairline bg-surface p-1">
2926
+ {tabs.map((t, idx) => (
2927
+ <button key={t.label} onClick={() => setI(idx)} className={"rounded-full px-4 py-2 text-sm font-medium transition " + (i === idx ? "gradient-bg text-black" : "text-muted hover:text-fg")}>{t.label}</button>
2928
+ ))}
2929
+ </div>
2930
+ <div className="mt-6">{tabs[i]?.content}</div>
2931
+ </div>
2932
+ );
2933
+ }
2934
+ `,
2935
+ "components/ui/timeline.tsx": `export function Timeline({ items }: { items: { date?: string; title: string; desc?: string }[] }) {
2936
+ return (
2937
+ <ol className="relative ml-3 border-l border-hairline">
2938
+ {items.map((it) => (
2939
+ <li key={it.title} className="mb-8 ml-6">
2940
+ <span aria-hidden className="absolute -left-[7px] mt-1.5 h-3 w-3 rounded-full gradient-bg" />
2941
+ {it.date ? <p className="text-xs font-semibold uppercase tracking-widest text-faint">{it.date}</p> : null}
2942
+ <h3 className="mt-1 font-semibold">{it.title}</h3>
2943
+ {it.desc ? <p className="mt-1 text-sm text-muted">{it.desc}</p> : null}
2944
+ </li>
2945
+ ))}
2946
+ </ol>
2947
+ );
2948
+ }
2949
+ `,
2950
+ "components/ui/pricing-table.tsx": `import Link from "next/link";
2951
+
2952
+ interface Tier { name: string; price: string; period?: string; features: string[]; ctaLabel?: string; ctaHref?: string; featured?: boolean; }
2953
+
2954
+ export function PricingTable({ tiers }: { tiers: Tier[] }) {
2955
+ return (
2956
+ <div className="grid gap-6 md:grid-cols-3">
2957
+ {tiers.map((t) => (
2958
+ <div key={t.name} className={"relative flex flex-col rounded-3xl border p-8 " + (t.featured ? "border-[color:var(--accent-to)] bg-surface shadow-lg" : "border-hairline bg-surface")}>
2959
+ {t.featured ? <span className="absolute -top-3 left-8 rounded-full gradient-bg px-3 py-1 text-xs font-bold text-black">Most popular</span> : null}
2960
+ <h3 className="font-semibold">{t.name}</h3>
2961
+ <div className="mt-3 flex items-end gap-1"><span className="text-4xl font-bold">{t.price}</span>{t.period ? <span className="mb-1 text-sm text-muted">/{t.period}</span> : null}</div>
2962
+ <ul className="mt-6 flex-1 space-y-2 text-sm text-muted">
2963
+ {t.features.map((f) => <li key={f} className="flex gap-2"><span className="gradient-text">\u2713</span>{f}</li>)}
2964
+ </ul>
2965
+ <Link href={t.ctaHref ?? "/contact"} className={"mt-8 rounded-full px-6 py-3 text-center font-semibold transition " + (t.featured ? "gradient-bg text-black hover:opacity-90" : "border border-hairline hover:bg-app")}>{t.ctaLabel ?? "Choose " + t.name}</Link>
2966
+ </div>
2967
+ ))}
2968
+ </div>
2969
+ );
2970
+ }
2971
+ `,
2972
+ "components/ui/logo-cloud.tsx": `export function LogoCloud({ names, label }: { names: string[]; label?: string }) {
2973
+ return (
2974
+ <div className="text-center">
2975
+ {label ? <p className="text-sm font-semibold uppercase tracking-widest text-faint">{label}</p> : null}
2976
+ <div className="mt-6 flex flex-wrap items-center justify-center gap-x-10 gap-y-4">
2977
+ {names.map((n) => <span key={n} className="text-lg font-bold text-muted opacity-70 transition hover:opacity-100">{n}</span>)}
2978
+ </div>
2979
+ </div>
2980
+ );
2981
+ }
2982
+ `,
2983
+ "components/ui/stat-band.tsx": `export function StatBand({ stats }: { stats: { value: string; label: string }[] }) {
2984
+ return (
2985
+ <div className="grid gap-6 rounded-3xl border border-hairline bg-surface p-8 sm:grid-cols-2 lg:grid-cols-4">
2986
+ {stats.map((s) => (
2987
+ <div key={s.label} className="text-center">
2988
+ <div className="gradient-text text-4xl font-bold tabular-nums">{s.value}</div>
2989
+ <div className="mt-1 text-sm text-muted">{s.label}</div>
2990
+ </div>
2991
+ ))}
2992
+ </div>
2993
+ );
2994
+ }
2995
+ `,
2996
+ "components/ui/team-grid.tsx": `export function TeamGrid({ members }: { members: { name: string; role: string; bio?: string }[] }) {
2997
+ return (
2998
+ <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
2999
+ {members.map((m) => (
3000
+ <div key={m.name} className="rounded-2xl border border-hairline bg-surface p-6 text-center transition hover:-translate-y-1">
3001
+ <div className="mx-auto flex h-16 w-16 items-center justify-center rounded-full gradient-bg text-xl font-bold text-black">{m.name.split(" ").map((x) => x[0]).join("").slice(0, 2)}</div>
3002
+ <h3 className="mt-4 font-semibold">{m.name}</h3>
3003
+ <p className="gradient-text text-sm">{m.role}</p>
3004
+ {m.bio ? <p className="mt-2 text-sm text-muted">{m.bio}</p> : null}
3005
+ </div>
3006
+ ))}
3007
+ </div>
3008
+ );
3009
+ }
3010
+ `,
3011
+ "components/ui/feature-split.tsx": `import type { ReactNode } from "react";
3012
+
3013
+ export function FeatureSplit({ eyebrow, title, desc, bullets, media, reverse = false }: { eyebrow?: string; title: string; desc?: string; bullets?: string[]; media?: ReactNode; reverse?: boolean }) {
3014
+ return (
3015
+ <div className={"grid items-center gap-10 md:grid-cols-2 " + (reverse ? "md:[&>*:first-child]:order-2" : "")}>
3016
+ <div>
3017
+ {eyebrow ? <p className="text-sm font-semibold uppercase tracking-widest text-faint">{eyebrow}</p> : null}
3018
+ <h2 className="mt-3 text-3xl font-bold sm:text-4xl">{title}</h2>
3019
+ {desc ? <p className="mt-4 text-lg text-muted">{desc}</p> : null}
3020
+ {bullets ? <ul className="mt-6 space-y-2 text-muted">{bullets.map((b) => <li key={b} className="flex gap-2"><span className="gradient-text">\u2713</span>{b}</li>)}</ul> : null}
3021
+ </div>
3022
+ <div className="relative overflow-hidden rounded-3xl border border-hairline bg-surface p-8">
3023
+ <div aria-hidden className="pointer-events-none absolute -right-10 -top-10 h-40 w-40 rounded-full gradient-bg opacity-30 blur-3xl" />
3024
+ <div className="relative">{media ?? <div className="grid h-48 place-items-center text-5xl">\u2728</div>}</div>
3025
+ </div>
3026
+ </div>
3027
+ );
3028
+ }
3029
+ `,
3030
+ "components/ui/gallery.tsx": `export function Gallery({ items }: { items: { label?: string; emoji?: string }[] }) {
3031
+ return (
3032
+ <div className="grid grid-cols-2 gap-4 sm:grid-cols-3">
3033
+ {items.map((it, i) => (
3034
+ <div key={i} className="group relative grid aspect-square place-items-center overflow-hidden rounded-2xl border border-hairline bg-surface">
3035
+ <div aria-hidden className="pointer-events-none absolute inset-0 gradient-bg opacity-10 transition group-hover:opacity-20" />
3036
+ <span className="relative text-4xl">{it.emoji ?? "\u{1F5BC}\uFE0F"}</span>
3037
+ {it.label ? <span className="absolute bottom-2 left-3 text-xs text-muted">{it.label}</span> : null}
3038
+ </div>
3039
+ ))}
3040
+ </div>
3041
+ );
3042
+ }
3043
+ `,
3044
+ "components/ui/rating.tsx": `export function Rating({ value = 5, count }: { value?: number; count?: number }) {
3045
+ return (
3046
+ <div className="inline-flex items-center gap-1 text-amber-400" aria-label={value + " out of 5"}>
3047
+ {[0, 1, 2, 3, 4].map((i) => <span key={i}>{i < Math.round(value) ? "\u2605" : "\u2606"}</span>)}
3048
+ {count ? <span className="ml-1 text-sm text-muted">({count})</span> : null}
3049
+ </div>
3050
+ );
3051
+ }
3052
+ `,
3053
+ "components/ui/progress.tsx": `export function Progress({ value, label }: { value: number; label?: string }) {
3054
+ const v = Math.max(0, Math.min(100, value));
3055
+ return (
3056
+ <div>
3057
+ {label ? <div className="mb-1 flex justify-between text-sm"><span>{label}</span><span className="text-muted">{v}%</span></div> : null}
3058
+ <div className="h-2 overflow-hidden rounded-full bg-app"><div className="h-full gradient-bg" style={{ width: v + "%" }} /></div>
3059
+ </div>
3060
+ );
3061
+ }
3062
+ `,
3063
+ "components/ui/breadcrumbs.tsx": `import Link from "next/link";
3064
+
3065
+ export function Breadcrumbs({ items }: { items: { label: string; href?: string }[] }) {
3066
+ return (
3067
+ <nav aria-label="Breadcrumb" className="flex flex-wrap items-center gap-2 text-sm text-muted">
3068
+ {items.map((it, i) => (
3069
+ <span key={it.label} className="flex items-center gap-2">
3070
+ {it.href ? <Link href={it.href} className="hover:text-fg">{it.label}</Link> : <span className="text-fg">{it.label}</span>}
3071
+ {i < items.length - 1 ? <span aria-hidden className="text-faint">/</span> : null}
3072
+ </span>
3073
+ ))}
3074
+ </nav>
3075
+ );
3076
+ }
3077
+ `,
3078
+ "components/ui/avatar.tsx": `export function Avatar({ name, size = 40 }: { name: string; size?: number }) {
3079
+ const initials = name.split(" ").map((x) => x[0]).join("").slice(0, 2).toUpperCase();
3080
+ return <span className="inline-flex items-center justify-center rounded-full gradient-bg font-bold text-black" style={{ width: size, height: size, fontSize: size * 0.4 }}>{initials}</span>;
3081
+ }
3082
+
3083
+ export function AvatarGroup({ names }: { names: string[] }) {
3084
+ return <div className="flex -space-x-2">{names.map((n) => <span key={n} className="rounded-full bg-app p-0.5"><Avatar name={n} size={36} /></span>)}</div>;
3085
+ }
2563
3086
  `,
2564
3087
  "components/ui/index.ts": `export * from "./section";
2565
3088
  export * from "./pill";
@@ -2571,23 +3094,50 @@ export * from "./cta-band";
2571
3094
  export * from "./bento";
2572
3095
  export * from "./area-chart";
2573
3096
  export * from "./newsletter";
3097
+ export * from "./badge";
3098
+ export * from "./callout";
3099
+ export * from "./accordion";
3100
+ export * from "./faq";
3101
+ export * from "./tabs";
3102
+ export * from "./timeline";
3103
+ export * from "./pricing-table";
3104
+ export * from "./logo-cloud";
3105
+ export * from "./stat-band";
3106
+ export * from "./team-grid";
3107
+ export * from "./feature-split";
3108
+ export * from "./gallery";
3109
+ export * from "./rating";
3110
+ export * from "./progress";
3111
+ export * from "./breadcrumbs";
3112
+ export * from "./avatar";
2574
3113
  `
2575
3114
  });
2576
3115
  function realPageFiles(ctx) {
2577
3116
  const k = ctx.template.key;
2578
3117
  const f = {};
2579
- if (k === "personal") f["app/work/page.tsx"] = workPage(ctx);
3118
+ if (k !== "dashboard") {
3119
+ f["app/faq/page.tsx"] = faqPage(ctx);
3120
+ f["app/careers/page.tsx"] = careersPage(ctx);
3121
+ }
3122
+ if (k === "personal") {
3123
+ f["app/work/page.tsx"] = workPage(ctx);
3124
+ f["app/uses/page.tsx"] = usesPage(ctx);
3125
+ }
2580
3126
  if (k === "business") {
2581
3127
  f["app/services/page.tsx"] = servicesPage(ctx);
2582
3128
  f["app/pricing/page.tsx"] = pricingPage(ctx);
3129
+ f["app/work/page.tsx"] = businessWorkPage(ctx);
2583
3130
  }
2584
3131
  if (k === "saas") {
2585
3132
  f["app/features/page.tsx"] = featuresPage(ctx);
2586
3133
  f["app/pricing/page.tsx"] = pricingPage(ctx);
3134
+ f["app/integrations/page.tsx"] = integrationsPage(ctx);
3135
+ f["app/changelog/page.tsx"] = changelogPage(ctx);
2587
3136
  }
2588
3137
  if (k === "ecommerce") {
2589
3138
  f["app/shop/page.tsx"] = shopPage(ctx);
2590
3139
  f["app/cart/page.tsx"] = cartPage();
3140
+ f["app/collections/page.tsx"] = collectionsPage(ctx);
2591
3141
  f["components/product-grid.tsx"] = productGrid();
2592
3142
  f["components/cart-view.tsx"] = cartView();
2593
3143
  }
@@ -2595,8 +3145,17 @@ function realPageFiles(ctx) {
2595
3145
  f["app/topics/page.tsx"] = topicsPage();
2596
3146
  f["app/newsletter/page.tsx"] = newsletterPage(ctx);
2597
3147
  }
2598
- if (k === "docs") f["app/guides/page.tsx"] = guidesPage();
2599
- if (k === "restaurant") f["app/menu/page.tsx"] = menuPage(ctx);
3148
+ if (k === "docs") {
3149
+ f["app/guides/page.tsx"] = guidesPage();
3150
+ f["app/changelog/page.tsx"] = changelogPage(ctx);
3151
+ f["app/api-reference/page.tsx"] = apiRefPage(ctx);
3152
+ }
3153
+ if (k === "restaurant") {
3154
+ f["app/menu/page.tsx"] = menuPage(ctx);
3155
+ f["app/gallery/page.tsx"] = galleryPage(ctx);
3156
+ f["app/reservations/page.tsx"] = reservationsPage(ctx);
3157
+ f["app/events/page.tsx"] = eventsPage(ctx);
3158
+ }
2600
3159
  if (k === "dashboard") {
2601
3160
  f["app/settings/page.tsx"] = settingsPage(ctx);
2602
3161
  f["components/settings-panel.tsx"] = settingsPanel();
@@ -2747,6 +3306,95 @@ var heroArt = (ctx) => {
2747
3306
  }
2748
3307
  `;
2749
3308
  };
3309
+ function richContent(ctx) {
3310
+ const n = ctx.template.siteName;
3311
+ const base = {
3312
+ stats: [
3313
+ { value: "10k+", label: "Monthly visitors" },
3314
+ { value: "99.9%", label: "Uptime" },
3315
+ { value: "4.9\u2605", label: "Average rating" },
3316
+ { value: "<1s", label: "Load time" }
3317
+ ],
3318
+ process: [
3319
+ { title: "Discover", desc: `We learn what ${n} needs and map the fastest path to value.` },
3320
+ { title: "Design", desc: "We shape the experience and validate it early with real content." },
3321
+ { title: "Build", desc: "We ship in weekly increments you can see and steer." },
3322
+ { title: "Launch", desc: "We go live, measure, and keep improving together." }
3323
+ ],
3324
+ testimonials: [
3325
+ { quote: `Working with ${n} was the smoothest launch we've had \u2014 everything just worked.`, author: "Sam Rivera", role: "Product Lead" },
3326
+ { quote: "Fast, polished and genuinely easy to build on. Highly recommend.", author: "Jordan Ellis", role: "Founder" },
3327
+ { quote: "The attention to detail shows on every single page.", author: "Priya Nair", role: "Design Director" }
3328
+ ],
3329
+ team: [
3330
+ { name: "Alex Morgan", role: "Founder & CEO", bio: "Sets the vision and keeps us honest." },
3331
+ { name: "Riya Sharma", role: "Head of Design", bio: "Makes every pixel earn its place." },
3332
+ { name: "Chris Doyle", role: "Lead Engineer", bio: "Ships fast without breaking things." }
3333
+ ],
3334
+ values: [
3335
+ { title: "Craft", desc: "We care about the details others skip." },
3336
+ { title: "Speed", desc: "We ship early and iterate in the open." },
3337
+ { title: "Honesty", desc: "Clear pricing, clear timelines, no surprises." },
3338
+ { title: "Partnership", desc: "Your goals are our goals." }
3339
+ ],
3340
+ faqs: [
3341
+ { q: `Is ${n} really production-ready?`, a: `Yes \u2014 every ${n} page is server-rendered, SEO-optimized and ships with sensible security headers out of the box.` },
3342
+ { q: "How do I get started?", a: "Clone the project, run npm install and npm run dev \u2014 you'll have a live site in under a minute." },
3343
+ { q: "Can I customize the design?", a: "Completely. Colours, fonts and layout are token-driven, so a few edits reskin the whole site." },
3344
+ { q: "Is it accessible and fast?", a: "Built mobile-first with semantic HTML, keyboard support and a strong Lighthouse baseline." },
3345
+ { q: "Do you support dark mode?", a: "Yes \u2014 light, dark and system themes with a no-flash script, powered by @lacspace/theme." },
3346
+ { q: "How do I deploy?", a: "Deploy to any Node host or Vercel in one click \u2014 sitemap, robots and OG images are all wired up." }
3347
+ ]
3348
+ };
3349
+ const over = {
3350
+ restaurant: {
3351
+ stats: [
3352
+ { value: "20+", label: "Years serving" },
3353
+ { value: "4.8\u2605", label: "Google rating" },
3354
+ { value: "120", label: "Seats" },
3355
+ { value: "Daily", label: "Fresh menu" }
3356
+ ],
3357
+ process: [
3358
+ { title: "Reserve", desc: `Book your table at ${n} online in seconds.` },
3359
+ { title: "Arrive", desc: "Settle in \u2014 we'll take it from here." },
3360
+ { title: "Savour", desc: "Seasonal plates, made from scratch." }
3361
+ ],
3362
+ testimonials: [
3363
+ { quote: `Best meal we've had all year \u2014 ${n} never misses.`, author: "Dana Lopez", role: "Regular" },
3364
+ { quote: "The tasting menu is an experience. Book ahead!", author: "Marco Bianchi", role: "Food writer" },
3365
+ { quote: "Warm service, unforgettable flavours.", author: "Aisha Khan", role: "Guest" }
3366
+ ]
3367
+ },
3368
+ ecommerce: {
3369
+ stats: [
3370
+ { value: "50k+", label: "Orders shipped" },
3371
+ { value: "4.9\u2605", label: "Customer rating" },
3372
+ { value: "48h", label: "Fast delivery" },
3373
+ { value: "30d", label: "Free returns" }
3374
+ ]
3375
+ }
3376
+ };
3377
+ return { ...base, ...over[ctx.template.key] ?? {} };
3378
+ }
3379
+ var extraHomeSections = (ctx) => {
3380
+ const r = richContent(ctx);
3381
+ const tst = r.testimonials.map((t) => `<Testimonial quote={${JSON.stringify(t.quote)}} author={${JSON.stringify(t.author)}} role={${JSON.stringify(t.role ?? "")}} />`).join("\n ");
3382
+ return `<section className="mx-auto max-w-6xl px-6 py-16">
3383
+ <p className="text-center text-sm font-semibold uppercase tracking-widest text-faint">By the numbers</p>
3384
+ <div className="mt-8"><StatBand stats={${JSON.stringify(r.stats)}} /></div>
3385
+ </section>
3386
+ <section className="mx-auto max-w-6xl px-6 py-16">
3387
+ <h2 className="text-center text-3xl font-bold sm:text-4xl">How it works</h2>
3388
+ <p className="mx-auto mt-3 max-w-xl text-center text-muted">A simple, proven path from first hello to launch day.</p>
3389
+ <div className="mt-10"><Steps items={${JSON.stringify(r.process)}} /></div>
3390
+ </section>
3391
+ <section className="mx-auto max-w-6xl px-6 py-16">
3392
+ <h2 className="text-center text-3xl font-bold sm:text-4xl">Loved by teams</h2>
3393
+ <div className="mt-10 grid gap-6 md:grid-cols-3">
3394
+ ${tst}
3395
+ </div>
3396
+ </section>`;
3397
+ };
2750
3398
  var showcaseSection = (ctx) => {
2751
3399
  const d = creativeData(ctx);
2752
3400
  const bullets = d.bullets.map((b) => `<li className="flex items-center gap-2 text-muted"><span className="text-[color:var(--accent-to)]">\u2713</span> ${b}</li>`).join("\n ");
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "create-lacspace-app",
3
- "version": "1.12.2",
3
+ "version": "1.14.0",
4
4
  "description": "Scaffold a beautiful, production-ready Next.js app from a Lacspace template — portfolio, business, e-commerce, SaaS, blog, docs, dashboard or restaurant — pre-wired with SEO, security headers, sitemap and robots. Like create-next-app, but you start gorgeous.",
5
5
  "type": "module",
6
6
  "bin": {
7
- "create-lacspace-app": "./dist/index.js"
7
+ "create-lacspace-app": "dist/index.js"
8
8
  },
9
9
  "files": [
10
10
  "dist"