@bendyline/squisq 1.4.1 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -1
- package/dist/{ContentContainer-DNx460y8.d.ts → ContentContainer-BXUlIf18.d.ts} +6 -2
- package/dist/{Doc-BeSeH2iX.d.ts → Doc-BBVGq1_9.d.ts} +922 -273
- package/dist/{ImageEditDoc-BTIvw0oq.d.ts → ImageEditDoc-FuyGtt6o.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-6ATE2PSM.js +344 -0
- package/dist/chunk-6ATE2PSM.js.map +1 -0
- package/dist/{chunk-57CVQCFX.js → chunk-A4O7GIWE.js} +74 -23
- package/dist/chunk-A4O7GIWE.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-ET53IIEP.js +1 -0
- package/dist/chunk-ET53IIEP.js.map +1 -0
- package/dist/chunk-HWVFJAAH.js +362 -0
- package/dist/chunk-HWVFJAAH.js.map +1 -0
- package/dist/{chunk-2TMAWB4Y.js → chunk-IMSCRLLV.js} +1 -1
- package/dist/chunk-IMSCRLLV.js.map +1 -0
- package/dist/{chunk-B4EEON3N.js → chunk-KKNUBQ6Y.js} +536 -103
- package/dist/chunk-KKNUBQ6Y.js.map +1 -0
- package/dist/chunk-LDQ2HJIX.js +596 -0
- package/dist/chunk-LDQ2HJIX.js.map +1 -0
- package/dist/chunk-LH7I6SH7.js +7208 -0
- package/dist/chunk-LH7I6SH7.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-K32VJONL.js → chunk-T5UK6YOB.js} +41 -2
- package/dist/chunk-T5UK6YOB.js.map +1 -0
- package/dist/{chunk-3K5OG6KI.js → chunk-TEEEILMP.js} +412 -186
- package/dist/chunk-TEEEILMP.js.map +1 -0
- package/dist/{chunk-FR2RBTKO.js → chunk-TQWLI6S2.js} +93 -27
- package/dist/chunk-TQWLI6S2.js.map +1 -0
- package/dist/{chunk-WMOI7FN3.js → chunk-UY7KGQ5R.js} +12 -2
- package/dist/{chunk-WMOI7FN3.js.map → chunk-UY7KGQ5R.js.map} +1 -1
- package/dist/{chunk-3E5F2XMR.js → chunk-VWUFZ6ZG.js} +29 -2
- package/dist/chunk-VWUFZ6ZG.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 +5 -5
- package/dist/doc/index.js +135 -8
- package/dist/generate/index.d.ts +3 -74
- package/dist/generate/index.js +2 -7
- 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 +12 -6
- package/dist/imageEdit/index.js +4 -1
- package/dist/index.d.ts +14 -11
- package/dist/index.js +265 -37
- package/dist/inlineIconMarker-CiE8Hlvz.d.ts +59 -0
- package/dist/jsonForm/index.d.ts +42 -1
- package/dist/jsonForm/index.js +9 -1
- package/dist/markdown/index.d.ts +228 -3
- package/dist/markdown/index.js +42 -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 +36 -8
- package/dist/spatial/index.d.ts +9 -4
- package/dist/spatial/index.js +1 -1
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.js +1 -1
- package/dist/story/index.d.ts +1021 -41
- package/dist/story/index.js +135 -8
- package/dist/{themeLibrary-BHjJ0Qx6.d.ts → themeLibrary-CehcJhzz.d.ts} +1 -1
- package/dist/timing/index.js +3 -5
- 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/dist/versions/index.d.ts +1 -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__/contentExtractor.test.ts +60 -0
- package/src/__tests__/coverBlock.test.ts +46 -1
- package/src/__tests__/customTemplateSample.test.ts +144 -0
- package/src/__tests__/customTemplatesFrontmatter.test.ts +236 -0
- package/src/__tests__/customThemesFrontmatter.test.ts +145 -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__/inputDescriptors.test.ts +162 -0
- package/src/__tests__/jsonForm.tokens.test.ts +84 -0
- package/src/__tests__/layoutBlock.test.ts +83 -0
- package/src/__tests__/layoutLayout.test.ts +169 -0
- package/src/__tests__/markdown.test.ts +87 -0
- package/src/__tests__/markdownSanitize.test.ts +79 -0
- package/src/__tests__/markdownToDoc.test.ts +391 -2
- package/src/__tests__/mediaAnnotations.test.ts +91 -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 +249 -0
- package/src/__tests__/templateAnnotationParse.test.ts +108 -0
- package/src/__tests__/templateMetadata.test.ts +31 -0
- package/src/__tests__/templates.test.ts +257 -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 +260 -0
- package/src/doc/annotationBlocks.ts +117 -0
- package/src/doc/customTemplatesFrontmatter.ts +314 -0
- package/src/doc/customThemesFrontmatter.ts +95 -0
- package/src/doc/docToMarkdown.ts +104 -5
- package/src/doc/getLayers.ts +49 -17
- package/src/doc/index.ts +47 -1
- package/src/doc/markdownToDoc.ts +411 -13
- package/src/doc/mediaAnnotations.ts +100 -0
- package/src/doc/resolveDocTheme.ts +55 -0
- package/src/doc/standaloneAnnotation.ts +58 -0
- package/src/doc/structuredData.ts +301 -0
- package/src/doc/templateInputs.ts +240 -0
- package/src/doc/templates/__tests__/customTemplate.test.ts +170 -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 +33 -18
- package/src/doc/templates/coverBlock.ts +35 -5
- package/src/doc/templates/customTemplate.ts +51 -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 +54 -26
- 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 +30 -15
- package/src/doc/templates/index.ts +225 -46
- package/src/doc/templates/inputDescriptors.ts +432 -0
- 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 +22 -34
- 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 +487 -0
- package/src/doc/templates/tokens/resolveTokens.ts +453 -0
- package/src/doc/templates/twoColumn.ts +48 -30
- package/src/doc/templates/videoPullQuote.ts +22 -12
- package/src/doc/templates/videoWithCaption.ts +21 -15
- 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/nearest.ts +59 -0
- package/src/doc/utils/shapeGeometry.ts +464 -0
- package/src/doc/utils/themeUtils.ts +75 -1
- package/src/doc/validate.ts +575 -0
- package/src/generate/contentExtractor.ts +148 -35
- package/src/generate/index.ts +0 -3
- 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/jsonForm/index.ts +2 -0
- package/src/jsonForm/tokens.ts +78 -0
- package/src/markdown/annotationCoercion.ts +295 -0
- package/src/markdown/attrTokens.ts +241 -0
- package/src/markdown/convert.ts +229 -26
- package/src/markdown/index.ts +37 -0
- package/src/markdown/sanitize.ts +318 -0
- package/src/markdown/stringify.ts +96 -6
- package/src/markdown/types.ts +66 -0
- package/src/markdown/utils.ts +111 -2
- package/src/recommend/templates.ts +24 -0
- package/src/schemas/BlockTemplates.ts +133 -4
- package/src/schemas/CustomTemplates.ts +126 -0
- package/src/schemas/Doc.ts +387 -65
- 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 +24 -5
- 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/storage/ContentContainer.ts +6 -2
- 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-2TMAWB4Y.js.map +0 -1
- package/dist/chunk-3E5F2XMR.js.map +0 -1
- package/dist/chunk-3K5OG6KI.js.map +0 -1
- package/dist/chunk-4X3JQXNM.js +0 -35
- package/dist/chunk-4X3JQXNM.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-FR2RBTKO.js.map +0 -1
- package/dist/chunk-H3AXU4MJ.js +0 -179
- package/dist/chunk-H3AXU4MJ.js.map +0 -1
- package/dist/chunk-K32VJONL.js.map +0 -1
- package/dist/chunk-KSWJR66U.js +0 -3706
- package/dist/chunk-KSWJR66U.js.map +0 -1
- package/dist/chunk-MYIH7FWD.js +0 -145
- package/dist/chunk-MYIH7FWD.js.map +0 -1
- package/dist/chunk-ZTX4PFFT.js.map +0 -1
- package/src/__tests__/slideshowGenerator.test.ts +0 -128
- package/src/generate/slideshowGenerator.ts +0 -273
|
@@ -11,16 +11,27 @@
|
|
|
11
11
|
|
|
12
12
|
import type { Layer, AnimationType } from '../../schemas/Doc.js';
|
|
13
13
|
import type { SectionHeaderInput, TemplateContext } from '../../schemas/BlockTemplates.js';
|
|
14
|
-
import {
|
|
15
|
-
|
|
14
|
+
import {
|
|
15
|
+
resolveColorScheme,
|
|
16
|
+
getThemeFont,
|
|
17
|
+
shouldUseShadow,
|
|
18
|
+
themedEntrance,
|
|
19
|
+
themedFontSize,
|
|
20
|
+
themedScrim,
|
|
21
|
+
themedImageTreatment,
|
|
22
|
+
} from '../utils/themeUtils.js';
|
|
16
23
|
|
|
17
24
|
export function sectionHeader(input: SectionHeaderInput, context: TemplateContext): Layer[] {
|
|
18
25
|
const { title = '', colorScheme = 'blue', imageSrc, imageAlt, ambientMotion } = input;
|
|
19
|
-
const { layout } = context;
|
|
26
|
+
const { theme, layout } = context;
|
|
27
|
+
|
|
28
|
+
const treatment = themedImageTreatment(context, input.imageTreatment);
|
|
20
29
|
const colors = resolveColorScheme(context, colorScheme);
|
|
21
30
|
|
|
22
|
-
// Scale font sizes for viewport
|
|
23
|
-
|
|
31
|
+
// Scale font sizes for viewport. Section dividers are the loudest
|
|
32
|
+
// interstitial in a doc, so the title sits a step above ordinary
|
|
33
|
+
// content-block headings.
|
|
34
|
+
const titleFontSize = themedFontSize(84, context, true);
|
|
24
35
|
|
|
25
36
|
const layers: Layer[] = [];
|
|
26
37
|
|
|
@@ -34,6 +45,7 @@ export function sectionHeader(input: SectionHeaderInput, context: TemplateContex
|
|
|
34
45
|
src: imageSrc,
|
|
35
46
|
alt: imageAlt || title,
|
|
36
47
|
fit: 'cover',
|
|
48
|
+
...(treatment ? { treatment } : {}),
|
|
37
49
|
},
|
|
38
50
|
position: { x: 0, y: 0, width: '100%', height: '100%' },
|
|
39
51
|
animation: ambientMotion
|
|
@@ -41,13 +53,14 @@ export function sectionHeader(input: SectionHeaderInput, context: TemplateContex
|
|
|
41
53
|
: { type: 'slowZoom', duration: 8, direction: 'in' },
|
|
42
54
|
});
|
|
43
55
|
|
|
44
|
-
//
|
|
56
|
+
// Theme-tinted overlay for text readability — light themes get a
|
|
57
|
+
// light scrim with dark theme text, dark themes the familiar dark one.
|
|
45
58
|
layers.push({
|
|
46
59
|
type: 'shape',
|
|
47
60
|
id: 'overlay',
|
|
48
61
|
content: {
|
|
49
62
|
shape: 'rect',
|
|
50
|
-
fill:
|
|
63
|
+
fill: themedScrim(context),
|
|
51
64
|
},
|
|
52
65
|
position: { x: 0, y: 0, width: '100%', height: '100%' },
|
|
53
66
|
});
|
|
@@ -78,7 +91,8 @@ export function sectionHeader(input: SectionHeaderInput, context: TemplateContex
|
|
|
78
91
|
});
|
|
79
92
|
}
|
|
80
93
|
|
|
81
|
-
// Section title
|
|
94
|
+
// Section title — theme text over the theme-tinted scrim (readable by
|
|
95
|
+
// construction), scheme text on the solid-color fallback
|
|
82
96
|
layers.push({
|
|
83
97
|
type: 'text',
|
|
84
98
|
id: 'title',
|
|
@@ -88,9 +102,9 @@ export function sectionHeader(input: SectionHeaderInput, context: TemplateContex
|
|
|
88
102
|
fontSize: titleFontSize,
|
|
89
103
|
fontFamily: getThemeFont(context, 'title'),
|
|
90
104
|
fontWeight: 'bold',
|
|
91
|
-
color: imageSrc ?
|
|
105
|
+
color: imageSrc ? theme.colors.text : colors.text,
|
|
92
106
|
textAlign: 'center',
|
|
93
|
-
shadow:
|
|
107
|
+
shadow: shouldUseShadow(context),
|
|
94
108
|
},
|
|
95
109
|
},
|
|
96
110
|
position: {
|
|
@@ -99,7 +113,7 @@ export function sectionHeader(input: SectionHeaderInput, context: TemplateContex
|
|
|
99
113
|
anchor: 'center',
|
|
100
114
|
width: layout.maxTextWidth,
|
|
101
115
|
},
|
|
102
|
-
animation: { type: 'fadeIn', duration: 1.5 },
|
|
116
|
+
animation: themedEntrance(context, 'text', { type: 'fadeIn', duration: 1.5 }),
|
|
103
117
|
});
|
|
104
118
|
|
|
105
119
|
return layers;
|
|
@@ -12,8 +12,15 @@
|
|
|
12
12
|
|
|
13
13
|
import type { Layer } from '../../schemas/Doc.js';
|
|
14
14
|
import type { StatHighlightInput, TemplateContext } from '../../schemas/BlockTemplates.js';
|
|
15
|
-
import {
|
|
16
|
-
|
|
15
|
+
import {
|
|
16
|
+
resolveColorScheme,
|
|
17
|
+
getTemplateHint,
|
|
18
|
+
getThemeFont,
|
|
19
|
+
shouldUseShadow,
|
|
20
|
+
themedFontSize,
|
|
21
|
+
themedSurfaceGradient,
|
|
22
|
+
themedImageTreatment,
|
|
23
|
+
} from '../utils/themeUtils.js';
|
|
17
24
|
import { createAccentLayers, getAccentLayout, adjustY, DEFAULT_LAYOUT } from './accentImage.js';
|
|
18
25
|
import { createBackgroundLayer } from './captionUtils.js';
|
|
19
26
|
|
|
@@ -39,20 +46,21 @@ export function statHighlight(input: StatHighlightInput, context: TemplateContex
|
|
|
39
46
|
const accentLayout = accentImage ? getAccentLayout(accentImage.position) : DEFAULT_LAYOUT;
|
|
40
47
|
|
|
41
48
|
// Scale font sizes — stat is dramatically large, description is understated
|
|
42
|
-
const statFontSize =
|
|
43
|
-
const descFontSize =
|
|
44
|
-
const detailFontSize =
|
|
49
|
+
const statFontSize = themedFontSize(148, context, true);
|
|
50
|
+
const descFontSize = themedFontSize(32, context, false);
|
|
51
|
+
const detailFontSize = themedFontSize(26, context, false);
|
|
45
52
|
|
|
46
|
-
const layers: Layer[] = [
|
|
47
|
-
createBackgroundLayer(
|
|
48
|
-
'bg',
|
|
49
|
-
`linear-gradient(180deg, ${theme.colors.background} 0%, #0f1520 100%)`,
|
|
50
|
-
),
|
|
51
|
-
];
|
|
53
|
+
const layers: Layer[] = [createBackgroundLayer('bg', themedSurfaceGradient(context, 180))];
|
|
52
54
|
|
|
53
55
|
// Add accent image layers (behind text, after background)
|
|
54
56
|
if (accentImage) {
|
|
55
|
-
layers.push(
|
|
57
|
+
layers.push(
|
|
58
|
+
...createAccentLayers(
|
|
59
|
+
accentImage,
|
|
60
|
+
input.id,
|
|
61
|
+
themedImageTreatment(context, input.imageTreatment),
|
|
62
|
+
),
|
|
63
|
+
);
|
|
56
64
|
}
|
|
57
65
|
|
|
58
66
|
// Big stat — hero element, dominates the slide
|
|
@@ -66,18 +74,23 @@ export function statHighlight(input: StatHighlightInput, context: TemplateContex
|
|
|
66
74
|
fontFamily: getThemeFont(context, 'title'),
|
|
67
75
|
fontWeight: 'bold',
|
|
68
76
|
color: colors.text,
|
|
69
|
-
shadow:
|
|
77
|
+
shadow: shouldUseShadow(context),
|
|
70
78
|
},
|
|
71
79
|
},
|
|
72
80
|
position: {
|
|
73
81
|
x: accentLayout.textCenterX,
|
|
74
|
-
y: adjustY('
|
|
82
|
+
y: adjustY('36%', accentLayout),
|
|
75
83
|
anchor: 'center',
|
|
76
84
|
},
|
|
77
|
-
animation:
|
|
85
|
+
animation:
|
|
86
|
+
getTemplateHint<string>(context, 'statHighlight', 'entrance', 'subtle') === 'dramatic'
|
|
87
|
+
? { type: 'zoomIn', duration: 0.4 }
|
|
88
|
+
: { type: 'zoomIn', duration: 0.6 },
|
|
78
89
|
});
|
|
79
90
|
|
|
80
|
-
// Description — smaller and understated beneath the stat
|
|
91
|
+
// Description — smaller and understated beneath the stat. Sits close
|
|
92
|
+
// under the stat (the ~26% fixed gap it used to get read as two
|
|
93
|
+
// unrelated elements floating in the panel).
|
|
81
94
|
layers.push({
|
|
82
95
|
type: 'text',
|
|
83
96
|
id: 'description',
|
|
@@ -88,13 +101,13 @@ export function statHighlight(input: StatHighlightInput, context: TemplateContex
|
|
|
88
101
|
fontFamily: getThemeFont(context, 'body'),
|
|
89
102
|
color: theme.colors.textMuted,
|
|
90
103
|
textAlign: 'center',
|
|
91
|
-
lineHeight: 1.
|
|
92
|
-
shadow:
|
|
104
|
+
lineHeight: 1.5,
|
|
105
|
+
shadow: shouldUseShadow(context),
|
|
93
106
|
},
|
|
94
107
|
},
|
|
95
108
|
position: {
|
|
96
109
|
x: accentLayout.textCenterX,
|
|
97
|
-
y: adjustY('
|
|
110
|
+
y: adjustY('54%', accentLayout),
|
|
98
111
|
width: accentLayout.textWidth,
|
|
99
112
|
anchor: 'center',
|
|
100
113
|
},
|
|
@@ -111,14 +124,18 @@ export function statHighlight(input: StatHighlightInput, context: TemplateContex
|
|
|
111
124
|
style: {
|
|
112
125
|
fontSize: detailFontSize,
|
|
113
126
|
fontFamily: getThemeFont(context, 'body'),
|
|
114
|
-
|
|
127
|
+
// Scheme *text* rather than *accent*: accents in the built-in
|
|
128
|
+
// schemes are tuned as chart/fill colors and drop below legible
|
|
129
|
+
// contrast as body copy on light surfaces.
|
|
130
|
+
color: colors.text,
|
|
115
131
|
textAlign: 'center',
|
|
116
|
-
shadow:
|
|
132
|
+
shadow: shouldUseShadow(context),
|
|
117
133
|
},
|
|
118
134
|
},
|
|
119
135
|
position: {
|
|
120
136
|
x: accentLayout.textCenterX,
|
|
121
|
-
y: adjustY('
|
|
137
|
+
y: adjustY('66%', accentLayout),
|
|
138
|
+
width: accentLayout.textWidth,
|
|
122
139
|
anchor: 'center',
|
|
123
140
|
},
|
|
124
141
|
animation: { type: 'fadeIn', duration: 1, delay: 1 },
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
* Title Block Template
|
|
3
3
|
*
|
|
4
4
|
* Large title with optional subtitle for doc intros.
|
|
5
|
-
* Centered text with fade-in animations
|
|
5
|
+
* Centered text with fade-in animations, composed as one lockup:
|
|
6
|
+
* accent rule, title, and subtitle are spaced from the title's
|
|
7
|
+
* estimated height instead of fixed slots that collide on wrap.
|
|
6
8
|
* Adapts font sizes and positioning for different viewports.
|
|
7
9
|
*
|
|
8
10
|
* This is shared code used by both site and efb-app doc renderers.
|
|
@@ -10,8 +12,15 @@
|
|
|
10
12
|
|
|
11
13
|
import type { Layer } from '../../schemas/Doc.js';
|
|
12
14
|
import type { TitleBlockInput, TemplateContext } from '../../schemas/BlockTemplates.js';
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
+
import {
|
|
16
|
+
getTemplateHint,
|
|
17
|
+
getThemeFont,
|
|
18
|
+
shouldUseShadow,
|
|
19
|
+
themedEntrance,
|
|
20
|
+
themedFontSize,
|
|
21
|
+
} from '../utils/themeUtils.js';
|
|
22
|
+
import { withAlpha } from '../../schemas/colorUtils.js';
|
|
23
|
+
import { estimateTextHeight } from './captionUtils.js';
|
|
15
24
|
|
|
16
25
|
/**
|
|
17
26
|
* Hint schema published for the theme validator + future customizer hint UI.
|
|
@@ -24,40 +33,68 @@ export const titleBlockHintSchema = {
|
|
|
24
33
|
|
|
25
34
|
export function titleBlock(input: TitleBlockInput, context: TemplateContext): Layer[] {
|
|
26
35
|
const { title, subtitle, backgroundColor } = input;
|
|
27
|
-
const { theme, layout } = context;
|
|
36
|
+
const { theme, layout, viewport } = context;
|
|
28
37
|
|
|
29
38
|
// Scale font sizes for viewport
|
|
30
|
-
const titleFontSize =
|
|
31
|
-
const subtitleFontSize =
|
|
39
|
+
const titleFontSize = themedFontSize(96, context, true);
|
|
40
|
+
const subtitleFontSize = themedFontSize(36, context, false);
|
|
32
41
|
|
|
33
42
|
const baseBg = backgroundColor || theme.colors.primary;
|
|
34
43
|
|
|
44
|
+
// Estimate the title's rendered height so the rule and subtitle key off
|
|
45
|
+
// its real extent — fixed slots let the rule overlap the ascenders and
|
|
46
|
+
// stranded the subtitle when the title wrapped.
|
|
47
|
+
const maxWidthPx = (parseFloat(layout.maxTextWidth) / 100) * viewport.width;
|
|
48
|
+
const titleH = estimateTextHeight(title, titleFontSize, maxWidthPx, 1.15);
|
|
49
|
+
const titleYPct = subtitle ? 42 : 48;
|
|
50
|
+
const px = (v: number) => (v / viewport.height) * 100;
|
|
51
|
+
|
|
35
52
|
const layers: Layer[] = [
|
|
36
|
-
// Background —
|
|
53
|
+
// Background — theme surface with a soft radial accent tint. The tint
|
|
54
|
+
// is translucent so the theme's text color keeps its contrast with the
|
|
55
|
+
// surface; a full-strength `primary` hotspot behind the title made
|
|
56
|
+
// dark-primary light themes unreadable.
|
|
37
57
|
{
|
|
38
58
|
type: 'shape',
|
|
39
59
|
id: 'bg',
|
|
40
60
|
content: {
|
|
41
61
|
shape: 'rect',
|
|
42
|
-
fill:
|
|
62
|
+
fill: theme.colors.background,
|
|
43
63
|
},
|
|
44
64
|
position: { x: 0, y: 0, width: '100%', height: '100%' },
|
|
45
65
|
},
|
|
46
|
-
// Subtle decorative line above title
|
|
47
66
|
{
|
|
67
|
+
type: 'shape',
|
|
68
|
+
id: 'bg-tint',
|
|
69
|
+
content: {
|
|
70
|
+
shape: 'rect',
|
|
71
|
+
fill: `radial-gradient(ellipse at 50% 40%, ${withAlpha(baseBg, 0.32)} 0%, ${withAlpha(baseBg, 0)} 75%)`,
|
|
72
|
+
},
|
|
73
|
+
position: { x: 0, y: 0, width: '100%', height: '100%' },
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
// Subtle decorative line, clear above the title's ascenders. Themes can
|
|
78
|
+
// hide it via `templateHints.title.showAccentLine: false` (the line is
|
|
79
|
+
// decorative; title/subtitle positions don't depend on it).
|
|
80
|
+
if (getTemplateHint(context, 'title', 'showAccentLine', true)) {
|
|
81
|
+
layers.push({
|
|
48
82
|
type: 'shape',
|
|
49
83
|
id: 'accent-line',
|
|
50
84
|
content: {
|
|
51
85
|
shape: 'rect',
|
|
52
|
-
fill:
|
|
86
|
+
fill: withAlpha(theme.colors.text, 0.3),
|
|
53
87
|
},
|
|
54
88
|
position: {
|
|
55
|
-
x: '
|
|
56
|
-
y:
|
|
57
|
-
width: '
|
|
58
|
-
height: '
|
|
89
|
+
x: '44%',
|
|
90
|
+
y: `${titleYPct - px(titleH / 2 + 56)}%`,
|
|
91
|
+
width: '12%',
|
|
92
|
+
height: '3px',
|
|
59
93
|
},
|
|
60
|
-
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
layers.push(
|
|
61
98
|
// Title
|
|
62
99
|
{
|
|
63
100
|
type: 'text',
|
|
@@ -70,21 +107,22 @@ export function titleBlock(input: TitleBlockInput, context: TemplateContext): La
|
|
|
70
107
|
fontWeight: 'bold',
|
|
71
108
|
color: theme.colors.text,
|
|
72
109
|
textAlign: 'center',
|
|
73
|
-
shadow:
|
|
110
|
+
shadow: shouldUseShadow(context),
|
|
74
111
|
},
|
|
75
112
|
},
|
|
76
113
|
position: {
|
|
77
114
|
x: '50%',
|
|
78
|
-
y:
|
|
115
|
+
y: `${titleYPct}%`,
|
|
79
116
|
anchor: 'center',
|
|
80
117
|
width: layout.maxTextWidth,
|
|
81
118
|
},
|
|
82
|
-
animation: { type: 'fadeIn', duration: 2 },
|
|
119
|
+
animation: themedEntrance(context, 'text', { type: 'fadeIn', duration: 2 }),
|
|
83
120
|
},
|
|
84
|
-
|
|
121
|
+
);
|
|
85
122
|
|
|
86
|
-
// Add subtitle if provided
|
|
123
|
+
// Add subtitle if provided — hangs from the title's estimated bottom edge
|
|
87
124
|
if (subtitle) {
|
|
125
|
+
const subH = estimateTextHeight(subtitle, subtitleFontSize, maxWidthPx, 1.5);
|
|
88
126
|
layers.push({
|
|
89
127
|
type: 'text',
|
|
90
128
|
id: 'subtitle',
|
|
@@ -100,7 +138,7 @@ export function titleBlock(input: TitleBlockInput, context: TemplateContext): La
|
|
|
100
138
|
},
|
|
101
139
|
position: {
|
|
102
140
|
x: '50%',
|
|
103
|
-
y:
|
|
141
|
+
y: `${titleYPct + px(titleH / 2 + 56 + subH / 2)}%`,
|
|
104
142
|
anchor: 'center',
|
|
105
143
|
width: layout.maxTextWidth,
|
|
106
144
|
},
|