@bendyline/squisq 1.5.2 → 2.0.1
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 +63 -10
- package/dist/{Doc-BBVGq1_9.d.ts → Doc-ylqWKDc_.d.ts} +248 -37
- package/dist/{ImageEditDoc-FuyGtt6o.d.ts → ImageEditDoc-D828IXJ1.d.ts} +1 -1
- package/dist/annotationCoercion-Dr_DY9Hx.d.ts +86 -0
- package/dist/{chunk-T5UK6YOB.js → chunk-2PWOO4ZE.js} +60 -17
- package/dist/chunk-2PWOO4ZE.js.map +1 -0
- package/dist/{chunk-VWUFZ6ZG.js → chunk-3E5F2XMR.js} +2 -29
- package/dist/chunk-3E5F2XMR.js.map +1 -0
- package/dist/chunk-4X3JQXNM.js +35 -0
- package/dist/chunk-4X3JQXNM.js.map +1 -0
- package/dist/{chunk-P3K7NLHF.js → chunk-5DKBFXPY.js} +31 -121
- package/dist/chunk-5DKBFXPY.js.map +1 -0
- package/dist/{chunk-DLXZMS5K.js → chunk-5J4HKRJF.js} +51 -3
- package/dist/chunk-5J4HKRJF.js.map +1 -0
- package/dist/chunk-5UYI3RJB.js +2503 -0
- package/dist/chunk-5UYI3RJB.js.map +1 -0
- package/dist/{chunk-BEQODJWV.js → chunk-66QO7XFB.js} +11 -291
- package/dist/chunk-66QO7XFB.js.map +1 -0
- package/dist/{chunk-HWVFJAAH.js → chunk-AMIR72JP.js} +28 -10
- package/dist/chunk-AMIR72JP.js.map +1 -0
- package/dist/chunk-CY2R2VPR.js +884 -0
- package/dist/chunk-CY2R2VPR.js.map +1 -0
- package/dist/chunk-FVJUUTEM.js +74 -0
- package/dist/chunk-FVJUUTEM.js.map +1 -0
- package/dist/{chunk-Q3ROPT5H.js → chunk-GZY66SDN.js} +1 -1
- package/dist/{chunk-Q3ROPT5H.js.map → chunk-GZY66SDN.js.map} +1 -1
- package/dist/chunk-JOQYPRDZ.js +127 -0
- package/dist/chunk-JOQYPRDZ.js.map +1 -0
- package/dist/{chunk-A4O7GIWE.js → chunk-MMPBOUK7.js} +10 -73
- package/dist/chunk-MMPBOUK7.js.map +1 -0
- package/dist/{chunk-LDQ2HJIX.js → chunk-PXLVXTLW.js} +252 -54
- package/dist/chunk-PXLVXTLW.js.map +1 -0
- package/dist/{chunk-TQWLI6S2.js → chunk-Q7LROV2H.js} +4 -2
- package/dist/{chunk-TQWLI6S2.js.map → chunk-Q7LROV2H.js.map} +1 -1
- package/dist/{chunk-GPLTCSXO.js → chunk-R2GC6RLD.js} +7 -7
- package/dist/chunk-R2GC6RLD.js.map +1 -0
- package/dist/chunk-R2YZTCLO.js +292 -0
- package/dist/chunk-R2YZTCLO.js.map +1 -0
- package/dist/chunk-S7A5D7ZJ.js +174 -0
- package/dist/chunk-S7A5D7ZJ.js.map +1 -0
- package/dist/chunk-TFJVXUHH.js +2358 -0
- package/dist/chunk-TFJVXUHH.js.map +1 -0
- package/dist/{chunk-LTN6I7QW.js → chunk-TUWMK62B.js} +55 -4
- package/dist/chunk-TUWMK62B.js.map +1 -0
- package/dist/{chunk-IMSCRLLV.js → chunk-VR7UPJ7C.js} +35 -25
- package/dist/chunk-VR7UPJ7C.js.map +1 -0
- package/dist/{chunk-KKNUBQ6Y.js → chunk-W4O2TX5I.js} +157 -92
- package/dist/chunk-W4O2TX5I.js.map +1 -0
- package/dist/{chunk-5TYS5V3G.js → chunk-X6DUONGT.js} +4204 -3560
- package/dist/chunk-X6DUONGT.js.map +1 -0
- package/dist/doc/index.d.ts +2334 -5
- package/dist/doc/index.js +127 -33
- package/dist/generate/index.d.ts +7 -2
- package/dist/generate/index.js +1 -1
- package/dist/imageEdit/index.d.ts +9 -6
- package/dist/imageEdit/index.js +3 -3
- package/dist/index.d.ts +12 -10
- package/dist/index.js +246 -80
- package/dist/jsonForm/index.d.ts +7 -3
- package/dist/jsonForm/index.js +9 -4
- package/dist/markdown/index.d.ts +6 -70
- package/dist/markdown/index.js +13 -9
- package/dist/narration/index.d.ts +618 -0
- package/dist/narration/index.js +82 -0
- package/dist/recommend/index.d.ts +15 -1
- package/dist/recommend/index.js +2 -2
- package/dist/schemas/index.d.ts +28 -6
- package/dist/schemas/index.js +15 -13
- package/dist/spatial/index.d.ts +0 -1
- package/dist/spatial/index.js +1 -1
- package/dist/storage/index.js +1 -1
- package/dist/{themeLibrary-CehcJhzz.d.ts → themeLibrary-RjVgLpUi.d.ts} +10 -11
- package/dist/timing/index.js +5 -3
- package/dist/transform/index.d.ts +35 -24
- package/dist/transform/index.js +9 -10
- package/dist/{types-DlAZ7MW4.d.ts → types-BwMPl2CB.d.ts} +1 -1
- package/dist/{types-D98li1gV.d.ts → types-C4kiRn_k.d.ts} +3 -1
- package/dist/versions/index.d.ts +2 -1
- package/dist/versions/index.js +2 -2
- package/package.json +6 -6
- package/src/__tests__/applyNarrationTiming.test.ts +190 -0
- package/src/__tests__/applyRenderStyle.test.ts +3 -3
- package/src/__tests__/asciiDiagramBattle.test.ts +246 -0
- package/src/__tests__/asciiDiagramDetect.test.ts +162 -0
- package/src/__tests__/asciiDiagramMapping.test.ts +38 -0
- package/src/__tests__/asciiDiagramParse.test.ts +233 -0
- package/src/__tests__/asciiDiagramPipeline.test.ts +273 -0
- package/src/__tests__/asciiDiagramRender.test.ts +162 -0
- package/src/__tests__/asciiDiagramRepair.test.ts +84 -0
- package/src/__tests__/asciiTimelineDetect.test.ts +157 -0
- package/src/__tests__/asciiTimelineParse.test.ts +205 -0
- package/src/__tests__/asciiTimelinePipeline.test.ts +349 -0
- package/src/__tests__/asciiTimelineRender.test.ts +376 -0
- package/src/__tests__/attrTokens.test.ts +5 -0
- package/src/__tests__/contentContainer.test.ts +43 -0
- package/src/__tests__/customTemplatesFrontmatter.test.ts +0 -15
- package/src/__tests__/customThemesFrontmatter.test.ts +1 -0
- package/src/__tests__/dataTable.test.ts +25 -15
- package/src/__tests__/diagramBlock.test.ts +3 -3
- package/src/__tests__/diagramText.test.ts +26 -0
- package/src/__tests__/docToMarkdownMedia.test.ts +83 -0
- package/src/__tests__/drawingBlock.test.ts +3 -3
- package/src/__tests__/fixtures/asciiDiagramBattle.ts +512 -0
- package/src/__tests__/fixtures/asciiDiagrams.ts +287 -0
- package/src/__tests__/fixtures/asciiTimelines.ts +35 -0
- package/src/__tests__/fixtures/treeviewFixtures.ts +243 -0
- package/src/__tests__/getLayers.test.ts +32 -18
- package/src/__tests__/getLayersFallback.test.ts +8 -8
- package/src/__tests__/imageEditVersions.test.ts +2 -0
- package/src/__tests__/jsonForm.pointer.test.ts +47 -1
- package/src/__tests__/layoutBlock.test.ts +3 -3
- package/src/__tests__/majorApiTypes.test.ts +18 -0
- package/src/__tests__/markdown.test.ts +54 -4
- package/src/__tests__/markdownSanitize.test.ts +7 -5
- package/src/__tests__/matchFontFamily.test.ts +114 -0
- package/src/__tests__/materializeBlockLayers.test.ts +135 -0
- package/src/__tests__/materializeTestUtils.ts +17 -0
- package/src/__tests__/narrationAlign.test.ts +150 -0
- package/src/__tests__/narrationFeatures.test.ts +71 -0
- package/src/__tests__/narrationNuclei.test.ts +45 -0
- package/src/__tests__/narrationPacing.test.ts +189 -0
- package/src/__tests__/narrationScript.test.ts +149 -0
- package/src/__tests__/narrationSessionRepro.test.ts +62 -0
- package/src/__tests__/narrationSidecar.test.ts +88 -0
- package/src/__tests__/narrationSyllables.test.ts +65 -0
- package/src/__tests__/narrationTestSignals.ts +167 -0
- package/src/__tests__/narrationVad.test.ts +66 -0
- package/src/__tests__/resolveDocTheme.test.ts +16 -2
- package/src/__tests__/rootExports.test.ts +18 -0
- package/src/__tests__/scopedContentContainer.test.ts +20 -0
- package/src/__tests__/shapeGeometry.test.ts +12 -0
- package/src/__tests__/templateAnnotationParse.test.ts +10 -0
- package/src/__tests__/templateInputs.test.ts +69 -0
- package/src/__tests__/templateMetadata.test.ts +2 -1
- package/src/__tests__/templates.test.ts +143 -17
- package/src/__tests__/themeCompile.test.ts +49 -22
- package/src/__tests__/transformProvenance.test.ts +160 -0
- package/src/__tests__/transformV2.test.ts +40 -14
- package/src/__tests__/treeviewBattle.test.ts +76 -0
- package/src/__tests__/treeviewDetect.test.ts +168 -0
- package/src/__tests__/treeviewParse.test.ts +118 -0
- package/src/__tests__/treeviewPipeline.test.ts +183 -0
- package/src/__tests__/treeviewRender.test.ts +91 -0
- package/src/__tests__/versions.test.ts +44 -0
- package/src/doc/applyNarrationTiming.ts +244 -0
- package/src/doc/asciiDiagram/chars.ts +210 -0
- package/src/doc/asciiDiagram/detect.ts +175 -0
- package/src/doc/asciiDiagram/index.ts +38 -0
- package/src/doc/asciiDiagram/mapping.ts +225 -0
- package/src/doc/asciiDiagram/parse.ts +1095 -0
- package/src/doc/asciiDiagram/render.ts +963 -0
- package/src/doc/asciiDiagram/repair.ts +400 -0
- package/src/doc/asciiDiagram/types.ts +65 -0
- package/src/doc/asciiTimeline/detect.ts +138 -0
- package/src/doc/asciiTimeline/index.ts +26 -0
- package/src/doc/asciiTimeline/mapping.ts +43 -0
- package/src/doc/asciiTimeline/parse.ts +870 -0
- package/src/doc/asciiTimeline/render.ts +427 -0
- package/src/doc/asciiTimeline/types.ts +73 -0
- package/src/doc/asciiTimeline/wrappedFlow.ts +427 -0
- package/src/doc/audioMapping.ts +60 -46
- package/src/doc/customTemplatesFrontmatter.ts +0 -41
- package/src/doc/docToMarkdown.ts +70 -2
- package/src/doc/index.ts +76 -4
- package/src/doc/markdownToDoc.ts +138 -2
- package/src/doc/materializeBlockLayers.ts +304 -0
- package/src/doc/mediaAnnotations.ts +20 -0
- package/src/doc/resolveDocTheme.ts +8 -7
- package/src/doc/templateInputs.ts +185 -2
- package/src/doc/templates/__tests__/customTemplateRegistry.test.ts +22 -8
- package/src/doc/templates/__tests__/listBlock.test.ts +64 -0
- package/src/doc/templates/diagramBlock.ts +237 -38
- package/src/doc/templates/fallbackBlock.ts +1 -1
- package/src/doc/templates/index.ts +134 -279
- package/src/doc/templates/inputDescriptors.ts +20 -1
- package/src/doc/templates/listBlock.ts +88 -30
- package/src/doc/templates/metadata.ts +10 -0
- package/src/doc/templates/persistentLayers.ts +12 -126
- package/src/doc/templates/registry.ts +88 -0
- package/src/doc/templates/templateNames.ts +22 -0
- package/src/doc/templates/timelineBlock.ts +613 -0
- package/src/doc/templates/treeBlock.ts +131 -0
- package/src/doc/treeview/chars.ts +72 -0
- package/src/doc/treeview/detect.ts +145 -0
- package/src/doc/treeview/index.ts +30 -0
- package/src/doc/treeview/mapping.ts +95 -0
- package/src/doc/treeview/parse.ts +201 -0
- package/src/doc/treeview/render.ts +41 -0
- package/src/doc/treeview/types.ts +43 -0
- package/src/doc/utils/applyRenderStyle.ts +2 -9
- package/src/doc/utils/diagramText.ts +78 -0
- package/src/doc/utils/shapeGeometry.ts +67 -5
- package/src/doc/validate.ts +1 -1
- package/src/generate/templateMapper.ts +7 -0
- package/src/imageEdit/export.ts +6 -5
- package/src/imageEdit/versionPaths.ts +13 -26
- package/src/imageEdit/versions.ts +21 -100
- package/src/index.ts +1 -0
- package/src/internal/immutable.ts +58 -0
- package/src/jsonForm/index.ts +9 -1
- package/src/jsonForm/pointer.ts +68 -23
- package/src/markdown/attrTokens.ts +7 -5
- package/src/markdown/index.ts +1 -0
- package/src/markdown/stringify.ts +4 -9
- package/src/markdown/utils.ts +36 -14
- package/src/narration/align.ts +514 -0
- package/src/narration/features.ts +231 -0
- package/src/narration/index.ts +86 -0
- package/src/narration/nuclei.ts +118 -0
- package/src/narration/pacing.ts +211 -0
- package/src/narration/script.ts +239 -0
- package/src/narration/session.ts +100 -0
- package/src/narration/sidecar.ts +187 -0
- package/src/narration/syllables.ts +85 -0
- package/src/narration/trace.ts +50 -0
- package/src/narration/types.ts +299 -0
- package/src/narration/vad.ts +131 -0
- package/src/recommend/numberHighlight.ts +25 -0
- package/src/recommend/templates.ts +108 -12
- package/src/schemas/BlockTemplates.ts +156 -7
- package/src/schemas/Doc.ts +72 -9
- package/src/schemas/Media.ts +12 -2
- package/src/schemas/Theme.ts +45 -25
- package/src/schemas/Viewport.ts +2 -2
- package/src/schemas/fontStacks.ts +79 -0
- package/src/schemas/themeCompile.ts +15 -0
- package/src/schemas/themeConstants.ts +2 -0
- package/src/schemas/themeLibrary.ts +25 -19
- package/src/schemas/themeValidator.ts +1 -1
- package/src/schemas/themes/gezellig.json +1 -1
- package/src/spatial/Geohash.ts +0 -3
- package/src/storage/ContentContainer.ts +17 -9
- package/src/storage/ScopedContentContainer.ts +45 -15
- package/src/transform/applyTransform.ts +5 -5
- package/src/transform/index.ts +3 -1
- package/src/transform/registry.ts +169 -49
- package/src/transform/templateSelector.ts +21 -2
- package/src/transform/timingAllocator.ts +152 -21
- package/src/transform/types.ts +14 -1
- package/src/versions/gitignore.ts +34 -0
- package/src/versions/index.ts +2 -0
- package/src/versions/operations.ts +18 -104
- package/src/versions/paths.ts +13 -28
- package/src/versions/snapshotStore.ts +202 -0
- package/src/versions/types.ts +3 -1
- package/dist/chunk-5TYS5V3G.js.map +0 -1
- package/dist/chunk-A4O7GIWE.js.map +0 -1
- package/dist/chunk-BEQODJWV.js.map +0 -1
- package/dist/chunk-DLXZMS5K.js.map +0 -1
- package/dist/chunk-GPLTCSXO.js.map +0 -1
- package/dist/chunk-HWVFJAAH.js.map +0 -1
- package/dist/chunk-IMSCRLLV.js.map +0 -1
- package/dist/chunk-JELIRVDP.js +0 -24
- package/dist/chunk-JELIRVDP.js.map +0 -1
- package/dist/chunk-KKNUBQ6Y.js.map +0 -1
- package/dist/chunk-LDQ2HJIX.js.map +0 -1
- package/dist/chunk-LTN6I7QW.js.map +0 -1
- package/dist/chunk-P3K7NLHF.js.map +0 -1
- package/dist/chunk-T5UK6YOB.js.map +0 -1
- package/dist/chunk-UY7KGQ5R.js +0 -192
- package/dist/chunk-UY7KGQ5R.js.map +0 -1
- package/dist/chunk-VLJJHDAC.js +0 -218
- package/dist/chunk-VLJJHDAC.js.map +0 -1
- package/dist/chunk-VWUFZ6ZG.js.map +0 -1
- package/dist/story/index.d.ts +0 -1801
- package/dist/story/index.js +0 -279
- package/src/doc/getLayers.ts +0 -195
- /package/dist/{story → narration}/index.js.map +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/doc/utils/shapeGeometry.ts"],"sourcesContent":["/**\n * shapeGeometry — pure SVG geometry for the drawing/diagram shape vocabulary.\n *\n * Three concerns, all deterministic and dependency-free:\n * - `shapePath(kind, x, y, w, h)` → an SVG path `d` for a named shape inscribed\n * in a bounding box. Returns null for the natively-rendered primitives\n * (rect / circle / line / text / path) so the caller can keep using a\n * `ShapeLayer` for those; everything else becomes a computed `PathLayer`.\n * - `markerPath(style, dir)` → the `<marker>` path for a line end-style, in the\n * standard 0–10 marker viewBox (shared by the SSR `PathLayer` renderer and the\n * editor's edge renderer).\n * - `connectorPath(routing, start, end)` + `snapEndpoints(a, b)` → the line/edge\n * geometry between two shapes (straight / orthogonal / curved), lifted from the\n * diagram template so drawings and diagrams draw identical connectors. The older\n * `clipEndpoints(a, b)` helper remains for free-angle clipping, but rendered\n * connectors use snapped ports so authored lines land on stable attachment points.\n */\n\nimport type { MarkerStyle } from '../../schemas/Doc.js';\n\n// ============================================\n// Shapes\n// ============================================\n\n/** Connector routing styles. */\nexport type ConnectorRouting = 'straight' | 'orthogonal' | 'curved';\n\n/**\n * Shape kinds rendered as computed paths (everything except the primitives the\n * renderer draws natively). Used by templates to decide ShapeLayer vs PathLayer.\n */\nexport const PATH_SHAPE_KINDS = new Set([\n 'triangle',\n 'right-triangle',\n 'diamond',\n 'pentagon',\n 'hexagon',\n 'octagon',\n 'star',\n 'star4',\n 'star6',\n 'parallelogram',\n 'trapezoid',\n 'plus',\n 'chevron',\n 'arrow-right',\n 'arrow-left',\n 'arrow-up',\n 'arrow-down',\n 'double-arrow',\n 'callout',\n 'cylinder',\n 'cloud',\n 'heart',\n 'lightning',\n]);\n\n/** Round to 1 decimal for compact, stable path output. */\nfunction r(n: number): number {\n return Math.round(n * 10) / 10;\n}\n\n/** Close a list of points into an `M … L … Z` polygon path. */\nfunction poly(points: ReadonlyArray<readonly [number, number]>): string {\n if (points.length === 0) return '';\n const [first, ...rest] = points;\n const head = `M ${r(first[0])} ${r(first[1])}`;\n const tail = rest.map(([x, y]) => `L ${r(x)} ${r(y)}`).join(' ');\n return `${head} ${tail} Z`;\n}\n\n/** Regular polygon points inscribed in the box ellipse, `rotation` in radians. */\nfunction regular(\n cx: number,\n cy: number,\n rx: number,\n ry: number,\n sides: number,\n rotation: number,\n): Array<[number, number]> {\n const pts: Array<[number, number]> = [];\n for (let i = 0; i < sides; i++) {\n const a = rotation + (i * 2 * Math.PI) / sides;\n pts.push([cx + rx * Math.cos(a), cy + ry * Math.sin(a)]);\n }\n return pts;\n}\n\n/** Star points alternating outer/inner radius. */\nfunction star(\n cx: number,\n cy: number,\n rx: number,\n ry: number,\n spikes: number,\n innerRatio: number,\n): Array<[number, number]> {\n const pts: Array<[number, number]> = [];\n const rot = -Math.PI / 2; // first point up\n for (let i = 0; i < spikes * 2; i++) {\n const outer = i % 2 === 0;\n const a = rot + (i * Math.PI) / spikes;\n const fx = outer ? rx : rx * innerRatio;\n const fy = outer ? ry : ry * innerRatio;\n pts.push([cx + fx * Math.cos(a), cy + fy * Math.sin(a)]);\n }\n return pts;\n}\n\n/**\n * SVG path `d` for a named shape inscribed in `[x, y, w, h]`, or null when the\n * kind is rendered natively (rect / circle / line / text / path / arrow).\n */\nexport function shapePath(kind: string, x: number, y: number, w: number, h: number): string | null {\n const cx = x + w / 2;\n const cy = y + h / 2;\n const rx = w / 2;\n const ry = h / 2;\n const right = x + w;\n const bottom = y + h;\n\n switch (kind) {\n case 'triangle':\n return poly([\n [cx, y],\n [right, bottom],\n [x, bottom],\n ]);\n case 'right-triangle':\n return poly([\n [x, y],\n [x, bottom],\n [right, bottom],\n ]);\n case 'diamond':\n return poly([\n [cx, y],\n [right, cy],\n [cx, bottom],\n [x, cy],\n ]);\n case 'pentagon':\n return poly(regular(cx, cy, rx, ry, 5, -Math.PI / 2));\n case 'hexagon': {\n // Flat top/bottom hexagon: inset the left/right vertices.\n const inset = w * 0.25;\n return poly([\n [x + inset, y],\n [right - inset, y],\n [right, cy],\n [right - inset, bottom],\n [x + inset, bottom],\n [x, cy],\n ]);\n }\n case 'octagon': {\n const cut = Math.min(w, h) * 0.29;\n return poly([\n [x + cut, y],\n [right - cut, y],\n [right, y + cut],\n [right, bottom - cut],\n [right - cut, bottom],\n [x + cut, bottom],\n [x, bottom - cut],\n [x, y + cut],\n ]);\n }\n case 'star':\n return poly(star(cx, cy, rx, ry, 5, 0.4));\n case 'star4':\n return poly(star(cx, cy, rx, ry, 4, 0.4));\n case 'star6':\n return poly(star(cx, cy, rx, ry, 6, 0.5));\n case 'parallelogram': {\n const off = w * 0.25;\n return poly([\n [x + off, y],\n [right, y],\n [right - off, bottom],\n [x, bottom],\n ]);\n }\n case 'trapezoid': {\n const off = w * 0.25;\n return poly([\n [x + off, y],\n [right - off, y],\n [right, bottom],\n [x, bottom],\n ]);\n }\n case 'plus': {\n const t = Math.min(w, h) / 3; // arm thickness\n const lx = x + (w - t) / 2;\n const rxp = lx + t;\n const ty = y + (h - t) / 2;\n const byp = ty + t;\n return poly([\n [lx, y],\n [rxp, y],\n [rxp, ty],\n [right, ty],\n [right, byp],\n [rxp, byp],\n [rxp, bottom],\n [lx, bottom],\n [lx, byp],\n [x, byp],\n [x, ty],\n [lx, ty],\n ]);\n }\n case 'chevron': {\n const notch = w * 0.25;\n return poly([\n [x, y],\n [right - notch, y],\n [right, cy],\n [right - notch, bottom],\n [x, bottom],\n [x + notch, cy],\n ]);\n }\n case 'arrow-right':\n return blockArrow(x, y, w, h, 'right');\n case 'arrow-left':\n return blockArrow(x, y, w, h, 'left');\n case 'arrow-up':\n return blockArrow(x, y, w, h, 'up');\n case 'arrow-down':\n return blockArrow(x, y, w, h, 'down');\n case 'double-arrow': {\n const head = w * 0.3;\n const bodyT = h * 0.4;\n const ty = cy - bodyT / 2;\n const by = cy + bodyT / 2;\n return poly([\n [x, cy],\n [x + head, y],\n [x + head, ty],\n [right - head, ty],\n [right - head, y],\n [right, cy],\n [right - head, bottom],\n [right - head, by],\n [x + head, by],\n [x + head, bottom],\n ]);\n }\n case 'callout': {\n // Speech bubble: rounded-ish body (square corners for path simplicity)\n // with a tail off the lower-left.\n const bodyH = h * 0.78;\n const bb = y + bodyH;\n const tailX = x + w * 0.25;\n return `M ${r(x)} ${r(y)} L ${r(right)} ${r(y)} L ${r(right)} ${r(bb)} L ${r(tailX + w * 0.12)} ${r(bb)} L ${r(tailX)} ${r(bottom)} L ${r(tailX - w * 0.02)} ${r(bb)} L ${r(x)} ${r(bb)} Z`;\n }\n case 'cylinder': {\n const ell = h * 0.16; // ellipse half-height\n return (\n `M ${r(x)} ${r(y + ell)} ` +\n `A ${r(rx)} ${r(ell)} 0 0 1 ${r(right)} ${r(y + ell)} ` +\n `L ${r(right)} ${r(bottom - ell)} ` +\n `A ${r(rx)} ${r(ell)} 0 0 1 ${r(x)} ${r(bottom - ell)} ` +\n `Z ` +\n // top ellipse outline\n `M ${r(x)} ${r(y + ell)} ` +\n `A ${r(rx)} ${r(ell)} 0 0 0 ${r(right)} ${r(y + ell)}`\n );\n }\n case 'cloud': {\n // Four bumps along the top + a flat-ish bottom, via arcs.\n const b = h * 0.5;\n return (\n `M ${r(x + w * 0.2)} ${r(bottom)} ` +\n `A ${r(w * 0.2)} ${r(b)} 0 0 1 ${r(x + w * 0.15)} ${r(cy)} ` +\n `A ${r(w * 0.2)} ${r(b)} 0 0 1 ${r(x + w * 0.45)} ${r(y + h * 0.2)} ` +\n `A ${r(w * 0.2)} ${r(b)} 0 0 1 ${r(x + w * 0.8)} ${r(y + h * 0.25)} ` +\n `A ${r(w * 0.18)} ${r(b)} 0 0 1 ${r(x + w * 0.85)} ${r(bottom)} ` +\n `Z`\n );\n }\n case 'heart': {\n const topY = y + h * 0.3;\n return (\n `M ${r(cx)} ${r(bottom)} ` +\n `C ${r(x - w * 0.1)} ${r(cy)} ${r(x)} ${r(y)} ${r(cx)} ${r(topY)} ` +\n `C ${r(right)} ${r(y)} ${r(right + w * 0.1)} ${r(cy)} ${r(cx)} ${r(bottom)} ` +\n `Z`\n );\n }\n case 'lightning':\n return poly([\n [x + w * 0.55, y],\n [x + w * 0.2, y + h * 0.55],\n [x + w * 0.45, y + h * 0.55],\n [x + w * 0.3, bottom],\n [right, y + h * 0.4],\n [x + w * 0.55, y + h * 0.4],\n ]);\n default:\n return null;\n }\n}\n\n/** Block arrow (body rectangle + triangular head) pointing in `dir`. */\nfunction blockArrow(\n x: number,\n y: number,\n w: number,\n h: number,\n dir: 'right' | 'left' | 'up' | 'down',\n): string {\n const right = x + w;\n const bottom = y + h;\n const cx = x + w / 2;\n const cy = y + h / 2;\n if (dir === 'right' || dir === 'left') {\n const head = w * 0.4;\n const bodyT = h * 0.5;\n const ty = cy - bodyT / 2;\n const by = cy + bodyT / 2;\n if (dir === 'right') {\n return poly([\n [x, ty],\n [right - head, ty],\n [right - head, y],\n [right, cy],\n [right - head, bottom],\n [right - head, by],\n [x, by],\n ]);\n }\n return poly([\n [right, ty],\n [x + head, ty],\n [x + head, y],\n [x, cy],\n [x + head, bottom],\n [x + head, by],\n [right, by],\n ]);\n }\n const head = h * 0.4;\n const bodyT = w * 0.5;\n const lx = cx - bodyT / 2;\n const rxp = cx + bodyT / 2;\n if (dir === 'down') {\n return poly([\n [lx, y],\n [rxp, y],\n [rxp, bottom - head],\n [right, bottom - head],\n [cx, bottom],\n [x, bottom - head],\n [lx, bottom - head],\n ]);\n }\n return poly([\n [lx, bottom],\n [rxp, bottom],\n [rxp, y + head],\n [right, y + head],\n [cx, y],\n [x, y + head],\n [lx, y + head],\n ]);\n}\n\n// ============================================\n// End markers\n// ============================================\n\n/**\n * The `<marker>` path for a line end-style, in the 0–10 marker viewBox.\n * `dir` selects orientation (`end` points along +x; `start` is mirrored).\n * Returns null for `'none'`. `filled` shapes paint with the stroke color;\n * non-filled (`open`) draw as a stroked outline.\n */\nexport function markerPath(\n style: MarkerStyle,\n dir: 'start' | 'end',\n): { d: string; filled: boolean } | null {\n const mirror = dir === 'start';\n const mx = (n: number) => (mirror ? 10 - n : n);\n const tri = (closed: boolean) => `M ${mx(0)} 0 L ${mx(10)} 5 L ${mx(0)} 10${closed ? ' z' : ''}`;\n switch (style) {\n case 'arrow':\n return { d: tri(true), filled: true };\n case 'open':\n return { d: tri(false), filled: false };\n case 'diamond':\n return { d: 'M 0 5 L 5 0 L 10 5 L 5 10 z', filled: true };\n case 'square':\n return { d: 'M 1 1 L 9 1 L 9 9 L 1 9 z', filled: true };\n case 'circle':\n return { d: 'M 0 5 A 5 5 0 1 0 10 5 A 5 5 0 1 0 0 5 z', filled: true };\n case 'none':\n default:\n return null;\n }\n}\n\n// ============================================\n// Connector routing\n// ============================================\n\nexport interface ClipBox {\n cx: number;\n cy: number;\n rx: number;\n ry: number;\n}\n\nexport type ConnectorPort =\n | 'top'\n | 'right'\n | 'bottom'\n | 'left'\n | 'top-left'\n | 'top-right'\n | 'bottom-right'\n | 'bottom-left';\n\nexport interface ConnectorSnapPoint {\n port: ConnectorPort;\n x: number;\n y: number;\n}\n\nexport interface ConnectorAnchor {\n side: 'top' | 'right' | 'bottom' | 'left';\n offset: number;\n}\n\n/** Intersection of the center-to-center line with `from`'s bounding box. */\nexport function clipPoint(from: ClipBox, to: ClipBox): { x: number; y: number } {\n const dx = to.cx - from.cx;\n const dy = to.cy - from.cy;\n if (dx === 0 && dy === 0) return { x: from.cx, y: from.cy };\n const sx = Math.abs(dx) > 0 ? from.rx / Math.abs(dx) : Infinity;\n const sy = Math.abs(dy) > 0 ? from.ry / Math.abs(dy) : Infinity;\n const s = Math.min(sx, sy);\n return { x: from.cx + dx * s, y: from.cy + dy * s };\n}\n\n/** Clip both endpoints of an edge to the two shapes it joins. */\nexport function clipEndpoints(\n a: ClipBox,\n b: ClipBox,\n): { start: { x: number; y: number }; end: { x: number; y: number } } {\n return { start: clipPoint(a, b), end: clipPoint(b, a) };\n}\n\n/** The stable connector ports exposed around a shape/card box. */\nexport function snapPoints(box: ClipBox): ConnectorSnapPoint[] {\n const left = box.cx - box.rx;\n const right = box.cx + box.rx;\n const top = box.cy - box.ry;\n const bottom = box.cy + box.ry;\n return [\n { port: 'top', x: box.cx, y: top },\n { port: 'right', x: right, y: box.cy },\n { port: 'bottom', x: box.cx, y: bottom },\n { port: 'left', x: left, y: box.cy },\n { port: 'top-left', x: left, y: top },\n { port: 'top-right', x: right, y: top },\n { port: 'bottom-right', x: right, y: bottom },\n { port: 'bottom-left', x: left, y: bottom },\n ];\n}\n\n/** Resolve a normalized authored anchor to a concrete point on a box. */\nexport function anchorPoint(box: ClipBox, anchor: ConnectorAnchor): ConnectorSnapPoint {\n const offset = Math.max(0, Math.min(1, anchor.offset));\n const left = box.cx - box.rx;\n const right = box.cx + box.rx;\n const top = box.cy - box.ry;\n const bottom = box.cy + box.ry;\n switch (anchor.side) {\n case 'top':\n return { port: 'top', x: left + (right - left) * offset, y: top };\n case 'right':\n return { port: 'right', x: right, y: top + (bottom - top) * offset };\n case 'bottom':\n return { port: 'bottom', x: left + (right - left) * offset, y: bottom };\n case 'left':\n return { port: 'left', x: left, y: top + (bottom - top) * offset };\n }\n}\n\n/** Nearest stable connector port on `box` to an arbitrary point. */\nexport function nearestSnapPoint(\n box: ClipBox,\n point: { x: number; y: number },\n): ConnectorSnapPoint {\n let best = snapPoints(box)[0];\n let bestScore = Number.POSITIVE_INFINITY;\n for (const candidate of snapPoints(box)) {\n const score = distanceSq(candidate, point) + portTieBreak(candidate.port);\n if (score < bestScore) {\n best = candidate;\n bestScore = score;\n }\n }\n return best;\n}\n\n/**\n * Pick the pair of connector ports, one on each box, with the shortest\n * distance between them. This gives stable attachments to side/corner handles\n * instead of arbitrary center-ray intersections.\n */\nexport function snapEndpoints(\n a: ClipBox,\n b: ClipBox,\n): { start: ConnectorSnapPoint; end: ConnectorSnapPoint } {\n let bestStart = snapPoints(a)[0];\n let bestEnd = snapPoints(b)[0];\n let bestScore = Number.POSITIVE_INFINITY;\n for (const start of snapPoints(a)) {\n for (const end of snapPoints(b)) {\n const score = distanceSq(start, end) + portTieBreak(start.port) + portTieBreak(end.port);\n if (score < bestScore) {\n bestStart = start;\n bestEnd = end;\n bestScore = score;\n }\n }\n }\n return { start: bestStart, end: bestEnd };\n}\n\nfunction distanceSq(a: { x: number; y: number }, b: { x: number; y: number }): number {\n const dx = a.x - b.x;\n const dy = a.y - b.y;\n return dx * dx + dy * dy;\n}\n\nfunction portTieBreak(port: ConnectorPort): number {\n return port.includes('-') ? 0.02 : 0;\n}\n\n/** Build the SVG `d` for a connector between two clipped endpoints. */\nexport function connectorPath(\n routing: ConnectorRouting,\n start: { x: number; y: number; port?: ConnectorPort },\n end: { x: number; y: number; port?: ConnectorPort },\n): string {\n if (routing === 'straight') {\n return `M ${r(start.x)} ${r(start.y)} L ${r(end.x)} ${r(end.y)}`;\n }\n if (routing === 'orthogonal') {\n const startAxis = portAxis(start.port);\n const endAxis = portAxis(end.port);\n if (startAxis === 'vertical' && endAxis === 'vertical') {\n const midY = (start.y + end.y) / 2;\n return `M ${r(start.x)} ${r(start.y)} L ${r(start.x)} ${r(midY)} L ${r(end.x)} ${r(midY)} L ${r(end.x)} ${r(end.y)}`;\n }\n if (startAxis === 'vertical' && endAxis === 'horizontal') {\n return `M ${r(start.x)} ${r(start.y)} L ${r(start.x)} ${r(end.y)} L ${r(end.x)} ${r(end.y)}`;\n }\n if (startAxis === 'horizontal' && endAxis === 'vertical') {\n return `M ${r(start.x)} ${r(start.y)} L ${r(end.x)} ${r(start.y)} L ${r(end.x)} ${r(end.y)}`;\n }\n const midX = (start.x + end.x) / 2;\n return `M ${r(start.x)} ${r(start.y)} L ${r(midX)} ${r(start.y)} L ${r(midX)} ${r(end.y)} L ${r(end.x)} ${r(end.y)}`;\n }\n // curved\n const distance = Math.hypot(end.x - start.x, end.y - start.y);\n const cp = Math.max(40, distance / 2);\n const startVector = portVector(start.port, { x: 1, y: 0 });\n const endVector = portVector(end.port, { x: -1, y: 0 });\n return `M ${r(start.x)} ${r(start.y)} C ${r(start.x + startVector.x * cp)} ${r(start.y + startVector.y * cp)}, ${r(end.x + endVector.x * cp)} ${r(end.y + endVector.y * cp)}, ${r(end.x)} ${r(end.y)}`;\n}\n\nfunction portAxis(port: ConnectorPort | undefined): 'horizontal' | 'vertical' | null {\n if (port === 'top' || port === 'bottom') return 'vertical';\n if (port === 'left' || port === 'right') return 'horizontal';\n return null;\n}\n\nfunction portVector(\n port: ConnectorPort | undefined,\n fallback: { x: number; y: number },\n): { x: number; y: number } {\n switch (port) {\n case 'top':\n return { x: 0, y: -1 };\n case 'right':\n return { x: 1, y: 0 };\n case 'bottom':\n return { x: 0, y: 1 };\n case 'left':\n return { x: -1, y: 0 };\n default:\n return fallback;\n }\n}\n\n/** Map a `lineStyle` (solid|dashed|dotted) to an SVG `stroke-dasharray`. */\nexport function lineStyleDasharray(style: string | undefined): string | undefined {\n switch (style?.toLowerCase()) {\n case 'dashed':\n case 'dash':\n return '8 6';\n case 'dotted':\n case 'dot':\n return '2 6';\n default:\n return undefined;\n }\n}\n"],"mappings":"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","names":["head","bodyT"]}
|
|
@@ -142,9 +142,8 @@ var MARKDOWN_PRIORITY = ["index.md", "doc.md", "document.md"];
|
|
|
142
142
|
function findDocumentPath(entries) {
|
|
143
143
|
const rootFiles = entries.filter((e) => !e.path.includes("/"));
|
|
144
144
|
for (const name of MARKDOWN_PRIORITY) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
145
|
+
const match = rootFiles.find((e) => e.path.toLowerCase() === name);
|
|
146
|
+
if (match) return match.path;
|
|
148
147
|
}
|
|
149
148
|
const firstMd = rootFiles.find((e) => e.path.toLowerCase().endsWith(".md"));
|
|
150
149
|
return firstMd?.path ?? null;
|
|
@@ -154,17 +153,20 @@ var MemoryContentContainer = class {
|
|
|
154
153
|
this.files = /* @__PURE__ */ new Map();
|
|
155
154
|
}
|
|
156
155
|
async readFile(path) {
|
|
157
|
-
|
|
156
|
+
const stored = this.files.get(path)?.data;
|
|
157
|
+
return stored ? stored.slice(0) : null;
|
|
158
158
|
}
|
|
159
159
|
async writeFile(path, data, mimeType) {
|
|
160
|
-
let
|
|
161
|
-
if (data
|
|
162
|
-
|
|
160
|
+
let source;
|
|
161
|
+
if (ArrayBuffer.isView(data)) {
|
|
162
|
+
source = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
163
163
|
} else {
|
|
164
|
-
|
|
164
|
+
source = new Uint8Array(data);
|
|
165
165
|
}
|
|
166
|
+
const owned = new Uint8Array(source.byteLength);
|
|
167
|
+
owned.set(source);
|
|
166
168
|
this.files.set(path, {
|
|
167
|
-
data: buffer,
|
|
169
|
+
data: owned.buffer,
|
|
168
170
|
mimeType: mimeType ?? guessMimeType(path)
|
|
169
171
|
});
|
|
170
172
|
}
|
|
@@ -230,19 +232,28 @@ function guessMimeType(path) {
|
|
|
230
232
|
}
|
|
231
233
|
|
|
232
234
|
// src/storage/ScopedContentContainer.ts
|
|
233
|
-
function
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
235
|
+
function normalizeRelativePath(path, label, options = {}) {
|
|
236
|
+
const original = path;
|
|
237
|
+
let normalized = label === "prefix" ? path.trim() : path;
|
|
238
|
+
if (normalized.includes("\\")) {
|
|
239
|
+
throw new Error(`ScopedContentContainer: ${label} must use forward slashes: ${original}`);
|
|
240
|
+
}
|
|
241
|
+
const hadTrailingSlash = normalized.endsWith("/");
|
|
242
|
+
normalized = normalized.replace(/^\/+|\/+$/g, "");
|
|
243
|
+
const segments = normalized === "" ? [] : normalized.split("/").filter(Boolean);
|
|
244
|
+
if (segments.some((segment) => segment === "." || segment === "..")) {
|
|
241
245
|
throw new Error(
|
|
242
|
-
`ScopedContentContainer:
|
|
246
|
+
`ScopedContentContainer: ${label} must not contain '.' or '..' segments: ${original}`
|
|
243
247
|
);
|
|
244
248
|
}
|
|
245
|
-
|
|
249
|
+
if (segments.length === 0 && !options.allowEmpty) {
|
|
250
|
+
throw new Error(`ScopedContentContainer: ${label} must not be empty`);
|
|
251
|
+
}
|
|
252
|
+
const result = segments.join("/");
|
|
253
|
+
return options.preserveTrailingSlash && hadTrailingSlash && result ? `${result}/` : result;
|
|
254
|
+
}
|
|
255
|
+
function normalizePrefix(prefix) {
|
|
256
|
+
return normalizeRelativePath(prefix, "prefix");
|
|
246
257
|
}
|
|
247
258
|
var ScopedContentContainer = class {
|
|
248
259
|
constructor(parent, prefix) {
|
|
@@ -250,10 +261,9 @@ var ScopedContentContainer = class {
|
|
|
250
261
|
this.prefix = normalizePrefix(prefix);
|
|
251
262
|
this.prefixSlash = `${this.prefix}/`;
|
|
252
263
|
}
|
|
253
|
-
toParent(path) {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
return this.prefixSlash + p;
|
|
264
|
+
toParent(path, options = {}) {
|
|
265
|
+
const normalized = normalizeRelativePath(path, "path", options);
|
|
266
|
+
return this.prefixSlash + normalized;
|
|
257
267
|
}
|
|
258
268
|
/** Strip the prefix from a parent-space path. Returns null if the path is outside the scope. */
|
|
259
269
|
fromParent(parentPath) {
|
|
@@ -270,7 +280,7 @@ var ScopedContentContainer = class {
|
|
|
270
280
|
return this.parent.removeFile(this.toParent(path));
|
|
271
281
|
}
|
|
272
282
|
async listFiles(prefix) {
|
|
273
|
-
const parentPrefix = prefix ? this.toParent(prefix
|
|
283
|
+
const parentPrefix = prefix == null ? this.prefixSlash : this.toParent(prefix, { allowEmpty: true, preserveTrailingSlash: true });
|
|
274
284
|
const entries = await this.parent.listFiles(parentPrefix);
|
|
275
285
|
const out = [];
|
|
276
286
|
for (const e of entries) {
|
|
@@ -367,4 +377,4 @@ export {
|
|
|
367
377
|
scopeContainer,
|
|
368
378
|
createMediaProviderFromContainer
|
|
369
379
|
};
|
|
370
|
-
//# sourceMappingURL=chunk-
|
|
380
|
+
//# sourceMappingURL=chunk-VR7UPJ7C.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/storage/MemoryStorageAdapter.ts","../src/storage/LocalStorageAdapter.ts","../src/storage/LocalForageAdapter.ts","../src/storage/ContentContainer.ts","../src/storage/ScopedContentContainer.ts","../src/storage/MediaProviderFromContainer.ts"],"sourcesContent":["/**\n * In-memory storage adapter for testing and SSR environments.\n * Data does not persist across page reloads.\n */\n\nimport type { StorageAdapter } from './Storage.js';\n\nexport class MemoryStorageAdapter implements StorageAdapter {\n readonly supportsEnumeration = true;\n private store = new Map<string, string>();\n\n async get<T>(key: string): Promise<T | null> {\n const val = this.store.get(key);\n if (val === undefined) return null;\n try {\n return JSON.parse(val) as T;\n } catch {\n return null;\n }\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n this.store.set(key, JSON.stringify(value));\n }\n\n async remove(key: string): Promise<void> {\n this.store.delete(key);\n }\n\n async clear(): Promise<void> {\n this.store.clear();\n }\n\n async keys(): Promise<string[]> {\n return Array.from(this.store.keys());\n }\n}\n","/**\n * localStorage adapter for web browsers.\n * Supports a configurable key prefix to namespace stored data.\n */\n\nimport type { StorageAdapter } from './Storage.js';\n\nexport class LocalStorageAdapter implements StorageAdapter {\n readonly supportsEnumeration = true;\n private prefix: string;\n\n constructor(prefix = '') {\n this.prefix = prefix;\n }\n\n async get<T>(key: string): Promise<T | null> {\n try {\n const raw = localStorage.getItem(this.prefix + key);\n if (raw === null) return null;\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n localStorage.setItem(this.prefix + key, JSON.stringify(value));\n }\n\n async remove(key: string): Promise<void> {\n localStorage.removeItem(this.prefix + key);\n }\n\n async clear(): Promise<void> {\n const keysToRemove: string[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const k = localStorage.key(i);\n if (k && k.startsWith(this.prefix)) {\n keysToRemove.push(k);\n }\n }\n for (const k of keysToRemove) {\n localStorage.removeItem(k);\n }\n }\n\n async keys(): Promise<string[]> {\n const result: string[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const k = localStorage.key(i);\n if (k && k.startsWith(this.prefix)) {\n result.push(k.slice(this.prefix.length));\n }\n }\n return result;\n }\n}\n","/**\n * LocalForage adapter - IndexedDB storage with automatic fallbacks.\n *\n * Uses localforage which provides IndexedDB storage with automatic\n * fallbacks to WebSQL and localStorage. This allows storing much more\n * data than raw localStorage (which is limited to ~5MB).\n *\n * Unlike LocalStorageAdapter, this adapter can store binary data\n * (ArrayBuffer, Blob, Uint8Array) natively without JSON serialization.\n *\n * Ported from qualla-internal/shared/services/StorageAdapters.ts with\n * configurable store name and key prefix.\n */\n\nimport localforage from 'localforage';\nimport type { StorageAdapter } from './Storage.js';\n\nexport interface LocalForageAdapterOptions {\n /** IndexedDB database name (default: 'squisq') */\n name?: string;\n /** IndexedDB object store name (default: 'data') */\n storeName?: string;\n /** Key prefix for namespacing (default: '') */\n prefix?: string;\n /** Human-readable description (default: 'Squisq storage') */\n description?: string;\n}\n\nexport class LocalForageAdapter implements StorageAdapter {\n readonly supportsEnumeration = true;\n private store: LocalForage;\n private prefix: string;\n\n constructor(options: LocalForageAdapterOptions = {}) {\n const {\n name = 'squisq',\n storeName = 'data',\n prefix = '',\n description = 'Squisq storage',\n } = options;\n\n this.prefix = prefix;\n this.store = localforage.createInstance({ name, storeName, description });\n }\n\n async get<T>(key: string): Promise<T | null> {\n try {\n const value = await this.store.getItem<T>(this.prefix + key);\n return value;\n } catch (e: unknown) {\n console.warn('[Storage] get (IndexedDB) failed:', key, e);\n return null;\n }\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n try {\n await this.store.setItem(this.prefix + key, value);\n } catch (e: unknown) {\n console.error('[Storage] set (IndexedDB) failed:', key, e);\n throw e;\n }\n }\n\n async remove(key: string): Promise<void> {\n try {\n await this.store.removeItem(this.prefix + key);\n } catch (e: unknown) {\n console.warn('[Storage] remove (IndexedDB) failed:', key, e);\n }\n }\n\n async clear(): Promise<void> {\n try {\n if (this.prefix) {\n // Only remove keys with our prefix\n const keys = await this.store.keys();\n const keysToRemove = keys.filter((k) => k.startsWith(this.prefix));\n await Promise.all(keysToRemove.map((k) => this.store.removeItem(k)));\n } else {\n // No prefix — clear the entire store\n await this.store.clear();\n }\n } catch (e: unknown) {\n console.error('[Storage] clear (IndexedDB) failed:', e);\n }\n }\n\n async keys(): Promise<string[]> {\n try {\n const allKeys = await this.store.keys();\n if (this.prefix) {\n return allKeys\n .filter((k) => k.startsWith(this.prefix))\n .map((k) => k.slice(this.prefix.length));\n }\n return allKeys;\n } catch (e: unknown) {\n console.warn('[Storage] keys (IndexedDB) failed:', e);\n return [];\n }\n }\n}\n","/**\n * ContentContainer — virtual file system for document containers.\n *\n * A Squisq document is more than just markdown: it's a container of files\n * including the primary markdown document, images, audio, timing data, and\n * other media. ContentContainer provides an abstract async file system\n * interface for reading, writing, and listing these files.\n *\n * Paths are forward-slash separated strings relative to the container root\n * (e.g., 'images/hero.jpg', 'index.md'). No leading slash.\n *\n * Implementations (in core):\n * - MemoryContentContainer — in-memory Map (for zip import, tests, transient use)\n * - ScopedContentContainer — a prefix-scoped view onto a parent container\n */\n\n/**\n * Metadata about a file in a ContentContainer.\n */\nexport interface ContentEntry {\n /** Relative path within the container (e.g., 'images/hero.jpg') */\n path: string;\n /** MIME type (e.g., 'image/jpeg') */\n mimeType: string;\n /** File size in bytes */\n size: number;\n}\n\n/**\n * Abstract async file system for document containers.\n *\n * All paths are forward-slash separated, relative to the container root,\n * with no leading slash. Example: 'images/hero.jpg', 'index.md'.\n */\nexport interface ContentContainer {\n /** Read a file's binary content. Returns null if the file does not exist. */\n readFile(path: string): Promise<ArrayBuffer | null>;\n\n /** Write a file. Creates or overwrites. */\n writeFile(path: string, data: ArrayBuffer | Uint8Array, mimeType?: string): Promise<void>;\n\n /** Remove a file. No-op if the file does not exist. */\n removeFile(path: string): Promise<void>;\n\n /**\n * List files in the container.\n *\n * Returns file **entries** (`ContentEntry[]` with `.path`/`.mimeType`/`.size`),\n * NOT bare path strings — despite the name. Read `entry.path` for the path;\n * calling string methods (e.g. `.startsWith`) directly on an entry will throw.\n * @param prefix — Optional path prefix to filter by (e.g., 'images/')\n */\n listFiles(prefix?: string): Promise<ContentEntry[]>;\n\n /** Check whether a file exists. */\n exists(path: string): Promise<boolean>;\n\n /**\n * Find the primary markdown document path.\n *\n * Discovery order: index.md → doc.md → document.md → first *.md at root.\n * Returns null if no markdown file is found at the root level.\n */\n getDocumentPath(): Promise<string | null>;\n\n /**\n * Convenience: read the primary markdown document as a UTF-8 string.\n * Returns null if no markdown file is found.\n */\n readDocument(): Promise<string | null>;\n\n /**\n * Convenience: write a markdown document.\n * @param markdown — The markdown content\n * @param filename — Filename to use (defaults to 'index.md')\n */\n writeDocument(markdown: string, filename?: string): Promise<void>;\n}\n\n// ============================================\n// Well-known markdown filenames in priority order\n// ============================================\n\nconst MARKDOWN_PRIORITY = ['index.md', 'doc.md', 'document.md'];\n\n/**\n * Find the primary markdown path from a list of file entries.\n * Exported for reuse by other ContentContainer implementations.\n */\nexport function findDocumentPath(entries: ContentEntry[]): string | null {\n // Only consider root-level files (no '/' in path)\n const rootFiles = entries.filter((e) => !e.path.includes('/'));\n\n for (const name of MARKDOWN_PRIORITY) {\n const match = rootFiles.find((e) => e.path.toLowerCase() === name);\n if (match) return match.path;\n }\n\n // Fallback: first .md file at root\n const firstMd = rootFiles.find((e) => e.path.toLowerCase().endsWith('.md'));\n return firstMd?.path ?? null;\n}\n\n// ============================================\n// MemoryContentContainer\n// ============================================\n\ninterface MemoryFile {\n data: ArrayBuffer;\n mimeType: string;\n}\n\n/**\n * In-memory ContentContainer backed by a Map.\n *\n * Used for zip import (deserialize into memory), tests, and transient operations.\n */\nexport class MemoryContentContainer implements ContentContainer {\n private files = new Map<string, MemoryFile>();\n\n async readFile(path: string): Promise<ArrayBuffer | null> {\n const stored = this.files.get(path)?.data;\n // A container owns its bytes. Returning the backing buffer would let a\n // caller mutate stored state without going through writeFile().\n return stored ? stored.slice(0) : null;\n }\n\n async writeFile(path: string, data: ArrayBuffer | Uint8Array, mimeType?: string): Promise<void> {\n // Copy to a standalone ArrayBuffer. Uint8Array/Buffer may share a larger\n // backing buffer (e.g., Node's buffer pool), so we must slice to the\n // exact byte range to avoid storing stale pool data.\n // ArrayBuffer.isView is cross-realm-safe (unlike `instanceof\n // ArrayBuffer`, which fails for values created in jsdom/iframes).\n let source: Uint8Array;\n if (ArrayBuffer.isView(data)) {\n source = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n } else {\n source = new Uint8Array(data);\n }\n // Always materialize in this realm, including for iframe ArrayBuffers and\n // views backed by SharedArrayBuffer.\n const owned = new Uint8Array(source.byteLength);\n owned.set(source);\n this.files.set(path, {\n data: owned.buffer,\n mimeType: mimeType ?? guessMimeType(path),\n });\n }\n\n async removeFile(path: string): Promise<void> {\n this.files.delete(path);\n }\n\n async listFiles(prefix?: string): Promise<ContentEntry[]> {\n const entries: ContentEntry[] = [];\n for (const [path, file] of this.files) {\n if (prefix && !path.startsWith(prefix)) continue;\n entries.push({\n path,\n mimeType: file.mimeType,\n size: file.data.byteLength,\n });\n }\n return entries;\n }\n\n async exists(path: string): Promise<boolean> {\n return this.files.has(path);\n }\n\n async getDocumentPath(): Promise<string | null> {\n return findDocumentPath(await this.listFiles());\n }\n\n async readDocument(): Promise<string | null> {\n const docPath = await this.getDocumentPath();\n if (!docPath) return null;\n const data = await this.readFile(docPath);\n if (!data) return null;\n return new TextDecoder().decode(data);\n }\n\n async writeDocument(markdown: string, filename?: string): Promise<void> {\n const name = filename ?? 'index.md';\n const data = new TextEncoder().encode(markdown);\n await this.writeFile(name, data, 'text/markdown');\n }\n}\n\n// ============================================\n// MIME type guessing\n// ============================================\n\nconst EXTENSION_MIME_MAP: Record<string, string> = {\n '.md': 'text/markdown',\n '.txt': 'text/plain',\n '.json': 'application/json',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.png': 'image/png',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.mp3': 'audio/mpeg',\n '.wav': 'audio/wav',\n '.ogg': 'audio/ogg',\n '.css': 'text/css',\n '.html': 'text/html',\n '.js': 'application/javascript',\n};\n\nfunction guessMimeType(path: string): string {\n const dot = path.lastIndexOf('.');\n if (dot === -1) return 'application/octet-stream';\n const ext = path.slice(dot).toLowerCase();\n return EXTENSION_MIME_MAP[ext] ?? 'application/octet-stream';\n}\n","/**\n * ScopedContentContainer\n *\n * Wraps a parent {@link ContentContainer} and prefixes every path with a\n * fixed subfolder, presenting that subfolder as the root. Useful for\n * sidecar folders (e.g. `<imagebasename>_files/`) where a component\n * should be able to read/write/list files relative to its own root\n * without knowing where it lives in the parent tree.\n *\n * Scopes nest: `scopeContainer(scopeContainer(parent, 'a'), 'b')` is\n * equivalent to `scopeContainer(parent, 'a/b')`.\n *\n * `getDocumentPath()` always returns `null` for scoped sidecars — they\n * are not document roots.\n */\n\nimport type { ContentContainer, ContentEntry } from './ContentContainer.js';\n\ninterface NormalizePathOptions {\n allowEmpty?: boolean;\n preserveTrailingSlash?: boolean;\n}\n\n/**\n * Normalize a container-relative path without ever resolving traversal.\n * Backslashes are rejected rather than translated because a filesystem-backed\n * parent may interpret them as separators even when an in-memory parent does\n * not. Dot segments are similarly rejected instead of collapsed so an invalid\n * caller path can never escape after a later platform-specific normalization.\n */\nfunction normalizeRelativePath(\n path: string,\n label: 'prefix' | 'path',\n options: NormalizePathOptions = {},\n): string {\n const original = path;\n let normalized = label === 'prefix' ? path.trim() : path;\n if (normalized.includes('\\\\')) {\n throw new Error(`ScopedContentContainer: ${label} must use forward slashes: ${original}`);\n }\n\n const hadTrailingSlash = normalized.endsWith('/');\n normalized = normalized.replace(/^\\/+|\\/+$/g, '');\n const segments = normalized === '' ? [] : normalized.split('/').filter(Boolean);\n if (segments.some((segment) => segment === '.' || segment === '..')) {\n throw new Error(\n `ScopedContentContainer: ${label} must not contain '.' or '..' segments: ${original}`,\n );\n }\n if (segments.length === 0 && !options.allowEmpty) {\n throw new Error(`ScopedContentContainer: ${label} must not be empty`);\n }\n\n const result = segments.join('/');\n return options.preserveTrailingSlash && hadTrailingSlash && result ? `${result}/` : result;\n}\n\n/** Normalize a prefix: strip leading/trailing slashes, ensure no `..` segments. */\nfunction normalizePrefix(prefix: string): string {\n return normalizeRelativePath(prefix, 'prefix');\n}\n\n/**\n * A ContentContainer view rooted at a subfolder of a parent container.\n * All paths passed to / returned from this container are relative to\n * the subfolder; the parent never sees an unprefixed path.\n */\nexport class ScopedContentContainer implements ContentContainer {\n private readonly parent: ContentContainer;\n /** Prefix without trailing slash. */\n readonly prefix: string;\n /** Prefix with trailing slash. */\n private readonly prefixSlash: string;\n\n constructor(parent: ContentContainer, prefix: string) {\n this.parent = parent;\n this.prefix = normalizePrefix(prefix);\n this.prefixSlash = `${this.prefix}/`;\n }\n\n private toParent(path: string, options: NormalizePathOptions = {}): string {\n const normalized = normalizeRelativePath(path, 'path', options);\n return this.prefixSlash + normalized;\n }\n\n /** Strip the prefix from a parent-space path. Returns null if the path is outside the scope. */\n private fromParent(parentPath: string): string | null {\n if (!parentPath.startsWith(this.prefixSlash)) return null;\n return parentPath.slice(this.prefixSlash.length);\n }\n\n readFile(path: string): Promise<ArrayBuffer | null> {\n return this.parent.readFile(this.toParent(path));\n }\n\n writeFile(path: string, data: ArrayBuffer | Uint8Array, mimeType?: string): Promise<void> {\n return this.parent.writeFile(this.toParent(path), data, mimeType);\n }\n\n removeFile(path: string): Promise<void> {\n return this.parent.removeFile(this.toParent(path));\n }\n\n async listFiles(prefix?: string): Promise<ContentEntry[]> {\n const parentPrefix =\n prefix == null\n ? this.prefixSlash\n : this.toParent(prefix, { allowEmpty: true, preserveTrailingSlash: true });\n const entries = await this.parent.listFiles(parentPrefix);\n const out: ContentEntry[] = [];\n for (const e of entries) {\n const local = this.fromParent(e.path);\n if (local === null) continue;\n out.push({ path: local, mimeType: e.mimeType, size: e.size });\n }\n return out;\n }\n\n exists(path: string): Promise<boolean> {\n return this.parent.exists(this.toParent(path));\n }\n\n /** Sidecars are not document roots. */\n async getDocumentPath(): Promise<string | null> {\n return null;\n }\n\n async readDocument(): Promise<string | null> {\n return null;\n }\n\n async writeDocument(): Promise<void> {\n throw new Error(\n 'ScopedContentContainer is a sidecar view and does not support writeDocument(). ' +\n 'Write to a specific path with writeFile() instead.',\n );\n }\n}\n\n/** Factory: convenience wrapper for `new ScopedContentContainer(parent, prefix)`. */\nexport function scopeContainer(parent: ContentContainer, prefix: string): ScopedContentContainer {\n return new ScopedContentContainer(parent, prefix);\n}\n","/**\n * MediaProviderFromContainer — bridges ContentContainer to MediaProvider.\n *\n * Creates a MediaProvider that resolves relative paths by reading binary data\n * from a ContentContainer and generating blob URLs. Blob URLs are cached and\n * revoked on dispose().\n *\n * This allows any ContentContainer (memory, slot-backed, zip-loaded) to be\n * used with existing rendering components (DocPlayer, ImageLayer, VideoLayer)\n * that consume MediaProvider.\n */\n\nimport type { MediaProvider, MediaEntry } from '../schemas/MediaProvider.js';\nimport type { ContentContainer } from './ContentContainer.js';\n\n/**\n * Create a MediaProvider backed by a ContentContainer.\n *\n * @param container — The ContentContainer to read/write media from\n * @returns A MediaProvider that resolves paths to blob URLs\n */\nexport function createMediaProviderFromContainer(container: ContentContainer): MediaProvider {\n const blobUrlCache = new Map<string, string>();\n\n return {\n async resolveUrl(relativePath: string): Promise<string> {\n const cached = blobUrlCache.get(relativePath);\n if (cached) return cached;\n\n const data = await container.readFile(relativePath);\n if (!data) return relativePath;\n\n const entries = await container.listFiles();\n const entry = entries.find((e) => e.path === relativePath);\n const mimeType = entry?.mimeType ?? 'application/octet-stream';\n\n const blob = new Blob([data], { type: mimeType });\n const url = URL.createObjectURL(blob);\n blobUrlCache.set(relativePath, url);\n return url;\n },\n\n async listMedia(): Promise<MediaEntry[]> {\n const entries = await container.listFiles();\n return entries\n .filter((e) => !e.path.toLowerCase().endsWith('.md'))\n .map((e) => ({\n name: e.path,\n mimeType: e.mimeType,\n size: e.size,\n }));\n },\n\n async addMedia(\n name: string,\n data: ArrayBuffer | Blob | Uint8Array,\n mimeType: string,\n ): Promise<string> {\n // Invalidate any cached blob URL for this path before overwriting\n const cached = blobUrlCache.get(name);\n if (cached) {\n URL.revokeObjectURL(cached);\n blobUrlCache.delete(name);\n }\n\n let buffer: ArrayBuffer | Uint8Array;\n if (data instanceof Blob) {\n buffer = await data.arrayBuffer();\n } else {\n buffer = data;\n }\n await container.writeFile(name, buffer, mimeType);\n return name;\n },\n\n async removeMedia(relativePath: string): Promise<void> {\n const cached = blobUrlCache.get(relativePath);\n if (cached) {\n URL.revokeObjectURL(cached);\n blobUrlCache.delete(relativePath);\n }\n await container.removeFile(relativePath);\n },\n\n dispose(): void {\n for (const url of blobUrlCache.values()) {\n URL.revokeObjectURL(url);\n }\n blobUrlCache.clear();\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cloneAndFreezeData
|
|
3
|
+
} from "./chunk-5J4HKRJF.js";
|
|
1
4
|
import {
|
|
2
5
|
isTransitionType
|
|
3
6
|
} from "./chunk-QE7TWGVT.js";
|
|
@@ -5,76 +8,8 @@ import {
|
|
|
5
8
|
// src/schemas/CustomTemplates.ts
|
|
6
9
|
var FRONTMATTER_CUSTOM_TEMPLATES_KEY = "squisq-custom-templates";
|
|
7
10
|
|
|
8
|
-
// src/schemas/
|
|
11
|
+
// src/schemas/themeConstants.ts
|
|
9
12
|
var THEME_SCHEMA_VERSION = "1";
|
|
10
|
-
var FRONTMATTER_CUSTOM_THEMES_KEY = "squisq-custom-themes";
|
|
11
|
-
function deepMerge(target, source) {
|
|
12
|
-
const result = { ...target };
|
|
13
|
-
for (const key of Object.keys(source)) {
|
|
14
|
-
const srcVal = source[key];
|
|
15
|
-
const tgtVal = target[key];
|
|
16
|
-
if (srcVal !== null && srcVal !== void 0 && typeof srcVal === "object" && !Array.isArray(srcVal) && tgtVal !== null && tgtVal !== void 0 && typeof tgtVal === "object" && !Array.isArray(tgtVal)) {
|
|
17
|
-
result[key] = deepMerge(
|
|
18
|
-
tgtVal,
|
|
19
|
-
srcVal
|
|
20
|
-
);
|
|
21
|
-
} else if (srcVal !== void 0) {
|
|
22
|
-
result[key] = srcVal;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return result;
|
|
26
|
-
}
|
|
27
|
-
function createTheme(base, overrides) {
|
|
28
|
-
const merged = deepMerge(
|
|
29
|
-
base,
|
|
30
|
-
overrides
|
|
31
|
-
);
|
|
32
|
-
if (!overrides.id && merged.id === base.id) {
|
|
33
|
-
merged.id = `${base.id}-custom`;
|
|
34
|
-
}
|
|
35
|
-
if (!merged.schemaVersion) merged.schemaVersion = THEME_SCHEMA_VERSION;
|
|
36
|
-
return merged;
|
|
37
|
-
}
|
|
38
|
-
var LIGHT_SURFACE = {
|
|
39
|
-
id: "light",
|
|
40
|
-
background: "#ffffff",
|
|
41
|
-
backgroundLight: "#f5f5f5",
|
|
42
|
-
text: "#1a1a1a",
|
|
43
|
-
textMuted: "#666666"
|
|
44
|
-
};
|
|
45
|
-
var DARK_SURFACE = {
|
|
46
|
-
id: "dark",
|
|
47
|
-
background: "#1a202c",
|
|
48
|
-
backgroundLight: "#2d3748",
|
|
49
|
-
text: "#f0f0f0",
|
|
50
|
-
textMuted: "#a0aec0"
|
|
51
|
-
};
|
|
52
|
-
function applySurface(theme, surface) {
|
|
53
|
-
return {
|
|
54
|
-
...theme,
|
|
55
|
-
colors: {
|
|
56
|
-
...theme.colors,
|
|
57
|
-
background: surface.background,
|
|
58
|
-
backgroundLight: surface.backgroundLight,
|
|
59
|
-
text: surface.text,
|
|
60
|
-
textMuted: surface.textMuted
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
var CUSTOM_THEME_REGISTRY = /* @__PURE__ */ new Map();
|
|
65
|
-
function registerTheme(theme) {
|
|
66
|
-
CUSTOM_THEME_REGISTRY.set(theme.id, theme);
|
|
67
|
-
}
|
|
68
|
-
function unregisterTheme(id) {
|
|
69
|
-
CUSTOM_THEME_REGISTRY.delete(id);
|
|
70
|
-
}
|
|
71
|
-
function getRegisteredThemes() {
|
|
72
|
-
return Array.from(CUSTOM_THEME_REGISTRY.values());
|
|
73
|
-
}
|
|
74
|
-
function lookupRegisteredTheme(id) {
|
|
75
|
-
if (!id) return void 0;
|
|
76
|
-
return CUSTOM_THEME_REGISTRY.get(id);
|
|
77
|
-
}
|
|
78
13
|
|
|
79
14
|
// src/schemas/colorUtils.ts
|
|
80
15
|
var HEX_RE = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
|
|
@@ -579,6 +514,90 @@ ${summary}${more}`);
|
|
|
579
514
|
return result.theme;
|
|
580
515
|
}
|
|
581
516
|
|
|
517
|
+
// src/schemas/Theme.ts
|
|
518
|
+
var FRONTMATTER_CUSTOM_THEMES_KEY = "squisq-custom-themes";
|
|
519
|
+
function deepMerge(target, source) {
|
|
520
|
+
const result = { ...target };
|
|
521
|
+
for (const key of Object.keys(source)) {
|
|
522
|
+
const srcVal = source[key];
|
|
523
|
+
const tgtVal = target[key];
|
|
524
|
+
if (srcVal !== null && srcVal !== void 0 && typeof srcVal === "object" && !Array.isArray(srcVal) && tgtVal !== null && tgtVal !== void 0 && typeof tgtVal === "object" && !Array.isArray(tgtVal)) {
|
|
525
|
+
result[key] = deepMerge(
|
|
526
|
+
tgtVal,
|
|
527
|
+
srcVal
|
|
528
|
+
);
|
|
529
|
+
} else if (srcVal !== void 0) {
|
|
530
|
+
result[key] = srcVal;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
return result;
|
|
534
|
+
}
|
|
535
|
+
function createTheme(base, overrides) {
|
|
536
|
+
const merged = deepMerge(
|
|
537
|
+
base,
|
|
538
|
+
overrides
|
|
539
|
+
);
|
|
540
|
+
if (!overrides.id && merged.id === base.id) {
|
|
541
|
+
merged.id = `${base.id}-custom`;
|
|
542
|
+
}
|
|
543
|
+
if (!merged.schemaVersion) merged.schemaVersion = THEME_SCHEMA_VERSION;
|
|
544
|
+
return merged;
|
|
545
|
+
}
|
|
546
|
+
var LIGHT_SURFACE = {
|
|
547
|
+
id: "light",
|
|
548
|
+
background: "#ffffff",
|
|
549
|
+
backgroundLight: "#f5f5f5",
|
|
550
|
+
text: "#1a1a1a",
|
|
551
|
+
textMuted: "#666666"
|
|
552
|
+
};
|
|
553
|
+
var DARK_SURFACE = {
|
|
554
|
+
id: "dark",
|
|
555
|
+
background: "#1a202c",
|
|
556
|
+
backgroundLight: "#2d3748",
|
|
557
|
+
text: "#f0f0f0",
|
|
558
|
+
textMuted: "#a0aec0"
|
|
559
|
+
};
|
|
560
|
+
function applySurface(theme, surface) {
|
|
561
|
+
return {
|
|
562
|
+
...theme,
|
|
563
|
+
colors: {
|
|
564
|
+
...theme.colors,
|
|
565
|
+
background: surface.background,
|
|
566
|
+
backgroundLight: surface.backgroundLight,
|
|
567
|
+
text: surface.text,
|
|
568
|
+
textMuted: surface.textMuted
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
function validatedThemeSnapshot(theme) {
|
|
573
|
+
const result = validateTheme(theme);
|
|
574
|
+
if (!result.valid || !result.theme) {
|
|
575
|
+
const details = result.errors.slice(0, 5).map((error) => `${error.path || "<root>"}: ${error.message}`).join("; ");
|
|
576
|
+
throw new TypeError(`Cannot register invalid theme: ${details}`);
|
|
577
|
+
}
|
|
578
|
+
return cloneAndFreezeData(result.theme);
|
|
579
|
+
}
|
|
580
|
+
function createThemeRegistry(initialThemes = []) {
|
|
581
|
+
const themes = /* @__PURE__ */ new Map();
|
|
582
|
+
const registry = {
|
|
583
|
+
register(theme) {
|
|
584
|
+
const snapshot = validatedThemeSnapshot(theme);
|
|
585
|
+
themes.set(snapshot.id, snapshot);
|
|
586
|
+
},
|
|
587
|
+
unregister(id) {
|
|
588
|
+
return themes.delete(id);
|
|
589
|
+
},
|
|
590
|
+
get(id) {
|
|
591
|
+
return themes.get(id);
|
|
592
|
+
},
|
|
593
|
+
list() {
|
|
594
|
+
return Array.from(themes.values());
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
for (const theme of initialThemes) registry.register(theme);
|
|
598
|
+
return Object.freeze(registry);
|
|
599
|
+
}
|
|
600
|
+
|
|
582
601
|
// src/schemas/themes/standard.json
|
|
583
602
|
var standard_default = {
|
|
584
603
|
schemaVersion: "1",
|
|
@@ -1388,7 +1407,7 @@ var gezellig_default = {
|
|
|
1388
1407
|
schemaVersion: "1",
|
|
1389
1408
|
id: "gezellig",
|
|
1390
1409
|
name: "Gezellig",
|
|
1391
|
-
description: "
|
|
1410
|
+
description: "Cozy, warm-hued palette with a subtle orange-tinted dark background, cream text, and sage and terracotta accents.",
|
|
1392
1411
|
colors: {
|
|
1393
1412
|
primary: "#b0724c",
|
|
1394
1413
|
secondary: "#667f62",
|
|
@@ -1505,24 +1524,29 @@ var BUILTIN_THEMES = {
|
|
|
1505
1524
|
};
|
|
1506
1525
|
|
|
1507
1526
|
// src/schemas/themeLibrary.ts
|
|
1508
|
-
var THEMES =
|
|
1527
|
+
var THEMES = Object.freeze(
|
|
1528
|
+
Object.fromEntries(
|
|
1529
|
+
Object.entries(BUILTIN_THEMES).map(([id, theme]) => [id, cloneAndFreezeData(theme)])
|
|
1530
|
+
)
|
|
1531
|
+
);
|
|
1509
1532
|
var DEFAULT_THEME_ID = "standard";
|
|
1510
1533
|
var DEFAULT_THEME = THEMES[DEFAULT_THEME_ID];
|
|
1511
|
-
function resolveTheme(id) {
|
|
1512
|
-
const registered =
|
|
1534
|
+
function resolveTheme(id, registry) {
|
|
1535
|
+
const registered = id ? registry?.get(id) : void 0;
|
|
1513
1536
|
if (registered) return registered;
|
|
1514
1537
|
if (id && id in THEMES) return THEMES[id];
|
|
1515
1538
|
return DEFAULT_THEME;
|
|
1516
1539
|
}
|
|
1517
|
-
function getAvailableThemes() {
|
|
1518
|
-
return
|
|
1540
|
+
function getAvailableThemes(registry) {
|
|
1541
|
+
return Array.from(
|
|
1542
|
+
/* @__PURE__ */ new Set([...Object.keys(THEMES), ...registry?.list().map((theme) => theme.id) ?? []])
|
|
1543
|
+
);
|
|
1519
1544
|
}
|
|
1520
|
-
function getThemeSummaries() {
|
|
1521
|
-
return
|
|
1522
|
-
|
|
1523
|
-
name:
|
|
1524
|
-
|
|
1525
|
-
}));
|
|
1545
|
+
function getThemeSummaries(registry) {
|
|
1546
|
+
return getAvailableThemes(registry).map((id) => {
|
|
1547
|
+
const theme = resolveTheme(id, registry);
|
|
1548
|
+
return { id, name: theme.name, description: theme.description };
|
|
1549
|
+
});
|
|
1526
1550
|
}
|
|
1527
1551
|
|
|
1528
1552
|
// src/schemas/fontStacks.ts
|
|
@@ -1709,19 +1733,52 @@ function buildGoogleFontsUrl(families) {
|
|
|
1709
1733
|
return `https://fonts.googleapis.com/css2?${params}&display=swap`;
|
|
1710
1734
|
}
|
|
1711
1735
|
var FONT_FALLBACKS = FALLBACK_BY_KIND;
|
|
1736
|
+
function normalizeFontName(name) {
|
|
1737
|
+
return name.trim().replace(/^["']+|["']+$/g, "").replace(/\s+/g, " ").toLowerCase();
|
|
1738
|
+
}
|
|
1739
|
+
var STACK_NAME_ALIASES = (() => {
|
|
1740
|
+
const aliases = {};
|
|
1741
|
+
for (const stack of AVAILABLE_FONT_STACKS) {
|
|
1742
|
+
aliases[normalizeFontName(stack.label)] = stack.id;
|
|
1743
|
+
if (stack.googleFontFamily) aliases[normalizeFontName(stack.googleFontFamily)] = stack.id;
|
|
1744
|
+
}
|
|
1745
|
+
Object.assign(aliases, {
|
|
1746
|
+
playfair: "playfair",
|
|
1747
|
+
"source serif": "source-serif",
|
|
1748
|
+
"source serif pro": "source-serif",
|
|
1749
|
+
"crimson pro": "crimson",
|
|
1750
|
+
cormorant: "cormorant",
|
|
1751
|
+
georgia: "system-serif",
|
|
1752
|
+
"times new roman": "system-serif",
|
|
1753
|
+
times: "system-serif",
|
|
1754
|
+
consolas: "system-mono",
|
|
1755
|
+
"courier new": "system-mono",
|
|
1756
|
+
courier: "system-mono",
|
|
1757
|
+
"segoe ui": "system-sans",
|
|
1758
|
+
"system-ui": "system-sans"
|
|
1759
|
+
});
|
|
1760
|
+
return aliases;
|
|
1761
|
+
})();
|
|
1762
|
+
var MONO_NAME_RE = /\b(mono|monospace|consolas|courier|menlo|inconsolata|cascadia|fira code|source code|code)\b/;
|
|
1763
|
+
var SERIF_NAME_RE = /\b(georgia|times|garamond|cambria|caslon|baskerville|bodoni|didot|palatino|book antiqua|goudy|minion|charter|constantia|century schoolbook|antiqua|roman)\b/;
|
|
1764
|
+
function guessFontFallback(name) {
|
|
1765
|
+
const n = normalizeFontName(name);
|
|
1766
|
+
if (MONO_NAME_RE.test(n)) return "monospace";
|
|
1767
|
+
if (n.includes("serif") && !n.includes("sans") || SERIF_NAME_RE.test(n)) return "serif";
|
|
1768
|
+
return "sans-serif";
|
|
1769
|
+
}
|
|
1770
|
+
function matchFontFamily(name) {
|
|
1771
|
+
const normalized = normalizeFontName(name);
|
|
1772
|
+
if (!normalized) return { stackId: "system-sans" };
|
|
1773
|
+
const stackId = STACK_NAME_ALIASES[normalized];
|
|
1774
|
+
if (stackId) return { stackId };
|
|
1775
|
+
const displayName = name.trim().replace(/^["']+|["']+$/g, "");
|
|
1776
|
+
return { custom: { name: displayName, fallback: guessFontFallback(name) } };
|
|
1777
|
+
}
|
|
1712
1778
|
|
|
1713
1779
|
export {
|
|
1714
1780
|
FRONTMATTER_CUSTOM_TEMPLATES_KEY,
|
|
1715
1781
|
THEME_SCHEMA_VERSION,
|
|
1716
|
-
FRONTMATTER_CUSTOM_THEMES_KEY,
|
|
1717
|
-
createTheme,
|
|
1718
|
-
LIGHT_SURFACE,
|
|
1719
|
-
DARK_SURFACE,
|
|
1720
|
-
applySurface,
|
|
1721
|
-
registerTheme,
|
|
1722
|
-
unregisterTheme,
|
|
1723
|
-
getRegisteredThemes,
|
|
1724
|
-
lookupRegisteredTheme,
|
|
1725
1782
|
isHex,
|
|
1726
1783
|
oklchLighten,
|
|
1727
1784
|
oklchDarken,
|
|
@@ -1734,6 +1791,12 @@ export {
|
|
|
1734
1791
|
deriveScale,
|
|
1735
1792
|
validateTheme,
|
|
1736
1793
|
assertTheme,
|
|
1794
|
+
FRONTMATTER_CUSTOM_THEMES_KEY,
|
|
1795
|
+
createTheme,
|
|
1796
|
+
LIGHT_SURFACE,
|
|
1797
|
+
DARK_SURFACE,
|
|
1798
|
+
applySurface,
|
|
1799
|
+
createThemeRegistry,
|
|
1737
1800
|
THEMES,
|
|
1738
1801
|
DEFAULT_THEME_ID,
|
|
1739
1802
|
DEFAULT_THEME,
|
|
@@ -1745,6 +1808,8 @@ export {
|
|
|
1745
1808
|
resolveFontFamily,
|
|
1746
1809
|
fontStack,
|
|
1747
1810
|
buildGoogleFontsUrl,
|
|
1748
|
-
FONT_FALLBACKS
|
|
1811
|
+
FONT_FALLBACKS,
|
|
1812
|
+
guessFontFallback,
|
|
1813
|
+
matchFontFamily
|
|
1749
1814
|
};
|
|
1750
|
-
//# sourceMappingURL=chunk-
|
|
1815
|
+
//# sourceMappingURL=chunk-W4O2TX5I.js.map
|