Jelajahi Sumber

add Iosevka custom font

Aneurin Barker Snook 11 bulan lalu
induk
melakukan
17b1113461

+ 29 - 0
fonts/IosevkaCustom@30.3.0/README.md

@@ -0,0 +1,29 @@
+# Iosevka Custom build plan
+
+This build plan includes only glyphs `U+0000-036F` to reduce the filesize of font files (which are much larger than normal for the web, but I _really_ like it).
+
+Font files are stored as [public assets](../../public/assets/IosevkaCustom@30.3.0/) with a custom stylesheet for loading.
+
+## Usage
+
+To rebuild the font files for any reason, replicate the process:
+
+1. [Import/customise as necessary](https://typeof.net/Iosevka/customizer)
+2. [Make any further changes by hand in the generated TOML](https://github.com/be5invis/Iosevka/blob/main/doc/custom-build.md)
+3. Install the Iosevka repository and dependencies, using the instructions in the link above
+4. Execute `npm run build webfont-unhinted::IosevkaCustom`
+5. Execute `cp dist/IosevkaCustom/WOFF2-Unhinted/*.woff2 <project-root>/public/assets/IosevkaCustom@30.3.0`
+
+When excluding glyphs, [codepoints.net](https://codepoints.net/basic_multilingual_plane) is a helpful reference. [Convert the hexadecimal values to decimal](https://www.rapidtables.com/convert/number/hex-to-decimal.html) for use in TOML.
+
+> Note: the font directory is named for the [latest version at the time of writing](https://github.com/be5invis/Iosevka/releases/tag/v30.3.0) and should be updated as applicable if the font files are rebuilt in future.
+
+## Issues
+
+This solution is work in progress, mainly because font files are quite large. I have already taken some steps to reduce client-side impact:
+
+- Removed glyphs outside the main latin range, since I don't use them
+- Used unhinted font files, which causes console warnings (`downloadable font: maxp: Bad maxZones: 0`) but reduces file size noticeably
+- [Deferred loading font stylesheet](https://stackoverflow.com/a/65076370) to prioritise other resources
+
+There may be opportunity for further optimisation, but for now I'm happy especially since all other resources are so lightweight.

+ 37 - 0
fonts/IosevkaCustom@30.3.0/private-build-plans.toml

@@ -0,0 +1,37 @@
+[buildPlans.IosevkaCustom]
+family = "Iosevka Custom"
+spacing = "quasi-proportional"
+serifs = "sans"
+noCvSs = true
+exportGlyphNames = false
+noLigation = true
+
+[buildPlans.IosevkaCustom.excludeChars]
+ranges = [[880,65535]]
+
+[buildPlans.IosevkaCustom.weights.Regular]
+shape = 400
+menu = 400
+css = 400
+
+[buildPlans.IosevkaCustom.weights.Bold]
+shape = 700
+menu = 700
+css = 700
+
+[buildPlans.IosevkaCustom.widths.Normal]
+shape = 500
+menu = 5
+css = "normal"
+
+[buildPlans.IosevkaCustom.slopes.Upright]
+angle = 0
+shape = "upright"
+menu = "upright"
+css = "normal"
+
+[buildPlans.IosevkaCustom.slopes.Italic]
+angle = 9.4
+shape = "italic"
+menu = "italic"
+css = "italic"

+ 2 - 4
index.html

@@ -5,9 +5,7 @@
     <!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title>Aneurin Barker Snook</title>
-    <link rel="preconnect" href="https://fonts.googleapis.com">
-    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
-    <link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap" rel="stylesheet">
+    <link x-data="font" rel="preload" as="style" onload="this.onload=null; this.rel='stylesheet'" x-bind:href="url">
   </head>
   <body>
     <main>
@@ -19,7 +17,7 @@
           </h1>
         </header>
 
-        <p class="description">Software engineer extraordinaire</p>
+        <p><em>Software engineer extraordinaire</em></p>
 
         <p>I have been working with computers for over twenty years and love to solve technical and business problems for a fair price.</p>
         <p>

TEMPAT SAMPAH
public/assets/IosevkaCustom@30.3.0/IosevkaCustom-Bold.woff2


TEMPAT SAMPAH
public/assets/IosevkaCustom@30.3.0/IosevkaCustom-BoldItalic.woff2


TEMPAT SAMPAH
public/assets/IosevkaCustom@30.3.0/IosevkaCustom-Italic.woff2


TEMPAT SAMPAH
public/assets/IosevkaCustom@30.3.0/IosevkaCustom-Regular.woff2


+ 37 - 0
public/assets/IosevkaCustom@30.3.0/style.css

@@ -0,0 +1,37 @@
+/* regular */
+@font-face {
+  font-family: 'Iosevka Custom';
+  font-weight: 400;
+  font-display: swap;
+  src: url(IosevkaCustom-Regular.woff2) format('woff2');
+  unicode-range: U+0000-0369;
+}
+
+/* bold */
+@font-face {
+  font-family: 'Iosevka Custom';
+  font-weight: 700;
+  font-display: swap;
+  src: url(IosevkaCustom-Bold.woff2) format('woff2');
+  unicode-range: U+0000-0369;
+}
+
+/* italic */
+@font-face {
+  font-family: 'Iosevka Custom';
+  font-style: italic;
+  font-weight: 400;
+  font-display: swap;
+  src: url(IosevkaCustom-Italic.woff2) format('woff2');
+  unicode-range: U+0000-0369;
+}
+
+/* bold italic */
+@font-face {
+  font-family: 'Iosevka Custom';
+  font-style: italic;
+  font-weight: 700;
+  font-display: swap;
+  src: url(IosevkaCustom-BoldItalic.woff2) format('woff2');
+  unicode-range: U+0000-0369;
+}

+ 0 - 0
public/skills.json → public/data/skills.json


+ 11 - 0
src/components/Font.ts

@@ -0,0 +1,11 @@
+export interface FontState {
+  url: string
+}
+
+export default function Font(): FontState {
+  const url = `//${document.location.host}/assets/IosevkaCustom@30.3.0/style.css`
+
+  return {
+    url,
+  }
+}

+ 3 - 1
src/components/Skills.ts

@@ -13,6 +13,8 @@ export interface SkillsState {
 }
 
 export default function Skills(): SkillsState {
+  const url = `//${document.location.host}/data/skills.json`
+
   function readCurrentTag() {
     const usp = new URLSearchParams(window.location.search)
     return usp.get('skill')
@@ -45,7 +47,7 @@ export default function Skills(): SkillsState {
       this.currentTag = tag
 
       try {
-        const res = await request.get(`//${document.location.host}/skills.json`)
+        const res = await request.get(url)
         this.skills = (res.json as Skill[]).sort((a, b) => a.name.localeCompare(b.name))
         updateVisibleSkills.apply(this)
       } catch (err) {

+ 2 - 0
src/main.ts

@@ -3,6 +3,7 @@ import Alpine from 'alpinejs'
 import Analytics from './components/Analytics'
 import Color from './components/Color'
 import Contact from './components/Contact'
+import Font from './components/Font'
 import Skills from './components/Skills'
 
 function main() {
@@ -10,6 +11,7 @@ function main() {
   Alpine.data('analytics', Analytics(import.meta.env.VITE_ANALYTICS_WEBSITE_ID || ''))
   Alpine.data('color', Color)
   Alpine.data('contact', Contact)
+  Alpine.data('font', Font)
   Alpine.data('skills', Skills)
   Alpine.start()
 }

+ 16 - 8
src/style.scss

@@ -2,6 +2,9 @@ $bp-tablet: 600px;
 $bp-desktop: 900px;
 $bp-super: 1200px;
 
+$font-weight: 400;
+$font-weight-bold: 700;
+
 $link-border-width: 0.2rem;
 
 @mixin prefer-light {
@@ -23,8 +26,9 @@ $link-border-width: 0.2rem;
 }
 
 :root {
-  font-family: 'Roboto Mono', monospace;
+  font-family: 'Iosevka Custom', monospace;
   font-size: 12pt;
+  font-weight: 400;
 
   @include prefer-light;
 
@@ -71,7 +75,7 @@ a {
 
 h1 {
   font-size: 2rem;
-  font-weight: 700;
+  font-weight: $font-weight-bold;
   line-height: 1.4em;
   margin: 0;
   padding: 0;
@@ -79,7 +83,7 @@ h1 {
 
 h2 {
   font-size: 1.4rem;
-  font-weight: 700;
+  font-weight: $font-weight-bold;
   line-height: 1em;
   margin: 0;
   padding: 0;
@@ -87,7 +91,7 @@ h2 {
 
 h3 {
   font-size: 1rem;
-  font-weight: 700;
+  font-weight: $font-weight-bold;
   line-height: 1em;
   margin: 0;
   padding: 0;
@@ -98,6 +102,14 @@ p {
   margin: 1rem 0;
 }
 
+em {
+  font-style: italic;
+}
+
+strong {
+  font-weight: 700;
+}
+
 ul {
   display: flex;
   flex-direction: column;
@@ -132,10 +144,6 @@ main {
       display: initial;
     }
   }
-
-  .description {
-    font-style: italic;
-  }
 }
 
 #skills {