refactor changes

This commit is contained in:
pj committed 2026-08-30 16:59:00 +05:30
1 parent df1a447a79
commit d4318554f6
36 files changed
+1251 -291

No files matched your search

+15
View File
@@ -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.
+74
View File
@@ -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 <app-dir> copy, reporting what changed
// node bin/sync-fonts.mjs <app-dir> --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 <app-dir> [--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}`);
+111
View File
@@ -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;
}
+91
View File
@@ -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);
}
Binary file not shown.
+93
View File
@@ -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.
Binary file not shown.
Binary file not shown.
+93
View File
@@ -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.
Binary file not shown.
Binary file not shown.
+94
View File
@@ -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.
Binary file not shown.
Binary file not shown.
+93
View File
@@ -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.
Binary file not shown.
Binary file not shown.
+93
View File
@@ -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.
Binary file not shown.
Binary file not shown.
+93
View File
@@ -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.
Binary file not shown.
+20
View File
@@ -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"]
}
+233
View File
@@ -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 `<select>` value and a stored preference both need.
*
* The two-character tag is the whole point: a system family can be called "Literata" and must not
* come back as the bundled one.
*/
export function encodeRef(ref: FontRef): string {
return ref.kind === "bundled" ? `b:${ref.id}` : `s:${ref.family}`;
}
export function decodeRef(value: string): FontRef {
return value.startsWith("s:")
? { kind: "system", family: value.slice(2) }
: { kind: "bundled", id: value.slice(2) };
}
/** The bare family name, which is what a Typst preamble names a face by. */
export function fontFamilyName(ref: FontRef): string {
if (ref.kind === "system") return ref.family;
return bundledFont(ref.id)?.family ?? "Literata";
}
/** What a picker calls it. Identical to the family for a system face, which has no other name. */
export function fontLabel(ref: FontRef): string {
if (ref.kind === "system") return ref.family;
return bundledFont(ref.id)?.label ?? ref.id;
}
/** A CSS font stack, which is what goes into `--font-book` and `--font-heading`. */
export function fontStack(ref: FontRef): string {
if (ref.kind === "bundled") {
const font = bundledFont(ref.id);
if (!font) return `"Literata", ${SERIF_FALLBACK}`;
return `"${font.family}", ${font.category === "sans" ? SANS_FALLBACK : SERIF_FALLBACK}`;
}
return `"${ref.family}", ${SERIF_FALLBACK}`;
}
export function refsEqual(a: FontRef, b: FontRef): boolean {
if (a.kind === "bundled" && b.kind === "bundled") return a.id === b.id;
if (a.kind === "system" && b.kind === "system") return a.family === b.family;
return false;
}
export function fontsEqual(a: FontPair, b: FontPair): boolean {
return refsEqual(a.body, b.body) && refsEqual(a.heading, b.heading);
}
/** Which preset this pair is, or null for a combination somebody built themselves. */
export function pairingFor(fonts: FontPair): string | null {
const match = FONT_PAIRINGS.find(
(p) => refsEqual(p.body, fonts.body) && refsEqual(p.heading, fonts.heading),
);
return match?.id ?? null;
}
/**
* The faces an export has to be handed, split by where their bytes come from.
*
* Bundled faces come back as ids rather than as records, because the id is what crosses the IPC
* boundary: the backend already has the bytes compiled in and looks them up by id. Deduplicated,
* because the common case is one family in both slots and asking the backend to load a two megabyte
* variable file twice is two megabytes of IPC for nothing.
*/
export function fontsUsed(fonts: FontPair): { bundled: string[]; system: string[] } {
const usedBundled = new Set<string>();
const usedSystem = new Set<string>();
for (const ref of [fonts.body, fonts.heading]) {
if (ref.kind === "bundled") {
if (bundledFont(ref.id)) usedBundled.add(ref.id);
} else {
usedSystem.add(ref.family);
}
}
return { bundled: [...usedBundled], system: [...usedSystem] };
}
/** Anything that is not a `FontRef`, from a stored preference written by another version. */
export function isFontRef(value: unknown): value is FontRef {
if (typeof value !== "object" || value === null) return false;
const ref = value as { kind?: unknown; id?: unknown; family?: unknown };
if (ref.kind === "bundled") return typeof ref.id === "string" && bundledFont(ref.id) !== undefined;
return ref.kind === "system" && typeof ref.family === "string" && ref.family !== "";
}
+61
View File
@@ -0,0 +1,61 @@
// The title bar glyphs, drawn on a 24 unit grid for a 1.6 stroke.
//
// Here because the two apps kept drifting. Each had its own idea of what a search or a moon looked
// like, they were adjusted independently, and the result was two products from the same hand that
// did not look related. A path is a design decision, not a detail, and the fix for two copies of a
// decision is one copy.
//
// Paths and not an icon dependency: a set is six hundred kilobytes for the handful of shapes a
// title bar needs, and every one of these is a few dozen bytes.
//
// Each app renders these through its own `Icon` component. The two components are identical today
// and are deliberately not shared: one is React, which would make this package depend on React for
// twenty four lines, and a component is where an app is entitled to differ.
/** A pane and its divider. Also the preview dock in Margin, mirrored. */
export const SIDEBAR = "M3 4.5h18v15H3zM9 4.5v15";
/** Margin's preview dock: the same pane with the divider on the other side. */
export const DOCK = "M3 4.5h18v15H3zM14 4.5v15";
export const SEARCH = "M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14zM20 20l-4-4";
/** A capital A with a tick beside it: the letter a checker is looking at, checked. */
export const SPELLING = "M4 17l4-10 4 10M5.4 13.4h5.2M15 17l2.5 2.5L22 14";
/** Three lines of a paragraph and a squiggle under the last, which is the mark grammar leaves. */
export const GRAMMAR = "M4 7h16M4 12h12M4 17h7M13.5 18.5c1-1.2 2-1.2 3 0s2 1.2 3 0";
/**
* A capital A beside a lowercase a, which is what a font panel has been called since there were
* font panels.
*
* Two letterforms and not one on a rule: a letter over a full width line is the underline button in
* every editor anybody has used. The other constraint is SPELLING above, which is also built on a
* capital A; what separates them is the shape to its right, a round bowl here and an angular tick
* there, and that difference survives 16px in a way a crossbar's height would not.
*/
export const FONT =
"M2.5 18L6.5 6l4 12M4.3 14.2h4.4M17 11.3a3.2 3.2 0 1 0 0 6.4a3.2 3.2 0 0 0 0-6.4M20.2 11.3v6.7";
/** The page's two edges with a double headed arrow between them. */
export const WIDTH = "M3 5v14M21 5v14M7 12h10M7 12l3-3M7 12l3 3M17 12l-3-3M17 12l-3 3";
export const EXPORT = "M5 13v6h14v-6M12 16V3M8 7l4-4 4 4";
export const MOON = "M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z";
/**
* The sun, which is the one glyph here that is not a single path: the disc has to be a circle so
* that it stays round at every size, and the rays have to be a path so that they keep their caps.
* Rendered as two children rather than one `d`.
*/
export const SUN_RAYS =
"M12 2v2M12 20v2M2 12h2M20 12h2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M19.1 4.9l-1.4 1.4M6.3 17.7l-1.4 1.4";
export const SUN_DISC = { cx: 12, cy: 12, r: 4 } as const;
export const MORE = "M5 12h.01M12 12h.01M19 12h.01";
export const CLOSE = "M6 6l12 12M18 6L6 18";
export const CHECK = "M20 6L9 17l-5-5";
+5
View File
@@ -0,0 +1,5 @@
// Everything both apps draw from. Two entry points as well as this one, `margin-shared/fonts` and
// `margin-shared/icons`, so a module that only wants the glyphs does not pull in the catalogue.
export * from "./fonts";
export * as icons from "./icons";