create-lacspace-app 1.9.0 → 1.11.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 +349 -34
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -174,6 +174,23 @@ body {
174
174
  /* indeterminate progress bar (used by the "under development" pages) */
175
175
  @keyframes loadbar { 0% { transform: translateX(-120%); } 100% { transform: translateX(340%); } }
176
176
 
177
+ /* ambient motion for illustrations & the aurora background */
178
+ @keyframes floaty { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-16px); } }
179
+ @keyframes spin-slow { to { transform: rotate(360deg); } }
180
+ @keyframes gradient-pan { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } }
181
+ @keyframes marquee-x { from { transform: translateX(0); } to { transform: translateX(-50%); } }
182
+ .animate-floaty { animation: floaty 6s ease-in-out infinite; }
183
+ .animate-floaty-slow { animation: floaty 9s ease-in-out infinite; }
184
+ .animate-spin-slow { animation: spin-slow 26s linear infinite; }
185
+ .gradient-text-animated {
186
+ background: linear-gradient(120deg, var(--accent-from), var(--accent-to), var(--accent-from));
187
+ background-size: 200% 200%;
188
+ -webkit-background-clip: text; background-clip: text; color: transparent;
189
+ animation: gradient-pan 6s ease infinite;
190
+ }
191
+ .marquee-track { display: flex; width: max-content; animation: marquee-x 32s linear infinite; }
192
+ .marquee-mask { -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); }
193
+
177
194
  /* soft entrance for content */
178
195
  @keyframes rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
179
196
  main > section, main > * { animation: rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) both; }
@@ -407,14 +424,21 @@ function homePage(ctx) {
407
424
  if (ctx.template.key === "dashboard") return dashboardHome(ctx);
408
425
  const shell = (inner) => `import { site } from "@/lib/site";
409
426
  import { LiveStats } from "@/components/live-stats";
427
+ import { Aurora } from "@/components/aurora";
428
+ import { HeroArt } from "@/components/hero-art";
410
429
 
411
430
  // \u2728 Self-canonical home page \u2014 one line, full SEO (title, canonical, OG, Twitter).
412
431
  export const metadata = site.meta({ title: ${JSON.stringify(n)}, path: "/" });
413
432
 
414
433
  export default function Home() {
415
434
  return (
416
- <main className="min-h-screen">
435
+ <main className="relative min-h-screen overflow-hidden">
436
+ {/* \u2728 Animated, theme-aware gradient backdrop */}
437
+ <Aurora />
417
438
  ${inner}
439
+ ${showcaseSection(ctx)}
440
+ ${marqueeSection(ctx)}
441
+ ${faqSection(ctx)}
418
442
  ${builtWithSection(ctx)}
419
443
  </main>
420
444
  );
@@ -1433,10 +1457,13 @@ function buildFiles(ctx) {
1433
1457
  files["components/site-header.tsx"] = siteHeader(ctx);
1434
1458
  files["components/site-footer.tsx"] = siteFooter(ctx);
1435
1459
  files["components/announcement-bar.tsx"] = announcementBar();
1460
+ files["components/aurora.tsx"] = aurora();
1461
+ files["components/hero-art.tsx"] = heroArt(ctx);
1436
1462
  }
1437
1463
  for (const page of stubPages(ctx)) {
1438
1464
  files[`app${page.path}/page.tsx`] = isDash ? dashboardStubPage(page) : underDevPage(page);
1439
1465
  }
1466
+ Object.assign(files, uiKitFiles());
1440
1467
  Object.assign(files, realPageFiles(ctx));
1441
1468
  if (isBlog) {
1442
1469
  files["lib/posts.ts"] = postsLib();
@@ -1875,16 +1902,21 @@ export default function Home() {
1875
1902
  );
1876
1903
  }
1877
1904
  `;
1905
+ var ctaBandJsx = (c2) => ` <CTABand title=${JSON.stringify(c2.title)}${c2.subtitle ? ` subtitle=${JSON.stringify(c2.subtitle)}` : ""}${c2.label ? ` ctaLabel=${JSON.stringify(c2.label)}` : ""}${c2.href ? ` ctaHref=${JSON.stringify(c2.href)}` : ""} />`;
1878
1906
  var pageFile = (o) => `import type { Metadata } from "next";
1879
1907
  import Link from "next/link";
1880
1908
  import { site } from "@/lib/site";
1909
+ import { Aurora } from "@/components/aurora";
1910
+ import { Section, Pill, StatCard, FeatureCard, Testimonial, Steps, CTABand } from "@/components/ui";
1881
1911
 
1882
1912
  export const metadata: Metadata = site.meta({ title: ${JSON.stringify(o.title)}, path: ${JSON.stringify(o.path)}, description: ${JSON.stringify(o.description)} });
1883
1913
 
1884
1914
  export default function Page() {
1885
1915
  return (
1886
- <main className="min-h-screen">
1916
+ <main className="relative min-h-screen overflow-hidden">
1917
+ <Aurora />
1887
1918
  ${o.body}
1919
+ ${o.cta ? ctaBandJsx(o.cta) : ""}
1888
1920
  </main>
1889
1921
  );
1890
1922
  }
@@ -1893,9 +1925,10 @@ var pricingPage = (ctx) => pageFile({
1893
1925
  title: "Pricing",
1894
1926
  path: "/pricing",
1895
1927
  description: `Simple, transparent pricing for ${ctx.template.siteName}. Start free and upgrade anytime.`,
1928
+ cta: { title: "Still deciding?", subtitle: "Talk to us and we'll help you pick the right plan.", label: "Contact sales", href: "/contact" },
1896
1929
  body: ` <section className="mx-auto max-w-3xl px-6 py-24 text-center">
1897
- <p className="text-sm font-semibold uppercase tracking-widest text-faint">Pricing</p>
1898
- <h1 className="mt-3 text-4xl font-bold sm:text-5xl">Simple, transparent <span className="gradient-text">pricing</span></h1>
1930
+ <Pill>Pricing</Pill>
1931
+ <h1 className="mt-4 text-4xl font-bold sm:text-5xl">Simple, transparent <span className="gradient-text">pricing</span></h1>
1899
1932
  <p className="mx-auto mt-4 max-w-xl text-lg text-muted">Start free. Upgrade when you're ready. Cancel anytime.</p>
1900
1933
  </section>
1901
1934
  <section className="mx-auto max-w-6xl px-6 pb-24">
@@ -1923,15 +1956,19 @@ var pricingPage = (ctx) => pageFile({
1923
1956
  ))}
