summaryrefslogtreecommitdiffhomepage
path: root/packages/ui/src/font-loader.ts
blob: f2b1e6be133efffdec46cf556a0e3fa1c083cf12 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
type MonoFont = {
  id: string
  family: string
  regular: string
  bold: string
}

let files: Record<string, () => Promise<string>> | undefined

function getFiles() {
  if (files) return files
  files = import.meta.glob("./assets/fonts/*.woff2", { import: "default" }) as Record<string, () => Promise<string>>
  return files
}

export const MONO_NERD_FONTS = [
  {
    id: "jetbrains-mono",
    family: "JetBrains Mono Nerd Font",
    regular: "./assets/fonts/jetbrains-mono-nerd-font.woff2",
    bold: "./assets/fonts/jetbrains-mono-nerd-font-bold.woff2",
  },
  {
    id: "fira-code",
    family: "Fira Code Nerd Font",
    regular: "./assets/fonts/fira-code-nerd-font.woff2",
    bold: "./assets/fonts/fira-code-nerd-font-bold.woff2",
  },
  {
    id: "cascadia-code",
    family: "Cascadia Code Nerd Font",
    regular: "./assets/fonts/cascadia-code-nerd-font.woff2",
    bold: "./assets/fonts/cascadia-code-nerd-font-bold.woff2",
  },
  {
    id: "hack",
    family: "Hack Nerd Font",
    regular: "./assets/fonts/hack-nerd-font.woff2",
    bold: "./assets/fonts/hack-nerd-font-bold.woff2",
  },
  {
    id: "source-code-pro",
    family: "Source Code Pro Nerd Font",
    regular: "./assets/fonts/source-code-pro-nerd-font.woff2",
    bold: "./assets/fonts/source-code-pro-nerd-font-bold.woff2",
  },
  {
    id: "inconsolata",
    family: "Inconsolata Nerd Font",
    regular: "./assets/fonts/inconsolata-nerd-font.woff2",
    bold: "./assets/fonts/inconsolata-nerd-font-bold.woff2",
  },
  {
    id: "roboto-mono",
    family: "Roboto Mono Nerd Font",
    regular: "./assets/fonts/roboto-mono-nerd-font.woff2",
    bold: "./assets/fonts/roboto-mono-nerd-font-bold.woff2",
  },
  {
    id: "ubuntu-mono",
    family: "Ubuntu Mono Nerd Font",
    regular: "./assets/fonts/ubuntu-mono-nerd-font.woff2",
    bold: "./assets/fonts/ubuntu-mono-nerd-font-bold.woff2",
  },
  {
    id: "intel-one-mono",
    family: "Intel One Mono Nerd Font",
    regular: "./assets/fonts/intel-one-mono-nerd-font.woff2",
    bold: "./assets/fonts/intel-one-mono-nerd-font-bold.woff2",
  },
  {
    id: "meslo-lgs",
    family: "Meslo LGS Nerd Font",
    regular: "./assets/fonts/meslo-lgs-nerd-font.woff2",
    bold: "./assets/fonts/meslo-lgs-nerd-font-bold.woff2",
  },
  {
    id: "iosevka",
    family: "Iosevka Nerd Font",
    regular: "./assets/fonts/iosevka-nerd-font.woff2",
    bold: "./assets/fonts/iosevka-nerd-font-bold.woff2",
  },
  {
    id: "geist-mono",
    family: "GeistMono Nerd Font",
    regular: "./assets/fonts/GeistMonoNerdFontMono-Regular.woff2",
    bold: "./assets/fonts/GeistMonoNerdFontMono-Bold.woff2",
  },
] satisfies MonoFont[]

const mono = Object.fromEntries(MONO_NERD_FONTS.map((font) => [font.id, font])) as Record<string, MonoFont>
const loads = new Map<string, Promise<void>>()

function css(font: { family: string; regular: string; bold: string }) {
  return `
    @font-face {
      font-family: "${font.family}";
      src: url("${font.regular}") format("woff2");
      font-display: swap;
      font-style: normal;
      font-weight: 400;
    }
    @font-face {
      font-family: "${font.family}";
      src: url("${font.bold}") format("woff2");
      font-display: swap;
      font-style: normal;
      font-weight: 700;
    }
  `
}

export function ensureMonoFont(id: string | undefined) {
  if (!id || id === "ibm-plex-mono") return Promise.resolve()
  if (typeof document !== "object") return Promise.resolve()
  const font = mono[id]
  if (!font) return Promise.resolve()
  const styleId = `oc-font-${font.id}`
  if (document.getElementById(styleId)) return Promise.resolve()
  const hit = loads.get(font.id)
  if (hit) return hit
  const files = getFiles()
  const load = Promise.all([files[font.regular]?.(), files[font.bold]?.()]).then(([regular, bold]) => {
    if (!regular || !bold) return
    if (document.getElementById(styleId)) return
    const style = document.createElement("style")
    style.id = styleId
    style.textContent = css({ family: font.family, regular, bold })
    document.head.appendChild(style)
  })
  loads.set(font.id, load)
  return load
}