forgecad 0.6.3 → 0.8.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.
Files changed (234) hide show
  1. package/README.md +3 -12
  2. package/dist/assets/{AdminPage-CeqCUUgu.js → AdminPage-D4bocK4E.js} +250 -151
  3. package/dist/assets/{BlogPage-P_AJP0v9.js → BlogPage-CJEXL_zJ.js} +94 -70
  4. package/dist/assets/{DocsPage-CKRV2iq2.js → DocsPage-D3A_g8V3.js} +329 -163
  5. package/dist/assets/{EditorApp-CnC2k4cW.css → EditorApp-BWYUSpUN.css} +590 -136
  6. package/dist/assets/EditorApp-Cihhqcsq.js +11692 -0
  7. package/dist/assets/{EmbedViewer-DBlzmQ5i.js → EmbedViewer-kWjKaC_t.js} +2 -4
  8. package/dist/assets/LandingPageProofDriven-Bg2IUc3l.css +856 -0
  9. package/dist/assets/LandingPageProofDriven-DXkKlyhI.js +601 -0
  10. package/dist/assets/PricingPage-BsU5vzEx.js +232 -0
  11. package/dist/assets/{SettingsPage-BqCh9JcC.js → SettingsPage-PqvpAKIs.js} +129 -5
  12. package/dist/assets/{evalWorker-Ql-aKwLA.js → evalWorker-C-hzNUMy.js} +8949 -3161
  13. package/dist/assets/{Viewport-CoB46f5R.js → index-Pz321YAt.js} +38382 -7501
  14. package/dist/assets/{index-2hfs_ub0.css → index-ay13WNfa.css} +726 -53
  15. package/dist/assets/{javascript-DCxGoE5Y.js → javascript-DAl8Gmyo.js} +1 -1
  16. package/dist/assets/{manifold-CqNMHHKO.js → manifold-BcbjWLIo.js} +4 -3
  17. package/dist/assets/{manifold-Cce9wRFz.js → manifold-DBckbFgx.js} +1 -1
  18. package/dist/assets/{manifold-D6BeHIOo.js → manifold-O2AAGXyj.js} +1 -1
  19. package/dist/assets/{reportWorker-sFEFonXf.js → reportWorker-Dxr-5A7w.js} +8760 -3559
  20. package/dist/assets/{vendor-react-Dt7-aaJH.js → vendor-react-CG3i_wp0.js} +65 -8
  21. package/dist/docs/index.html +2 -2
  22. package/dist/docs-raw/CLI.md +341 -718
  23. package/dist/docs-raw/generated/assembly.md +699 -112
  24. package/dist/docs-raw/generated/concepts.md +1834 -1346
  25. package/dist/docs-raw/generated/core.md +1012 -1059
  26. package/dist/docs-raw/generated/curves.md +759 -116
  27. package/dist/docs-raw/generated/lib.md +43 -748
  28. package/dist/docs-raw/generated/output.md +139 -245
  29. package/dist/docs-raw/generated/sdf.md +208 -0
  30. package/dist/docs-raw/generated/sheet-metal.md +473 -21
  31. package/dist/docs-raw/generated/sketch.md +1518 -362
  32. package/dist/docs-raw/generated/viewport.md +368 -299
  33. package/dist/docs-raw/generated/wood.md +104 -0
  34. package/dist/index.html +2 -2
  35. package/dist/landing/proof-ams-adapter.png +0 -0
  36. package/dist/landing/proof-bolt-and-nut.png +0 -0
  37. package/dist/landing/proof-fillet-enclosure.png +0 -0
  38. package/dist/landing/proof-glasses.png +0 -0
  39. package/dist/landing/proof-gyroid.png +0 -0
  40. package/dist/sitemap.xml +6 -6
  41. package/dist-cli/forgecad.js +12321 -5700
  42. package/dist-cli/forgecad.js.map +1 -0
  43. package/dist-cli/solver-46FFSK2U.js +363 -0
  44. package/dist-cli/solver-46FFSK2U.js.map +1 -0
  45. package/dist-skill/CONTEXT.md +4890 -6302
  46. package/dist-skill/SKILL-dev.md +22 -66
  47. package/dist-skill/SKILL.md +20 -59
  48. package/dist-skill/docs/API/core/concepts.md +37 -92
  49. package/dist-skill/docs/CLI.md +341 -718
  50. package/dist-skill/docs/generated/assembly.md +699 -112
  51. package/dist-skill/docs/generated/core.md +1012 -1059
  52. package/dist-skill/docs/generated/curves.md +759 -116
  53. package/dist-skill/docs/generated/lib.md +43 -748
  54. package/dist-skill/docs/generated/output.md +139 -245
  55. package/dist-skill/docs/generated/sdf.md +208 -0
  56. package/dist-skill/docs/generated/sheet-metal.md +473 -21
  57. package/dist-skill/docs/generated/sketch.md +1518 -362
  58. package/dist-skill/docs/generated/viewport.md +368 -299
  59. package/dist-skill/docs/generated/wood.md +104 -0
  60. package/dist-skill/docs/guides/coordinate-system.md +11 -17
  61. package/dist-skill/docs/guides/geometry-conventions.md +13 -70
  62. package/dist-skill/docs/guides/joint-design.md +78 -0
  63. package/dist-skill/docs/guides/modeling-recipes.md +22 -195
  64. package/dist-skill/docs/guides/positioning.md +88 -147
  65. package/dist-skill/docs-dev/API/core/concepts.md +78 -0
  66. package/dist-skill/docs-dev/CLI.md +488 -0
  67. package/dist-skill/{docs → docs-dev}/blueprint-first.md +5 -0
  68. package/dist-skill/{docs → docs-dev}/coding-best-practices.md +6 -8
  69. package/dist-skill/{docs → docs-dev}/coding.md +2 -4
  70. package/dist-skill/docs-dev/component-model.md +164 -0
  71. package/dist-skill/docs-dev/generated/assembly.md +779 -0
  72. package/dist-skill/docs-dev/generated/core.md +1676 -0
  73. package/dist-skill/docs-dev/generated/curves.md +855 -0
  74. package/dist-skill/docs-dev/generated/lib.md +55 -0
  75. package/dist-skill/docs-dev/generated/output.md +234 -0
  76. package/dist-skill/docs-dev/generated/sdf.md +208 -0
  77. package/dist-skill/docs-dev/generated/sheet-metal.md +506 -0
  78. package/dist-skill/docs-dev/generated/sketch.md +1753 -0
  79. package/dist-skill/docs-dev/generated/viewport.md +513 -0
  80. package/dist-skill/docs-dev/generated/wood.md +104 -0
  81. package/dist-skill/docs-dev/guides/coordinate-system.md +46 -0
  82. package/dist-skill/docs-dev/guides/geometry-conventions.md +52 -0
  83. package/dist-skill/docs-dev/guides/joint-design.md +78 -0
  84. package/dist-skill/docs-dev/guides/modeling-recipes.md +77 -0
  85. package/dist-skill/docs-dev/guides/positioning.md +151 -0
  86. package/dist-skill/{docs → docs-dev}/guides/skill-maintenance.md +21 -10
  87. package/dist-skill/{docs → docs-dev}/internals/compiler.md +5 -6
  88. package/dist-skill/{docs → docs-dev}/internals/constraint-solver-quality.md +0 -1
  89. package/dist-skill/{docs → docs-dev}/internals/constraint-solver.md +0 -1
  90. package/dist-skill/{docs → docs-dev}/internals/sketch-2d-pipeline.md +2 -3
  91. package/examples/api/attachTo-basics.forge.js +8 -8
  92. package/examples/api/bill-of-materials.forge.js +9 -9
  93. package/examples/api/bolt-pattern.forge.js +5 -5
  94. package/examples/api/boolean-operations.forge.js +5 -5
  95. package/examples/api/bounding-box-visualizer.forge.js +3 -3
  96. package/examples/api/clone-duplicate.forge.js +2 -2
  97. package/examples/api/colors-union-vs-array.forge.js +6 -6
  98. package/examples/api/connector-assembly.forge.js +8 -6
  99. package/examples/api/connector-basics.forge.js +7 -7
  100. package/examples/api/constrained-sketch-mechanical.forge.js +4 -4
  101. package/examples/api/elbow-test.forge.js +3 -3
  102. package/examples/api/extrude-options.forge.js +8 -14
  103. package/examples/api/feature-created-faces.forge.js +6 -10
  104. package/examples/api/fillet-showcase.forge.js +2 -2
  105. package/examples/api/folded-service-panel-cover.forge.js +2 -2
  106. package/examples/api/gears-tier1.forge.js +5 -5
  107. package/examples/api/group-test.forge.js +3 -3
  108. package/examples/api/group-vs-union.forge.js +1 -1
  109. package/examples/api/highlight-debug.forge.js +4 -0
  110. package/examples/api/js-module-pillars.js +1 -1
  111. package/examples/api/js-module-scene.js +2 -2
  112. package/examples/api/mesh-import-slats.forge.js +4 -4
  113. package/examples/api/patterns.forge.js +3 -3
  114. package/examples/api/pointAlong-orientation.forge.js +3 -3
  115. package/examples/api/profile-2020-b-slot6.forge.js +4 -5
  116. package/examples/api/route-perimeter-flange.forge.js +1 -1
  117. package/examples/api/sdf-rover-demo.forge.js +10 -10
  118. package/examples/api/sketch-on-face-demo.forge.js +2 -2
  119. package/examples/api/sketch-regions.forge.js +4 -4
  120. package/examples/api/sketch-rounding-strategies.forge.js +1 -1
  121. package/examples/api/smooth-curve-connections.forge.js +1 -1
  122. package/examples/api/transition-curves.forge.js +4 -4
  123. package/examples/api/variable-sweep-pure-sdf-test.forge.js +162 -0
  124. package/examples/api/variable-sweep-test.forge.js +2 -2
  125. package/examples/api/wood-joinery.forge.js +60 -0
  126. package/examples/compiler-corpus/enclosure-shell-cuts.forge.js +3 -3
  127. package/examples/compiler-corpus/fastener-plate-variants.forge.js +2 -2
  128. package/examples/constraints/01-fully-constrained-rect.forge.js +2 -2
  129. package/examples/constraints/02-underconstrained-triangle.forge.js +1 -1
  130. package/examples/constraints/03-redundant-constraints.forge.js +2 -2
  131. package/examples/constraints/05-parallel-with-linedistance.forge.js +2 -2
  132. package/examples/constraints/06-complex-spectrogram.forge.js +1 -1
  133. package/examples/constraints/07-perpendicular-chain.forge.js +4 -4
  134. package/examples/constraints/08-symmetric-bracket.forge.js +4 -4
  135. package/examples/constraints/09-stress-spiral.forge.js +1 -1
  136. package/examples/constraints/10-stress-honeycomb.forge.js +1 -1
  137. package/examples/constraints/11-surface-grid.forge.js +2 -2
  138. package/examples/constraints/12-surface-nested.forge.js +4 -4
  139. package/examples/constraints/13-surface-complex.forge.js +1 -1
  140. package/examples/exact-arc-housing.forge.js +12 -0
  141. package/examples/experiments/drone-arm.forge.js +53 -0
  142. package/examples/furniture/adjustable-table.forge.js +15 -15
  143. package/examples/furniture/bathroom.forge.js +26 -26
  144. package/examples/furniture/chair.forge.js +13 -13
  145. package/examples/furniture/picture-frame.forge.js +6 -6
  146. package/examples/furniture/shoe-rack-doors.forge.js +8 -8
  147. package/examples/furniture/shoe-rack.forge.js +7 -7
  148. package/examples/furniture/table-lamp.forge.js +8 -8
  149. package/examples/gcode/lissajous-vase.forge.js +4 -4
  150. package/examples/gcode/math-surface.forge.js +3 -3
  151. package/examples/gcode/parametric-vase.forge.js +4 -4
  152. package/examples/gcode/spiral-tower.forge.js +4 -4
  153. package/examples/generative/crystal-growth.forge.js +9 -9
  154. package/examples/generative/frost-spires.forge.js +9 -9
  155. package/examples/generative/golden-spiral-tower.forge.js +11 -11
  156. package/examples/generative/molten-forge.forge.js +6 -6
  157. package/examples/generative/neon-coral.forge.js +7 -7
  158. package/examples/mechanical/3d-printer.forge.js +37 -37
  159. package/examples/mechanical/5-finger-robot-hand.forge.js +19 -19
  160. package/examples/mechanical/airplane-propeller.forge.js +9 -9
  161. package/examples/mechanical/bolt-and-nut.forge.js +10 -10
  162. package/examples/mechanical/door-with-hinges.forge.js +7 -7
  163. package/examples/mechanical/fillet-enclosure.forge.js +15 -11
  164. package/examples/mechanical/headphone-hanger-v2.forge.js +11 -11
  165. package/examples/mechanical/robot_hand.forge.js +24 -24
  166. package/examples/mechanical/robot_hand_2.forge.js +26 -26
  167. package/examples/nurbs-surface.forge.js +8 -0
  168. package/examples/nurbs-tube.forge.js +7 -0
  169. package/examples/products/bottle.forge.js +8 -8
  170. package/examples/products/chess-set.forge.js +25 -25
  171. package/examples/products/classical-piano.forge.js +20 -20
  172. package/examples/products/clock.forge.js +33 -33
  173. package/examples/products/cup.forge.js +5 -5
  174. package/examples/products/iphone.forge.js +20 -20
  175. package/examples/products/laptop.forge.js +24 -24
  176. package/examples/products/laser-cut-box.forge.js +6 -6
  177. package/examples/products/laser-cut-tray.forge.js +6 -6
  178. package/examples/products/liquid-soap-dispenser.forge.js +23 -23
  179. package/examples/products/origami-fish.forge.js +14 -12
  180. package/examples/products/spiderman-cake.forge.js +6 -6
  181. package/examples/shelf/container.forge.js +5 -5
  182. package/examples/shelf/shelf-unit.forge.js +6 -6
  183. package/examples/toolbox/bolted-joint.forge.js +7 -7
  184. package/package.json +9 -4
  185. package/dist/assets/EditorApp-B-vQvgam.js +0 -9888
  186. package/dist/assets/LandingPage-C5n9hDXI.js +0 -322
  187. package/dist/assets/PublishedModelPage-Dt7PCVBj.js +0 -146
  188. package/dist/assets/__vite-browser-external-CURh0WXD.js +0 -8
  189. package/dist/assets/deserializeRunResult-BLAFoiE0.js +0 -19365
  190. package/dist/assets/index-1CYp3zUp.js +0 -1455
  191. package/dist-skill/docs/API/API.md +0 -1666
  192. package/dist-skill/docs/API/README.md +0 -37
  193. package/dist-skill/docs/API/assembly/assembly.md +0 -617
  194. package/dist-skill/docs/API/core/edge-queries.md +0 -130
  195. package/dist-skill/docs/API/core/parameters.md +0 -122
  196. package/dist-skill/docs/API/core/reserved-terms.md +0 -137
  197. package/dist-skill/docs/API/core/sdf.md +0 -326
  198. package/dist-skill/docs/API/core/skill-cli.md +0 -194
  199. package/dist-skill/docs/API/core/skill-guide.md +0 -205
  200. package/dist-skill/docs/API/core/specs.md +0 -186
  201. package/dist-skill/docs/API/core/topology.md +0 -372
  202. package/dist-skill/docs/API/entities.md +0 -268
  203. package/dist-skill/docs/API/output/bom.md +0 -58
  204. package/dist-skill/docs/API/output/brep-export.md +0 -87
  205. package/dist-skill/docs/API/output/dimensions.md +0 -67
  206. package/dist-skill/docs/API/output/export.md +0 -110
  207. package/dist-skill/docs/API/output/gcode.md +0 -195
  208. package/dist-skill/docs/API/runtime/viewport.md +0 -420
  209. package/dist-skill/docs/API/sheet-metal/sheet-metal.md +0 -185
  210. package/dist-skill/docs/API/sketch/anchor.md +0 -37
  211. package/dist-skill/docs/API/sketch/booleans.md +0 -91
  212. package/dist-skill/docs/API/sketch/core.md +0 -73
  213. package/dist-skill/docs/API/sketch/extrude.md +0 -62
  214. package/dist-skill/docs/API/sketch/on-face.md +0 -104
  215. package/dist-skill/docs/API/sketch/operations.md +0 -78
  216. package/dist-skill/docs/API/sketch/path.md +0 -75
  217. package/dist-skill/docs/API/sketch/primitives.md +0 -146
  218. package/dist-skill/docs/API/sketch/regions.md +0 -80
  219. package/dist-skill/docs/API/sketch/text.md +0 -108
  220. package/dist-skill/docs/API/sketch/transforms.md +0 -65
  221. package/dist-skill/docs/API/toolbox/fasteners.md +0 -129
  222. package/dist-skill/docs/INDEX.md +0 -94
  223. package/dist-skill/docs/RELEASING.md +0 -55
  224. package/dist-skill/docs/cli-monetization.md +0 -111
  225. package/dist-skill/docs/deployment.md +0 -281
  226. package/dist-skill/docs/generated/concepts.md +0 -2112
  227. package/dist-skill/docs/internals/shape-from-slices.md +0 -152
  228. package/dist-skill/docs/platform/admin.md +0 -45
  229. package/dist-skill/docs/platform/architecture.md +0 -79
  230. package/dist-skill/docs/platform/auth.md +0 -110
  231. package/dist-skill/docs/platform/email.md +0 -67
  232. package/dist-skill/docs/platform/projects.md +0 -111
  233. package/dist-skill/docs/platform/sharing.md +0 -90
  234. package/dist-skill/docs/runbook.md +0 -345
