@bagelink/blox 1.15.178 → 1.15.180

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 (67) hide show
  1. package/dist/{PreviewApp-B8EmNfyH.cjs → PreviewApp-APyemzqx.cjs} +1 -1
  2. package/dist/{PreviewApp-DdkAQqw2.js → PreviewApp-BKTydm92.js} +1 -1
  3. package/dist/{PreviewApp.vue_vue_type_style_index_0_lang-CPBuld3j.cjs → PreviewApp.vue_vue_type_style_index_0_lang-C0ZVst7R.cjs} +6 -6
  4. package/dist/{PreviewApp.vue_vue_type_style_index_0_lang-1JKQVLm2.js → PreviewApp.vue_vue_type_style_index_0_lang-DHb-NJ4C.js} +1 -1
  5. package/dist/api/index.d.ts +22 -0
  6. package/dist/api/index.d.ts.map +1 -1
  7. package/dist/components/BloxRouterView.vue.d.ts +26 -15
  8. package/dist/components/BloxRouterView.vue.d.ts.map +1 -1
  9. package/dist/composables/useLocale.d.ts +7 -0
  10. package/dist/composables/useLocale.d.ts.map +1 -1
  11. package/dist/composables/useLocaleNav.d.ts +2 -2
  12. package/dist/composables/useLocaleNav.d.ts.map +1 -1
  13. package/dist/content/{ContentDetailHost.vue.d.ts → ContentDetailView.vue.d.ts} +1 -1
  14. package/dist/content/ContentDetailView.vue.d.ts.map +1 -0
  15. package/dist/content/ContentHost.vue.d.ts +3 -0
  16. package/dist/content/ContentHost.vue.d.ts.map +1 -0
  17. package/dist/content/index.d.ts +9 -0
  18. package/dist/content/index.d.ts.map +1 -0
  19. package/dist/content/registry.d.ts +73 -0
  20. package/dist/content/registry.d.ts.map +1 -0
  21. package/dist/content/routes.d.ts +48 -0
  22. package/dist/content/routes.d.ts.map +1 -0
  23. package/dist/content/useContentItem.d.ts +37 -5
  24. package/dist/content/useContentItem.d.ts.map +1 -1
  25. package/dist/content/useContentSeo.d.ts +20 -7
  26. package/dist/content/useContentSeo.d.ts.map +1 -1
  27. package/dist/core.d.ts +3 -1
  28. package/dist/core.d.ts.map +1 -1
  29. package/dist/createBloxApp.d.ts.map +1 -1
  30. package/dist/data/useData.d.ts +91 -0
  31. package/dist/data/useData.d.ts.map +1 -0
  32. package/dist/index.cjs +185 -138
  33. package/dist/index.d.ts +7 -13
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.mjs +177 -131
  36. package/dist/localeRoutes.d.ts +15 -0
  37. package/dist/localeRoutes.d.ts.map +1 -0
  38. package/dist/localeStrategy.d.ts +13 -0
  39. package/dist/localeStrategy.d.ts.map +1 -1
  40. package/dist/{prerender-NHAqrTm3.js → prerender-DB1R4jiQ.js} +10 -9
  41. package/dist/{prerender-H72-UrK4.cjs → prerender-DXGy7pee.cjs} +10 -9
  42. package/dist/{core-KRHc4Bob.cjs → routes-C97aL4cQ.cjs} +415 -220
  43. package/dist/{core-Bp2bf8e4.js → routes-bhjTTXfU.js} +444 -249
  44. package/dist/ssg/cli.cjs +1 -1
  45. package/dist/ssg/cli.mjs +1 -1
  46. package/dist/ssg/createSSREntry.d.ts.map +1 -1
  47. package/dist/ssg/index.cjs +28 -19
  48. package/dist/ssg/index.mjs +31 -22
  49. package/dist/ssg/render-resolved-page.d.ts +6 -0
  50. package/dist/ssg/render-resolved-page.d.ts.map +1 -1
  51. package/dist/ssg/seo.d.ts +9 -3
  52. package/dist/ssg/seo.d.ts.map +1 -1
  53. package/dist/vite-plugin.cjs +2 -2
  54. package/dist/vite-plugin.d.ts.map +1 -1
  55. package/dist/vite-plugin.mjs +2 -2
  56. package/package.json +1 -1
  57. package/dist/components/LocaleRouterLink.vue.d.ts +0 -28
  58. package/dist/components/LocaleRouterLink.vue.d.ts.map +0 -1
  59. package/dist/composables/useData.d.ts +0 -22
  60. package/dist/composables/useData.d.ts.map +0 -1
  61. package/dist/composables/useSeo.d.ts +0 -20
  62. package/dist/composables/useSeo.d.ts.map +0 -1
  63. package/dist/content/ContentDetailHost.vue.d.ts.map +0 -1
  64. package/dist/content/defineContent.d.ts +0 -22
  65. package/dist/content/defineContent.d.ts.map +0 -1
  66. package/dist/routing/withLocaleRoutes.d.ts +0 -8
  67. package/dist/routing/withLocaleRoutes.d.ts.map +0 -1
