@ciderpress/ui 1.0.0-rc.1 → 1.0.0-rc.11

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.
Files changed (162) hide show
  1. package/dist/head/css/loader-apple.css +1 -1
  2. package/dist/head/css/loader-dots.css +1 -1
  3. package/dist/head/css/themes/amber.css +1 -1
  4. package/dist/head/css/themes/arcade.css +1 -1
  5. package/dist/head/css/themes/grannysmith.css +1 -1
  6. package/dist/head/css/themes/honeycrisp.css +1 -1
  7. package/dist/head/css/themes/midnight.css +1 -1
  8. package/dist/head/css/themes/mulled.css +1 -1
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.mjs +4 -3
  11. package/dist/node.d.ts +1 -1
  12. package/dist/node.mjs +732 -55
  13. package/dist/plugins/mermaid/MermaidRenderer.tsx +49 -6
  14. package/dist/theme/components/footer/site-footer.tsx +68 -9
  15. package/dist/theme/components/home/cta.css +15 -0
  16. package/dist/theme/components/home/cta.tsx +10 -2
  17. package/dist/theme/components/home/feature-card.css +1 -1
  18. package/dist/theme/components/home/feature-card.tsx +8 -10
  19. package/dist/theme/components/home/feature.tsx +54 -31
  20. package/dist/theme/components/home/hero-demo.css +38 -0
  21. package/dist/theme/components/home/home-visual.tsx +226 -0
  22. package/dist/theme/components/home/layout.tsx +410 -108
  23. package/dist/theme/components/home/split.css +46 -19
  24. package/dist/theme/components/home/split.tsx +28 -8
  25. package/dist/theme/components/home/tabs.css +299 -0
  26. package/dist/theme/components/home/tabs.tsx +351 -0
  27. package/dist/theme/components/home/trust-strip.css +41 -0
  28. package/dist/theme/components/home/trust-strip.tsx +168 -11
  29. package/dist/theme/components/home/workspaces.tsx +176 -38
  30. package/dist/theme/components/nav/branch-tag.tsx +7 -7
  31. package/dist/theme/components/nav/ciderpress-docs-bar.css +13 -1
  32. package/dist/theme/components/nav/ciderpress-docs-bar.tsx +33 -2
  33. package/dist/theme/components/nav/ciderpress-header.css +2 -1
  34. package/dist/theme/components/nav/ciderpress-header.tsx +26 -3
  35. package/dist/theme/components/nav/ciderpress-nav-hamburger.css +50 -0
  36. package/dist/theme/components/nav/ciderpress-nav-hamburger.tsx +95 -9
  37. package/dist/theme/components/nav/ciderpress-nav-menu.css +88 -0
  38. package/dist/theme/components/nav/ciderpress-nav-menu.tsx +397 -38
  39. package/dist/theme/components/nav/ciderpress-nav-social-links.tsx +27 -22
  40. package/dist/theme/components/nav/floating-branch-indicator.tsx +7 -7
  41. package/dist/theme/components/nav/header-icon.css +24 -0
  42. package/dist/theme/components/nav/header-icon.tsx +119 -0
  43. package/dist/theme/components/nav/header-logo.css +16 -0
  44. package/dist/theme/components/nav/header-logo.tsx +200 -0
  45. package/dist/theme/components/nav/layout.tsx +117 -16
  46. package/dist/theme/components/nav/nav-logo.tsx +16 -19
  47. package/dist/theme/components/openapi/index.ts +0 -2
  48. package/dist/theme/components/openapi/openapi.css +0 -14
  49. package/dist/theme/components/shared/card-icon.tsx +37 -0
  50. package/dist/theme/components/shared/ciderpress-logo.tsx +5 -1
  51. package/dist/theme/components/shared/icon.tsx +120 -35
  52. package/dist/theme/components/shared/resolve-card-icon.ts +53 -12
  53. package/dist/theme/components/shared/section-card.tsx +37 -6
  54. package/dist/theme/components/sidebar/sidebar-badge.css +50 -0
  55. package/dist/theme/components/sidebar/sidebar-badge.tsx +153 -0
  56. package/dist/theme/components/sidebar/sidebar-links.tsx +6 -2
  57. package/dist/theme/components/sidebar/sidebar-scope.tsx +24 -1
  58. package/dist/theme/components/theme-provider.tsx +27 -11
  59. package/dist/theme/components/workspaces/card.css +4 -0
  60. package/dist/theme/components/workspaces/card.tsx +10 -12
  61. package/dist/theme/components/workspaces/grid.tsx +18 -6
  62. package/dist/theme/hooks/use-ciderpress.ts +65 -5
  63. package/dist/theme/hooks/use-nav-items.ts +82 -11
  64. package/dist/theme/index.tsx +10 -3
  65. package/dist/theme/lib/read-social-links.ts +4 -3
  66. package/dist/theme/lib/rich-text-parse.ts +740 -0
  67. package/dist/theme/lib/rich-text.test.tsx +342 -0
  68. package/dist/theme/lib/rich-text.tsx +86 -0
  69. package/dist/theme/lib/theme-favicon.ts +1 -1
  70. package/dist/theme/lib/with-mount-base.ts +31 -0
  71. package/dist/theme/styles/overrides/fonts.css +7 -4
  72. package/dist/theme/styles/overrides/footnotes.css +54 -0
  73. package/dist/theme/styles/overrides/home.css +11 -2
  74. package/dist/theme/styles/overrides/lists.css +83 -0
  75. package/dist/theme/styles/overrides/rail.css +27 -10
  76. package/dist/theme/styles/overrides/rspress.css +10 -5
  77. package/dist/theme/styles/overrides/section-card.css +9 -0
  78. package/dist/theme/styles/overrides/sidebar.css +22 -0
  79. package/dist/theme/styles/overrides/tokens.css +41 -23
  80. package/dist/theme/styles/rich-text.css +106 -0
  81. package/dist/theme/styles/themes/amber.css +32 -2
  82. package/dist/theme/styles/themes/arcade.css +16 -1
  83. package/dist/theme/styles/themes/grannysmith.css +32 -2
  84. package/dist/theme/styles/themes/honeycrisp.css +37 -7
  85. package/dist/theme/styles/themes/midnight.css +16 -1
  86. package/dist/theme/styles/themes/mulled.css +54 -9
  87. package/package.json +18 -16
  88. package/src/theme/components/footer/site-footer.tsx +68 -9
  89. package/src/theme/components/home/cta.css +15 -0
  90. package/src/theme/components/home/cta.tsx +10 -2
  91. package/src/theme/components/home/feature-card.css +1 -1
  92. package/src/theme/components/home/feature-card.tsx +8 -10
  93. package/src/theme/components/home/feature.tsx +54 -31
  94. package/src/theme/components/home/hero-demo.css +38 -0
  95. package/src/theme/components/home/home-visual.tsx +226 -0
  96. package/src/theme/components/home/layout.tsx +410 -108
  97. package/src/theme/components/home/split.css +46 -19
  98. package/src/theme/components/home/split.tsx +28 -8
  99. package/src/theme/components/home/tabs.css +299 -0
  100. package/src/theme/components/home/tabs.tsx +351 -0
  101. package/src/theme/components/home/trust-strip.css +41 -0
  102. package/src/theme/components/home/trust-strip.tsx +168 -11
  103. package/src/theme/components/home/workspaces.tsx +176 -38
  104. package/src/theme/components/nav/branch-tag.tsx +7 -7
  105. package/src/theme/components/nav/ciderpress-docs-bar.css +13 -1
  106. package/src/theme/components/nav/ciderpress-docs-bar.tsx +33 -2
  107. package/src/theme/components/nav/ciderpress-header.css +2 -1
  108. package/src/theme/components/nav/ciderpress-header.tsx +26 -3
  109. package/src/theme/components/nav/ciderpress-nav-hamburger.css +50 -0
  110. package/src/theme/components/nav/ciderpress-nav-hamburger.tsx +95 -9
  111. package/src/theme/components/nav/ciderpress-nav-menu.css +88 -0
  112. package/src/theme/components/nav/ciderpress-nav-menu.tsx +397 -38
  113. package/src/theme/components/nav/ciderpress-nav-social-links.tsx +27 -22
  114. package/src/theme/components/nav/floating-branch-indicator.tsx +7 -7
  115. package/src/theme/components/nav/header-icon.css +24 -0
  116. package/src/theme/components/nav/header-icon.tsx +119 -0
  117. package/src/theme/components/nav/header-logo.css +16 -0
  118. package/src/theme/components/nav/header-logo.tsx +200 -0
  119. package/src/theme/components/nav/layout.tsx +117 -16
  120. package/src/theme/components/nav/nav-logo.tsx +16 -19
  121. package/src/theme/components/openapi/index.ts +0 -2
  122. package/src/theme/components/openapi/openapi.css +0 -14
  123. package/src/theme/components/shared/card-icon.tsx +37 -0
  124. package/src/theme/components/shared/ciderpress-logo.tsx +5 -1
  125. package/src/theme/components/shared/icon.tsx +120 -35
  126. package/src/theme/components/shared/resolve-card-icon.ts +53 -12
  127. package/src/theme/components/shared/section-card.tsx +37 -6
  128. package/src/theme/components/sidebar/sidebar-badge.css +50 -0
  129. package/src/theme/components/sidebar/sidebar-badge.tsx +153 -0
  130. package/src/theme/components/sidebar/sidebar-links.tsx +6 -2
  131. package/src/theme/components/sidebar/sidebar-scope.tsx +24 -1
  132. package/src/theme/components/theme-provider.tsx +27 -11
  133. package/src/theme/components/workspaces/card.css +4 -0
  134. package/src/theme/components/workspaces/card.tsx +10 -12
  135. package/src/theme/components/workspaces/grid.tsx +18 -6
  136. package/src/theme/hooks/use-ciderpress.ts +65 -5
  137. package/src/theme/hooks/use-nav-items.ts +82 -11
  138. package/src/theme/index.tsx +10 -3
  139. package/src/theme/lib/read-social-links.ts +4 -3
  140. package/src/theme/lib/rich-text-parse.ts +740 -0
  141. package/src/theme/lib/rich-text.test.tsx +342 -0
  142. package/src/theme/lib/rich-text.tsx +86 -0
  143. package/src/theme/lib/theme-favicon.ts +1 -1
  144. package/src/theme/lib/with-mount-base.ts +31 -0
  145. package/src/theme/styles/overrides/fonts.css +7 -4
  146. package/src/theme/styles/overrides/footnotes.css +54 -0
  147. package/src/theme/styles/overrides/home.css +11 -2
  148. package/src/theme/styles/overrides/lists.css +83 -0
  149. package/src/theme/styles/overrides/rail.css +27 -10
  150. package/src/theme/styles/overrides/rspress.css +10 -5
  151. package/src/theme/styles/overrides/section-card.css +9 -0
  152. package/src/theme/styles/overrides/sidebar.css +22 -0
  153. package/src/theme/styles/overrides/tokens.css +41 -23
  154. package/src/theme/styles/rich-text.css +106 -0
  155. package/src/theme/styles/themes/amber.css +32 -2
  156. package/src/theme/styles/themes/arcade.css +16 -1
  157. package/src/theme/styles/themes/grannysmith.css +32 -2
  158. package/src/theme/styles/themes/honeycrisp.css +37 -7
  159. package/src/theme/styles/themes/midnight.css +16 -1
  160. package/src/theme/styles/themes/mulled.css +54 -9
  161. package/dist/theme/components/openapi/copy-markdown-button.tsx +0 -41
  162. package/src/theme/components/openapi/copy-markdown-button.tsx +0 -41
