@bendyline/squisq 2.1.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE.md +24 -0
- package/README.md +8 -8
- package/dist/{ContentContainer-BXUlIf18.d.ts → ContentContainer-B2w9sUoL.d.ts} +15 -0
- package/dist/{Doc-DynJleo-.d.ts → Doc-COe-rPQB.d.ts} +7 -5
- package/dist/{ImageEditDoc-Ca4Tr9uN.d.ts → ImageEditDoc-dtKahVyD.d.ts} +1 -1
- package/dist/{annotationCoercion-Dr_DY9Hx.d.ts → annotationCoercion-PtRQhk5V.d.ts} +1 -1
- package/dist/{chunk-VWCJ2WXC.js → chunk-2ZWIXGAC.js} +0 -1
- package/dist/{chunk-VYFRI7R6.js → chunk-32R2RZAO.js} +72 -3
- package/dist/chunk-3IGPAPQ7.js +645 -0
- package/dist/{chunk-QE7TWGVT.js → chunk-4VOD55SX.js} +0 -1
- package/dist/{chunk-3E5F2XMR.js → chunk-67L6WRJN.js} +0 -1
- package/dist/{chunk-5DKBFXPY.js → chunk-6ECMNUIP.js} +26 -18
- package/dist/{chunk-DBS6RIFL.js → chunk-7N4G32LG.js} +0 -1
- package/dist/{chunk-JOQYPRDZ.js → chunk-7YEZFHLS.js} +10 -8
- package/dist/{chunk-2UQOHYE2.js → chunk-7ZAAICW4.js} +0 -1
- package/dist/{chunk-66QO7XFB.js → chunk-ACZOVWX3.js} +117 -7
- package/dist/{chunk-5J4HKRJF.js → chunk-BAOV476U.js} +0 -1
- package/dist/chunk-BCCXTMN5.js +699 -0
- package/dist/{chunk-JHZWYRSW.js → chunk-C33GTPUZ.js} +11 -4
- package/dist/{chunk-XNLB57UD.js → chunk-EK446BUE.js} +18 -2
- package/dist/{chunk-VR7UPJ7C.js → chunk-FCG3BIZN.js} +12 -1
- package/dist/{chunk-JI77MGAK.js → chunk-GIIOY6XR.js} +2178 -1291
- package/dist/{chunk-Q7LROV2H.js → chunk-NKNMGIIN.js} +0 -1
- package/dist/chunk-OPO5K4DZ.js +241 -0
- package/dist/{chunk-TUWMK62B.js → chunk-PUS54YU6.js} +45 -2
- package/dist/{chunk-OTKVFVL6.js → chunk-QNTQIEIV.js} +130 -47
- package/dist/{chunk-5UYI3RJB.js → chunk-QWCFK5FN.js} +55 -40
- package/dist/{chunk-GZY66SDN.js → chunk-R3KTTOMS.js} +0 -1
- package/dist/{chunk-ILWDXLUK.js → chunk-RS5AP3J4.js} +49 -10
- package/dist/{chunk-QUUPYOSP.js → chunk-SPTY4C6F.js} +136 -5
- package/dist/{chunk-4X3JQXNM.js → chunk-XOFT65EX.js} +1 -2
- package/dist/{chunk-FVTQSNR7.js → chunk-XRW6P7IF.js} +13 -5
- package/dist/{chunk-R2YZTCLO.js → chunk-ZQKZSJAX.js} +1 -2
- package/dist/doc/index.d.ts +311 -13
- package/dist/doc/index.js +25 -17
- package/dist/generate/index.d.ts +2 -2
- package/dist/generate/index.js +1 -3
- package/dist/icons/index.js +2 -4
- package/dist/icons/inlineIconMarker.js +1 -2
- package/dist/imageEdit/index.d.ts +48 -17
- package/dist/imageEdit/index.js +3 -4
- package/dist/index.d.ts +13 -13
- package/dist/index.js +67 -33
- package/dist/jsonForm/index.d.ts +10 -3
- package/dist/jsonForm/index.js +8 -7
- package/dist/markdown/index.d.ts +75 -11
- package/dist/markdown/index.js +32 -7
- package/dist/{materializePageSection-DDzubQXo.d.ts → materializePageSection-BSMOocve.d.ts} +2 -2
- package/dist/narration/index.d.ts +16 -3
- package/dist/narration/index.js +12 -14
- package/dist/random/index.d.ts +11 -2
- package/dist/random/index.js +1 -3
- package/dist/recommend/index.d.ts +1 -1
- package/dist/recommend/index.js +2 -4
- package/dist/schemas/index.d.ts +18 -6
- package/dist/schemas/index.js +7 -6
- package/dist/spatial/index.d.ts +2 -1
- package/dist/spatial/index.js +1 -2
- package/dist/storage/index.d.ts +4 -2
- package/dist/storage/index.js +1 -2
- package/dist/{themeLibrary-B72m0W1y.d.ts → themeLibrary-BUTWjufL.d.ts} +1 -1
- package/dist/timing/index.js +2 -4
- package/dist/transform/index.d.ts +3 -3
- package/dist/transform/index.js +6 -7
- package/dist/{types-C4kiRn_k.d.ts → types-8QjefM9J.d.ts} +38 -2
- package/dist/{types-BwMPl2CB.d.ts → types-CUNc9biN.d.ts} +24 -1
- package/dist/versions/index.d.ts +14 -11
- package/dist/versions/index.js +2 -3
- package/package.json +8 -3
- package/dist/chunk-2UQOHYE2.js.map +0 -1
- package/dist/chunk-3E5F2XMR.js.map +0 -1
- package/dist/chunk-4X3JQXNM.js.map +0 -1
- package/dist/chunk-5DKBFXPY.js.map +0 -1
- package/dist/chunk-5J4HKRJF.js.map +0 -1
- package/dist/chunk-5UYI3RJB.js.map +0 -1
- package/dist/chunk-66QO7XFB.js.map +0 -1
- package/dist/chunk-AMIR72JP.js +0 -380
- package/dist/chunk-AMIR72JP.js.map +0 -1
- package/dist/chunk-DBS6RIFL.js.map +0 -1
- package/dist/chunk-DNJKBAI7.js +0 -1
- package/dist/chunk-DNJKBAI7.js.map +0 -1
- package/dist/chunk-ET53IIEP.js +0 -1
- package/dist/chunk-ET53IIEP.js.map +0 -1
- package/dist/chunk-FVTQSNR7.js.map +0 -1
- package/dist/chunk-GZY66SDN.js.map +0 -1
- package/dist/chunk-ILWDXLUK.js.map +0 -1
- package/dist/chunk-JHZWYRSW.js.map +0 -1
- package/dist/chunk-JI77MGAK.js.map +0 -1
- package/dist/chunk-JOQYPRDZ.js.map +0 -1
- package/dist/chunk-OTKVFVL6.js.map +0 -1
- package/dist/chunk-PGGGKYWG.js +0 -1
- package/dist/chunk-PGGGKYWG.js.map +0 -1
- package/dist/chunk-Q7LROV2H.js.map +0 -1
- package/dist/chunk-QE7TWGVT.js.map +0 -1
- package/dist/chunk-QUUPYOSP.js.map +0 -1
- package/dist/chunk-R2GC6RLD.js +0 -344
- package/dist/chunk-R2GC6RLD.js.map +0 -1
- package/dist/chunk-R2YZTCLO.js.map +0 -1
- package/dist/chunk-S7A5D7ZJ.js +0 -174
- package/dist/chunk-S7A5D7ZJ.js.map +0 -1
- package/dist/chunk-TUWMK62B.js.map +0 -1
- package/dist/chunk-V543AI2F.js +0 -1
- package/dist/chunk-V543AI2F.js.map +0 -1
- package/dist/chunk-VR7UPJ7C.js.map +0 -1
- package/dist/chunk-VWCJ2WXC.js.map +0 -1
- package/dist/chunk-VYFRI7R6.js.map +0 -1
- package/dist/chunk-XNLB57UD.js.map +0 -1
- package/dist/chunk-ZLQKNOZQ.js +0 -1
- package/dist/chunk-ZLQKNOZQ.js.map +0 -1
- package/dist/doc/index.js.map +0 -1
- package/dist/generate/index.js.map +0 -1
- package/dist/icons/index.js.map +0 -1
- package/dist/icons/inlineIconMarker.js.map +0 -1
- package/dist/imageEdit/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/jsonForm/index.js.map +0 -1
- package/dist/markdown/index.js.map +0 -1
- package/dist/narration/index.js.map +0 -1
- package/dist/random/index.js.map +0 -1
- package/dist/recommend/index.js.map +0 -1
- package/dist/schemas/index.js.map +0 -1
- package/dist/spatial/index.js.map +0 -1
- package/dist/storage/index.js.map +0 -1
- package/dist/timing/index.js.map +0 -1
- package/dist/transform/index.js.map +0 -1
- package/dist/versions/index.js.map +0 -1
- package/src/__tests__/animationUtils.test.ts +0 -117
- package/src/__tests__/annotationCoercion.test.ts +0 -243
- package/src/__tests__/applyNarrationTiming.test.ts +0 -190
- package/src/__tests__/applyRenderStyle.test.ts +0 -146
- package/src/__tests__/asciiDiagramBattle.test.ts +0 -246
- package/src/__tests__/asciiDiagramDetect.test.ts +0 -162
- package/src/__tests__/asciiDiagramMapping.test.ts +0 -38
- package/src/__tests__/asciiDiagramParse.test.ts +0 -233
- package/src/__tests__/asciiDiagramPipeline.test.ts +0 -273
- package/src/__tests__/asciiDiagramRender.test.ts +0 -162
- package/src/__tests__/asciiDiagramRepair.test.ts +0 -84
- package/src/__tests__/asciiTimelineDetect.test.ts +0 -157
- package/src/__tests__/asciiTimelineParse.test.ts +0 -205
- package/src/__tests__/asciiTimelinePipeline.test.ts +0 -349
- package/src/__tests__/asciiTimelineRender.test.ts +0 -376
- package/src/__tests__/atmosphereLayers.test.ts +0 -108
- package/src/__tests__/attrTokens.test.ts +0 -167
- package/src/__tests__/colorUtils.test.ts +0 -112
- package/src/__tests__/contentContainer.test.ts +0 -325
- package/src/__tests__/contentExtractor.test.ts +0 -243
- package/src/__tests__/coverBlock.test.ts +0 -310
- package/src/__tests__/customTemplateSample.test.ts +0 -144
- package/src/__tests__/customTemplatesFrontmatter.test.ts +0 -221
- package/src/__tests__/customThemesFrontmatter.test.ts +0 -146
- package/src/__tests__/dataTable.test.ts +0 -145
- package/src/__tests__/diagramBlock.test.ts +0 -122
- package/src/__tests__/diagramLayout.test.ts +0 -134
- package/src/__tests__/diagramText.test.ts +0 -26
- package/src/__tests__/docToMarkdownMedia.test.ts +0 -83
- package/src/__tests__/drawing.test.ts +0 -109
- package/src/__tests__/drawingBlock.test.ts +0 -124
- package/src/__tests__/drawingLayout.test.ts +0 -171
- package/src/__tests__/fixtures/asciiDiagramBattle.ts +0 -512
- package/src/__tests__/fixtures/asciiDiagrams.ts +0 -287
- package/src/__tests__/fixtures/asciiTimelines.ts +0 -35
- package/src/__tests__/fixtures/treeviewFixtures.ts +0 -243
- package/src/__tests__/geohash.test.ts +0 -110
- package/src/__tests__/getLayers.test.ts +0 -243
- package/src/__tests__/getLayersFallback.test.ts +0 -103
- package/src/__tests__/haversine.test.ts +0 -63
- package/src/__tests__/iconResolve.test.ts +0 -122
- package/src/__tests__/imageEditExportSvg.test.ts +0 -70
- package/src/__tests__/imageEditState.test.ts +0 -74
- package/src/__tests__/imageEditVersions.test.ts +0 -243
- package/src/__tests__/inferDocumentTitle.test.ts +0 -50
- package/src/__tests__/inlineIconMarker.test.ts +0 -36
- package/src/__tests__/inputDescriptors.test.ts +0 -162
- package/src/__tests__/jsonForm.chooseControl.test.ts +0 -86
- package/src/__tests__/jsonForm.evaluateWhen.test.ts +0 -59
- package/src/__tests__/jsonForm.inferSchema.test.ts +0 -25
- package/src/__tests__/jsonForm.pointer.test.ts +0 -149
- package/src/__tests__/jsonForm.tokens.test.ts +0 -84
- package/src/__tests__/layoutBlock.test.ts +0 -83
- package/src/__tests__/layoutLayout.test.ts +0 -169
- package/src/__tests__/localForageAdapter.test.ts +0 -155
- package/src/__tests__/majorApiTypes.test.ts +0 -18
- package/src/__tests__/markdown.test.ts +0 -1009
- package/src/__tests__/markdownIcons.test.ts +0 -104
- package/src/__tests__/markdownSanitize.test.ts +0 -81
- package/src/__tests__/markdownToDoc.test.ts +0 -957
- package/src/__tests__/matchFontFamily.test.ts +0 -114
- package/src/__tests__/materializeBlockLayers.test.ts +0 -167
- package/src/__tests__/materializePageSections.test.ts +0 -404
- package/src/__tests__/materializeTestUtils.ts +0 -17
- package/src/__tests__/mediaAnnotations.test.ts +0 -91
- package/src/__tests__/mediaSchedule.test.ts +0 -118
- package/src/__tests__/narrationAlign.test.ts +0 -150
- package/src/__tests__/narrationFeatures.test.ts +0 -71
- package/src/__tests__/narrationNuclei.test.ts +0 -45
- package/src/__tests__/narrationPacing.test.ts +0 -189
- package/src/__tests__/narrationScript.test.ts +0 -149
- package/src/__tests__/narrationSessionRepro.test.ts +0 -62
- package/src/__tests__/narrationSidecar.test.ts +0 -88
- package/src/__tests__/narrationSyllables.test.ts +0 -65
- package/src/__tests__/narrationTestSignals.ts +0 -167
- package/src/__tests__/narrationVad.test.ts +0 -66
- package/src/__tests__/pageStyle.test.ts +0 -258
- package/src/__tests__/pandocAttrParse.test.ts +0 -187
- package/src/__tests__/recommendTemplates.test.ts +0 -183
- package/src/__tests__/resolveDocTheme.test.ts +0 -69
- package/src/__tests__/rootExports.test.ts +0 -61
- package/src/__tests__/scopedContentContainer.test.ts +0 -109
- package/src/__tests__/seededRandom.test.ts +0 -142
- package/src/__tests__/shapeGeometry.test.ts +0 -138
- package/src/__tests__/shapeVocabulary.test.ts +0 -133
- package/src/__tests__/storage.test.ts +0 -60
- package/src/__tests__/structuredData.test.ts +0 -249
- package/src/__tests__/surface.test.ts +0 -68
- package/src/__tests__/templateAnnotationParse.test.ts +0 -173
- package/src/__tests__/templateInputs.test.ts +0 -69
- package/src/__tests__/templateMetadata.test.ts +0 -32
- package/src/__tests__/templates.test.ts +0 -710
- package/src/__tests__/themeCompile.test.ts +0 -225
- package/src/__tests__/themeValidator.test.ts +0 -131
- package/src/__tests__/timing.test.ts +0 -167
- package/src/__tests__/transformProvenance.test.ts +0 -160
- package/src/__tests__/transformV2.test.ts +0 -163
- package/src/__tests__/transitionNormalize.test.ts +0 -61
- package/src/__tests__/treeviewBattle.test.ts +0 -76
- package/src/__tests__/treeviewDetect.test.ts +0 -168
- package/src/__tests__/treeviewParse.test.ts +0 -118
- package/src/__tests__/treeviewPipeline.test.ts +0 -183
- package/src/__tests__/treeviewRender.test.ts +0 -91
- package/src/__tests__/validateDoc.test.ts +0 -260
- package/src/__tests__/versions.test.ts +0 -459
- package/src/doc/annotationBlocks.ts +0 -117
- package/src/doc/applyNarrationTiming.ts +0 -244
- package/src/doc/asciiDiagram/chars.ts +0 -210
- package/src/doc/asciiDiagram/detect.ts +0 -175
- package/src/doc/asciiDiagram/index.ts +0 -38
- package/src/doc/asciiDiagram/mapping.ts +0 -225
- package/src/doc/asciiDiagram/parse.ts +0 -1095
- package/src/doc/asciiDiagram/render.ts +0 -963
- package/src/doc/asciiDiagram/repair.ts +0 -400
- package/src/doc/asciiDiagram/types.ts +0 -65
- package/src/doc/asciiTimeline/detect.ts +0 -138
- package/src/doc/asciiTimeline/index.ts +0 -26
- package/src/doc/asciiTimeline/mapping.ts +0 -43
- package/src/doc/asciiTimeline/parse.ts +0 -870
- package/src/doc/asciiTimeline/render.ts +0 -427
- package/src/doc/asciiTimeline/types.ts +0 -73
- package/src/doc/asciiTimeline/wrappedFlow.ts +0 -427
- package/src/doc/audioMapping.ts +0 -442
- package/src/doc/customTemplatesFrontmatter.ts +0 -273
- package/src/doc/customThemesFrontmatter.ts +0 -95
- package/src/doc/docToMarkdown.ts +0 -284
- package/src/doc/index.ts +0 -161
- package/src/doc/markdownToDoc.ts +0 -1054
- package/src/doc/materializeBlockLayers.ts +0 -465
- package/src/doc/mediaAnnotations.ts +0 -120
- package/src/doc/page/PageSection.ts +0 -174
- package/src/doc/page/materializePageSection.ts +0 -616
- package/src/doc/page/resolvePageBlock.ts +0 -108
- package/src/doc/page/sectionExtractors.ts +0 -466
- package/src/doc/pageCss.ts +0 -628
- package/src/doc/resolveDocTheme.ts +0 -56
- package/src/doc/standaloneAnnotation.ts +0 -58
- package/src/doc/structuredData.ts +0 -301
- package/src/doc/templateInputs.ts +0 -424
- package/src/doc/templates/__tests__/customTemplate.test.ts +0 -170
- package/src/doc/templates/__tests__/customTemplateRegistry.test.ts +0 -124
- package/src/doc/templates/__tests__/listBlock.test.ts +0 -64
- package/src/doc/templates/accentImage.ts +0 -362
- package/src/doc/templates/captionUtils.ts +0 -56
- package/src/doc/templates/comparisonBar.ts +0 -173
- package/src/doc/templates/coverBlock.ts +0 -255
- package/src/doc/templates/customTemplate.ts +0 -51
- package/src/doc/templates/dataTable.ts +0 -102
- package/src/doc/templates/dateEvent.ts +0 -147
- package/src/doc/templates/definitionCard.ts +0 -140
- package/src/doc/templates/diagramBlock.ts +0 -403
- package/src/doc/templates/diagramLayout.ts +0 -159
- package/src/doc/templates/drawingBlock.ts +0 -325
- package/src/doc/templates/drawingLayout.ts +0 -539
- package/src/doc/templates/factCard.ts +0 -146
- package/src/doc/templates/fallbackBlock.ts +0 -123
- package/src/doc/templates/featureBlock.ts +0 -209
- package/src/doc/templates/fullBleedQuote.ts +0 -83
- package/src/doc/templates/imageWithCaption.ts +0 -186
- package/src/doc/templates/index.ts +0 -642
- package/src/doc/templates/inputDescriptors.ts +0 -451
- package/src/doc/templates/layoutBlock.ts +0 -43
- package/src/doc/templates/layoutLayout.ts +0 -243
- package/src/doc/templates/listBlock.ts +0 -207
- package/src/doc/templates/mapBlock.ts +0 -138
- package/src/doc/templates/metadata.ts +0 -130
- package/src/doc/templates/persistentLayers.ts +0 -526
- package/src/doc/templates/photoGrid.ts +0 -190
- package/src/doc/templates/pullQuote.ts +0 -141
- package/src/doc/templates/quoteBlock.ts +0 -141
- package/src/doc/templates/registry.ts +0 -88
- package/src/doc/templates/sectionHeader.ts +0 -120
- package/src/doc/templates/statHighlight.ts +0 -146
- package/src/doc/templates/templateNames.ts +0 -22
- package/src/doc/templates/timelineBlock.ts +0 -613
- package/src/doc/templates/titleBlock.ts +0 -150
- package/src/doc/templates/tokens/__tests__/resolveTokens.test.ts +0 -487
- package/src/doc/templates/tokens/resolveTokens.ts +0 -453
- package/src/doc/templates/treeBlock.ts +0 -131
- package/src/doc/templates/twoColumn.ts +0 -263
- package/src/doc/templates/videoPullQuote.ts +0 -142
- package/src/doc/templates/videoWithCaption.ts +0 -135
- package/src/doc/treeview/chars.ts +0 -72
- package/src/doc/treeview/detect.ts +0 -145
- package/src/doc/treeview/index.ts +0 -30
- package/src/doc/treeview/mapping.ts +0 -95
- package/src/doc/treeview/parse.ts +0 -201
- package/src/doc/treeview/render.ts +0 -41
- package/src/doc/treeview/types.ts +0 -43
- package/src/doc/utils/animationUtils.ts +0 -399
- package/src/doc/utils/applyRenderStyle.ts +0 -106
- package/src/doc/utils/diagramText.ts +0 -78
- package/src/doc/utils/imageTreatment.ts +0 -70
- package/src/doc/utils/nearest.ts +0 -59
- package/src/doc/utils/shapeGeometry.ts +0 -614
- package/src/doc/utils/themeUtils.ts +0 -243
- package/src/doc/validate.ts +0 -575
- package/src/generate/contentExtractor.ts +0 -921
- package/src/generate/index.ts +0 -18
- package/src/generate/templateMapper.ts +0 -177
- package/src/icons/iconData.ts +0 -31
- package/src/icons/index.ts +0 -26
- package/src/icons/inlineIconMarker.ts +0 -73
- package/src/icons/resolve.ts +0 -139
- package/src/imageEdit/ImageEditVersionManager.ts +0 -73
- package/src/imageEdit/export.ts +0 -410
- package/src/imageEdit/index.ts +0 -72
- package/src/imageEdit/persistence.ts +0 -113
- package/src/imageEdit/state.ts +0 -112
- package/src/imageEdit/versionPaths.ts +0 -44
- package/src/imageEdit/versions.ts +0 -152
- package/src/index.ts +0 -15
- package/src/internal/immutable.ts +0 -58
- package/src/jsonForm/chooseControl.ts +0 -88
- package/src/jsonForm/evaluateWhen.ts +0 -59
- package/src/jsonForm/index.ts +0 -32
- package/src/jsonForm/inferSchema.ts +0 -25
- package/src/jsonForm/pointer.ts +0 -154
- package/src/jsonForm/tokens.ts +0 -78
- package/src/jsonForm/types.ts +0 -167
- package/src/markdown/annotationCoercion.ts +0 -295
- package/src/markdown/attrTokens.ts +0 -243
- package/src/markdown/convert.ts +0 -1353
- package/src/markdown/htmlParse.ts +0 -212
- package/src/markdown/index.ts +0 -152
- package/src/markdown/parse.ts +0 -103
- package/src/markdown/sanitize.ts +0 -318
- package/src/markdown/stringify.ts +0 -207
- package/src/markdown/types.ts +0 -710
- package/src/markdown/utils.ts +0 -459
- package/src/narration/align.ts +0 -514
- package/src/narration/features.ts +0 -231
- package/src/narration/index.ts +0 -86
- package/src/narration/nuclei.ts +0 -118
- package/src/narration/pacing.ts +0 -211
- package/src/narration/script.ts +0 -239
- package/src/narration/session.ts +0 -100
- package/src/narration/sidecar.ts +0 -187
- package/src/narration/syllables.ts +0 -85
- package/src/narration/trace.ts +0 -50
- package/src/narration/types.ts +0 -299
- package/src/narration/vad.ts +0 -131
- package/src/ngeohash.d.ts +0 -11
- package/src/random/SeededRandom.ts +0 -127
- package/src/random/index.ts +0 -1
- package/src/recommend/index.ts +0 -16
- package/src/recommend/numberHighlight.ts +0 -25
- package/src/recommend/templates.ts +0 -393
- package/src/schemas/BlockTemplates.ts +0 -1046
- package/src/schemas/CustomTemplates.ts +0 -126
- package/src/schemas/Doc.ts +0 -1073
- package/src/schemas/ImageEditDoc.ts +0 -102
- package/src/schemas/LayoutStrategy.ts +0 -178
- package/src/schemas/Media.ts +0 -179
- package/src/schemas/MediaProvider.ts +0 -70
- package/src/schemas/PageStyle.ts +0 -213
- package/src/schemas/Theme.ts +0 -413
- package/src/schemas/Transitions.ts +0 -224
- package/src/schemas/Types.ts +0 -15
- package/src/schemas/Viewport.ts +0 -91
- package/src/schemas/colorUtils.ts +0 -219
- package/src/schemas/fontStacks.ts +0 -339
- package/src/schemas/index.ts +0 -31
- package/src/schemas/pageStyleDefaults.ts +0 -204
- package/src/schemas/themeCompile.ts +0 -244
- package/src/schemas/themeConstants.ts +0 -2
- package/src/schemas/themeLibrary.ts +0 -60
- package/src/schemas/themeValidator.ts +0 -609
- package/src/schemas/themes/bold.json +0 -77
- package/src/schemas/themes/cinematic.json +0 -143
- package/src/schemas/themes/documentary.json +0 -125
- package/src/schemas/themes/gezellig.json +0 -123
- package/src/schemas/themes/index.ts +0 -53
- package/src/schemas/themes/magazine.json +0 -126
- package/src/schemas/themes/minimalist.json +0 -74
- package/src/schemas/themes/morning-light.json +0 -117
- package/src/schemas/themes/standard-dark.json +0 -109
- package/src/schemas/themes/standard.json +0 -98
- package/src/schemas/themes/tech-dark.json +0 -143
- package/src/schemas/themes/warm-earth.json +0 -74
- package/src/spatial/Geohash.ts +0 -196
- package/src/spatial/Haversine.ts +0 -59
- package/src/spatial/index.ts +0 -2
- package/src/storage/ContentContainer.ts +0 -220
- package/src/storage/LocalForageAdapter.ts +0 -103
- package/src/storage/LocalStorageAdapter.ts +0 -57
- package/src/storage/MediaProviderFromContainer.ts +0 -92
- package/src/storage/MemoryStorageAdapter.ts +0 -37
- package/src/storage/ScopedContentContainer.ts +0 -143
- package/src/storage/Storage.ts +0 -28
- package/src/storage/index.ts +0 -9
- package/src/timing/index.ts +0 -17
- package/src/timing/narrationTiming.ts +0 -220
- package/src/timing/readingTime.ts +0 -94
- package/src/transform/applyTransform.ts +0 -122
- package/src/transform/blockAnalyzer.ts +0 -181
- package/src/transform/index.ts +0 -23
- package/src/transform/registry.ts +0 -217
- package/src/transform/styles/dataDriven.ts +0 -18
- package/src/transform/styles/documentary.ts +0 -18
- package/src/transform/styles/index.ts +0 -5
- package/src/transform/styles/magazine.ts +0 -19
- package/src/transform/styles/minimal.ts +0 -18
- package/src/transform/styles/narrative.ts +0 -19
- package/src/transform/templateSelector.ts +0 -389
- package/src/transform/timingAllocator.ts +0 -257
- package/src/transform/types.ts +0 -158
- package/src/versions/DocumentVersionManager.ts +0 -70
- package/src/versions/gitignore.ts +0 -34
- package/src/versions/index.ts +0 -56
- package/src/versions/operations.ts +0 -144
- package/src/versions/paths.ts +0 -51
- package/src/versions/snapshotStore.ts +0 -202
- package/src/versions/timestamp.ts +0 -48
- package/src/versions/types.ts +0 -93
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
anchorPoint,
|
|
3
|
+
base64ToUtf8,
|
|
3
4
|
connectorPath,
|
|
4
5
|
lineStyleDasharray,
|
|
5
6
|
shapePath,
|
|
6
7
|
snapEndpoints
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-PUS54YU6.js";
|
|
8
9
|
import {
|
|
9
10
|
detectAsciiDiagram,
|
|
10
11
|
detectAsciiTimeline,
|
|
@@ -19,7 +20,7 @@ import {
|
|
|
19
20
|
parseAsciiTimeline,
|
|
20
21
|
pickAutoTemplate,
|
|
21
22
|
profileBlockContents
|
|
22
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-QWCFK5FN.js";
|
|
23
24
|
import {
|
|
24
25
|
DEFAULT_THEME,
|
|
25
26
|
FRONTMATTER_CUSTOM_TEMPLATES_KEY,
|
|
@@ -30,16 +31,17 @@ import {
|
|
|
30
31
|
resolveFontFamily,
|
|
31
32
|
validateTheme,
|
|
32
33
|
withAlpha
|
|
33
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-C33GTPUZ.js";
|
|
34
35
|
import {
|
|
35
36
|
VIEWPORT_PRESETS,
|
|
36
37
|
cloneData,
|
|
37
38
|
createTemplateContext,
|
|
38
39
|
getTwoColumnPositions,
|
|
40
|
+
getViewportOrientation,
|
|
39
41
|
isPersistentLayerTemplate,
|
|
40
42
|
isTemplateBlock,
|
|
41
43
|
scaledFontSize2 as scaledFontSize
|
|
42
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-BAOV476U.js";
|
|
43
45
|
import {
|
|
44
46
|
KNOWN_BLOCK_META_KEYS,
|
|
45
47
|
coerceAnnotationValues,
|
|
@@ -48,25 +50,25 @@ import {
|
|
|
48
50
|
parseTimeSeconds,
|
|
49
51
|
splitKeyValueToken,
|
|
50
52
|
tokenizeAttrTokens
|
|
51
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-ZQKZSJAX.js";
|
|
52
54
|
import {
|
|
53
55
|
extractPlainText,
|
|
54
56
|
readFrontmatterThemeId,
|
|
55
57
|
walkMarkdownTree
|
|
56
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-BCCXTMN5.js";
|
|
57
59
|
import {
|
|
58
60
|
resolveBlockTransition
|
|
59
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-4VOD55SX.js";
|
|
60
62
|
import {
|
|
61
63
|
estimateReadingTime
|
|
62
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-XOFT65EX.js";
|
|
63
65
|
import {
|
|
64
66
|
estimateSpokenWordCount
|
|
65
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-67L6WRJN.js";
|
|
66
68
|
import {
|
|
67
69
|
SeededRandom,
|
|
68
70
|
hashString
|
|
69
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-XRW6P7IF.js";
|
|
70
72
|
|
|
71
73
|
// src/doc/templates/persistentLayers.ts
|
|
72
74
|
var GRADIENT_PRESETS = {
|
|
@@ -198,14 +200,19 @@ function expandTitleCaption(config) {
|
|
|
198
200
|
const isBottom = config.position.includes("bottom");
|
|
199
201
|
const isLeft = config.position.includes("left");
|
|
200
202
|
const pad = 3;
|
|
203
|
+
const thumbPad = 1.5;
|
|
201
204
|
const pillHeight = hasSubtitle ? "15%" : "7%";
|
|
202
205
|
const bgYPos = isBottom ? hasSubtitle ? "78%" : "84%" : "2%";
|
|
203
|
-
const
|
|
204
|
-
const
|
|
206
|
+
const pillW = config.showThumbnail ? 30 : 28;
|
|
207
|
+
const pillX = isLeft ? pad : 100 - pad - pillW;
|
|
208
|
+
const bgXPos = `${pillX}%`;
|
|
209
|
+
const thumbWNum = hasSubtitle ? 6 : 5;
|
|
210
|
+
const thumbW = `${thumbWNum}%`;
|
|
205
211
|
const thumbH = hasSubtitle ? "10%" : "5%";
|
|
206
|
-
const
|
|
207
|
-
const
|
|
208
|
-
const
|
|
212
|
+
const innerX = pillX + thumbPad;
|
|
213
|
+
const innerW = pillW - thumbPad * 2;
|
|
214
|
+
const textX = config.showThumbnail && isLeft ? `${innerX + thumbWNum + thumbPad}%` : `${innerX}%`;
|
|
215
|
+
const textWidth = config.showThumbnail ? `${innerW - thumbWNum - thumbPad}%` : `${innerW}%`;
|
|
209
216
|
const titleYPos = isBottom ? hasSubtitle ? "80%" : "86%" : "4%";
|
|
210
217
|
layers.push({
|
|
211
218
|
type: "shape",
|
|
@@ -218,12 +225,12 @@ function expandTitleCaption(config) {
|
|
|
218
225
|
position: {
|
|
219
226
|
x: bgXPos,
|
|
220
227
|
y: bgYPos,
|
|
221
|
-
width:
|
|
228
|
+
width: `${pillW}%`,
|
|
222
229
|
height: pillHeight
|
|
223
230
|
}
|
|
224
231
|
});
|
|
225
232
|
if (config.showThumbnail && config.thumbnailSrc) {
|
|
226
|
-
const thumbX = isLeft ? `${
|
|
233
|
+
const thumbX = isLeft ? `${innerX}%` : `${pillX + pillW - thumbPad - thumbWNum}%`;
|
|
227
234
|
const thumbY = isBottom ? hasSubtitle ? `${78 + thumbPad}%` : "85%" : "3%";
|
|
228
235
|
layers.push({
|
|
229
236
|
type: "image",
|
|
@@ -620,84 +627,6 @@ function titleBlock(input, context) {
|
|
|
620
627
|
return layers;
|
|
621
628
|
}
|
|
622
629
|
|
|
623
|
-
// src/doc/templates/sectionHeader.ts
|
|
624
|
-
function sectionHeader(input, context) {
|
|
625
|
-
const { title = "", colorScheme = "blue", imageSrc, imageAlt, ambientMotion } = input;
|
|
626
|
-
const { theme, layout } = context;
|
|
627
|
-
const treatment = themedImageTreatment(context, input.imageTreatment);
|
|
628
|
-
const colors = resolveColorScheme(context, colorScheme);
|
|
629
|
-
const titleFontSize = themedFontSize(84, context, true);
|
|
630
|
-
const layers = [];
|
|
631
|
-
if (imageSrc) {
|
|
632
|
-
layers.push({
|
|
633
|
-
type: "image",
|
|
634
|
-
id: "bg-image",
|
|
635
|
-
content: {
|
|
636
|
-
src: imageSrc,
|
|
637
|
-
alt: imageAlt || title,
|
|
638
|
-
fit: "cover",
|
|
639
|
-
...treatment ? { treatment } : {}
|
|
640
|
-
},
|
|
641
|
-
position: { x: 0, y: 0, width: "100%", height: "100%" },
|
|
642
|
-
animation: ambientMotion ? { type: ambientMotion, duration: 8 } : { type: "slowZoom", duration: 8, direction: "in" }
|
|
643
|
-
});
|
|
644
|
-
layers.push({
|
|
645
|
-
type: "shape",
|
|
646
|
-
id: "overlay",
|
|
647
|
-
content: {
|
|
648
|
-
shape: "rect",
|
|
649
|
-
fill: themedScrim(context)
|
|
650
|
-
},
|
|
651
|
-
position: { x: 0, y: 0, width: "100%", height: "100%" }
|
|
652
|
-
});
|
|
653
|
-
} else {
|
|
654
|
-
layers.push({
|
|
655
|
-
type: "shape",
|
|
656
|
-
id: "bg",
|
|
657
|
-
content: {
|
|
658
|
-
shape: "rect",
|
|
659
|
-
fill: colors.bg
|
|
660
|
-
},
|
|
661
|
-
position: { x: 0, y: 0, width: "100%", height: "100%" }
|
|
662
|
-
});
|
|
663
|
-
layers.push({
|
|
664
|
-
type: "shape",
|
|
665
|
-
id: "line-top",
|
|
666
|
-
content: { shape: "rect", fill: `${colors.text}33` },
|
|
667
|
-
position: { x: "50%", y: "40%", width: "20%", height: "2px", anchor: "center" }
|
|
668
|
-
});
|
|
669
|
-
layers.push({
|
|
670
|
-
type: "shape",
|
|
671
|
-
id: "line-bottom",
|
|
672
|
-
content: { shape: "rect", fill: `${colors.text}33` },
|
|
673
|
-
position: { x: "50%", y: "60%", width: "20%", height: "2px", anchor: "center" }
|
|
674
|
-
});
|
|
675
|
-
}
|
|
676
|
-
layers.push({
|
|
677
|
-
type: "text",
|
|
678
|
-
id: "title",
|
|
679
|
-
content: {
|
|
680
|
-
text: title,
|
|
681
|
-
style: {
|
|
682
|
-
fontSize: titleFontSize,
|
|
683
|
-
fontFamily: getThemeFont(context, "title"),
|
|
684
|
-
fontWeight: "bold",
|
|
685
|
-
color: imageSrc ? theme.colors.text : colors.text,
|
|
686
|
-
textAlign: "center",
|
|
687
|
-
shadow: shouldUseShadow(context)
|
|
688
|
-
}
|
|
689
|
-
},
|
|
690
|
-
position: {
|
|
691
|
-
x: "50%",
|
|
692
|
-
y: "50%",
|
|
693
|
-
anchor: "center",
|
|
694
|
-
width: layout.maxTextWidth
|
|
695
|
-
},
|
|
696
|
-
animation: themedEntrance(context, "text", { type: "fadeIn", duration: 1.5 })
|
|
697
|
-
});
|
|
698
|
-
return layers;
|
|
699
|
-
}
|
|
700
|
-
|
|
701
630
|
// src/doc/templates/accentImage.ts
|
|
702
631
|
var PERCENTAGE_RE = /^(\d+(?:\.\d+)?)\s*%?$/;
|
|
703
632
|
var DEFAULT_LAYOUT = {
|
|
@@ -928,6 +857,92 @@ function adjustY(originalY, layout) {
|
|
|
928
857
|
return yStr;
|
|
929
858
|
}
|
|
930
859
|
|
|
860
|
+
// src/doc/templates/sectionHeader.ts
|
|
861
|
+
function sectionHeader(input, context) {
|
|
862
|
+
const { title = "", colorScheme = "blue", imageSrc, imageAlt, ambientMotion } = input;
|
|
863
|
+
const { theme, layout } = context;
|
|
864
|
+
const treatment = themedImageTreatment(context, input.imageTreatment);
|
|
865
|
+
const colors = resolveColorScheme(context, colorScheme);
|
|
866
|
+
const titleFontSize = themedFontSize(84, context, true);
|
|
867
|
+
const layers = [];
|
|
868
|
+
if (imageSrc) {
|
|
869
|
+
layers.push({
|
|
870
|
+
type: "image",
|
|
871
|
+
id: "bg-image",
|
|
872
|
+
content: {
|
|
873
|
+
src: imageSrc,
|
|
874
|
+
alt: imageAlt || title,
|
|
875
|
+
fit: "cover",
|
|
876
|
+
...treatment ? { treatment } : {}
|
|
877
|
+
},
|
|
878
|
+
position: { x: 0, y: 0, width: "100%", height: "100%" },
|
|
879
|
+
// Route through mapAmbientMotion like every other image template: the
|
|
880
|
+
// authored vocabulary (`zoomIn`/`panLeft`/…) are NOT AnimationTypes, so
|
|
881
|
+
// passing them raw produced an unknown animation here while the same
|
|
882
|
+
// input animated correctly on imageWithCaption/coverBlock/accentImage.
|
|
883
|
+
animation: mapAmbientMotion(ambientMotion, 8) ?? {
|
|
884
|
+
type: "slowZoom",
|
|
885
|
+
duration: 8,
|
|
886
|
+
direction: "in"
|
|
887
|
+
}
|
|
888
|
+
});
|
|
889
|
+
layers.push({
|
|
890
|
+
type: "shape",
|
|
891
|
+
id: "overlay",
|
|
892
|
+
content: {
|
|
893
|
+
shape: "rect",
|
|
894
|
+
fill: themedScrim(context)
|
|
895
|
+
},
|
|
896
|
+
position: { x: 0, y: 0, width: "100%", height: "100%" }
|
|
897
|
+
});
|
|
898
|
+
} else {
|
|
899
|
+
layers.push({
|
|
900
|
+
type: "shape",
|
|
901
|
+
id: "bg",
|
|
902
|
+
content: {
|
|
903
|
+
shape: "rect",
|
|
904
|
+
fill: colors.bg
|
|
905
|
+
},
|
|
906
|
+
position: { x: 0, y: 0, width: "100%", height: "100%" }
|
|
907
|
+
});
|
|
908
|
+
layers.push({
|
|
909
|
+
type: "shape",
|
|
910
|
+
id: "line-top",
|
|
911
|
+
content: { shape: "rect", fill: withAlpha(colors.text, 0.2) },
|
|
912
|
+
position: { x: "50%", y: "40%", width: "20%", height: "2px", anchor: "center" }
|
|
913
|
+
});
|
|
914
|
+
layers.push({
|
|
915
|
+
type: "shape",
|
|
916
|
+
id: "line-bottom",
|
|
917
|
+
content: { shape: "rect", fill: withAlpha(colors.text, 0.2) },
|
|
918
|
+
position: { x: "50%", y: "60%", width: "20%", height: "2px", anchor: "center" }
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
layers.push({
|
|
922
|
+
type: "text",
|
|
923
|
+
id: "title",
|
|
924
|
+
content: {
|
|
925
|
+
text: title,
|
|
926
|
+
style: {
|
|
927
|
+
fontSize: titleFontSize,
|
|
928
|
+
fontFamily: getThemeFont(context, "title"),
|
|
929
|
+
fontWeight: "bold",
|
|
930
|
+
color: imageSrc ? theme.colors.text : colors.text,
|
|
931
|
+
textAlign: "center",
|
|
932
|
+
shadow: shouldUseShadow(context)
|
|
933
|
+
}
|
|
934
|
+
},
|
|
935
|
+
position: {
|
|
936
|
+
x: "50%",
|
|
937
|
+
y: "50%",
|
|
938
|
+
anchor: "center",
|
|
939
|
+
width: layout.maxTextWidth
|
|
940
|
+
},
|
|
941
|
+
animation: themedEntrance(context, "text", { type: "fadeIn", duration: 1.5 })
|
|
942
|
+
});
|
|
943
|
+
return layers;
|
|
944
|
+
}
|
|
945
|
+
|
|
931
946
|
// src/doc/templates/statHighlight.ts
|
|
932
947
|
function statHighlight(input, context) {
|
|
933
948
|
const { stat, description, detail, colorScheme = "blue", accentImage } = input;
|
|
@@ -1020,10 +1035,11 @@ function statHighlight(input, context) {
|
|
|
1020
1035
|
|
|
1021
1036
|
// src/doc/templates/quoteBlock.ts
|
|
1022
1037
|
function quoteBlock(input, context) {
|
|
1023
|
-
const { quote, attribution, accentImage } = input;
|
|
1038
|
+
const { title, quote, attribution, accentImage } = input;
|
|
1024
1039
|
const { theme, viewport } = context;
|
|
1025
1040
|
const accentLayout = accentImage ? getAccentLayout(accentImage.position) : DEFAULT_LAYOUT;
|
|
1026
1041
|
const quoteFontSize = themedFontSize(48, context, true);
|
|
1042
|
+
const titleFontSize = themedFontSize(34, context, true);
|
|
1027
1043
|
const attrFontSize = themedFontSize(26, context, false);
|
|
1028
1044
|
const quoteLineHeight = Math.max(theme.typography.titleLineHeight ?? 1.4, 1.25);
|
|
1029
1045
|
const decorativeQuoteFontSize = themedFontSize(280, context, true);
|
|
@@ -1037,6 +1053,30 @@ function quoteBlock(input, context) {
|
|
|
1037
1053
|
)
|
|
1038
1054
|
);
|
|
1039
1055
|
}
|
|
1056
|
+
if (title) {
|
|
1057
|
+
layers.push({
|
|
1058
|
+
type: "text",
|
|
1059
|
+
id: "quote-title",
|
|
1060
|
+
content: {
|
|
1061
|
+
text: title,
|
|
1062
|
+
style: {
|
|
1063
|
+
fontSize: titleFontSize,
|
|
1064
|
+
fontFamily: getThemeFont(context, "body"),
|
|
1065
|
+
fontWeight: "bold",
|
|
1066
|
+
color: theme.colors.textMuted,
|
|
1067
|
+
textAlign: "center",
|
|
1068
|
+
shadow: shouldUseShadow(context)
|
|
1069
|
+
}
|
|
1070
|
+
},
|
|
1071
|
+
position: {
|
|
1072
|
+
x: accentLayout.textCenterX,
|
|
1073
|
+
y: adjustY("14%", accentLayout),
|
|
1074
|
+
width: accentLayout.textWidth,
|
|
1075
|
+
anchor: "center"
|
|
1076
|
+
},
|
|
1077
|
+
animation: { type: "fadeIn", duration: 0.8 }
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1040
1080
|
layers.push({
|
|
1041
1081
|
type: "text",
|
|
1042
1082
|
id: "deco-quote",
|
|
@@ -1055,7 +1095,7 @@ function quoteBlock(input, context) {
|
|
|
1055
1095
|
anchor: "center"
|
|
1056
1096
|
}
|
|
1057
1097
|
});
|
|
1058
|
-
const quoteYPct = attribution ? 45 : 50;
|
|
1098
|
+
const quoteYPct = attribution ? 45 : title ? 52 : 50;
|
|
1059
1099
|
layers.push({
|
|
1060
1100
|
type: "text",
|
|
1061
1101
|
id: "quote",
|
|
@@ -1520,7 +1560,7 @@ function imageWithCaption(input, context) {
|
|
|
1520
1560
|
imageSrc,
|
|
1521
1561
|
imageAlt,
|
|
1522
1562
|
caption: rawCaption,
|
|
1523
|
-
captionPosition
|
|
1563
|
+
captionPosition = "bottom",
|
|
1524
1564
|
ambientMotion,
|
|
1525
1565
|
isTitle,
|
|
1526
1566
|
subtitle,
|
|
@@ -1612,6 +1652,8 @@ function imageWithCaption(input, context) {
|
|
|
1612
1652
|
return layers;
|
|
1613
1653
|
}
|
|
1614
1654
|
if (caption) {
|
|
1655
|
+
const captionBgY = captionPosition === "top" ? "7%" : captionPosition === "center" ? "42%" : "68%";
|
|
1656
|
+
const captionY = captionPosition === "top" ? "13%" : captionPosition === "center" ? "48%" : "74%";
|
|
1615
1657
|
layers.push({
|
|
1616
1658
|
type: "shape",
|
|
1617
1659
|
id: "caption-gradient",
|
|
@@ -1621,7 +1663,7 @@ function imageWithCaption(input, context) {
|
|
|
1621
1663
|
},
|
|
1622
1664
|
position: {
|
|
1623
1665
|
x: 0,
|
|
1624
|
-
y:
|
|
1666
|
+
y: captionBgY,
|
|
1625
1667
|
width: "100%",
|
|
1626
1668
|
height: "16%"
|
|
1627
1669
|
}
|
|
@@ -1643,7 +1685,7 @@ function imageWithCaption(input, context) {
|
|
|
1643
1685
|
},
|
|
1644
1686
|
position: {
|
|
1645
1687
|
x: "50%",
|
|
1646
|
-
y:
|
|
1688
|
+
y: captionY,
|
|
1647
1689
|
anchor: "center",
|
|
1648
1690
|
width: "78%"
|
|
1649
1691
|
},
|
|
@@ -2158,6 +2200,8 @@ function getGridPositions(count, gridHeight, stacked) {
|
|
|
2158
2200
|
const halfW = 50 - GAP / 2;
|
|
2159
2201
|
const halfH = gridHeight / 2 - GAP / 2;
|
|
2160
2202
|
switch (count) {
|
|
2203
|
+
case 1:
|
|
2204
|
+
return [{ x: 0, y: 0, w: 100, h: gridHeight }];
|
|
2161
2205
|
case 2:
|
|
2162
2206
|
if (stacked) {
|
|
2163
2207
|
return [
|
|
@@ -2322,12 +2366,14 @@ function comparisonBar(input, context) {
|
|
|
2322
2366
|
const barHeight = 6;
|
|
2323
2367
|
const topBarY = 36;
|
|
2324
2368
|
const bottomBarY = 58;
|
|
2325
|
-
const
|
|
2369
|
+
const leftExtent = Math.max(0, leftValue);
|
|
2370
|
+
const rightExtent = Math.max(0, rightValue);
|
|
2371
|
+
const maxValue = Math.max(leftExtent, rightExtent, 1);
|
|
2326
2372
|
const longestLabelPx = Math.max(leftDisplay.length, rightDisplay.length) * valueFontSize * 0.58;
|
|
2327
2373
|
const labelWidthPct = longestLabelPx / viewport.width * 100;
|
|
2328
2374
|
const maxBarWidth = Math.max(20, Math.min(65, 96 - barStartX - labelWidthPct - 2));
|
|
2329
|
-
const leftBarWidth =
|
|
2330
|
-
const rightBarWidth =
|
|
2375
|
+
const leftBarWidth = leftExtent / maxValue * maxBarWidth;
|
|
2376
|
+
const rightBarWidth = rightExtent / maxValue * maxBarWidth;
|
|
2331
2377
|
return [
|
|
2332
2378
|
// Background
|
|
2333
2379
|
{
|
|
@@ -2461,7 +2507,10 @@ function pullQuote(input, context) {
|
|
|
2461
2507
|
...treatment ? { treatment } : {}
|
|
2462
2508
|
},
|
|
2463
2509
|
position: { x: 0, y: 0, width: "100%", height: "100%" },
|
|
2464
|
-
|
|
2510
|
+
// Same authored `ambientMotion` vocabulary as every other image
|
|
2511
|
+
// template — map it to a real Ken Burns animation rather than passing
|
|
2512
|
+
// the token straight through as an animation type.
|
|
2513
|
+
animation: mapAmbientMotion(ambientMotion, 15)
|
|
2465
2514
|
},
|
|
2466
2515
|
// Dark overlay for text readability
|
|
2467
2516
|
{
|
|
@@ -2553,7 +2602,7 @@ function videoWithCaption(input, context) {
|
|
|
2553
2602
|
videoSrc,
|
|
2554
2603
|
posterSrc,
|
|
2555
2604
|
videoAlt,
|
|
2556
|
-
clipStart,
|
|
2605
|
+
clipStart = 0,
|
|
2557
2606
|
clipEnd,
|
|
2558
2607
|
sourceDuration,
|
|
2559
2608
|
caption: rawCaption,
|
|
@@ -2563,6 +2612,7 @@ function videoWithCaption(input, context) {
|
|
|
2563
2612
|
} = input;
|
|
2564
2613
|
const caption = rawCaption ? cleanCaption(rawCaption) : rawCaption;
|
|
2565
2614
|
const { theme } = context;
|
|
2615
|
+
const resolvedClipEnd = Math.max(clipStart, clipEnd ?? clipStart + Math.max(0, input.duration));
|
|
2566
2616
|
const captionFontSize = themedFontSize(30, context, false);
|
|
2567
2617
|
const creditFontSize = themedFontSize(16, context, false);
|
|
2568
2618
|
const layers = [
|
|
@@ -2576,7 +2626,7 @@ function videoWithCaption(input, context) {
|
|
|
2576
2626
|
alt: videoAlt,
|
|
2577
2627
|
fit: "cover",
|
|
2578
2628
|
clipStart,
|
|
2579
|
-
clipEnd,
|
|
2629
|
+
clipEnd: resolvedClipEnd,
|
|
2580
2630
|
sourceDuration,
|
|
2581
2631
|
credit: videoCredit,
|
|
2582
2632
|
license: videoLicense
|
|
@@ -4920,6 +4970,7 @@ var TEMPLATE_INPUT_DESCRIPTORS = {
|
|
|
4920
4970
|
{ key: "colorScheme", description: "Color scheme for the stat", valueHint: COLOR_SCHEME_HINT }
|
|
4921
4971
|
],
|
|
4922
4972
|
quote: [
|
|
4973
|
+
{ key: "title", description: "Optional heading above the quote" },
|
|
4923
4974
|
{ key: "quote", description: "The quote text" },
|
|
4924
4975
|
{ key: "attribution", description: "Attribution (author, source)" }
|
|
4925
4976
|
],
|
|
@@ -5227,7 +5278,7 @@ function fallbackBlockLayers(block, context, notice) {
|
|
|
5227
5278
|
style: {
|
|
5228
5279
|
fontSize: themedFontSize(18, context),
|
|
5229
5280
|
fontFamily: getThemeFont(context, "body"),
|
|
5230
|
-
color:
|
|
5281
|
+
color: withAlpha(colors.text, 0.6),
|
|
5231
5282
|
textAlign: "center"
|
|
5232
5283
|
}
|
|
5233
5284
|
},
|
|
@@ -5242,1287 +5293,2111 @@ function extractBodyText(block) {
|
|
|
5242
5293
|
return `${text.slice(0, MAX_BODY_CHARS).trimEnd()}\u2026`;
|
|
5243
5294
|
}
|
|
5244
5295
|
|
|
5245
|
-
// src/doc/
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5296
|
+
// src/doc/asciiDiagram/types.ts
|
|
5297
|
+
var ASCII_CHAR_W = 14;
|
|
5298
|
+
var ASCII_CHAR_H = 28;
|
|
5299
|
+
|
|
5300
|
+
// src/doc/asciiDiagram/mapping.ts
|
|
5301
|
+
function asciiCellToCanvas(col, row) {
|
|
5302
|
+
return { x: col * ASCII_CHAR_W, y: row * ASCII_CHAR_H };
|
|
5249
5303
|
}
|
|
5250
|
-
function
|
|
5251
|
-
const theme = options.theme ?? DEFAULT_THEME;
|
|
5252
|
-
const viewport = options.viewport ?? VIEWPORT_PRESETS.landscape;
|
|
5253
|
-
const blockIndex = options.blockIndex ?? 0;
|
|
5254
|
-
const totalBlocks = options.totalBlocks ?? 1;
|
|
5255
|
-
const effectivePersistentLayers = options.persistentLayers === false ? void 0 : options.persistentLayers ?? theme.persistentLayers;
|
|
5256
|
-
const existingLayers = block.layers;
|
|
5257
|
-
if (existingLayers && existingLayers.length > 0 && !isTemplateBlock(block)) {
|
|
5258
|
-
const layers = appendMermaidLayers(cloneData(existingLayers), block, theme, viewport);
|
|
5259
|
-
return {
|
|
5260
|
-
layers: injectPersistentLayers(
|
|
5261
|
-
layers,
|
|
5262
|
-
block,
|
|
5263
|
-
theme,
|
|
5264
|
-
effectivePersistentLayers,
|
|
5265
|
-
runtime.expandedPersistentLayers
|
|
5266
|
-
),
|
|
5267
|
-
source: "authored"
|
|
5268
|
-
};
|
|
5269
|
-
}
|
|
5270
|
-
if (!isTemplateBlock(block)) {
|
|
5271
|
-
const layers = appendMermaidLayers([], block, theme, viewport);
|
|
5272
|
-
return {
|
|
5273
|
-
layers: injectPersistentLayers(
|
|
5274
|
-
layers,
|
|
5275
|
-
block,
|
|
5276
|
-
theme,
|
|
5277
|
-
effectivePersistentLayers,
|
|
5278
|
-
runtime.expandedPersistentLayers
|
|
5279
|
-
),
|
|
5280
|
-
source: layers.length > 0 ? "rich-content" : "empty"
|
|
5281
|
-
};
|
|
5282
|
-
}
|
|
5283
|
-
const context = runtime.templateContext ? cloneData(runtime.templateContext) : createTemplateContext(theme, blockIndex, totalBlocks, viewport);
|
|
5284
|
-
context.block = cloneData(block);
|
|
5285
|
-
const execution = executeTemplateMaterialization(block, context, runtime.registry);
|
|
5286
|
-
if (execution.status === "ok") {
|
|
5287
|
-
const styledLayers = runtime.applyRenderStyle !== false ? applyRenderStyleToLayers(execution.layers, block, theme) : execution.layers;
|
|
5288
|
-
const layers = appendMermaidLayers(styledLayers, block, theme, viewport);
|
|
5289
|
-
return {
|
|
5290
|
-
layers: injectPersistentLayers(
|
|
5291
|
-
layers,
|
|
5292
|
-
block,
|
|
5293
|
-
theme,
|
|
5294
|
-
effectivePersistentLayers,
|
|
5295
|
-
runtime.expandedPersistentLayers
|
|
5296
|
-
),
|
|
5297
|
-
source: "template"
|
|
5298
|
-
};
|
|
5299
|
-
}
|
|
5300
|
-
const diagnostic = toLayerMaterializationDiagnostic(block.template, execution);
|
|
5301
|
-
if ((options.failureMode ?? "fallback") === "empty") {
|
|
5302
|
-
const layers = appendMermaidLayers([], block, theme, viewport);
|
|
5303
|
-
return {
|
|
5304
|
-
layers: injectPersistentLayers(
|
|
5305
|
-
layers,
|
|
5306
|
-
block,
|
|
5307
|
-
theme,
|
|
5308
|
-
effectivePersistentLayers,
|
|
5309
|
-
runtime.expandedPersistentLayers
|
|
5310
|
-
),
|
|
5311
|
-
source: layers.length > 0 ? "rich-content" : "empty",
|
|
5312
|
-
diagnostic
|
|
5313
|
-
};
|
|
5314
|
-
}
|
|
5315
|
-
const fallbackLayers = appendMermaidLayers(
|
|
5316
|
-
fallbackBlockLayers(block, context, diagnostic.message),
|
|
5317
|
-
block,
|
|
5318
|
-
theme,
|
|
5319
|
-
viewport
|
|
5320
|
-
);
|
|
5304
|
+
function canvasToAsciiCell(x, y) {
|
|
5321
5305
|
return {
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
block,
|
|
5325
|
-
theme,
|
|
5326
|
-
effectivePersistentLayers,
|
|
5327
|
-
runtime.expandedPersistentLayers
|
|
5328
|
-
),
|
|
5329
|
-
source: "fallback",
|
|
5330
|
-
diagnostic
|
|
5306
|
+
col: Math.max(0, Math.round(x / ASCII_CHAR_W)),
|
|
5307
|
+
row: Math.max(0, Math.round(y / ASCII_CHAR_H))
|
|
5331
5308
|
};
|
|
5332
5309
|
}
|
|
5333
|
-
function
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
const
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
let y = resolvePositionValue(position.y, viewport.height);
|
|
5351
|
-
const anchor = position.anchor ?? "top-left";
|
|
5352
|
-
if (anchor === "center") {
|
|
5353
|
-
x -= width / 2;
|
|
5354
|
-
y -= height / 2;
|
|
5355
|
-
} else {
|
|
5356
|
-
if (anchor.endsWith("right")) x -= width;
|
|
5357
|
-
if (anchor.startsWith("bottom")) y -= height;
|
|
5358
|
-
}
|
|
5359
|
-
return { x, y, width, height };
|
|
5360
|
-
}
|
|
5361
|
-
function overlapArea(a, b) {
|
|
5362
|
-
const width = Math.max(0, Math.min(a.x + a.width, b.x + b.width) - Math.max(a.x, b.x));
|
|
5363
|
-
const height = Math.max(0, Math.min(a.y + a.height, b.y + b.height) - Math.max(a.y, b.y));
|
|
5364
|
-
return width * height;
|
|
5365
|
-
}
|
|
5366
|
-
function mermaidRegion(layers, viewport) {
|
|
5367
|
-
const occupied = layers.filter((layer) => layer.type !== "shape" && layer.type !== "path" && layer.type !== "mermaid").map(
|
|
5368
|
-
(layer) => positionRect(
|
|
5369
|
-
layer.position,
|
|
5370
|
-
viewport,
|
|
5371
|
-
layer.type === "text" ? viewport.width * 0.45 : viewport.width * 0.5,
|
|
5372
|
-
layer.type === "text" ? viewport.height * 0.2 : viewport.height * 0.55
|
|
5373
|
-
)
|
|
5374
|
-
);
|
|
5375
|
-
if (occupied.length === 0) {
|
|
5376
|
-
return {
|
|
5377
|
-
x: viewport.width * 0.06,
|
|
5378
|
-
y: viewport.height * 0.08,
|
|
5379
|
-
width: viewport.width * 0.88,
|
|
5380
|
-
height: viewport.height * 0.84
|
|
5381
|
-
};
|
|
5382
|
-
}
|
|
5383
|
-
const candidates = [
|
|
5384
|
-
{
|
|
5385
|
-
x: viewport.width * 0.52,
|
|
5386
|
-
y: viewport.height * 0.12,
|
|
5387
|
-
width: viewport.width * 0.44,
|
|
5388
|
-
height: viewport.height * 0.76
|
|
5389
|
-
},
|
|
5390
|
-
{
|
|
5391
|
-
x: viewport.width * 0.04,
|
|
5392
|
-
y: viewport.height * 0.12,
|
|
5393
|
-
width: viewport.width * 0.44,
|
|
5394
|
-
height: viewport.height * 0.76
|
|
5395
|
-
},
|
|
5396
|
-
{
|
|
5397
|
-
x: viewport.width * 0.15,
|
|
5398
|
-
y: viewport.height * 0.53,
|
|
5399
|
-
width: viewport.width * 0.7,
|
|
5400
|
-
height: viewport.height * 0.41
|
|
5401
|
-
}
|
|
5402
|
-
];
|
|
5403
|
-
return candidates.reduce((best, candidate) => {
|
|
5404
|
-
const score = occupied.reduce((sum, rect) => sum + overlapArea(candidate, rect), 0);
|
|
5405
|
-
const bestScore = occupied.reduce((sum, rect) => sum + overlapArea(best, rect), 0);
|
|
5406
|
-
return score < bestScore ? candidate : best;
|
|
5407
|
-
});
|
|
5408
|
-
}
|
|
5409
|
-
function appendMermaidLayers(layers, block, theme, viewport) {
|
|
5410
|
-
const sources = mermaidSources(block);
|
|
5411
|
-
if (sources.length === 0 || layers.some((layer) => layer.type === "mermaid")) return layers;
|
|
5412
|
-
const region = mermaidRegion(layers, viewport);
|
|
5413
|
-
const columns = sources.length === 1 ? 1 : 2;
|
|
5414
|
-
const rows = Math.ceil(sources.length / columns);
|
|
5415
|
-
const gap = Math.min(viewport.width, viewport.height) * 0.018;
|
|
5416
|
-
const width = (region.width - gap * (columns - 1)) / columns;
|
|
5417
|
-
const height = (region.height - gap * (rows - 1)) / rows;
|
|
5418
|
-
const mermaidLayers = sources.map((source, index) => ({
|
|
5419
|
-
id: `${block.id}-mermaid-${index + 1}`,
|
|
5420
|
-
type: "mermaid",
|
|
5421
|
-
position: {
|
|
5422
|
-
x: region.x + index % columns * (width + gap),
|
|
5423
|
-
y: region.y + Math.floor(index / columns) * (height + gap),
|
|
5424
|
-
width,
|
|
5425
|
-
height
|
|
5426
|
-
},
|
|
5427
|
-
content: {
|
|
5428
|
-
source,
|
|
5429
|
-
background: theme.colors.backgroundLight,
|
|
5430
|
-
foreground: theme.colors.text,
|
|
5431
|
-
padding: Math.max(12, Math.round(Math.min(width, height) * 0.025))
|
|
5432
|
-
}
|
|
5310
|
+
function asciiDiagramToTemplateData(diagram) {
|
|
5311
|
+
const nodes = diagram.nodes.map((n) => ({
|
|
5312
|
+
id: n.id,
|
|
5313
|
+
label: n.label,
|
|
5314
|
+
...asciiCellToCanvas(n.col, n.row),
|
|
5315
|
+
w: n.wCols * ASCII_CHAR_W,
|
|
5316
|
+
h: n.hRows * ASCII_CHAR_H,
|
|
5317
|
+
...n.containerId ? { container: n.containerId } : {}
|
|
5318
|
+
}));
|
|
5319
|
+
const anchors = inferEdgeAnchors(nodes, diagram.edges);
|
|
5320
|
+
const edges = diagram.edges.map((e, index) => ({
|
|
5321
|
+
source: e.source,
|
|
5322
|
+
target: e.target,
|
|
5323
|
+
...e.label ? { label: e.label } : {},
|
|
5324
|
+
...e.directed ? {} : { directed: false },
|
|
5325
|
+
...anchors[index],
|
|
5326
|
+
routing: "orthogonal"
|
|
5433
5327
|
}));
|
|
5434
|
-
return
|
|
5328
|
+
return { nodes, edges };
|
|
5435
5329
|
}
|
|
5436
|
-
function
|
|
5437
|
-
const
|
|
5438
|
-
const
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
}
|
|
5443
|
-
const templateFn = registry[resolveTemplateName(safeTemplateBlock.template)];
|
|
5444
|
-
if (!templateFn) return { status: "unknown-template", layers: [] };
|
|
5445
|
-
const { templateData, templateOverrides } = safeTemplateBlock;
|
|
5446
|
-
const input = templateData || templateOverrides ? {
|
|
5447
|
-
...safeTemplateBlock,
|
|
5448
|
-
...templateData,
|
|
5449
|
-
...coerceTemplateParams(safeTemplateBlock.template, templateOverrides ?? {}).input
|
|
5450
|
-
} : safeTemplateBlock;
|
|
5451
|
-
try {
|
|
5452
|
-
const renderedLayers = templateFn(input, safeContext);
|
|
5453
|
-
if (!Array.isArray(renderedLayers)) {
|
|
5330
|
+
function inferEdgeAnchors(nodes, edges) {
|
|
5331
|
+
const nodeById = new Map(nodes.map((node) => [node.id, node]));
|
|
5332
|
+
const pairs = edges.map((edge) => {
|
|
5333
|
+
const source = nodeById.get(edge.source);
|
|
5334
|
+
const target = nodeById.get(edge.target);
|
|
5335
|
+
if (!source || !target) {
|
|
5454
5336
|
return {
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
receivedType: typeof renderedLayers
|
|
5337
|
+
sourceAnchor: { side: "right", offset: 0.5 },
|
|
5338
|
+
targetAnchor: { side: "left", offset: 0.5 }
|
|
5458
5339
|
};
|
|
5459
5340
|
}
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5341
|
+
const sourceW = source.w ?? ASCII_CHAR_W * 12;
|
|
5342
|
+
const sourceH = source.h ?? ASCII_CHAR_H * 3;
|
|
5343
|
+
const targetW = target.w ?? ASCII_CHAR_W * 12;
|
|
5344
|
+
const targetH = target.h ?? ASCII_CHAR_H * 3;
|
|
5345
|
+
const dx = target.x + targetW / 2 - (source.x + sourceW / 2);
|
|
5346
|
+
const dy = target.y + targetH / 2 - (source.y + sourceH / 2);
|
|
5347
|
+
const horizontalDistance = Math.abs(dx) / Math.max(1, (sourceW + targetW) / 2);
|
|
5348
|
+
const verticalDistance = Math.abs(dy) / Math.max(1, (sourceH + targetH) / 2);
|
|
5349
|
+
if (verticalDistance >= horizontalDistance) {
|
|
5350
|
+
return dy >= 0 ? {
|
|
5351
|
+
sourceAnchor: { side: "bottom", offset: 0.5 },
|
|
5352
|
+
targetAnchor: { side: "top", offset: 0.5 }
|
|
5353
|
+
} : {
|
|
5354
|
+
sourceAnchor: { side: "top", offset: 0.5 },
|
|
5355
|
+
targetAnchor: { side: "bottom", offset: 0.5 }
|
|
5356
|
+
};
|
|
5357
|
+
}
|
|
5358
|
+
return dx >= 0 ? {
|
|
5359
|
+
sourceAnchor: { side: "right", offset: 0.5 },
|
|
5360
|
+
targetAnchor: { side: "left", offset: 0.5 }
|
|
5361
|
+
} : {
|
|
5362
|
+
sourceAnchor: { side: "left", offset: 0.5 },
|
|
5363
|
+
targetAnchor: { side: "right", offset: 0.5 }
|
|
5471
5364
|
};
|
|
5365
|
+
});
|
|
5366
|
+
distributeOffsets(pairs, edges, nodes, "source");
|
|
5367
|
+
distributeOffsets(pairs, edges, nodes, "target");
|
|
5368
|
+
return pairs;
|
|
5369
|
+
}
|
|
5370
|
+
function distributeOffsets(pairs, edges, nodes, endpoint) {
|
|
5371
|
+
const nodeById = new Map(nodes.map((node) => [node.id, node]));
|
|
5372
|
+
const groups = /* @__PURE__ */ new Map();
|
|
5373
|
+
for (let index = 0; index < edges.length; index++) {
|
|
5374
|
+
const edge = edges[index];
|
|
5375
|
+
const anchor = endpoint === "source" ? pairs[index].sourceAnchor : pairs[index].targetAnchor;
|
|
5376
|
+
const nodeId = endpoint === "source" ? edge.source : edge.target;
|
|
5377
|
+
const key = `${nodeId}:${anchor.side}`;
|
|
5378
|
+
const group = groups.get(key) ?? [];
|
|
5379
|
+
group.push(index);
|
|
5380
|
+
groups.set(key, group);
|
|
5472
5381
|
}
|
|
5473
|
-
|
|
5382
|
+
for (const indexes of groups.values()) {
|
|
5383
|
+
if (indexes.length < 2) continue;
|
|
5384
|
+
const side = endpoint === "source" ? pairs[indexes[0]].sourceAnchor.side : pairs[indexes[0]].targetAnchor.side;
|
|
5385
|
+
indexes.sort((a, b) => {
|
|
5386
|
+
const oppositeA = nodeById.get(endpoint === "source" ? edges[a].target : edges[a].source);
|
|
5387
|
+
const oppositeB = nodeById.get(endpoint === "source" ? edges[b].target : edges[b].source);
|
|
5388
|
+
const axisA = side === "top" || side === "bottom" ? oppositeA?.x ?? 0 : oppositeA?.y ?? 0;
|
|
5389
|
+
const axisB = side === "top" || side === "bottom" ? oppositeB?.x ?? 0 : oppositeB?.y ?? 0;
|
|
5390
|
+
return axisA - axisB || a - b;
|
|
5391
|
+
});
|
|
5392
|
+
indexes.forEach((edgeIndex, rank) => {
|
|
5393
|
+
const anchor = endpoint === "source" ? pairs[edgeIndex].sourceAnchor : pairs[edgeIndex].targetAnchor;
|
|
5394
|
+
anchor.offset = (rank + 1) / (indexes.length + 1);
|
|
5395
|
+
});
|
|
5396
|
+
}
|
|
5397
|
+
}
|
|
5398
|
+
function asciiDiagramFromTemplateData(nodes, edges, options = {}) {
|
|
5399
|
+
const ids = new Set(nodes.map((n) => n.id));
|
|
5400
|
+
const outNodes = nodes.map((n) => {
|
|
5401
|
+
const { col, row } = canvasToAsciiCell(n.x, n.y);
|
|
5402
|
+
const labelLines = n.label.length > 0 ? n.label.split("\n") : [];
|
|
5403
|
+
const innerW = labelLines.reduce((w, l) => Math.max(w, l.length), 0);
|
|
5404
|
+
const wCols = typeof n.w === "number" ? Math.max(3, Math.round(n.w / ASCII_CHAR_W)) : innerW + 4;
|
|
5405
|
+
const hRows = typeof n.h === "number" ? Math.max(3, Math.round(n.h / ASCII_CHAR_H)) : labelLines.length + 2;
|
|
5474
5406
|
return {
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5407
|
+
id: n.id,
|
|
5408
|
+
label: n.label,
|
|
5409
|
+
col,
|
|
5410
|
+
row,
|
|
5411
|
+
wCols: Math.max(wCols, 3),
|
|
5412
|
+
hRows: Math.max(hRows, 3),
|
|
5413
|
+
...n.container && ids.has(n.container) && n.container !== n.id ? { containerId: n.container } : {}
|
|
5479
5414
|
};
|
|
5480
|
-
}
|
|
5415
|
+
});
|
|
5481
5416
|
return {
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5417
|
+
nodes: outNodes,
|
|
5418
|
+
edges: edges.filter((e) => ids.has(e.source) && ids.has(e.target)).map((e) => ({
|
|
5419
|
+
source: e.source,
|
|
5420
|
+
target: e.target,
|
|
5421
|
+
...e.label ? { label: e.label } : {},
|
|
5422
|
+
directed: e.directed !== false
|
|
5423
|
+
})),
|
|
5424
|
+
style: options.style ?? "unicode",
|
|
5425
|
+
warnings: []
|
|
5486
5426
|
};
|
|
5487
5427
|
}
|
|
5488
|
-
function
|
|
5489
|
-
|
|
5490
|
-
const
|
|
5491
|
-
|
|
5492
|
-
|
|
5428
|
+
function asciiDiagramFromBlocks(children, options = {}) {
|
|
5429
|
+
const layout = computeDiagramLayout(children);
|
|
5430
|
+
const nodes = layout.nodes.map((n) => ({
|
|
5431
|
+
id: n.id,
|
|
5432
|
+
label: n.label,
|
|
5433
|
+
x: n.x,
|
|
5434
|
+
y: n.y
|
|
5435
|
+
}));
|
|
5436
|
+
const edges = layout.edges.map((e) => ({
|
|
5437
|
+
source: e.source,
|
|
5438
|
+
target: e.target,
|
|
5439
|
+
...e.type ? { label: e.type } : {}
|
|
5440
|
+
}));
|
|
5441
|
+
const diagram = asciiDiagramFromTemplateData(nodes, edges, options);
|
|
5442
|
+
diagram.warnings.push(...layout.warnings);
|
|
5443
|
+
return diagram;
|
|
5493
5444
|
}
|
|
5494
5445
|
|
|
5495
|
-
// src/doc/
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
label:
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5446
|
+
// src/doc/asciiTimeline/mapping.ts
|
|
5447
|
+
function asciiTimelineToTemplateData(timeline) {
|
|
5448
|
+
const globalStart = timeline.tracks.length > 0 ? Math.min(...timeline.tracks.map((track) => track.startColumn)) : 0;
|
|
5449
|
+
const globalEnd = timeline.tracks.length > 0 ? Math.max(...timeline.tracks.map((track) => track.endColumn)) : 1;
|
|
5450
|
+
const span = Math.max(1, globalEnd - globalStart);
|
|
5451
|
+
const tracks = timeline.tracks.map((track) => ({
|
|
5452
|
+
id: track.id,
|
|
5453
|
+
...track.label ? { label: track.label } : {},
|
|
5454
|
+
...track.endLabel ? { endLabel: track.endLabel } : {},
|
|
5455
|
+
events: track.events.map(
|
|
5456
|
+
(event) => ({
|
|
5457
|
+
id: event.id,
|
|
5458
|
+
label: event.label,
|
|
5459
|
+
...event.description ? { description: event.description } : {},
|
|
5460
|
+
position: clamp012((event.column - globalStart) / span),
|
|
5461
|
+
...event.side ? { side: event.side } : {},
|
|
5462
|
+
...event.descriptionSide ? { descriptionSide: event.descriptionSide } : {},
|
|
5463
|
+
...event.callout === false ? { callout: false } : {},
|
|
5464
|
+
...event.marker ? { marker: event.marker } : {}
|
|
5465
|
+
})
|
|
5466
|
+
)
|
|
5467
|
+
}));
|
|
5468
|
+
const links = timeline.links.map((link) => ({ ...link }));
|
|
5469
|
+
return { tracks, links };
|
|
5470
|
+
}
|
|
5471
|
+
function clamp012(value) {
|
|
5472
|
+
return Math.max(0, Math.min(1, value));
|
|
5473
|
+
}
|
|
5474
|
+
|
|
5475
|
+
// src/doc/treeview/mapping.ts
|
|
5476
|
+
function treeToTemplateData(tree) {
|
|
5477
|
+
return { items: tree.roots.map(toItem) };
|
|
5478
|
+
}
|
|
5479
|
+
function toItem(node) {
|
|
5480
|
+
return {
|
|
5481
|
+
id: node.id,
|
|
5482
|
+
label: node.label,
|
|
5483
|
+
...node.isDir ? { isDir: true } : {},
|
|
5484
|
+
...node.comment ? { comment: node.comment } : {},
|
|
5485
|
+
children: node.children.map(toItem)
|
|
5486
|
+
};
|
|
5487
|
+
}
|
|
5488
|
+
function treeFromTemplateData(items, options = {}) {
|
|
5489
|
+
const roots = items.map(fromItem);
|
|
5490
|
+
return { roots, style: options.style ?? "unicode", warnings: [] };
|
|
5491
|
+
}
|
|
5492
|
+
function fromItem(item) {
|
|
5493
|
+
const children = Array.isArray(item.children) ? item.children.map(fromItem) : [];
|
|
5494
|
+
return {
|
|
5495
|
+
id: typeof item.id === "string" && item.id ? item.id : "node",
|
|
5496
|
+
label: typeof item.label === "string" ? item.label : "",
|
|
5497
|
+
children,
|
|
5498
|
+
isDir: item.isDir === true || children.length > 0,
|
|
5499
|
+
...item.comment ? { comment: item.comment } : {}
|
|
5500
|
+
};
|
|
5501
|
+
}
|
|
5502
|
+
function treeFromMarkdownList(list) {
|
|
5503
|
+
const usedIds = /* @__PURE__ */ new Map();
|
|
5504
|
+
const slugify2 = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "node";
|
|
5505
|
+
const idFor = (label) => {
|
|
5506
|
+
const base = slugify2(label.replace(/\/$/, ""));
|
|
5507
|
+
const count = usedIds.get(base) ?? 0;
|
|
5508
|
+
usedIds.set(base, count + 1);
|
|
5509
|
+
return count === 0 ? base : `${base}-${count + 1}`;
|
|
5510
|
+
};
|
|
5511
|
+
const itemToNode = (item) => {
|
|
5512
|
+
const labelNode = item.children.find((c) => c.type !== "list");
|
|
5513
|
+
const label = labelNode ? extractPlainText(labelNode).trim() : "";
|
|
5514
|
+
const childLists = item.children.filter((c) => c.type === "list");
|
|
5515
|
+
const children = [];
|
|
5516
|
+
for (const cl of childLists) for (const ci of cl.children) children.push(itemToNode(ci));
|
|
5517
|
+
return {
|
|
5518
|
+
id: idFor(label),
|
|
5519
|
+
label,
|
|
5520
|
+
children,
|
|
5521
|
+
isDir: label.endsWith("/") || children.length > 0
|
|
5522
|
+
};
|
|
5523
|
+
};
|
|
5524
|
+
return { roots: list.children.map(itemToNode), style: "unicode", warnings: [] };
|
|
5525
|
+
}
|
|
5526
|
+
function findFirstList(contents) {
|
|
5527
|
+
return contents?.find((n) => n.type === "list");
|
|
5528
|
+
}
|
|
5529
|
+
|
|
5530
|
+
// src/doc/templateInputs.ts
|
|
5531
|
+
var VIDEO_FILE_RE = /\.(?:webm|mp4|mov|m4v|ogv)(?:[?#].*)?$/i;
|
|
5532
|
+
function extractBodyPlainText(contents) {
|
|
5533
|
+
if (!contents || contents.length === 0) return "";
|
|
5534
|
+
return contents.filter((node) => !(node.type === "code" && node.lang?.trim().toLowerCase() === "mermaid")).map((n) => extractPlainText(n)).join("\n").trim();
|
|
5535
|
+
}
|
|
5536
|
+
function extractListItems(contents) {
|
|
5537
|
+
if (!contents) return [];
|
|
5538
|
+
const items = [];
|
|
5539
|
+
for (const node of contents) {
|
|
5540
|
+
if (node.type === "list") {
|
|
5541
|
+
for (const item of node.children) {
|
|
5542
|
+
const text = extractPlainText(item).trim();
|
|
5543
|
+
if (text) items.push(text);
|
|
5544
|
+
}
|
|
5545
|
+
}
|
|
5546
|
+
}
|
|
5547
|
+
return items;
|
|
5548
|
+
}
|
|
5549
|
+
function parseDim(raw) {
|
|
5550
|
+
if (raw === void 0) return void 0;
|
|
5551
|
+
const n = parseFloat(raw);
|
|
5552
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
5553
|
+
}
|
|
5554
|
+
function extractImages(contents, limit = Infinity) {
|
|
5555
|
+
if (!contents || contents.length === 0) return [];
|
|
5556
|
+
const found = [];
|
|
5557
|
+
function fromHtml(nodes) {
|
|
5558
|
+
for (const node of nodes) {
|
|
5559
|
+
if (found.length >= limit) return;
|
|
5560
|
+
if (!node || typeof node !== "object") continue;
|
|
5561
|
+
const n = node;
|
|
5562
|
+
if (n.type === "htmlElement" && n.tagName === "img") {
|
|
5563
|
+
const attrs = n.attributes;
|
|
5564
|
+
if (attrs && typeof attrs.src === "string" && attrs.src) {
|
|
5565
|
+
found.push({
|
|
5566
|
+
src: attrs.src,
|
|
5567
|
+
alt: typeof attrs.alt === "string" ? attrs.alt : "",
|
|
5568
|
+
width: parseDim(attrs.width),
|
|
5569
|
+
height: parseDim(attrs.height)
|
|
5570
|
+
});
|
|
5571
|
+
}
|
|
5572
|
+
}
|
|
5573
|
+
if (Array.isArray(n.children)) fromHtml(n.children);
|
|
5574
|
+
}
|
|
5575
|
+
}
|
|
5576
|
+
function walk(node) {
|
|
5577
|
+
if (found.length >= limit) return;
|
|
5578
|
+
if (!node || typeof node !== "object") return;
|
|
5579
|
+
const n = node;
|
|
5580
|
+
if (n.type === "image" && typeof n.url === "string" && n.url) {
|
|
5581
|
+
found.push({ src: n.url, alt: typeof n.alt === "string" ? n.alt : "" });
|
|
5582
|
+
return;
|
|
5583
|
+
}
|
|
5584
|
+
if ((n.type === "htmlBlock" || n.type === "htmlInline") && Array.isArray(n.htmlChildren)) {
|
|
5585
|
+
fromHtml(n.htmlChildren);
|
|
5586
|
+
}
|
|
5587
|
+
if (Array.isArray(n.children)) {
|
|
5588
|
+
for (const child of n.children) walk(child);
|
|
5589
|
+
}
|
|
5590
|
+
}
|
|
5591
|
+
for (const node of contents) {
|
|
5592
|
+
if (found.length >= limit) break;
|
|
5593
|
+
walk(node);
|
|
5594
|
+
}
|
|
5595
|
+
return found;
|
|
5596
|
+
}
|
|
5597
|
+
function extractFirstImage(contents) {
|
|
5598
|
+
return extractImages(contents, 1)[0] ?? null;
|
|
5599
|
+
}
|
|
5600
|
+
function extractEmbeddedVideos(contents, limit = Infinity) {
|
|
5601
|
+
if (!contents || contents.length === 0) return [];
|
|
5602
|
+
const found = [];
|
|
5603
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5604
|
+
const add = (video) => {
|
|
5605
|
+
if (!video.src || found.length >= limit || seen.has(video.src)) return;
|
|
5606
|
+
seen.add(video.src);
|
|
5607
|
+
found.push(video);
|
|
5608
|
+
};
|
|
5609
|
+
function nestedSource(children) {
|
|
5610
|
+
if (!Array.isArray(children)) return void 0;
|
|
5611
|
+
for (const child of children) {
|
|
5612
|
+
if (!child || typeof child !== "object") continue;
|
|
5613
|
+
const node = child;
|
|
5614
|
+
if (node.tagName === "source") {
|
|
5615
|
+
const attrs = node.attributes;
|
|
5616
|
+
if (typeof attrs?.src === "string" && attrs.src) return attrs.src;
|
|
5617
|
+
}
|
|
5618
|
+
const nested = nestedSource(node.children);
|
|
5619
|
+
if (nested) return nested;
|
|
5620
|
+
}
|
|
5621
|
+
return void 0;
|
|
5622
|
+
}
|
|
5623
|
+
function walk(node) {
|
|
5624
|
+
if (found.length >= limit || !node || typeof node !== "object") return;
|
|
5625
|
+
const n = node;
|
|
5626
|
+
if (n.type === "htmlElement" && n.tagName === "video") {
|
|
5627
|
+
const attrs = n.attributes;
|
|
5628
|
+
const src = attrs?.src || nestedSource(n.children);
|
|
5629
|
+
if (src) {
|
|
5630
|
+
add({
|
|
5631
|
+
src,
|
|
5632
|
+
...attrs?.poster ? { posterSrc: attrs.poster } : {},
|
|
5633
|
+
alt: attrs?.["aria-label"] || attrs?.title || attrs?.alt || ""
|
|
5634
|
+
});
|
|
5635
|
+
}
|
|
5636
|
+
} else if ((n.type === "link" || n.type === "image") && typeof n.url === "string" && VIDEO_FILE_RE.test(n.url)) {
|
|
5637
|
+
add({
|
|
5638
|
+
src: n.url,
|
|
5639
|
+
alt: typeof n.alt === "string" ? n.alt : extractPlainText(n).trim()
|
|
5640
|
+
});
|
|
5641
|
+
}
|
|
5642
|
+
if (Array.isArray(n.children)) n.children.forEach(walk);
|
|
5643
|
+
if (Array.isArray(n.htmlChildren)) n.htmlChildren.forEach(walk);
|
|
5644
|
+
}
|
|
5645
|
+
contents.forEach(walk);
|
|
5646
|
+
return found;
|
|
5647
|
+
}
|
|
5648
|
+
function extractFirstEmbeddedVideo(contents) {
|
|
5649
|
+
return extractEmbeddedVideos(contents, 1)[0] ?? null;
|
|
5650
|
+
}
|
|
5651
|
+
function extractTableFromContents(contents) {
|
|
5652
|
+
if (!contents) return null;
|
|
5653
|
+
for (const node of contents) {
|
|
5654
|
+
if (node.type === "table") {
|
|
5655
|
+
const table = node;
|
|
5656
|
+
const [headerRow, ...bodyRows] = table.children;
|
|
5657
|
+
if (!headerRow) return null;
|
|
5658
|
+
const headers = headerRow.children.map((cell) => extractPlainText(cell).trim());
|
|
5659
|
+
const rows = bodyRows.map((row) => row.children.map((cell) => extractPlainText(cell).trim()));
|
|
5660
|
+
return { headers, rows, align: table.align };
|
|
5661
|
+
}
|
|
5662
|
+
}
|
|
5663
|
+
return null;
|
|
5664
|
+
}
|
|
5665
|
+
function extractBlockquoteText(contents) {
|
|
5666
|
+
if (!contents) return "";
|
|
5667
|
+
for (const node of contents) {
|
|
5668
|
+
if (node.type === "blockquote") return extractPlainText(node).trim();
|
|
5669
|
+
}
|
|
5670
|
+
return "";
|
|
5671
|
+
}
|
|
5672
|
+
function firstParagraph(contents) {
|
|
5673
|
+
if (!contents) return null;
|
|
5674
|
+
const index = contents.findIndex((node) => node.type === "paragraph");
|
|
5675
|
+
if (index < 0) return null;
|
|
5676
|
+
return {
|
|
5677
|
+
node: contents[index],
|
|
5678
|
+
index
|
|
5679
|
+
};
|
|
5680
|
+
}
|
|
5681
|
+
function leadingStrongStat(paragraph) {
|
|
5682
|
+
for (const child of paragraph.children) {
|
|
5683
|
+
if (child.type === "text" && child.value.trim() === "") continue;
|
|
5684
|
+
if (child.type !== "strong") return null;
|
|
5685
|
+
const text = extractPlainText(child).trim();
|
|
5686
|
+
const match = text.match(/^(?:[$€£¥]\s*)?[+-]?\d+(?:[.,]\d+)*(?:\s?(?:[%‰x×]|[A-Za-z]+))?/);
|
|
5687
|
+
return match?.[0].trim() || null;
|
|
5688
|
+
}
|
|
5689
|
+
return null;
|
|
5690
|
+
}
|
|
5691
|
+
function removeStatPhrase(text, start, end) {
|
|
5692
|
+
const before = text.slice(0, start).trim();
|
|
5693
|
+
let after = text.slice(end);
|
|
5694
|
+
if (!before) after = after.replace(/^\s*(?:[-–—:]\s*)?/, "");
|
|
5695
|
+
else after = after.trim();
|
|
5696
|
+
return [before, after].filter(Boolean).join(" ").trim();
|
|
5697
|
+
}
|
|
5698
|
+
function bodyWithoutParagraphStat(contents, paragraphIndex, paragraphText, start, end) {
|
|
5699
|
+
if (!contents) return "";
|
|
5700
|
+
return contents.map(
|
|
5701
|
+
(node, index) => index === paragraphIndex ? removeStatPhrase(paragraphText, start, end) : extractPlainText(node).trim()
|
|
5702
|
+
).filter(Boolean).join("\n").trim();
|
|
5703
|
+
}
|
|
5704
|
+
function deriveStatHighlightInputs(headingText, contents, bodyText3) {
|
|
5705
|
+
const paragraph = firstParagraph(contents);
|
|
5706
|
+
if (paragraph) {
|
|
5707
|
+
const paragraphText = extractPlainText(paragraph.node).trim();
|
|
5708
|
+
const strongStat = leadingStrongStat(paragraph.node);
|
|
5709
|
+
if (strongStat) {
|
|
5710
|
+
const start = paragraphText.indexOf(strongStat);
|
|
5711
|
+
const description = bodyWithoutParagraphStat(
|
|
5712
|
+
contents,
|
|
5713
|
+
paragraph.index,
|
|
5714
|
+
paragraphText,
|
|
5715
|
+
start,
|
|
5716
|
+
start + strongStat.length
|
|
5717
|
+
);
|
|
5718
|
+
return {
|
|
5719
|
+
stat: strongStat,
|
|
5720
|
+
description: description || headingText || strongStat
|
|
5721
|
+
};
|
|
5722
|
+
}
|
|
5723
|
+
}
|
|
5724
|
+
const trimmedHeading = headingText.trim();
|
|
5725
|
+
const headingStat = matchNumberHighlight(trimmedHeading);
|
|
5726
|
+
if (headingStat && headingStat.index === 0 && headingStat.end === trimmedHeading.length) {
|
|
5727
|
+
return { stat: headingText, description: bodyText3 || headingText };
|
|
5728
|
+
}
|
|
5729
|
+
if (paragraph) {
|
|
5730
|
+
const paragraphText = extractPlainText(paragraph.node).trim();
|
|
5731
|
+
const bodyStat = matchNumberHighlight(paragraphText);
|
|
5732
|
+
if (bodyStat) {
|
|
5733
|
+
const description = bodyWithoutParagraphStat(
|
|
5734
|
+
contents,
|
|
5735
|
+
paragraph.index,
|
|
5736
|
+
paragraphText,
|
|
5737
|
+
bodyStat.index,
|
|
5738
|
+
bodyStat.end
|
|
5739
|
+
);
|
|
5740
|
+
return {
|
|
5741
|
+
stat: bodyStat.value,
|
|
5742
|
+
description: description || headingText || bodyStat.value
|
|
5743
|
+
};
|
|
5744
|
+
}
|
|
5745
|
+
}
|
|
5746
|
+
return { stat: headingText, description: bodyText3 || headingText };
|
|
5747
|
+
}
|
|
5748
|
+
function normalizeCoverageText(value) {
|
|
5749
|
+
return value.replace(/\s+/g, " ").trim();
|
|
5750
|
+
}
|
|
5751
|
+
function autoTemplatePreservesContent(templateName, contents) {
|
|
5752
|
+
const nodes = contents ?? [];
|
|
5753
|
+
switch (templateName) {
|
|
5754
|
+
case "quote":
|
|
5755
|
+
return nodes.length === 1 && nodes[0]?.type === "blockquote";
|
|
5756
|
+
case "dataTable":
|
|
5757
|
+
return nodes.length === 1 && nodes[0]?.type === "table";
|
|
5758
|
+
case "list":
|
|
5759
|
+
return nodes.length === 1 && nodes[0]?.type === "list";
|
|
5760
|
+
case "diagram":
|
|
5761
|
+
case "timeline":
|
|
5762
|
+
return nodes.length === 1 && nodes[0]?.type === "code";
|
|
5763
|
+
case "tree":
|
|
5764
|
+
return nodes.length === 1 && (nodes[0]?.type === "code" || nodes[0]?.type === "list");
|
|
5765
|
+
case "photoGrid": {
|
|
5766
|
+
const images = extractImages(nodes);
|
|
5767
|
+
if (images.length < 2 || images.length > 4) return false;
|
|
5768
|
+
const bodyText3 = normalizeCoverageText(extractBodyPlainText(nodes));
|
|
5769
|
+
const representedText = normalizeCoverageText(
|
|
5770
|
+
images.map((image) => image.alt).filter(Boolean).join(" ")
|
|
5771
|
+
);
|
|
5772
|
+
return bodyText3 === "" || bodyText3 === representedText;
|
|
5773
|
+
}
|
|
5774
|
+
case "videoWithCaption": {
|
|
5775
|
+
const videos = extractEmbeddedVideos(nodes);
|
|
5776
|
+
if (videos.length !== 1) return false;
|
|
5777
|
+
const bodyText3 = normalizeCoverageText(extractBodyPlainText(nodes));
|
|
5778
|
+
return bodyText3 === normalizeCoverageText(videos[0]?.alt ?? "");
|
|
5779
|
+
}
|
|
5780
|
+
case "leftFeature":
|
|
5781
|
+
case "rightFeature":
|
|
5782
|
+
case "statHighlight":
|
|
5783
|
+
return true;
|
|
5784
|
+
default:
|
|
5785
|
+
return false;
|
|
5786
|
+
}
|
|
5787
|
+
}
|
|
5788
|
+
function deriveTemplateInputs(templateName, headingText, contents, options = {}) {
|
|
5789
|
+
const placeholders = options.placeholders === true;
|
|
5790
|
+
const bodyText3 = extractBodyPlainText(contents);
|
|
5791
|
+
switch (templateName) {
|
|
5792
|
+
case "statHighlight": {
|
|
5793
|
+
const inputs = deriveStatHighlightInputs(headingText, contents, bodyText3);
|
|
5794
|
+
if (options.preserveSourceHeading && headingText && inputs.stat !== headingText && inputs.description !== headingText) {
|
|
5795
|
+
return {
|
|
5796
|
+
...inputs,
|
|
5797
|
+
description: headingText,
|
|
5798
|
+
...inputs.description ? { detail: inputs.description } : {}
|
|
5799
|
+
};
|
|
5800
|
+
}
|
|
5801
|
+
return inputs;
|
|
5802
|
+
}
|
|
5803
|
+
case "quote": {
|
|
5804
|
+
const quote = extractBlockquoteText(contents) || bodyText3;
|
|
5805
|
+
if (quote) return { quote, ...headingText ? { title: headingText } : {} };
|
|
5806
|
+
return { quote: headingText };
|
|
5807
|
+
}
|
|
5808
|
+
case "fullBleedQuote":
|
|
5809
|
+
case "pullQuote": {
|
|
5810
|
+
const text = extractBlockquoteText(contents) || bodyText3 || headingText;
|
|
5811
|
+
return { text };
|
|
5812
|
+
}
|
|
5813
|
+
case "factCard":
|
|
5814
|
+
return { fact: headingText, explanation: bodyText3 || headingText };
|
|
5815
|
+
case "comparisonBar":
|
|
5816
|
+
return placeholders ? { leftLabel: "A", leftValue: 60, rightLabel: "B", rightValue: 40 } : null;
|
|
5817
|
+
case "list": {
|
|
5818
|
+
const items = extractListItems(contents);
|
|
5819
|
+
if (items.length > 0) return { items, ...headingText ? { title: headingText } : {} };
|
|
5820
|
+
return placeholders ? { items: ["Item 1", "Item 2", "Item 3"] } : null;
|
|
5821
|
+
}
|
|
5822
|
+
case "definitionCard":
|
|
5823
|
+
return { term: headingText, definition: bodyText3 || headingText };
|
|
5824
|
+
case "dateEvent":
|
|
5825
|
+
return { date: headingText, description: bodyText3 || headingText };
|
|
5826
|
+
case "dataTable": {
|
|
5827
|
+
const tableData = extractTableFromContents(contents);
|
|
5828
|
+
if (tableData) return { ...tableData, ...headingText ? { title: headingText } : {} };
|
|
5829
|
+
return placeholders ? { headers: ["Column"], rows: [["Data"]] } : null;
|
|
5830
|
+
}
|
|
5831
|
+
case "imageWithCaption": {
|
|
5832
|
+
const img = extractFirstImage(contents);
|
|
5833
|
+
if (!img) return placeholders ? { caption: headingText } : null;
|
|
5834
|
+
return { imageSrc: img.src, imageAlt: img.alt || headingText, caption: headingText };
|
|
5835
|
+
}
|
|
5836
|
+
case "photoGrid": {
|
|
5837
|
+
const images = extractImages(contents, 4);
|
|
5838
|
+
if (images.length < 2) return placeholders ? {} : null;
|
|
5839
|
+
return {
|
|
5840
|
+
images: images.map((i) => ({ src: i.src, alt: i.alt })),
|
|
5841
|
+
caption: headingText
|
|
5842
|
+
};
|
|
5843
|
+
}
|
|
5844
|
+
case "videoWithCaption": {
|
|
5845
|
+
const video = extractFirstEmbeddedVideo(contents);
|
|
5846
|
+
if (!video) return placeholders ? { caption: headingText } : null;
|
|
5847
|
+
return {
|
|
5848
|
+
videoSrc: video.src,
|
|
5849
|
+
posterSrc: video.posterSrc,
|
|
5850
|
+
videoAlt: video.alt || headingText,
|
|
5851
|
+
caption: headingText
|
|
5852
|
+
};
|
|
5853
|
+
}
|
|
5854
|
+
case "leftFeature":
|
|
5855
|
+
case "rightFeature": {
|
|
5856
|
+
const img = extractFirstImage(contents);
|
|
5857
|
+
if (!img && !placeholders) return null;
|
|
5858
|
+
return {
|
|
5859
|
+
imageSrc: img?.src ?? "",
|
|
5860
|
+
imageAlt: img?.alt || headingText,
|
|
5861
|
+
imageWidth: img?.width,
|
|
5862
|
+
imageHeight: img?.height,
|
|
5863
|
+
title: headingText,
|
|
5864
|
+
body: bodyText3
|
|
5865
|
+
};
|
|
5866
|
+
}
|
|
5867
|
+
case "diagram": {
|
|
5868
|
+
const fences = (contents ?? []).filter((n) => n.type === "code");
|
|
5869
|
+
const fence = fences.length === 1 && isEligibleAsciiFenceLang(fences[0].lang) ? fences[0] : void 0;
|
|
5870
|
+
const detection = fence ? detectAsciiDiagram(fence.value, { explicit: isExplicitDiagramLang(fence.lang) }) : void 0;
|
|
5871
|
+
if (!detection?.isDiagram || !detection.diagram) return placeholders ? {} : null;
|
|
5872
|
+
const { nodes, edges } = asciiDiagramToTemplateData(detection.diagram);
|
|
5873
|
+
return { nodes, edges, ...headingText ? { title: headingText } : {} };
|
|
5874
|
+
}
|
|
5875
|
+
case "timeline": {
|
|
5876
|
+
const fences = (contents ?? []).filter((n) => n.type === "code");
|
|
5877
|
+
const fence = fences.length === 1 && isEligibleAsciiTimelineFenceLang(fences[0].lang) ? fences[0] : void 0;
|
|
5878
|
+
const detection = fence ? detectAsciiTimeline(fence.value, { explicit: true }) : void 0;
|
|
5879
|
+
if (!detection?.isTimeline || !detection.timeline) return placeholders ? {} : null;
|
|
5880
|
+
const { tracks, links } = asciiTimelineToTemplateData(detection.timeline);
|
|
5881
|
+
return { tracks, links, ...headingText ? { title: headingText } : {} };
|
|
5882
|
+
}
|
|
5883
|
+
case "tree": {
|
|
5884
|
+
const fences = (contents ?? []).filter((n) => n.type === "code");
|
|
5885
|
+
const fence = fences.length === 1 && isEligibleTreeFenceLang(fences[0].lang) ? fences[0] : void 0;
|
|
5886
|
+
if (fence) {
|
|
5887
|
+
const detection = detectTree(fence.value, { explicit: isExplicitTreeLang(fence.lang) });
|
|
5888
|
+
if (detection.isTree && detection.tree) {
|
|
5889
|
+
const { items } = treeToTemplateData(detection.tree);
|
|
5890
|
+
return { items, ...headingText ? { title: headingText } : {} };
|
|
5891
|
+
}
|
|
5892
|
+
}
|
|
5893
|
+
const list = findFirstList(contents);
|
|
5894
|
+
if (list) {
|
|
5895
|
+
const { items } = treeToTemplateData(treeFromMarkdownList(list));
|
|
5896
|
+
if (items.length > 0) return { items, ...headingText ? { title: headingText } : {} };
|
|
5897
|
+
}
|
|
5898
|
+
return placeholders ? {} : null;
|
|
5899
|
+
}
|
|
5900
|
+
default:
|
|
5901
|
+
return placeholders ? {} : null;
|
|
5902
|
+
}
|
|
5903
|
+
}
|
|
5904
|
+
|
|
5905
|
+
// src/doc/templates/mediaLayoutPolicy.ts
|
|
5906
|
+
var TITLE_VARIANTS = {
|
|
5907
|
+
landscape: {
|
|
5908
|
+
wide: "title-stack",
|
|
5909
|
+
tall: "split",
|
|
5910
|
+
square: "title-stack",
|
|
5911
|
+
multiple: "title-stack"
|
|
5912
|
+
},
|
|
5913
|
+
square: {
|
|
5914
|
+
wide: "title-stack",
|
|
5915
|
+
tall: "split",
|
|
5916
|
+
square: "title-stack",
|
|
5917
|
+
multiple: "title-stack"
|
|
5918
|
+
},
|
|
5919
|
+
portrait: {
|
|
5920
|
+
wide: "title-stack",
|
|
5921
|
+
tall: "title-stack",
|
|
5922
|
+
square: "title-stack",
|
|
5923
|
+
multiple: "title-stack"
|
|
5924
|
+
}
|
|
5925
|
+
};
|
|
5926
|
+
var TEXT_VARIANTS = {
|
|
5927
|
+
landscape: {
|
|
5928
|
+
wide: "split",
|
|
5929
|
+
tall: "split",
|
|
5930
|
+
square: "split",
|
|
5931
|
+
multiple: "split"
|
|
5932
|
+
},
|
|
5933
|
+
square: {
|
|
5934
|
+
wide: "text-stack",
|
|
5935
|
+
tall: "split",
|
|
5936
|
+
square: "text-stack",
|
|
5937
|
+
multiple: "text-stack"
|
|
5938
|
+
},
|
|
5939
|
+
portrait: {
|
|
5940
|
+
wide: "text-stack",
|
|
5941
|
+
tall: "text-stack",
|
|
5942
|
+
square: "text-stack",
|
|
5943
|
+
multiple: "text-stack"
|
|
5944
|
+
}
|
|
5945
|
+
};
|
|
5946
|
+
var DENSE_VARIANTS = {
|
|
5947
|
+
landscape: {
|
|
5948
|
+
wide: "dense-stack",
|
|
5949
|
+
tall: "dense-stack",
|
|
5950
|
+
square: "dense-stack",
|
|
5951
|
+
multiple: "dense-stack"
|
|
5952
|
+
},
|
|
5953
|
+
square: {
|
|
5954
|
+
wide: "dense-stack",
|
|
5955
|
+
tall: "dense-stack",
|
|
5956
|
+
square: "dense-stack",
|
|
5957
|
+
multiple: "dense-stack"
|
|
5958
|
+
},
|
|
5959
|
+
portrait: {
|
|
5960
|
+
wide: "dense-stack",
|
|
5961
|
+
tall: "dense-stack",
|
|
5962
|
+
square: "dense-stack",
|
|
5963
|
+
multiple: "dense-stack"
|
|
5964
|
+
}
|
|
5965
|
+
};
|
|
5966
|
+
var BLOCK_MEDIA_LAYOUT_POLICIES = {
|
|
5967
|
+
title: {
|
|
5968
|
+
summary: "Text-only by default; supplemental media gets a title band plus a reserved field.",
|
|
5969
|
+
noMedia: "template-default",
|
|
5970
|
+
ownership: "supplemental",
|
|
5971
|
+
unconsumedMedia: "reserved-slot",
|
|
5972
|
+
variants: TITLE_VARIANTS
|
|
5973
|
+
},
|
|
5974
|
+
sectionHeader: {
|
|
5975
|
+
summary: "Uses its authored background image when present; otherwise supplemental media receives a title composition.",
|
|
5976
|
+
noMedia: "template-without-optional-media",
|
|
5977
|
+
ownership: "optional-native",
|
|
5978
|
+
nativeLayout: "background-image",
|
|
5979
|
+
additionalMediaLayout: "overlay-inset",
|
|
5980
|
+
unconsumedMedia: "reserve-when-no-native-media",
|
|
5981
|
+
variants: TITLE_VARIANTS
|
|
5982
|
+
},
|
|
5983
|
+
statHighlight: {
|
|
5984
|
+
summary: "Uses its optional accent image natively; otherwise supplemental media occupies a companion field.",
|
|
5985
|
+
noMedia: "template-without-optional-media",
|
|
5986
|
+
ownership: "optional-native",
|
|
5987
|
+
nativeLayout: "accent-strip-or-inset",
|
|
5988
|
+
additionalMediaLayout: "overlay-inset",
|
|
5989
|
+
unconsumedMedia: "reserve-when-no-native-media",
|
|
5990
|
+
variants: TEXT_VARIANTS
|
|
5508
5991
|
},
|
|
5509
5992
|
quote: {
|
|
5510
|
-
|
|
5511
|
-
|
|
5993
|
+
summary: "Uses its optional accent image natively; otherwise supplemental media is paired with the quote.",
|
|
5994
|
+
noMedia: "template-without-optional-media",
|
|
5995
|
+
ownership: "optional-native",
|
|
5996
|
+
nativeLayout: "accent-strip-or-inset",
|
|
5997
|
+
additionalMediaLayout: "overlay-inset",
|
|
5998
|
+
unconsumedMedia: "reserve-when-no-native-media",
|
|
5999
|
+
variants: TEXT_VARIANTS
|
|
5512
6000
|
},
|
|
5513
6001
|
factCard: {
|
|
5514
|
-
|
|
5515
|
-
|
|
6002
|
+
summary: "Uses its optional accent image natively; otherwise supplemental media is paired with the fact card.",
|
|
6003
|
+
noMedia: "template-without-optional-media",
|
|
6004
|
+
ownership: "optional-native",
|
|
6005
|
+
nativeLayout: "accent-strip-or-inset",
|
|
6006
|
+
additionalMediaLayout: "overlay-inset",
|
|
6007
|
+
unconsumedMedia: "reserve-when-no-native-media",
|
|
6008
|
+
variants: TEXT_VARIANTS
|
|
5516
6009
|
},
|
|
5517
6010
|
twoColumn: {
|
|
5518
|
-
|
|
5519
|
-
|
|
6011
|
+
summary: "Text comparison by default; supplemental media stacks below the dense two-column panel.",
|
|
6012
|
+
noMedia: "template-default",
|
|
6013
|
+
ownership: "supplemental",
|
|
6014
|
+
unconsumedMedia: "reserved-slot",
|
|
6015
|
+
variants: DENSE_VARIANTS
|
|
5520
6016
|
},
|
|
5521
6017
|
dateEvent: {
|
|
5522
|
-
|
|
5523
|
-
|
|
6018
|
+
summary: "Uses its optional accent image natively; otherwise supplemental media is paired with the event.",
|
|
6019
|
+
noMedia: "template-without-optional-media",
|
|
6020
|
+
ownership: "optional-native",
|
|
6021
|
+
nativeLayout: "accent-strip-or-inset",
|
|
6022
|
+
additionalMediaLayout: "overlay-inset",
|
|
6023
|
+
unconsumedMedia: "reserve-when-no-native-media",
|
|
6024
|
+
variants: TEXT_VARIANTS
|
|
5524
6025
|
},
|
|
5525
6026
|
imageWithCaption: {
|
|
5526
|
-
|
|
5527
|
-
|
|
6027
|
+
summary: "Requires one primary image and owns its full-bleed image/caption geometry.",
|
|
6028
|
+
noMedia: "unsupported",
|
|
6029
|
+
ownership: "required-native",
|
|
6030
|
+
nativeLayout: "full-bleed-image",
|
|
6031
|
+
additionalMediaLayout: "overlay-inset",
|
|
6032
|
+
unconsumedMedia: "retain-native-layout"
|
|
5528
6033
|
},
|
|
5529
6034
|
leftFeature: {
|
|
5530
|
-
|
|
5531
|
-
|
|
6035
|
+
summary: "Requires a primary image in the left feature cell; text occupies the right cell.",
|
|
6036
|
+
noMedia: "unsupported",
|
|
6037
|
+
ownership: "required-native",
|
|
6038
|
+
nativeLayout: "feature-left",
|
|
6039
|
+
additionalMediaLayout: "overlay-inset",
|
|
6040
|
+
unconsumedMedia: "retain-native-layout"
|
|
5532
6041
|
},
|
|
5533
6042
|
rightFeature: {
|
|
5534
|
-
|
|
5535
|
-
|
|
6043
|
+
summary: "Requires a primary image in the right feature cell; text occupies the left cell.",
|
|
6044
|
+
noMedia: "unsupported",
|
|
6045
|
+
ownership: "required-native",
|
|
6046
|
+
nativeLayout: "feature-right",
|
|
6047
|
+
additionalMediaLayout: "overlay-inset",
|
|
6048
|
+
unconsumedMedia: "retain-native-layout"
|
|
5536
6049
|
},
|
|
5537
6050
|
map: {
|
|
5538
|
-
|
|
5539
|
-
|
|
6051
|
+
summary: "The map canvas is the primary visual; other media must not reflow its geography.",
|
|
6052
|
+
noMedia: "intrinsic-visual",
|
|
6053
|
+
ownership: "intrinsic-visual",
|
|
6054
|
+
nativeLayout: "map-canvas",
|
|
6055
|
+
additionalMediaLayout: "overlay-inset",
|
|
6056
|
+
unconsumedMedia: "retain-native-layout"
|
|
5540
6057
|
},
|
|
5541
6058
|
fullBleedQuote: {
|
|
5542
|
-
|
|
5543
|
-
|
|
6059
|
+
summary: "Despite its name this is text-only; supplemental media receives the same dramatic title treatment.",
|
|
6060
|
+
noMedia: "template-default",
|
|
6061
|
+
ownership: "supplemental",
|
|
6062
|
+
unconsumedMedia: "reserved-slot",
|
|
6063
|
+
variants: TITLE_VARIANTS
|
|
5544
6064
|
},
|
|
5545
6065
|
list: {
|
|
5546
|
-
|
|
5547
|
-
|
|
6066
|
+
summary: "Uses its optional accent image natively; otherwise supplemental media is paired with the list.",
|
|
6067
|
+
noMedia: "template-without-optional-media",
|
|
6068
|
+
ownership: "optional-native",
|
|
6069
|
+
nativeLayout: "accent-strip-or-inset",
|
|
6070
|
+
additionalMediaLayout: "overlay-inset",
|
|
6071
|
+
unconsumedMedia: "reserve-when-no-native-media",
|
|
6072
|
+
variants: TEXT_VARIANTS
|
|
5548
6073
|
},
|
|
5549
6074
|
photoGrid: {
|
|
5550
|
-
|
|
5551
|
-
|
|
6075
|
+
summary: "Requires a primary image collection and owns the complete tiled media field.",
|
|
6076
|
+
noMedia: "unsupported",
|
|
6077
|
+
ownership: "required-native",
|
|
6078
|
+
nativeLayout: "photo-grid",
|
|
6079
|
+
additionalMediaLayout: "overlay-inset",
|
|
6080
|
+
unconsumedMedia: "retain-native-layout"
|
|
5552
6081
|
},
|
|
5553
6082
|
definitionCard: {
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
pullQuote: {
|
|
5562
|
-
label: "Pull Quote",
|
|
5563
|
-
description: "A stylized pull quote with large decorative marks and centered text."
|
|
5564
|
-
},
|
|
5565
|
-
videoWithCaption: {
|
|
5566
|
-
label: "Video with Caption",
|
|
5567
|
-
description: "Embeds a video player with an optional caption below."
|
|
5568
|
-
},
|
|
5569
|
-
videoPullQuote: {
|
|
5570
|
-
label: "Video Pull Quote",
|
|
5571
|
-
description: "Combines a video panel with a highlighted pull quote side-by-side."
|
|
5572
|
-
},
|
|
5573
|
-
dataTable: {
|
|
5574
|
-
label: "Data Table",
|
|
5575
|
-
description: "Renders tabular data in a clean, styled table with a header row."
|
|
5576
|
-
},
|
|
5577
|
-
diagram: {
|
|
5578
|
-
label: "Diagram",
|
|
5579
|
-
description: "Renders sub-headings as connected nodes \u2014 edit visually as a node-and-edge diagram."
|
|
6083
|
+
summary: "Uses its optional accent image natively; otherwise supplemental media is paired with the definition.",
|
|
6084
|
+
noMedia: "template-without-optional-media",
|
|
6085
|
+
ownership: "optional-native",
|
|
6086
|
+
nativeLayout: "accent-strip-or-inset",
|
|
6087
|
+
additionalMediaLayout: "overlay-inset",
|
|
6088
|
+
unconsumedMedia: "reserve-when-no-native-media",
|
|
6089
|
+
variants: TEXT_VARIANTS
|
|
5580
6090
|
},
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
position: { x: 0, y: 0, width: "100%", height: "100%" }
|
|
5659
|
-
},
|
|
5660
|
-
{
|
|
5661
|
-
type: "shape",
|
|
5662
|
-
id: "cover-bg-tint",
|
|
5663
|
-
content: {
|
|
5664
|
-
shape: "rect",
|
|
5665
|
-
fill: `radial-gradient(ellipse at 50% 40%, ${withAlpha(theme.colors.primary, 0.16)} 0%, ${withAlpha(theme.colors.primary, 0.07)} 38%, ${withAlpha(theme.colors.primary, 0)} 78%)`
|
|
5666
|
-
},
|
|
5667
|
-
position: { x: 0, y: 0, width: "100%", height: "100%" }
|
|
5668
|
-
}
|
|
5669
|
-
);
|
|
5670
|
-
} else {
|
|
5671
|
-
layers.push({
|
|
5672
|
-
type: "shape",
|
|
5673
|
-
id: "cover-bg",
|
|
5674
|
-
content: {
|
|
5675
|
-
shape: "rect",
|
|
5676
|
-
fill: `radial-gradient(ellipse at 50% 40%, ${theme.colors.primary} 0%, ${theme.colors.background} 100%)`
|
|
5677
|
-
},
|
|
5678
|
-
position: { x: 0, y: 0, width: "100%", height: "100%" }
|
|
5679
|
-
});
|
|
5680
|
-
}
|
|
5681
|
-
layers.push({
|
|
5682
|
-
type: "shape",
|
|
5683
|
-
id: "cover-accent",
|
|
5684
|
-
content: {
|
|
5685
|
-
shape: "rect",
|
|
5686
|
-
fill: standardLightCover ? withAlpha(theme.colors.primary, 0.24) : "rgba(255, 255, 255, 0.2)"
|
|
5687
|
-
},
|
|
5688
|
-
position: {
|
|
5689
|
-
x: "35%",
|
|
5690
|
-
y: subtitle ? "42%" : "58%",
|
|
5691
|
-
width: "30%",
|
|
5692
|
-
height: "2px"
|
|
5693
|
-
}
|
|
5694
|
-
});
|
|
5695
|
-
}
|
|
5696
|
-
layers.push({
|
|
5697
|
-
type: "text",
|
|
5698
|
-
id: "cover-title",
|
|
5699
|
-
content: {
|
|
5700
|
-
text: title,
|
|
5701
|
-
style: {
|
|
5702
|
-
fontSize: titleFontSize,
|
|
5703
|
-
fontFamily: getThemeFont(context, "title"),
|
|
5704
|
-
fontWeight: "bold",
|
|
5705
|
-
color: theme.colors.text,
|
|
5706
|
-
textAlign: "center",
|
|
5707
|
-
shadow: !standardLightCover
|
|
5708
|
-
}
|
|
5709
|
-
},
|
|
5710
|
-
position: {
|
|
5711
|
-
x: "50%",
|
|
5712
|
-
y: heroSrc ? subtitle ? "70%" : "75%" : subtitle ? layout.primaryY : "50%",
|
|
5713
|
-
anchor: "center",
|
|
5714
|
-
width: layout.maxTextWidth
|
|
5715
|
-
},
|
|
5716
|
-
// No animation delay - shown immediately at rest
|
|
5717
|
-
animation: { type: "fadeIn", duration: 0.8 }
|
|
5718
|
-
});
|
|
5719
|
-
if (subtitle) {
|
|
5720
|
-
layers.push({
|
|
5721
|
-
type: "text",
|
|
5722
|
-
id: "cover-subtitle",
|
|
5723
|
-
content: {
|
|
5724
|
-
text: subtitle,
|
|
5725
|
-
style: {
|
|
5726
|
-
fontSize: subtitleFontSize,
|
|
5727
|
-
fontFamily: getThemeFont(context, "body"),
|
|
5728
|
-
fontWeight: standardLightCover ? "bold" : "normal",
|
|
5729
|
-
color: standardLightCover ? withAlpha(theme.colors.text, 0.78) : theme.colors.textMuted,
|
|
5730
|
-
textAlign: "center",
|
|
5731
|
-
lineHeight: 1.5
|
|
5732
|
-
}
|
|
5733
|
-
},
|
|
5734
|
-
position: {
|
|
5735
|
-
x: "50%",
|
|
5736
|
-
y: heroSrc ? "82%" : layout.secondaryY,
|
|
5737
|
-
anchor: "center",
|
|
5738
|
-
width: layout.maxTextWidth
|
|
5739
|
-
},
|
|
5740
|
-
animation: { type: "fadeIn", duration: 0.8, delay: 0.2 }
|
|
5741
|
-
});
|
|
6091
|
+
comparisonBar: {
|
|
6092
|
+
summary: "Data bars are primary; supplemental media stacks below to preserve horizontal scale.",
|
|
6093
|
+
noMedia: "template-default",
|
|
6094
|
+
ownership: "supplemental",
|
|
6095
|
+
unconsumedMedia: "reserved-slot",
|
|
6096
|
+
variants: DENSE_VARIANTS
|
|
6097
|
+
},
|
|
6098
|
+
pullQuote: {
|
|
6099
|
+
summary: "Requires and owns a full-bleed background image behind the quote lockup.",
|
|
6100
|
+
noMedia: "unsupported",
|
|
6101
|
+
ownership: "required-native",
|
|
6102
|
+
nativeLayout: "full-bleed-image",
|
|
6103
|
+
additionalMediaLayout: "overlay-inset",
|
|
6104
|
+
unconsumedMedia: "retain-native-layout"
|
|
6105
|
+
},
|
|
6106
|
+
videoWithCaption: {
|
|
6107
|
+
summary: "Requires one primary video and owns its full-bleed video/caption geometry.",
|
|
6108
|
+
noMedia: "unsupported",
|
|
6109
|
+
ownership: "required-native",
|
|
6110
|
+
nativeLayout: "full-bleed-video",
|
|
6111
|
+
additionalMediaLayout: "overlay-inset",
|
|
6112
|
+
unconsumedMedia: "retain-native-layout"
|
|
6113
|
+
},
|
|
6114
|
+
videoPullQuote: {
|
|
6115
|
+
summary: "Requires and owns a full-bleed video behind the quote lockup.",
|
|
6116
|
+
noMedia: "unsupported",
|
|
6117
|
+
ownership: "required-native",
|
|
6118
|
+
nativeLayout: "full-bleed-video",
|
|
6119
|
+
additionalMediaLayout: "overlay-inset",
|
|
6120
|
+
unconsumedMedia: "retain-native-layout"
|
|
6121
|
+
},
|
|
6122
|
+
dataTable: {
|
|
6123
|
+
summary: "The table remains wide; supplemental media stacks below the dense data region.",
|
|
6124
|
+
noMedia: "template-default",
|
|
6125
|
+
ownership: "supplemental",
|
|
6126
|
+
unconsumedMedia: "reserved-slot",
|
|
6127
|
+
variants: DENSE_VARIANTS
|
|
6128
|
+
},
|
|
6129
|
+
diagram: {
|
|
6130
|
+
summary: "The node-and-edge canvas is intrinsic media and retains its spatial coordinate system.",
|
|
6131
|
+
noMedia: "intrinsic-visual",
|
|
6132
|
+
ownership: "intrinsic-visual",
|
|
6133
|
+
nativeLayout: "spatial-canvas",
|
|
6134
|
+
additionalMediaLayout: "overlay-inset",
|
|
6135
|
+
unconsumedMedia: "retain-native-layout"
|
|
6136
|
+
},
|
|
6137
|
+
tree: {
|
|
6138
|
+
summary: "The interactive tree canvas is intrinsic media and retains its full layout region.",
|
|
6139
|
+
noMedia: "intrinsic-visual",
|
|
6140
|
+
ownership: "intrinsic-visual",
|
|
6141
|
+
nativeLayout: "spatial-canvas",
|
|
6142
|
+
additionalMediaLayout: "overlay-inset",
|
|
6143
|
+
unconsumedMedia: "retain-native-layout"
|
|
6144
|
+
},
|
|
6145
|
+
timeline: {
|
|
6146
|
+
summary: "The track canvas is intrinsic media and retains its shared horizontal time scale.",
|
|
6147
|
+
noMedia: "intrinsic-visual",
|
|
6148
|
+
ownership: "intrinsic-visual",
|
|
6149
|
+
nativeLayout: "spatial-canvas",
|
|
6150
|
+
additionalMediaLayout: "overlay-inset",
|
|
6151
|
+
unconsumedMedia: "retain-native-layout"
|
|
6152
|
+
},
|
|
6153
|
+
layout: {
|
|
6154
|
+
summary: "The authored layer canvas is intrinsic media and must preserve absolute placement.",
|
|
6155
|
+
noMedia: "intrinsic-visual",
|
|
6156
|
+
ownership: "intrinsic-visual",
|
|
6157
|
+
nativeLayout: "freeform-canvas",
|
|
6158
|
+
additionalMediaLayout: "overlay-inset",
|
|
6159
|
+
unconsumedMedia: "retain-native-layout"
|
|
6160
|
+
},
|
|
6161
|
+
drawing: {
|
|
6162
|
+
summary: "The drawing canvas is intrinsic media and must preserve authored geometry.",
|
|
6163
|
+
noMedia: "intrinsic-visual",
|
|
6164
|
+
ownership: "intrinsic-visual",
|
|
6165
|
+
nativeLayout: "freeform-canvas",
|
|
6166
|
+
additionalMediaLayout: "overlay-inset",
|
|
6167
|
+
unconsumedMedia: "retain-native-layout"
|
|
5742
6168
|
}
|
|
5743
|
-
|
|
6169
|
+
};
|
|
6170
|
+
function getBlockMediaLayoutPolicy(template) {
|
|
6171
|
+
if (!template) return void 0;
|
|
6172
|
+
return BLOCK_MEDIA_LAYOUT_POLICIES[template];
|
|
5744
6173
|
}
|
|
5745
|
-
|
|
6174
|
+
|
|
6175
|
+
// src/doc/richMediaLayout.ts
|
|
6176
|
+
function rect(viewport, x, y, width, height) {
|
|
5746
6177
|
return {
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
ambientMotion: config.ambientMotion,
|
|
5752
|
-
heroCredit: config.heroCredit,
|
|
5753
|
-
heroLicense: config.heroLicense
|
|
6178
|
+
x: viewport.width * x,
|
|
6179
|
+
y: viewport.height * y,
|
|
6180
|
+
width: viewport.width * width,
|
|
6181
|
+
height: viewport.height * height
|
|
5754
6182
|
};
|
|
5755
6183
|
}
|
|
5756
|
-
function
|
|
5757
|
-
|
|
5758
|
-
|
|
6184
|
+
function mediaShape(mediaCount, aspectRatios) {
|
|
6185
|
+
if (mediaCount > 1) return "multiple";
|
|
6186
|
+
const aspect = aspectRatios[0] ?? 16 / 9;
|
|
6187
|
+
if (aspect < 0.8) return "tall";
|
|
6188
|
+
if (aspect > 1.25) return "wide";
|
|
6189
|
+
return "square";
|
|
5759
6190
|
}
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
viewport,
|
|
5768
|
-
persistentLayers: persistentLayers ?? false,
|
|
5769
|
-
blockIndex,
|
|
5770
|
-
totalBlocks,
|
|
5771
|
-
failureMode
|
|
5772
|
-
},
|
|
5773
|
-
{ registry, expandedPersistentLayers }
|
|
5774
|
-
);
|
|
5775
|
-
if (materialized.diagnostic) {
|
|
5776
|
-
onDiagnostic?.(materialized.diagnostic, sourceBlock, blockIndex);
|
|
6191
|
+
function stackedTitleLayout(viewport, orientation) {
|
|
6192
|
+
if (orientation === "portrait") {
|
|
6193
|
+
return {
|
|
6194
|
+
contentRect: rect(viewport, 0.06, 0.04, 0.88, 0.3),
|
|
6195
|
+
mediaRect: rect(viewport, 0.06, 0.39, 0.88, 0.55),
|
|
6196
|
+
fontScale: 0.76
|
|
6197
|
+
};
|
|
5777
6198
|
}
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
6199
|
+
if (orientation === "square") {
|
|
6200
|
+
return {
|
|
6201
|
+
contentRect: rect(viewport, 0.05, 0.04, 0.9, 0.33),
|
|
6202
|
+
mediaRect: rect(viewport, 0.07, 0.42, 0.86, 0.51),
|
|
6203
|
+
fontScale: 0.72
|
|
6204
|
+
};
|
|
6205
|
+
}
|
|
6206
|
+
return {
|
|
6207
|
+
contentRect: rect(viewport, 0.04, 0.03, 0.92, 0.32),
|
|
6208
|
+
mediaRect: rect(viewport, 0.08, 0.4, 0.84, 0.52),
|
|
6209
|
+
fontScale: 0.72
|
|
5789
6210
|
};
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
6211
|
+
}
|
|
6212
|
+
function splitLayout(viewport, orientation) {
|
|
6213
|
+
const square = orientation === "square";
|
|
6214
|
+
return {
|
|
6215
|
+
contentRect: rect(viewport, square ? 0.05 : 0.04, 0.05, square ? 0.42 : 0.43, 0.9),
|
|
6216
|
+
mediaRect: rect(viewport, square ? 0.52 : 0.53, 0.07, square ? 0.43 : 0.43, 0.86),
|
|
6217
|
+
fontScale: 0.72
|
|
6218
|
+
};
|
|
6219
|
+
}
|
|
6220
|
+
function stackedTextLayout(viewport, orientation, dense) {
|
|
6221
|
+
if (orientation === "portrait") {
|
|
6222
|
+
return {
|
|
6223
|
+
contentRect: rect(viewport, 0.06, 0.04, 0.88, dense ? 0.41 : 0.36),
|
|
6224
|
+
mediaRect: rect(viewport, 0.06, dense ? 0.5 : 0.45, 0.88, dense ? 0.44 : 0.49),
|
|
6225
|
+
fontScale: dense ? 0.42 : 0.44
|
|
6226
|
+
};
|
|
5793
6227
|
}
|
|
5794
|
-
|
|
6228
|
+
if (orientation === "square") {
|
|
6229
|
+
return {
|
|
6230
|
+
contentRect: rect(viewport, 0.05, 0.04, 0.9, dense ? 0.43 : 0.36),
|
|
6231
|
+
mediaRect: rect(viewport, 0.07, dense ? 0.52 : 0.45, 0.86, dense ? 0.41 : 0.48),
|
|
6232
|
+
fontScale: dense ? 0.45 : 0.46
|
|
6233
|
+
};
|
|
6234
|
+
}
|
|
6235
|
+
return {
|
|
6236
|
+
contentRect: rect(viewport, 0.05, 0.03, 0.9, dense ? 0.46 : 0.35),
|
|
6237
|
+
mediaRect: rect(viewport, 0.07, dense ? 0.55 : 0.43, 0.86, dense ? 0.38 : 0.49),
|
|
6238
|
+
fontScale: dense ? 0.5 : 0.48
|
|
6239
|
+
};
|
|
5795
6240
|
}
|
|
5796
|
-
function
|
|
5797
|
-
const
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
);
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
6241
|
+
function overlayMediaRect(viewport, shape) {
|
|
6242
|
+
const orientation = getViewportOrientation(viewport);
|
|
6243
|
+
if (orientation === "portrait") {
|
|
6244
|
+
switch (shape) {
|
|
6245
|
+
case "tall":
|
|
6246
|
+
return rect(viewport, 0.55, 0.5, 0.38, 0.44);
|
|
6247
|
+
case "square":
|
|
6248
|
+
return rect(viewport, 0.49, 0.58, 0.44, 0.35);
|
|
6249
|
+
case "multiple":
|
|
6250
|
+
return rect(viewport, 0.07, 0.67, 0.86, 0.27);
|
|
6251
|
+
case "wide":
|
|
6252
|
+
return rect(viewport, 0.07, 0.71, 0.86, 0.23);
|
|
6253
|
+
}
|
|
6254
|
+
}
|
|
6255
|
+
if (orientation === "square") {
|
|
6256
|
+
switch (shape) {
|
|
6257
|
+
case "tall":
|
|
6258
|
+
return rect(viewport, 0.68, 0.1, 0.27, 0.8);
|
|
6259
|
+
case "square":
|
|
6260
|
+
return rect(viewport, 0.55, 0.52, 0.4, 0.4);
|
|
6261
|
+
case "multiple":
|
|
6262
|
+
return rect(viewport, 0.08, 0.62, 0.84, 0.31);
|
|
6263
|
+
case "wide":
|
|
6264
|
+
return rect(viewport, 0.08, 0.68, 0.84, 0.27);
|
|
6265
|
+
}
|
|
6266
|
+
}
|
|
6267
|
+
switch (shape) {
|
|
6268
|
+
case "tall":
|
|
6269
|
+
return rect(viewport, 0.7, 0.1, 0.26, 0.8);
|
|
6270
|
+
case "square":
|
|
6271
|
+
return rect(viewport, 0.62, 0.22, 0.34, 0.56);
|
|
6272
|
+
case "multiple":
|
|
6273
|
+
return rect(viewport, 0.52, 0.5, 0.44, 0.42);
|
|
6274
|
+
case "wide":
|
|
6275
|
+
return rect(viewport, 0.54, 0.58, 0.42, 0.34);
|
|
6276
|
+
}
|
|
6277
|
+
}
|
|
6278
|
+
function designedLayout(variant, viewport) {
|
|
6279
|
+
const orientation = getViewportOrientation(viewport);
|
|
6280
|
+
switch (variant) {
|
|
6281
|
+
case "title-stack":
|
|
6282
|
+
return stackedTitleLayout(viewport, orientation);
|
|
6283
|
+
case "split":
|
|
6284
|
+
return splitLayout(viewport, orientation);
|
|
6285
|
+
case "text-stack":
|
|
6286
|
+
return stackedTextLayout(viewport, orientation, false);
|
|
6287
|
+
case "dense-stack":
|
|
6288
|
+
return stackedTextLayout(viewport, orientation, true);
|
|
5833
6289
|
}
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
const remainingDuration = audioSegment.duration - fixedDuration;
|
|
5883
|
-
const scaleFactor = contentBlockDuration > 0 && remainingDuration > 0 ? remainingDuration / contentBlockDuration : 1;
|
|
5884
|
-
const expandedInfos = [];
|
|
5885
|
-
for (const { block, originalIndex } of segmentBlocks) {
|
|
5886
|
-
const expandedBlock = materializeScheduledBlock(
|
|
5887
|
-
block,
|
|
5888
|
-
originalIndex,
|
|
5889
|
-
totalBlocks,
|
|
5890
|
-
theme,
|
|
5891
|
-
viewport,
|
|
5892
|
-
effectivePersistentLayers,
|
|
5893
|
-
expandedPersistentLayers,
|
|
5894
|
-
registry,
|
|
5895
|
-
failureMode,
|
|
5896
|
-
onDiagnostic
|
|
5897
|
-
);
|
|
5898
|
-
const templateBlock = block;
|
|
5899
|
-
expandedInfos.push({
|
|
5900
|
-
block: expandedBlock,
|
|
5901
|
-
originalIndex,
|
|
5902
|
-
templateBlock,
|
|
5903
|
-
hasSourceTiming: typeof templateBlock.sourceStartTime === "number"
|
|
5904
|
-
});
|
|
5905
|
-
}
|
|
5906
|
-
const hasAnySourceTiming = expandedInfos.some((info) => info.hasSourceTiming);
|
|
5907
|
-
expandedInfos.sort((a, b) => {
|
|
5908
|
-
if (hasAnySourceTiming) {
|
|
5909
|
-
const aIsHeader = a.templateBlock.template === "sectionHeader";
|
|
5910
|
-
const bIsHeader = b.templateBlock.template === "sectionHeader";
|
|
5911
|
-
if (aIsHeader && !bIsHeader) return -1;
|
|
5912
|
-
if (!aIsHeader && bIsHeader) return 1;
|
|
5913
|
-
if (a.hasSourceTiming && b.hasSourceTiming) {
|
|
5914
|
-
return a.templateBlock.sourceStartTime - b.templateBlock.sourceStartTime;
|
|
5915
|
-
}
|
|
5916
|
-
if (a.hasSourceTiming && !b.hasSourceTiming) return -1;
|
|
5917
|
-
if (!a.hasSourceTiming && b.hasSourceTiming) return 1;
|
|
5918
|
-
}
|
|
5919
|
-
return a.originalIndex - b.originalIndex;
|
|
5920
|
-
});
|
|
5921
|
-
let offsetWithinSegment = 0;
|
|
5922
|
-
for (let i = 0; i < expandedInfos.length; i++) {
|
|
5923
|
-
const info = expandedInfos[i];
|
|
5924
|
-
const { block: expandedBlock, templateBlock } = info;
|
|
5925
|
-
if (info.hasSourceTiming) {
|
|
5926
|
-
const sourceStart = templateBlock.sourceStartTime;
|
|
5927
|
-
expandedBlock.startTime = audioSegment.startTime + sourceStart;
|
|
5928
|
-
if (typeof templateBlock.sourceDuration === "number") {
|
|
5929
|
-
expandedBlock.duration = Math.max(5, templateBlock.sourceDuration);
|
|
5930
|
-
}
|
|
5931
|
-
offsetWithinSegment = sourceStart + expandedBlock.duration;
|
|
5932
|
-
} else if (templateBlock.template === "sectionHeader") {
|
|
5933
|
-
expandedBlock.startTime = audioSegment.startTime + offsetWithinSegment;
|
|
5934
|
-
offsetWithinSegment += expandedBlock.duration;
|
|
5935
|
-
} else {
|
|
5936
|
-
expandedBlock.startTime = audioSegment.startTime + offsetWithinSegment;
|
|
5937
|
-
const scaledDuration = expandedBlock.duration * scaleFactor;
|
|
5938
|
-
expandedBlock.duration = scaledDuration;
|
|
5939
|
-
offsetWithinSegment += scaledDuration;
|
|
5940
|
-
}
|
|
5941
|
-
expandedBlocks[info.originalIndex] = expandedBlock;
|
|
5942
|
-
}
|
|
5943
|
-
const segmentExpandedBlocks = expandedInfos.map((info) => expandedBlocks[info.originalIndex]).sort((a, b) => a.startTime - b.startTime);
|
|
5944
|
-
for (let i = 0; i < segmentExpandedBlocks.length - 1; i++) {
|
|
5945
|
-
const current = segmentExpandedBlocks[i];
|
|
5946
|
-
const next = segmentExpandedBlocks[i + 1];
|
|
5947
|
-
const currentEnd = current.startTime + current.duration;
|
|
5948
|
-
if (currentEnd > next.startTime) {
|
|
5949
|
-
current.duration = next.startTime - current.startTime;
|
|
5950
|
-
} else if (currentEnd < next.startTime - 0.5) {
|
|
5951
|
-
current.duration = Math.max(0.1, next.startTime - current.startTime);
|
|
5952
|
-
}
|
|
5953
|
-
}
|
|
5954
|
-
const MIN_TRANSITION_GAP = 5;
|
|
5955
|
-
const segmentEnd = audioSegment.startTime + audioSegment.duration;
|
|
5956
|
-
while (segmentExpandedBlocks.length > 1) {
|
|
5957
|
-
const lastBlock = segmentExpandedBlocks[segmentExpandedBlocks.length - 1];
|
|
5958
|
-
const timeFromLastToEnd = segmentEnd - lastBlock.startTime;
|
|
5959
|
-
if (timeFromLastToEnd < MIN_TRANSITION_GAP && lastBlock.template !== "sectionHeader") {
|
|
5960
|
-
const prevBlock = segmentExpandedBlocks[segmentExpandedBlocks.length - 2];
|
|
5961
|
-
prevBlock.duration = segmentEnd - prevBlock.startTime;
|
|
5962
|
-
lastBlock.duration = 0;
|
|
5963
|
-
lastBlock.startTime = segmentEnd;
|
|
5964
|
-
segmentExpandedBlocks.pop();
|
|
5965
|
-
} else {
|
|
5966
|
-
if (lastBlock.startTime + lastBlock.duration < segmentEnd) {
|
|
5967
|
-
lastBlock.duration = segmentEnd - lastBlock.startTime;
|
|
6290
|
+
}
|
|
6291
|
+
function resolvePositionValue(value, dimension) {
|
|
6292
|
+
if (value === void 0) return 0;
|
|
6293
|
+
if (typeof value === "number") return value;
|
|
6294
|
+
const percent = value.match(/^\s*(-?\d+(?:\.\d+)?)%\s*$/);
|
|
6295
|
+
if (percent) return Number(percent[1]) / 100 * dimension;
|
|
6296
|
+
const numeric = Number.parseFloat(value);
|
|
6297
|
+
return Number.isFinite(numeric) ? numeric : 0;
|
|
6298
|
+
}
|
|
6299
|
+
function isZero(value) {
|
|
6300
|
+
return value === 0 || value === "0" || value === "0%";
|
|
6301
|
+
}
|
|
6302
|
+
function isFullViewportBackground(layer, viewport) {
|
|
6303
|
+
if (layer.type !== "shape" && layer.type !== "image") return false;
|
|
6304
|
+
const { position } = layer;
|
|
6305
|
+
const fullWidth = position.width === "100%" || position.width === viewport.width;
|
|
6306
|
+
const fullHeight = position.height === "100%" || position.height === viewport.height;
|
|
6307
|
+
return isZero(position.x) && isZero(position.y) && fullWidth && fullHeight;
|
|
6308
|
+
}
|
|
6309
|
+
function mapPosition(position, contentRect, viewport) {
|
|
6310
|
+
const mapped = {
|
|
6311
|
+
...position,
|
|
6312
|
+
x: contentRect.x + resolvePositionValue(position.x, viewport.width) / viewport.width * contentRect.width,
|
|
6313
|
+
y: contentRect.y + resolvePositionValue(position.y, viewport.height) / viewport.height * contentRect.height
|
|
6314
|
+
};
|
|
6315
|
+
if (position.width !== void 0) {
|
|
6316
|
+
mapped.width = resolvePositionValue(position.width, viewport.width) / viewport.width * contentRect.width;
|
|
6317
|
+
}
|
|
6318
|
+
if (position.height !== void 0) {
|
|
6319
|
+
mapped.height = resolvePositionValue(position.height, viewport.height) / viewport.height * contentRect.height;
|
|
6320
|
+
}
|
|
6321
|
+
return mapped;
|
|
6322
|
+
}
|
|
6323
|
+
function mapForegroundLayers(layers, contentRect, viewport, fontScale, template) {
|
|
6324
|
+
const mapped = layers.map((layer) => {
|
|
6325
|
+
if (isFullViewportBackground(layer, viewport)) return layer;
|
|
6326
|
+
const position = mapPosition(layer.position, contentRect, viewport);
|
|
6327
|
+
if (layer.type === "text") {
|
|
6328
|
+
return {
|
|
6329
|
+
...layer,
|
|
6330
|
+
position,
|
|
6331
|
+
content: {
|
|
6332
|
+
...layer.content,
|
|
6333
|
+
style: {
|
|
6334
|
+
...layer.content.style,
|
|
6335
|
+
fontSize: Math.max(12, Math.round(layer.content.style.fontSize * fontScale)),
|
|
6336
|
+
...layer.content.style.padding !== void 0 ? { padding: Math.round(layer.content.style.padding * fontScale) } : {}
|
|
6337
|
+
}
|
|
5968
6338
|
}
|
|
5969
|
-
|
|
5970
|
-
}
|
|
6339
|
+
};
|
|
5971
6340
|
}
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
6341
|
+
return { ...layer, position };
|
|
6342
|
+
});
|
|
6343
|
+
return arrangeTitleFamily(mapped, template, contentRect, viewport);
|
|
6344
|
+
}
|
|
6345
|
+
function arrangeTitleFamily(layers, template, contentRect, viewport) {
|
|
6346
|
+
const centerX = contentRect.x + contentRect.width / 2;
|
|
6347
|
+
const centerY = contentRect.y + contentRect.height / 2;
|
|
6348
|
+
if (template === "sectionHeader") {
|
|
6349
|
+
return layers.map((layer) => {
|
|
6350
|
+
if (layer.id === "title") {
|
|
6351
|
+
return {
|
|
6352
|
+
...layer,
|
|
6353
|
+
position: {
|
|
6354
|
+
...layer.position,
|
|
6355
|
+
x: centerX,
|
|
6356
|
+
y: centerY,
|
|
6357
|
+
width: contentRect.width * 0.9,
|
|
6358
|
+
anchor: "center"
|
|
6359
|
+
}
|
|
6360
|
+
};
|
|
5976
6361
|
}
|
|
6362
|
+
if (layer.id === "line-top" || layer.id === "line-bottom") {
|
|
6363
|
+
const direction = layer.id === "line-top" ? -1 : 1;
|
|
6364
|
+
return {
|
|
6365
|
+
...layer,
|
|
6366
|
+
position: {
|
|
6367
|
+
...layer.position,
|
|
6368
|
+
x: centerX,
|
|
6369
|
+
y: centerY + direction * contentRect.height * 0.28,
|
|
6370
|
+
width: Math.min(contentRect.width * 0.22, viewport.width * 0.2),
|
|
6371
|
+
height: 2,
|
|
6372
|
+
anchor: "center"
|
|
6373
|
+
}
|
|
6374
|
+
};
|
|
6375
|
+
}
|
|
6376
|
+
return layer;
|
|
6377
|
+
});
|
|
6378
|
+
}
|
|
6379
|
+
if (template !== "title") return layers;
|
|
6380
|
+
const title = layers.find((layer) => layer.type === "text" && layer.id === "title");
|
|
6381
|
+
const subtitle = layers.find((layer) => layer.type === "text" && layer.id === "subtitle");
|
|
6382
|
+
if (!title || title.type !== "text") return layers;
|
|
6383
|
+
const subtitleText = subtitle?.type === "text" ? subtitle : void 0;
|
|
6384
|
+
const maxWidth = contentRect.width * 0.9;
|
|
6385
|
+
const decorationGap = Math.max(12, Math.min(viewport.width, viewport.height) * 0.018);
|
|
6386
|
+
const textGap = subtitleText ? decorationGap : 0;
|
|
6387
|
+
const availableHeight = contentRect.height * 0.78;
|
|
6388
|
+
let titleFontSize = title.content.style.fontSize;
|
|
6389
|
+
let subtitleFontSize = subtitleText?.content.style.fontSize ?? 0;
|
|
6390
|
+
const measure = () => {
|
|
6391
|
+
const titleHeight = estimateTextHeight(
|
|
6392
|
+
title.content.text,
|
|
6393
|
+
titleFontSize,
|
|
6394
|
+
maxWidth,
|
|
6395
|
+
title.content.style.lineHeight ?? 1.15
|
|
6396
|
+
);
|
|
6397
|
+
const subtitleHeight = subtitleText ? estimateTextHeight(
|
|
6398
|
+
subtitleText.content.text,
|
|
6399
|
+
subtitleFontSize,
|
|
6400
|
+
maxWidth,
|
|
6401
|
+
subtitleText.content.style.lineHeight ?? 1.5
|
|
6402
|
+
) : 0;
|
|
6403
|
+
return { titleHeight, subtitleHeight, total: titleHeight + textGap + subtitleHeight };
|
|
6404
|
+
};
|
|
6405
|
+
let measured = measure();
|
|
6406
|
+
if (measured.total > availableHeight) {
|
|
6407
|
+
const fit = Math.max(0.5, availableHeight / measured.total);
|
|
6408
|
+
titleFontSize = Math.max(18, Math.round(titleFontSize * fit));
|
|
6409
|
+
subtitleFontSize = Math.max(14, Math.round(subtitleFontSize * fit));
|
|
6410
|
+
measured = measure();
|
|
6411
|
+
}
|
|
6412
|
+
const top = contentRect.y + (contentRect.height - measured.total) / 2;
|
|
6413
|
+
const titleY = top + measured.titleHeight / 2;
|
|
6414
|
+
const subtitleY = top + measured.titleHeight + textGap + measured.subtitleHeight / 2;
|
|
6415
|
+
return layers.map((layer) => {
|
|
6416
|
+
if (layer.id === "title" && layer.type === "text") {
|
|
6417
|
+
return {
|
|
6418
|
+
...layer,
|
|
6419
|
+
position: { ...layer.position, x: centerX, y: titleY, width: maxWidth, anchor: "center" },
|
|
6420
|
+
content: {
|
|
6421
|
+
...layer.content,
|
|
6422
|
+
style: { ...layer.content.style, fontSize: titleFontSize }
|
|
6423
|
+
}
|
|
6424
|
+
};
|
|
5977
6425
|
}
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
break;
|
|
6426
|
+
if (layer.id === "subtitle" && layer.type === "text") {
|
|
6427
|
+
return {
|
|
6428
|
+
...layer,
|
|
6429
|
+
position: {
|
|
6430
|
+
...layer.position,
|
|
6431
|
+
x: centerX,
|
|
6432
|
+
y: subtitleY,
|
|
6433
|
+
width: maxWidth,
|
|
6434
|
+
anchor: "center"
|
|
6435
|
+
},
|
|
6436
|
+
content: {
|
|
6437
|
+
...layer.content,
|
|
6438
|
+
style: { ...layer.content.style, fontSize: subtitleFontSize }
|
|
5992
6439
|
}
|
|
5993
|
-
}
|
|
6440
|
+
};
|
|
5994
6441
|
}
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
id: `${block.id}-split-${p}`,
|
|
6006
|
-
startTime: block.startTime + p * partDuration,
|
|
6007
|
-
duration: partDuration,
|
|
6008
|
-
audioSegment: block.audioSegment,
|
|
6009
|
-
layers: (block.layers ?? []).map((layer) => ({
|
|
6010
|
-
...cloneData(layer),
|
|
6011
|
-
id: `${layer.id}-split-${p}`
|
|
6012
|
-
})),
|
|
6013
|
-
transition: { type: "dissolve", duration: 1 },
|
|
6014
|
-
template: block.template
|
|
6015
|
-
};
|
|
6016
|
-
expandedBlocks.push(splitBlock);
|
|
6017
|
-
}
|
|
6442
|
+
if (layer.id === "accent-line") {
|
|
6443
|
+
return {
|
|
6444
|
+
...layer,
|
|
6445
|
+
position: {
|
|
6446
|
+
...layer.position,
|
|
6447
|
+
x: centerX,
|
|
6448
|
+
y: Math.max(contentRect.y + 2, top - decorationGap * 0.75),
|
|
6449
|
+
width: Math.min(contentRect.width * 0.18, viewport.width * 0.12),
|
|
6450
|
+
height: 3,
|
|
6451
|
+
anchor: "center"
|
|
6018
6452
|
}
|
|
6019
|
-
}
|
|
6453
|
+
};
|
|
6020
6454
|
}
|
|
6021
|
-
|
|
6022
|
-
|
|
6455
|
+
return layer;
|
|
6456
|
+
});
|
|
6023
6457
|
}
|
|
6024
|
-
function
|
|
6025
|
-
|
|
6458
|
+
function positionRect(position, viewport, fallbackWidth, fallbackHeight) {
|
|
6459
|
+
const width = position.width ? resolvePositionValue(position.width, viewport.width) : fallbackWidth;
|
|
6460
|
+
const height = position.height ? resolvePositionValue(position.height, viewport.height) : fallbackHeight;
|
|
6461
|
+
let x = resolvePositionValue(position.x, viewport.width);
|
|
6462
|
+
let y = resolvePositionValue(position.y, viewport.height);
|
|
6463
|
+
const anchor = position.anchor ?? "top-left";
|
|
6464
|
+
if (anchor === "center") {
|
|
6465
|
+
x -= width / 2;
|
|
6466
|
+
y -= height / 2;
|
|
6467
|
+
} else {
|
|
6468
|
+
if (anchor.endsWith("right")) x -= width;
|
|
6469
|
+
if (anchor.startsWith("bottom")) y -= height;
|
|
6470
|
+
}
|
|
6471
|
+
return { x, y, width, height };
|
|
6026
6472
|
}
|
|
6027
|
-
function
|
|
6028
|
-
|
|
6473
|
+
function overlapArea(a, b) {
|
|
6474
|
+
const width = Math.max(0, Math.min(a.x + a.width, b.x + b.width) - Math.max(a.x, b.x));
|
|
6475
|
+
const height = Math.max(0, Math.min(a.y + a.height, b.y + b.height) - Math.max(a.y, b.y));
|
|
6476
|
+
return width * height;
|
|
6029
6477
|
}
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6478
|
+
function leastObstructedMediaRect(layers, viewport) {
|
|
6479
|
+
const occupied = layers.filter((layer) => layer.type !== "shape" && layer.type !== "path" && layer.type !== "mermaid").map(
|
|
6480
|
+
(layer) => positionRect(
|
|
6481
|
+
layer.position,
|
|
6482
|
+
viewport,
|
|
6483
|
+
layer.type === "text" ? viewport.width * 0.45 : viewport.width * 0.5,
|
|
6484
|
+
layer.type === "text" ? viewport.height * 0.2 : viewport.height * 0.55
|
|
6485
|
+
)
|
|
6486
|
+
);
|
|
6487
|
+
if (occupied.length === 0) return rect(viewport, 0.06, 0.08, 0.88, 0.84);
|
|
6488
|
+
const candidates = [
|
|
6489
|
+
rect(viewport, 0.52, 0.12, 0.44, 0.76),
|
|
6490
|
+
rect(viewport, 0.04, 0.12, 0.44, 0.76),
|
|
6491
|
+
rect(viewport, 0.15, 0.53, 0.7, 0.41)
|
|
6492
|
+
];
|
|
6493
|
+
return candidates.reduce((best, candidate) => {
|
|
6494
|
+
const score = occupied.reduce((sum, item) => sum + overlapArea(candidate, item), 0);
|
|
6495
|
+
const bestScore = occupied.reduce((sum, item) => sum + overlapArea(best, item), 0);
|
|
6496
|
+
return score < bestScore ? candidate : best;
|
|
6497
|
+
});
|
|
6038
6498
|
}
|
|
6039
|
-
function
|
|
6499
|
+
function resolveSupplementalMediaLayout(layers, template, viewport, mediaCount, aspectRatios) {
|
|
6500
|
+
const policy = getBlockMediaLayoutPolicy(template);
|
|
6501
|
+
const shape = mediaShape(mediaCount, aspectRatios);
|
|
6502
|
+
const alreadyOwnsMedia = layers.some(
|
|
6503
|
+
(layer) => layer.type === "image" || layer.type === "video" || layer.type === "map" || layer.type === "mermaid"
|
|
6504
|
+
);
|
|
6505
|
+
const retainNativeLayout = policy?.unconsumedMedia === "retain-native-layout" || policy?.unconsumedMedia === "reserve-when-no-native-media" && alreadyOwnsMedia;
|
|
6506
|
+
if (policy?.additionalMediaLayout === "overlay-inset" && retainNativeLayout) {
|
|
6507
|
+
return {
|
|
6508
|
+
layers,
|
|
6509
|
+
mediaRect: overlayMediaRect(viewport, shape),
|
|
6510
|
+
framed: true
|
|
6511
|
+
};
|
|
6512
|
+
}
|
|
6513
|
+
const canReserve = policy?.unconsumedMedia === "reserved-slot" || policy?.unconsumedMedia === "reserve-when-no-native-media" && !alreadyOwnsMedia;
|
|
6514
|
+
if (!policy || !canReserve || !policy.variants) {
|
|
6515
|
+
return {
|
|
6516
|
+
layers,
|
|
6517
|
+
mediaRect: leastObstructedMediaRect(layers, viewport),
|
|
6518
|
+
framed: false
|
|
6519
|
+
};
|
|
6520
|
+
}
|
|
6521
|
+
const orientation = getViewportOrientation(viewport);
|
|
6522
|
+
const layout = designedLayout(policy.variants[orientation][shape], viewport);
|
|
6040
6523
|
return {
|
|
6041
|
-
|
|
6042
|
-
|
|
6524
|
+
layers: mapForegroundLayers(
|
|
6525
|
+
layers,
|
|
6526
|
+
layout.contentRect,
|
|
6527
|
+
viewport,
|
|
6528
|
+
layout.fontScale,
|
|
6529
|
+
template ?? ""
|
|
6530
|
+
),
|
|
6531
|
+
mediaRect: layout.mediaRect,
|
|
6532
|
+
framed: true
|
|
6043
6533
|
};
|
|
6044
6534
|
}
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
w: n.wCols * ASCII_CHAR_W,
|
|
6051
|
-
h: n.hRows * ASCII_CHAR_H,
|
|
6052
|
-
...n.containerId ? { container: n.containerId } : {}
|
|
6053
|
-
}));
|
|
6054
|
-
const anchors = inferEdgeAnchors(nodes, diagram.edges);
|
|
6055
|
-
const edges = diagram.edges.map((e, index) => ({
|
|
6056
|
-
source: e.source,
|
|
6057
|
-
target: e.target,
|
|
6058
|
-
...e.label ? { label: e.label } : {},
|
|
6059
|
-
...e.directed ? {} : { directed: false },
|
|
6060
|
-
...anchors[index],
|
|
6061
|
-
routing: "orthogonal"
|
|
6062
|
-
}));
|
|
6063
|
-
return { nodes, edges };
|
|
6535
|
+
|
|
6536
|
+
// src/doc/materializeBlockLayers.ts
|
|
6537
|
+
function materializeBlockLayers(block, options = {}) {
|
|
6538
|
+
const registry = options.customTemplates && options.customTemplates.length > 0 ? buildRegistry(options.customTemplates) : templateRegistry;
|
|
6539
|
+
return materializeBlockLayersWithRuntime(block, options, { registry });
|
|
6064
6540
|
}
|
|
6065
|
-
function
|
|
6066
|
-
const
|
|
6067
|
-
const
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6541
|
+
function materializeBlockLayersWithRuntime(block, options, runtime) {
|
|
6542
|
+
const theme = options.theme ?? DEFAULT_THEME;
|
|
6543
|
+
const viewport = options.viewport ?? VIEWPORT_PRESETS.landscape;
|
|
6544
|
+
const blockIndex = options.blockIndex ?? 0;
|
|
6545
|
+
const totalBlocks = options.totalBlocks ?? 1;
|
|
6546
|
+
const effectivePersistentLayers = options.persistentLayers === false ? void 0 : options.persistentLayers ?? theme.persistentLayers;
|
|
6547
|
+
const existingLayers = block.layers;
|
|
6548
|
+
if (existingLayers && existingLayers.length > 0 && !isTemplateBlock(block)) {
|
|
6549
|
+
const layers = appendRichContentLayers(
|
|
6550
|
+
cloneData(existingLayers),
|
|
6551
|
+
block,
|
|
6552
|
+
theme,
|
|
6553
|
+
viewport
|
|
6554
|
+
);
|
|
6555
|
+
return {
|
|
6556
|
+
layers: injectPersistentLayers(
|
|
6557
|
+
layers,
|
|
6558
|
+
block,
|
|
6559
|
+
theme,
|
|
6560
|
+
effectivePersistentLayers,
|
|
6561
|
+
runtime.expandedPersistentLayers
|
|
6562
|
+
),
|
|
6563
|
+
source: "authored"
|
|
6564
|
+
};
|
|
6565
|
+
}
|
|
6566
|
+
if (!isTemplateBlock(block)) {
|
|
6567
|
+
const layers = appendRichContentLayers([], block, theme, viewport);
|
|
6568
|
+
return {
|
|
6569
|
+
layers: injectPersistentLayers(
|
|
6570
|
+
layers,
|
|
6571
|
+
block,
|
|
6572
|
+
theme,
|
|
6573
|
+
effectivePersistentLayers,
|
|
6574
|
+
runtime.expandedPersistentLayers
|
|
6575
|
+
),
|
|
6576
|
+
source: layers.length > 0 ? "rich-content" : "empty"
|
|
6099
6577
|
};
|
|
6100
|
-
});
|
|
6101
|
-
distributeOffsets(pairs, edges, nodes, "source");
|
|
6102
|
-
distributeOffsets(pairs, edges, nodes, "target");
|
|
6103
|
-
return pairs;
|
|
6104
|
-
}
|
|
6105
|
-
function distributeOffsets(pairs, edges, nodes, endpoint) {
|
|
6106
|
-
const nodeById = new Map(nodes.map((node) => [node.id, node]));
|
|
6107
|
-
const groups = /* @__PURE__ */ new Map();
|
|
6108
|
-
for (let index = 0; index < edges.length; index++) {
|
|
6109
|
-
const edge = edges[index];
|
|
6110
|
-
const anchor = endpoint === "source" ? pairs[index].sourceAnchor : pairs[index].targetAnchor;
|
|
6111
|
-
const nodeId = endpoint === "source" ? edge.source : edge.target;
|
|
6112
|
-
const key = `${nodeId}:${anchor.side}`;
|
|
6113
|
-
const group = groups.get(key) ?? [];
|
|
6114
|
-
group.push(index);
|
|
6115
|
-
groups.set(key, group);
|
|
6116
6578
|
}
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6579
|
+
const context = runtime.templateContext ? cloneData(runtime.templateContext) : createTemplateContext(theme, blockIndex, totalBlocks, viewport);
|
|
6580
|
+
context.block = cloneData(block);
|
|
6581
|
+
const execution = executeTemplateMaterialization(block, context, runtime.registry);
|
|
6582
|
+
if (execution.status === "ok") {
|
|
6583
|
+
const styledLayers = runtime.applyRenderStyle !== false ? applyRenderStyleToLayers(execution.layers, block, theme) : execution.layers;
|
|
6584
|
+
const layers = appendRichContentLayers(styledLayers, block, theme, viewport);
|
|
6585
|
+
return {
|
|
6586
|
+
layers: injectPersistentLayers(
|
|
6587
|
+
layers,
|
|
6588
|
+
block,
|
|
6589
|
+
theme,
|
|
6590
|
+
effectivePersistentLayers,
|
|
6591
|
+
runtime.expandedPersistentLayers
|
|
6592
|
+
),
|
|
6593
|
+
source: "template"
|
|
6594
|
+
};
|
|
6131
6595
|
}
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
const outNodes = nodes.map((n) => {
|
|
6136
|
-
const { col, row } = canvasToAsciiCell(n.x, n.y);
|
|
6137
|
-
const labelLines = n.label.length > 0 ? n.label.split("\n") : [];
|
|
6138
|
-
const innerW = labelLines.reduce((w, l) => Math.max(w, l.length), 0);
|
|
6139
|
-
const wCols = typeof n.w === "number" ? Math.max(3, Math.round(n.w / ASCII_CHAR_W)) : innerW + 4;
|
|
6140
|
-
const hRows = typeof n.h === "number" ? Math.max(3, Math.round(n.h / ASCII_CHAR_H)) : labelLines.length + 2;
|
|
6596
|
+
const diagnostic = toLayerMaterializationDiagnostic(block.template, execution);
|
|
6597
|
+
if ((options.failureMode ?? "fallback") === "empty") {
|
|
6598
|
+
const layers = appendRichContentLayers([], block, theme, viewport);
|
|
6141
6599
|
return {
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6600
|
+
layers: injectPersistentLayers(
|
|
6601
|
+
layers,
|
|
6602
|
+
block,
|
|
6603
|
+
theme,
|
|
6604
|
+
effectivePersistentLayers,
|
|
6605
|
+
runtime.expandedPersistentLayers
|
|
6606
|
+
),
|
|
6607
|
+
source: layers.length > 0 ? "rich-content" : "empty",
|
|
6608
|
+
diagnostic
|
|
6149
6609
|
};
|
|
6150
|
-
}
|
|
6610
|
+
}
|
|
6611
|
+
const fallbackLayers = appendRichContentLayers(
|
|
6612
|
+
fallbackBlockLayers(block, context, diagnostic.message),
|
|
6613
|
+
block,
|
|
6614
|
+
theme,
|
|
6615
|
+
viewport
|
|
6616
|
+
);
|
|
6151
6617
|
return {
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6618
|
+
layers: injectPersistentLayers(
|
|
6619
|
+
fallbackLayers,
|
|
6620
|
+
block,
|
|
6621
|
+
theme,
|
|
6622
|
+
effectivePersistentLayers,
|
|
6623
|
+
runtime.expandedPersistentLayers
|
|
6624
|
+
),
|
|
6625
|
+
source: "fallback",
|
|
6626
|
+
diagnostic
|
|
6161
6627
|
};
|
|
6162
6628
|
}
|
|
6163
|
-
function
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
label: n.label,
|
|
6168
|
-
x: n.x,
|
|
6169
|
-
y: n.y
|
|
6170
|
-
}));
|
|
6171
|
-
const edges = layout.edges.map((e) => ({
|
|
6172
|
-
source: e.source,
|
|
6173
|
-
target: e.target,
|
|
6174
|
-
...e.type ? { label: e.type } : {}
|
|
6175
|
-
}));
|
|
6176
|
-
const diagram = asciiDiagramFromTemplateData(nodes, edges, options);
|
|
6177
|
-
diagram.warnings.push(...layout.warnings);
|
|
6178
|
-
return diagram;
|
|
6629
|
+
function mermaidSources(block) {
|
|
6630
|
+
return (block.contents ?? []).filter(
|
|
6631
|
+
(node) => node.type === "code" && node.lang?.trim().toLowerCase() === "mermaid"
|
|
6632
|
+
).map((node) => node.value).filter((source) => source.trim().length > 0);
|
|
6179
6633
|
}
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
const
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6634
|
+
function collectRichMediaItems(layers, block) {
|
|
6635
|
+
const existingImages = new Set(
|
|
6636
|
+
layers.filter((layer) => layer.type === "image").map((layer) => layer.content.src)
|
|
6637
|
+
);
|
|
6638
|
+
const existingVideos = new Set(
|
|
6639
|
+
layers.filter((layer) => layer.type === "video").map((layer) => layer.content.src)
|
|
6640
|
+
);
|
|
6641
|
+
const existingMermaid = new Set(
|
|
6642
|
+
layers.filter((layer) => layer.type === "mermaid").map((layer) => layer.content.source)
|
|
6643
|
+
);
|
|
6644
|
+
const embeddedVideos = extractEmbeddedVideos(block.contents);
|
|
6645
|
+
const videos = embeddedVideos.filter((video) => !existingVideos.has(video.src));
|
|
6646
|
+
const videoSources = new Set(embeddedVideos.map((video) => video.src));
|
|
6647
|
+
const seenImages = new Set(existingImages);
|
|
6648
|
+
const images = extractImages(block.contents).filter((image) => {
|
|
6649
|
+
if (videoSources.has(image.src) || seenImages.has(image.src)) return false;
|
|
6650
|
+
seenImages.add(image.src);
|
|
6651
|
+
return true;
|
|
6652
|
+
});
|
|
6653
|
+
const sources = mermaidSources(block).filter((source) => !existingMermaid.has(source));
|
|
6654
|
+
return [
|
|
6655
|
+
...images.map(
|
|
6656
|
+
(image) => ({
|
|
6657
|
+
kind: "image",
|
|
6658
|
+
src: image.src,
|
|
6659
|
+
alt: image.alt,
|
|
6660
|
+
...image.width && image.height ? { aspectRatio: image.width / image.height } : {}
|
|
6200
6661
|
})
|
|
6201
|
-
)
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6662
|
+
),
|
|
6663
|
+
...videos.map(
|
|
6664
|
+
(video) => ({
|
|
6665
|
+
kind: "video",
|
|
6666
|
+
src: video.src,
|
|
6667
|
+
...video.posterSrc ? { posterSrc: video.posterSrc } : {},
|
|
6668
|
+
alt: video.alt,
|
|
6669
|
+
aspectRatio: 16 / 9
|
|
6670
|
+
})
|
|
6671
|
+
),
|
|
6672
|
+
...sources.map((source) => ({ kind: "mermaid", source, aspectRatio: 16 / 9 }))
|
|
6673
|
+
];
|
|
6213
6674
|
}
|
|
6214
|
-
function
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6675
|
+
function gridCells(region, count, viewport, inset) {
|
|
6676
|
+
const unit = Math.min(viewport.width, viewport.height);
|
|
6677
|
+
const padding = inset ? unit * 0.025 : 0;
|
|
6678
|
+
const gap = count > 1 ? unit * 0.018 : 0;
|
|
6679
|
+
const inner = {
|
|
6680
|
+
x: region.x + padding,
|
|
6681
|
+
y: region.y + padding,
|
|
6682
|
+
width: Math.max(0, region.width - padding * 2),
|
|
6683
|
+
height: Math.max(0, region.height - padding * 2)
|
|
6221
6684
|
};
|
|
6685
|
+
const columns = Math.min(
|
|
6686
|
+
count,
|
|
6687
|
+
Math.max(1, Math.ceil(Math.sqrt(count * (inner.width / Math.max(1, inner.height)))))
|
|
6688
|
+
);
|
|
6689
|
+
const rows = Math.ceil(count / columns);
|
|
6690
|
+
const width = (inner.width - gap * (columns - 1)) / columns;
|
|
6691
|
+
const height = (inner.height - gap * (rows - 1)) / rows;
|
|
6692
|
+
return Array.from({ length: count }, (_, index) => ({
|
|
6693
|
+
x: inner.x + index % columns * (width + gap),
|
|
6694
|
+
y: inner.y + Math.floor(index / columns) * (height + gap),
|
|
6695
|
+
width,
|
|
6696
|
+
height
|
|
6697
|
+
}));
|
|
6222
6698
|
}
|
|
6223
|
-
function
|
|
6224
|
-
const
|
|
6225
|
-
|
|
6226
|
-
}
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
return {
|
|
6230
|
-
id: typeof item.id === "string" && item.id ? item.id : "node",
|
|
6231
|
-
label: typeof item.label === "string" ? item.label : "",
|
|
6232
|
-
children,
|
|
6233
|
-
isDir: item.isDir === true || children.length > 0,
|
|
6234
|
-
...item.comment ? { comment: item.comment } : {}
|
|
6235
|
-
};
|
|
6699
|
+
function effectiveImageTreatment(theme, block) {
|
|
6700
|
+
const override = block.imageTreatment;
|
|
6701
|
+
if (override === "none") return void 0;
|
|
6702
|
+
const base = override ? { type: override, strength: theme.style.imageTreatment?.strength } : theme.style.imageTreatment;
|
|
6703
|
+
if (!base || base.type === "none") return void 0;
|
|
6704
|
+
return base.type === "duotone" && !base.color ? { ...base, color: theme.colors.primary } : base;
|
|
6236
6705
|
}
|
|
6237
|
-
function
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
const idFor = (label) => {
|
|
6241
|
-
const base = slugify2(label.replace(/\/$/, ""));
|
|
6242
|
-
const count = usedIds.get(base) ?? 0;
|
|
6243
|
-
usedIds.set(base, count + 1);
|
|
6244
|
-
return count === 0 ? base : `${base}-${count + 1}`;
|
|
6245
|
-
};
|
|
6246
|
-
const itemToNode = (item) => {
|
|
6247
|
-
const labelNode = item.children.find((c) => c.type !== "list");
|
|
6248
|
-
const label = labelNode ? extractPlainText(labelNode).trim() : "";
|
|
6249
|
-
const childLists = item.children.filter((c) => c.type === "list");
|
|
6250
|
-
const children = [];
|
|
6251
|
-
for (const cl of childLists) for (const ci of cl.children) children.push(itemToNode(ci));
|
|
6706
|
+
function richMediaLayer(item, position, block, theme, kindIndex) {
|
|
6707
|
+
if (item.kind === "image") {
|
|
6708
|
+
const treatment = effectiveImageTreatment(theme, block);
|
|
6252
6709
|
return {
|
|
6253
|
-
id:
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6710
|
+
id: `${block.id}-embedded-image-${kindIndex}`,
|
|
6711
|
+
type: "image",
|
|
6712
|
+
position,
|
|
6713
|
+
content: {
|
|
6714
|
+
src: item.src,
|
|
6715
|
+
alt: item.alt || block.title || "Embedded image",
|
|
6716
|
+
fit: "contain",
|
|
6717
|
+
...treatment ? { treatment } : {}
|
|
6718
|
+
}
|
|
6257
6719
|
};
|
|
6258
|
-
}
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
if (!contents) return [];
|
|
6272
|
-
const items = [];
|
|
6273
|
-
for (const node of contents) {
|
|
6274
|
-
if (node.type === "list") {
|
|
6275
|
-
for (const item of node.children) {
|
|
6276
|
-
const text = extractPlainText(item).trim();
|
|
6277
|
-
if (text) items.push(text);
|
|
6720
|
+
}
|
|
6721
|
+
if (item.kind === "video") {
|
|
6722
|
+
return {
|
|
6723
|
+
id: `${block.id}-embedded-video-${kindIndex}`,
|
|
6724
|
+
type: "video",
|
|
6725
|
+
position,
|
|
6726
|
+
content: {
|
|
6727
|
+
src: item.src,
|
|
6728
|
+
...item.posterSrc ? { posterSrc: item.posterSrc } : {},
|
|
6729
|
+
alt: item.alt || block.title || "Embedded video",
|
|
6730
|
+
fit: "contain",
|
|
6731
|
+
clipStart: 0,
|
|
6732
|
+
clipEnd: Math.max(0, block.duration)
|
|
6278
6733
|
}
|
|
6279
|
-
}
|
|
6734
|
+
};
|
|
6280
6735
|
}
|
|
6281
|
-
return
|
|
6282
|
-
}
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6736
|
+
return {
|
|
6737
|
+
id: `${block.id}-mermaid-${kindIndex}`,
|
|
6738
|
+
type: "mermaid",
|
|
6739
|
+
position,
|
|
6740
|
+
content: {
|
|
6741
|
+
source: item.source,
|
|
6742
|
+
background: theme.colors.backgroundLight,
|
|
6743
|
+
foreground: theme.colors.text,
|
|
6744
|
+
padding: Math.max(12, Math.round(Math.min(position.width, position.height) * 0.025))
|
|
6745
|
+
}
|
|
6746
|
+
};
|
|
6287
6747
|
}
|
|
6288
|
-
function
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6748
|
+
function appendRichContentLayers(layers, block, theme, viewport) {
|
|
6749
|
+
const items = collectRichMediaItems(layers, block);
|
|
6750
|
+
if (items.length === 0) return layers;
|
|
6751
|
+
const layout = resolveSupplementalMediaLayout(
|
|
6752
|
+
layers,
|
|
6753
|
+
block.template ? resolveTemplateName(block.template) : void 0,
|
|
6754
|
+
viewport,
|
|
6755
|
+
items.length,
|
|
6756
|
+
items.map((item) => item.aspectRatio)
|
|
6757
|
+
);
|
|
6758
|
+
const cells = gridCells(layout.mediaRect, items.length, viewport, layout.framed);
|
|
6759
|
+
const counters = { image: 0, video: 0, mermaid: 0 };
|
|
6760
|
+
const mediaLayers = items.map((item, index) => {
|
|
6761
|
+
counters[item.kind] += 1;
|
|
6762
|
+
return richMediaLayer(item, cells[index], block, theme, counters[item.kind]);
|
|
6763
|
+
});
|
|
6764
|
+
const frame = layout.framed ? {
|
|
6765
|
+
id: `${block.id}-rich-media-frame`,
|
|
6766
|
+
type: "shape",
|
|
6767
|
+
position: layout.mediaRect,
|
|
6768
|
+
content: {
|
|
6769
|
+
shape: "rect",
|
|
6770
|
+
fill: theme.colors.backgroundLight,
|
|
6771
|
+
stroke: withAlpha(theme.colors.text, 0.14),
|
|
6772
|
+
strokeWidth: 2,
|
|
6773
|
+
borderRadius: Math.max(12, Math.round(Math.min(viewport.width, viewport.height) * 0.018))
|
|
6308
6774
|
}
|
|
6775
|
+
} : void 0;
|
|
6776
|
+
return [...layout.layers, ...frame ? [frame] : [], ...mediaLayers];
|
|
6777
|
+
}
|
|
6778
|
+
function executeTemplateMaterialization(templateBlock, context, registry) {
|
|
6779
|
+
const safeTemplateBlock = cloneData(templateBlock);
|
|
6780
|
+
const safeContext = cloneData(context);
|
|
6781
|
+
const maybeChildren = safeTemplateBlock.children;
|
|
6782
|
+
if ((!safeContext.children || safeContext.children.length === 0) && maybeChildren?.length) {
|
|
6783
|
+
safeContext.children = maybeChildren;
|
|
6309
6784
|
}
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
|
|
6785
|
+
const templateFn = registry[resolveTemplateName(safeTemplateBlock.template)];
|
|
6786
|
+
if (!templateFn) return { status: "unknown-template", layers: [] };
|
|
6787
|
+
const { templateData, templateOverrides } = safeTemplateBlock;
|
|
6788
|
+
const sourceBlock = safeTemplateBlock;
|
|
6789
|
+
const derivedInputs = sourceBlock.sourceHeading ? deriveTemplateInputs(
|
|
6790
|
+
safeTemplateBlock.template,
|
|
6791
|
+
sourceBlock.title ?? "",
|
|
6792
|
+
sourceBlock.contents
|
|
6793
|
+
) : null;
|
|
6794
|
+
const coercedOverrides = coerceTemplateParams(
|
|
6795
|
+
safeTemplateBlock.template,
|
|
6796
|
+
templateOverrides ?? {}
|
|
6797
|
+
).input;
|
|
6798
|
+
const input = derivedInputs || templateData || templateOverrides ? {
|
|
6799
|
+
...derivedInputs,
|
|
6800
|
+
...safeTemplateBlock,
|
|
6801
|
+
...templateData,
|
|
6802
|
+
...coercedOverrides
|
|
6803
|
+
} : safeTemplateBlock;
|
|
6804
|
+
const explicitQuote = Object.prototype.hasOwnProperty.call(coercedOverrides, "quote") ? coercedOverrides.quote : Object.prototype.hasOwnProperty.call(templateData ?? {}, "quote") ? templateData?.quote : Object.prototype.hasOwnProperty.call(safeTemplateBlock, "quote") ? safeTemplateBlock.quote : void 0;
|
|
6805
|
+
if (resolveTemplateName(safeTemplateBlock.template) === "quote" && derivedInputs && !Object.prototype.hasOwnProperty.call(derivedInputs, "title") && !(typeof explicitQuote === "string" && explicitQuote.trim())) {
|
|
6806
|
+
const quoteInput = input;
|
|
6807
|
+
quoteInput.quote = derivedInputs.quote;
|
|
6808
|
+
if (!Object.prototype.hasOwnProperty.call(templateData ?? {}, "title") && !Object.prototype.hasOwnProperty.call(coercedOverrides, "title")) {
|
|
6809
|
+
delete quoteInput.title;
|
|
6320
6810
|
}
|
|
6321
|
-
|
|
6322
|
-
|
|
6811
|
+
}
|
|
6812
|
+
try {
|
|
6813
|
+
const renderedLayers = templateFn(input, safeContext);
|
|
6814
|
+
if (!Array.isArray(renderedLayers)) {
|
|
6815
|
+
return {
|
|
6816
|
+
status: "invalid-result",
|
|
6817
|
+
layers: [],
|
|
6818
|
+
receivedType: typeof renderedLayers
|
|
6819
|
+
};
|
|
6323
6820
|
}
|
|
6821
|
+
return { status: "ok", layers: cloneData(renderedLayers) };
|
|
6822
|
+
} catch (error) {
|
|
6823
|
+
return { status: "error", layers: [], error };
|
|
6324
6824
|
}
|
|
6325
|
-
|
|
6326
|
-
|
|
6327
|
-
|
|
6825
|
+
}
|
|
6826
|
+
function toLayerMaterializationDiagnostic(template, execution) {
|
|
6827
|
+
if (execution.status === "unknown-template") {
|
|
6828
|
+
return {
|
|
6829
|
+
code: "unknown-template",
|
|
6830
|
+
template,
|
|
6831
|
+
message: `Unknown template "${template}"`
|
|
6832
|
+
};
|
|
6328
6833
|
}
|
|
6329
|
-
|
|
6834
|
+
if (execution.status === "invalid-result") {
|
|
6835
|
+
return {
|
|
6836
|
+
code: "invalid-template-result",
|
|
6837
|
+
template,
|
|
6838
|
+
receivedType: execution.receivedType,
|
|
6839
|
+
message: `Template "${template}" returned ${execution.receivedType}, not a layer array`
|
|
6840
|
+
};
|
|
6841
|
+
}
|
|
6842
|
+
return {
|
|
6843
|
+
code: "template-error",
|
|
6844
|
+
template,
|
|
6845
|
+
cause: execution.error,
|
|
6846
|
+
message: `Template "${template}" failed`
|
|
6847
|
+
};
|
|
6330
6848
|
}
|
|
6331
|
-
function
|
|
6332
|
-
|
|
6849
|
+
function injectPersistentLayers(layers, block, theme, persistentLayers, expanded) {
|
|
6850
|
+
if (!persistentLayers) return layers;
|
|
6851
|
+
const bottomLayers = expanded?.bottomLayers ?? expandPersistentLayers(persistentLayers.bottomLayers, theme);
|
|
6852
|
+
const topLayers = expanded?.topLayers ?? expandPersistentLayers(persistentLayers.topLayers, theme);
|
|
6853
|
+
return wrapWithPersistentLayers(layers, block, bottomLayers, topLayers);
|
|
6333
6854
|
}
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6855
|
+
|
|
6856
|
+
// src/doc/templates/metadata.ts
|
|
6857
|
+
var TEMPLATE_METADATA = {
|
|
6858
|
+
title: {
|
|
6859
|
+
label: "Title",
|
|
6860
|
+
description: "A bold opening slide with large title text, perfect for covers and chapters."
|
|
6861
|
+
},
|
|
6862
|
+
sectionHeader: {
|
|
6863
|
+
label: "Section Header",
|
|
6864
|
+
description: "A clean section break with a prominent title and optional subtitle."
|
|
6865
|
+
},
|
|
6866
|
+
statHighlight: {
|
|
6867
|
+
label: "Stat Highlight",
|
|
6868
|
+
description: "Showcases a single key number or metric with supporting context."
|
|
6869
|
+
},
|
|
6870
|
+
quote: {
|
|
6871
|
+
label: "Quote",
|
|
6872
|
+
description: "Displays a stylized pull quote with decorative marks and attribution."
|
|
6873
|
+
},
|
|
6874
|
+
factCard: {
|
|
6875
|
+
label: "Fact Card",
|
|
6876
|
+
description: "Presents a focused fact or insight with a labeled header and body text."
|
|
6877
|
+
},
|
|
6878
|
+
twoColumn: {
|
|
6879
|
+
label: "Two Column",
|
|
6880
|
+
description: "Divides the slide into two equal side-by-side content columns."
|
|
6881
|
+
},
|
|
6882
|
+
dateEvent: {
|
|
6883
|
+
label: "Date Event",
|
|
6884
|
+
description: "Highlights a date-based event or milestone with a prominent date display."
|
|
6885
|
+
},
|
|
6886
|
+
imageWithCaption: {
|
|
6887
|
+
label: "Image with Caption",
|
|
6888
|
+
description: "Displays a full-bleed image with an optional caption below."
|
|
6889
|
+
},
|
|
6890
|
+
leftFeature: {
|
|
6891
|
+
label: "Left Feature",
|
|
6892
|
+
description: "Image on the left, title and body text stacked on the right."
|
|
6893
|
+
},
|
|
6894
|
+
rightFeature: {
|
|
6895
|
+
label: "Right Feature",
|
|
6896
|
+
description: "Image on the right, title and body text stacked on the left."
|
|
6897
|
+
},
|
|
6898
|
+
map: {
|
|
6899
|
+
label: "Map",
|
|
6900
|
+
description: "Embeds an interactive map centered on a geographic location."
|
|
6901
|
+
},
|
|
6902
|
+
fullBleedQuote: {
|
|
6903
|
+
label: "Full Bleed Quote",
|
|
6904
|
+
description: "A full-width quote that spans the entire slide for maximum impact."
|
|
6905
|
+
},
|
|
6906
|
+
list: {
|
|
6907
|
+
label: "List",
|
|
6908
|
+
description: "Renders a bulleted or numbered list in a clean, card-style layout."
|
|
6909
|
+
},
|
|
6910
|
+
photoGrid: {
|
|
6911
|
+
label: "Photo Grid",
|
|
6912
|
+
description: "Arranges multiple photos in a 2\xD72 or 3\xD73 mosaic grid."
|
|
6913
|
+
},
|
|
6914
|
+
definitionCard: {
|
|
6915
|
+
label: "Definition Card",
|
|
6916
|
+
description: "Shows a term and its definition in a structured, dictionary-style card."
|
|
6917
|
+
},
|
|
6918
|
+
comparisonBar: {
|
|
6919
|
+
label: "Comparison Bar",
|
|
6920
|
+
description: "Visualizes two or more values side-by-side with labeled horizontal bars."
|
|
6921
|
+
},
|
|
6922
|
+
pullQuote: {
|
|
6923
|
+
label: "Pull Quote",
|
|
6924
|
+
description: "A stylized pull quote with large decorative marks and centered text."
|
|
6925
|
+
},
|
|
6926
|
+
videoWithCaption: {
|
|
6927
|
+
label: "Video with Caption",
|
|
6928
|
+
description: "Embeds a video player with an optional caption below."
|
|
6929
|
+
},
|
|
6930
|
+
videoPullQuote: {
|
|
6931
|
+
label: "Video Pull Quote",
|
|
6932
|
+
description: "Combines a video panel with a highlighted pull quote side-by-side."
|
|
6933
|
+
},
|
|
6934
|
+
dataTable: {
|
|
6935
|
+
label: "Data Table",
|
|
6936
|
+
description: "Renders tabular data in a clean, styled table with a header row."
|
|
6937
|
+
},
|
|
6938
|
+
diagram: {
|
|
6939
|
+
label: "Diagram",
|
|
6940
|
+
description: "Renders sub-headings as connected nodes \u2014 edit visually as a node-and-edge diagram."
|
|
6941
|
+
},
|
|
6942
|
+
tree: {
|
|
6943
|
+
label: "Tree",
|
|
6944
|
+
description: "Renders an ASCII file-tree / outline fence as a filesystem-style treeview \u2014 edit as an outline."
|
|
6945
|
+
},
|
|
6946
|
+
timeline: {
|
|
6947
|
+
label: "Timeline",
|
|
6948
|
+
description: "Plots events across one or more horizontal tracks with callouts and optional branching links."
|
|
6949
|
+
},
|
|
6950
|
+
layout: {
|
|
6951
|
+
label: "Layout",
|
|
6952
|
+
description: "Free-form 2D canvas \u2014 drag layers into place. Use for one-off block layouts that don't fit a template."
|
|
6953
|
+
},
|
|
6954
|
+
drawing: {
|
|
6955
|
+
label: "Drawing",
|
|
6956
|
+
description: "Free-form sketches \u2014 draw shapes, paths, and text directly on a 2D surface."
|
|
6957
|
+
}
|
|
6958
|
+
};
|
|
6959
|
+
|
|
6960
|
+
// src/doc/templates/coverBlock.ts
|
|
6961
|
+
var COVER_TITLE_BASE_PX = 120;
|
|
6962
|
+
var COVER_TITLE_COMFORTABLE_CHARS = 26;
|
|
6963
|
+
var COVER_TITLE_MIN_BASE_PX = 62;
|
|
6964
|
+
function fitCoverTitleSize(title) {
|
|
6965
|
+
const len = title.trim().length;
|
|
6966
|
+
if (len <= COVER_TITLE_COMFORTABLE_CHARS) return COVER_TITLE_BASE_PX;
|
|
6967
|
+
const scaled = COVER_TITLE_BASE_PX * Math.sqrt(COVER_TITLE_COMFORTABLE_CHARS / len);
|
|
6968
|
+
return Math.max(COVER_TITLE_MIN_BASE_PX, Math.round(scaled));
|
|
6969
|
+
}
|
|
6970
|
+
function isStandardLightCover(context) {
|
|
6971
|
+
const { theme } = context;
|
|
6972
|
+
return theme.id === "standard" && relativeLuminance(theme.colors.background) > 0.85;
|
|
6973
|
+
}
|
|
6974
|
+
var COVER_SCRIM_STOPS = [
|
|
6975
|
+
{ pos: 0, alpha: 0.95 },
|
|
6976
|
+
{ pos: 38, alpha: 0.86 },
|
|
6977
|
+
{ pos: 58, alpha: 0.4 },
|
|
6978
|
+
{ pos: 78, alpha: 0.1 },
|
|
6979
|
+
{ pos: 100, alpha: 0 }
|
|
6980
|
+
];
|
|
6981
|
+
function coverScrimGradient(background) {
|
|
6982
|
+
const stops = COVER_SCRIM_STOPS.map((s) => `${withAlpha(background, s.alpha)} ${s.pos}%`);
|
|
6983
|
+
return `linear-gradient(0deg, ${stops.join(", ")})`;
|
|
6984
|
+
}
|
|
6985
|
+
function coverBlock(input, context) {
|
|
6986
|
+
const treatment = themedImageTreatment(context, input.imageTreatment);
|
|
6987
|
+
const { heroSrc, heroAlt, title, subtitle, ambientMotion, heroCredit, heroLicense } = input;
|
|
6988
|
+
const { theme, layout } = context;
|
|
6989
|
+
const standardLightCover = !heroSrc && isStandardLightCover(context);
|
|
6990
|
+
const titleFontSize = themedFontSize(fitCoverTitleSize(title), context, true);
|
|
6991
|
+
const subtitleFontSize = themedFontSize(40, context, false);
|
|
6992
|
+
const layers = [];
|
|
6993
|
+
if (heroSrc) {
|
|
6994
|
+
const imageAnimation = mapAmbientMotion(ambientMotion);
|
|
6995
|
+
layers.push(
|
|
6996
|
+
{
|
|
6997
|
+
type: "image",
|
|
6998
|
+
id: "cover-hero",
|
|
6999
|
+
content: {
|
|
7000
|
+
src: heroSrc,
|
|
7001
|
+
alt: heroAlt || title,
|
|
7002
|
+
fit: "cover",
|
|
7003
|
+
credit: heroCredit,
|
|
7004
|
+
license: heroLicense,
|
|
7005
|
+
...treatment ? { treatment } : {}
|
|
7006
|
+
},
|
|
7007
|
+
position: { x: 0, y: 0, width: "100%", height: "100%" },
|
|
7008
|
+
animation: imageAnimation
|
|
7009
|
+
},
|
|
7010
|
+
{
|
|
7011
|
+
type: "shape",
|
|
7012
|
+
id: "cover-gradient",
|
|
7013
|
+
content: {
|
|
7014
|
+
shape: "rect",
|
|
7015
|
+
fill: coverScrimGradient(theme.colors.background)
|
|
7016
|
+
},
|
|
7017
|
+
position: { x: 0, y: 0, width: "100%", height: "100%" }
|
|
7018
|
+
}
|
|
7019
|
+
);
|
|
7020
|
+
} else {
|
|
7021
|
+
if (standardLightCover) {
|
|
7022
|
+
layers.push(
|
|
7023
|
+
{
|
|
7024
|
+
type: "shape",
|
|
7025
|
+
id: "cover-bg",
|
|
7026
|
+
content: {
|
|
7027
|
+
shape: "rect",
|
|
7028
|
+
fill: theme.colors.background
|
|
7029
|
+
},
|
|
7030
|
+
position: { x: 0, y: 0, width: "100%", height: "100%" }
|
|
7031
|
+
},
|
|
7032
|
+
{
|
|
7033
|
+
type: "shape",
|
|
7034
|
+
id: "cover-bg-tint",
|
|
7035
|
+
content: {
|
|
7036
|
+
shape: "rect",
|
|
7037
|
+
fill: `radial-gradient(ellipse at 50% 40%, ${withAlpha(theme.colors.primary, 0.16)} 0%, ${withAlpha(theme.colors.primary, 0.07)} 38%, ${withAlpha(theme.colors.primary, 0)} 78%)`
|
|
7038
|
+
},
|
|
7039
|
+
position: { x: 0, y: 0, width: "100%", height: "100%" }
|
|
7040
|
+
}
|
|
7041
|
+
);
|
|
7042
|
+
} else {
|
|
7043
|
+
layers.push({
|
|
7044
|
+
type: "shape",
|
|
7045
|
+
id: "cover-bg",
|
|
7046
|
+
content: {
|
|
7047
|
+
shape: "rect",
|
|
7048
|
+
fill: `radial-gradient(ellipse at 50% 40%, ${theme.colors.primary} 0%, ${theme.colors.background} 100%)`
|
|
7049
|
+
},
|
|
7050
|
+
position: { x: 0, y: 0, width: "100%", height: "100%" }
|
|
7051
|
+
});
|
|
6344
7052
|
}
|
|
7053
|
+
layers.push({
|
|
7054
|
+
type: "shape",
|
|
7055
|
+
id: "cover-accent",
|
|
7056
|
+
content: {
|
|
7057
|
+
shape: "rect",
|
|
7058
|
+
fill: standardLightCover ? withAlpha(theme.colors.primary, 0.24) : "rgba(255, 255, 255, 0.2)"
|
|
7059
|
+
},
|
|
7060
|
+
position: {
|
|
7061
|
+
x: "35%",
|
|
7062
|
+
y: subtitle ? "42%" : "58%",
|
|
7063
|
+
width: "30%",
|
|
7064
|
+
height: "2px"
|
|
7065
|
+
}
|
|
7066
|
+
});
|
|
6345
7067
|
}
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
7068
|
+
layers.push({
|
|
7069
|
+
type: "text",
|
|
7070
|
+
id: "cover-title",
|
|
7071
|
+
content: {
|
|
7072
|
+
text: title,
|
|
7073
|
+
style: {
|
|
7074
|
+
fontSize: titleFontSize,
|
|
7075
|
+
fontFamily: getThemeFont(context, "title"),
|
|
7076
|
+
fontWeight: "bold",
|
|
7077
|
+
color: theme.colors.text,
|
|
7078
|
+
textAlign: "center",
|
|
7079
|
+
shadow: !standardLightCover
|
|
7080
|
+
}
|
|
7081
|
+
},
|
|
7082
|
+
position: {
|
|
7083
|
+
x: "50%",
|
|
7084
|
+
y: heroSrc ? subtitle ? "70%" : "75%" : subtitle ? layout.primaryY : "50%",
|
|
7085
|
+
anchor: "center",
|
|
7086
|
+
width: layout.maxTextWidth
|
|
7087
|
+
},
|
|
7088
|
+
// No animation delay - shown immediately at rest
|
|
7089
|
+
animation: { type: "fadeIn", duration: 0.8 }
|
|
7090
|
+
});
|
|
7091
|
+
if (subtitle) {
|
|
7092
|
+
layers.push({
|
|
7093
|
+
type: "text",
|
|
7094
|
+
id: "cover-subtitle",
|
|
7095
|
+
content: {
|
|
7096
|
+
text: subtitle,
|
|
7097
|
+
style: {
|
|
7098
|
+
fontSize: subtitleFontSize,
|
|
7099
|
+
fontFamily: getThemeFont(context, "body"),
|
|
7100
|
+
fontWeight: standardLightCover ? "bold" : "normal",
|
|
7101
|
+
color: standardLightCover ? withAlpha(theme.colors.text, 0.78) : theme.colors.textMuted,
|
|
7102
|
+
textAlign: "center",
|
|
7103
|
+
lineHeight: 1.5
|
|
7104
|
+
}
|
|
7105
|
+
},
|
|
7106
|
+
position: {
|
|
7107
|
+
x: "50%",
|
|
7108
|
+
y: heroSrc ? "82%" : layout.secondaryY,
|
|
7109
|
+
anchor: "center",
|
|
7110
|
+
width: layout.maxTextWidth
|
|
7111
|
+
},
|
|
7112
|
+
animation: { type: "fadeIn", duration: 0.8, delay: 0.2 }
|
|
7113
|
+
});
|
|
6352
7114
|
}
|
|
6353
|
-
return
|
|
7115
|
+
return layers;
|
|
6354
7116
|
}
|
|
6355
|
-
function
|
|
6356
|
-
if (!contents) return null;
|
|
6357
|
-
const index = contents.findIndex((node) => node.type === "paragraph");
|
|
6358
|
-
if (index < 0) return null;
|
|
7117
|
+
function startBlockToCoverInput(config) {
|
|
6359
7118
|
return {
|
|
6360
|
-
|
|
6361
|
-
|
|
7119
|
+
heroSrc: config.heroSrc,
|
|
7120
|
+
heroAlt: config.heroAlt,
|
|
7121
|
+
title: config.title,
|
|
7122
|
+
subtitle: config.subtitle,
|
|
7123
|
+
ambientMotion: config.ambientMotion,
|
|
7124
|
+
heroCredit: config.heroCredit,
|
|
7125
|
+
heroLicense: config.heroLicense
|
|
6362
7126
|
};
|
|
6363
7127
|
}
|
|
6364
|
-
function
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
if (child.type !== "strong") return null;
|
|
6368
|
-
const text = extractPlainText(child).trim();
|
|
6369
|
-
const match = text.match(/^(?:[$€£¥]\s*)?[+-]?\d+(?:[.,]\d+)*(?:\s?(?:[%‰x×]|[A-Za-z]+))?/);
|
|
6370
|
-
return match?.[0].trim() || null;
|
|
6371
|
-
}
|
|
6372
|
-
return null;
|
|
6373
|
-
}
|
|
6374
|
-
function removeStatPhrase(text, start, end) {
|
|
6375
|
-
const before = text.slice(0, start).trim();
|
|
6376
|
-
let after = text.slice(end);
|
|
6377
|
-
if (!before) after = after.replace(/^\s*(?:[-–—:]\s*)?/, "");
|
|
6378
|
-
else after = after.trim();
|
|
6379
|
-
return [before, after].filter(Boolean).join(" ").trim();
|
|
6380
|
-
}
|
|
6381
|
-
function bodyWithoutParagraphStat(contents, paragraphIndex, paragraphText, start, end) {
|
|
6382
|
-
if (!contents) return "";
|
|
6383
|
-
return contents.map(
|
|
6384
|
-
(node, index) => index === paragraphIndex ? removeStatPhrase(paragraphText, start, end) : extractPlainText(node).trim()
|
|
6385
|
-
).filter(Boolean).join("\n").trim();
|
|
7128
|
+
function expandCoverBlock(config, context) {
|
|
7129
|
+
const input = startBlockToCoverInput(config);
|
|
7130
|
+
return coverBlock(input, context);
|
|
6386
7131
|
}
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
};
|
|
6405
|
-
}
|
|
7132
|
+
|
|
7133
|
+
// src/doc/templates/index.ts
|
|
7134
|
+
function materializeScheduledBlock(sourceBlock, blockIndex, totalBlocks, theme, viewport, persistentLayers, expandedPersistentLayers, registry, failureMode, onDiagnostic) {
|
|
7135
|
+
const materialized = materializeBlockLayersWithRuntime(
|
|
7136
|
+
sourceBlock,
|
|
7137
|
+
{
|
|
7138
|
+
theme,
|
|
7139
|
+
viewport,
|
|
7140
|
+
persistentLayers: persistentLayers ?? false,
|
|
7141
|
+
blockIndex,
|
|
7142
|
+
totalBlocks,
|
|
7143
|
+
failureMode
|
|
7144
|
+
},
|
|
7145
|
+
{ registry, expandedPersistentLayers }
|
|
7146
|
+
);
|
|
7147
|
+
if (materialized.diagnostic) {
|
|
7148
|
+
onDiagnostic?.(materialized.diagnostic, sourceBlock, blockIndex);
|
|
6406
7149
|
}
|
|
6407
|
-
const
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
7150
|
+
const expandedBlock = isTemplateBlock(sourceBlock) ? {
|
|
7151
|
+
id: sourceBlock.id,
|
|
7152
|
+
startTime: 0,
|
|
7153
|
+
duration: sourceBlock.duration,
|
|
7154
|
+
audioSegment: sourceBlock.audioSegment,
|
|
7155
|
+
...materialized.layers.length > 0 ? { layers: materialized.layers } : {},
|
|
7156
|
+
transition: sourceBlock.transition,
|
|
7157
|
+
template: sourceBlock.template
|
|
7158
|
+
} : {
|
|
7159
|
+
...cloneData(sourceBlock),
|
|
7160
|
+
...materialized.layers.length > 0 ? { layers: materialized.layers } : {}
|
|
7161
|
+
};
|
|
7162
|
+
const transition = resolveBlockTransition(expandedBlock, theme, blockIndex);
|
|
7163
|
+
if (transition !== expandedBlock.transition) {
|
|
7164
|
+
expandedBlock.transition = transition;
|
|
6411
7165
|
}
|
|
6412
|
-
|
|
6413
|
-
|
|
6414
|
-
|
|
6415
|
-
|
|
6416
|
-
|
|
6417
|
-
|
|
6418
|
-
|
|
6419
|
-
|
|
6420
|
-
|
|
6421
|
-
|
|
7166
|
+
return expandedBlock;
|
|
7167
|
+
}
|
|
7168
|
+
function expandDocBlocks(blocks, options = {}) {
|
|
7169
|
+
const opts = options;
|
|
7170
|
+
const theme = opts.theme ?? DEFAULT_THEME;
|
|
7171
|
+
const viewport = opts.viewport ?? VIEWPORT_PRESETS.landscape;
|
|
7172
|
+
const {
|
|
7173
|
+
persistentLayers,
|
|
7174
|
+
audioSegments,
|
|
7175
|
+
customTemplates,
|
|
7176
|
+
failureMode = "fallback",
|
|
7177
|
+
onDiagnostic
|
|
7178
|
+
} = opts;
|
|
7179
|
+
const totalBlocks = blocks.length;
|
|
7180
|
+
const registry = customTemplates && customTemplates.length > 0 ? buildRegistry(customTemplates) : templateRegistry;
|
|
7181
|
+
const effectivePersistentLayers = persistentLayers === false ? void 0 : persistentLayers ?? theme.persistentLayers;
|
|
7182
|
+
const expandedPersistentLayers = effectivePersistentLayers ? {
|
|
7183
|
+
bottomLayers: expandPersistentLayers(effectivePersistentLayers.bottomLayers, theme),
|
|
7184
|
+
topLayers: expandPersistentLayers(effectivePersistentLayers.topLayers, theme)
|
|
7185
|
+
} : void 0;
|
|
7186
|
+
if (!audioSegments || audioSegments.length === 0) {
|
|
7187
|
+
let currentTime = 0;
|
|
7188
|
+
return blocks.map((block, index) => {
|
|
7189
|
+
const expandedBlock = materializeScheduledBlock(
|
|
7190
|
+
block,
|
|
7191
|
+
index,
|
|
7192
|
+
totalBlocks,
|
|
7193
|
+
theme,
|
|
7194
|
+
viewport,
|
|
7195
|
+
effectivePersistentLayers,
|
|
7196
|
+
expandedPersistentLayers,
|
|
7197
|
+
registry,
|
|
7198
|
+
failureMode,
|
|
7199
|
+
onDiagnostic
|
|
6422
7200
|
);
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
}
|
|
7201
|
+
expandedBlock.startTime = currentTime;
|
|
7202
|
+
currentTime += expandedBlock.duration;
|
|
7203
|
+
return expandedBlock;
|
|
7204
|
+
});
|
|
6428
7205
|
}
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
switch (templateName) {
|
|
6435
|
-
case "statHighlight":
|
|
6436
|
-
return deriveStatHighlightInputs(headingText, contents, bodyText3);
|
|
6437
|
-
case "quote": {
|
|
6438
|
-
const quote = extractBlockquoteText(contents) || bodyText3 || headingText;
|
|
6439
|
-
return { quote };
|
|
6440
|
-
}
|
|
6441
|
-
case "fullBleedQuote":
|
|
6442
|
-
case "pullQuote": {
|
|
6443
|
-
const text = extractBlockquoteText(contents) || bodyText3 || headingText;
|
|
6444
|
-
return { text };
|
|
7206
|
+
const blocksBySegment = /* @__PURE__ */ new Map();
|
|
7207
|
+
blocks.forEach((block, index) => {
|
|
7208
|
+
const segmentIndex = block.audioSegment ?? 0;
|
|
7209
|
+
if (!blocksBySegment.has(segmentIndex)) {
|
|
7210
|
+
blocksBySegment.set(segmentIndex, []);
|
|
6445
7211
|
}
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
7212
|
+
blocksBySegment.get(segmentIndex).push({ block, originalIndex: index });
|
|
7213
|
+
});
|
|
7214
|
+
const expandedBlocks = new Array(blocks.length);
|
|
7215
|
+
for (const [segmentIndex, segmentBlocks] of blocksBySegment) {
|
|
7216
|
+
const audioSegment = audioSegments[segmentIndex];
|
|
7217
|
+
if (!audioSegment) {
|
|
7218
|
+
let offsetTime = 0;
|
|
7219
|
+
for (const { block, originalIndex } of segmentBlocks) {
|
|
7220
|
+
const expandedBlock = materializeScheduledBlock(
|
|
7221
|
+
block,
|
|
7222
|
+
originalIndex,
|
|
7223
|
+
totalBlocks,
|
|
7224
|
+
theme,
|
|
7225
|
+
viewport,
|
|
7226
|
+
effectivePersistentLayers,
|
|
7227
|
+
expandedPersistentLayers,
|
|
7228
|
+
registry,
|
|
7229
|
+
failureMode,
|
|
7230
|
+
onDiagnostic
|
|
7231
|
+
);
|
|
7232
|
+
expandedBlock.startTime = offsetTime;
|
|
7233
|
+
offsetTime += expandedBlock.duration;
|
|
7234
|
+
expandedBlocks[originalIndex] = expandedBlock;
|
|
7235
|
+
}
|
|
7236
|
+
continue;
|
|
6454
7237
|
}
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
7238
|
+
const sectionHeaderBlocks = [];
|
|
7239
|
+
const contentBlocks = [];
|
|
7240
|
+
for (const item of segmentBlocks) {
|
|
7241
|
+
const templateBlock = item.block;
|
|
7242
|
+
if (templateBlock.template === "sectionHeader") {
|
|
7243
|
+
sectionHeaderBlocks.push(item);
|
|
7244
|
+
} else {
|
|
7245
|
+
contentBlocks.push(item);
|
|
7246
|
+
}
|
|
6463
7247
|
}
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
7248
|
+
const fixedDuration = sectionHeaderBlocks.reduce((sum, { block }) => {
|
|
7249
|
+
return sum + (block.duration ?? 0);
|
|
7250
|
+
}, 0);
|
|
7251
|
+
const contentBlockDuration = contentBlocks.reduce((sum, { block }) => {
|
|
7252
|
+
return sum + (block.duration ?? 0);
|
|
7253
|
+
}, 0);
|
|
7254
|
+
const remainingDuration = audioSegment.duration - fixedDuration;
|
|
7255
|
+
const scaleFactor = contentBlockDuration > 0 && remainingDuration > 0 ? remainingDuration / contentBlockDuration : 1;
|
|
7256
|
+
const expandedInfos = [];
|
|
7257
|
+
for (const { block, originalIndex } of segmentBlocks) {
|
|
7258
|
+
const expandedBlock = materializeScheduledBlock(
|
|
7259
|
+
block,
|
|
7260
|
+
originalIndex,
|
|
7261
|
+
totalBlocks,
|
|
7262
|
+
theme,
|
|
7263
|
+
viewport,
|
|
7264
|
+
effectivePersistentLayers,
|
|
7265
|
+
expandedPersistentLayers,
|
|
7266
|
+
registry,
|
|
7267
|
+
failureMode,
|
|
7268
|
+
onDiagnostic
|
|
7269
|
+
);
|
|
7270
|
+
const templateBlock = block;
|
|
7271
|
+
expandedInfos.push({
|
|
7272
|
+
block: expandedBlock,
|
|
7273
|
+
originalIndex,
|
|
7274
|
+
templateBlock,
|
|
7275
|
+
hasSourceTiming: typeof templateBlock.sourceStartTime === "number"
|
|
7276
|
+
});
|
|
6468
7277
|
}
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
if (
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
7278
|
+
const hasAnySourceTiming = expandedInfos.some((info) => info.hasSourceTiming);
|
|
7279
|
+
expandedInfos.sort((a, b) => {
|
|
7280
|
+
if (hasAnySourceTiming) {
|
|
7281
|
+
const aIsHeader = a.templateBlock.template === "sectionHeader";
|
|
7282
|
+
const bIsHeader = b.templateBlock.template === "sectionHeader";
|
|
7283
|
+
if (aIsHeader && !bIsHeader) return -1;
|
|
7284
|
+
if (!aIsHeader && bIsHeader) return 1;
|
|
7285
|
+
if (a.hasSourceTiming && b.hasSourceTiming) {
|
|
7286
|
+
return a.templateBlock.sourceStartTime - b.templateBlock.sourceStartTime;
|
|
7287
|
+
}
|
|
7288
|
+
if (a.hasSourceTiming && !b.hasSourceTiming) return -1;
|
|
7289
|
+
if (!a.hasSourceTiming && b.hasSourceTiming) return 1;
|
|
7290
|
+
}
|
|
7291
|
+
return a.originalIndex - b.originalIndex;
|
|
7292
|
+
});
|
|
7293
|
+
let offsetWithinSegment = 0;
|
|
7294
|
+
for (let i = 0; i < expandedInfos.length; i++) {
|
|
7295
|
+
const info = expandedInfos[i];
|
|
7296
|
+
const { block: expandedBlock, templateBlock } = info;
|
|
7297
|
+
if (info.hasSourceTiming) {
|
|
7298
|
+
const sourceStart = templateBlock.sourceStartTime;
|
|
7299
|
+
expandedBlock.startTime = audioSegment.startTime + sourceStart;
|
|
7300
|
+
if (typeof templateBlock.sourceDuration === "number") {
|
|
7301
|
+
expandedBlock.duration = Math.max(5, templateBlock.sourceDuration);
|
|
7302
|
+
}
|
|
7303
|
+
offsetWithinSegment = sourceStart + expandedBlock.duration;
|
|
7304
|
+
} else if (templateBlock.template === "sectionHeader") {
|
|
7305
|
+
expandedBlock.startTime = audioSegment.startTime + offsetWithinSegment;
|
|
7306
|
+
offsetWithinSegment += expandedBlock.duration;
|
|
7307
|
+
} else {
|
|
7308
|
+
expandedBlock.startTime = audioSegment.startTime + offsetWithinSegment;
|
|
7309
|
+
const scaledDuration = expandedBlock.duration * scaleFactor;
|
|
7310
|
+
expandedBlock.duration = scaledDuration;
|
|
7311
|
+
offsetWithinSegment += scaledDuration;
|
|
7312
|
+
}
|
|
7313
|
+
expandedBlocks[info.originalIndex] = expandedBlock;
|
|
6476
7314
|
}
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
const
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
body: bodyText3
|
|
6488
|
-
};
|
|
7315
|
+
const segmentExpandedBlocks = expandedInfos.map((info) => expandedBlocks[info.originalIndex]).sort((a, b) => a.startTime - b.startTime);
|
|
7316
|
+
for (let i = 0; i < segmentExpandedBlocks.length - 1; i++) {
|
|
7317
|
+
const current = segmentExpandedBlocks[i];
|
|
7318
|
+
const next = segmentExpandedBlocks[i + 1];
|
|
7319
|
+
const currentEnd = current.startTime + current.duration;
|
|
7320
|
+
if (currentEnd > next.startTime) {
|
|
7321
|
+
current.duration = next.startTime - current.startTime;
|
|
7322
|
+
} else if (currentEnd < next.startTime - 0.5) {
|
|
7323
|
+
current.duration = Math.max(0.1, next.startTime - current.startTime);
|
|
7324
|
+
}
|
|
6489
7325
|
}
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
const
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
7326
|
+
const MIN_TRANSITION_GAP = 5;
|
|
7327
|
+
const segmentEnd = audioSegment.startTime + audioSegment.duration;
|
|
7328
|
+
while (segmentExpandedBlocks.length > 1) {
|
|
7329
|
+
const lastBlock = segmentExpandedBlocks[segmentExpandedBlocks.length - 1];
|
|
7330
|
+
const timeFromLastToEnd = segmentEnd - lastBlock.startTime;
|
|
7331
|
+
if (timeFromLastToEnd < MIN_TRANSITION_GAP && lastBlock.template !== "sectionHeader") {
|
|
7332
|
+
const prevBlock = segmentExpandedBlocks[segmentExpandedBlocks.length - 2];
|
|
7333
|
+
prevBlock.duration = segmentEnd - prevBlock.startTime;
|
|
7334
|
+
lastBlock.duration = 0;
|
|
7335
|
+
lastBlock.startTime = segmentEnd;
|
|
7336
|
+
segmentExpandedBlocks.pop();
|
|
7337
|
+
} else {
|
|
7338
|
+
if (lastBlock.startTime + lastBlock.duration < segmentEnd) {
|
|
7339
|
+
lastBlock.duration = segmentEnd - lastBlock.startTime;
|
|
7340
|
+
}
|
|
7341
|
+
break;
|
|
7342
|
+
}
|
|
6497
7343
|
}
|
|
6498
|
-
|
|
6499
|
-
const
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
const { tracks, links } = asciiTimelineToTemplateData(detection.timeline);
|
|
6504
|
-
return { tracks, links, ...headingText ? { title: headingText } : {} };
|
|
7344
|
+
if (segmentExpandedBlocks.length === 1) {
|
|
7345
|
+
const onlyBlock = segmentExpandedBlocks[0];
|
|
7346
|
+
if (onlyBlock.startTime + onlyBlock.duration < segmentEnd) {
|
|
7347
|
+
onlyBlock.duration = segmentEnd - onlyBlock.startTime;
|
|
7348
|
+
}
|
|
6505
7349
|
}
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
const
|
|
6511
|
-
if (
|
|
6512
|
-
const
|
|
6513
|
-
|
|
7350
|
+
let changed = true;
|
|
7351
|
+
while (changed) {
|
|
7352
|
+
changed = false;
|
|
7353
|
+
for (let i = segmentExpandedBlocks.length - 1; i >= 1; i--) {
|
|
7354
|
+
const block = segmentExpandedBlocks[i];
|
|
7355
|
+
if (block.duration > 0 && block.duration < MIN_TRANSITION_GAP) {
|
|
7356
|
+
const prev = segmentExpandedBlocks[i - 1];
|
|
7357
|
+
const blockEnd = block.startTime + block.duration;
|
|
7358
|
+
prev.duration = blockEnd - prev.startTime;
|
|
7359
|
+
block.duration = 0;
|
|
7360
|
+
block.startTime = segmentEnd;
|
|
7361
|
+
segmentExpandedBlocks.splice(i, 1);
|
|
7362
|
+
changed = true;
|
|
7363
|
+
break;
|
|
6514
7364
|
}
|
|
6515
7365
|
}
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
7366
|
+
}
|
|
7367
|
+
const MAX_BLOCK_DURATION = 20;
|
|
7368
|
+
for (let i = 0; i < segmentExpandedBlocks.length; i++) {
|
|
7369
|
+
const block = segmentExpandedBlocks[i];
|
|
7370
|
+
if (block.duration > MAX_BLOCK_DURATION) {
|
|
7371
|
+
const numParts = Math.ceil(block.duration / MAX_BLOCK_DURATION);
|
|
7372
|
+
const partDuration = block.duration / numParts;
|
|
7373
|
+
if (partDuration >= MIN_TRANSITION_GAP) {
|
|
7374
|
+
block.duration = partDuration;
|
|
7375
|
+
for (let p = 1; p < numParts; p++) {
|
|
7376
|
+
const splitBlock = {
|
|
7377
|
+
id: `${block.id}-split-${p}`,
|
|
7378
|
+
startTime: block.startTime + p * partDuration,
|
|
7379
|
+
duration: partDuration,
|
|
7380
|
+
audioSegment: block.audioSegment,
|
|
7381
|
+
layers: (block.layers ?? []).map((layer) => ({
|
|
7382
|
+
...cloneData(layer),
|
|
7383
|
+
id: `${layer.id}-split-${p}`
|
|
7384
|
+
})),
|
|
7385
|
+
transition: { type: "dissolve", duration: 1 },
|
|
7386
|
+
template: block.template
|
|
7387
|
+
};
|
|
7388
|
+
expandedBlocks.push(splitBlock);
|
|
7389
|
+
}
|
|
7390
|
+
}
|
|
6520
7391
|
}
|
|
6521
|
-
return placeholders ? {} : null;
|
|
6522
7392
|
}
|
|
6523
|
-
default:
|
|
6524
|
-
return placeholders ? {} : null;
|
|
6525
7393
|
}
|
|
7394
|
+
return expandedBlocks.filter((block) => block && block.duration > 0);
|
|
7395
|
+
}
|
|
7396
|
+
function getAvailableTemplates() {
|
|
7397
|
+
return Object.keys(templateRegistry);
|
|
7398
|
+
}
|
|
7399
|
+
function hasTemplate(name) {
|
|
7400
|
+
return resolveTemplateName(name) in templateRegistry;
|
|
6526
7401
|
}
|
|
6527
7402
|
|
|
6528
7403
|
// src/doc/customTemplatesFrontmatter.ts
|
|
@@ -6602,15 +7477,6 @@ function renameKeys(value, map) {
|
|
|
6602
7477
|
function isDefaultViewport(v) {
|
|
6603
7478
|
return !v || v.width === DEFAULT_VIEWPORT.width && v.height === DEFAULT_VIEWPORT.height;
|
|
6604
7479
|
}
|
|
6605
|
-
function base64ToUtf8(b64) {
|
|
6606
|
-
if (typeof globalThis.atob === "function") {
|
|
6607
|
-
const binary = globalThis.atob(b64);
|
|
6608
|
-
const bytes = new Uint8Array(binary.length);
|
|
6609
|
-
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
6610
|
-
return new TextDecoder().decode(bytes);
|
|
6611
|
-
}
|
|
6612
|
-
return Buffer.from(b64, "base64").toString("utf-8");
|
|
6613
|
-
}
|
|
6614
7480
|
function readCustomTemplatesFromFrontmatter(frontmatter) {
|
|
6615
7481
|
if (!frontmatter) return void 0;
|
|
6616
7482
|
const candidates = normalizeCandidates(frontmatter[FRONTMATTER_CUSTOM_TEMPLATES_KEY]);
|
|
@@ -7090,10 +7956,18 @@ function expandStandaloneAnnotations(blocks, makeId, defaultDuration) {
|
|
|
7090
7956
|
makeId,
|
|
7091
7957
|
defaultDuration
|
|
7092
7958
|
});
|
|
7093
|
-
if (produced.length
|
|
7094
|
-
block
|
|
7959
|
+
if (produced.length === 0) {
|
|
7960
|
+
out.push(block);
|
|
7961
|
+
continue;
|
|
7962
|
+
}
|
|
7963
|
+
block.contents = leading;
|
|
7964
|
+
const nestable = (block.children?.length ?? 0) > 0 && !isContainerTemplate(block.template);
|
|
7965
|
+
if (nestable) {
|
|
7966
|
+
block.children = [...produced, ...block.children];
|
|
7967
|
+
out.push(block);
|
|
7968
|
+
} else {
|
|
7969
|
+
out.push(block, ...produced);
|
|
7095
7970
|
}
|
|
7096
|
-
out.push(block, ...produced);
|
|
7097
7971
|
}
|
|
7098
7972
|
return out;
|
|
7099
7973
|
}
|
|
@@ -7465,8 +8339,10 @@ function applyAutoTemplates(blocks, resolvedDefault, state) {
|
|
|
7465
8339
|
if (block.sourceHeading && !annotated && block.template === resolvedDefault) {
|
|
7466
8340
|
const profile = profileBlockContents(block.contents ?? []);
|
|
7467
8341
|
const picked = pickAutoTemplate(profile, state.featureIndex);
|
|
7468
|
-
if (picked) {
|
|
7469
|
-
const inputs = deriveTemplateInputs(picked, block.title ?? "", block.contents
|
|
8342
|
+
if (picked && autoTemplatePreservesContent(picked, block.contents)) {
|
|
8343
|
+
const inputs = deriveTemplateInputs(picked, block.title ?? "", block.contents, {
|
|
8344
|
+
preserveSourceHeading: true
|
|
8345
|
+
});
|
|
7470
8346
|
if (inputs) {
|
|
7471
8347
|
if (picked === "leftFeature" || picked === "rightFeature") state.featureIndex += 1;
|
|
7472
8348
|
block.template = picked;
|
|
@@ -7814,7 +8690,11 @@ function buildNarrationTimingJson(script, alignment, durationSec, options) {
|
|
|
7814
8690
|
duration: Number.isFinite(durationSec) && durationSec >= 0 ? durationSec : 0,
|
|
7815
8691
|
bookmarks,
|
|
7816
8692
|
blocks,
|
|
7817
|
-
|
|
8693
|
+
// Write only what `parseNarrationTimingJson` will read back, so the codec
|
|
8694
|
+
// is a round-trip pair. A non-finite value would serialize to `null`
|
|
8695
|
+
// (JSON has no NaN) and be dropped on parse anyway — omitting it here
|
|
8696
|
+
// keeps the emitted sidecar honest rather than carrying a dead field.
|
|
8697
|
+
...finiteNumber(options?.cameraOffsetSec) ? { cameraOffsetSec: options.cameraOffsetSec } : {},
|
|
7818
8698
|
generator: {
|
|
7819
8699
|
name: "squisq-teleprompter",
|
|
7820
8700
|
method: "dsp-align",
|
|
@@ -7825,6 +8705,9 @@ function buildNarrationTimingJson(script, alignment, durationSec, options) {
|
|
|
7825
8705
|
function finiteNonNegative(value) {
|
|
7826
8706
|
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
7827
8707
|
}
|
|
8708
|
+
function finiteNumber(value) {
|
|
8709
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
8710
|
+
}
|
|
7828
8711
|
function parseNarrationTimingJson(data) {
|
|
7829
8712
|
try {
|
|
7830
8713
|
const text = typeof data === "string" ? data : new TextDecoder().decode(data instanceof Uint8Array ? data : new Uint8Array(data));
|
|
@@ -7878,7 +8761,7 @@ function parseNarrationTimingJson(data) {
|
|
|
7878
8761
|
duration: raw.duration,
|
|
7879
8762
|
bookmarks,
|
|
7880
8763
|
blocks,
|
|
7881
|
-
...
|
|
8764
|
+
...finiteNumber(raw.cameraOffsetSec) ? { cameraOffsetSec: raw.cameraOffsetSec } : {},
|
|
7882
8765
|
...typeof raw.generator === "object" && raw.generator !== null ? { generator: raw.generator } : {}
|
|
7883
8766
|
};
|
|
7884
8767
|
} catch {
|
|
@@ -7908,11 +8791,11 @@ export {
|
|
|
7908
8791
|
themedScrim,
|
|
7909
8792
|
getTemplateHint,
|
|
7910
8793
|
titleBlock,
|
|
7911
|
-
sectionHeader,
|
|
7912
8794
|
DEFAULT_LAYOUT,
|
|
7913
8795
|
getAccentLayout,
|
|
7914
8796
|
createAccentLayers,
|
|
7915
8797
|
adjustY,
|
|
8798
|
+
sectionHeader,
|
|
7916
8799
|
statHighlight,
|
|
7917
8800
|
quoteBlock,
|
|
7918
8801
|
factCard,
|
|
@@ -7957,13 +8840,6 @@ export {
|
|
|
7957
8840
|
coerceTemplateParams,
|
|
7958
8841
|
lintTemplateParams,
|
|
7959
8842
|
fallbackBlockLayers,
|
|
7960
|
-
materializeBlockLayers,
|
|
7961
|
-
TEMPLATE_METADATA,
|
|
7962
|
-
coverBlock,
|
|
7963
|
-
expandCoverBlock,
|
|
7964
|
-
expandDocBlocks,
|
|
7965
|
-
getAvailableTemplates,
|
|
7966
|
-
hasTemplate,
|
|
7967
8843
|
ASCII_CHAR_W,
|
|
7968
8844
|
ASCII_CHAR_H,
|
|
7969
8845
|
asciiCellToCanvas,
|
|
@@ -7980,9 +8856,21 @@ export {
|
|
|
7980
8856
|
extractListItems,
|
|
7981
8857
|
extractImages,
|
|
7982
8858
|
extractFirstImage,
|
|
8859
|
+
extractEmbeddedVideos,
|
|
8860
|
+
extractFirstEmbeddedVideo,
|
|
7983
8861
|
extractTableFromContents,
|
|
7984
8862
|
extractBlockquoteText,
|
|
8863
|
+
autoTemplatePreservesContent,
|
|
7985
8864
|
deriveTemplateInputs,
|
|
8865
|
+
BLOCK_MEDIA_LAYOUT_POLICIES,
|
|
8866
|
+
getBlockMediaLayoutPolicy,
|
|
8867
|
+
materializeBlockLayers,
|
|
8868
|
+
TEMPLATE_METADATA,
|
|
8869
|
+
coverBlock,
|
|
8870
|
+
expandCoverBlock,
|
|
8871
|
+
expandDocBlocks,
|
|
8872
|
+
getAvailableTemplates,
|
|
8873
|
+
hasTemplate,
|
|
7986
8874
|
readCustomTemplatesFromFrontmatter,
|
|
7987
8875
|
writeCustomTemplatesToFrontmatter,
|
|
7988
8876
|
readCustomThemesFromFrontmatter,
|
|
@@ -8010,4 +8898,3 @@ export {
|
|
|
8010
8898
|
buildNarrationTimingJson,
|
|
8011
8899
|
parseNarrationTimingJson
|
|
8012
8900
|
};
|
|
8013
|
-
//# sourceMappingURL=chunk-JI77MGAK.js.map
|