@@ -2,8 +2,9 @@ var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  var _a;
5
- import { u as useParams, e as useNavigate, r as reactExports, j as jsxRuntimeExports, L as Link } from "./vendor-react-Dt7-aaJH.js";
6
- import { H as HighlightJS, j as javascript$1 } from "./javascript-DCxGoE5Y.js";
5
+ import { u as useParams, h as useNavigate, r as reactExports, j as jsxRuntimeExports, L as Link } from "./vendor-react-CG3i_wp0.js";
6
+ import { H as HighlightJS, j as javascript$1 } from "./javascript-DAl8Gmyo.js";
7
+ import { a as applyTheme } from "./index-Pz321YAt.js";
7
8
  function M() {
8
9
  return { async: false, breaks: false, extensions: null, gfm: true, hooks: null, pedantic: false, renderer: null, silent: false, tokenizer: null, walkTokens: null };
9
10
  }
@@ -3721,7 +3722,7 @@ function slugify(text) {
3721
3722
  return text.toLowerCase().replace(/`/g, "").replace(/<[^>]*>/g, "").replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").trim();
3722
3723
  }
3723
3724
  const renderer = new g.Renderer();
3724
- renderer.code = function({ text, lang }) {
3725
+ renderer.code = ({ text, lang }) => {
3725
3726
  let highlighted;
3726
3727
  if (lang && HighlightJS.getLanguage(lang)) {
3727
3728
  highlighted = HighlightJS.highlight(text, { language: lang }).value;
@@ -3730,38 +3731,42 @@ renderer.code = function({ text, lang }) {
3730
3731
  }
3731
3732
  return `<pre class="fc-docs-code"><code class="hljs language-${lang || ""}">${highlighted}</code></pre>`;
3732
3733
  };
3733
- renderer.heading = function({ text, depth }) {
3734
+ renderer.heading = ({ text, depth }) => {
3734
3735
  const id = slugify(text);
3735
- return `<h${depth} id="${id}">${text}<a class="fc-docs-anchor" href="#${id}" aria-label="Link to this section">#</a></h${depth}>
3736
+ const html = g.parseInline(text, { async: false });
3737
+ return `<h${depth} id="${id}">${html}<a class="fc-docs-anchor" href="#${id}" aria-label="Link to this section">#</a></h${depth}>
3736
3738
  `;
3737
3739
  };
3738
- renderer.table = function({ header, rows }) {
3740
+ renderer.table = ({
3741
+ header,
3742
+ rows
3743
+ }) => {
3744
+ const inline = (t) => g.parseInline(t, { async: false });
3739
3745
  let html = '<table class="fc-docs-table"><thead><tr>';
3740
3746
  for (const cell of header) {
3741
3747
  const align = cell.align ? ` style="text-align:${cell.align}"` : "";
3742
- html += `<th${align}>${cell.text}</th>`;
3748
+ html += `<th${align}>${inline(cell.text)}</th>`;
3743
3749
  }
3744
3750
  html += "</tr></thead><tbody>";
3745
3751
  for (const row of rows) {
3746
3752
  html += "<tr>";
3747
3753
  for (const cell of row) {
3748
3754
  const align = cell.align ? ` style="text-align:${cell.align}"` : "";
3749
- html += `<td${align}>${cell.text}</td>`;
3755
+ html += `<td${align}>${inline(cell.text)}</td>`;
3750
3756
  }
3751
3757
  html += "</tr>";
3752
3758
  }
3753
3759
  html += "</tbody></table>";
3754
3760
  return html;
3755
3761
  };
3756
- renderer.codespan = function({ text }) {
3757
- return `<code class="fc-docs-inline-code">${text}</code>`;
3758
- };
3759
- renderer.blockquote = function({ text }) {
3760
- return `<blockquote class="fc-docs-blockquote">${text}</blockquote>`;
3761
- };
3762
+ renderer.codespan = ({ text }) => `<code class="fc-docs-inline-code">${text}</code>`;
3763
+ renderer.blockquote = ({ text }) => `<blockquote class="fc-docs-blockquote">${text}</blockquote>`;
3762
3764
  g.use({ renderer, gfm: true, breaks: false });
3765
+ function stripFrontmatter(md) {
3766
+ return md.replace(/^---\n[\s\S]*?\n---\n/, "");
3767
+ }
3763
3768
  function renderToHtml(md) {
3764
- return g.parse(md, { async: false });
3769
+ return g.parse(stripFrontmatter(md), { async: false });
3765
3770
  }
3766
3771
  const DOC_SECTIONS = [
3767
3772
  { slug: "core", title: "Core", description: "Primitives, booleans, transforms, patterns" },
@@ -3772,11 +3777,10 @@ const DOC_SECTIONS = [
3772
3777
  { slug: "lib", title: "Library", description: "Gears, fasteners, pipes" },
3773
3778
  { slug: "sheet-metal", title: "Sheet Metal", description: "Bends, flat patterns" },
3774
3779
  { slug: "viewport", title: "Viewport", description: "Camera, animation, scenes" },
3780
+ { slug: "sdf", title: "SDF (Experimental)", description: "Organic forms, smooth booleans, TPMS" },
3775
3781
  { slug: "concepts", title: "Concepts", description: "Semantic data structures" }
3776
3782
  ];
3777
- const CLI_SECTIONS = [
3778
- { slug: "cli", title: "CLI Reference", description: "Command-line tools and options" }
3779
- ];
3783
+ const CLI_SECTIONS = [{ slug: "cli", title: "CLI", description: "Install, run, export, publish — from your terminal" }];
3780
3784
  const ALL_SECTIONS = [...DOC_SECTIONS, ...CLI_SECTIONS];
3781
3785
  function buildSearchEntries(slug, sectionTitle, md) {
3782
3786
  const entries = [];
@@ -3810,17 +3814,58 @@ function buildSearchEntries(slug, sectionTitle, md) {
3810
3814
  const sigMatch = line.match(/^(\w+)\(.*\):/);
3811
3815
  if (sigMatch && !sig) sig = line.trim();
3812
3816
  if (!line.startsWith("```") && line.trim()) {
3813
- buffer.push(line.replace(/[#*`\[\]]/g, "").trim());
3817
+ buffer.push(line.replace(/[#*`[\]]/g, "").trim());
3814
3818
  }
3815
3819
  }
3816
3820
  flush();
3817
3821
  return entries;
3818
3822
  }
3819
- function SiteNav({ onSearchOpen }) {
3823
+ function SidebarToggle({ side, open, onClick }) {
3824
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
3825
+ "button",
3826
+ {
3827
+ className: `fc-docs-sidebar-toggle ${side}`,
3828
+ onClick,
3829
+ type: "button",
3830
+ title: `${open ? "Hide" : "Show"} ${side === "left" ? "navigation" : "page outline"}`,
3831
+ children: side === "left" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3832
+ /* @__PURE__ */ jsxRuntimeExports.jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
3833
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M9 3v18" })
3834
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3835
+ /* @__PURE__ */ jsxRuntimeExports.jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
3836
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M15 3v18" })
3837
+ ] })
3838
+ }
3839
+ );
3840
+ }
3841
+ function ThemeToggle() {
3842
+ const [dark, setDark] = reactExports.useState(() => (localStorage.getItem("fc-theme") || "dark") !== "light");
3843
+ const toggle = reactExports.useCallback(() => {
3844
+ const next = dark ? "light" : "dark";
3845
+ applyTheme(next);
3846
+ localStorage.setItem("fc-theme", next);
3847
+ setDark(!dark);
3848
+ }, [dark]);
3849
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "fc-docs-theme-toggle", onClick: toggle, type: "button", title: dark ? "Switch to light mode" : "Switch to dark mode", children: dark ? /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3850
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "5" }),
3851
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" })
3852
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" }) }) });
3853
+ }
3854
+ function SiteNav({
3855
+ onSearchOpen,
3856
+ showSidebar,
3857
+ showToc,
3858
+ onToggleSidebar,
3859
+ onToggleToc,
3860
+ hasToc
3861
+ }) {
3820
3862
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("nav", { className: "fc-docs-nav", children: [
3821
- /* @__PURE__ */ jsxRuntimeExports.jsxs(Link, { to: "/", className: "fc-docs-nav-logo", children: [
3822
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontSize: 20 }, children: "⚒" }),
3823
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "ForgeCAD" })
3863
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-docs-nav-left", children: [
3864
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SidebarToggle, { side: "left", open: showSidebar, onClick: onToggleSidebar }),
3865
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Link, { to: "/", className: "fc-docs-nav-logo", children: [
3866
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontSize: 20 }, children: "⚒" }),
3867
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "ForgeCAD" })
3868
+ ] })
3824
3869
  ] }),