@@ -1,21 +1,32 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- import { BLOX_WEBSITE_ID_WINDOW_KEY, BLOX_STATE_WINDOW_KEY, BLOX_DATA_WINDOW_KEY } from "./ssg/client.mjs";
5
- import { inject, computed, ref, defineComponent, onMounted, unref, openBlock, createBlock, Teleport, createElementBlock, createElementVNode, createCommentVNode, onUnmounted, watch, h, provide, resolveComponent, createVNode, toDisplayString, withCtx, createTextVNode, Fragment, onServerPrefetch, toValue, useAttrs, mergeProps, renderSlot, normalizeProps, resolveDynamicComponent } from "vue";
6
- import { useRoute, useRouter, RouterLink } from "vue-router";
4
+ import { inject, computed, ref, defineComponent, onMounted, unref, openBlock, createBlock, Teleport, createElementBlock, createElementVNode, createCommentVNode, onUnmounted, watch, h, provide, resolveComponent, createVNode, toDisplayString, withCtx, createTextVNode, Fragment, getCurrentInstance, shallowRef, onServerPrefetch, toValue, markRaw, resolveDynamicComponent } from "vue";
5
+ import { useRoute, useRouter } from "vue-router";
6
+ import { BLOX_WEBSITE_ID_WINDOW_KEY, BLOX_STATE_WINDOW_KEY } from "./ssg/client.mjs";
7
7
  import { getI18n, Loading } from "@bagelink/vue";
8
- const BASE = "/api";
8
+ let BASE = "/api";
9
9
  let _websiteName = "";
10
10
  let _store = "";
11
11
  let _websiteId = null;
12
+ let _origin = "";
12
13
  function configureApi(websiteName, store) {
13
14
  _websiteName = websiteName;
14
15
  _store = store;
15
16
  _websiteId = null;
16
17
  }
18
+ function setApiOrigin(base) {
19
+ if (!base) return;
20
+ try {
21
+ const u = new URL(base);
22
+ _origin = u.origin;
23
+ BASE = u.pathname && u.pathname !== "/" ? u.pathname.replace(/\/$/, "") : "";
24
+ } catch {
25
+ }
26
+ }
17
27
  async function request(path, { locale: locale2, params, ...opts } = {}) {
18
- const url = new URL(`${BASE}${path}`, window.location.origin);
28
+ const origin = _origin || (typeof window !== "undefined" ? window.location.origin : "");
29
+ const url = new URL(`${BASE}${path}`, origin || void 0);
19
30
  if (locale2) url.searchParams.set("locale", locale2);
20
31
  if (params) {
21
32
  for (const [k, v] of Object.entries(params)) url.searchParams.set(k, String(v));
@@ -61,6 +72,16 @@ async function listItems(collection, { locale: locale2, q, offset = 0, limit = 1
61
72
  params: { ...q ? { q } : {}, offset, limit }
62
73
  });
63
74
  }
75
+ async function getItemBySlug(collection, slug, locale2) {
76
+ const res = await listItems(collection, { locale: locale2, q: `slug eq "${slug}"`, limit: 1 });
77
+ const items = Array.isArray(res) ? res : (res == null ? void 0 : res.items) ?? [];
78
+ return items[0] ?? null;
79
+ }
80
+ async function getItemById(collection, id, locale2) {
81
+ const res = await listItems(collection, { locale: locale2, q: `id eq "${id}"`, limit: 1 });
82
+ const items = Array.isArray(res) ? res : (res == null ? void 0 : res.items) ?? [];
83
+ return items[0] ?? null;
84
+ }
64
85
  const BLOX_REGISTRY_KEY = Symbol("blox:registry");
65
86
  const BLOX_CONFIG_KEY = Symbol("blox:config");
66
87
  const BLOX_LOCALE_STRATEGY_KEY = Symbol("blox:locale-strategy");
@@ -115,7 +136,7 @@ function useBloxEdit(configOverride) {
115
136
  }
116
137
  return { config, enabled, showEdit, studioBaseUrl, editUrl, enable, dismiss, init };
117
138
  }