package/dist/node.mjs CHANGED
@@ -4,13 +4,16 @@ import { existsSync, readFileSync } from "node:fs";
4
4
  import { createRequire } from "node:module";
5
5
  import node_path from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
+ import { resolveOptionalIcon, serializeIcon } from "@ciderpress/config";
7
8
  import { BRAND_COLORS, BUILT_IN_THEMES, DEFAULT_THEME_NAME, defineTheme, isBuiltInTheme, resolveDefaultVariant, resolveThemeAlias, resolveThemeVariants, themeToCss } from "@ciderpress/theme";
8
- import { match as match_match } from "massaman/match";
9
+ import { P, match as match_match } from "massaman/match";
9
10
  import { visit as external_unist_util_visit_visit } from "unist-util-visit";
10
11
  import path_0 from "path";
11
12
  import { Project, SyntaxKind as external_ts_morph_SyntaxKind } from "ts-morph";
12
13
  import node_process from "node:process";
13
14
  import katex from "katex";
15
+ import { unfold } from "massaman/array";
16
+ import react from "react";
14
17
  import { fileURLToPath as __rspack_fileURLToPath } from "node:url";
15
18
  import { dirname as __rspack_dirname } from "node:path";
16
19
  import { createRequire as __rspack_createRequire } from "node:module";
@@ -8763,7 +8766,7 @@ const svgCaseSensitiveTagNames = [
8763
8766
  'textPath'
8764
8767
  ];
8765
8768
  const lib_h = createH(property_information_html, 'div');
