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