meno-core 1.0.45 → 1.0.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/build-astro.ts +214 -63
  2. package/dist/bin/cli.js +2 -2
  3. package/dist/build-static.js +7 -7
  4. package/dist/chunks/{chunk-NZTSJS5C.js → chunk-2QK6U5UK.js} +3 -2
  5. package/dist/chunks/{chunk-NZTSJS5C.js.map → chunk-2QK6U5UK.js.map} +2 -2
  6. package/dist/chunks/{chunk-BZQKEJQY.js → chunk-77ZB6353.js} +29 -18
  7. package/dist/chunks/chunk-77ZB6353.js.map +7 -0
  8. package/dist/chunks/{chunk-TVH3TC2T.js → chunk-C6U5T5S5.js} +6 -6
  9. package/dist/chunks/{chunk-5ZASE4IG.js → chunk-FED5MME6.js} +234 -11
  10. package/dist/chunks/{chunk-5ZASE4IG.js.map → chunk-FED5MME6.js.map} +3 -3
  11. package/dist/chunks/{chunk-5Z5VQRTJ.js → chunk-I7YIGZXT.js} +4 -4
  12. package/dist/chunks/{chunk-5Z5VQRTJ.js.map → chunk-I7YIGZXT.js.map} +2 -2
  13. package/dist/chunks/{chunk-OUNJ76QM.js → chunk-ORN7S4AP.js} +5 -5
  14. package/dist/chunks/{chunk-GYF3ABI3.js → chunk-UUA5LEWF.js} +3 -3
  15. package/dist/chunks/{chunk-GYF3ABI3.js.map → chunk-UUA5LEWF.js.map} +2 -2
  16. package/dist/chunks/{chunk-WQSG5WHC.js → chunk-ZTKHJQ2Z.js} +2 -2
  17. package/dist/chunks/{chunk-F7MA62WG.js → chunk-ZWYDT3QJ.js} +3 -3
  18. package/dist/chunks/{configService-6KTT6GRT.js → configService-DYCUEURL.js} +3 -3
  19. package/dist/chunks/{constants-L5IKLB6U.js → constants-GWBAD66U.js} +2 -2
  20. package/dist/entries/server-router.js +7 -7
  21. package/dist/lib/client/index.js +4 -4
  22. package/dist/lib/server/index.js +586 -142
  23. package/dist/lib/server/index.js.map +3 -3
  24. package/dist/lib/shared/index.js +7 -3
  25. package/dist/lib/shared/index.js.map +2 -2
  26. package/dist/lib/test-utils/index.js +1 -1
  27. package/lib/client/templateEngine.test.ts +64 -0
  28. package/lib/server/astro/astroEmitHelpers.ts +18 -0
  29. package/lib/server/astro/cmsPageEmitter.ts +31 -1
  30. package/lib/server/astro/componentEmitter.test.ts +59 -0
  31. package/lib/server/astro/componentEmitter.ts +43 -10
  32. package/lib/server/astro/cssCollector.ts +58 -11
  33. package/lib/server/astro/nodeToAstro.test.ts +397 -5
  34. package/lib/server/astro/nodeToAstro.ts +478 -63
  35. package/lib/server/astro/pageEmitter.ts +31 -1
  36. package/lib/server/astro/tailwindMapper.test.ts +119 -0
  37. package/lib/server/astro/tailwindMapper.ts +67 -1
  38. package/lib/server/runtime/httpServer.ts +12 -4
  39. package/lib/server/ssr/htmlGenerator.ts +1 -1
  40. package/lib/server/ssr/jsCollector.ts +2 -2
  41. package/lib/server/ssr/ssrRenderer.test.ts +32 -0
  42. package/lib/server/ssr/ssrRenderer.ts +26 -11
  43. package/lib/shared/constants.ts +1 -0
  44. package/lib/shared/cssGeneration.test.ts +109 -3
  45. package/lib/shared/cssGeneration.ts +98 -13
  46. package/lib/shared/cssNamedColors.ts +47 -0
  47. package/lib/shared/cssProperties.ts +2 -2
  48. package/lib/shared/index.ts +1 -0
  49. package/package.json +1 -1
  50. package/dist/chunks/chunk-BZQKEJQY.js.map +0 -7
  51. /package/dist/chunks/{chunk-TVH3TC2T.js.map → chunk-C6U5T5S5.js.map} +0 -0
  52. /package/dist/chunks/{chunk-OUNJ76QM.js.map → chunk-ORN7S4AP.js.map} +0 -0
  53. /package/dist/chunks/{chunk-WQSG5WHC.js.map → chunk-ZTKHJQ2Z.js.map} +0 -0
  54. /package/dist/chunks/{chunk-F7MA62WG.js.map → chunk-ZWYDT3QJ.js.map} +0 -0
  55. /package/dist/chunks/{configService-6KTT6GRT.js.map → configService-DYCUEURL.js.map} +0 -0
  56. /package/dist/chunks/{constants-L5IKLB6U.js.map → constants-GWBAD66U.js.map} +0 -0
@@ -3,7 +3,7 @@ import {
3
3
  } from "../../chunks/chunk-4OFZP5NQ.js";
4
4
  import {
5
5
  buildStaticPages
6
- } from "../../chunks/chunk-OUNJ76QM.js";
6
+ } from "../../chunks/chunk-ORN7S4AP.js";
7
7
  import {
8
8
  ComponentService,
9
9
  EnumService,
@@ -32,7 +32,7 @@ import {
32
32
  logResponseTime,
33
33
  withErrorHandling,
34
34
  withLogging
35
- } from "../../chunks/chunk-TVH3TC2T.js";
35
+ } from "../../chunks/chunk-C6U5T5S5.js";
36
36
  import {
37
37
  CMSService,
38
38
  ColorService,
@@ -65,6 +65,7 @@ import {
65
65
  loadBreakpointConfig,
66
66
  loadComponentDirectory,
67
67
  loadI18nConfig,
68
+ loadIconsConfig,
68
69
  loadJSONFile,
69
70
  loadProjectConfig,
70
71
  loadResponsiveScalesConfig,
@@ -82,11 +83,11 @@ import {
82
83
  styleToString,
83
84
  translatePath,
84
85
  variableService
85
- } from "../../chunks/chunk-BZQKEJQY.js";
86
+ } from "../../chunks/chunk-77ZB6353.js";
86
87
  import {
87
88
  ConfigService,
88
89
  configService
89
- } from "../../chunks/chunk-WQSG5WHC.js";
90
+ } from "../../chunks/chunk-ZTKHJQ2Z.js";
90
91
  import {
91
92
  bundleFile,
92
93
  createRuntimeServer,
@@ -100,7 +101,7 @@ import {
100
101
  resolveProjectPath,
101
102
  setProjectRoot,
102
103
  validateJS
103
- } from "../../chunks/chunk-5Z5VQRTJ.js";
104
+ } from "../../chunks/chunk-I7YIGZXT.js";
104
105
  import {
105
106
  ensureDir,
106
107
  fileExists,
@@ -117,7 +118,7 @@ import {
117
118
  } from "../../chunks/chunk-WQFG7PAH.js";
118
119
  import "../../chunks/chunk-IF3RATBY.js";
119
120
  import "../../chunks/chunk-KITQJYZV.js";
120
- import "../../chunks/chunk-F7MA62WG.js";
121
+ import "../../chunks/chunk-ZWYDT3QJ.js";
121
122
  import {
122
123
  extractInteractiveStyleMappings,
123
124
  generateAllInteractiveCSS,
@@ -127,13 +128,15 @@ import {
127
128
  isItemDraftForLocale,
128
129
  isVoidElement,
129
130
  singularize
130
- } from "../../chunks/chunk-5ZASE4IG.js";
131
+ } from "../../chunks/chunk-FED5MME6.js";
131
132
  import {
132
133
  DEFAULT_BREAKPOINTS,
133
134
  DEFAULT_I18N_CONFIG,
134
135
  buildLocalizedPath,
136
+ getScaleMultiplier,
135
137
  isI18nValue,
136
- resolveI18nValue
138
+ resolveI18nValue,
139
+ scalePropertyValue
137
140
  } from "../../chunks/chunk-XSWR3QLI.js";
138
141
  import "../../chunks/chunk-UB44F4Z2.js";
139
142
  import {
@@ -144,11 +147,11 @@ import {
144
147
  SERVER_PORT,
145
148
  SERVE_PORT,
146
149
  init_constants
147
- } from "../../chunks/chunk-NZTSJS5C.js";
150
+ } from "../../chunks/chunk-2QK6U5UK.js";
148
151
  import "../../chunks/chunk-KSBZ2L7C.js";
149
152
 
150
153
  // build-astro.ts
151
- import { existsSync, readdirSync, mkdirSync, rmSync, statSync, copyFileSync } from "fs";
154
+ import { existsSync, readdirSync, mkdirSync, rmSync, statSync, copyFileSync, writeFileSync } from "fs";
152
155
  import { writeFile as writeFile2, readFile } from "fs/promises";
153
156
  import { join } from "path";
154
157
  import { createHash } from "crypto";
@@ -582,7 +585,7 @@ function stylesToTailwind(style) {
582
585
  }
583
586
  return { classes, dynamicStyles };
584
587
  }