3825
3870
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-docs-nav-links", children: [
3826
3871
  /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: onSearchOpen, className: "fc-docs-search-trigger", type: "button", children: [
@@ -3833,46 +3878,55 @@ function SiteNav({ onSearchOpen }) {
3833
3878
  ] }),
3834
3879
  /* @__PURE__ */ jsxRuntimeExports.jsx(Link, { to: "/docs", className: "fc-docs-nav-active", children: "Docs" }),
3835
3880
  false,
3836
- /* @__PURE__ */ jsxRuntimeExports.jsx(Link, { to: "/", className: "fc-docs-nav-cta", children: "Back to Editor" })
3881
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Link, { to: "/", className: "fc-docs-nav-cta", children: "Back to Editor" }),
3882
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ThemeToggle, {}),
3883
+ hasToc && /* @__PURE__ */ jsxRuntimeExports.jsx(SidebarToggle, { side: "right", open: showToc, onClick: onToggleToc })
3837
3884
  ] })
3838
3885
  ] });
3839
3886
  }
3840
- function Sidebar({ activeSlug }) {
3887
+ function Sidebar({ activeSlug, open, onClose }) {
3841
3888
  const activeRef = reactExports.useRef(null);
3842
3889
  reactExports.useEffect(() => {
3843
3890
  var _a2;
3844
3891
  (_a2 = activeRef.current) == null ? void 0 : _a2.scrollIntoView({ block: "nearest" });
3845
3892
  }, [activeSlug]);
3846
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("aside", { className: "fc-docs-sidebar", children: [
3847
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fc-docs-sidebar-group-title", children: "API Reference" }),
3848
- DOC_SECTIONS.map((s) => /* @__PURE__ */ jsxRuntimeExports.jsx(
3849
- Link,
3850
- {
3851
- ref: activeSlug === s.slug ? activeRef : void 0,
3852
- to: `/docs/${s.slug}`,
3853
- className: `fc-docs-sidebar-link${activeSlug === s.slug ? " active" : ""}`,
3854
- children: s.title
3855
- },
3856
- s.slug
3857
- )),
3858
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fc-docs-sidebar-group-title", style: { marginTop: 16 }, children: "Tools" }),
3859
- CLI_SECTIONS.map((s) => /* @__PURE__ */ jsxRuntimeExports.jsx(
3860
- Link,
3893
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
3894
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
3895
+ "div",
3861
3896
  {
3862
- ref: activeSlug === s.slug ? activeRef : void 0,
3863
- to: `/docs/${s.slug}`,
3864
- className: `fc-docs-sidebar-link${activeSlug === s.slug ? " active" : ""}`,
3865
- children: s.title
3866
- },
3867
- s.slug
3868
- ))
3897
+ className: `fc-docs-sidebar-backdrop${open ? " open" : ""}`,
3898
+ onClick: onClose
3899
+ }
3900
+ ),
3901
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("aside", { className: `fc-docs-sidebar${open ? " open" : ""}`, children: [
3902
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fc-docs-sidebar-group-title", children: "API Reference" }),
3903
+ DOC_SECTIONS.map((s) => /* @__PURE__ */ jsxRuntimeExports.jsx(
3904
+ Link,
3905
+ {
3906
+ ref: activeSlug === s.slug ? activeRef : void 0,
3907
+ to: `/docs/${s.slug}`,
3908
+ className: `fc-docs-sidebar-link${activeSlug === s.slug ? " active" : ""}`,
3909
+ onClick: onClose,
3910
+ children: s.title
3911
+ },
3912
+ s.slug
3913
+ )),
3914
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fc-docs-sidebar-group-title", style: { marginTop: 16 }, children: "Tools" }),
3915
+ CLI_SECTIONS.map((s) => /* @__PURE__ */ jsxRuntimeExports.jsx(
3916
+ Link,
3917
+ {
3918
+ ref: activeSlug === s.slug ? activeRef : void 0,
3919
+ to: `/docs/${s.slug}`,
3920
+ className: `fc-docs-sidebar-link${activeSlug === s.slug ? " active" : ""}`,
3921
+ onClick: onClose,
3922
+ children: s.title
3923
+ },
3924
+ s.slug
3925
+ ))
3926
+ ] })
3869
3927
  ] });
