@ohhwells/bridge 0.1.127 → 0.1.128
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.cjs +742 -657
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -4
- package/dist/index.d.ts +18 -4
- package/dist/index.js +742 -657
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -31,6 +31,12 @@ function enforceLinkHrefs() {
|
|
|
31
31
|
|
|
32
32
|
// src/lib/ai-tree.ts
|
|
33
33
|
var AI_TREE_SCHEMA_VERSIONS = [1];
|
|
34
|
+
function legacyVerticalPaddingAlias(spacing) {
|
|
35
|
+
if (spacing === "tight") return "s";
|
|
36
|
+
if (spacing === "balanced") return "m";
|
|
37
|
+
if (spacing === "airy") return "l";
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
34
40
|
var BUTTON_FILL_TOKENS = ["dark", "primary", "accent", "light"];
|
|
35
41
|
var BUTTON_STYLES = ["solid", "outline", "ghost"];
|
|
36
42
|
var BUTTON_RADII = ["square", "rounded", "pill"];
|
|
@@ -53,7 +59,10 @@ var AI_TREE_TOKENS = {
|
|
|
53
59
|
radiusButton: 10,
|
|
54
60
|
radiusCard: 18,
|
|
55
61
|
sectionMaxWidth: 1280,
|
|
56
|
-
|
|
62
|
+
/** 6-step vertical-padding scale (OHH-789) — replaces the deprecated tight/balanced/airy
|
|
63
|
+
* map; `m` keeps the old `balanced` value (64) so already-generated sites render unchanged.
|
|
64
|
+
* `none` is the true zero floor for an explicit "remove the padding" ask. */
|
|
65
|
+
sectionPaddingByScale: { none: 0, xs: 24, s: 40, m: 64, l: 96, xl: 128 },
|
|
57
66
|
type: {
|
|
58
67
|
display: { size: 56, line: 1.1, weight: 700 },
|
|
59
68
|
h2: { size: 40, line: 1.15, weight: 700 },
|
|
@@ -71,205 +80,566 @@ function isRenderableTree(value) {
|
|
|
71
80
|
return AI_TREE_SCHEMA_VERSIONS.includes(tree.schemaVersion) && tree.type === "section" && Array.isArray(tree.rows);
|
|
72
81
|
}
|
|
73
82
|
|
|
74
|
-
// src/lib/
|
|
75
|
-
var
|
|
76
|
-
var
|
|
77
|
-
function
|
|
78
|
-
return
|
|
79
|
-
}
|
|
80
|
-
var EMPTY_AI_SECTIONS = { v: 1, sections: [] };
|
|
81
|
-
function parseAiSectionsState(raw) {
|
|
82
|
-
if (!raw) return EMPTY_AI_SECTIONS;
|
|
83
|
+
// src/lib/section-styles.ts
|
|
84
|
+
var STYLE_STORE_KEY = "__ohw_styles";
|
|
85
|
+
var STYLE_SHEET_ID = "ohw-section-styles";
|
|
86
|
+
function parseStyleStore(raw) {
|
|
87
|
+
if (!raw) return null;
|
|
83
88
|
try {
|
|
84
89
|
const parsed = JSON.parse(raw);
|
|
85
|
-
if (parsed?.v !== 1
|
|
86
|
-
const sections = parsed.sections.filter(
|
|
87
|
-
(entry) => typeof entry === "object" && entry !== null && typeof entry.id === "string" && entry.id.length > 0 && isRenderableTree(entry.tree)
|
|
88
|
-
).map((entry) => ({
|
|
89
|
-
...entry,
|
|
90
|
-
label: typeof entry.label === "string" ? entry.label : "Generated section",
|
|
91
|
-
media: entry.media && typeof entry.media === "object" ? entry.media : {}
|
|
92
|
-
}));
|
|
93
|
-
const removed = Array.isArray(parsed.removed) ? parsed.removed.filter((id) => typeof id === "string" && id.length > 0) : [];
|
|
90
|
+
if (parsed?.v !== 1) return null;
|
|
94
91
|
return {
|
|
95
92
|
v: 1,
|
|
96
|
-
sections,
|
|
97
|
-
|
|
98
|
-
...parsed.hideTemplate === true ? { hideTemplate: true } : {}
|
|
93
|
+
sections: typeof parsed.sections === "object" && parsed.sections ? parsed.sections : {},
|
|
94
|
+
nodes: typeof parsed.nodes === "object" && parsed.nodes ? parsed.nodes : {}
|
|
99
95
|
};
|
|
100
96
|
} catch {
|
|
101
|
-
return
|
|
97
|
+
return null;
|
|
102
98
|
}
|
|
103
99
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
...selfEdit ? priorEntry?.beforeSection ? { beforeSection: priorEntry.beforeSection } : {} : insertBefore && payload.targetSectionId ? { beforeSection: payload.targetSectionId } : {},
|
|
117
|
-
...selfEdit ? priorEntry?.replaces ? { replaces: priorEntry.replaces } : {} : payload.mode === "replace" && payload.targetSectionId ? { replaces: payload.targetSectionId } : {},
|
|
118
|
-
tree: payload.tree,
|
|
119
|
-
media: payload.media ?? {},
|
|
120
|
-
...payload.brand && typeof payload.brand === "object" ? { brand: payload.brand } : {}
|
|
100
|
+
var BG_VALUES = {
|
|
101
|
+
surface: "color-mix(in srgb, var(--ohw-brand-light, var(--color-light, #ECECEB)) 94%, var(--ohw-brand-dark, var(--color-dark, #0C0A09)))",
|
|
102
|
+
accent: "var(--ohw-brand-primary, var(--color-primary, #0078E5))",
|
|
103
|
+
"accent-soft": "color-mix(in srgb, var(--ohw-brand-primary, var(--color-primary, #0078E5)) 12%, var(--ohw-brand-light, var(--color-light, #FFFFFF)))"
|
|
104
|
+
};
|
|
105
|
+
var NAVBAR_COLOR_TOKENS = ["dark", "primary", "accent", "light"];
|
|
106
|
+
function navbarColorVar(token) {
|
|
107
|
+
const fallback = {
|
|
108
|
+
dark: "#0C0A09",
|
|
109
|
+
primary: "#0078E5",
|
|
110
|
+
accent: "#0078E5",
|
|
111
|
+
light: "#FFFFFF"
|
|
121
112
|
};
|
|
122
|
-
|
|
123
|
-
return { ...state, v: 1, sections: [...others, entry] };
|
|
113
|
+
return `var(--ohw-brand-${token}, var(--color-${token}, ${fallback[token]}))`;
|
|
124
114
|
}
|
|
125
|
-
function
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
...entry.tree,
|
|
135
|
-
rows: entry.tree.rows.map((row) => ({ ...row, blocks: row.blocks.map((block) => ({ ...block })) }))
|
|
136
|
-
};
|
|
137
|
-
nextTrees.set(id, fresh);
|
|
138
|
-
return fresh;
|
|
139
|
-
};
|
|
140
|
-
const nodes = {};
|
|
141
|
-
for (const [key, override] of Object.entries(store.nodes)) {
|
|
142
|
-
const match = override.align !== void 0 && key.startsWith(AI_SLOT_KEY_PREFIX) ? key.match(/^ai\.(.+?)\.r(\d+)\.b(\d+)(?:\.|$)/) : null;
|
|
143
|
-
const tree = match ? treeFor(match[1]) : void 0;
|
|
144
|
-
const block = match && tree ? tree.rows[Number(match[2])]?.blocks[Number(match[3])] : void 0;
|
|
145
|
-
if (!block) {
|
|
146
|
-
nodes[key] = override;
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
block.align = override.align;
|
|
150
|
-
const rest = { ...override };
|
|
151
|
-
delete rest.align;
|
|
152
|
-
if (Object.keys(rest).length > 0) nodes[key] = rest;
|
|
115
|
+
function resolveNavbarValue(value) {
|
|
116
|
+
if (value === void 0) return void 0;
|
|
117
|
+
return NAVBAR_COLOR_TOKENS.includes(value) ? navbarColorVar(value) : value;
|
|
118
|
+
}
|
|
119
|
+
var HEADLINE_SIZES = { md: 24, lg: 32, xl: 40, display: 56 };
|
|
120
|
+
function styleSheetCss() {
|
|
121
|
+
const rules = [];
|
|
122
|
+
for (const [tone, value] of Object.entries(BG_VALUES)) {
|
|
123
|
+
rules.push(`[data-ohw-style-bg="${tone}"] { background: ${value} !important; }`);
|
|
153
124
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
delete rest.align;
|
|
166
|
-
if (Object.keys(rest).length > 0) sections[sectionId] = rest;
|
|
125
|
+
rules.push(
|
|
126
|
+
`[data-ohw-style-bg="accent"] { color: var(--ohw-brand-light, var(--color-light, #FFFFFF)) !important; }`
|
|
127
|
+
);
|
|
128
|
+
rules.push(
|
|
129
|
+
`[data-ohw-style-distribution="space-between"] { display: flex !important; flex-direction: column; justify-content: space-between; }`,
|
|
130
|
+
`[data-ohw-style-distribution="center"] { display: flex !important; flex-direction: column; justify-content: center; }`
|
|
131
|
+
);
|
|
132
|
+
for (const [scale, size] of Object.entries(HEADLINE_SIZES)) {
|
|
133
|
+
rules.push(
|
|
134
|
+
`[data-ohw-style-headline="${scale}"] :is(h1, h2, h3) { font-size: ${size}px !important; line-height: 1.15 !important; }`
|
|
135
|
+
);
|
|
167
136
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
return tree ? { ...entry, tree } : entry;
|
|
176
|
-
})
|
|
177
|
-
},
|
|
178
|
-
store: { v: 1, sections, nodes },
|
|
179
|
-
changed: true
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
function removeFromState(state, id) {
|
|
183
|
-
return { ...state, v: 1, sections: state.sections.filter((entry) => entry.id !== id) };
|
|
184
|
-
}
|
|
185
|
-
function deleteSectionFromState(state, sectionId) {
|
|
186
|
-
if (state.sections.some((entry) => entry.id === sectionId)) {
|
|
187
|
-
return removeFromState(state, sectionId);
|
|
137
|
+
rules.push(
|
|
138
|
+
`[data-ohw-style-aspect="fill-height"] img { height: 100% !important; aspect-ratio: auto !important; object-fit: cover; }`
|
|
139
|
+
);
|
|
140
|
+
for (const aspect of ["1:1", "4:5", "3:4", "3:2", "16:9", "2:1", "3:1"]) {
|
|
141
|
+
rules.push(
|
|
142
|
+
`[data-ohw-style-aspect="${aspect.replace(":", "-")}"] img { aspect-ratio: ${aspect.replace(":", " / ")} !important; height: auto !important; object-fit: cover; }`
|
|
143
|
+
);
|
|
188
144
|
}
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const generated = new Set(state.sections.map((entry) => entry.id));
|
|
195
|
-
const reapedIds = [...new Set(removedIds)].filter((id) => generated.has(id) && !excludeIds.has(id));
|
|
196
|
-
if (reapedIds.length === 0) {
|
|
197
|
-
return { state, store, reapedIds: [], slotPrefixes: [], changed: false };
|
|
145
|
+
const pad = { tight: 40, balanced: 64, airy: 96 };
|
|
146
|
+
for (const [spacing, px2] of Object.entries(pad)) {
|
|
147
|
+
rules.push(
|
|
148
|
+
`[data-ohw-style-spacing="${spacing}"] { padding-top: ${px2}px !important; padding-bottom: ${px2}px !important; }`
|
|
149
|
+
);
|
|
198
150
|
}
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
sections: state.sections.filter((entry) => !reaped.has(entry.id))
|
|
205
|
-
};
|
|
206
|
-
let nextStore = store;
|
|
207
|
-
if (store) {
|
|
208
|
-
const sections = {};
|
|
209
|
-
for (const [key, override] of Object.entries(store.sections)) {
|
|
210
|
-
if (!reaped.has(key)) sections[key] = override;
|
|
211
|
-
}
|
|
212
|
-
const nodes = {};
|
|
213
|
-
for (const [key, override] of Object.entries(store.nodes)) {
|
|
214
|
-
if (!slotPrefixes.some((prefix) => key.startsWith(prefix))) nodes[key] = override;
|
|
215
|
-
}
|
|
216
|
-
nextStore = { v: 1, sections, nodes };
|
|
151
|
+
for (const [step, px2] of Object.entries(AI_TREE_TOKENS.sectionPaddingByScale)) {
|
|
152
|
+
const vpCss = px2 === 0 ? "0px" : `clamp(${Math.max(16, Math.round(px2 * 0.5))}px, ${(px2 / 9).toFixed(2)}vw, ${px2}px)`;
|
|
153
|
+
rules.push(
|
|
154
|
+
`[data-ohw-style-vpadding="${step}"] { padding-top: ${vpCss} !important; padding-bottom: ${vpCss} !important; }`
|
|
155
|
+
);
|
|
217
156
|
}
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
var
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
var SITE_OG_IMAGE_KEY = "__ohw_og_image";
|
|
227
|
-
var BRAND_CHROME_KEYS = /* @__PURE__ */ new Set([
|
|
228
|
-
BRAND_NAME_KEY,
|
|
229
|
-
BRAND_TITLE_KEY,
|
|
230
|
-
BRAND_FAVICON_LETTER_KEY,
|
|
231
|
-
SITE_DESCRIPTION_KEY,
|
|
232
|
-
SITE_OG_IMAGE_KEY
|
|
233
|
-
]);
|
|
234
|
-
function upsertMeta(selector, attr, token, value) {
|
|
235
|
-
let el = document.head.querySelector(selector);
|
|
236
|
-
if (!el) {
|
|
237
|
-
el = document.createElement("meta");
|
|
238
|
-
el.setAttribute(attr, token);
|
|
239
|
-
document.head.appendChild(el);
|
|
157
|
+
rules.push(
|
|
158
|
+
`[data-ohw-style-corners="sharp"] :is(.card, [data-ohw-card], img, picture, figure, [data-ohw-editable="bg-image"]) { border-radius: 0 !important; }`,
|
|
159
|
+
`[data-ohw-style-corners="sharp"] :has(> img) { border-radius: 0 !important; }`,
|
|
160
|
+
`[data-ohw-style-corners="rounded"] :is(.card, [data-ohw-card], img, picture, figure, [data-ohw-editable="bg-image"]) { border-radius: max(0.75rem, var(--radius, 0px)) !important; }`,
|
|
161
|
+
`[data-ohw-style-corners="rounded"] :has(> img) { border-radius: max(0.75rem, var(--radius, 0px)) !important; }`
|
|
162
|
+
);
|
|
163
|
+
for (const align of ["left", "center", "right"]) {
|
|
164
|
+
rules.push(`[data-ohw-style-align="${align}"] { text-align: ${align} !important; }`);
|
|
240
165
|
}
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
function removeMeta(selector) {
|
|
244
|
-
document.head.querySelector(selector)?.remove();
|
|
245
|
-
}
|
|
246
|
-
function escapeXml(value) {
|
|
247
|
-
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
166
|
+
return rules.join("\n");
|
|
248
167
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
const
|
|
252
|
-
|
|
168
|
+
var STYLE_FONT_LINK_ID = "ohw-style-fonts";
|
|
169
|
+
function loadStyleFonts(families) {
|
|
170
|
+
const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
|
|
171
|
+
const existing = document.getElementById(STYLE_FONT_LINK_ID);
|
|
172
|
+
if (unique.length === 0) {
|
|
173
|
+
existing?.remove();
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
|
|
177
|
+
const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
|
|
178
|
+
let link = existing;
|
|
253
179
|
if (!link) {
|
|
254
180
|
link = document.createElement("link");
|
|
255
|
-
link.
|
|
181
|
+
link.id = STYLE_FONT_LINK_ID;
|
|
182
|
+
link.rel = "stylesheet";
|
|
256
183
|
document.head.appendChild(link);
|
|
257
184
|
}
|
|
258
|
-
link.type = "image/svg+xml";
|
|
259
185
|
if (link.href !== href) link.href = href;
|
|
260
186
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
187
|
+
var SECTION_ATTRS = {
|
|
188
|
+
sectionBackground: "data-ohw-style-bg",
|
|
189
|
+
textDistribution: "data-ohw-style-distribution",
|
|
190
|
+
headlineScale: "data-ohw-style-headline",
|
|
191
|
+
imageAspect: "data-ohw-style-aspect",
|
|
192
|
+
spacing: "data-ohw-style-spacing",
|
|
193
|
+
verticalPadding: "data-ohw-style-vpadding",
|
|
194
|
+
cornerStyle: "data-ohw-style-corners",
|
|
195
|
+
align: "data-ohw-style-align"
|
|
196
|
+
};
|
|
197
|
+
var NODE_WROTE_ATTR = "data-ohw-style-node";
|
|
198
|
+
var NODE_PROPS = [
|
|
199
|
+
"color",
|
|
200
|
+
"font-family",
|
|
201
|
+
"font-size",
|
|
202
|
+
"text-align",
|
|
203
|
+
"justify-content",
|
|
204
|
+
"align-items"
|
|
205
|
+
];
|
|
206
|
+
var ALIGN_JUSTIFY = {
|
|
207
|
+
left: "flex-start",
|
|
208
|
+
center: "center",
|
|
209
|
+
right: "flex-end"
|
|
210
|
+
};
|
|
211
|
+
function saveInline(el, prop) {
|
|
212
|
+
const attr = `data-ohw-style-prev-${prop}`;
|
|
213
|
+
if (el.hasAttribute(attr)) return;
|
|
214
|
+
const value = el.style.getPropertyValue(prop) || (prop === "background" ? el.style.getPropertyValue("background-color") : "");
|
|
215
|
+
el.setAttribute(attr, value);
|
|
216
|
+
}
|
|
217
|
+
function restoreInline(el, prop) {
|
|
218
|
+
const attr = `data-ohw-style-prev-${prop}`;
|
|
219
|
+
if (!el.hasAttribute(attr)) return;
|
|
220
|
+
const prev = el.getAttribute(attr) ?? "";
|
|
221
|
+
if (prev) el.style.setProperty(prop, prev);
|
|
222
|
+
else el.style.removeProperty(prop);
|
|
223
|
+
el.removeAttribute(attr);
|
|
224
|
+
}
|
|
225
|
+
function ensureStyleSheet() {
|
|
226
|
+
let el = document.getElementById(STYLE_SHEET_ID);
|
|
227
|
+
if (!el) {
|
|
228
|
+
el = document.createElement("style");
|
|
229
|
+
el.id = STYLE_SHEET_ID;
|
|
230
|
+
document.head.appendChild(el);
|
|
231
|
+
}
|
|
232
|
+
const css = styleSheetCss();
|
|
233
|
+
if (el.textContent !== css) el.textContent = css;
|
|
234
|
+
}
|
|
235
|
+
function clearSectionAttrs(root) {
|
|
236
|
+
for (const attr of Object.values(SECTION_ATTRS)) {
|
|
237
|
+
for (const el of Array.from(root.querySelectorAll(`[${attr}]`))) el.removeAttribute(attr);
|
|
238
|
+
}
|
|
239
|
+
for (const el of Array.from(root.querySelectorAll("[data-ohw-style-bgcolor]"))) {
|
|
240
|
+
restoreInline(el, "background");
|
|
241
|
+
el.removeAttribute("data-ohw-style-bgcolor");
|
|
242
|
+
}
|
|
243
|
+
for (const el of Array.from(root.querySelectorAll("[data-ohw-style-minheight]"))) {
|
|
244
|
+
restoreInline(el, "min-height");
|
|
245
|
+
el.removeAttribute("data-ohw-style-minheight");
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function clearNodeProps(root) {
|
|
249
|
+
for (const el of Array.from(root.querySelectorAll(`[${NODE_WROTE_ATTR}]`))) {
|
|
250
|
+
const h = el;
|
|
251
|
+
for (const prop of NODE_PROPS) restoreInline(h, prop);
|
|
252
|
+
h.removeAttribute(NODE_WROTE_ATTR);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
function alignSubjectOf(el) {
|
|
256
|
+
const button = el.closest('[data-ohw-role="button"]');
|
|
257
|
+
if (button?.parentElement) return button.parentElement;
|
|
258
|
+
let subject = el;
|
|
259
|
+
while (subject.parentElement && !subject.parentElement.hasAttribute("data-ohw-section") && /^inline/.test(getComputedStyle(subject).display)) {
|
|
260
|
+
subject = subject.parentElement;
|
|
261
|
+
}
|
|
262
|
+
const TEXT_ROW = /^(P|LI|H[1-6]|BLOCKQUOTE|FIGCAPTION|DT|DD)$/;
|
|
263
|
+
const parent = subject.parentElement;
|
|
264
|
+
if (parent && TEXT_ROW.test(parent.tagName) && /^(inline-)?flex$/.test(getComputedStyle(parent).display)) {
|
|
265
|
+
return parent;
|
|
266
|
+
}
|
|
267
|
+
if (parent && !parent.hasAttribute("data-ohw-section")) {
|
|
268
|
+
const pcs = getComputedStyle(parent);
|
|
269
|
+
const children = Array.from(parent.children);
|
|
270
|
+
const textRowChild = (c) => c.hasAttribute("data-ohw-editable") || (c.textContent ?? "").trim().length === 0 || c.getAttribute("aria-hidden") === "true";
|
|
271
|
+
if (/^(inline-)?flex$/.test(pcs.display) && pcs.flexDirection.startsWith("row") && children.length > 0 && children.some((c) => c.hasAttribute("data-ohw-editable")) && children.every(textRowChild)) {
|
|
272
|
+
return parent;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
const row = subject.closest("li");
|
|
276
|
+
if (row && row !== subject && /^(inline-)?flex$/.test(getComputedStyle(row).display)) {
|
|
277
|
+
return row;
|
|
278
|
+
}
|
|
279
|
+
return subject;
|
|
280
|
+
}
|
|
281
|
+
function applyStylesToDom(store) {
|
|
282
|
+
ensureStyleSheet();
|
|
283
|
+
clearSectionAttrs(document);
|
|
284
|
+
clearNodeProps(document);
|
|
285
|
+
loadStyleFonts(
|
|
286
|
+
store ? [
|
|
287
|
+
...Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []),
|
|
288
|
+
...Object.values(store.sections).flatMap((s) => s.fontFamily ? [s.fontFamily] : [])
|
|
289
|
+
] : []
|
|
290
|
+
);
|
|
291
|
+
if (!store) return;
|
|
292
|
+
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
293
|
+
const escaped = CSS.escape(sectionId);
|
|
294
|
+
const byInstance = document.querySelectorAll(`[data-ohw-instance="${escaped}"]`);
|
|
295
|
+
const sections = Array.from(
|
|
296
|
+
byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`)
|
|
297
|
+
);
|
|
298
|
+
const isNavbar = sectionId === "navbar";
|
|
299
|
+
if (isNavbar) {
|
|
300
|
+
const drawer = document.querySelector("[data-ohw-nav-drawer]");
|
|
301
|
+
if (drawer && !sections.includes(drawer)) sections.push(drawer);
|
|
302
|
+
const header = document.querySelector("[data-ohw-nav-root]");
|
|
303
|
+
if (header && !sections.includes(header)) sections.push(header);
|
|
304
|
+
}
|
|
305
|
+
for (const marker of Array.from(sections)) {
|
|
306
|
+
const isDrawerMarker = isNavbar && marker.hasAttribute("data-ohw-nav-drawer");
|
|
307
|
+
const section = marker.querySelector(":scope > [data-ai-section]") ?? marker;
|
|
308
|
+
for (const [prop, attr] of Object.entries(SECTION_ATTRS)) {
|
|
309
|
+
const value = override[prop];
|
|
310
|
+
if (value === void 0) continue;
|
|
311
|
+
if (prop === "sectionBackground" && override.sectionBackgroundColor !== void 0) continue;
|
|
312
|
+
section.setAttribute(attr, String(value).replace(":", "-"));
|
|
313
|
+
}
|
|
314
|
+
const bgOverride = isDrawerMarker ? override.navbarMobileBackground : override.sectionBackgroundColor;
|
|
315
|
+
const textOverride = isDrawerMarker ? override.navbarMobileTextColor : override.textColor;
|
|
316
|
+
const bgValue = isNavbar ? resolveNavbarValue(bgOverride) : bgOverride;
|
|
317
|
+
const textValue = isNavbar ? resolveNavbarValue(textOverride) : textOverride;
|
|
318
|
+
if (bgValue !== void 0) {
|
|
319
|
+
saveInline(section, "background");
|
|
320
|
+
section.style.setProperty("background", bgValue, "important");
|
|
321
|
+
section.setAttribute("data-ohw-style-bgcolor", "");
|
|
322
|
+
}
|
|
323
|
+
if (override.minHeight !== void 0 && !isDrawerMarker) {
|
|
324
|
+
const minHeightCss = override.minHeight === "full" ? "var(--ohw-canvas-h, calc(100vh - 80px))" : override.minHeight === "half" ? "calc(var(--ohw-canvas-h, 100vh) / 2)" : void 0;
|
|
325
|
+
saveInline(section, "min-height");
|
|
326
|
+
if (minHeightCss) section.style.setProperty("min-height", minHeightCss, "important");
|
|
327
|
+
else section.style.removeProperty("min-height");
|
|
328
|
+
section.setAttribute("data-ohw-style-minheight", "");
|
|
329
|
+
}
|
|
330
|
+
if (textValue !== void 0 || override.fontFamily !== void 0) {
|
|
331
|
+
const textEls = marker.querySelectorAll(
|
|
332
|
+
'[data-ohw-editable="text"], [data-ohw-editable="plain"], [data-ohw-field-label]'
|
|
333
|
+
);
|
|
334
|
+
for (const el of Array.from(textEls)) {
|
|
335
|
+
if (textValue !== void 0) {
|
|
336
|
+
saveInline(el, "color");
|
|
337
|
+
el.style.setProperty("color", textValue, "important");
|
|
338
|
+
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
339
|
+
}
|
|
340
|
+
if (override.fontFamily !== void 0) {
|
|
341
|
+
saveInline(el, "font-family");
|
|
342
|
+
el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
|
|
343
|
+
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
for (const [key, override] of Object.entries(store.nodes)) {
|
|
350
|
+
const nodes = document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`);
|
|
351
|
+
for (const el of Array.from(nodes)) {
|
|
352
|
+
if (override.color !== void 0) {
|
|
353
|
+
saveInline(el, "color");
|
|
354
|
+
el.style.setProperty("color", override.color, "important");
|
|
355
|
+
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
356
|
+
}
|
|
357
|
+
if (override.fontFamily !== void 0) {
|
|
358
|
+
saveInline(el, "font-family");
|
|
359
|
+
el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
|
|
360
|
+
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
361
|
+
}
|
|
362
|
+
if (override.fontSize !== void 0) {
|
|
363
|
+
saveInline(el, "font-size");
|
|
364
|
+
el.style.setProperty("font-size", `${override.fontSize}px`, "important");
|
|
365
|
+
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
366
|
+
}
|
|
367
|
+
if (override.align !== void 0) {
|
|
368
|
+
const subject = alignSubjectOf(el);
|
|
369
|
+
saveInline(subject, "text-align");
|
|
370
|
+
saveInline(subject, "justify-content");
|
|
371
|
+
subject.style.setProperty("text-align", override.align, "important");
|
|
372
|
+
subject.style.setProperty(
|
|
373
|
+
"justify-content",
|
|
374
|
+
ALIGN_JUSTIFY[override.align] ?? "flex-start",
|
|
375
|
+
"important"
|
|
376
|
+
);
|
|
377
|
+
subject.setAttribute(NODE_WROTE_ATTR, "");
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
382
|
+
if (override.headingColor === void 0) continue;
|
|
383
|
+
const escaped = CSS.escape(sectionId);
|
|
384
|
+
const byInstance = document.querySelectorAll(`[data-ohw-instance="${escaped}"]`);
|
|
385
|
+
const sections = byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`);
|
|
386
|
+
for (const marker of Array.from(sections)) {
|
|
387
|
+
const headings = marker.querySelectorAll(
|
|
388
|
+
":is(h1, h2, h3, h4, h5, h6)[data-ohw-editable], :is(h1, h2, h3, h4, h5, h6) > [data-ohw-editable]"
|
|
389
|
+
);
|
|
390
|
+
for (const el of Array.from(headings)) {
|
|
391
|
+
saveInline(el, "color");
|
|
392
|
+
el.style.setProperty("color", override.headingColor, "important");
|
|
393
|
+
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// src/lib/ai-sections-store.ts
|
|
400
|
+
var AI_SECTIONS_KEY = "__ohw_ai_sections";
|
|
401
|
+
var AI_SLOT_KEY_PREFIX = "ai.";
|
|
402
|
+
function aiSlotKeyPrefixFor(sectionId) {
|
|
403
|
+
return `${AI_SLOT_KEY_PREFIX}${sectionId}.`;
|
|
404
|
+
}
|
|
405
|
+
var EMPTY_AI_SECTIONS = { v: 1, sections: [] };
|
|
406
|
+
function parseAiSectionsState(raw) {
|
|
407
|
+
if (!raw) return EMPTY_AI_SECTIONS;
|
|
408
|
+
try {
|
|
409
|
+
const parsed = JSON.parse(raw);
|
|
410
|
+
if (parsed?.v !== 1 || !Array.isArray(parsed.sections)) return EMPTY_AI_SECTIONS;
|
|
411
|
+
const sections = parsed.sections.filter(
|
|
412
|
+
(entry) => typeof entry === "object" && entry !== null && typeof entry.id === "string" && entry.id.length > 0 && isRenderableTree(entry.tree)
|
|
413
|
+
).map((entry) => ({
|
|
414
|
+
...entry,
|
|
415
|
+
label: typeof entry.label === "string" ? entry.label : "Generated section",
|
|
416
|
+
media: entry.media && typeof entry.media === "object" ? entry.media : {}
|
|
417
|
+
}));
|
|
418
|
+
const removed = Array.isArray(parsed.removed) ? parsed.removed.filter((id) => typeof id === "string" && id.length > 0) : [];
|
|
419
|
+
return {
|
|
420
|
+
v: 1,
|
|
421
|
+
sections,
|
|
422
|
+
...removed.length ? { removed } : {},
|
|
423
|
+
...parsed.hideTemplate === true ? { hideTemplate: true } : {}
|
|
424
|
+
};
|
|
425
|
+
} catch {
|
|
426
|
+
return EMPTY_AI_SECTIONS;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
function serializeAiSectionsState(state) {
|
|
430
|
+
return JSON.stringify(state);
|
|
431
|
+
}
|
|
432
|
+
function resolveSectionSettingsContext(sectionId, aiSectionsRaw, stylesRaw) {
|
|
433
|
+
const genSettings = parseAiSectionsState(aiSectionsRaw).sections.find(
|
|
434
|
+
(entry) => entry.id === sectionId
|
|
435
|
+
)?.tree.settings;
|
|
436
|
+
if (genSettings) return genSettings;
|
|
437
|
+
const styleOverride = parseStyleStore(stylesRaw)?.sections[sectionId];
|
|
438
|
+
if (!styleOverride?.verticalPadding && !styleOverride?.minHeight && !styleOverride?.spacing) {
|
|
439
|
+
return void 0;
|
|
440
|
+
}
|
|
441
|
+
return {
|
|
442
|
+
verticalPadding: styleOverride.verticalPadding ?? legacyVerticalPaddingAlias(styleOverride.spacing),
|
|
443
|
+
minHeight: styleOverride.minHeight
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
function applyTreeToState(state, payload) {
|
|
447
|
+
const insertBefore = payload.mode === "insert" && payload.position === "before";
|
|
448
|
+
const priorEntry = state.sections.find((existing) => existing.id === payload.id);
|
|
449
|
+
const selfEdit = payload.mode === "replace" && payload.targetSectionId === payload.id;
|
|
450
|
+
const entry = {
|
|
451
|
+
id: payload.id,
|
|
452
|
+
label: payload.label ?? "Generated section",
|
|
453
|
+
...typeof payload.path === "string" && payload.path ? { path: payload.path } : {},
|
|
454
|
+
afterSection: selfEdit ? priorEntry?.afterSection ?? null : payload.mode === "insert" && !insertBefore ? payload.targetSectionId ?? null : null,
|
|
455
|
+
...selfEdit ? priorEntry?.beforeSection ? { beforeSection: priorEntry.beforeSection } : {} : insertBefore && payload.targetSectionId ? { beforeSection: payload.targetSectionId } : {},
|
|
456
|
+
...selfEdit ? priorEntry?.replaces ? { replaces: priorEntry.replaces } : {} : payload.mode === "replace" && payload.targetSectionId ? { replaces: payload.targetSectionId } : {},
|
|
457
|
+
tree: payload.tree,
|
|
458
|
+
media: payload.media ?? {},
|
|
459
|
+
...payload.brand && typeof payload.brand === "object" ? { brand: payload.brand } : {}
|
|
460
|
+
};
|
|
461
|
+
const others = state.sections.filter((existing) => existing.id !== entry.id);
|
|
462
|
+
return { ...state, v: 1, sections: [...others, entry] };
|
|
463
|
+
}
|
|
464
|
+
function foldAlignIntoTrees(state, store) {
|
|
465
|
+
const byId = new Map(state.sections.map((entry) => [entry.id, entry]));
|
|
466
|
+
const nextTrees = /* @__PURE__ */ new Map();
|
|
467
|
+
const treeFor = (id) => {
|
|
468
|
+
const cloned = nextTrees.get(id);
|
|
469
|
+
if (cloned) return cloned;
|
|
470
|
+
const entry = byId.get(id);
|
|
471
|
+
if (!entry) return void 0;
|
|
472
|
+
const fresh = {
|
|
473
|
+
...entry.tree,
|
|
474
|
+
rows: entry.tree.rows.map((row) => ({ ...row, blocks: row.blocks.map((block) => ({ ...block })) }))
|
|
475
|
+
};
|
|
476
|
+
nextTrees.set(id, fresh);
|
|
477
|
+
return fresh;
|
|
478
|
+
};
|
|
479
|
+
const nodes = {};
|
|
480
|
+
for (const [key, override] of Object.entries(store.nodes)) {
|
|
481
|
+
const match = override.align !== void 0 && key.startsWith(AI_SLOT_KEY_PREFIX) ? key.match(/^ai\.(.+?)\.r(\d+)\.b(\d+)(?:\.|$)/) : null;
|
|
482
|
+
const tree = match ? treeFor(match[1]) : void 0;
|
|
483
|
+
const block = match && tree ? tree.rows[Number(match[2])]?.blocks[Number(match[3])] : void 0;
|
|
484
|
+
if (!block) {
|
|
485
|
+
nodes[key] = override;
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
block.align = override.align;
|
|
489
|
+
const rest = { ...override };
|
|
490
|
+
delete rest.align;
|
|
491
|
+
if (Object.keys(rest).length > 0) nodes[key] = rest;
|
|
492
|
+
}
|
|
493
|
+
const sections = {};
|
|
494
|
+
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
495
|
+
const tree = override.align !== void 0 ? treeFor(sectionId) : void 0;
|
|
496
|
+
if (!tree) {
|
|
497
|
+
sections[sectionId] = override;
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
for (const row of tree.rows) {
|
|
501
|
+
for (const block of row.blocks) block.align = override.align;
|
|
502
|
+
}
|
|
503
|
+
const rest = { ...override };
|
|
504
|
+
delete rest.align;
|
|
505
|
+
if (Object.keys(rest).length > 0) sections[sectionId] = rest;
|
|
506
|
+
}
|
|
507
|
+
if (nextTrees.size === 0) return { state, store, changed: false };
|
|
508
|
+
return {
|
|
509
|
+
state: {
|
|
510
|
+
...state,
|
|
511
|
+
v: 1,
|
|
512
|
+
sections: state.sections.map((entry) => {
|
|
513
|
+
const tree = nextTrees.get(entry.id);
|
|
514
|
+
return tree ? { ...entry, tree } : entry;
|
|
515
|
+
})
|
|
516
|
+
},
|
|
517
|
+
store: { v: 1, sections, nodes },
|
|
518
|
+
changed: true
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
function foldSectionHeightIntoTrees(state, store) {
|
|
522
|
+
const byId = new Map(state.sections.map((entry) => [entry.id, entry]));
|
|
523
|
+
const nextEntries = /* @__PURE__ */ new Map();
|
|
524
|
+
const sections = {};
|
|
525
|
+
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
526
|
+
const entry = byId.get(sectionId);
|
|
527
|
+
const touchesHeight = override.verticalPadding !== void 0 || override.minHeight !== void 0;
|
|
528
|
+
if (!entry || !touchesHeight) {
|
|
529
|
+
sections[sectionId] = override;
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
const nextSettings = { ...entry.tree.settings ?? {} };
|
|
533
|
+
if (override.verticalPadding !== void 0) nextSettings.verticalPadding = override.verticalPadding;
|
|
534
|
+
if (override.minHeight !== void 0) nextSettings.minHeight = override.minHeight;
|
|
535
|
+
nextEntries.set(sectionId, { ...entry, tree: { ...entry.tree, settings: nextSettings } });
|
|
536
|
+
const rest = { ...override };
|
|
537
|
+
delete rest.verticalPadding;
|
|
538
|
+
delete rest.minHeight;
|
|
539
|
+
if (Object.keys(rest).length > 0) sections[sectionId] = rest;
|
|
540
|
+
}
|
|
541
|
+
if (nextEntries.size === 0) return { state, store, changed: false };
|
|
542
|
+
return {
|
|
543
|
+
state: {
|
|
544
|
+
...state,
|
|
545
|
+
v: 1,
|
|
546
|
+
sections: state.sections.map((entry) => nextEntries.get(entry.id) ?? entry)
|
|
547
|
+
},
|
|
548
|
+
store: { v: 1, sections, nodes: store.nodes },
|
|
549
|
+
changed: true
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
function removeFromState(state, id) {
|
|
553
|
+
return { ...state, v: 1, sections: state.sections.filter((entry) => entry.id !== id) };
|
|
554
|
+
}
|
|
555
|
+
function deleteSectionFromState(state, sectionId) {
|
|
556
|
+
if (state.sections.some((entry) => entry.id === sectionId)) {
|
|
557
|
+
return removeFromState(state, sectionId);
|
|
558
|
+
}
|
|
559
|
+
const removed = state.removed ?? [];
|
|
560
|
+
if (removed.includes(sectionId)) return state;
|
|
561
|
+
return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
|
|
562
|
+
}
|
|
563
|
+
function reapRemovedAiSections(state, store, removedIds, excludeIds = /* @__PURE__ */ new Set()) {
|
|
564
|
+
const generated = new Set(state.sections.map((entry) => entry.id));
|
|
565
|
+
const reapedIds = [...new Set(removedIds)].filter((id) => generated.has(id) && !excludeIds.has(id));
|
|
566
|
+
if (reapedIds.length === 0) {
|
|
567
|
+
return { state, store, reapedIds: [], slotPrefixes: [], changed: false };
|
|
568
|
+
}
|
|
569
|
+
const reaped = new Set(reapedIds);
|
|
570
|
+
const slotPrefixes = reapedIds.map(aiSlotKeyPrefixFor);
|
|
571
|
+
const nextState = {
|
|
572
|
+
...state,
|
|
573
|
+
v: 1,
|
|
574
|
+
sections: state.sections.filter((entry) => !reaped.has(entry.id))
|
|
575
|
+
};
|
|
576
|
+
let nextStore = store;
|
|
577
|
+
if (store) {
|
|
578
|
+
const sections = {};
|
|
579
|
+
for (const [key, override] of Object.entries(store.sections)) {
|
|
580
|
+
if (!reaped.has(key)) sections[key] = override;
|
|
581
|
+
}
|
|
582
|
+
const nodes = {};
|
|
583
|
+
for (const [key, override] of Object.entries(store.nodes)) {
|
|
584
|
+
if (!slotPrefixes.some((prefix) => key.startsWith(prefix))) nodes[key] = override;
|
|
585
|
+
}
|
|
586
|
+
nextStore = { v: 1, sections, nodes };
|
|
587
|
+
}
|
|
588
|
+
return { state: nextState, store: nextStore, reapedIds, slotPrefixes, changed: true };
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// src/lib/brand-chrome.ts
|
|
592
|
+
var BRAND_NAME_KEY = "__ohw_brand_name";
|
|
593
|
+
var BRAND_TITLE_KEY = "__ohw_site_title";
|
|
594
|
+
var BRAND_FAVICON_LETTER_KEY = "__ohw_favicon_letter";
|
|
595
|
+
var SITE_DESCRIPTION_KEY = "__ohw_site_description";
|
|
596
|
+
var SITE_OG_IMAGE_KEY = "__ohw_og_image";
|
|
597
|
+
var BRAND_CHROME_KEYS = /* @__PURE__ */ new Set([
|
|
598
|
+
BRAND_NAME_KEY,
|
|
599
|
+
BRAND_TITLE_KEY,
|
|
600
|
+
BRAND_FAVICON_LETTER_KEY,
|
|
601
|
+
SITE_DESCRIPTION_KEY,
|
|
602
|
+
SITE_OG_IMAGE_KEY
|
|
603
|
+
]);
|
|
604
|
+
function upsertMeta(selector, attr, token, value) {
|
|
605
|
+
let el = document.head.querySelector(selector);
|
|
606
|
+
if (!el) {
|
|
607
|
+
el = document.createElement("meta");
|
|
608
|
+
el.setAttribute(attr, token);
|
|
609
|
+
document.head.appendChild(el);
|
|
610
|
+
}
|
|
611
|
+
if (el.getAttribute("content") !== value) el.setAttribute("content", value);
|
|
612
|
+
}
|
|
613
|
+
function removeMeta(selector) {
|
|
614
|
+
document.head.querySelector(selector)?.remove();
|
|
615
|
+
}
|
|
616
|
+
function escapeXml(value) {
|
|
617
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
618
|
+
}
|
|
619
|
+
function applyLetterFavicon(letter) {
|
|
620
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="12" fill="#111827"/><text x="32" y="46" font-family="system-ui,-apple-system,Segoe UI,sans-serif" font-size="40" font-weight="700" text-anchor="middle" fill="#ffffff">${escapeXml(letter)}</text></svg>`;
|
|
621
|
+
const href = `data:image/svg+xml,${encodeURIComponent(svg)}`;
|
|
622
|
+
let link = document.head.querySelector('link[rel="icon"]');
|
|
623
|
+
if (!link) {
|
|
624
|
+
link = document.createElement("link");
|
|
625
|
+
link.rel = "icon";
|
|
626
|
+
document.head.appendChild(link);
|
|
627
|
+
}
|
|
628
|
+
link.type = "image/svg+xml";
|
|
629
|
+
if (link.href !== href) link.href = href;
|
|
630
|
+
}
|
|
631
|
+
function applyDescription(description) {
|
|
632
|
+
if (!description) return;
|
|
633
|
+
upsertMeta('meta[name="description"]', "name", "description", description);
|
|
634
|
+
upsertMeta('meta[property="og:description"]', "property", "og:description", description);
|
|
635
|
+
upsertMeta('meta[name="twitter:description"]', "name", "twitter:description", description);
|
|
636
|
+
}
|
|
637
|
+
function applyOgImage(url) {
|
|
638
|
+
if (url) {
|
|
639
|
+
upsertMeta('meta[property="og:image"]', "property", "og:image", url);
|
|
640
|
+
upsertMeta('meta[name="twitter:image"]', "name", "twitter:image", url);
|
|
641
|
+
upsertMeta('meta[name="twitter:card"]', "name", "twitter:card", "summary_large_image");
|
|
642
|
+
return;
|
|
273
643
|
}
|
|
274
644
|
removeMeta('meta[property="og:image"]');
|
|
275
645
|
removeMeta('meta[name="twitter:image"]');
|
|
@@ -468,520 +838,222 @@ function isButtonStyle(value) {
|
|
|
468
838
|
const v = value;
|
|
469
839
|
return BUTTON_FILL_TOKENS.includes(v.fill) && BUTTON_FILL_TOKENS.includes(v.textColor) && BUTTON_STYLES.includes(v.style) && BUTTON_RADII.includes(v.radius) && BUTTON_SIZES.includes(v.size);
|
|
470
840
|
}
|
|
471
|
-
function parseCustomFontWeight(raw) {
|
|
472
|
-
if (typeof raw !== "object" || raw === null) return null;
|
|
473
|
-
const w = raw;
|
|
474
|
-
if (typeof w.weight !== "number" || !Number.isFinite(w.weight)) return null;
|
|
475
|
-
if (typeof w.url !== "string" || !w.url) return null;
|
|
476
|
-
if (typeof w.format !== "string" || !CUSTOM_FONT_FORMATS.has(w.format)) return null;
|
|
477
|
-
const weightEnd = typeof w.weightEnd === "number" && Number.isFinite(w.weightEnd) && w.weightEnd > w.weight ? w.weightEnd : void 0;
|
|
478
|
-
return { weight: w.weight, ...weightEnd !== void 0 ? { weightEnd } : {}, url: w.url, format: w.format };
|
|
479
|
-
}
|
|
480
|
-
function parseCustomFont(raw) {
|
|
481
|
-
if (typeof raw !== "object" || raw === null) return null;
|
|
482
|
-
const f = raw;
|
|
483
|
-
if (typeof f.family !== "string" || !f.family) return null;
|
|
484
|
-
if (typeof f.label !== "string" || !f.label) return null;
|
|
485
|
-
if (!Array.isArray(f.weights)) return null;
|
|
486
|
-
const weights = f.weights.map(parseCustomFontWeight).filter((w) => w !== null);
|
|
487
|
-
if (weights.length === 0) return null;
|
|
488
|
-
return { family: f.family, label: f.label, weights };
|
|
489
|
-
}
|
|
490
|
-
var BUTTON_FIELDS = Object.keys(ROLES_BY_FIELD);
|
|
491
|
-
function parseTouchedButtons(raw) {
|
|
492
|
-
const out = {};
|
|
493
|
-
for (const variant of ["primary", "secondary"]) {
|
|
494
|
-
const list = raw?.[variant];
|
|
495
|
-
if (Array.isArray(list)) out[variant] = BUTTON_FIELDS.filter((f) => list.includes(f));
|
|
496
|
-
}
|
|
497
|
-
return out;
|
|
498
|
-
}
|
|
499
|
-
function parseBrandKit(raw) {
|
|
500
|
-
if (!raw) return null;
|
|
501
|
-
try {
|
|
502
|
-
const parsed = JSON.parse(raw);
|
|
503
|
-
const p = parsed?.palette;
|
|
504
|
-
const f = parsed?.fonts;
|
|
505
|
-
const palette = p && typeof p.dark === "string" && typeof p.primary === "string" && typeof p.accent === "string" && typeof p.light === "string" ? { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light } : void 0;
|
|
506
|
-
const fonts = f && typeof f.heading === "string" && typeof f.body === "string" ? { heading: f.heading, body: f.body } : void 0;
|
|
507
|
-
const customFonts = Array.isArray(parsed?.customFonts) ? parsed.customFonts.map(parseCustomFont).filter((c) => c !== null) : void 0;
|
|
508
|
-
const b = parsed?.buttons;
|
|
509
|
-
const buttons = b && isButtonStyle(b.primary) && isButtonStyle(b.secondary) ? { primary: b.primary, secondary: b.secondary } : void 0;
|
|
510
|
-
if (!palette && !fonts && !customFonts && !buttons) return null;
|
|
511
|
-
return {
|
|
512
|
-
...palette ? { palette } : {},
|
|
513
|
-
...fonts ? { fonts } : {},
|
|
514
|
-
...customFonts ? { customFonts } : {},
|
|
515
|
-
...buttons ? { buttons } : {},
|
|
516
|
-
...parsed.touched && typeof parsed.touched === "object" ? {
|
|
517
|
-
touched: {
|
|
518
|
-
palette: parsed.touched.palette === true,
|
|
519
|
-
fonts: parsed.touched.fonts === true,
|
|
520
|
-
buttons: parseTouchedButtons(parsed.touched.buttons)
|
|
521
|
-
}
|
|
522
|
-
} : {}
|
|
523
|
-
};
|
|
524
|
-
} catch {
|
|
525
|
-
return null;
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
function familyOf(stack) {
|
|
529
|
-
const first = stack.split(",")[0]?.trim() ?? "";
|
|
530
|
-
return first.replace(/^['"]|['"]$/g, "");
|
|
531
|
-
}
|
|
532
|
-
function quoteFamily(family) {
|
|
533
|
-
return `'${family.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
534
|
-
}
|
|
535
|
-
var WEIGHT_SCALE = [100, 200, 300, 400, 500, 600, 700, 800, 900];
|
|
536
|
-
function loadBrandFonts(families) {
|
|
537
|
-
const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
|
|
538
|
-
if (unique.length === 0) return;
|
|
539
|
-
const weights = WEIGHT_SCALE.join(";");
|
|
540
|
-
const spec = unique.map((f) => `family=${f.replace(/ /g, "+")}:wght@${weights}`).join("&");
|
|
541
|
-
const href = `https://fonts.googleapis.com/css2?${spec}&display=swap`;
|
|
542
|
-
let link = document.getElementById(BRAND_FONT_LINK_ID);
|
|
543
|
-
if (!link) {
|
|
544
|
-
link = document.createElement("link");
|
|
545
|
-
link.id = BRAND_FONT_LINK_ID;
|
|
546
|
-
link.rel = "stylesheet";
|
|
547
|
-
document.head.appendChild(link);
|
|
548
|
-
}
|
|
549
|
-
if (link.href !== href) link.href = href;
|
|
550
|
-
}
|
|
551
|
-
var BUTTON_RULES_STYLE_ID = "ohw-brand-button-rules";
|
|
552
|
-
function buttonRulesCss(kit) {
|
|
553
|
-
const rule = (variant) => {
|
|
554
|
-
const roles = touchedButtonRoles(variant, kit);
|
|
555
|
-
const v = (role) => `var(--brand-button-${variant}-${role})`;
|
|
556
|
-
const decls = [];
|
|
557
|
-
if (roles.has("bg")) decls.push(`background:${v("bg")} !important`);
|
|
558
|
-
if (roles.has("text")) decls.push(`color:${v("text")} !important`);
|
|
559
|
-
if (roles.has("border")) decls.push(`border:1.5px solid ${v("border")} !important`);
|
|
560
|
-
if (roles.has("radius")) decls.push(`border-radius:${v("radius")} !important`);
|
|
561
|
-
if (roles.has("padding-x")) decls.push(`padding:var(--brand-button-${variant}-padding, ${v("padding-y")} ${v("padding-x")}) !important`);
|
|
562
|
-
if (roles.has("font-size")) decls.push(`font-size:${v("font-size")} !important`);
|
|
563
|
-
if (decls.length === 0) return "";
|
|
564
|
-
const selectors = [`html .btn--${variant}`, `html .btn-${variant}`];
|
|
565
|
-
const labelRule = roles.has("text") ? `${selectors.map((x) => `${x} *`).join(",")}{color:inherit !important}` : "";
|
|
566
|
-
return `${selectors.join(",")}{${decls.join(";")}}` + labelRule + (roles.has("bg") ? `${selectors.map((x) => `${x}:hover`).join(",")}{opacity:0.88}` : "");
|
|
567
|
-
};
|
|
568
|
-
return rule("primary") + rule("secondary");
|
|
569
|
-
}
|
|
570
|
-
function syncButtonRules(kit) {
|
|
571
|
-
let el = document.getElementById(BUTTON_RULES_STYLE_ID);
|
|
572
|
-
const css = kit ? buttonRulesCss(kit) : "";
|
|
573
|
-
if (!css) {
|
|
574
|
-
el?.remove();
|
|
575
|
-
return;
|
|
576
|
-
}
|
|
577
|
-
if (!el) {
|
|
578
|
-
el = document.createElement("style");
|
|
579
|
-
el.id = BUTTON_RULES_STYLE_ID;
|
|
580
|
-
document.head.appendChild(el);
|
|
581
|
-
}
|
|
582
|
-
if (el.textContent !== css) el.textContent = css;
|
|
583
|
-
}
|
|
584
|
-
function escapeCssString(value) {
|
|
585
|
-
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
586
|
-
}
|
|
587
|
-
function loadCustomFonts(fonts) {
|
|
588
|
-
const list = fonts ?? [];
|
|
589
|
-
let style = document.getElementById(CUSTOM_FONT_STYLE_ID);
|
|
590
|
-
if (list.length === 0) {
|
|
591
|
-
style?.remove();
|
|
592
|
-
return;
|
|
593
|
-
}
|
|
594
|
-
if (!style) {
|
|
595
|
-
style = document.createElement("style");
|
|
596
|
-
style.id = CUSTOM_FONT_STYLE_ID;
|
|
597
|
-
document.head.appendChild(style);
|
|
598
|
-
}
|
|
599
|
-
style.textContent = list.flatMap(
|
|
600
|
-
(font) => font.weights.map((w) => {
|
|
601
|
-
const weightDescriptor = w.weightEnd ? `${w.weight} ${w.weightEnd}` : `${w.weight}`;
|
|
602
|
-
return `@font-face { font-family: '${escapeCssString(font.family)}'; src: url('${escapeCssString(w.url)}') format('${w.format}'); font-weight: ${weightDescriptor}; font-display: swap; }`;
|
|
603
|
-
})
|
|
604
|
-
).join("\n");
|
|
605
|
-
}
|
|
606
|
-
function applyBrandToDom(kit) {
|
|
607
|
-
const root = document.documentElement;
|
|
608
|
-
if (!kit) {
|
|
609
|
-
for (const name of [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES, ...BUTTON_VAR_NAMES]) {
|
|
610
|
-
root.style.removeProperty(name);
|
|
611
|
-
}
|
|
612
|
-
for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
|
|
613
|
-
document.getElementById(BRAND_FONT_LINK_ID)?.remove();
|
|
614
|
-
document.getElementById(CUSTOM_FONT_STYLE_ID)?.remove();
|
|
615
|
-
syncButtonRules(null);
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
618
|
-
const applyPalette = kit.touched ? kit.touched.palette === true : true;
|
|
619
|
-
const applyFonts = kit.touched ? kit.touched.fonts === true : true;
|
|
620
|
-
if (kit.palette) {
|
|
621
|
-
if (applyPalette) {
|
|
622
|
-
for (const [name, value] of Object.entries(brandColorVars(kit.palette))) root.style.setProperty(name, value);
|
|
623
|
-
} else {
|
|
624
|
-
for (const name of [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES]) root.style.removeProperty(name);
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
if (kit.buttons) {
|
|
628
|
-
for (const name of BUTTON_VAR_NAMES) root.style.removeProperty(name);
|
|
629
|
-
for (const [name, value] of Object.entries(buttonStyleVars({ ...kit, buttons: kit.buttons }))) root.style.setProperty(name, value);
|
|
630
|
-
}
|
|
631
|
-
syncButtonRules(kit.buttons ? kit : null);
|
|
632
|
-
if (kit.customFonts) {
|
|
633
|
-
loadCustomFonts(kit.customFonts);
|
|
634
|
-
}
|
|
635
|
-
if (kit.fonts) {
|
|
636
|
-
if (applyFonts) {
|
|
637
|
-
const heading = quoteFamily(kit.fonts.heading);
|
|
638
|
-
const body = quoteFamily(kit.fonts.body);
|
|
639
|
-
for (const name of FONT_VARS.heading) root.style.setProperty(name, heading);
|
|
640
|
-
for (const name of FONT_VARS.body) root.style.setProperty(name, body);
|
|
641
|
-
const customFamilies = new Set((kit.customFonts ?? []).map((f) => f.family));
|
|
642
|
-
const googleFamilies = [familyOf(kit.fonts.heading), familyOf(kit.fonts.body)].filter(
|
|
643
|
-
(f) => !customFamilies.has(f)
|
|
644
|
-
);
|
|
645
|
-
loadBrandFonts(googleFamilies);
|
|
646
|
-
} else {
|
|
647
|
-
for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
|
|
648
|
-
document.getElementById(BRAND_FONT_LINK_ID)?.remove();
|
|
649
|
-
}
|
|
650
|
-
}
|
|
841
|
+
function parseCustomFontWeight(raw) {
|
|
842
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
843
|
+
const w = raw;
|
|
844
|
+
if (typeof w.weight !== "number" || !Number.isFinite(w.weight)) return null;
|
|
845
|
+
if (typeof w.url !== "string" || !w.url) return null;
|
|
846
|
+
if (typeof w.format !== "string" || !CUSTOM_FONT_FORMATS.has(w.format)) return null;
|
|
847
|
+
const weightEnd = typeof w.weightEnd === "number" && Number.isFinite(w.weightEnd) && w.weightEnd > w.weight ? w.weightEnd : void 0;
|
|
848
|
+
return { weight: w.weight, ...weightEnd !== void 0 ? { weightEnd } : {}, url: w.url, format: w.format };
|
|
651
849
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
850
|
+
function parseCustomFont(raw) {
|
|
851
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
852
|
+
const f = raw;
|
|
853
|
+
if (typeof f.family !== "string" || !f.family) return null;
|
|
854
|
+
if (typeof f.label !== "string" || !f.label) return null;
|
|
855
|
+
if (!Array.isArray(f.weights)) return null;
|
|
856
|
+
const weights = f.weights.map(parseCustomFontWeight).filter((w) => w !== null);
|
|
857
|
+
if (weights.length === 0) return null;
|
|
858
|
+
return { family: f.family, label: f.label, weights };
|
|
659
859
|
}
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
const
|
|
663
|
-
const
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
if (node.nodeType !== Node.ELEMENT_NODE) continue;
|
|
667
|
-
const el = node;
|
|
668
|
-
const tag = el.tagName.toLowerCase();
|
|
669
|
-
if (!ALLOWED_HEAD_TAGS.has(tag)) continue;
|
|
670
|
-
const built = document.createElement(tag);
|
|
671
|
-
for (const attr of Array.from(el.attributes)) built.setAttribute(attr.name, attr.value);
|
|
672
|
-
if (tag === "script" || tag === "style" || tag === "noscript") built.textContent = el.textContent;
|
|
673
|
-
built.dataset.ohwCustomCode = slot;
|
|
674
|
-
nodes.push(built);
|
|
860
|
+
var BUTTON_FIELDS = Object.keys(ROLES_BY_FIELD);
|
|
861
|
+
function parseTouchedButtons(raw) {
|
|
862
|
+
const out = {};
|
|
863
|
+
for (const variant of ["primary", "secondary"]) {
|
|
864
|
+
const list = raw?.[variant];
|
|
865
|
+
if (Array.isArray(list)) out[variant] = BUTTON_FIELDS.filter((f) => list.includes(f));
|
|
675
866
|
}
|
|
676
|
-
return
|
|
677
|
-
}
|
|
678
|
-
function applyCustomCodeToHead(content) {
|
|
679
|
-
clearExisting("after");
|
|
680
|
-
clearExisting("before");
|
|
681
|
-
const afterNodes = buildNodes(content[CUSTOM_CODE_AFTER_HEAD_KEY], "after");
|
|
682
|
-
if (afterNodes.length > 0) document.head.prepend(...afterNodes);
|
|
683
|
-
const beforeNodes = buildNodes(content[CUSTOM_CODE_BEFORE_HEAD_KEY], "before");
|
|
684
|
-
if (beforeNodes.length > 0) document.head.append(...beforeNodes);
|
|
867
|
+
return out;
|
|
685
868
|
}
|
|
686
|
-
|
|
687
|
-
// src/lib/section-styles.ts
|
|
688
|
-
var STYLE_STORE_KEY = "__ohw_styles";
|
|
689
|
-
var STYLE_SHEET_ID = "ohw-section-styles";
|
|
690
|
-
function parseStyleStore(raw) {
|
|
869
|
+
function parseBrandKit(raw) {
|
|
691
870
|
if (!raw) return null;
|
|
692
871
|
try {
|
|
693
872
|
const parsed = JSON.parse(raw);
|
|
694
|
-
|
|
873
|
+
const p = parsed?.palette;
|
|
874
|
+
const f = parsed?.fonts;
|
|
875
|
+
const palette = p && typeof p.dark === "string" && typeof p.primary === "string" && typeof p.accent === "string" && typeof p.light === "string" ? { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light } : void 0;
|
|
876
|
+
const fonts = f && typeof f.heading === "string" && typeof f.body === "string" ? { heading: f.heading, body: f.body } : void 0;
|
|
877
|
+
const customFonts = Array.isArray(parsed?.customFonts) ? parsed.customFonts.map(parseCustomFont).filter((c) => c !== null) : void 0;
|
|
878
|
+
const b = parsed?.buttons;
|
|
879
|
+
const buttons = b && isButtonStyle(b.primary) && isButtonStyle(b.secondary) ? { primary: b.primary, secondary: b.secondary } : void 0;
|
|
880
|
+
if (!palette && !fonts && !customFonts && !buttons) return null;
|
|
695
881
|
return {
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
882
|
+
...palette ? { palette } : {},
|
|
883
|
+
...fonts ? { fonts } : {},
|
|
884
|
+
...customFonts ? { customFonts } : {},
|
|
885
|
+
...buttons ? { buttons } : {},
|
|
886
|
+
...parsed.touched && typeof parsed.touched === "object" ? {
|
|
887
|
+
touched: {
|
|
888
|
+
palette: parsed.touched.palette === true,
|
|
889
|
+
fonts: parsed.touched.fonts === true,
|
|
890
|
+
buttons: parseTouchedButtons(parsed.touched.buttons)
|
|
891
|
+
}
|
|
892
|
+
} : {}
|
|
699
893
|
};
|
|
700
894
|
} catch {
|
|
701
895
|
return null;
|
|
702
896
|
}
|
|
703
897
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
"accent-soft": "color-mix(in srgb, var(--ohw-brand-primary, var(--color-primary, #0078E5)) 12%, var(--ohw-brand-light, var(--color-light, #FFFFFF)))"
|
|
708
|
-
};
|
|
709
|
-
var NAVBAR_COLOR_TOKENS = ["dark", "primary", "accent", "light"];
|
|
710
|
-
function navbarColorVar(token) {
|
|
711
|
-
const fallback = {
|
|
712
|
-
dark: "#0C0A09",
|
|
713
|
-
primary: "#0078E5",
|
|
714
|
-
accent: "#0078E5",
|
|
715
|
-
light: "#FFFFFF"
|
|
716
|
-
};
|
|
717
|
-
return `var(--ohw-brand-${token}, var(--color-${token}, ${fallback[token]}))`;
|
|
718
|
-
}
|
|
719
|
-
function resolveNavbarValue(value) {
|
|
720
|
-
if (value === void 0) return void 0;
|
|
721
|
-
return NAVBAR_COLOR_TOKENS.includes(value) ? navbarColorVar(value) : value;
|
|
898
|
+
function familyOf(stack) {
|
|
899
|
+
const first = stack.split(",")[0]?.trim() ?? "";
|
|
900
|
+
return first.replace(/^['"]|['"]$/g, "");
|
|
722
901
|
}
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
const rules = [];
|
|
726
|
-
for (const [tone, value] of Object.entries(BG_VALUES)) {
|
|
727
|
-
rules.push(`[data-ohw-style-bg="${tone}"] { background: ${value} !important; }`);
|
|
728
|
-
}
|
|
729
|
-
rules.push(
|
|
730
|
-
`[data-ohw-style-bg="accent"] { color: var(--ohw-brand-light, var(--color-light, #FFFFFF)) !important; }`
|
|
731
|
-
);
|
|
732
|
-
rules.push(
|
|
733
|
-
`[data-ohw-style-distribution="space-between"] { display: flex !important; flex-direction: column; justify-content: space-between; }`,
|
|
734
|
-
`[data-ohw-style-distribution="center"] { display: flex !important; flex-direction: column; justify-content: center; }`
|
|
735
|
-
);
|
|
736
|
-
for (const [scale, size] of Object.entries(HEADLINE_SIZES)) {
|
|
737
|
-
rules.push(
|
|
738
|
-
`[data-ohw-style-headline="${scale}"] :is(h1, h2, h3) { font-size: ${size}px !important; line-height: 1.15 !important; }`
|
|
739
|
-
);
|
|
740
|
-
}
|
|
741
|
-
rules.push(
|
|
742
|
-
`[data-ohw-style-aspect="fill-height"] img { height: 100% !important; aspect-ratio: auto !important; object-fit: cover; }`
|
|
743
|
-
);
|
|
744
|
-
for (const aspect of ["1:1", "4:5", "3:4", "3:2", "16:9", "2:1", "3:1"]) {
|
|
745
|
-
rules.push(
|
|
746
|
-
`[data-ohw-style-aspect="${aspect.replace(":", "-")}"] img { aspect-ratio: ${aspect.replace(":", " / ")} !important; height: auto !important; object-fit: cover; }`
|
|
747
|
-
);
|
|
748
|
-
}
|
|
749
|
-
const pad = { tight: 40, balanced: 64, airy: 96 };
|
|
750
|
-
for (const [spacing, px2] of Object.entries(pad)) {
|
|
751
|
-
rules.push(
|
|
752
|
-
`[data-ohw-style-spacing="${spacing}"] { padding-top: ${px2}px !important; padding-bottom: ${px2}px !important; }`
|
|
753
|
-
);
|
|
754
|
-
}
|
|
755
|
-
rules.push(
|
|
756
|
-
`[data-ohw-style-corners="sharp"] :is(.card, [data-ohw-card], img, picture, figure, [data-ohw-editable="bg-image"]) { border-radius: 0 !important; }`,
|
|
757
|
-
`[data-ohw-style-corners="sharp"] :has(> img) { border-radius: 0 !important; }`,
|
|
758
|
-
`[data-ohw-style-corners="rounded"] :is(.card, [data-ohw-card], img, picture, figure, [data-ohw-editable="bg-image"]) { border-radius: max(0.75rem, var(--radius, 0px)) !important; }`,
|
|
759
|
-
`[data-ohw-style-corners="rounded"] :has(> img) { border-radius: max(0.75rem, var(--radius, 0px)) !important; }`
|
|
760
|
-
);
|
|
761
|
-
for (const align of ["left", "center", "right"]) {
|
|
762
|
-
rules.push(`[data-ohw-style-align="${align}"] { text-align: ${align} !important; }`);
|
|
763
|
-
}
|
|
764
|
-
return rules.join("\n");
|
|
902
|
+
function quoteFamily(family) {
|
|
903
|
+
return `'${family.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
765
904
|
}
|
|
766
|
-
var
|
|
767
|
-
function
|
|
905
|
+
var WEIGHT_SCALE = [100, 200, 300, 400, 500, 600, 700, 800, 900];
|
|
906
|
+
function loadBrandFonts(families) {
|
|
768
907
|
const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
|
|
775
|
-
const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
|
|
776
|
-
let link = existing;
|
|
908
|
+
if (unique.length === 0) return;
|
|
909
|
+
const weights = WEIGHT_SCALE.join(";");
|
|
910
|
+
const spec = unique.map((f) => `family=${f.replace(/ /g, "+")}:wght@${weights}`).join("&");
|
|
911
|
+
const href = `https://fonts.googleapis.com/css2?${spec}&display=swap`;
|
|
912
|
+
let link = document.getElementById(BRAND_FONT_LINK_ID);
|
|
777
913
|
if (!link) {
|
|
778
914
|
link = document.createElement("link");
|
|
779
|
-
link.id =
|
|
915
|
+
link.id = BRAND_FONT_LINK_ID;
|
|
780
916
|
link.rel = "stylesheet";
|
|
781
917
|
document.head.appendChild(link);
|
|
782
918
|
}
|
|
783
919
|
if (link.href !== href) link.href = href;
|
|
784
920
|
}
|
|
785
|
-
var
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
};
|
|
794
|
-
|
|
795
|
-
var
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
var ALIGN_JUSTIFY = {
|
|
804
|
-
left: "flex-start",
|
|
805
|
-
center: "center",
|
|
806
|
-
right: "flex-end"
|
|
807
|
-
};
|
|
808
|
-
function saveInline(el, prop) {
|
|
809
|
-
const attr = `data-ohw-style-prev-${prop}`;
|
|
810
|
-
if (el.hasAttribute(attr)) return;
|
|
811
|
-
const value = el.style.getPropertyValue(prop) || (prop === "background" ? el.style.getPropertyValue("background-color") : "");
|
|
812
|
-
el.setAttribute(attr, value);
|
|
813
|
-
}
|
|
814
|
-
function restoreInline(el, prop) {
|
|
815
|
-
const attr = `data-ohw-style-prev-${prop}`;
|
|
816
|
-
if (!el.hasAttribute(attr)) return;
|
|
817
|
-
const prev = el.getAttribute(attr) ?? "";
|
|
818
|
-
if (prev) el.style.setProperty(prop, prev);
|
|
819
|
-
else el.style.removeProperty(prop);
|
|
820
|
-
el.removeAttribute(attr);
|
|
921
|
+
var BUTTON_RULES_STYLE_ID = "ohw-brand-button-rules";
|
|
922
|
+
function buttonRulesCss(kit) {
|
|
923
|
+
const rule = (variant) => {
|
|
924
|
+
const roles = touchedButtonRoles(variant, kit);
|
|
925
|
+
const v = (role) => `var(--brand-button-${variant}-${role})`;
|
|
926
|
+
const decls = [];
|
|
927
|
+
if (roles.has("bg")) decls.push(`background:${v("bg")} !important`);
|
|
928
|
+
if (roles.has("text")) decls.push(`color:${v("text")} !important`);
|
|
929
|
+
if (roles.has("border")) decls.push(`border:1.5px solid ${v("border")} !important`);
|
|
930
|
+
if (roles.has("radius")) decls.push(`border-radius:${v("radius")} !important`);
|
|
931
|
+
if (roles.has("padding-x")) decls.push(`padding:var(--brand-button-${variant}-padding, ${v("padding-y")} ${v("padding-x")}) !important`);
|
|
932
|
+
if (roles.has("font-size")) decls.push(`font-size:${v("font-size")} !important`);
|
|
933
|
+
if (decls.length === 0) return "";
|
|
934
|
+
const selectors = [`html .btn--${variant}`, `html .btn-${variant}`];
|
|
935
|
+
const labelRule = roles.has("text") ? `${selectors.map((x) => `${x} *`).join(",")}{color:inherit !important}` : "";
|
|
936
|
+
return `${selectors.join(",")}{${decls.join(";")}}` + labelRule + (roles.has("bg") ? `${selectors.map((x) => `${x}:hover`).join(",")}{opacity:0.88}` : "");
|
|
937
|
+
};
|
|
938
|
+
return rule("primary") + rule("secondary");
|
|
821
939
|
}
|
|
822
|
-
function
|
|
823
|
-
let el = document.getElementById(
|
|
940
|
+
function syncButtonRules(kit) {
|
|
941
|
+
let el = document.getElementById(BUTTON_RULES_STYLE_ID);
|
|
942
|
+
const css = kit ? buttonRulesCss(kit) : "";
|
|
943
|
+
if (!css) {
|
|
944
|
+
el?.remove();
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
824
947
|
if (!el) {
|
|
825
948
|
el = document.createElement("style");
|
|
826
|
-
el.id =
|
|
949
|
+
el.id = BUTTON_RULES_STYLE_ID;
|
|
827
950
|
document.head.appendChild(el);
|
|
828
951
|
}
|
|
829
|
-
const css = styleSheetCss();
|
|
830
952
|
if (el.textContent !== css) el.textContent = css;
|
|
831
953
|
}
|
|
832
|
-
function
|
|
833
|
-
|
|
834
|
-
for (const el of Array.from(root.querySelectorAll(`[${attr}]`))) el.removeAttribute(attr);
|
|
835
|
-
}
|
|
836
|
-
for (const el of Array.from(root.querySelectorAll("[data-ohw-style-bgcolor]"))) {
|
|
837
|
-
restoreInline(el, "background");
|
|
838
|
-
el.removeAttribute("data-ohw-style-bgcolor");
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
function clearNodeProps(root) {
|
|
842
|
-
for (const el of Array.from(root.querySelectorAll(`[${NODE_WROTE_ATTR}]`))) {
|
|
843
|
-
const h = el;
|
|
844
|
-
for (const prop of NODE_PROPS) restoreInline(h, prop);
|
|
845
|
-
h.removeAttribute(NODE_WROTE_ATTR);
|
|
846
|
-
}
|
|
954
|
+
function escapeCssString(value) {
|
|
955
|
+
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
847
956
|
}
|
|
848
|
-
function
|
|
849
|
-
const
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
}
|
|
855
|
-
const TEXT_ROW = /^(P|LI|H[1-6]|BLOCKQUOTE|FIGCAPTION|DT|DD)$/;
|
|
856
|
-
const parent = subject.parentElement;
|
|
857
|
-
if (parent && TEXT_ROW.test(parent.tagName) && /^(inline-)?flex$/.test(getComputedStyle(parent).display)) {
|
|
858
|
-
return parent;
|
|
859
|
-
}
|
|
860
|
-
if (parent && !parent.hasAttribute("data-ohw-section")) {
|
|
861
|
-
const pcs = getComputedStyle(parent);
|
|
862
|
-
const children = Array.from(parent.children);
|
|
863
|
-
const textRowChild = (c) => c.hasAttribute("data-ohw-editable") || (c.textContent ?? "").trim().length === 0 || c.getAttribute("aria-hidden") === "true";
|
|
864
|
-
if (/^(inline-)?flex$/.test(pcs.display) && pcs.flexDirection.startsWith("row") && children.length > 0 && children.some((c) => c.hasAttribute("data-ohw-editable")) && children.every(textRowChild)) {
|
|
865
|
-
return parent;
|
|
866
|
-
}
|
|
957
|
+
function loadCustomFonts(fonts) {
|
|
958
|
+
const list = fonts ?? [];
|
|
959
|
+
let style = document.getElementById(CUSTOM_FONT_STYLE_ID);
|
|
960
|
+
if (list.length === 0) {
|
|
961
|
+
style?.remove();
|
|
962
|
+
return;
|
|
867
963
|
}
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
964
|
+
if (!style) {
|
|
965
|
+
style = document.createElement("style");
|
|
966
|
+
style.id = CUSTOM_FONT_STYLE_ID;
|
|
967
|
+
document.head.appendChild(style);
|
|
871
968
|
}
|
|
872
|
-
|
|
969
|
+
style.textContent = list.flatMap(
|
|
970
|
+
(font) => font.weights.map((w) => {
|
|
971
|
+
const weightDescriptor = w.weightEnd ? `${w.weight} ${w.weightEnd}` : `${w.weight}`;
|
|
972
|
+
return `@font-face { font-family: '${escapeCssString(font.family)}'; src: url('${escapeCssString(w.url)}') format('${w.format}'); font-weight: ${weightDescriptor}; font-display: swap; }`;
|
|
973
|
+
})
|
|
974
|
+
).join("\n");
|
|
873
975
|
}
|
|
874
|
-
function
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
store ? [
|
|
880
|
-
...Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []),
|
|
881
|
-
...Object.values(store.sections).flatMap((s) => s.fontFamily ? [s.fontFamily] : [])
|
|
882
|
-
] : []
|
|
883
|
-
);
|
|
884
|
-
if (!store) return;
|
|
885
|
-
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
886
|
-
const escaped = CSS.escape(sectionId);
|
|
887
|
-
const byInstance = document.querySelectorAll(`[data-ohw-instance="${escaped}"]`);
|
|
888
|
-
const sections = Array.from(
|
|
889
|
-
byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`)
|
|
890
|
-
);
|
|
891
|
-
const isNavbar = sectionId === "navbar";
|
|
892
|
-
if (isNavbar) {
|
|
893
|
-
const drawer = document.querySelector("[data-ohw-nav-drawer]");
|
|
894
|
-
if (drawer && !sections.includes(drawer)) sections.push(drawer);
|
|
895
|
-
const header = document.querySelector("[data-ohw-nav-root]");
|
|
896
|
-
if (header && !sections.includes(header)) sections.push(header);
|
|
897
|
-
}
|
|
898
|
-
for (const marker of Array.from(sections)) {
|
|
899
|
-
const isDrawerMarker = isNavbar && marker.hasAttribute("data-ohw-nav-drawer");
|
|
900
|
-
const section = marker.querySelector(":scope > [data-ai-section]") ?? marker;
|
|
901
|
-
for (const [prop, attr] of Object.entries(SECTION_ATTRS)) {
|
|
902
|
-
const value = override[prop];
|
|
903
|
-
if (value === void 0) continue;
|
|
904
|
-
if (prop === "sectionBackground" && override.sectionBackgroundColor !== void 0) continue;
|
|
905
|
-
section.setAttribute(attr, String(value).replace(":", "-"));
|
|
906
|
-
}
|
|
907
|
-
const bgOverride = isDrawerMarker ? override.navbarMobileBackground : override.sectionBackgroundColor;
|
|
908
|
-
const textOverride = isDrawerMarker ? override.navbarMobileTextColor : override.textColor;
|
|
909
|
-
const bgValue = isNavbar ? resolveNavbarValue(bgOverride) : bgOverride;
|
|
910
|
-
const textValue = isNavbar ? resolveNavbarValue(textOverride) : textOverride;
|
|
911
|
-
if (bgValue !== void 0) {
|
|
912
|
-
saveInline(section, "background");
|
|
913
|
-
section.style.setProperty("background", bgValue, "important");
|
|
914
|
-
section.setAttribute("data-ohw-style-bgcolor", "");
|
|
915
|
-
}
|
|
916
|
-
if (textValue !== void 0 || override.fontFamily !== void 0) {
|
|
917
|
-
const textEls = marker.querySelectorAll(
|
|
918
|
-
'[data-ohw-editable="text"], [data-ohw-editable="plain"], [data-ohw-field-label]'
|
|
919
|
-
);
|
|
920
|
-
for (const el of Array.from(textEls)) {
|
|
921
|
-
if (textValue !== void 0) {
|
|
922
|
-
saveInline(el, "color");
|
|
923
|
-
el.style.setProperty("color", textValue, "important");
|
|
924
|
-
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
925
|
-
}
|
|
926
|
-
if (override.fontFamily !== void 0) {
|
|
927
|
-
saveInline(el, "font-family");
|
|
928
|
-
el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
|
|
929
|
-
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
}
|
|
976
|
+
function applyBrandToDom(kit) {
|
|
977
|
+
const root = document.documentElement;
|
|
978
|
+
if (!kit) {
|
|
979
|
+
for (const name of [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES, ...BUTTON_VAR_NAMES]) {
|
|
980
|
+
root.style.removeProperty(name);
|
|
933
981
|
}
|
|
982
|
+
for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
|
|
983
|
+
document.getElementById(BRAND_FONT_LINK_ID)?.remove();
|
|
984
|
+
document.getElementById(CUSTOM_FONT_STYLE_ID)?.remove();
|
|
985
|
+
syncButtonRules(null);
|
|
986
|
+
return;
|
|
934
987
|
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
}
|
|
943
|
-
if (override.fontFamily !== void 0) {
|
|
944
|
-
saveInline(el, "font-family");
|
|
945
|
-
el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
|
|
946
|
-
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
947
|
-
}
|
|
948
|
-
if (override.fontSize !== void 0) {
|
|
949
|
-
saveInline(el, "font-size");
|
|
950
|
-
el.style.setProperty("font-size", `${override.fontSize}px`, "important");
|
|
951
|
-
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
952
|
-
}
|
|
953
|
-
if (override.align !== void 0) {
|
|
954
|
-
const subject = alignSubjectOf(el);
|
|
955
|
-
saveInline(subject, "text-align");
|
|
956
|
-
saveInline(subject, "justify-content");
|
|
957
|
-
subject.style.setProperty("text-align", override.align, "important");
|
|
958
|
-
subject.style.setProperty(
|
|
959
|
-
"justify-content",
|
|
960
|
-
ALIGN_JUSTIFY[override.align] ?? "flex-start",
|
|
961
|
-
"important"
|
|
962
|
-
);
|
|
963
|
-
subject.setAttribute(NODE_WROTE_ATTR, "");
|
|
964
|
-
}
|
|
988
|
+
const applyPalette = kit.touched ? kit.touched.palette === true : true;
|
|
989
|
+
const applyFonts = kit.touched ? kit.touched.fonts === true : true;
|
|
990
|
+
if (kit.palette) {
|
|
991
|
+
if (applyPalette) {
|
|
992
|
+
for (const [name, value] of Object.entries(brandColorVars(kit.palette))) root.style.setProperty(name, value);
|
|
993
|
+
} else {
|
|
994
|
+
for (const name of [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES]) root.style.removeProperty(name);
|
|
965
995
|
}
|
|
966
996
|
}
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
const
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
997
|
+
if (kit.buttons) {
|
|
998
|
+
for (const name of BUTTON_VAR_NAMES) root.style.removeProperty(name);
|
|
999
|
+
for (const [name, value] of Object.entries(buttonStyleVars({ ...kit, buttons: kit.buttons }))) root.style.setProperty(name, value);
|
|
1000
|
+
}
|
|
1001
|
+
syncButtonRules(kit.buttons ? kit : null);
|
|
1002
|
+
if (kit.customFonts) {
|
|
1003
|
+
loadCustomFonts(kit.customFonts);
|
|
1004
|
+
}
|
|
1005
|
+
if (kit.fonts) {
|
|
1006
|
+
if (applyFonts) {
|
|
1007
|
+
const heading = quoteFamily(kit.fonts.heading);
|
|
1008
|
+
const body = quoteFamily(kit.fonts.body);
|
|
1009
|
+
for (const name of FONT_VARS.heading) root.style.setProperty(name, heading);
|
|
1010
|
+
for (const name of FONT_VARS.body) root.style.setProperty(name, body);
|
|
1011
|
+
const customFamilies = new Set((kit.customFonts ?? []).map((f) => f.family));
|
|
1012
|
+
const googleFamilies = [familyOf(kit.fonts.heading), familyOf(kit.fonts.body)].filter(
|
|
1013
|
+
(f) => !customFamilies.has(f)
|
|
975
1014
|
);
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
}
|
|
1015
|
+
loadBrandFonts(googleFamilies);
|
|
1016
|
+
} else {
|
|
1017
|
+
for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
|
|
1018
|
+
document.getElementById(BRAND_FONT_LINK_ID)?.remove();
|
|
981
1019
|
}
|
|
982
1020
|
}
|
|
983
1021
|
}
|
|
984
1022
|
|
|
1023
|
+
// src/lib/custom-code.ts
|
|
1024
|
+
var ALLOWED_HEAD_TAGS = /* @__PURE__ */ new Set(["style", "meta", "link", "script", "noscript", "base"]);
|
|
1025
|
+
var CUSTOM_CODE_AFTER_HEAD_KEY = "__ohw_custom_code_after_head";
|
|
1026
|
+
var CUSTOM_CODE_BEFORE_HEAD_KEY = "__ohw_custom_code_before_head";
|
|
1027
|
+
function clearExisting(slot) {
|
|
1028
|
+
document.querySelectorAll(`[data-ohw-custom-code="${slot}"]`).forEach((el) => el.remove());
|
|
1029
|
+
}
|
|
1030
|
+
function buildNodes(raw, slot) {
|
|
1031
|
+
if (!raw || !raw.trim()) return [];
|
|
1032
|
+
const parsed = new DOMParser().parseFromString(raw, "text/html");
|
|
1033
|
+
const source = [...parsed.head.childNodes, ...parsed.body.childNodes];
|
|
1034
|
+
const nodes = [];
|
|
1035
|
+
for (const node of source) {
|
|
1036
|
+
if (node.nodeType !== Node.ELEMENT_NODE) continue;
|
|
1037
|
+
const el = node;
|
|
1038
|
+
const tag = el.tagName.toLowerCase();
|
|
1039
|
+
if (!ALLOWED_HEAD_TAGS.has(tag)) continue;
|
|
1040
|
+
const built = document.createElement(tag);
|
|
1041
|
+
for (const attr of Array.from(el.attributes)) built.setAttribute(attr.name, attr.value);
|
|
1042
|
+
if (tag === "script" || tag === "style" || tag === "noscript") built.textContent = el.textContent;
|
|
1043
|
+
built.dataset.ohwCustomCode = slot;
|
|
1044
|
+
nodes.push(built);
|
|
1045
|
+
}
|
|
1046
|
+
return nodes;
|
|
1047
|
+
}
|
|
1048
|
+
function applyCustomCodeToHead(content) {
|
|
1049
|
+
clearExisting("after");
|
|
1050
|
+
clearExisting("before");
|
|
1051
|
+
const afterNodes = buildNodes(content[CUSTOM_CODE_AFTER_HEAD_KEY], "after");
|
|
1052
|
+
if (afterNodes.length > 0) document.head.prepend(...afterNodes);
|
|
1053
|
+
const beforeNodes = buildNodes(content[CUSTOM_CODE_BEFORE_HEAD_KEY], "before");
|
|
1054
|
+
if (beforeNodes.length > 0) document.head.append(...beforeNodes);
|
|
1055
|
+
}
|
|
1056
|
+
|
|
985
1057
|
// src/ui/ai-tree/aiSectionsManager.tsx
|
|
986
1058
|
import { flushSync } from "react-dom";
|
|
987
1059
|
import { createRoot } from "react-dom/client";
|
|
@@ -3229,7 +3301,9 @@ function AiTreeRenderer({
|
|
|
3229
3301
|
...band ? { buttonLabel: band.buttonLabel } : {}
|
|
3230
3302
|
};
|
|
3231
3303
|
const settings = tree.settings ?? {};
|
|
3232
|
-
const pad = AI_TREE_TOKENS.
|
|
3304
|
+
const pad = AI_TREE_TOKENS.sectionPaddingByScale[settings.verticalPadding ?? legacyVerticalPaddingAlias(settings.spacing) ?? "m"];
|
|
3305
|
+
const padCss = pad === 0 ? "0px" : `clamp(${Math.max(16, Math.round(pad * 0.5))}px, ${(pad / 9).toFixed(2)}vw, ${pad}px)`;
|
|
3306
|
+
const minHeightCss = settings.minHeight === "full" ? "var(--ohw-canvas-h, calc(100vh - 80px))" : settings.minHeight === "half" ? "calc(var(--ohw-canvas-h, 100vh) / 2)" : void 0;
|
|
3233
3307
|
const isOverlay = tree.scaffold === "overlay";
|
|
3234
3308
|
const overlayAlpha = { low: 0.25, medium: 0.45, high: 0.65 }[settings.overlayIntensity ?? "medium"];
|
|
3235
3309
|
const backgroundUrl = isOverlay && settings.backgroundMedia ? ctx.resolveMedia(settings.backgroundMedia) : null;
|
|
@@ -3268,7 +3342,9 @@ function AiTreeRenderer({
|
|
|
3268
3342
|
...bgAttrs,
|
|
3269
3343
|
style: {
|
|
3270
3344
|
position: "relative",
|
|
3271
|
-
padding: `${
|
|
3345
|
+
padding: `${padCss} 0`,
|
|
3346
|
+
minHeight: minHeightCss,
|
|
3347
|
+
boxSizing: "border-box",
|
|
3272
3348
|
background: toneBackground ?? (isOverlay && !backgroundUrl ? "#DBEAFE" : void 0),
|
|
3273
3349
|
backgroundImage: backgroundUrl ? `url(${backgroundUrl})` : void 0,
|
|
3274
3350
|
backgroundSize: "cover",
|
|
@@ -26175,19 +26251,20 @@ function OhhwellsBridge() {
|
|
|
26175
26251
|
let previousSections;
|
|
26176
26252
|
const store = parseStyleStore(value);
|
|
26177
26253
|
if (store) {
|
|
26178
|
-
const
|
|
26179
|
-
|
|
26180
|
-
|
|
26254
|
+
const foldedAlign = foldAlignIntoTrees(parseAiSectionsState(aiSectionsRef.current), store);
|
|
26255
|
+
const foldedHeight = foldSectionHeightIntoTrees(foldedAlign.state, foldedAlign.store);
|
|
26256
|
+
if (foldedAlign.changed || foldedHeight.changed) {
|
|
26257
|
+
const nextSections = serializeAiSectionsState(foldedHeight.state);
|
|
26181
26258
|
if (nextSections !== aiSectionsRef.current) {
|
|
26182
26259
|
previousSections = aiSectionsRef.current;
|
|
26183
26260
|
aiSectionsRef.current = nextSections;
|
|
26184
|
-
applyAiSectionsToDom(
|
|
26261
|
+
applyAiSectionsToDom(foldedHeight.state);
|
|
26185
26262
|
postToParentRef.current({
|
|
26186
26263
|
type: "ow:change",
|
|
26187
26264
|
nodes: [{ key: AI_SECTIONS_KEY, text: nextSections }]
|
|
26188
26265
|
});
|
|
26189
26266
|
}
|
|
26190
|
-
value = JSON.stringify(
|
|
26267
|
+
value = JSON.stringify(foldedHeight.store);
|
|
26191
26268
|
}
|
|
26192
26269
|
}
|
|
26193
26270
|
stylesRef.current = value;
|
|
@@ -26795,7 +26872,15 @@ function OhhwellsBridge() {
|
|
|
26795
26872
|
width: box.width,
|
|
26796
26873
|
height: box.height
|
|
26797
26874
|
} : null;
|
|
26798
|
-
|
|
26875
|
+
const settings = resolveSectionSettingsContext(sectionId, aiSectionsRef.current, stylesRef.current);
|
|
26876
|
+
postToParentRef.current({
|
|
26877
|
+
type: "ow:section-nodes",
|
|
26878
|
+
sectionId,
|
|
26879
|
+
found: !!sectionEl,
|
|
26880
|
+
nodes,
|
|
26881
|
+
rect,
|
|
26882
|
+
...settings ? { settings } : {}
|
|
26883
|
+
});
|
|
26799
26884
|
};
|
|
26800
26885
|
let selectionChangeRaf = null;
|
|
26801
26886
|
const runSelectionChange = () => {
|
|
@@ -27460,7 +27545,7 @@ function OhhwellsBridge() {
|
|
|
27460
27545
|
postToParent2({
|
|
27461
27546
|
type: "ow:ready",
|
|
27462
27547
|
version: "1",
|
|
27463
|
-
bridgeVersion: "0.1.
|
|
27548
|
+
bridgeVersion: "0.1.127",
|
|
27464
27549
|
path: pathname,
|
|
27465
27550
|
nodes: collectEditableNodes(editContentRef.current),
|
|
27466
27551
|
sections
|