@bendyline/squisq 1.4.1 → 1.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-BeSeH2iX.d.ts → Doc-BsMkmzH8.d.ts} +838 -268
- package/dist/{ImageEditDoc-BTIvw0oq.d.ts → ImageEditDoc-DvoeHMP9.d.ts} +11 -4
- package/dist/{chunk-ZTX4PFFT.js → chunk-2OIBZYKP.js} +75 -2
- package/dist/chunk-2OIBZYKP.js.map +1 -0
- package/dist/chunk-2UQOHYE2.js +45 -0
- package/dist/chunk-2UQOHYE2.js.map +1 -0
- package/dist/{chunk-B4EEON3N.js → chunk-4AKUQPEE.js} +536 -103
- package/dist/chunk-4AKUQPEE.js.map +1 -0
- package/dist/chunk-4ZFRZBU2.js +6582 -0
- package/dist/chunk-4ZFRZBU2.js.map +1 -0
- package/dist/{chunk-57CVQCFX.js → chunk-7MQGNR76.js} +79 -3
- package/dist/chunk-7MQGNR76.js.map +1 -0
- package/dist/{chunk-5WFRKURX.js → chunk-DLXZMS5K.js} +4 -2
- package/dist/chunk-DLXZMS5K.js.map +1 -0
- package/dist/{chunk-MYIH7FWD.js → chunk-FBKP5CAO.js} +1 -1
- package/dist/chunk-FBKP5CAO.js.map +1 -0
- package/dist/chunk-KZNXZ5SM.js +333 -0
- package/dist/chunk-KZNXZ5SM.js.map +1 -0
- package/dist/{chunk-WMOI7FN3.js → chunk-LRCV7N7F.js} +12 -2
- package/dist/{chunk-WMOI7FN3.js.map → chunk-LRCV7N7F.js.map} +1 -1
- package/dist/{chunk-3K5OG6KI.js → chunk-OH43RPTP.js} +403 -187
- package/dist/chunk-OH43RPTP.js.map +1 -0
- package/dist/{chunk-H3AXU4MJ.js → chunk-OKJOQXK4.js} +149 -2
- package/dist/chunk-OKJOQXK4.js.map +1 -0
- package/dist/chunk-PGGGKYWG.js +1 -0
- package/dist/chunk-PGGGKYWG.js.map +1 -0
- package/dist/{chunk-7UDSRZKG.js → chunk-Q3ROPT5H.js} +35 -14
- package/dist/chunk-Q3ROPT5H.js.map +1 -0
- package/dist/chunk-QE7TWGVT.js +178 -0
- package/dist/chunk-QE7TWGVT.js.map +1 -0
- package/dist/chunk-RUDYOTA6.js +345 -0
- package/dist/chunk-RUDYOTA6.js.map +1 -0
- package/dist/chunk-TVSGLUID.js +596 -0
- package/dist/chunk-TVSGLUID.js.map +1 -0
- package/dist/chunk-ZLQKNOZQ.js +1 -0
- package/dist/chunk-ZLQKNOZQ.js.map +1 -0
- package/dist/doc/index.d.ts +4 -4
- package/dist/doc/index.js +124 -6
- package/dist/generate/index.d.ts +9 -2
- package/dist/generate/index.js +1 -1
- package/dist/icons/index.d.ts +3 -26
- package/dist/icons/index.js +13 -0
- package/dist/icons/inlineIconMarker.d.ts +1 -0
- package/dist/icons/inlineIconMarker.js +15 -0
- package/dist/icons/inlineIconMarker.js.map +1 -0
- package/dist/imageEdit/index.d.ts +11 -5
- package/dist/imageEdit/index.js +4 -1
- package/dist/index.d.ts +11 -8
- package/dist/index.js +243 -24
- package/dist/inlineIconMarker-CiE8Hlvz.d.ts +59 -0
- package/dist/markdown/index.d.ts +212 -3
- package/dist/markdown/index.js +40 -7
- package/dist/recommend/index.d.ts +1 -1
- package/dist/recommend/index.js +3 -2
- package/dist/schemas/index.d.ts +28 -8
- package/dist/schemas/index.js +35 -5
- package/dist/spatial/index.d.ts +9 -4
- package/dist/spatial/index.js +1 -1
- package/dist/story/index.d.ts +906 -40
- package/dist/story/index.js +124 -6
- package/dist/{themeLibrary-BHjJ0Qx6.d.ts → themeLibrary-DQQKuRMx.d.ts} +1 -1
- package/dist/transform/index.d.ts +48 -10
- package/dist/transform/index.js +17 -481
- package/dist/transform/index.js.map +1 -1
- package/dist/{types-BdZkdJ3z.d.ts → types-DlAZ7MW4.d.ts} +115 -1
- package/package.json +6 -1
- package/src/__tests__/animationUtils.test.ts +40 -0
- package/src/__tests__/annotationCoercion.test.ts +243 -0
- package/src/__tests__/applyRenderStyle.test.ts +146 -0
- package/src/__tests__/atmosphereLayers.test.ts +108 -0
- package/src/__tests__/attrTokens.test.ts +162 -0
- package/src/__tests__/customTemplateSample.test.ts +83 -0
- package/src/__tests__/customTemplatesFrontmatter.test.ts +205 -0
- package/src/__tests__/customThemesFrontmatter.test.ts +118 -0
- package/src/__tests__/diagramBlock.test.ts +122 -0
- package/src/__tests__/diagramLayout.test.ts +134 -0
- package/src/__tests__/drawing.test.ts +109 -0
- package/src/__tests__/drawingBlock.test.ts +124 -0
- package/src/__tests__/drawingLayout.test.ts +171 -0
- package/src/__tests__/geohash.test.ts +6 -5
- package/src/__tests__/getLayers.test.ts +6 -2
- package/src/__tests__/getLayersFallback.test.ts +103 -0
- package/src/__tests__/imageEditExportSvg.test.ts +70 -0
- package/src/__tests__/imageEditVersions.test.ts +72 -0
- package/src/__tests__/inlineIconMarker.test.ts +36 -0
- package/src/__tests__/layoutBlock.test.ts +83 -0
- package/src/__tests__/layoutLayout.test.ts +169 -0
- package/src/__tests__/markdown.test.ts +23 -0
- package/src/__tests__/markdownSanitize.test.ts +64 -0
- package/src/__tests__/markdownToDoc.test.ts +223 -2
- package/src/__tests__/mediaAnnotations.test.ts +64 -0
- package/src/__tests__/mediaSchedule.test.ts +118 -0
- package/src/__tests__/pandocAttrParse.test.ts +187 -0
- package/src/__tests__/resolveDocTheme.test.ts +55 -0
- package/src/__tests__/rootExports.test.ts +43 -0
- package/src/__tests__/shapeGeometry.test.ts +89 -0
- package/src/__tests__/shapeVocabulary.test.ts +133 -0
- package/src/__tests__/structuredData.test.ts +179 -0
- package/src/__tests__/templateAnnotationParse.test.ts +108 -0
- package/src/__tests__/templateMetadata.test.ts +21 -0
- package/src/__tests__/templates.test.ts +145 -4
- package/src/__tests__/themeCompile.test.ts +42 -0
- package/src/__tests__/themeValidator.test.ts +6 -0
- package/src/__tests__/transformV2.test.ts +137 -0
- package/src/__tests__/transitionNormalize.test.ts +61 -0
- package/src/__tests__/validateDoc.test.ts +100 -0
- package/src/doc/customTemplatesFrontmatter.ts +308 -0
- package/src/doc/customThemesFrontmatter.ts +90 -0
- package/src/doc/docToMarkdown.ts +73 -4
- package/src/doc/getLayers.ts +40 -17
- package/src/doc/index.ts +35 -1
- package/src/doc/markdownToDoc.ts +333 -12
- package/src/doc/mediaAnnotations.ts +118 -0
- package/src/doc/resolveDocTheme.ts +55 -0
- package/src/doc/structuredData.ts +230 -0
- package/src/doc/templateInputs.ts +240 -0
- package/src/doc/templates/__tests__/customTemplate.test.ts +151 -0
- package/src/doc/templates/__tests__/customTemplateRegistry.test.ts +110 -0
- package/src/doc/templates/accentImage.ts +30 -6
- package/src/doc/templates/captionUtils.ts +23 -0
- package/src/doc/templates/comparisonBar.ts +26 -18
- package/src/doc/templates/coverBlock.ts +7 -4
- package/src/doc/templates/customTemplate.ts +45 -0
- package/src/doc/templates/dataTable.ts +37 -19
- package/src/doc/templates/dateEvent.ts +41 -20
- package/src/doc/templates/definitionCard.ts +26 -18
- package/src/doc/templates/diagramBlock.ts +204 -0
- package/src/doc/templates/diagramLayout.ts +159 -0
- package/src/doc/templates/drawingBlock.ts +325 -0
- package/src/doc/templates/drawingLayout.ts +539 -0
- package/src/doc/templates/factCard.ts +51 -25
- package/src/doc/templates/fallbackBlock.ts +123 -0
- package/src/doc/templates/featureBlock.ts +20 -13
- package/src/doc/templates/fullBleedQuote.ts +18 -8
- package/src/doc/templates/imageWithCaption.ts +22 -9
- package/src/doc/templates/index.ts +215 -46
- package/src/doc/templates/layoutBlock.ts +43 -0
- package/src/doc/templates/layoutLayout.ts +243 -0
- package/src/doc/templates/listBlock.ts +56 -30
- package/src/doc/templates/mapBlock.ts +15 -12
- package/src/doc/templates/metadata.ts +120 -0
- package/src/doc/templates/persistentLayers.ts +129 -11
- package/src/doc/templates/photoGrid.ts +23 -12
- package/src/doc/templates/pullQuote.ts +30 -12
- package/src/doc/templates/quoteBlock.ts +54 -29
- package/src/doc/templates/sectionHeader.ts +25 -11
- package/src/doc/templates/statHighlight.ts +39 -22
- package/src/doc/templates/titleBlock.ts +59 -21
- package/src/doc/templates/tokens/__tests__/resolveTokens.test.ts +221 -0
- package/src/doc/templates/tokens/resolveTokens.ts +0 -0
- package/src/doc/templates/twoColumn.ts +48 -30
- package/src/doc/templates/videoPullQuote.ts +22 -12
- package/src/doc/templates/videoWithCaption.ts +13 -8
- package/src/doc/utils/animationUtils.ts +267 -3
- package/src/doc/utils/applyRenderStyle.ts +113 -0
- package/src/doc/utils/imageTreatment.ts +70 -0
- package/src/doc/utils/shapeGeometry.ts +464 -0
- package/src/doc/utils/themeUtils.ts +75 -1
- package/src/doc/validate.ts +476 -0
- package/src/generate/slideshowGenerator.ts +7 -0
- package/src/icons/index.ts +8 -0
- package/src/icons/inlineIconMarker.ts +73 -0
- package/src/imageEdit/export.ts +85 -2
- package/src/imageEdit/index.ts +1 -0
- package/src/imageEdit/persistence.ts +51 -0
- package/src/index.ts +2 -0
- package/src/markdown/annotationCoercion.ts +295 -0
- package/src/markdown/attrTokens.ts +222 -0
- package/src/markdown/convert.ts +229 -26
- package/src/markdown/index.ts +36 -0
- package/src/markdown/sanitize.ts +298 -0
- package/src/markdown/stringify.ts +84 -3
- package/src/markdown/types.ts +66 -0
- package/src/markdown/utils.ts +49 -1
- package/src/recommend/templates.ts +24 -0
- package/src/schemas/BlockTemplates.ts +133 -4
- package/src/schemas/CustomTemplates.ts +74 -0
- package/src/schemas/Doc.ts +353 -29
- package/src/schemas/ImageEditDoc.ts +11 -4
- package/src/schemas/Media.ts +169 -0
- package/src/schemas/Theme.ts +23 -1
- package/src/schemas/Transitions.ts +224 -0
- package/src/schemas/colorUtils.ts +33 -0
- package/src/schemas/fontStacks.ts +5 -2
- package/src/schemas/index.ts +3 -0
- package/src/schemas/themeCompile.ts +23 -4
- package/src/schemas/themeValidator.ts +49 -11
- package/src/schemas/themes/cinematic.json +69 -12
- package/src/schemas/themes/documentary.json +58 -11
- package/src/schemas/themes/gezellig.json +60 -11
- package/src/schemas/themes/magazine.json +54 -9
- package/src/schemas/themes/morning-light.json +52 -9
- package/src/schemas/themes/standard-dark.json +48 -13
- package/src/schemas/themes/standard.json +44 -12
- package/src/schemas/themes/tech-dark.json +65 -12
- package/src/spatial/Geohash.ts +52 -21
- package/src/transform/applyTransform.ts +43 -4
- package/src/transform/index.ts +1 -0
- package/src/transform/registry.ts +44 -13
- package/src/transform/styles/dataDriven.ts +2 -1
- package/src/transform/styles/documentary.ts +2 -1
- package/src/transform/styles/magazine.ts +3 -1
- package/src/transform/styles/minimal.ts +2 -1
- package/src/transform/styles/narrative.ts +3 -1
- package/src/transform/templateSelector.ts +87 -11
- package/src/transform/types.ts +35 -2
- package/dist/chunk-3K5OG6KI.js.map +0 -1
- package/dist/chunk-57CVQCFX.js.map +0 -1
- package/dist/chunk-5WFRKURX.js.map +0 -1
- package/dist/chunk-7UDSRZKG.js.map +0 -1
- package/dist/chunk-B4EEON3N.js.map +0 -1
- package/dist/chunk-H3AXU4MJ.js.map +0 -1
- package/dist/chunk-KSWJR66U.js +0 -3706
- package/dist/chunk-KSWJR66U.js.map +0 -1
- package/dist/chunk-MYIH7FWD.js.map +0 -1
- package/dist/chunk-ZTX4PFFT.js.map +0 -1
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fallback Block Rendering
|
|
3
|
+
*
|
|
4
|
+
* The graceful-degradation guarantee: a block whose template can't render —
|
|
5
|
+
* unknown template name, template function threw, or returned a non-array —
|
|
6
|
+
* still renders its heading and body text as a plain, readable card instead
|
|
7
|
+
* of a blank slide. A small notice line names the problem so authors (and
|
|
8
|
+
* agents reviewing screenshots) can see *why* the block degraded.
|
|
9
|
+
*
|
|
10
|
+
* This is intentionally not a registered template: it can't be requested by
|
|
11
|
+
* name, only reached when a requested template fails. See `getLayers()`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { Layer } from '../../schemas/Doc.js';
|
|
15
|
+
import type { Block } from '../../schemas/Doc.js';
|
|
16
|
+
import type { DocBlock, TemplateContext } from '../../schemas/BlockTemplates.js';
|
|
17
|
+
import { resolveColorScheme, getThemeFont, themedFontSize } from '../utils/themeUtils.js';
|
|
18
|
+
import { extractPlainText } from '../../markdown/utils.js';
|
|
19
|
+
|
|
20
|
+
/** Cap body text so a long section doesn't overflow the card. */
|
|
21
|
+
const MAX_BODY_CHARS = 600;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Render a block's heading + body text as plain layers, with a notice line
|
|
25
|
+
* describing why the requested template didn't render.
|
|
26
|
+
*
|
|
27
|
+
* @param block The block that failed to render via its template.
|
|
28
|
+
* @param context Template context (theme, viewport).
|
|
29
|
+
* @param notice Short problem description, e.g. `Unknown template "photGrid"`.
|
|
30
|
+
*/
|
|
31
|
+
export function fallbackBlockLayers(
|
|
32
|
+
block: DocBlock,
|
|
33
|
+
context: TemplateContext,
|
|
34
|
+
notice: string,
|
|
35
|
+
): Layer[] {
|
|
36
|
+
const colors = resolveColorScheme(context, 'blue');
|
|
37
|
+
const { layout } = context;
|
|
38
|
+
|
|
39
|
+
const title = (block as Block).title ?? (block as Block).id ?? '';
|
|
40
|
+
const body = extractBodyText(block as Block);
|
|
41
|
+
|
|
42
|
+
const layers: Layer[] = [
|
|
43
|
+
{
|
|
44
|
+
type: 'shape',
|
|
45
|
+
id: 'fallback-bg',
|
|
46
|
+
content: { shape: 'rect', fill: colors.bg },
|
|
47
|
+
position: { x: 0, y: 0, width: '100%', height: '100%' },
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
if (title) {
|
|
52
|
+
layers.push({
|
|
53
|
+
type: 'text',
|
|
54
|
+
id: 'fallback-title',
|
|
55
|
+
content: {
|
|
56
|
+
text: title,
|
|
57
|
+
style: {
|
|
58
|
+
fontSize: themedFontSize(56, context, true),
|
|
59
|
+
fontFamily: getThemeFont(context, 'title'),
|
|
60
|
+
fontWeight: 'bold',
|
|
61
|
+
color: colors.text,
|
|
62
|
+
textAlign: 'center',
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
position: {
|
|
66
|
+
x: '50%',
|
|
67
|
+
y: body ? '28%' : '50%',
|
|
68
|
+
anchor: 'center',
|
|
69
|
+
width: layout.maxTextWidth,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (body) {
|
|
75
|
+
layers.push({
|
|
76
|
+
type: 'text',
|
|
77
|
+
id: 'fallback-body',
|
|
78
|
+
content: {
|
|
79
|
+
text: body,
|
|
80
|
+
style: {
|
|
81
|
+
fontSize: themedFontSize(28, context),
|
|
82
|
+
fontFamily: getThemeFont(context, 'body'),
|
|
83
|
+
color: colors.text,
|
|
84
|
+
textAlign: 'center',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
position: {
|
|
88
|
+
x: '50%',
|
|
89
|
+
y: '55%',
|
|
90
|
+
anchor: 'center',
|
|
91
|
+
width: layout.maxTextWidth,
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
layers.push({
|
|
97
|
+
type: 'text',
|
|
98
|
+
id: 'fallback-notice',
|
|
99
|
+
content: {
|
|
100
|
+
text: `⚠ ${notice}`,
|
|
101
|
+
style: {
|
|
102
|
+
fontSize: themedFontSize(18, context),
|
|
103
|
+
fontFamily: getThemeFont(context, 'body'),
|
|
104
|
+
color: `${colors.text}99`,
|
|
105
|
+
textAlign: 'center',
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
position: { x: '50%', y: '92%', anchor: 'center', width: layout.maxTextWidth },
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
return layers;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Plain text of a block's body contents, truncated for card display. */
|
|
115
|
+
function extractBodyText(block: Block): string {
|
|
116
|
+
if (!block.contents || block.contents.length === 0) return '';
|
|
117
|
+
const text = block.contents
|
|
118
|
+
.map((node) => extractPlainText(node))
|
|
119
|
+
.join('\n')
|
|
120
|
+
.trim();
|
|
121
|
+
if (text.length <= MAX_BODY_CHARS) return text;
|
|
122
|
+
return `${text.slice(0, MAX_BODY_CHARS).trimEnd()}…`;
|
|
123
|
+
}
|
|
@@ -18,8 +18,12 @@ import type {
|
|
|
18
18
|
RightFeatureInput,
|
|
19
19
|
TemplateContext,
|
|
20
20
|
} from '../../schemas/BlockTemplates.js';
|
|
21
|
-
import {
|
|
22
|
-
|
|
21
|
+
import {
|
|
22
|
+
getThemeFont,
|
|
23
|
+
themedEntrance,
|
|
24
|
+
themedFontSize,
|
|
25
|
+
themedImageTreatment,
|
|
26
|
+
} from '../utils/themeUtils.js';
|
|
23
27
|
|
|
24
28
|
type FeatureInput = LeftFeatureInput | RightFeatureInput;
|
|
25
29
|
|
|
@@ -34,6 +38,8 @@ function buildFeatureLayers(
|
|
|
34
38
|
): Layer[] {
|
|
35
39
|
const { imageSrc, imageAlt, imageWidth, imageHeight, title, body } = input;
|
|
36
40
|
const { theme, layout } = context;
|
|
41
|
+
|
|
42
|
+
const treatment = themedImageTreatment(context, input.imageTreatment);
|
|
37
43
|
// Treat the image as "sized" when the host gave us an explicit width
|
|
38
44
|
// or height — that's our cue that the user resized the image in the
|
|
39
45
|
// editor and we should respect that as a sizing hint instead of
|
|
@@ -44,8 +50,8 @@ function buildFeatureLayers(
|
|
|
44
50
|
// behave consistently on narrow viewports.
|
|
45
51
|
const stack = layout.stackColumns;
|
|
46
52
|
|
|
47
|
-
const titleFontSize =
|
|
48
|
-
const bodyFontSize =
|
|
53
|
+
const titleFontSize = themedFontSize(48, context, true);
|
|
54
|
+
const bodyFontSize = themedFontSize(24, context, false);
|
|
49
55
|
|
|
50
56
|
// Image takes the full left or right half. The text column gets the
|
|
51
57
|
// opposite half, with a comfortable inset so the text doesn't kiss
|
|
@@ -90,17 +96,17 @@ function buildFeatureLayers(
|
|
|
90
96
|
}
|
|
91
97
|
|
|
92
98
|
// Text-column geometry. `textX` is the LEFT edge of the column when
|
|
93
|
-
// the side is "left" (image left, text right)
|
|
94
|
-
// the column
|
|
95
|
-
//
|
|
96
|
-
//
|
|
99
|
+
// the side is "left" (image left, text right); when the side is
|
|
100
|
+
// "right" the column occupies the left half, inset from the card edge.
|
|
101
|
+
// The mirror lives in the layout only — fully right-aligned
|
|
102
|
+
// (ragged-left) running text on rightFeature was genuinely hard to read.
|
|
97
103
|
const COLUMN_INSET = 4; // % of block width — padding from card edge / divider
|
|
98
104
|
const textColumnWidth = stack ? 90 : 42;
|
|
99
105
|
const textX = stack
|
|
100
106
|
? `${(100 - textColumnWidth) / 2}%`
|
|
101
107
|
: side === 'left'
|
|
102
108
|
? `${50 + COLUMN_INSET}%` // text column starts just past the divider
|
|
103
|
-
: `${
|
|
109
|
+
: `${COLUMN_INSET + 2}%`; // left edge of the left-half text column
|
|
104
110
|
|
|
105
111
|
// Stack the title above the body, with the pair vertically centered
|
|
106
112
|
// in the text column. The title sits 8% above center; body sits 2%
|
|
@@ -108,8 +114,8 @@ function buildFeatureLayers(
|
|
|
108
114
|
// sizes used by the inline preview gutter without overflowing.
|
|
109
115
|
const titleY = stack ? '60%' : body ? '42%' : '50%';
|
|
110
116
|
const bodyY = stack ? '78%' : title ? '55%' : '50%';
|
|
111
|
-
const textAnchor =
|
|
112
|
-
const textAlign
|
|
117
|
+
const textAnchor = 'top-left';
|
|
118
|
+
const textAlign = 'left' as const;
|
|
113
119
|
|
|
114
120
|
// Paint our own background so the text column has a theme-paired
|
|
115
121
|
// surface to sit on. The host wrapper's surface isn't always theme-
|
|
@@ -136,6 +142,7 @@ function buildFeatureLayers(
|
|
|
136
142
|
src: imageSrc,
|
|
137
143
|
alt: imageAlt ?? title ?? '',
|
|
138
144
|
fit: imageFit,
|
|
145
|
+
...(treatment ? { treatment } : {}),
|
|
139
146
|
},
|
|
140
147
|
position: { x: imgX, y: imgY, width: imgW, height: imgH },
|
|
141
148
|
});
|
|
@@ -162,7 +169,7 @@ function buildFeatureLayers(
|
|
|
162
169
|
anchor: textAnchor,
|
|
163
170
|
width: `${textColumnWidth}%`,
|
|
164
171
|
},
|
|
165
|
-
animation: { type: 'fadeIn', duration: 0.8 },
|
|
172
|
+
animation: themedEntrance(context, 'text', { type: 'fadeIn', duration: 0.8 }),
|
|
166
173
|
});
|
|
167
174
|
}
|
|
168
175
|
|
|
@@ -186,7 +193,7 @@ function buildFeatureLayers(
|
|
|
186
193
|
anchor: textAnchor,
|
|
187
194
|
width: `${textColumnWidth}%`,
|
|
188
195
|
},
|
|
189
|
-
animation: { type: 'fadeIn', duration: 0.8, delay: 0.2 },
|
|
196
|
+
animation: themedEntrance(context, 'text', { type: 'fadeIn', duration: 0.8, delay: 0.2 }),
|
|
190
197
|
});
|
|
191
198
|
}
|
|
192
199
|
|
|
@@ -10,8 +10,14 @@
|
|
|
10
10
|
|
|
11
11
|
import type { Layer } from '../../schemas/Doc.js';
|
|
12
12
|
import type { FullBleedQuoteInput, TemplateContext } from '../../schemas/BlockTemplates.js';
|
|
13
|
-
import {
|
|
14
|
-
|
|
13
|
+
import {
|
|
14
|
+
resolveColorScheme,
|
|
15
|
+
getTemplateHint,
|
|
16
|
+
getThemeFont,
|
|
17
|
+
shouldUseShadow,
|
|
18
|
+
themedFontSize,
|
|
19
|
+
} from '../utils/themeUtils.js';
|
|
20
|
+
import { oklchDarken } from '../../schemas/colorUtils.js';
|
|
15
21
|
|
|
16
22
|
/**
|
|
17
23
|
* Hint schema published for the theme validator + future customizer hint UI.
|
|
@@ -28,20 +34,21 @@ export const fullBleedQuoteHintSchema = {
|
|
|
28
34
|
|
|
29
35
|
export function fullBleedQuote(input: FullBleedQuoteInput, context: TemplateContext): Layer[] {
|
|
30
36
|
const { text, colorScheme = 'blue' } = input;
|
|
31
|
-
const { theme } = context;
|
|
32
37
|
const colors = resolveColorScheme(context, colorScheme);
|
|
33
38
|
|
|
34
39
|
// Massive font for dramatic impact
|
|
35
|
-
const textFontSize =
|
|
40
|
+
const textFontSize = themedFontSize(120, context, true);
|
|
36
41
|
|
|
37
42
|
return [
|
|
38
|
-
// Background —
|
|
43
|
+
// Background — radial vignette built from the color scheme's own
|
|
44
|
+
// surface, so the card takes on the scheme (and the theme behind it)
|
|
45
|
+
// instead of vignetting every theme into hard black.
|
|
39
46
|
{
|
|
40
47
|
type: 'shape',
|
|
41
48
|
id: 'bg',
|
|
42
49
|
content: {
|
|
43
50
|
shape: 'rect',
|
|
44
|
-
fill: `radial-gradient(ellipse at 50% 50%, ${
|
|
51
|
+
fill: `radial-gradient(ellipse at 50% 50%, ${colors.bg} 0%, ${oklchDarken(colors.bg, 0.12)} 100%)`,
|
|
45
52
|
},
|
|
46
53
|
position: { x: 0, y: 0, width: '100%', height: '100%' },
|
|
47
54
|
},
|
|
@@ -58,7 +65,7 @@ export function fullBleedQuote(input: FullBleedQuoteInput, context: TemplateCont
|
|
|
58
65
|
color: colors.text,
|
|
59
66
|
textAlign: 'center',
|
|
60
67
|
lineHeight: 1.2,
|
|
61
|
-
shadow:
|
|
68
|
+
shadow: shouldUseShadow(context),
|
|
62
69
|
},
|
|
63
70
|
},
|
|
64
71
|
position: {
|
|
@@ -67,7 +74,10 @@ export function fullBleedQuote(input: FullBleedQuoteInput, context: TemplateCont
|
|
|
67
74
|
anchor: 'center',
|
|
68
75
|
width: '85%',
|
|
69
76
|
},
|
|
70
|
-
animation:
|
|
77
|
+
animation:
|
|
78
|
+
getTemplateHint<string>(context, 'fullBleedQuote', 'entrance', 'subtle') === 'dramatic'
|
|
79
|
+
? { type: 'zoomIn', duration: 0.8 }
|
|
80
|
+
: { type: 'fadeIn', duration: 1.5 },
|
|
71
81
|
},
|
|
72
82
|
];
|
|
73
83
|
}
|
|
@@ -10,8 +10,13 @@
|
|
|
10
10
|
|
|
11
11
|
import type { Layer } from '../../schemas/Doc.js';
|
|
12
12
|
import type { ImageWithCaptionInput, TemplateContext } from '../../schemas/BlockTemplates.js';
|
|
13
|
-
import {
|
|
14
|
-
|
|
13
|
+
import {
|
|
14
|
+
getThemeFont,
|
|
15
|
+
shouldUseShadow,
|
|
16
|
+
themedFontSize,
|
|
17
|
+
themedImageTreatment,
|
|
18
|
+
} from '../utils/themeUtils.js';
|
|
19
|
+
import { withAlpha } from '../../schemas/colorUtils.js';
|
|
15
20
|
import { cleanCaption } from './captionUtils.js';
|
|
16
21
|
import { mapAmbientMotion } from './accentImage.js';
|
|
17
22
|
|
|
@@ -30,10 +35,12 @@ export function imageWithCaption(input: ImageWithCaptionInput, context: Template
|
|
|
30
35
|
const caption = rawCaption ? cleanCaption(rawCaption) : rawCaption;
|
|
31
36
|
const { theme, layout } = context;
|
|
32
37
|
|
|
38
|
+
const treatment = themedImageTreatment(context, input.imageTreatment);
|
|
39
|
+
|
|
33
40
|
// Scale font sizes for viewport
|
|
34
|
-
const captionFontSize =
|
|
35
|
-
const titleFontSize =
|
|
36
|
-
const subtitleFontSize =
|
|
41
|
+
const captionFontSize = themedFontSize(36, context, false);
|
|
42
|
+
const titleFontSize = themedFontSize(96, context, true);
|
|
43
|
+
const subtitleFontSize = themedFontSize(36, context, false);
|
|
37
44
|
|
|
38
45
|
// Determine animation based on ambientMotion setting
|
|
39
46
|
// Support both new 'ambientMotion' and legacy 'kenBurns' property
|
|
@@ -54,12 +61,18 @@ export function imageWithCaption(input: ImageWithCaptionInput, context: Template
|
|
|
54
61
|
fit: 'cover',
|
|
55
62
|
credit: imageCredit,
|
|
56
63
|
license: imageLicense,
|
|
64
|
+
...(treatment ? { treatment } : {}),
|
|
57
65
|
},
|
|
58
66
|
position: { x: 0, y: 0, width: '100%', height: '100%' },
|
|
59
67
|
animation: imageAnimation,
|
|
60
68
|
},
|
|
61
69
|
];
|
|
62
70
|
|
|
71
|
+
// Scrim gradients are tinted from the theme background so the theme
|
|
72
|
+
// text color painted on top stays readable by construction — a fixed
|
|
73
|
+
// black scrim put dark theme text on a dark band in light themes.
|
|
74
|
+
const bg = theme.colors.background;
|
|
75
|
+
|
|
63
76
|
// TITLE MODE: Large centered title over hero image (like cover slide)
|
|
64
77
|
if (isTitle && caption) {
|
|
65
78
|
// Full gradient overlay for title readability (similar to cover slide)
|
|
@@ -68,7 +81,7 @@ export function imageWithCaption(input: ImageWithCaptionInput, context: Template
|
|
|
68
81
|
id: 'title-gradient',
|
|
69
82
|
content: {
|
|
70
83
|
shape: 'rect',
|
|
71
|
-
fill:
|
|
84
|
+
fill: `linear-gradient(0deg, ${withAlpha(bg, 0.85)} 0%, ${withAlpha(bg, 0.45)} 40%, ${withAlpha(bg, 0.1)} 70%, ${withAlpha(bg, 0)} 100%)`,
|
|
72
85
|
},
|
|
73
86
|
position: { x: 0, y: 0, width: '100%', height: '100%' },
|
|
74
87
|
});
|
|
@@ -85,7 +98,7 @@ export function imageWithCaption(input: ImageWithCaptionInput, context: Template
|
|
|
85
98
|
fontWeight: 'bold',
|
|
86
99
|
color: theme.colors.text,
|
|
87
100
|
textAlign: 'center',
|
|
88
|
-
shadow:
|
|
101
|
+
shadow: shouldUseShadow(context),
|
|
89
102
|
},
|
|
90
103
|
},
|
|
91
104
|
position: {
|
|
@@ -133,7 +146,7 @@ export function imageWithCaption(input: ImageWithCaptionInput, context: Template
|
|
|
133
146
|
id: 'caption-gradient',
|
|
134
147
|
content: {
|
|
135
148
|
shape: 'rect',
|
|
136
|
-
fill:
|
|
149
|
+
fill: `linear-gradient(0deg, ${withAlpha(bg, 0.8)} 0%, ${withAlpha(bg, 0.35)} 60%, ${withAlpha(bg, 0)} 100%)`,
|
|
137
150
|
},
|
|
138
151
|
position: {
|
|
139
152
|
x: 0,
|
|
@@ -154,7 +167,7 @@ export function imageWithCaption(input: ImageWithCaptionInput, context: Template
|
|
|
154
167
|
fontFamily: getThemeFont(context, 'body'),
|
|
155
168
|
color: theme.colors.text,
|
|
156
169
|
textAlign: 'center',
|
|
157
|
-
shadow:
|
|
170
|
+
shadow: shouldUseShadow(context),
|
|
158
171
|
},
|
|
159
172
|
},
|
|
160
173
|
position: {
|