3870
3928
  }
3871
- function SearchOverlay({
3872
- open,
3873
- onClose,
3874
- searchIndex
3875
- }) {
3929
+ function SearchOverlay({ open, onClose, searchIndex }) {
3876
3930
  const inputRef = reactExports.useRef(null);
3877
3931
  const [query, setQuery] = reactExports.useState("");
3878
3932
  const [selected, setSelected] = reactExports.useState(0);
@@ -3894,101 +3948,208 @@ function SearchOverlay({
3894
3948
  reactExports.useEffect(() => {
3895
3949
  setSelected(0);
3896
3950
  }, [query]);
3897
- const selectResult = reactExports.useCallback((idx) => {
3898
- const hit = results[idx];
3899
- if (!hit) return;
3900
- onClose();
3901
- const anchor = hit.item.anchor ? `#${hit.item.anchor}` : "";
3902
- navigate(`/docs/${hit.item.slug}${anchor}`);
3903
- }, [results, onClose, navigate]);
3904
- const onKeyDown = reactExports.useCallback((e) => {
3905
- if (e.key === "ArrowDown") {
3906
- e.preventDefault();
3907
- setSelected((s) => Math.min(s + 1, results.length - 1));
3908
- } else if (e.key === "ArrowUp") {
3909
- e.preventDefault();
3910
- setSelected((s) => Math.max(s - 1, 0));
3911
- } else if (e.key === "Enter") {
3912
- e.preventDefault();
3913
- selectResult(selected);
3914
- } else if (e.key === "Escape") {
3915
- e.preventDefault();
3951
+ const selectResult = reactExports.useCallback(
3952
+ (idx) => {
3953
+ const hit = results[idx];
3954
+ if (!hit) return;
3916
3955
  onClose();
3917
- }
3918
- }, [results.length, selected, selectResult, onClose]);
3956
+ const anchor = hit.item.anchor ? `#${hit.item.anchor}` : "";
3957
+ navigate(`/docs/${hit.item.slug}${anchor}`);
3958
+ },
3959
+ [results, onClose, navigate]
3960
+ );
3961
+ const onKeyDown = reactExports.useCallback(
3962
+ (e) => {
3963
+ if (e.key === "ArrowDown") {
3964
+ e.preventDefault();
3965
+ setSelected((s) => Math.min(s + 1, results.length - 1));
3966
+ } else if (e.key === "ArrowUp") {
3967
+ e.preventDefault();
3968
+ setSelected((s) => Math.max(s - 1, 0));
3969
+ } else if (e.key === "Enter") {
3970
+ e.preventDefault();
3971
+ selectResult(selected);
3972
+ } else if (e.key === "Escape") {
3973
+ e.preventDefault();
3974
+ onClose();
3975
+ }
3976
+ },
3977
+ [results.length, selected, selectResult, onClose]
3978
+ );
3919
3979
  if (!open) return null;
3920
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fc-docs-search-overlay", onClick: (e) => {
3921
- if (e.target === e.currentTarget) onClose();
3922
- }, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-docs-search-modal", children: [
3923
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-docs-search-input-wrap", children: [
3924
- /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", style: { color: "var(--fc-textDim)", flexShrink: 0 }, children: [
3925
- /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "11", cy: "11", r: "8" }),
3926
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m21 21-4.35-4.35" })
3927
- ] }),
3928
- /* @__PURE__ */ jsxRuntimeExports.jsx(
3929
- "input",
3930
- {
3931
- ref: inputRef,
3932
- type: "text",
3933
- placeholder: "Search docs...",
3934
- value: query,
3935
- onChange: (e) => setQuery(e.target.value),
3936
- onKeyDown,
3937
- autoComplete: "off",
3938
- spellCheck: false
3939
- }
3940
- ),
3941
- /* @__PURE__ */ jsxRuntimeExports.jsx("kbd", { children: "esc" })
3942
- ] }),
3943
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-docs-search-results", children: [
3944
- query.trim() && results.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-docs-search-empty", children: [
3945
- "No results for “",
3946
- query,
3947
- "”"
3948
- ] }),
3949
- results.map((hit, i) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
3950
- "div",
3980
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
3981
+ "div",
3982
+ {
3983
+ className: "fc-docs-search-overlay",
3984
+ onClick: (e) => {
3985
+ if (e.target === e.currentTarget) onClose();
3986
+ },
3987
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-docs-search-modal", children: [
3988
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-docs-search-input-wrap", children: [
3989
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
3990
+ "svg",
3991
+ {
3992
+ width: "18",
3993
+ height: "18",
3994
+ viewBox: "0 0 24 24",
3995
+ fill: "none",
3996
+ stroke: "currentColor",
3997
+ strokeWidth: "2",
3998
+ style: { color: "var(--fc-textDim)", flexShrink: 0 },
3999
+ children: [
4000
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "11", cy: "11", r: "8" }),
4001
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m21 21-4.35-4.35" })
4002
+ ]
4003
+ }
4004
+ ),
4005
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4006
+ "input",
4007
+ {
4008
+ ref: inputRef,
4009
+ type: "text",
4010
+ placeholder: "Search docs...",
4011
+ value: query,
4012
+ onChange: (e) => setQuery(e.target.value),
4013
+ onKeyDown,
4014
+ autoComplete: "off",
4015
+ spellCheck: false
4016
+ }
4017
+ ),
4018
+ /* @__PURE__ */ jsxRuntimeExports.jsx("kbd", { children: "esc" })
4019
+ ] }),
4020
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-docs-search-results", children: [
4021
+ query.trim() && results.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-docs-search-empty", children: [
4022
+ "No results for “",
4023
+ query,
4024
+ "”"
4025
+ ] }),
4026
+ results.map((hit, i) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
4027
+ "div",
4028
+ {
4029
+ className: `fc-docs-search-result${i === selected ? " selected" : ""}`,
4030
+ onClick: () => selectResult(i),
4031
+ onMouseEnter: () => setSelected(i),
4032
+ children: [
4033
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fc-docs-search-result-title", children: hit.item.title }),
4034
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fc-docs-search-result-category", children: hit.item.category }),
4035
+ hit.item.content && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fc-docs-search-result-snippet", children: hit.item.content.slice(0, 120) })
4036
+ ]
4037
+ },
4038
+ `${hit.item.slug}-${hit.item.anchor}-${i}`
4039
+ ))
4040
+ ] }),
4041
+ query.trim() && results.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-docs-search-footer", children: [
4042
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
4043
+ /* @__PURE__ */ jsxRuntimeExports.jsx("kbd", { children: "↑↓" }),
4044
+ " navigate"
4045
+ ] }),
4046
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
4047
+ /* @__PURE__ */ jsxRuntimeExports.jsx("kbd", { children: "↵" }),
4048
+ " open"
4049
+ ] }),
4050
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
4051
+ /* @__PURE__ */ jsxRuntimeExports.jsx("kbd", { children: "esc" }),
4052
+ " close"
4053
+ ] })
4054
+ ] })
4055
+ ] })
4056
+ }
4057
+ );
4058
+ }
4059
+ function extractTocEntries(container) {
4060
+ var _a2;
4061
+ const headings = Array.from(container.querySelectorAll("h2, h3"));
4062
+ const entries = [];
4063
+ for (const h of headings) {
4064
+ const id = h.id;
4065
+ if (!id) continue;
4066
+ const text = ((_a2 = h.textContent) == null ? void 0 : _a2.replace(/#$/, "").trim()) || "";
4067
+ if (!text) continue;
4068
+ entries.push({ id, text, depth: parseInt(h.tagName[1]) });
4069
+ }
4070
+ return entries;
4071
+ }
4072
+ function OnThisPage({ contentRef, html, open, onClose }) {
4073
+ const [entries, setEntries] = reactExports.useState([]);
4074
+ const [activeId, setActiveId] = reactExports.useState("");
4075
+ reactExports.useEffect(() => {
4076
+ if (!html || !contentRef.current) {
4077
+ setEntries([]);
4078
+ return;
4079
+ }
4080
+ const raf = requestAnimationFrame(() => {
4081
+ if (contentRef.current) setEntries(extractTocEntries(contentRef.current));
4082
+ });
4083
+ return () => cancelAnimationFrame(raf);
4084
+ }, [html]);
4085
+ reactExports.useEffect(() => {
4086
+ if (entries.length === 0 || !contentRef.current) return;
4087
+ const scrollContainer = contentRef.current.closest(".fc-docs-main");
4088
+ if (!scrollContainer) return;
4089
+ const handleScroll = () => {
4090
+ var _a2;
4091
+ const headings = Array.from(((_a2 = contentRef.current) == null ? void 0 : _a2.querySelectorAll("h2, h3")) ?? []);
4092
+ let current = "";
4093
+ for (const h of headings) {
4094
+ if (h.getBoundingClientRect().top <= 100) current = h.id;
4095
+ else break;
4096
+ }
4097
+ setActiveId(current);
4098
+ };
4099
+ scrollContainer.addEventListener("scroll", handleScroll, { passive: true });
4100
+ handleScroll();
4101
+ return () => scrollContainer.removeEventListener("scroll", handleScroll);
4102
+ }, [entries, contentRef]);
4103
+ if (entries.length === 0) return null;
4104
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4105
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4106
+ "div",
4107
+ {
4108
+ className: `fc-docs-toc-backdrop${open ? " open" : ""}`,
4109
+ onClick: onClose
4110
+ }
4111
+ ),
4112
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("aside", { className: `fc-docs-toc${open ? " open" : ""}`, children: [
4113
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fc-docs-toc-handle" }),
4114
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fc-docs-toc-title", children: "On this page" }),
4115
+ entries.map((e) => /* @__PURE__ */ jsxRuntimeExports.jsx(
4116
+ "a",
3951
4117
  {
3952
- className: `fc-docs-search-result${i === selected ? " selected" : ""}`,
3953
- onClick: () => selectResult(i),
3954
- onMouseEnter: () => setSelected(i),
3955
- children: [
3956
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fc-docs-search-result-title", children: hit.item.title }),
3957
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fc-docs-search-result-category", children: hit.item.category }),
3958
- hit.item.content && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fc-docs-search-result-snippet", children: hit.item.content.slice(0, 120) })
3959
- ]
4118
+ href: `#${e.id}`,
4119
+ className: `fc-docs-toc-link${e.depth === 3 ? " indent" : ""}${activeId === e.id ? " active" : ""}`,
4120
+ onClick: (ev) => {
4121
+ var _a2;
4122
+ ev.preventDefault();
4123
+ onClose();
4124
+ const target = (_a2 = contentRef.current) == null ? void 0 : _a2.querySelector(`#${CSS.escape(e.id)}`);
4125
+ if (target) {
4126
+ target.scrollIntoView({ behavior: "smooth", block: "start" });
4127
+ history.replaceState(null, "", `#${e.id}`);
4128
+ }
4129
+ },
4130
+ children: e.text
3960
4131
  },
3961
- `${hit.item.slug}-${hit.item.anchor}-${i}`
4132
+ e.id
3962
4133
  ))
3963
- ] }),
3964
- query.trim() && results.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-docs-search-footer", children: [
3965
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
3966
- /* @__PURE__ */ jsxRuntimeExports.jsx("kbd", { children: "↑↓" }),
3967
- " navigate"
3968
- ] }),
3969
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
3970
- /* @__PURE__ */ jsxRuntimeExports.jsx("kbd", { children: "↵" }),
3971
- " open"
3972
- ] }),
3973
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
3974
- /* @__PURE__ */ jsxRuntimeExports.jsx("kbd", { children: "esc" }),
3975
- " close"
3976
- ] })
3977
4134
  ] })
