@sevenfold/setto-client 0.34.0 → 0.36.0
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/blog/SettoBlog.d.ts +20 -0
- package/dist/blog/data.d.ts +36 -0
- package/dist/blog/index.d.ts +2 -0
- package/dist/blog/render.d.ts +16 -0
- package/dist/blog/strings.d.ts +25 -0
- package/dist/blog.js +13 -0
- package/dist/blog.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/lib/media.d.ts +16 -0
- package/dist/lib/optimized-image.d.ts +14 -2
- package/dist/pages/manifest.d.ts +18 -1
- package/dist/setto-client.js +762 -200
- package/dist/setto-client.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/vite/index.d.ts +6 -0
- package/dist/vite/plugin.d.ts +32 -0
- package/dist/vite/static.d.ts +78 -0
- package/dist/vite.js +550 -0
- package/dist/vite.js.map +1 -0
- package/package.json +10 -2
- package/virtual.d.ts +11 -0
package/dist/setto-client.js
CHANGED
|
@@ -21461,8 +21461,9 @@ class ThemeStore {
|
|
|
21461
21461
|
}
|
|
21462
21462
|
const PAGES_MANIFEST_VERSION = 1;
|
|
21463
21463
|
const PAGES_PATH = "src/content/pages.json";
|
|
21464
|
-
const BUILTIN_SECTION_TYPES = ["text"];
|
|
21464
|
+
const BUILTIN_SECTION_TYPES = ["text", "blog", "blog-latest"];
|
|
21465
21465
|
const ID = /^[a-z0-9][a-z0-9-]{0,62}$/;
|
|
21466
|
+
const POST_SLUG = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
21466
21467
|
const PATH = /^\/(?:[a-z0-9][a-z0-9-]*(?:\/[a-z0-9][a-z0-9-]*)*)?$/;
|
|
21467
21468
|
function isRecord$1(value) {
|
|
21468
21469
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -21529,6 +21530,15 @@ function parseManifest(input) {
|
|
|
21529
21530
|
sections
|
|
21530
21531
|
});
|
|
21531
21532
|
});
|
|
21533
|
+
const blogs = pages.flatMap(
|
|
21534
|
+
(p, i) => p.sections.flatMap((s, j) => s.type === "blog" ? [{ page: p, at: `pages[${i}].sections[${j}]` }] : [])
|
|
21535
|
+
);
|
|
21536
|
+
if (blogs.length > 1) {
|
|
21537
|
+
issues.push({ at: blogs[1].at, message: "a site has one blog; another blog section is already on a page" });
|
|
21538
|
+
}
|
|
21539
|
+
for (const blog of blogs) {
|
|
21540
|
+
if (blog.page.path === "/") issues.push({ at: blog.at, message: "the blog cannot be the front page" });
|
|
21541
|
+
}
|
|
21532
21542
|
const menu = parseMenu(input.menu, "menu", issues);
|
|
21533
21543
|
const footer2 = parseMenu(input.footer, "footer", issues);
|
|
21534
21544
|
if (issues.length > 0) return { ok: false, issues };
|
|
@@ -21572,7 +21582,23 @@ function normalisePath(path2) {
|
|
|
21572
21582
|
}
|
|
21573
21583
|
function pageForPath(manifest, path2) {
|
|
21574
21584
|
const wanted = normalisePath(path2);
|
|
21575
|
-
return manifest.pages.find((p) => p.path === wanted) ?? null;
|
|
21585
|
+
return manifest.pages.find((p) => p.path === wanted) ?? (blogSlugForPath(manifest, path2) ? blogPage(manifest).page : null);
|
|
21586
|
+
}
|
|
21587
|
+
function blogPage(manifest) {
|
|
21588
|
+
for (const page of manifest.pages) {
|
|
21589
|
+
const section = page.sections.find((s) => s.type === "blog");
|
|
21590
|
+
if (section) return { page, section };
|
|
21591
|
+
}
|
|
21592
|
+
return null;
|
|
21593
|
+
}
|
|
21594
|
+
function blogSlugForPath(manifest, path2) {
|
|
21595
|
+
const blog = blogPage(manifest);
|
|
21596
|
+
if (!blog || blog.page.path === "/") return null;
|
|
21597
|
+
const wanted = normalisePath(path2);
|
|
21598
|
+
const prefix = `${blog.page.path}/`;
|
|
21599
|
+
if (!wanted.startsWith(prefix)) return null;
|
|
21600
|
+
const slug = wanted.slice(prefix.length);
|
|
21601
|
+
return slug.length <= 80 && POST_SLUG.test(slug) ? slug : null;
|
|
21576
21602
|
}
|
|
21577
21603
|
function pageById(manifest, id) {
|
|
21578
21604
|
return manifest.pages.find((p) => p.id === id) ?? null;
|
|
@@ -22124,7 +22150,7 @@ function withoutCheckoutIntent() {
|
|
|
22124
22150
|
}
|
|
22125
22151
|
const FAB_SIZE = 52;
|
|
22126
22152
|
const FAB_INSET = 16;
|
|
22127
|
-
const STYLE_ID$
|
|
22153
|
+
const STYLE_ID$3 = "setto-edit-layout";
|
|
22128
22154
|
const HTML_CLASS = "setto-edit-mode";
|
|
22129
22155
|
function useSettoDocumentLayout(active) {
|
|
22130
22156
|
useEffect(() => {
|
|
@@ -22133,10 +22159,10 @@ function useSettoDocumentLayout(active) {
|
|
|
22133
22159
|
html2.classList.add(HTML_CLASS);
|
|
22134
22160
|
html2.style.setProperty("--setto-fab-size", `${FAB_SIZE}px`);
|
|
22135
22161
|
html2.style.setProperty("--setto-fab-inset", `${FAB_INSET}px`);
|
|
22136
|
-
let styleEl = document.getElementById(STYLE_ID$
|
|
22162
|
+
let styleEl = document.getElementById(STYLE_ID$3);
|
|
22137
22163
|
if (!styleEl) {
|
|
22138
22164
|
styleEl = document.createElement("style");
|
|
22139
|
-
styleEl.id = STYLE_ID$
|
|
22165
|
+
styleEl.id = STYLE_ID$3;
|
|
22140
22166
|
styleEl.textContent = `
|
|
22141
22167
|
html.setto-edit-mode {
|
|
22142
22168
|
width: 100%;
|
|
@@ -33040,7 +33066,7 @@ function formatHeadingAsSetext(node2, state) {
|
|
|
33040
33066
|
);
|
|
33041
33067
|
}
|
|
33042
33068
|
function heading(node2, _, state, info) {
|
|
33043
|
-
const
|
|
33069
|
+
const rank2 = Math.max(Math.min(6, node2.depth || 1), 1);
|
|
33044
33070
|
const tracker = state.createTracker(info);
|
|
33045
33071
|
if (formatHeadingAsSetext(node2, state)) {
|
|
33046
33072
|
const exit3 = state.enter("headingSetext");
|
|
@@ -33052,14 +33078,14 @@ function heading(node2, _, state, info) {
|
|
|
33052
33078
|
});
|
|
33053
33079
|
subexit2();
|
|
33054
33080
|
exit3();
|
|
33055
|
-
return value2 + "\n" + (
|
|
33081
|
+
return value2 + "\n" + (rank2 === 1 ? "=" : "-").repeat(
|
|
33056
33082
|
// The whole size…
|
|
33057
33083
|
value2.length - // Minus the position of the character after the last EOL (or
|
|
33058
33084
|
// 0 if there is none)…
|
|
33059
33085
|
(Math.max(value2.lastIndexOf("\r"), value2.lastIndexOf("\n")) + 1)
|
|
33060
33086
|
);
|
|
33061
33087
|
}
|
|
33062
|
-
const sequence = "#".repeat(
|
|
33088
|
+
const sequence = "#".repeat(rank2);
|
|
33063
33089
|
const exit2 = state.enter("headingAtx");
|
|
33064
33090
|
const subexit = state.enter("phrasing");
|
|
33065
33091
|
tracker.move(sequence + " ");
|
|
@@ -37714,6 +37740,18 @@ function SettoIcon({ k, icons, size = 24, className, style }) {
|
|
|
37714
37740
|
)
|
|
37715
37741
|
] });
|
|
37716
37742
|
}
|
|
37743
|
+
const SETTO_MEDIA_HOST = "3adyw42hy72dtzjo.public.blob.vercel-storage.com";
|
|
37744
|
+
const SETTO_MEDIA_BLOG_PREFIX = "/blog/";
|
|
37745
|
+
function isSettoMediaUrl(src) {
|
|
37746
|
+
if (!src) return false;
|
|
37747
|
+
try {
|
|
37748
|
+
const url = new URL(src);
|
|
37749
|
+
return url.protocol === "https:" && url.hostname === SETTO_MEDIA_HOST && !url.username && !url.password && url.port === "" && url.pathname.startsWith(SETTO_MEDIA_BLOG_PREFIX);
|
|
37750
|
+
} catch {
|
|
37751
|
+
return false;
|
|
37752
|
+
}
|
|
37753
|
+
}
|
|
37754
|
+
const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
37717
37755
|
const SETTO_IMAGE_WIDTHS = [384, 640, 828, 1080, 1440, 1920, 2560];
|
|
37718
37756
|
const SETTO_IMAGE_QUALITY = 75;
|
|
37719
37757
|
const settoVercelImagesConfig = {
|
|
@@ -37721,12 +37759,23 @@ const settoVercelImagesConfig = {
|
|
|
37721
37759
|
qualities: [SETTO_IMAGE_QUALITY],
|
|
37722
37760
|
formats: ["image/avif", "image/webp"],
|
|
37723
37761
|
localPatterns: [{ pathname: "^/images/.*$", search: "" }],
|
|
37762
|
+
// Vercel reads hostname and pathname as regular expressions; anchored so a
|
|
37763
|
+
// look-alike host cannot borrow the optimizer. Checked on a deployment
|
|
37764
|
+
// (R24): this form resizes, an unlisted host or path is refused with 400.
|
|
37765
|
+
remotePatterns: [
|
|
37766
|
+
{
|
|
37767
|
+
protocol: "https",
|
|
37768
|
+
hostname: `^${escapeRegExp(SETTO_MEDIA_HOST)}$`,
|
|
37769
|
+
pathname: `^${escapeRegExp(SETTO_MEDIA_BLOG_PREFIX)}.*$`
|
|
37770
|
+
}
|
|
37771
|
+
],
|
|
37724
37772
|
minimumCacheTTL: 2678400
|
|
37725
37773
|
};
|
|
37726
37774
|
const OPTIMIZABLE = /\.(jpe?g|png|webp|avif)$/i;
|
|
37727
37775
|
function isOptimizable(src) {
|
|
37728
|
-
if (!src
|
|
37729
|
-
return OPTIMIZABLE.test(src.split(/[?#]/)[0]);
|
|
37776
|
+
if (!src) return false;
|
|
37777
|
+
if (src.startsWith("/images/")) return OPTIMIZABLE.test(src.split(/[?#]/)[0]);
|
|
37778
|
+
return isSettoMediaUrl(src) && OPTIMIZABLE.test(new URL(src).pathname);
|
|
37730
37779
|
}
|
|
37731
37780
|
function hasNoOptimizer(hostname) {
|
|
37732
37781
|
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]" || hostname.endsWith(".localhost");
|
|
@@ -37980,12 +38029,12 @@ function SettoImage({ srcKey, alt, className, style, ...rest }) {
|
|
|
37980
38029
|
)
|
|
37981
38030
|
] });
|
|
37982
38031
|
}
|
|
37983
|
-
const STYLE_ID$
|
|
38032
|
+
const STYLE_ID$2 = "setto-repeater-styles";
|
|
37984
38033
|
function useRepeaterStyles() {
|
|
37985
38034
|
useEffect(() => {
|
|
37986
|
-
if (document.getElementById(STYLE_ID$
|
|
38035
|
+
if (document.getElementById(STYLE_ID$2)) return;
|
|
37987
38036
|
const el = document.createElement("style");
|
|
37988
|
-
el.id = STYLE_ID$
|
|
38037
|
+
el.id = STYLE_ID$2;
|
|
37989
38038
|
el.textContent = `
|
|
37990
38039
|
.setto-repeater-remove {
|
|
37991
38040
|
opacity: 0;
|
|
@@ -38111,6 +38160,695 @@ const removeBtnStyle = {
|
|
|
38111
38160
|
boxShadow: "0 1px 4px rgba(0,0,0,0.18)",
|
|
38112
38161
|
fontFamily: 'system-ui, -apple-system, "Segoe UI", sans-serif'
|
|
38113
38162
|
};
|
|
38163
|
+
function usePageManifest() {
|
|
38164
|
+
const { pageStore, config } = useSetto();
|
|
38165
|
+
const snap = useSyncExternalStore(
|
|
38166
|
+
(cb) => pageStore?.subscribe(() => cb()) ?? (() => {
|
|
38167
|
+
}),
|
|
38168
|
+
() => pageStore?.snapshot() ?? EMPTY_PAGE_STORE_SNAPSHOT,
|
|
38169
|
+
() => pageStore?.snapshot() ?? EMPTY_PAGE_STORE_SNAPSHOT
|
|
38170
|
+
);
|
|
38171
|
+
return pageStore ? snap.manifest : bundledManifest(config.pages);
|
|
38172
|
+
}
|
|
38173
|
+
function useSettoMenu(list2 = "menu") {
|
|
38174
|
+
const manifest = usePageManifest();
|
|
38175
|
+
return manifest ? visibleMenu(manifest, list2) : null;
|
|
38176
|
+
}
|
|
38177
|
+
function SettoPage({ pageId, path: path2, sections = {}, builtins, fallback = null }) {
|
|
38178
|
+
const manifest = usePageManifest();
|
|
38179
|
+
const { editMode } = useSetto();
|
|
38180
|
+
if (!manifest) {
|
|
38181
|
+
if (!pageId && path2 !== void 0 && path2 !== "/" && path2 !== "") return /* @__PURE__ */ jsx(Fragment, { children: fallback });
|
|
38182
|
+
return /* @__PURE__ */ jsx(Fragment, { children: Object.entries(sections).map(([id, Component]) => /* @__PURE__ */ jsx(Component, {}, id)) });
|
|
38183
|
+
}
|
|
38184
|
+
const page = pageId ? pageById(manifest, pageId) : pageForPath(manifest, path2 ?? "/");
|
|
38185
|
+
if (!page) {
|
|
38186
|
+
if (pageId) {
|
|
38187
|
+
return /* @__PURE__ */ jsx(Fragment, { children: Object.entries(sections).map(([id, Component]) => /* @__PURE__ */ jsx(Component, {}, id)) });
|
|
38188
|
+
}
|
|
38189
|
+
return /* @__PURE__ */ jsx(Fragment, { children: fallback });
|
|
38190
|
+
}
|
|
38191
|
+
if (page.hidden && !editMode) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
|
|
38192
|
+
return /* @__PURE__ */ jsx(PageBody, { page, sections, builtins, editMode, manifest });
|
|
38193
|
+
}
|
|
38194
|
+
function PageBody({
|
|
38195
|
+
page,
|
|
38196
|
+
sections,
|
|
38197
|
+
builtins,
|
|
38198
|
+
editMode,
|
|
38199
|
+
manifest
|
|
38200
|
+
}) {
|
|
38201
|
+
usePageTitle(page);
|
|
38202
|
+
const HiddenPageNote = useSettoChromeSlot("hidden-page");
|
|
38203
|
+
const listed = new Set(manifest.pages.flatMap((p) => p.sections.map((s) => s.id)));
|
|
38204
|
+
const unlisted = Object.keys(sections).filter((id) => !listed.has(id));
|
|
38205
|
+
const firstVisible = page.sections.find((s) => !s.hidden && (s.type || sections[s.id]))?.id;
|
|
38206
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38207
|
+
page.hidden && editMode ? HiddenPageNote ? /* @__PURE__ */ jsx(HiddenPageNote, { pageId: page.id }) : /* @__PURE__ */ jsx(HiddenNote, { text: "Denne siden er skjult for besøkende." }) : null,
|
|
38208
|
+
page.sections.map((section) => /* @__PURE__ */ jsx(Fragment$1, { children: renderSection(section, sections, builtins, editMode, section.id === firstVisible) }, section.id)),
|
|
38209
|
+
unlisted.map((id) => {
|
|
38210
|
+
const Component = sections[id];
|
|
38211
|
+
return /* @__PURE__ */ jsx(Component, {}, id);
|
|
38212
|
+
})
|
|
38213
|
+
] });
|
|
38214
|
+
}
|
|
38215
|
+
function renderSection(section, sections, builtins, editMode, first) {
|
|
38216
|
+
if (section.hidden) {
|
|
38217
|
+
return editMode ? /* @__PURE__ */ jsx(HiddenSection, { section }) : null;
|
|
38218
|
+
}
|
|
38219
|
+
if (section.type) {
|
|
38220
|
+
const Builtin = builtins?.[section.type] ?? BUILTIN_RENDERERS[section.type];
|
|
38221
|
+
return /* @__PURE__ */ jsx(Builtin, { sectionId: section.id, first });
|
|
38222
|
+
}
|
|
38223
|
+
const Component = sections[section.id];
|
|
38224
|
+
if (!Component) {
|
|
38225
|
+
warnOnce(section.id);
|
|
38226
|
+
return null;
|
|
38227
|
+
}
|
|
38228
|
+
return /* @__PURE__ */ jsx(Component, {});
|
|
38229
|
+
}
|
|
38230
|
+
const warned = /* @__PURE__ */ new Set();
|
|
38231
|
+
function warnOnce(id) {
|
|
38232
|
+
if (warned.has(id)) return;
|
|
38233
|
+
warned.add(id);
|
|
38234
|
+
console.warn(`[setto] section "${id}" is in pages.json but the page does not provide it`);
|
|
38235
|
+
}
|
|
38236
|
+
function HiddenSection({ section }) {
|
|
38237
|
+
const { pageStore } = useSetto();
|
|
38238
|
+
const Offered = useSettoChromeSlot("hidden-section");
|
|
38239
|
+
const label = section.label ?? section.id;
|
|
38240
|
+
if (Offered) return /* @__PURE__ */ jsx(Offered, { sectionId: section.id, label });
|
|
38241
|
+
return /* @__PURE__ */ jsxs("div", { "data-setto-ui": true, style: hiddenBarStyle, children: [
|
|
38242
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
38243
|
+
"Skjult: ",
|
|
38244
|
+
label
|
|
38245
|
+
] }),
|
|
38246
|
+
pageStore ? /* @__PURE__ */ jsx(
|
|
38247
|
+
"button",
|
|
38248
|
+
{
|
|
38249
|
+
type: "button",
|
|
38250
|
+
"data-setto-ui": true,
|
|
38251
|
+
style: hiddenBtnStyle,
|
|
38252
|
+
onClick: () => pageStore.apply([{ op: "show_section", sectionId: section.id }]),
|
|
38253
|
+
children: "Vis"
|
|
38254
|
+
}
|
|
38255
|
+
) : null
|
|
38256
|
+
] });
|
|
38257
|
+
}
|
|
38258
|
+
function HiddenNote({ text: text2 }) {
|
|
38259
|
+
return /* @__PURE__ */ jsx("div", { "data-setto-ui": true, style: hiddenBarStyle, children: /* @__PURE__ */ jsx("span", { children: text2 }) });
|
|
38260
|
+
}
|
|
38261
|
+
function usePageTitle(page) {
|
|
38262
|
+
const { t } = useTranslation();
|
|
38263
|
+
const original = useRef(null);
|
|
38264
|
+
const title = page.path === "/" ? null : t(page.titleKey);
|
|
38265
|
+
useEffect(() => {
|
|
38266
|
+
if (!title || typeof document === "undefined") return;
|
|
38267
|
+
original.current ??= document.title;
|
|
38268
|
+
const base = original.current;
|
|
38269
|
+
document.title = base ? `${title} · ${base}` : title;
|
|
38270
|
+
return () => {
|
|
38271
|
+
document.title = base;
|
|
38272
|
+
};
|
|
38273
|
+
}, [title]);
|
|
38274
|
+
}
|
|
38275
|
+
function SettoTextSection({ sectionId, first }) {
|
|
38276
|
+
const keys2 = builtinKeys(sectionId);
|
|
38277
|
+
const { i18n } = useTranslation();
|
|
38278
|
+
const { store, editMode } = useSetto();
|
|
38279
|
+
const intro2 = store ? store.get(keys2.intro, i18n.language) : i18n.t(keys2.intro, { defaultValue: "" });
|
|
38280
|
+
const Heading = first ? "h1" : "h2";
|
|
38281
|
+
return /* @__PURE__ */ jsx(SettoSection, { sectionId, style: textSectionStyle, children: /* @__PURE__ */ jsxs("div", { style: textInnerStyle, children: [
|
|
38282
|
+
/* @__PURE__ */ jsx(Heading, { style: first ? textH1Style : textH2Style, children: /* @__PURE__ */ jsx(T, { k: keys2.heading }) }),
|
|
38283
|
+
intro2 || editMode ? /* @__PURE__ */ jsx("p", { style: textIntroStyle, children: /* @__PURE__ */ jsx(T, { k: keys2.intro }) }) : null,
|
|
38284
|
+
/* @__PURE__ */ jsx(
|
|
38285
|
+
SettoRepeater,
|
|
38286
|
+
{
|
|
38287
|
+
itemsKey: keys2.items,
|
|
38288
|
+
defaultItem: { heading: "Overskrift", text: "Tekst" },
|
|
38289
|
+
itemLabel: "avsnitt",
|
|
38290
|
+
children: (itemKey) => /* @__PURE__ */ jsx(TextItem, { sectionId, itemKey })
|
|
38291
|
+
}
|
|
38292
|
+
)
|
|
38293
|
+
] }) });
|
|
38294
|
+
}
|
|
38295
|
+
function TextItem({ sectionId, itemKey }) {
|
|
38296
|
+
const keys2 = builtinKeys(sectionId);
|
|
38297
|
+
const { i18n } = useTranslation();
|
|
38298
|
+
const { store, editMode } = useSetto();
|
|
38299
|
+
const heading2 = store ? store.get(keys2.itemHeading(itemKey), i18n.language) : i18n.t(keys2.itemHeading(itemKey), { defaultValue: "" });
|
|
38300
|
+
return /* @__PURE__ */ jsxs("div", { style: textItemStyle, children: [
|
|
38301
|
+
heading2 || editMode ? /* @__PURE__ */ jsx("h3", { style: textH3Style, children: /* @__PURE__ */ jsx(T, { k: keys2.itemHeading(itemKey) }) }) : null,
|
|
38302
|
+
/* @__PURE__ */ jsx("p", { style: textParagraphStyle, children: /* @__PURE__ */ jsx(T, { k: keys2.itemText(itemKey) }) })
|
|
38303
|
+
] });
|
|
38304
|
+
}
|
|
38305
|
+
const BUILTIN_RENDERERS = {
|
|
38306
|
+
text: SettoTextSection,
|
|
38307
|
+
blog: SettoBlogSection,
|
|
38308
|
+
"blog-latest": SettoBlogLatest
|
|
38309
|
+
};
|
|
38310
|
+
const textSectionStyle = { padding: "clamp(48px, 8vw, 96px) 16px" };
|
|
38311
|
+
const textInnerStyle = { maxWidth: "68ch", margin: "0 auto" };
|
|
38312
|
+
const textH1Style = {
|
|
38313
|
+
fontFamily: "var(--setto-display-font, inherit)",
|
|
38314
|
+
fontSize: "clamp(2rem, 4vw, 2.75rem)",
|
|
38315
|
+
lineHeight: 1.15,
|
|
38316
|
+
fontWeight: 600,
|
|
38317
|
+
margin: "0 0 0.75em"
|
|
38318
|
+
};
|
|
38319
|
+
const textH2Style = { ...textH1Style, fontSize: "clamp(1.5rem, 3vw, 2rem)" };
|
|
38320
|
+
const textH3Style = {
|
|
38321
|
+
fontFamily: "var(--setto-display-font, inherit)",
|
|
38322
|
+
fontSize: "1.125rem",
|
|
38323
|
+
lineHeight: 1.3,
|
|
38324
|
+
fontWeight: 600,
|
|
38325
|
+
margin: "0 0 0.4em"
|
|
38326
|
+
};
|
|
38327
|
+
const textIntroStyle = { fontSize: "1.125rem", lineHeight: 1.6, opacity: 0.85, margin: "0 0 2em" };
|
|
38328
|
+
const textItemStyle = { margin: "0 0 1.75em" };
|
|
38329
|
+
const textParagraphStyle = { lineHeight: 1.7, margin: 0, whiteSpace: "pre-line" };
|
|
38330
|
+
const hiddenBarStyle = {
|
|
38331
|
+
display: "flex",
|
|
38332
|
+
alignItems: "center",
|
|
38333
|
+
justifyContent: "center",
|
|
38334
|
+
gap: 12,
|
|
38335
|
+
padding: "10px 16px",
|
|
38336
|
+
margin: "4px 0",
|
|
38337
|
+
border: "1px dashed rgba(100, 10, 255, 0.45)",
|
|
38338
|
+
borderRadius: 8,
|
|
38339
|
+
background: "rgba(100, 10, 255, 0.05)",
|
|
38340
|
+
color: "#3b2a66",
|
|
38341
|
+
font: '500 13px system-ui, -apple-system, "Segoe UI", sans-serif'
|
|
38342
|
+
};
|
|
38343
|
+
const hiddenBtnStyle = {
|
|
38344
|
+
border: "none",
|
|
38345
|
+
borderRadius: 999,
|
|
38346
|
+
padding: "4px 12px",
|
|
38347
|
+
background: "#640AFF",
|
|
38348
|
+
color: "#fff",
|
|
38349
|
+
font: '600 12px system-ui, -apple-system, "Segoe UI", sans-serif',
|
|
38350
|
+
cursor: "pointer"
|
|
38351
|
+
};
|
|
38352
|
+
const BLOG_ROUTE = "/blogg";
|
|
38353
|
+
const BLOG_SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
38354
|
+
const BLOG_SLUG_MAX = 80;
|
|
38355
|
+
const YOUTUBE_ID_PATTERN = /^[A-Za-z0-9_-]{11}$/;
|
|
38356
|
+
function isValidBlogSlug(slug) {
|
|
38357
|
+
return slug.length <= BLOG_SLUG_MAX && BLOG_SLUG_PATTERN.test(slug);
|
|
38358
|
+
}
|
|
38359
|
+
function byDateDesc(a, b) {
|
|
38360
|
+
return a.date === b.date ? a.slug.localeCompare(b.slug) : a.date < b.date ? 1 : -1;
|
|
38361
|
+
}
|
|
38362
|
+
function postsForLanguage(posts, language, fallbackLanguage) {
|
|
38363
|
+
const bySlug = /* @__PURE__ */ new Map();
|
|
38364
|
+
for (const post2 of posts) {
|
|
38365
|
+
const current = bySlug.get(post2.slug);
|
|
38366
|
+
if (!current || rank(post2, language, fallbackLanguage) < rank(current, language, fallbackLanguage)) {
|
|
38367
|
+
bySlug.set(post2.slug, post2);
|
|
38368
|
+
}
|
|
38369
|
+
}
|
|
38370
|
+
return [...bySlug.values()].sort(byDateDesc);
|
|
38371
|
+
}
|
|
38372
|
+
function postForSlug(posts, slug, language, fallbackLanguage) {
|
|
38373
|
+
return postsForLanguage(posts.filter((p) => p.slug === slug), language, fallbackLanguage)[0] ?? null;
|
|
38374
|
+
}
|
|
38375
|
+
function rank(post2, language, fallbackLanguage) {
|
|
38376
|
+
if (post2.locale === language) return 0;
|
|
38377
|
+
if (post2.locale === fallbackLanguage) return 1;
|
|
38378
|
+
return 2;
|
|
38379
|
+
}
|
|
38380
|
+
function formatPostDate(date, language) {
|
|
38381
|
+
const parsed = /* @__PURE__ */ new Date(`${date}T12:00:00Z`);
|
|
38382
|
+
if (Number.isNaN(parsed.getTime())) return date;
|
|
38383
|
+
const locale = language === "no" || language === "nb" || language === "nn" ? "nb-NO" : language;
|
|
38384
|
+
try {
|
|
38385
|
+
return new Intl.DateTimeFormat(locale, { day: "numeric", month: "long", year: "numeric", timeZone: "UTC" }).format(parsed);
|
|
38386
|
+
} catch {
|
|
38387
|
+
return date;
|
|
38388
|
+
}
|
|
38389
|
+
}
|
|
38390
|
+
const NO = {
|
|
38391
|
+
blog: "Blogg",
|
|
38392
|
+
latest: "Fra bloggen",
|
|
38393
|
+
allPosts: "Alle innlegg",
|
|
38394
|
+
readMore: "Les mer",
|
|
38395
|
+
back: "Alle innlegg",
|
|
38396
|
+
empty: "Ingen innlegg ennå.",
|
|
38397
|
+
notFound: "Fant ikke innlegget.",
|
|
38398
|
+
loading: "Henter innlegget …",
|
|
38399
|
+
share: "Del",
|
|
38400
|
+
moreShare: "Flere valg …",
|
|
38401
|
+
copyLink: "Kopier lenke",
|
|
38402
|
+
copied: "Lenken er kopiert",
|
|
38403
|
+
email: "E-post",
|
|
38404
|
+
video: "Video",
|
|
38405
|
+
play: "Spill av"
|
|
38406
|
+
};
|
|
38407
|
+
const EN = {
|
|
38408
|
+
blog: "Blog",
|
|
38409
|
+
latest: "From the blog",
|
|
38410
|
+
allPosts: "All posts",
|
|
38411
|
+
readMore: "Read more",
|
|
38412
|
+
back: "All posts",
|
|
38413
|
+
empty: "No posts yet.",
|
|
38414
|
+
notFound: "That post could not be found.",
|
|
38415
|
+
loading: "Loading the post …",
|
|
38416
|
+
share: "Share",
|
|
38417
|
+
moreShare: "More …",
|
|
38418
|
+
copyLink: "Copy link",
|
|
38419
|
+
copied: "Link copied",
|
|
38420
|
+
email: "Email",
|
|
38421
|
+
video: "Video",
|
|
38422
|
+
play: "Play"
|
|
38423
|
+
};
|
|
38424
|
+
function blogStrings(language) {
|
|
38425
|
+
return language === "no" || language === "nb" || language === "nn" ? NO : EN;
|
|
38426
|
+
}
|
|
38427
|
+
function BlogBody({ nodes, language }) {
|
|
38428
|
+
return /* @__PURE__ */ jsx(Fragment, { children: nodes.map((node2, i) => renderFlow(node2, i, language)) });
|
|
38429
|
+
}
|
|
38430
|
+
function renderFlow(node2, key, language) {
|
|
38431
|
+
switch (node2.type) {
|
|
38432
|
+
case "paragraph":
|
|
38433
|
+
return /* @__PURE__ */ jsx("p", { children: renderPhrasing(node2.children) }, key);
|
|
38434
|
+
case "heading": {
|
|
38435
|
+
const Tag = node2.depth === 2 ? "h2" : node2.depth === 3 ? "h3" : "h4";
|
|
38436
|
+
return /* @__PURE__ */ jsx(Tag, { children: renderPhrasing(node2.children) }, key);
|
|
38437
|
+
}
|
|
38438
|
+
case "list": {
|
|
38439
|
+
const items = node2.children.map((item, i) => /* @__PURE__ */ jsx("li", { children: item.children.map((child, j) => renderListChild(child, j, item.spread === true, language)) }, i));
|
|
38440
|
+
return node2.ordered ? /* @__PURE__ */ jsx("ol", { start: node2.start ?? void 0, children: items }, key) : /* @__PURE__ */ jsx("ul", { children: items }, key);
|
|
38441
|
+
}
|
|
38442
|
+
case "blockquote":
|
|
38443
|
+
return /* @__PURE__ */ jsx("blockquote", { children: node2.children.map((child, i) => renderFlow(child, i, language)) }, key);
|
|
38444
|
+
case "thematicBreak":
|
|
38445
|
+
return /* @__PURE__ */ jsx("hr", {}, key);
|
|
38446
|
+
case "code":
|
|
38447
|
+
return /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: node2.value }) }, key);
|
|
38448
|
+
case "table":
|
|
38449
|
+
return /* @__PURE__ */ jsx(BlogTable, { table: node2 }, key);
|
|
38450
|
+
case "mdxJsxFlowElement":
|
|
38451
|
+
return /* @__PURE__ */ jsx(BlogComponent, { element: node2, language }, key);
|
|
38452
|
+
default:
|
|
38453
|
+
return null;
|
|
38454
|
+
}
|
|
38455
|
+
}
|
|
38456
|
+
function renderListChild(child, key, spread, language) {
|
|
38457
|
+
if (child.type === "paragraph" && !spread) return /* @__PURE__ */ jsx("span", { children: renderPhrasing(child.children) }, key);
|
|
38458
|
+
return renderFlow(child, key, language);
|
|
38459
|
+
}
|
|
38460
|
+
function renderPhrasing(children) {
|
|
38461
|
+
return children.map((child, i) => {
|
|
38462
|
+
switch (child.type) {
|
|
38463
|
+
case "text":
|
|
38464
|
+
return child.value;
|
|
38465
|
+
case "emphasis":
|
|
38466
|
+
return /* @__PURE__ */ jsx("em", { children: renderPhrasing(child.children) }, i);
|
|
38467
|
+
case "strong":
|
|
38468
|
+
return /* @__PURE__ */ jsx("strong", { children: renderPhrasing(child.children) }, i);
|
|
38469
|
+
case "delete":
|
|
38470
|
+
return /* @__PURE__ */ jsx("del", { children: renderPhrasing(child.children) }, i);
|
|
38471
|
+
case "inlineCode":
|
|
38472
|
+
return /* @__PURE__ */ jsx("code", { children: child.value }, i);
|
|
38473
|
+
case "break":
|
|
38474
|
+
return /* @__PURE__ */ jsx("br", {}, i);
|
|
38475
|
+
case "link": {
|
|
38476
|
+
const safe = isSafeHref(child.url);
|
|
38477
|
+
if (!safe) return /* @__PURE__ */ jsx("span", { children: renderPhrasing(child.children) }, i);
|
|
38478
|
+
const external = /^https?:\/\//i.test(child.url);
|
|
38479
|
+
return /* @__PURE__ */ jsx("a", { href: child.url, ...external ? { rel: "noopener noreferrer" } : {}, children: renderPhrasing(child.children) }, i);
|
|
38480
|
+
}
|
|
38481
|
+
default:
|
|
38482
|
+
return null;
|
|
38483
|
+
}
|
|
38484
|
+
});
|
|
38485
|
+
}
|
|
38486
|
+
function BlogTable({ table: table2 }) {
|
|
38487
|
+
const [head2, ...rows] = table2.children;
|
|
38488
|
+
const align = (i) => table2.align?.[i] ?? void 0;
|
|
38489
|
+
return /* @__PURE__ */ jsx("div", { className: "setto-blog__table", children: /* @__PURE__ */ jsxs("table", { children: [
|
|
38490
|
+
head2 ? /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: head2.children.map((cell, i) => /* @__PURE__ */ jsx("th", { style: { textAlign: align(i) }, children: renderPhrasing(cell.children) }, i)) }) }) : null,
|
|
38491
|
+
/* @__PURE__ */ jsx("tbody", { children: rows.map((row, r) => /* @__PURE__ */ jsx("tr", { children: row.children.map((cell, i) => /* @__PURE__ */ jsx("td", { style: { textAlign: align(i) }, children: renderPhrasing(cell.children) }, i)) }, r)) })
|
|
38492
|
+
] }) });
|
|
38493
|
+
}
|
|
38494
|
+
function attrs(element2) {
|
|
38495
|
+
const out = {};
|
|
38496
|
+
for (const attribute of element2.attributes) {
|
|
38497
|
+
const a = attribute;
|
|
38498
|
+
if (a.type === "mdxJsxAttribute" && typeof a.value === "string") out[a.name] = a.value;
|
|
38499
|
+
}
|
|
38500
|
+
return out;
|
|
38501
|
+
}
|
|
38502
|
+
function BlogComponent({ element: element2, language }) {
|
|
38503
|
+
const props = attrs(element2);
|
|
38504
|
+
switch (element2.name) {
|
|
38505
|
+
case "Image":
|
|
38506
|
+
return props.src && props.alt !== void 0 ? /* @__PURE__ */ jsxs("figure", { className: "setto-blog__figure", children: [
|
|
38507
|
+
/* @__PURE__ */ jsx(BlogImg, { src: props.src, alt: props.alt, sizes: "(min-width: 760px) 720px, 100vw" }),
|
|
38508
|
+
props.caption ? /* @__PURE__ */ jsx("figcaption", { children: props.caption }) : null
|
|
38509
|
+
] }) : null;
|
|
38510
|
+
case "Gallery": {
|
|
38511
|
+
const images = element2.children.filter(
|
|
38512
|
+
(child) => child.type === "mdxJsxFlowElement" && child.name === "Image"
|
|
38513
|
+
);
|
|
38514
|
+
return /* @__PURE__ */ jsxs("figure", { className: "setto-blog__gallery", children: [
|
|
38515
|
+
/* @__PURE__ */ jsx("div", { className: "setto-blog__gallery-grid", children: images.map((image2, i) => {
|
|
38516
|
+
const a = attrs(image2);
|
|
38517
|
+
return a.src ? /* @__PURE__ */ jsxs("figure", { className: "setto-blog__gallery-item", children: [
|
|
38518
|
+
/* @__PURE__ */ jsx(BlogImg, { src: a.src, alt: a.alt ?? "", sizes: "(min-width: 760px) 360px, 50vw" }),
|
|
38519
|
+
a.caption ? /* @__PURE__ */ jsx("figcaption", { children: a.caption }) : null
|
|
38520
|
+
] }, i) : null;
|
|
38521
|
+
}) }),
|
|
38522
|
+
props.caption ? /* @__PURE__ */ jsx("figcaption", { children: props.caption }) : null
|
|
38523
|
+
] });
|
|
38524
|
+
}
|
|
38525
|
+
case "YouTube":
|
|
38526
|
+
return props.id && YOUTUBE_ID_PATTERN.test(props.id) ? /* @__PURE__ */ jsx(YouTubeEmbed, { id: props.id, title: props.title, language }) : null;
|
|
38527
|
+
case "Callout":
|
|
38528
|
+
return /* @__PURE__ */ jsx("aside", { className: "setto-blog__callout", "data-tone": props.tone ?? "info", children: element2.children.map((child, i) => renderFlow(child, i, language)) });
|
|
38529
|
+
default:
|
|
38530
|
+
return null;
|
|
38531
|
+
}
|
|
38532
|
+
}
|
|
38533
|
+
function BlogImg({ src, alt, sizes, className }) {
|
|
38534
|
+
const { config } = useSetto();
|
|
38535
|
+
const [failed, setFailed] = useState(false);
|
|
38536
|
+
const optimize = config.images?.optimize === true && !failed && isOptimizable(src) && !(typeof window !== "undefined" && hasNoOptimizer(window.location.hostname));
|
|
38537
|
+
if (!optimize) return /* @__PURE__ */ jsx("img", { src, alt, loading: "lazy", decoding: "async", className });
|
|
38538
|
+
return /* @__PURE__ */ jsx(
|
|
38539
|
+
"img",
|
|
38540
|
+
{
|
|
38541
|
+
src: optimizedUrl(src, 1080),
|
|
38542
|
+
srcSet: optimizedSrcSet(src),
|
|
38543
|
+
sizes,
|
|
38544
|
+
alt,
|
|
38545
|
+
loading: "lazy",
|
|
38546
|
+
decoding: "async",
|
|
38547
|
+
className,
|
|
38548
|
+
onError: () => setFailed(true)
|
|
38549
|
+
}
|
|
38550
|
+
);
|
|
38551
|
+
}
|
|
38552
|
+
function YouTubeEmbed({ id, title, language }) {
|
|
38553
|
+
const [playing, setPlaying] = useState(false);
|
|
38554
|
+
const strings = blogStrings(language);
|
|
38555
|
+
const label = title ?? strings.video;
|
|
38556
|
+
return /* @__PURE__ */ jsxs("figure", { className: "setto-blog__video", children: [
|
|
38557
|
+
/* @__PURE__ */ jsx("div", { className: "setto-blog__video-frame", children: playing ? /* @__PURE__ */ jsx(
|
|
38558
|
+
"iframe",
|
|
38559
|
+
{
|
|
38560
|
+
src: `https://www.youtube-nocookie.com/embed/${id}?autoplay=1&rel=0`,
|
|
38561
|
+
title: label,
|
|
38562
|
+
allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
|
|
38563
|
+
allowFullScreen: true,
|
|
38564
|
+
referrerPolicy: "strict-origin-when-cross-origin"
|
|
38565
|
+
}
|
|
38566
|
+
) : /* @__PURE__ */ jsxs("button", { type: "button", className: "setto-blog__video-play", onClick: () => setPlaying(true), "aria-label": `${strings.play}: ${label}`, children: [
|
|
38567
|
+
/* @__PURE__ */ jsx("img", { src: `https://i.ytimg.com/vi/${id}/hqdefault.jpg`, alt: "", loading: "lazy", decoding: "async" }),
|
|
38568
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "setto-blog__video-icon", children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 68 48", width: "68", height: "48", children: [
|
|
38569
|
+
/* @__PURE__ */ jsx("path", { d: "M66.5 7.7A8.5 8.5 0 0 0 60.5 1.7C55.2.3 34 .3 34 .3s-21.2 0-26.5 1.4A8.5 8.5 0 0 0 1.5 7.7C.1 13 .1 24 .1 24s0 11 1.4 16.3a8.5 8.5 0 0 0 6 6c5.3 1.4 26.5 1.4 26.5 1.4s21.2 0 26.5-1.4a8.5 8.5 0 0 0 6-6C67.9 35 67.9 24 67.9 24s0-11-1.4-16.3z", fill: "#f00" }),
|
|
38570
|
+
/* @__PURE__ */ jsx("path", { d: "M45 24 27 14v20", fill: "#fff" })
|
|
38571
|
+
] }) })
|
|
38572
|
+
] }) }),
|
|
38573
|
+
title ? /* @__PURE__ */ jsx("figcaption", { children: title }) : null
|
|
38574
|
+
] });
|
|
38575
|
+
}
|
|
38576
|
+
const LATEST_COUNT = 3;
|
|
38577
|
+
function useBlogContext() {
|
|
38578
|
+
const { config } = useSetto();
|
|
38579
|
+
const { i18n, t } = useTranslation();
|
|
38580
|
+
const manifest = usePageManifest();
|
|
38581
|
+
const language = i18n.language || config.languages?.[0] || "no";
|
|
38582
|
+
const fallbackLanguage = config.languages?.[0] ?? "no";
|
|
38583
|
+
const route = typeof window === "undefined" ? { basename: "", rest: "/" } : languageFromPath(window.location.pathname, config.languages ?? [fallbackLanguage]);
|
|
38584
|
+
const href = (path2) => `${route.basename}${path2}`;
|
|
38585
|
+
return { config, t, manifest, language, fallbackLanguage, strings: blogStrings(language), path: route.rest, href };
|
|
38586
|
+
}
|
|
38587
|
+
function blogPathOf(manifest) {
|
|
38588
|
+
return manifest && blogPage(manifest)?.page.path || BLOG_ROUTE;
|
|
38589
|
+
}
|
|
38590
|
+
function SettoBlogSection({ sectionId, first }) {
|
|
38591
|
+
useBlogStyles();
|
|
38592
|
+
const ctx = useBlogContext();
|
|
38593
|
+
const slug = ctx.manifest ? blogSlugForPath(ctx.manifest, ctx.path) : null;
|
|
38594
|
+
const page = ctx.manifest ? findSection(ctx.manifest, sectionId)?.page : void 0;
|
|
38595
|
+
const title = page ? ctx.t(page.titleKey, { defaultValue: ctx.strings.blog }) : ctx.strings.blog;
|
|
38596
|
+
const blogPath = blogPathOf(ctx.manifest);
|
|
38597
|
+
const inner = useRef(null);
|
|
38598
|
+
const clear = useClearFixedHeader(inner, first);
|
|
38599
|
+
return /* @__PURE__ */ jsx(SettoSection, { sectionId, className: "setto-blog", children: /* @__PURE__ */ jsx("div", { className: "setto-blog__inner", ref: inner, style: clear ? { paddingTop: clear } : void 0, children: slug ? /* @__PURE__ */ jsx(BlogPostView, { slug, blogPath, ctx }) : /* @__PURE__ */ jsx(BlogIndexView, { title, first, blogPath, ctx }) }) });
|
|
38600
|
+
}
|
|
38601
|
+
function SettoBlog({ basePath = BLOG_ROUTE, title }) {
|
|
38602
|
+
useBlogStyles();
|
|
38603
|
+
const ctx = useBlogContext();
|
|
38604
|
+
const base = normalisePath(basePath);
|
|
38605
|
+
const here = normalisePath(ctx.path);
|
|
38606
|
+
const rest = here.startsWith(`${base}/`) ? here.slice(base.length + 1) : "";
|
|
38607
|
+
const slug = rest && isValidBlogSlug(rest) ? rest : null;
|
|
38608
|
+
const inner = useRef(null);
|
|
38609
|
+
const clear = useClearFixedHeader(inner, true);
|
|
38610
|
+
return /* @__PURE__ */ jsx("section", { className: "setto-blog", children: /* @__PURE__ */ jsx("div", { className: "setto-blog__inner", ref: inner, style: clear ? { paddingTop: clear } : void 0, children: slug ? /* @__PURE__ */ jsx(BlogPostView, { slug, blogPath: base, ctx }) : /* @__PURE__ */ jsx(BlogIndexView, { title: title ?? ctx.strings.blog, first: true, blogPath: base, ctx }) }) });
|
|
38611
|
+
}
|
|
38612
|
+
function useClearFixedHeader(ref, enabled) {
|
|
38613
|
+
const [clear, setClear] = useState(0);
|
|
38614
|
+
useLayoutEffect(() => {
|
|
38615
|
+
if (!enabled || typeof window === "undefined") return;
|
|
38616
|
+
const measure = () => {
|
|
38617
|
+
const el = ref.current;
|
|
38618
|
+
if (!el) return;
|
|
38619
|
+
const covering = document.elementsFromPoint(window.innerWidth / 2, 1).map((node2) => fixedAncestor(node2)).find((node2) => node2 !== null && !node2.contains(el));
|
|
38620
|
+
const headerBottom = covering ? covering.getBoundingClientRect().bottom : 0;
|
|
38621
|
+
const start = el.getBoundingClientRect().top + window.scrollY;
|
|
38622
|
+
const overlap = Math.ceil(headerBottom + 16 - start);
|
|
38623
|
+
setClear(overlap > 0 ? overlap : 0);
|
|
38624
|
+
};
|
|
38625
|
+
measure();
|
|
38626
|
+
window.addEventListener("resize", measure);
|
|
38627
|
+
return () => window.removeEventListener("resize", measure);
|
|
38628
|
+
}, [ref, enabled]);
|
|
38629
|
+
return clear;
|
|
38630
|
+
}
|
|
38631
|
+
function fixedAncestor(node2) {
|
|
38632
|
+
for (let at = node2; at && at !== document.body; at = at.parentElement) {
|
|
38633
|
+
if (getComputedStyle(at).position === "fixed") return at;
|
|
38634
|
+
}
|
|
38635
|
+
return null;
|
|
38636
|
+
}
|
|
38637
|
+
function BlogIndexView({ title, first, blogPath, ctx }) {
|
|
38638
|
+
const posts = ctx.config.blog ? postsForLanguage(ctx.config.blog.posts, ctx.language, ctx.fallbackLanguage) : [];
|
|
38639
|
+
const Heading = first ? "h1" : "h2";
|
|
38640
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38641
|
+
/* @__PURE__ */ jsx(Heading, { className: "setto-blog__title", children: title }),
|
|
38642
|
+
posts.length === 0 ? /* @__PURE__ */ jsx("p", { className: "setto-blog__empty", children: ctx.strings.empty }) : /* @__PURE__ */ jsx("div", { className: "setto-blog__list", children: posts.map((post2) => /* @__PURE__ */ jsx(PostCard, { post: post2, blogPath, ctx, headingLevel: first ? "h2" : "h3" }, post2.slug)) })
|
|
38643
|
+
] });
|
|
38644
|
+
}
|
|
38645
|
+
function PostCard({
|
|
38646
|
+
post: post2,
|
|
38647
|
+
blogPath,
|
|
38648
|
+
ctx,
|
|
38649
|
+
headingLevel
|
|
38650
|
+
}) {
|
|
38651
|
+
const Heading = headingLevel;
|
|
38652
|
+
const href = ctx.href(`${blogPath}/${post2.slug}`);
|
|
38653
|
+
return /* @__PURE__ */ jsxs("article", { className: "setto-blog__card", children: [
|
|
38654
|
+
post2.cover ? /* @__PURE__ */ jsx("a", { href, className: "setto-blog__card-cover", tabIndex: -1, "aria-hidden": "true", children: /* @__PURE__ */ jsx(BlogImg, { src: post2.cover, alt: "", sizes: "(min-width: 960px) 360px, (min-width: 640px) 50vw, 100vw" }) }) : null,
|
|
38655
|
+
/* @__PURE__ */ jsxs("div", { className: "setto-blog__card-body", children: [
|
|
38656
|
+
/* @__PURE__ */ jsx("time", { className: "setto-blog__date", dateTime: post2.date, children: formatPostDate(post2.date, ctx.language) }),
|
|
38657
|
+
/* @__PURE__ */ jsx(Heading, { className: "setto-blog__card-title", children: /* @__PURE__ */ jsx("a", { href, children: post2.title }) }),
|
|
38658
|
+
/* @__PURE__ */ jsx("p", { className: "setto-blog__card-lead", children: post2.description }),
|
|
38659
|
+
/* @__PURE__ */ jsxs("a", { href, className: "setto-blog__more", "aria-label": `${ctx.strings.readMore}: ${post2.title}`, children: [
|
|
38660
|
+
ctx.strings.readMore,
|
|
38661
|
+
" ",
|
|
38662
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "→" })
|
|
38663
|
+
] })
|
|
38664
|
+
] })
|
|
38665
|
+
] });
|
|
38666
|
+
}
|
|
38667
|
+
function BlogPostView({ slug, blogPath, ctx }) {
|
|
38668
|
+
const blog = ctx.config.blog;
|
|
38669
|
+
const summary = blog ? postForSlug(blog.posts, slug, ctx.language, ctx.fallbackLanguage) : null;
|
|
38670
|
+
const [post2, setPost] = useState(null);
|
|
38671
|
+
const [state, setState] = useState(summary ? "loading" : "missing");
|
|
38672
|
+
useEffect(() => {
|
|
38673
|
+
if (!blog || !summary) {
|
|
38674
|
+
setState("missing");
|
|
38675
|
+
return;
|
|
38676
|
+
}
|
|
38677
|
+
let live = true;
|
|
38678
|
+
setState("loading");
|
|
38679
|
+
blog.load(summary.slug, summary.locale).then((loaded) => {
|
|
38680
|
+
if (!live) return;
|
|
38681
|
+
setPost(loaded);
|
|
38682
|
+
setState(loaded ? "ready" : "missing");
|
|
38683
|
+
}).catch(() => live && setState("missing"));
|
|
38684
|
+
return () => {
|
|
38685
|
+
live = false;
|
|
38686
|
+
};
|
|
38687
|
+
}, [blog, summary?.slug, summary?.locale]);
|
|
38688
|
+
usePostTitle(summary?.title ?? null, ctx.config.displayName);
|
|
38689
|
+
const back = /* @__PURE__ */ jsxs("a", { href: ctx.href(blogPath), className: "setto-blog__back", children: [
|
|
38690
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "←" }),
|
|
38691
|
+
" ",
|
|
38692
|
+
ctx.strings.back
|
|
38693
|
+
] });
|
|
38694
|
+
if (!summary || state === "missing") {
|
|
38695
|
+
return /* @__PURE__ */ jsxs("div", { className: "setto-blog__post", children: [
|
|
38696
|
+
back,
|
|
38697
|
+
/* @__PURE__ */ jsx("p", { className: "setto-blog__empty", children: ctx.strings.notFound })
|
|
38698
|
+
] });
|
|
38699
|
+
}
|
|
38700
|
+
const fm = post2?.frontmatter ?? summary;
|
|
38701
|
+
return /* @__PURE__ */ jsxs("article", { className: "setto-blog__post", lang: fm.locale, children: [
|
|
38702
|
+
back,
|
|
38703
|
+
/* @__PURE__ */ jsxs("header", { className: "setto-blog__post-header", children: [
|
|
38704
|
+
/* @__PURE__ */ jsx("time", { className: "setto-blog__date", dateTime: fm.date, children: formatPostDate(fm.date, ctx.language) }),
|
|
38705
|
+
/* @__PURE__ */ jsx("h1", { className: "setto-blog__post-title", children: fm.title }),
|
|
38706
|
+
/* @__PURE__ */ jsx("p", { className: "setto-blog__lead", children: fm.description })
|
|
38707
|
+
] }),
|
|
38708
|
+
fm.cover ? /* @__PURE__ */ jsx("figure", { className: "setto-blog__cover", children: /* @__PURE__ */ jsx(BlogImg, { src: fm.cover, alt: "", sizes: "(min-width: 1040px) 960px, 100vw" }) }) : null,
|
|
38709
|
+
state === "ready" && post2 ? /* @__PURE__ */ jsx("div", { className: "setto-blog__prose", children: /* @__PURE__ */ jsx(BlogBody, { nodes: post2.body.children, language: ctx.language }) }) : /* @__PURE__ */ jsx("p", { className: "setto-blog__loading", "aria-live": "polite", children: ctx.strings.loading }),
|
|
38710
|
+
/* @__PURE__ */ jsx(ShareBar, { title: fm.title, strings: ctx.strings })
|
|
38711
|
+
] });
|
|
38712
|
+
}
|
|
38713
|
+
function usePostTitle(title, siteName) {
|
|
38714
|
+
useEffect(() => {
|
|
38715
|
+
if (!title || typeof document === "undefined") return;
|
|
38716
|
+
const previous2 = document.title;
|
|
38717
|
+
const timer = window.setTimeout(() => {
|
|
38718
|
+
document.title = siteName ? `${title} · ${siteName}` : title;
|
|
38719
|
+
}, 0);
|
|
38720
|
+
return () => {
|
|
38721
|
+
window.clearTimeout(timer);
|
|
38722
|
+
document.title = previous2;
|
|
38723
|
+
};
|
|
38724
|
+
}, [title, siteName]);
|
|
38725
|
+
}
|
|
38726
|
+
function ShareBar({ title, strings }) {
|
|
38727
|
+
const [copied, setCopied] = useState(false);
|
|
38728
|
+
const [native, setNative] = useState(false);
|
|
38729
|
+
useEffect(() => setNative(typeof navigator !== "undefined" && typeof navigator.share === "function"), []);
|
|
38730
|
+
const url = typeof window === "undefined" ? "" : `${window.location.origin}${window.location.pathname}`;
|
|
38731
|
+
const u = encodeURIComponent(url);
|
|
38732
|
+
const t = encodeURIComponent(title);
|
|
38733
|
+
return /* @__PURE__ */ jsxs("div", { className: "setto-blog__share", "aria-label": strings.share, children: [
|
|
38734
|
+
/* @__PURE__ */ jsx("span", { className: "setto-blog__share-label", children: strings.share }),
|
|
38735
|
+
native ? /* @__PURE__ */ jsx("button", { type: "button", onClick: () => void navigator.share({ title, url }).catch(() => void 0), children: strings.moreShare }) : null,
|
|
38736
|
+
/* @__PURE__ */ jsx("a", { href: `https://www.facebook.com/sharer/sharer.php?u=${u}`, target: "_blank", rel: "noopener noreferrer", children: "Facebook" }),
|
|
38737
|
+
/* @__PURE__ */ jsx("a", { href: `https://www.linkedin.com/sharing/share-offsite/?url=${u}`, target: "_blank", rel: "noopener noreferrer", children: "LinkedIn" }),
|
|
38738
|
+
/* @__PURE__ */ jsx("a", { href: `mailto:?subject=${t}&body=${u}`, children: strings.email }),
|
|
38739
|
+
/* @__PURE__ */ jsx(
|
|
38740
|
+
"button",
|
|
38741
|
+
{
|
|
38742
|
+
type: "button",
|
|
38743
|
+
onClick: () => {
|
|
38744
|
+
void navigator.clipboard?.writeText(url).then(() => {
|
|
38745
|
+
setCopied(true);
|
|
38746
|
+
window.setTimeout(() => setCopied(false), 2e3);
|
|
38747
|
+
});
|
|
38748
|
+
},
|
|
38749
|
+
children: copied ? strings.copied : strings.copyLink
|
|
38750
|
+
}
|
|
38751
|
+
)
|
|
38752
|
+
] });
|
|
38753
|
+
}
|
|
38754
|
+
function SettoBlogLatest({ sectionId, first }) {
|
|
38755
|
+
useBlogStyles();
|
|
38756
|
+
const ctx = useBlogContext();
|
|
38757
|
+
if (!ctx.config.blog) return null;
|
|
38758
|
+
const posts = postsForLanguage(ctx.config.blog.posts, ctx.language, ctx.fallbackLanguage).slice(0, LATEST_COUNT);
|
|
38759
|
+
if (posts.length === 0) return null;
|
|
38760
|
+
const blogPath = blogPathOf(ctx.manifest);
|
|
38761
|
+
const Heading = first ? "h1" : "h2";
|
|
38762
|
+
return /* @__PURE__ */ jsx(SettoSection, { sectionId, className: "setto-blog setto-blog--latest", children: /* @__PURE__ */ jsxs("div", { className: "setto-blog__inner setto-blog__inner--wide", children: [
|
|
38763
|
+
/* @__PURE__ */ jsxs("div", { className: "setto-blog__latest-head", children: [
|
|
38764
|
+
/* @__PURE__ */ jsx(Heading, { className: "setto-blog__title", children: ctx.strings.latest }),
|
|
38765
|
+
/* @__PURE__ */ jsxs("a", { href: ctx.href(blogPath), className: "setto-blog__more", children: [
|
|
38766
|
+
ctx.strings.allPosts,
|
|
38767
|
+
" ",
|
|
38768
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "→" })
|
|
38769
|
+
] })
|
|
38770
|
+
] }),
|
|
38771
|
+
/* @__PURE__ */ jsx("div", { className: "setto-blog__list", children: posts.map((post2) => /* @__PURE__ */ jsx(PostCard, { post: post2, blogPath, ctx, headingLevel: "h3" }, post2.slug)) })
|
|
38772
|
+
] }) });
|
|
38773
|
+
}
|
|
38774
|
+
const STYLE_ID$1 = "setto-blog-styles";
|
|
38775
|
+
const BLOG_CSS = `
|
|
38776
|
+
.setto-blog{padding:clamp(48px,8vw,96px) 16px}
|
|
38777
|
+
.setto-blog :where(.setto-blog__inner){max-width:68ch;margin:0 auto}
|
|
38778
|
+
.setto-blog :where(.setto-blog__inner--wide){max-width:1120px}
|
|
38779
|
+
.setto-blog :where(.setto-blog__title){font-family:var(--setto-display-font,inherit);font-size:clamp(2rem,4vw,2.75rem);line-height:1.15;font-weight:600;margin:0 0 .75em}
|
|
38780
|
+
.setto-blog :where(.setto-blog__list){display:grid;gap:clamp(1.5rem,3vw,2.5rem);grid-template-columns:repeat(auto-fill,minmax(min(100%,300px),1fr))}
|
|
38781
|
+
.setto-blog :where(.setto-blog__card){display:grid;gap:.9rem;align-content:start}
|
|
38782
|
+
.setto-blog :where(.setto-blog__card-cover){display:block;overflow:hidden;border-radius:.9rem;aspect-ratio:16/10}
|
|
38783
|
+
.setto-blog :where(.setto-blog__card-cover img,.setto-blog__cover img,.setto-blog__figure img,.setto-blog__gallery-item img){display:block;width:100%;height:100%;object-fit:cover}
|
|
38784
|
+
.setto-blog :where(.setto-blog__card-body){display:grid;gap:.45rem}
|
|
38785
|
+
.setto-blog :where(.setto-blog__card-title){font-family:var(--setto-display-font,inherit);font-size:1.3rem;line-height:1.25;font-weight:600;margin:0}
|
|
38786
|
+
.setto-blog :where(.setto-blog__card-lead){margin:0;line-height:1.55}
|
|
38787
|
+
.setto-blog :where(.setto-blog__date){font-size:.875rem;letter-spacing:.01em}
|
|
38788
|
+
.setto-blog :where(.setto-blog__more,.setto-blog__back){display:inline-flex;gap:.35em;align-items:center;font-weight:500;width:fit-content}
|
|
38789
|
+
.setto-blog :where(.setto-blog__back){margin-bottom:2rem}
|
|
38790
|
+
.setto-blog :where(.setto-blog__latest-head){display:flex;flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:.5rem 1.5rem;margin-bottom:1.75rem}
|
|
38791
|
+
.setto-blog :where(.setto-blog__latest-head .setto-blog__title){margin:0}
|
|
38792
|
+
.setto-blog :where(.setto-blog__post-header){display:grid;gap:.6rem;margin-bottom:2rem}
|
|
38793
|
+
.setto-blog :where(.setto-blog__post-title){font-family:var(--setto-display-font,inherit);font-size:clamp(2rem,5vw,3rem);line-height:1.1;font-weight:600;margin:0}
|
|
38794
|
+
.setto-blog :where(.setto-blog__lead){font-size:1.2rem;line-height:1.5;margin:0}
|
|
38795
|
+
.setto-blog :where(.setto-blog__cover){margin:0 0 2.5rem;overflow:hidden;border-radius:1rem;aspect-ratio:16/9}
|
|
38796
|
+
.setto-blog :where(.setto-blog__prose){font-size:1.075rem;line-height:1.7}
|
|
38797
|
+
.setto-blog :where(.setto-blog__prose > * + *){margin-top:1.15em}
|
|
38798
|
+
.setto-blog :where(.setto-blog__prose h2,.setto-blog__prose h3,.setto-blog__prose h4){font-family:var(--setto-display-font,inherit);line-height:1.25;font-weight:600;margin:1.8em 0 0}
|
|
38799
|
+
.setto-blog :where(.setto-blog__prose h2){font-size:1.6rem}
|
|
38800
|
+
.setto-blog :where(.setto-blog__prose h3){font-size:1.3rem}
|
|
38801
|
+
.setto-blog :where(.setto-blog__prose h4){font-size:1.1rem}
|
|
38802
|
+
.setto-blog :where(.setto-blog__prose ul,.setto-blog__prose ol){padding-left:1.4em}
|
|
38803
|
+
.setto-blog :where(.setto-blog__prose ul){list-style:disc}
|
|
38804
|
+
.setto-blog :where(.setto-blog__prose ol){list-style:decimal}
|
|
38805
|
+
.setto-blog :where(.setto-blog__prose li + li){margin-top:.35em}
|
|
38806
|
+
.setto-blog :where(.setto-blog__prose blockquote){margin-left:0;padding-left:1.1em;border-left-width:3px;border-left-style:solid;font-style:italic}
|
|
38807
|
+
.setto-blog :where(.setto-blog__prose pre){overflow-x:auto;padding:1em;border-radius:.6rem;font-size:.9em}
|
|
38808
|
+
.setto-blog :where(.setto-blog__prose code){font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.92em}
|
|
38809
|
+
.setto-blog :where(.setto-blog__prose hr){border:0;border-top-width:1px;border-top-style:solid;margin:2.5em 0}
|
|
38810
|
+
.setto-blog :where(.setto-blog__prose a){text-decoration:underline;text-underline-offset:.18em}
|
|
38811
|
+
.setto-blog :where(.setto-blog__table){overflow-x:auto}
|
|
38812
|
+
.setto-blog :where(.setto-blog__table table){border-collapse:collapse;width:100%;font-size:.95em}
|
|
38813
|
+
.setto-blog :where(.setto-blog__table th,.setto-blog__table td){padding:.55em .8em;border-bottom-width:1px;border-bottom-style:solid;text-align:left}
|
|
38814
|
+
.setto-blog :where(.setto-blog__figure,.setto-blog__gallery,.setto-blog__video){margin:2em 0}
|
|
38815
|
+
.setto-blog :where(.setto-blog__figure img){border-radius:.8rem;height:auto}
|
|
38816
|
+
.setto-blog :where(figcaption){font-size:.9rem;margin-top:.6em;opacity:.75}
|
|
38817
|
+
.setto-blog :where(.setto-blog__gallery-grid){display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,150px),1fr))}
|
|
38818
|
+
.setto-blog :where(.setto-blog__gallery-item){margin:0}
|
|
38819
|
+
.setto-blog :where(.setto-blog__gallery-item img){border-radius:.6rem;aspect-ratio:4/3}
|
|
38820
|
+
.setto-blog :where(.setto-blog__video-frame){position:relative;aspect-ratio:16/9;border-radius:.8rem;overflow:hidden}
|
|
38821
|
+
.setto-blog :where(.setto-blog__video-frame iframe){position:absolute;inset:0;width:100%;height:100%;border:0}
|
|
38822
|
+
.setto-blog :where(.setto-blog__video-play){position:absolute;inset:0;width:100%;height:100%;padding:0;border:0;cursor:pointer;display:grid;place-items:center}
|
|
38823
|
+
.setto-blog :where(.setto-blog__video-play img){position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
|
|
38824
|
+
.setto-blog :where(.setto-blog__video-icon){position:relative;display:block;line-height:0}
|
|
38825
|
+
.setto-blog :where(.setto-blog__callout){padding:1.1em 1.3em;border-radius:.8rem;border-left-width:4px;border-left-style:solid}
|
|
38826
|
+
.setto-blog :where(.setto-blog__callout > * + *){margin-top:.7em}
|
|
38827
|
+
.setto-blog :where(.setto-blog__callout ul,.setto-blog__callout ol){padding-left:1.3em;list-style:disc}
|
|
38828
|
+
.setto-blog :where(.setto-blog__share){display:flex;flex-wrap:wrap;gap:.5rem .9rem;align-items:center;margin-top:3rem;padding-top:1.5rem;border-top-width:1px;border-top-style:solid}
|
|
38829
|
+
.setto-blog :where(.setto-blog__share-label){font-weight:600}
|
|
38830
|
+
.setto-blog :where(.setto-blog__share a,.setto-blog__share button){font:inherit;padding:.35rem .85rem;border-radius:999px;border-width:1px;border-style:solid;cursor:pointer;text-decoration:none;line-height:1.4}
|
|
38831
|
+
.setto-blog :where(.setto-blog__empty,.setto-blog__loading){opacity:.75}
|
|
38832
|
+
:where(.setto-blog){color:inherit}
|
|
38833
|
+
:where(.setto-blog__date){opacity:.7}
|
|
38834
|
+
:where(.setto-blog a){color:inherit}
|
|
38835
|
+
:where(.setto-blog__prose blockquote,.setto-blog__prose hr,.setto-blog__table th,.setto-blog__table td,.setto-blog__share){border-color:color-mix(in srgb,currentColor 18%,transparent)}
|
|
38836
|
+
:where(.setto-blog__prose pre,.setto-blog__card-cover){background:color-mix(in srgb,currentColor 6%,transparent)}
|
|
38837
|
+
:where(.setto-blog__share a,.setto-blog__share button){border-color:color-mix(in srgb,currentColor 30%,transparent);background:transparent;color:inherit}
|
|
38838
|
+
:where(.setto-blog__callout){background:color-mix(in srgb,currentColor 5%,transparent);border-left-color:color-mix(in srgb,currentColor 40%,transparent)}
|
|
38839
|
+
:where(.setto-blog__callout[data-tone="tip"]){border-left-color:#0f7b4f}
|
|
38840
|
+
:where(.setto-blog__callout[data-tone="warning"]){border-left-color:#b54708}
|
|
38841
|
+
:where(.setto-blog__video-frame){background:#000}
|
|
38842
|
+
`;
|
|
38843
|
+
function useBlogStyles() {
|
|
38844
|
+
useInsertionEffect(() => {
|
|
38845
|
+
if (typeof document === "undefined" || document.getElementById(STYLE_ID$1)) return;
|
|
38846
|
+
const el = document.createElement("style");
|
|
38847
|
+
el.id = STYLE_ID$1;
|
|
38848
|
+
el.textContent = BLOG_CSS;
|
|
38849
|
+
document.head.appendChild(el);
|
|
38850
|
+
}, []);
|
|
38851
|
+
}
|
|
38114
38852
|
const FORM_FIELD_TYPES = [
|
|
38115
38853
|
"text",
|
|
38116
38854
|
"email",
|
|
@@ -39113,193 +39851,6 @@ const iframeStyle = {
|
|
|
39113
39851
|
height: "100%",
|
|
39114
39852
|
border: 0
|
|
39115
39853
|
};
|
|
39116
|
-
function usePageManifest() {
|
|
39117
|
-
const { pageStore, config } = useSetto();
|
|
39118
|
-
const snap = useSyncExternalStore(
|
|
39119
|
-
(cb) => pageStore?.subscribe(() => cb()) ?? (() => {
|
|
39120
|
-
}),
|
|
39121
|
-
() => pageStore?.snapshot() ?? EMPTY_PAGE_STORE_SNAPSHOT,
|
|
39122
|
-
() => pageStore?.snapshot() ?? EMPTY_PAGE_STORE_SNAPSHOT
|
|
39123
|
-
);
|
|
39124
|
-
return pageStore ? snap.manifest : bundledManifest(config.pages);
|
|
39125
|
-
}
|
|
39126
|
-
function useSettoMenu(list2 = "menu") {
|
|
39127
|
-
const manifest = usePageManifest();
|
|
39128
|
-
return manifest ? visibleMenu(manifest, list2) : null;
|
|
39129
|
-
}
|
|
39130
|
-
function SettoPage({ pageId, path: path2, sections = {}, builtins, fallback = null }) {
|
|
39131
|
-
const manifest = usePageManifest();
|
|
39132
|
-
const { editMode } = useSetto();
|
|
39133
|
-
if (!manifest) {
|
|
39134
|
-
if (!pageId && path2 !== void 0 && path2 !== "/" && path2 !== "") return /* @__PURE__ */ jsx(Fragment, { children: fallback });
|
|
39135
|
-
return /* @__PURE__ */ jsx(Fragment, { children: Object.entries(sections).map(([id, Component]) => /* @__PURE__ */ jsx(Component, {}, id)) });
|
|
39136
|
-
}
|
|
39137
|
-
const page = pageId ? pageById(manifest, pageId) : pageForPath(manifest, path2 ?? "/");
|
|
39138
|
-
if (!page) {
|
|
39139
|
-
if (pageId) {
|
|
39140
|
-
return /* @__PURE__ */ jsx(Fragment, { children: Object.entries(sections).map(([id, Component]) => /* @__PURE__ */ jsx(Component, {}, id)) });
|
|
39141
|
-
}
|
|
39142
|
-
return /* @__PURE__ */ jsx(Fragment, { children: fallback });
|
|
39143
|
-
}
|
|
39144
|
-
if (page.hidden && !editMode) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
|
|
39145
|
-
return /* @__PURE__ */ jsx(PageBody, { page, sections, builtins, editMode, manifest });
|
|
39146
|
-
}
|
|
39147
|
-
function PageBody({
|
|
39148
|
-
page,
|
|
39149
|
-
sections,
|
|
39150
|
-
builtins,
|
|
39151
|
-
editMode,
|
|
39152
|
-
manifest
|
|
39153
|
-
}) {
|
|
39154
|
-
usePageTitle(page);
|
|
39155
|
-
const HiddenPageNote = useSettoChromeSlot("hidden-page");
|
|
39156
|
-
const listed = new Set(manifest.pages.flatMap((p) => p.sections.map((s) => s.id)));
|
|
39157
|
-
const unlisted = Object.keys(sections).filter((id) => !listed.has(id));
|
|
39158
|
-
const firstVisible = page.sections.find((s) => !s.hidden && (s.type || sections[s.id]))?.id;
|
|
39159
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
39160
|
-
page.hidden && editMode ? HiddenPageNote ? /* @__PURE__ */ jsx(HiddenPageNote, { pageId: page.id }) : /* @__PURE__ */ jsx(HiddenNote, { text: "Denne siden er skjult for besøkende." }) : null,
|
|
39161
|
-
page.sections.map((section) => /* @__PURE__ */ jsx(Fragment$1, { children: renderSection(section, sections, builtins, editMode, section.id === firstVisible) }, section.id)),
|
|
39162
|
-
unlisted.map((id) => {
|
|
39163
|
-
const Component = sections[id];
|
|
39164
|
-
return /* @__PURE__ */ jsx(Component, {}, id);
|
|
39165
|
-
})
|
|
39166
|
-
] });
|
|
39167
|
-
}
|
|
39168
|
-
function renderSection(section, sections, builtins, editMode, first) {
|
|
39169
|
-
if (section.hidden) {
|
|
39170
|
-
return editMode ? /* @__PURE__ */ jsx(HiddenSection, { section }) : null;
|
|
39171
|
-
}
|
|
39172
|
-
if (section.type) {
|
|
39173
|
-
const Builtin = builtins?.[section.type] ?? BUILTIN_RENDERERS[section.type];
|
|
39174
|
-
return /* @__PURE__ */ jsx(Builtin, { sectionId: section.id, first });
|
|
39175
|
-
}
|
|
39176
|
-
const Component = sections[section.id];
|
|
39177
|
-
if (!Component) {
|
|
39178
|
-
warnOnce(section.id);
|
|
39179
|
-
return null;
|
|
39180
|
-
}
|
|
39181
|
-
return /* @__PURE__ */ jsx(Component, {});
|
|
39182
|
-
}
|
|
39183
|
-
const warned = /* @__PURE__ */ new Set();
|
|
39184
|
-
function warnOnce(id) {
|
|
39185
|
-
if (warned.has(id)) return;
|
|
39186
|
-
warned.add(id);
|
|
39187
|
-
console.warn(`[setto] section "${id}" is in pages.json but the page does not provide it`);
|
|
39188
|
-
}
|
|
39189
|
-
function HiddenSection({ section }) {
|
|
39190
|
-
const { pageStore } = useSetto();
|
|
39191
|
-
const Offered = useSettoChromeSlot("hidden-section");
|
|
39192
|
-
const label = section.label ?? section.id;
|
|
39193
|
-
if (Offered) return /* @__PURE__ */ jsx(Offered, { sectionId: section.id, label });
|
|
39194
|
-
return /* @__PURE__ */ jsxs("div", { "data-setto-ui": true, style: hiddenBarStyle, children: [
|
|
39195
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
39196
|
-
"Skjult: ",
|
|
39197
|
-
label
|
|
39198
|
-
] }),
|
|
39199
|
-
pageStore ? /* @__PURE__ */ jsx(
|
|
39200
|
-
"button",
|
|
39201
|
-
{
|
|
39202
|
-
type: "button",
|
|
39203
|
-
"data-setto-ui": true,
|
|
39204
|
-
style: hiddenBtnStyle,
|
|
39205
|
-
onClick: () => pageStore.apply([{ op: "show_section", sectionId: section.id }]),
|
|
39206
|
-
children: "Vis"
|
|
39207
|
-
}
|
|
39208
|
-
) : null
|
|
39209
|
-
] });
|
|
39210
|
-
}
|
|
39211
|
-
function HiddenNote({ text: text2 }) {
|
|
39212
|
-
return /* @__PURE__ */ jsx("div", { "data-setto-ui": true, style: hiddenBarStyle, children: /* @__PURE__ */ jsx("span", { children: text2 }) });
|
|
39213
|
-
}
|
|
39214
|
-
function usePageTitle(page) {
|
|
39215
|
-
const { t } = useTranslation();
|
|
39216
|
-
const original = useRef(null);
|
|
39217
|
-
const title = page.path === "/" ? null : t(page.titleKey);
|
|
39218
|
-
useEffect(() => {
|
|
39219
|
-
if (!title || typeof document === "undefined") return;
|
|
39220
|
-
original.current ??= document.title;
|
|
39221
|
-
const base = original.current;
|
|
39222
|
-
document.title = base ? `${title} · ${base}` : title;
|
|
39223
|
-
return () => {
|
|
39224
|
-
document.title = base;
|
|
39225
|
-
};
|
|
39226
|
-
}, [title]);
|
|
39227
|
-
}
|
|
39228
|
-
function SettoTextSection({ sectionId, first }) {
|
|
39229
|
-
const keys2 = builtinKeys(sectionId);
|
|
39230
|
-
const { i18n } = useTranslation();
|
|
39231
|
-
const { store, editMode } = useSetto();
|
|
39232
|
-
const intro2 = store ? store.get(keys2.intro, i18n.language) : i18n.t(keys2.intro, { defaultValue: "" });
|
|
39233
|
-
const Heading = first ? "h1" : "h2";
|
|
39234
|
-
return /* @__PURE__ */ jsx(SettoSection, { sectionId, style: textSectionStyle, children: /* @__PURE__ */ jsxs("div", { style: textInnerStyle, children: [
|
|
39235
|
-
/* @__PURE__ */ jsx(Heading, { style: first ? textH1Style : textH2Style, children: /* @__PURE__ */ jsx(T, { k: keys2.heading }) }),
|
|
39236
|
-
intro2 || editMode ? /* @__PURE__ */ jsx("p", { style: textIntroStyle, children: /* @__PURE__ */ jsx(T, { k: keys2.intro }) }) : null,
|
|
39237
|
-
/* @__PURE__ */ jsx(
|
|
39238
|
-
SettoRepeater,
|
|
39239
|
-
{
|
|
39240
|
-
itemsKey: keys2.items,
|
|
39241
|
-
defaultItem: { heading: "Overskrift", text: "Tekst" },
|
|
39242
|
-
itemLabel: "avsnitt",
|
|
39243
|
-
children: (itemKey) => /* @__PURE__ */ jsx(TextItem, { sectionId, itemKey })
|
|
39244
|
-
}
|
|
39245
|
-
)
|
|
39246
|
-
] }) });
|
|
39247
|
-
}
|
|
39248
|
-
function TextItem({ sectionId, itemKey }) {
|
|
39249
|
-
const keys2 = builtinKeys(sectionId);
|
|
39250
|
-
const { i18n } = useTranslation();
|
|
39251
|
-
const { store, editMode } = useSetto();
|
|
39252
|
-
const heading2 = store ? store.get(keys2.itemHeading(itemKey), i18n.language) : i18n.t(keys2.itemHeading(itemKey), { defaultValue: "" });
|
|
39253
|
-
return /* @__PURE__ */ jsxs("div", { style: textItemStyle, children: [
|
|
39254
|
-
heading2 || editMode ? /* @__PURE__ */ jsx("h3", { style: textH3Style, children: /* @__PURE__ */ jsx(T, { k: keys2.itemHeading(itemKey) }) }) : null,
|
|
39255
|
-
/* @__PURE__ */ jsx("p", { style: textParagraphStyle, children: /* @__PURE__ */ jsx(T, { k: keys2.itemText(itemKey) }) })
|
|
39256
|
-
] });
|
|
39257
|
-
}
|
|
39258
|
-
const BUILTIN_RENDERERS = {
|
|
39259
|
-
text: SettoTextSection
|
|
39260
|
-
};
|
|
39261
|
-
const textSectionStyle = { padding: "clamp(48px, 8vw, 96px) 16px" };
|
|
39262
|
-
const textInnerStyle = { maxWidth: "68ch", margin: "0 auto" };
|
|
39263
|
-
const textH1Style = {
|
|
39264
|
-
fontFamily: "var(--setto-display-font, inherit)",
|
|
39265
|
-
fontSize: "clamp(2rem, 4vw, 2.75rem)",
|
|
39266
|
-
lineHeight: 1.15,
|
|
39267
|
-
fontWeight: 600,
|
|
39268
|
-
margin: "0 0 0.75em"
|
|
39269
|
-
};
|
|
39270
|
-
const textH2Style = { ...textH1Style, fontSize: "clamp(1.5rem, 3vw, 2rem)" };
|
|
39271
|
-
const textH3Style = {
|
|
39272
|
-
fontFamily: "var(--setto-display-font, inherit)",
|
|
39273
|
-
fontSize: "1.125rem",
|
|
39274
|
-
lineHeight: 1.3,
|
|
39275
|
-
fontWeight: 600,
|
|
39276
|
-
margin: "0 0 0.4em"
|
|
39277
|
-
};
|
|
39278
|
-
const textIntroStyle = { fontSize: "1.125rem", lineHeight: 1.6, opacity: 0.85, margin: "0 0 2em" };
|
|
39279
|
-
const textItemStyle = { margin: "0 0 1.75em" };
|
|
39280
|
-
const textParagraphStyle = { lineHeight: 1.7, margin: 0, whiteSpace: "pre-line" };
|
|
39281
|
-
const hiddenBarStyle = {
|
|
39282
|
-
display: "flex",
|
|
39283
|
-
alignItems: "center",
|
|
39284
|
-
justifyContent: "center",
|
|
39285
|
-
gap: 12,
|
|
39286
|
-
padding: "10px 16px",
|
|
39287
|
-
margin: "4px 0",
|
|
39288
|
-
border: "1px dashed rgba(100, 10, 255, 0.45)",
|
|
39289
|
-
borderRadius: 8,
|
|
39290
|
-
background: "rgba(100, 10, 255, 0.05)",
|
|
39291
|
-
color: "#3b2a66",
|
|
39292
|
-
font: '500 13px system-ui, -apple-system, "Segoe UI", sans-serif'
|
|
39293
|
-
};
|
|
39294
|
-
const hiddenBtnStyle = {
|
|
39295
|
-
border: "none",
|
|
39296
|
-
borderRadius: 999,
|
|
39297
|
-
padding: "4px 12px",
|
|
39298
|
-
background: "#640AFF",
|
|
39299
|
-
color: "#fff",
|
|
39300
|
-
font: '600 12px system-ui, -apple-system, "Segoe UI", sans-serif',
|
|
39301
|
-
cursor: "pointer"
|
|
39302
|
-
};
|
|
39303
39854
|
const DEFAULT_DURATION = {
|
|
39304
39855
|
fadeIn: 600,
|
|
39305
39856
|
slideUp: 700,
|
|
@@ -40262,6 +40813,7 @@ export {
|
|
|
40262
40813
|
AuthGate,
|
|
40263
40814
|
BLOCK_REGISTRY,
|
|
40264
40815
|
BLOCK_TYPES,
|
|
40816
|
+
BLOG_CSS,
|
|
40265
40817
|
BUILTIN_SECTION_TYPES,
|
|
40266
40818
|
CHECKOUT_INTENT,
|
|
40267
40819
|
DEFAULT_LANGUAGE,
|
|
@@ -40280,11 +40832,15 @@ export {
|
|
|
40280
40832
|
SETTO_BASE,
|
|
40281
40833
|
SETTO_IMAGE_QUALITY,
|
|
40282
40834
|
SETTO_IMAGE_WIDTHS,
|
|
40835
|
+
SETTO_MEDIA_HOST,
|
|
40283
40836
|
SETTO_MODULES,
|
|
40284
40837
|
SettoAdminApp,
|
|
40285
40838
|
SettoAnimation,
|
|
40286
40839
|
SettoBlock,
|
|
40287
40840
|
SettoBlockTree,
|
|
40841
|
+
SettoBlog,
|
|
40842
|
+
SettoBlogLatest,
|
|
40843
|
+
SettoBlogSection,
|
|
40288
40844
|
SettoChat,
|
|
40289
40845
|
SettoChrome,
|
|
40290
40846
|
SettoContext,
|
|
@@ -40306,6 +40862,8 @@ export {
|
|
|
40306
40862
|
alternateLinks,
|
|
40307
40863
|
applyOp,
|
|
40308
40864
|
applyOps,
|
|
40865
|
+
blogPage,
|
|
40866
|
+
blogSlugForPath,
|
|
40309
40867
|
builtinKeys,
|
|
40310
40868
|
checkoutIntentUrl,
|
|
40311
40869
|
countChanges,
|
|
@@ -40315,6 +40873,7 @@ export {
|
|
|
40315
40873
|
fieldTypeHasPlaceholder,
|
|
40316
40874
|
findSection,
|
|
40317
40875
|
formFieldsPrefix,
|
|
40876
|
+
formatPostDate,
|
|
40318
40877
|
isAdminDeploymentView,
|
|
40319
40878
|
isAdminPanelView,
|
|
40320
40879
|
isAdminRoute,
|
|
@@ -40322,6 +40881,7 @@ export {
|
|
|
40322
40881
|
isLinkContext,
|
|
40323
40882
|
isOptimizable,
|
|
40324
40883
|
isSafeHref,
|
|
40884
|
+
isSettoMediaUrl,
|
|
40325
40885
|
languageFromPath,
|
|
40326
40886
|
languageName,
|
|
40327
40887
|
nodeChildren,
|
|
@@ -40335,6 +40895,8 @@ export {
|
|
|
40335
40895
|
parseManifest,
|
|
40336
40896
|
pathForLanguage,
|
|
40337
40897
|
pickInitialLanguage,
|
|
40898
|
+
postForSlug,
|
|
40899
|
+
postsForLanguage,
|
|
40338
40900
|
readLocaleFields,
|
|
40339
40901
|
redirectForVisitor,
|
|
40340
40902
|
serialiseManifest,
|