@kensio/colophon 2.2.0 → 2.4.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/README.md +62 -265
- package/dist/background.d.ts +7 -2
- package/dist/background.d.ts.map +1 -1
- package/dist/background.js +44 -1
- package/dist/background.js.map +1 -1
- package/dist/cli/args.d.ts +14 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +67 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/config.d.ts +12 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +43 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +35 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli.js +34 -6
- package/dist/cli.js.map +1 -1
- package/dist/config/defaults.d.ts +65 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +64 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +22 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +54 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/resolve.d.ts +31 -0
- package/dist/config/resolve.d.ts.map +1 -0
- package/dist/config/resolve.js +82 -0
- package/dist/config/resolve.js.map +1 -0
- package/dist/config/size.d.ts +20 -0
- package/dist/config/size.d.ts.map +1 -0
- package/dist/config/size.js +47 -0
- package/dist/config/size.js.map +1 -0
- package/dist/config.d.ts +27 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +78 -2
- package/dist/config.js.map +1 -1
- package/dist/content/index.d.ts +5 -51
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +3 -115
- package/dist/content/index.js.map +1 -1
- package/dist/content/props.d.ts +15 -0
- package/dist/content/props.d.ts.map +1 -0
- package/dist/content/props.js +71 -0
- package/dist/content/props.js.map +1 -0
- package/dist/content/slug.d.ts +23 -0
- package/dist/content/slug.d.ts.map +1 -0
- package/dist/content/slug.js +52 -0
- package/dist/content/slug.js.map +1 -0
- package/dist/content/walk.d.ts +17 -0
- package/dist/content/walk.d.ts.map +1 -0
- package/dist/content/walk.js +57 -0
- package/dist/content/walk.js.map +1 -0
- package/dist/fonts/index.d.ts +11 -0
- package/dist/fonts/index.d.ts.map +1 -0
- package/dist/fonts/index.js +12 -0
- package/dist/fonts/index.js.map +1 -0
- package/dist/fonts/materialise.d.ts +7 -0
- package/dist/fonts/materialise.d.ts.map +1 -0
- package/dist/fonts/materialise.js +47 -0
- package/dist/fonts/materialise.js.map +1 -0
- package/dist/fonts/resolve.d.ts +7 -0
- package/dist/fonts/resolve.d.ts.map +1 -0
- package/dist/fonts/resolve.js +50 -0
- package/dist/fonts/resolve.js.map +1 -0
- package/dist/fonts.d.ts +18 -0
- package/dist/fonts.d.ts.map +1 -0
- package/dist/fonts.js +102 -0
- package/dist/fonts.js.map +1 -0
- package/dist/generate/extra.d.ts +16 -0
- package/dist/generate/extra.d.ts.map +1 -0
- package/dist/generate/extra.js +60 -0
- package/dist/generate/extra.js.map +1 -0
- package/dist/generate/index.d.ts +19 -0
- package/dist/generate/index.d.ts.map +1 -0
- package/dist/generate/index.js +46 -0
- package/dist/generate/index.js.map +1 -0
- package/dist/generate/job.d.ts +35 -0
- package/dist/generate/job.d.ts.map +1 -0
- package/dist/generate/job.js +2 -0
- package/dist/generate/job.js.map +1 -0
- package/dist/generate/options.d.ts +56 -0
- package/dist/generate/options.d.ts.map +1 -0
- package/dist/generate/options.js +17 -0
- package/dist/generate/options.js.map +1 -0
- package/dist/generate/output-path.d.ts +12 -0
- package/dist/generate/output-path.d.ts.map +1 -0
- package/dist/generate/output-path.js +18 -0
- package/dist/generate/output-path.js.map +1 -0
- package/dist/generate/outputs.d.ts +28 -0
- package/dist/generate/outputs.d.ts.map +1 -0
- package/dist/generate/outputs.js +71 -0
- package/dist/generate/outputs.js.map +1 -0
- package/dist/generate/plan.d.ts +21 -0
- package/dist/generate/plan.d.ts.map +1 -0
- package/dist/generate/plan.js +72 -0
- package/dist/generate/plan.js.map +1 -0
- package/dist/generate/render-image.d.ts +11 -0
- package/dist/generate/render-image.d.ts.map +1 -0
- package/dist/generate/render-image.js +27 -0
- package/dist/generate/render-image.js.map +1 -0
- package/dist/generate.d.ts +27 -6
- package/dist/generate.d.ts.map +1 -1
- package/dist/generate.js +69 -15
- package/dist/generate.js.map +1 -1
- package/dist/highlight/color.d.ts +9 -0
- package/dist/highlight/color.d.ts.map +1 -0
- package/dist/highlight/color.js +15 -0
- package/dist/highlight/color.js.map +1 -0
- package/dist/highlight/grid.d.ts +14 -0
- package/dist/highlight/grid.d.ts.map +1 -0
- package/dist/highlight/grid.js +36 -0
- package/dist/highlight/grid.js.map +1 -0
- package/dist/highlight/index.d.ts +12 -0
- package/dist/highlight/index.d.ts.map +1 -0
- package/dist/highlight/index.js +31 -0
- package/dist/highlight/index.js.map +1 -0
- package/dist/highlight/language.d.ts +13 -0
- package/dist/highlight/language.d.ts.map +1 -0
- package/dist/highlight/language.js +41 -0
- package/dist/highlight/language.js.map +1 -0
- package/dist/highlight/normalise.d.ts +17 -0
- package/dist/highlight/normalise.d.ts.map +1 -0
- package/dist/highlight/normalise.js +37 -0
- package/dist/highlight/normalise.js.map +1 -0
- package/dist/highlight/types.d.ts +40 -0
- package/dist/highlight/types.d.ts.map +1 -0
- package/dist/highlight/types.js +2 -0
- package/dist/highlight/types.js.map +1 -0
- package/dist/image/index.d.ts +18 -0
- package/dist/image/index.d.ts.map +1 -0
- package/dist/image/index.js +42 -0
- package/dist/image/index.js.map +1 -0
- package/dist/image/jpeg.d.ts +10 -0
- package/dist/image/jpeg.d.ts.map +1 -0
- package/dist/image/jpeg.js +57 -0
- package/dist/image/jpeg.js.map +1 -0
- package/dist/image/load.d.ts +4 -0
- package/dist/image/load.d.ts.map +1 -0
- package/dist/image/load.js +60 -0
- package/dist/image/load.js.map +1 -0
- package/dist/image/media.d.ts +10 -0
- package/dist/image/media.d.ts.map +1 -0
- package/dist/image/media.js +37 -0
- package/dist/image/media.js.map +1 -0
- package/dist/image/resolve.d.ts +13 -0
- package/dist/image/resolve.d.ts.map +1 -0
- package/dist/image/resolve.js +38 -0
- package/dist/image/resolve.js.map +1 -0
- package/dist/image/size.d.ts +22 -0
- package/dist/image/size.d.ts.map +1 -0
- package/dist/image/size.js +60 -0
- package/dist/image/size.js.map +1 -0
- package/dist/image/svg.d.ts +12 -0
- package/dist/image/svg.d.ts.map +1 -0
- package/dist/image/svg.js +61 -0
- package/dist/image/svg.js.map +1 -0
- package/dist/image/uri.d.ts +9 -0
- package/dist/image/uri.d.ts.map +1 -0
- package/dist/image/uri.js +22 -0
- package/dist/image/uri.js.map +1 -0
- package/dist/index.d.ts +19 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/layout/block.d.ts +37 -0
- package/dist/layout/block.d.ts.map +1 -0
- package/dist/layout/block.js +26 -0
- package/dist/layout/block.js.map +1 -0
- package/dist/layout/box.d.ts +20 -0
- package/dist/layout/box.d.ts.map +1 -0
- package/dist/layout/box.js +61 -0
- package/dist/layout/box.js.map +1 -0
- package/dist/layout/distribute.d.ts +15 -0
- package/dist/layout/distribute.d.ts.map +1 -0
- package/dist/layout/distribute.js +30 -0
- package/dist/layout/distribute.js.map +1 -0
- package/dist/layout/image.d.ts +42 -0
- package/dist/layout/image.d.ts.map +1 -0
- package/dist/layout/image.js +34 -0
- package/dist/layout/image.js.map +1 -0
- package/dist/layout/index.d.ts +40 -0
- package/dist/layout/index.d.ts.map +1 -0
- package/dist/layout/index.js +30 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/layout/lines.d.ts +45 -0
- package/dist/layout/lines.d.ts.map +1 -0
- package/dist/layout/lines.js +71 -0
- package/dist/layout/lines.js.map +1 -0
- package/dist/layout/measure.d.ts +11 -0
- package/dist/layout/measure.d.ts.map +1 -0
- package/dist/layout/measure.js +11 -0
- package/dist/layout/measure.js.map +1 -0
- package/dist/layout/panel.d.ts +20 -0
- package/dist/layout/panel.d.ts.map +1 -0
- package/dist/layout/panel.js +22 -0
- package/dist/layout/panel.js.map +1 -0
- package/dist/layout/row.d.ts +15 -0
- package/dist/layout/row.d.ts.map +1 -0
- package/dist/layout/row.js +20 -0
- package/dist/layout/row.js.map +1 -0
- package/dist/layout/scrim.d.ts +23 -0
- package/dist/layout/scrim.d.ts.map +1 -0
- package/dist/layout/scrim.js +38 -0
- package/dist/layout/scrim.js.map +1 -0
- package/dist/layout/stack.d.ts +14 -0
- package/dist/layout/stack.d.ts.map +1 -0
- package/dist/layout/stack.js +19 -0
- package/dist/layout/stack.js.map +1 -0
- package/dist/layout/types.d.ts +49 -0
- package/dist/layout/types.d.ts.map +1 -0
- package/dist/layout/types.js +2 -0
- package/dist/layout/types.js.map +1 -0
- package/dist/manifest/build.d.ts +14 -0
- package/dist/manifest/build.d.ts.map +1 -0
- package/dist/manifest/build.js +43 -0
- package/dist/manifest/build.js.map +1 -0
- package/dist/manifest/index.d.ts +27 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +31 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/manifest/order.d.ts +12 -0
- package/dist/manifest/order.d.ts.map +1 -0
- package/dist/manifest/order.js +17 -0
- package/dist/manifest/order.js.map +1 -0
- package/dist/manifest/page.d.ts +24 -0
- package/dist/manifest/page.d.ts.map +1 -0
- package/dist/manifest/page.js +55 -0
- package/dist/manifest/page.js.map +1 -0
- package/dist/measure/estimate.d.ts +10 -0
- package/dist/measure/estimate.d.ts.map +1 -0
- package/dist/measure/estimate.js +58 -0
- package/dist/measure/estimate.js.map +1 -0
- package/dist/measure/faces.d.ts +15 -0
- package/dist/measure/faces.d.ts.map +1 -0
- package/dist/measure/faces.js +70 -0
- package/dist/measure/faces.js.map +1 -0
- package/dist/measure/index.d.ts +16 -0
- package/dist/measure/index.d.ts.map +1 -0
- package/dist/measure/index.js +0 -0
- package/dist/measure/index.js.map +1 -0
- package/dist/measure/runs.d.ts +17 -0
- package/dist/measure/runs.d.ts.map +1 -0
- package/dist/measure/runs.js +39 -0
- package/dist/measure/runs.js.map +1 -0
- package/dist/measure/select.d.ts +13 -0
- package/dist/measure/select.d.ts.map +1 -0
- package/dist/measure/select.js +47 -0
- package/dist/measure/select.js.map +1 -0
- package/dist/meta/html.d.ts +14 -0
- package/dist/meta/html.d.ts.map +1 -0
- package/dist/meta/html.js +24 -0
- package/dist/meta/html.js.map +1 -0
- package/dist/meta/index.d.ts +11 -0
- package/dist/meta/index.d.ts.map +1 -0
- package/dist/meta/index.js +11 -0
- package/dist/meta/index.js.map +1 -0
- package/dist/meta/tags.d.ts +21 -0
- package/dist/meta/tags.d.ts.map +1 -0
- package/dist/meta/tags.js +72 -0
- package/dist/meta/tags.js.map +1 -0
- package/dist/meta/url.d.ts +15 -0
- package/dist/meta/url.d.ts.map +1 -0
- package/dist/meta/url.js +34 -0
- package/dist/meta/url.js.map +1 -0
- package/dist/placement/check.d.ts +16 -0
- package/dist/placement/check.d.ts.map +1 -0
- package/dist/placement/check.js +40 -0
- package/dist/placement/check.js.map +1 -0
- package/dist/placement/index.d.ts +29 -0
- package/dist/placement/index.d.ts.map +1 -0
- package/dist/placement/index.js +61 -0
- package/dist/placement/index.js.map +1 -0
- package/dist/placement/relative.d.ts +31 -0
- package/dist/placement/relative.d.ts.map +1 -0
- package/dist/placement/relative.js +53 -0
- package/dist/placement/relative.js.map +1 -0
- package/dist/pool.d.ts +18 -0
- package/dist/pool.d.ts.map +1 -0
- package/dist/pool.js +56 -0
- package/dist/pool.js.map +1 -0
- package/dist/props.d.ts +7 -0
- package/dist/props.d.ts.map +1 -0
- package/dist/props.js +17 -0
- package/dist/props.js.map +1 -0
- package/dist/render/index.d.ts +10 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +27 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/png.d.ts +10 -0
- package/dist/render/png.d.ts.map +1 -0
- package/dist/render/png.js +30 -0
- package/dist/render/png.js.map +1 -0
- package/dist/render/svg.d.ts +12 -0
- package/dist/render/svg.d.ts.map +1 -0
- package/dist/render/svg.js +35 -0
- package/dist/render/svg.js.map +1 -0
- package/dist/render/template.d.ts +9 -0
- package/dist/render/template.d.ts.map +1 -0
- package/dist/render/template.js +17 -0
- package/dist/render/template.js.map +1 -0
- package/dist/render.d.ts +6 -2
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +31 -10
- package/dist/render.js.map +1 -1
- package/dist/stamp/chunk.d.ts +16 -0
- package/dist/stamp/chunk.d.ts.map +1 -0
- package/dist/stamp/chunk.js +46 -0
- package/dist/stamp/chunk.js.map +1 -0
- package/dist/stamp/config-digest.d.ts +11 -0
- package/dist/stamp/config-digest.d.ts.map +1 -0
- package/dist/stamp/config-digest.js +62 -0
- package/dist/stamp/config-digest.js.map +1 -0
- package/dist/stamp/digest.d.ts +8 -0
- package/dist/stamp/digest.d.ts.map +1 -0
- package/dist/stamp/digest.js +20 -0
- package/dist/stamp/digest.js.map +1 -0
- package/dist/stamp/index.d.ts +20 -0
- package/dist/stamp/index.d.ts.map +1 -0
- package/dist/stamp/index.js +40 -0
- package/dist/stamp/index.js.map +1 -0
- package/dist/stamp/read.d.ts +7 -0
- package/dist/stamp/read.d.ts.map +1 -0
- package/dist/stamp/read.js +62 -0
- package/dist/stamp/read.js.map +1 -0
- package/dist/stamp.d.ts +29 -0
- package/dist/stamp.d.ts.map +1 -0
- package/dist/stamp.js +198 -0
- package/dist/stamp.js.map +1 -0
- package/dist/templates/attribution.d.ts +17 -0
- package/dist/templates/attribution.d.ts.map +1 -0
- package/dist/templates/attribution.js +39 -0
- package/dist/templates/attribution.js.map +1 -0
- package/dist/templates/banner/badge.d.ts +7 -0
- package/dist/templates/banner/badge.d.ts.map +1 -0
- package/dist/templates/banner/badge.js +21 -0
- package/dist/templates/banner/badge.js.map +1 -0
- package/dist/templates/banner/index.d.ts +12 -0
- package/dist/templates/banner/index.d.ts.map +1 -0
- package/dist/templates/banner/index.js +68 -0
- package/dist/templates/banner/index.js.map +1 -0
- package/dist/templates/banner/lines.d.ts +22 -0
- package/dist/templates/banner/lines.d.ts.map +1 -0
- package/dist/templates/banner/lines.js +35 -0
- package/dist/templates/banner/lines.js.map +1 -0
- package/dist/templates/banner/version.d.ts +9 -0
- package/dist/templates/banner/version.d.ts.map +1 -0
- package/dist/templates/banner/version.js +21 -0
- package/dist/templates/banner/version.js.map +1 -0
- package/dist/templates/card/index.d.ts +10 -0
- package/dist/templates/card/index.d.ts.map +1 -0
- package/dist/templates/card/index.js +55 -0
- package/dist/templates/card/index.js.map +1 -0
- package/dist/templates/card/lines.d.ts +21 -0
- package/dist/templates/card/lines.d.ts.map +1 -0
- package/dist/templates/card/lines.js +36 -0
- package/dist/templates/card/lines.js.map +1 -0
- package/dist/templates/code/chrome.d.ts +13 -0
- package/dist/templates/code/chrome.d.ts.map +1 -0
- package/dist/templates/code/chrome.js +33 -0
- package/dist/templates/code/chrome.js.map +1 -0
- package/dist/templates/code/clip.d.ts +18 -0
- package/dist/templates/code/clip.d.ts.map +1 -0
- package/dist/templates/code/clip.js +44 -0
- package/dist/templates/code/clip.js.map +1 -0
- package/dist/templates/code/ellipsis.d.ts +3 -0
- package/dist/templates/code/ellipsis.d.ts.map +1 -0
- package/dist/templates/code/ellipsis.js +3 -0
- package/dist/templates/code/ellipsis.js.map +1 -0
- package/dist/templates/code/fit.d.ts +27 -0
- package/dist/templates/code/fit.d.ts.map +1 -0
- package/dist/templates/code/fit.js +59 -0
- package/dist/templates/code/fit.js.map +1 -0
- package/dist/templates/code/index.d.ts +12 -0
- package/dist/templates/code/index.d.ts.map +1 -0
- package/dist/templates/code/index.js +65 -0
- package/dist/templates/code/index.js.map +1 -0
- package/dist/templates/code/layout.d.ts +21 -0
- package/dist/templates/code/layout.d.ts.map +1 -0
- package/dist/templates/code/layout.js +21 -0
- package/dist/templates/code/layout.js.map +1 -0
- package/dist/templates/code/panel.d.ts +30 -0
- package/dist/templates/code/panel.d.ts.map +1 -0
- package/dist/templates/code/panel.js +52 -0
- package/dist/templates/code/panel.js.map +1 -0
- package/dist/templates/code/plate.d.ts +17 -0
- package/dist/templates/code/plate.d.ts.map +1 -0
- package/dist/templates/code/plate.js +34 -0
- package/dist/templates/code/plate.js.map +1 -0
- package/dist/templates/code/spans.d.ts +19 -0
- package/dist/templates/code/spans.d.ts.map +1 -0
- package/dist/templates/code/spans.js +36 -0
- package/dist/templates/code/spans.js.map +1 -0
- package/dist/templates/code/warn.d.ts +11 -0
- package/dist/templates/code/warn.d.ts.map +1 -0
- package/dist/templates/code/warn.js +24 -0
- package/dist/templates/code/warn.js.map +1 -0
- package/dist/templates/code/width.d.ts +10 -0
- package/dist/templates/code/width.d.ts.map +1 -0
- package/dist/templates/code/width.js +26 -0
- package/dist/templates/code/width.js.map +1 -0
- package/dist/templates/footer.d.ts +29 -0
- package/dist/templates/footer.d.ts.map +1 -0
- package/dist/templates/footer.js +35 -0
- package/dist/templates/footer.js.map +1 -0
- package/dist/templates/index.d.ts +4 -4
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/templates/index.js +7 -7
- package/dist/templates/index.js.map +1 -1
- package/dist/templates/logo.d.ts +15 -0
- package/dist/templates/logo.d.ts.map +1 -0
- package/dist/templates/logo.js +30 -0
- package/dist/templates/logo.js.map +1 -0
- package/dist/templates/measure.d.ts +11 -0
- package/dist/templates/measure.d.ts.map +1 -0
- package/dist/templates/measure.js +11 -0
- package/dist/templates/measure.js.map +1 -0
- package/dist/templates/props.d.ts +2 -2
- package/dist/templates/props.js +2 -2
- package/dist/templates/text.d.ts +37 -0
- package/dist/templates/text.d.ts.map +1 -0
- package/dist/templates/text.js +26 -0
- package/dist/templates/text.js.map +1 -0
- package/dist/text/break.d.ts +11 -0
- package/dist/text/break.d.ts.map +1 -0
- package/dist/text/break.js +30 -0
- package/dist/text/break.js.map +1 -0
- package/dist/text/element.d.ts +18 -0
- package/dist/text/element.d.ts.map +1 -0
- package/dist/text/element.js +19 -0
- package/dist/text/element.js.map +1 -0
- package/dist/text/escape.d.ts +5 -0
- package/dist/text/escape.d.ts.map +1 -0
- package/dist/text/escape.js +12 -0
- package/dist/text/escape.js.map +1 -0
- package/dist/text/fit.d.ts +30 -0
- package/dist/text/fit.d.ts.map +1 -0
- package/dist/text/fit.js +29 -0
- package/dist/text/fit.js.map +1 -0
- package/dist/text/index.d.ts +9 -0
- package/dist/text/index.d.ts.map +1 -0
- package/dist/text/index.js +6 -0
- package/dist/text/index.js.map +1 -0
- package/dist/text/stack.d.ts +24 -0
- package/dist/text/stack.d.ts.map +1 -0
- package/dist/text/stack.js +18 -0
- package/dist/text/stack.js.map +1 -0
- package/dist/text/wrap.d.ts +22 -0
- package/dist/text/wrap.d.ts.map +1 -0
- package/dist/text/wrap.js +41 -0
- package/dist/text/wrap.js.map +1 -0
- package/dist/types.d.ts +458 -18
- package/dist/types.d.ts.map +1 -1
- package/dist/validate/check.d.ts +13 -0
- package/dist/validate/check.d.ts.map +1 -0
- package/dist/validate/check.js +34 -0
- package/dist/validate/check.js.map +1 -0
- package/dist/validate/index.d.ts +15 -0
- package/dist/validate/index.d.ts.map +1 -0
- package/dist/validate/index.js +42 -0
- package/dist/validate/index.js.map +1 -0
- package/dist/validate/keys.d.ts +75 -0
- package/dist/validate/keys.d.ts.map +1 -0
- package/dist/validate/keys.js +203 -0
- package/dist/validate/keys.js.map +1 -0
- package/dist/validate/overrides.d.ts +5 -0
- package/dist/validate/overrides.d.ts.map +1 -0
- package/dist/validate/overrides.js +43 -0
- package/dist/validate/overrides.js.map +1 -0
- package/dist/validate/placement.d.ts +10 -0
- package/dist/validate/placement.d.ts.map +1 -0
- package/dist/validate/placement.js +38 -0
- package/dist/validate/placement.js.map +1 -0
- package/dist/validate/sizes.d.ts +9 -0
- package/dist/validate/sizes.d.ts.map +1 -0
- package/dist/validate/sizes.js +27 -0
- package/dist/validate/sizes.js.map +1 -0
- package/dist/validate/suggest.d.ts +10 -0
- package/dist/validate/suggest.d.ts.map +1 -0
- package/dist/validate/suggest.js +73 -0
- package/dist/validate/suggest.js.map +1 -0
- package/dist/validate/values.d.ts +21 -0
- package/dist/validate/values.d.ts.map +1 -0
- package/dist/validate/values.js +71 -0
- package/dist/validate/values.js.map +1 -0
- package/dist/validate.d.ts +15 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +300 -0
- package/dist/validate.js.map +1 -0
- package/package.json +19 -6
package/dist/stamp.js
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { open, readFile } from "node:fs/promises";
|
|
3
|
+
import { crc32 } from "node:zlib";
|
|
4
|
+
/**
|
|
5
|
+
* PNG `tEXt` keyword the stamp is stored under. Keeping it in the image means
|
|
6
|
+
* there is no sidecar file to fall out of sync, and deleting an image deletes
|
|
7
|
+
* its stamp with it.
|
|
8
|
+
*/
|
|
9
|
+
const stampKeyword = "colophon";
|
|
10
|
+
/**
|
|
11
|
+
* How much of a PNG to read when looking for a stamp. The stamp goes in
|
|
12
|
+
* immediately after `IHDR`, so this only has to cover the header — reading
|
|
13
|
+
* whole images just to compare a hash would defeat the point of skipping them.
|
|
14
|
+
*/
|
|
15
|
+
const headBytes = 4096;
|
|
16
|
+
const pngSignature = Buffer.from([
|
|
17
|
+
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
|
|
18
|
+
]);
|
|
19
|
+
/** Signature + the whole `IHDR` chunk: length, type, 13 bytes of data, CRC. */
|
|
20
|
+
const afterHeader = pngSignature.length + 4 + 4 + 13 + 4;
|
|
21
|
+
function sha256(value) {
|
|
22
|
+
return createHash("sha256").update(value).digest("hex");
|
|
23
|
+
}
|
|
24
|
+
function isRecord(value) {
|
|
25
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* `JSON.stringify` with object keys sorted, so that reordering frontmatter
|
|
29
|
+
* without changing it does not look like a change.
|
|
30
|
+
*/
|
|
31
|
+
function stableStringify(value) {
|
|
32
|
+
return JSON.stringify(value, (_key, raw) => isRecord(raw)
|
|
33
|
+
? Object.fromEntries(Object.keys(raw)
|
|
34
|
+
.toSorted((a, b) => a.localeCompare(b))
|
|
35
|
+
.map((key) => [key, raw[key]]))
|
|
36
|
+
: raw);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The installed Colophon version. The built-in templates ship in this package,
|
|
40
|
+
* so an upgrade can change what an image looks like without anything in the
|
|
41
|
+
* project changing; folding the version into the stamp makes that upgrade
|
|
42
|
+
* re-render rather than leave the old images in place.
|
|
43
|
+
*/
|
|
44
|
+
async function packageVersion() {
|
|
45
|
+
const manifest = await readFile(new URL("../package.json", import.meta.url), "utf8");
|
|
46
|
+
return JSON.parse(manifest).version;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Digest one configured font by its contents, not its path: replacing the file
|
|
50
|
+
* at the same path changes every image drawn with it.
|
|
51
|
+
*/
|
|
52
|
+
async function fontDigest(font) {
|
|
53
|
+
const bytes = "data" in font ? font.data : await readFile(font.path);
|
|
54
|
+
return sha256(stableStringify({ family: font.family, bytes: sha256(bytes) }));
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Digest the config fields that affect what an image looks like.
|
|
58
|
+
*
|
|
59
|
+
* `onWarning` is left out because it cannot change a pixel. So are `sizes` and
|
|
60
|
+
* `templates`: the one size and the one template an image actually uses go into
|
|
61
|
+
* its own stamp, so adding a third size or an unrelated custom template does
|
|
62
|
+
* not invalidate everything already on disk.
|
|
63
|
+
*/
|
|
64
|
+
async function configDigest(config) {
|
|
65
|
+
const fonts = await Promise.all(config.fonts.map(async (font) => fontDigest(font)));
|
|
66
|
+
return sha256(stableStringify({
|
|
67
|
+
version: await packageVersion(),
|
|
68
|
+
colors: config.colors,
|
|
69
|
+
background: config.background,
|
|
70
|
+
fonts,
|
|
71
|
+
systemFonts: config.systemFonts,
|
|
72
|
+
fontFamily: config.fontFamily,
|
|
73
|
+
footer: config.footer,
|
|
74
|
+
badge: config.badge,
|
|
75
|
+
code: config.code,
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Build a {@link Stamper} for a resolved config. Asynchronous because it reads
|
|
80
|
+
* the configured font files; do it once per run rather than once per image.
|
|
81
|
+
*/
|
|
82
|
+
export async function createStamper(config) {
|
|
83
|
+
const base = await configDigest(config);
|
|
84
|
+
const templateDigests = new Map();
|
|
85
|
+
// A custom template is config the project controls, so its source counts as
|
|
86
|
+
// part of the input. Built-in templates are covered by the package version.
|
|
87
|
+
// Source text is all there is to go on: a template that reads something its
|
|
88
|
+
// own code does not name — a closed-over value, a file — can change without
|
|
89
|
+
// the stamp noticing, and needs `overwrite` to pick it up.
|
|
90
|
+
const templateDigest = (name) => {
|
|
91
|
+
const cached = templateDigests.get(name);
|
|
92
|
+
if (cached !== undefined) {
|
|
93
|
+
return cached;
|
|
94
|
+
}
|
|
95
|
+
const template = config.templates[name];
|
|
96
|
+
const digest = template === undefined ? "" : sha256(template.render.toString());
|
|
97
|
+
templateDigests.set(name, digest);
|
|
98
|
+
return digest;
|
|
99
|
+
};
|
|
100
|
+
return {
|
|
101
|
+
stamp(props, size) {
|
|
102
|
+
return sha256(stableStringify([
|
|
103
|
+
base,
|
|
104
|
+
templateDigest(props.template),
|
|
105
|
+
// The whole size, not just its dimensions: a size carries its own
|
|
106
|
+
// config overrides, and changing one has to re-render that image.
|
|
107
|
+
size,
|
|
108
|
+
props,
|
|
109
|
+
]));
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* A PNG `tEXt` chunk: length, type, `keyword\0text`, CRC over type and data.
|
|
115
|
+
*/
|
|
116
|
+
function textChunk(keyword, text) {
|
|
117
|
+
const data = Buffer.concat([
|
|
118
|
+
Buffer.from(keyword, "latin1"),
|
|
119
|
+
Buffer.from([0]),
|
|
120
|
+
Buffer.from(text, "latin1"),
|
|
121
|
+
]);
|
|
122
|
+
const chunk = Buffer.alloc(4 + 4 + data.length + 4);
|
|
123
|
+
chunk.writeUInt32BE(data.length, 0);
|
|
124
|
+
chunk.write("tEXt", 4, "latin1");
|
|
125
|
+
data.copy(chunk, 8);
|
|
126
|
+
chunk.writeUInt32BE(crc32(chunk.subarray(4, 8 + data.length)), 8 + data.length);
|
|
127
|
+
return chunk;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Return `png` with the stamp embedded as a `tEXt` chunk, inserted straight
|
|
131
|
+
* after the header so it can be read back without decoding the image.
|
|
132
|
+
*/
|
|
133
|
+
export function stampPng(png, stamp) {
|
|
134
|
+
if (png.length < afterHeader ||
|
|
135
|
+
!png.subarray(0, pngSignature.length).equals(pngSignature) ||
|
|
136
|
+
png.toString("latin1", 12, 16) !== "IHDR") {
|
|
137
|
+
throw new Error("Cannot stamp: not a PNG image.");
|
|
138
|
+
}
|
|
139
|
+
return Buffer.concat([
|
|
140
|
+
png.subarray(0, afterHeader),
|
|
141
|
+
textChunk(stampKeyword, stamp),
|
|
142
|
+
png.subarray(afterHeader),
|
|
143
|
+
]);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Find the stamp in the leading bytes of a PNG, or `undefined` if there is
|
|
147
|
+
* none — the image was written by something else, or by a Colophon that did
|
|
148
|
+
* not stamp yet.
|
|
149
|
+
*/
|
|
150
|
+
function findStamp(head) {
|
|
151
|
+
if (!head.subarray(0, pngSignature.length).equals(pngSignature)) {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
let offset = pngSignature.length;
|
|
155
|
+
while (offset + 8 <= head.length) {
|
|
156
|
+
const length = head.readUInt32BE(offset);
|
|
157
|
+
const type = head.toString("latin1", offset + 4, offset + 8);
|
|
158
|
+
const start = offset + 8;
|
|
159
|
+
const end = start + length;
|
|
160
|
+
// Image data starts here; anything past it is not worth reading for a hash.
|
|
161
|
+
if (type === "IDAT" || type === "IEND" || end > head.length) {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
if (type === "tEXt") {
|
|
165
|
+
const data = head.subarray(start, end);
|
|
166
|
+
const separator = data.indexOf(0);
|
|
167
|
+
if (separator !== -1 &&
|
|
168
|
+
data.toString("latin1", 0, separator) === stampKeyword) {
|
|
169
|
+
return data.toString("latin1", separator + 1);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
offset = end + 4;
|
|
173
|
+
}
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Read the stamp out of a PNG file. Returns `undefined` when the file is
|
|
178
|
+
* missing, unreadable, not a PNG, or carries no stamp — all of which mean the
|
|
179
|
+
* image cannot be shown to be up to date, so it should be rendered again.
|
|
180
|
+
*/
|
|
181
|
+
export async function readPngStamp(file) {
|
|
182
|
+
let handle;
|
|
183
|
+
try {
|
|
184
|
+
handle = await open(file, "r");
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
const buffer = Buffer.alloc(headBytes);
|
|
191
|
+
const { bytesRead } = await handle.read(buffer, 0, headBytes, 0);
|
|
192
|
+
return findStamp(buffer.subarray(0, bytesRead));
|
|
193
|
+
}
|
|
194
|
+
finally {
|
|
195
|
+
await handle.close();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=stamp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stamp.js","sourceRoot":"","sources":["../src/stamp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ImageAsset, MeasureText, ResolvedConfig } from "../types.js";
|
|
2
|
+
import type { FooterPlacement } from "./footer.js";
|
|
3
|
+
/** Where the attribution line goes: a footer placement, plus room to lay it out. */
|
|
4
|
+
export interface AttributionPlacement extends FooterPlacement {
|
|
5
|
+
/** Left edge and width of the content area the line is set within. */
|
|
6
|
+
readonly left: number;
|
|
7
|
+
readonly width: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The footer line, with the post's avatar before it.
|
|
11
|
+
*
|
|
12
|
+
* Both belong to the same idea, which is who made this, so they are drawn as
|
|
13
|
+
* one line rather than tucked into separate corners. Without an avatar this is
|
|
14
|
+
* the footer exactly as it was, down to the byte.
|
|
15
|
+
*/
|
|
16
|
+
export declare function attribution(config: ResolvedConfig, placement: AttributionPlacement, avatar: ImageAsset | undefined, measure: MeasureText): string;
|
|
17
|
+
//# sourceMappingURL=attribution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attribution.d.ts","sourceRoot":"","sources":["../../src/templates/attribution.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAYnD,oFAAoF;AACpF,MAAM,WAAW,oBAAqB,SAAQ,eAAe;IAC3D,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,oBAAoB,EAC/B,MAAM,EAAE,UAAU,GAAG,SAAS,EAC9B,OAAO,EAAE,WAAW,GACnB,MAAM,CAqCR"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { image, measureIn, row } from "../layout/index.js";
|
|
2
|
+
import { footerElement, hasFooter } from "./footer.js";
|
|
3
|
+
/** The avatar's diameter, as a multiple of the footer's font size. */
|
|
4
|
+
const avatarScale = 1.9;
|
|
5
|
+
/** Where a circular avatar's centre sits above the footer's baseline. */
|
|
6
|
+
const avatarRise = 0.34;
|
|
7
|
+
/** Unique within one image, which is as many avatars as there are. */
|
|
8
|
+
const avatarId = "colophon-avatar";
|
|
9
|
+
/**
|
|
10
|
+
* The footer line, with the post's avatar before it.
|
|
11
|
+
*
|
|
12
|
+
* Both belong to the same idea, which is who made this, so they are drawn as
|
|
13
|
+
* one line rather than tucked into separate corners. Without an avatar this is
|
|
14
|
+
* the footer exactly as it was, down to the byte.
|
|
15
|
+
*/
|
|
16
|
+
export function attribution(config, placement, avatar, measure) {
|
|
17
|
+
if (avatar === undefined) {
|
|
18
|
+
return footerElement(config, placement);
|
|
19
|
+
}
|
|
20
|
+
const { fontSize } = placement;
|
|
21
|
+
const size = Math.round(fontSize * avatarScale);
|
|
22
|
+
const text = hasFooter(config) ? (config.footer ?? "") : "";
|
|
23
|
+
const gap = text === "" ? 0 : Math.round(fontSize * 0.5);
|
|
24
|
+
const textWidth = text === ""
|
|
25
|
+
? 0
|
|
26
|
+
: measureIn(measure, config.fontFamily, 500)(text, fontSize);
|
|
27
|
+
// Only the horizontal placement comes from the row. The baseline is the one
|
|
28
|
+
// the template asked for, so a footer with no avatar and a footer with one
|
|
29
|
+
// sit at the same height.
|
|
30
|
+
const [portrait, label] = row([{ size }, { size: Math.round(textWidth), gapBefore: gap }], { x: placement.left, y: placement.y, width: placement.width, height: size }, placement.anchor === "middle" ? "centre" : "start");
|
|
31
|
+
const top = Math.round(placement.y - fontSize * avatarRise - size / 2);
|
|
32
|
+
return (image({ x: portrait?.x ?? placement.left, y: top, width: size, height: size }, avatar.href, { fit: "cover", radius: Math.round(size / 2), id: avatarId }) +
|
|
33
|
+
footerElement(config, {
|
|
34
|
+
...placement,
|
|
35
|
+
x: label?.x ?? placement.left,
|
|
36
|
+
anchor: "start",
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=attribution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attribution.js","sourceRoot":"","sources":["../../src/templates/attribution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEvD,sEAAsE;AACtE,MAAM,WAAW,GAAG,GAAG,CAAC;AAExB,yEAAyE;AACzE,MAAM,UAAU,GAAG,IAAI,CAAC;AAExB,sEAAsE;AACtE,MAAM,QAAQ,GAAG,iBAAiB,CAAC;AASnC;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,MAAsB,EACtB,SAA+B,EAC/B,MAA8B,EAC9B,OAAoB;IAEpB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,WAAW,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5D,MAAM,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC;IACzD,MAAM,SAAS,GACb,IAAI,KAAK,EAAE;QACT,CAAC,CAAC,CAAC;QACH,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAEjE,4EAA4E;IAC5E,2EAA2E;IAC3E,0BAA0B;IAC1B,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,GAAG,CAC3B,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,EAC3D,EAAE,CAAC,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAC3E,SAAS,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CACnD,CAAC;IAEF,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,QAAQ,GAAG,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;IAEvE,OAAO,CACL,KAAK,CACH,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EACvE,MAAM,CAAC,IAAI,EACX,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAC7D;QACD,aAAa,CAAC,MAAM,EAAE;YACpB,GAAG,SAAS;YACZ,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,SAAS,CAAC,IAAI;YAC7B,MAAM,EAAE,OAAO;SAChB,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Badge } from "../../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The corner badge: a rounded plate with the badge text on it, sized from the
|
|
4
|
+
* plate height so it scales with the image rather than the text length.
|
|
5
|
+
*/
|
|
6
|
+
export declare function renderBadge(badge: Badge, fontFamily: string, brand: string, pad: number, height: number): string;
|
|
7
|
+
//# sourceMappingURL=badge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../../../src/templates/banner/badge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C;;;GAGG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,MAAM,CAoBR"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { box, textElement } from "../../layout/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* The corner badge: a rounded plate with the badge text on it, sized from the
|
|
4
|
+
* plate height so it scales with the image rather than the text length.
|
|
5
|
+
*/
|
|
6
|
+
export function renderBadge(badge, fontFamily, brand, pad, height) {
|
|
7
|
+
const fontSize = Math.round(height * 0.6);
|
|
8
|
+
const padX = Math.round(height * 0.36);
|
|
9
|
+
const width = Math.round(badge.text.length * fontSize * 0.64 + padX * 2);
|
|
10
|
+
const plate = box({ x: pad, y: pad, width, height }, { radius: Math.round(height * 0.1), fill: badge.background ?? "#ffffff" });
|
|
11
|
+
const text = textElement(badge.text, {
|
|
12
|
+
x: pad + padX,
|
|
13
|
+
y: pad + Math.round(height * 0.72),
|
|
14
|
+
fontFamily,
|
|
15
|
+
fontSize,
|
|
16
|
+
fontWeight: 900,
|
|
17
|
+
fill: badge.color ?? brand,
|
|
18
|
+
});
|
|
19
|
+
return plate + text;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=badge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"badge.js","sourceRoot":"","sources":["../../../src/templates/banner/badge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,KAAY,EACZ,UAAkB,EAClB,KAAa,EACb,GAAW,EACX,MAAc;IAEd,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;IAEzE,MAAM,KAAK,GAAG,GAAG,CACf,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,EACjC,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,UAAU,IAAI,SAAS,EAAE,CAC1E,CAAC;IAEF,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE;QACnC,CAAC,EAAE,GAAG,GAAG,IAAI;QACb,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;QAClC,UAAU;QACV,QAAQ;QACR,UAAU,EAAE,GAAG;QACf,IAAI,EAAE,KAAK,CAAC,KAAK,IAAI,KAAK;KAC3B,CAAC,CAAC;IAEH,OAAO,KAAK,GAAG,IAAI,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Template } from "../../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Generalised "banner" template: a left-aligned title with an optional
|
|
4
|
+
* version and wrapped subtitle, an optional corner badge, and an optional
|
|
5
|
+
* footer. This is the configurable descendant of the original `npm_package`
|
|
6
|
+
* layout.
|
|
7
|
+
*
|
|
8
|
+
* A logo goes in the opposite corner to the badge, which is the corner the
|
|
9
|
+
* left-aligned text leaves free, and the avatar sits with the footer.
|
|
10
|
+
*/
|
|
11
|
+
export declare const bannerTemplate: Template;
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/banner/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,gBAAgB,CAAC;AAOhE;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,EAAE,QAmF5B,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { drawLines, inset } from "../../layout/index.js";
|
|
2
|
+
import { optionalString } from "../../props.js";
|
|
3
|
+
import { attribution } from "../attribution.js";
|
|
4
|
+
import { footerBaseline, hasFooter } from "../footer.js";
|
|
5
|
+
import { logoElement, logoRect } from "../logo.js";
|
|
6
|
+
import { renderBadge } from "./badge.js";
|
|
7
|
+
import { bannerLines } from "./lines.js";
|
|
8
|
+
/**
|
|
9
|
+
* Generalised "banner" template: a left-aligned title with an optional
|
|
10
|
+
* version and wrapped subtitle, an optional corner badge, and an optional
|
|
11
|
+
* footer. This is the configurable descendant of the original `npm_package`
|
|
12
|
+
* layout.
|
|
13
|
+
*
|
|
14
|
+
* A logo goes in the opposite corner to the badge, which is the corner the
|
|
15
|
+
* left-aligned text leaves free, and the avatar sits with the footer.
|
|
16
|
+
*/
|
|
17
|
+
export const bannerTemplate = {
|
|
18
|
+
name: "banner",
|
|
19
|
+
render({ props, config, dimensions, measure, logo, avatar, }) {
|
|
20
|
+
const { width, height } = dimensions;
|
|
21
|
+
const { fontFamily } = config;
|
|
22
|
+
const pad = Math.round(width * 0.075);
|
|
23
|
+
const footerFs = Math.round(height * 0.034);
|
|
24
|
+
const badgeHeight = Math.round(height * 0.072);
|
|
25
|
+
const mark = logoRect(logo, dimensions, pad, "start");
|
|
26
|
+
const subtitle = optionalString(props.subtitle);
|
|
27
|
+
const hasSubtitle = subtitle !== undefined && subtitle !== "";
|
|
28
|
+
// The text sits between whatever the marks along the top and the footer
|
|
29
|
+
// along the bottom leave behind.
|
|
30
|
+
const topMark = Math.max(config.badge === undefined ? 0 : badgeHeight, mark?.height ?? 0);
|
|
31
|
+
const area = inset({ x: 0, y: 0, width, height }, {
|
|
32
|
+
top: pad + (topMark === 0 ? 0 : topMark + Math.round(height * 0.03)),
|
|
33
|
+
right: pad,
|
|
34
|
+
left: pad,
|
|
35
|
+
bottom: pad +
|
|
36
|
+
(hasFooter(config) || avatar !== undefined
|
|
37
|
+
? footerFs + Math.round(height * 0.02)
|
|
38
|
+
: 0),
|
|
39
|
+
});
|
|
40
|
+
const lines = bannerLines(props, {
|
|
41
|
+
height,
|
|
42
|
+
contentWidth: area.width,
|
|
43
|
+
titleFs: Math.round(height * (hasSubtitle ? 0.078 : 0.092)),
|
|
44
|
+
versionFs: Math.round(height * 0.04),
|
|
45
|
+
subFs: Math.round(height * 0.05),
|
|
46
|
+
measure,
|
|
47
|
+
fontFamily,
|
|
48
|
+
});
|
|
49
|
+
const body = drawLines(lines, area, {
|
|
50
|
+
fontFamily,
|
|
51
|
+
fill: config.colors.foreground,
|
|
52
|
+
lineHeight: 1.28,
|
|
53
|
+
});
|
|
54
|
+
const badge = config.badge === undefined
|
|
55
|
+
? ""
|
|
56
|
+
: renderBadge(config.badge, fontFamily, config.colors.brand, pad, badgeHeight);
|
|
57
|
+
const footer = attribution(config, {
|
|
58
|
+
x: pad,
|
|
59
|
+
y: footerBaseline(height, pad, footerFs),
|
|
60
|
+
fontSize: footerFs,
|
|
61
|
+
opacity: 0.78,
|
|
62
|
+
left: pad,
|
|
63
|
+
width: width - pad * 2,
|
|
64
|
+
}, avatar, measure);
|
|
65
|
+
return badge + logoElement(logo, mark) + body + footer;
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/banner/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { MeasureText, MetaImageProps } from "../../types.js";
|
|
2
|
+
import type { TextLine } from "../../layout/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* The font sizes the banner's text is drawn at, all keyed to image height,
|
|
5
|
+
* along with the space it has and how to measure text into it.
|
|
6
|
+
*/
|
|
7
|
+
export interface BannerSizes {
|
|
8
|
+
readonly height: number;
|
|
9
|
+
readonly contentWidth: number;
|
|
10
|
+
readonly titleFs: number;
|
|
11
|
+
readonly versionFs: number;
|
|
12
|
+
readonly subFs: number;
|
|
13
|
+
readonly measure: MeasureText;
|
|
14
|
+
readonly fontFamily: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The banner's text block: the wrapped title, an optional version, and the
|
|
18
|
+
* wrapped subtitle. Extra breathing room goes before the version and subtitle
|
|
19
|
+
* groups so the three do not read as one squashed block.
|
|
20
|
+
*/
|
|
21
|
+
export declare function bannerLines(props: MetaImageProps, sizes: BannerSizes): TextLine[];
|
|
22
|
+
//# sourceMappingURL=lines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lines.d.ts","sourceRoot":"","sources":["../../../src/templates/banner/lines.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAStD;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,cAAc,EACrB,KAAK,EAAE,WAAW,GACjB,QAAQ,EAAE,CAuBZ"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { blockLines } from "../../layout/index.js";
|
|
2
|
+
import { versionLines } from "./version.js";
|
|
3
|
+
const maxTitleLines = 3;
|
|
4
|
+
const maxSubtitleLines = 4;
|
|
5
|
+
const titleFloor = 0.62;
|
|
6
|
+
const subtitleFloor = 0.8;
|
|
7
|
+
/**
|
|
8
|
+
* The banner's text block: the wrapped title, an optional version, and the
|
|
9
|
+
* wrapped subtitle. Extra breathing room goes before the version and subtitle
|
|
10
|
+
* groups so the three do not read as one squashed block.
|
|
11
|
+
*/
|
|
12
|
+
export function bannerLines(props, sizes) {
|
|
13
|
+
const { height, contentWidth, measure, fontFamily } = sizes;
|
|
14
|
+
return [
|
|
15
|
+
...blockLines(props.title, measure, fontFamily, {
|
|
16
|
+
maxWidth: contentWidth,
|
|
17
|
+
maxLines: maxTitleLines,
|
|
18
|
+
fontSize: sizes.titleFs,
|
|
19
|
+
floor: titleFloor,
|
|
20
|
+
fontWeight: 800,
|
|
21
|
+
opacity: 0.98,
|
|
22
|
+
}),
|
|
23
|
+
...versionLines(props, sizes),
|
|
24
|
+
...blockLines(props.subtitle, measure, fontFamily, {
|
|
25
|
+
maxWidth: contentWidth,
|
|
26
|
+
maxLines: maxSubtitleLines,
|
|
27
|
+
fontSize: sizes.subFs,
|
|
28
|
+
floor: subtitleFloor,
|
|
29
|
+
fontWeight: 500,
|
|
30
|
+
opacity: 0.86,
|
|
31
|
+
gapBefore: Math.round(height * 0.045),
|
|
32
|
+
}),
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=lines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lines.js","sourceRoot":"","sources":["../../../src/templates/banner/lines.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,aAAa,GAAG,CAAC,CAAC;AACxB,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAC3B,MAAM,UAAU,GAAG,IAAI,CAAC;AACxB,MAAM,aAAa,GAAG,GAAG,CAAC;AAgB1B;;;;GAIG;AACH,MAAM,UAAU,WAAW,CACzB,KAAqB,EACrB,KAAkB;IAElB,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC;IAE5D,OAAO;QACL,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE;YAC9C,QAAQ,EAAE,YAAY;YACtB,QAAQ,EAAE,aAAa;YACvB,QAAQ,EAAE,KAAK,CAAC,OAAO;YACvB,KAAK,EAAE,UAAU;YACjB,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,IAAI;SACd,CAAC;QACF,GAAG,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC;QAC7B,GAAG,UAAU,CAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE;YACjD,QAAQ,EAAE,YAAY;YACtB,QAAQ,EAAE,gBAAgB;YAC1B,QAAQ,EAAE,KAAK,CAAC,KAAK;YACrB,KAAK,EAAE,aAAa;YACpB,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;SACtC,CAAC;KACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { MetaImageProps } from "../../types.js";
|
|
2
|
+
import type { TextLine } from "../../layout/index.js";
|
|
3
|
+
import type { BannerSizes } from "./lines.js";
|
|
4
|
+
/**
|
|
5
|
+
* The version line, or nothing where there is no version. It is never wrapped
|
|
6
|
+
* or shrunk: a version string that needed either would not be one.
|
|
7
|
+
*/
|
|
8
|
+
export declare function versionLines(props: MetaImageProps, sizes: BannerSizes): readonly TextLine[];
|
|
9
|
+
//# sourceMappingURL=version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/templates/banner/version.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,cAAc,EACrB,KAAK,EAAE,WAAW,GACjB,SAAS,QAAQ,EAAE,CAgBrB"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { optionalString } from "../../props.js";
|
|
2
|
+
/**
|
|
3
|
+
* The version line, or nothing where there is no version. It is never wrapped
|
|
4
|
+
* or shrunk: a version string that needed either would not be one.
|
|
5
|
+
*/
|
|
6
|
+
export function versionLines(props, sizes) {
|
|
7
|
+
const version = optionalString(props.version);
|
|
8
|
+
if (version === undefined || version === "") {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
return [
|
|
12
|
+
{
|
|
13
|
+
text: `v${version}`,
|
|
14
|
+
fontSize: sizes.versionFs,
|
|
15
|
+
fontWeight: 700,
|
|
16
|
+
opacity: 0.85,
|
|
17
|
+
gapBefore: Math.round(sizes.height * 0.03),
|
|
18
|
+
},
|
|
19
|
+
];
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/templates/banner/version.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAIhD;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAqB,EACrB,KAAkB;IAElB,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAE9C,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;QAC5C,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO;QACL;YACE,IAAI,EAAE,IAAI,OAAO,EAAE;YACnB,QAAQ,EAAE,KAAK,CAAC,SAAS;YACzB,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;SAC3C;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Template } from "../../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Minimal "card" template: a centred title with an optional subtitle. No
|
|
4
|
+
* badge or version, so it is a quieter alternative to `banner`.
|
|
5
|
+
*
|
|
6
|
+
* A logo goes above the title, centred like everything else here, and the
|
|
7
|
+
* avatar sits with the footer along the bottom.
|
|
8
|
+
*/
|
|
9
|
+
export declare const cardTemplate: Template;
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/card/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,gBAAgB,CAAC;AAMhE;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,EAAE,QA8D1B,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { drawLines, inset } from "../../layout/index.js";
|
|
2
|
+
import { attribution } from "../attribution.js";
|
|
3
|
+
import { footerBaseline, hasFooter } from "../footer.js";
|
|
4
|
+
import { logoElement, logoRect } from "../logo.js";
|
|
5
|
+
import { cardLines } from "./lines.js";
|
|
6
|
+
/**
|
|
7
|
+
* Minimal "card" template: a centred title with an optional subtitle. No
|
|
8
|
+
* badge or version, so it is a quieter alternative to `banner`.
|
|
9
|
+
*
|
|
10
|
+
* A logo goes above the title, centred like everything else here, and the
|
|
11
|
+
* avatar sits with the footer along the bottom.
|
|
12
|
+
*/
|
|
13
|
+
export const cardTemplate = {
|
|
14
|
+
name: "card",
|
|
15
|
+
render({ props, config, dimensions, measure, logo, avatar, }) {
|
|
16
|
+
const { width, height } = dimensions;
|
|
17
|
+
const pad = Math.round(width * 0.09);
|
|
18
|
+
const footerFs = Math.round(height * 0.032);
|
|
19
|
+
const mark = logoRect(logo, dimensions, pad, "middle");
|
|
20
|
+
const area = inset({ x: 0, y: 0, width, height }, {
|
|
21
|
+
top: pad + (mark === undefined ? 0 : mark.height + pad / 2),
|
|
22
|
+
right: pad,
|
|
23
|
+
left: pad,
|
|
24
|
+
bottom: pad +
|
|
25
|
+
(hasFooter(config) || avatar !== undefined
|
|
26
|
+
? footerFs + Math.round(height * 0.02)
|
|
27
|
+
: 0),
|
|
28
|
+
});
|
|
29
|
+
const lines = cardLines(props, {
|
|
30
|
+
measure,
|
|
31
|
+
fontFamily: config.fontFamily,
|
|
32
|
+
contentWidth: area.width,
|
|
33
|
+
titleFs: Math.round(height * 0.1),
|
|
34
|
+
subFs: Math.round(height * 0.045),
|
|
35
|
+
height,
|
|
36
|
+
});
|
|
37
|
+
const body = drawLines(lines, area, {
|
|
38
|
+
fontFamily: config.fontFamily,
|
|
39
|
+
fill: config.colors.foreground,
|
|
40
|
+
lineHeight: 1.28,
|
|
41
|
+
anchor: "middle",
|
|
42
|
+
});
|
|
43
|
+
const footer = attribution(config, {
|
|
44
|
+
x: Math.round(width / 2),
|
|
45
|
+
y: footerBaseline(height, pad, footerFs),
|
|
46
|
+
fontSize: footerFs,
|
|
47
|
+
opacity: 0.75,
|
|
48
|
+
anchor: "middle",
|
|
49
|
+
left: pad,
|
|
50
|
+
width: width - pad * 2,
|
|
51
|
+
}, avatar, measure);
|
|
52
|
+
return logoElement(logo, mark) + body + footer;
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/card/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAa;IACpC,IAAI,EAAE,MAAM;IACZ,MAAM,CAAC,EACL,KAAK,EACL,MAAM,EACN,UAAU,EACV,OAAO,EACP,IAAI,EACJ,MAAM,GACU;QAChB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;QAC5C,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;QAEvD,MAAM,IAAI,GAAG,KAAK,CAChB,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAC7B;YACE,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC;YAC3D,KAAK,EAAE,GAAG;YACV,IAAI,EAAE,GAAG;YACT,MAAM,EACJ,GAAG;gBACH,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,KAAK,SAAS;oBACxC,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;oBACtC,CAAC,CAAC,CAAC,CAAC;SACT,CACF,CAAC;QAEF,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,EAAE;YAC7B,OAAO;YACP,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,YAAY,EAAE,IAAI,CAAC,KAAK;YACxB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC;YACjC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;YACjC,MAAM;SACP,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE;YAClC,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU;YAC9B,UAAU,EAAE,IAAI;YAChB,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,WAAW,CACxB,MAAM,EACN;YACE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;YACxB,CAAC,EAAE,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC;YACxC,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,QAAQ;YAChB,IAAI,EAAE,GAAG;YACT,KAAK,EAAE,KAAK,GAAG,GAAG,GAAG,CAAC;SACvB,EACD,MAAM,EACN,OAAO,CACR,CAAC;QAEF,OAAO,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,IAAI,GAAG,MAAM,CAAC;IACjD,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { MeasureText, MetaImageProps } from "../../types.js";
|
|
2
|
+
import type { TextLine } from "../../layout/index.js";
|
|
3
|
+
/** The space the card's text has, and how to measure text into it. */
|
|
4
|
+
export interface CardText {
|
|
5
|
+
readonly measure: MeasureText;
|
|
6
|
+
readonly fontFamily: string;
|
|
7
|
+
readonly contentWidth: number;
|
|
8
|
+
readonly titleFs: number;
|
|
9
|
+
readonly subFs: number;
|
|
10
|
+
readonly height: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The card's text block: the wrapped title, then the wrapped subtitle.
|
|
14
|
+
*
|
|
15
|
+
* The gap before the subtitle is smaller than the banner's, because the card
|
|
16
|
+
* has only the two groups and they belong together. It is not nothing, though:
|
|
17
|
+
* a title that wraps ends on a line the subtitle would otherwise sit straight
|
|
18
|
+
* underneath, and the change of size and weight alone does not separate them.
|
|
19
|
+
*/
|
|
20
|
+
export declare function cardLines(props: MetaImageProps, text: CardText): TextLine[];
|
|
21
|
+
//# sourceMappingURL=lines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lines.d.ts","sourceRoot":"","sources":["../../../src/templates/card/lines.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAQtD,sEAAsE;AACtE,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,EAAE,CAsB3E"}
|