8766
- const s = createH(property_information_svg, 'g', svgCaseSensitiveTagNames);
8769
+ const lib_s = createH(property_information_svg, 'g', svgCaseSensitiveTagNames);
8767
8770
  function lib_location(file) {
8768
8771
  const value = String(file);
8769
8772
  const indices = [];
@@ -8915,7 +8918,7 @@ function lib_element(state, node) {
8915
8918
  const name = (attribute.prefix ? attribute.prefix + ':' : '') + attribute.name;
8916
8919
  if (!own.call(proto, name)) properties[name] = attribute.value;
8917
8920
  }
8918
- const x = 'svg' === state.schema.space ? s : lib_h;
8921
+ const x = 'svg' === state.schema.space ? lib_s : lib_h;
8919
8922
  const result = x(node.tagName, properties, hast_util_from_parse5_lib_all(state, node.childNodes));
8920
8923
  patch(state, node, result);
8921
8924
  if ('template' === result.tagName) {
@@ -17285,8 +17288,14 @@ const APPLE_LOADER_CSS = readCss('css/loader-apple.css');
17285
17288
  const DOTS_LOADER_CSS = readCss('css/loader-dots.css');
17286
17289
  const DEFAULT_LOADER_STYLE = 'apple';
17287
17290
  function resolveLoaderCss(loader) {
17291
+ if (false === loader) return '';
17288
17292
  if ('classic' === loader) return BACKDROP_CSS + DOTS_LOADER_CSS;
17289
- return BACKDROP_CSS + APPLE_LOADER_CSS;
17293
+ if ('apple' === loader) return BACKDROP_CSS + APPLE_LOADER_CSS;
17294
+ if (isStaticLoader(loader)) return BACKDROP_CSS + buildCustomLoaderCss(loader);
17295
+ return BACKDROP_CSS;
17296
+ }
17297
+ function isStaticLoader(loader) {
17298
+ return 'content' in loader && 'string' == typeof loader.content;
17290
17299
  }
17291
17300
  function getThemeCss(themeName, loader = DEFAULT_LOADER_STYLE) {
17292
17301
  const loaderCss = resolveLoaderCss(loader);
@@ -17296,14 +17305,78 @@ function getThemeCss(themeName, loader = DEFAULT_LOADER_STYLE) {
17296
17305
  if (themeColors) return themeColors + loaderCss;
17297
17306
  return loaderCss;
17298
17307
  }
17308
+ function buildCustomLoaderCss(config) {
17309
+ const glyph = resolveGlyphUrl(config.content);
17310
+ const label = config.label ?? 'loading';
17311
+ const hasLabel = label.length > 0;
17312
+ const labelRule = match_match(hasLabel).with(true, ()=>buildLabelCss(label)).otherwise(()=>'');
17313
+ const marginLeft = match_match(hasLabel).with(true, ()=>'-110px').otherwise(()=>'-32px');
17314
+ return `
17315
+ html::before {
17316
+ content: '';
17317
+ position: fixed;
17318
+ top: 50%;
17319
+ left: 50%;
17320
+ width: 64px;
17321
+ height: 64px;
17322
+ margin-left: ${marginLeft};
17323
+ margin-top: -32px;
17324
+ background-image: ${glyph};
17325
+ background-repeat: no-repeat;
17326
+ background-position: center center;
17327
+ background-size: contain;
17328
+ image-rendering: pixelated;
17329
+ z-index: 9999;
17330
+ pointer-events: none;
17331
+ opacity: 1;
17332
+ transition: opacity 0.2s ease;
17333
+ }
17334
+ ${labelRule}
17335
+ html.cp-loader-fade::before,
17336
+ html.cp-loader-fade::after {
17337
+ opacity: 0;
17338
+ }
17339
+ html[data-cp-ready]::before,
17340
+ html[data-cp-ready]::after {
17341
+ display: none;
17342
+ }
17343
+ `;
17344
+ }
17345
+ function resolveGlyphUrl(content) {
17346
+ if (content.includes('<svg')) return `url("data:image/svg+xml;utf8,${encodeURIComponent(content)}")`;
17347
+ const safe = content.replaceAll('\\', String.raw`\\`).replaceAll('"', String.raw`\"`).replaceAll('<', String.raw`\3c `).replaceAll('\n', String.raw`\A `).replaceAll('\r', String.raw`\D `).replaceAll('\f', String.raw`\C `);
17348
+ return `url("${safe}")`;
17349
+ }
17350
+ function buildLabelCss(label) {
17351
+ const escaped = label.replaceAll('\\', String.raw`\\`).replaceAll("'", String.raw`\'`).replaceAll('<', String.raw`\3c `).replaceAll('\n', String.raw`\A `).replaceAll('\r', String.raw`\D `).replaceAll('\f', String.raw`\C `);
17352
+ return `html::after {
17353
+ content: '${escaped}';
17354
+ position: fixed;
17355
+ top: 50%;
17356
+ left: 50%;
17357
+ width: 160px;
17358
+ margin-left: -40px;
17359
+ margin-top: -14px;
17360
+ text-align: left;
17361
+ color: var(--cp-c-text-2, #888);
17362
+ font-family: var(--cp-ff-display, 'Geist Pixel Square', ui-sans-serif, system-ui, sans-serif);
17363
+ font-size: 28px;
17364
+ font-weight: 400;
17365
+ line-height: 1;
17366
+ letter-spacing: 0.04em;
17367
+ z-index: 9999;
17368
+ pointer-events: none;
17369
+ opacity: 1;
17370
+ transition: opacity 0.2s ease;
17371
+ }`;
17372
+ }
17299
17373
  function ciderpressPlugin() {
17300
17374
  const componentsDir = node_path.resolve(import.meta.dirname, 'theme', 'components');
17301
17375
  return {
17302
17376
  name: 'ciderpress',
17303
17377
  globalUIComponents: [
17304
17378
  node_path.resolve(componentsDir, 'theme-provider.tsx'),
17305
- node_path.resolve(componentsDir, 'edit-source-button.tsx'),
17306
- node_path.resolve(componentsDir, 'nav', 'nav-logo.tsx')
17379
+ node_path.resolve(componentsDir, 'edit-source-button.tsx')
17307
17380
  ]
17308
17381
  };
17309
17382
  }
@@ -17379,6 +17452,410 @@ function mermaidPlugin(options = {}) {
17379
17452
  builderConfig: remarkMermaid.builderConfig
17380
17453
  };
17381
17454
  }
17455
+ const SAFE_PROTOCOLS = new Set([
17456
+ 'http:',
17457
+ 'https:',
17458
+ 'mailto:',
17459
+ 'tel:'
17460
+ ]);
17461
+ const PROTOCOL_PATTERN = /^[a-z][a-z0-9+.-]*:/i;
17462
+ const FORBIDDEN_CHARS_PATTERN = /[\u0000-\u0020\u007F]/u;
17463
+ function safeUrl(href) {
17464
+ const trimmed = href.trim();
17465
+ if (FORBIDDEN_CHARS_PATTERN.test(trimmed)) return null;
17466
+ return match_match(trimmed).with('', ()=>null).with(P.string.startsWith('#'), ()=>trimmed).with(P.string.startsWith('/'), ()=>trimmed).with(P.string.startsWith('./'), ()=>trimmed).with(P.string.startsWith('../'), ()=>trimmed).otherwise(()=>{
17467
+ const match_ = trimmed.match(PROTOCOL_PATTERN);
17468
+ if (!match_) return trimmed;
17469
+ const scheme = match_[0].toLowerCase();
17470
+ if (SAFE_PROTOCOLS.has(scheme)) return trimmed;
17471
+ return null;
17472
+ });
17473
+ }
17474
+ const ALLOWED_TAGS = new Set([
17475
+ 'b',
17476
+ 'strong',
17477
+ 'i',
17478
+ 'em',
17479
+ 'code',
17480
+ 'kbd',
17481
+ 'mark',
17482
+ 'sup',
17483
+ 'sub',
17484
+ 'span',
17485
+ 'small',
17486
+ 'u',
17487
+ 's',
17488
+ 'del',
17489
+ 'ins'
17490
+ ]);
17491
+ const STRIPPED_TAGS = new Set([
17492
+ "script",
17493
+ 'style',
17494
+ 'iframe',
17495
+ 'object',
17496
+ 'embed',
17497
+ 'template',
17498
+ "noscript"
17499
+ ]);
17500
+ const ACCENT_CLASS = 'cp-accent';
17501
+ const MARK_CLASS = 'cp-mark';
17502
+ const TOKEN_PATTERN = /(?:\\([*=`[\]<\\]))|(?:`([^`]+)`)|(?:\*\*([\s\S]+?)\*\*)|(?:==([\s\S]+?)==)|(?:(?<!\*)\*(?=[^\s*])([^*\n]+?)(?<=[^\s*])\*(?!\*))|(?:\[([^\]]*)\]\(((?:[^()\s]|\([^()\s]*\))+)\))|(?:<(\/?)\s*([a-zA-Z][a-zA-Z0-9-]*)(?=[\s/>])((?:"[^"]*"|'[^']*'|[^>"'])*)>)/;
17503
+ const ATTR_PATTERN = /([a-zA-Z-]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
17504
+ const CLOSE_TAG_BOUNDARY = /[\s>]/;
17505
+ function parseRichText(text) {
17506
+ if ('string' != typeof text || 0 === text.length) return [];
17507
+ return parseInline({
17508
+ input: text,
17509
+ inLink: false
17510
+ });
17511
+ }
17512
+ function toPlainText(text) {
17513
+ return flattenNodes(parseRichText(text));
17514
+ }
17515
+ function parseInline({ input, inLink }) {
17516
+ return unfold((remaining)=>{
17517
+ if (0 === remaining.length) return false;
17518
+ const found = TOKEN_PATTERN.exec(remaining);
17519
+ if (null === found) return [
17520
+ [
17521
+ {
17522
+ kind: 'text',
17523
+ value: remaining
17524
+ }
17525
+ ],
17526
+ ''
17527
+ ];
17528
+ const lead = remaining.slice(0, found.index);
17529
+ const after = remaining.slice(found.index + found[0].length);
17530
+ const step = consumeToken({
17531
+ found,
17532
+ after,
17533
+ inLink
17534
+ });
17535
+ return [
17536
+ [
17537
+ ...textNodes(lead),
17538
+ ...step.nodes
17539
+ ],
17540
+ step.rest
17541
+ ];
17542
+ }, input).flat();
17543
+ }
17544
+ function textNodes(lead) {
17545
+ if (0 === lead.length) return [];
17546
+ return [
17547
+ {
17548
+ kind: 'text',
17549
+ value: lead
17550
+ }
17551
+ ];
17552
+ }
17553
+ function consumeToken({ found, after, inLink }) {
17554
+ const [, escaped, code, bold, highlight, italic, linkText, linkHref, closing, tagName, rawAttrs] = found;
17555
+ if (void 0 !== escaped) return {
17556
+ nodes: [
17557
+ {
17558
+ kind: 'text',
17559
+ value: escaped
17560
+ }
17561
+ ],
17562
+ rest: after
17563
+ };
17564
+ if (void 0 !== code) return {
17565
+ nodes: [
17566
+ codeNode(code)
17567
+ ],
17568
+ rest: after
17569
+ };
17570
+ if (void 0 !== bold) return {
17571
+ nodes: [
17572
+ accentNode(parseInline({
17573
+ input: bold,
17574
+ inLink
17575
+ }))
17576
+ ],
17577
+ rest: after
17578
+ };
17579
+ if (void 0 !== highlight) return {
17580
+ nodes: [
17581
+ markNode(parseInline({
17582
+ input: highlight,
17583
+ inLink
17584
+ }))
17585
+ ],
17586
+ rest: after
17587
+ };
17588
+ if (void 0 !== italic) return {
17589
+ nodes: [
17590
+ rich_text_parse_element({
17591
+ tag: 'em',
17592
+ children: parseInline({
17593
+ input: italic,
17594
+ inLink
17595
+ })
17596
+ })
17597
+ ],
17598
+ rest: after
17599
+ };
17600
+ if (void 0 !== linkHref) return {
17601
+ nodes: linkNodes({
17602
+ text: linkText ?? '',
17603
+ href: linkHref,
17604
+ inLink
17605
+ }),
17606
+ rest: after
17607
+ };
17608
+ if (void 0 !== tagName) {
17609
+ const tail = (rawAttrs ?? '').trimEnd();
17610
+ const isSelfClosing = tail.endsWith('/');
17611
+ return consumeTag({
17612
+ tagName: tagName.toLowerCase(),
17613
+ attrs: match_match(isSelfClosing).with(true, ()=>tail.slice(0, -1)).otherwise(()=>tail),
17614
+ isClosing: '/' === closing,
17615
+ isSelfClosing,
17616
+ after,
17617
+ inLink
17618
+ });
17619
+ }
17620
+ return {
17621
+ nodes: [
17622
+ {
17623
+ kind: 'text',
17624
+ value: found[0]
17625
+ }
17626
+ ],
17627
+ rest: after
17628
+ };
17629
+ }
17630
+ function consumeTag(params) {
17631
+ const { tagName, attrs, isClosing, isSelfClosing, after, inLink } = params;
17632
+ if (isClosing) return {
17633
+ nodes: [],
17634
+ rest: after
17635
+ };
17636
+ if ('br' === tagName) return {
17637
+ nodes: [
17638
+ {
17639
+ kind: 'break'
17640
+ }
17641
+ ],
17642
+ rest: after
17643
+ };
17644
+ if (isSelfClosing) return {
17645
+ nodes: selfClosingNodes({
17646
+ tagName,
17647
+ attrs
17648
+ }),
17649
+ rest: after
17650
+ };
17651
+ const close = findClosingTag({
17652
+ text: after,
17653
+ tagName
17654
+ });
17655
+ if (null === close) {
17656
+ if (STRIPPED_TAGS.has(tagName)) return {
17657
+ nodes: [],
17658
+ rest: ''
17659
+ };
17660
+ return {
17661
+ nodes: [],
17662
+ rest: after
17663
+ };
17664
+ }
17665
+ const inner = after.slice(0, close.start);
17666
+ const rest = after.slice(close.end);
17667
+ if (STRIPPED_TAGS.has(tagName)) return {
17668
+ nodes: [],
17669
+ rest
17670
+ };
17671
+ if ('a' === tagName) return {
17672
+ nodes: anchorNodes({
17673
+ attrs,
17674
+ inner,
17675
+ inLink
17676
+ }),
17677
+ rest
17678
+ };
17679
+ if (ALLOWED_TAGS.has(tagName)) return {
17680
+ nodes: [
17681
+ taggedElement({
17682
+ tag: tagName,
17683
+ attrs,
17684
+ children: parseInline({
17685
+ input: inner,
17686
+ inLink
17687
+ })
17688
+ })
17689
+ ],
17690
+ rest
17691
+ };
17692
+ return {
17693
+ nodes: parseInline({
17694
+ input: inner,
17695
+ inLink
17696
+ }),
17697
+ rest
17698
+ };
17699
+ }
17700
+ function selfClosingNodes({ tagName, attrs }) {
17701
+ if (!ALLOWED_TAGS.has(tagName)) return [];
17702
+ return [
17703
+ taggedElement({
17704
+ tag: tagName,
17705
+ attrs,
17706
+ children: []
17707
+ })
17708
+ ];
17709
+ }
17710
+ function findClosingTag({ text, tagName }) {
17711
+ return scanForClose({
17712
+ lower: text.toLowerCase(),
17713
+ tagName,
17714
+ from: 0
17715
+ });
17716
+ }
17717
+ function scanForClose({ lower, tagName, from }) {
17718
+ const needle = `</${tagName}`;
17719
+ const candidates = unfold((offset)=>{
17720
+ const at = lower.indexOf(needle, offset);
17721
+ if (-1 === at) return false;
17722
+ return [
17723
+ at,
17724
+ at + needle.length
17725
+ ];
17726
+ }, from);
17727
+ const start = candidates.find((at)=>CLOSE_TAG_BOUNDARY.test(lower.charAt(at + needle.length)));
17728
+ if (void 0 === start) return null;
17729
+ const gt = lower.indexOf('>', start);
17730
+ if (-1 === gt) return null;
17731
+ return {
17732
+ start,
17733
+ end: gt + 1
17734
+ };
17735
+ }
17736
+ function parseAttrs(attrs) {
17737
+ const entries = [
17738
+ ...attrs.matchAll(ATTR_PATTERN)
17739
+ ];
17740
+ return entries.reduce((acc, entry)=>{
17741
+ const name = entry[1].toLowerCase();
17742
+ const value = entry[2] ?? entry[3] ?? '';
17743
+ return match_match(name).with('class', ()=>({
17744
+ ...acc,
17745
+ className: value
17746
+ })).with('classname', ()=>({
17747
+ ...acc,
17748
+ className: value
17749
+ })).with('title', ()=>({
17750
+ ...acc,
17751
+ title: value
17752
+ })).with('href', ()=>({
17753
+ ...acc,
17754
+ href: value
17755
+ })).otherwise(()=>acc);
17756
+ }, {});
17757
+ }
17758
+ function taggedElement({ tag, attrs, children }) {
17759
+ const parsed = parseAttrs(attrs);
17760
+ return {
17761
+ kind: 'element',
17762
+ tag,
17763
+ className: parsed.className,
17764
+ title: parsed.title,
17765
+ children
17766
+ };
17767
+ }
17768
+ function anchorNodes({ attrs, inner, inLink }) {
17769
+ const { href } = parseAttrs(attrs);
17770
+ if (void 0 === href || inLink) return parseInline({
17771
+ input: inner,
17772
+ inLink
17773
+ });
17774
+ const safe = safeUrl(href);
17775
+ if (null === safe) return parseInline({
17776
+ input: inner,
17777
+ inLink
17778
+ });
17779
+ const children = parseInline({
17780
+ input: inner,
17781
+ inLink: true
17782
+ });
17783
+ return linkOrChildren({
17784
+ href: safe,
17785
+ children
17786
+ });
17787
+ }
17788
+ function linkNodes({ text, href, inLink }) {
17789
+ const safe = safeUrl(href);
17790
+ if (null === safe || inLink) return parseInline({
17791
+ input: text,
17792
+ inLink
17793
+ });
17794
+ return linkOrChildren({
17795
+ href: safe,
17796
+ children: parseInline({
17797
+ input: text,
17798
+ inLink: true
17799
+ })
17800
+ });
17801
+ }
17802
+ function linkOrChildren({ href, children }) {
17803
+ if (0 === children.length) return [];
17804
+ return [
17805
+ {
17806
+ kind: 'link',
17807
+ href,
17808
+ children
17809
+ }
17810
+ ];
17811
+ }
17812
+ function codeNode(value) {
17813
+ return {
17814
+ kind: 'code',
17815
+ value
17816
+ };
17817
+ }
17818
+ function accentNode(children) {
17819
+ return {
17820
+ kind: 'element',
17821
+ tag: 'strong',
17822
+ className: ACCENT_CLASS,
17823
+ children
17824
+ };
17825
+ }
17826
+ function markNode(children) {
17827
+ return {
17828
+ kind: 'element',
17829
+ tag: 'mark',
17830
+ className: MARK_CLASS,
17831
+ children
17832
+ };
17833
+ }
17834
+ function rich_text_parse_element({ tag, children }) {
17835
+ return {
17836
+ kind: 'element',
17837
+ tag,
17838
+ children
17839
+ };
17840
+ }
17841
+ function flattenNodes(nodes) {
17842
+ return nodes.map(flattenNode).join('');
17843
+ }
17844
+ function flattenNode(node) {
17845
+ return match_match(node).with({
17846
+ kind: 'text'
17847
+ }, (n)=>n.value).with({
17848
+ kind: 'code'
17849
+ }, (n)=>n.value).with({
17850
+ kind: 'break'
17851
+ }, ()=>' ').with({
17852
+ kind: 'link'
17853
+ }, (n)=>flattenNodes(n.children)).with({
17854
+ kind: 'element'
17855
+ }, (n)=>flattenNodes(n.children)).exhaustive();
17856
+ }
17857
+ const DEFAULT_LOADER_MIN_MS = 150;
17858
+ const DEFAULT_LOADER_MAX_MS = 5000;
17382
17859
  const VSCODE_SET_JS = "document.documentElement.dataset.ciderpressEnv='vscode'";
17383
17860
  const VSCODE_NAV_JS = readJs('js/vscode-nav.js');
17384
17861
  const LOADER_DOTS_JS = readJs('js/loader-dots.js');
@@ -17395,7 +17872,22 @@ function createRspressConfig(options) {
17395
17872
  name: 'scopes.json',
17396
17873
  fallback: []
17397
17874
  });
17875
+ const pageBadges = loadGenerated({
17876
+ contentDir: paths.contentDir,
17877
+ name: 'badges.json',
17878
+ fallback: {}
17879
+ });
17398
17880
  const gitBranch = detectGitBranch();
17881
+ const brand = config.brand;
17882
+ const home = config.home;
17883
+ const editLink = config.editLink;
17884
+ const reportLink = config.reportLink;
17885
+ const topbar = config.topbar;
17886
+ const sidebar = config.sidebar;
17887
+ const footer = config.footer;
17888
+ const favicon = brand && brand.favicon;
17889
+ const loaderRaw = brand && brand.loader;
17890
+ const logoRaw = brand && brand.logo;
17399
17891
  const themeName = resolveThemeName(config, options.themeOverride);
17400
17892
  const userThemes = resolveUserThemes(config);
17401
17893
  const variant = resolveActiveVariant({
@@ -17408,35 +17900,59 @@ function createRspressConfig(options) {
17408
17900
  const themeColors = resolveThemeColors(config);
17409
17901
  const themeDarkColors = resolveThemeDarkColors(config);
17410
17902
  const userThemesCss = userThemes.map(themeToCss).join('');
17411
- const loaderStyle = config.loader ?? 'apple';
17903
+ const loaderStyle = resolveLoaderStyle(loaderRaw);
17412
17904
  const themeCss = getThemeCss(themeName, loaderStyle) + userThemesCss;
17413
17905
  const themeRegistry = [
17414
17906
  ...BUILT_IN_THEME_REGISTRY,
17415
17907
  ...userThemes.map(buildRegistryEntry)
17416
17908
  ];
17417
17909
  const isVscode = true === vscode;
17910
+ const loaderMaxMs = resolveLoaderMaxMs(loaderRaw);
17418
17911
  const headScriptBody = buildHeadScriptBody({
17419
17912
  variant,
17420
17913
  themeName,
17421
17914
  vscode: isVscode,
17422
- registry: themeRegistry
17915
+ registry: themeRegistry,
17916
+ loaderMaxMs,
17917
+ useDotsLoader: 'classic' === loaderStyle,
17918
+ loaderEnabled: false !== loaderStyle
17423
17919
  });
17424
17920
  const selfRequire = createRequire(import.meta.url);
17425
17921
  const reactAlias = node_path.dirname(selfRequire.resolve('react/package.json'));
17426
17922
  const reactDomAlias = node_path.dirname(selfRequire.resolve('react-dom/package.json'));
17427
17923
  const userConfigAlias = resolveUserConfigAlias(paths.repoRoot);
17428
- const resolvedLogo = resolveLogo(config.logo);
17924
+ const envBase = process.env.CIDERPRESS_BASE;
17925
+ const resolvedBase = match_match([
17926
+ envBase,
17927
+ config.base
17928
+ ]).with([
17929
+ P.string.minLength(1),
17930
+ P._
17931
+ ], ([b])=>b).with([
17932
+ P._,
17933
+ P.string.minLength(1)
17934
+ ], ([, b])=>b).otherwise(()=>'/');
17935
+ const siteBlock = buildSiteBlock({
17936
+ config,
17937
+ editLink,
17938
+ reportLink,
17939
+ feedback: config.feedback,
17940
+ topbar,
17941
+ sidebar,
17942
+ footer
17943
+ });
17429
17944
  return {
17430
17945
  root: paths.contentDir,
17431
17946
  outDir: paths.distDir,
17947
+ base: resolvedBase,
17432
17948
  route: {
17433
17949
  cleanUrls: true
17434
17950
  },
17435
17951
  llms: true,
17436
- title: config.title ?? 'ciderpress',
17437
- description: config.description ?? 'Documentation',
17438
- icon: config.icon ?? '/icon.svg',
17439
- logo: resolvedLogo,
17952
+ title: toPlainText(config.title ?? 'ciderpress'),
17953
+ description: toPlainText(config.description ?? 'Documentation'),
17954
+ icon: resolveFaviconPath(favicon),
17955
+ logo: match_match(logoRaw).with(P.string, (l)=>l).otherwise(()=>''),
17440
17956
  logoText: '',
17441
17957
  themeDir: node_path.resolve(import.meta.dirname, 'theme'),
17442
17958
  plugins: [
@@ -17451,7 +17967,12 @@ function createRspressConfig(options) {
17451
17967
  markdown: {
17452
17968
  remarkPlugins: [
17453
17969
  remarkMathToDiv
17454
- ]
17970
+ ],
17971
+ link: {
17972
+ checkDeadLinks: {
17973
+ excludes: (url)=>url.startsWith('/examples/')
17974
+ }
17975
+ }
17455
17976
  },
17456
17977
  builderConfig: {
17457
17978
  ...(()=>{
@@ -17462,6 +17983,7 @@ function createRspressConfig(options) {
17462
17983
  })(),
17463
17984
  html: {
17464
17985
  tags: [
17986
+ ...resolveFaviconLinkTags(favicon),
17465
17987
  {
17466
17988
  tag: 'style',
17467
17989
  children: themeCss,
@@ -17498,7 +18020,15 @@ function createRspressConfig(options) {
17498
18020
  __CIDERPRESS_THEME_DARK_COLORS__: JSON.stringify(JSON.stringify(themeDarkColors)),
17499
18021
  __CIDERPRESS_THEME_SWITCHER__: JSON.stringify(themeSwitcher),
17500
18022
  __CIDERPRESS_THEME_REGISTRY__: JSON.stringify(JSON.stringify(themeRegistry)),
17501
- __CIDERPRESS_VSCODE__: JSON.stringify(isVscode)
18023
+ __CIDERPRESS_VSCODE__: JSON.stringify(isVscode),
18024
+ __CIDERPRESS_HAS_USER_FAVICON__: JSON.stringify(void 0 !== favicon),
18025
+ __CIDERPRESS_LOADER_MIN_MS__: JSON.stringify(resolveLoaderMinMs(loaderRaw)),
18026
+ __CIDERPRESS_LOADER_MAX_MS__: JSON.stringify(resolveLoaderMaxMs(loaderRaw)),
18027
+ __CIDERPRESS_HAS_VARIANT_TOGGLE__: JSON.stringify(resolveHasVariantToggle({
18028
+ themeName,
18029
+ themeSwitcher,
18030
+ registry: themeRegistry
18031
+ }))
17502
18032
  }
17503
18033
  },
17504
18034
  output: {
@@ -17515,29 +18045,26 @@ function createRspressConfig(options) {
17515
18045
  },
17516
18046
  ...{
17517
18047
  workspaces,
17518
- standaloneScopePaths
18048
+ standaloneScopePaths,
18049
+ pageBadges
17519
18050
  },
17520
18051
  ...{
17521
- socialLinks: config.socialLinks,
18052
+ socialLinks: serializeSocials(config.socials),
17522
18053
  sidebarAbove: resolveSidebarLinks({
17523
18054
  config,
17524
- position: 'above'
18055
+ position: 'top'
17525
18056
  }),
17526
18057
  sidebarBelow: resolveSidebarLinks({
17527
18058
  config,
17528
- position: 'below'
18059
+ position: 'bottom'
17529
18060
  }),
17530
- home: resolveHomeConfig(config),
17531
- ciderpressFooter: config.footer,
17532
- site: config.site
18061
+ home: resolveHomeConfig(home),
18062
+ ciderpressFooter: footer,
18063
+ site: siteBlock
17533
18064
  }
17534
18065
  }
17535
18066
  };
17536
18067
  }
17537
- function resolveLogo(logo) {
17538
- if ('string' == typeof logo) return logo;
17539
- if (null == logo) return '/logo.svg';
17540
- }
17541
18068
  function loadGenerated(params) {
17542
18069
  const p = node_path.resolve(params.contentDir, '.generated', params.name);
17543
18070
  if (!existsSync(p)) {
@@ -17565,17 +18092,35 @@ function resolveThemeName(config, override) {
17565
18092
  const registeredNames = collectRegisteredThemeNames(config);
17566
18093
  const requested = resolveThemeAlias(resolveRequestedThemeName(config, override));
17567
18094
  if (registeredNames.has(requested)) return requested;
17568
- process.stderr.write(`[ciderpress] Unknown theme '${requested}' — not a built-in and not declared in config.themes. Falling back to '${DEFAULT_THEME_NAME}'.\n`);
18095
+ process.stderr.write(`[ciderpress] Unknown theme '${requested}' — not a built-in and not declared in theme.themes. Falling back to '${DEFAULT_THEME_NAME}'.\n`);
17569
18096
  return DEFAULT_THEME_NAME;
17570
18097
  }
17571
18098
  function resolveRequestedThemeName(config, override) {
17572
18099
  if (override) return override;
17573
- if (config.theme && config.theme.name) return config.theme.name;
18100
+ const fromThemes = resolveDefaultEntryName(config.theme && config.theme.themes);
18101
+ if (void 0 !== fromThemes) return fromThemes;
17574
18102
  return DEFAULT_THEME_NAME;
17575
18103
  }
18104
+ function resolveDefaultEntryName(themes) {
18105
+ if (void 0 === themes || 0 === themes.length) return;
18106
+ const marked = themes.find(isDefaultMarked);
18107
+ if (void 0 !== marked) return readThemeEntryName(marked);
18108
+ return readThemeEntryName(themes[0]);
18109
+ }
18110
+ function isDefaultMarked(entry) {
18111
+ if ('string' == typeof entry) return false;
18112
+ const obj = entry;
18113
+ return true === obj.default;
18114
+ }
18115
+ function readThemeEntryName(entry) {
18116
+ if ('string' == typeof entry) return entry;
18117
+ const obj = entry;
18118
+ if ('string' == typeof obj.name) return obj.name;
18119
+ return '';
18120
+ }
17576
18121
  function collectRegisteredThemeNames(config) {
17577
18122
  const builtIn = Object.keys(BUILT_IN_THEMES);
17578
- const user = (config.themes ?? []).map((t)=>t.name);
18123
+ const user = resolveUserThemeInputs(config).map((t)=>t.name);
17579
18124
  return new Set([
17580
18125
  ...builtIn,
17581
18126
  ...user
@@ -17584,8 +18129,8 @@ function collectRegisteredThemeNames(config) {
17584
18129
  function resolveActiveVariant(params) {
17585
18130
  const supported = resolveSupportedVariants(params.themeName, params.userThemes);
17586
18131
  const themeBlock = params.config.theme;
17587
- const fromConfig = match_match(themeBlock).with(void 0, ()=>{}).otherwise((block)=>block.variant);
17588
- const requested = params.override ?? fromConfig;
18132
+ const fromConfig = match_match(themeBlock).with(void 0, ()=>void 0).otherwise((block)=>block.defaultVariant);
18133
+ const requested = match_match(params.override).with(P.nonNullable, (o)=>o).otherwise(()=>normaliseConfigVariant(fromConfig));
17589
18134
  if (void 0 !== requested && supported.includes(requested)) return requested;
17590
18135
  if (void 0 !== requested) process.stderr.write(`[ciderpress] Theme '${params.themeName}' does not declare variant '${requested}'. Falling back to its default variant.\n`);
17591
18136
  if (isBuiltInTheme(params.themeName)) return resolveDefaultVariant(params.themeName);
@@ -17593,6 +18138,9 @@ function resolveActiveVariant(params) {
17593
18138
  if (userTheme) return userTheme.defaultVariant;
17594
18139
  return 'dark';
17595
18140
  }
18141
+ function normaliseConfigVariant(raw) {
18142
+ if ('light' === raw || 'dark' === raw) return raw;
18143
+ }
17596
18144
  function resolveSupportedVariants(themeName, userThemes) {
17597
18145
  if (isBuiltInTheme(themeName)) return resolveThemeVariants(themeName);
17598
18146
  const userTheme = userThemes.find((t)=>t.name === themeName);
@@ -17602,39 +18150,123 @@ function resolveSupportedVariants(themeName, userThemes) {
17602
18150
  ];
17603
18151
  }
17604
18152
  function resolveThemeSwitcher(config) {
17605
- if (config.theme && config.theme.switcher) return config.theme.switcher;
18153
+ const themeBlock = config.theme;
18154
+ if (void 0 === themeBlock) return false;
18155
+ if (void 0 !== themeBlock.themeSwitcher) return themeBlock.themeSwitcher;
18156
+ const themes = themeBlock.themes;
18157
+ if (void 0 !== themes && themes.length > 1) return true;
17606
18158
  return false;
17607
18159
  }
17608
18160
  function resolveThemeColors(config) {
17609
- if (config.theme && config.theme.colors) return config.theme.colors;
18161
+ if (config.theme && config.theme.overrides) return config.theme.overrides;
17610
18162
  return {};
17611
18163
  }
17612
- function resolveThemeDarkColors(config) {
17613
- if (config.theme && config.theme.darkColors) return config.theme.darkColors;
18164
+ function resolveThemeDarkColors(_config) {
17614
18165
  return {};
17615
18166
  }
18167
+ function resolveUserThemeInputs(config) {
18168
+ const themes = config.theme && config.theme.themes;
18169
+ if (!themes) return [];
18170
+ return themes.flatMap((entry)=>{
18171
+ if ('string' == typeof entry) return [];
18172
+ const obj = entry;
18173
+ if (!('variants' in obj)) return [];
18174
+ const { default: _default, ...rest } = obj;
18175
+ return [
18176
+ rest
18177
+ ];
18178
+ });
18179
+ }
17616
18180
  function resolveUserThemes(config) {
17617
- if (!config.themes) return [];
17618
- return config.themes.map(defineTheme);
18181
+ return resolveUserThemeInputs(config).map(defineTheme);
17619
18182
  }
17620
18183
  function resolveSidebarLinks(params) {
17621
- const items = params.config.sidebar && params.config.sidebar[params.position];
17622
- if (items) return items;
17623
- return [];
18184
+ const sidebar = params.config.sidebar;
18185
+ if (void 0 === sidebar) return [];
18186
+ const items = sidebar[params.position];
18187
+ if (!items) return [];
18188
+ return items.map((item)=>({
18189
+ text: item.text,
18190
+ link: item.href,
18191
+ icon: serializeIcon(resolveOptionalIcon(item.icon)),
18192
+ style: mapButtonVariantToStyle(item.variant),
18193
+ shape: item.shape
18194
+ }));
17624
18195
  }
17625
- function resolveHomeConfig(config) {
17626
- if (config.home) return {
17627
- features: config.home.features,
17628
- workspaces: {
17629
- columns: 2,
17630
- ...config.home.workspaces
17631
- }
17632
- };
18196
+ function mapButtonVariantToStyle(variant) {
18197
+ return match_match(variant).with(void 0, ()=>void 0).with('primary', ()=>'brand').with('secondary', ()=>'alt').with('ghost', ()=>'ghost').exhaustive();
18198
+ }
18199
+ function serializeSocials(socials) {
18200
+ if (void 0 === socials) return [];
18201
+ return socials.map((entry)=>({
18202
+ icon: entry.icon,
18203
+ url: entry.url,
18204
+ label: entry.label
18205
+ }));
18206
+ }
18207
+ function buildSiteBlock(params) {
18208
+ const editBlock = match_match(params.editLink).with(void 0, ()=>void 0).with(false, ()=>void 0).otherwise((e)=>{
18209
+ if (void 0 === e.repo) return;
18210
+ return {
18211
+ repo: e.repo,
18212
+ branch: e.branch,
18213
+ directory: e.directory,
18214
+ label: e.label
18215
+ };
18216
+ });
18217
+ const reportBlock = match_match(params.reportLink).with(void 0, ()=>void 0).with(false, ()=>void 0).otherwise((r)=>{
18218
+ if (void 0 === r.repo) return;
18219
+ return {
18220
+ repo: r.repo,
18221
+ branch: r.branch,
18222
+ directory: r.directory,
18223
+ label: r.label
18224
+ };
18225
+ });
18226
+ const topbar = params.topbar;
18227
+ const topbarCta = match_match(topbar).with(void 0, ()=>void 0).otherwise((t)=>{
18228
+ const cta = t.cta;
18229
+ if (void 0 === cta) return;
18230
+ return {
18231
+ text: cta.text,
18232
+ href: cta.href
18233
+ };
18234
+ });
18235
+ const announcement = match_match(topbar).with(void 0, ()=>void 0).otherwise((t)=>t.announcement);
18236
+ const sidebar = params.sidebar;
18237
+ const sidebarPromo = match_match(sidebar).with(void 0, ()=>void 0).otherwise((s)=>s.promo);
18238
+ const footer = params.footer;
18239
+ const footerBlock = match_match(footer).with(void 0, ()=>void 0).otherwise((f)=>({
18240
+ columns: f.columns,
18241
+ tagline: f.tagline,
18242
+ brandMark: f.brandMark
18243
+ }));
18244
+ const feedbackBlock = match_match(params.feedback).with(true, ()=>({
18245
+ enabled: true,
18246
+ question: void 0
18247
+ })).with(P.union(false, void 0), ()=>({
18248
+ enabled: false,
18249
+ question: void 0
18250
+ })).otherwise((f)=>({
18251
+ enabled: true,
18252
+ question: f.question
18253
+ }));
17633
18254
  return {
17634
- workspaces: {
17635
- columns: 2
17636
- }
18255
+ version: params.config.version,
18256
+ edit: editBlock,
18257
+ report: reportBlock,
18258
+ topbarCta,
18259
+ sidebarPromo,
18260
+ announcement,
18261
+ footer: footerBlock,
18262
+ feedback: feedbackBlock
18263
+ };
18264
+ }
18265
+ function resolveHomeConfig(home) {
18266
+ if (void 0 === home) return {
18267
+ hero: {}
17637
18268
  };
18269
+ return home;
17638
18270
  }
17639
18271
  function buildHeadScriptBody(options) {
17640
18272
  const minimalRegistry = options.registry.map((entry)=>({
@@ -17684,12 +18316,57 @@ function buildHeadScriptBody(options) {
17684
18316
  ].join(';');
17685
18317
  return '';
17686
18318
  })();
18319
+ const fallbackJs = match_match(options.loaderEnabled).with(true, ()=>`setTimeout(function(){var d=document.documentElement;if(d.dataset.cpReady!=='true'){d.classList.add('cp-loader-fade');setTimeout(function(){d.dataset.cpReady='true'},220)}},${options.loaderMaxMs})`).otherwise(()=>'');
18320
+ const loaderJs = match_match(options.useDotsLoader).with(true, ()=>LOADER_DOTS_JS).otherwise(()=>'');
17687
18321
  return [
17688
18322
  resolveJs,
17689
18323
  vscodeJs,
17690
- LOADER_DOTS_JS
18324
+ loaderJs,
18325
+ fallbackJs
17691
18326
  ].filter(Boolean).join(';');
17692
18327
  }
18328
+ function resolveLoaderStyle(loader) {
18329
+ if (void 0 === loader) return 'apple';
18330
+ return loader;
18331
+ }
18332
+ function resolveLoaderMinMs(loader) {
18333
+ if (isLoaderConfig(loader) && 'number' == typeof loader.minDisplayMs) return loader.minDisplayMs;
18334
+ return DEFAULT_LOADER_MIN_MS;
18335
+ }
18336
+ function resolveLoaderMaxMs(loader) {
18337
+ if (isLoaderConfig(loader) && 'number' == typeof loader.maxDisplayMs) return loader.maxDisplayMs;
18338
+ return DEFAULT_LOADER_MAX_MS;
18339
+ }
18340
+ function isLoaderConfig(loader) {
18341
+ return 'object' == typeof loader && null !== loader;
18342
+ }
18343
+ function resolveFaviconPath(favicon) {
18344
+ if (void 0 === favicon) return '/icon.svg';
18345
+ if ('string' == typeof favicon) return favicon;
18346
+ return favicon.src;
18347
+ }
18348
+ function resolveFaviconLinkTags(favicon) {
18349
+ if (void 0 === favicon || 'string' == typeof favicon) return [];
18350
+ if (void 0 === favicon.type) return [];
18351
+ return [
18352
+ {
18353
+ tag: 'link',
18354
+ attrs: {
18355
+ rel: 'icon',
18356
+ href: favicon.src,
18357
+ type: favicon.type
18358
+ },
18359
+ head: true,
18360
+ append: false
18361
+ }
18362
+ ];
18363
+ }
18364
+ function resolveHasVariantToggle(params) {
18365
+ if (params.themeSwitcher) return true;
18366
+ const entry = params.registry.find((e)=>e.name === params.themeName);
18367
+ if (void 0 === entry) return false;
18368
+ return entry.variants.length > 1;
18369
+ }
17693
18370
  function buildRegistryEntry(theme) {
17694
18371
  const defaultTokens = theme.variants[theme.defaultVariant];
17695
18372
  const swatch = match_match(defaultTokens).with(void 0, ()=>'').otherwise((tokens)=>tokens.colors.brand.primary);
@@ -17738,7 +18415,7 @@ const CIDERPRESS_ART = Object.freeze([
17738
18415
  ]);
17739
18416
  function CiderpressLogo(props) {
17740
18417
  const title = props.title ?? 'ciderpress';
17741
- return /*#__PURE__*/ React.createElement("svg", {
18418
+ return /*#__PURE__*/ react.createElement("svg", {
17742
18419
  xmlns: "http://www.w3.org/2000/svg",
17743
18420
  viewBox: LOGO_VIEWBOX,
17744
18421
  className: props.className,
@@ -17748,11 +18425,11 @@ function CiderpressLogo(props) {
17748
18425
  color: `var(--rp-c-brand, ${LOGO_FALLBACK_COLOR})`
17749
18426
  },
17750
18427
  role: "img"
17751
- }, /*#__PURE__*/ React.createElement("title", null, title), /*#__PURE__*/ React.createElement("g", {
18428
+ }, /*#__PURE__*/ react.createElement("title", null, title), /*#__PURE__*/ react.createElement("g", {
17752
18429
  transform: `translate(${X_OFFSET}, ${Y_OFFSET})`,
17753
18430
  fontFamily: FONT_STACK,
17754
18431
  fill: "currentColor"
17755
- }, CIDERPRESS_ART.map((line, i)=>/*#__PURE__*/ React.createElement("text", {
18432
+ }, CIDERPRESS_ART.map((line, i)=>/*#__PURE__*/ react.createElement("text", {
17756
18433
  key: line,
17757
18434
  fontSize: FONT_SIZE,
17758
18435
  y: i * LINE_HEIGHT,