create-fornix 0.0.8 → 0.0.9
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.
- package/dist/index.js +273 -77
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -329,6 +329,39 @@ const { title } = Astro.props;${tailwindImport}
|
|
|
329
329
|
<slot />
|
|
330
330
|
</body>
|
|
331
331
|
</html>
|
|
332
|
+
|
|
333
|
+
<style is:global>
|
|
334
|
+
*, *::before, *::after {
|
|
335
|
+
box-sizing: border-box;
|
|
336
|
+
margin: 0;
|
|
337
|
+
padding: 0;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
html {
|
|
341
|
+
scroll-behavior: smooth;
|
|
342
|
+
-webkit-font-smoothing: antialiased;
|
|
343
|
+
-moz-osx-font-smoothing: grayscale;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
body {
|
|
347
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
348
|
+
background: var(--color-background, #0f172a);
|
|
349
|
+
color: var(--color-foreground, #f8fafc);
|
|
350
|
+
line-height: 1.6;
|
|
351
|
+
min-height: 100vh;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
img, video {
|
|
355
|
+
max-width: 100%;
|
|
356
|
+
height: auto;
|
|
357
|
+
display: block;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
a {
|
|
361
|
+
color: inherit;
|
|
362
|
+
text-decoration: none;
|
|
363
|
+
}
|
|
364
|
+
</style>
|
|
332
365
|
`.trim() + "\n";
|
|
333
366
|
if (config.deployTarget === "cloudflare") {
|
|
334
367
|
const wrangler = {
|
|
@@ -373,7 +406,7 @@ function generateAstroConfig(config, blocks = []) {
|
|
|
373
406
|
local: "defineConfig"
|
|
374
407
|
});
|
|
375
408
|
const configObject = module.exports.default.$args[0];
|
|
376
|
-
if (config.renderMode === "server") {
|
|
409
|
+
if (config.renderMode === "server" || config.renderMode === "hybrid") {
|
|
377
410
|
configObject.output = "server";
|
|
378
411
|
}
|
|
379
412
|
const adapter = ADAPTER_MAP[config.deployTarget];
|
|
@@ -427,22 +460,11 @@ function generateTailwindConfig(config) {
|
|
|
427
460
|
if (config.cssEngine !== "tailwind") {
|
|
428
461
|
return ok(null);
|
|
429
462
|
}
|
|
430
|
-
const themeBlock = [
|
|
431
|
-
"@theme {",
|
|
432
|
-
" --color-primary: var(--color-primary);",
|
|
433
|
-
" --color-secondary: var(--color-secondary);",
|
|
434
|
-
" --color-accent: var(--color-accent);",
|
|
435
|
-
" --color-background: var(--color-background);",
|
|
436
|
-
" --color-foreground: var(--color-foreground);",
|
|
437
|
-
"}"
|
|
438
|
-
].join("\n");
|
|
439
463
|
const lines = [
|
|
440
464
|
'@import "tailwindcss";',
|
|
441
465
|
'@import "./src/styles/palettes/_current.css";',
|
|
442
466
|
"",
|
|
443
467
|
`@source "./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}";`,
|
|
444
|
-
"",
|
|
445
|
-
themeBlock,
|
|
446
468
|
""
|
|
447
469
|
];
|
|
448
470
|
return ok(lines.join("\n"));
|
|
@@ -615,7 +637,7 @@ function generateContentConfig(blocks) {
|
|
|
615
637
|
'import { defineCollection, z } from "astro:content";'
|
|
616
638
|
];
|
|
617
639
|
const collections = [];
|
|
618
|
-
const
|
|
640
|
+
const dataCollectionNames = /* @__PURE__ */ new Set();
|
|
619
641
|
for (const block of blocks) {
|
|
620
642
|
if (block.collections && block.collections.length > 0) {
|
|
621
643
|
for (const col of block.collections) {
|
|
@@ -632,27 +654,15 @@ function generateContentConfig(blocks) {
|
|
|
632
654
|
}
|
|
633
655
|
const slots = block.ai?.contentSlots;
|
|
634
656
|
if (slots && Object.keys(slots).length > 0) {
|
|
635
|
-
const schemaFields = Object.entries(slots).map(([name, slot]) => ` ${name}: ${zodTypeForSlot(slot)}.optional(),`).join("\n");
|
|
636
657
|
const subdirectory = TYPE_DIRECTORY[block.type] ?? block.type;
|
|
637
|
-
|
|
638
|
-
dataCollections.set(subdirectory, []);
|
|
639
|
-
}
|
|
640
|
-
dataCollections.get(subdirectory).push(
|
|
641
|
-
` // ${block.name}
|
|
642
|
-
z.object({
|
|
643
|
-
${schemaFields}
|
|
644
|
-
})`
|
|
645
|
-
);
|
|
658
|
+
dataCollectionNames.add(subdirectory);
|
|
646
659
|
}
|
|
647
660
|
}
|
|
648
|
-
for (const
|
|
649
|
-
const schemaStr = schemas.length === 1 ? schemas[0] : `z.union([
|
|
650
|
-
${schemas.join(",\n")}
|
|
651
|
-
])`;
|
|
661
|
+
for (const colName of dataCollectionNames) {
|
|
652
662
|
collections.push(
|
|
653
663
|
` "${colName}": defineCollection({
|
|
654
664
|
type: "data",
|
|
655
|
-
schema:
|
|
665
|
+
schema: z.record(z.unknown()),
|
|
656
666
|
})`
|
|
657
667
|
);
|
|
658
668
|
}
|
|
@@ -666,20 +676,6 @@ ${schemas.join(",\n")}
|
|
|
666
676
|
];
|
|
667
677
|
return lines.join("\n");
|
|
668
678
|
}
|
|
669
|
-
function zodTypeForSlot(slot) {
|
|
670
|
-
switch (slot.type) {
|
|
671
|
-
case "string":
|
|
672
|
-
return "z.string()";
|
|
673
|
-
case "number":
|
|
674
|
-
return "z.number()";
|
|
675
|
-
case "boolean":
|
|
676
|
-
return "z.boolean()";
|
|
677
|
-
case "array":
|
|
678
|
-
return "z.array(z.unknown())";
|
|
679
|
-
case "object":
|
|
680
|
-
return "z.record(z.unknown())";
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
679
|
function buildDefaultFromSlots(slots) {
|
|
684
680
|
const content = {};
|
|
685
681
|
for (const [name, slot] of Object.entries(slots)) {
|
|
@@ -703,13 +699,13 @@ function defaultValueForType(type) {
|
|
|
703
699
|
}
|
|
704
700
|
|
|
705
701
|
// src/scaffold/i18n-wiring.ts
|
|
706
|
-
function wireI18n(config) {
|
|
702
|
+
function wireI18n(config, manifests) {
|
|
707
703
|
const files = {};
|
|
708
704
|
if (config.locales.length < 2) {
|
|
709
705
|
return ok(files);
|
|
710
706
|
}
|
|
711
707
|
files["src/i18n/utils.ts"] = generateI18nUtils(config);
|
|
712
|
-
files["src/pages/[locale]/index.astro"] = generateLocaleIndexPage(config);
|
|
708
|
+
files["src/pages/[locale]/index.astro"] = generateLocaleIndexPage(config, manifests ?? []);
|
|
713
709
|
return ok(files);
|
|
714
710
|
}
|
|
715
711
|
function generateI18nUtils(config) {
|
|
@@ -744,11 +740,21 @@ export function t<T>(
|
|
|
744
740
|
}
|
|
745
741
|
`;
|
|
746
742
|
}
|
|
747
|
-
function generateLocaleIndexPage(config) {
|
|
743
|
+
function generateLocaleIndexPage(config, manifests) {
|
|
744
|
+
const sectionBlocks = manifests.filter((m) => m.type === "section");
|
|
745
|
+
const imports = [];
|
|
746
|
+
const tags = [];
|
|
747
|
+
for (const block of sectionBlocks) {
|
|
748
|
+
const componentName = block.name.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
749
|
+
imports.push(`import ${componentName} from '../../../components/sections/${block.name}.astro';`);
|
|
750
|
+
tags.push(` <${componentName} />`);
|
|
751
|
+
}
|
|
752
|
+
const importSection = imports.length > 0 ? imports.join("\n") + "\n" : "";
|
|
753
|
+
const blockSection = tags.length > 0 ? "\n" + tags.join("\n") + "\n " : "\n <h1>" + config.projectName + "</h1>\n <p>Locale: {locale}</p>\n ";
|
|
748
754
|
return `---
|
|
749
|
-
import { locales } from "
|
|
750
|
-
import Layout from "
|
|
751
|
-
|
|
755
|
+
import { locales } from "../../../i18n/utils";
|
|
756
|
+
import Layout from "../../../layouts/Layout.astro";
|
|
757
|
+
${importSection}
|
|
752
758
|
export function getStaticPaths() {
|
|
753
759
|
return locales.map((locale) => ({ params: { locale } }));
|
|
754
760
|
}
|
|
@@ -756,10 +762,7 @@ export function getStaticPaths() {
|
|
|
756
762
|
const { locale } = Astro.params;
|
|
757
763
|
---
|
|
758
764
|
<Layout title="${config.projectName}">
|
|
759
|
-
<main>
|
|
760
|
-
<h1>${config.projectName}</h1>
|
|
761
|
-
<p>Locale: {locale}</p>
|
|
762
|
-
</main>
|
|
765
|
+
<main>${blockSection}</main>
|
|
763
766
|
</Layout>
|
|
764
767
|
`;
|
|
765
768
|
}
|
|
@@ -875,7 +878,7 @@ function scaffold(input) {
|
|
|
875
878
|
return err(contentResult.error);
|
|
876
879
|
}
|
|
877
880
|
Object.assign(files, contentResult.value);
|
|
878
|
-
const i18nResult = wireI18n(config);
|
|
881
|
+
const i18nResult = wireI18n(config, resolvedManifests);
|
|
879
882
|
if (!isOk(i18nResult)) {
|
|
880
883
|
return err(i18nResult.error);
|
|
881
884
|
}
|
|
@@ -1503,7 +1506,7 @@ function manifest(name, overrides = {}) {
|
|
|
1503
1506
|
var FIXTURE_MANIFESTS = {
|
|
1504
1507
|
"hero-gradient": manifest("hero-gradient", {
|
|
1505
1508
|
category: "hero",
|
|
1506
|
-
conflicts: ["hero-video"],
|
|
1509
|
+
conflicts: ["hero-video", "hero-split"],
|
|
1507
1510
|
ai: {
|
|
1508
1511
|
whenToUse: "Landing page hero with gradient background",
|
|
1509
1512
|
whenNotToUse: "Internal pages",
|
|
@@ -1515,7 +1518,8 @@ var FIXTURE_MANIFESTS = {
|
|
|
1515
1518
|
}
|
|
1516
1519
|
}),
|
|
1517
1520
|
"footer-minimal": manifest("footer-minimal", {
|
|
1518
|
-
category: "footer"
|
|
1521
|
+
category: "footer",
|
|
1522
|
+
conflicts: ["footer-rich"]
|
|
1519
1523
|
}),
|
|
1520
1524
|
"cta-simple": manifest("cta-simple", {
|
|
1521
1525
|
category: "cta"
|
|
@@ -1626,17 +1630,96 @@ var FIXTURE_MANIFESTS = {
|
|
|
1626
1630
|
}
|
|
1627
1631
|
}
|
|
1628
1632
|
}),
|
|
1629
|
-
"hero-video": manifest("hero-video"
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1633
|
+
"hero-video": manifest("hero-video", {
|
|
1634
|
+
category: "hero",
|
|
1635
|
+
conflicts: ["hero-gradient", "hero-split"],
|
|
1636
|
+
files: [
|
|
1637
|
+
{ source: "hero-video.astro", destination: "src/components/sections/hero-video.astro" },
|
|
1638
|
+
{ source: "hero-video.css", destination: "src/styles/sections/hero-video.css" }
|
|
1639
|
+
],
|
|
1640
|
+
ai: {
|
|
1641
|
+
whenToUse: "Hero with background video",
|
|
1642
|
+
whenNotToUse: "Static sites",
|
|
1643
|
+
pairsWith: [],
|
|
1644
|
+
contentSlots: {
|
|
1645
|
+
headline: { type: "string" },
|
|
1646
|
+
subheadline: { type: "string" },
|
|
1647
|
+
ctaText: { type: "string" },
|
|
1648
|
+
ctaHref: { type: "string" },
|
|
1649
|
+
videoUrl: { type: "string" },
|
|
1650
|
+
posterUrl: { type: "string" }
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
}),
|
|
1654
|
+
"features-bento": manifest("features-bento", {
|
|
1655
|
+
category: "features",
|
|
1656
|
+
ai: {
|
|
1657
|
+
whenToUse: "Feature showcase in bento grid",
|
|
1658
|
+
whenNotToUse: "Simple pages",
|
|
1659
|
+
pairsWith: [],
|
|
1660
|
+
contentSlots: {
|
|
1661
|
+
headline: { type: "string" },
|
|
1662
|
+
subheadline: { type: "string" },
|
|
1663
|
+
items: { type: "array" }
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
}),
|
|
1667
|
+
"pricing-table": manifest("pricing-table", {
|
|
1668
|
+
category: "pricing",
|
|
1669
|
+
conflicts: ["pricing-comparison"],
|
|
1670
|
+
ai: {
|
|
1671
|
+
whenToUse: "Pricing plans display",
|
|
1672
|
+
whenNotToUse: "Free products",
|
|
1673
|
+
pairsWith: [],
|
|
1674
|
+
contentSlots: {
|
|
1675
|
+
headline: { type: "string" },
|
|
1676
|
+
subheadline: { type: "string" },
|
|
1677
|
+
plans: { type: "array" }
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
}),
|
|
1681
|
+
"faq-accordion": manifest("faq-accordion", {
|
|
1682
|
+
category: "faq",
|
|
1683
|
+
ai: {
|
|
1684
|
+
whenToUse: "Frequently asked questions",
|
|
1685
|
+
whenNotToUse: "Simple pages",
|
|
1686
|
+
pairsWith: [],
|
|
1687
|
+
contentSlots: {
|
|
1688
|
+
headline: { type: "string" },
|
|
1689
|
+
items: { type: "array" }
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
}),
|
|
1693
|
+
"footer-rich": manifest("footer-rich", {
|
|
1694
|
+
category: "footer",
|
|
1695
|
+
conflicts: ["footer-minimal"],
|
|
1696
|
+
ai: {
|
|
1697
|
+
whenToUse: "Multi-column footer with links",
|
|
1698
|
+
whenNotToUse: "Minimal sites",
|
|
1699
|
+
pairsWith: [],
|
|
1700
|
+
contentSlots: {
|
|
1701
|
+
brand: { type: "string" },
|
|
1702
|
+
description: { type: "string" },
|
|
1703
|
+
columns: { type: "array" },
|
|
1704
|
+
copyright: { type: "string" }
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
}),
|
|
1634
1708
|
"testimonials-carousel": manifest("testimonials-carousel"),
|
|
1635
1709
|
"contact-form": manifest("contact-form"),
|
|
1636
|
-
"hero-split": manifest("hero-split"
|
|
1637
|
-
|
|
1710
|
+
"hero-split": manifest("hero-split", {
|
|
1711
|
+
category: "hero",
|
|
1712
|
+
conflicts: ["hero-gradient", "hero-video"]
|
|
1713
|
+
}),
|
|
1714
|
+
"header-transparent": manifest("header-transparent", {
|
|
1715
|
+
category: "header",
|
|
1716
|
+
conflicts: ["header-sticky"]
|
|
1717
|
+
}),
|
|
1638
1718
|
"cta-newsletter": manifest("cta-newsletter"),
|
|
1639
|
-
"header-sticky": manifest("header-sticky"
|
|
1719
|
+
"header-sticky": manifest("header-sticky", {
|
|
1720
|
+
category: "header",
|
|
1721
|
+
conflicts: ["header-transparent"]
|
|
1722
|
+
})
|
|
1640
1723
|
};
|
|
1641
1724
|
var FIXTURE_BLOCK_SOURCES = {
|
|
1642
1725
|
"hero-gradient": {
|
|
@@ -1769,11 +1852,31 @@ export function getStaticPaths() { return [{ params: { slug: '1' } }]; }
|
|
|
1769
1852
|
<slot />`,
|
|
1770
1853
|
"default-content.json": `{ "sidebarLinks": [], "logoutText": "" }`
|
|
1771
1854
|
},
|
|
1772
|
-
"hero-video": {
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1855
|
+
"hero-video": {
|
|
1856
|
+
"hero-video.astro": "<section>Hero Video</section>\n",
|
|
1857
|
+
"hero-video.css": ".hero-video { min-height: 80vh; }\n",
|
|
1858
|
+
"default-content.json": '{"headline":"Experience the Future","subheadline":"Immersive experiences.","ctaText":"Get Started","ctaHref":"#","videoUrl":"","posterUrl":""}'
|
|
1859
|
+
},
|
|
1860
|
+
"features-bento": {
|
|
1861
|
+
"features-bento.astro": "<section>Features Bento</section>\n",
|
|
1862
|
+
"features-bento.css": ".features-bento { padding: 4rem 2rem; }\n",
|
|
1863
|
+
"default-content.json": '{"headline":"Features","subheadline":"Everything you need.","items":[{"title":"Fast","description":"Lightning speed."}]}'
|
|
1864
|
+
},
|
|
1865
|
+
"pricing-table": {
|
|
1866
|
+
"pricing-table.astro": "<section>Pricing</section>\n",
|
|
1867
|
+
"pricing-table.css": ".pricing-table { padding: 4rem 2rem; }\n",
|
|
1868
|
+
"default-content.json": '{"headline":"Pricing","subheadline":"Simple pricing.","plans":[{"name":"Free","price":"$0","features":["Basic"]}]}'
|
|
1869
|
+
},
|
|
1870
|
+
"faq-accordion": {
|
|
1871
|
+
"faq-accordion.astro": "<section>FAQ</section>\n",
|
|
1872
|
+
"faq-accordion.css": ".faq-accordion { padding: 4rem 2rem; }\n",
|
|
1873
|
+
"default-content.json": '{"headline":"FAQ","items":[{"question":"How does it work?","answer":"It just works."}]}'
|
|
1874
|
+
},
|
|
1875
|
+
"footer-rich": {
|
|
1876
|
+
"footer-rich.astro": "<section>Footer</section>\n",
|
|
1877
|
+
"footer-rich.css": ".footer-rich { padding: 3rem 2rem; }\n",
|
|
1878
|
+
"default-content.json": '{"brand":"Acme","description":"Building the future.","columns":[],"copyright":"\xA9 2025"}'
|
|
1879
|
+
},
|
|
1777
1880
|
"testimonials-carousel": { "testimonials-carousel.astro": "<section>Testimonials</section>\n" },
|
|
1778
1881
|
"contact-form": { "contact-form.astro": "<section>Contact</section>\n" },
|
|
1779
1882
|
"hero-split": { "hero-split.astro": "<section>Hero Split</section>\n" },
|
|
@@ -2067,7 +2170,7 @@ async function runManualFlow(input) {
|
|
|
2067
2170
|
message: "Choose a render mode",
|
|
2068
2171
|
options: [
|
|
2069
2172
|
{ value: "static", label: "Static (SSG)", hint: "Pre-built HTML, fastest" },
|
|
2070
|
-
{ value: "hybrid", label: "Hybrid", hint: "Static
|
|
2173
|
+
{ value: "hybrid", label: "Hybrid", hint: "Static + per-page SSR opt-in" },
|
|
2071
2174
|
{ value: "server", label: "Server (SSR)", hint: "Server-rendered on every request" }
|
|
2072
2175
|
]
|
|
2073
2176
|
});
|
|
@@ -2285,7 +2388,7 @@ function runPostScaffold(input, callbacks) {
|
|
|
2285
2388
|
log(pc2.dim(` ${config.packageManager} install`));
|
|
2286
2389
|
}
|
|
2287
2390
|
log(pc2.dim(` ${config.packageManager} dev`));
|
|
2288
|
-
log(pc2.dim(` fornix add <block>`));
|
|
2391
|
+
log(pc2.dim(` npx create-fornix add <block>`));
|
|
2289
2392
|
log("");
|
|
2290
2393
|
}
|
|
2291
2394
|
function installDependencies(projectDir, packageManager, verbose, log, warn) {
|
|
@@ -2378,9 +2481,9 @@ function generateClaudeMd(projectDir, config, blockNames) {
|
|
|
2378
2481
|
lines.push("");
|
|
2379
2482
|
lines.push(`- \`${config.packageManager} dev\` \u2014 start development server`);
|
|
2380
2483
|
lines.push(`- \`${config.packageManager} build\` \u2014 build for production`);
|
|
2381
|
-
lines.push("- `fornix add <block>` \u2014 add a new block");
|
|
2382
|
-
lines.push("- `fornix remove <block>` \u2014 remove a block");
|
|
2383
|
-
lines.push("- `fornix status` \u2014 show project configuration");
|
|
2484
|
+
lines.push("- `npx create-fornix add <block>` \u2014 add a new block");
|
|
2485
|
+
lines.push("- `npx create-fornix remove <block>` \u2014 remove a block");
|
|
2486
|
+
lines.push("- `npx create-fornix status` \u2014 show project configuration");
|
|
2384
2487
|
lines.push("");
|
|
2385
2488
|
lines.push("## File Structure");
|
|
2386
2489
|
lines.push("");
|
|
@@ -3829,8 +3932,9 @@ async function runFlagDrivenMode(args2, manifests, allPalettes) {
|
|
|
3829
3932
|
async function runScaffold(config, manifests, allPalettes, dryRun, verbose, skipInstall, skipGit) {
|
|
3830
3933
|
const spinner2 = p2.spinner();
|
|
3831
3934
|
spinner2.start("Fetching blocks from registry...");
|
|
3832
|
-
const
|
|
3833
|
-
const
|
|
3935
|
+
const selectedBlockNames = config.blocks.map((b) => b.name);
|
|
3936
|
+
const allBlockNames = preResolveDependencies(selectedBlockNames, manifests);
|
|
3937
|
+
const blockResults = await fetchBlocks(allBlockNames);
|
|
3834
3938
|
const blockSources = {};
|
|
3835
3939
|
const blockDefaultContent = {};
|
|
3836
3940
|
for (const result2 of blockResults) {
|
|
@@ -3977,12 +4081,79 @@ function showNoProviderGuide() {
|
|
|
3977
4081
|
console.error(" export CLOUDFLARE_ACCOUNT_ID=... CLOUDFLARE_API_TOKEN=...\n");
|
|
3978
4082
|
console.error(pc3.dim(" Or use manual mode: npx create-fornix --manual\n"));
|
|
3979
4083
|
}
|
|
4084
|
+
function preResolveDependencies(selected, manifests) {
|
|
4085
|
+
const result = /* @__PURE__ */ new Set();
|
|
4086
|
+
function walk(name) {
|
|
4087
|
+
if (result.has(name)) return;
|
|
4088
|
+
const manifest2 = manifests[name];
|
|
4089
|
+
if (!manifest2) {
|
|
4090
|
+
result.add(name);
|
|
4091
|
+
return;
|
|
4092
|
+
}
|
|
4093
|
+
for (const dep of manifest2.requires) {
|
|
4094
|
+
walk(dep);
|
|
4095
|
+
}
|
|
4096
|
+
result.add(name);
|
|
4097
|
+
}
|
|
4098
|
+
for (const name of selected) {
|
|
4099
|
+
walk(name);
|
|
4100
|
+
}
|
|
4101
|
+
return [...result];
|
|
4102
|
+
}
|
|
3980
4103
|
|
|
3981
4104
|
// src/cli/commands/add.ts
|
|
3982
4105
|
import { defineCommand as defineCommand2 } from "citty";
|
|
3983
4106
|
import pc4 from "picocolors";
|
|
3984
4107
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, existsSync as existsSync4, mkdirSync as mkdirSync5 } from "fs";
|
|
3985
4108
|
import { join as join7, dirname as dirname3 } from "path";
|
|
4109
|
+
|
|
4110
|
+
// src/scaffold/page-updater.ts
|
|
4111
|
+
function blockNameToComponentName(blockName) {
|
|
4112
|
+
return blockName.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
4113
|
+
}
|
|
4114
|
+
function blockNameToImportPath(blockName) {
|
|
4115
|
+
return `../components/sections/${blockName}.astro`;
|
|
4116
|
+
}
|
|
4117
|
+
function addBlockToPage(pageContent, blockName) {
|
|
4118
|
+
const componentName = blockNameToComponentName(blockName);
|
|
4119
|
+
const importPath = blockNameToImportPath(blockName);
|
|
4120
|
+
if (pageContent.includes(importPath) || pageContent.includes(`import ${componentName}`)) {
|
|
4121
|
+
return pageContent;
|
|
4122
|
+
}
|
|
4123
|
+
const importLine = `import ${componentName} from '${importPath}';`;
|
|
4124
|
+
const componentTag = ` <${componentName} />`;
|
|
4125
|
+
const frontmatterEnd = pageContent.indexOf("---", pageContent.indexOf("---") + 3);
|
|
4126
|
+
if (frontmatterEnd === -1) {
|
|
4127
|
+
return pageContent;
|
|
4128
|
+
}
|
|
4129
|
+
let updated = pageContent.slice(0, frontmatterEnd) + importLine + "\n" + pageContent.slice(frontmatterEnd);
|
|
4130
|
+
const mainCloseIndex = updated.lastIndexOf("</main>");
|
|
4131
|
+
if (mainCloseIndex !== -1) {
|
|
4132
|
+
updated = updated.slice(0, mainCloseIndex) + componentTag + "\n " + updated.slice(mainCloseIndex);
|
|
4133
|
+
}
|
|
4134
|
+
return updated;
|
|
4135
|
+
}
|
|
4136
|
+
function removeBlockFromPage(pageContent, blockName) {
|
|
4137
|
+
const componentName = blockNameToComponentName(blockName);
|
|
4138
|
+
const importPath = blockNameToImportPath(blockName);
|
|
4139
|
+
let updated = pageContent;
|
|
4140
|
+
const importRegex = new RegExp(
|
|
4141
|
+
`^\\s*import\\s+${componentName}\\s+from\\s+['"]${escapeRegex(importPath)}['"];?\\s*\\n?`,
|
|
4142
|
+
"m"
|
|
4143
|
+
);
|
|
4144
|
+
updated = updated.replace(importRegex, "");
|
|
4145
|
+
const tagRegex = new RegExp(
|
|
4146
|
+
`^\\s*<${componentName}\\s*/?>\\s*\\n?`,
|
|
4147
|
+
"m"
|
|
4148
|
+
);
|
|
4149
|
+
updated = updated.replace(tagRegex, "");
|
|
4150
|
+
return updated;
|
|
4151
|
+
}
|
|
4152
|
+
function escapeRegex(str) {
|
|
4153
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4154
|
+
}
|
|
4155
|
+
|
|
4156
|
+
// src/cli/commands/add.ts
|
|
3986
4157
|
var addCommand = defineCommand2({
|
|
3987
4158
|
meta: {
|
|
3988
4159
|
name: "add",
|
|
@@ -4125,6 +4296,20 @@ var addCommand = defineCommand2({
|
|
|
4125
4296
|
});
|
|
4126
4297
|
}
|
|
4127
4298
|
writeFileSync5(manifestPath, JSON.stringify(manifest2, null, 2) + "\n");
|
|
4299
|
+
const indexPath = join7(cwd, "src/pages/index.astro");
|
|
4300
|
+
if (existsSync4(indexPath)) {
|
|
4301
|
+
let pageContent = readFileSync5(indexPath, "utf-8");
|
|
4302
|
+
for (const name of blocksToAdd) {
|
|
4303
|
+
const bManifest = manifests[name];
|
|
4304
|
+
if (bManifest && bManifest.type === "section") {
|
|
4305
|
+
pageContent = addBlockToPage(pageContent, name);
|
|
4306
|
+
}
|
|
4307
|
+
}
|
|
4308
|
+
writeFileSync5(indexPath, pageContent);
|
|
4309
|
+
if (typedArgs.verbose) {
|
|
4310
|
+
console.log(` ${pc4.dim("\u270E")} updated index.astro`);
|
|
4311
|
+
}
|
|
4312
|
+
}
|
|
4128
4313
|
console.log();
|
|
4129
4314
|
for (const name of blocksToAdd) {
|
|
4130
4315
|
const isDep = name !== blockName;
|
|
@@ -4261,6 +4446,17 @@ var removeCommand = defineCommand3({
|
|
|
4261
4446
|
}
|
|
4262
4447
|
manifest2.blocks = manifest2.blocks.filter((b) => b.name !== blockName);
|
|
4263
4448
|
writeFileSync6(manifestPath, JSON.stringify(manifest2, null, 2) + "\n");
|
|
4449
|
+
const indexPath = join8(cwd, "src/pages/index.astro");
|
|
4450
|
+
if (existsSync5(indexPath)) {
|
|
4451
|
+
const original = readFileSync6(indexPath, "utf-8");
|
|
4452
|
+
const updated = removeBlockFromPage(original, blockName);
|
|
4453
|
+
if (updated !== original) {
|
|
4454
|
+
writeFileSync6(indexPath, updated);
|
|
4455
|
+
if (typedArgs.verbose) {
|
|
4456
|
+
console.log(` ${pc5.dim("\u270E")} updated index.astro`);
|
|
4457
|
+
}
|
|
4458
|
+
}
|
|
4459
|
+
}
|
|
4264
4460
|
console.log();
|
|
4265
4461
|
console.log(` ${pc5.red("-")} ${pc5.bold(blockName)} removed`);
|
|
4266
4462
|
if (dependents.length > 0) {
|
|
@@ -4992,7 +5188,7 @@ async function validateContent(input) {
|
|
|
4992
5188
|
}
|
|
4993
5189
|
const schemaShape = {};
|
|
4994
5190
|
for (const [slotName, slot] of Object.entries(contentSlots)) {
|
|
4995
|
-
schemaShape[slotName] =
|
|
5191
|
+
schemaShape[slotName] = zodTypeForSlot(slot.type);
|
|
4996
5192
|
}
|
|
4997
5193
|
const schema = z5.object(schemaShape);
|
|
4998
5194
|
const parseResult = schema.safeParse(data);
|
|
@@ -5004,7 +5200,7 @@ async function validateContent(input) {
|
|
|
5004
5200
|
);
|
|
5005
5201
|
return ok({ valid: false, errors });
|
|
5006
5202
|
}
|
|
5007
|
-
function
|
|
5203
|
+
function zodTypeForSlot(slotType) {
|
|
5008
5204
|
switch (slotType) {
|
|
5009
5205
|
case "string":
|
|
5010
5206
|
return z5.string();
|