118
- const _hoisted_1$3 = {
139
+ const _hoisted_1$2 = {
119
140
  key: 0,
120
141
  class: "blox-admin-bar"
121
142
  };
@@ -138,7 +159,7 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
138
159
  key: 0,
139
160
  to: "body"
140
161
  }, [
141
- unref(showEdit) && __props.websiteId && __props.pageId ? (openBlock(), createElementBlock("div", _hoisted_1$3, [
162
+ unref(showEdit) && __props.websiteId && __props.pageId ? (openBlock(), createElementBlock("div", _hoisted_1$2, [
142
163
  createElementVNode("button", {
143
164
  type: "button",
144
165
  class: "blox-admin-btn",
@@ -159,15 +180,26 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
159
180
  };
160
181
  }
161
182
  });
162
- const locale = ref(localStorage.getItem("blox:locale") || "en");
183
+ const _hasStorage = typeof localStorage !== "undefined";
184
+ const locale = ref((_hasStorage ? localStorage.getItem("blox:locale") : null) || "en");
163
185
  const currentAlternates = ref({});
186
+ function setActiveLocale(l) {
187
+ locale.value = l;
188
+ try {
189
+ const i18n = getI18n();
190
+ if (i18n == null ? void 0 : i18n.global) i18n.global.locale.value = l;
191
+ } catch {
192
+ }
193
+ }
164
194
  function useLocale() {
165
195
  const dir = computed(() => locale.value === "he" || locale.value === "ar" ? "rtl" : "ltr");
166
196
  function setLocale(l) {
167
197
  locale.value = l;
168
- localStorage.setItem("blox:locale", l);
169
- document.documentElement.lang = l;
170
- document.documentElement.dir = dir.value;
198
+ if (typeof localStorage !== "undefined") localStorage.setItem("blox:locale", l);
199
+ if (typeof document !== "undefined") {
200
+ document.documentElement.lang = l;
201
+ document.documentElement.dir = dir.value;
202
+ }
171
203
  try {
172
204
  const i18n = getI18n();
173
205
  if (i18n == null ? void 0 : i18n.global) i18n.global.locale.value = l;
@@ -283,7 +315,7 @@ const PageRenderer = defineComponent({
283
315
  );
284
316
  }
285
317
  });
286
- const _hoisted_1$2 = {
318
+ const _hoisted_1$1 = {
287
319
  key: 0,
288
320
  class: "blox-loading flex column h-100vh justify-content-center"
289
321
  };
@@ -291,11 +323,11 @@ const _hoisted_2$1 = {
291
323
  key: 1,
292
324
  class: "blox-not-found"
293
325
  };
294
- const _hoisted_3 = {
326
+ const _hoisted_3$1 = {
295
327
  key: 2,
296
328
  class: "blox-error color-red"
297
329
  };
298
- const _hoisted_4 = {
330
+ const _hoisted_4$1 = {
299
331
  key: 0,
300
332
  class: "blox-nav-progress"
301
333
  };
@@ -399,7 +431,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
399
431
  return (_ctx, _cache) => {
400
432
  const _component_RouterLink = resolveComponent("RouterLink");
401
433
  return openBlock(), createElementBlock("div", null, [
402
- initialLoading.value && blocks.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_1$2, [
434
+ initialLoading.value && blocks.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_1$1, [
403
435
  createVNode(unref(Loading))
404
436
  ])) : notFound.value ? (openBlock(), createElementBlock("div", _hoisted_2$1, [
405
437
  _cache[0] || (_cache[0] = createElementVNode("h2", null, "404", -1)),
@@ -410,8 +442,8 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
410
442
  ]),
411
443
  _: 1
412
444
  })
413
- ])) : error.value ? (openBlock(), createElementBlock("div", _hoisted_3, toDisplayString(error.value), 1)) : (openBlock(), createElementBlock(Fragment, { key: 3 }, [
414
- navigating.value ? (openBlock(), createElementBlock("div", _hoisted_4)) : createCommentVNode("", true),
445
+ ])) : error.value ? (openBlock(), createElementBlock("div", _hoisted_3$1, toDisplayString(error.value), 1)) : (openBlock(), createElementBlock(Fragment, { key: 3 }, [
446
+ navigating.value ? (openBlock(), createElementBlock("div", _hoisted_4$1)) : createCommentVNode("", true),
415
447
  createVNode(unref(PageRenderer), { blocks: blocks.value }, null, 8, ["blocks"])
416
448
  ], 64)),
417
449
  unref(adminConfig) ? (openBlock(), createBlock(_sfc_main$3, {
@@ -423,6 +455,111 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
423
455
  };
424
456
  }
425
457
  });
458
+ const BLOX_DATA_WINDOW_KEY = "__BLOX_DATA__";
459
+ const BLOX_DATA_KEY = Symbol("blox-data");
460
+ function provideBloxData(app, opts = {}) {
461
+ const isServer = opts.server ?? false;
462
+ const payload = isServer ? null : readPayload();
463
+ const registry2 = { ssr: /* @__PURE__ */ new Map(), payload, isServer, seo: {}, seoSources: [] };
464
+ app.provide(BLOX_DATA_KEY, registry2);
465
+ globalThis.__BLOX_DATA_REGISTRY__ = registry2;
466
+ return registry2;
467
+ }
468
+ function readPayload() {
469
+ if (typeof window === "undefined") return null;
470
+ const raw = window[BLOX_DATA_WINDOW_KEY];
471
+ if (raw && typeof raw === "object" && !Array.isArray(raw)) {
472
+ return raw;
473
+ }
474
+ return null;
475
+ }
476
+ function getRegistry() {
477
+ if (getCurrentInstance()) {
478
+ const injected = inject(BLOX_DATA_KEY, null);
479
+ if (injected) return injected;
480
+ }
481
+ return globalThis.__BLOX_DATA_REGISTRY__ ?? null;
482
+ }
483
+ function getRegistryData() {
484
+ return getRegistry();
485
+ }
486
+ function collectBloxData(registry2) {
487
+ return Object.fromEntries(registry2.ssr);
488
+ }
489
+ function useSeo(source) {
490
+ const registry2 = getRegistry();
491
+ if (registry2 == null ? void 0 : registry2.isServer) {
492
+ registry2.seoSources.push(source);
493
+ return;
494
+ }
495
+ if (getCurrentInstance()) {
496
+ watch(source, (v) => {
497
+ if ((v == null ? void 0 : v.title) && typeof document !== "undefined") document.title = v.title;
498
+ }, { immediate: true });
499
+ }
500
+ }
501
+ function collectBloxSeo(registry2) {
502
+ for (const source of registry2.seoSources) {
503
+ const v = source();
504
+ if (!v) continue;
505
+ if (v.title) registry2.seo.title = v.title;
506
+ if (v.description) registry2.seo.description = v.description;
507
+ if (v.image) registry2.seo.image = v.image;
508
+ if (v.alternates && Object.keys(v.alternates).length) registry2.seo.alternates = v.alternates;
509
+ }
510
+ return registry2.seo;
511
+ }
512
+ function useData(key, fetcher, options) {
513
+ const registry2 = getRegistry();
514
+ const data = shallowRef(options.default);
515
+ const pending = ref(false);
516
+ const error = ref(null);
517
+ const currentKey = () => toValue(key);
518
+ const initialKey = currentKey();
519
+ if ((registry2 == null ? void 0 : registry2.payload) && initialKey in registry2.payload) {
520
+ data.value = registry2.payload[initialKey];
521
+ watchKey(initialKey);
522
+ return { data, pending, error, refresh };
523
+ }
524
+ if ((registry2 == null ? void 0 : registry2.isServer) && options.server !== false) {
525
+ onServerPrefetch(async () => {
526
+ try {
527
+ const value = await fetcher();
528
+ data.value = value;
529
+ registry2.ssr.set(currentKey(), value);
530
+ } catch (e) {
531
+ error.value = e;
532
+ registry2.ssr.set(currentKey(), options.default);
533
+ }
534
+ });
535
+ return { data, pending, error, refresh };
536
+ }
537
+ void refresh();
538
+ watchKey(null);
539
+ return { data, pending, error, refresh };
540
+ function watchKey(skipInitial) {
541
+ if ((registry2 == null ? void 0 : registry2.isServer) || !getCurrentInstance()) return;
542
+ watch(currentKey, (k) => {
543
+ if (k === skipInitial) return;
544
+ if ((registry2 == null ? void 0 : registry2.payload) && k in registry2.payload) {
545
+ data.value = registry2.payload[k];
546
+ return;
547
+ }
548
+ void refresh();
549
+ });
550
+ }
551
+ async function refresh() {
552
+ pending.value = true;
553
+ error.value = null;
554
+ try {
555
+ data.value = await fetcher();
556
+ } catch (e) {
557
+ error.value = e;
558
+ } finally {
559
+ pending.value = false;
560
+ }
561
+ }
562
+ }
426
563
  function normalizeLink(href) {
427
564
  const v = href == null ? void 0 : href.trim();
428
565
  if (!v) return void 0;
@@ -509,198 +646,6 @@ function installSmartLinks(router) {
509
646
  document.addEventListener("click", onClick);
510
647
  return () => document.removeEventListener("click", onClick);
511
648
  }
512
- function isServer() {
513
- try {
514
- if (false) ;
515
- } catch {
516
- }
517
- return typeof window === "undefined";
518
- }
519
- function readPayload() {
520
- const root = typeof window !== "undefined" ? window : globalThis;
521
- const existing = root[BLOX_DATA_WINDOW_KEY];
522
- if (existing && typeof existing === "object" && !Array.isArray(existing)) {
523
- return existing;
524
- }
525
- const fresh = {};
526
- root[BLOX_DATA_WINDOW_KEY] = fresh;
527
- return fresh;
528
- }
529
- function resolveDefault(opts) {
530
- if (typeof opts.default === "function") return opts.default();
531
- return opts.default;
532
- }
533
- function useData(key, handler, opts = {}) {
534
- const data = ref(resolveDefault(opts));
535
- const pending = ref(false);
536
- const error = ref(null);
537
- async function refresh() {
538
- const k = toValue(key);
539
- pending.value = true;
540
- error.value = null;
541
- try {
542
- const result = await handler();
543
- data.value = result;
544
- readPayload()[k] = result;
545
- } catch (e) {
546
- error.value = e instanceof Error ? e : new Error(String(e));
547
- } finally {
548
- pending.value = false;
549
- }
550
- }
551
- function hydrateFromPayload() {
552
- const k = toValue(key);
553
- const payload = readPayload();
554
- if (!Object.prototype.hasOwnProperty.call(payload, k)) return false;
555
- data.value = payload[k];
556
- return true;
557
- }
558
- if (isServer()) {
559
- onServerPrefetch(() => refresh());
560
- } else if (!hydrateFromPayload()) {
561
- void refresh();
562
- }
563
- watch(() => toValue(key), () => {
564
- if (!hydrateFromPayload()) void refresh();
565
- });
566
- return { data, pending, error, refresh };
567
- }
568
- function withLocaleRoutes(path, component, locales, defaultLocale) {
569
- const normalized = path.startsWith("/") ? path : `/${path}`;
570
- const others = locales.filter((l) => l && l !== defaultLocale);
571
- const localePattern = others.join("|");
572
- const routes = [
573
- { path: normalized, component }
574
- ];
575
- if (localePattern) {
576
- routes.push({
577
- path: `/:locale(${localePattern})${normalized}`,
578
- component
579
- });
580
- }
581
- return routes;
582
- }
583
- const _hoisted_1$1 = ["href"];
584
- const _hoisted_2 = ["href"];
585
- const _sfc_main$1 = /* @__PURE__ */ defineComponent({
586
- ...{ inheritAttrs: false },
587
- __name: "LocaleRouterLink",
588
- props: {
589
- to: {},
590
- replace: { type: Boolean },
591
- activeClass: {},
592
- exactActiveClass: {},
593
- ariaCurrentValue: {}
594
- },
595
- setup(__props) {
596
- const props = __props;
597
- const attrs = useAttrs();
598
- const strategy = inject(BLOX_LOCALE_STRATEGY_KEY, null);
599
- const { locale: locale2 } = useLocale();
600
- const resolved = computed(() => {
601
- if (typeof props.to !== "string") {
602
- return { kind: "route", to: props.to };
603
- }
604
- const href = normalizeLink(props.to) ?? props.to.trim();
605
- const kind = classifyLink(href);
606
- if (kind === "external") return { kind: "external", href };
607
- if (kind === "special") return { kind: "special", href };
608
- const path = toInternalPath(href);
609
- const loc = String(locale2.value || "").slice(0, 2).toLowerCase();
610
- const to = strategy ? strategy.toPath(path, loc || void 0) : path;
611
- return { kind: "route", to };
612
- });
613
- return (_ctx, _cache) => {
614
- return resolved.value.kind === "external" ? (openBlock(), createElementBlock("a", mergeProps({ key: 0 }, unref(attrs), {
615
- href: resolved.value.href,
616
- target: "_blank",
617
- rel: "noopener noreferrer"
618
- }), [
619
- renderSlot(_ctx.$slots, "default")
620
- ], 16, _hoisted_1$1)) : resolved.value.kind === "special" ? (openBlock(), createElementBlock("a", mergeProps({ key: 1 }, unref(attrs), {
621
- href: resolved.value.href
622
- }), [
623
- renderSlot(_ctx.$slots, "default")
624
- ], 16, _hoisted_2)) : (openBlock(), createBlock(unref(RouterLink), normalizeProps(mergeProps({ key: 2 }, { ...props, ...unref(attrs), to: resolved.value.to })), {
625
- default: withCtx(() => [
626
- renderSlot(_ctx.$slots, "default")
627
- ]),
628
- _: 3
629
- }, 16));
630
- };
631
- }
632
- });
633
- const BLOX_CONTENT_ITEM_KEY = Symbol("blox-content-item");
634
- function useContentItem() {
635
- return inject(BLOX_CONTENT_ITEM_KEY, null) ?? ref(null);
636
- }
637
- const _hoisted_1 = {
638
- key: 1,
639
- class: "blox-content-detail"
640
- };
641
- const _sfc_main = /* @__PURE__ */ defineComponent({
642
- __name: "ContentDetailHost",
643
- setup(__props) {
644
- const route = useRoute();
645
- const { locale: locale2 } = useLocale();
646
- const def = computed(() => route.meta.contentDef);
647
- const slug = computed(() => String(route.params.slug ?? ""));
648
- const { data: item } = useData(
649
- () => {
650
- var _a;
651
- return `content:${((_a = def.value) == null ? void 0 : _a.collection) ?? ""}:${slug.value}:${locale2.value}`;
652
- },
653
- async () => {
654
- var _a, _b;
655
- const collection = (_a = def.value) == null ? void 0 : _a.collection;
656
- const s = slug.value;
657
- if (!collection || !s) return null;
658
- const escaped = s.replace(/"/g, '\\"');
659
- const page = await listItems(collection, {
660
- locale: locale2.value,
661
- q: `slug eq "${escaped}"`,
662
- limit: 1
663
- });
664
- return ((_b = page.items) == null ? void 0 : _b[0]) ?? null;
665
- },
666
- { default: null }
667
- );
668
- provide(BLOX_CONTENT_ITEM_KEY, item);
669
- const Detail = computed(() => {
670
- var _a;
671
- return (_a = def.value) == null ? void 0 : _a.component;
672
- });
673
- return (_ctx, _cache) => {
674
- return Detail.value ? (openBlock(), createBlock(resolveDynamicComponent(Detail.value), { key: 0 })) : unref(item) ? (openBlock(), createElementBlock("div", _hoisted_1, [
675
- createElementVNode("pre", null, toDisplayString(unref(item)), 1)
676
- ])) : createCommentVNode("", true);
677
- };
678
- }
679
- });
680
- const registry = [];
681
- function defineContent(defs) {
682
- registry.length = 0;
683
- registry.push(...defs);
684
- }
685
- function contentRoutes() {
686
- return registry;
687
- }
688
- function registerContentRoutesOnRouter(router, locales, defaultLocale) {
689
- for (const def of registry) {
690
- const routes = withLocaleRoutes(def.route, _sfc_main, locales, defaultLocale);
691
- routes.forEach((r, i) => {
692
- router.addRoute({
693
- ...r,
694
- // Only the default-locale path gets the stable name.
695
- name: i === 0 ? def.name : void 0,
696
- meta: {
697
- ...r.meta ?? {},
698
- contentDef: def
699
- }
700
- });
701
- });
702
- }
703
- }
704
649
  function createPathStrategy(options) {
705
650
  const { defaultLocale, supportedLocales } = options;
706
651
  let _currentLocale = defaultLocale;
@@ -730,10 +675,7 @@ function createPathStrategy(options) {
730
675
  },
731
676
  toPath(slug, locale2) {
732
677
  const loc = locale2 || _currentLocale;
733
- let s = slug || "/";
734
- if (s && !s.startsWith("/") && !/^(https?:|mailto:|tel:|sms:|whatsapp:|geo:|#|\/\/)/i.test(s)) {
735
- s = `/${s}`;
736
- }
678
+ let s = slug ? slug.startsWith("/") ? slug : `/${slug}` : "/";
737
679
  const segments = s.replace(/^\//, "").split("/").filter(Boolean);
738
680
  if (segments[0] && supportedLocales.includes(segments[0])) {
739
681
  const rest = segments.slice(1).join("/");
@@ -755,6 +697,18 @@ function createPathStrategy(options) {
755
697
  })();
756
698
  const target = locale2 === defaultLocale ? bare : bare === "/" ? `/${locale2}` : `/${locale2}${bare}`;
757
699
  router.push(target);
700
+ },
701
+ normalize(path, intendedLocale) {
702
+ const p = path || "/";
703
+ const [pathname, ...restQ] = p.split(/(?=[?#])/);
704
+ const suffix = restQ.join("");
705
+ const segments = (pathname || "/").replace(/^\//, "").split("/").filter(Boolean);
706
+ const first = segments[0];
707
+ if (first && supportedLocales.includes(first)) return null;
708
+ if (intendedLocale === defaultLocale) return null;
709
+ const bare = segments.length ? `/${segments.join("/")}` : "/";
710
+ const rebuilt = bare === "/" ? `/${intendedLocale}` : `/${intendedLocale}${bare}`;
711
+ return `${rebuilt}${suffix}`;
758
712
  }
759
713
  };
760
714
  }
@@ -789,6 +743,9 @@ function createDomainStrategy(options) {
789
743
  const { protocol } = window.location;
790
744
  const s = slug || "/";
791
745
  window.location.href = `${protocol}//${domain}${s}`;
746
+ },
747
+ normalize() {
748
+ return null;
792
749
  }
793
750
  };
794
751
  }
@@ -825,6 +782,10 @@ class BloxInstance {
825
782
  this._strategy = createLocaleStrategy(options ?? {});
826
783
  this._adminEdit = options == null ? void 0 : options.adminEdit;
827
784
  }
785
+ /** The active locale strategy (path/domain). Used by the nav guard. */
786
+ get strategy() {
787
+ return this._strategy;
788
+ }
828
789
  registerModules(modules) {
829
790
  const list = Array.isArray(modules) ? modules : Object.values(modules);
830
791
  for (const mod of list) {
@@ -898,14 +859,9 @@ class BloxInstance {
898
859
  }
899
860
  router.addRoute({
900
861
  path: "/_blox_preview",
901
- component: () => import("./PreviewApp-DdkAQqw2.js"),
862
+ component: () => import("./PreviewApp-BKTydm92.js"),
902
863
  beforeEnter: () => window.parent !== window ? true : "/"
903
864
  });
904
- registerContentRoutesOnRouter(
905
- router,
906
- this._config.supportedLocales,
907
- this._config.defaultLocale
908
- );
909
865
  router.addRoute({ path: "/:pathMatch(.*)*", component: _sfc_main$2 });
910
866
  this._routeRegistered = true;
911
867
  return this;
@@ -937,7 +893,6 @@ class BloxInstance {
937
893
  app.provide(BLOX_CONFIG_KEY, this._config);
938
894
  app.provide(BLOX_LOCALE_STRATEGY_KEY, this._strategy);
939
895
  if (this._adminEdit) app.provide(BLOX_ADMIN_CONFIG_KEY, this._adminEdit);
940
- app._context.components.RouterLink = _sfc_main$1;
941
896
  }
942
897
  }
943
898
  function isBlockDefinition(value) {
@@ -953,39 +908,279 @@ function createBlox(options) {
953
908
  if (options == null ? void 0 : options.router) instance.registerRoutes(options.router);
954
909
  return instance;
955
910
  }
911
+ const registry = /* @__PURE__ */ new Map();
912
+ function paramsOf(route) {
913
+ return [...route.matchAll(/:([A-Za-z0-9_]+)/g)].map((m) => m[1]);
914
+ }
915
+ function defineContent(inputs) {
916
+ for (const input of inputs) {
917
+ const params = paramsOf(input.route);
918
+ if (!params.includes("slug")) {
919
+ throw new Error(`[blox/content] route "${input.route}" for "${input.name}" must contain a :slug param`);
920
+ }
921
+ registry.set(input.name, {
922
+ name: input.name,
923
+ collection: input.collection,
924
+ route: input.route,
925
+ component: input.component,
926
+ view: input.view,
927
+ params
928
+ });
929
+ }
930
+ }
931
+ function contentRoutes() {
932
+ return [...registry.values()];
933
+ }
934
+ function getContentRoute(name) {
935
+ return registry.get(name);
936
+ }
937
+ function getContentRouteByCollection(collection) {
938
+ for (const r of registry.values()) if (r.collection === collection) return r;
939
+ return void 0;
940
+ }
941
+ const CONTENT_ITEM_CTX = Symbol("blox:content-item-ctx");
942
+ function useContentItem(collectionArg, slugArg) {
943
+ const { locale: locale2 } = useLocale();
944
+ const ctx = inject(CONTENT_ITEM_CTX, null);
945
+ const route = safeRoute();
946
+ const coll = () => {
947
+ var _a, _b;
948
+ if (collectionArg != null) return String(toValue(collectionArg) || "");
949
+ if (ctx) return String(toValue(ctx.collection) || "");
950
+ const name = (_a = route == null ? void 0 : route.meta) == null ? void 0 : _a.content;
951
+ return name ? ((_b = getContentRoute(name)) == null ? void 0 : _b.collection) ?? "" : "";
952
+ };
953
+ const slg = () => {
954
+ var _a;
955
+ if (slugArg != null) return String(toValue(slugArg) || "");
956
+ if (ctx) return String(toValue(ctx.slug) || "");
957
+ return String(((_a = route == null ? void 0 : route.params) == null ? void 0 : _a.slug) ?? "");
958
+ };
959
+ const loc = () => String(locale2.value || "en").slice(0, 2).toLowerCase();
960
+ const { data } = useData(
961
+ () => `content:${coll()}:${slg()}:${loc()}`,
962
+ async () => {
963
+ const c = coll();
964
+ const s = slg();
965
+ if (!c || !s) return null;
966
+ const res = await listItems(c, { locale: loc(), limit: 1e3 });
967
+ const items = Array.isArray(res) ? res : (res == null ? void 0 : res.items) ?? [];
968
+ return items.find((it) => String((it == null ? void 0 : it.slug) ?? "") === s) ?? null;
969
+ },
970
+ { default: null }
971
+ );
972
+ return data;
973
+ }
974
+ function provideContentItem(collection, slug) {
975
+ provide(CONTENT_ITEM_CTX, { collection, slug });
976
+ }
977
+ function safeRoute() {
978
+ try {
979
+ return useRoute();
980
+ } catch {
981
+ return null;
982
+ }
983
+ }
984
+ const _hoisted_1 = {
985
+ key: 0,
986
+ class: "blox-content-detail"
987
+ };
988
+ const _hoisted_2 = ["src", "alt"];
989
+ const _hoisted_3 = {
990
+ key: 1,
991
+ class: "blox-content-detail__title"
992
+ };
993
+ const _hoisted_4 = ["innerHTML"];
994
+ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
995
+ __name: "ContentDetailView",
996
+ setup(__props) {
997
+ const route = useRoute();
998
+ const item = useContentItem();
999
+ const schema = computed(() => {
1000
+ var _a, _b;
1001
+ const name = (_a = route.meta) == null ? void 0 : _a.content;
1002
+ return (name ? (_b = getContentRoute(name)) == null ? void 0 : _b.view : void 0) ?? {};
1003
+ });
1004
+ function field(key) {
1005
+ if (!key || !item.value) return "";
1006
+ return String(item.value[key] ?? "");
1007
+ }
1008
+ const title = computed(() => field(schema.value.title));
1009
+ const body = computed(() => field(schema.value.body));
1010
+ const description = computed(() => {
1011
+ const raw = field(schema.value.description) || body.value;
1012
+ return raw.replace(/<[^>]*>/g, "").replace(/\s+/g, " ").trim().slice(0, 160);
1013
+ });
1014
+ const image = computed(() => {
1015
+ var _a;
1016
+ const v = schema.value.image ? (_a = item.value) == null ? void 0 : _a[schema.value.image] : void 0;
1017
+ if (!v) return "";
1018
+ return typeof v === "object" ? v.imageURL ?? "" : String(v);
1019
+ });
1020
+ useSeo(() => {
1021
+ if (!item.value) return null;
1022
+ return { title: title.value, description: description.value, image: image.value };
1023
+ });
1024
+ return (_ctx, _cache) => {
1025
+ return unref(item) ? (openBlock(), createElementBlock("article", _hoisted_1, [
1026
+ image.value ? (openBlock(), createElementBlock("img", {
1027
+ key: 0,
1028
+ class: "blox-content-detail__image",
1029
+ src: image.value,
1030
+ alt: title.value
1031
+ }, null, 8, _hoisted_2)) : createCommentVNode("", true),
1032
+ title.value ? (openBlock(), createElementBlock("h1", _hoisted_3, toDisplayString(title.value), 1)) : createCommentVNode("", true),
1033
+ body.value ? (openBlock(), createElementBlock("div", {
1034
+ key: 2,
1035
+ class: "blox-content-detail__body",
1036
+ innerHTML: body.value
1037
+ }, null, 8, _hoisted_4)) : createCommentVNode("", true)
1038
+ ])) : createCommentVNode("", true);
1039
+ };
1040
+ }
1041
+ });
1042
+ const _sfc_main = /* @__PURE__ */ defineComponent({
1043
+ __name: "ContentHost",
1044
+ setup(__props) {
1045
+ var _a;
1046
+ const route = useRoute();
1047
+ const name = (_a = route.meta) == null ? void 0 : _a.content;
1048
+ const registration = name ? getContentRoute(name) : void 0;
1049
+ const component = markRaw((registration == null ? void 0 : registration.component) ?? _sfc_main$1);
1050
+ provideContentItem(
1051
+ () => (registration == null ? void 0 : registration.collection) ?? "",
1052
+ () => String(route.params.slug ?? "")
1053
+ );
1054
+ return (_ctx, _cache) => {
1055
+ return openBlock(), createBlock(resolveDynamicComponent(unref(component)), {
1056
+ key: unref(route).fullPath
1057
+ });
1058
+ };
1059
+ }
1060
+ });
1061
+ function generateContentRoutes(supportedLocales, defaultLocale) {
1062
+ const records = [];
1063
+ for (const route of contentRoutes()) {
1064
+ const bare = route.route.startsWith("/") ? route.route : `/${route.route}`;
1065
+ records.push({
1066
+ path: bare,
1067
+ name: route.name,
1068
+ component: _sfc_main,
1069
+ meta: { content: route.name }
1070
+ });
1071
+ for (const loc of supportedLocales) {
1072
+ if (loc === defaultLocale) continue;
1073
+ records.push({
1074
+ path: `/${loc}${bare}`,
1075
+ name: `${route.name}:${loc}`,
1076
+ component: _sfc_main,
1077
+ meta: { content: route.name }
1078
+ });
1079
+ }
1080
+ }
1081
+ return records;
1082
+ }
1083
+ function installLocaleAwareResolve(router, strategy) {
1084
+ const { locale: locale2 } = useLocale();
1085
+ const supported = strategy.locales;
1086
+ const defaultLocale = strategy.defaultLocale;
1087
+ const activeLocale = () => String(locale2.value || "").slice(0, 2).toLowerCase() || defaultLocale;
1088
+ const originalResolve = router.resolve.bind(router);
1089
+ router.resolve = (to, currentLocation) => {
1090
+ if (typeof to === "string") {
1091
+ const href = normalizeLink(to) ?? to;
1092
+ if (classifyLink(href) === "internal") {
1093
+ to = strategy.toPath(href, activeLocale());
1094
+ }
1095
+ } else if (to && typeof to === "object" && typeof to.name === "string") {
1096
+ const base = to.name.split(":")[0];
1097
+ if (getContentRoute(base) && supported.length) {
1098
+ const loc = activeLocale();
1099
+ const name = loc && loc !== defaultLocale ? `${base}:${loc}` : base;
1100
+ if (router.hasRoute(name)) to = { ...to, name };
1101
+ }
1102
+ }
1103
+ return originalResolve(to, currentLocation);
1104
+ };
1105
+ }
1106
+ function installContentFallback(router, supportedLocales, defaultLocale) {
1107
+ const localeOf = (path) => {
1108
+ const first = path.replace(/^\//, "").split("/")[0];
1109
+ return first && supportedLocales.includes(first) ? first : defaultLocale;
1110
+ };
1111
+ router.beforeResolve(async (to) => {
1112
+ var _a;
1113
+ const name = (_a = to.meta) == null ? void 0 : _a.content;
1114
+ if (!name) return true;
1115
+ const registration = getContentRoute(name);
1116
+ if (!registration) return true;
1117
+ const slug = String(to.params.slug ?? "");
1118
+ if (!slug) return true;
1119
+ const urlLocale = localeOf(to.path);
1120
+ const here = await getItemBySlug(registration.collection, slug, urlLocale).catch(() => null);
1121
+ if (here) return true;
1122
+ const probe = await getItemBySlug(registration.collection, slug).catch(() => null);
1123
+ const available = Array.isArray(probe == null ? void 0 : probe.available_locales) ? probe.available_locales : [];
1124
+ const target = [defaultLocale, ...supportedLocales].find(
1125
+ (l) => l !== urlLocale && available.includes(l)
1126
+ );
1127
+ if (!target || !probe) return true;
1128
+ const targetItem = await getItemBySlug(registration.collection, slug, target).catch(() => null);
1129
+ const targetSlug = String((targetItem == null ? void 0 : targetItem.slug) ?? slug);
1130
+ const barePath = registration.route.replace(/:slug(?=\/|$)/, targetSlug);
1131
+ const redirect = target === defaultLocale ? barePath : `/${target}${barePath}`;
1132
+ return redirect;
1133
+ });
1134
+ }
956
1135
  export {
957
- useBloxEdit as A,
958
- BLOX_REGISTRY_KEY as B,
959
- useContentItem as C,
960
- useData as D,
961
- withLocaleRoutes as E,
1136
+ _sfc_main$1 as A,
1137
+ BLOX_DATA_WINDOW_KEY as B,
1138
+ _sfc_main as C,
1139
+ GLOBAL_REF_KEY as D,
1140
+ classifyLink as E,
1141
+ configureApi as F,
962
1142
  GlobalBlockHost as G,
1143
+ contentRoutes as H,
1144
+ defineContent as I,
1145
+ getContentRouteByCollection as J,
1146
+ getWebsiteId as K,
1147
+ getWebsiteIdSync as L,
1148
+ isAbsoluteExternal as M,
1149
+ isSpecialScheme as N,
1150
+ listItems as O,
963
1151
  PageRenderer as P,
1152
+ normalizeTo as Q,
1153
+ provideContentItem as R,
1154
+ resolvePath as S,
1155
+ toInternalPath as T,
1156
+ useBloxEdit as U,
1157
+ useContentItem as V,
1158
+ useData as W,
964
1159
  _sfc_main$3 as _,
965
- BLOX_LOCALE_STRATEGY_KEY as a,
966
- BLOX_ADMIN_CONFIG_KEY as b,
967
- createBlox as c,
968
- BLOX_CONFIG_KEY as d,
969
- BLOX_CONTENT_ITEM_KEY as e,
970
- BLOX_GLOBAL_RESOLVER_KEY as f,
971
- globalRefOf as g,
972
- BloxInstance as h,
973
- installSmartLinks as i,
974
- _sfc_main$2 as j,
975
- GLOBAL_REF_KEY as k,
976
- _sfc_main$1 as l,
977
- classifyLink as m,
1160
+ setActiveLocale as a,
1161
+ collectBloxSeo as b,
1162
+ collectBloxData as c,
1163
+ createBlox as d,
1164
+ BLOX_REGISTRY_KEY as e,
1165
+ globalRefOf as f,
1166
+ generateContentRoutes as g,
1167
+ BLOX_LOCALE_STRATEGY_KEY as h,
1168
+ installLocaleAwareResolve as i,
1169
+ useSeo as j,
1170
+ getRegistryData as k,
1171
+ getItemBySlug as l,
1172
+ getItemById as m,
978
1173
  normalizeLink as n,
979
- configureApi as o,
980
- contentRoutes as p,
981
- defineContent as q,
982
- getWebsiteId as r,
983
- getWebsiteIdSync as s,
984
- isAbsoluteExternal as t,
1174
+ getContentRoute as o,
1175
+ provideBloxData as p,
1176
+ installContentFallback as q,
1177
+ installSmartLinks as r,
1178
+ setApiOrigin as s,
1179
+ BLOX_ADMIN_CONFIG_KEY as t,
985
1180
  useLocale as u,
986
- isSpecialScheme as v,
987
- listItems as w,
988
- normalizeTo as x,
989
- resolvePath as y,
990
- toInternalPath as z
1181
+ BLOX_CONFIG_KEY as v,
1182
+ BLOX_DATA_KEY as w,
1183
+ BLOX_GLOBAL_RESOLVER_KEY as x,
1184
+ BloxInstance as y,
1185
+ _sfc_main$2 as z
991
1186
  };