3978
- ] }) });
4135
+ ] });
3979
4136
  }
3980
- function DocContent({ slug }) {
4137
+ function DocContent({ slug, contentRef, onHtml }) {
3981
4138
  const [html, setHtml] = reactExports.useState(null);
3982
4139
  const [error, setError] = reactExports.useState(null);
3983
- const contentRef = reactExports.useRef(null);
3984
4140
  reactExports.useEffect(() => {
3985
4141
  setHtml(null);
3986
4142
  setError(null);
4143
+ onHtml(null);
3987
4144
  const filename = slug === "cli" ? "CLI.md" : `generated/${slug}.md`;
3988
4145
  fetch(`/docs-raw/${filename}`).then((r) => {
3989
4146
  if (!r.ok) throw new Error(`Not found: ${filename}`);
3990
4147
  return r.text();
3991
- }).then((md) => setHtml(renderToHtml(md))).catch((e) => setError(e.message));
4148
+ }).then((md) => {
4149
+ const h = renderToHtml(md);
4150
+ setHtml(h);
4151
+ onHtml(h);
4152
+ }).catch((e) => setError(e.message));
3992
4153
  }, [slug]);
3993
4154
  reactExports.useEffect(() => {
3994
4155
  if (!html || !contentRef.current) return;
@@ -4031,14 +4192,7 @@ function DocContent({ slug }) {
4031
4192
  if (html === null) {
4032
4193
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { padding: 40, color: "var(--fc-textDim)" }, children: "Loading..." });
4033
4194
  }
4034
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
4035
- "div",
4036
- {
4037
- ref: contentRef,
4038
- className: "fc-docs-content",
4039
- dangerouslySetInnerHTML: { __html: html }
4040
- }
4041
- );
4195
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: contentRef, className: "fc-docs-content", dangerouslySetInnerHTML: { __html: html } });
4042
4196
  }
