@bendyline/squisq 2.13.1 → 2.13.3
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/dist/{Doc-C7iCmmmF.d.ts → Doc-BPhdJFS_.d.ts} +53 -2
- package/dist/{ImageEditDoc-CxRHe41J.d.ts → ImageEditDoc-DDx-sw_S.d.ts} +1 -1
- package/dist/{chunk-ITLJQG7Z.js → chunk-5FUBK3DK.js} +527 -266
- package/dist/{chunk-HE3HQZWU.js → chunk-6NWVLLMI.js} +104 -1
- package/dist/{chunk-3A6YM375.js → chunk-D3JQMZUT.js} +8 -8
- package/dist/chunk-DOOUVVOM.js +78 -0
- package/dist/{chunk-2LTALYXX.js → chunk-F3LRTRST.js} +15 -10
- package/dist/{chunk-5SVFLLOD.js → chunk-ISVJ42I3.js} +3 -0
- package/dist/{chunk-7ZXCS3UU.js → chunk-JFJZ4NS6.js} +2 -2
- package/dist/{chunk-V4USYYYO.js → chunk-JOBMPMY5.js} +1 -1
- package/dist/{chunk-HGCIIXHP.js → chunk-POZCKPCO.js} +235 -4
- package/dist/{chunk-DCO5GYVW.js → chunk-VX7MPZOK.js} +5 -5
- package/dist/doc/index.d.ts +100 -15
- package/dist/doc/index.js +15 -7
- package/dist/fence/index.d.ts +1 -1
- package/dist/generate/index.d.ts +1 -1
- package/dist/imageEdit/index.d.ts +3 -3
- package/dist/index.d.ts +5 -5
- package/dist/index.js +26 -18
- package/dist/jsonForm/index.d.ts +1 -1
- package/dist/jsonForm/index.js +1 -1
- package/dist/markdown/index.js +11 -12
- package/dist/{materializePageSection-_5uQrEYP.d.ts → materializePageSection-DnQi-0TA.d.ts} +1 -1
- package/dist/mediaEdit/index.d.ts +2 -2
- package/dist/narration/index.d.ts +1 -1
- package/dist/narration/index.js +5 -5
- package/dist/recommend/index.js +3 -2
- package/dist/schemas/index.d.ts +4 -4
- package/dist/schemas/index.js +1 -1
- package/dist/{themeLibrary-DsntZLoa.d.ts → themeLibrary-DM7eSK1w.d.ts} +1 -1
- package/dist/timing/index.d.ts +1 -1
- package/dist/transform/index.d.ts +2 -2
- package/dist/transform/index.js +6 -6
- package/package.json +1 -1
- package/dist/chunk-Y25EJEZN.js +0 -178
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
extractEmbeddedVideos,
|
|
11
11
|
extractHostedVideos,
|
|
12
12
|
extractImages,
|
|
13
|
+
extractMediaFromContents,
|
|
13
14
|
extractRichListItems,
|
|
14
15
|
extractTableFromContents,
|
|
15
16
|
isEligibleAsciiFenceLang,
|
|
@@ -19,15 +20,19 @@ import {
|
|
|
19
20
|
isExplicitTimelineLang,
|
|
20
21
|
isExplicitTreeLang,
|
|
21
22
|
isMaterializedMediaNode,
|
|
23
|
+
isMediaAnnotationName,
|
|
22
24
|
isPictureFence,
|
|
25
|
+
isPictureParagraph,
|
|
23
26
|
markdownBlockSeparatorLines,
|
|
27
|
+
parseAnnotationInner,
|
|
24
28
|
parseAsciiDiagram,
|
|
25
29
|
parseAsciiTimeline,
|
|
30
|
+
parseStandaloneAnnotation,
|
|
26
31
|
pickAutoTemplate,
|
|
27
32
|
profileBlockContents,
|
|
28
33
|
renderMarkdownBlocksHtml,
|
|
29
34
|
treeToTemplateData
|
|
30
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-POZCKPCO.js";
|
|
31
36
|
import {
|
|
32
37
|
anchorPoint,
|
|
33
38
|
base64ToUtf8,
|
|
@@ -58,33 +63,25 @@ import {
|
|
|
58
63
|
validateTheme,
|
|
59
64
|
withAlpha
|
|
60
65
|
} from "./chunk-WNEH3BZP.js";
|
|
61
|
-
import {
|
|
62
|
-
mediaEditValuesFromAttributes,
|
|
63
|
-
mediaEditValuesFromParams,
|
|
64
|
-
parseMediaEdits
|
|
65
|
-
} from "./chunk-L7QZORLB.js";
|
|
66
66
|
import {
|
|
67
67
|
TABLE_FED_TEMPLATES,
|
|
68
68
|
isContainerTemplate,
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
splitKeyValueToken,
|
|
72
|
-
tokenizeAttrTokens
|
|
73
|
-
} from "./chunk-Y25EJEZN.js";
|
|
69
|
+
resolveTemplateName
|
|
70
|
+
} from "./chunk-DOOUVVOM.js";
|
|
74
71
|
import {
|
|
75
72
|
KNOWN_BLOCK_META_KEYS,
|
|
76
73
|
coerceAnnotationValues,
|
|
77
74
|
extractPlainText,
|
|
78
75
|
isSvgIslandLang,
|
|
79
76
|
isVideoEmbedUrl,
|
|
77
|
+
matchTrailingTemplateAnnotation,
|
|
80
78
|
mediaKindForUrl,
|
|
81
79
|
parseNumber,
|
|
82
80
|
parseSvgIsland,
|
|
83
|
-
parseTimeSeconds,
|
|
84
81
|
parseVideoEmbedUrl,
|
|
85
82
|
readFrontmatterThemeId,
|
|
86
83
|
walkMarkdownTree
|
|
87
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-6NWVLLMI.js";
|
|
88
85
|
import {
|
|
89
86
|
resolveBlockTransition
|
|
90
87
|
} from "./chunk-P53Z4RYC.js";
|
|
@@ -1791,12 +1788,12 @@ function statHighlight(input, context) {
|
|
|
1791
1788
|
const statTop = groupTop;
|
|
1792
1789
|
const descTop = statTop + statBoxH + gap;
|
|
1793
1790
|
const detailTop = descTop + descBoxH + detailGap;
|
|
1794
|
-
const
|
|
1791
|
+
const pct2 = (px) => `${Number((px / frameH * 100).toFixed(3))}%`;
|
|
1795
1792
|
const box = (top, height) => ({
|
|
1796
1793
|
x: accentLayout.textCenterX,
|
|
1797
|
-
y:
|
|
1794
|
+
y: pct2(top + height / 2),
|
|
1798
1795
|
width: accentLayout.textWidth,
|
|
1799
|
-
height:
|
|
1796
|
+
height: pct2(height),
|
|
1800
1797
|
anchor: "center"
|
|
1801
1798
|
});
|
|
1802
1799
|
layers.push({
|
|
@@ -1880,7 +1877,7 @@ function quoteBlock(input, context) {
|
|
|
1880
1877
|
const accentImage = accentForViewport(input.accentImage, viewport);
|
|
1881
1878
|
const H = viewport.height;
|
|
1882
1879
|
const W = viewport.width;
|
|
1883
|
-
const
|
|
1880
|
+
const pct2 = (px) => `${Number((px / H * 100).toFixed(3))}%`;
|
|
1884
1881
|
const accentLayout = accentImage ? getAccentLayout(accentImage.position) : DEFAULT_LAYOUT;
|
|
1885
1882
|
const yShiftPx = accentLayout.adjustY ? accentLayout.textYAdjust / 100 * H : 0;
|
|
1886
1883
|
const colWidthPct = parseFloat(accentLayout.textWidth);
|
|
@@ -1938,9 +1935,9 @@ function quoteBlock(input, context) {
|
|
|
1938
1935
|
},
|
|
1939
1936
|
position: {
|
|
1940
1937
|
x: colLeft,
|
|
1941
|
-
y:
|
|
1938
|
+
y: pct2(bandTopPx),
|
|
1942
1939
|
width: accentLayout.textWidth,
|
|
1943
|
-
height:
|
|
1940
|
+
height: pct2(titleFit.heightPx),
|
|
1944
1941
|
anchor: "top-left"
|
|
1945
1942
|
},
|
|
1946
1943
|
animation: { type: "fadeIn", duration: 0.8 }
|
|
@@ -1994,7 +1991,7 @@ function quoteBlock(input, context) {
|
|
|
1994
1991
|
},
|
|
1995
1992
|
position: {
|
|
1996
1993
|
x: accentLayout.textCenterX,
|
|
1997
|
-
y:
|
|
1994
|
+
y: pct2(quoteTopPx - decoMarginPx - decoFontSize * 0.6),
|
|
1998
1995
|
anchor: "center"
|
|
1999
1996
|
}
|
|
2000
1997
|
});
|
|
@@ -2020,9 +2017,9 @@ function quoteBlock(input, context) {
|
|
|
2020
2017
|
},
|
|
2021
2018
|
position: {
|
|
2022
2019
|
x: colLeft,
|
|
2023
|
-
y:
|
|
2020
|
+
y: pct2(quoteTopPx),
|
|
2024
2021
|
width: accentLayout.textWidth,
|
|
2025
|
-
height:
|
|
2022
|
+
height: pct2(quoteFit.heightPx),
|
|
2026
2023
|
anchor: "top-left"
|
|
2027
2024
|
},
|
|
2028
2025
|
animation: motionEntrance(context, { type: "fadeIn", duration: 2 })
|
|
@@ -2047,9 +2044,9 @@ function quoteBlock(input, context) {
|
|
|
2047
2044
|
},
|
|
2048
2045
|
position: {
|
|
2049
2046
|
x: colLeft,
|
|
2050
|
-
y:
|
|
2047
|
+
y: pct2(quoteBottomPx + attrGapPx),
|
|
2051
2048
|
width: accentLayout.textWidth,
|
|
2052
|
-
height:
|
|
2049
|
+
height: pct2(attrFit.heightPx),
|
|
2053
2050
|
anchor: "top-left"
|
|
2054
2051
|
},
|
|
2055
2052
|
animation: { type: "fadeIn", duration: 1, delay: 1.5 }
|
|
@@ -2133,12 +2130,12 @@ function factCard(input, context) {
|
|
|
2133
2130
|
const factTop = groupTop;
|
|
2134
2131
|
const explainTop = factTop + factBoxH + gap;
|
|
2135
2132
|
const sourceTop = explainTop + explainBoxH + sourceGap;
|
|
2136
|
-
const
|
|
2133
|
+
const pct2 = (px) => `${Number((px / frameH * 100).toFixed(3))}%`;
|
|
2137
2134
|
const box = (top, height) => ({
|
|
2138
2135
|
x: accentLayout.textCenterX,
|
|
2139
|
-
y:
|
|
2136
|
+
y: pct2(top + height / 2),
|
|
2140
2137
|
width: accentLayout.textWidth,
|
|
2141
|
-
height:
|
|
2138
|
+
height: pct2(height),
|
|
2142
2139
|
anchor: "center"
|
|
2143
2140
|
});
|
|
2144
2141
|
layers.push({
|
|
@@ -2965,6 +2962,17 @@ function rightFeature(input, context) {
|
|
|
2965
2962
|
return buildFeatureLayers(input, context, "right");
|
|
2966
2963
|
}
|
|
2967
2964
|
|
|
2965
|
+
// src/doc/templates/mediaFeatureBlock.ts
|
|
2966
|
+
function topFeature(input, context) {
|
|
2967
|
+
return contentBlock({ ...input, template: "content" }, context, { omitPictures: true });
|
|
2968
|
+
}
|
|
2969
|
+
function bottomFeature(input, context) {
|
|
2970
|
+
return contentBlock({ ...input, template: "content" }, context, { omitPictures: true });
|
|
2971
|
+
}
|
|
2972
|
+
function mediaOnly(input, context) {
|
|
2973
|
+
return contentBlock({ ...input, template: "content" }, context);
|
|
2974
|
+
}
|
|
2975
|
+
|
|
2968
2976
|
// src/doc/templates/mapBlock.ts
|
|
2969
2977
|
function mapBlock(input, context) {
|
|
2970
2978
|
const {
|
|
@@ -3090,7 +3098,7 @@ function fullBleedQuote(input, context) {
|
|
|
3090
3098
|
const colors = resolveColorScheme(context, colorScheme);
|
|
3091
3099
|
const H = viewport.height;
|
|
3092
3100
|
const W = viewport.width;
|
|
3093
|
-
const
|
|
3101
|
+
const pct2 = (px) => `${Number((px / H * 100).toFixed(3))}%`;
|
|
3094
3102
|
const impactFontSize = themedFontSize(120, context, true);
|
|
3095
3103
|
const baseFontSize = Math.round(impactFontSize * lengthFactor(text));
|
|
3096
3104
|
const bandHeightPx = (BAND_BOTTOM3 - BAND_TOP3) * H;
|
|
@@ -3141,9 +3149,9 @@ function fullBleedQuote(input, context) {
|
|
|
3141
3149
|
},
|
|
3142
3150
|
position: {
|
|
3143
3151
|
x: `${COLUMN_LEFT * 100}%`,
|
|
3144
|
-
y:
|
|
3152
|
+
y: pct2(topPx),
|
|
3145
3153
|
width: `${COLUMN_WIDTH * 100}%`,
|
|
3146
|
-
height:
|
|
3154
|
+
height: pct2(fit.heightPx),
|
|
3147
3155
|
anchor: "top-left"
|
|
3148
3156
|
},
|
|
3149
3157
|
animation: motionEntrance(
|
|
@@ -3605,12 +3613,12 @@ function definitionCard(input, context) {
|
|
|
3605
3613
|
const ruleTop = termTop + termH + ruleGap;
|
|
3606
3614
|
const defTop = ruleTop + RULE_HEIGHT_PX + defGap;
|
|
3607
3615
|
const originTop = defTop + defH + originGap;
|
|
3608
|
-
const
|
|
3616
|
+
const pct2 = (px) => `${(px / viewport.height * 100).toFixed(3)}%`;
|
|
3609
3617
|
const box = (topPx, heightPx) => {
|
|
3610
3618
|
const height = Math.round(heightPx);
|
|
3611
3619
|
return {
|
|
3612
3620
|
x: accentLayout.textCenterX,
|
|
3613
|
-
y:
|
|
3621
|
+
y: pct2(topPx + height / 2),
|
|
3614
3622
|
width: accentLayout.textWidth,
|
|
3615
3623
|
height,
|
|
3616
3624
|
anchor: "center"
|
|
@@ -3657,7 +3665,7 @@ function definitionCard(input, context) {
|
|
|
3657
3665
|
},
|
|
3658
3666
|
position: {
|
|
3659
3667
|
x: columnLeft,
|
|
3660
|
-
y:
|
|
3668
|
+
y: pct2(ruleTop),
|
|
3661
3669
|
width: "30%",
|
|
3662
3670
|
height: `${RULE_HEIGHT_PX}px`,
|
|
3663
3671
|
anchor: "top-left"
|
|
@@ -3883,7 +3891,7 @@ var ATTR_LINE_HEIGHT = 1.4;
|
|
|
3883
3891
|
function pullQuoteLockup(options, context) {
|
|
3884
3892
|
const { text, attribution, overMedia } = options;
|
|
3885
3893
|
const { theme, viewport } = context;
|
|
3886
|
-
const
|
|
3894
|
+
const pct2 = (px) => px / viewport.height * 100;
|
|
3887
3895
|
const quoteBaseSize = themedFontSize(52, context, true);
|
|
3888
3896
|
const quoteMinSize = Math.max(18, themedFontSize(24, context, true));
|
|
3889
3897
|
const attrFontSize = themedFontSize(26, context, false);
|
|
@@ -3910,12 +3918,12 @@ function pullQuoteLockup(options, context) {
|
|
|
3910
3918
|
const gapPx = attribution ? Math.max(16, fit.fontSize * 0.6) : 0;
|
|
3911
3919
|
const stackHeightPx = fit.heightPx + gapPx + attrHeightPx;
|
|
3912
3920
|
const stackTopPx = Math.max(frameTopPx, viewport.height / 2 - stackHeightPx / 2);
|
|
3913
|
-
const quoteTopPct =
|
|
3914
|
-
const attrTopPct =
|
|
3921
|
+
const quoteTopPct = pct2(stackTopPx);
|
|
3922
|
+
const attrTopPct = pct2(stackTopPx + fit.heightPx + gapPx);
|
|
3915
3923
|
const decoHeadroomPx = stackTopPx - 0.03 * viewport.height;
|
|
3916
3924
|
const decoFontSize = Math.min(decoBaseSize, Math.floor(decoHeadroomPx / 0.6));
|
|
3917
3925
|
const showDeco = decoFontSize >= decoMinSize;
|
|
3918
|
-
const decoYPct = quoteTopPct -
|
|
3926
|
+
const decoYPct = quoteTopPct - pct2(decoFontSize * 0.55);
|
|
3919
3927
|
const shadow = overMedia ? true : shouldUseShadow(context);
|
|
3920
3928
|
const quoteColor = overMedia ? "#ffffff" : theme.colors.text;
|
|
3921
3929
|
const attrColor = overMedia ? "rgba(255, 255, 255, 0.85)" : theme.colors.textMuted;
|
|
@@ -5524,6 +5532,30 @@ var BLOCK_MEDIA_LAYOUT_POLICIES = {
|
|
|
5524
5532
|
additionalMediaLayout: "overlay-inset",
|
|
5525
5533
|
unconsumedMedia: "retain-native-layout"
|
|
5526
5534
|
},
|
|
5535
|
+
topFeature: {
|
|
5536
|
+
summary: "Body media spans the full width across the top; the heading and complete body take a band below sized to the text. Without media it is a content slide.",
|
|
5537
|
+
noMedia: "template-default",
|
|
5538
|
+
ownership: "native-slot",
|
|
5539
|
+
nativeLayout: "feature-top",
|
|
5540
|
+
additionalMediaLayout: "overlay-inset",
|
|
5541
|
+
unconsumedMedia: "retain-native-layout"
|
|
5542
|
+
},
|
|
5543
|
+
bottomFeature: {
|
|
5544
|
+
summary: "The heading and complete body take a band across the top sized to the text; body media spans the full width below. Without media it is a content slide.",
|
|
5545
|
+
noMedia: "template-default",
|
|
5546
|
+
ownership: "native-slot",
|
|
5547
|
+
nativeLayout: "feature-bottom",
|
|
5548
|
+
additionalMediaLayout: "overlay-inset",
|
|
5549
|
+
unconsumedMedia: "retain-native-layout"
|
|
5550
|
+
},
|
|
5551
|
+
mediaOnly: {
|
|
5552
|
+
summary: "Body media fills the whole slide with no text; without media the heading and body render as a content slide.",
|
|
5553
|
+
noMedia: "template-default",
|
|
5554
|
+
ownership: "native-slot",
|
|
5555
|
+
nativeLayout: "full-frame",
|
|
5556
|
+
additionalMediaLayout: "overlay-inset",
|
|
5557
|
+
unconsumedMedia: "retain-native-layout"
|
|
5558
|
+
},
|
|
5527
5559
|
map: {
|
|
5528
5560
|
summary: "The map canvas is the primary visual; other media must not reflow its geography.",
|
|
5529
5561
|
noMedia: "intrinsic-visual",
|
|
@@ -6198,12 +6230,144 @@ function leastObstructedMediaRect(layers, viewport) {
|
|
|
6198
6230
|
return score < bestScore ? candidate : best;
|
|
6199
6231
|
});
|
|
6200
6232
|
}
|
|
6233
|
+
var MEDIA_BANDS = {
|
|
6234
|
+
"feature-top": "top",
|
|
6235
|
+
"feature-bottom": "bottom",
|
|
6236
|
+
"full-frame": "full"
|
|
6237
|
+
};
|
|
6238
|
+
var BLOCK_GAP_EM = 0.55;
|
|
6239
|
+
function textLayer(layers, id) {
|
|
6240
|
+
const layer = layers.find((candidate) => candidate.id === id);
|
|
6241
|
+
return layer?.type === "text" ? layer : void 0;
|
|
6242
|
+
}
|
|
6243
|
+
function mediaBandLayout(layers, viewport, band, aspect) {
|
|
6244
|
+
const backdrop = layers.filter((layer) => isFullViewportBackground(layer, viewport));
|
|
6245
|
+
const title = textLayer(layers, "title");
|
|
6246
|
+
const body = textLayer(layers, "body");
|
|
6247
|
+
if (band === "full" || !title && !body) {
|
|
6248
|
+
return { layers: backdrop, mediaRect: rect(viewport, 0, 0, 1, 1), framed: false };
|
|
6249
|
+
}
|
|
6250
|
+
const { width, height } = viewport;
|
|
6251
|
+
const unit = Math.min(width, height);
|
|
6252
|
+
const margin = unit * 0.045;
|
|
6253
|
+
const gap = unit * 0.03;
|
|
6254
|
+
const innerGap = title && body ? unit * 0.02 : 0;
|
|
6255
|
+
const textWidth = width - margin * 2;
|
|
6256
|
+
const maxBandHeight = height * (body ? 0.4 : 0.2);
|
|
6257
|
+
const titleLineHeight = title?.content.style.lineHeight ?? 1.15;
|
|
6258
|
+
const titleBaseSize = Math.max(
|
|
6259
|
+
title?.content.style.fontSize ?? 0,
|
|
6260
|
+
Math.round((body?.content.style.fontSize ?? 0) * 1.2)
|
|
6261
|
+
);
|
|
6262
|
+
const titleWrapWidth = title ? Math.min(
|
|
6263
|
+
textWidth * 0.86,
|
|
6264
|
+
fitWrapWidth(
|
|
6265
|
+
title.content.text,
|
|
6266
|
+
titleBaseSize,
|
|
6267
|
+
textWidth,
|
|
6268
|
+
title.content.style.fontFamily ?? ""
|
|
6269
|
+
)
|
|
6270
|
+
) : textWidth;
|
|
6271
|
+
const titleFit = title ? fitProse({
|
|
6272
|
+
text: title.content.text,
|
|
6273
|
+
baseFontSize: titleBaseSize,
|
|
6274
|
+
minFontSize: Math.min(titleBaseSize, unit * 0.03),
|
|
6275
|
+
maxWidthPx: titleWrapWidth,
|
|
6276
|
+
maxHeightPx: body ? maxBandHeight * 0.35 : maxBandHeight,
|
|
6277
|
+
lineHeight: titleLineHeight
|
|
6278
|
+
}) : void 0;
|
|
6279
|
+
const titleHeight = titleFit?.heightPx ?? 0;
|
|
6280
|
+
const bodyRoom = maxBandHeight - titleHeight - innerGap;
|
|
6281
|
+
const bodyLineHeight = body?.content.style.lineHeight ?? 1.35;
|
|
6282
|
+
const blockGaps = body ? (body.content.text.match(/\n[^\S\n]*\n/g) ?? []).length : 0;
|
|
6283
|
+
const bodyBaseSize = body?.content.style.fontSize ?? 0;
|
|
6284
|
+
const headroomLines = 1;
|
|
6285
|
+
const bodyText3 = body?.content.text.replace(/\n[^\S\n]*\n/g, "\n") ?? "";
|
|
6286
|
+
const bodyFit = body ? fitProse({
|
|
6287
|
+
text: bodyText3,
|
|
6288
|
+
baseFontSize: bodyBaseSize,
|
|
6289
|
+
minFontSize: Math.min(bodyBaseSize, unit * 0.016),
|
|
6290
|
+
// HTML wraps on real glyphs; wide ones (CJK, emoji) fill lines in
|
|
6291
|
+
// half the characters the estimate assumes, so count lines narrower.
|
|
6292
|
+
maxWidthPx: fitWrapWidth(
|
|
6293
|
+
bodyText3,
|
|
6294
|
+
bodyBaseSize,
|
|
6295
|
+
textWidth,
|
|
6296
|
+
body.content.style.fontFamily ?? ""
|
|
6297
|
+
),
|
|
6298
|
+
maxHeightPx: bodyRoom - (blockGaps * BLOCK_GAP_EM + headroomLines * bodyLineHeight) * bodyBaseSize,
|
|
6299
|
+
lineHeight: bodyLineHeight
|
|
6300
|
+
}) : void 0;
|
|
6301
|
+
const bodyHeight = bodyFit ? Math.min(
|
|
6302
|
+
bodyRoom,
|
|
6303
|
+
bodyFit.heightPx + (blockGaps * BLOCK_GAP_EM + headroomLines * bodyLineHeight) * bodyFit.fontSize
|
|
6304
|
+
) : 0;
|
|
6305
|
+
const bandHeight = titleHeight + innerGap + bodyHeight;
|
|
6306
|
+
const roomForMedia = height - margin - gap - bandHeight;
|
|
6307
|
+
const mediaHeight = aspect && Number.isFinite(aspect) && aspect > 0 ? Math.min(roomForMedia, width / aspect) : roomForMedia;
|
|
6308
|
+
const offset = (roomForMedia - mediaHeight) / 2;
|
|
6309
|
+
const mediaTop = band === "top" ? offset : margin + offset + bandHeight + gap;
|
|
6310
|
+
const bandTop = band === "top" ? mediaTop + mediaHeight + gap : margin + offset;
|
|
6311
|
+
const placed = [...backdrop];
|
|
6312
|
+
if (title && titleFit) {
|
|
6313
|
+
placed.push({
|
|
6314
|
+
...title,
|
|
6315
|
+
position: {
|
|
6316
|
+
x: margin,
|
|
6317
|
+
y: bandTop,
|
|
6318
|
+
width: titleWrapWidth,
|
|
6319
|
+
height: titleHeight,
|
|
6320
|
+
anchor: "top-left"
|
|
6321
|
+
},
|
|
6322
|
+
content: {
|
|
6323
|
+
...title.content,
|
|
6324
|
+
style: {
|
|
6325
|
+
...title.content.style,
|
|
6326
|
+
fontSize: titleFit.fontSize,
|
|
6327
|
+
lineHeight: titleLineHeight,
|
|
6328
|
+
...titleFit.maxLines ? { maxLines: titleFit.maxLines } : {}
|
|
6329
|
+
}
|
|
6330
|
+
}
|
|
6331
|
+
});
|
|
6332
|
+
}
|
|
6333
|
+
if (body && bodyFit) {
|
|
6334
|
+
placed.push({
|
|
6335
|
+
...body,
|
|
6336
|
+
position: {
|
|
6337
|
+
x: margin,
|
|
6338
|
+
y: bandTop + titleHeight + innerGap,
|
|
6339
|
+
width: textWidth,
|
|
6340
|
+
height: bodyHeight,
|
|
6341
|
+
anchor: "top-left"
|
|
6342
|
+
},
|
|
6343
|
+
content: {
|
|
6344
|
+
...body.content,
|
|
6345
|
+
style: {
|
|
6346
|
+
...body.content.style,
|
|
6347
|
+
fontSize: bodyFit.fontSize,
|
|
6348
|
+
lineHeight: bodyLineHeight,
|
|
6349
|
+
...bodyFit.maxLines ? { maxLines: bodyFit.maxLines } : {}
|
|
6350
|
+
}
|
|
6351
|
+
}
|
|
6352
|
+
});
|
|
6353
|
+
}
|
|
6354
|
+
return {
|
|
6355
|
+
layers: placed,
|
|
6356
|
+
mediaRect: { x: 0, y: mediaTop, width, height: mediaHeight },
|
|
6357
|
+
framed: false
|
|
6358
|
+
};
|
|
6359
|
+
}
|
|
6201
6360
|
function resolveSupplementalMediaLayout(layers, template, viewport, mediaCount, aspectRatios, featureOptions = {}) {
|
|
6202
6361
|
const policy = getBlockMediaLayoutPolicy(template);
|
|
6203
6362
|
const shape = mediaShape(mediaCount, aspectRatios);
|
|
6204
6363
|
const alreadyOwnsMedia = layers.some(
|
|
6205
6364
|
(layer) => layer.type === "image" || layer.type === "video" || layer.type === "videoEmbed" || layer.type === "map" || layer.type === "mermaid" || layer.type === "svg"
|
|
6206
6365
|
);
|
|
6366
|
+
const band = policy?.nativeLayout ? MEDIA_BANDS[policy.nativeLayout] : void 0;
|
|
6367
|
+
if (band && !alreadyOwnsMedia) {
|
|
6368
|
+
const aspect = mediaCount === 1 ? featureOptions.knownAspectRatios?.[0] : void 0;
|
|
6369
|
+
return mediaBandLayout(layers, viewport, band, aspect);
|
|
6370
|
+
}
|
|
6207
6371
|
if (!alreadyOwnsMedia && (policy?.nativeLayout === "feature-left" || policy?.nativeLayout === "feature-right")) {
|
|
6208
6372
|
const { position } = featureMediaSlot(
|
|
6209
6373
|
policy.nativeLayout === "feature-left" ? "left" : "right",
|
|
@@ -6884,6 +7048,35 @@ var BOLD_CHAR_WIDTH_EM = 0.66;
|
|
|
6884
7048
|
function estimateTextWidth(text, fontSize, charWidthEm = AVERAGE_CHAR_WIDTH_EM) {
|
|
6885
7049
|
return text.length * fontSize * charWidthEm;
|
|
6886
7050
|
}
|
|
7051
|
+
var DISPLAY_CHAR_EM = {
|
|
7052
|
+
space: 0.27,
|
|
7053
|
+
narrowLower: 0.36,
|
|
7054
|
+
wideLower: 0.86,
|
|
7055
|
+
lower: 0.57,
|
|
7056
|
+
narrowUpper: 0.4,
|
|
7057
|
+
wideUpper: 0.95,
|
|
7058
|
+
upper: 0.7,
|
|
7059
|
+
digit: 0.57,
|
|
7060
|
+
punct: 0.34,
|
|
7061
|
+
other: 0.62
|
|
7062
|
+
};
|
|
7063
|
+
function displayCharEm(ch) {
|
|
7064
|
+
if (ch === " ") return DISPLAY_CHAR_EM.space;
|
|
7065
|
+
if ("fijlrt".includes(ch)) return DISPLAY_CHAR_EM.narrowLower;
|
|
7066
|
+
if (ch === "m" || ch === "w") return DISPLAY_CHAR_EM.wideLower;
|
|
7067
|
+
if (ch >= "a" && ch <= "z") return DISPLAY_CHAR_EM.lower;
|
|
7068
|
+
if (ch === "I" || ch === "J") return DISPLAY_CHAR_EM.narrowUpper;
|
|
7069
|
+
if (ch === "M" || ch === "W") return DISPLAY_CHAR_EM.wideUpper;
|
|
7070
|
+
if (ch >= "A" && ch <= "Z") return DISPLAY_CHAR_EM.upper;
|
|
7071
|
+
if (ch >= "0" && ch <= "9") return DISPLAY_CHAR_EM.digit;
|
|
7072
|
+
if (".,:;-/'\u2019!?()".includes(ch)) return DISPLAY_CHAR_EM.punct;
|
|
7073
|
+
return DISPLAY_CHAR_EM.other;
|
|
7074
|
+
}
|
|
7075
|
+
function estimateDisplayTextWidth(text, fontSize) {
|
|
7076
|
+
let em = 0;
|
|
7077
|
+
for (const ch of text.normalize("NFD").replace(/\p{M}/gu, "")) em += displayCharEm(ch);
|
|
7078
|
+
return em * fontSize;
|
|
7079
|
+
}
|
|
6887
7080
|
|
|
6888
7081
|
// src/doc/templates/timelineBlock.ts
|
|
6889
7082
|
var clamp01 = (value) => Math.max(0, Math.min(1, value));
|
|
@@ -7773,7 +7966,7 @@ function shapeLayers(s, x, y, w, h, context, defaultStroke, defaultFill, fontAdj
|
|
|
7773
7966
|
const fill = s.fill ?? defaultFill;
|
|
7774
7967
|
if (s.kind === "text") {
|
|
7775
7968
|
out.push(
|
|
7776
|
-
|
|
7969
|
+
textLayer2(
|
|
7777
7970
|
`shape-${s.id}`,
|
|
7778
7971
|
s.text ?? s.label ?? "",
|
|
7779
7972
|
x + w / 2,
|
|
@@ -7832,7 +8025,7 @@ function shapeLayers(s, x, y, w, h, context, defaultStroke, defaultFill, fontAdj
|
|
|
7832
8025
|
}
|
|
7833
8026
|
if (s.label) {
|
|
7834
8027
|
out.push(
|
|
7835
|
-
|
|
8028
|
+
textLayer2(
|
|
7836
8029
|
`shape-label-${s.id}`,
|
|
7837
8030
|
s.label,
|
|
7838
8031
|
x + w / 2,
|
|
@@ -7847,7 +8040,7 @@ function shapeLayers(s, x, y, w, h, context, defaultStroke, defaultFill, fontAdj
|
|
|
7847
8040
|
}
|
|
7848
8041
|
if (s.sublabel) {
|
|
7849
8042
|
out.push(
|
|
7850
|
-
|
|
8043
|
+
textLayer2(
|
|
7851
8044
|
`shape-sublabel-${s.id}`,
|
|
7852
8045
|
s.sublabel,
|
|
7853
8046
|
x + w / 2,
|
|
@@ -7862,7 +8055,7 @@ function shapeLayers(s, x, y, w, h, context, defaultStroke, defaultFill, fontAdj
|
|
|
7862
8055
|
}
|
|
7863
8056
|
return out;
|
|
7864
8057
|
}
|
|
7865
|
-
function
|
|
8058
|
+
function textLayer2(id, text, cx, cy, width, context, color, bold, fontAdj) {
|
|
7866
8059
|
return {
|
|
7867
8060
|
type: "text",
|
|
7868
8061
|
id,
|
|
@@ -8407,6 +8600,9 @@ var templateRegistry = {
|
|
|
8407
8600
|
imageWithCaption,
|
|
8408
8601
|
leftFeature,
|
|
8409
8602
|
rightFeature,
|
|
8603
|
+
topFeature,
|
|
8604
|
+
bottomFeature,
|
|
8605
|
+
mediaOnly,
|
|
8410
8606
|
map: mapBlock,
|
|
8411
8607
|
fullBleedQuote,
|
|
8412
8608
|
list: listBlock,
|
|
@@ -8725,6 +8921,9 @@ var TEMPLATE_INPUT_DESCRIPTORS = {
|
|
|
8725
8921
|
],
|
|
8726
8922
|
leftFeature: FEATURE_DESCRIPTORS(),
|
|
8727
8923
|
rightFeature: FEATURE_DESCRIPTORS(),
|
|
8924
|
+
topFeature: [{ key: "title", description: "Heading shown with the body under the media" }],
|
|
8925
|
+
bottomFeature: [{ key: "title", description: "Heading shown with the body above the media" }],
|
|
8926
|
+
mediaOnly: [{ key: "title", description: "Heading, shown only when the block has no media" }],
|
|
8728
8927
|
map: [
|
|
8729
8928
|
{
|
|
8730
8929
|
key: "center",
|
|
@@ -9421,11 +9620,13 @@ function appendRichContentLayers(layers, block, theme, viewport, mediaAspectRati
|
|
|
9421
9620
|
const timedLayers = applyEmbeddedVideoTiming(layers, block);
|
|
9422
9621
|
const items = collectRichMediaItems(timedLayers, block);
|
|
9423
9622
|
if (items.length === 0) return timedLayers;
|
|
9424
|
-
const
|
|
9623
|
+
const knownAspects = items.map((item) => {
|
|
9425
9624
|
const key = item.kind === "image" || item.kind === "video" ? item.src : item.kind === "mermaid" ? item.source : void 0;
|
|
9426
9625
|
const intrinsic = key ? mediaAspectRatios?.[key] : void 0;
|
|
9427
|
-
|
|
9626
|
+
if (intrinsic && Number.isFinite(intrinsic) && intrinsic > 0) return intrinsic;
|
|
9627
|
+
return item.kind === "video" ? void 0 : item.aspectRatio;
|
|
9428
9628
|
});
|
|
9629
|
+
const aspects = items.map((item, index) => knownAspects[index] ?? item.aspectRatio);
|
|
9429
9630
|
const layout = block.summaryLayout === "feature" ? resolveFeatureSummaryLayout(timedLayers, viewport, aspects) : resolveSupplementalMediaLayout(
|
|
9430
9631
|
timedLayers,
|
|
9431
9632
|
block.template ? resolveTemplateName(block.template) : void 0,
|
|
@@ -9434,7 +9635,8 @@ function appendRichContentLayers(layers, block, theme, viewport, mediaAspectRati
|
|
|
9434
9635
|
aspects,
|
|
9435
9636
|
{
|
|
9436
9637
|
summaryFeature: block.summaryMode === "headings-and-features" && !timedLayers.some((layer) => layer.id === "feature-body"),
|
|
9437
|
-
stackColumns: createTemplateContext(theme, 0, 1, viewport).layout.stackColumns
|
|
9638
|
+
stackColumns: createTemplateContext(theme, 0, 1, viewport).layout.stackColumns,
|
|
9639
|
+
knownAspectRatios: knownAspects
|
|
9438
9640
|
}
|
|
9439
9641
|
);
|
|
9440
9642
|
const cells = gridCells(layout.mediaRect, items.length, viewport, layout.framed);
|
|
@@ -9596,6 +9798,18 @@ var TEMPLATE_METADATA = {
|
|
|
9596
9798
|
label: "Right Feature",
|
|
9597
9799
|
description: "Image on the right, title and body text stacked on the left."
|
|
9598
9800
|
},
|
|
9801
|
+
topFeature: {
|
|
9802
|
+
label: "Top Feature",
|
|
9803
|
+
description: "Image or video across the full width at the top, title and body text below."
|
|
9804
|
+
},
|
|
9805
|
+
bottomFeature: {
|
|
9806
|
+
label: "Bottom Feature",
|
|
9807
|
+
description: "Title and body text at the top, image or video across the full width below."
|
|
9808
|
+
},
|
|
9809
|
+
mediaOnly: {
|
|
9810
|
+
label: "Media Only",
|
|
9811
|
+
description: "The image or video fills the slide, with no title, text or caption."
|
|
9812
|
+
},
|
|
9599
9813
|
map: {
|
|
9600
9814
|
label: "Map",
|
|
9601
9815
|
description: "Embeds an interactive map centered on a geographic location."
|
|
@@ -9761,6 +9975,24 @@ var TEMPLATE_AUTHORING_METADATA = {
|
|
|
9761
9975
|
safeForContentFirst: false,
|
|
9762
9976
|
placement: "heading"
|
|
9763
9977
|
},
|
|
9978
|
+
topFeature: {
|
|
9979
|
+
role: "media",
|
|
9980
|
+
bodyPolicy: "complete",
|
|
9981
|
+
safeForContentFirst: false,
|
|
9982
|
+
placement: "heading"
|
|
9983
|
+
},
|
|
9984
|
+
bottomFeature: {
|
|
9985
|
+
role: "media",
|
|
9986
|
+
bodyPolicy: "complete",
|
|
9987
|
+
safeForContentFirst: false,
|
|
9988
|
+
placement: "heading"
|
|
9989
|
+
},
|
|
9990
|
+
mediaOnly: {
|
|
9991
|
+
role: "media",
|
|
9992
|
+
bodyPolicy: "ignored",
|
|
9993
|
+
safeForContentFirst: false,
|
|
9994
|
+
placement: "heading"
|
|
9995
|
+
},
|
|
9764
9996
|
map: {
|
|
9765
9997
|
role: "spatial",
|
|
9766
9998
|
bodyPolicy: "structured",
|
|
@@ -9921,13 +10153,227 @@ function coverScrimGradient(background) {
|
|
|
9921
10153
|
const stops = COVER_SCRIM_STOPS.map((s) => `${withAlpha(background, s.alpha)} ${s.pos}%`);
|
|
9922
10154
|
return `linear-gradient(0deg, ${stops.join(", ")})`;
|
|
9923
10155
|
}
|
|
10156
|
+
var FROSTED_LINE_HEIGHT = 1.12;
|
|
10157
|
+
var FROSTED_MAX_LINES = 3;
|
|
10158
|
+
var FROSTED_SQUARE_SHARE = 0.9;
|
|
10159
|
+
var FROSTED_PAD_X_EM = 0.45;
|
|
10160
|
+
var FROSTED_PAD_Y_EM = 0.3;
|
|
10161
|
+
var FROSTED_RADIUS_EM = 0.3;
|
|
10162
|
+
var FROSTED_BLUR_SHARE = 0.0167;
|
|
10163
|
+
var FROSTED_BOTTOM_MARGIN_PCT = { wide: 7, tall: 17 };
|
|
10164
|
+
var FROSTED_TINT_UNDER_LIGHT_TEXT = "rgba(12, 12, 14, 0.26)";
|
|
10165
|
+
var FROSTED_TINT_UNDER_DARK_TEXT = "rgba(250, 250, 250, 0.5)";
|
|
10166
|
+
var FROSTED_BACKDROP_CONTRAST = 0.65;
|
|
10167
|
+
var COVER_SUBTITLE_BASE_PX = 40;
|
|
10168
|
+
var INK_EM = { xHeight: 0.45, ascent: 0.71, accentedCapital: 0.8, descent: 0.165 };
|
|
10169
|
+
function opticalCentreShiftEm(lines) {
|
|
10170
|
+
const first = (lines[0] ?? "").normalize("NFD");
|
|
10171
|
+
const last = lines[lines.length - 1] ?? "";
|
|
10172
|
+
const top = /[A-Z]\p{M}/u.test(first) ? INK_EM.accentedCapital : /[A-Zbdfhklt0-9]|[a-z]\p{M}/u.test(first) ? INK_EM.ascent : INK_EM.xHeight;
|
|
10173
|
+
const bottom = /[gjpqyQ,;]/.test(last) ? INK_EM.descent : 0;
|
|
10174
|
+
return Math.round(((top - bottom) / 2 - INK_EM.xHeight / 2) * 1e3) / 1e3;
|
|
10175
|
+
}
|
|
10176
|
+
function wrapDisplayLine(line, fontSize, maxWidth) {
|
|
10177
|
+
const lines = [];
|
|
10178
|
+
let current = "";
|
|
10179
|
+
for (const word of line.trim().split(/\s+/).filter(Boolean)) {
|
|
10180
|
+
const candidate = current ? `${current} ${word}` : word;
|
|
10181
|
+
if (!current || estimateDisplayTextWidth(candidate, fontSize) <= maxWidth) {
|
|
10182
|
+
current = candidate;
|
|
10183
|
+
} else {
|
|
10184
|
+
lines.push(current);
|
|
10185
|
+
current = word;
|
|
10186
|
+
}
|
|
10187
|
+
}
|
|
10188
|
+
if (current) lines.push(current);
|
|
10189
|
+
return lines.length > 0 ? lines : [""];
|
|
10190
|
+
}
|
|
10191
|
+
function balancedDisplayLines(line, fontSize, maxWidth) {
|
|
10192
|
+
const greedy = wrapDisplayLine(line, fontSize, maxWidth);
|
|
10193
|
+
if (greedy.length < 2) return greedy;
|
|
10194
|
+
let lo = Math.max(
|
|
10195
|
+
...line.split(/\s+/).filter(Boolean).map((word) => estimateDisplayTextWidth(word, fontSize))
|
|
10196
|
+
);
|
|
10197
|
+
let hi = maxWidth;
|
|
10198
|
+
if (lo >= hi) return greedy;
|
|
10199
|
+
while (hi - lo > 0.5) {
|
|
10200
|
+
const mid = (lo + hi) / 2;
|
|
10201
|
+
if (wrapDisplayLine(line, fontSize, mid).length <= greedy.length) hi = mid;
|
|
10202
|
+
else lo = mid;
|
|
10203
|
+
}
|
|
10204
|
+
return wrapDisplayLine(line, fontSize, hi);
|
|
10205
|
+
}
|
|
10206
|
+
function frostedCoverLayout(title, subtitle, context) {
|
|
10207
|
+
const { width: frameW, height: frameH } = context.viewport;
|
|
10208
|
+
const shortSide = Math.min(frameW, frameH);
|
|
10209
|
+
const maxPlateWidth = FROSTED_SQUARE_SHARE * shortSide;
|
|
10210
|
+
const minSize = themedFontSize(COVER_TITLE_MIN_BASE_PX, context, true);
|
|
10211
|
+
const wrapAt = (size) => {
|
|
10212
|
+
const column2 = maxPlateWidth - 2 * FROSTED_PAD_X_EM * size;
|
|
10213
|
+
const lines2 = title.split("\n").flatMap((line) => balancedDisplayLines(line, size, column2));
|
|
10214
|
+
const width = Math.max(...lines2.map((line) => estimateDisplayTextWidth(line, size)));
|
|
10215
|
+
return { lines: lines2, width, column: column2 };
|
|
10216
|
+
};
|
|
10217
|
+
let fontSize = themedFontSize(fitCoverTitleSize(title), context, true);
|
|
10218
|
+
let wrapped = wrapAt(fontSize);
|
|
10219
|
+
while ((wrapped.lines.length > FROSTED_MAX_LINES || wrapped.width > wrapped.column) && fontSize > minSize) {
|
|
10220
|
+
fontSize = Math.max(minSize, Math.floor(fontSize * 0.95));
|
|
10221
|
+
wrapped = wrapAt(fontSize);
|
|
10222
|
+
}
|
|
10223
|
+
const { lines, column } = wrapped;
|
|
10224
|
+
const textWidth = Math.min(wrapped.width, column);
|
|
10225
|
+
const textHeight = lines.length * fontSize * FROSTED_LINE_HEIGHT;
|
|
10226
|
+
const padX = FROSTED_PAD_X_EM * fontSize;
|
|
10227
|
+
const padY = FROSTED_PAD_Y_EM * fontSize;
|
|
10228
|
+
let sub;
|
|
10229
|
+
if (subtitle?.trim()) {
|
|
10230
|
+
const subSize = themedFontSize(COVER_SUBTITLE_BASE_PX, context, false);
|
|
10231
|
+
const subLines = subtitle.split("\n").flatMap((line) => wrapDisplayLine(line, subSize, column));
|
|
10232
|
+
sub = {
|
|
10233
|
+
lines: subLines,
|
|
10234
|
+
width: Math.min(
|
|
10235
|
+
column,
|
|
10236
|
+
Math.max(...subLines.map((l) => estimateDisplayTextWidth(l, subSize)))
|
|
10237
|
+
),
|
|
10238
|
+
height: subLines.length * subSize * 1.3,
|
|
10239
|
+
fontSize: subSize,
|
|
10240
|
+
gap: 0.3 * fontSize
|
|
10241
|
+
};
|
|
10242
|
+
}
|
|
10243
|
+
const plateWidth = Math.max(textWidth, sub?.width ?? 0) + 2 * padX;
|
|
10244
|
+
const plateHeight = textHeight + (sub ? sub.gap + sub.height : 0) + 2 * padY;
|
|
10245
|
+
const marginPct = frameH > frameW ? FROSTED_BOTTOM_MARGIN_PCT.tall : FROSTED_BOTTOM_MARGIN_PCT.wide;
|
|
10246
|
+
const plateBottom = frameH * (1 - marginPct / 100);
|
|
10247
|
+
const plateY = plateBottom - plateHeight;
|
|
10248
|
+
const cx = frameW / 2;
|
|
10249
|
+
const longestChars = Math.max(...lines.map((line) => line.length));
|
|
10250
|
+
const titleBoxWidth = Math.max(textWidth, longestChars * fontSize * 0.5 + 1);
|
|
10251
|
+
return {
|
|
10252
|
+
fontSize,
|
|
10253
|
+
lines,
|
|
10254
|
+
plate: {
|
|
10255
|
+
x: cx - plateWidth / 2,
|
|
10256
|
+
y: plateY,
|
|
10257
|
+
width: plateWidth,
|
|
10258
|
+
height: plateHeight,
|
|
10259
|
+
radius: FROSTED_RADIUS_EM * fontSize
|
|
10260
|
+
},
|
|
10261
|
+
// The box spans the plate's padding too: shrink-to-fit measures the font's whole
|
|
10262
|
+
// ascent and descent (about 1.3 em), which overflows a box of 1.12 em lines and
|
|
10263
|
+
// would scale every title down by up to 14%.
|
|
10264
|
+
title: {
|
|
10265
|
+
cx,
|
|
10266
|
+
cy: plateY + padY + textHeight / 2,
|
|
10267
|
+
width: titleBoxWidth,
|
|
10268
|
+
height: textHeight + 2 * padY
|
|
10269
|
+
},
|
|
10270
|
+
...sub ? {
|
|
10271
|
+
subtitle: {
|
|
10272
|
+
cx,
|
|
10273
|
+
cy: plateY + padY + textHeight + sub.gap + sub.height / 2,
|
|
10274
|
+
width: Math.max(
|
|
10275
|
+
sub.width,
|
|
10276
|
+
Math.max(...sub.lines.map((l) => l.length)) * sub.fontSize * 0.5 + 1
|
|
10277
|
+
),
|
|
10278
|
+
height: sub.height,
|
|
10279
|
+
fontSize: sub.fontSize,
|
|
10280
|
+
lines: sub.lines
|
|
10281
|
+
}
|
|
10282
|
+
} : {},
|
|
10283
|
+
baselineShift: opticalCentreShiftEm(lines),
|
|
10284
|
+
blur: Math.round(FROSTED_BLUR_SHARE * shortSide)
|
|
10285
|
+
};
|
|
10286
|
+
}
|
|
10287
|
+
function pct(value, total) {
|
|
10288
|
+
return `${Math.round(value / total * 1e4) / 100}%`;
|
|
10289
|
+
}
|
|
10290
|
+
function frostedCoverLayers(input, context) {
|
|
10291
|
+
const { theme, viewport } = context;
|
|
10292
|
+
const layout = frostedCoverLayout(input.title, input.subtitle, context);
|
|
10293
|
+
const lightText = relativeLuminance(theme.colors.text) > 0.5;
|
|
10294
|
+
const { plate } = layout;
|
|
10295
|
+
const layers = [
|
|
10296
|
+
{
|
|
10297
|
+
type: "shape",
|
|
10298
|
+
id: "cover-plate",
|
|
10299
|
+
content: {
|
|
10300
|
+
shape: "rect",
|
|
10301
|
+
fill: lightText ? FROSTED_TINT_UNDER_LIGHT_TEXT : FROSTED_TINT_UNDER_DARK_TEXT,
|
|
10302
|
+
borderRadius: Math.round(plate.radius),
|
|
10303
|
+
backdropBlur: layout.blur,
|
|
10304
|
+
...lightText ? { backdropContrast: FROSTED_BACKDROP_CONTRAST } : {}
|
|
10305
|
+
},
|
|
10306
|
+
position: {
|
|
10307
|
+
x: pct(plate.x, viewport.width),
|
|
10308
|
+
y: pct(plate.y, viewport.height),
|
|
10309
|
+
width: pct(plate.width, viewport.width),
|
|
10310
|
+
height: pct(plate.height, viewport.height)
|
|
10311
|
+
}
|
|
10312
|
+
},
|
|
10313
|
+
{
|
|
10314
|
+
type: "text",
|
|
10315
|
+
id: "cover-title",
|
|
10316
|
+
content: {
|
|
10317
|
+
text: layout.lines.join("\n"),
|
|
10318
|
+
style: {
|
|
10319
|
+
fontSize: layout.fontSize,
|
|
10320
|
+
fontFamily: getThemeFont(context, "title"),
|
|
10321
|
+
fontWeight: "bold",
|
|
10322
|
+
color: theme.colors.text,
|
|
10323
|
+
textAlign: "center",
|
|
10324
|
+
verticalAlign: "middle",
|
|
10325
|
+
lineHeight: FROSTED_LINE_HEIGHT,
|
|
10326
|
+
baselineShift: layout.baselineShift,
|
|
10327
|
+
shadow: lightText,
|
|
10328
|
+
shrinkToFit: true
|
|
10329
|
+
}
|
|
10330
|
+
},
|
|
10331
|
+
position: {
|
|
10332
|
+
x: "50%",
|
|
10333
|
+
y: pct(layout.title.cy, viewport.height),
|
|
10334
|
+
anchor: "center",
|
|
10335
|
+
width: pct(layout.title.width, viewport.width),
|
|
10336
|
+
height: pct(layout.title.height, viewport.height)
|
|
10337
|
+
},
|
|
10338
|
+
animation: getMotionProfile(context).coverWordReveal ? { type: "wordReveal", duration: 0.5, delay: 0.1, stagger: 0.12 } : { type: "fadeIn", duration: 0.8 }
|
|
10339
|
+
}
|
|
10340
|
+
];
|
|
10341
|
+
if (layout.subtitle) {
|
|
10342
|
+
layers.push({
|
|
10343
|
+
type: "text",
|
|
10344
|
+
id: "cover-subtitle",
|
|
10345
|
+
content: {
|
|
10346
|
+
text: layout.subtitle.lines.join("\n"),
|
|
10347
|
+
style: {
|
|
10348
|
+
fontSize: layout.subtitle.fontSize,
|
|
10349
|
+
fontFamily: getThemeFont(context, "body"),
|
|
10350
|
+
fontWeight: "normal",
|
|
10351
|
+
color: lightText ? withAlpha(theme.colors.text, 0.86) : theme.colors.textMuted,
|
|
10352
|
+
textAlign: "center",
|
|
10353
|
+
verticalAlign: "middle",
|
|
10354
|
+
lineHeight: 1.3,
|
|
10355
|
+
shrinkToFit: true
|
|
10356
|
+
}
|
|
10357
|
+
},
|
|
10358
|
+
position: {
|
|
10359
|
+
x: "50%",
|
|
10360
|
+
y: pct(layout.subtitle.cy, viewport.height),
|
|
10361
|
+
anchor: "center",
|
|
10362
|
+
width: pct(layout.subtitle.width, viewport.width),
|
|
10363
|
+
height: pct(layout.subtitle.height, viewport.height)
|
|
10364
|
+
},
|
|
10365
|
+
animation: motionEntrance(context, { type: "fadeIn", duration: 0.8, delay: 0.2 })
|
|
10366
|
+
});
|
|
10367
|
+
}
|
|
10368
|
+
return layers;
|
|
10369
|
+
}
|
|
9924
10370
|
function coverBlock(input, context) {
|
|
9925
10371
|
const treatment = themedImageTreatment(context, input.imageTreatment);
|
|
9926
10372
|
const { heroSrc, heroAlt, title, subtitle, ambientMotion, heroCredit, heroLicense } = input;
|
|
9927
10373
|
const { theme, layout, viewport } = context;
|
|
9928
10374
|
const standardLightCover = !heroSrc && isStandardLightCover(context);
|
|
9929
10375
|
const titleFontSize = themedFontSize(fitCoverTitleSize(title), context, true);
|
|
9930
|
-
const subtitleFontSize = themedFontSize(
|
|
10376
|
+
const subtitleFontSize = themedFontSize(COVER_SUBTITLE_BASE_PX, context, false);
|
|
9931
10377
|
const titleYPct = subtitle ? parseFloat(layout.primaryY) : 50;
|
|
9932
10378
|
const maxWidthPx = parseFloat(layout.maxTextWidth) / 100 * viewport.width;
|
|
9933
10379
|
const titleH = Math.max(
|
|
@@ -9951,31 +10397,30 @@ function coverBlock(input, context) {
|
|
|
9951
10397
|
const layers = [];
|
|
9952
10398
|
if (heroSrc) {
|
|
9953
10399
|
const imageAnimation = mapAmbientMotion(ambientMotion);
|
|
9954
|
-
layers.push(
|
|
9955
|
-
|
|
9956
|
-
|
|
9957
|
-
|
|
9958
|
-
|
|
9959
|
-
|
|
9960
|
-
|
|
9961
|
-
|
|
9962
|
-
|
|
9963
|
-
|
|
9964
|
-
...treatment ? { treatment } : {}
|
|
9965
|
-
},
|
|
9966
|
-
position: { x: 0, y: 0, width: "100%", height: "100%" },
|
|
9967
|
-
animation: imageAnimation
|
|
10400
|
+
layers.push({
|
|
10401
|
+
type: "image",
|
|
10402
|
+
id: "cover-hero",
|
|
10403
|
+
content: {
|
|
10404
|
+
src: heroSrc,
|
|
10405
|
+
alt: heroAlt || title,
|
|
10406
|
+
fit: "cover",
|
|
10407
|
+
credit: heroCredit,
|
|
10408
|
+
license: heroLicense,
|
|
10409
|
+
...treatment ? { treatment } : {}
|
|
9968
10410
|
},
|
|
9969
|
-
{
|
|
9970
|
-
|
|
9971
|
-
|
|
9972
|
-
|
|
9973
|
-
|
|
9974
|
-
|
|
9975
|
-
|
|
9976
|
-
|
|
9977
|
-
|
|
9978
|
-
|
|
10411
|
+
position: { x: 0, y: 0, width: "100%", height: "100%" },
|
|
10412
|
+
animation: imageAnimation
|
|
10413
|
+
});
|
|
10414
|
+
if (input.coverStyle === "frosted") return [...layers, ...frostedCoverLayers(input, context)];
|
|
10415
|
+
layers.push({
|
|
10416
|
+
type: "shape",
|
|
10417
|
+
id: "cover-gradient",
|
|
10418
|
+
content: {
|
|
10419
|
+
shape: "rect",
|
|
10420
|
+
fill: coverScrimGradient(theme.colors.background)
|
|
10421
|
+
},
|
|
10422
|
+
position: { x: 0, y: 0, width: "100%", height: "100%" }
|
|
10423
|
+
});
|
|
9979
10424
|
} else {
|
|
9980
10425
|
if (standardLightCover) {
|
|
9981
10426
|
layers.push(
|
|
@@ -10084,7 +10529,8 @@ function startBlockToCoverInput(config) {
|
|
|
10084
10529
|
subtitle: config.subtitle,
|
|
10085
10530
|
ambientMotion: config.ambientMotion,
|
|
10086
10531
|
heroCredit: config.heroCredit,
|
|
10087
|
-
heroLicense: config.heroLicense
|
|
10532
|
+
heroLicense: config.heroLicense,
|
|
10533
|
+
...config.coverStyle ? { coverStyle: config.coverStyle } : {}
|
|
10088
10534
|
};
|
|
10089
10535
|
}
|
|
10090
10536
|
function expandCoverBlock(config, context, template = "cover") {
|
|
@@ -10653,193 +11099,6 @@ function extractTableData(table) {
|
|
|
10653
11099
|
};
|
|
10654
11100
|
}
|
|
10655
11101
|
|
|
10656
|
-
// src/doc/standaloneAnnotation.ts
|
|
10657
|
-
function parseAnnotationInner(inner) {
|
|
10658
|
-
const tokens = tokenizeAttrTokens(inner.trim());
|
|
10659
|
-
const firstIsParam = tokens.length > 0 && tokens[0].indexOf("=") > 0;
|
|
10660
|
-
const template = firstIsParam || tokens.length === 0 ? void 0 : tokens[0];
|
|
10661
|
-
const startIdx = firstIsParam ? 0 : 1;
|
|
10662
|
-
const params = {};
|
|
10663
|
-
for (let i = startIdx; i < tokens.length; i++) {
|
|
10664
|
-
const kv = splitKeyValueToken(tokens[i]);
|
|
10665
|
-
if (kv) params[kv.key] = kv.value;
|
|
10666
|
-
}
|
|
10667
|
-
return { template, params };
|
|
10668
|
-
}
|
|
10669
|
-
function parseStandaloneAnnotation(node) {
|
|
10670
|
-
if (node.type !== "paragraph") return null;
|
|
10671
|
-
const children = node.children ?? [];
|
|
10672
|
-
if (children.length !== 1 || children[0].type !== "text") return null;
|
|
10673
|
-
const text = children[0].value.trim();
|
|
10674
|
-
const match = matchTrailingTemplateAnnotation(text);
|
|
10675
|
-
if (!match || match.index !== 0) return null;
|
|
10676
|
-
return parseAnnotationInner(match.inner);
|
|
10677
|
-
}
|
|
10678
|
-
|
|
10679
|
-
// src/doc/mediaAnnotations.ts
|
|
10680
|
-
var MEDIA_TEMPLATES = /* @__PURE__ */ new Set(["audio", "video", "media"]);
|
|
10681
|
-
function isMediaAnnotationName(name) {
|
|
10682
|
-
return name != null && MEDIA_TEMPLATES.has(name);
|
|
10683
|
-
}
|
|
10684
|
-
function time(raw) {
|
|
10685
|
-
if (raw == null) return null;
|
|
10686
|
-
return parseTimeSeconds(raw);
|
|
10687
|
-
}
|
|
10688
|
-
function videoPlacement(params) {
|
|
10689
|
-
const explicit = params.placement ?? params.presentation;
|
|
10690
|
-
if (explicit === "content") return "content";
|
|
10691
|
-
if (explicit === "pip" || explicit === "picture-in-picture") return "picture-in-picture";
|
|
10692
|
-
if (explicit === "overlay" || explicit === "full-frame") return "overlay";
|
|
10693
|
-
if (params.pip === "" || params.pip === "true") return "picture-in-picture";
|
|
10694
|
-
if (params.overlay === "" || params.overlay === "true") return "overlay";
|
|
10695
|
-
return void 0;
|
|
10696
|
-
}
|
|
10697
|
-
function lockToBlock(raw) {
|
|
10698
|
-
return raw !== "false" && raw !== "0";
|
|
10699
|
-
}
|
|
10700
|
-
function videoPipSize(raw) {
|
|
10701
|
-
return raw === "small" || raw === "large" ? raw : void 0;
|
|
10702
|
-
}
|
|
10703
|
-
function videoPipShape(raw) {
|
|
10704
|
-
return raw === "square" || raw === "wide" ? raw : void 0;
|
|
10705
|
-
}
|
|
10706
|
-
function videoPipPosition(raw) {
|
|
10707
|
-
return raw === "top-left" || raw === "top-right" || raw === "bottom-left" || raw === "bottom-right" ? raw : void 0;
|
|
10708
|
-
}
|
|
10709
|
-
function toMediaClip(parsed, id) {
|
|
10710
|
-
const { template, params } = parsed;
|
|
10711
|
-
if (!template || !MEDIA_TEMPLATES.has(template)) return null;
|
|
10712
|
-
const src = params.src;
|
|
10713
|
-
if (!src) return null;
|
|
10714
|
-
const kind = template === "video" ? "video" : "audio";
|
|
10715
|
-
const anchor = params.anchor === "document" || params.span === "document" ? "document" : "block";
|
|
10716
|
-
const clip = {
|
|
10717
|
-
id,
|
|
10718
|
-
src,
|
|
10719
|
-
kind,
|
|
10720
|
-
startAt: time(params.startAt ?? params.startTime) ?? 0,
|
|
10721
|
-
anchor
|
|
10722
|
-
};
|
|
10723
|
-
const placement = kind === "video" ? videoPlacement(params) : void 0;
|
|
10724
|
-
if (placement && placement !== "content") clip.placement = placement;
|
|
10725
|
-
const pipSize = videoPipSize(params.pipSize);
|
|
10726
|
-
const pipShape = videoPipShape(params.pipShape);
|
|
10727
|
-
const pipPosition = videoPipPosition(params.pipPosition);
|
|
10728
|
-
if (pipSize) clip.pipSize = pipSize;
|
|
10729
|
-
if (pipShape) clip.pipShape = pipShape;
|
|
10730
|
-
if (pipPosition) clip.pipPosition = pipPosition;
|
|
10731
|
-
if (kind === "video" && placement && placement !== "content" && params.lockToBlock != null) {
|
|
10732
|
-
const locked = lockToBlock(params.lockToBlock);
|
|
10733
|
-
clip.lockToBlock = locked;
|
|
10734
|
-
clip.anchor = locked ? "block" : "document";
|
|
10735
|
-
if (locked) clip.startAt = 0;
|
|
10736
|
-
}
|
|
10737
|
-
const clipStart = time(params.clipStart);
|
|
10738
|
-
const clipEnd = time(params.clipEnd);
|
|
10739
|
-
if (clipStart != null) clip.clipStart = clipStart;
|
|
10740
|
-
if (clipEnd != null) clip.clipEnd = clipEnd;
|
|
10741
|
-
if (clip.lockToBlock === true) delete clip.clipEnd;
|
|
10742
|
-
if (params.spillover === "true" || params.spillover === "") clip.spillover = true;
|
|
10743
|
-
const edits = parseMediaEdits(mediaEditValuesFromParams(params));
|
|
10744
|
-
if (edits) clip.edits = edits;
|
|
10745
|
-
return clip;
|
|
10746
|
-
}
|
|
10747
|
-
function firstVideoElement(children) {
|
|
10748
|
-
const visit = (nodes) => {
|
|
10749
|
-
for (const child of nodes) {
|
|
10750
|
-
if (child.type !== "htmlElement") continue;
|
|
10751
|
-
if (child.tagName === "video") return child;
|
|
10752
|
-
const nested = visit(child.children);
|
|
10753
|
-
if (nested) return nested;
|
|
10754
|
-
}
|
|
10755
|
-
return null;
|
|
10756
|
-
};
|
|
10757
|
-
return visit(children);
|
|
10758
|
-
}
|
|
10759
|
-
function standaloneHtmlVideo(node) {
|
|
10760
|
-
if (node.type === "htmlBlock") {
|
|
10761
|
-
if (!/^\s*<video\b/i.test(node.rawHtml)) return null;
|
|
10762
|
-
const element = firstVideoElement(node.htmlChildren);
|
|
10763
|
-
return element ? { element, raw: node.rawHtml.trim() } : null;
|
|
10764
|
-
}
|
|
10765
|
-
if (node.type !== "paragraph" || !node.children.every((child) => child.type === "htmlInline")) {
|
|
10766
|
-
return null;
|
|
10767
|
-
}
|
|
10768
|
-
const raw = node.children.map((child) => child.type === "htmlInline" ? child.rawHtml : "").join("");
|
|
10769
|
-
if (!/^\s*<video\b[\s\S]*<\/video>\s*$/i.test(raw)) return null;
|
|
10770
|
-
for (const child of node.children) {
|
|
10771
|
-
if (child.type !== "htmlInline") continue;
|
|
10772
|
-
const element = firstVideoElement(child.htmlChildren);
|
|
10773
|
-
if (element) return { element, raw: raw.trim() };
|
|
10774
|
-
}
|
|
10775
|
-
return null;
|
|
10776
|
-
}
|
|
10777
|
-
function htmlVideoClip(node, id) {
|
|
10778
|
-
const authored = standaloneHtmlVideo(node);
|
|
10779
|
-
if (!authored) return null;
|
|
10780
|
-
const { element } = authored;
|
|
10781
|
-
const placement = videoPlacement({
|
|
10782
|
-
placement: element.attributes["data-squisq-video-placement"] ?? ""
|
|
10783
|
-
});
|
|
10784
|
-
if (!placement || placement === "content") return null;
|
|
10785
|
-
const src = element.attributes.src;
|
|
10786
|
-
if (!src) return null;
|
|
10787
|
-
const locked = lockToBlock(element.attributes["data-squisq-video-lock-to-block"]);
|
|
10788
|
-
const clip = {
|
|
10789
|
-
id,
|
|
10790
|
-
src,
|
|
10791
|
-
kind: "video",
|
|
10792
|
-
placement,
|
|
10793
|
-
lockToBlock: locked,
|
|
10794
|
-
startAt: locked ? 0 : time(element.attributes["data-squisq-video-start-at"]) ?? 0,
|
|
10795
|
-
anchor: locked ? "block" : "document"
|
|
10796
|
-
};
|
|
10797
|
-
const pipSize = videoPipSize(element.attributes["data-squisq-video-pip-size"]);
|
|
10798
|
-
const pipShape = videoPipShape(element.attributes["data-squisq-video-pip-shape"]);
|
|
10799
|
-
const pipPosition = videoPipPosition(element.attributes["data-squisq-video-pip-position"]);
|
|
10800
|
-
if (pipSize) clip.pipSize = pipSize;
|
|
10801
|
-
if (pipShape) clip.pipShape = pipShape;
|
|
10802
|
-
if (pipPosition) clip.pipPosition = pipPosition;
|
|
10803
|
-
const clipStart = time(element.attributes["data-squisq-video-clip-start"]);
|
|
10804
|
-
const clipEnd = time(element.attributes["data-squisq-video-clip-end"]);
|
|
10805
|
-
if (clipStart != null) clip.clipStart = clipStart;
|
|
10806
|
-
if (!locked && clipEnd != null) clip.clipEnd = clipEnd;
|
|
10807
|
-
const edits = parseMediaEdits(mediaEditValuesFromAttributes("video", element.attributes));
|
|
10808
|
-
if (edits) clip.edits = edits;
|
|
10809
|
-
return clip;
|
|
10810
|
-
}
|
|
10811
|
-
function extractMediaFromContents(contents, makeId, blockId) {
|
|
10812
|
-
const media = [];
|
|
10813
|
-
const documentMedia = [];
|
|
10814
|
-
const remaining = [];
|
|
10815
|
-
let index = 0;
|
|
10816
|
-
let originalIndex = 0;
|
|
10817
|
-
for (const node of contents ?? []) {
|
|
10818
|
-
const parsed = parseStandaloneAnnotation(node);
|
|
10819
|
-
const clip = parsed ? toMediaClip(parsed, "") : htmlVideoClip(node, "");
|
|
10820
|
-
if (clip) {
|
|
10821
|
-
clip.id = makeId(clip.src, index++);
|
|
10822
|
-
const line = node.position?.start.line;
|
|
10823
|
-
if (line != null) clip.sourceLine = line;
|
|
10824
|
-
if (blockId !== void 0) {
|
|
10825
|
-
const authoredHtml = standaloneHtmlVideo(node);
|
|
10826
|
-
const rawText = node.type === "paragraph" && node.children?.[0]?.type === "text" ? node.children[0].value.trim() : authoredHtml?.raw;
|
|
10827
|
-
clip.origin = {
|
|
10828
|
-
blockId,
|
|
10829
|
-
index: originalIndex,
|
|
10830
|
-
...rawText !== void 0 ? { raw: rawText } : {},
|
|
10831
|
-
...authoredHtml ? { format: "html" } : {}
|
|
10832
|
-
};
|
|
10833
|
-
}
|
|
10834
|
-
(clip.anchor === "document" ? documentMedia : media).push(clip);
|
|
10835
|
-
} else {
|
|
10836
|
-
remaining.push(node);
|
|
10837
|
-
}
|
|
10838
|
-
originalIndex++;
|
|
10839
|
-
}
|
|
10840
|
-
return { media, documentMedia, remaining };
|
|
10841
|
-
}
|
|
10842
|
-
|
|
10843
11102
|
// src/doc/annotationBlocks.ts
|
|
10844
11103
|
function applyBlockMeta(block, m) {
|
|
10845
11104
|
if (m.build) block.build = m.build;
|
|
@@ -11841,7 +12100,7 @@ function resolveBuildTimeline(steps, spec, duration, timing) {
|
|
|
11841
12100
|
let consumed = 0;
|
|
11842
12101
|
let previous = 0;
|
|
11843
12102
|
const matched = timing?.sourceText === buildSourceText(steps) && timing.starts.length === steps.length && timing.starts.every(
|
|
11844
|
-
(
|
|
12103
|
+
(time, i) => Number.isFinite(time) && time >= 0 && (i === 0 || time >= timing.starts[i - 1])
|
|
11845
12104
|
);
|
|
11846
12105
|
const starts = steps.map((_, i) => {
|
|
11847
12106
|
const automatic = intro + Math.max(0, latest - intro) * consumed / Math.max(1, total);
|
|
@@ -11858,15 +12117,15 @@ function resolveBuildTimeline(steps, spec, duration, timing) {
|
|
|
11858
12117
|
);
|
|
11859
12118
|
return { starts, entrance, compressed: steps.length > 0 && end < steps.length * 0.8 };
|
|
11860
12119
|
}
|
|
11861
|
-
function buildCursorAtTime(timeline,
|
|
12120
|
+
function buildCursorAtTime(timeline, time) {
|
|
11862
12121
|
let revealed = 0;
|
|
11863
12122
|
for (const start of timeline.starts) {
|
|
11864
|
-
if (
|
|
12123
|
+
if (time < start) break;
|
|
11865
12124
|
revealed++;
|
|
11866
12125
|
}
|
|
11867
12126
|
return {
|
|
11868
12127
|
revealed,
|
|
11869
|
-
progress: revealed === 0 ? 0 : timeline.entrance === 0 ? 1 : Math.min(1, Math.max(0, (
|
|
12128
|
+
progress: revealed === 0 ? 0 : timeline.entrance === 0 ? 1 : Math.min(1, Math.max(0, (time - timeline.starts[revealed - 1]) / timeline.entrance))
|
|
11870
12129
|
};
|
|
11871
12130
|
}
|
|
11872
12131
|
function buildTargetState(index, steps, cursor, spec, motion = true) {
|
|
@@ -11937,13 +12196,13 @@ function resolveDocBuildTiming(doc, blocks) {
|
|
|
11937
12196
|
}
|
|
11938
12197
|
|
|
11939
12198
|
// src/doc/templates/contentBlock.ts
|
|
11940
|
-
function bodyNodes(context) {
|
|
12199
|
+
function bodyNodes(context, omitPictures) {
|
|
11941
12200
|
if (context.block?.summaryMode === "headings-and-features") return [];
|
|
11942
12201
|
return (context.block?.contents ?? []).filter(
|
|
11943
12202
|
// Mermaid source and hosted-video links are already materialized as
|
|
11944
12203
|
// visual layers (a diagram, a player). Repeating them as prose makes the
|
|
11945
12204
|
// loss-averse default noisy without preserving any additional meaning.
|
|
11946
|
-
(node) => !isMaterializedMediaNode(node)
|
|
12205
|
+
(node) => !isMaterializedMediaNode(node) && !(omitPictures && isPictureParagraph(node))
|
|
11947
12206
|
);
|
|
11948
12207
|
}
|
|
11949
12208
|
function listParagraphs(list, level = 0) {
|
|
@@ -11988,10 +12247,10 @@ function bodyFontSize(body, context) {
|
|
|
11988
12247
|
const base = body.length > 1800 ? 18 : body.length > 1100 ? 21 : body.length > 650 ? 24 : 28;
|
|
11989
12248
|
return themedFontSize(base, context, false);
|
|
11990
12249
|
}
|
|
11991
|
-
function contentBlock(input, context) {
|
|
12250
|
+
function contentBlock(input, context, options = {}) {
|
|
11992
12251
|
const { theme } = context;
|
|
11993
12252
|
const title = input.title ?? context.block?.title ?? "";
|
|
11994
|
-
const markdown = bodyNodes(context);
|
|
12253
|
+
const markdown = bodyNodes(context, options.omitPictures === true);
|
|
11995
12254
|
const paragraphs = completeBodyParagraphs(markdown);
|
|
11996
12255
|
const body = paragraphs.map(plainParagraphText).join("\n");
|
|
11997
12256
|
const builds = planContentBuilds(markdown, input.build ?? context.block?.build);
|
|
@@ -12093,6 +12352,9 @@ export {
|
|
|
12093
12352
|
imageWithCaption,
|
|
12094
12353
|
leftFeature,
|
|
12095
12354
|
rightFeature,
|
|
12355
|
+
topFeature,
|
|
12356
|
+
bottomFeature,
|
|
12357
|
+
mediaOnly,
|
|
12096
12358
|
mapBlock,
|
|
12097
12359
|
fullBleedQuote,
|
|
12098
12360
|
listBlock,
|
|
@@ -12149,7 +12411,6 @@ export {
|
|
|
12149
12411
|
parseYamlSubset,
|
|
12150
12412
|
findFirstTable,
|
|
12151
12413
|
extractTableData,
|
|
12152
|
-
parseStandaloneAnnotation,
|
|
12153
12414
|
getPinnedBlockMeta,
|
|
12154
12415
|
markdownToDoc,
|
|
12155
12416
|
flattenBlocks,
|