meno-core 1.0.45 → 1.0.47

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 (63) hide show
  1. package/build-astro.ts +211 -124
  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-TVH3TC2T.js → chunk-47UNLQUU.js} +6 -6
  7. package/dist/chunks/{chunk-F7MA62WG.js → chunk-BCLGRZ3U.js} +5 -5
  8. package/dist/chunks/{chunk-F7MA62WG.js.map → chunk-BCLGRZ3U.js.map} +2 -2
  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-BZQKEJQY.js → chunk-FGUZOYJX.js} +49 -30
  12. package/dist/chunks/chunk-FGUZOYJX.js.map +7 -0
  13. package/dist/chunks/{chunk-5Z5VQRTJ.js → chunk-I7YIGZXT.js} +4 -4
  14. package/dist/chunks/{chunk-5Z5VQRTJ.js.map → chunk-I7YIGZXT.js.map} +2 -2
  15. package/dist/chunks/{chunk-OUNJ76QM.js → chunk-LJFB5EBT.js} +5 -5
  16. package/dist/chunks/{chunk-GYF3ABI3.js → chunk-UUA5LEWF.js} +3 -3
  17. package/dist/chunks/{chunk-GYF3ABI3.js.map → chunk-UUA5LEWF.js.map} +2 -2
  18. package/dist/chunks/{chunk-WQSG5WHC.js → chunk-ZTKHJQ2Z.js} +2 -2
  19. package/dist/chunks/{configService-6KTT6GRT.js → configService-DYCUEURL.js} +3 -3
  20. package/dist/chunks/{constants-L5IKLB6U.js → constants-GWBAD66U.js} +2 -2
  21. package/dist/entries/server-router.js +7 -7
  22. package/dist/lib/client/index.js +7 -5
  23. package/dist/lib/client/index.js.map +2 -2
  24. package/dist/lib/server/index.js +631 -208
  25. package/dist/lib/server/index.js.map +3 -3
  26. package/dist/lib/shared/index.js +7 -3
  27. package/dist/lib/shared/index.js.map +2 -2
  28. package/dist/lib/test-utils/index.js +1 -1
  29. package/lib/client/core/ComponentBuilder.test.ts +21 -0
  30. package/lib/client/core/ComponentBuilder.ts +8 -1
  31. package/lib/client/templateEngine.test.ts +64 -0
  32. package/lib/server/astro/astroEmitHelpers.ts +23 -0
  33. package/lib/server/astro/cmsPageEmitter.ts +46 -3
  34. package/lib/server/astro/componentEmitter.test.ts +59 -0
  35. package/lib/server/astro/componentEmitter.ts +53 -12
  36. package/lib/server/astro/cssCollector.ts +58 -11
  37. package/lib/server/astro/nodeToAstro.test.ts +397 -5
  38. package/lib/server/astro/nodeToAstro.ts +494 -65
  39. package/lib/server/astro/pageEmitter.ts +46 -3
  40. package/lib/server/astro/tailwindMapper.test.ts +119 -0
  41. package/lib/server/astro/tailwindMapper.ts +67 -1
  42. package/lib/server/runtime/httpServer.ts +12 -4
  43. package/lib/server/ssr/htmlGenerator.test.ts +3 -2
  44. package/lib/server/ssr/htmlGenerator.ts +6 -1
  45. package/lib/server/ssr/imageMetadata.ts +15 -9
  46. package/lib/server/ssr/jsCollector.ts +2 -2
  47. package/lib/server/ssr/ssrRenderer.test.ts +79 -0
  48. package/lib/server/ssr/ssrRenderer.ts +35 -20
  49. package/lib/shared/constants.ts +1 -0
  50. package/lib/shared/cssGeneration.test.ts +109 -3
  51. package/lib/shared/cssGeneration.ts +98 -13
  52. package/lib/shared/cssNamedColors.ts +47 -0
  53. package/lib/shared/cssProperties.ts +2 -2
  54. package/lib/shared/index.ts +1 -0
  55. package/lib/shared/styleNodeUtils.test.ts +47 -1
  56. package/lib/shared/styleNodeUtils.ts +7 -7
  57. package/package.json +1 -1
  58. package/dist/chunks/chunk-BZQKEJQY.js.map +0 -7
  59. /package/dist/chunks/{chunk-TVH3TC2T.js.map → chunk-47UNLQUU.js.map} +0 -0
  60. /package/dist/chunks/{chunk-OUNJ76QM.js.map → chunk-LJFB5EBT.js.map} +0 -0
  61. /package/dist/chunks/{chunk-WQSG5WHC.js.map → chunk-ZTKHJQ2Z.js.map} +0 -0
  62. /package/dist/chunks/{configService-6KTT6GRT.js.map → configService-DYCUEURL.js.map} +0 -0
  63. /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-LJFB5EBT.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-47UNLQUU.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-FGUZOYJX.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-BCLGRZ3U.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,28 @@ 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
+ function astroComponentName(name) {
744
+ return name.charAt(0).toUpperCase() + name.slice(1);
745
+ }
746
+
690
747
  // lib/server/astro/nodeToAstro.ts