4043
4197
  function DocsIndex() {
4044
4198
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-docs-index", children: [
@@ -4068,6 +4222,10 @@ function DocsPage() {
4068
4222
  const navigate = useNavigate();
4069
4223
  const [searchOpen, setSearchOpen] = reactExports.useState(false);
4070
4224
  const [searchIndex, setSearchIndex] = reactExports.useState(null);
4225
+ const contentRef = reactExports.useRef(null);
4226
+ const [docHtml, setDocHtml] = reactExports.useState(null);
4227
+ const [showSidebar, setShowSidebar] = reactExports.useState(() => window.innerWidth > 900);
4228
+ const [showToc, setShowToc] = reactExports.useState(() => window.innerWidth > 1200);
4071
4229
  const buildSearchIndex = reactExports.useCallback(async () => {
4072
4230
  if (searchIndex) return;
4073
4231
  const entries = [];
@@ -4076,25 +4234,27 @@ function DocsPage() {
4076
4234
  try {
4077
4235
  const r = await fetch(`/docs-raw/${filename}`);
4078
4236
  if (!r.ok) return;
4079
- const md = await r.text();
4237
+ const md = stripFrontmatter(await r.text());
4080
4238
  entries.push(...buildSearchEntries(section.slug, section.title, md));
4081
4239
  } catch {
4082
4240
  }
4083
4241
  });
4084
4242
  await Promise.all(fetches);
4085
- setSearchIndex(new Fuse(entries, {
4086
- keys: [
4087
- { name: "title", weight: 0.45 },
4088
- { name: "signature", weight: 0.25 },
4089
- { name: "category", weight: 0.15 },
4090
- { name: "content", weight: 0.15 }
4091
- ],
4092
- threshold: 0.35,
4093
- distance: 100,
4094
- includeMatches: true,
4095
- minMatchCharLength: 1,
4096
- ignoreLocation: true
4097
- }));
4243
+ setSearchIndex(
4244
+ new Fuse(entries, {
4245
+ keys: [
4246
+ { name: "title", weight: 0.45 },
4247
+ { name: "signature", weight: 0.25 },
4248
+ { name: "category", weight: 0.15 },
4249
+ { name: "content", weight: 0.15 }
4250
+ ],
4251
+ threshold: 0.35,
4252
+ distance: 100,
4253
+ includeMatches: true,
4254
+ minMatchCharLength: 1,
4255
+ ignoreLocation: true
4256
+ })
4257
+ );
4098
4258
  }, [searchIndex]);
4099
4259
  const openSearch = reactExports.useCallback(() => {
4100
4260
  setSearchOpen(true);
@@ -4121,20 +4281,26 @@ function DocsPage() {
4121
4281
  document.addEventListener("keydown", handler);
4122
4282
  return () => document.removeEventListener("keydown", handler);
4123
4283
  }, [slug, openSearch, navigate]);
4284
+ const closeSidebar = reactExports.useCallback(() => setShowSidebar(false), []);
4285
+ const closeToc = reactExports.useCallback(() => setShowToc(false), []);
4124
4286
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-docs-layout", children: [
4125
- /* @__PURE__ */ jsxRuntimeExports.jsx(SiteNav, { onSearchOpen: openSearch }),
4126
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-docs-body", children: [
4127
- /* @__PURE__ */ jsxRuntimeExports.jsx(Sidebar, { activeSlug: slug }),
4128
- /* @__PURE__ */ jsxRuntimeExports.jsx("main", { className: "fc-docs-main", children: slug ? /* @__PURE__ */ jsxRuntimeExports.jsx(DocContent, { slug }) : /* @__PURE__ */ jsxRuntimeExports.jsx(DocsIndex, {}) })
4129
- ] }),
4130
4287
  /* @__PURE__ */ jsxRuntimeExports.jsx(
4131
- SearchOverlay,
4288
+ SiteNav,
4132
4289
  {
4133
- open: searchOpen,
4134
- onClose: () => setSearchOpen(false),
4135
- searchIndex
4290
+ onSearchOpen: openSearch,
4291
+ showSidebar,
4292
+ showToc,
4293
+ onToggleSidebar: () => setShowSidebar((s) => !s),
4294
+ onToggleToc: () => setShowToc((s) => !s),
4295
+ hasToc: !!slug
4136
4296
  }
4137
- )
4297
+ ),
4298
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fc-docs-body", children: [
4299
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Sidebar, { activeSlug: slug, open: showSidebar, onClose: closeSidebar }),
4300
+ /* @__PURE__ */ jsxRuntimeExports.jsx("main", { className: "fc-docs-main", children: slug ? /* @__PURE__ */ jsxRuntimeExports.jsx(DocContent, { slug, contentRef, onHtml: setDocHtml }) : /* @__PURE__ */ jsxRuntimeExports.jsx(DocsIndex, {}) }),
4301
+ slug && /* @__PURE__ */ jsxRuntimeExports.jsx(OnThisPage, { contentRef, html: docHtml, open: showToc, onClose: closeToc })
4302
+ ] }),
4303
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SearchOverlay, { open: searchOpen, onClose: () => setSearchOpen(false), searchIndex })
4138
4304
  ] });
4139
4305
  }
4140
4306
  export {