@universalcms/connect 0.13.3 → 0.18.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/README.md +6 -4
- package/dist/cli.mjs +7 -5
- package/dist/guided.mjs +79 -3
- package/dist/native-website-server.mjs +47 -16
- package/dist/native-website.mjs +28 -23
- package/dist/publication.css +5 -0
- package/dist/publication.mjs +10 -4
- package/dist/react-publication.mjs +23 -1
- package/dist/react-website.d.mts +1 -1
- package/dist/react-website.mjs +5 -3
- package/dist/templates/next-theme/app/[[...cmsPath]]/page.tsx +13 -4
- package/dist/templates/next-theme/app/api/cms-source/route.ts +10 -0
- package/dist/templates/next-theme/app/api/universalcms/[endpoint]/route.ts +2 -2
- package/dist/templates/next-theme/app/api/universalcms/form/route.ts +8 -0
- package/dist/templates/next-theme/app/cms-preview/page.tsx +28 -0
- package/dist/templates/next-theme/app/globals.css +94 -10
- package/dist/templates/next-theme/app/layout.tsx +11 -1
- package/dist/templates/next-theme/app/not-found.tsx +6 -3
- package/dist/templates/next-theme/app/robots.txt/route.ts +2 -2
- package/dist/templates/next-theme/app/sitemap.xml/route.ts +2 -2
- package/dist/templates/next-theme/components/site-chrome.tsx +38 -0
- package/dist/templates/next-theme/lib/universalcms.ts +11 -0
- package/dist/templates/next-theme/next.config.mjs +17 -1
- package/dist/theme-client.d.mts +4 -0
- package/dist/theme-client.mjs +70 -0
- package/dist/theme-preview.mjs +149 -0
- package/dist/theme.d.mts +9 -2
- package/dist/theme.mjs +190 -3
- package/dist/vendor/react-document.mjs +12 -3
- package/dist/vendor/react-preview-protocol.mjs +45 -0
- package/dist/website-schema.mjs +19 -4
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @universalcms/connect
|
|
2
2
|
|
|
3
3
|
Local, deterministic website setup without AI. Universal CMS stays hosted; this
|
|
4
|
-
package creates a website integration, not a CMS installation. Version 0.
|
|
4
|
+
package creates a website integration, not a CMS installation. Version 0.18.0 is
|
|
5
5
|
prepared locally; this repository does not establish its public npm availability.
|
|
6
6
|
|
|
7
7
|
## Quick start
|
|
@@ -20,6 +20,8 @@ connection (Next.js): the CMS manages menus, branding, SEO, analytics, scripts,
|
|
|
20
20
|
consent and redirects while the site renders every page. Add
|
|
21
21
|
`<CmsNavigation location="header" />` from `@universalcms/connect/react-website`
|
|
22
22
|
where CMS menus should appear.
|
|
23
|
+
Add `--reset` to disconnect the folder first and connect it to another website
|
|
24
|
+
or organization.
|
|
23
25
|
The individual commands below remain for developers and reviewed integrations.
|
|
24
26
|
|
|
25
27
|
Supported templates: **Next.js 16 App Router on Node**, **React 19.2+ with
|
|
@@ -262,7 +264,7 @@ custom adapter still requires review, not forced overwriting.
|
|
|
262
264
|
For an operator's downloaded artifact, the installation is:
|
|
263
265
|
|
|
264
266
|
```sh
|
|
265
|
-
npm install --save-prod ./vendor/universalcms-connect-0.
|
|
267
|
+
npm install --save-prod ./vendor/universalcms-connect-0.18.0.tgz
|
|
266
268
|
```
|
|
267
269
|
|
|
268
270
|
Use your project's package manager. These paths are examples for downloaded
|
|
@@ -539,7 +541,7 @@ npx --no-install universalcms-connect init \
|
|
|
539
541
|
--environment 22222222-2222-4222-8222-222222222222
|
|
540
542
|
```
|
|
541
543
|
|
|
542
|
-
After a public release, `npx @universalcms/connect@0.
|
|
544
|
+
After a public release, `npx @universalcms/connect@0.18.0 init` is the equivalent
|
|
543
545
|
registry entry point. Copy the real IDs/API origin from **Developer setup**.
|
|
544
546
|
Missing values are prompted in a terminal; `--non-interactive` fails instead.
|
|
545
547
|
Init prints a plan. Run the same command with `--apply` after reviewing it.
|
|
@@ -589,7 +591,7 @@ The CMS button reads the website's **`/api/cms-source`** endpoint. Current Next.
|
|
|
589
591
|
prepares delivery scaffolding. React/Vite setup serves its reviewed public manifest through the normal dev command.
|
|
590
592
|
Custom exporters need their explicit adapter; a delivery check alone is insufficient.
|
|
591
593
|
|
|
592
|
-
Use the CMS's reviewed 0.
|
|
594
|
+
Use the CMS's reviewed 0.18.0 package for the staged commands and current source
|
|
593
595
|
discovery. Review source diagnostics and complete public
|
|
594
596
|
mappings for unsupported pages. Restart the website using its normal server command, then run:
|
|
595
597
|
|
package/dist/cli.mjs
CHANGED
|
@@ -20,7 +20,7 @@ import { WEBSITE_SECTIONS } from './website-http.mjs';
|
|
|
20
20
|
import { setupSource, applySourcePlan, syncSource, readSourceSettings } from './source-setup.mjs';
|
|
21
21
|
import { processIo, runCreate, runGuided } from './guided.mjs';
|
|
22
22
|
|
|
23
|
-
const help = `Universal CMS connector 0.
|
|
23
|
+
const help = `Universal CMS connector 0.18.0
|
|
24
24
|
|
|
25
25
|
Quick start (recommended) — run in your website folder:
|
|
26
26
|
npx @universalcms/connect@latest --cms https://YOUR_CMS_ADDRESS
|
|
@@ -33,9 +33,11 @@ Quick start (recommended) — run in your website folder:
|
|
|
33
33
|
--cms <origin> Your Universal CMS address (or UNIVERSALCMS_URL)
|
|
34
34
|
--code <code> One-time code from Developer setup → Connect without a browser
|
|
35
35
|
--details Show every file and technical message
|
|
36
|
+
--reset Disconnect this folder first, then connect it to another website or organization
|
|
36
37
|
|
|
37
38
|
New website managed entirely from the CMS (pages, posts, menus, design):
|
|
38
39
|
npx @universalcms/connect@latest create my-website --cms https://YOUR_CMS_ADDRESS
|
|
40
|
+
Add --from ../existing-site to bring over its pages and menus (Next.js).
|
|
39
41
|
|
|
40
42
|
Individual steps (advanced):
|
|
41
43
|
Usage: universalcms-connect <start|inspect-pages|review-pages|preflight|review-routes|review-layout|connect|setup|setup-settings|check-settings|server-key|setup-source|sync-source|finalize-source|analyze|init|check|check-source|check-publication> [options]
|
|
@@ -334,11 +336,11 @@ async function ask(prompt) {
|
|
|
334
336
|
|
|
335
337
|
function guidedArguments(args) {
|
|
336
338
|
if (args[0] === 'start') args = args.slice(1);
|
|
337
|
-
const names = new Set(['--cms', '--code', '--project']), options = {};
|
|
339
|
+
const names = new Set(['--cms', '--code', '--project', '--from']), options = {};
|
|
338
340
|
for (let index = 0; index < args.length; index++) {
|
|
339
341
|
const name = args[index];
|
|
340
342
|
if (Object.hasOwn(options, name)) throw new SetupError('Each option can be given once.');
|
|
341
|
-
if (name === '--details') { options[name] = true; continue; }
|
|
343
|
+
if (name === '--details' || name === '--reset') { options[name] = true; continue; }
|
|
342
344
|
if (!names.has(name)) throw new SetupError(`Unknown option ${JSON.stringify(name.slice(0, 40))}. Use --help for instructions.`);
|
|
343
345
|
const value = args[++index];
|
|
344
346
|
if (!value || value.startsWith('--')) throw new SetupError('An option is missing its value.');
|
|
@@ -355,7 +357,7 @@ async function main() {
|
|
|
355
357
|
const options = guidedArguments(rest);
|
|
356
358
|
if (!process.stdin.isTTY || !process.stderr.isTTY) throw new SetupError('This setup needs an interactive terminal.');
|
|
357
359
|
const io = processIo({ ask, write: value => process.stdout.write(value) });
|
|
358
|
-
await runCreate(process.cwd(), name ?? (await ask('Folder name for the new website: ')).trim(), { cms: options['--cms'], code: options['--code'] }, io);
|
|
360
|
+
await runCreate(process.cwd(), name ?? (await ask('Folder name for the new website: ')).trim(), { cms: options['--cms'], code: options['--code'], from: options['--from'] }, io);
|
|
359
361
|
return;
|
|
360
362
|
}
|
|
361
363
|
if (first === undefined || first === 'start' || first.startsWith('--')) {
|
|
@@ -363,7 +365,7 @@ async function main() {
|
|
|
363
365
|
// it expires in ten minutes, works once and never reaches project files.
|
|
364
366
|
const options = guidedArguments(process.argv.slice(2));
|
|
365
367
|
if (!process.stdin.isTTY || !process.stderr.isTTY) throw new SetupError('This setup needs an interactive terminal. Run it directly in your website folder.');
|
|
366
|
-
await runGuided(options['--project'] ?? process.cwd(), { cms: options['--cms'], code: options['--code'], details: options['--details'] === true }, processIo({ ask, write: value => process.stdout.write(value) }));
|
|
368
|
+
await runGuided(options['--project'] ?? process.cwd(), { cms: options['--cms'], code: options['--code'], details: options['--details'] === true, reset: options['--reset'] === true }, processIo({ ask, write: value => process.stdout.write(value) }));
|
|
367
369
|
return;
|
|
368
370
|
}
|
|
369
371
|
const { command, options } = argumentsFor(process.argv.slice(2));
|
package/dist/guided.mjs
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { createHash, randomBytes, timingSafeEqual } from 'node:crypto';
|
|
10
10
|
import { createServer } from 'node:http';
|
|
11
11
|
import { spawn } from 'node:child_process';
|
|
12
|
-
import { cp, lstat, mkdir, readdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
12
|
+
import { chmod, cp, lstat, mkdir, readdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
13
13
|
import path from 'node:path';
|
|
14
14
|
import { fileURLToPath } from 'node:url';
|
|
15
15
|
import { analyze, applyPlan, projectRoot, readProjectFile, SetupError } from './core.mjs';
|
|
@@ -21,6 +21,7 @@ import { checkPublication } from './publication-check.mjs';
|
|
|
21
21
|
import { finalizeSource } from './source-finalize.mjs';
|
|
22
22
|
import { preflightSetup } from './preflight.mjs';
|
|
23
23
|
import { planSettingsOnly, SETTINGS_ONLY_FILE } from './settings-only-setup.mjs';
|
|
24
|
+
import { discoverSite } from './site-discovery.mjs';
|
|
24
25
|
import { applyEnvironment, planEnvironment } from './setup-environment.mjs';
|
|
25
26
|
import { themeConfiguration } from './theme.mjs';
|
|
26
27
|
|
|
@@ -378,9 +379,15 @@ export async function runGuided(directory, options, io) {
|
|
|
378
379
|
const analysis = await analyze(root).catch(() => ({}));
|
|
379
380
|
const framework = typeof analysis.framework === 'string' && analysis.framework !== 'Unknown' ? analysis.framework : null;
|
|
380
381
|
io.write(`✔ Found ${framework ? `a ${framework} website` : 'a website'} in ${path.basename(root)}\n`);
|
|
382
|
+
if (options.reset) await resetConnection(root, io);
|
|
381
383
|
|
|
382
384
|
// A Universal CMS theme website only needs pairing and its private key.
|
|
383
385
|
if (await readProjectFile(root, THEME_FILE) !== null) {
|
|
386
|
+
const connectedTheme = await readConnection(root).catch(() => null);
|
|
387
|
+
if (connectedTheme && !options.reset && !options.code && (await readSetupEnvironment(root)).keyConfigured && await readProjectFile(root, IMPORT_FILE) !== null) {
|
|
388
|
+
await closeImport(root, connectedTheme, io);
|
|
389
|
+
return themeDone(root, connectedTheme, await packageManager(root, manifest), false, io);
|
|
390
|
+
}
|
|
384
391
|
const cms = cmsOrigin(options.cms ?? io.env.UNIVERSALCMS_URL ?? '') ?? fail('Add --cms with your Universal CMS address.');
|
|
385
392
|
const approval = options.code ? { code: options.code } : await waitForBrowserApproval({ cms, io, request: { origin: suggestedOrigin(manifest, null) ?? `http://localhost:${THEME_PORT}`, project: path.basename(root).slice(0, 80), framework: 'Universal CMS theme' } });
|
|
386
393
|
const paired = await redeem(cms, approval.code, approval.verifier, io.fetch);
|
|
@@ -429,7 +436,7 @@ export async function runGuided(directory, options, io) {
|
|
|
429
436
|
: await waitForBrowserApproval({ cms, io, request: { origin: saved?.websiteOrigin ?? suggestedOrigin(manifest, framework) ?? '', project: path.basename(root).slice(0, 80), framework: framework ?? '' } });
|
|
430
437
|
let mode = 'full';
|
|
431
438
|
const mismatch = connection => saved && (saved.siteId !== connection.siteId || saved.environmentId !== connection.environmentId);
|
|
432
|
-
const different = 'This folder is already connected to a different website or environment in the CMS. Choose the same website when approving, or
|
|
439
|
+
const different = 'This folder is already connected to a different website or environment in the CMS. Choose the same website when approving, or run the command again with --reset to connect it to the other website. Nothing was changed.';
|
|
433
440
|
// Check (and safely fix) the website before redeeming, so a blocked site
|
|
434
441
|
// never leaves an unused key behind. The approval expires on its own.
|
|
435
442
|
if (approval.scope && !installed) {
|
|
@@ -471,6 +478,41 @@ export const THEME_FILE = '.universalcms/theme.json';
|
|
|
471
478
|
export const THEME_WEBSITE_FILE = '.universalcms/website.json';
|
|
472
479
|
const THEME_PORT = 3100;
|
|
473
480
|
|
|
481
|
+
const RESET_FILES = ['.universalcms/connection.json', '.universalcms/settings-only.json', '.universalcms/discovered.json', '.universalcms/website.json'];
|
|
482
|
+
const RESET_ENV = /^\s*(?:export\s+)?(CMS_API_BASE_URL|CMS_SITE_ID|CMS_ENVIRONMENT_ID|CMS_LOCALE|CMS_API_KEY|CMS_WEBSITE_ORIGIN|CMS_SOURCE_ORIGIN|CMS_ADMIN_ORIGIN)\s*=/;
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* `--reset`: disconnect this folder from its CMS website so it can be connected
|
|
486
|
+
* to another website or organization. Removes only the saved connection and the
|
|
487
|
+
* private CMS_* values; generated integration code stays and is updated when
|
|
488
|
+
* the folder is connected again in the same run.
|
|
489
|
+
*/
|
|
490
|
+
export async function resetConnection(directory, io) {
|
|
491
|
+
const root = await projectRoot(directory);
|
|
492
|
+
const settingsOnly = await readProjectFile(root, SETTINGS_ONLY_FILE) !== null, theme = await readProjectFile(root, THEME_FILE) !== null;
|
|
493
|
+
const full = !settingsOnly && !theme && (await readProjectFile(root, '.universalcms/publication.config.json') !== null || await readProjectFile(root, '.universalcms/website.integration.json') !== null);
|
|
494
|
+
if (full) fail('This folder has a full page integration (pages are bound to CMS content for one website). Moving it to another website needs your developer: the page bindings and imported content belong to the current website. Nothing was changed.');
|
|
495
|
+
const present = [];
|
|
496
|
+
for (const file of RESET_FILES) if (await readProjectFile(root, file) !== null) present.push(file);
|
|
497
|
+
const envText = await readProjectFile(root, '.env.local');
|
|
498
|
+
const envLines = envText === null ? [] : envText.split(/\r?\n/).filter(line => RESET_ENV.test(line));
|
|
499
|
+
const saved = await readConnection(root).catch(() => null);
|
|
500
|
+
if (!present.length && !envLines.length) { io.write('This folder is not connected to a CMS website. Nothing to reset.\n'); return false; }
|
|
501
|
+
io.write(`\nDisconnect this folder${saved ? ` from website ${saved.siteId} (${saved.websiteOrigin})` : ''}:\n`);
|
|
502
|
+
for (const file of present) io.write(` remove: ${file}\n`);
|
|
503
|
+
if (envLines.length) io.write(` remove from .env.local: ${envLines.map(line => line.split('=')[0].replace(/^\s*(export\s+)?/, '').trim()).join(', ')}\n`);
|
|
504
|
+
io.write('Your pages, design and other settings stay as they are. You will connect it to a website right after this.\n');
|
|
505
|
+
if (!yes(await io.ask('Disconnect? [Y/n] '))) fail('Nothing was changed.');
|
|
506
|
+
for (const file of present) await rm(path.join(root, file), { force: true });
|
|
507
|
+
if (envLines.length) {
|
|
508
|
+
const kept = envText.split(/(\r?\n)/).reduce((out, part, index, parts) => { if (index % 2 === 0 && !RESET_ENV.test(part)) out.push(part + (parts[index + 1] ?? '')); return out; }, []).join('');
|
|
509
|
+
await writeFile(path.join(root, '.env.local'), kept, { mode: 0o600 });
|
|
510
|
+
await chmod(path.join(root, '.env.local'), 0o600);
|
|
511
|
+
}
|
|
512
|
+
io.write('✔ Disconnected. The old website key still works until you revoke it in that website\'s Developer setup → Advanced → website keys.\n');
|
|
513
|
+
return true;
|
|
514
|
+
}
|
|
515
|
+
|
|
474
516
|
/** Save the public theme connection and the private key after pairing. */
|
|
475
517
|
async function connectTheme(root, paired, io) {
|
|
476
518
|
const { connection } = paired;
|
|
@@ -491,6 +533,33 @@ function themeDone(root, connection, manager, created, io) {
|
|
|
491
533
|
return { connected: true, mode: 'theme', done: true };
|
|
492
534
|
}
|
|
493
535
|
|
|
536
|
+
export const IMPORT_FILE = '.universalcms/import.json';
|
|
537
|
+
|
|
538
|
+
/** Read a previous Next.js website's pages (text, headings, images, links) and menus, without running it. */
|
|
539
|
+
export async function collectPreviousSite(from, io) {
|
|
540
|
+
const oldRoot = await projectRoot(from).catch(() => fail(`The folder ${from} was not found. Point --from at your existing website folder (the one with package.json).`));
|
|
541
|
+
const manifest = await manifestOf(oldRoot);
|
|
542
|
+
if (!manifest.dependencies?.next && !manifest.devDependencies?.next) fail('Moving content automatically supports Next.js (App Router) websites in this version. Nothing was changed.');
|
|
543
|
+
const { collectSource } = await import('./source-collect.mjs');
|
|
544
|
+
const collected = await collectSource({ root: oldRoot, locale: 'en' });
|
|
545
|
+
const discovered = await discoverSite(oldRoot);
|
|
546
|
+
io.write(`✔ Found ${collected.entries.length} page${collected.entries.length === 1 ? '' : 's'} and ${discovered.navigation.header.length + discovered.navigation.footer.length} menu links in ${path.basename(oldRoot)}\n`);
|
|
547
|
+
if (collected.diagnostics?.unsupported) io.write(` (${collected.diagnostics.unsupported} page${collected.diagnostics.unsupported === 1 ? '' : 's'} with dynamic content were skipped — recreate them in the CMS)\n`);
|
|
548
|
+
return { entries: collected.entries, pages: discovered.pages, navigation: discovered.navigation };
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/** After the CMS import, the copy of the previous website's content is removed. */
|
|
552
|
+
async function closeImport(root, connection, io) {
|
|
553
|
+
if (await readProjectFile(root, IMPORT_FILE) === null) return;
|
|
554
|
+
const setup = `${connection.adminOrigin}/sites/${connection.siteId}#setup?environmentId=${connection.environmentId}`;
|
|
555
|
+
io.write(`\nNext, bring your previous website's pages and menus into the CMS:\n Start this website (npm run dev), then open Developer setup:\n ${setup}\n Click “Connect & fetch content” and “Import into Header & footer”.\n`);
|
|
556
|
+
await io.openUrl(setup);
|
|
557
|
+
const answer = (await io.ask('\nDid the CMS show “Website content fetched”? [y/N] ')).trim().toLowerCase();
|
|
558
|
+
if (!['y', 'yes'].includes(answer)) { io.write('No problem — the import stays available. Run the same command in this folder again when it is done.\n'); return; }
|
|
559
|
+
await rm(path.join(root, IMPORT_FILE), { force: true });
|
|
560
|
+
io.write('✔ Import finished; the copied content was removed from this folder\n');
|
|
561
|
+
}
|
|
562
|
+
|
|
494
563
|
/** `create <folder>`: start a new website rendered entirely from Universal CMS. */
|
|
495
564
|
export async function runCreate(parent, name, options, io) {
|
|
496
565
|
if (typeof name !== 'string' || !/^[a-z0-9][a-z0-9._-]{0,63}$/i.test(name)) fail('Choose a simple folder name for the new website, for example: my-website');
|
|
@@ -505,6 +574,7 @@ export async function runCreate(parent, name, options, io) {
|
|
|
505
574
|
}
|
|
506
575
|
})();
|
|
507
576
|
io.write(`\nUniversal CMS · create a new website in ${name}\n`);
|
|
577
|
+
const previous = options.from ? await collectPreviousSite(path.resolve(parent, options.from), io) : null;
|
|
508
578
|
// Copy into a temporary sibling first so a failed copy never leaves a half-made folder.
|
|
509
579
|
const staging = `${root}.universalcms-${randomBytes(4).toString('hex')}`;
|
|
510
580
|
await cp(fileURLToPath(new URL('./templates/next-theme/', import.meta.url)), staging, { recursive: true, errorOnExist: true, force: false });
|
|
@@ -525,7 +595,13 @@ export async function runCreate(parent, name, options, io) {
|
|
|
525
595
|
const paired = await redeem(cms, approval.code, approval.verifier, io.fetch);
|
|
526
596
|
io.write(`✔ Approved: ${paired.siteName || 'your website'} (${paired.connection.websiteOrigin})\n`);
|
|
527
597
|
await connectTheme(root, paired, io);
|
|
528
|
-
|
|
598
|
+
if (previous) {
|
|
599
|
+
await writeFile(path.join(root, IMPORT_FILE), `${JSON.stringify({ version: 1, siteId: paired.connection.siteId, environmentId: paired.connection.environmentId, ...previous })}\n`);
|
|
600
|
+
io.write('✔ Previous website content saved for import\n');
|
|
601
|
+
}
|
|
602
|
+
const result = themeDone(root, paired.connection, 'npm', true, io);
|
|
603
|
+
if (previous) io.write(`\n Then import your previous content: run “npx @universalcms/connect@latest” inside ${name} and follow the steps.\n`);
|
|
604
|
+
return result;
|
|
529
605
|
}
|
|
530
606
|
|
|
531
607
|
/** Ask the running website's settings endpoint, as the CMS admin does. */
|
|
@@ -11719,10 +11719,17 @@ function CmsForm({ definition, entryId, blockId, revisionId, variant, endpoint,
|
|
|
11719
11719
|
// ../react/src/index.tsx
|
|
11720
11720
|
var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
|
|
11721
11721
|
var supported2 = /* @__PURE__ */ new Set(["paragraph", "heading", "quote", "list", "code", "image", "gallery", "button", "divider", "spacer", "faq", "table", "embed", "form", "section", "columns"]);
|
|
11722
|
-
var styles = { align: ["left", "center", "right"], size: ["small", "normal", "large"], tone: ["default", "muted", "accent", "inverse"], spaceAbove: ["none", "small", "medium", "large"], spaceBelow: ["none", "small", "medium", "large"], hideOnMobile: [true], hideOnDesktop: [true] };
|
|
11722
|
+
var styles = { align: ["left", "center", "right"], size: ["small", "normal", "large"], tone: ["default", "muted", "accent", "inverse"], spaceAbove: ["none", "small", "medium", "large"], spaceBelow: ["none", "small", "medium", "large"], hideOnMobile: [true], hideOnDesktop: [true], padding: ["none", "small", "medium", "large"], radius: ["none", "small", "medium", "large", "pill"], border: [true], weight: ["normal", "medium", "bold"], maxWidth: ["narrow", "normal", "full"], animation: ["fade-up", "fade-in", "zoom-in", "slide-left"] };
|
|
11723
|
+
function blockColors(block2) {
|
|
11724
|
+
const style = record(block2.style), hex2 = (value) => typeof value === "string" && /^#[0-9a-fA-F]{6}$/.test(value) ? value : void 0;
|
|
11725
|
+
const color = hex2(style.textColor), background = hex2(style.background);
|
|
11726
|
+
if (!color && !background) return void 0;
|
|
11727
|
+
return { ...color ? { "--cms-block-color": color, color } : {}, ...background ? { "--cms-block-background": background, background } : {} };
|
|
11728
|
+
}
|
|
11723
11729
|
function blockClasses(block2) {
|
|
11724
11730
|
const style = record(block2.style);
|
|
11725
|
-
|
|
11731
|
+
const mobile = record(style.mobile), phone = ["align", "size", "padding", "spaceAbove", "spaceBelow"];
|
|
11732
|
+
return ["cms-block", `cms-block-${text(block2.type)}`, ...Object.entries(styles).flatMap(([key, allowed]) => allowed.includes(style[key]) ? [`cms-${key}-${String(style[key])}`] : []), ...phone.flatMap((key) => styles[key].includes(mobile[key]) ? [`cms-m-${key}-${String(mobile[key])}`] : [])].join(" ");
|
|
11726
11733
|
}
|
|
11727
11734
|
function image(data, key) {
|
|
11728
11735
|
const src = safeUrl(data.url, false);
|
|
@@ -11847,7 +11854,7 @@ function CmsDocument({ document: document2, components = {}, entryId, revisionId
|
|
|
11847
11854
|
}
|
|
11848
11855
|
}
|
|
11849
11856
|
const anchor = text(record(block2.style).anchor);
|
|
11850
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { id: /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(anchor) ? anchor : void 0, className: `${blockClasses(block2)}${preview && id2 === selectedId ? " cms-selected" : ""}`, ...preview ? { "data-cms-block": id2, "data-cms-type": type } : {}, children: node }, id2 || index);
|
|
11857
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { id: /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(anchor) ? anchor : void 0, className: `${blockClasses(block2)}${preview && id2 === selectedId ? " cms-selected" : ""}`, style: blockColors(block2), ...preview ? { "data-cms-block": id2, "data-cms-type": type } : {}, children: node }, id2 || index);
|
|
11851
11858
|
}
|
|
11852
11859
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: ["cms-document", className].filter(Boolean).join(" "), children: renderMany(document2.blocks, "root") });
|
|
11853
11860
|
}
|
|
@@ -12790,9 +12797,10 @@ function publicEntry(value) {
|
|
|
12790
12797
|
const raw = record2(value), entry2 = validatePublishedDocumentEntry(value, { kind: text2(raw.kind, 40), slug: text2(raw.slug, 160), locale: text2(raw.locale, 35) });
|
|
12791
12798
|
return { ...entry2, ...Object.fromEntries(["path", "seo", "author", "categories", "tags", "translations", "canonicalUrl", "publishedAt"].map((name) => [name, raw[name]])) };
|
|
12792
12799
|
}
|
|
12793
|
-
|
|
12800
|
+
var FormEndpoint = (0, import_react5.createContext)(void 0);
|
|
12801
|
+
function CmsWebsitePage({ scope, pathname, initialEntry, initialResult, initialSettings, chrome = true, formEndpoint }) {
|
|
12794
12802
|
const path2 = pathname ?? (typeof window === "undefined" ? "/" : window.location.pathname);
|
|
12795
|
-
return /* @__PURE__ */ import_react5.default.createElement(WebsitePageLoader, { key: `${scope}:${path2}`, scope, pathname: path2, initialEntry, initialResult, initialSettings, chrome });
|
|
12803
|
+
return /* @__PURE__ */ import_react5.default.createElement(FormEndpoint.Provider, { value: formEndpoint }, /* @__PURE__ */ import_react5.default.createElement(WebsitePageLoader, { key: `${scope}:${path2}`, scope, pathname: path2, initialEntry, initialResult, initialSettings, chrome }));
|
|
12796
12804
|
}
|
|
12797
12805
|
function WebsitePageLoader({ scope, pathname, initialEntry, initialResult, initialSettings, chrome }) {
|
|
12798
12806
|
const [page, setPage] = (0, import_react5.useState)(() => {
|
|
@@ -12885,7 +12893,7 @@ function PublishedPage({ entry: entry2, pathname, related }) {
|
|
|
12885
12893
|
}, [entry2, presentation.showTableOfContents]);
|
|
12886
12894
|
const route2 = (0, import_react5.useMemo)(() => ({ identity: { kind: entry2.kind, slug: entry2.slug, locale: entry2.locale }, baseline: entry2.document, bindings: {} }), [entry2]);
|
|
12887
12895
|
const publishedDate = Number.isFinite(Date.parse(entry2.publishedAt)) ? new Date(entry2.publishedAt).toLocaleDateString(entry2.locale) : "";
|
|
12888
|
-
return /* @__PURE__ */ import_react5.default.createElement("main", { className: `cms-website-page cms-website-layout-${presentation.layout}` }, presentation.showBreadcrumbs && /* @__PURE__ */ import_react5.default.createElement("nav", { "aria-label": "Breadcrumbs" }, /* @__PURE__ */ import_react5.default.createElement(SafeLink, { url: "/" }, "Home"), /* @__PURE__ */ import_react5.default.createElement("span", { "aria-hidden": "true" }, " / "), /* @__PURE__ */ import_react5.default.createElement("span", { "aria-current": "page" }, entry2.document.title)), /* @__PURE__ */ import_react5.default.createElement("h1", null, entry2.document.title), entry2.document.excerpt && /* @__PURE__ */ import_react5.default.createElement("p", { className: "cms-website-excerpt" }, entry2.document.excerpt), presentation.showDate && publishedDate && /* @__PURE__ */ import_react5.default.createElement("time", { dateTime: entry2.publishedAt }, publishedDate), presentation.showFeaturedImage && presentation.featuredImage.url && /* @__PURE__ */ import_react5.default.createElement("img", { className: "cms-website-featured", src: presentation.featuredImage.url, alt: presentation.featuredImage.alt, referrerPolicy: "no-referrer" }), !!headings.length && /* @__PURE__ */ import_react5.default.createElement("nav", { className: "cms-website-toc", "aria-label": "Table of contents" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "On this page"), /* @__PURE__ */ import_react5.default.createElement("ul", null, headings.map((item) => /* @__PURE__ */ import_react5.default.createElement("li", { key: item.id }, /* @__PURE__ */ import_react5.default.createElement(SafeLink, { url: `${pathname}#${encodeURIComponent(item.id)}` }, item.title))))), /* @__PURE__ */ import_react5.default.createElement("div", { ref: content }, /* @__PURE__ */ import_react5.default.createElement(PublishedDocumentProvider, { initialEntry: entry2, pathname, route: route2 }, /* @__PURE__ */ import_react5.default.createElement(CmsPublishedDocument, null))), presentation.author && /* @__PURE__ */ import_react5.default.createElement("aside", { className: "cms-website-author", "aria-label": "About the author" }, presentation.author.avatarUrl && /* @__PURE__ */ import_react5.default.createElement("img", { src: presentation.author.avatarUrl, alt: "", loading: "lazy", referrerPolicy: "no-referrer" }), /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("h2", null, presentation.author.url ? /* @__PURE__ */ import_react5.default.createElement(SafeLink, { url: presentation.author.url }, presentation.author.name) : presentation.author.name), /* @__PURE__ */ import_react5.default.createElement("p", null, presentation.author.jobTitle), /* @__PURE__ */ import_react5.default.createElement("p", null, presentation.author.bio))), (presentation.categories.length > 0 || presentation.tags.length > 0) && /* @__PURE__ */ import_react5.default.createElement("nav", { className: "cms-website-terms", "aria-label": "Categories and tags" }, [...presentation.categories, ...presentation.tags].map((term2, index) => /* @__PURE__ */ import_react5.default.createElement(SafeLink, { key: `${term2.id}:${index}`, url: term2.path }, term2.name))), presentation.showShare && /* @__PURE__ */ import_react5.default.createElement(SharePage, { title: entry2.document.title, path: entry2.path || pathname }), presentation.showRelated && Array.isArray(related) && related.length > 0 && /* @__PURE__ */ import_react5.default.createElement("aside", { className: "cms-website-related" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "Related content"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "cms-website-cards" }, related.slice(0, 6).map((value, index) => {
|
|
12896
|
+
return /* @__PURE__ */ import_react5.default.createElement("main", { className: `cms-website-page cms-website-layout-${presentation.layout}` }, presentation.showBreadcrumbs && /* @__PURE__ */ import_react5.default.createElement("nav", { "aria-label": "Breadcrumbs" }, /* @__PURE__ */ import_react5.default.createElement(SafeLink, { url: "/" }, "Home"), /* @__PURE__ */ import_react5.default.createElement("span", { "aria-hidden": "true" }, " / "), /* @__PURE__ */ import_react5.default.createElement("span", { "aria-current": "page" }, entry2.document.title)), /* @__PURE__ */ import_react5.default.createElement("h1", null, entry2.document.title), entry2.document.excerpt && /* @__PURE__ */ import_react5.default.createElement("p", { className: "cms-website-excerpt" }, entry2.document.excerpt), presentation.showDate && publishedDate && /* @__PURE__ */ import_react5.default.createElement("time", { dateTime: entry2.publishedAt }, publishedDate), presentation.showFeaturedImage && presentation.featuredImage.url && /* @__PURE__ */ import_react5.default.createElement("img", { className: "cms-website-featured", src: presentation.featuredImage.url, alt: presentation.featuredImage.alt, referrerPolicy: "no-referrer" }), !!headings.length && /* @__PURE__ */ import_react5.default.createElement("nav", { className: "cms-website-toc", "aria-label": "Table of contents" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "On this page"), /* @__PURE__ */ import_react5.default.createElement("ul", null, headings.map((item) => /* @__PURE__ */ import_react5.default.createElement("li", { key: item.id }, /* @__PURE__ */ import_react5.default.createElement(SafeLink, { url: `${pathname}#${encodeURIComponent(item.id)}` }, item.title))))), /* @__PURE__ */ import_react5.default.createElement("div", { ref: content }, /* @__PURE__ */ import_react5.default.createElement(PublishedDocumentProvider, { initialEntry: entry2, pathname, route: route2, formEndpoint: (0, import_react5.useContext)(FormEndpoint) }, /* @__PURE__ */ import_react5.default.createElement(CmsPublishedDocument, null))), presentation.author && /* @__PURE__ */ import_react5.default.createElement("aside", { className: "cms-website-author", "aria-label": "About the author" }, presentation.author.avatarUrl && /* @__PURE__ */ import_react5.default.createElement("img", { src: presentation.author.avatarUrl, alt: "", loading: "lazy", referrerPolicy: "no-referrer" }), /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("h2", null, presentation.author.url ? /* @__PURE__ */ import_react5.default.createElement(SafeLink, { url: presentation.author.url }, presentation.author.name) : presentation.author.name), /* @__PURE__ */ import_react5.default.createElement("p", null, presentation.author.jobTitle), /* @__PURE__ */ import_react5.default.createElement("p", null, presentation.author.bio))), (presentation.categories.length > 0 || presentation.tags.length > 0) && /* @__PURE__ */ import_react5.default.createElement("nav", { className: "cms-website-terms", "aria-label": "Categories and tags" }, [...presentation.categories, ...presentation.tags].map((term2, index) => /* @__PURE__ */ import_react5.default.createElement(SafeLink, { key: `${term2.id}:${index}`, url: term2.path }, term2.name))), presentation.showShare && /* @__PURE__ */ import_react5.default.createElement(SharePage, { title: entry2.document.title, path: entry2.path || pathname }), presentation.showRelated && Array.isArray(related) && related.length > 0 && /* @__PURE__ */ import_react5.default.createElement("aside", { className: "cms-website-related" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "Related content"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "cms-website-cards" }, related.slice(0, 6).map((value, index) => {
|
|
12889
12897
|
const row = record2(value);
|
|
12890
12898
|
return publicHref(row.path)?.startsWith("/") ? /* @__PURE__ */ import_react5.default.createElement("article", { key: index }, /* @__PURE__ */ import_react5.default.createElement("h3", null, /* @__PURE__ */ import_react5.default.createElement(SafeLink, { url: row.path }, text2(row.title, 200))), /* @__PURE__ */ import_react5.default.createElement("p", null, text2(row.excerpt, 500))) : null;
|
|
12891
12899
|
}))));
|
|
@@ -12987,8 +12995,15 @@ var styleValues = {
|
|
|
12987
12995
|
size: ["small", "normal", "large"],
|
|
12988
12996
|
tone: ["default", "muted", "accent", "inverse"],
|
|
12989
12997
|
spaceAbove: ["none", "small", "medium", "large"],
|
|
12990
|
-
spaceBelow: ["none", "small", "medium", "large"]
|
|
12998
|
+
spaceBelow: ["none", "small", "medium", "large"],
|
|
12999
|
+
padding: ["none", "small", "medium", "large"],
|
|
13000
|
+
radius: ["none", "small", "medium", "large", "pill"],
|
|
13001
|
+
weight: ["normal", "medium", "bold"],
|
|
13002
|
+
maxWidth: ["narrow", "normal", "full"],
|
|
13003
|
+
animation: ["fade-up", "fade-in", "zoom-in", "slide-left"]
|
|
12991
13004
|
};
|
|
13005
|
+
var mobileStyle = (style) => !own(style, "mobile") || object(style.mobile) && Object.keys(style.mobile).every((key) => ["align", "size", "padding", "spaceAbove", "spaceBelow"].includes(key)) && ["align", "size", "padding", "spaceAbove", "spaceBelow"].every((key) => optionalEnum(style.mobile, key, styleValues[key]));
|
|
13006
|
+
var styleHex = (style, key) => !own(style, key) || typeof style[key] === "string" && /^#[0-9a-fA-F]{6}$/.test(style[key]);
|
|
12992
13007
|
var optionalEnum = (value, key, choices) => !own(value, key) || choices.includes(value[key]);
|
|
12993
13008
|
var optionalString = (value, key, max) => !own(value, key) || boundedString(value[key], max);
|
|
12994
13009
|
var optionalBoolean = (value, key) => !own(value, key) || typeof value[key] === "boolean";
|
|
@@ -13043,11 +13058,11 @@ function validDocument(document2) {
|
|
|
13043
13058
|
return values.every((block2) => {
|
|
13044
13059
|
if (!object(block2) || !uuid2.test(block2.id) || ids.has(block2.id) || ids.size >= 400 || block2.version !== 1 || !boundedString(block2.text, 3e4)) return false;
|
|
13045
13060
|
ids.add(block2.id);
|
|
13046
|
-
if (block2.style !== void 0 && (!object(block2.style) || Object.entries(styleValues).some(([key, values2]) => !optionalEnum(block2.style, key, values2)) || !optionalBoolean(block2.style, "hideOnMobile") || !optionalBoolean(block2.style, "hideOnDesktop") || own(block2.style, "anchor") && (!boundedString(block2.style.anchor, 80) || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(block2.style.anchor)))) return false;
|
|
13061
|
+
if (block2.style !== void 0 && (!object(block2.style) || Object.entries(styleValues).some(([key, values2]) => !optionalEnum(block2.style, key, values2)) || !optionalBoolean(block2.style, "hideOnMobile") || !optionalBoolean(block2.style, "hideOnDesktop") || !optionalBoolean(block2.style, "border") || !styleHex(block2.style, "textColor") || !styleHex(block2.style, "background") || !mobileStyle(block2.style) || own(block2.style, "anchor") && (!boundedString(block2.style.anchor, 80) || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(block2.style.anchor)))) return false;
|
|
13047
13062
|
if (leafTypes.has(block2.type)) return leafData(block2);
|
|
13048
13063
|
const d = block2.data;
|
|
13049
13064
|
if (!object(d)) return false;
|
|
13050
|
-
if (block2.type === "section" && level === 0) return optionalEnum(d, "background", ["none", "muted", "accent", "dark"]) && optionalEnum(d, "padding", ["none", "small", "medium", "large"]) && optionalEnum(d, "width", ["normal", "wide", "full"]) && blocks(d.blocks, 1, 100);
|
|
13065
|
+
if (block2.type === "section" && level === 0) return optionalEnum(d, "background", ["none", "muted", "accent", "dark"]) && optionalEnum(d, "padding", ["none", "small", "medium", "large"]) && optionalEnum(d, "width", ["normal", "wide", "full"]) && (!own(d, "globalId") || typeof d.globalId === "string" && uuid2.test(d.globalId)) && blocks(d.blocks, 1, 100);
|
|
13051
13066
|
if (block2.type === "columns" && level < 2) return optionalEnum(d, "layout", ["1-1", "1-2", "2-1", "1-1-1", "1-1-1-1"]) && optionalEnum(d, "gap", ["small", "medium", "large"]) && optionalBoolean(d, "stackOnMobile") && Array.isArray(d.columns) && d.columns.length === (d.layout ?? "1-1").split("-").length && d.columns.every((column) => blocks(column, 2, 50));
|
|
13052
13067
|
return false;
|
|
13053
13068
|
});
|
|
@@ -13078,12 +13093,13 @@ var dataKeys = {
|
|
|
13078
13093
|
table: ["header", "rows"],
|
|
13079
13094
|
embed: ["url", "provider", "aspect"],
|
|
13080
13095
|
form: ["formKey", "submitLabel", "successMessage", "consentText"],
|
|
13081
|
-
section: ["background", "padding", "width"],
|
|
13096
|
+
section: ["background", "padding", "width", "globalId"],
|
|
13082
13097
|
columns: ["layout", "gap", "stackOnMobile"]
|
|
13083
13098
|
};
|
|
13084
13099
|
function publicBlock(block2) {
|
|
13085
13100
|
const result = pick(block2, ["id", "type", "version", "text"]);
|
|
13086
|
-
if (object(block2.style)) result.style = pick(block2.style, [...Object.keys(styleValues), "hideOnMobile", "hideOnDesktop", "anchor"]);
|
|
13101
|
+
if (object(block2.style)) result.style = pick(block2.style, [...Object.keys(styleValues), "hideOnMobile", "hideOnDesktop", "border", "textColor", "background", "anchor"]);
|
|
13102
|
+
if (result.style && object(block2.style.mobile)) result.style.mobile = pick(block2.style.mobile, ["align", "size", "padding", "spaceAbove", "spaceBelow"]);
|
|
13087
13103
|
if (object(block2.data)) {
|
|
13088
13104
|
const data = pick(block2.data, dataKeys[block2.type] ?? []);
|
|
13089
13105
|
if (block2.type === "gallery") data.images = block2.data.images.map((image2) => pick(image2, ["id", "url", "alt", "width", "height", "srcset"]));
|
|
@@ -13849,8 +13865,8 @@ var require_util = __commonJS2({
|
|
|
13849
13865
|
function uint8ArrayToBase64url(bytes) {
|
|
13850
13866
|
return uint8ArrayToBase64(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
13851
13867
|
}
|
|
13852
|
-
function hexToUint8Array(
|
|
13853
|
-
const cleanHex =
|
|
13868
|
+
function hexToUint8Array(hex2) {
|
|
13869
|
+
const cleanHex = hex2.replace(/^0x/, "");
|
|
13854
13870
|
if (cleanHex.length % 2 !== 0) {
|
|
13855
13871
|
throw new Error("Invalid hex string length");
|
|
13856
13872
|
}
|
|
@@ -32044,7 +32060,7 @@ var require_schemas2 = __commonJS2({
|
|
|
32044
32060
|
exports.jwt = jwt;
|
|
32045
32061
|
exports.stringFormat = stringFormat;
|
|
32046
32062
|
exports.hostname = hostname;
|
|
32047
|
-
exports.hex =
|
|
32063
|
+
exports.hex = hex2;
|
|
32048
32064
|
exports.hash = hash;
|
|
32049
32065
|
exports.number = number;
|
|
32050
32066
|
exports.int = int;
|
|
@@ -32630,7 +32646,7 @@ var require_schemas2 = __commonJS2({
|
|
|
32630
32646
|
function hostname(_params) {
|
|
32631
32647
|
return core._stringFormat(exports.ZodCustomStringFormat, "hostname", core.regexes.hostname, _params);
|
|
32632
32648
|
}
|
|
32633
|
-
function
|
|
32649
|
+
function hex2(_params) {
|
|
32634
32650
|
return core._stringFormat(exports.ZodCustomStringFormat, "hex", core.regexes.hex, _params);
|
|
32635
32651
|
}
|
|
32636
32652
|
function hash(alg, params) {
|
|
@@ -34843,7 +34859,11 @@ var link2 = import_zod.z.object({ label: import_zod.z.string().trim().min(1).max
|
|
|
34843
34859
|
var links = import_zod.z.array(link2).max(40);
|
|
34844
34860
|
var headerLink = link2.extend({ url: link2.shape.url.optional(), children: import_zod.z.array(link2).max(20).optional() }).refine((value) => value.url !== void 0 || (value.children?.length ?? 0) > 0, { message: "Header links without dropdown children need a URL", path: ["url"] });
|
|
34845
34861
|
var footerGroup = import_zod.z.object({ title: import_zod.z.string().trim().min(1).max(80), links: import_zod.z.array(link2).max(20) });
|
|
34862
|
+
var designFonts = ["system", "Inter", "Roboto", "Open Sans", "Lato", "Poppins", "Montserrat", "Nunito", "Merriweather", "Playfair Display", "Lora", "Source Serif 4"];
|
|
34863
|
+
var hex = import_zod.z.string().regex(/^#[0-9a-fA-F]{6}$/);
|
|
34864
|
+
var designColors = import_zod.z.object({ primary: hex, primaryText: hex, background: hex, surface: hex, text: hex, mutedText: hex, border: hex });
|
|
34846
34865
|
var configurationSchemas = {
|
|
34866
|
+
design: import_zod.z.object({ colors: designColors, typography: import_zod.z.object({ bodyFont: import_zod.z.enum(designFonts), headingFont: import_zod.z.enum(designFonts), baseSize: import_zod.z.number().int().min(14).max(20), headingWeight: import_zod.z.union([import_zod.z.literal(500), import_zod.z.literal(600), import_zod.z.literal(700), import_zod.z.literal(800)]) }), layout: import_zod.z.object({ containerWidth: import_zod.z.number().int().min(720).max(1440), radius: import_zod.z.number().int().min(0).max(24), spacing: import_zod.z.enum(["compact", "comfortable", "spacious"]) }), buttons: import_zod.z.object({ style: import_zod.z.enum(["solid", "outline", "soft"]), shape: import_zod.z.enum(["square", "rounded", "pill"]), uppercase: import_zod.z.boolean() }), header: import_zod.z.object({ layout: import_zod.z.enum(["left", "centered", "split"]), sticky: import_zod.z.boolean(), ctaLabel: import_zod.z.string().max(40), ctaUrl: import_zod.z.string().max(2048) }).optional(), footer: import_zod.z.object({ layout: import_zod.z.enum(["simple", "centered", "columns"]), showSocial: import_zod.z.boolean() }).optional() }),
|
|
34847
34867
|
branding: import_zod.z.object({ description: import_zod.z.string().max(2e3), logoUrl: url, faviconUrl: url, logoAlt: text3, accentColor: import_zod.z.string().regex(/^#[0-9a-fA-F]{6}$/) }),
|
|
34848
34868
|
social: import_zod.z.object({ profiles: import_zod.z.array(socialProfile).max(20), alignment: import_zod.z.enum(["left", "center", "right"]).optional() }),
|
|
34849
34869
|
seo: import_zod.z.object({
|
|
@@ -34904,6 +34924,15 @@ var styleSchema = import_zod2.z.object({
|
|
|
34904
34924
|
spaceBelow: import_zod2.z.enum(["none", "small", "medium", "large"]).optional(),
|
|
34905
34925
|
hideOnMobile: import_zod2.z.boolean().optional(),
|
|
34906
34926
|
hideOnDesktop: import_zod2.z.boolean().optional(),
|
|
34927
|
+
textColor: import_zod2.z.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),
|
|
34928
|
+
background: import_zod2.z.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),
|
|
34929
|
+
padding: import_zod2.z.enum(["none", "small", "medium", "large"]).optional(),
|
|
34930
|
+
radius: import_zod2.z.enum(["none", "small", "medium", "large", "pill"]).optional(),
|
|
34931
|
+
border: import_zod2.z.boolean().optional(),
|
|
34932
|
+
weight: import_zod2.z.enum(["normal", "medium", "bold"]).optional(),
|
|
34933
|
+
maxWidth: import_zod2.z.enum(["narrow", "normal", "full"]).optional(),
|
|
34934
|
+
mobile: import_zod2.z.object({ align: import_zod2.z.enum(["left", "center", "right"]).optional(), size: import_zod2.z.enum(["small", "normal", "large"]).optional(), padding: import_zod2.z.enum(["none", "small", "medium", "large"]).optional(), spaceAbove: import_zod2.z.enum(["none", "small", "medium", "large"]).optional(), spaceBelow: import_zod2.z.enum(["none", "small", "medium", "large"]).optional() }).strict().optional(),
|
|
34935
|
+
animation: import_zod2.z.enum(["fade-up", "fade-in", "zoom-in", "slide-left"]).optional(),
|
|
34907
34936
|
anchor: import_zod2.z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).max(80).optional()
|
|
34908
34937
|
});
|
|
34909
34938
|
var id = import_zod2.z.string().uuid();
|
|
@@ -34968,6 +34997,8 @@ var sectionSchema = block("section", import_zod2.z.object({
|
|
|
34968
34997
|
background: import_zod2.z.enum(["none", "muted", "accent", "dark"]).default("none"),
|
|
34969
34998
|
padding: import_zod2.z.enum(["none", "small", "medium", "large"]).default("medium"),
|
|
34970
34999
|
width: import_zod2.z.enum(["normal", "wide", "full"]).default("normal"),
|
|
35000
|
+
/** Linked to a saved site section: websites show that section's current content. */
|
|
35001
|
+
globalId: import_zod2.z.string().uuid().optional(),
|
|
34971
35002
|
blocks: import_zod2.z.array(import_zod2.z.union([leafSchema, columnsSchema])).max(100)
|
|
34972
35003
|
}));
|
|
34973
35004
|
var blockSchema = import_zod2.z.union([leafSchema, columnsSchema, sectionSchema]);
|
|
@@ -35172,7 +35203,7 @@ function serializeNativeWebsite(value) {
|
|
|
35172
35203
|
var website_default = ".cms-website { --cms-website-accent: #2563eb; }\n.cms-website-header:empty, .cms-website-footer:empty { display: none; }\n.cms-website-header, .cms-website-footer { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem; padding: 1rem clamp(1rem, 4vw, 3rem); color: inherit; background: inherit; }\n.cms-website-header:not(:has(> *)), .cms-website-footer:not(:has(> *)) { display: none; }\n.cms-website-header { border-bottom: 1px solid color-mix(in srgb, currentColor 15%, transparent); }\n.cms-website-footer { border-top: 1px solid color-mix(in srgb, currentColor 15%, transparent); }\n.cms-website a { overflow-wrap: anywhere; }\n.cms-website-header a, .cms-website-footer a, .cms-website-supplement a, .cms-website-page a { color: var(--cms-website-accent); }\n.cms-website-branding { max-width: 40rem; }\n.cms-website-branding img { display: block; max-width: min(15rem, 70vw); max-height: 4rem; width: auto; height: auto; object-fit: contain; }\n.cms-website-branding p { margin: .5rem 0 0; font-size: .9rem; }\n.cms-website-navigation { max-width: 100%; }\n.cms-website-navigation ul, .cms-website-social, .cms-website-languages, .cms-website-terms { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1.25rem; margin: 0; padding: 0; list-style: none; }\n.cms-website-navigation a, .cms-website-navigation summary, .cms-website-social a, .cms-website-languages a, .cms-website-terms a { display: inline-flex; gap: .5rem; align-items: center; min-height: 2.75rem; }\n.cms-website-navigation details { position: relative; }\n.cms-website-navigation summary { cursor: pointer; }\n.cms-website-navigation summary::after { content: '\u2304'; margin-inline-start: .3rem; }\n.cms-website-navigation details > ul { position: absolute; z-index: 40; top: 100%; min-width: 12rem; max-width: min(20rem, 85vw); flex-direction: column; align-items: stretch; gap: 0; padding: .5rem 1rem; border: 1px solid #64748b; border-radius: .5rem; color: #0f172a; background: #fff; box-shadow: 0 .5rem 1.5rem #0002; }\n.cms-website-footer-groups { display: flex; gap: 2rem; flex-wrap: wrap; }\n.cms-website-footer-groups h2 { font-size: 1rem; margin: .75rem 0; }\n.cms-website-footer-groups ul { flex-direction: column; align-items: start; gap: 0; }\n.cms-website-social img { width: 1.25rem; height: 1.25rem; object-fit: contain; }\n.cms-website-align-left { justify-content: flex-start; }.cms-website-align-center { justify-content: center; }.cms-website-align-right { justify-content: flex-end; }\n.cms-website-languages [aria-current=page] { font-weight: 700; text-decoration: underline; }\n.cms-website-page { width: min(100% - 2rem, 72rem); margin: 0 auto; padding: 3rem 0; overflow-wrap: anywhere; }\n.cms-website-page.cms-website-layout-narrow, .cms-website-native.cms-website-layout-narrow { max-width: 48rem; margin-inline: auto; }\n.cms-website-page.cms-website-layout-wide { width: min(100% - 2rem, 90rem); }\n.cms-website-native.cms-website-layout-standard { max-width: 80rem; margin-inline: auto; }\n.cms-website-native.cms-website-layout-wide { max-width: 100%; }\n.cms-website-page > h1 { font-size: clamp(2rem, 5vw, 3.5rem); line-height: 1.15; margin: 1rem 0; }\n.cms-website-excerpt { font-size: 1.15rem; line-height: 1.7; }\n.cms-website-featured { display: block; width: 100%; height: auto; max-height: 36rem; object-fit: cover; margin: 1.5rem 0; border-radius: .75rem; }\n.cms-website-toc, .cms-website-author, .cms-website-related { margin-block: 2rem; padding: 1.25rem; border: 1px solid color-mix(in srgb, currentColor 20%, transparent); border-radius: .75rem; }\n.cms-website-toc h2, .cms-website-author h2, .cms-website-related h2 { font-size: 1.25rem; }\n.cms-website-author { display: flex; align-items: flex-start; gap: 1rem; }\n.cms-website-author img { width: 4rem; height: 4rem; object-fit: cover; border-radius: 50%; }\n.cms-website-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); gap: 1.5rem; }\n.cms-website-cards article { padding: 1rem; border: 1px solid color-mix(in srgb, currentColor 20%, transparent); border-radius: .5rem; }\n.cms-website-share { display: flex; gap: .75rem; align-items: center; margin-block: 1rem; }\n.cms-website-share button, .cms-website-preferences, .cms-website-consent button { min-height: 2.75rem; padding: .5rem 1rem; font: inherit; border: 1px solid #64748b; border-radius: .4rem; cursor: pointer; background: transparent; color: inherit; }\n.cms-website-supplement { margin: 1rem clamp(1rem, 4vw, 3rem); }\n.cms-website-consent { position: fixed; z-index: 1000; bottom: 1rem; width: min(32rem, calc(100vw - 2rem)); max-height: calc(100dvh - 2rem); overflow-y: auto; box-sizing: border-box; padding: 1.25rem; border: 1px solid #cbd5e1; border-radius: .75rem; background: #fff; color: #0f172a; box-shadow: 0 .5rem 3rem #0003; font: 1rem/1.5 system-ui, sans-serif; }\n.cms-website-consent h2 { margin: 0 0 .5rem; font-size: 1.25rem; }.cms-website-consent p { margin: .5rem 0; }\n.cms-website-consent fieldset { margin: 1rem 0; padding: .75rem; }.cms-website-consent label { display: flex; align-items: center; gap: .5rem; min-height: 2.75rem; }.cms-website-consent input { width: 1.2rem; height: 1.2rem; }\n.cms-website-consent-actions { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1rem; }\n.cms-website-bottom-left { left: 1rem; }.cms-website-bottom-right { right: 1rem; }.cms-website-bottom-center { left: 50%; transform: translateX(-50%); }\n.cms-website-error { margin: 4rem auto; padding: 1rem; max-width: 48rem; }\n.cms-website :focus-visible { outline: 3px solid var(--cms-website-accent); outline-offset: 3px; }\n@media(max-width: 640px) { .cms-website-header, .cms-website-footer { align-items: stretch; flex-direction: column; }.cms-website-navigation details > ul { position: static; max-width: 100%; }.cms-website-page { padding-block: 1.5rem; }.cms-website-author { flex-wrap: wrap; } }\n";
|
|
35173
35204
|
|
|
35174
35205
|
// native-css:/Users/jasmeet/Codex/Universal-CMS/integrations/react/src/styles.css
|
|
35175
|
-
var styles_default = ".cms-document{overflow-wrap:anywhere}.cms-document img{max-width:100%;height:auto}.cms-document pre,.cms-table-scroll{overflow-x:auto}.cms-document figure{margin:0}.cms-document blockquote{border-inline-start:3px solid currentColor;padding-inline-start:1rem}.cms-document table{border-collapse:collapse;width:100%}.cms-document th,.cms-document td{border:1px solid #8886;padding:.6rem;text-align:start}.cms-gallery,.cms-columns{display:grid;gap:1rem}.cms-grid-2,.cms-layout-1-1{grid-template-columns:repeat(2,minmax(0,1fr))}.cms-grid-3,.cms-layout-1-1-1{grid-template-columns:repeat(3,minmax(0,1fr))}.cms-grid-4,.cms-layout-1-1-1-1{grid-template-columns:repeat(4,minmax(0,1fr))}.cms-layout-1-2{grid-template-columns:minmax(0,1fr) minmax(0,2fr)}.cms-layout-2-1{grid-template-columns:minmax(0,2fr) minmax(0,1fr)}.cms-gap-small{gap:.5rem}.cms-gap-large{gap:2rem}.cms-embed{border:0;width:100%;height:auto}.cms-button{display:inline-block;padding:.65rem 1rem;border:1px solid currentColor;border-radius:.4rem}.cms-button-link{border:0;padding:0}.cms-form fieldset{border:0;padding:0;display:grid;gap:1rem}.cms-form-field{display:grid;gap:.35rem}.cms-form input,.cms-form textarea,.cms-form select{font:inherit;max-width:100%;padding:.6rem}.cms-form input[type=checkbox]{margin-inline-end:.5rem}.cms-selected{outline:2px solid #2563eb;outline-offset:3px}.cms-align-left{text-align:left}.cms-align-center{text-align:center}.cms-align-right{text-align:right}.cms-size-small{font-size:.875em}.cms-size-large{font-size:1.25em}.cms-tone-muted{opacity:.75}.cms-tone-accent{color:var(--cms-accent,#2563eb)}.cms-tone-inverse,.cms-section-dark{background:#20242c;color:#fff}.cms-section-muted{background:#8881}.cms-section-accent{background:var(--cms-accent,#2563eb);color:#fff}.cms-padding-small{padding:.75rem}.cms-padding-medium{padding:1.5rem}.cms-padding-large{padding:3rem}.cms-width-normal{max-width:70rem;margin-inline:auto}.cms-width-wide{max-width:90rem;margin-inline:auto}.cms-spaceAbove-small{margin-top:.5rem}.cms-spaceAbove-medium{margin-top:1rem}.cms-spaceAbove-large{margin-top:2rem}.cms-spaceBelow-small{margin-bottom:.5rem}.cms-spaceBelow-medium{margin-bottom:1rem}.cms-spaceBelow-large{margin-bottom:2rem}.cms-spaceAbove-none{margin-top:0}.cms-spaceBelow-none{margin-bottom:0}@media(min-width:641px){.cms-hideOnDesktop-true{display:none}}@media(max-width:640px){.cms-hideOnMobile-true{display:none}.cms-stack,.cms-gallery{grid-template-columns:minmax(0,1fr)}.cms-padding-large{padding:1.5rem}}\n\n.cms-document .cms-block,.cms-document .cms-column{min-width:0}.cms-block-paragraph>p,.cms-block-heading>h2,.cms-block-heading>h3,.cms-block-heading>h4,.cms-block-quote>blockquote,.cms-document figcaption,.cms-block-faq p{white-space:pre-line}.cms-image-align-left{text-align:left}.cms-image-align-center{text-align:center}.cms-image-align-right{text-align:right}.cms-image-align-full img{width:100%}.cms-document .cms-image-align-left img,.cms-document .cms-image-align-center img,.cms-document .cms-image-align-right img{display:inline-block}.cms-gallery img{width:100%;height:auto}.cms-table-scroll:focus-visible{outline:2px solid var(--cms-accent,#2563eb);outline-offset:3px}\n";
|
|
35206
|
+
var styles_default = ".cms-document{overflow-wrap:anywhere}.cms-document img{max-width:100%;height:auto}.cms-document pre,.cms-table-scroll{overflow-x:auto}.cms-document figure{margin:0}.cms-document blockquote{border-inline-start:3px solid currentColor;padding-inline-start:1rem}.cms-document table{border-collapse:collapse;width:100%}.cms-document th,.cms-document td{border:1px solid #8886;padding:.6rem;text-align:start}.cms-gallery,.cms-columns{display:grid;gap:1rem}.cms-grid-2,.cms-layout-1-1{grid-template-columns:repeat(2,minmax(0,1fr))}.cms-grid-3,.cms-layout-1-1-1{grid-template-columns:repeat(3,minmax(0,1fr))}.cms-grid-4,.cms-layout-1-1-1-1{grid-template-columns:repeat(4,minmax(0,1fr))}.cms-layout-1-2{grid-template-columns:minmax(0,1fr) minmax(0,2fr)}.cms-layout-2-1{grid-template-columns:minmax(0,2fr) minmax(0,1fr)}.cms-gap-small{gap:.5rem}.cms-gap-large{gap:2rem}.cms-embed{border:0;width:100%;height:auto}.cms-button{display:inline-block;padding:.65rem 1rem;border:1px solid currentColor;border-radius:.4rem}.cms-button-link{border:0;padding:0}.cms-form fieldset{border:0;padding:0;display:grid;gap:1rem}.cms-form-field{display:grid;gap:.35rem}.cms-form input,.cms-form textarea,.cms-form select{font:inherit;max-width:100%;padding:.6rem}.cms-form input[type=checkbox]{margin-inline-end:.5rem}.cms-selected{outline:2px solid #2563eb;outline-offset:3px}.cms-align-left{text-align:left}.cms-align-center{text-align:center}.cms-align-right{text-align:right}.cms-size-small{font-size:.875em}.cms-size-large{font-size:1.25em}.cms-tone-muted{opacity:.75}.cms-tone-accent{color:var(--cms-accent,#2563eb)}.cms-tone-inverse,.cms-section-dark{background:#20242c;color:#fff}.cms-section-muted{background:#8881}.cms-section-accent{background:var(--cms-accent,#2563eb);color:#fff}.cms-padding-small{padding:.75rem}.cms-padding-medium{padding:1.5rem}.cms-padding-large{padding:3rem}.cms-width-normal{max-width:70rem;margin-inline:auto}.cms-width-wide{max-width:90rem;margin-inline:auto}.cms-spaceAbove-small{margin-top:.5rem}.cms-spaceAbove-medium{margin-top:1rem}.cms-spaceAbove-large{margin-top:2rem}.cms-spaceBelow-small{margin-bottom:.5rem}.cms-spaceBelow-medium{margin-bottom:1rem}.cms-spaceBelow-large{margin-bottom:2rem}.cms-spaceAbove-none{margin-top:0}.cms-spaceBelow-none{margin-bottom:0}@media(min-width:641px){.cms-hideOnDesktop-true{display:none}}@media(max-width:640px){.cms-hideOnMobile-true{display:none}.cms-stack,.cms-gallery{grid-template-columns:minmax(0,1fr)}.cms-padding-large{padding:1.5rem}}\n\n.cms-document .cms-block,.cms-document .cms-column{min-width:0}.cms-block-paragraph>p,.cms-block-heading>h2,.cms-block-heading>h3,.cms-block-heading>h4,.cms-block-quote>blockquote,.cms-document figcaption,.cms-block-faq p{white-space:pre-line}.cms-image-align-left{text-align:left}.cms-image-align-center{text-align:center}.cms-image-align-right{text-align:right}.cms-image-align-full img{width:100%}.cms-document .cms-image-align-left img,.cms-document .cms-image-align-center img,.cms-document .cms-image-align-right img{display:inline-block}.cms-gallery img{width:100%;height:auto}.cms-table-scroll:focus-visible{outline:2px solid var(--cms-accent,#2563eb);outline-offset:3px}\n\n.cms-preview-toolbar{display:flex;gap:2px;padding:3px;border-radius:8px;background:#1c1940;box-shadow:0 6px 18px rgb(0 0 0/18%)}.cms-preview-toolbar button{width:28px;height:28px;border:0;border-radius:6px;background:transparent;color:#fff;font:600 13px/1 system-ui,sans-serif;cursor:pointer}.cms-preview-toolbar button:hover{background:rgb(255 255 255/14%)}.cms-inline-editing{outline:none;cursor:text;caret-color:currentColor}\n.cms-padding-none{padding:0}.cms-padding-small{padding:.75rem}.cms-padding-medium{padding:1.5rem}.cms-padding-large{padding:3rem}.cms-radius-none{border-radius:0}.cms-radius-small{border-radius:.375rem}.cms-radius-medium{border-radius:.75rem}.cms-radius-large{border-radius:1.25rem}.cms-radius-pill{border-radius:999px}.cms-border-true{border:1px solid color-mix(in srgb,currentColor 18%,transparent)}.cms-weight-normal{font-weight:400}.cms-weight-medium{font-weight:500}.cms-weight-bold{font-weight:700}.cms-maxWidth-narrow{max-width:42rem;margin-inline:auto}.cms-maxWidth-normal{max-width:64rem;margin-inline:auto}.cms-maxWidth-full{max-width:none}\n@media (max-width:760px){.cms-m-align-left{text-align:left!important}.cms-m-align-center{text-align:center!important}.cms-m-align-right{text-align:right!important}.cms-m-size-small{font-size:.875em!important}.cms-m-size-normal{font-size:1em!important}.cms-m-size-large{font-size:1.25em!important}.cms-m-padding-none{padding:0!important}.cms-m-padding-small{padding:.75rem!important}.cms-m-padding-medium{padding:1.25rem!important}.cms-m-padding-large{padding:2.5rem!important}.cms-m-spaceAbove-none{margin-top:0!important}.cms-m-spaceAbove-small{margin-top:.5rem!important}.cms-m-spaceAbove-medium{margin-top:1.25rem!important}.cms-m-spaceAbove-large{margin-top:2.5rem!important}.cms-m-spaceBelow-none{margin-bottom:0!important}.cms-m-spaceBelow-small{margin-bottom:.5rem!important}.cms-m-spaceBelow-medium{margin-bottom:1.25rem!important}.cms-m-spaceBelow-large{margin-bottom:2.5rem!important}}\n.cms-preview-drag{display:grid;place-items:center;width:28px;height:28px;border-radius:6px;color:#fff;cursor:grab;font:600 14px/1 system-ui,sans-serif}.cms-preview-drag:hover{background:rgb(255 255 255/14%)}\n";
|
|
35176
35207
|
|
|
35177
35208
|
// src/native-website-server.tsx
|
|
35178
35209
|
function renderNativeWebsite(value, childrenHtml = "") {
|