@xosen/site-sdk 0.0.13 → 0.0.14

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.
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Shared reactive store for page data loaded via usePageData.
3
+ * Allows useDynamicLayout to reactively read layout from fetched pages.
4
+ */
5
+ export declare const pageDataStore: Record<string, any>;
6
+ /**
7
+ * Initialize store with preloaded data from __SITE_DATA__.
8
+ */
9
+ export declare function initPageDataStore(): void;
package/dist/index.js CHANGED
@@ -1,29 +1,29 @@
1
- import { ref as w, onMounted as _, watch as b, computed as c, onUnmounted as E, provide as N } from "vue";
1
+ import { ref as w, onMounted as T, watch as _, computed as u, onUnmounted as N, reactive as L, provide as P } from "vue";
2
2
  import { useI18n as S } from "vue-i18n";
3
- import { useRoute as L } from "vue-router";
4
- function J(o, a) {
3
+ import { useRoute as I } from "vue-router";
4
+ function Z(o, a) {
5
5
  const t = w(null), { locale: e } = S(), n = window.__SITE_DATA__, s = n?.locale;
6
6
  function r() {
7
7
  return n && n[o] && e.value === s ? (t.value = n[o], !0) : !1;
8
8
  }
9
9
  async function i() {
10
10
  try {
11
- const u = await fetch(`/api/content/${a}:${e.value}`);
12
- u.ok && (t.value = await u.json());
11
+ const c = await fetch(`/api/content/${a}:${e.value}`);
12
+ c.ok && (t.value = await c.json());
13
13
  } catch {
14
14
  }
15
15
  }
16
- return _(() => {
16
+ return T(() => {
17
17
  r() || i();
18
- }), b(e, () => {
18
+ }), _(e, () => {
19
19
  i();
20
20
  }), t;
21
21
  }
22
- function B() {
23
- const o = window.__SITE_DATA__, a = c(() => o?.config || null), t = c(() => o?.components || {}), e = c(() => a.value?.navigation || []), n = c(() => a.value?.locales || []), s = c(() => a.value?.defaultLocale || "en"), r = c(() => a.value?.branding || {}), i = c(() => a.value?.footer || {}), u = c(() => a.value?.features || {});
24
- function f(d) {
25
- const y = u.value[d];
26
- return typeof y == "boolean" ? y : typeof y == "object";
22
+ function q() {
23
+ const o = window.__SITE_DATA__, a = u(() => o?.config || null), t = u(() => o?.components || {}), e = u(() => a.value?.navigation || []), n = u(() => a.value?.locales || []), s = u(() => a.value?.defaultLocale || "en"), r = u(() => a.value?.branding || {}), i = u(() => a.value?.footer || {}), c = u(() => a.value?.features || {});
24
+ function p(m) {
25
+ const g = c.value[m];
26
+ return typeof g == "boolean" ? g : typeof g == "object";
27
27
  }
28
28
  return {
29
29
  config: a,
@@ -33,19 +33,19 @@ function B() {
33
33
  defaultLocale: s,
34
34
  branding: r,
35
35
  footer: i,
36
- features: u,
37
- hasFeature: f
36
+ features: c,
37
+ hasFeature: p
38
38
  };
39
39
  }
40
- function Y(o) {
40
+ function H(o) {
41
41
  function a(t) {
42
42
  const e = document.documentElement;
43
43
  if (t.colors)
44
44
  for (const [n, s] of Object.entries(t.colors))
45
- s && e.style.setProperty(`--x-color-${P(n)}`, s);
45
+ s && e.style.setProperty(`--x-color-${D(n)}`, s);
46
46
  t.typography?.fontFamily && e.style.setProperty("--x-font-family", t.typography.fontFamily), t.typography?.headingFont && e.style.setProperty("--x-font-heading", t.typography.headingFont), t.typography?.baseFontSize && e.style.setProperty("--x-font-size", t.typography.baseFontSize), t.shape?.borderRadius && e.style.setProperty("--x-border-radius", t.shape.borderRadius), t.shape?.maxWidth && e.style.setProperty("--x-max-width", t.shape.maxWidth);
47
47
  }
48
- _(() => {
48
+ T(() => {
49
49
  if (o) {
50
50
  a(o);
51
51
  return;
@@ -58,10 +58,10 @@ function Y(o) {
58
58
  });
59
59
  });
60
60
  }
61
- function P(o) {
61
+ function D(o) {
62
62
  return o.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
63
63
  }
64
- function X() {
64
+ function Q() {
65
65
  const a = window.__SITE_DATA__?.apiBase || "";
66
66
  async function t(s) {
67
67
  const r = await fetch(`${a}${s}`);
@@ -81,89 +81,99 @@ function X() {
81
81
  getProducts: n
82
82
  };
83
83
  }
84
- function x() {
84
+ function A() {
85
85
  try {
86
86
  return window.self !== window.top;
87
87
  } catch {
88
88
  return !0;
89
89
  }
90
90
  }
91
- function Z(o) {
92
- x() && o.beforeEach((a, t) => !t.name);
91
+ function V(o) {
92
+ A() && o.beforeEach((a, t) => !t.name);
93
93
  }
94
- function A() {
95
- const o = w(null), a = w(x());
94
+ function C() {
95
+ const o = w(null), a = w(A());
96
96
  function t(e) {
97
97
  const n = e.data;
98
98
  n?.type === "xosen-preview-update" && n.page && (o.value = n.page, a.value = !0);
99
99
  }
100
- return _(() => {
100
+ return T(() => {
101
101
  window.addEventListener("message", t);
102
- }), E(() => {
102
+ }), N(() => {
103
103
  window.removeEventListener("message", t);
104
104
  }), {
105
105
  previewPage: o,
106
106
  isPreviewMode: a
107
107
  };
108
108
  }
109
- const I = /* @__PURE__ */ Symbol("pageContext");
110
- function q(o) {
111
- const { locale: a } = S(), { previewPage: t, isPreviewMode: e } = A(), n = window.__SITE_DATA__, s = w(null), r = w(!0), i = w(!1), u = c(() => typeof o == "string" ? o : o.value), f = c(() => `page:${u.value}`), d = c(() => {
109
+ const R = /* @__PURE__ */ Symbol("pageContext"), $ = L({});
110
+ function j() {
111
+ const o = window.__SITE_DATA__;
112
+ if (o)
113
+ for (const a of Object.keys(o))
114
+ a.startsWith("page:") && ($[a] = o[a]);
115
+ }
116
+ j();
117
+ function ee(o) {
118
+ const { locale: a } = S(), { previewPage: t, isPreviewMode: e } = C(), n = window.__SITE_DATA__, s = w(null), r = w(!0), i = w(!1), c = u(() => typeof o == "string" ? o : o.value), p = u(() => `page:${c.value}`), m = u(() => {
112
119
  const l = e.value ? t.value : s.value;
113
120
  if (!l) return {};
114
- const { blocks: v, meta: p, slug: g, locale: M, ...C } = l;
115
- return C;
121
+ const { blocks: f, meta: d, slug: W, locale: J, ...E } = l;
122
+ return E;
116
123
  });
117
- N(I, d);
118
- const y = c(() => e.value && t.value?.slug === u.value ? t.value.blocks || [] : s.value?.blocks || []);
119
- function T() {
120
- const l = n?.[f.value];
121
- return l && a.value === n?.locale ? (s.value = l, i.value = !1, h(), !0) : !1;
124
+ P(R, m);
125
+ const g = u(() => e.value && t.value?.slug === c.value ? t.value.blocks || [] : s.value?.blocks || []);
126
+ function b(l) {
127
+ s.value = l, l && ($[p.value] = l);
128
+ }
129
+ function y() {
130
+ const l = n?.[p.value];
131
+ return l && a.value === n?.locale ? (b(l), i.value = !1, v(), !0) : !1;
122
132
  }
123
- async function m() {
133
+ async function h() {
124
134
  r.value = !0, i.value = !1;
125
135
  try {
126
- const l = await fetch(`/api/content/${f.value}:${a.value}`);
127
- l.ok ? (s.value = await l.json(), h()) : (s.value = null, i.value = !0);
136
+ const l = await fetch(`/api/content/${p.value}:${a.value}`);
137
+ l.ok ? (b(await l.json()), v()) : (b(null), i.value = !0);
128
138
  } catch {
129
- s.value = null, i.value = !0;
139
+ b(null), i.value = !0;
130
140
  } finally {
131
141
  r.value = !1;
132
142
  }
133
143
  }
134
- function h() {
144
+ function v() {
135
145
  if (!s.value) return;
136
146
  if (s.value.title) {
137
- const v = n?.config?.branding, p = v?.siteName ? ` — ${v.siteName}` : "";
138
- document.title = `${s.value.title}${p}`;
147
+ const f = n?.config?.branding, d = f?.siteName ? ` — ${f.siteName}` : "";
148
+ document.title = `${s.value.title}${d}`;
139
149
  }
140
150
  const l = s.value.meta?.description;
141
151
  if (l) {
142
- const v = document.querySelector('meta[name="description"]');
143
- v && v.setAttribute("content", l);
152
+ const f = document.querySelector('meta[name="description"]');
153
+ f && f.setAttribute("content", l);
144
154
  }
145
155
  }
146
- return b(t, (l) => {
147
- l?.slug === u.value && (r.value = !1, i.value = !1, (l.title || l.blocks) && (s.value = {
156
+ return _(t, (l) => {
157
+ l?.slug === c.value && (r.value = !1, i.value = !1, (l.title || l.blocks) && (s.value = {
148
158
  ...s.value || {},
149
159
  ...l.title ? { title: l.title } : {},
150
160
  ...l.blocks ? { blocks: l.blocks } : {}
151
- }, h()));
152
- }), _(() => {
153
- T() ? r.value = !1 : m();
154
- }), b(a, () => m()), b(u, () => {
155
- T() ? r.value = !1 : m();
161
+ }, v()));
162
+ }), T(() => {
163
+ y() ? r.value = !1 : h();
164
+ }), _(a, () => h()), _(c, () => {
165
+ y() ? r.value = !1 : h();
156
166
  }), {
157
167
  page: s,
158
- blocks: y,
159
- pageContext: d,
168
+ blocks: g,
169
+ pageContext: m,
160
170
  loading: r,
161
171
  notFound: i,
162
172
  isPreviewMode: e,
163
- reload: m
173
+ reload: h
164
174
  };
165
175
  }
166
- function H() {
176
+ function te() {
167
177
  const { locale: o } = S(), a = window.__SITE_DATA__, t = a?.locale, e = w({ ...a?.components || {} });
168
178
  async function n(r) {
169
179
  if (r === t) {
@@ -176,11 +186,11 @@ function H() {
176
186
  } catch {
177
187
  }
178
188
  }
179
- b(o, (r) => n(r)), _(() => {
189
+ _(o, (r) => n(r)), T(() => {
180
190
  o.value !== t && n(o.value);
181
191
  });
182
192
  function s(r) {
183
- return c(() => e.value[r] || null);
193
+ return u(() => e.value[r] || null);
184
194
  }
185
195
  return {
186
196
  /** All components (reactive, locale-aware) */
@@ -191,8 +201,8 @@ function H() {
191
201
  reload: () => n(o.value)
192
202
  };
193
203
  }
194
- function Q() {
195
- const { locale: o } = S(), a = window.__SITE_DATA__, t = c(() => a?.config?.locales || []), e = c(() => a?.config?.defaultLocale || "en"), n = c(() => t.value.length > 1);
204
+ function ae() {
205
+ const { locale: o } = S(), a = window.__SITE_DATA__, t = u(() => a?.config?.locales || []), e = u(() => a?.config?.defaultLocale || "en"), n = u(() => t.value.length > 1);
196
206
  function s(i) {
197
207
  o.value = i, localStorage.setItem("x-site-locale", i);
198
208
  }
@@ -208,12 +218,12 @@ function Q() {
208
218
  resolveText: r
209
219
  };
210
220
  }
211
- const R = {
221
+ const O = {
212
222
  sm: 600,
213
223
  md: 960,
214
224
  lg: 1280,
215
225
  xl: 1920
216
- }, D = {
226
+ }, z = {
217
227
  grid: {
218
228
  default: {
219
229
  areas: ["header", "main", "footer"],
@@ -225,7 +235,7 @@ const R = {
225
235
  main: { type: "slot" },
226
236
  footer: { component: "footer" }
227
237
  }
228
- }, j = {
238
+ }, F = {
229
239
  grid: {
230
240
  default: {
231
241
  areas: ["main"]
@@ -235,7 +245,7 @@ const R = {
235
245
  main: { type: "slot" }
236
246
  }
237
247
  };
238
- function $(o, a) {
248
+ function k(o, a) {
239
249
  const t = [];
240
250
  if (o.areas?.length) {
241
251
  const e = o.areas.map((n) => `"${n}"`).join(" ");
@@ -243,47 +253,47 @@ function $(o, a) {
243
253
  }
244
254
  return o.columns && t.push(`grid-template-columns: ${o.columns}`), o.rows && t.push(`grid-template-rows: ${o.rows}`), o.gap && t.push(`gap: ${o.gap}`), t.length ? `${a} { ${t.join("; ")}; }` : "";
245
255
  }
246
- function O(o, a) {
256
+ function G(o, a) {
247
257
  const t = [`${a} { display: grid; min-height: 100vh; }`], e = o.grid;
248
258
  if (!e) return t.join(`
249
259
  `);
250
260
  if (e.default) {
251
- const n = $(e.default, a);
261
+ const n = k(e.default, a);
252
262
  n && t.push(n);
253
263
  }
254
264
  for (const n of ["sm", "md", "lg", "xl"]) {
255
265
  const s = e[n];
256
266
  if (!s) continue;
257
- const r = $(s, a);
258
- r && t.push(`@media (min-width: ${R[n]}px) { ${r} }`);
267
+ const r = k(s, a);
268
+ r && t.push(`@media (min-width: ${O[n]}px) { ${r} }`);
259
269
  }
260
270
  return t.join(`
261
271
  `);
262
272
  }
263
- function V() {
264
- const o = L(), { previewPage: a, isPreviewMode: t } = A(), e = window.__SITE_DATA__, n = `dl-${Math.random().toString(36).slice(2, 8)}`, s = c(() => ["dynamic-layout", n]), r = c(() => {
273
+ function oe() {
274
+ const o = I(), { previewPage: a, isPreviewMode: t } = C(), e = window.__SITE_DATA__, n = `dl-${Math.random().toString(36).slice(2, 8)}`, s = u(() => ["dynamic-layout", n]), r = u(() => {
265
275
  if (o.path === "/_preview_")
266
276
  return a.value?.layout || "landing";
267
277
  if (t.value && a.value?.layout)
268
278
  return a.value.layout;
269
- const f = o.path === "/" ? "page:home" : `page:${o.params.slug || ""}`;
270
- return e?.[f]?.layout || "default";
271
- }), i = c(() => {
272
- const f = e?.config?.layouts;
273
- if (f) {
274
- const d = f[r.value] || f.default;
275
- if (d?.zones) return d;
279
+ const p = o.path === "/" ? "page:home" : `page:${o.params.slug || ""}`;
280
+ return ($[p] || e?.[p])?.layout || "default";
281
+ }), i = u(() => {
282
+ const p = e?.config?.layouts;
283
+ if (p) {
284
+ const m = p[r.value] || p.default;
285
+ if (m?.zones) return m;
276
286
  }
277
- return r.value === "landing" ? j : D;
278
- }), u = c(() => O(i.value, `.${n}`));
287
+ return r.value === "landing" ? F : z;
288
+ }), c = u(() => G(i.value, `.${n}`));
279
289
  return {
280
290
  layoutName: r,
281
291
  layoutConfig: i,
282
- layoutCSS: u,
292
+ layoutCSS: c,
283
293
  layoutClass: s
284
294
  };
285
295
  }
286
- const ee = {
296
+ const ne = {
287
297
  type: "layout",
288
298
  displayName: "Layout",
289
299
  description: "CSS Grid layout with responsive breakpoints and component zones",
@@ -317,7 +327,7 @@ const ee = {
317
327
  { key: "class", type: "text", label: "CSS Class" },
318
328
  { key: "container", type: "switch", label: "Wrap in Container" }
319
329
  ]
320
- }, te = {
330
+ }, se = {
321
331
  default: {
322
332
  displayName: "Full Width",
323
333
  config: {
@@ -385,8 +395,8 @@ const ee = {
385
395
  }
386
396
  }
387
397
  }
388
- }, z = /\.(js|css|png|jpg|jpeg|gif|svg|ico|woff2?|ttf|eot|webp|avif|map|json|txt|xml|webmanifest)$/;
389
- function F(o, a) {
398
+ }, M = /\.(js|css|png|jpg|jpeg|gif|svg|ico|woff2?|ttf|eot|webp|avif|map|json|txt|xml|webmanifest)$/;
399
+ function U(o, a) {
390
400
  const e = new URL(o.url).searchParams.get("lang");
391
401
  if (e && a.supportedLocales?.includes(e)) return e;
392
402
  if (a.supportedLocales?.length) {
@@ -396,7 +406,7 @@ function F(o, a) {
396
406
  }
397
407
  return a.defaultLocale;
398
408
  }
399
- function G(o, a, t) {
409
+ function K(o, a, t) {
400
410
  if (!o.pathname.startsWith("/api/content/")) return null;
401
411
  const e = decodeURIComponent(o.pathname.replace("/api/content/", ""));
402
412
  return e ? (async () => {
@@ -414,7 +424,7 @@ function G(o, a, t) {
414
424
  }) : Response.json({ error: "Not found" }, { status: 404 });
415
425
  })() : Promise.resolve(Response.json({ error: "Key is required" }, { status: 400 }));
416
426
  }
417
- function k(o, a, t) {
427
+ function x(o, a, t) {
418
428
  let e = o;
419
429
  if (a.title) {
420
430
  const n = t ? ` — ${t}` : "";
@@ -422,46 +432,46 @@ function k(o, a, t) {
422
432
  }
423
433
  return a.meta?.description && (e = e.replace(/(<meta\s+name="description"\s+content=")[^"]*(")/, `$1${a.meta.description}$2`)), a.meta?.ogTitle && (e = e.replace(/(<meta\s+property="og:title"\s+content=")[^"]*(")/, `$1${a.meta.ogTitle}$2`)), a.html && (e = e.replace('<div id="app"></div>', `<div id="app">${a.html}</div>`)), e;
424
434
  }
425
- function ae(o) {
435
+ function re(o) {
426
436
  return {
427
437
  async fetch(a, t) {
428
- const e = new URL(a.url), n = G(e, t, o.defaultLocale);
438
+ const e = new URL(a.url), n = K(e, t, o.defaultLocale);
429
439
  if (n) return n;
430
- if (z.test(e.pathname))
440
+ if (M.test(e.pathname))
431
441
  return t.ASSETS.fetch(a);
432
- const s = F(a, o), r = new URL("/index.html", a.url);
433
- let u = await (await t.ASSETS.fetch(new Request(r))).text();
434
- const f = o.defaultLocale, [d, y] = await Promise.all([
442
+ const s = U(a, o), r = new URL("/index.html", a.url);
443
+ let c = await (await t.ASSETS.fetch(new Request(r))).text();
444
+ const p = o.defaultLocale, [m, g] = await Promise.all([
435
445
  t.SITE_CONTENT.get("config"),
436
446
  t.SITE_CONTENT.get(`content:${s}`)
437
- ]), T = d ? JSON.parse(d) : {};
438
- let m = y ? JSON.parse(y) : {};
439
- if (!y && s !== f) {
440
- const p = await t.SITE_CONTENT.get(`content:${f}`);
441
- p && (m = JSON.parse(p));
447
+ ]), b = m ? JSON.parse(m) : {};
448
+ let y = g ? JSON.parse(g) : {};
449
+ if (!g && s !== p) {
450
+ const f = await t.SITE_CONTENT.get(`content:${p}`);
451
+ f && (y = JSON.parse(f));
442
452
  }
443
453
  const h = e.pathname.match(/^\/p\/(.+)$/);
444
454
  if (h) {
445
- const p = h[1];
446
- if (!m[p]) {
447
- let g = await t.SITE_CONTENT.get(`page:${p}:${s}`);
448
- !g && s !== f && (g = await t.SITE_CONTENT.get(`page:${p}:${f}`)), g && (m[p] = JSON.parse(g));
455
+ const f = h[1];
456
+ if (!y[f]) {
457
+ let d = await t.SITE_CONTENT.get(`page:${f}:${s}`);
458
+ !d && s !== p && (d = await t.SITE_CONTENT.get(`page:${f}:${p}`)), d && (y[f] = JSON.parse(d));
449
459
  }
450
460
  }
451
- const l = {
461
+ const v = {
452
462
  locale: s,
453
- config: T
463
+ config: b
454
464
  };
455
- for (const [p, g] of Object.entries(m))
456
- l[`page:${p}`] = g;
465
+ for (const [f, d] of Object.entries(y))
466
+ v[`page:${f}`] = d;
457
467
  if (h) {
458
- const p = h[1], g = l[`page:${p}`];
459
- g && (u = k(u, g, o.siteName));
468
+ const f = h[1], d = v[`page:${f}`];
469
+ d && (c = x(c, d, o.siteName));
460
470
  }
461
- e.pathname === "/" && m.home && (u = k(u, m.home, o.siteName));
462
- const v = `<script>window.__SITE_DATA__ = ${JSON.stringify(l)};<\/script>`;
463
- return u = u.replace("</head>", `${v}
464
- </head>`), new Response(u, {
471
+ e.pathname === "/" && y.home && (c = x(c, y.home, o.siteName));
472
+ const l = `<script>window.__SITE_DATA__ = ${JSON.stringify(v)};<\/script>`;
473
+ return c = c.replace("</head>", `${l}
474
+ </head>`), new Response(c, {
465
475
  headers: {
466
476
  "Content-Type": "text/html;charset=utf-8",
467
477
  "Cache-Control": "public, max-age=60"
@@ -471,20 +481,20 @@ function ae(o) {
471
481
  };
472
482
  }
473
483
  export {
474
- I as PAGE_CONTEXT_KEY,
475
- O as buildLayoutCSS,
476
- ae as createSiteWorker,
477
- x as isInPreview,
478
- te as layoutPresets,
479
- ee as layoutSchema,
480
- Z as setupPreviewRouter,
481
- V as useDynamicLayout,
482
- A as useLivePreview,
483
- Q as useLocaleSwitcher,
484
- q as usePageData,
485
- X as useSiteApi,
486
- H as useSiteComponents,
487
- B as useSiteConfig,
488
- J as useSiteData,
489
- Y as useSkin
484
+ R as PAGE_CONTEXT_KEY,
485
+ G as buildLayoutCSS,
486
+ re as createSiteWorker,
487
+ A as isInPreview,
488
+ se as layoutPresets,
489
+ ne as layoutSchema,
490
+ V as setupPreviewRouter,
491
+ oe as useDynamicLayout,
492
+ C as useLivePreview,
493
+ ae as useLocaleSwitcher,
494
+ ee as usePageData,
495
+ Q as useSiteApi,
496
+ te as useSiteComponents,
497
+ q as useSiteConfig,
498
+ Z as useSiteData,
499
+ H as useSkin
490
500
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xosen/site-sdk",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "description": "Shared Vue components and composables for Xosen site templates",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,24 @@
1
+ import { reactive } from 'vue';
2
+
3
+ /**
4
+ * Shared reactive store for page data loaded via usePageData.
5
+ * Allows useDynamicLayout to reactively read layout from fetched pages.
6
+ */
7
+ export const pageDataStore = reactive<Record<string, any>>({});
8
+
9
+ /**
10
+ * Initialize store with preloaded data from __SITE_DATA__.
11
+ */
12
+ export function initPageDataStore() {
13
+ const siteData = (window as any).__SITE_DATA__;
14
+ if (!siteData) return;
15
+
16
+ for (const key of Object.keys(siteData)) {
17
+ if (key.startsWith('page:')) {
18
+ pageDataStore[key] = siteData[key];
19
+ }
20
+ }
21
+ }
22
+
23
+ // Auto-init on import
24
+ initPageDataStore();
@@ -1,9 +1,10 @@
1
- import { computed, type Ref } from 'vue';
1
+ import { computed } from 'vue';
2
2
  import { useRoute } from 'vue-router';
3
3
 
4
4
  import type { SiteData } from '../types/config.js';
5
5
  import type { GridBreakpoint, LayoutConfig } from '../types/layout.js';
6
6
  import { useLivePreview } from './useLivePreview.js';
7
+ import { pageDataStore } from './pageDataStore.js';
7
8
 
8
9
  const BREAKPOINTS: Record<string, number> = {
9
10
  sm: 600,
@@ -102,7 +103,8 @@ export function useDynamicLayout() {
102
103
  return previewPage.value.layout;
103
104
  }
104
105
  const pageKey = route.path === '/' ? 'page:home' : `page:${route.params.slug || ''}`;
105
- const pageData = siteData?.[pageKey];
106
+ // Read from reactive store (updated by usePageData on fetch)
107
+ const pageData = pageDataStore[pageKey] || siteData?.[pageKey];
106
108
  return pageData?.layout || 'default';
107
109
  });
108
110
 
@@ -5,6 +5,7 @@ import type { Block } from '../types/blocks.js';
5
5
  import type { PageConfig, PageContext, SiteData } from '../types/config.js';
6
6
  import { PAGE_CONTEXT_KEY } from '../types/config.js';
7
7
  import { useLivePreview } from './useLivePreview.js';
8
+ import { pageDataStore } from './pageDataStore.js';
8
9
 
9
10
  export interface UsePageDataReturn {
10
11
  /** Resolved page data (from preload, API, or preview) */
@@ -46,7 +47,7 @@ export function usePageData(slug: Ref<string> | string): UsePageDataReturn {
46
47
  const pageContext = computed<PageContext>(() => {
47
48
  const p = isPreviewMode.value ? previewPage.value : page.value;
48
49
  if (!p) return {};
49
- const { blocks, meta, slug: _s, locale: _l, ...rest } = p as any;
50
+ const { blocks: _blocks, meta: _meta, slug: _s, locale: _l, ...rest } = p as any;
50
51
  return rest;
51
52
  });
52
53
 
@@ -61,10 +62,17 @@ export function usePageData(slug: Ref<string> | string): UsePageDataReturn {
61
62
  return page.value?.blocks || [];
62
63
  });
63
64
 
65
+ function setPage(data: PageConfig | null) {
66
+ page.value = data;
67
+ if (data) {
68
+ pageDataStore[pageKey.value] = data;
69
+ }
70
+ }
71
+
64
72
  function loadFromPreloaded(): boolean {
65
73
  const preloaded = siteData?.[pageKey.value];
66
74
  if (preloaded && locale.value === siteData?.locale) {
67
- page.value = preloaded as PageConfig;
75
+ setPage(preloaded as PageConfig);
68
76
  notFound.value = false;
69
77
  applyMeta();
70
78
  return true;
@@ -78,14 +86,14 @@ export function usePageData(slug: Ref<string> | string): UsePageDataReturn {
78
86
  try {
79
87
  const res = await fetch(`/api/content/${pageKey.value}:${locale.value}`);
80
88
  if (res.ok) {
81
- page.value = await res.json();
89
+ setPage(await res.json());
82
90
  applyMeta();
83
91
  } else {
84
- page.value = null;
92
+ setPage(null);
85
93
  notFound.value = true;
86
94
  }
87
95
  } catch {
88
- page.value = null;
96
+ setPage(null);
89
97
  notFound.value = true;
90
98
  } finally {
91
99
  loading.value = false;