585
- function responsiveStylesToTailwind(style, breakpoints) {
588
+ function responsiveStylesToTailwind(style, breakpoints, responsiveScales) {
586
589
  if (!style) return { classes: [], dynamicStyles: {} };
587
590
  const allClasses = [];
588
591
  const allDynamicStyles = {};
@@ -616,6 +619,9 @@ function responsiveStylesToTailwind(style, breakpoints) {
616
619
  allClasses.push(...classes.map((cls) => `${prefix}${cls}`));
617
620
  Object.assign(allDynamicStyles, dynamicStyles);
618
621
  }
622
+ if (responsiveScales?.enabled === true && responsive.base) {
623
+ appendAutoScaledClasses(responsive, breakpoints, responsiveScales, allClasses);
624
+ }
619
625
  } else {
620
626
  const { classes, dynamicStyles } = stylesToTailwind(style);
621
627
  allClasses.push(...classes);
@@ -623,6 +629,35 @@ function responsiveStylesToTailwind(style, breakpoints) {
623
629
  }
624
630
  return { classes: allClasses, dynamicStyles: allDynamicStyles };
625
631
  }
632
+ function appendAutoScaledClasses(responsive, breakpoints, responsiveScales, out) {
633
+ const base = responsive.base;
634
+ if (!base) return;
635
+ const baseRef = responsiveScales.baseReference ?? 16;
636
+ const sortedBps = Object.entries(breakpoints).map(([name, cfg]) => ({ name, value: cfg?.breakpoint })).filter(
637
+ (bp) => typeof bp.value === "number" && bp.value > 0
638
+ ).sort((a, b) => b.value - a.value);
639
+ for (const [property, value] of Object.entries(base)) {
640
+ if (isStyleMapping(value)) continue;
641
+ if (value == null) continue;
642
+ const strValue = String(value);
643
+ if (strValue === "" || hasTemplateExpression(strValue)) continue;
644
+ for (const { name: bpName, value: bpPixels } of sortedBps) {
645
+ const bpBranch = responsive[bpName];
646
+ if (bpBranch && property in bpBranch) continue;
647
+ const scale = getScaleMultiplier(
648
+ responsiveScales,
649
+ property,
650
+ bpName
651
+ );
652
+ if (scale == null) continue;
653
+ const scaledValue = scalePropertyValue(strValue, baseRef, scale);
654
+ if (scaledValue == null || scaledValue === strValue) continue;
655
+ const scaledClass = propertyToTailwind(property, scaledValue);
656
+ if (!scaledClass) continue;
657
+ out.push(`max-[${bpPixels}px]:${scaledClass}`);
658
+ }
659
+ }
660
+ }
626
661
 
627
662
  // lib/server/astro/nodeToAstro.ts
628
663
  init_constants();
@@ -687,6 +722,25 @@ function transformItemTemplate(text, itemVar = "item", indexVar, sourceVar) {
687
722
  return text;
688
723
  }
689
724
 
725
+ // lib/server/astro/astroEmitHelpers.ts
726
+ init_constants();
727
+ function stripRawHtmlPrefixDeep(value) {
728
+ if (typeof value === "string") {
729
+ return value.startsWith(RAW_HTML_PREFIX) ? value.slice(RAW_HTML_PREFIX.length) : value;
730
+ }
731
+ if (Array.isArray(value)) {
732
+ return value.map((item) => stripRawHtmlPrefixDeep(item));
733
+ }
734
+ if (value !== null && typeof value === "object") {
735
+ const out = {};
736
+ for (const [k, v] of Object.entries(value)) {
737
+ out[k] = stripRawHtmlPrefixDeep(v);
738
+ }
739
+ return out;
740
+ }
741
+ return value;
742
+ }
743
+
690
744
  // lib/server/astro/nodeToAstro.ts
691
745
  function ind(ctx) {
692
746
  return " ".repeat(ctx.indent);
@@ -751,7 +805,7 @@ function escapeJSX(s) {
751
805
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
752
806
  }
753
807
  function escapeTemplateLiteral(s) {
754
- return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
808
+ return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
755
809
  }
756
810
  function collectStyleMappings(style) {
757
811
  if (!style) return [];
@@ -808,7 +862,7 @@ function getClassForValue(property, value, breakpointPrefix) {
808
862
  return breakpointPrefix ? `${breakpointPrefix}${twClass}` : twClass;
809
863
  }
810
864
  function buildClassAndStyleExpression(style, interactiveStyles, elementClass, ctx) {
811
- const result = style ? responsiveStylesToTailwind(style, ctx.breakpoints) : { classes: [], dynamicStyles: {} };
865
+ const result = style ? responsiveStylesToTailwind(style, ctx.breakpoints, ctx.responsiveScales) : { classes: [], dynamicStyles: {} };
812
866
  const staticClasses = result.classes;
813
867
  const dynamicStyles = result.dynamicStyles;
814
868
  if (elementClass) {
@@ -899,7 +953,7 @@ function resolveTemplate(text, ctx) {
899
953
  let propName = fullMatch[1].trim();
900
954
  if (ctx.listItemBinding) propName = rewriteItemVar(propName, ctx.listItemBinding);
901
955
  if (ctx.listIndexVar) propName = replaceItemMetaVars(propName, ctx.listIndexVar, ctx.listSourceVar);
902
- if (ctx.componentProps[propName]?.type === "rich-text") {
956
+ if (ctx.componentProps[propName]?.type === "rich-text" || ctx.componentProps[propName]?.type === "embed") {
903
957
  return `<Fragment set:html={${propName}} />`;
904
958
  }
905
959
  return `{${propName}}`;
@@ -988,6 +1042,7 @@ function buildAttributesString(attributes, ctx) {
988
1042
  return parts.length > 0 ? " " + parts.join(" ") : "";
989
1043
  }
990
1044
  function formatPropValue(value) {
1045
+ value = stripRawHtmlPrefixDeep(value);
991
1046
  if (typeof value === "string") return `"${escapeJSX(value)}"`;
992
1047
  if (typeof value === "number") return `{${value}}`;
993
1048
  if (typeof value === "boolean") return `{${value}}`;
@@ -1005,12 +1060,11 @@ function nodeToAstro(node, ctx) {
1005
1060
  if (typeof node === "object" && !Array.isArray(node) && isI18nValue(node)) {
1006
1061
  const resolved = resolveI18n(node, ctx);
1007
1062
  if (typeof resolved === "string") {
1008
- return `${ind(ctx)}${escapeJSX(resolved)}
1009
- `;
1063
+ return nodeToAstro(resolved, ctx);
1010
1064
  }
1011
1065
  if (ctx.isComponentDef && isI18nValue(resolved)) {
1012
1066
  ctx.needsI18nResolver = true;
1013
- return `${ind(ctx)}{r(${JSON.stringify(resolved)})}
1067
+ return `${ind(ctx)}{r(${JSON.stringify(stripRawHtmlPrefixDeep(resolved))})}
1014
1068
  `;
1015
1069
  }
1016
1070
  return `${ind(ctx)}${String(resolved ?? "")}
@@ -1032,7 +1086,8 @@ function nodeToAstro(node, ctx) {
1032
1086
  `;
1033
1087
  }
1034
1088
  if (node.startsWith(RAW_HTML_PREFIX)) {
1035
- const rawHtml = node.slice(RAW_HTML_PREFIX.length);
1089
+ const rawSlice = node.slice(RAW_HTML_PREFIX.length);
1090
+ const rawHtml = ctx.processedRawHtml?.get(rawSlice) ?? rawSlice;
1036
1091
  return `${ind(ctx)}<Fragment set:html={\`${escapeTemplateLiteral(rawHtml)}\`} />
1037
1092
  `;
1038
1093
  }
@@ -1079,6 +1134,7 @@ function nodeToAstro(node, ctx) {
1079
1134
  var IMG_TAILWIND_PREFIXES = ["object-", "rounded", "border", "shadow", "[filter", "[transform", "mix-blend"];
1080
1135
  var IMG_OPACITY_PATTERN = /^opacity-/;
1081
1136
  var DEFAULT_SIZES2 = "100vw";
1137
+ var IMG_FILL_CLASSES = ["block", "w-full", "h-full"];
1082
1138
  function splitImageClasses(allClasses) {
1083
1139
  const imgClasses = [];
1084
1140
  const pictureClasses = [];
@@ -1092,6 +1148,156 @@ function splitImageClasses(allClasses) {
1092
1148
  }
1093
1149
  return { pictureClasses, imgClasses };
1094
1150
  }
1151
+ function extractPxWidth(val) {
1152
+ if (typeof val === "number" && Number.isFinite(val) && val > 0) return val;
1153
+ if (typeof val !== "string") return null;
1154
+ const match = val.trim().match(/^(\d+(?:\.\d+)?)px$/);
1155
+ if (!match) return null;
1156
+ const n = parseFloat(match[1]);
1157
+ return n > 0 ? n : null;
1158
+ }
1159
+ function computeSizesAttribute(style, breakpoints) {
1160
+ if (!style) return DEFAULT_SIZES2;
1161
+ const responsive = isResponsiveStyle2(style);
1162
+ const baseStyle = responsive ? style.base : style;
1163
+ const baseWidth = baseStyle ? extractPxWidth(baseStyle.width) : null;
1164
+ if (baseWidth == null) return DEFAULT_SIZES2;
1165
+ const bpEntries = Object.entries(breakpoints).sort(
1166
+ (a, b) => a[1].breakpoint - b[1].breakpoint
1167
+ );
1168
+ const parts = [];
1169
+ for (const [name, entry] of bpEntries) {
1170
+ let effective = null;
1171
+ if (responsive) {
1172
+ const bpStyle = style[name];
1173
+ effective = bpStyle ? extractPxWidth(bpStyle.width) : null;
1174
+ if (effective == null) {
1175
+ for (const [largerName, largerEntry] of bpEntries) {
1176
+ if (largerEntry.breakpoint <= entry.breakpoint) continue;
1177
+ const largerStyle = style[largerName];
1178
+ const larger = largerStyle ? extractPxWidth(largerStyle.width) : null;
1179
+ if (larger != null) {
1180
+ effective = larger;
1181
+ break;
1182
+ }
1183
+ }
1184
+ }
1185
+ if (effective == null) effective = baseWidth;
1186
+ } else {
1187
+ effective = baseWidth;
1188
+ }
1189
+ parts.push(`(max-width: ${entry.breakpoint}px) ${effective}px`);
1190
+ }
1191
+ parts.push(`${baseWidth}px`);
1192
+ return parts.join(", ");
1193
+ }
1194
+ function injectInlineStyle(styleAttr, extraCss) {
1195
+ if (!extraCss) return styleAttr;
1196
+ if (!styleAttr) return ` style="${extraCss}"`;
1197
+ return styleAttr.replace(/style="([^"]*)"/, (_, existing) => {
1198
+ const trimmed = existing.trimEnd();
1199
+ const sep = trimmed.length > 0 && !trimmed.endsWith(";") ? ";" : "";
1200
+ return `style="${existing}${sep}${extraCss}"`;
1201
+ });
1202
+ }
1203
+ var PICTURE_WIDTHS = [500, 800, 1080, 1600, 2400];
1204
+ function imagePathToVarName(srcPath) {
1205
+ const stripped = srcPath.replace(/^\/+/, "").replace(/^images\//, "").replace(/\.[^.]+$/, "");
1206
+ const parts = stripped.split(/[/_\-\s.]+/).filter(Boolean);
1207
+ if (parts.length === 0) return "imgAsset";
1208
+ const camel = parts.map((p, i) => {
1209
+ const clean = p.replace(/[^a-zA-Z0-9]/g, "");
1210
+ if (!clean) return "";
1211
+ if (i === 0) return clean.toLowerCase();
1212
+ return clean[0].toUpperCase() + clean.slice(1).toLowerCase();
1213
+ }).join("");
1214
+ if (!camel) return "imgAsset";
1215
+ return "img" + camel[0].toUpperCase() + camel.slice(1);
1216
+ }
1217
+ function imageImportPath(srcPath, fileDepth) {
1218
+ const rest = srcPath.replace(/^\/+/, "").replace(/^images\//, "");
1219
+ const ups = "../".repeat(Math.max(0, fileDepth) + 1);
1220
+ return `${ups}assets/images/${rest}`;
1221
+ }
1222
+ function isStaticImageSrc(src, ctx) {
1223
+ if (!src) return false;
1224
+ if (typeof src !== "string") return false;
1225
+ if (hasTemplates(src)) return false;
1226
+ if (!src.startsWith("/images/")) return false;
1227
+ if (!ctx.imageMetadataMap?.has(src)) return false;
1228
+ return true;
1229
+ }
1230
+ function registerStaticImageImport(src, ctx) {
1231
+ if (!ctx.imageImports) ctx.imageImports = /* @__PURE__ */ new Map();
1232
+ const depth = ctx.fileDepth ?? 0;
1233
+ const importPath = imageImportPath(src, depth);
1234
+ for (const [existingName, existingPath] of ctx.imageImports) {
1235
+ if (existingPath === importPath) return existingName;
1236
+ }
1237
+ const base = imagePathToVarName(src);
1238
+ let name = base;
1239
+ let counter = 2;
1240
+ while (ctx.imageImports.has(name)) {
1241
+ name = `${base}${counter++}`;
1242
+ }
1243
+ ctx.imageImports.set(name, importPath);
1244
+ return name;
1245
+ }
1246
+ function splitStaticClassExpr(classExpr) {
1247
+ if (classExpr.includes("class:list=")) return null;
1248
+ const classMatch = classExpr.match(/class="([^"]*)"/);
1249
+ if (!classMatch) return { outerClasses: [], innerClasses: [] };
1250
+ const all = classMatch[1].split(/\s+/).filter(Boolean);
1251
+ const { pictureClasses, imgClasses } = splitImageClasses(all);
1252
+ return { outerClasses: pictureClasses, innerClasses: imgClasses };
1253
+ }
1254
+ function formatPictureAttributesProp(classValue, styleAttr) {
1255
+ const styleMatch = styleAttr.match(/style="([^"]*)"/);
1256
+ const parts = [];
1257
+ if (classValue) parts.push(`class: ${JSON.stringify(classValue)}`);
1258
+ if (styleMatch) parts.push(`style: ${JSON.stringify(styleMatch[1])}`);
1259
+ if (parts.length === 0) return "";
1260
+ return ` pictureAttributes={{${parts.join(", ")}}}`;
1261
+ }
1262
+ function emitStaticPictureImage(src, alt, loading, fetchpriority, sizesValue, classExpr, styleAttr, ifExpr, ifClose, blurHash, ctx) {
1263
+ const varName = registerStaticImageImport(src, ctx);
1264
+ const widthsLiteral = `[${PICTURE_WIDTHS.join(", ")}]`;
1265
+ const altAttr = alt !== void 0 ? ` alt="${escapeJSX(String(alt))}"` : ' alt=""';
1266
+ const loadingAttr = loading ? ` loading="${escapeJSX(loading)}"` : "";
1267
+ const fetchpriorityAttr = fetchpriority ? ` fetchpriority="${escapeJSX(fetchpriority)}"` : "";
1268
+ const split = splitStaticClassExpr(classExpr);
1269
+ if (blurHash) {
1270
+ const blurCss = `background-image:url(${escapeJSX(blurHash)});background-size:cover`;
1271
+ const blurStyleAttr = injectInlineStyle(styleAttr, blurCss);
1272
+ const onloadAttr = ` onload="this.parentElement.style.backgroundImage=''"`;
1273
+ if (split) {
1274
+ const outerClassValue = split.outerClasses.join(" ");
1275
+ const pictureAttrs = formatPictureAttributesProp(outerClassValue, blurStyleAttr);
1276
+ const innerClasses = [...split.innerClasses, ...IMG_FILL_CLASSES];
1277
+ const innerClassAttr = ` class="${innerClasses.join(" ")}"`;
1278
+ return `${ifExpr}${ind(ctx)}<Picture${pictureAttrs} src={${varName}}${altAttr}${innerClassAttr} formats={['avif','webp']} widths={${widthsLiteral}} sizes="${escapeJSX(sizesValue)}"${loadingAttr}${fetchpriorityAttr}${onloadAttr} />
1279
+ ${ifClose}`;
1280
+ }
1281
+ const wrapperClassExpr = classExpr;
1282
+ const wrapperStyleAttr = injectInlineStyle(styleAttr, blurCss);
1283
+ const fillClassAttr = ` class="${IMG_FILL_CLASSES.join(" ")}"`;
1284
+ return `${ifExpr}${ind(ctx)}<div${wrapperClassExpr}${wrapperStyleAttr}>
1285
+ ${ind(ctx)} <Picture pictureAttributes={{class: "${IMG_FILL_CLASSES.join(" ")}"}} src={${varName}}${altAttr}${fillClassAttr} formats={['avif','webp']} widths={${widthsLiteral}} sizes="${escapeJSX(sizesValue)}"${loadingAttr}${fetchpriorityAttr} onload="this.parentElement.parentElement.style.backgroundImage=''" />
1286
+ ${ind(ctx)}</div>
1287
+ ${ifClose}`;
1288
+ }
1289
+ if (split) {
1290
+ const outerClassValue = split.outerClasses.join(" ");
1291
+ const innerClassAttr = split.innerClasses.length > 0 ? ` class="${split.innerClasses.join(" ")}"` : "";
1292
+ const pictureAttrs = formatPictureAttributesProp(outerClassValue, styleAttr);
1293
+ return `${ifExpr}${ind(ctx)}<Picture${pictureAttrs} src={${varName}}${altAttr}${innerClassAttr} formats={['avif','webp']} widths={${widthsLiteral}} sizes="${escapeJSX(sizesValue)}"${loadingAttr}${fetchpriorityAttr} />
1294
+ ${ifClose}`;
1295
+ }
1296
+ return `${ifExpr}${ind(ctx)}<div${classExpr}${styleAttr}>
1297
+ ${ind(ctx)} <Picture src={${varName}}${altAttr} formats={['avif','webp']} widths={${widthsLiteral}} sizes="${escapeJSX(sizesValue)}"${loadingAttr}${fetchpriorityAttr} />
1298
+ ${ind(ctx)}</div>
1299
+ ${ifClose}`;
1300
+ }
1095
1301
  function emitImageNode(node, ctx) {
1096
1302
  const style = node.style;
1097
1303
  let elementClass = null;
@@ -1117,7 +1323,22 @@ function emitImageNode(node, ctx) {
1117
1323
  if (width === void 0 && metadata.width) width = metadata.width;
1118
1324
  if (height === void 0 && metadata.height) height = metadata.height;
1119
1325
  }
1120
- const sizesValue = sizes || DEFAULT_SIZES2;
1326
+ const sizesValue = sizes || computeSizesAttribute(style, ctx.breakpoints);
1327
+ if (isStaticImageSrc(src, ctx)) {
1328
+ return emitStaticPictureImage(
1329
+ src,
1330
+ alt,
1331
+ loading,
1332
+ fetchpriority,
1333
+ sizesValue,
1334
+ classExpr,
1335
+ styleAttr,
1336
+ emitIfOpen(node, ctx),
1337
+ emitIfClose(node, ctx),
1338
+ metadata?.blurHash,
1339
+ ctx
1340
+ );
1341
+ }
1121
1342
  const imageSpecificKeys = /* @__PURE__ */ new Set(["src", "alt", "loading", "width", "height", "sizes", "srcset", "fetchpriority"]);
1122
1343
  const otherAttrs = {};
1123
1344
  if (node.attributes) {
@@ -1133,31 +1354,44 @@ function emitImageNode(node, ctx) {
1133
1354
  if (loading) imgAttrs += ` loading="${escapeJSX(String(loading))}"`;
1134
1355
  if (width !== void 0) imgAttrs += ` width="${escapeJSX(String(width))}"`;
1135
1356
  if (height !== void 0) imgAttrs += ` height="${escapeJSX(String(height))}"`;
1136
- let blurStyle = "";
1137
- if (metadata?.blurHash) {
1138
- blurStyle = ` style="background-image: url(${escapeJSX(metadata.blurHash)}); background-size: cover;" onload="this.style.backgroundImage=''"`;
1139
- }
1357
+ const hasAvif = !!(metadata?.avifSrcset && ctx.imageFormat !== "webp");
1358
+ const hasBlur = !!metadata?.blurHash;
1359
+ const useWrapper = hasAvif || hasBlur;
1360
+ const blurWrapperCss = hasBlur ? `background-image:url(${escapeJSX(metadata.blurHash)});background-size:cover` : "";
1361
+ const blurOnload = hasBlur ? ` onload="this.parentElement.style.backgroundImage=''"` : "";
1140
1362
  const ifExpr = emitIfOpen(node, ctx);
1141
1363
  const ifClose = emitIfClose(node, ctx);
1142
- if (metadata?.avifSrcset && ctx.imageFormat !== "webp") {
1143
- const classMatch = classExpr.match(/class="([^"]*)"/);
1364
+ if (useWrapper) {
1365
+ const imgFillClasses = IMG_FILL_CLASSES.slice();
1144
1366
  const classListMatch = classExpr.match(/class:list={\[(.+)\]}/);
1367
+ const classMatch = classExpr.match(/class="([^"]*)"/);
1368
+ let pictureClassExpr = "";
1369
+ let imgClassAttr = "";
1145
1370
  if (classListMatch) {
1146
- return `${ifExpr}${ind(ctx)}<picture${classExpr}${styleAttr}>
1371
+ pictureClassExpr = classExpr;
1372
+ imgClassAttr = ` class="${imgFillClasses.join(" ")}"`;
1373
+ } else {
1374
+ const allClasses = classMatch ? classMatch[1].split(/\s+/).filter(Boolean) : [];
1375
+ const { pictureClasses, imgClasses } = splitImageClasses(allClasses);
1376
+ const fullImgClasses = [...imgClasses, ...imgFillClasses];
1377
+ pictureClassExpr = pictureClasses.length > 0 ? ` class="${pictureClasses.join(" ")}"` : "";
1378
+ imgClassAttr = fullImgClasses.length > 0 ? ` class="${fullImgClasses.join(" ")}"` : "";
1379
+ }
1380
+ const wrapperStyleAttr = injectInlineStyle(styleAttr, blurWrapperCss);
1381
+ if (hasAvif) {
1382
+ return `${ifExpr}${ind(ctx)}<picture${pictureClassExpr}${wrapperStyleAttr}>
1147
1383
  ${ind(ctx)} <source type="image/avif" srcset="${escapeJSX(metadata.avifSrcset)}" sizes="${escapeJSX(sizesValue)}" />
1148
1384
  ${ind(ctx)} <source type="image/webp" srcset="${escapeJSX(metadata.srcset)}" sizes="${escapeJSX(sizesValue)}" />
1149
- ${ind(ctx)} <img${imgAttrs}${blurStyle}${otherAttrsStr} />
1385
+ ${ind(ctx)} <img${imgClassAttr}${imgAttrs}${blurOnload}${otherAttrsStr} />
1150
1386
  ${ind(ctx)}</picture>
1151
1387
  ${ifClose}`;
1152
1388
  }
1153
- const allClasses = classMatch ? classMatch[1].split(/\s+/).filter(Boolean) : [];
1154
- const { pictureClasses, imgClasses } = splitImageClasses(allClasses);
1155
- const pictureClassAttr = pictureClasses.length > 0 ? ` class="${pictureClasses.join(" ")}"` : "";
1156
- const imgClassAttr = imgClasses.length > 0 ? ` class="${imgClasses.join(" ")}"` : "";
1157
- return `${ifExpr}${ind(ctx)}<picture${pictureClassAttr}${styleAttr}>
1158
- ${ind(ctx)} <source type="image/avif" srcset="${escapeJSX(metadata.avifSrcset)}" sizes="${escapeJSX(sizesValue)}" />
1159
- ${ind(ctx)} <source type="image/webp" srcset="${escapeJSX(metadata.srcset)}" sizes="${escapeJSX(sizesValue)}" />
1160
- ${ind(ctx)} <img${imgClassAttr}${imgAttrs}${blurStyle}${otherAttrsStr} />
1389
+ if (metadata?.srcset) {
1390
+ imgAttrs += ` srcset="${escapeJSX(metadata.srcset)}"`;
1391
+ imgAttrs += ` sizes="${escapeJSX(sizesValue)}"`;
1392
+ }
1393
+ return `${ifExpr}${ind(ctx)}<picture${pictureClassExpr}${wrapperStyleAttr}>
1394
+ ${ind(ctx)} <img${imgClassAttr}${imgAttrs}${blurOnload}${otherAttrsStr} />
1161
1395
  ${ind(ctx)}</picture>
1162
1396
  ${ifClose}`;
1163
1397
  }
@@ -1165,7 +1399,7 @@ ${ifClose}`;
1165
1399
  imgAttrs += ` srcset="${escapeJSX(metadata.srcset)}"`;
1166
1400
  imgAttrs += ` sizes="${escapeJSX(sizesValue)}"`;
1167
1401
  }
1168
- return `${ifExpr}${ind(ctx)}<img${classExpr}${styleAttr}${imgAttrs}${blurStyle}${otherAttrsStr} />
1402
+ return `${ifExpr}${ind(ctx)}<img${classExpr}${styleAttr}${imgAttrs}${otherAttrsStr} />
1169
1403
  ${ifClose}`;
1170
1404
  }
1171
1405
  function emitHtmlNode(node, ctx) {
@@ -1248,20 +1482,27 @@ function emitComponentInstance(node, ctx) {
1248
1482
  }
1249
1483
  } else if (ctx.isComponentDef && isI18nValue(value)) {
1250
1484
  ctx.needsI18nResolver = true;
1251
- propParts.push(`${key}={r(${JSON.stringify(value)})}`);
1485
+ propParts.push(`${key}={r(${JSON.stringify(stripRawHtmlPrefixDeep(value))})}`);
1252
1486
  } else {
1253
- propParts.push(`${key}=${formatPropValue(value)}`);
1487
+ const targetInterface = ctx.globalComponents[name]?.component?.interface;
1488
+ const propDef = targetInterface?.[key];
1489
+ if (typeof value === "string" && (propDef?.type === "rich-text" || propDef?.type === "embed")) {
1490
+ propParts.push(`${key}={\`${escapeTemplateLiteral(stripRawHtmlPrefixDeep(value))}\`}`);
1491
+ } else {
1492
+ propParts.push(`${key}=${formatPropValue(value)}`);
1493
+ }
1254
1494
  }
1255
1495
  }
1256
1496
  }
1257
1497
  if (node.style) {
1258
- const { classes: instanceClasses } = responsiveStylesToTailwind(node.style, ctx.breakpoints);
1498
+ const { classes: instanceClasses } = responsiveStylesToTailwind(node.style, ctx.breakpoints, ctx.responsiveScales);
1259
1499
  if (instanceClasses.length > 0) {
1260
1500
  propParts.push(`class="${instanceClasses.join(" ")}"`);
1261
1501
  }
1262
1502
  }
1263
1503
  const propsStr = propParts.length > 0 ? " " + propParts.join(" ") : "";
1264
- const children = emitChildren(node.children, ctx);
1504
+ const childCtx = { ...ctx, elementPath: [0] };
1505
+ const children = emitChildren(node.children, childCtx);
1265
1506
  if (!children.trim()) {
1266
1507
  return `${ifExpr}${ind(ctx)}<${name}${propsStr} />
1267
1508
  ${emitIfClose(node, ctx)}`;
@@ -1426,30 +1667,52 @@ function emitImageTypeNode(node, ctx) {
1426
1667
  );
1427
1668
  const src = node.src;
1428
1669
  const alt = node.alt;
1670
+ if (isStaticImageSrc(src, ctx)) {
1671
+ const staticMeta = ctx.imageMetadataMap.get(src);
1672
+ return emitStaticPictureImage(
1673
+ src,
1674
+ alt,
1675
+ void 0,
1676
+ void 0,
1677
+ computeSizesAttribute(style, ctx.breakpoints),
1678
+ classExpr,
1679
+ styleAttr,
1680
+ "",
1681
+ "",
1682
+ staticMeta.blurHash,
1683
+ ctx
1684
+ );
1685
+ }
1429
1686
  let imgAttrs = "";
1430
1687
  if (src) imgAttrs += ` src="${escapeJSX(String(src))}"`;
1431
1688
  if (alt !== void 0) imgAttrs += ` alt="${escapeJSX(String(alt))}"`;
1432
1689
  const metadata = src ? ctx.imageMetadataMap?.get(String(src)) : void 0;
1433
- if (metadata) {
1434
- let width = metadata.width;
1435
- let height = metadata.height;
1436
- if (width !== void 0) imgAttrs += ` width="${width}"`;
1437
- if (height !== void 0) imgAttrs += ` height="${height}"`;
1438
- let blurStyle = "";
1439
- if (metadata.blurHash) {
1440
- blurStyle = ` style="background-image: url(${escapeJSX(metadata.blurHash)}); background-size: cover;" onload="this.style.backgroundImage=''"`;
1441
- }
1442
- const sizesValue = DEFAULT_SIZES2;
1443
- if (metadata.avifSrcset && ctx.imageFormat !== "webp") {
1444
- const classMatch = classExpr.match(/class="([^"]*)"/);
1445
- const allClasses = classMatch ? classMatch[1].split(/\s+/).filter(Boolean) : [];
1446
- const { pictureClasses, imgClasses } = splitImageClasses(allClasses);
1447
- const pictureClassAttr = pictureClasses.length > 0 ? ` class="${pictureClasses.join(" ")}"` : "";
1448
- const imgClassAttr = imgClasses.length > 0 ? ` class="${imgClasses.join(" ")}"` : "";
1449
- return `${ind(ctx)}<picture${pictureClassAttr}${styleAttr}>
1690
+ if (!metadata) {
1691
+ return `${ind(ctx)}<img${classExpr}${styleAttr}${imgAttrs} />
1692
+ `;
1693
+ }
1694
+ if (metadata.width !== void 0) imgAttrs += ` width="${metadata.width}"`;
1695
+ if (metadata.height !== void 0) imgAttrs += ` height="${metadata.height}"`;
1696
+ const sizesValue = computeSizesAttribute(style, ctx.breakpoints);
1697
+ const hasAvif = !!(metadata.avifSrcset && ctx.imageFormat !== "webp");
1698
+ const hasBlur = !!metadata.blurHash;
1699
+ const useWrapper = hasAvif || hasBlur;
1700
+ const blurWrapperCss = hasBlur ? `background-image:url(${escapeJSX(metadata.blurHash)});background-size:cover` : "";
1701
+ const blurOnload = hasBlur ? ` onload="this.parentElement.style.backgroundImage=''"` : "";
1702
+ if (useWrapper) {
1703
+ const imgFillClasses = IMG_FILL_CLASSES.slice();
1704
+ const classMatch = classExpr.match(/class="([^"]*)"/);
1705
+ const allClasses = classMatch ? classMatch[1].split(/\s+/).filter(Boolean) : [];
1706
+ const { pictureClasses, imgClasses } = splitImageClasses(allClasses);
1707
+ const fullImgClasses = [...imgClasses, ...imgFillClasses];
1708
+ const pictureClassAttr = pictureClasses.length > 0 ? ` class="${pictureClasses.join(" ")}"` : "";
1709
+ const imgClassAttr = fullImgClasses.length > 0 ? ` class="${fullImgClasses.join(" ")}"` : "";
1710
+ const wrapperStyleAttr = injectInlineStyle(styleAttr, blurWrapperCss);
1711
+ if (hasAvif) {
1712
+ return `${ind(ctx)}<picture${pictureClassAttr}${wrapperStyleAttr}>
1450
1713
  ${ind(ctx)} <source type="image/avif" srcset="${escapeJSX(metadata.avifSrcset)}" sizes="${escapeJSX(sizesValue)}" />
1451
1714
  ${ind(ctx)} <source type="image/webp" srcset="${escapeJSX(metadata.srcset)}" sizes="${escapeJSX(sizesValue)}" />
1452
- ${ind(ctx)} <img${imgClassAttr}${imgAttrs}${blurStyle} />
1715
+ ${ind(ctx)} <img${imgClassAttr}${imgAttrs}${blurOnload} />
1453
1716
  ${ind(ctx)}</picture>
1454
1717
  `;
1455
1718
  }
@@ -1457,6 +1720,14 @@ ${ind(ctx)}</picture>
1457
1720
  imgAttrs += ` srcset="${escapeJSX(metadata.srcset)}"`;
1458
1721
  imgAttrs += ` sizes="${escapeJSX(sizesValue)}"`;
1459
1722
  }
1723
+ return `${ind(ctx)}<picture${pictureClassAttr}${wrapperStyleAttr}>
1724
+ ${ind(ctx)} <img${imgClassAttr}${imgAttrs}${blurOnload} />
1725
+ ${ind(ctx)}</picture>
1726
+ `;
1727
+ }
1728
+ if (metadata.srcset) {
1729
+ imgAttrs += ` srcset="${escapeJSX(metadata.srcset)}"`;
1730
+ imgAttrs += ` sizes="${escapeJSX(sizesValue)}"`;
1460
1731
  }
1461
1732
  return `${ind(ctx)}<img${classExpr}${styleAttr}${imgAttrs} />
1462
1733
  `;
@@ -1575,13 +1846,13 @@ function emitLocaleListNode(node, ctx) {
1575
1846
  ctx
1576
1847
  );
1577
1848
  const itemStyle = node.itemStyle;
1578
- const itemResult = itemStyle ? responsiveStylesToTailwind(itemStyle, ctx.breakpoints) : { classes: [], dynamicStyles: {} };
1849
+ const itemResult = itemStyle ? responsiveStylesToTailwind(itemStyle, ctx.breakpoints, ctx.responsiveScales) : { classes: [], dynamicStyles: {} };
1579
1850
  const itemClasses = itemResult.classes;
1580
1851
  const activeItemStyle = node.activeItemStyle;
1581
- const activeResult = activeItemStyle ? responsiveStylesToTailwind(activeItemStyle, ctx.breakpoints) : { classes: [], dynamicStyles: {} };
1852
+ const activeResult = activeItemStyle ? responsiveStylesToTailwind(activeItemStyle, ctx.breakpoints, ctx.responsiveScales) : { classes: [], dynamicStyles: {} };
1582
1853
  const activeItemClasses = [...itemClasses, ...activeResult.classes];
1583
1854
  const separatorStyle = node.separatorStyle;
1584
- const sepResult = separatorStyle ? responsiveStylesToTailwind(separatorStyle, ctx.breakpoints) : { classes: [], dynamicStyles: {} };
1855
+ const sepResult = separatorStyle ? responsiveStylesToTailwind(separatorStyle, ctx.breakpoints, ctx.responsiveScales) : { classes: [], dynamicStyles: {} };
1585
1856
  const separatorClasses = sepResult.classes;
1586
1857
  const localeIconMap = /* @__PURE__ */ new Map();
1587
1858
  for (const localeConfig of i18nConfig.locales) {
@@ -1590,7 +1861,7 @@ function emitLocaleListNode(node, ctx) {
1590
1861
  }
1591
1862
  }
1592
1863
  const flagStyle = node.flagStyle;
1593
- const flagResult = flagStyle ? responsiveStylesToTailwind(flagStyle, ctx.breakpoints) : { classes: [], dynamicStyles: {} };
1864
+ const flagResult = flagStyle ? responsiveStylesToTailwind(flagStyle, ctx.breakpoints, ctx.responsiveScales) : { classes: [], dynamicStyles: {} };
1594
1865
  const flagClasses = flagResult.classes;
1595
1866
  const links = [];
1596
1867
  const currentLocale = ctx.locale || i18nConfig.defaultLocale;
@@ -1776,7 +2047,7 @@ function propDefToTSType(def) {
1776
2047
  }
1777
2048
  function formatDefault(def) {
1778
2049
  if (!("default" in def) || def.default === void 0) return null;
1779
- const val = def.default;
2050
+ const val = stripRawHtmlPrefixDeep(def.default);
1780
2051
  if (typeof val === "string") return JSON.stringify(val);
1781
2052
  if (typeof val === "number" || typeof val === "boolean") return String(val);
1782
2053
  if (typeof val === "object" && val !== null && "_i18n" in val) {
@@ -1818,7 +2089,7 @@ function mergeClassNameOntoRoot(template) {
1818
2089
  }
1819
2090
  return prefix + tagName + ` class={className}` + attrs + close + template.slice(fullMatch.length);
1820
2091
  }
1821
- function emitAstroComponent(name, def, allComponents, breakpoints = DEFAULT_BREAKPOINTS, defaultLocale = "en") {
2092
+ function emitAstroComponent(name, def, allComponents, breakpoints = DEFAULT_BREAKPOINTS, defaultLocale = "en", responsiveScales) {
1822
2093
  const comp = def.component;
1823
2094
  const propDefs = comp.interface || {};
1824
2095
  const structure = comp.structure;
@@ -1836,11 +2107,22 @@ function emitAstroComponent(name, def, allComponents, breakpoints = DEFAULT_BREA
1836
2107
  fileType: "component",
1837
2108
  fileName: name,
1838
2109
  breakpoints,
1839
- defaultLocale
2110
+ responsiveScales,
2111
+ defaultLocale,
2112
+ imageImports: /* @__PURE__ */ new Map(),
2113
+ fileDepth: 0
2114
+ // components live at src/components/
1840
2115
  };
1841
2116
  let templateBody = nodeToAstro(structure, ctx);
1842
2117
  templateBody = mergeClassNameOntoRoot(templateBody);
1843
- const frontmatter = buildFrontmatter(name, propDefs, ctx.imports, ctx.dynamicTags, ctx.needsI18nResolver ? defaultLocale : void 0);
2118
+ const frontmatter = buildFrontmatter(
2119
+ name,
2120
+ propDefs,
2121
+ ctx.imports,
2122
+ ctx.dynamicTags,
2123
+ ctx.needsI18nResolver ? defaultLocale : void 0,
2124
+ ctx.imageImports
2125
+ );
1844
2126
  const styleSection = comp.css ? `
1845
2127
  <style>
1846
2128
  ${comp.css}
@@ -1851,11 +2133,18 @@ ${comp.css}
1851
2133
  ${frontmatter}---
1852
2134
  ${templateBody}${styleSection}${scriptSection}`;
1853
2135
  }
1854
- function buildFrontmatter(componentName, propDefs, imports, dynamicTags, i18nDefaultLocale) {
2136
+ function buildFrontmatter(componentName, propDefs, imports, dynamicTags, i18nDefaultLocale, imageImports) {
1855
2137
  const lines = [];
1856
2138
  for (const imp of Array.from(imports).sort()) {
1857
2139
  lines.push(`import ${imp} from './${imp}.astro';`);
1858
2140
  }
2141
+ if (imageImports && imageImports.size > 0) {
2142
+ lines.push(`import { Picture } from 'astro:assets';`);
2143
+ const sortedImages = Array.from(imageImports.entries()).sort(([a], [b]) => a.localeCompare(b));
2144
+ for (const [varName, importPath] of sortedImages) {
2145
+ lines.push(`import ${varName} from '${importPath}';`);
2146
+ }
2147
+ }
1859
2148
  if (lines.length > 0) lines.push("");
1860
2149
  const propEntries = Object.entries(propDefs);
1861
2150
  {
@@ -1948,7 +2237,13 @@ function transformDefineVarsJS(js, varNames) {
1948
2237
  return result;
1949
2238
  }
1950
2239
  function buildScriptSection(js, comp, propDefs) {
1951
- const elInit = "const el = document.currentScript.previousElementSibling;";
2240
+ const cleanTextNodes = `(function _w(n){var c=n.firstChild,x;while(c){x=c.nextSibling;if(c.nodeType===3){if(!c.textContent.trim())n.removeChild(c)}else if(c.nodeType===1)_w(c);c=x}})(el);`;
2241
+ const deferWrapper = (innerJS) => `var el = document.currentScript.previousElementSibling;
2242
+ function __init__() {
2243
+ ${cleanTextNodes}
2244
+ ${innerJS}
2245
+ }
2246
+ if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', __init__); } else { __init__(); }`;
1952
2247
  if (comp.defineVars) {
1953
2248
  const vars = comp.defineVars === true ? Object.keys(propDefs).filter((k) => k !== "children") : comp.defineVars;
1954
2249
  if (vars.length > 0) {
@@ -1956,23 +2251,25 @@ function buildScriptSection(js, comp, propDefs) {
1956
2251
  const defineVarsObj = `{ ${vars.join(", ")} }`;
1957
2252
  return `
1958
2253
  <script define:vars={${defineVarsObj}}>
1959
- ${elInit}
1960
- ${transformedJS}
2254
+ (function(){
2255
+ ${deferWrapper(transformedJS)}
2256
+ })();
1961
2257
  </script>
1962
2258
  `;
1963
2259
  }
1964
2260
  }
1965
2261
  return `
1966
2262
  <script is:inline>
1967
- ${elInit}
1968
- ${js}
2263
+ (function(){
2264
+ ${deferWrapper(js)}
2265
+ })();
1969
2266
  </script>
1970
2267
  `;
1971
2268
  }
1972
2269
 
1973
2270
  // lib/server/astro/pageEmitter.ts
1974
2271
  function escapeTemplateLiteral2(s) {
1975
- return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
2272
+ return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
1976
2273
  }
1977
2274
  function escapeJSX2(s) {
1978
2275
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
@@ -1997,11 +2294,13 @@ function emitAstroPage(options) {
1997
2294
  ssrFallbacks,
1998
2295
  pageName,
1999
2296
  breakpoints: breakpointsOpt,
2297
+ responsiveScales,
2000
2298
  imageMetadataMap,
2001
2299
  i18nConfig,
2002
2300
  currentPageSlugMap,
2003
2301
  slugMappings,
2004
- imageFormat
2302
+ imageFormat,
2303
+ processedRawHtml
2005
2304
  } = options;
2006
2305
  const breakpoints = breakpointsOpt ?? DEFAULT_BREAKPOINTS;
2007
2306
  const root = pageData.root;
@@ -2020,6 +2319,7 @@ function emitAstroPage(options) {
2020
2319
  fileType: "page",
2021
2320
  fileName: pageName,
2022
2321
  breakpoints,
2322
+ responsiveScales,
2023
2323
  imageMetadataMap,
2024
2324
  locale,
2025
2325
  i18nConfig,
@@ -2028,7 +2328,10 @@ function emitAstroPage(options) {
2028
2328
  astroImports: /* @__PURE__ */ new Set(),
2029
2329
  slugMappings,
2030
2330
  i18nDefaultLocale: i18nConfig?.defaultLocale,
2031
- imageFormat
2331
+ imageFormat,
2332
+ processedRawHtml,
2333
+ imageImports: /* @__PURE__ */ new Map(),
2334
+ fileDepth
2032
2335
  };
2033
2336
  const templateBody = nodeToAstro(root, ctx);
2034
2337
  const importLines = [];
@@ -2037,6 +2340,13 @@ function emitAstroPage(options) {
2037
2340
  importLines.push(`import { ${astroImports.join(", ")} } from 'astro:content';`);
2038
2341
  }
2039
2342
  importLines.push(`import BaseLayout from '${layoutImportPath2}';`);
2343
+ if (ctx.imageImports && ctx.imageImports.size > 0) {
2344
+ importLines.push(`import { Picture } from 'astro:assets';`);
2345
+ const sortedImages = Array.from(ctx.imageImports.entries()).sort(([a], [b]) => a.localeCompare(b));
2346
+ for (const [varName, importPath] of sortedImages) {
2347
+ importLines.push(`import ${varName} from '${importPath}';`);
2348
+ }
2349
+ }
2040
2350
  const componentImports = Array.from(ctx.imports).sort();
2041
2351
  for (const comp of componentImports) {
2042
2352
  const path = componentImportPath(fileDepth, comp);
@@ -2087,7 +2397,7 @@ import BaseLayout from '${layoutImport}';
2087
2397
 
2088
2398
  // lib/server/astro/cmsPageEmitter.ts
2089
2399
  function escapeTemplateLiteral3(s) {
2090
- return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
2400
+ return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
2091
2401
  }
2092
2402
  function escapeJSX3(s) {
2093
2403
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
@@ -2206,10 +2516,12 @@ function emitCMSPage(options) {
2206
2516
  ssrFallbacks,
2207
2517
  pageName,
2208
2518
  breakpoints: breakpointsOpt,
2519
+ responsiveScales,
2209
2520
  imageMetadataMap,
2210
2521
  i18nConfig,
2211
2522
  isMultiLocale,
2212
- slugMappings
2523
+ slugMappings,
2524
+ processedRawHtml
2213
2525
  } = options;
2214
2526
  const breakpoints = breakpointsOpt ?? DEFAULT_BREAKPOINTS;
2215
2527
  const binding = "entry";
@@ -2245,6 +2557,7 @@ function emitCMSPage(options) {
2245
2557
  fileType: "page",
2246
2558
  fileName: pageName,
2247
2559
  breakpoints,
2560
+ responsiveScales,
2248
2561
  imageMetadataMap,
2249
2562
  locale,
2250
2563
  cmsMode: true,
@@ -2253,12 +2566,22 @@ function emitCMSPage(options) {
2253
2566
  cmsWrapFn: wrapFn,
2254
2567
  slugMappings,
2255
2568
  i18nDefaultLocale: i18nConfig.defaultLocale,
2256
- imageFormat: options.imageFormat
2569
+ imageFormat: options.imageFormat,
2570
+ processedRawHtml,
2571
+ imageImports: /* @__PURE__ */ new Map(),
2572
+ fileDepth
2257
2573
  };
2258
2574
  const templateBody = nodeToAstro(root, ctx);
2259
2575
  const importLines = [];
2260
2576
  importLines.push(`import { getCollection } from 'astro:content';`);
2261
2577
  importLines.push(`import BaseLayout from '${layoutImportPath2}';`);
2578
+ if (ctx.imageImports && ctx.imageImports.size > 0) {
2579
+ importLines.push(`import { Picture } from 'astro:assets';`);
2580
+ const sortedImages = Array.from(ctx.imageImports.entries()).sort(([a], [b]) => a.localeCompare(b));
2581
+ for (const [varName, importPath] of sortedImages) {
2582
+ importLines.push(`import ${varName} from '${importPath}';`);
2583
+ }
2584
+ }
2262
2585
  const componentImports = Array.from(ctx.imports).sort();
2263
2586
  for (const comp of componentImports) {
2264
2587
  const path = componentImportPath2(fileDepth, comp);
@@ -2338,25 +2661,32 @@ function isStyleMapping3(value) {
2338
2661
  function isResponsiveStyle3(style) {
2339
2662
  return "base" in style || "tablet" in style || "mobile" in style;
2340
2663
  }
2341
- function collectFromStyle(style, classes, breakpoints) {
2664
+ function collectFromStyle(style, classes, breakpoints, responsiveScales) {
2342
2665
  if (!style) return;
2343
2666
  if (isResponsiveStyle3(style)) {
2344
2667
  for (const [bp, bpStyle] of Object.entries(style)) {
2345
2668
  if (!bpStyle) continue;
2346
2669
  let prefix = "";
2670
+ let bpName;
2347
2671
  if (bp !== "base") {
2348
2672
  const bpValue = breakpoints[bp]?.breakpoint;
2349
2673
  if (bpValue) {
2350
2674
  prefix = `max-[${bpValue}px]:`;
2675
+ bpName = bp;
2351
2676
  }
2352
2677
  }
2353
- collectFromFlatStyle(bpStyle, prefix, classes);
2678
+ collectFromFlatStyle(bpStyle, prefix, classes, breakpoints, responsiveScales, bpName);
2354
2679
  }
2355
2680
  } else {
2356
- collectFromFlatStyle(style, "", classes);
2681
+ collectFromFlatStyle(style, "", classes, breakpoints, responsiveScales);
2357
2682
  }
2358
2683
  }
2359
- function collectFromFlatStyle(style, prefix, classes) {
2684
+ function collectFromFlatStyle(style, prefix, classes, breakpoints, responsiveScales, sourceBreakpoint) {
2685
+ const shouldAutoScale = responsiveScales?.enabled === true && sourceBreakpoint === void 0;
2686
+ const scaleBreakpoints = shouldAutoScale ? Object.entries(breakpoints).map(([name, cfg]) => ({ name, value: cfg?.breakpoint })).filter(
2687
+ (bp) => typeof bp.value === "number" && bp.value > 0
2688
+ ).sort((a, b) => b.value - a.value) : [];
2689
+ const baseRef = responsiveScales?.baseReference ?? 16;
2360
2690
  for (const [property, value] of Object.entries(style)) {
2361
2691
  if (!isStyleMapping3(value)) continue;
2362
2692
  for (const [, cssValue] of Object.entries(value.values)) {
@@ -2364,41 +2694,58 @@ function collectFromFlatStyle(style, prefix, classes) {
2364
2694
  if (twClass) {
2365
2695
  classes.add(prefix ? `${prefix}${twClass}` : twClass);
2366
2696
  }
2697
+ if (shouldAutoScale && responsiveScales) {
2698
+ const strValue = String(cssValue);
2699
+ if (strValue === "") continue;
2700
+ for (const { name: bpName, value: bpPixels } of scaleBreakpoints) {
2701
+ const scale = getScaleMultiplier(
2702
+ responsiveScales,
2703
+ property,
2704
+ bpName
2705
+ );
2706
+ if (scale == null) continue;
2707
+ const scaledValue = scalePropertyValue(strValue, baseRef, scale);
2708
+ if (scaledValue == null || scaledValue === strValue) continue;
2709
+ const scaledClass = propertyToTailwind(property, scaledValue);
2710
+ if (!scaledClass) continue;
2711
+ classes.add(`max-[${bpPixels}px]:${scaledClass}`);
2712
+ }
2713
+ }
2367
2714
  }
2368
2715
  }
2369
2716
  }
2370
- function walkNode(node, classes, breakpoints) {
2717
+ function walkNode(node, classes, breakpoints, responsiveScales) {
2371
2718
  if (!node || typeof node === "string" || typeof node === "number") return;
2372
2719
  if (Array.isArray(node)) {
2373
2720
  for (const child of node) {
2374
- walkNode(child, classes, breakpoints);
2721
+ walkNode(child, classes, breakpoints, responsiveScales);
2375
2722
  }
2376
2723
  return;
2377
2724
  }
2378
2725
  if ("style" in node && node.style) {
2379
- collectFromStyle(node.style, classes, breakpoints);
2726
+ collectFromStyle(node.style, classes, breakpoints, responsiveScales);
2380
2727
  }
2381
2728
  if ("interactiveStyles" in node && Array.isArray(node.interactiveStyles)) {
2382
2729
  for (const rule of node.interactiveStyles) {
2383
2730
  if (rule.style) {
2384
- collectFromStyle(rule.style, classes, breakpoints);
2731
+ collectFromStyle(rule.style, classes, breakpoints, responsiveScales);
2385
2732
  }
2386
2733
  }
2387
2734
  }
2388
2735
  if ("children" in node && node.children) {
2389
2736
  if (Array.isArray(node.children)) {
2390
2737
  for (const child of node.children) {
2391
- walkNode(child, classes, breakpoints);
2738
+ walkNode(child, classes, breakpoints, responsiveScales);
2392
2739
  }
2393
2740
  }
2394
2741
  }
2395
2742
  }
2396
- function collectAllMappingClasses(componentDefs, breakpoints = DEFAULT_BREAKPOINTS) {
2743
+ function collectAllMappingClasses(componentDefs, breakpoints = DEFAULT_BREAKPOINTS, responsiveScales) {
2397
2744
  const classes = /* @__PURE__ */ new Set();
2398
2745
  for (const def of Object.values(componentDefs)) {
2399
2746
  const structure = def.component?.structure;
2400
2747
  if (structure) {
2401
- walkNode(structure, classes, breakpoints);
2748
+ walkNode(structure, classes, breakpoints, responsiveScales);
2402
2749
  }
2403
2750
  }
2404
2751
  return classes;
@@ -2408,18 +2755,40 @@ function collectAllMappingClasses(componentDefs, breakpoints = DEFAULT_BREAKPOIN
2408
2755
  function hashContent2(content) {
2409
2756
  return createHash("sha256").update(content).digest("hex").slice(0, 8);
2410
2757
  }
2411
- function copyDirectory(src, dest) {
2758
+ function writePageScript(javascript, scriptsDir) {
2759
+ if (!javascript) return [];
2760
+ const hash = hashContent2(javascript);
2761
+ const scriptFile = `${hash}.js`;
2762
+ if (!existsSync(scriptsDir)) {
2763
+ mkdirSync(scriptsDir, { recursive: true });
2764
+ }
2765
+ const fullScriptPath = join(scriptsDir, scriptFile);
2766
+ if (!existsSync(fullScriptPath)) {
2767
+ writeFileSync(fullScriptPath, javascript, "utf-8");
2768
+ }
2769
+ return [`/_scripts/${scriptFile}`];
2770
+ }
2771
+ function copyDirectory(src, dest, filter) {
2412
2772
  if (!existsSync(src)) return;
2413
2773
  if (!existsSync(dest)) mkdirSync(dest, { recursive: true });
2414
2774
  const files = readdirSync(src);
2415
2775
  for (const file of files) {
2776
+ if (filter && !filter(file)) continue;
2416
2777
  const srcPath = join(src, file);
2417
2778
  const destPath = join(dest, file);
2418
2779
  const stat = statSync(srcPath);
2419
- if (stat.isDirectory()) copyDirectory(srcPath, destPath);
2780
+ if (stat.isDirectory()) copyDirectory(srcPath, destPath, filter);
2420
2781
  else copyFileSync(srcPath, destPath);
2421
2782
  }
2422
2783
  }
2784
+ var imageVariantSuffixRe = new RegExp(
2785
+ `-(${RESPONSIVE_WIDTHS.join("|")})\\.(webp|avif)$`
2786
+ );
2787
+ function shouldCopyImageForAstro(filename) {
2788
+ if (filename === "manifest.json") return false;
2789
+ if (imageVariantSuffixRe.test(filename)) return false;
2790
+ return true;
2791
+ }
2423
2792
  function isCMSPage(pageData) {
2424
2793
  return pageData.meta?.source === "cms" && !!pageData.meta?.cms;
2425
2794
  }
@@ -2588,6 +2957,7 @@ async function buildAstroProject(projectRoot, outputDir) {
2588
2957
  const allComponentCSS = /* @__PURE__ */ new Set();
2589
2958
  const jsContents = /* @__PURE__ */ new Map();
2590
2959
  let errorCount = 0;
2960
+ let projectNeedsFormHandler = false;
2591
2961
  function mergeInteractiveStyles(source) {
2592
2962
  for (const [key, value] of source) {
2593
2963
  if (!allInteractiveStyles.has(key)) {
@@ -2606,6 +2976,9 @@ async function buildAstroProject(projectRoot, outputDir) {
2606
2976
  jsContents.set(hash, result.javascript);
2607
2977
  }
2608
2978
  }
2979
+ if (!projectNeedsFormHandler && needsFormHandler(result.html)) {
2980
+ projectNeedsFormHandler = true;
2981
+ }
2609
2982
  allResults.push({
2610
2983
  html: result.html,
2611
2984
  meta: result.meta,
@@ -2620,7 +2993,8 @@ async function buildAstroProject(projectRoot, outputDir) {
2620
2993
  pageData,
2621
2994
  pageName,
2622
2995
  isCMSPage: isCMSPage3,
2623
- ssrFallbackCollector: result.ssrFallbackCollector
2996
+ ssrFallbackCollector: result.ssrFallbackCollector,
2997
+ processedRawHtmlCollector: result.processedRawHtmlCollector
2624
2998
  });
2625
2999
  }
2626
3000
  for (const file of pageFiles) {
@@ -2680,8 +3054,39 @@ async function buildAstroProject(projectRoot, outputDir) {
2680
3054
  const fontPreloads = generateFontPreloadTags();
2681
3055
  const mergedLibraries = mergeLibraries(globalLibraries, componentLibraries);
2682
3056
  const buildLibraries = filterLibrariesByContext(mergedLibraries, "build");
2683
- const libraryTags = generateLibraryTags(buildLibraries);
3057
+ const inlineContents = /* @__PURE__ */ new Map();
3058
+ const localLibsToCopy = [];
3059
+ for (const css of buildLibraries.css || []) {
3060
+ if (!css.url.startsWith("/")) continue;
3061
+ const shouldInline = css.inline !== false;
3062
+ const relPath = css.url.slice(1);
3063
+ const srcPath = join(projectPaths.project, relPath);
3064
+ if (!existsSync(srcPath)) continue;
3065
+ if (shouldInline) {
3066
+ try {
3067
+ inlineContents.set(css.url, await readFile(srcPath, "utf-8"));
3068
+ } catch {
3069
+ localLibsToCopy.push(relPath);
3070
+ }
3071
+ } else {
3072
+ localLibsToCopy.push(relPath);
3073
+ }
3074
+ }
3075
+ for (const js of buildLibraries.js || []) {
3076
+ if (js.url.startsWith("/")) {
3077
+ const relPath = js.url.slice(1);
3078
+ if (existsSync(join(projectPaths.project, relPath))) {
3079
+ localLibsToCopy.push(relPath);
3080
+ }
3081
+ }
3082
+ }
3083
+ const libraryTags = generateLibraryTags(buildLibraries, inlineContents);
2684
3084
  const defaultTheme = themeConfig.default || "light";
3085
+ const customCode = configService.getCustomCode();
3086
+ const iconsConfig = await loadIconsConfig();
3087
+ const faviconTag = iconsConfig.favicon ? `<link rel="icon" href="${iconsConfig.favicon.replace(/"/g, "&quot;")}" />` : "";
3088
+ const appleTouchIconTag = iconsConfig.appleTouchIcon ? `<link rel="apple-touch-icon" href="${iconsConfig.appleTouchIcon.replace(/"/g, "&quot;")}" />` : "";
3089
+ const iconTagsHtml = [faviconTag, appleTouchIconTag].filter(Boolean).join("\n ");
2685
3090
  const templatesDir = projectPaths.templates();
2686
3091
  const templateSchemas = [];
2687
3092
  let cmsPageCount = 0;
@@ -2776,12 +3181,14 @@ Processing ${templateFiles.length} CMS template(s)...
2776
3181
  ssrFallbacks,
2777
3182
  pageName: file.replace(".json", ""),
2778
3183
  breakpoints,
3184
+ responsiveScales,
2779
3185
  imageMetadataMap,
2780
3186
  i18nConfig,
2781
3187
  isMultiLocale: false,
2782
3188
  // Each file handles one locale
2783
3189
  slugMappings,
2784
- imageFormat: configService.getImageFormat()
3190
+ imageFormat: configService.getImageFormat(),
3191
+ processedRawHtml: metaResult.processedRawHtmlCollector
2785
3192
  });
2786
3193
  const astroFileFull = join(pagesOutDir, astroFilePath);
2787
3194
  const astroFileDir = astroFileFull.substring(0, astroFileFull.lastIndexOf("/"));
@@ -2798,12 +3205,12 @@ Processing ${templateFiles.length} CMS template(s)...
2798
3205
  }
2799
3206
  }
2800
3207
  }
2801
- const mappingClasses = collectAllMappingClasses(globalComponents, breakpoints);
3208
+ const mappingClasses = collectAllMappingClasses(globalComponents, breakpoints, responsiveScales);
2802
3209
  const fontCSS = generateFontCSS();
2803
3210
  const themeColorCSS = generateThemeColorVariablesCSS(themeConfig);
2804
3211
  const variablesCSS = generateVariablesCSS(variablesConfig, breakpoints, responsiveScales);
2805
3212
  const remConversionConfig = configService.getRemConversion();
2806
- const interactiveCSS = generateAllInteractiveCSS(allInteractiveStyles, breakpoints, remConversionConfig);
3213
+ const interactiveCSS = generateAllInteractiveCSS(allInteractiveStyles, breakpoints, remConversionConfig, responsiveScales);
2807
3214
  const componentCSSCombined = Array.from(allComponentCSS).join("\n");
2808
3215
  const baseCSS = `@layer base {
2809
3216
  * { margin: 0; padding: 0; box-sizing: border-box; }
@@ -2814,13 +3221,24 @@ Processing ${templateFiles.length} CMS template(s)...
2814
3221
  .olink { text-decoration: none; display: block; }
2815
3222
  .oem { display: inline-block; }
2816
3223
  }`;
2817
- const tailwindDirectives = `@tailwind base;
2818
- @tailwind components;
2819
- @tailwind utilities;`;
3224
+ const safelistClasses = Array.from(mappingClasses);
3225
+ const safelistDirectives = safelistClasses.map((c) => `@source inline("${c}");`).join("\n");
3226
+ const tailwindDirectives = safelistDirectives ? `@import "tailwindcss";
3227
+
3228
+ ${safelistDirectives}` : `@import "tailwindcss";`;
2820
3229
  const globalCSS = [tailwindDirectives, fontCSS, themeColorCSS, variablesCSS, baseCSS, componentCSSCombined, interactiveCSS].filter(Boolean).join("\n\n");
2821
3230
  await writeFile2(join(stylesDir, "global.css"), globalCSS, "utf-8");
2822
3231
  console.log(`
2823
3232
  Generated global.css (${(globalCSS.length / 1024).toFixed(1)} KB)`);
3233
+ const escForTemplateLiteral = (s) => s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
3234
+ const customHeadLiteral = escForTemplateLiteral(customCode.head || "");
3235
+ const customBodyStartLiteral = escForTemplateLiteral(customCode.bodyStart || "");
3236
+ const customBodyEndLiteral = escForTemplateLiteral(customCode.bodyEnd || "");
3237
+ const iconTagsLiteral = escForTemplateLiteral(iconTagsHtml);
3238
+ const formHandlerBlock = projectNeedsFormHandler ? `
3239
+ <script is:inline>
3240
+ ${formHandlerScript}
3241
+ </script>` : "";
2824
3242
  const baseLayoutContent = `---
2825
3243
  import '../styles/global.css';
2826
3244
 
@@ -2841,16 +3259,20 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
2841
3259
  <head>
2842
3260
  <meta charset="UTF-8">
2843
3261
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
3262
+ <Fragment set:html={\`${iconTagsLiteral}\`} />
2844
3263
  <Fragment set:html={fontPreloads} />
2845
3264
  <Fragment set:html={libraryTags.headCSS || ''} />
2846
3265
  <Fragment set:html={libraryTags.headJS || ''} />
2847
3266
  <Fragment set:html={meta} />
3267
+ <Fragment set:html={\`${customHeadLiteral}\`} />
2848
3268
  <title>{title}</title>
2849
3269
  </head>
2850
3270
  <body>
3271
+ <Fragment set:html={\`${customBodyStartLiteral}\`} />
2851
3272
  <slot />
2852
3273
  {scripts.map((s) => <script src={s} />)}
2853
3274
  <Fragment set:html={libraryTags.bodyEndJS || ''} />
3275
+ <Fragment set:html={\`${customBodyEndLiteral}\`} />${formHandlerBlock}
2854
3276
  </body>
2855
3277
  </html>
2856
3278
  `;
@@ -2859,7 +3281,7 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
2859
3281
  let componentFileCount = 0;
2860
3282
  for (const [compName, compDef] of Object.entries(globalComponents)) {
2861
3283
  try {
2862
- const astroContent = emitAstroComponent(compName, compDef, globalComponents, breakpoints, i18nConfig.defaultLocale);
3284
+ const astroContent = emitAstroComponent(compName, compDef, globalComponents, breakpoints, i18nConfig.defaultLocale, responsiveScales);
2863
3285
  await writeFile2(join(componentsOutDir, `${compName}.astro`), astroContent, "utf-8");
2864
3286
  componentFileCount++;
2865
3287
  } catch (error) {
@@ -2869,20 +3291,7 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
2869
3291
  console.log(`Generated ${componentFileCount} component .astro file(s)`);
2870
3292
  for (const result of allResults) {
2871
3293
  const importPath = layoutImportPath(result.fileDepth);
2872
- const scriptPaths = [];
2873
- if (result.javascript) {
2874
- const hash = hashContent2(result.javascript);
2875
- const scriptFile = `${hash}.js`;
2876
- const scriptPublicPath = `/_scripts/${scriptFile}`;
2877
- if (!existsSync(scriptsDir)) {
2878
- mkdirSync(scriptsDir, { recursive: true });
2879
- }
2880
- const fullScriptPath = join(scriptsDir, scriptFile);
2881
- if (!existsSync(fullScriptPath)) {
2882
- await writeFile2(fullScriptPath, result.javascript, "utf-8");
2883
- }
2884
- scriptPaths.push(scriptPublicPath);
2885
- }
3294
+ let scriptPaths = [];
2886
3295
  let astroContent;
2887
3296
  if (result.pageData) {
2888
3297
  try {
@@ -2897,23 +3306,27 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
2897
3306
  theme: defaultTheme,
2898
3307
  fontPreloads,
2899
3308
  libraryTags,
2900
- scriptPaths,
3309
+ scriptPaths: [],
2901
3310
  layoutImportPath: importPath,
2902
3311
  fileDepth: result.fileDepth,
2903
3312
  ssrFallbacks,
2904
3313
  pageName: result.pageName || "index",
2905
3314
  breakpoints,
3315
+ responsiveScales,
2906
3316
  imageMetadataMap,
2907
3317
  i18nConfig: i18nConfig.locales.length > 1 ? i18nConfig : void 0,
2908
3318
  currentPageSlugMap: pageSlugMap,
2909
3319
  slugMappings: i18nConfig.locales.length > 1 ? slugMappings : void 0,
2910
- imageFormat: configService.getImageFormat()
3320
+ imageFormat: configService.getImageFormat(),
3321
+ processedRawHtml: result.processedRawHtmlCollector
2911
3322
  });
2912
3323
  } catch (error) {
2913
3324
  console.warn(` Warning: component emission failed for ${result.urlPath}, using SSR fallback: ${error?.message}`);
3325
+ scriptPaths = writePageScript(result.javascript, scriptsDir);
2914
3326
  astroContent = buildSSRFallbackPage(result, importPath, fontPreloads, libraryTags, defaultTheme, scriptPaths);
2915
3327
  }
2916
3328
  } else {
3329
+ scriptPaths = writePageScript(result.javascript, scriptsDir);
2917
3330
  astroContent = buildSSRFallbackPage(result, importPath, fontPreloads, libraryTags, defaultTheme, scriptPaths);
2918
3331
  }
2919
3332
  const astroFileFull = join(pagesOutDir, result.astroFilePath);
@@ -2924,6 +3337,24 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
2924
3337
  await writeFile2(astroFileFull, astroContent, "utf-8");
2925
3338
  }
2926
3339
  console.log(`Generated ${allResults.length} .astro page file(s)`);
3340
+ const robotsTsContent = `import type { APIRoute } from 'astro';
3341
+
3342
+ export const GET: APIRoute = () => {
3343
+ const siteUrl = import.meta.env.SITE;
3344
+ const robotsTxt = [
3345
+ 'User-agent: *',
3346
+ 'Allow: /',
3347
+ '',
3348
+ siteUrl ? \`Sitemap: \${siteUrl}/sitemap-index.xml\` : '',
3349
+ ].filter(Boolean).join('\\n');
3350
+
3351
+ return new Response(robotsTxt, {
3352
+ headers: { 'Content-Type': 'text/plain; charset=utf-8' },
3353
+ });
3354
+ };
3355
+ `;
3356
+ await writeFile2(join(pagesOutDir, "robots.txt.ts"), robotsTsContent, "utf-8");
3357
+ console.log("Generated robots.txt.ts endpoint");
2927
3358
  let collectionCount = 0;
2928
3359
  if (templateSchemas.length > 0) {
2929
3360
  const contentDir = join(srcDir, "content");
@@ -2959,7 +3390,7 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
2959
3390
  }
2960
3391
  }
2961
3392
  collectionDefs.push(` '${schema.id}': defineCollection({
2962
- type: 'data',
3393
+ loader: glob({ pattern: '**/*.json', base: './src/content/${schema.id}' }),
2963
3394
  schema: z.object({
2964
3395
  ${fieldDefs.join(",\n")}
2965
3396
  })
@@ -2967,6 +3398,7 @@ ${fieldDefs.join(",\n")}
2967
3398
  collectionCount++;
2968
3399
  }
2969
3400
  const configContent = `import { z, defineCollection } from 'astro:content';
3401
+ import { glob } from 'astro/loaders';
2970
3402
 
2971
3403
  const collections = {
2972
3404
  ${collectionDefs.join(",\n")}
@@ -2974,12 +3406,18 @@ ${collectionDefs.join(",\n")}
2974
3406
 
2975
3407
  export { collections };
2976
3408
  `;
2977
- await writeFile2(join(contentDir, "config.ts"), configContent, "utf-8");
2978
- console.log(`Generated ${collectionCount} content collection(s) with config.ts`);
3409
+ await writeFile2(join(srcDir, "content.config.ts"), configContent, "utf-8");
3410
+ console.log(`Generated ${collectionCount} content collection(s) with content.config.ts`);
2979
3411
  }
2980
- const assetDirs = ["fonts", "images", "icons", "videos", "assets"];
2981
3412
  let copiedAssets = 0;
2982
- for (const dir of assetDirs) {
3413
+ const imagesSrcDir = join(projectPaths.project, "images");
3414
+ if (existsSync(imagesSrcDir)) {
3415
+ copyDirectory(imagesSrcDir, join(srcDir, "assets", "images"), shouldCopyImageForAstro);
3416
+ copyDirectory(imagesSrcDir, join(publicDir, "images"));
3417
+ copiedAssets++;
3418
+ }
3419
+ const publicAssetDirs = ["fonts", "icons", "videos", "assets"];
3420
+ for (const dir of publicAssetDirs) {
2983
3421
  const srcAssetDir = join(projectPaths.project, dir);
2984
3422
  if (existsSync(srcAssetDir)) {
2985
3423
  copyDirectory(srcAssetDir, join(publicDir, dir));
@@ -2991,6 +3429,14 @@ export { collections };
2991
3429
  copyDirectory(librariesDir, join(publicDir, "libraries"));
2992
3430
  copiedAssets++;
2993
3431
  }
3432
+ for (const relPath of localLibsToCopy) {
3433
+ const srcPath = join(projectPaths.project, relPath);
3434
+ const destPath = join(publicDir, relPath);
3435
+ const destDir = destPath.substring(0, destPath.lastIndexOf("/"));
3436
+ if (destDir && !existsSync(destDir)) mkdirSync(destDir, { recursive: true });
3437
+ copyFileSync(srcPath, destPath);
3438
+ copiedAssets++;
3439
+ }
2994
3440
  if (copiedAssets > 0) {
2995
3441
  console.log(`Copied ${copiedAssets} asset director${copiedAssets === 1 ? "y" : "ies"} to public/`);
2996
3442
  }
@@ -3006,9 +3452,14 @@ export { collections };
3006
3452
  preview: "astro preview"
3007
3453
  },
3008
3454
  dependencies: {
3009
- "astro": "^4.0.0",
3010
- "@astrojs/tailwind": "^5.0.0",
3011
- "tailwindcss": "^3.4.0"
3455
+ "astro": "^6.0.0",
3456
+ "@astrojs/sitemap": "^3.0.0",
3457
+ "@tailwindcss/vite": "^4.0.0",
3458
+ "tailwindcss": "^4.0.0"
3459
+ },
3460
+ // Astro 6 expects Vite 7; pin it so npm doesn't pull Vite 8+ and warn.
3461
+ overrides: {
3462
+ "vite": "^7.0.0"
3012
3463
  }
3013
3464
  };
3014
3465
  await writeFile2(join(outDir, "package.json"), JSON.stringify(packageJson, null, 2), "utf-8");
@@ -3020,34 +3471,23 @@ export { collections };
3020
3471
  routing: { prefixDefaultLocale: false },
3021
3472
  },` : "";
3022
3473
  const astroConfig = `import { defineConfig } from 'astro/config';
3023
- import tailwind from '@astrojs/tailwind';
3474
+ import tailwindcss from '@tailwindcss/vite';
3475
+ import sitemap from '@astrojs/sitemap';
3024
3476
 
3025
3477
  export default defineConfig({${siteUrl ? `
3026
3478
  site: '${siteUrl}',` : ""}${i18nBlock}
3027
- integrations: [tailwind({ applyBaseStyles: false })],
3028
- });
3029
- `;
3030
- const safelistArray = Array.from(mappingClasses);
3031
- const safelistLiteral = safelistArray.length > 0 ? `
3032
- safelist: [
3033
- ${safelistArray.map((c) => ` '${c}'`).join(",\n")}
3034
- ],` : "";
3035
- const tailwindConfig = `/** @type {import('tailwindcss').Config} */
3036
- export default {
3037
- content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],${safelistLiteral}
3038
- theme: {
3039
- extend: {},
3479
+ integrations: [sitemap()],
3480
+ vite: {
3481
+ plugins: [tailwindcss()],
3040
3482
  },
3041
- plugins: [],
3042
- };
3483
+ });
3043
3484
  `;
3044
- await writeFile2(join(outDir, "tailwind.config.mjs"), tailwindConfig, "utf-8");
3045
3485
  await writeFile2(join(outDir, "astro.config.mjs"), astroConfig, "utf-8");
3046
3486
  const tsConfig = {
3047
3487
  extends: "astro/tsconfigs/strict"
3048
3488
  };
3049
3489
  await writeFile2(join(outDir, "tsconfig.json"), JSON.stringify(tsConfig, null, 2), "utf-8");
3050
- console.log("Generated package.json, astro.config.mjs, tailwind.config.mjs, tsconfig.json");
3490
+ console.log("Generated package.json, astro.config.mjs, tsconfig.json");
3051
3491
  const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
3052
3492
  const totalPages = allResults.length;
3053
3493
  console.log("\n" + "=".repeat(50));
@@ -3062,6 +3502,10 @@ export default {
3062
3502
  if (errorCount > 0) {
3063
3503
  console.log(` Errors: ${errorCount}`);
3064
3504
  }
3505
+ console.log(` SEO: sitemap (@astrojs/sitemap), robots.txt`);
3506
+ if (projectNeedsFormHandler) {
3507
+ console.log(` Forms: fetch handler injected`);
3508
+ }
3065
3509
  console.log(` Time: ${elapsed}s`);
3066
3510
  console.log(` Output: ${outDir}`);
3067
3511
  console.log("");