@ohhwells/bridge 0.1.124 → 0.1.126

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -512,6 +512,16 @@ declare function TooltipContent({ className, sideOffset, side, children, hideArr
512
512
  hideArrow?: boolean;
513
513
  }): react_jsx_runtime.JSX.Element;
514
514
 
515
+ interface EmptySectionProps {
516
+ title: string;
517
+ homeHref?: string;
518
+ /** data-ohw-key values for the editable text nodes — omit a key to leave that node non-editable. */
519
+ eyebrowKey?: string;
520
+ titleKey?: string;
521
+ subtitleKey?: string;
522
+ }
523
+ declare function EmptySection({ title, homeHref, eyebrowKey, titleKey, subtitleKey }: EmptySectionProps): react_jsx_runtime.JSX.Element;
524
+
515
525
  declare function isEditSessionActive(): boolean;
516
526
 
517
527
  type CarouselSlide = {
@@ -535,4 +545,4 @@ declare function useOhwCarousel(key: string, initial: CarouselSlide[]): {
535
545
  bind: Record<string, string>;
536
546
  };
537
547
 
538
- export { AI_DEFAULT_BRAND, AI_TREE_SCHEMA_VERSIONS, AI_TREE_TOKENS, type AiBlockNode, type AiBrandKit, type AiLayoutTree, AiTreeRenderer, type AiTreeRendererProps, type CarouselSlide, CustomToolbar, CustomToolbarButton, CustomToolbarDivider, DragHandle, DropIndicator, type DropIndicatorProps, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, ItemActionToolbar, type ItemActionToolbarProps, ItemInteractionLayer, type ItemInteractionLayerProps, type ItemInteractionState, LinkEditorPanel, type LinkModalMode, type LinkModalProps, type LinkPage, LinkPopover, type LinkSection, OhhwellsBridge, SchedulingWidget, type SectionScaffold, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, buildTarget, dropIndicatorVariants, filterAvailablePages, getEditModeInitialState, isEditSessionActive, isRenderableTree, isValidUrl, parseTarget, toggleVariants, useOhwCarousel, validateUrlInput };
548
+ export { AI_DEFAULT_BRAND, AI_TREE_SCHEMA_VERSIONS, AI_TREE_TOKENS, type AiBlockNode, type AiBrandKit, type AiLayoutTree, AiTreeRenderer, type AiTreeRendererProps, type CarouselSlide, CustomToolbar, CustomToolbarButton, CustomToolbarDivider, DragHandle, DropIndicator, type DropIndicatorProps, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, EmptySection, type EmptySectionProps, ItemActionToolbar, type ItemActionToolbarProps, ItemInteractionLayer, type ItemInteractionLayerProps, type ItemInteractionState, LinkEditorPanel, type LinkModalMode, type LinkModalProps, type LinkPage, LinkPopover, type LinkSection, OhhwellsBridge, SchedulingWidget, type SectionScaffold, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, buildTarget, dropIndicatorVariants, filterAvailablePages, getEditModeInitialState, isEditSessionActive, isRenderableTree, isValidUrl, parseTarget, toggleVariants, useOhwCarousel, validateUrlInput };
package/dist/index.d.ts CHANGED
@@ -512,6 +512,16 @@ declare function TooltipContent({ className, sideOffset, side, children, hideArr
512
512
  hideArrow?: boolean;
513
513
  }): react_jsx_runtime.JSX.Element;
514
514
 
515
+ interface EmptySectionProps {
516
+ title: string;
517
+ homeHref?: string;
518
+ /** data-ohw-key values for the editable text nodes — omit a key to leave that node non-editable. */
519
+ eyebrowKey?: string;
520
+ titleKey?: string;
521
+ subtitleKey?: string;
522
+ }
523
+ declare function EmptySection({ title, homeHref, eyebrowKey, titleKey, subtitleKey }: EmptySectionProps): react_jsx_runtime.JSX.Element;
524
+
515
525
  declare function isEditSessionActive(): boolean;
516
526
 
517
527
  type CarouselSlide = {
@@ -535,4 +545,4 @@ declare function useOhwCarousel(key: string, initial: CarouselSlide[]): {
535
545
  bind: Record<string, string>;
536
546
  };
537
547
 
538
- export { AI_DEFAULT_BRAND, AI_TREE_SCHEMA_VERSIONS, AI_TREE_TOKENS, type AiBlockNode, type AiBrandKit, type AiLayoutTree, AiTreeRenderer, type AiTreeRendererProps, type CarouselSlide, CustomToolbar, CustomToolbarButton, CustomToolbarDivider, DragHandle, DropIndicator, type DropIndicatorProps, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, ItemActionToolbar, type ItemActionToolbarProps, ItemInteractionLayer, type ItemInteractionLayerProps, type ItemInteractionState, LinkEditorPanel, type LinkModalMode, type LinkModalProps, type LinkPage, LinkPopover, type LinkSection, OhhwellsBridge, SchedulingWidget, type SectionScaffold, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, buildTarget, dropIndicatorVariants, filterAvailablePages, getEditModeInitialState, isEditSessionActive, isRenderableTree, isValidUrl, parseTarget, toggleVariants, useOhwCarousel, validateUrlInput };
548
+ export { AI_DEFAULT_BRAND, AI_TREE_SCHEMA_VERSIONS, AI_TREE_TOKENS, type AiBlockNode, type AiBrandKit, type AiLayoutTree, AiTreeRenderer, type AiTreeRendererProps, type CarouselSlide, CustomToolbar, CustomToolbarButton, CustomToolbarDivider, DragHandle, DropIndicator, type DropIndicatorProps, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, EmptySection, type EmptySectionProps, ItemActionToolbar, type ItemActionToolbarProps, ItemInteractionLayer, type ItemInteractionLayerProps, type ItemInteractionState, LinkEditorPanel, type LinkModalMode, type LinkModalProps, type LinkPage, LinkPopover, type LinkSection, OhhwellsBridge, SchedulingWidget, type SectionScaffold, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, buildTarget, dropIndicatorVariants, filterAvailablePages, getEditModeInitialState, isEditSessionActive, isRenderableTree, isValidUrl, parseTarget, toggleVariants, useOhwCarousel, validateUrlInput };
package/dist/index.js CHANGED
@@ -222,10 +222,14 @@ function reapRemovedAiSections(state, store, removedIds, excludeIds = /* @__PURE
222
222
  var BRAND_NAME_KEY = "__ohw_brand_name";
223
223
  var BRAND_TITLE_KEY = "__ohw_site_title";
224
224
  var BRAND_FAVICON_LETTER_KEY = "__ohw_favicon_letter";
225
+ var SITE_DESCRIPTION_KEY = "__ohw_site_description";
226
+ var SITE_OG_IMAGE_KEY = "__ohw_og_image";
225
227
  var BRAND_CHROME_KEYS = /* @__PURE__ */ new Set([
226
228
  BRAND_NAME_KEY,
227
229
  BRAND_TITLE_KEY,
228
- BRAND_FAVICON_LETTER_KEY
230
+ BRAND_FAVICON_LETTER_KEY,
231
+ SITE_DESCRIPTION_KEY,
232
+ SITE_OG_IMAGE_KEY
229
233
  ]);
230
234
  function upsertMeta(selector, attr, token, value) {
231
235
  let el = document.head.querySelector(selector);
@@ -236,6 +240,9 @@ function upsertMeta(selector, attr, token, value) {
236
240
  }
237
241
  if (el.getAttribute("content") !== value) el.setAttribute("content", value);
238
242
  }
243
+ function removeMeta(selector) {
244
+ document.head.querySelector(selector)?.remove();
245
+ }
239
246
  function escapeXml(value) {
240
247
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
241
248
  }
@@ -251,6 +258,22 @@ function applyLetterFavicon(letter) {
251
258
  link.type = "image/svg+xml";
252
259
  if (link.href !== href) link.href = href;
253
260
  }
261
+ function applyDescription(description) {
262
+ if (!description) return;
263
+ upsertMeta('meta[name="description"]', "name", "description", description);
264
+ upsertMeta('meta[property="og:description"]', "property", "og:description", description);
265
+ upsertMeta('meta[name="twitter:description"]', "name", "twitter:description", description);
266
+ }
267
+ function applyOgImage(url) {
268
+ if (url) {
269
+ upsertMeta('meta[property="og:image"]', "property", "og:image", url);
270
+ upsertMeta('meta[name="twitter:image"]', "name", "twitter:image", url);
271
+ upsertMeta('meta[name="twitter:card"]', "name", "twitter:card", "summary_large_image");
272
+ return;
273
+ }
274
+ removeMeta('meta[property="og:image"]');
275
+ removeMeta('meta[name="twitter:image"]');
276
+ }
254
277
  function applyBrandChrome(content) {
255
278
  const name = content[BRAND_NAME_KEY];
256
279
  if (typeof name === "string" && name.length > 0) {
@@ -269,6 +292,13 @@ function applyBrandChrome(content) {
269
292
  if (typeof letter === "string" && letter.length > 0) {
270
293
  applyLetterFavicon(letter);
271
294
  }
295
+ const description = content[SITE_DESCRIPTION_KEY];
296
+ if (typeof description === "string" && description.length > 0) {
297
+ applyDescription(description);
298
+ }
299
+ if (Object.prototype.hasOwnProperty.call(content, SITE_OG_IMAGE_KEY)) {
300
+ applyOgImage(String(content[SITE_OG_IMAGE_KEY] ?? "").trim());
301
+ }
272
302
  }
273
303
 
274
304
  // src/lib/brand-kit.ts
@@ -19551,21 +19581,10 @@ function parseSchedulingInsertAfter(insertAfter) {
19551
19581
  insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
19552
19582
  };
19553
19583
  }
19554
- function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
19555
- const parsed = parseSchedulingInsertAfter(insertAfter);
19556
- const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
19557
- const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
19558
- return { effectiveInsertAfter, insertBefore };
19559
- }
19560
- function getSchedulingMountPoint(insertAfter) {
19561
- const { anchor } = parseSchedulingInsertAfter(insertAfter);
19562
- let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
19563
- if (!anchorEl && anchor === "scheduling") {
19564
- const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
19565
- anchorEl = widgets.at(-1) ?? null;
19566
- }
19567
- if (!anchorEl) return null;
19568
- return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
19584
+ function resolveEntryAnchor(entry) {
19585
+ if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
19586
+ const parsed = parseSchedulingInsertAfter(entry.insertAfter);
19587
+ return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
19569
19588
  }
19570
19589
  function schedulingMountDepth(insertAfter) {
19571
19590
  if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
@@ -19582,8 +19601,7 @@ function getPageSchedulingEntries(raw) {
19582
19601
  }
19583
19602
  }
19584
19603
  function isSchedulingWidgetMissing(entry) {
19585
- const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
19586
- return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
19604
+ return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
19587
19605
  }
19588
19606
  function hasMissingSchedulingWidgets(entries) {
19589
19607
  return entries.some(isSchedulingWidgetMissing);
@@ -19621,17 +19639,18 @@ function initSectionsFromContent(content, removeExisting = false, currentPath =
19621
19639
  } catch {
19622
19640
  }
19623
19641
  }
19624
- function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
19625
- const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
19626
- const sectionId = schedulingSectionId(effectiveInsertAfter);
19642
+ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
19643
+ const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
19644
+ const sectionId = schedulingSectionId(widgetId);
19627
19645
  if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
19628
- const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
19629
- if (!mountPoint) return false;
19646
+ const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
19647
+ if (!anchorEl) return false;
19648
+ const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
19630
19649
  const container = document.createElement("div");
19631
19650
  container.dataset.ohwSectionContainer = "scheduling";
19632
19651
  container.dataset.ohwInstance = sectionId;
19633
- if (insertBefore) {
19634
- const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
19652
+ if (beforeId) {
19653
+ const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
19635
19654
  const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
19636
19655
  if (!beforePoint) return false;
19637
19656
  beforePoint.insertAdjacentElement("beforebegin", container);
@@ -19642,20 +19661,26 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
19642
19661
  }
19643
19662
  tail.insertAdjacentElement("afterend", container);
19644
19663
  }
19645
- const root = createRoot2(container);
19646
- schedulingRoots.set(container, root);
19647
- flushSync2(() => {
19648
- root.render(
19649
- /* @__PURE__ */ jsx36(
19650
- SchedulingWidget,
19651
- {
19652
- notifyOnConnect,
19653
- initialScheduleId: scheduleId,
19654
- insertAfter: effectiveInsertAfter
19655
- }
19656
- )
19657
- );
19658
- });
19664
+ try {
19665
+ const root = createRoot2(container);
19666
+ schedulingRoots.set(container, root);
19667
+ flushSync2(() => {
19668
+ root.render(
19669
+ /* @__PURE__ */ jsx36(
19670
+ SchedulingWidget,
19671
+ {
19672
+ notifyOnConnect,
19673
+ initialScheduleId: scheduleId,
19674
+ insertAfter: widgetId
19675
+ }
19676
+ )
19677
+ );
19678
+ });
19679
+ } catch (err) {
19680
+ console.error("[ow:scheduling] render threw", err);
19681
+ container.remove();
19682
+ return false;
19683
+ }
19659
19684
  const tracker = getSectionsTracker();
19660
19685
  let sections = [];
19661
19686
  try {
@@ -19663,10 +19688,12 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
19663
19688
  } catch {
19664
19689
  }
19665
19690
  const inEditor = typeof window !== "undefined" && window.self !== window.top;
19666
- if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
19691
+ if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
19667
19692
  sections.push({
19668
19693
  type: "scheduling",
19669
- insertAfter: effectiveInsertAfter,
19694
+ insertAfter: widgetId,
19695
+ anchorId,
19696
+ beforeId: beforeId ?? null,
19670
19697
  pagePath: window.location.pathname,
19671
19698
  ...scheduleId ? { scheduleId } : {}
19672
19699
  });
@@ -19680,7 +19707,8 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
19680
19707
  for (let i = pending.length - 1; i >= 0; i--) {
19681
19708
  const entry = pending[i];
19682
19709
  const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
19683
- if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId ?? null)) {
19710
+ const { anchorId, beforeId } = resolveEntryAnchor(entry);
19711
+ if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
19684
19712
  pending.splice(i, 1);
19685
19713
  }
19686
19714
  }
@@ -20743,6 +20771,7 @@ function StateToggle({
20743
20771
  );
20744
20772
  }
20745
20773
  var contentCache = /* @__PURE__ */ new Map();
20774
+ var fetchedContentPaths = /* @__PURE__ */ new Set();
20746
20775
  var brandingCache = /* @__PURE__ */ new Map();
20747
20776
  var OHW_LOADER_STYLE = {
20748
20777
  position: "fixed",
@@ -20949,6 +20978,7 @@ function OhhwellsBridge() {
20949
20978
  if (!subdomainFromQuery || typeof window === "undefined") return;
20950
20979
  const url = new URL(window.location.href);
20951
20980
  if (!url.searchParams.has("subdomain")) return;
20981
+ if (!resolveSubdomain(null)) return;
20952
20982
  url.searchParams.delete("subdomain");
20953
20983
  window.history.replaceState(null, "", url.pathname + url.search + url.hash);
20954
20984
  }, [subdomainFromQuery]);
@@ -22995,7 +23025,9 @@ function OhhwellsBridge() {
22995
23025
  let cancelled = false;
22996
23026
  setFetchState("loading");
22997
23027
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
22998
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
23028
+ const initialPath = pathname;
23029
+ fetchedContentPaths.add(`${subdomain}::${initialPath}`);
23030
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
22999
23031
  if (cancelled) return;
23000
23032
  const content = data?.content ?? {};
23001
23033
  const branding = Boolean(data?.showBranding);
@@ -23192,6 +23224,17 @@ function OhhwellsBridge() {
23192
23224
  debounceTimer = setTimeout(applyFromCache, 150);
23193
23225
  };
23194
23226
  applyFromCache();
23227
+ const pathCacheKey = `${subdomain}::${pathname}`;
23228
+ if (!fetchedContentPaths.has(pathCacheKey)) {
23229
+ fetchedContentPaths.add(pathCacheKey);
23230
+ const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
23231
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
23232
+ if (!data?.content) return;
23233
+ contentCache.set(subdomain, data.content);
23234
+ applyFromCache();
23235
+ }).catch(() => {
23236
+ });
23237
+ }
23195
23238
  observer = new MutationObserver(scheduleApply);
23196
23239
  observer.observe(document.body, { childList: true, subtree: true });
23197
23240
  return () => {
@@ -26056,6 +26099,21 @@ function OhhwellsBridge() {
26056
26099
  type: "text",
26057
26100
  text: editContentRef.current[CUSTOM_CODE_AFTER_HEAD_KEY] ?? ""
26058
26101
  });
26102
+ nodes.push({
26103
+ key: BRAND_TITLE_KEY,
26104
+ type: "text",
26105
+ text: editContentRef.current[BRAND_TITLE_KEY] ?? ""
26106
+ });
26107
+ nodes.push({
26108
+ key: SITE_DESCRIPTION_KEY,
26109
+ type: "text",
26110
+ text: editContentRef.current[SITE_DESCRIPTION_KEY] ?? ""
26111
+ });
26112
+ nodes.push({
26113
+ key: SITE_OG_IMAGE_KEY,
26114
+ type: "text",
26115
+ text: editContentRef.current[SITE_OG_IMAGE_KEY] ?? ""
26116
+ });
26059
26117
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
26060
26118
  const formKey = formKeyOf(form);
26061
26119
  if (!formKey) return;
@@ -26078,8 +26136,12 @@ function OhhwellsBridge() {
26078
26136
  if (inserted) {
26079
26137
  const tracker = getSectionsTracker();
26080
26138
  postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
26081
- const h = document.body.scrollHeight;
26082
- if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
26139
+ const reportHeight = () => {
26140
+ const h = document.body.scrollHeight;
26141
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
26142
+ };
26143
+ reportHeight();
26144
+ setTimeout(reportHeight, 500);
26083
26145
  }
26084
26146
  };
26085
26147
  const handleSwitchSchedule = (e) => {
@@ -26805,7 +26867,7 @@ function OhhwellsBridge() {
26805
26867
  postToParent2({
26806
26868
  type: "ow:ready",
26807
26869
  version: "1",
26808
- bridgeVersion: "0.1.123",
26870
+ bridgeVersion: "0.1.125",
26809
26871
  path: pathname,
26810
26872
  nodes: collectEditableNodes(editContentRef.current),
26811
26873
  sections
@@ -27892,6 +27954,59 @@ function OhhwellsBridge() {
27892
27954
  ) : null
27893
27955
  ] });
27894
27956
  }
27957
+
27958
+ // src/ui/EmptySection.tsx
27959
+ import Link3 from "next/link";
27960
+ import { Fragment as Fragment11, jsx as jsx37, jsxs as jsxs24 } from "react/jsx-runtime";
27961
+ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
27962
+ return /* @__PURE__ */ jsxs24(Fragment11, { children: [
27963
+ /* @__PURE__ */ jsx37(
27964
+ "p",
27965
+ {
27966
+ style: {
27967
+ fontFamily: "var(--brand-font-body)",
27968
+ fontSize: "0.75rem",
27969
+ fontWeight: 500,
27970
+ letterSpacing: "0.15em",
27971
+ textTransform: "uppercase",
27972
+ color: "var(--brand-accent)",
27973
+ marginBottom: "1.5rem"
27974
+ },
27975
+ children: /* @__PURE__ */ jsx37(Link3, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ jsx37("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
27976
+ }
27977
+ ),
27978
+ /* @__PURE__ */ jsx37(
27979
+ "h1",
27980
+ {
27981
+ style: {
27982
+ fontFamily: "var(--brand-font-heading)",
27983
+ fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
27984
+ lineHeight: 1.1,
27985
+ letterSpacing: "-0.025em",
27986
+ color: "var(--brand-text)",
27987
+ marginBottom: "1rem"
27988
+ },
27989
+ ...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
27990
+ children: title
27991
+ }
27992
+ ),
27993
+ /* @__PURE__ */ jsx37(
27994
+ "p",
27995
+ {
27996
+ style: {
27997
+ fontFamily: "var(--brand-font-body)",
27998
+ fontSize: "1rem",
27999
+ lineHeight: 1.7,
28000
+ fontWeight: 300,
28001
+ color: "var(--brand-text-muted)",
28002
+ maxWidth: "340px"
28003
+ },
28004
+ ...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
28005
+ children: "This page doesn't have any content yet."
28006
+ }
28007
+ )
28008
+ ] });
28009
+ }
27895
28010
  export {
27896
28011
  AI_DEFAULT_BRAND,
27897
28012
  AI_TREE_SCHEMA_VERSIONS,
@@ -27908,6 +28023,7 @@ export {
27908
28023
  DropdownMenuItem,
27909
28024
  DropdownMenuSeparator,
27910
28025
  DropdownMenuTrigger,
28026
+ EmptySection,
27911
28027
  ItemActionToolbar,
27912
28028
  ItemInteractionLayer,
27913
28029
  LinkEditorPanel,