@lettercamp/cli 0.1.7 → 0.1.9
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/account.js +20 -8
- package/dist/build.js +22 -5
- package/dist/cli.js +15 -6
- package/dist/code-block.js +50 -0
- package/dist/code-detection.js +24 -0
- package/dist/code-highlight.js +54 -0
- package/dist/component-blocks.js +32 -0
- package/dist/custom-layout.js +32 -0
- package/dist/deploy.js +131 -0
- package/dist/dev.js +28 -10
- package/dist/domain.js +190 -0
- package/dist/hosting.js +132 -0
- package/dist/lettercamp.js +1 -4
- package/dist/media-dimensions.js +154 -0
- package/dist/new.js +1 -1
- package/dist/preview.js +1 -1
- package/dist/prompts.js +31 -0
- package/dist/publication-links.js +23 -0
- package/dist/react.js +15 -0
- package/dist/upload.js +40 -10
- package/dist/workspace.js +5 -3
- package/package.json +11 -2
- package/renderer/src/components/AuthorByline.astro +20 -11
- package/renderer/src/components/BlogHome.astro +14 -57
- package/renderer/src/components/Footer.astro +12 -9
- package/renderer/src/components/Header.astro +38 -0
- package/renderer/src/components/MobileMenuIcons.astro +7 -0
- package/renderer/src/components/PostCard.astro +12 -5
- package/renderer/src/components/SocialLink.astro +4 -4
- package/renderer/src/layouts/SiteLayout.astro +70 -51
- package/renderer/src/lib/analytics.ts +21 -0
- package/renderer/src/lib/author-dialog.ts +102 -0
- package/renderer/src/lib/authors.js +18 -0
- package/renderer/src/lib/block-widths.ts +35 -0
- package/renderer/src/lib/branding.js +15 -0
- package/renderer/src/lib/button.js +10 -0
- package/renderer/src/lib/category-routes.js +19 -0
- package/renderer/src/lib/code-block.ts +46 -0
- package/renderer/src/lib/font-fallbacks.js +196 -0
- package/renderer/src/lib/fonts.js +48 -0
- package/renderer/src/lib/home-layout.ts +5 -0
- package/renderer/src/lib/image-radius.ts +5 -0
- package/renderer/src/lib/image-rounding.ts +28 -0
- package/renderer/src/lib/image-widths.ts +13 -0
- package/renderer/src/lib/metadata.js +47 -0
- package/renderer/src/lib/mobile-navigation.ts +76 -0
- package/renderer/src/lib/post-layout.ts +6 -0
- package/renderer/src/lib/post-share.ts +264 -0
- package/renderer/src/lib/post-toc.ts +69 -0
- package/renderer/src/lib/posts.js +14 -6
- package/renderer/src/lib/publication-url.js +14 -0
- package/renderer/src/lib/table-styles.ts +12 -0
- package/renderer/src/lib/urls.js +3 -0
- package/renderer/src/pages/[...slug].astro +21 -11
- package/renderer/src/pages/category/[tag].astro +16 -0
- package/renderer/src/pages/category/index.astro +4 -0
- package/renderer/src/pages/index.astro +1 -1
- package/renderer/src/styles/post-share.css +57 -0
- package/renderer/src/styles/site.css +261 -91
- package/dist/public-assets.js +0 -29
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Generated from lettercamp/lib/authors.ts.
|
|
2
|
+
export function readAuthors(value) {
|
|
3
|
+
if (!Array.isArray(value))
|
|
4
|
+
return [];
|
|
5
|
+
return value.flatMap(item => item && typeof item.name === "string"
|
|
6
|
+
? [{ name: item.name, ...(typeof item.image === "string" ? { image: item.image } : {}) }] : []);
|
|
7
|
+
}
|
|
8
|
+
// Keep blank names while editing; only bylines omit unfinished author rows.
|
|
9
|
+
export function resolveAuthors(source) {
|
|
10
|
+
return readAuthors(source.authors);
|
|
11
|
+
}
|
|
12
|
+
// Names alone are not identities: two contributors can share a name.
|
|
13
|
+
export function authorKey(author) {
|
|
14
|
+
return JSON.stringify([author.name.trim().toLowerCase(), author.image || ""]);
|
|
15
|
+
}
|
|
16
|
+
export function uniqueAuthors(authors) {
|
|
17
|
+
return [...new Map(authors.filter(author => author.name.trim()).map(author => [authorKey(author), author])).values()];
|
|
18
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Generated from lettercamp/lib/block-widths.ts.
|
|
2
|
+
// One sizing contract for editor surfaces and published body blocks.
|
|
3
|
+
const blocks = ':is(.publication-post .prose > table, [data-lettercamp-table], [data-lettercamp-code][data-code-width], [data-block-width], .publication-post .prose :is(img, video)[data-image-width]:not([width]), .publication-post .prose :is(img, video):is([data-image-width="wide"], [data-image-width="full"]))';
|
|
4
|
+
const wide = ':is([data-table-width="wide"], [data-code-width="wide"], [data-block-width="wide"], [data-image-width="wide"])';
|
|
5
|
+
const full = ':is([data-table-width="full"], [data-code-width="full"], [data-block-width="full"], [data-image-width="full"])';
|
|
6
|
+
|
|
7
|
+
export const blockWidthStyles = `
|
|
8
|
+
.publication-post { container-type: inline-size; }
|
|
9
|
+
.publication-post .prose [data-lettercamp-component] { display: grid; grid-template-columns: minmax(0, 1fr); }
|
|
10
|
+
.publication-post .prose [data-lettercamp-component] > :not(style, script),
|
|
11
|
+
.publication-post .prose [data-lettercamp-component] > astro-island > :not(style, script) {
|
|
12
|
+
box-sizing: border-box; width: 100%; max-width: 100%; min-width: 0;
|
|
13
|
+
}
|
|
14
|
+
${blocks} {
|
|
15
|
+
--block-normal-width: 100%;
|
|
16
|
+
--block-display-width: var(--block-normal-width);
|
|
17
|
+
box-sizing: border-box; width: var(--block-display-width); max-width: var(--block-normal-width); margin-inline: auto;
|
|
18
|
+
}
|
|
19
|
+
${blocks}${wide} {
|
|
20
|
+
--block-display-width: max(var(--block-normal-width), min(calc(var(--block-normal-width) + 128px), var(--block-available-width, 100cqw)));
|
|
21
|
+
max-width: none; margin-inline: calc((100% - var(--block-display-width)) / 2);
|
|
22
|
+
margin-left: calc((100% - var(--block-display-width)) / 2 + min(0px, (var(--block-available-width, 100cqw) - var(--block-display-width)) / 2 - var(--block-column-offset, 0px)));
|
|
23
|
+
}
|
|
24
|
+
${blocks}${full} {
|
|
25
|
+
--block-display-width: max(var(--block-normal-width), var(--block-available-width, 100cqw));
|
|
26
|
+
max-width: none; margin-inline: calc((100% - var(--block-display-width)) / 2);
|
|
27
|
+
margin-left: calc((100% - var(--block-display-width)) / 2 - var(--block-column-offset, 0px));
|
|
28
|
+
}
|
|
29
|
+
/* The two-column TOC layout shifts the reading column 106px from center. */
|
|
30
|
+
@media (min-width: 761px) and (max-width: 1199px) {
|
|
31
|
+
.publication-post[data-post-hero="split"][data-post-toc="visible"] .article-body-with-toc .prose {
|
|
32
|
+
--block-column-offset: 106px;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const defaultSiteBranding = {
|
|
2
|
+
name: 'Lettercamp Blog',
|
|
3
|
+
logo: 'https://lettercamp.com/lettercamp-logo.png?v=7',
|
|
4
|
+
favicon: 'https://lettercamp.com/favicon-96x96.png?v=7',
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export function withDefaultBranding(source) {
|
|
8
|
+
const branding = Object.fromEntries(Object.entries(defaultSiteBranding).map(([key, fallback]) =>
|
|
9
|
+
[key, typeof source[key] === 'string' && source[key].trim() ? source[key] : fallback]));
|
|
10
|
+
return {
|
|
11
|
+
...source,
|
|
12
|
+
...branding,
|
|
13
|
+
home: { ...source.home, title: source.home?.title ?? (branding.name === defaultSiteBranding.name ? branding.name : `${branding.name} Blog`) },
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Keep the color fallback and contrast calculation aligned with the editor preview.
|
|
2
|
+
export function buttonColors(value) {
|
|
3
|
+
const background = typeof value === 'string' && /^#[0-9a-f]{6}$/i.test(value) ? value : '#111111';
|
|
4
|
+
const channels = [1, 3, 5].map(offset => {
|
|
5
|
+
const channel = parseInt(background.slice(offset, offset + 2), 16) / 255;
|
|
6
|
+
return channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4;
|
|
7
|
+
});
|
|
8
|
+
const luminance = channels[0] * 0.2126 + channels[1] * 0.7152 + channels[2] * 0.0722;
|
|
9
|
+
return { background, text: luminance > 0.179 ? '#000000' : '#ffffff' };
|
|
10
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Generated from lettercamp/lib/category-routes.ts.
|
|
2
|
+
export function categoryTag(category) {
|
|
3
|
+
return category.trim().normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu, "-").replace(/^-+|-+$/g, "") || "category";
|
|
4
|
+
}
|
|
5
|
+
export function categoryRoutes(categories) {
|
|
6
|
+
const names = [...new Set(categories.map(name => name.trim()).filter(Boolean))];
|
|
7
|
+
const used = new Set();
|
|
8
|
+
const tags = new Map();
|
|
9
|
+
// Assign unique tags independently of the posts' date order.
|
|
10
|
+
for (const name of [...names].sort()) {
|
|
11
|
+
const base = categoryTag(name);
|
|
12
|
+
let tag = base;
|
|
13
|
+
for (let suffix = 2; used.has(tag); suffix++)
|
|
14
|
+
tag = `${base}-${suffix}`;
|
|
15
|
+
used.add(tag);
|
|
16
|
+
tags.set(name, tag);
|
|
17
|
+
}
|
|
18
|
+
return names.map(name => ({ name, tag: tags.get(name), href: `/category/${encodeURIComponent(tags.get(name))}/` }));
|
|
19
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Generated from lettercamp/lib/code-block.ts.
|
|
2
|
+
export const codeThemes = { classic: "Classic", ocean: "Ocean", forest: "Forest", mono: "Monochrome" } as const;
|
|
3
|
+
export type CodeBlockSettings = { width: "regular" | "wide" | "full"; wrap: boolean; theme: keyof typeof codeThemes; caption: string };
|
|
4
|
+
const settingPattern = /(?:^|\s)lc-(width|wrap|theme|caption)=([^\s]*)/g;
|
|
5
|
+
|
|
6
|
+
export function readCodeSettings(meta = ""): CodeBlockSettings {
|
|
7
|
+
const settings: CodeBlockSettings = { width: "regular", wrap: true, theme: "classic", caption: "" };
|
|
8
|
+
for (const match of meta.matchAll(settingPattern)) {
|
|
9
|
+
const [, key, value] = match;
|
|
10
|
+
if (key === "width" && (value === "regular" || value === "wide" || value === "full")) settings.width = value;
|
|
11
|
+
if (key === "theme" && Object.hasOwn(codeThemes, value)) settings.theme = value as CodeBlockSettings["theme"];
|
|
12
|
+
if (key === "wrap") settings.wrap = value !== "false";
|
|
13
|
+
if (key === "caption") { try { settings.caption = decodeURIComponent(value); } catch { /* Keep malformed source editable. */ } }
|
|
14
|
+
}
|
|
15
|
+
return settings;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function writeCodeSettings(meta: string, patch: Partial<CodeBlockSettings>) {
|
|
19
|
+
const settings = { ...readCodeSettings(meta), ...patch };
|
|
20
|
+
return [meta.replace(settingPattern, "").trim(), `lc-width=${settings.width}`, `lc-wrap=${settings.wrap}`, `lc-theme=${settings.theme}`,
|
|
21
|
+
...(settings.caption ? [`lc-caption=${encodeURIComponent(settings.caption)}`] : [])].filter(Boolean).join(" ");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// The editor and both publication renderers use the same token classes and palette.
|
|
25
|
+
export const codeBlockStyles = `
|
|
26
|
+
[data-lettercamp-code] { --code-keyword: #8250a0; --code-string: #3d7757; --code-number: #a15c32; --code-name: #326b99; --code-comment: #93939b; color: #414146; }
|
|
27
|
+
[data-lettercamp-code][data-code-width] { margin-block: 24px; }
|
|
28
|
+
[data-lettercamp-code][data-code-theme="ocean"] { --code-keyword: #3d62a8; --code-string: #277c85; --code-number: #98623e; --code-name: #6961a4; }
|
|
29
|
+
[data-lettercamp-code][data-code-theme="forest"] { --code-keyword: #47724a; --code-string: #827030; --code-number: #a25d47; --code-name: #3c7b79; }
|
|
30
|
+
[data-lettercamp-code][data-code-theme="mono"] { --code-keyword: #45454a; --code-string: #62626a; --code-number: #62626a; --code-name: #45454a; }
|
|
31
|
+
[data-lettercamp-code] .tok-keyword, [data-lettercamp-code] .tok-operator { color: var(--code-keyword); }
|
|
32
|
+
[data-lettercamp-code] .tok-string, [data-lettercamp-code] .tok-string2, [data-lettercamp-code] .tok-inserted { color: var(--code-string); }
|
|
33
|
+
[data-lettercamp-code] .tok-number, [data-lettercamp-code] .tok-bool, [data-lettercamp-code] .tok-atom, [data-lettercamp-code] .tok-literal { color: var(--code-number); }
|
|
34
|
+
[data-lettercamp-code] .tok-typeName, [data-lettercamp-code] .tok-className, [data-lettercamp-code] .tok-propertyName, [data-lettercamp-code] .tok-definition, [data-lettercamp-code] .tok-variableName2, [data-lettercamp-code] .tok-labelName { color: var(--code-name); }
|
|
35
|
+
[data-lettercamp-code] .tok-comment, [data-lettercamp-code] .tok-meta { color: var(--code-comment); }
|
|
36
|
+
[data-lettercamp-code] .tok-invalid, [data-lettercamp-code] .tok-deleted { color: #aa4747; }
|
|
37
|
+
[data-lettercamp-code] .tok-strong { font-weight: 600; }
|
|
38
|
+
[data-lettercamp-code] .tok-emphasis { font-style: italic; }
|
|
39
|
+
figure[data-lettercamp-code] > pre { box-sizing: border-box; margin: 0; padding: 16px 0; overflow-x: auto; border-radius: 8px; background: #fafafa; color: #414146; font: 13px/1.7 ui-monospace, SFMono-Regular, Menlo, monospace; tab-size: 4; }
|
|
40
|
+
figure[data-lettercamp-code] > pre > code { display: block; width: max-content; min-width: 100%; padding: 0; background: transparent; color: inherit; font: inherit; white-space: normal; counter-reset: code-line; }
|
|
41
|
+
[data-lettercamp-code] .code-line { position: relative; display: block; box-sizing: border-box; min-height: 1.7em; padding: 0 18px 0 calc(var(--code-gutter, 3ch) + 24px); white-space: pre; }
|
|
42
|
+
[data-lettercamp-code] .code-line::before { position: absolute; left: 8px; width: var(--code-gutter, 3ch); text-align: right; content: counter(code-line); counter-increment: code-line; color: #b4b4bc; user-select: none; font-variant-numeric: tabular-nums; }
|
|
43
|
+
[data-lettercamp-code][data-code-wrap="true"] > pre > code { width: 100%; }
|
|
44
|
+
[data-lettercamp-code][data-code-wrap="true"] .code-line { white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
45
|
+
figure[data-lettercamp-code] > figcaption { margin: 8px 0 0; color: #888; font: 13px/1.5 var(--font-family, inherit); text-align: center; overflow-wrap: anywhere; }
|
|
46
|
+
`;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// Generated from lettercamp/lib/font-fallbacks.ts.
|
|
2
|
+
export const fontFallbacks = {
|
|
3
|
+
"Inter": { generic: "sans-serif", faces: [
|
|
4
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "107.1194%", "ascentOverride": "90.4365%", "descentOverride": "22.5180%", "lineGapOverride": "0.0000%" },
|
|
5
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "108.2147%", "ascentOverride": "89.5211%", "descentOverride": "22.2900%", "lineGapOverride": "0.0000%" },
|
|
6
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "101.5259%", "ascentOverride": "95.4190%", "descentOverride": "23.7586%", "lineGapOverride": "0.0000%" },
|
|
7
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "102.5432%", "ascentOverride": "94.4723%", "descentOverride": "23.5229%", "lineGapOverride": "0.0000%" },
|
|
8
|
+
] },
|
|
9
|
+
"Geist": { generic: "sans-serif", faces: [
|
|
10
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "104.7553%", "ascentOverride": "95.9379%", "descentOverride": "28.1609%", "lineGapOverride": "0.0000%" },
|
|
11
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "107.2228%", "ascentOverride": "93.7301%", "descentOverride": "27.5128%", "lineGapOverride": "0.0000%" },
|
|
12
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "101.8791%", "ascentOverride": "98.6463%", "descentOverride": "28.9559%", "lineGapOverride": "0.0000%" },
|
|
13
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "103.9626%", "ascentOverride": "96.6694%", "descentOverride": "28.3756%", "lineGapOverride": "0.0000%" },
|
|
14
|
+
] },
|
|
15
|
+
"Lora": { generic: "serif", faces: [
|
|
16
|
+
{ "weight": 400, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "115.2000%", "ascentOverride": "87.3264%", "descentOverride": "23.7847%", "lineGapOverride": "0.0000%" },
|
|
17
|
+
{ "weight": 500, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "116.4308%", "ascentOverride": "86.4033%", "descentOverride": "23.5333%", "lineGapOverride": "0.0000%" },
|
|
18
|
+
{ "weight": 600, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "110.4903%", "ascentOverride": "91.0487%", "descentOverride": "24.7986%", "lineGapOverride": "0.0000%" },
|
|
19
|
+
{ "weight": 700, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "111.4149%", "ascentOverride": "90.2931%", "descentOverride": "24.5928%", "lineGapOverride": "0.0000%" },
|
|
20
|
+
] },
|
|
21
|
+
"Merriweather": { generic: "serif", faces: [
|
|
22
|
+
{ "weight": 400, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "119.3846%", "ascentOverride": "82.4227%", "descentOverride": "22.8673%", "lineGapOverride": "0.0000%" },
|
|
23
|
+
{ "weight": 500, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "119.8769%", "ascentOverride": "82.0842%", "descentOverride": "22.7734%", "lineGapOverride": "0.0000%" },
|
|
24
|
+
{ "weight": 600, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "113.3797%", "ascentOverride": "86.7880%", "descentOverride": "24.0784%", "lineGapOverride": "0.0000%" },
|
|
25
|
+
{ "weight": 700, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "115.3445%", "ascentOverride": "85.3097%", "descentOverride": "23.6682%", "lineGapOverride": "0.0000%" },
|
|
26
|
+
] },
|
|
27
|
+
"Open Sans": { generic: "sans-serif", faces: [
|
|
28
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "105.1479%", "ascentOverride": "101.6519%", "descentOverride": "27.8625%", "lineGapOverride": "0.0000%" },
|
|
29
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "107.1194%", "ascentOverride": "99.7810%", "descentOverride": "27.3497%", "lineGapOverride": "0.0000%" },
|
|
30
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "101.2208%", "ascentOverride": "105.5957%", "descentOverride": "28.9435%", "lineGapOverride": "0.0000%" },
|
|
31
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "104.7813%", "ascentOverride": "102.0075%", "descentOverride": "27.9600%", "lineGapOverride": "0.0000%" },
|
|
32
|
+
] },
|
|
33
|
+
"Playfair Display": { generic: "serif", faces: [
|
|
34
|
+
{ "weight": 400, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "111.2615%", "ascentOverride": "97.2483%", "descentOverride": "22.5595%", "lineGapOverride": "0.0000%" },
|
|
35
|
+
{ "weight": 500, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "112.2462%", "ascentOverride": "96.3953%", "descentOverride": "22.3616%", "lineGapOverride": "0.0000%" },
|
|
36
|
+
{ "weight": 600, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "106.0984%", "ascentOverride": "101.9808%", "descentOverride": "23.6573%", "lineGapOverride": "0.0000%" },
|
|
37
|
+
{ "weight": 700, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "107.0230%", "ascentOverride": "101.0997%", "descentOverride": "23.4529%", "lineGapOverride": "0.0000%" },
|
|
38
|
+
] },
|
|
39
|
+
"Roboto": { generic: "sans-serif", faces: [
|
|
40
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "99.7809%", "ascentOverride": "92.9771%", "descentOverride": "24.4677%", "lineGapOverride": "0.0000%" },
|
|
41
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "100.6572%", "ascentOverride": "92.1677%", "descentOverride": "24.2547%", "lineGapOverride": "0.0000%" },
|
|
42
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "93.8962%", "ascentOverride": "98.8042%", "descentOverride": "26.0011%", "lineGapOverride": "0.0000%" },
|
|
43
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "94.2014%", "ascentOverride": "98.4841%", "descentOverride": "25.9169%", "lineGapOverride": "0.0000%" },
|
|
44
|
+
] },
|
|
45
|
+
"Libre Baskerville": { generic: "serif", faces: [
|
|
46
|
+
{ "weight": 400, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "127.2615%", "ascentOverride": "76.2210%", "descentOverride": "21.2162%", "lineGapOverride": "0.0000%" },
|
|
47
|
+
{ "weight": 500, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "128.7385%", "ascentOverride": "75.3466%", "descentOverride": "20.9728%", "lineGapOverride": "0.0000%" },
|
|
48
|
+
{ "weight": 600, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "121.5856%", "ascentOverride": "79.7792%", "descentOverride": "22.2066%", "lineGapOverride": "0.0000%" },
|
|
49
|
+
{ "weight": 700, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "122.5102%", "ascentOverride": "79.1771%", "descentOverride": "22.0390%", "lineGapOverride": "0.0000%" },
|
|
50
|
+
] },
|
|
51
|
+
"Lato": { generic: "sans-serif", faces: [
|
|
52
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "97.6894%", "ascentOverride": "101.0345%", "descentOverride": "21.8038%", "lineGapOverride": "0.0000%" },
|
|
53
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "92.8163%", "ascentOverride": "106.3391%", "descentOverride": "22.9486%", "lineGapOverride": "0.0000%" },
|
|
54
|
+
] },
|
|
55
|
+
"Source Serif 4": { generic: "serif", faces: [
|
|
56
|
+
{ "weight": 400, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "117.9077%", "ascentOverride": "87.8653%", "descentOverride": "28.4121%", "lineGapOverride": "0.0000%" },
|
|
57
|
+
{ "weight": 500, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "118.6462%", "ascentOverride": "87.3185%", "descentOverride": "28.2352%", "lineGapOverride": "0.0000%" },
|
|
58
|
+
{ "weight": 600, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "112.3395%", "ascentOverride": "92.2205%", "descentOverride": "29.8203%", "lineGapOverride": "0.0000%" },
|
|
59
|
+
{ "weight": 700, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "114.1887%", "ascentOverride": "90.7270%", "descentOverride": "29.3374%", "lineGapOverride": "0.0000%" },
|
|
60
|
+
] },
|
|
61
|
+
"Source Sans 3": { generic: "sans-serif", faces: [
|
|
62
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "93.7639%", "ascentOverride": "109.2105%", "descentOverride": "42.6604%", "lineGapOverride": "0.0000%" },
|
|
63
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "95.1097%", "ascentOverride": "107.6651%", "descentOverride": "42.0567%", "lineGapOverride": "0.0000%" },
|
|
64
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "89.7953%", "ascentOverride": "114.0371%", "descentOverride": "44.5458%", "lineGapOverride": "0.0000%" },
|
|
65
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "92.2954%", "ascentOverride": "110.9481%", "descentOverride": "43.3391%", "lineGapOverride": "0.0000%" },
|
|
66
|
+
] },
|
|
67
|
+
"Montserrat": { generic: "sans-serif", faces: [
|
|
68
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "112.8307%", "ascentOverride": "85.7923%", "descentOverride": "22.2457%", "lineGapOverride": "0.0000%" },
|
|
69
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "114.6252%", "ascentOverride": "84.4491%", "descentOverride": "21.8975%", "lineGapOverride": "0.0000%" },
|
|
70
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "108.3377%", "ascentOverride": "89.3502%", "descentOverride": "23.1683%", "lineGapOverride": "0.0000%" },
|
|
71
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "110.4212%", "ascentOverride": "87.6644%", "descentOverride": "22.7312%", "lineGapOverride": "0.0000%" },
|
|
72
|
+
] },
|
|
73
|
+
"Poppins": { generic: "sans-serif", faces: [
|
|
74
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "112.1577%", "ascentOverride": "93.6182%", "descentOverride": "31.2061%", "lineGapOverride": "8.9160%" },
|
|
75
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "113.5036%", "ascentOverride": "92.5081%", "descentOverride": "30.8360%", "lineGapOverride": "8.8103%" },
|
|
76
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "106.2543%", "ascentOverride": "98.8195%", "descentOverride": "32.9398%", "lineGapOverride": "9.4114%" },
|
|
77
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "107.2960%", "ascentOverride": "97.8601%", "descentOverride": "32.6200%", "lineGapOverride": "9.3200%" },
|
|
78
|
+
] },
|
|
79
|
+
"Nunito Sans": { generic: "sans-serif", faces: [
|
|
80
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "101.3906%", "ascentOverride": "99.7134%", "descentOverride": "34.8159%", "lineGapOverride": "0.0000%" },
|
|
81
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "102.2878%", "ascentOverride": "98.8387%", "descentOverride": "34.5105%", "lineGapOverride": "0.0000%" },
|
|
82
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "95.8372%", "ascentOverride": "105.4914%", "descentOverride": "36.8333%", "lineGapOverride": "0.0000%" },
|
|
83
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "97.9207%", "ascentOverride": "103.2469%", "descentOverride": "36.0496%", "lineGapOverride": "0.0000%" },
|
|
84
|
+
] },
|
|
85
|
+
"Work Sans": { generic: "sans-serif", faces: [
|
|
86
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "111.9334%", "ascentOverride": "83.0851%", "descentOverride": "21.7093%", "lineGapOverride": "0.0000%" },
|
|
87
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "112.1577%", "ascentOverride": "82.9189%", "descentOverride": "21.6659%", "lineGapOverride": "0.0000%" },
|
|
88
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "104.3792%", "ascentOverride": "89.0982%", "descentOverride": "23.2805%", "lineGapOverride": "0.0000%" },
|
|
89
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "104.5876%", "ascentOverride": "88.9207%", "descentOverride": "23.2341%", "lineGapOverride": "0.0000%" },
|
|
90
|
+
] },
|
|
91
|
+
"DM Sans": { generic: "sans-serif", faces: [
|
|
92
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "104.5310%", "ascentOverride": "94.9001%", "descentOverride": "29.6563%", "lineGapOverride": "0.0000%" },
|
|
93
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "106.3255%", "ascentOverride": "93.2984%", "descentOverride": "29.1557%", "lineGapOverride": "0.0000%" },
|
|
94
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "101.0458%", "ascentOverride": "98.1733%", "descentOverride": "30.6792%", "lineGapOverride": "0.0000%" },
|
|
95
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "102.7125%", "ascentOverride": "96.5802%", "descentOverride": "30.1813%", "lineGapOverride": "0.0000%" },
|
|
96
|
+
] },
|
|
97
|
+
"Manrope": { generic: "sans-serif", faces: [
|
|
98
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "103.1851%", "ascentOverride": "103.3095%", "descentOverride": "29.0740%", "lineGapOverride": "0.0000%" },
|
|
99
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "105.0918%", "ascentOverride": "101.4351%", "descentOverride": "28.5465%", "lineGapOverride": "0.0000%" },
|
|
100
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "99.3790%", "ascentOverride": "107.2661%", "descentOverride": "30.1875%", "lineGapOverride": "0.0000%" },
|
|
101
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "101.1499%", "ascentOverride": "105.3881%", "descentOverride": "29.6589%", "lineGapOverride": "0.0000%" },
|
|
102
|
+
] },
|
|
103
|
+
"Figtree": { generic: "sans-serif", faces: [
|
|
104
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "100.7176%", "ascentOverride": "94.3231%", "descentOverride": "24.8219%", "lineGapOverride": "0.0000%" },
|
|
105
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "101.6149%", "ascentOverride": "93.4902%", "descentOverride": "24.6027%", "lineGapOverride": "0.0000%" },
|
|
106
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "95.4205%", "ascentOverride": "99.5593%", "descentOverride": "26.1998%", "lineGapOverride": "0.0000%" },
|
|
107
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "96.4623%", "ascentOverride": "98.4841%", "descentOverride": "25.9169%", "lineGapOverride": "0.0000%" },
|
|
108
|
+
] },
|
|
109
|
+
"Outfit": { generic: "sans-serif", faces: [
|
|
110
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "99.8204%", "ascentOverride": "100.1800%", "descentOverride": "26.0468%", "lineGapOverride": "0.0000%" },
|
|
111
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "100.0447%", "ascentOverride": "99.9553%", "descentOverride": "25.9884%", "lineGapOverride": "0.0000%" },
|
|
112
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "94.5872%", "ascentOverride": "105.7226%", "descentOverride": "27.4879%", "lineGapOverride": "0.0000%" },
|
|
113
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "96.0456%", "ascentOverride": "104.1172%", "descentOverride": "27.0705%", "lineGapOverride": "0.0000%" },
|
|
114
|
+
] },
|
|
115
|
+
"Plus Jakarta Sans": { generic: "sans-serif", faces: [
|
|
116
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "104.9796%", "ascentOverride": "98.8763%", "descentOverride": "21.1470%", "lineGapOverride": "0.0000%" },
|
|
117
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "106.3255%", "ascentOverride": "97.6247%", "descentOverride": "20.8793%", "lineGapOverride": "0.0000%" },
|
|
118
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "99.7957%", "ascentOverride": "104.0125%", "descentOverride": "22.2454%", "lineGapOverride": "0.0000%" },
|
|
119
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "100.8374%", "ascentOverride": "102.9380%", "descentOverride": "22.0156%", "lineGapOverride": "0.0000%" },
|
|
120
|
+
] },
|
|
121
|
+
"Raleway": { generic: "sans-serif", faces: [
|
|
122
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "103.8581%", "ascentOverride": "90.5081%", "descentOverride": "22.5308%", "lineGapOverride": "0.0000%" },
|
|
123
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "105.4283%", "ascentOverride": "89.1602%", "descentOverride": "22.1952%", "lineGapOverride": "0.0000%" },
|
|
124
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "98.9624%", "ascentOverride": "94.9856%", "descentOverride": "23.6454%", "lineGapOverride": "0.0000%" },
|
|
125
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "100.2124%", "ascentOverride": "93.8008%", "descentOverride": "23.3504%", "lineGapOverride": "0.0000%" },
|
|
126
|
+
] },
|
|
127
|
+
"IBM Plex Sans": { generic: "sans-serif", faces: [
|
|
128
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "101.1663%", "ascentOverride": "101.3184%", "descentOverride": "27.1830%", "lineGapOverride": "0.0000%" },
|
|
129
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "103.4094%", "ascentOverride": "99.1206%", "descentOverride": "26.5933%", "lineGapOverride": "0.0000%" },
|
|
130
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "97.2956%", "ascentOverride": "105.3490%", "descentOverride": "28.2644%", "lineGapOverride": "0.0000%" },
|
|
131
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "98.5457%", "ascentOverride": "104.0127%", "descentOverride": "27.9058%", "lineGapOverride": "0.0000%" },
|
|
132
|
+
] },
|
|
133
|
+
"Noto Sans": { generic: "sans-serif", faces: [
|
|
134
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "106.3255%", "ascentOverride": "100.5403%", "descentOverride": "27.5569%", "lineGapOverride": "0.0000%" },
|
|
135
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "108.1200%", "ascentOverride": "98.8716%", "descentOverride": "27.0995%", "lineGapOverride": "0.0000%" },
|
|
136
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "102.5042%", "ascentOverride": "104.2884%", "descentOverride": "28.5842%", "lineGapOverride": "0.0000%" },
|
|
137
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "104.7959%", "ascentOverride": "102.0078%", "descentOverride": "27.9591%", "lineGapOverride": "0.0000%" },
|
|
138
|
+
] },
|
|
139
|
+
"Crimson Pro": { generic: "serif", faces: [
|
|
140
|
+
{ "weight": 400, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "98.5577%", "ascentOverride": "90.9604%", "descentOverride": "21.7988%", "lineGapOverride": "0.0000%" },
|
|
141
|
+
{ "weight": 500, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "100.4808%", "ascentOverride": "89.2195%", "descentOverride": "21.3816%", "lineGapOverride": "0.0000%" },
|
|
142
|
+
{ "weight": 600, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "96.3883%", "ascentOverride": "93.0076%", "descentOverride": "22.2894%", "lineGapOverride": "0.0000%" },
|
|
143
|
+
{ "weight": 700, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "98.6456%", "ascentOverride": "90.8793%", "descentOverride": "21.7794%", "lineGapOverride": "0.0000%" },
|
|
144
|
+
] },
|
|
145
|
+
"Literata": { generic: "serif", faces: [
|
|
146
|
+
{ "weight": 400, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "118.1538%", "ascentOverride": "99.6159%", "descentOverride": "26.0677%", "lineGapOverride": "0.0000%" },
|
|
147
|
+
{ "weight": 500, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "120.8615%", "ascentOverride": "97.3842%", "descentOverride": "25.4837%", "lineGapOverride": "0.0000%" },
|
|
148
|
+
{ "weight": 600, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "115.5756%", "ascentOverride": "101.8381%", "descentOverride": "26.6492%", "lineGapOverride": "0.0000%" },
|
|
149
|
+
{ "weight": 700, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "118.3494%", "ascentOverride": "99.4513%", "descentOverride": "26.0246%", "lineGapOverride": "0.0000%" },
|
|
150
|
+
] },
|
|
151
|
+
"DM Serif Display": { generic: "serif", faces: [
|
|
152
|
+
{ "weight": 400, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "109.7846%", "ascentOverride": "94.3666%", "descentOverride": "30.5143%", "lineGapOverride": "0.0000%" },
|
|
153
|
+
] },
|
|
154
|
+
"Bitter": { generic: "serif", faces: [
|
|
155
|
+
{ "weight": 400, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "114.4615%", "ascentOverride": "81.6868%", "descentOverride": "23.1519%", "lineGapOverride": "0.0000%" },
|
|
156
|
+
{ "weight": 500, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "115.2000%", "ascentOverride": "81.1632%", "descentOverride": "23.0035%", "lineGapOverride": "0.0000%" },
|
|
157
|
+
{ "weight": 600, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "108.8722%", "ascentOverride": "85.8805%", "descentOverride": "24.3405%", "lineGapOverride": "0.0000%" },
|
|
158
|
+
{ "weight": 700, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "109.5657%", "ascentOverride": "85.3369%", "descentOverride": "24.1864%", "lineGapOverride": "0.0000%" },
|
|
159
|
+
] },
|
|
160
|
+
"Noto Serif": { generic: "serif", faces: [
|
|
161
|
+
{ "weight": 400, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "118.4000%", "ascentOverride": "90.2872%", "descentOverride": "24.7466%", "lineGapOverride": "0.0000%" },
|
|
162
|
+
{ "weight": 500, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "120.6154%", "ascentOverride": "88.6288%", "descentOverride": "24.2921%", "lineGapOverride": "0.0000%" },
|
|
163
|
+
{ "weight": 600, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "115.5756%", "ascentOverride": "92.4936%", "descentOverride": "25.3514%", "lineGapOverride": "0.0000%" },
|
|
164
|
+
{ "weight": 700, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "118.3494%", "ascentOverride": "90.3257%", "descentOverride": "24.7572%", "lineGapOverride": "0.0000%" },
|
|
165
|
+
] },
|
|
166
|
+
"IBM Plex Serif": { generic: "serif", faces: [
|
|
167
|
+
{ "weight": 400, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "116.4308%", "ascentOverride": "88.0351%", "descentOverride": "23.6192%", "lineGapOverride": "0.0000%" },
|
|
168
|
+
{ "weight": 500, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "118.6462%", "ascentOverride": "86.3913%", "descentOverride": "23.1782%", "lineGapOverride": "0.0000%" },
|
|
169
|
+
{ "weight": 600, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "112.8018%", "ascentOverride": "90.8673%", "descentOverride": "24.3790%", "lineGapOverride": "0.0000%" },
|
|
170
|
+
{ "weight": 700, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "114.6510%", "ascentOverride": "89.4017%", "descentOverride": "23.9858%", "lineGapOverride": "0.0000%" },
|
|
171
|
+
] },
|
|
172
|
+
"Roboto Slab": { generic: "serif", faces: [
|
|
173
|
+
{ "weight": 400, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "116.8269%", "ascentOverride": "89.6926%", "descentOverride": "23.1964%", "lineGapOverride": "0.0000%" },
|
|
174
|
+
{ "weight": 500, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "117.6683%", "ascentOverride": "89.0513%", "descentOverride": "23.0305%", "lineGapOverride": "0.0000%" },
|
|
175
|
+
{ "weight": 600, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "110.7223%", "ascentOverride": "94.6378%", "descentOverride": "24.4753%", "lineGapOverride": "0.0000%" },
|
|
176
|
+
{ "weight": 700, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "111.0609%", "ascentOverride": "94.3492%", "descentOverride": "24.4007%", "lineGapOverride": "0.0000%" },
|
|
177
|
+
] },
|
|
178
|
+
"Newsreader": { generic: "serif", faces: [
|
|
179
|
+
{ "weight": 400, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "105.4769%", "ascentOverride": "69.6835%", "descentOverride": "25.1240%", "lineGapOverride": "0.0000%" },
|
|
180
|
+
{ "weight": 500, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "107.9385%", "ascentOverride": "68.0944%", "descentOverride": "24.5510%", "lineGapOverride": "0.0000%" },
|
|
181
|
+
{ "weight": 600, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "104.0181%", "ascentOverride": "70.6608%", "descentOverride": "25.4763%", "lineGapOverride": "0.0000%" },
|
|
182
|
+
{ "weight": 700, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "106.6763%", "ascentOverride": "68.9000%", "descentOverride": "24.8415%", "lineGapOverride": "0.0000%" },
|
|
183
|
+
] },
|
|
184
|
+
"EB Garamond": { generic: "serif", faces: [
|
|
185
|
+
{ "weight": 400, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "94.7692%", "ascentOverride": "106.2581%", "descentOverride": "31.4448%", "lineGapOverride": "0.0000%" },
|
|
186
|
+
{ "weight": 500, "local": ["Times New Roman", "TimesNewRomanPSMT"], "sizeAdjust": "98.2154%", "ascentOverride": "102.5298%", "descentOverride": "30.3415%", "lineGapOverride": "0.0000%" },
|
|
187
|
+
{ "weight": 600, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "95.0032%", "ascentOverride": "105.9965%", "descentOverride": "31.3674%", "lineGapOverride": "0.0000%" },
|
|
188
|
+
{ "weight": 700, "local": ["Times New Roman Bold", "TimesNewRomanPS-BoldMT"], "sizeAdjust": "98.0081%", "ascentOverride": "102.7466%", "descentOverride": "30.4056%", "lineGapOverride": "0.0000%" },
|
|
189
|
+
] },
|
|
190
|
+
"Atkinson Hyperlegible Next": { generic: "sans-serif", faces: [
|
|
191
|
+
{ "weight": 400, "local": ["Arial", "ArialMT"], "sizeAdjust": "99.5961%", "ascentOverride": "98.7991%", "descentOverride": "31.7282%", "lineGapOverride": "0.0000%" },
|
|
192
|
+
{ "weight": 500, "local": ["Arial", "ArialMT"], "sizeAdjust": "102.5122%", "ascentOverride": "95.9886%", "descentOverride": "30.8256%", "lineGapOverride": "0.0000%" },
|
|
193
|
+
{ "weight": 600, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "97.2956%", "ascentOverride": "101.1351%", "descentOverride": "32.4783%", "lineGapOverride": "0.0000%" },
|
|
194
|
+
{ "weight": 700, "local": ["Arial Bold", "Arial-BoldMT"], "sizeAdjust": "99.5874%", "ascentOverride": "98.8077%", "descentOverride": "31.7309%", "lineGapOverride": "0.0000%" },
|
|
195
|
+
] },
|
|
196
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Generated from lettercamp/lib/font-resources.ts.
|
|
2
|
+
import { fontFallbacks } from "./font-fallbacks.js";
|
|
3
|
+
export function fontResources(typography = {}) {
|
|
4
|
+
const quote = (value) => '"' + Array.from(String(value), char => /[a-zA-Z0-9 -]/.test(char) ? char : '\\' + char.codePointAt(0).toString(16) + ' ').join('') + '"';
|
|
5
|
+
const google = new Set();
|
|
6
|
+
const custom = new Map();
|
|
7
|
+
const faces = [];
|
|
8
|
+
const resolve = (input) => {
|
|
9
|
+
const value = input && typeof input === "object" ? input : undefined;
|
|
10
|
+
if (value && typeof value.url === 'string' && !(typeof value.google === 'string' && value.google.trim())) {
|
|
11
|
+
try {
|
|
12
|
+
const url = new URL(value.url);
|
|
13
|
+
if (url.protocol !== 'https:' || url.username || url.password)
|
|
14
|
+
throw new Error();
|
|
15
|
+
const weight = typeof value.weight === 'string' && /^(?:[1-9]\d{0,2}|1000)(?: (?:[1-9]\d{0,2}|1000))?$/.test(value.weight) ? value.weight : '400';
|
|
16
|
+
const key = url.href + ' ' + weight;
|
|
17
|
+
if (!custom.has(key)) {
|
|
18
|
+
const family = 'Lettercamp Custom ' + custom.size;
|
|
19
|
+
custom.set(key, family);
|
|
20
|
+
faces.push('@font-face{font-family:' + quote(family) + ';src:url(' + quote(url.href) + ');font-weight:' + weight + ';font-style:normal;font-display:swap;}');
|
|
21
|
+
}
|
|
22
|
+
return quote(custom.get(key)) + ', Arial, Helvetica, sans-serif';
|
|
23
|
+
}
|
|
24
|
+
catch { /* Invalid custom URLs use the default family. */ }
|
|
25
|
+
}
|
|
26
|
+
const family = value && typeof value.google === 'string' && value.google.trim() ? value.google.trim() : 'Inter';
|
|
27
|
+
const fallback = Object.hasOwn(fontFallbacks, family) ? fontFallbacks[family] : undefined;
|
|
28
|
+
if (fallback) {
|
|
29
|
+
const alias = family + ' Fallback';
|
|
30
|
+
if (!google.has(family))
|
|
31
|
+
for (const face of fallback.faces) {
|
|
32
|
+
faces.push('@font-face{font-family:' + quote(alias) + ';src:' + face.local.map(name => 'local(' + quote(name) + ')').join(',')
|
|
33
|
+
+ ';font-weight:' + face.weight + ';font-style:normal;size-adjust:' + face.sizeAdjust
|
|
34
|
+
+ ';ascent-override:' + face.ascentOverride + ';descent-override:' + face.descentOverride + ';line-gap-override:' + face.lineGapOverride + ';}');
|
|
35
|
+
}
|
|
36
|
+
google.add(family);
|
|
37
|
+
return quote(family) + ', ' + quote(alias) + ', ' + fallback.generic;
|
|
38
|
+
}
|
|
39
|
+
google.add(family);
|
|
40
|
+
return quote(family) + ', Arial, Helvetica, sans-serif';
|
|
41
|
+
};
|
|
42
|
+
const headingFamily = resolve(typography.headingFont);
|
|
43
|
+
const bodyFamily = resolve(typography.bodyFont);
|
|
44
|
+
return {
|
|
45
|
+
headingFamily, bodyFamily, css: faces.join('\n'),
|
|
46
|
+
googleUrl: google.size ? 'https://fonts.googleapis.com/css2?' + [...google].map(family => 'family=' + encodeURIComponent(family) + ':wght@' + (Object.hasOwn(fontFallbacks, family) ? fontFallbacks[family].faces.map(face => face.weight).join(';') : '400;500;600;700')).join('&') + '&display=swap' : null,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Generated from lettercamp/lib/image-rounding.ts.
|
|
2
|
+
export const defaultImageRadius = 2;
|
|
3
|
+
export function readImageRadius(value: unknown): number {
|
|
4
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 20 ? value : defaultImageRadius;
|
|
5
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export { readImageRadius } from "./image-radius";
|
|
2
|
+
|
|
3
|
+
export const siteImageSelector = ".post-card-cover, .cover img, .prose img, .article-hero-image img";
|
|
4
|
+
// Observe published and preview content, including live editor replacements.
|
|
5
|
+
export const imageRoundingScript = `(
|
|
6
|
+
function observeImageSizes(root, selector) {
|
|
7
|
+
const observed = new Set();
|
|
8
|
+
const resize = new ResizeObserver(entries => {
|
|
9
|
+
for (const entry of entries) {
|
|
10
|
+
const box = entry.borderBoxSize[0];
|
|
11
|
+
const size = box ? Math.min(box.inlineSize, box.blockSize) : Math.min(entry.contentRect.width, entry.contentRect.height);
|
|
12
|
+
entry.target.style.setProperty("--image-short-side", size + "px");
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
const sync = () => {
|
|
16
|
+
for (const target of observed) {
|
|
17
|
+
if (!root.contains(target)) { resize.unobserve(target); observed.delete(target); }
|
|
18
|
+
}
|
|
19
|
+
for (const target of root.querySelectorAll(selector)) {
|
|
20
|
+
if (!observed.has(target)) { observed.add(target); resize.observe(target); }
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
sync();
|
|
24
|
+
const mutations = new MutationObserver(sync);
|
|
25
|
+
mutations.observe(root, { childList: true, subtree: true });
|
|
26
|
+
return () => { resize.disconnect(); mutations.disconnect(); };
|
|
27
|
+
}
|
|
28
|
+
)(document, ${JSON.stringify(siteImageSelector)});`;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const imageWidthStyles = `
|
|
2
|
+
.publication-post { container-type: inline-size; }
|
|
3
|
+
.publication-post .prose video[data-image-width] { width: 100%; height: auto; }
|
|
4
|
+
.publication-post .prose span:has(> img[data-image-width]),
|
|
5
|
+
.publication-post .prose span:has(> a > img[data-image-width]) { display: block; }
|
|
6
|
+
.publication-post .article-hero-image { width: min(100%, var(--post-content-width)); max-width: none; margin-inline: auto; }
|
|
7
|
+
.publication-post .article-hero-image:not([data-image-width="regular"]):not([data-image-width="full"]) { width: min(100%, calc(var(--post-content-width) + 128px)); max-width: none; }
|
|
8
|
+
.publication-post .article-hero-image[data-image-width="full"] { width: 100%; max-width: none; }
|
|
9
|
+
.publication-post .article-hero-image[data-image-width="regular"] { width: min(100%, var(--cover-image-width, var(--post-content-width)), var(--post-content-width)); max-width: none; }
|
|
10
|
+
.publication-post .article-hero:has(.article-hero-image:not([data-image-width="regular"])) { display: block; }
|
|
11
|
+
.publication-post .article-hero:has(.article-hero-image:not([data-image-width="regular"])) .article-intro { max-width: var(--post-content-width); margin-inline: auto; }
|
|
12
|
+
.publication-post .article-hero:has(.article-hero-image:not([data-image-width="regular"])) .article-hero-image { margin-top: 32px; }
|
|
13
|
+
`;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Generated from lettercamp/lib/page-metadata.ts.
|
|
2
|
+
export function pageMetadata(site, page, url, article = false, basePath = "") {
|
|
3
|
+
const seo = site.seo && typeof site.seo === "object" ? site.seo : {};
|
|
4
|
+
const text = (value) => typeof value === "string" ? value.trim() : "";
|
|
5
|
+
const title = text(page.title) || text(site.name);
|
|
6
|
+
const pageTitle = title === site.name ? title : `${title} — ${text(site.name)}`;
|
|
7
|
+
const homepage = !article && new URL(url).pathname.replace(/\/+$/, "") === basePath.replace(/\/+$/, "");
|
|
8
|
+
const documentTitle = text(page.metaTitle) || (homepage && text(seo.metaTitle)) || pageTitle;
|
|
9
|
+
const description = text(page.metaDescription) || text(page.description) || text(site.description);
|
|
10
|
+
const socialTitle = text(page.ogTitle) || (homepage && (text(seo.ogTitle) || text(seo.metaTitle))) || title;
|
|
11
|
+
const socialDescription = text(page.ogDescription) || text(page.description) || text(seo.ogDescription) || description;
|
|
12
|
+
const canonical = new URL(url);
|
|
13
|
+
canonical.search = "";
|
|
14
|
+
canonical.hash = "";
|
|
15
|
+
const resolveUrl = (value) => {
|
|
16
|
+
try {
|
|
17
|
+
const resolved = text(value) && new URL(text(value), canonical);
|
|
18
|
+
return resolved && ["https:", "http:"].includes(resolved.protocol) ? resolved.href : "";
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return "";
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const imageUrl = resolveUrl(page.ogImage || page.image || seo.ogImage);
|
|
25
|
+
const imageAlt = text(page.ogImageAlt) || (page.ogImage || page.image ? text(page.imageAlt) : text(seo.ogImageAlt));
|
|
26
|
+
const twitterImageUrl = resolveUrl(page.twitterImage) || imageUrl;
|
|
27
|
+
const language = text(page.language) || text(site.language) || "en";
|
|
28
|
+
let locale = "";
|
|
29
|
+
try {
|
|
30
|
+
const parsed = new Intl.Locale(language).maximize();
|
|
31
|
+
locale = `${parsed.language}_${parsed.region}`;
|
|
32
|
+
}
|
|
33
|
+
catch { }
|
|
34
|
+
const keywords = page.keywords || seo.keywords || "";
|
|
35
|
+
return {
|
|
36
|
+
documentTitle, description, socialTitle, socialDescription, imageUrl, imageAlt, language, locale,
|
|
37
|
+
canonical: resolveUrl(page.canonicalUrl) || canonical.href,
|
|
38
|
+
keywords: Array.isArray(keywords) ? keywords.filter(value => typeof value === "string").join(", ") : text(keywords),
|
|
39
|
+
robots: page.noindex === true ? "noindex, follow" : "index, follow",
|
|
40
|
+
videoUrl: resolveUrl(page.ogVideo), videoType: text(page.ogVideoType),
|
|
41
|
+
twitterTitle: text(page.twitterTitle) || socialTitle,
|
|
42
|
+
twitterDescription: text(page.twitterDescription) || socialDescription,
|
|
43
|
+
twitterImageUrl, twitterImageAlt: text(page.twitterImageAlt) || (page.twitterImage ? "" : imageAlt),
|
|
44
|
+
twitterCard: ["summary", "summary_large_image"].includes(text(page.twitterCard)) ? text(page.twitterCard) : twitterImageUrl ? "summary_large_image" : "summary",
|
|
45
|
+
twitterSite: text(page.twitterSite), twitterCreator: text(page.twitterCreator),
|
|
46
|
+
};
|
|
47
|
+
}
|