diff --git a/package.json b/package.json index 530b072..061fcac 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,9 @@ "build": "tsc && vite build", "preview": "vite preview", "tauri": "tauri", - "dmg": "tauri build --bundles dmg" + "dmg": "tauri build --bundles dmg", + "fonts:sync": "node node_modules/margin-shared/bin/sync-fonts.mjs .", + "fonts:check": "node node_modules/margin-shared/bin/sync-fonts.mjs . --check" }, "dependencies": { "@tauri-apps/api": "^2", @@ -21,6 +23,7 @@ "@tiptap/pm": "^3.27.1", "@tiptap/react": "^3.27.1", "@tiptap/starter-kit": "^3.27.1", + "margin-shared": "file:./shared", "pdfjs-dist": "^6.0.227", "react": "^19.1.0", "react-dom": "^19.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a14b022..1ee989e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,6 +38,9 @@ importers: '@tiptap/starter-kit': specifier: ^3.27.1 version: 3.27.1 + margin-shared: + specifier: file:./shared + version: file:shared pdfjs-dist: specifier: ^6.0.227 version: 6.0.227 @@ -887,6 +890,10 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + margin-shared@file:shared: + resolution: {directory: shared, type: directory} + hasBin: true + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -1784,6 +1791,8 @@ snapshots: dependencies: yallist: 3.1.1 + margin-shared@file:shared: {} + ms@2.1.3: {} nanoid@3.3.14: {} diff --git a/shared/README.md b/shared/README.md new file mode 100644 index 0000000..bcb3c05 --- /dev/null +++ b/shared/README.md @@ -0,0 +1,15 @@ +# margin-shared + +The faces, palette and glyphs [Margin](../) and Margin Docs both draw from. It is the one copy of +the decisions the two apps have to agree on: which six fonts they offer, what their named pairings +are, the 35 design tokens they share, and the title bar icon paths. + +No build step and no dependencies. Both apps resolve the TypeScript source directly through their +bundler, so an edit here is live in both on the next dev server restart. + +Margin consumes it as `"margin-shared": "file:./shared"`. Margin Docs, which lives in a separate +repository, uses a relative path to this directory; see its `package.json`. + +The font binaries in `fonts/` are the source of truth, and each app keeps a vendored copy under +`public/fonts` because its Rust PDF exporter reads them with `include_bytes!` before any npm install +has run. Run `pnpm fonts:sync` in an app to refresh that copy and `pnpm fonts:check` to verify it. diff --git a/shared/bin/sync-fonts.mjs b/shared/bin/sync-fonts.mjs new file mode 100755 index 0000000..bf6d5dd --- /dev/null +++ b/shared/bin/sync-fonts.mjs @@ -0,0 +1,74 @@ +#!/usr/bin/env node +// Copies this package's font files into an app's public/fonts, or checks that they already match. +// +// The copies exist because both apps' `src-tauri/src/pdf.rs` reads the same files with +// `include_bytes!`, so the bytes have to be on disk at a path cargo can see before any npm install +// has run. Serving them out of node_modules would mean a cargo build that fails on a fresh clone +// until the front end was installed, which is a worse trade than a vendored copy with a named +// upstream and a check that fails loudly when the two drift. +// +// node bin/sync-fonts.mjs copy, reporting what changed +// node bin/sync-fonts.mjs --check compare only, exit 1 on any difference + +import { readdirSync, readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const here = dirname(fileURLToPath(import.meta.url)); +const source = resolve(here, "..", "fonts"); + +const args = process.argv.slice(2); +const check = args.includes("--check"); +const target = args.find((a) => !a.startsWith("--")); + +if (!target) { + console.error("usage: sync-fonts.mjs [--check]"); + process.exit(2); +} + +const dest = resolve(process.cwd(), target, "public", "fonts"); +const files = readdirSync(source).filter((f) => f.endsWith(".ttf") || f.endsWith(".txt")).sort(); + +if (!check) mkdirSync(dest, { recursive: true }); + +const wrong = []; +let copied = 0; + +for (const file of files) { + const from = join(source, file); + const to = join(dest, file); + const want = readFileSync(from); + const have = existsSync(to) ? readFileSync(to) : null; + + if (have !== null && have.equals(want)) continue; + + if (check) { + wrong.push(`${have === null ? "missing" : "differs"}: ${file}`); + continue; + } + writeFileSync(to, want); + copied += 1; +} + +// A file the app has and the package does not is reported rather than deleted. It is far more +// likely to be a face somebody is in the middle of adding than something to throw away, and this +// script does not get to be the reason an asset disappears. +if (existsSync(dest)) { + for (const file of readdirSync(dest)) { + if (!files.includes(file)) wrong.push(`not in the package, left alone: ${file}`); + } +} + +if (check) { + if (wrong.length === 0) { + console.log(`fonts match margin-shared (${files.length} files)`); + process.exit(0); + } + console.error("public/fonts is out of step with margin-shared:"); + for (const line of wrong) console.error(` ${line}`); + console.error("\nrun: pnpm fonts:sync"); + process.exit(1); +} + +console.log(copied === 0 ? `fonts already current (${files.length} files)` : `synced ${copied} file(s)`); +for (const line of wrong) console.log(` note: ${line}`); diff --git a/shared/css/fonts.css b/shared/css/fonts.css new file mode 100644 index 0000000..077b0d8 --- /dev/null +++ b/shared/css/fonts.css @@ -0,0 +1,111 @@ +/* The six families src/fonts.ts offers, bound to the variable files in fonts/. + * + * The URLs are absolute site paths, so each app serves these out of its own `public/fonts`. The + * copies there are vendored from this package and kept honest by `bin/sync-fonts.mjs`; they are not + * imported from node_modules, because both apps' `src-tauri/src/pdf.rs` reads the same files with + * `include_bytes!` and a cargo build must not depend on an npm install having run first. + * + * Every one is a variable file with an upright and an italic cut, so a weight anywhere in the + * declared range is a real instance rather than a synthesised one, and italic is the designer's + * italic rather than a slant applied by the browser. + * + * `font-display: block` throughout, and that is the unusual choice. The alternative is a first + * paint in Georgia that reflows into Literata a moment later, and a page of prose that resets its + * line breaks under the caret is worse than a page that arrives a beat late. The files are local to + * the bundle, so the beat is a disk read. */ + +@font-face { + font-family: "Hanken Grotesk"; + src: url("/fonts/HankenGrotesk-VF.ttf") format("truetype-variations"); + font-weight: 100 900; + font-style: normal; + font-display: block; +} + +@font-face { + font-family: "Hanken Grotesk"; + src: url("/fonts/HankenGrotesk-Italic-VF.ttf") format("truetype-variations"); + font-weight: 100 900; + font-style: italic; + font-display: block; +} + +@font-face { + font-family: "Literata"; + src: url("/fonts/Literata-VF.ttf") format("truetype-variations"); + font-weight: 200 900; + font-style: normal; + font-display: block; +} + +@font-face { + font-family: "Literata"; + src: url("/fonts/Literata-Italic-VF.ttf") format("truetype-variations"); + font-weight: 200 900; + font-style: italic; + font-display: block; +} + +@font-face { + font-family: "EB Garamond"; + src: url("/fonts/EBGaramond-VF.ttf") format("truetype-variations"); + font-weight: 400 800; + font-style: normal; + font-display: block; +} + +@font-face { + font-family: "EB Garamond"; + src: url("/fonts/EBGaramond-Italic-VF.ttf") format("truetype-variations"); + font-weight: 400 800; + font-style: italic; + font-display: block; +} + +@font-face { + font-family: "Lora"; + src: url("/fonts/Lora-VF.ttf") format("truetype-variations"); + font-weight: 400 700; + font-style: normal; + font-display: block; +} + +@font-face { + font-family: "Lora"; + src: url("/fonts/Lora-Italic-VF.ttf") format("truetype-variations"); + font-weight: 400 700; + font-style: italic; + font-display: block; +} + +@font-face { + font-family: "Source Serif 4"; + src: url("/fonts/SourceSerif4-VF.ttf") format("truetype-variations"); + font-weight: 200 900; + font-style: normal; + font-display: block; +} + +@font-face { + font-family: "Source Serif 4"; + src: url("/fonts/SourceSerif4-Italic-VF.ttf") format("truetype-variations"); + font-weight: 200 900; + font-style: italic; + font-display: block; +} + +@font-face { + font-family: "Fraunces"; + src: url("/fonts/Fraunces-VF.ttf") format("truetype-variations"); + font-weight: 100 900; + font-style: normal; + font-display: block; +} + +@font-face { + font-family: "Fraunces"; + src: url("/fonts/Fraunces-Italic-VF.ttf") format("truetype-variations"); + font-weight: 100 900; + font-style: italic; + font-display: block; +} diff --git a/shared/css/tokens.css b/shared/css/tokens.css new file mode 100644 index 0000000..1a9646c --- /dev/null +++ b/shared/css/tokens.css @@ -0,0 +1,91 @@ +/* The palette, the type scale and the shape constants both apps are built from. + * + * These 35 tokens already held identical values in the two repos before this package existed, which + * is the argument for moving them: they were identical by somebody remembering to copy a hex across, + * and that is not a mechanism. A colour that only exists in one app is not here. Each app layers its + * own sheet on top of this one and adds what only it needs, which is a preview pane width in Margin + * and a document typography scale in Margin Docs. + * + * --font-book and --font-heading are the two a document overrides at runtime, per book or per + * document. What is set here is the default pair, and the only place that decides what an untouched + * page looks like. */ + +:root { + --font-ui: "Hanken Grotesk", ui-sans-serif, system-ui, -apple-system, sans-serif; + --font-book: "Literata", Georgia, "Times New Roman", serif; + --font-heading: "Literata", Georgia, "Times New Roman", serif; + + --r-sm: 5px; + --r-md: 8px; + --r-lg: 12px; + + --pane-sidebar: 248px; + --measure: 46em; + --titlebar-h: 46px; + + --t-1: 11px; + --t-2: 12px; + --t-3: 13px; + --t-4: 15px; + + --ease: cubic-bezier(0.22, 0.61, 0.36, 1); +} + +:root, +:root[data-theme="light"] { + --paper: #fcfbf7; + --shell: #f1ece2; + --sidebar: #ece6da; + --raised: #fbfaf6; + + --ink: #23201b; + --ink-soft: #6b6458; + --ink-faint: #9b9484; + + --line: #e3ddce; + --line-strong: #d6cfbd; + + --accent: #2a2622; + --accent-ink: #100e0b; + --accent-wash: rgba(35, 32, 27, 0.08); + --accent-contrast: #faf7f0; + --selection: rgba(35, 32, 27, 0.14); + --glass: rgba(252, 251, 247, 0.86); + + --danger: #b4453a; + --danger-ink: #963327; + --danger-wash: rgba(180, 69, 58, 0.1); + --danger-contrast: #faf7f0; + + --shadow-page: 0 1px 2px rgba(35, 32, 27, 0.06), 0 14px 30px rgba(35, 32, 27, 0.09); + --shadow-pop: 0 8px 24px rgba(35, 32, 27, 0.14); +} + +:root[data-theme="dark"] { + --paper: #1d1a16; + --shell: #151310; + --sidebar: #1a1713; + --raised: #232019; + + --ink: #ece6da; + --ink-soft: #a89f8e; + --ink-faint: #756d5e; + + --line: #2c2823; + --line-strong: #3a352d; + + --accent: #efe9dc; + --accent-ink: #ffffff; + --accent-wash: rgba(239, 233, 220, 0.12); + --accent-contrast: #1a1714; + --selection: rgba(239, 233, 220, 0.18); + --glass: rgba(33, 30, 25, 0.88); + + --danger: #d97a6f; + --danger-ink: #e58e84; + --danger-wash: rgba(217, 122, 111, 0.16); + --danger-contrast: #1a1714; + + --shadow-page: 0 1px 2px rgba(0, 0, 0, 0.4), 0 14px 34px rgba(0, 0, 0, 0.5); + --shadow-pop: 0 8px 24px rgba(0, 0, 0, 0.55); +} diff --git a/shared/fonts/EBGaramond-Italic-VF.ttf b/shared/fonts/EBGaramond-Italic-VF.ttf new file mode 100644 index 0000000..f9ad996 Binary files /dev/null and b/shared/fonts/EBGaramond-Italic-VF.ttf differ diff --git a/shared/fonts/EBGaramond-OFL.txt b/shared/fonts/EBGaramond-OFL.txt new file mode 100644 index 0000000..c1ec5e1 --- /dev/null +++ b/shared/fonts/EBGaramond-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2017 The EB Garamond Project Authors (https://github.com/octaviopardo/EBGaramond12) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/shared/fonts/EBGaramond-VF.ttf b/shared/fonts/EBGaramond-VF.ttf new file mode 100644 index 0000000..52d34b8 Binary files /dev/null and b/shared/fonts/EBGaramond-VF.ttf differ diff --git a/shared/fonts/Fraunces-Italic-VF.ttf b/shared/fonts/Fraunces-Italic-VF.ttf new file mode 100644 index 0000000..2ddf59a Binary files /dev/null and b/shared/fonts/Fraunces-Italic-VF.ttf differ diff --git a/shared/fonts/Fraunces-OFL.txt b/shared/fonts/Fraunces-OFL.txt new file mode 100644 index 0000000..22fa7ce --- /dev/null +++ b/shared/fonts/Fraunces-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2018 The Fraunces Project Authors (https://github.com/undercasetype/Fraunces) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/shared/fonts/Fraunces-VF.ttf b/shared/fonts/Fraunces-VF.ttf new file mode 100644 index 0000000..8210f94 Binary files /dev/null and b/shared/fonts/Fraunces-VF.ttf differ diff --git a/shared/fonts/HankenGrotesk-Italic-VF.ttf b/shared/fonts/HankenGrotesk-Italic-VF.ttf new file mode 100644 index 0000000..eb28513 Binary files /dev/null and b/shared/fonts/HankenGrotesk-Italic-VF.ttf differ diff --git a/shared/fonts/HankenGrotesk-OFL.txt b/shared/fonts/HankenGrotesk-OFL.txt new file mode 100644 index 0000000..9c8185d --- /dev/null +++ b/shared/fonts/HankenGrotesk-OFL.txt @@ -0,0 +1,94 @@ +Copyright 2021 The Hanken Grotesk Project Authors (https://github.com/marcologous/hanken-grotesk) + + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/shared/fonts/HankenGrotesk-VF.ttf b/shared/fonts/HankenGrotesk-VF.ttf new file mode 100644 index 0000000..65a8f7b Binary files /dev/null and b/shared/fonts/HankenGrotesk-VF.ttf differ diff --git a/shared/fonts/Literata-Italic-VF.ttf b/shared/fonts/Literata-Italic-VF.ttf new file mode 100644 index 0000000..8690209 Binary files /dev/null and b/shared/fonts/Literata-Italic-VF.ttf differ diff --git a/shared/fonts/Literata-OFL.txt b/shared/fonts/Literata-OFL.txt new file mode 100644 index 0000000..9d3b4e3 --- /dev/null +++ b/shared/fonts/Literata-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2017 The Literata Project Authors (https://github.com/googlefonts/literata) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/shared/fonts/Literata-VF.ttf b/shared/fonts/Literata-VF.ttf new file mode 100644 index 0000000..0a81b49 Binary files /dev/null and b/shared/fonts/Literata-VF.ttf differ diff --git a/shared/fonts/Lora-Italic-VF.ttf b/shared/fonts/Lora-Italic-VF.ttf new file mode 100644 index 0000000..e973ccf Binary files /dev/null and b/shared/fonts/Lora-Italic-VF.ttf differ diff --git a/shared/fonts/Lora-OFL.txt b/shared/fonts/Lora-OFL.txt new file mode 100644 index 0000000..d0ce7fe --- /dev/null +++ b/shared/fonts/Lora-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2011 The Lora Project Authors (https://github.com/cyrealtype/Lora-Cyrillic), with Reserved Font Name "Lora". + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/shared/fonts/Lora-VF.ttf b/shared/fonts/Lora-VF.ttf new file mode 100644 index 0000000..ee1914c Binary files /dev/null and b/shared/fonts/Lora-VF.ttf differ diff --git a/shared/fonts/SourceSerif4-Italic-VF.ttf b/shared/fonts/SourceSerif4-Italic-VF.ttf new file mode 100644 index 0000000..ccb969a Binary files /dev/null and b/shared/fonts/SourceSerif4-Italic-VF.ttf differ diff --git a/shared/fonts/SourceSerif4-OFL.txt b/shared/fonts/SourceSerif4-OFL.txt new file mode 100644 index 0000000..318074e --- /dev/null +++ b/shared/fonts/SourceSerif4-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2014 The Source Serif 4 Project Authors (https://github.com/adobe-fonts/source-serif) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/shared/fonts/SourceSerif4-VF.ttf b/shared/fonts/SourceSerif4-VF.ttf new file mode 100644 index 0000000..40bbb58 Binary files /dev/null and b/shared/fonts/SourceSerif4-VF.ttf differ diff --git a/shared/package.json b/shared/package.json new file mode 100644 index 0000000..abe4d96 --- /dev/null +++ b/shared/package.json @@ -0,0 +1,20 @@ +{ + "name": "margin-shared", + "version": "0.1.0", + "private": true, + "license": "MIT", + "type": "module", + "description": "The faces, palette and glyphs Margin and Margin Docs both draw from.", + "types": "./src/index.ts", + "exports": { + ".": "./src/index.ts", + "./fonts": "./src/fonts.ts", + "./icons": "./src/icons.ts", + "./css/fonts.css": "./css/fonts.css", + "./css/tokens.css": "./css/tokens.css" + }, + "bin": { + "margin-shared-fonts": "./bin/sync-fonts.mjs" + }, + "files": ["src", "css", "fonts", "bin"] +} diff --git a/shared/src/fonts.ts b/shared/src/fonts.ts new file mode 100644 index 0000000..ce3e258 --- /dev/null +++ b/shared/src/fonts.ts @@ -0,0 +1,233 @@ +// The faces both apps offer, and the two slots they set them into. +// +// This lives in one place because the two apps have to agree about it. A face named here is a +// `@font-face` in css/fonts.css, a file in fonts/, and a family a Typst preamble names on the way +// to a PDF, and those four lists going out of step with each other is a document that renders in +// one app and falls back to Georgia in the other. There is no way to keep four lists in two repos +// honest by hand, so there is one list. +// +// Two slots and not one. Body and heading are the only typographic decision worth a control: +// a document that lets its author pick a face per paragraph is a word processor, and neither of +// these is one. The scale, the leading and the measure belong to each app's own stylesheet, which +// decided them once for every document. +// +// A `FontRef` is stored, not a family name. "Literata" as a string cannot say whether it means the +// file in fonts/ or a copy the user installed themselves, and those are two different faces the +// moment one of them is updated. + +export type FontCategory = "serif" | "sans" | "display"; + +/** One face that ships in fonts/, in the variable file both editors render from. */ +export interface BundledFont { + id: string; + label: string; + /** The CSS family name, which is also what a Typst preamble names it by. */ + family: string; + category: FontCategory; + regular: string; + italic: string; + /** The weight range the variable file covers, for the `@font-face` in css/fonts.css. */ + weight: string; +} + +/** + * The six, and the order a picker lists them in: the serifs a page of prose is set in, the one + * display face, then the sans both apps' own chrome already uses. + * + * Literata and Hanken Grotesk are first-class here and also special: they are the two that have + * static instances cut for PDF export, so they are the only pair whose bold really is bold on the + * page. The other four export as their variable file at one weight, which each app's pdf.rs + * explains. + */ +export const BUNDLED_FONTS: readonly BundledFont[] = [ + { + id: "literata", + label: "Literata", + family: "Literata", + category: "serif", + regular: "Literata-VF.ttf", + italic: "Literata-Italic-VF.ttf", + weight: "200 900", + }, + { + id: "eb-garamond", + label: "EB Garamond", + family: "EB Garamond", + category: "serif", + regular: "EBGaramond-VF.ttf", + italic: "EBGaramond-Italic-VF.ttf", + weight: "400 800", + }, + { + id: "lora", + label: "Lora", + family: "Lora", + category: "serif", + regular: "Lora-VF.ttf", + italic: "Lora-Italic-VF.ttf", + weight: "400 700", + }, + { + id: "source-serif", + label: "Source Serif 4", + family: "Source Serif 4", + category: "serif", + regular: "SourceSerif4-VF.ttf", + italic: "SourceSerif4-Italic-VF.ttf", + weight: "200 900", + }, + { + id: "fraunces", + label: "Fraunces", + family: "Fraunces", + category: "display", + regular: "Fraunces-VF.ttf", + italic: "Fraunces-Italic-VF.ttf", + weight: "100 900", + }, + { + id: "hanken", + label: "Hanken Grotesk", + family: "Hanken Grotesk", + category: "sans", + regular: "HankenGrotesk-VF.ttf", + italic: "HankenGrotesk-Italic-VF.ttf", + weight: "100 900", + }, +]; + +/** One of the six, or a family off the machine. */ +export type FontRef = { kind: "bundled"; id: string } | { kind: "system"; family: string }; + +/** + * What one book or one document is set in. + * + * Named for the pair rather than for either app's noun, because the two call the thing it belongs + * to different names. Each app aliases it: `BookFonts` in Margin, `DocumentFonts` in Margin Docs. + */ +export interface FontPair { + body: FontRef; + heading: FontRef; +} + +/** + * A named pair, which is what a picker offers first. + * + * Pairing two faces is the part of this that takes an eye, and a list of twelve families with no + * opinion attached is how a document ends up in Fraunces body text. The presets are the answer to + * "make this look like something"; the two selects underneath are for somebody who already knows. + */ +export interface FontPairing { + id: string; + label: string; + body: FontRef; + heading: FontRef; +} + +const bundled = (id: string): FontRef => ({ kind: "bundled", id }); + +export const FONT_PAIRINGS: readonly FontPairing[] = [ + { id: "quiet-press", label: "Quiet Press", body: bundled("literata"), heading: bundled("literata") }, + { id: "classic", label: "Classic", body: bundled("eb-garamond"), heading: bundled("eb-garamond") }, + { id: "editorial", label: "Editorial", body: bundled("source-serif"), heading: bundled("fraunces") }, + { id: "modern", label: "Modern", body: bundled("lora"), heading: bundled("hanken") }, + { id: "contrast", label: "Contrast", body: bundled("literata"), heading: bundled("hanken") }, + { id: "plain", label: "Plain", body: bundled("hanken"), heading: bundled("hanken") }, +]; + +/** What a page is set in until somebody says otherwise: the css/tokens.css pair, in FontRef form. */ +export const DEFAULT_FONTS: FontPair = { body: bundled("literata"), heading: bundled("literata") }; + +// The two tails from css/tokens.css, so a face that fails to load falls back to what the app would +// have used anyway rather than to the webview's default. +const SERIF_FALLBACK = `Georgia, "Times New Roman", serif`; +const SANS_FALLBACK = `ui-sans-serif, system-ui, -apple-system, sans-serif`; + +export function bundledFont(id: string): BundledFont | undefined { + return BUNDLED_FONTS.find((f) => f.id === id); +} + +/** + * A `FontRef` as one string, which is what a `