1924
1957
  </div>
1925
1958
  <p className="mt-10 text-center text-sm text-faint">All plans include SSL, unlimited bandwidth and a 14-day money-back guarantee.</p>
1959
+ </section>
1960
+ <section className="px-6 pb-8">
1961
+ <Testimonial quote="We switched in an afternoon and never looked back. Worth every penny." author="Sam Rivera" role="CTO, Globex" />
1926
1962
  </section>`
1927
1963
  });
1928
1964
  var servicesPage = (ctx) => pageFile({
1929
1965
  title: "Services",
1930
1966
  path: "/services",
1931
1967
  description: `What ${ctx.template.siteName} can do for you \u2014 from strategy to launch.`,
1968
+ cta: { title: "Have a project in mind?", subtitle: "Tell us what you're building and we'll take it from there.", label: "Start a conversation", href: "/contact" },
1932
1969
  body: ` <section className="mx-auto max-w-3xl px-6 py-24 text-center">
1933
- <p className="text-sm font-semibold uppercase tracking-widest text-faint">Services</p>
1934
- <h1 className="mt-3 text-4xl font-bold sm:text-5xl">What we <span className="gradient-text">do</span></h1>
1970
+ <Pill>Services</Pill>
1971
+ <h1 className="mt-4 text-4xl font-bold sm:text-5xl">What we <span className="gradient-text">do</span></h1>
1935
1972
  <p className="mx-auto mt-4 max-w-xl text-lg text-muted">End-to-end help \u2014 from the first sketch to a product your customers love.</p>
1936
1973
  </section>
1937
1974
  <section className="mx-auto max-w-6xl px-6 pb-16">
@@ -1944,29 +1981,25 @@ var servicesPage = (ctx) => pageFile({
1944
1981
  { icon: "\u{1F4C8}", title: "Growth", desc: "Experiments and optimization that move the numbers." },
1945
1982
  { icon: "\u{1F91D}", title: "Support", desc: "Ongoing care so your product keeps getting better." },
1946
1983
  ].map((s) => (
1947
- <div key={s.title} className="rounded-2xl border border-hairline bg-surface p-6 transition hover:-translate-y-1">
1948
- <div className="mb-4 inline-flex h-12 w-12 items-center justify-center rounded-xl gradient-bg text-2xl">{s.icon}</div>
1949
- <h3 className="font-semibold">{s.title}</h3>
1950
- <p className="mt-1 text-sm text-muted">{s.desc}</p>
1951
- </div>
1984
+ <FeatureCard key={s.title} icon={s.icon} title={s.title} desc={s.desc} />
1952
1985
  ))}
1953
1986
  </div>
1954
1987
  </section>