691
748
  function ind(ctx) {
692
749
  return " ".repeat(ctx.indent);
@@ -751,7 +808,7 @@ function escapeJSX(s) {
751
808
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
752
809
  }
753
810
  function escapeTemplateLiteral(s) {
754
- return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
811
+ return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
755
812
  }
756
813
  function collectStyleMappings(style) {
757
814
  if (!style) return [];
@@ -808,7 +865,7 @@ function getClassForValue(property, value, breakpointPrefix) {
808
865
  return breakpointPrefix ? `${breakpointPrefix}${twClass}` : twClass;
809
866
  }
810
867
  function buildClassAndStyleExpression(style, interactiveStyles, elementClass, ctx) {
811
- const result = style ? responsiveStylesToTailwind(style, ctx.breakpoints) : { classes: [], dynamicStyles: {} };
868
+ const result = style ? responsiveStylesToTailwind(style, ctx.breakpoints, ctx.responsiveScales) : { classes: [], dynamicStyles: {} };
812
869
  const staticClasses = result.classes;
813
870
  const dynamicStyles = result.dynamicStyles;
814
871
  if (elementClass) {
@@ -899,7 +956,7 @@ function resolveTemplate(text, ctx) {
899
956
  let propName = fullMatch[1].trim();
900
957
  if (ctx.listItemBinding) propName = rewriteItemVar(propName, ctx.listItemBinding);
901
958
  if (ctx.listIndexVar) propName = replaceItemMetaVars(propName, ctx.listIndexVar, ctx.listSourceVar);
902
- if (ctx.componentProps[propName]?.type === "rich-text") {
959
+ if (ctx.componentProps[propName]?.type === "rich-text" || ctx.componentProps[propName]?.type === "embed") {
903
960
  return `<Fragment set:html={${propName}} />`;
904
961
  }
905
962
  return `{${propName}}`;
@@ -988,6 +1045,7 @@ function buildAttributesString(attributes, ctx) {
988
1045
  return parts.length > 0 ? " " + parts.join(" ") : "";
989
1046
  }
990
1047
  function formatPropValue(value) {
1048
+ value = stripRawHtmlPrefixDeep(value);
991
1049
  if (typeof value === "string") return `"${escapeJSX(value)}"`;
992
1050
  if (typeof value === "number") return `{${value}}`;
993
1051
  if (typeof value === "boolean") return `{${value}}`;
@@ -1005,12 +1063,11 @@ function nodeToAstro(node, ctx) {
1005
1063
  if (typeof node === "object" && !Array.isArray(node) && isI18nValue(node)) {
1006
1064
  const resolved = resolveI18n(node, ctx);
1007
1065
  if (typeof resolved === "string") {
1008
- return `${ind(ctx)}${escapeJSX(resolved)}
1009
- `;
1066
+ return nodeToAstro(resolved, ctx);
1010
1067
  }
1011
1068
  if (ctx.isComponentDef && isI18nValue(resolved)) {
1012
1069
  ctx.needsI18nResolver = true;
1013
- return `${ind(ctx)}{r(${JSON.stringify(resolved)})}
1070
+ return `${ind(ctx)}{r(${JSON.stringify(stripRawHtmlPrefixDeep(resolved))})}
1014
1071
  `;
1015
1072
  }
1016
1073
  return `${ind(ctx)}${String(resolved ?? "")}
@@ -1032,7 +1089,8 @@ function nodeToAstro(node, ctx) {
1032
1089
  `;
1033
1090
  }
1034
1091
  if (node.startsWith(RAW_HTML_PREFIX)) {
1035
- const rawHtml = node.slice(RAW_HTML_PREFIX.length);
1092
+ const rawSlice = node.slice(RAW_HTML_PREFIX.length);
1093
+ const rawHtml = ctx.processedRawHtml?.get(rawSlice) ?? rawSlice;
1036
1094
  return `${ind(ctx)}<Fragment set:html={\`${escapeTemplateLiteral(rawHtml)}\`} />
1037
1095
  `;
1038
1096
  }
@@ -1079,6 +1137,7 @@ function nodeToAstro(node, ctx) {
1079
1137
  var IMG_TAILWIND_PREFIXES = ["object-", "rounded", "border", "shadow", "[filter", "[transform", "mix-blend"];
1080
1138
  var IMG_OPACITY_PATTERN = /^opacity-/;
1081
1139
  var DEFAULT_SIZES2 = "100vw";
1140
+ var IMG_FILL_CLASSES = ["block", "w-full", "h-full"];
1082
1141
  function splitImageClasses(allClasses) {
1083
1142
  const imgClasses = [];
1084
1143
  const pictureClasses = [];
@@ -1092,11 +1151,164 @@ function splitImageClasses(allClasses) {
1092
1151
  }
1093
1152
  return { pictureClasses, imgClasses };
1094
1153
  }
1154
+ function extractPxWidth(val) {
1155
+ if (typeof val === "number" && Number.isFinite(val) && val > 0) return val;
1156
+ if (typeof val !== "string") return null;
1157
+ const match = val.trim().match(/^(\d+(?:\.\d+)?)px$/);
1158
+ if (!match) return null;
1159
+ const n = parseFloat(match[1]);
1160
+ return n > 0 ? n : null;
1161
+ }
1162
+ function computeSizesAttribute(style, breakpoints) {
1163
+ if (!style) return DEFAULT_SIZES2;
1164
+ const responsive = isResponsiveStyle2(style);
1165
+ const baseStyle = responsive ? style.base : style;
1166
+ const baseWidth = baseStyle ? extractPxWidth(baseStyle.width) : null;
1167
+ if (baseWidth == null) return DEFAULT_SIZES2;
1168
+ const bpEntries = Object.entries(breakpoints).sort(
1169
+ (a, b) => a[1].breakpoint - b[1].breakpoint
1170
+ );
1171
+ const parts = [];
1172
+ for (const [name, entry] of bpEntries) {
1173
+ let effective = null;
1174
+ if (responsive) {
1175
+ const bpStyle = style[name];
1176
+ effective = bpStyle ? extractPxWidth(bpStyle.width) : null;
1177
+ if (effective == null) {
1178
+ for (const [largerName, largerEntry] of bpEntries) {
1179
+ if (largerEntry.breakpoint <= entry.breakpoint) continue;
1180
+ const largerStyle = style[largerName];
1181
+ const larger = largerStyle ? extractPxWidth(largerStyle.width) : null;
1182
+ if (larger != null) {
1183
+ effective = larger;
1184
+ break;
1185
+ }
1186
+ }
1187
+ }
1188
+ if (effective == null) effective = baseWidth;
1189
+ } else {
1190
+ effective = baseWidth;
1191
+ }
1192
+ parts.push(`(max-width: ${entry.breakpoint}px) ${effective}px`);
1193
+ }
1194
+ parts.push(`${baseWidth}px`);
1195
+ return parts.join(", ");
1196
+ }
1197
+ function injectInlineStyle(styleAttr, extraCss) {
1198
+ if (!extraCss) return styleAttr;
1199
+ if (!styleAttr) return ` style="${extraCss}"`;
1200
+ return styleAttr.replace(/style="([^"]*)"/, (_, existing) => {
1201
+ const trimmed = existing.trimEnd();
1202
+ const sep = trimmed.length > 0 && !trimmed.endsWith(";") ? ";" : "";
1203
+ return `style="${existing}${sep}${extraCss}"`;
1204
+ });
1205
+ }
1206
+ var PICTURE_WIDTHS = [500, 800, 1080, 1600, 2400];
1207
+ function imagePathToVarName(srcPath) {
1208
+ const stripped = srcPath.replace(/^\/+/, "").replace(/^images\//, "").replace(/\.[^.]+$/, "");
1209
+ const parts = stripped.split(/[/_\-\s.]+/).filter(Boolean);
1210
+ if (parts.length === 0) return "imgAsset";
1211
+ const camel = parts.map((p, i) => {
1212
+ const clean = p.replace(/[^a-zA-Z0-9]/g, "");
1213
+ if (!clean) return "";
1214
+ if (i === 0) return clean.toLowerCase();
1215
+ return clean[0].toUpperCase() + clean.slice(1).toLowerCase();
1216
+ }).join("");
1217
+ if (!camel) return "imgAsset";
1218
+ return "img" + camel[0].toUpperCase() + camel.slice(1);
1219
+ }
1220
+ function imageImportPath(srcPath, fileDepth) {
1221
+ const rest = srcPath.replace(/^\/+/, "").replace(/^images\//, "");
1222
+ const ups = "../".repeat(Math.max(0, fileDepth) + 1);
1223
+ return `${ups}assets/images/${rest}`;
1224
+ }
1225
+ function isStaticImageSrc(src, ctx) {
1226
+ if (!src) return false;
1227
+ if (typeof src !== "string") return false;
1228
+ if (hasTemplates(src)) return false;
1229
+ if (!src.startsWith("/images/")) return false;
1230
+ if (!ctx.imageMetadataMap?.has(src)) return false;
1231
+ return true;
1232
+ }
1233
+ function registerStaticImageImport(src, ctx) {
1234
+ if (!ctx.imageImports) ctx.imageImports = /* @__PURE__ */ new Map();
1235
+ const depth = ctx.fileDepth ?? 0;
1236
+ const importPath = imageImportPath(src, depth);
1237
+ for (const [existingName, existingPath] of ctx.imageImports) {
1238
+ if (existingPath === importPath) return existingName;
1239
+ }
1240
+ const base = imagePathToVarName(src);
1241
+ let name = base;
1242
+ let counter = 2;
1243
+ while (ctx.imageImports.has(name)) {
1244
+ name = `${base}${counter++}`;
1245
+ }
1246
+ ctx.imageImports.set(name, importPath);
1247
+ return name;
1248
+ }
1249
+ function splitStaticClassExpr(classExpr) {
1250
+ if (classExpr.includes("class:list=")) return null;
1251
+ const classMatch = classExpr.match(/class="([^"]*)"/);
1252
+ if (!classMatch) return { outerClasses: [], innerClasses: [] };
1253
+ const all = classMatch[1].split(/\s+/).filter(Boolean);
1254
+ const { pictureClasses, imgClasses } = splitImageClasses(all);
1255
+ return { outerClasses: pictureClasses, innerClasses: imgClasses };
1256
+ }
1257
+ function formatPictureAttributesProp(classValue, styleAttr) {
1258
+ const styleMatch = styleAttr.match(/style="([^"]*)"/);
1259
+ const parts = [];
1260
+ if (classValue) parts.push(`class: ${JSON.stringify(classValue)}`);
1261
+ if (styleMatch) parts.push(`style: ${JSON.stringify(styleMatch[1])}`);
1262
+ if (parts.length === 0) return "";
1263
+ return ` pictureAttributes={{${parts.join(", ")}}}`;
1264
+ }
1265
+ function emitStaticPictureImage(src, alt, loading, fetchpriority, sizesValue, classExpr, styleAttr, ifExpr, ifClose, blurHash, ctx) {
1266
+ const varName = registerStaticImageImport(src, ctx);
1267
+ const widthsLiteral = `[${PICTURE_WIDTHS.join(", ")}]`;
1268
+ const altAttr = alt !== void 0 ? ` alt="${escapeJSX(String(alt))}"` : ' alt=""';
1269
+ const loadingAttr = loading ? ` loading="${escapeJSX(loading)}"` : "";
1270
+ const fetchpriorityAttr = fetchpriority ? ` fetchpriority="${escapeJSX(fetchpriority)}"` : "";
1271
+ const split = splitStaticClassExpr(classExpr);
1272
+ if (blurHash) {
1273
+ const blurCss = `background-image:url(${escapeJSX(blurHash)});background-size:cover`;
1274
+ const blurStyleAttr = injectInlineStyle(styleAttr, blurCss);
1275
+ const onloadAttr = ` onload="this.parentElement.style.backgroundImage=''"`;
1276
+ if (split) {
1277
+ const outerClassValue = split.outerClasses.join(" ");
1278
+ const pictureAttrs = formatPictureAttributesProp(outerClassValue, blurStyleAttr);
1279
+ const innerClasses = [...split.innerClasses, ...IMG_FILL_CLASSES];
1280
+ const innerClassAttr = ` class="${innerClasses.join(" ")}"`;
1281
+ return `${ifExpr}${ind(ctx)}<Picture${pictureAttrs} src={${varName}}${altAttr}${innerClassAttr} formats={['avif','webp']} widths={${widthsLiteral}} sizes="${escapeJSX(sizesValue)}"${loadingAttr}${fetchpriorityAttr}${onloadAttr} />
1282
+ ${ifClose}`;
1283
+ }
1284
+ const wrapperClassExpr = classExpr;
1285
+ const wrapperStyleAttr = injectInlineStyle(styleAttr, blurCss);
1286
+ const fillClassAttr = ` class="${IMG_FILL_CLASSES.join(" ")}"`;
1287
+ return `${ifExpr}${ind(ctx)}<div${wrapperClassExpr}${wrapperStyleAttr}>
1288
+ ${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=''" />
1289
+ ${ind(ctx)}</div>
1290
+ ${ifClose}`;
1291
+ }
1292
+ if (split) {
1293
+ const outerClassValue = split.outerClasses.join(" ");
1294
+ const innerClassAttr = split.innerClasses.length > 0 ? ` class="${split.innerClasses.join(" ")}"` : "";
1295
+ const pictureAttrs = formatPictureAttributesProp(outerClassValue, styleAttr);
1296
+ return `${ifExpr}${ind(ctx)}<Picture${pictureAttrs} src={${varName}}${altAttr}${innerClassAttr} formats={['avif','webp']} widths={${widthsLiteral}} sizes="${escapeJSX(sizesValue)}"${loadingAttr}${fetchpriorityAttr} />
1297
+ ${ifClose}`;
1298
+ }
1299
+ return `${ifExpr}${ind(ctx)}<div${classExpr}${styleAttr}>
1300
+ ${ind(ctx)} <Picture src={${varName}}${altAttr} formats={['avif','webp']} widths={${widthsLiteral}} sizes="${escapeJSX(sizesValue)}"${loadingAttr}${fetchpriorityAttr} />
1301
+ ${ind(ctx)}</div>
1302
+ ${ifClose}`;
1303
+ }
1095
1304
  function emitImageNode(node, ctx) {
1096
1305
  const style = node.style;
1097
1306
  let elementClass = null;
1098
1307
  if (node.interactiveStyles && node.interactiveStyles.length > 0 || node.generateElementClass) {
1099
1308
  elementClass = buildElementClass(ctx, node.label);
1309
+ if (elementClass && node.interactiveStyles?.length && ctx.collectedInteractiveStyles) {
1310
+ ctx.collectedInteractiveStyles.set(elementClass, node.interactiveStyles);
1311
+ }
1100
1312
  }
1101
1313
  const { classExpr, styleAttr } = buildClassAndStyleExpression(
1102
1314
  style,
@@ -1117,7 +1329,22 @@ function emitImageNode(node, ctx) {
1117
1329
  if (width === void 0 && metadata.width) width = metadata.width;
1118
1330
  if (height === void 0 && metadata.height) height = metadata.height;
1119
1331
  }
1120
- const sizesValue = sizes || DEFAULT_SIZES2;
1332
+ const sizesValue = sizes || computeSizesAttribute(style, ctx.breakpoints);
1333
+ if (isStaticImageSrc(src, ctx)) {
1334
+ return emitStaticPictureImage(
1335
+ src,
1336
+ alt,
1337
+ loading,
1338
+ fetchpriority,
1339
+ sizesValue,
1340
+ classExpr,
1341
+ styleAttr,
1342
+ emitIfOpen(node, ctx),
1343
+ emitIfClose(node, ctx),
1344
+ metadata?.blurHash,
1345
+ ctx
1346
+ );
1347
+ }
1121
1348
  const imageSpecificKeys = /* @__PURE__ */ new Set(["src", "alt", "loading", "width", "height", "sizes", "srcset", "fetchpriority"]);
1122
1349
  const otherAttrs = {};
1123
1350
  if (node.attributes) {
@@ -1133,31 +1360,44 @@ function emitImageNode(node, ctx) {
1133
1360
  if (loading) imgAttrs += ` loading="${escapeJSX(String(loading))}"`;
1134
1361
  if (width !== void 0) imgAttrs += ` width="${escapeJSX(String(width))}"`;
1135
1362
  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
- }
1363
+ const hasAvif = !!(metadata?.avifSrcset && ctx.imageFormat !== "webp");
1364
+ const hasBlur = !!metadata?.blurHash;
1365
+ const useWrapper = hasAvif || hasBlur;
1366
+ const blurWrapperCss = hasBlur ? `background-image:url(${escapeJSX(metadata.blurHash)});background-size:cover` : "";
1367
+ const blurOnload = hasBlur ? ` onload="this.parentElement.style.backgroundImage=''"` : "";
1140
1368
  const ifExpr = emitIfOpen(node, ctx);
1141
1369
  const ifClose = emitIfClose(node, ctx);
1142
- if (metadata?.avifSrcset && ctx.imageFormat !== "webp") {
1143
- const classMatch = classExpr.match(/class="([^"]*)"/);
1370
+ if (useWrapper) {
1371
+ const imgFillClasses = IMG_FILL_CLASSES.slice();
1144
1372
  const classListMatch = classExpr.match(/class:list={\[(.+)\]}/);
1373
+ const classMatch = classExpr.match(/class="([^"]*)"/);
1374
+ let pictureClassExpr = "";
1375
+ let imgClassAttr = "";
1145
1376
  if (classListMatch) {
1146
- return `${ifExpr}${ind(ctx)}<picture${classExpr}${styleAttr}>
1377
+ pictureClassExpr = classExpr;
1378
+ imgClassAttr = ` class="${imgFillClasses.join(" ")}"`;
1379
+ } else {
1380
+ const allClasses = classMatch ? classMatch[1].split(/\s+/).filter(Boolean) : [];
1381
+ const { pictureClasses, imgClasses } = splitImageClasses(allClasses);
1382
+ const fullImgClasses = [...imgClasses, ...imgFillClasses];
1383
+ pictureClassExpr = pictureClasses.length > 0 ? ` class="${pictureClasses.join(" ")}"` : "";
1384
+ imgClassAttr = fullImgClasses.length > 0 ? ` class="${fullImgClasses.join(" ")}"` : "";
1385
+ }
1386
+ const wrapperStyleAttr = injectInlineStyle(styleAttr, blurWrapperCss);
1387
+ if (hasAvif) {
1388
+ return `${ifExpr}${ind(ctx)}<picture${pictureClassExpr}${wrapperStyleAttr}>
1147
1389
  ${ind(ctx)} <source type="image/avif" srcset="${escapeJSX(metadata.avifSrcset)}" sizes="${escapeJSX(sizesValue)}" />
1148
1390
  ${ind(ctx)} <source type="image/webp" srcset="${escapeJSX(metadata.srcset)}" sizes="${escapeJSX(sizesValue)}" />
1149
- ${ind(ctx)} <img${imgAttrs}${blurStyle}${otherAttrsStr} />
1391
+ ${ind(ctx)} <img${imgClassAttr}${imgAttrs}${blurOnload}${otherAttrsStr} />
1150
1392
  ${ind(ctx)}</picture>
1151
1393
  ${ifClose}`;
1152
1394
  }
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} />
1395
+ if (metadata?.srcset) {
1396
+ imgAttrs += ` srcset="${escapeJSX(metadata.srcset)}"`;
1397
+ imgAttrs += ` sizes="${escapeJSX(sizesValue)}"`;
1398
+ }
1399
+ return `${ifExpr}${ind(ctx)}<picture${pictureClassExpr}${wrapperStyleAttr}>
1400
+ ${ind(ctx)} <img${imgClassAttr}${imgAttrs}${blurOnload}${otherAttrsStr} />
1161
1401
  ${ind(ctx)}</picture>
1162
1402
  ${ifClose}`;
1163
1403
  }
@@ -1165,7 +1405,7 @@ ${ifClose}`;
1165
1405
  imgAttrs += ` srcset="${escapeJSX(metadata.srcset)}"`;
1166
1406
  imgAttrs += ` sizes="${escapeJSX(sizesValue)}"`;
1167
1407
  }
1168
- return `${ifExpr}${ind(ctx)}<img${classExpr}${styleAttr}${imgAttrs}${blurStyle}${otherAttrsStr} />
1408
+ return `${ifExpr}${ind(ctx)}<img${classExpr}${styleAttr}${imgAttrs}${otherAttrsStr} />
1169
1409
  ${ifClose}`;
1170
1410
  }
1171
1411
  function emitHtmlNode(node, ctx) {
@@ -1192,6 +1432,9 @@ function emitHtmlNode(node, ctx) {
1192
1432
  let elementClass = null;
1193
1433
  if (node.interactiveStyles && node.interactiveStyles.length > 0 || node.generateElementClass) {
1194
1434
  elementClass = buildElementClass(ctx, label);
1435
+ if (elementClass && node.interactiveStyles?.length && ctx.collectedInteractiveStyles) {
1436
+ ctx.collectedInteractiveStyles.set(elementClass, node.interactiveStyles);
1437
+ }
1195
1438
  }
1196
1439
  const { classExpr, styleAttr } = buildClassAndStyleExpression(style, node.interactiveStyles, elementClass, ctx);
1197
1440
  const attrs = buildAttributesString(node.attributes, ctx);
@@ -1210,8 +1453,8 @@ ${emitIfClose(node, ctx)}`;
1210
1453
  ${emitIfClose(node, ctx)}`;
1211
1454
  }
1212
1455
  function emitComponentInstance(node, ctx) {
1213
- const name = node.component;
1214
- ctx.imports.add(name);
1456
+ const name = astroComponentName(node.component);
1457
+ ctx.imports.add(node.component);
1215
1458
  const ifExpr = emitIfOpen(node, ctx);
1216
1459
  const propParts = [];
1217
1460
  if (node.props) {
@@ -1248,20 +1491,27 @@ function emitComponentInstance(node, ctx) {
1248
1491
  }
1249
1492
  } else if (ctx.isComponentDef && isI18nValue(value)) {
1250
1493
  ctx.needsI18nResolver = true;
1251
- propParts.push(`${key}={r(${JSON.stringify(value)})}`);
1494
+ propParts.push(`${key}={r(${JSON.stringify(stripRawHtmlPrefixDeep(value))})}`);
1252
1495
  } else {
1253
- propParts.push(`${key}=${formatPropValue(value)}`);
1496
+ const targetInterface = ctx.globalComponents[name]?.component?.interface;
1497
+ const propDef = targetInterface?.[key];
1498
+ if (typeof value === "string" && (propDef?.type === "rich-text" || propDef?.type === "embed")) {
1499
+ propParts.push(`${key}={\`${escapeTemplateLiteral(stripRawHtmlPrefixDeep(value))}\`}`);
1500
+ } else {
1501
+ propParts.push(`${key}=${formatPropValue(value)}`);
1502
+ }
1254
1503
  }
1255
1504
  }
1256
1505
  }
1257
1506
  if (node.style) {
1258
- const { classes: instanceClasses } = responsiveStylesToTailwind(node.style, ctx.breakpoints);
1507
+ const { classes: instanceClasses } = responsiveStylesToTailwind(node.style, ctx.breakpoints, ctx.responsiveScales);
1259
1508
  if (instanceClasses.length > 0) {
1260
1509
  propParts.push(`class="${instanceClasses.join(" ")}"`);
1261
1510
  }
1262
1511
  }
1263
1512
  const propsStr = propParts.length > 0 ? " " + propParts.join(" ") : "";
1264
- const children = emitChildren(node.children, ctx);
1513
+ const childCtx = { ...ctx, elementPath: [0] };
1514
+ const children = emitChildren(node.children, childCtx);
1265
1515
  if (!children.trim()) {
1266
1516
  return `${ifExpr}${ind(ctx)}<${name}${propsStr} />
1267
1517
  ${emitIfClose(node, ctx)}`;
@@ -1288,6 +1538,9 @@ function emitEmbedNode(node, ctx) {
1288
1538
  let elementClass = null;
1289
1539
  if (node.interactiveStyles && node.interactiveStyles.length > 0 || node.generateElementClass) {
1290
1540
  elementClass = buildElementClass(ctx, node.label);
1541
+ if (elementClass && node.interactiveStyles?.length && ctx.collectedInteractiveStyles) {
1542
+ ctx.collectedInteractiveStyles.set(elementClass, node.interactiveStyles);
1543
+ }
1291
1544
  }
1292
1545
  const { classExpr, styleAttr } = buildClassAndStyleExpression(style, node.interactiveStyles, elementClass, ctx);
1293
1546
  const attrs = buildAttributesString(node.attributes, ctx);
@@ -1341,6 +1594,9 @@ function emitLinkNode(node, ctx) {
1341
1594
  let elementClass = null;
1342
1595
  if (node.interactiveStyles && node.interactiveStyles.length > 0 || node.generateElementClass) {
1343
1596
  elementClass = buildElementClass(ctx, node.label);
1597
+ if (elementClass && node.interactiveStyles?.length && ctx.collectedInteractiveStyles) {
1598
+ ctx.collectedInteractiveStyles.set(elementClass, node.interactiveStyles);
1599
+ }
1344
1600
  }
1345
1601
  const { classExpr, styleAttr } = buildClassAndStyleExpression(style, node.interactiveStyles, elementClass, ctx);
1346
1602
  let finalClassExpr = classExpr;
@@ -1417,6 +1673,9 @@ function emitImageTypeNode(node, ctx) {
1417
1673
  let elementClass = null;
1418
1674
  if (node.interactiveStyles && node.interactiveStyles.length > 0 || node.generateElementClass) {
1419
1675
  elementClass = buildElementClass(ctx, node.label);
1676
+ if (elementClass && node.interactiveStyles?.length && ctx.collectedInteractiveStyles) {
1677
+ ctx.collectedInteractiveStyles.set(elementClass, node.interactiveStyles);
1678
+ }
1420
1679
  }
1421
1680
  const { classExpr, styleAttr } = buildClassAndStyleExpression(
1422
1681
  style,
@@ -1426,30 +1685,52 @@ function emitImageTypeNode(node, ctx) {
1426
1685
  );
1427
1686
  const src = node.src;
1428
1687
  const alt = node.alt;
1688
+ if (isStaticImageSrc(src, ctx)) {
1689
+ const staticMeta = ctx.imageMetadataMap.get(src);
1690
+ return emitStaticPictureImage(
1691
+ src,
1692
+ alt,
1693
+ void 0,
1694
+ void 0,
1695
+ computeSizesAttribute(style, ctx.breakpoints),
1696
+ classExpr,
1697
+ styleAttr,
1698
+ "",
1699
+ "",
1700
+ staticMeta.blurHash,
1701
+ ctx
1702
+ );
1703
+ }
1429
1704
  let imgAttrs = "";
1430
1705
  if (src) imgAttrs += ` src="${escapeJSX(String(src))}"`;
1431
1706
  if (alt !== void 0) imgAttrs += ` alt="${escapeJSX(String(alt))}"`;
1432
1707
  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}>
1708
+ if (!metadata) {
1709
+ return `${ind(ctx)}<img${classExpr}${styleAttr}${imgAttrs} />
1710
+ `;
1711
+ }
1712
+ if (metadata.width !== void 0) imgAttrs += ` width="${metadata.width}"`;
1713
+ if (metadata.height !== void 0) imgAttrs += ` height="${metadata.height}"`;
1714
+ const sizesValue = computeSizesAttribute(style, ctx.breakpoints);
1715
+ const hasAvif = !!(metadata.avifSrcset && ctx.imageFormat !== "webp");
1716
+ const hasBlur = !!metadata.blurHash;
1717
+ const useWrapper = hasAvif || hasBlur;
1718
+ const blurWrapperCss = hasBlur ? `background-image:url(${escapeJSX(metadata.blurHash)});background-size:cover` : "";
1719
+ const blurOnload = hasBlur ? ` onload="this.parentElement.style.backgroundImage=''"` : "";
1720
+ if (useWrapper) {
1721
+ const imgFillClasses = IMG_FILL_CLASSES.slice();
1722
+ const classMatch = classExpr.match(/class="([^"]*)"/);
1723
+ const allClasses = classMatch ? classMatch[1].split(/\s+/).filter(Boolean) : [];
1724
+ const { pictureClasses, imgClasses } = splitImageClasses(allClasses);
1725
+ const fullImgClasses = [...imgClasses, ...imgFillClasses];
1726
+ const pictureClassAttr = pictureClasses.length > 0 ? ` class="${pictureClasses.join(" ")}"` : "";
1727
+ const imgClassAttr = fullImgClasses.length > 0 ? ` class="${fullImgClasses.join(" ")}"` : "";
1728
+ const wrapperStyleAttr = injectInlineStyle(styleAttr, blurWrapperCss);
1729
+ if (hasAvif) {
1730
+ return `${ind(ctx)}<picture${pictureClassAttr}${wrapperStyleAttr}>
1450
1731
  ${ind(ctx)} <source type="image/avif" srcset="${escapeJSX(metadata.avifSrcset)}" sizes="${escapeJSX(sizesValue)}" />
1451
1732
  ${ind(ctx)} <source type="image/webp" srcset="${escapeJSX(metadata.srcset)}" sizes="${escapeJSX(sizesValue)}" />
1452
- ${ind(ctx)} <img${imgClassAttr}${imgAttrs}${blurStyle} />
1733
+ ${ind(ctx)} <img${imgClassAttr}${imgAttrs}${blurOnload} />
1453
1734
  ${ind(ctx)}</picture>
1454
1735
  `;
1455
1736
  }
@@ -1457,6 +1738,14 @@ ${ind(ctx)}</picture>
1457
1738
  imgAttrs += ` srcset="${escapeJSX(metadata.srcset)}"`;
1458
1739
  imgAttrs += ` sizes="${escapeJSX(sizesValue)}"`;
1459
1740
  }
1741
+ return `${ind(ctx)}<picture${pictureClassAttr}${wrapperStyleAttr}>
1742
+ ${ind(ctx)} <img${imgClassAttr}${imgAttrs}${blurOnload} />
1743
+ ${ind(ctx)}</picture>
1744
+ `;
1745
+ }
1746
+ if (metadata.srcset) {
1747
+ imgAttrs += ` srcset="${escapeJSX(metadata.srcset)}"`;
1748
+ imgAttrs += ` sizes="${escapeJSX(sizesValue)}"`;
1460
1749
  }
1461
1750
  return `${ind(ctx)}<img${classExpr}${styleAttr}${imgAttrs} />
1462
1751
  `;
@@ -1567,6 +1856,9 @@ function emitLocaleListNode(node, ctx) {
1567
1856
  let elementClass = null;
1568
1857
  if (node.interactiveStyles && node.interactiveStyles.length > 0 || node.generateElementClass) {
1569
1858
  elementClass = buildElementClass(ctx, node.label);
1859
+ if (elementClass && node.interactiveStyles?.length && ctx.collectedInteractiveStyles) {
1860
+ ctx.collectedInteractiveStyles.set(elementClass, node.interactiveStyles);
1861
+ }
1570
1862
  }
1571
1863
  const { classExpr: containerClassExpr, styleAttr: containerStyleAttr } = buildClassAndStyleExpression(
1572
1864
  style,
@@ -1575,13 +1867,13 @@ function emitLocaleListNode(node, ctx) {
1575
1867
  ctx
1576
1868
  );
1577
1869
  const itemStyle = node.itemStyle;
1578
- const itemResult = itemStyle ? responsiveStylesToTailwind(itemStyle, ctx.breakpoints) : { classes: [], dynamicStyles: {} };
1870
+ const itemResult = itemStyle ? responsiveStylesToTailwind(itemStyle, ctx.breakpoints, ctx.responsiveScales) : { classes: [], dynamicStyles: {} };
1579
1871
  const itemClasses = itemResult.classes;
1580
1872
  const activeItemStyle = node.activeItemStyle;
1581
- const activeResult = activeItemStyle ? responsiveStylesToTailwind(activeItemStyle, ctx.breakpoints) : { classes: [], dynamicStyles: {} };
1873
+ const activeResult = activeItemStyle ? responsiveStylesToTailwind(activeItemStyle, ctx.breakpoints, ctx.responsiveScales) : { classes: [], dynamicStyles: {} };
1582
1874
  const activeItemClasses = [...itemClasses, ...activeResult.classes];
1583
1875
  const separatorStyle = node.separatorStyle;
1584
- const sepResult = separatorStyle ? responsiveStylesToTailwind(separatorStyle, ctx.breakpoints) : { classes: [], dynamicStyles: {} };
1876
+ const sepResult = separatorStyle ? responsiveStylesToTailwind(separatorStyle, ctx.breakpoints, ctx.responsiveScales) : { classes: [], dynamicStyles: {} };
1585
1877
  const separatorClasses = sepResult.classes;
1586
1878
  const localeIconMap = /* @__PURE__ */ new Map();
1587
1879
  for (const localeConfig of i18nConfig.locales) {
@@ -1590,7 +1882,7 @@ function emitLocaleListNode(node, ctx) {
1590
1882
  }
1591
1883
  }
1592
1884
  const flagStyle = node.flagStyle;
1593
- const flagResult = flagStyle ? responsiveStylesToTailwind(flagStyle, ctx.breakpoints) : { classes: [], dynamicStyles: {} };
1885
+ const flagResult = flagStyle ? responsiveStylesToTailwind(flagStyle, ctx.breakpoints, ctx.responsiveScales) : { classes: [], dynamicStyles: {} };
1594
1886
  const flagClasses = flagResult.classes;
1595
1887
  const links = [];
1596
1888
  const currentLocale = ctx.locale || i18nConfig.defaultLocale;
@@ -1776,7 +2068,7 @@ function propDefToTSType(def) {
1776
2068
  }
1777
2069
  function formatDefault(def) {
1778
2070
  if (!("default" in def) || def.default === void 0) return null;
1779
- const val = def.default;
2071
+ const val = stripRawHtmlPrefixDeep(def.default);
1780
2072
  if (typeof val === "string") return JSON.stringify(val);
1781
2073
  if (typeof val === "number" || typeof val === "boolean") return String(val);
1782
2074
  if (typeof val === "object" && val !== null && "_i18n" in val) {
@@ -1818,7 +2110,7 @@ function mergeClassNameOntoRoot(template) {
1818
2110
  }
1819
2111
  return prefix + tagName + ` class={className}` + attrs + close + template.slice(fullMatch.length);
1820
2112
  }
1821
- function emitAstroComponent(name, def, allComponents, breakpoints = DEFAULT_BREAKPOINTS, defaultLocale = "en") {
2113
+ function emitAstroComponent(name, def, allComponents, breakpoints = DEFAULT_BREAKPOINTS, defaultLocale = "en", responsiveScales, remConfig) {
1822
2114
  const comp = def.component;
1823
2115
  const propDefs = comp.interface || {};
1824
2116
  const structure = comp.structure;
@@ -1836,25 +2128,49 @@ function emitAstroComponent(name, def, allComponents, breakpoints = DEFAULT_BREA
1836
2128
  fileType: "component",
1837
2129
  fileName: name,
1838
2130
  breakpoints,
1839
- defaultLocale
2131
+ responsiveScales,
2132
+ defaultLocale,
2133
+ imageImports: /* @__PURE__ */ new Map(),
2134
+ fileDepth: 0,
2135
+ // components live at src/components/
2136
+ collectedInteractiveStyles: /* @__PURE__ */ new Map()
1840
2137
  };
1841
2138
  let templateBody = nodeToAstro(structure, ctx);
1842
2139
  templateBody = mergeClassNameOntoRoot(templateBody);
1843
- const frontmatter = buildFrontmatter(name, propDefs, ctx.imports, ctx.dynamicTags, ctx.needsI18nResolver ? defaultLocale : void 0);
2140
+ const frontmatter = buildFrontmatter(
2141
+ name,
2142
+ propDefs,
2143
+ ctx.imports,
2144
+ ctx.dynamicTags,
2145
+ ctx.needsI18nResolver ? defaultLocale : void 0,
2146
+ ctx.imageImports
2147
+ );
1844
2148
  const styleSection = comp.css ? `
1845
2149
  <style>
1846
2150
  ${comp.css}
1847
2151
  </style>
2152
+ ` : "";
2153
+ const interactiveStyleSection = ctx.collectedInteractiveStyles.size > 0 ? `
2154
+ <style is:global>
2155
+ ${generateAllInteractiveCSS(ctx.collectedInteractiveStyles, breakpoints, remConfig, responsiveScales)}
2156
+ </style>
1848
2157
  ` : "";
1849
2158
  const scriptSection = comp.javascript ? buildScriptSection(comp.javascript, comp, propDefs) : "";
1850
2159
  return `---
1851
2160
  ${frontmatter}---
1852
- ${templateBody}${styleSection}${scriptSection}`;
2161
+ ${templateBody}${styleSection}${interactiveStyleSection}${scriptSection}`;
1853
2162
  }
1854
- function buildFrontmatter(componentName, propDefs, imports, dynamicTags, i18nDefaultLocale) {
2163
+ function buildFrontmatter(componentName, propDefs, imports, dynamicTags, i18nDefaultLocale, imageImports) {
1855
2164
  const lines = [];
1856
2165
  for (const imp of Array.from(imports).sort()) {
1857
- lines.push(`import ${imp} from './${imp}.astro';`);
2166
+ lines.push(`import ${astroComponentName(imp)} from './${imp}.astro';`);
2167
+ }
2168
+ if (imageImports && imageImports.size > 0) {
2169
+ lines.push(`import { Picture } from 'astro:assets';`);
2170
+ const sortedImages = Array.from(imageImports.entries()).sort(([a], [b]) => a.localeCompare(b));
2171
+ for (const [varName, importPath] of sortedImages) {
2172
+ lines.push(`import ${varName} from '${importPath}';`);
2173
+ }
1858
2174
  }
1859
2175
  if (lines.length > 0) lines.push("");
1860
2176
  const propEntries = Object.entries(propDefs);
@@ -1948,7 +2264,13 @@ function transformDefineVarsJS(js, varNames) {
1948
2264
  return result;
1949
2265
  }
1950
2266
  function buildScriptSection(js, comp, propDefs) {
1951
- const elInit = "const el = document.currentScript.previousElementSibling;";
2267
+ 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){if(c.tagName==='SCRIPT')n.removeChild(c);else _w(c)}c=x}})(el);`;
2268
+ const deferWrapper = (innerJS) => `var el = document.currentScript.previousElementSibling;
2269
+ function __init__() {
2270
+ ${cleanTextNodes}
2271
+ ${innerJS}
2272
+ }
2273
+ if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', __init__); } else { __init__(); }`;
1952
2274
  if (comp.defineVars) {
1953
2275
  const vars = comp.defineVars === true ? Object.keys(propDefs).filter((k) => k !== "children") : comp.defineVars;
1954
2276
  if (vars.length > 0) {
@@ -1956,23 +2278,25 @@ function buildScriptSection(js, comp, propDefs) {
1956
2278
  const defineVarsObj = `{ ${vars.join(", ")} }`;
1957
2279
  return `
1958
2280
  <script define:vars={${defineVarsObj}}>
1959
- ${elInit}
1960
- ${transformedJS}
2281
+ (function(){
2282
+ ${deferWrapper(transformedJS)}
2283
+ })();
1961
2284
  </script>
1962
2285
  `;
1963
2286
  }
1964
2287
  }
1965
2288
  return `
1966
2289
  <script is:inline>
1967
- ${elInit}
1968
- ${js}
2290
+ (function(){
2291
+ ${deferWrapper(js)}
2292
+ })();
1969
2293
  </script>
1970
2294
  `;
1971
2295
  }
1972
2296
 
1973
2297
  // lib/server/astro/pageEmitter.ts
1974
2298
  function escapeTemplateLiteral2(s) {
1975
- return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
2299
+ return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
1976
2300
  }
1977
2301
  function escapeJSX2(s) {
1978
2302
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
@@ -1997,11 +2321,14 @@ function emitAstroPage(options) {
1997
2321
  ssrFallbacks,
1998
2322
  pageName,
1999
2323
  breakpoints: breakpointsOpt,
2324
+ responsiveScales,
2000
2325
  imageMetadataMap,
2001
2326
  i18nConfig,
2002
2327
  currentPageSlugMap,
2003
2328
  slugMappings,
2004
- imageFormat
2329
+ imageFormat,
2330
+ processedRawHtml,
2331
+ remConfig
2005
2332
  } = options;
2006
2333
  const breakpoints = breakpointsOpt ?? DEFAULT_BREAKPOINTS;
2007
2334
  const root = pageData.root;
@@ -2020,6 +2347,7 @@ function emitAstroPage(options) {
2020
2347
  fileType: "page",
2021
2348
  fileName: pageName,
2022
2349
  breakpoints,
2350
+ responsiveScales,
2023
2351
  imageMetadataMap,
2024
2352
  locale,
2025
2353
  i18nConfig,
@@ -2028,7 +2356,11 @@ function emitAstroPage(options) {
2028
2356
  astroImports: /* @__PURE__ */ new Set(),
2029
2357
  slugMappings,
2030
2358
  i18nDefaultLocale: i18nConfig?.defaultLocale,
2031
- imageFormat
2359
+ imageFormat,
2360
+ processedRawHtml,
2361
+ imageImports: /* @__PURE__ */ new Map(),
2362
+ fileDepth,
2363
+ collectedInteractiveStyles: /* @__PURE__ */ new Map()
2032
2364
  };
2033
2365
  const templateBody = nodeToAstro(root, ctx);
2034
2366
  const importLines = [];
@@ -2037,16 +2369,28 @@ function emitAstroPage(options) {
2037
2369
  importLines.push(`import { ${astroImports.join(", ")} } from 'astro:content';`);
2038
2370
  }
2039
2371
  importLines.push(`import BaseLayout from '${layoutImportPath2}';`);
2372
+ if (ctx.imageImports && ctx.imageImports.size > 0) {
2373
+ importLines.push(`import { Picture } from 'astro:assets';`);
2374
+ const sortedImages = Array.from(ctx.imageImports.entries()).sort(([a], [b]) => a.localeCompare(b));
2375
+ for (const [varName, importPath] of sortedImages) {
2376
+ importLines.push(`import ${varName} from '${importPath}';`);
2377
+ }
2378
+ }
2040
2379
  const componentImports = Array.from(ctx.imports).sort();
2041
2380
  for (const comp of componentImports) {
2042
2381
  const path = componentImportPath(fileDepth, comp);
2043
- importLines.push(`import ${comp} from '${path}';`);
2382
+ importLines.push(`import ${astroComponentName(comp)} from '${path}';`);
2044
2383
  }
2045
2384
  const scriptsArrayLiteral = scriptPaths.length > 0 ? `[${scriptPaths.map((s) => `"${s}"`).join(", ")}]` : "[]";
2046
2385
  const libraryTagsLiteral = `{ headCSS: \`${escapeTemplateLiteral2(libraryTags.headCSS || "")}\`, headJS: \`${escapeTemplateLiteral2(libraryTags.headJS || "")}\`, bodyEndJS: \`${escapeTemplateLiteral2(libraryTags.bodyEndJS || "")}\` }`;
2047
2386
  const escapedMeta = escapeTemplateLiteral2(meta);
2048
2387
  const escapedFontPreloads = escapeTemplateLiteral2(fontPreloads);
2049
2388
  const extraFrontmatter = ctx.frontmatterLines && ctx.frontmatterLines.length > 0 ? "\n" + ctx.frontmatterLines.join("\n") : "";
2389
+ const interactiveStyleSection = ctx.collectedInteractiveStyles.size > 0 ? `
2390
+ <style is:global>
2391
+ ${generateAllInteractiveCSS(ctx.collectedInteractiveStyles, breakpoints, remConfig, responsiveScales)}
2392
+ </style>
2393
+ ` : "";
2050
2394
  return `---
2051
2395
  ${importLines.join("\n")}${extraFrontmatter}
2052
2396
  ---
@@ -2062,7 +2406,7 @@ ${importLines.join("\n")}${extraFrontmatter}
2062
2406
  <div id="root">
2063
2407
  ${templateBody} </div>
2064
2408
  </BaseLayout>
2065
- `;
2409
+ ${interactiveStyleSection}`;
2066
2410
  }
2067
2411
  function buildEmptyPage(layoutImport, title, meta, locale, theme, fontPreloads, libraryTags, scriptPaths) {
2068
2412
  const escapedMeta = escapeTemplateLiteral2(meta);
@@ -2087,7 +2431,7 @@ import BaseLayout from '${layoutImport}';
2087
2431
 
2088
2432
  // lib/server/astro/cmsPageEmitter.ts
2089
2433
  function escapeTemplateLiteral3(s) {
2090
- return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
2434
+ return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
2091
2435
  }
2092
2436
  function escapeJSX3(s) {
2093
2437
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
@@ -2206,10 +2550,13 @@ function emitCMSPage(options) {
2206
2550
  ssrFallbacks,
2207
2551
  pageName,
2208
2552
  breakpoints: breakpointsOpt,
2553
+ responsiveScales,
2209
2554
  imageMetadataMap,
2210
2555
  i18nConfig,
2211
2556
  isMultiLocale,
2212
- slugMappings
2557
+ slugMappings,
2558
+ processedRawHtml,
2559
+ remConfig
2213
2560
  } = options;
2214
2561
  const breakpoints = breakpointsOpt ?? DEFAULT_BREAKPOINTS;
2215
2562
  const binding = "entry";
@@ -2245,6 +2592,7 @@ function emitCMSPage(options) {
2245
2592
  fileType: "page",
2246
2593
  fileName: pageName,
2247
2594
  breakpoints,
2595
+ responsiveScales,
2248
2596
  imageMetadataMap,
2249
2597
  locale,
2250
2598
  cmsMode: true,
@@ -2253,16 +2601,27 @@ function emitCMSPage(options) {
2253
2601
  cmsWrapFn: wrapFn,
2254
2602
  slugMappings,
2255
2603
  i18nDefaultLocale: i18nConfig.defaultLocale,
2256
- imageFormat: options.imageFormat
2604
+ imageFormat: options.imageFormat,
2605
+ processedRawHtml,
2606
+ imageImports: /* @__PURE__ */ new Map(),
2607
+ fileDepth,
2608
+ collectedInteractiveStyles: /* @__PURE__ */ new Map()
2257
2609
  };
2258
2610
  const templateBody = nodeToAstro(root, ctx);
2259
2611
  const importLines = [];
2260
2612
  importLines.push(`import { getCollection } from 'astro:content';`);
2261
2613
  importLines.push(`import BaseLayout from '${layoutImportPath2}';`);
2614
+ if (ctx.imageImports && ctx.imageImports.size > 0) {
2615
+ importLines.push(`import { Picture } from 'astro:assets';`);
2616
+ const sortedImages = Array.from(ctx.imageImports.entries()).sort(([a], [b]) => a.localeCompare(b));
2617
+ for (const [varName, importPath] of sortedImages) {
2618
+ importLines.push(`import ${varName} from '${importPath}';`);
2619
+ }
2620
+ }
2262
2621
  const componentImports = Array.from(ctx.imports).sort();
2263
2622
  for (const comp of componentImports) {
2264
2623
  const path = componentImportPath2(fileDepth, comp);
2265
- importLines.push(`import ${comp} from '${path}';`);
2624
+ importLines.push(`import ${astroComponentName(comp)} from '${path}';`);
2266
2625
  }
2267
2626
  const staticPaths = buildGetStaticPaths(cmsSchema, isMultiLocale, i18nConfig, locale);
2268
2627
  const scriptsArrayLiteral = scriptPaths.length > 0 ? `[${scriptPaths.map((s) => `"${s}"`).join(", ")}]` : "[]";
@@ -2277,6 +2636,11 @@ function emitCMSPage(options) {
2277
2636
  if (v && typeof v === 'object' && v._i18n) return v['${locale}'] ?? v['${i18nConfig.defaultLocale}'] ?? Object.values(v).find(x => x !== true && x !== undefined) ?? '';
2278
2637
  return v ?? '';
2279
2638
  }`;
2639
+ const interactiveStyleSection = ctx.collectedInteractiveStyles.size > 0 ? `
2640
+ <style is:global>
2641
+ ${generateAllInteractiveCSS(ctx.collectedInteractiveStyles, breakpoints, remConfig, responsiveScales)}
2642
+ </style>
2643
+ ` : "";
2280
2644
  return `---
2281
2645
  ${importLines.join("\n")}
2282
2646
 
@@ -2296,7 +2660,7 @@ ${resolverHelper}
2296
2660
  <div id="root">
2297
2661
  ${templateBody} </div>
2298
2662
  </BaseLayout>
2299
- `;
2663
+ ${interactiveStyleSection}`;
2300
2664
  }
2301
2665
  function buildEmptyCMSPage(layoutImport, title, meta, locale, theme, fontPreloads, libraryTags, scriptPaths, cmsSchema, isMultiLocale, i18nConfig, binding, richTextFields) {
2302
2666
  const escapedMeta = escapeTemplateLiteral3(meta);
@@ -2338,25 +2702,32 @@ function isStyleMapping3(value) {
2338
2702
  function isResponsiveStyle3(style) {
2339
2703
  return "base" in style || "tablet" in style || "mobile" in style;
2340
2704
  }
2341
- function collectFromStyle(style, classes, breakpoints) {
2705
+ function collectFromStyle(style, classes, breakpoints, responsiveScales) {
2342
2706
  if (!style) return;
2343
2707
  if (isResponsiveStyle3(style)) {
2344
2708
  for (const [bp, bpStyle] of Object.entries(style)) {
2345
2709
  if (!bpStyle) continue;
2346
2710
  let prefix = "";
2711
+ let bpName;
2347
2712
  if (bp !== "base") {
2348
2713
  const bpValue = breakpoints[bp]?.breakpoint;
2349
2714
  if (bpValue) {
2350
2715
  prefix = `max-[${bpValue}px]:`;
2716
+ bpName = bp;
2351
2717
  }
2352
2718
  }
2353
- collectFromFlatStyle(bpStyle, prefix, classes);
2719
+ collectFromFlatStyle(bpStyle, prefix, classes, breakpoints, responsiveScales, bpName);
2354
2720
  }
2355
2721
  } else {
2356
- collectFromFlatStyle(style, "", classes);
2722
+ collectFromFlatStyle(style, "", classes, breakpoints, responsiveScales);
2357
2723
  }
2358
2724
  }
2359
- function collectFromFlatStyle(style, prefix, classes) {
2725
+ function collectFromFlatStyle(style, prefix, classes, breakpoints, responsiveScales, sourceBreakpoint) {
2726
+ const shouldAutoScale = responsiveScales?.enabled === true && sourceBreakpoint === void 0;
2727
+ const scaleBreakpoints = shouldAutoScale ? Object.entries(breakpoints).map(([name, cfg]) => ({ name, value: cfg?.breakpoint })).filter(
2728
+ (bp) => typeof bp.value === "number" && bp.value > 0
2729
+ ).sort((a, b) => b.value - a.value) : [];
2730
+ const baseRef = responsiveScales?.baseReference ?? 16;
2360
2731
  for (const [property, value] of Object.entries(style)) {
2361
2732
  if (!isStyleMapping3(value)) continue;
2362
2733
  for (const [, cssValue] of Object.entries(value.values)) {
@@ -2364,41 +2735,58 @@ function collectFromFlatStyle(style, prefix, classes) {
2364
2735
  if (twClass) {
2365
2736
  classes.add(prefix ? `${prefix}${twClass}` : twClass);
2366
2737
  }
2738
+ if (shouldAutoScale && responsiveScales) {
2739
+ const strValue = String(cssValue);
2740
+ if (strValue === "") continue;
2741
+ for (const { name: bpName, value: bpPixels } of scaleBreakpoints) {
2742
+ const scale = getScaleMultiplier(
2743
+ responsiveScales,
2744
+ property,
2745
+ bpName
2746
+ );
2747
+ if (scale == null) continue;
2748
+ const scaledValue = scalePropertyValue(strValue, baseRef, scale);
2749
+ if (scaledValue == null || scaledValue === strValue) continue;
2750
+ const scaledClass = propertyToTailwind(property, scaledValue);
2751
+ if (!scaledClass) continue;
2752
+ classes.add(`max-[${bpPixels}px]:${scaledClass}`);
2753
+ }
2754
+ }
2367
2755
  }
2368
2756
  }
2369
2757
  }
2370
- function walkNode(node, classes, breakpoints) {
2758
+ function walkNode(node, classes, breakpoints, responsiveScales) {
2371
2759
  if (!node || typeof node === "string" || typeof node === "number") return;
2372
2760
  if (Array.isArray(node)) {
2373
2761
  for (const child of node) {
2374
- walkNode(child, classes, breakpoints);
2762
+ walkNode(child, classes, breakpoints, responsiveScales);
2375
2763
  }
2376
2764
  return;
2377
2765
  }
2378
2766
  if ("style" in node && node.style) {
2379
- collectFromStyle(node.style, classes, breakpoints);
2767
+ collectFromStyle(node.style, classes, breakpoints, responsiveScales);
2380
2768
  }
2381
2769
  if ("interactiveStyles" in node && Array.isArray(node.interactiveStyles)) {
2382
2770
  for (const rule of node.interactiveStyles) {
2383
2771
  if (rule.style) {
2384
- collectFromStyle(rule.style, classes, breakpoints);
2772
+ collectFromStyle(rule.style, classes, breakpoints, responsiveScales);
2385
2773
  }
2386
2774
  }
2387
2775
  }
2388
2776
  if ("children" in node && node.children) {
2389
2777
  if (Array.isArray(node.children)) {
2390
2778
  for (const child of node.children) {
2391
- walkNode(child, classes, breakpoints);
2779
+ walkNode(child, classes, breakpoints, responsiveScales);
2392
2780
  }
2393
2781
  }
2394
2782
  }
2395
2783
  }
2396
- function collectAllMappingClasses(componentDefs, breakpoints = DEFAULT_BREAKPOINTS) {
2784
+ function collectAllMappingClasses(componentDefs, breakpoints = DEFAULT_BREAKPOINTS, responsiveScales) {
2397
2785
  const classes = /* @__PURE__ */ new Set();
2398
2786
  for (const def of Object.values(componentDefs)) {
2399
2787
  const structure = def.component?.structure;
2400
2788
  if (structure) {
2401
- walkNode(structure, classes, breakpoints);
2789
+ walkNode(structure, classes, breakpoints, responsiveScales);
2402
2790
  }
2403
2791
  }
2404
2792
  return classes;
@@ -2408,18 +2796,40 @@ function collectAllMappingClasses(componentDefs, breakpoints = DEFAULT_BREAKPOIN
2408
2796
  function hashContent2(content) {
2409
2797
  return createHash("sha256").update(content).digest("hex").slice(0, 8);
2410
2798
  }
2411
- function copyDirectory(src, dest) {
2799
+ function writePageScript(javascript, scriptsDir) {
2800
+ if (!javascript) return [];
2801
+ const hash = hashContent2(javascript);
2802
+ const scriptFile = `${hash}.js`;
2803
+ if (!existsSync(scriptsDir)) {
2804
+ mkdirSync(scriptsDir, { recursive: true });
2805
+ }
2806
+ const fullScriptPath = join(scriptsDir, scriptFile);
2807
+ if (!existsSync(fullScriptPath)) {
2808
+ writeFileSync(fullScriptPath, javascript, "utf-8");
2809
+ }
2810
+ return [`/_scripts/${scriptFile}`];
2811
+ }
2812
+ function copyDirectory(src, dest, filter) {
2412
2813
  if (!existsSync(src)) return;
2413
2814
  if (!existsSync(dest)) mkdirSync(dest, { recursive: true });
2414
2815
  const files = readdirSync(src);
2415
2816
  for (const file of files) {
2817
+ if (filter && !filter(file)) continue;
2416
2818
  const srcPath = join(src, file);
2417
2819
  const destPath = join(dest, file);
2418
2820
  const stat = statSync(srcPath);
2419
- if (stat.isDirectory()) copyDirectory(srcPath, destPath);
2821
+ if (stat.isDirectory()) copyDirectory(srcPath, destPath, filter);
2420
2822
  else copyFileSync(srcPath, destPath);
2421
2823
  }
2422
2824
  }
2825
+ var imageVariantSuffixRe = new RegExp(
2826
+ `-(${RESPONSIVE_WIDTHS.join("|")})\\.(webp|avif)$`
2827
+ );
2828
+ function shouldCopyImageForAstro(filename) {
2829
+ if (filename === "manifest.json") return false;
2830
+ if (imageVariantSuffixRe.test(filename)) return false;
2831
+ return true;
2832
+ }
2423
2833
  function isCMSPage(pageData) {
2424
2834
  return pageData.meta?.source === "cms" && !!pageData.meta?.cms;
2425
2835
  }
@@ -2507,14 +2917,10 @@ import BaseLayout from '${importPath}';
2507
2917
  `;
2508
2918
  }
2509
2919
  async function buildAstroProject(projectRoot, outputDir) {
2510
- const startTime = Date.now();
2511
- console.log("\u{1F3D7}\uFE0F Building Astro export...\n");
2512
2920
  configService.reset();
2513
2921
  const projectConfig = await loadProjectConfig();
2514
2922
  const siteUrl = projectConfig.siteUrl?.replace(/\/$/, "") || "";
2515
2923
  const i18nConfig = await loadI18nConfig();
2516
- console.log(`\u{1F310} Locales: ${i18nConfig.locales.map((l) => l.code).join(", ")} (default: ${i18nConfig.defaultLocale})
2517
- `);
2518
2924
  await migrateTemplatesDirectory();
2519
2925
  const { components, warnings, errors: compErrors } = await loadComponentDirectory(projectPaths.components());
2520
2926
  const globalComponents = {};
@@ -2523,12 +2929,9 @@ async function buildAstroProject(projectRoot, outputDir) {
2523
2929
  });
2524
2930
  for (const w of warnings) console.warn(` Warning: ${w}`);
2525
2931
  for (const e of compErrors) console.error(` Error: ${e}`);
2526
- console.log(`Loaded ${components.size} global component(s)
2527
- `);
2528
2932
  const cmsProvider = new FileSystemCMSProvider(projectPaths.templates(), projectPaths.cms());
2529
2933
  const cmsService = new CMSService(cmsProvider);
2530
2934
  await cmsService.initialize();
2531
- console.log("CMS service initialized\n");
2532
2935
  const themeConfig = await colorService.loadThemeConfig();
2533
2936
  const variablesConfig = await variableService.loadConfig();
2534
2937
  const breakpoints = await loadBreakpointConfig();
@@ -2537,10 +2940,6 @@ async function buildAstroProject(projectRoot, outputDir) {
2537
2940
  const globalLibraries = configService.getLibraries();
2538
2941
  const componentLibraries = collectComponentLibraries(globalComponents);
2539
2942
  const imageMetadataMap = await buildImageMetadataMap();
2540
- if (imageMetadataMap.size > 0) {
2541
- console.log(`Loaded image metadata for ${imageMetadataMap.size} image(s)
2542
- `);
2543
- }
2544
2943
  const outDir = outputDir || join(projectPaths.project, "astro-export");
2545
2944
  if (existsSync(outDir)) {
2546
2945
  rmSync(outDir, { recursive: true, force: true });
@@ -2566,8 +2965,6 @@ async function buildAstroProject(projectRoot, outputDir) {
2566
2965
  console.warn("No pages found in ./pages directory");
2567
2966
  return { pages: 0, cmsPages: 0, collections: 0, errors: 0 };
2568
2967
  }
2569
- console.log(`Found ${pageFiles.length} page(s) to process
2570
- `);
2571
2968
  const slugMappings = [];
2572
2969
  for (const file of pageFiles) {
2573
2970
  const pageName = file.replace(".json", "");
@@ -2588,6 +2985,7 @@ async function buildAstroProject(projectRoot, outputDir) {
2588
2985
  const allComponentCSS = /* @__PURE__ */ new Set();
2589
2986
  const jsContents = /* @__PURE__ */ new Map();
2590
2987
  let errorCount = 0;
2988
+ let projectNeedsFormHandler = false;
2591
2989
  function mergeInteractiveStyles(source) {
2592
2990
  for (const [key, value] of source) {
2593
2991
  if (!allInteractiveStyles.has(key)) {
@@ -2606,6 +3004,9 @@ async function buildAstroProject(projectRoot, outputDir) {
2606
3004
  jsContents.set(hash, result.javascript);
2607
3005
  }
2608
3006
  }
3007
+ if (!projectNeedsFormHandler && needsFormHandler(result.html)) {
3008
+ projectNeedsFormHandler = true;
3009
+ }
2609
3010
  allResults.push({
2610
3011
  html: result.html,
2611
3012
  meta: result.meta,
@@ -2620,7 +3021,8 @@ async function buildAstroProject(projectRoot, outputDir) {
2620
3021
  pageData,
2621
3022
  pageName,
2622
3023
  isCMSPage: isCMSPage3,
2623
- ssrFallbackCollector: result.ssrFallbackCollector
3024
+ ssrFallbackCollector: result.ssrFallbackCollector,
3025
+ processedRawHtmlCollector: result.processedRawHtmlCollector
2624
3026
  });
2625
3027
  }
2626
3028
  for (const file of pageFiles) {
@@ -2636,7 +3038,6 @@ async function buildAstroProject(projectRoot, outputDir) {
2636
3038
  const pageData = parseJSON(pageContent);
2637
3039
  const isDevBuild = process.env.MENO_DEV_BUILD === "true";
2638
3040
  if (pageData.meta?.draft === true && !isDevBuild) {
2639
- console.log(` Skipping draft: ${basePath}`);
2640
3041
  continue;
2641
3042
  }
2642
3043
  const slugs = pageData.meta?.slugs;
@@ -2670,7 +3071,6 @@ async function buildAstroProject(projectRoot, outputDir) {
2670
3071
  // isProductionBuild
2671
3072
  );
2672
3073
  processRenderResult(result, urlPath, astroFilePath, fileDepth, pageData, pageName, false);
2673
- console.log(` Rendered: ${urlPath}`);
2674
3074
  }
2675
3075
  } catch (error) {
2676
3076
  console.error(` Error rendering ${basePath}:`, error?.message || error);
@@ -2680,18 +3080,45 @@ async function buildAstroProject(projectRoot, outputDir) {
2680
3080
  const fontPreloads = generateFontPreloadTags();
2681
3081
  const mergedLibraries = mergeLibraries(globalLibraries, componentLibraries);
2682
3082
  const buildLibraries = filterLibrariesByContext(mergedLibraries, "build");
2683
- const libraryTags = generateLibraryTags(buildLibraries);
3083
+ const inlineContents = /* @__PURE__ */ new Map();
3084
+ const localLibsToCopy = [];
3085
+ for (const css of buildLibraries.css || []) {
3086
+ if (!css.url.startsWith("/")) continue;
3087
+ const shouldInline = css.inline !== false;
3088
+ const relPath = css.url.slice(1);
3089
+ const srcPath = join(projectPaths.project, relPath);
3090
+ if (!existsSync(srcPath)) continue;
3091
+ if (shouldInline) {
3092
+ try {
3093
+ inlineContents.set(css.url, await readFile(srcPath, "utf-8"));
3094
+ } catch {
3095
+ localLibsToCopy.push(relPath);
3096
+ }
3097
+ } else {
3098
+ localLibsToCopy.push(relPath);
3099
+ }
3100
+ }
3101
+ for (const js of buildLibraries.js || []) {
3102
+ if (js.url.startsWith("/")) {
3103
+ const relPath = js.url.slice(1);
3104
+ if (existsSync(join(projectPaths.project, relPath))) {
3105
+ localLibsToCopy.push(relPath);
3106
+ }
3107
+ }
3108
+ }
3109
+ const libraryTags = generateLibraryTags(buildLibraries, inlineContents);
2684
3110
  const defaultTheme = themeConfig.default || "light";
3111
+ const customCode = configService.getCustomCode();
3112
+ const iconsConfig = await loadIconsConfig();
3113
+ const faviconTag = iconsConfig.favicon ? `<link rel="icon" href="${iconsConfig.favicon.replace(/"/g, "&quot;")}" />` : "";
3114
+ const appleTouchIconTag = iconsConfig.appleTouchIcon ? `<link rel="apple-touch-icon" href="${iconsConfig.appleTouchIcon.replace(/"/g, "&quot;")}" />` : "";
3115
+ const iconTagsHtml = [faviconTag, appleTouchIconTag].filter(Boolean).join("\n ");
3116
+ const remConversionConfig = configService.getRemConversion();
2685
3117
  const templatesDir = projectPaths.templates();
2686
3118
  const templateSchemas = [];
2687
3119
  let cmsPageCount = 0;
2688
3120
  if (existsSync(templatesDir)) {
2689
3121
  const templateFiles = readdirSync(templatesDir).filter((f) => f.endsWith(".json"));
2690
- if (templateFiles.length > 0) {
2691
- console.log(`
2692
- Processing ${templateFiles.length} CMS template(s)...
2693
- `);
2694
- }
2695
3122
  for (const file of templateFiles) {
2696
3123
  const templateContent = await loadJSONFile(join(templatesDir, file));
2697
3124
  if (!templateContent) continue;
@@ -2699,7 +3126,6 @@ Processing ${templateFiles.length} CMS template(s)...
2699
3126
  const pageData = parseJSON(templateContent);
2700
3127
  const isDevBuild = process.env.MENO_DEV_BUILD === "true";
2701
3128
  if (pageData.meta?.draft === true && !isDevBuild) {
2702
- console.log(` Skipping draft template: ${file}`);
2703
3129
  continue;
2704
3130
  }
2705
3131
  if (!isCMSPage(pageData)) {
@@ -2708,14 +3134,8 @@ Processing ${templateFiles.length} CMS template(s)...
2708
3134
  }
2709
3135
  const cmsSchema = pageData.meta.cms;
2710
3136
  templateSchemas.push(cmsSchema);
2711
- console.log(` CMS Collection: ${cmsSchema.id}`);
2712
3137
  const items = await cmsService.queryItems({ collection: cmsSchema.id });
2713
3138
  const itemCount = items.length;
2714
- if (itemCount === 0) {
2715
- console.log(` No items found in cms/${cmsSchema.id}/`);
2716
- } else {
2717
- console.log(` Found ${itemCount} item(s)`);
2718
- }
2719
3139
  const defaultLocale = i18nConfig.defaultLocale;
2720
3140
  const dummyPath = cmsSchema.urlPattern.replace("{{slug}}", "__placeholder__");
2721
3141
  const metaResult = await renderPageSSR(
@@ -2776,12 +3196,15 @@ Processing ${templateFiles.length} CMS template(s)...
2776
3196
  ssrFallbacks,
2777
3197
  pageName: file.replace(".json", ""),
2778
3198
  breakpoints,
3199
+ responsiveScales,
2779
3200
  imageMetadataMap,
2780
3201
  i18nConfig,
2781
3202
  isMultiLocale: false,
2782
3203
  // Each file handles one locale
2783
3204
  slugMappings,
2784
- imageFormat: configService.getImageFormat()
3205
+ imageFormat: configService.getImageFormat(),
3206
+ processedRawHtml: metaResult.processedRawHtmlCollector,
3207
+ remConfig: remConversionConfig
2785
3208
  });
2786
3209
  const astroFileFull = join(pagesOutDir, astroFilePath);
2787
3210
  const astroFileDir = astroFileFull.substring(0, astroFileFull.lastIndexOf("/"));
@@ -2790,7 +3213,6 @@ Processing ${templateFiles.length} CMS template(s)...
2790
3213
  }
2791
3214
  await writeFile2(astroFileFull, astroContent, "utf-8");
2792
3215
  }
2793
- console.log(` Generated: ${pathPrefix}[slug].astro (${itemCount} items \xD7 ${localesToEmit.length} locale(s))`);
2794
3216
  cmsPageCount += itemCount * i18nConfig.locales.length;
2795
3217
  } catch (error) {
2796
3218
  console.error(` Error processing template ${file}:`, error?.message || error);
@@ -2798,29 +3220,36 @@ Processing ${templateFiles.length} CMS template(s)...
2798
3220
  }
2799
3221
  }
2800
3222
  }
2801
- const mappingClasses = collectAllMappingClasses(globalComponents, breakpoints);
3223
+ const mappingClasses = collectAllMappingClasses(globalComponents, breakpoints, responsiveScales);
2802
3224
  const fontCSS = generateFontCSS();
2803
3225
  const themeColorCSS = generateThemeColorVariablesCSS(themeConfig);
2804
3226
  const variablesCSS = generateVariablesCSS(variablesConfig, breakpoints, responsiveScales);
2805
- const remConversionConfig = configService.getRemConversion();
2806
- const interactiveCSS = generateAllInteractiveCSS(allInteractiveStyles, breakpoints, remConversionConfig);
2807
3227
  const componentCSSCombined = Array.from(allComponentCSS).join("\n");
2808
3228
  const baseCSS = `@layer base {
2809
3229
  * { margin: 0; padding: 0; box-sizing: border-box; }
2810
3230
  body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif; }
2811
3231
  button { background: none; border: none; padding: 0; font: inherit; cursor: pointer; outline: inherit; }
2812
- img { display: block; width: 100%; height: 100%; }
3232
+ img { max-width: 100%; height: auto; }
2813
3233
  picture { display: block; }
2814
- .olink { text-decoration: none; display: block; }
3234
+ .olink { text-decoration: none; display: block; color: inherit; }
2815
3235
  .oem { display: inline-block; }
2816
3236
  }`;
2817
- const tailwindDirectives = `@tailwind base;
2818
- @tailwind components;
2819
- @tailwind utilities;`;
2820
- const globalCSS = [tailwindDirectives, fontCSS, themeColorCSS, variablesCSS, baseCSS, componentCSSCombined, interactiveCSS].filter(Boolean).join("\n\n");
3237
+ const safelistClasses = Array.from(mappingClasses);
3238
+ const safelistDirectives = safelistClasses.map((c) => `@source inline("${c}");`).join("\n");
3239
+ const tailwindDirectives = safelistDirectives ? `@import "tailwindcss";
3240
+
3241
+ ${safelistDirectives}` : `@import "tailwindcss";`;
3242
+ const globalCSS = [tailwindDirectives, fontCSS, themeColorCSS, variablesCSS, baseCSS, componentCSSCombined].filter(Boolean).join("\n\n");
2821
3243
  await writeFile2(join(stylesDir, "global.css"), globalCSS, "utf-8");
2822
- console.log(`
2823
- Generated global.css (${(globalCSS.length / 1024).toFixed(1)} KB)`);
3244
+ const escForTemplateLiteral = (s) => s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
3245
+ const customHeadLiteral = escForTemplateLiteral(customCode.head || "");
3246
+ const customBodyStartLiteral = escForTemplateLiteral(customCode.bodyStart || "");
3247
+ const customBodyEndLiteral = escForTemplateLiteral(customCode.bodyEnd || "");
3248
+ const iconTagsLiteral = escForTemplateLiteral(iconTagsHtml);
3249
+ const formHandlerBlock = projectNeedsFormHandler ? `
3250
+ <script is:inline>
3251
+ ${formHandlerScript}
3252
+ </script>` : "";
2824
3253
  const baseLayoutContent = `---
2825
3254
  import '../styles/global.css';
2826
3255
 
@@ -2841,48 +3270,37 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
2841
3270
  <head>
2842
3271
  <meta charset="UTF-8">
2843
3272
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
3273
+ <Fragment set:html={\`${iconTagsLiteral}\`} />
2844
3274
  <Fragment set:html={fontPreloads} />
2845
3275
  <Fragment set:html={libraryTags.headCSS || ''} />
2846
3276
  <Fragment set:html={libraryTags.headJS || ''} />
2847
3277
  <Fragment set:html={meta} />
3278
+ <Fragment set:html={\`${customHeadLiteral}\`} />
2848
3279
  <title>{title}</title>
2849
3280
  </head>
2850
3281
  <body>
3282
+ <Fragment set:html={\`${customBodyStartLiteral}\`} />
2851
3283
  <slot />
2852
3284
  {scripts.map((s) => <script src={s} />)}
2853
3285
  <Fragment set:html={libraryTags.bodyEndJS || ''} />
3286
+ <Fragment set:html={\`${customBodyEndLiteral}\`} />${formHandlerBlock}
2854
3287
  </body>
2855
3288
  </html>
2856
3289
  `;
2857
3290
  await writeFile2(join(layoutsDir, "BaseLayout.astro"), baseLayoutContent, "utf-8");
2858
- console.log("Generated BaseLayout.astro");
2859
3291
  let componentFileCount = 0;
2860
3292
  for (const [compName, compDef] of Object.entries(globalComponents)) {
2861
3293
  try {
2862
- const astroContent = emitAstroComponent(compName, compDef, globalComponents, breakpoints, i18nConfig.defaultLocale);
3294
+ const astroContent = emitAstroComponent(compName, compDef, globalComponents, breakpoints, i18nConfig.defaultLocale, responsiveScales, remConversionConfig);
2863
3295
  await writeFile2(join(componentsOutDir, `${compName}.astro`), astroContent, "utf-8");
2864
3296
  componentFileCount++;
2865
3297
  } catch (error) {
2866
3298
  console.warn(` Warning: could not generate component ${compName}: ${error?.message}`);
2867
3299
  }
2868
3300
  }
2869
- console.log(`Generated ${componentFileCount} component .astro file(s)`);
2870
3301
  for (const result of allResults) {
2871
3302
  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
- }
3303
+ let scriptPaths = [];
2886
3304
  let astroContent;
2887
3305
  if (result.pageData) {
2888
3306
  try {
@@ -2897,23 +3315,28 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
2897
3315
  theme: defaultTheme,
2898
3316
  fontPreloads,
2899
3317
  libraryTags,
2900
- scriptPaths,
3318
+ scriptPaths: [],
2901
3319
  layoutImportPath: importPath,
2902
3320
  fileDepth: result.fileDepth,
2903
3321
  ssrFallbacks,
2904
3322
  pageName: result.pageName || "index",
2905
3323
  breakpoints,
3324
+ responsiveScales,
2906
3325
  imageMetadataMap,
2907
3326
  i18nConfig: i18nConfig.locales.length > 1 ? i18nConfig : void 0,
2908
3327
  currentPageSlugMap: pageSlugMap,
2909
3328
  slugMappings: i18nConfig.locales.length > 1 ? slugMappings : void 0,
2910
- imageFormat: configService.getImageFormat()
3329
+ imageFormat: configService.getImageFormat(),
3330
+ processedRawHtml: result.processedRawHtmlCollector,
3331
+ remConfig: remConversionConfig
2911
3332
  });
2912
3333
  } catch (error) {
2913
3334
  console.warn(` Warning: component emission failed for ${result.urlPath}, using SSR fallback: ${error?.message}`);
3335
+ scriptPaths = writePageScript(result.javascript, scriptsDir);
2914
3336
  astroContent = buildSSRFallbackPage(result, importPath, fontPreloads, libraryTags, defaultTheme, scriptPaths);
2915
3337
  }
2916
3338
  } else {
3339
+ scriptPaths = writePageScript(result.javascript, scriptsDir);
2917
3340
  astroContent = buildSSRFallbackPage(result, importPath, fontPreloads, libraryTags, defaultTheme, scriptPaths);
2918
3341
  }
2919
3342
  const astroFileFull = join(pagesOutDir, result.astroFilePath);
@@ -2923,7 +3346,23 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
2923
3346
  }
2924
3347
  await writeFile2(astroFileFull, astroContent, "utf-8");
2925
3348
  }
2926
- console.log(`Generated ${allResults.length} .astro page file(s)`);
3349
+ const robotsTsContent = `import type { APIRoute } from 'astro';
3350
+
3351
+ export const GET: APIRoute = () => {
3352
+ const siteUrl = import.meta.env.SITE;
3353
+ const robotsTxt = [
3354
+ 'User-agent: *',
3355
+ 'Allow: /',
3356
+ '',
3357
+ siteUrl ? \`Sitemap: \${siteUrl}/sitemap-index.xml\` : '',
3358
+ ].filter(Boolean).join('\\n');
3359
+
3360
+ return new Response(robotsTxt, {
3361
+ headers: { 'Content-Type': 'text/plain; charset=utf-8' },
3362
+ });
3363
+ };
3364
+ `;
3365
+ await writeFile2(join(pagesOutDir, "robots.txt.ts"), robotsTsContent, "utf-8");
2927
3366
  let collectionCount = 0;
2928
3367
  if (templateSchemas.length > 0) {
2929
3368
  const contentDir = join(srcDir, "content");
@@ -2959,7 +3398,7 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
2959
3398
  }
2960
3399
  }
2961
3400
  collectionDefs.push(` '${schema.id}': defineCollection({
2962
- type: 'data',
3401
+ loader: glob({ pattern: '**/*.json', base: './src/content/${schema.id}' }),
2963
3402
  schema: z.object({
2964
3403
  ${fieldDefs.join(",\n")}
2965
3404
  })
@@ -2967,6 +3406,7 @@ ${fieldDefs.join(",\n")}
2967
3406
  collectionCount++;
2968
3407
  }
2969
3408
  const configContent = `import { z, defineCollection } from 'astro:content';
3409
+ import { glob } from 'astro/loaders';
2970
3410
 
2971
3411
  const collections = {
2972
3412
  ${collectionDefs.join(",\n")}
@@ -2974,25 +3414,30 @@ ${collectionDefs.join(",\n")}
2974
3414
 
2975
3415
  export { collections };
2976
3416
  `;
2977
- await writeFile2(join(contentDir, "config.ts"), configContent, "utf-8");
2978
- console.log(`Generated ${collectionCount} content collection(s) with config.ts`);
3417
+ await writeFile2(join(srcDir, "content.config.ts"), configContent, "utf-8");
2979
3418
  }
2980
- const assetDirs = ["fonts", "images", "icons", "videos", "assets"];
2981
- let copiedAssets = 0;
2982
- for (const dir of assetDirs) {
3419
+ const imagesSrcDir = join(projectPaths.project, "images");
3420
+ if (existsSync(imagesSrcDir)) {
3421
+ copyDirectory(imagesSrcDir, join(srcDir, "assets", "images"), shouldCopyImageForAstro);
3422
+ copyDirectory(imagesSrcDir, join(publicDir, "images"));
3423
+ }
3424
+ const publicAssetDirs = ["fonts", "icons", "videos", "assets"];
3425
+ for (const dir of publicAssetDirs) {
2983
3426
  const srcAssetDir = join(projectPaths.project, dir);
2984
3427
  if (existsSync(srcAssetDir)) {
2985
3428
  copyDirectory(srcAssetDir, join(publicDir, dir));
2986
- copiedAssets++;
2987
3429
  }
2988
3430
  }
2989
3431
  const librariesDir = join(projectPaths.project, "libraries");
2990
3432
  if (existsSync(librariesDir)) {
2991
3433
  copyDirectory(librariesDir, join(publicDir, "libraries"));
2992
- copiedAssets++;
2993
3434
  }
2994
- if (copiedAssets > 0) {
2995
- console.log(`Copied ${copiedAssets} asset director${copiedAssets === 1 ? "y" : "ies"} to public/`);
3435
+ for (const relPath of localLibsToCopy) {
3436
+ const srcPath = join(projectPaths.project, relPath);
3437
+ const destPath = join(publicDir, relPath);
3438
+ const destDir = destPath.substring(0, destPath.lastIndexOf("/"));
3439
+ if (destDir && !existsSync(destDir)) mkdirSync(destDir, { recursive: true });
3440
+ copyFileSync(srcPath, destPath);
2996
3441
  }
2997
3442
  const packageJson = {
2998
3443
  name: "astro-export",
@@ -3006,9 +3451,14 @@ export { collections };
3006
3451
  preview: "astro preview"
3007
3452
  },
3008
3453
  dependencies: {
3009
- "astro": "^4.0.0",
3010
- "@astrojs/tailwind": "^5.0.0",
3011
- "tailwindcss": "^3.4.0"
3454
+ "astro": "^6.0.0",
3455
+ "@astrojs/sitemap": "^3.0.0",
3456
+ "@tailwindcss/vite": "^4.0.0",
3457
+ "tailwindcss": "^4.0.0"
3458
+ },
3459
+ // Astro 6 expects Vite 7; pin it so npm doesn't pull Vite 8+ and warn.
3460
+ overrides: {
3461
+ "vite": "^7.0.0"
3012
3462
  }
3013
3463
  };
3014
3464
  await writeFile2(join(outDir, "package.json"), JSON.stringify(packageJson, null, 2), "utf-8");
@@ -3020,51 +3470,24 @@ export { collections };
3020
3470
  routing: { prefixDefaultLocale: false },
3021
3471
  },` : "";
3022
3472
  const astroConfig = `import { defineConfig } from 'astro/config';
3023
- import tailwind from '@astrojs/tailwind';
3473
+ import tailwindcss from '@tailwindcss/vite';
3474
+ import sitemap from '@astrojs/sitemap';
3024
3475
 
3025
3476
  export default defineConfig({${siteUrl ? `
3026
3477
  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: {},
3478
+ integrations: [sitemap()],
3479
+ vite: {
3480
+ plugins: [tailwindcss()],
3040
3481
  },
3041
- plugins: [],
3042
- };
3482
+ });
3043
3483
  `;
3044
- await writeFile2(join(outDir, "tailwind.config.mjs"), tailwindConfig, "utf-8");
3045
3484
  await writeFile2(join(outDir, "astro.config.mjs"), astroConfig, "utf-8");
3046
3485
  const tsConfig = {
3047
3486
  extends: "astro/tsconfigs/strict"
3048
3487
  };
3049
3488
  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");
3051
- const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
3489
+ await writeFile2(join(outDir, "src", "env.d.ts"), '/// <reference path="../.astro/types.d.ts" />\n', "utf-8");
3052
3490
  const totalPages = allResults.length;
3053
- console.log("\n" + "=".repeat(50));
3054
- console.log("Astro export complete!");
3055
- console.log(` Pages: ${totalPages - cmsPageCount}`);
3056
- if (cmsPageCount > 0) {
3057
- console.log(` CMS pages: ${cmsPageCount}`);
3058
- }
3059
- if (collectionCount > 0) {
3060
- console.log(` Content collections: ${collectionCount}`);
3061
- }
3062
- if (errorCount > 0) {
3063
- console.log(` Errors: ${errorCount}`);
3064
- }
3065
- console.log(` Time: ${elapsed}s`);
3066
- console.log(` Output: ${outDir}`);
3067
- console.log("");
3068
3491
  return {
3069
3492
  pages: totalPages - cmsPageCount,
3070
3493
  cmsPages: cmsPageCount,