@bendyline/squisq 2.4.3 → 2.5.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/dist/{Doc-BKKcPjfe.d.ts → Doc-DBadkoP4.d.ts} +30 -2
- package/dist/{ImageEditDoc-CU1cXxRd.d.ts → ImageEditDoc-Cq2a3c30.d.ts} +1 -1
- package/dist/{chunk-7TJJA2RI.js → chunk-6MVWWZHL.js} +1 -1
- package/dist/{chunk-EMXYZLRH.js → chunk-7Z5T3CUI.js} +1 -1
- package/dist/{chunk-2HY2ZA7U.js → chunk-GSJEGMKF.js} +317 -18
- package/dist/{chunk-JUAC2QWP.js → chunk-HXMV7WQB.js} +1 -1
- package/dist/{chunk-D6YTLQCL.js → chunk-NBKAXPSX.js} +177 -176
- package/dist/{chunk-AQF5ZYDI.js → chunk-NNL3HHKA.js} +139 -15
- package/dist/doc/index.d.ts +121 -14
- package/dist/doc/index.js +18 -4
- 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 +20 -6
- package/dist/jsonForm/index.d.ts +1 -1
- package/dist/markdown/index.js +3 -3
- package/dist/{materializePageSection-WDJCTJEm.d.ts → materializePageSection-DgOFYge7.d.ts} +1 -1
- package/dist/narration/index.d.ts +1 -1
- package/dist/narration/index.js +3 -3
- package/dist/schemas/index.d.ts +4 -4
- package/dist/{themeLibrary-BMXXLZBU.d.ts → themeLibrary-8BQMY2HV.d.ts} +1 -1
- package/dist/transform/index.d.ts +2 -2
- package/package.json +1 -1
|
@@ -456,6 +456,25 @@ interface SectionHeaderInput extends BaseTemplateBlock {
|
|
|
456
456
|
/** Ambient motion for background image */
|
|
457
457
|
ambientMotion?: 'zoomIn' | 'zoomOut' | 'panLeft' | 'panRight';
|
|
458
458
|
}
|
|
459
|
+
/**
|
|
460
|
+
* Big text - thumbnail-style display card with the title in gigantic
|
|
461
|
+
* uppercase type, sized to fill the frame minus a small padding margin.
|
|
462
|
+
* With an image, the title sits over a full-bleed photo with a theme-tinted
|
|
463
|
+
* contrast bloom behind the text; without one, it sits on a clean theme
|
|
464
|
+
* surface. Shows nothing but the title — body content feeds narration only.
|
|
465
|
+
* Built for YouTube covers and social thumbnails.
|
|
466
|
+
*/
|
|
467
|
+
interface BigTextInput extends BaseTemplateBlock {
|
|
468
|
+
template: 'bigText';
|
|
469
|
+
/** The display text (rendered uppercase). */
|
|
470
|
+
title: string;
|
|
471
|
+
/** Optional full-bleed background image path. */
|
|
472
|
+
imageSrc?: string;
|
|
473
|
+
/** Alt text for the background image. */
|
|
474
|
+
imageAlt?: string;
|
|
475
|
+
/** Ambient motion for the background image. */
|
|
476
|
+
ambientMotion?: 'zoomIn' | 'zoomOut' | 'panLeft' | 'panRight';
|
|
477
|
+
}
|
|
459
478
|
/**
|
|
460
479
|
* Content block - loss-averse heading and body layout.
|
|
461
480
|
*
|
|
@@ -1066,7 +1085,7 @@ type ChartTemplateInput = BarChartInput | ColumnChartInput | PieChartInput | Don
|
|
|
1066
1085
|
/**
|
|
1067
1086
|
* Union of all template block types.
|
|
1068
1087
|
*/
|
|
1069
|
-
type TemplateBlock = TitleBlockInput | SectionHeaderInput | ContentBlockInput | StatHighlightInput | QuoteBlockInput | FactCardInput | TwoColumnInput | DateEventInput | ImageWithCaptionInput | LeftFeatureInput | RightFeatureInput | MapBlockInput | FullBleedQuoteInput | ListBlockInput | PhotoGridInput | DefinitionCardInput | ComparisonBarInput | PullQuoteInput | VideoWithCaptionInput | VideoPullQuoteInput | DataTableInput | BarChartInput | ColumnChartInput | PieChartInput | DonutChartInput | LineChartInput | AreaChartInput | ScatterChartInput | DiagramBlockInput | TreeBlockInput | TimelineBlockInput | DrawingBlockInput | RawLayersInput;
|
|
1088
|
+
type TemplateBlock = TitleBlockInput | SectionHeaderInput | BigTextInput | ContentBlockInput | StatHighlightInput | QuoteBlockInput | FactCardInput | TwoColumnInput | DateEventInput | ImageWithCaptionInput | LeftFeatureInput | RightFeatureInput | MapBlockInput | FullBleedQuoteInput | ListBlockInput | PhotoGridInput | DefinitionCardInput | ComparisonBarInput | PullQuoteInput | VideoWithCaptionInput | VideoPullQuoteInput | DataTableInput | BarChartInput | ColumnChartInput | PieChartInput | DonutChartInput | LineChartInput | AreaChartInput | ScatterChartInput | DiagramBlockInput | TreeBlockInput | TimelineBlockInput | DrawingBlockInput | RawLayersInput;
|
|
1070
1089
|
/**
|
|
1071
1090
|
* A block can be either a raw Block or a TemplateBlock.
|
|
1072
1091
|
*/
|
|
@@ -2638,6 +2657,15 @@ interface TextStyle {
|
|
|
2638
2657
|
padding?: number;
|
|
2639
2658
|
/** Maximum number of lines before truncation (adds "..." to last line) */
|
|
2640
2659
|
maxLines?: number;
|
|
2660
|
+
/**
|
|
2661
|
+
* Fit the rendered text to the layer's box: the renderer measures the
|
|
2662
|
+
* real glyphs and scales the text down (never up) to stay inside the box,
|
|
2663
|
+
* and — when vertically centered — centers the whole wrapped block on the
|
|
2664
|
+
* anchor instead of hanging extra lines below it. For display type sized
|
|
2665
|
+
* from estimates (e.g. the bigText template), where the actual font can
|
|
2666
|
+
* run wider than any pure width model.
|
|
2667
|
+
*/
|
|
2668
|
+
shrinkToFit?: boolean;
|
|
2641
2669
|
}
|
|
2642
2670
|
/**
|
|
2643
2671
|
* Animation to apply to a layer.
|
|
@@ -2770,4 +2798,4 @@ declare function getBlockAtTime(blocks: Block[], time: number): Block | null;
|
|
|
2770
2798
|
*/
|
|
2771
2799
|
declare function getCaptionAtTime(captions: CaptionTrack | undefined, time: number): CaptionPhrase | null;
|
|
2772
2800
|
|
|
2773
|
-
export { type
|
|
2801
|
+
export { type ImageLayer as $, type AccentImage as A, type BarChartInput as B, type CaptionPhrase as C, DARK_SURFACE as D, DEFAULT_DOC_FONT as E, DEFAULT_TITLE_FONT as F, type DataTableInput as G, type DateEventInput as H, type DeepPartial as I, type DefinitionCardInput as J, type DiagramBlockInput as K, type DiagramEdgeAnchor as L, type DiagramTemplateEdge as M, type DiagramTemplateNode as N, type Doc as O, type DocBlock as P, type DocDiagnostic as Q, type DonutChartInput as R, type DrawingBlockInput as S, FRONTMATTER_CUSTOM_TEMPLATES_KEY as T, FRONTMATTER_CUSTOM_THEMES_KEY as U, type FactCardInput as V, type FontFamily as W, type FontFamilyKind as X, type FullBleedQuoteInput as Y, type GradientBackgroundConfig as Z, type ImageBackgroundConfig as _, type AccentPosition as a, type ScheduledClip as a$, type ImageTreatment as a0, type ImageWithCaptionInput as a1, LIGHT_SURFACE as a2, type Layer as a3, type LayerRepeat as a4, type LayoutHints as a5, type LeftFeatureInput as a6, type LineChartInput as a7, type LinearGradient as a8, type ListBlockInput as a9, type PageAccentRotation as aA, type PageBackground as aB, type PageDesignFamily as aC, type PageEmphasis as aD, type PageHeadingTreatment as aE, type PageSectionKind as aF, type PageSectionOverride as aG, type PageTokens as aH, type PathLayer as aI, type PatternBackgroundConfig as aJ, type PersistentLayer as aK, type PersistentLayerConfig as aL, type PersistentLayerTemplate as aM, type PersistentLayerTemplateConfig as aN, type PersistentLayerTemplateType as aO, type PhotoGridInput as aP, type PieChartInput as aQ, type PipStyle as aR, type Position as aS, type ProgressIndicatorConfig as aT, type PromotedBodyAnnotation as aU, type PullQuoteInput as aV, type QuoteBlockInput as aW, type RawLayersInput as aX, type RenderStyle as aY, type RightFeatureInput as aZ, type ScatterChartInput as a_, type MapBlockInput as aa, type MapLayer as ab, type MapMarker as ac, type MapTileStyle as ad, type MarkerStyle as ae, type MediaClip as af, type MediaScheduleOptions as ag, type MermaidLayer as ah, PAGE_ACCENT_STRATEGIES as ai, PAGE_BACKGROUNDS as aj, PAGE_BACKGROUND_RHYTHMS as ak, PAGE_DESIGN_FAMILIES as al, PAGE_DIVIDERS as am, PAGE_EMPHASES as an, PAGE_EYEBROWS as ao, PAGE_HEADING_CASES as ap, PAGE_HEADING_SCALES as aq, PAGE_HEADING_UNDERLINES as ar, PAGE_HERO_STYLES as as, PAGE_IMAGE_FRAMINGS as at, PAGE_NUMERAL_STYLES as au, PAGE_PATTERNS as av, PAGE_QUOTE_MARKS as aw, PAGE_SECTION_KINDS as ax, PAGE_SECTION_SPACINGS as ay, PAGE_SHADOWS as az, type AmbientGradientConfig as b, getSegmentAtTime as b$, type SectionHeaderInput as b0, type ShapeFilter as b1, type ShapeLayer as b2, type ShapePattern as b3, type SolidBackgroundConfig as b4, type StartBlockConfig as b5, type StatHighlightInput as b6, type SurfaceScheme as b7, THEME_SCHEMA_VERSION as b8, type TableLayer as b9, type TreeTemplateItem as bA, type TwoColumnInput as bB, VIEWPORT_PRESETS as bC, type VideoLayer as bD, type VideoPipPosition as bE, type VideoPipShape as bF, type VideoPipSize as bG, type VideoPlacement as bH, type VideoPresentation as bI, type VideoPullQuoteInput as bJ, type VideoWithCaptionInput as bK, type ViewportConfig as bL, type ViewportOrientation as bM, type ViewportPreset as bN, type VignetteConfig as bO, applySurface as bP, calculateDuration as bQ, calculateFontScale as bR, createTemplateContext as bS, createTheme as bT, createThemeRegistry as bU, getAspectRatioString as bV, getBlockAtTime as bW, getCaptionAtTime as bX, getDocPlaybackDuration as bY, getLayoutHints as bZ, getSafeTextBounds as b_, type TableLayerStyle as ba, type TemplateBlock as bb, type TemplateContext as bc, type TemplateFunction as bd, type TemplateRegistry as be, type TextLayer as bf, type TextStyle as bg, type Theme as bh, type ThemeColorPalette as bi, type ThemeColorScheme as bj, type ThemePageStyle as bk, type ThemeRegistry as bl, type ThemeSchemaVersion as bm, type ThemeSeedColors as bn, type ThemeStyle as bo, type ThemeTypography as bp, type TimelineBlockInput as bq, type TimelineTemplateEvent as br, type TimelineTemplateLink as bs, type TimelineTemplateTrack as bt, type TitleBlockInput as bu, type TitleCaptionConfig as bv, type TreeBlockInput as bw, type TreeLayer as bx, type TreeLayerItem as by, type TreeLayerStyle as bz, type Animation as c, getTwoColumnPositions as c0, getViewport as c1, getViewportOrientation as c2, isCustomTemplateDefinition as c3, isPersistentLayerTemplate as c4, isTemplateBlock as c5, scaledFontSize$1 as c6, resolveMediaSchedule as c7, scaledFontSize as c8, validateCustomTemplateDefinition as c9, type AnimationType as d, type AreaChartInput as e, type AudioBookmark as f, type AudioSegment as g, type AudioTimingData as h, type AudioTrack as i, type BigTextInput as j, type Block as k, type BlockConnection as l, type BorderStyle as m, type CaptionTrack as n, type CaptionWord as o, type ChartBaseFields as p, type ChartTemplateInput as q, type ColorScheme as r, type ColumnChartInput as s, type ComparisonBarInput as t, type ContentBlockInput as u, type CornerBrandingConfig as v, type CustomTemplateDefinition as w, type CustomTemplateLayer as x, type CustomTemplateValidationError as y, type CustomTemplateValidationResult as z };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { $ as ImageLayer, bf as TextLayer, b2 as ShapeLayer, aI as PathLayer } from './Doc-DBadkoP4.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* ImageEditDoc — JSON document describing a layered, editable image.
|
|
@@ -56,7 +56,7 @@ import {
|
|
|
56
56
|
sanitizeUrl,
|
|
57
57
|
splitKeyValueToken,
|
|
58
58
|
tokenizeAttrTokens
|
|
59
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-NBKAXPSX.js";
|
|
60
60
|
import {
|
|
61
61
|
extractPlainText,
|
|
62
62
|
readFrontmatterThemeId,
|
|
@@ -934,6 +934,138 @@ function sectionHeader(input, context) {
|
|
|
934
934
|
return layers;
|
|
935
935
|
}
|
|
936
936
|
|
|
937
|
+
// src/doc/templates/bigText.ts
|
|
938
|
+
var BIG_TEXT_LINE_HEIGHT = 1.05;
|
|
939
|
+
var BIG_TEXT_WIDTH_FRACTION = 0.92;
|
|
940
|
+
var BIG_TEXT_HEIGHT_FRACTION = 0.86;
|
|
941
|
+
var BIG_TEXT_CHAR_WIDTH = 0.62;
|
|
942
|
+
var BIG_TEXT_MIN_PX = 48;
|
|
943
|
+
function wrappedLineCount(wordLengths, charsPerLine) {
|
|
944
|
+
let lines = 1;
|
|
945
|
+
let current = 0;
|
|
946
|
+
for (const length of wordLengths) {
|
|
947
|
+
const withWord = current === 0 ? length : current + 1 + length;
|
|
948
|
+
if (withWord <= charsPerLine) {
|
|
949
|
+
current = withWord;
|
|
950
|
+
} else {
|
|
951
|
+
lines += 1;
|
|
952
|
+
current = length;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
return lines;
|
|
956
|
+
}
|
|
957
|
+
function fitBigTextSize(title, viewport) {
|
|
958
|
+
const availWidth = viewport.width * BIG_TEXT_WIDTH_FRACTION;
|
|
959
|
+
const availHeight = viewport.height * BIG_TEXT_HEIGHT_FRACTION;
|
|
960
|
+
const wordLengths = title.trim().split(/\s+/).filter(Boolean).map((word) => word.length);
|
|
961
|
+
if (wordLengths.length === 0) return Math.floor(availHeight / BIG_TEXT_LINE_HEIGHT);
|
|
962
|
+
const longestWord = Math.max(...wordLengths);
|
|
963
|
+
const widthCap = availWidth / (BIG_TEXT_CHAR_WIDTH * longestWord);
|
|
964
|
+
const singleLineCap = availHeight / BIG_TEXT_LINE_HEIGHT;
|
|
965
|
+
const fits = (size) => {
|
|
966
|
+
const charsPerLine = Math.max(1, Math.floor(availWidth / (size * BIG_TEXT_CHAR_WIDTH)));
|
|
967
|
+
const lines = wrappedLineCount(wordLengths, charsPerLine);
|
|
968
|
+
return lines * size * BIG_TEXT_LINE_HEIGHT <= availHeight;
|
|
969
|
+
};
|
|
970
|
+
let low = BIG_TEXT_MIN_PX;
|
|
971
|
+
let high = Math.min(widthCap, singleLineCap);
|
|
972
|
+
if (high <= low) return Math.max(BIG_TEXT_MIN_PX, Math.floor(high));
|
|
973
|
+
if (!fits(low)) return BIG_TEXT_MIN_PX;
|
|
974
|
+
for (let i = 0; i < 24; i += 1) {
|
|
975
|
+
const mid = (low + high) / 2;
|
|
976
|
+
if (fits(mid)) low = mid;
|
|
977
|
+
else high = mid;
|
|
978
|
+
}
|
|
979
|
+
return Math.floor(low);
|
|
980
|
+
}
|
|
981
|
+
function bigTextBloom(background) {
|
|
982
|
+
return `radial-gradient(ellipse at 50% 50%, ${withAlpha(background, 0.92)} 0%, ${withAlpha(background, 0.78)} 38%, ${withAlpha(background, 0.32)} 66%, ${withAlpha(background, 0)} 88%)`;
|
|
983
|
+
}
|
|
984
|
+
function bigText(input, context) {
|
|
985
|
+
const { title = "", imageSrc, imageAlt, ambientMotion } = input;
|
|
986
|
+
const { theme, viewport } = context;
|
|
987
|
+
const treatment = themedImageTreatment(context, input.imageTreatment);
|
|
988
|
+
const displayTitle = title.toUpperCase();
|
|
989
|
+
const titleFontSize = fitBigTextSize(displayTitle, viewport);
|
|
990
|
+
const layers = [];
|
|
991
|
+
if (imageSrc) {
|
|
992
|
+
layers.push(
|
|
993
|
+
{
|
|
994
|
+
type: "image",
|
|
995
|
+
id: "bigtext-image",
|
|
996
|
+
content: {
|
|
997
|
+
src: imageSrc,
|
|
998
|
+
alt: imageAlt || title,
|
|
999
|
+
fit: "cover",
|
|
1000
|
+
...treatment ? { treatment } : {}
|
|
1001
|
+
},
|
|
1002
|
+
position: { x: 0, y: 0, width: "100%", height: "100%" },
|
|
1003
|
+
animation: mapAmbientMotion(ambientMotion, 8) ?? {
|
|
1004
|
+
type: "slowZoom",
|
|
1005
|
+
duration: 8,
|
|
1006
|
+
direction: "in"
|
|
1007
|
+
}
|
|
1008
|
+
},
|
|
1009
|
+
{
|
|
1010
|
+
type: "shape",
|
|
1011
|
+
id: "bigtext-bloom",
|
|
1012
|
+
content: {
|
|
1013
|
+
shape: "rect",
|
|
1014
|
+
fill: bigTextBloom(theme.colors.background)
|
|
1015
|
+
},
|
|
1016
|
+
position: { x: 0, y: 0, width: "100%", height: "100%" }
|
|
1017
|
+
}
|
|
1018
|
+
);
|
|
1019
|
+
} else {
|
|
1020
|
+
layers.push(
|
|
1021
|
+
{
|
|
1022
|
+
type: "shape",
|
|
1023
|
+
id: "bigtext-bg",
|
|
1024
|
+
content: {
|
|
1025
|
+
shape: "rect",
|
|
1026
|
+
fill: theme.colors.background
|
|
1027
|
+
},
|
|
1028
|
+
position: { x: 0, y: 0, width: "100%", height: "100%" }
|
|
1029
|
+
},
|
|
1030
|
+
{
|
|
1031
|
+
type: "shape",
|
|
1032
|
+
id: "bigtext-tint",
|
|
1033
|
+
content: {
|
|
1034
|
+
shape: "rect",
|
|
1035
|
+
fill: `radial-gradient(ellipse at 50% 50%, ${withAlpha(theme.colors.primary, 0.38)} 0%, ${withAlpha(theme.colors.primary, 0.14)} 48%, ${withAlpha(theme.colors.primary, 0)} 78%)`
|
|
1036
|
+
},
|
|
1037
|
+
position: { x: 0, y: 0, width: "100%", height: "100%" }
|
|
1038
|
+
}
|
|
1039
|
+
);
|
|
1040
|
+
}
|
|
1041
|
+
layers.push({
|
|
1042
|
+
type: "text",
|
|
1043
|
+
id: "bigtext-title",
|
|
1044
|
+
content: {
|
|
1045
|
+
text: displayTitle,
|
|
1046
|
+
style: {
|
|
1047
|
+
fontSize: titleFontSize,
|
|
1048
|
+
fontFamily: getThemeFont(context, "title"),
|
|
1049
|
+
fontWeight: "bold",
|
|
1050
|
+
color: theme.colors.text,
|
|
1051
|
+
textAlign: "center",
|
|
1052
|
+
lineHeight: BIG_TEXT_LINE_HEIGHT,
|
|
1053
|
+
shadow: !!imageSrc,
|
|
1054
|
+
shrinkToFit: true
|
|
1055
|
+
}
|
|
1056
|
+
},
|
|
1057
|
+
position: {
|
|
1058
|
+
x: "50%",
|
|
1059
|
+
y: "50%",
|
|
1060
|
+
anchor: "center",
|
|
1061
|
+
width: `${BIG_TEXT_WIDTH_FRACTION * 100}%`,
|
|
1062
|
+
height: `${BIG_TEXT_HEIGHT_FRACTION * 100}%`
|
|
1063
|
+
},
|
|
1064
|
+
animation: themedEntrance(context, "text", { type: "fadeIn", duration: 1 })
|
|
1065
|
+
});
|
|
1066
|
+
return layers;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
937
1069
|
// src/doc/templates/contentBlock.ts
|
|
938
1070
|
function completeBodyText(context) {
|
|
939
1071
|
return (context.block?.contents ?? []).filter((node) => !(node.type === "code" && node.lang?.trim().toLowerCase() === "mermaid")).map((node) => extractPlainText(node)).join("\n").trim();
|
|
@@ -2414,7 +2546,7 @@ function renderInlineHtml(nodes) {
|
|
|
2414
2546
|
case "mention":
|
|
2415
2547
|
return escapeInlineHtml(`@${node.displayName}`);
|
|
2416
2548
|
case "inlineIcon":
|
|
2417
|
-
return
|
|
2549
|
+
return `<i class="fa-${node.family} fa-${node.name}" aria-hidden="true"></i>`;
|
|
2418
2550
|
case "htmlInline":
|
|
2419
2551
|
return escapeInlineHtml(node.rawHtml);
|
|
2420
2552
|
}
|
|
@@ -2525,10 +2657,16 @@ function extractEmbeddedVideos(contents, limit = Infinity) {
|
|
|
2525
2657
|
const attrs = n.attributes;
|
|
2526
2658
|
const src = attrs?.src || nestedSource(n.children);
|
|
2527
2659
|
if (src) {
|
|
2660
|
+
const startAt = attrs?.["data-squisq-video-start-at"] ? parseTimeSeconds(attrs["data-squisq-video-start-at"]) : null;
|
|
2661
|
+
const clipStart = attrs?.["data-squisq-video-clip-start"] ? parseTimeSeconds(attrs["data-squisq-video-clip-start"]) : null;
|
|
2662
|
+
const clipEnd = attrs?.["data-squisq-video-clip-end"] ? parseTimeSeconds(attrs["data-squisq-video-clip-end"]) : null;
|
|
2528
2663
|
add({
|
|
2529
2664
|
src,
|
|
2530
2665
|
...attrs?.poster ? { posterSrc: attrs.poster } : {},
|
|
2531
|
-
alt: attrs?.["aria-label"] || attrs?.title || attrs?.alt || ""
|
|
2666
|
+
alt: attrs?.["aria-label"] || attrs?.title || attrs?.alt || "",
|
|
2667
|
+
...startAt != null ? { startAt } : {},
|
|
2668
|
+
...clipStart != null ? { clipStart } : {},
|
|
2669
|
+
...clipEnd != null ? { clipEnd } : {}
|
|
2532
2670
|
});
|
|
2533
2671
|
}
|
|
2534
2672
|
} else if ((n.type === "link" || n.type === "image") && typeof n.url === "string" && VIDEO_FILE_RE.test(n.url)) {
|
|
@@ -2757,6 +2895,13 @@ function deriveTemplateInputs(templateName, headingText, contents, options = {})
|
|
|
2757
2895
|
if (!img) return placeholders ? { caption: headingText } : null;
|
|
2758
2896
|
return { imageSrc: img.src, imageAlt: img.alt || headingText, caption: headingText };
|
|
2759
2897
|
}
|
|
2898
|
+
case "bigText": {
|
|
2899
|
+
const img = extractFirstImage(contents);
|
|
2900
|
+
return {
|
|
2901
|
+
title: headingText,
|
|
2902
|
+
...img ? { imageSrc: img.src, imageAlt: img.alt || headingText } : {}
|
|
2903
|
+
};
|
|
2904
|
+
}
|
|
2760
2905
|
case "photoGrid": {
|
|
2761
2906
|
const images = extractImages(contents, 4);
|
|
2762
2907
|
if (images.length < 2) return placeholders ? {} : null;
|
|
@@ -3767,9 +3912,9 @@ function fitDiagramLabel(text, boxWidth, boxHeight, preferredFontSize) {
|
|
|
3767
3912
|
};
|
|
3768
3913
|
}
|
|
3769
3914
|
function countWrappedLines(text, fontSize, maxWidth) {
|
|
3770
|
-
return text.split("\n").reduce((count, line) => count +
|
|
3915
|
+
return text.split("\n").reduce((count, line) => count + wrappedLineCount2(line, fontSize, maxWidth), 0);
|
|
3771
3916
|
}
|
|
3772
|
-
function
|
|
3917
|
+
function wrappedLineCount2(text, fontSize, maxWidth) {
|
|
3773
3918
|
if (!text.trim()) return 1;
|
|
3774
3919
|
const charsPerLine = Math.floor(maxWidth / (fontSize * 0.5));
|
|
3775
3920
|
if (charsPerLine <= 0) return 1;
|
|
@@ -6615,6 +6760,7 @@ function scatterChart(input, context) {
|
|
|
6615
6760
|
var templateRegistry = {
|
|
6616
6761
|
title: titleBlock,
|
|
6617
6762
|
sectionHeader,
|
|
6763
|
+
bigText,
|
|
6618
6764
|
content: contentBlock,
|
|
6619
6765
|
statHighlight,
|
|
6620
6766
|
quote: quoteBlock,
|
|
@@ -6829,6 +6975,12 @@ var TEMPLATE_INPUT_DESCRIPTORS = {
|
|
|
6829
6975
|
{ key: "imageAlt", description: "Alt text for the background image" },
|
|
6830
6976
|
{ key: "ambientMotion", description: "Slow zoom/pan effect", values: AMBIENT_MOTION_VALUES }
|
|
6831
6977
|
],
|
|
6978
|
+
bigText: [
|
|
6979
|
+
{ key: "title", description: "The display text (rendered uppercase)" },
|
|
6980
|
+
{ key: "imageSrc", description: "Optional full-bleed background image path" },
|
|
6981
|
+
{ key: "imageAlt", description: "Alt text for the background image" },
|
|
6982
|
+
{ key: "ambientMotion", description: "Slow zoom/pan effect", values: AMBIENT_MOTION_VALUES }
|
|
6983
|
+
],
|
|
6832
6984
|
content: [{ key: "title", description: "Heading shown above the complete body" }],
|
|
6833
6985
|
statHighlight: [
|
|
6834
6986
|
{ key: "stat", description: 'The statistic (e.g. "89%", "2x")' },
|
|
@@ -7245,6 +7397,15 @@ var BLOCK_MEDIA_LAYOUT_POLICIES = {
|
|
|
7245
7397
|
unconsumedMedia: "reserve-when-no-native-media",
|
|
7246
7398
|
variants: TITLE_VARIANTS
|
|
7247
7399
|
},
|
|
7400
|
+
bigText: {
|
|
7401
|
+
summary: "Uses its authored background image (behind a contrast bloom) when present; otherwise renders gigantic text on the theme surface.",
|
|
7402
|
+
noMedia: "template-without-optional-media",
|
|
7403
|
+
ownership: "optional-native",
|
|
7404
|
+
nativeLayout: "background-image",
|
|
7405
|
+
additionalMediaLayout: "overlay-inset",
|
|
7406
|
+
unconsumedMedia: "reserve-when-no-native-media",
|
|
7407
|
+
variants: TITLE_VARIANTS
|
|
7408
|
+
},
|
|
7248
7409
|
content: {
|
|
7249
7410
|
summary: "Preserves the complete heading and body; supplemental media receives a companion field.",
|
|
7250
7411
|
noMedia: "template-default",
|
|
@@ -8125,7 +8286,10 @@ function collectRichMediaItems(layers, block) {
|
|
|
8125
8286
|
src: video.src,
|
|
8126
8287
|
...video.posterSrc ? { posterSrc: video.posterSrc } : {},
|
|
8127
8288
|
alt: video.alt,
|
|
8128
|
-
aspectRatio: 16 / 9
|
|
8289
|
+
aspectRatio: 16 / 9,
|
|
8290
|
+
...video.startAt != null ? { startAt: video.startAt } : {},
|
|
8291
|
+
...video.clipStart != null ? { clipStart: video.clipStart } : {},
|
|
8292
|
+
...video.clipEnd != null ? { clipEnd: video.clipEnd } : {}
|
|
8129
8293
|
})
|
|
8130
8294
|
),
|
|
8131
8295
|
...sources.map((source) => ({ kind: "mermaid", source, aspectRatio: 16 / 9 })),
|
|
@@ -8181,6 +8345,7 @@ function richMediaLayers(item, position, block, theme, kindIndex) {
|
|
|
8181
8345
|
];
|
|
8182
8346
|
}
|
|
8183
8347
|
if (item.kind === "video") {
|
|
8348
|
+
const clipStart = Math.max(0, item.clipStart ?? 0);
|
|
8184
8349
|
return [
|
|
8185
8350
|
{
|
|
8186
8351
|
id: `${block.id}-embedded-video-${kindIndex}`,
|
|
@@ -8191,8 +8356,9 @@ function richMediaLayers(item, position, block, theme, kindIndex) {
|
|
|
8191
8356
|
...item.posterSrc ? { posterSrc: item.posterSrc } : {},
|
|
8192
8357
|
alt: item.alt || block.title || "Embedded video",
|
|
8193
8358
|
fit: "contain",
|
|
8194
|
-
clipStart
|
|
8195
|
-
clipEnd: Math.max(0, block.duration)
|
|
8359
|
+
clipStart,
|
|
8360
|
+
clipEnd: Math.max(clipStart, item.clipEnd ?? clipStart + Math.max(0, block.duration)),
|
|
8361
|
+
...item.startAt != null ? { startAt: Math.max(0, item.startAt) } : {}
|
|
8196
8362
|
}
|
|
8197
8363
|
}
|
|
8198
8364
|
];
|
|
@@ -8233,11 +8399,36 @@ function richMediaLayers(item, position, block, theme, kindIndex) {
|
|
|
8233
8399
|
`${block.id}-embedded-${item.template}-${kindIndex}`
|
|
8234
8400
|
);
|
|
8235
8401
|
}
|
|
8402
|
+
function applyEmbeddedVideoTiming(layers, block) {
|
|
8403
|
+
const timedBySrc = new Map(
|
|
8404
|
+
extractEmbeddedVideos(block.contents).filter((video) => video.startAt != null || video.clipStart != null || video.clipEnd != null).map((video) => [video.src, video])
|
|
8405
|
+
);
|
|
8406
|
+
if (timedBySrc.size === 0) return layers;
|
|
8407
|
+
return layers.map((layer) => {
|
|
8408
|
+
if (layer.type !== "video") return layer;
|
|
8409
|
+
const video = timedBySrc.get(layer.content.src);
|
|
8410
|
+
if (!video) return layer;
|
|
8411
|
+
const clipStart = Math.max(0, video.clipStart ?? layer.content.clipStart);
|
|
8412
|
+
return {
|
|
8413
|
+
...layer,
|
|
8414
|
+
content: {
|
|
8415
|
+
...layer.content,
|
|
8416
|
+
clipStart,
|
|
8417
|
+
clipEnd: Math.max(
|
|
8418
|
+
clipStart,
|
|
8419
|
+
video.clipEnd ?? (video.clipStart != null ? clipStart + Math.max(0, block.duration) : layer.content.clipEnd)
|
|
8420
|
+
),
|
|
8421
|
+
...video.startAt != null ? { startAt: Math.max(0, video.startAt) } : {}
|
|
8422
|
+
}
|
|
8423
|
+
};
|
|
8424
|
+
});
|
|
8425
|
+
}
|
|
8236
8426
|
function appendRichContentLayers(layers, block, theme, viewport) {
|
|
8237
|
-
const
|
|
8238
|
-
|
|
8427
|
+
const timedLayers = applyEmbeddedVideoTiming(layers, block);
|
|
8428
|
+
const items = collectRichMediaItems(timedLayers, block);
|
|
8429
|
+
if (items.length === 0) return timedLayers;
|
|
8239
8430
|
const layout = resolveSupplementalMediaLayout(
|
|
8240
|
-
|
|
8431
|
+
timedLayers,
|
|
8241
8432
|
block.template ? resolveTemplateName(block.template) : void 0,
|
|
8242
8433
|
viewport,
|
|
8243
8434
|
items.length,
|
|
@@ -8356,6 +8547,10 @@ var TEMPLATE_METADATA = {
|
|
|
8356
8547
|
label: "Section Header",
|
|
8357
8548
|
description: "A clean section break with a prominent title and optional background image."
|
|
8358
8549
|
},
|
|
8550
|
+
bigText: {
|
|
8551
|
+
label: "Big Text",
|
|
8552
|
+
description: "Gigantic uppercase display text \u2014 thumbnail-style \u2014 on a theme surface or over an image with a contrast bloom."
|
|
8553
|
+
},
|
|
8359
8554
|
content: {
|
|
8360
8555
|
label: "Content",
|
|
8361
8556
|
description: "Shows a heading and the complete body in a loss-averse content-first layout."
|
|
@@ -8496,6 +8691,12 @@ var TEMPLATE_AUTHORING_METADATA = {
|
|
|
8496
8691
|
safeForContentFirst: false,
|
|
8497
8692
|
placement: "heading"
|
|
8498
8693
|
},
|
|
8694
|
+
bigText: {
|
|
8695
|
+
role: "opener",
|
|
8696
|
+
bodyPolicy: "ignored",
|
|
8697
|
+
safeForContentFirst: false,
|
|
8698
|
+
placement: "heading"
|
|
8699
|
+
},
|
|
8499
8700
|
content: {
|
|
8500
8701
|
role: "content",
|
|
8501
8702
|
bodyPolicy: "complete",
|
|
@@ -8847,8 +9048,81 @@ function startBlockToCoverInput(config) {
|
|
|
8847
9048
|
heroLicense: config.heroLicense
|
|
8848
9049
|
};
|
|
8849
9050
|
}
|
|
8850
|
-
function expandCoverBlock(config, context) {
|
|
9051
|
+
function expandCoverBlock(config, context, template = "cover") {
|
|
8851
9052
|
const input = startBlockToCoverInput(config);
|
|
9053
|
+
const base = {
|
|
9054
|
+
id: "cover-block",
|
|
9055
|
+
duration: 0,
|
|
9056
|
+
audioSegment: -1
|
|
9057
|
+
};
|
|
9058
|
+
if (template === "title") {
|
|
9059
|
+
return titleBlock(
|
|
9060
|
+
{
|
|
9061
|
+
...base,
|
|
9062
|
+
template: "title",
|
|
9063
|
+
title: input.title,
|
|
9064
|
+
subtitle: input.subtitle
|
|
9065
|
+
},
|
|
9066
|
+
context
|
|
9067
|
+
);
|
|
9068
|
+
}
|
|
9069
|
+
if (template === "sectionHeader") {
|
|
9070
|
+
return sectionHeader(
|
|
9071
|
+
{
|
|
9072
|
+
...base,
|
|
9073
|
+
template: "sectionHeader",
|
|
9074
|
+
title: input.title,
|
|
9075
|
+
imageSrc: input.heroSrc,
|
|
9076
|
+
imageAlt: input.heroAlt,
|
|
9077
|
+
ambientMotion: input.ambientMotion
|
|
9078
|
+
},
|
|
9079
|
+
context
|
|
9080
|
+
);
|
|
9081
|
+
}
|
|
9082
|
+
if (template === "bigText" || template === "bigTextImage") {
|
|
9083
|
+
const useHero = template === "bigTextImage" && !!input.heroSrc;
|
|
9084
|
+
return bigText(
|
|
9085
|
+
{
|
|
9086
|
+
...base,
|
|
9087
|
+
template: "bigText",
|
|
9088
|
+
title: input.title,
|
|
9089
|
+
...useHero ? {
|
|
9090
|
+
imageSrc: input.heroSrc,
|
|
9091
|
+
imageAlt: input.heroAlt ?? input.title,
|
|
9092
|
+
ambientMotion: input.ambientMotion
|
|
9093
|
+
} : {}
|
|
9094
|
+
},
|
|
9095
|
+
context
|
|
9096
|
+
);
|
|
9097
|
+
}
|
|
9098
|
+
if (template === "imageWithCaption") {
|
|
9099
|
+
if (!input.heroSrc) {
|
|
9100
|
+
return titleBlock(
|
|
9101
|
+
{
|
|
9102
|
+
...base,
|
|
9103
|
+
template: "title",
|
|
9104
|
+
title: input.title,
|
|
9105
|
+
subtitle: input.subtitle
|
|
9106
|
+
},
|
|
9107
|
+
context
|
|
9108
|
+
);
|
|
9109
|
+
}
|
|
9110
|
+
return imageWithCaption(
|
|
9111
|
+
{
|
|
9112
|
+
...base,
|
|
9113
|
+
template: "imageWithCaption",
|
|
9114
|
+
imageSrc: input.heroSrc,
|
|
9115
|
+
imageAlt: input.heroAlt ?? input.title,
|
|
9116
|
+
caption: input.title,
|
|
9117
|
+
subtitle: input.subtitle,
|
|
9118
|
+
ambientMotion: input.ambientMotion,
|
|
9119
|
+
imageCredit: input.heroCredit,
|
|
9120
|
+
imageLicense: input.heroLicense,
|
|
9121
|
+
isTitle: true
|
|
9122
|
+
},
|
|
9123
|
+
context
|
|
9124
|
+
);
|
|
9125
|
+
}
|
|
8852
9126
|
return coverBlock(input, context);
|
|
8853
9127
|
}
|
|
8854
9128
|
|
|
@@ -10105,7 +10379,7 @@ function markdownToDoc(markdownDoc, options) {
|
|
|
10105
10379
|
...documentMedia.length > 0 ? { documentMedia } : {}
|
|
10106
10380
|
};
|
|
10107
10381
|
if (options?.generateCoverBlock ?? true) {
|
|
10108
|
-
const coverConfig = buildStartBlock(markdownDoc, rootBlocks);
|
|
10382
|
+
const coverConfig = buildStartBlock(markdownDoc, rootBlocks, options?.fileName);
|
|
10109
10383
|
if (coverConfig) {
|
|
10110
10384
|
doc.startBlock = coverConfig;
|
|
10111
10385
|
}
|
|
@@ -10355,12 +10629,35 @@ function findFirstImage(node) {
|
|
|
10355
10629
|
}
|
|
10356
10630
|
return void 0;
|
|
10357
10631
|
}
|
|
10358
|
-
function
|
|
10359
|
-
|
|
10360
|
-
|
|
10361
|
-
|
|
10632
|
+
function shallowestHeadingBlock(rootBlocks) {
|
|
10633
|
+
let best;
|
|
10634
|
+
for (const block of rootBlocks) {
|
|
10635
|
+
const depth = block.sourceHeading?.depth;
|
|
10636
|
+
if (depth === void 0) continue;
|
|
10637
|
+
const title = block.title ?? extractPlainText(block.sourceHeading);
|
|
10638
|
+
if (!title) continue;
|
|
10639
|
+
if (!best || depth < best.sourceHeading.depth) {
|
|
10640
|
+
best = block;
|
|
10641
|
+
if (depth === 1) break;
|
|
10642
|
+
}
|
|
10643
|
+
}
|
|
10644
|
+
return best;
|
|
10645
|
+
}
|
|
10646
|
+
function fileNameCoverTitle(fileName) {
|
|
10647
|
+
if (!fileName) return void 0;
|
|
10648
|
+
const base = fileName.split(/[\\/]/).pop() ?? "";
|
|
10649
|
+
const stem = base.replace(/\.[^.]+$/, "").replace(/[-_]+/g, " ").replace(/\s+/g, " ").trim();
|
|
10650
|
+
if (!stem) return void 0;
|
|
10651
|
+
return stem.charAt(0).toUpperCase() + stem.slice(1);
|
|
10652
|
+
}
|
|
10653
|
+
function buildStartBlock(markdownDoc, rootBlocks, fileName) {
|
|
10654
|
+
const frontmatterTitle = typeof markdownDoc.frontmatter?.title === "string" ? markdownDoc.frontmatter.title.trim() : void 0;
|
|
10655
|
+
const headingBlock = shallowestHeadingBlock(rootBlocks);
|
|
10656
|
+
const headingTitle = headingBlock ? headingBlock.title ?? extractPlainText(headingBlock.sourceHeading) : void 0;
|
|
10657
|
+
const title = frontmatterTitle || headingTitle || fileNameCoverTitle(fileName);
|
|
10362
10658
|
if (!title) return void 0;
|
|
10363
|
-
const
|
|
10659
|
+
const subtitleBlock = headingBlock ?? rootBlocks[0];
|
|
10660
|
+
const subtitle = subtitleBlock?.contents?.[0]?.type === "paragraph" ? extractPlainText(subtitleBlock.contents[0]) : void 0;
|
|
10364
10661
|
const firstImage = findFirstImage(markdownDoc);
|
|
10365
10662
|
const config = {
|
|
10366
10663
|
title,
|
|
@@ -10708,6 +11005,8 @@ export {
|
|
|
10708
11005
|
createAccentLayers,
|
|
10709
11006
|
adjustY,
|
|
10710
11007
|
sectionHeader,
|
|
11008
|
+
fitBigTextSize,
|
|
11009
|
+
bigText,
|
|
10711
11010
|
contentBlock,
|
|
10712
11011
|
statHighlight,
|
|
10713
11012
|
quoteBlock,
|