1955
- <section className="mx-auto max-w-3xl px-6 pb-24 text-center">
1956
- <h2 className="text-2xl font-bold">Have a project in mind?</h2>
1957
- <Link href="/contact" className="mt-6 inline-block rounded-full gradient-bg px-8 py-3 font-semibold text-black">Start a conversation</Link>
1988
+ <section className="px-6 pb-8">
1989
+ <Testimonial quote="They shipped faster than we thought possible \u2014 and it looked incredible." author="Jordan Ellis" role="Founder, Northwind" />
1958
1990
  </section>`
1959
1991
  });
1960
1992
  var featuresPage = (ctx) => pageFile({
1961
1993
  title: "Features",
1962
1994
  path: "/features",
1963
1995
  description: `Everything ${ctx.template.siteName} gives your team, in one place.`,
1996
+ cta: { title: "Ready to ship faster?", subtitle: "Start free \u2014 no credit card required.", label: "See pricing", href: "/pricing" },
1964
1997
  body: ` <section className="mx-auto max-w-3xl px-6 py-24 text-center">
1965
- <p className="text-sm font-semibold uppercase tracking-widest text-faint">Features</p>
1966
- <h1 className="mt-3 text-4xl font-bold sm:text-5xl">Built to <span className="gradient-text">ship faster</span></h1>
1998
+ <Pill>Features</Pill>
1999
+ <h1 className="mt-4 text-4xl font-bold sm:text-5xl">Built to <span className="gradient-text">ship faster</span></h1>
1967
2000
  <p className="mx-auto mt-4 max-w-xl text-lg text-muted">A focused set of features that do the heavy lifting so your team can move.</p>
1968
2001
  </section>
1969
- <section className="mx-auto max-w-6xl px-6 pb-24">
2002
+ <section className="mx-auto max-w-6xl px-6 pb-16">
1970
2003
  <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
1971
2004
  {[
1972
2005
  { icon: "\u26A1", title: "Fast by default", desc: "Edge-rendered and cached \u2014 instant everywhere." },
@@ -1976,25 +2009,27 @@ var featuresPage = (ctx) => pageFile({
1976
2009
  { icon: "\u{1F9E9}", title: "Extensible", desc: "A clean API and webhooks for anything custom." },
1977
2010
  { icon: "\u{1F317}", title: "Delightful UX", desc: "Dark mode, a \u2318K palette and thoughtful details." },
1978
2011
  ].map((f) => (
1979
- <div key={f.title} className="rounded-2xl border border-hairline bg-surface p-6 transition hover:-translate-y-1">
1980
- <div className="mb-4 inline-flex h-12 w-12 items-center justify-center rounded-xl gradient-bg text-2xl">{f.icon}</div>
1981
- <h3 className="font-semibold">{f.title}</h3>
1982
- <p className="mt-1 text-sm text-muted">{f.desc}</p>
1983
- </div>
2012
+ <FeatureCard key={f.title} icon={f.icon} title={f.title} desc={f.desc} />
1984
2013
  ))}
1985
2014
  </div>
1986
- <div className="mt-12 text-center">
1987
- <Link href="/pricing" className="inline-block rounded-full gradient-bg px-8 py-3 font-semibold text-black">See pricing</Link>
1988
- </div>
2015
+ </section>
2016
+ <section className="mx-auto max-w-5xl px-6 pb-8">
2017
+ <h2 className="mb-8 text-center text-2xl font-bold">How it works</h2>
2018
+ <Steps items={[
2019
+ { title: "Connect", desc: "Sign up and link the tools you already use." },
2020
+ { title: "Configure", desc: "Set it up your way in a few clicks \u2014 no code required." },
2021
+ { title: "Ship", desc: "Go live and watch the numbers in real time." },
2022
+ ]} />
1989
2023
  </section>`
1990
2024
  });
1991
2025
  var workPage = (ctx) => pageFile({
1992
2026
  title: "Work",
1993
2027
  path: "/work",
1994
2028
  description: `Selected projects by ${ctx.template.siteName}.`,
2029
+ cta: { title: "Have something in mind?", subtitle: "I'm currently open to new projects.", label: "Get in touch", href: "/contact" },
1995
2030
  body: ` <section className="mx-auto max-w-3xl px-6 py-24">
1996
- <p className="text-sm font-semibold uppercase tracking-widest text-faint">Work</p>
1997
- <h1 className="mt-3 text-4xl font-bold sm:text-5xl">Selected <span className="gradient-text">work</span></h1>
2031
+ <Pill>Work</Pill>
2032
+ <h1 className="mt-4 text-4xl font-bold sm:text-5xl">Selected <span className="gradient-text">work</span></h1>
1998
2033
  <p className="mt-4 text-lg text-muted">A few things I've designed and built recently.</p>
1999
2034
  </section>
2000
2035
  <section className="mx-auto max-w-6xl px-6 pb-24">
@@ -2023,9 +2058,10 @@ var menuPage = (ctx) => pageFile({
2023
2058
  title: "Menu",
2024
2059
  path: "/menu",
2025
2060
  description: `The menu at ${ctx.template.siteName} \u2014 seasonal plates and natural wine.`,
2061
+ cta: { title: "Hungry?", subtitle: "Book a table \u2014 we can't wait to cook for you.", label: "Reserve a table", href: "/reservations" },
2026
2062
  body: ` <section className="mx-auto max-w-3xl px-6 py-24 text-center">
2027
- <p className="text-sm font-semibold uppercase tracking-widest text-faint">Menu</p>
2028
- <h1 className="mt-3 text-4xl font-bold sm:text-5xl gradient-text">Tonight's menu</h1>
2063
+ <Pill>Menu</Pill>
2064
+ <h1 className="mt-4 text-4xl font-bold sm:text-5xl gradient-text">Tonight's menu</h1>
2029
2065
  <p className="mx-auto mt-4 max-w-xl text-lg text-muted">Seasonal, ingredient-led and always changing. Here's what we're serving now.</p>
2030
2066
  </section>
2031
2067
  <section className="mx-auto max-w-3xl px-6 pb-24">
@@ -2046,18 +2082,16 @@ var menuPage = (ctx) => pageFile({
2046
2082
  </div>
2047
2083
  </div>
2048
2084
  ))}
2049
- <div className="text-center">
2050
- <Link href="/reservations" className="inline-block rounded-full gradient-bg px-8 py-3 font-semibold text-black">Book a table</Link>
2051
- </div>
2052
2085
  </section>`
2053
2086
  });
2054
2087
  var cardGridPage = (o) => pageFile({
2055
2088
  title: o.title,
2056
2089
  path: o.path,
2057
2090
  description: o.lead,
2091
+ cta: o.cta,
2058
2092
  body: ` <section className="mx-auto max-w-3xl px-6 py-24">
2059
- <p className="text-sm font-semibold uppercase tracking-widest text-faint">${o.eyebrow}</p>
2060
- <h1 className="mt-3 text-4xl font-bold sm:text-5xl">${o.heading}</h1>
2093
+ <Pill>${o.eyebrow}</Pill>
2094
+ <h1 className="mt-4 text-4xl font-bold sm:text-5xl">${o.heading}</h1>
2061
2095
  <p className="mt-4 text-lg text-muted">${o.lead}</p>
2062
2096
  </section>
2063
2097
  <section className="mx-auto max-w-6xl px-6 pb-24">
@@ -2077,6 +2111,7 @@ var topicsPage = (ctx) => cardGridPage({
2077
2111
  eyebrow: "Topics",
2078
2112
  heading: "Browse by topic",
2079
2113
  lead: "Find what you care about \u2014 from deep dives to quick notes.",
2114
+ cta: { title: "Never miss a post", subtitle: "Subscribe and get new pieces in your inbox.", label: "Join the newsletter", href: "/newsletter" },
2080
2115
  items: [
2081
2116
  { title: "Engineering", desc: "How we build and the decisions behind it." },
2082
2117
  { title: "Design", desc: "Craft, systems and the details that matter." },
@@ -2092,6 +2127,7 @@ var guidesPage = (ctx) => cardGridPage({
2092
2127
  eyebrow: "Guides",
2093
2128
  heading: "Guides & tutorials",
2094
2129
  lead: "Task-focused walkthroughs to get you productive fast.",
2130
+ cta: { title: "Can't find what you need?", subtitle: "We're happy to help \u2014 reach out any time.", label: "Contact us", href: "/contact" },
2095
2131
  items: [
2096
2132
  { title: "Getting started", desc: "Install, configure and run your first build." },
2097
2133
  { title: "Authentication", desc: "Add sign-in, sessions and protected routes." },
@@ -2275,6 +2311,97 @@ export function SettingsPanel() {
2275
2311
  );
2276
2312
  }
2277
2313
  `;
2314
+ var uiKitFiles = () => ({
2315
+ "components/ui/section.tsx": `import type { ReactNode } from "react";
2316
+
2317
+ export function Section({ eyebrow, title, lead, children, className = "" }: { eyebrow?: string; title?: string; lead?: string; children?: ReactNode; className?: string }) {
2318
+ return (
2319
+ <section className={"mx-auto max-w-6xl px-6 py-16 " + className}>
2320
+ {eyebrow ? <p className="text-sm font-semibold uppercase tracking-widest text-faint">{eyebrow}</p> : null}
2321
+ {title ? <h2 className="mt-3 text-3xl font-bold sm:text-4xl">{title}</h2> : null}
2322
+ {lead ? <p className="mt-4 max-w-2xl text-lg text-muted">{lead}</p> : null}
2323
+ {children ? <div className="mt-10">{children}</div> : null}
2324
+ </section>
2325
+ );
2326
+ }
2327
+ `,
2328
+ "components/ui/pill.tsx": `import type { ReactNode } from "react";
2329
+
2330
+ export function Pill({ children, className = "" }: { children: ReactNode; className?: string }) {
2331
+ return <span className={"inline-flex items-center gap-1 rounded-full border border-hairline bg-surface px-3 py-1 text-xs font-semibold uppercase tracking-widest text-muted " + className}>{children}</span>;
2332
+ }
2333
+ `,
2334
+ "components/ui/stat-card.tsx": `export function StatCard({ label, value, delta }: { label: string; value: string; delta?: string }) {
2335
+ return (
2336
+ <div className="rounded-2xl border border-hairline bg-surface p-6 transition hover:-translate-y-1">
2337
+ <div className="text-3xl font-bold tabular-nums">{value}</div>
2338
+ <div className="mt-1 text-sm text-muted">{label}</div>
2339
+ {delta ? <div className="mt-2 text-xs font-medium text-emerald-400">{delta}</div> : null}
2340
+ </div>
2341
+ );
2342
+ }
2343
+ `,
2344
+ "components/ui/feature-card.tsx": `import type { ReactNode } from "react";
2345
+
2346
+ export function FeatureCard({ icon, title, desc }: { icon?: ReactNode; title: string; desc: string }) {
2347
+ return (
2348
+ <div className="rounded-2xl border border-hairline bg-surface p-6 transition hover:-translate-y-1 hover:border-[color:var(--accent-to)]">
2349
+ {icon ? <div className="mb-4 inline-flex h-12 w-12 items-center justify-center rounded-xl gradient-bg text-2xl">{icon}</div> : null}
2350
+ <h3 className="font-semibold">{title}</h3>
2351
+ <p className="mt-1 text-sm leading-relaxed text-muted">{desc}</p>
2352
+ </div>
2353
+ );
2354
+ }
2355
+ `,
2356
+ "components/ui/testimonial.tsx": `export function Testimonial({ quote, author, role }: { quote: string; author: string; role?: string }) {
2357
+ return (
2358
+ <figure className="mx-auto max-w-2xl rounded-3xl border border-hairline bg-surface p-8 text-center">
2359
+ <div className="text-4xl leading-none gradient-text">&ldquo;</div>
2360
+ <blockquote className="mt-2 text-lg font-medium leading-relaxed">{quote}</blockquote>
2361
+ <figcaption className="mt-4 text-sm text-muted">\u2014 {author}{role ? ", " + role : ""}</figcaption>
2362
+ </figure>
2363
+ );
2364
+ }
2365
+ `,
2366
+ "components/ui/steps.tsx": `export function Steps({ items }: { items: { title: string; desc: string }[] }) {
2367
+ return (
2368
+ <ol className="grid gap-6 sm:grid-cols-3">
2369
+ {items.map((s, i) => (
2370
+ <li key={s.title} className="rounded-2xl border border-hairline bg-surface p-6">
2371
+ <div className="mb-3 inline-flex h-8 w-8 items-center justify-center rounded-full gradient-bg text-sm font-bold text-black">{i + 1}</div>
2372
+ <h3 className="font-semibold">{s.title}</h3>
2373
+ <p className="mt-1 text-sm text-muted">{s.desc}</p>
2374
+ </li>
2375
+ ))}
2376
+ </ol>
2377
+ );
2378
+ }
2379
+ `,
2380
+ "components/ui/cta-band.tsx": `import Link from "next/link";
2381
+
2382
+ export function CTABand({ title, subtitle, ctaLabel = "Get started", ctaHref = "/contact" }: { title: string; subtitle?: string; ctaLabel?: string; ctaHref?: string }) {
2383
+ return (
2384
+ <section className="mx-auto max-w-6xl px-6 py-20">
2385
+ <div className="relative overflow-hidden rounded-3xl border border-hairline bg-surface p-10 text-center sm:p-16">
2386
+ <div aria-hidden className="pointer-events-none absolute -right-16 -top-16 h-56 w-56 rounded-full gradient-bg opacity-40 blur-3xl animate-floaty" />
2387
+ <div aria-hidden className="pointer-events-none absolute -bottom-16 -left-16 h-56 w-56 rounded-full gradient-bg opacity-30 blur-3xl animate-floaty-slow" />
2388
+ <h2 className="relative text-3xl font-bold sm:text-4xl">{title}</h2>
2389
+ {subtitle ? <p className="relative mx-auto mt-3 max-w-xl text-muted">{subtitle}</p> : null}
2390
+ <Link href={ctaHref} className="relative mt-8 inline-block rounded-full gradient-bg px-8 py-3 font-semibold text-black transition hover:opacity-90">{ctaLabel}</Link>
2391
+ </div>
2392
+ </section>
2393
+ );
2394
+ }
2395
+ `,
2396
+ "components/ui/index.ts": `export * from "./section";
2397
+ export * from "./pill";
2398
+ export * from "./stat-card";
2399
+ export * from "./feature-card";
2400
+ export * from "./testimonial";
2401
+ export * from "./steps";
2402
+ export * from "./cta-band";
2403
+ `
2404
+ });
2278
2405
  function realPageFiles(ctx) {
2279
2406
  const k = ctx.template.key;
2280
2407
  const f = {};
@@ -2302,6 +2429,194 @@ function realPageFiles(ctx) {
2302
2429
  }
2303
2430
  return f;
2304
2431
  }
2432
+ function creativeData(ctx) {
2433
+ const n = ctx.template.siteName;
2434
+ const map = {
2435
+ personal: {
2436
+ emoji: "\u{1F44B}",
2437
+ chips: ["Design", "Code", "Ship"],
2438
+ showcaseTitle: "Design & build, end to end",
2439
+ showcaseLead: `${n} turns ideas into polished products \u2014 from the first sketch to the last pixel.`,
2440
+ bullets: ["10+ years shipping web & mobile", "Design systems that scale", "Obsessed with the details"],
2441
+ marqueeLabel: "Worked with",
2442
+ marquee: ["Aurora", "Northwind", "Lumen", "Harbor", "Cadence", "Meadow"],
2443
+ faq: [
2444
+ { q: "Are you available for freelance?", a: "Yes \u2014 I take on a couple of projects each quarter. Reach out via the contact page." },
2445
+ { q: "What do you work with?", a: "React, Next.js and TypeScript, with a lot of care for UX and performance." },
2446
+ { q: "Do you do both design and development?", a: "Both \u2014 I can take a project from concept all the way to production." }
2447
+ ]
2448
+ },
2449
+ business: {
2450
+ emoji: "\u{1F3E2}",
2451
+ chips: ["Strategy", "Design", "Launch"],
2452
+ showcaseTitle: "Everything you need to grow",
2453
+ showcaseLead: `${n} partners with you from strategy to launch \u2014 one senior team, accountable for outcomes.`,
2454
+ bullets: ["Senior team, no hand-offs", "Fixed timelines & clear pricing", "We sweat the details"],
2455
+ marqueeLabel: "Trusted by teams at",
2456
+ marquee: ["Northwind", "Globex", "Initech", "Umbrella", "Soylent", "Hooli"],
2457
+ faq: [
2458
+ { q: "How do engagements work?", a: "We scope a clear plan, agree a fixed timeline, and ship in weekly increments." },
2459
+ { q: "What does it cost?", a: "See our pricing page for plans, or contact us for a custom quote." },
2460
+ { q: "How soon can we start?", a: "Usually within two weeks. Get in touch to check availability." }
2461
+ ]
2462
+ },
2463
+ ecommerce: {
2464
+ emoji: "\u{1F6CD}\uFE0F",
2465
+ chips: ["Shop", "Bag", "Checkout"],
2466
+ showcaseTitle: "Thoughtfully made, delivered fast",
2467
+ showcaseLead: `${n} curates beautiful things and ships them worldwide \u2014 with easy returns, always.`,
2468
+ bullets: ["Free worldwide shipping", "30-day easy returns", "Sustainably sourced"],
2469
+ marqueeLabel: "Why shop with us",
2470
+ marquee: ["Free shipping", "Easy returns", "Secure checkout", "Ethically made", "Gift wrapping", "Loved by 10k+"],
2471
+ faq: [
2472
+ { q: "How long is shipping?", a: "Most orders arrive in 3\u20135 business days with free worldwide shipping." },
2473
+ { q: "What's your return policy?", a: "30 days, no questions asked \u2014 see the returns page for details." },
2474
+ { q: "Is checkout secure?", a: "Yes \u2014 payments are encrypted and we never store your card details." }
2475
+ ]
2476
+ },
2477
+ saas: {
2478
+ emoji: "\u26A1",
2479
+ chips: ["Analytics", "Billing", "API"],
2480
+ showcaseTitle: "The platform your team will love",
2481
+ showcaseLead: `${n} brings analytics, billing and automation into one fast, secure place.`,
2482
+ bullets: ["Set up in minutes", "SOC 2-ready security", "Scales with you"],
2483
+ marqueeLabel: "Powering teams at",
2484
+ marquee: ["Globex", "Initech", "Hooli", "Pied Piper", "Umbrella", "Stark"],
2485
+ faq: [
2486
+ { q: "Is there a free plan?", a: "Yes \u2014 start free and upgrade when you're ready. See the pricing page." },
2487
+ { q: "How is my data secured?", a: "Encryption in transit and at rest, audit logs, and SSO on higher plans." },
2488
+ { q: "Can I self-host?", a: "Contact sales \u2014 we offer flexible deployment options." }
2489
+ ]
2490
+ },
2491
+ blog: {
2492
+ emoji: "\u270D\uFE0F",
2493
+ chips: ["Essays", "Notes", "Stories"],
2494
+ showcaseTitle: "Words worth your time",
2495
+ showcaseLead: `${n} publishes essays and notes on building things that matter \u2014 no fluff.`,
2496
+ bullets: ["New pieces most weeks", "No clickbait, ever", "Written by practitioners"],
2497
+ marqueeLabel: "Topics we cover",
2498
+ marquee: ["Engineering", "Design", "Product", "Culture", "Tutorials", "Announcements"],
2499
+ faq: [
2500
+ { q: "How often do you publish?", a: "A new piece most weeks \u2014 subscribe so you never miss one." },
2501
+ { q: "Can I contribute?", a: "We love guest posts. Pitch us via the contact page." },
2502
+ { q: "Is there a newsletter?", a: "Yes \u2014 head to the newsletter page to join." }
2503
+ ]
2504
+ },
2505
+ docs: {
2506
+ emoji: "\u{1F4DA}",
2507
+ chips: ["Guides", "API", "Examples"],
2508
+ showcaseTitle: "Everything you need to build",
2509
+ showcaseLead: `${n} gives you guides, API references and copy-paste examples \u2014 all in one place.`,
2510
+ bullets: ["Quickstart in 5 minutes", "Searchable & versioned", "Real, runnable examples"],
2511
+ marqueeLabel: "What you'll find",
2512
+ marquee: ["Quickstart", "Guides", "API reference", "Examples", "Migrations", "Troubleshooting"],
2513
+ faq: [
2514
+ { q: "Where do I start?", a: "Head to the guides for a 5-minute quickstart." },
2515
+ { q: "Is there an API reference?", a: "Yes \u2014 the API page has the full reference." },
2516
+ { q: "How do I report a docs issue?", a: "Use the contact page \u2014 we fix docs fast." }
2517
+ ]
2518
+ },
2519
+ restaurant: {
2520
+ emoji: "\u{1F377}",
2521
+ chips: ["Menu", "Wine", "Reserve"],
2522
+ showcaseTitle: "Seasonal plates, natural wine",
2523
+ showcaseLead: `${n} serves ingredient-led plates and natural wine in a warm, low-lit room.`,
2524
+ bullets: ["Menu changes with the seasons", "Natural, low-intervention wine", "Walk-ins welcome"],
2525
+ marqueeLabel: "On the pass",
2526
+ marquee: ["Wood-fired", "Local produce", "Natural wine", "House-made pasta", "Seasonal", "Fresh sourdough"],
2527
+ faq: [
2528
+ { q: "Do you take reservations?", a: "Yes \u2014 book via the reservations page. Walk-ins are welcome too." },
2529
+ { q: "Any dietary options?", a: "Plenty \u2014 vegetarian and vegan plates change weekly. Just ask about allergies." },
2530
+ { q: "When are you open?", a: "Wednesday to Sunday, 5pm till late." }
2531
+ ]
2532
+ }
2533
+ };
2534
+ return map[ctx.template.key] ?? map.business;
2535
+ }
2536
+ var aurora = () => `export function Aurora() {
2537
+ return (
2538
+ <div aria-hidden className="pointer-events-none absolute inset-x-0 top-0 -z-10 h-[720px] overflow-hidden">
2539
+ <div className="absolute -left-20 -top-16 h-96 w-96 rounded-full opacity-30 blur-3xl animate-floaty" style={{ background: "radial-gradient(circle, var(--accent-from), transparent 70%)" }} />
2540
+ <div className="absolute -right-10 top-40 h-80 w-80 rounded-full opacity-25 blur-3xl animate-floaty-slow" style={{ background: "radial-gradient(circle, var(--accent-to), transparent 70%)" }} />
2541
+ <div className="absolute left-1/3 top-72 h-72 w-72 rounded-full opacity-20 blur-3xl animate-floaty" style={{ background: "radial-gradient(circle, var(--accent-to), transparent 70%)" }} />
2542
+ </div>
2543
+ );
2544
+ }
2545
+ `;
2546
+ var heroArt = (ctx) => {
2547
+ const d = creativeData(ctx);
2548
+ const initials = ctx.template.siteName.trim().split(/\s+/).slice(0, 2).map((w) => (w[0] ?? "").toUpperCase()).join("") || "A";
2549
+ return `export function HeroArt() {
2550
+ return (
2551
+ <div className="relative mx-auto aspect-square w-full max-w-sm select-none">
2552
+ {/* orbiting rings */}
2553
+ <div className="absolute inset-0 rounded-full border border-hairline animate-spin-slow" />
2554
+ <div className="absolute inset-10 rounded-full border border-hairline animate-spin-slow" style={{ animationDirection: "reverse" }} />
2555
+ <div className="absolute inset-0 rounded-full opacity-40 blur-2xl gradient-bg" />
2556
+ {/* center badge with the platform initials */}
2557
+ <div className="absolute left-1/2 top-1/2 flex h-28 w-28 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-3xl gradient-bg text-4xl font-black text-black shadow-2xl animate-floaty">
2558
+ ${JSON.stringify(initials)}
2559
+ </div>
2560
+ {/* floating labels */}
2561
+ <div className="absolute left-0 top-10 flex items-center gap-2 rounded-xl border border-hairline bg-app px-3 py-2 text-xs font-medium shadow-lg animate-floaty">
2562
+ <span>${d.emoji}</span> ${JSON.stringify(d.chips[0])}
2563
+ </div>
2564
+ <div className="absolute right-0 top-28 rounded-xl border border-hairline bg-app px-3 py-2 text-xs font-medium shadow-lg animate-floaty-slow">
2565
+ ${JSON.stringify(d.chips[1])}
2566
+ </div>
2567
+ <div className="absolute bottom-8 left-6 rounded-xl border border-hairline bg-app px-3 py-2 text-xs font-medium shadow-lg animate-floaty" style={{ animationDelay: "1.2s" }}>
2568
+ ${JSON.stringify(d.chips[2])}
2569
+ </div>
2570
+ </div>
2571
+ );
2572
+ }
2573
+ `;
2574
+ };
2575
+ var showcaseSection = (ctx) => {
2576
+ const d = creativeData(ctx);
2577
+ 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 ");
2578
+ return `<section className="mx-auto grid max-w-6xl items-center gap-12 px-6 py-20 md:grid-cols-2">
2579
+ <div>
2580
+ <p className="text-sm font-semibold uppercase tracking-widest text-faint">${ctx.template.siteName}</p>
2581
+ <h2 className="mt-3 text-3xl font-bold sm:text-4xl">${d.showcaseTitle}</h2>
2582
+ <p className="mt-4 max-w-md text-lg text-muted">${d.showcaseLead}</p>
2583
+ <ul className="mt-6 space-y-3 text-sm">
2584
+ ${bullets}
2585
+ </ul>
2586
+ </div>
2587
+ <HeroArt />
2588
+ </section>`;
2589
+ };
2590
+ var marqueeSection = (ctx) => {
2591
+ const d = creativeData(ctx);
2592
+ const chip = (t) => `<span className="rounded-full border border-hairline bg-surface px-5 py-2 text-sm font-medium text-muted">${t}</span>`;
2593
+ const track = d.marquee.map(chip).join("\n ");
2594
+ return `<section className="border-y border-hairline py-10">
2595
+ <p className="mb-6 text-center text-xs font-semibold uppercase tracking-widest text-faint">${d.marqueeLabel}</p>
2596
+ <div className="marquee-mask overflow-hidden">
2597
+ <div className="marquee-track gap-4">
2598
+ ${track}
2599
+ ${track}
2600
+ </div>
2601
+ </div>
2602
+ </section>`;
2603
+ };
2604
+ var faqSection = (ctx) => {
2605
+ const d = creativeData(ctx);
2606
+ const items = d.faq.map((f) => `<details className="group rounded-2xl border border-hairline bg-surface p-5">
2607
+ <summary className="flex cursor-pointer list-none items-center justify-between gap-4 font-medium">
2608
+ ${f.q}
2609
+ <span className="text-muted transition group-open:rotate-45">+</span>
2610
+ </summary>
2611
+ <p className="mt-3 text-sm leading-relaxed text-muted">${f.a}</p>
2612
+ </details>`).join("\n ");
2613
+ return `<section className="mx-auto max-w-3xl px-6 py-20">
2614
+ <h2 className="text-center text-3xl font-bold">Frequently asked</h2>
2615
+ <div className="mt-10 space-y-3">
2616
+ ${items}
2617
+ </div>
2618
+ </section>`;
2619
+ };
2305
2620
  function parseArgs(list) {
2306
2621
  const a = { yes: false, install: true, git: true, pm: "npm", help: false };
2307
2622
  for (let i = 0; i < list.length; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-lacspace-app",
3
- "version": "1.9.0",
3
+ "version": "1.11.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": {