Browse Source

fix(app): don't bundle fonts (#19329)

Adam 3 weeks ago
parent
commit
b8fb75a94a
86 changed files with 418 additions and 549 deletions
  1. 2 1
      packages/app/e2e/selectors.ts
  2. 242 53
      packages/app/e2e/settings/settings.spec.ts
  3. 52 46
      packages/app/src/components/settings-general.tsx
  4. 54 37
      packages/app/src/context/settings.tsx
  5. 4 15
      packages/app/src/i18n/ar.ts
  6. 4 15
      packages/app/src/i18n/br.ts
  7. 4 15
      packages/app/src/i18n/bs.ts
  8. 4 15
      packages/app/src/i18n/da.ts
  9. 4 15
      packages/app/src/i18n/de.ts
  10. 4 15
      packages/app/src/i18n/en.ts
  11. 4 15
      packages/app/src/i18n/es.ts
  12. 4 15
      packages/app/src/i18n/fr.ts
  13. 4 15
      packages/app/src/i18n/ja.ts
  14. 4 15
      packages/app/src/i18n/ko.ts
  15. 4 15
      packages/app/src/i18n/no.ts
  16. 4 15
      packages/app/src/i18n/pl.ts
  17. 4 15
      packages/app/src/i18n/ru.ts
  18. 4 15
      packages/app/src/i18n/th.ts
  19. 4 15
      packages/app/src/i18n/tr.ts
  20. 4 15
      packages/app/src/i18n/zh.ts
  21. 4 15
      packages/app/src/i18n/zht.ts
  22. 0 1
      packages/ui/package.json
  23. BIN
      packages/ui/src/assets/fonts/CaskaydiaCoveNerdFontMono-Bold.woff2
  24. BIN
      packages/ui/src/assets/fonts/CaskaydiaCoveNerdFontMono-Regular.woff2
  25. BIN
      packages/ui/src/assets/fonts/FiraCodeNerdFontMono-Bold.woff2
  26. BIN
      packages/ui/src/assets/fonts/FiraCodeNerdFontMono-Regular.woff2
  27. BIN
      packages/ui/src/assets/fonts/GeistMonoNerdFontMono-Bold.woff2
  28. BIN
      packages/ui/src/assets/fonts/GeistMonoNerdFontMono-Medium.woff2
  29. BIN
      packages/ui/src/assets/fonts/GeistMonoNerdFontMono-Regular.woff2
  30. BIN
      packages/ui/src/assets/fonts/HackNerdFontMono-Bold.woff2
  31. BIN
      packages/ui/src/assets/fonts/HackNerdFontMono-Regular.woff2
  32. BIN
      packages/ui/src/assets/fonts/InconsolataNerdFontMono-Bold.woff2
  33. BIN
      packages/ui/src/assets/fonts/InconsolataNerdFontMono-Regular.woff2
  34. BIN
      packages/ui/src/assets/fonts/IntoneMonoNerdFontMono-Bold.woff2
  35. BIN
      packages/ui/src/assets/fonts/IntoneMonoNerdFontMono-Regular.woff2
  36. BIN
      packages/ui/src/assets/fonts/JetBrainsMonoNerdFontMono-Bold.woff2
  37. BIN
      packages/ui/src/assets/fonts/JetBrainsMonoNerdFontMono-Regular.woff2
  38. BIN
      packages/ui/src/assets/fonts/MesloLGSNerdFontMono-Bold.woff2
  39. BIN
      packages/ui/src/assets/fonts/MesloLGSNerdFontMono-Regular.woff2
  40. BIN
      packages/ui/src/assets/fonts/RobotoMonoNerdFontMono-Bold.woff2
  41. BIN
      packages/ui/src/assets/fonts/RobotoMonoNerdFontMono-Regular.woff2
  42. BIN
      packages/ui/src/assets/fonts/SauceCodeProNerdFontMono-Bold.woff2
  43. BIN
      packages/ui/src/assets/fonts/SauceCodeProNerdFontMono-Regular.woff2
  44. BIN
      packages/ui/src/assets/fonts/UbuntuMonoNerdFontMono-Bold.woff2
  45. BIN
      packages/ui/src/assets/fonts/UbuntuMonoNerdFontMono-Regular.woff2
  46. 0 1
      packages/ui/src/assets/fonts/cascadia-code-nerd-font-bold.woff2
  47. 0 1
      packages/ui/src/assets/fonts/cascadia-code-nerd-font.woff2
  48. 0 1
      packages/ui/src/assets/fonts/fira-code-nerd-font-bold.woff2
  49. 0 1
      packages/ui/src/assets/fonts/fira-code-nerd-font.woff2
  50. BIN
      packages/ui/src/assets/fonts/geist-italic-medium.otf
  51. BIN
      packages/ui/src/assets/fonts/geist-italic-regular.otf
  52. BIN
      packages/ui/src/assets/fonts/geist-italic.ttf
  53. BIN
      packages/ui/src/assets/fonts/geist-italic.woff2
  54. BIN
      packages/ui/src/assets/fonts/geist-medium.otf
  55. 0 1
      packages/ui/src/assets/fonts/geist-mono-bold.woff2
  56. BIN
      packages/ui/src/assets/fonts/geist-mono-italic.ttf
  57. BIN
      packages/ui/src/assets/fonts/geist-mono-italic.woff2
  58. 0 1
      packages/ui/src/assets/fonts/geist-mono-medium.woff2
  59. BIN
      packages/ui/src/assets/fonts/geist-mono.ttf
  60. 0 1
      packages/ui/src/assets/fonts/geist-mono.woff2
  61. BIN
      packages/ui/src/assets/fonts/geist-regular.otf
  62. BIN
      packages/ui/src/assets/fonts/geist.ttf
  63. BIN
      packages/ui/src/assets/fonts/geist.woff2
  64. 0 1
      packages/ui/src/assets/fonts/hack-nerd-font-bold.woff2
  65. 0 1
      packages/ui/src/assets/fonts/hack-nerd-font.woff2
  66. BIN
      packages/ui/src/assets/fonts/ibm-plex-mono.otf
  67. 0 1
      packages/ui/src/assets/fonts/inconsolata-nerd-font-bold.woff2
  68. 0 1
      packages/ui/src/assets/fonts/inconsolata-nerd-font.woff2
  69. 0 1
      packages/ui/src/assets/fonts/intel-one-mono-nerd-font-bold.woff2
  70. 0 1
      packages/ui/src/assets/fonts/intel-one-mono-nerd-font.woff2
  71. BIN
      packages/ui/src/assets/fonts/inter-italic.otf
  72. BIN
      packages/ui/src/assets/fonts/inter-italic.woff2
  73. BIN
      packages/ui/src/assets/fonts/inter.otf
  74. BIN
      packages/ui/src/assets/fonts/iosevka-nerd-font-bold.woff2
  75. BIN
      packages/ui/src/assets/fonts/iosevka-nerd-font.woff2
  76. 0 1
      packages/ui/src/assets/fonts/jetbrains-mono-nerd-font-bold.woff2
  77. 0 1
      packages/ui/src/assets/fonts/jetbrains-mono-nerd-font.woff2
  78. 0 1
      packages/ui/src/assets/fonts/meslo-lgs-nerd-font-bold.woff2
  79. 0 1
      packages/ui/src/assets/fonts/meslo-lgs-nerd-font.woff2
  80. 0 1
      packages/ui/src/assets/fonts/roboto-mono-nerd-font-bold.woff2
  81. 0 1
      packages/ui/src/assets/fonts/roboto-mono-nerd-font.woff2
  82. 0 1
      packages/ui/src/assets/fonts/source-code-pro-nerd-font-bold.woff2
  83. 0 1
      packages/ui/src/assets/fonts/source-code-pro-nerd-font.woff2
  84. 0 1
      packages/ui/src/assets/fonts/ubuntu-mono-nerd-font-bold.woff2
  85. 0 1
      packages/ui/src/assets/fonts/ubuntu-mono-nerd-font.woff2
  86. 0 133
      packages/ui/src/font-loader.ts

+ 2 - 1
packages/app/e2e/selectors.ts

@@ -19,7 +19,8 @@ export const promptVariantSelector = '[data-component="prompt-variant-control"]'
 export const settingsLanguageSelectSelector = '[data-action="settings-language"]'
 export const settingsColorSchemeSelector = '[data-action="settings-color-scheme"]'
 export const settingsThemeSelector = '[data-action="settings-theme"]'
-export const settingsFontSelector = '[data-action="settings-font"]'
+export const settingsCodeFontSelector = '[data-action="settings-code-font"]'
+export const settingsUIFontSelector = '[data-action="settings-ui-font"]'
 export const settingsNotificationsAgentSelector = '[data-action="settings-notifications-agent"]'
 export const settingsNotificationsPermissionsSelector = '[data-action="settings-notifications-permissions"]'
 export const settingsNotificationsErrorsSelector = '[data-action="settings-notifications-errors"]'

+ 242 - 53
packages/app/e2e/settings/settings.spec.ts

@@ -2,7 +2,7 @@ import { test, expect, settingsKey } from "../fixtures"
 import { closeDialog, openSettings } from "../actions"
 import {
   settingsColorSchemeSelector,
-  settingsFontSelector,
+  settingsCodeFontSelector,
   settingsLanguageSelectSelector,
   settingsNotificationsAgentSelector,
   settingsNotificationsErrorsSelector,
@@ -12,6 +12,7 @@ import {
   settingsSoundsErrorsSelector,
   settingsSoundsPermissionsSelector,
   settingsThemeSelector,
+  settingsUIFontSelector,
   settingsUpdatesStartupSelector,
 } from "../selectors"
 
@@ -152,39 +153,199 @@ test("legacy oc-1 theme migrates to oc-2", async ({ page, gotoSession }) => {
     .toBeNull()
 })
 
-test("changing font persists in localStorage and updates CSS variable", async ({ page, gotoSession }) => {
+test("typing a code font with spaces persists and updates CSS variable", async ({ page, gotoSession }) => {
   await gotoSession()
 
   const dialog = await openSettings(page)
-  const select = dialog.locator(settingsFontSelector)
-  await expect(select).toBeVisible()
-
-  const initialFontFamily = await page.evaluate(() => {
-    return getComputedStyle(document.documentElement).getPropertyValue("--font-family-mono")
-  })
+  const input = dialog.locator(settingsCodeFontSelector)
+  await expect(input).toBeVisible()
+  await expect(input).toHaveAttribute("placeholder", "IBM Plex Mono")
+
+  const initialFontFamily = await page.evaluate(() =>
+    getComputedStyle(document.documentElement).getPropertyValue("--font-family-mono").trim(),
+  )
+  const initialUIFamily = await page.evaluate(() =>
+    getComputedStyle(document.documentElement).getPropertyValue("--font-family-sans").trim(),
+  )
   expect(initialFontFamily).toContain("IBM Plex Mono")
 
-  await select.locator('[data-slot="select-select-trigger"]').click()
+  const next = "Test Mono"
 
-  const items = page.locator('[data-slot="select-select-item"]')
-  await items.nth(2).click()
+  await input.click()
+  await input.clear()
+  await input.pressSequentially(next)
+  await expect(input).toHaveValue(next)
 
-  await page.waitForTimeout(100)
+  await expect
+    .poll(async () => {
+      return await page.evaluate((key) => {
+        const raw = localStorage.getItem(key)
+        return raw ? JSON.parse(raw) : null
+      }, settingsKey)
+    })
+    .toMatchObject({
+      appearance: {
+        font: next,
+      },
+    })
 
-  const stored = await page.evaluate((key) => {
-    const raw = localStorage.getItem(key)
-    return raw ? JSON.parse(raw) : null
-  }, settingsKey)
+  const newFontFamily = await page.evaluate(() =>
+    getComputedStyle(document.documentElement).getPropertyValue("--font-family-mono").trim(),
+  )
+  const newUIFamily = await page.evaluate(() =>
+    getComputedStyle(document.documentElement).getPropertyValue("--font-family-sans").trim(),
+  )
+  expect(newFontFamily).toContain(next)
+  expect(newFontFamily).not.toBe(initialFontFamily)
+  expect(newUIFamily).toBe(initialUIFamily)
+})
 
-  expect(stored?.appearance?.font).not.toBe("ibm-plex-mono")
+test("typing a UI font with spaces persists and updates CSS variable", async ({ page, gotoSession }) => {
+  await gotoSession()
 
-  const newFontFamily = await page.evaluate(() => {
-    return getComputedStyle(document.documentElement).getPropertyValue("--font-family-mono")
-  })
+  const dialog = await openSettings(page)
+  const input = dialog.locator(settingsUIFontSelector)
+  await expect(input).toBeVisible()
+  await expect(input).toHaveAttribute("placeholder", "Inter")
+
+  const initialFontFamily = await page.evaluate(() =>
+    getComputedStyle(document.documentElement).getPropertyValue("--font-family-sans").trim(),
+  )
+  const initialCodeFamily = await page.evaluate(() =>
+    getComputedStyle(document.documentElement).getPropertyValue("--font-family-mono").trim(),
+  )
+  expect(initialFontFamily).toContain("Inter")
+
+  const next = "Test Sans"
+
+  await input.click()
+  await input.clear()
+  await input.pressSequentially(next)
+  await expect(input).toHaveValue(next)
+
+  await expect
+    .poll(async () => {
+      return await page.evaluate((key) => {
+        const raw = localStorage.getItem(key)
+        return raw ? JSON.parse(raw) : null
+      }, settingsKey)
+    })
+    .toMatchObject({
+      appearance: {
+        uiFont: next,
+      },
+    })
+
+  const newFontFamily = await page.evaluate(() =>
+    getComputedStyle(document.documentElement).getPropertyValue("--font-family-sans").trim(),
+  )
+  const newCodeFamily = await page.evaluate(() =>
+    getComputedStyle(document.documentElement).getPropertyValue("--font-family-mono").trim(),
+  )
+  expect(newFontFamily).toContain(next)
   expect(newFontFamily).not.toBe(initialFontFamily)
+  expect(newCodeFamily).toBe(initialCodeFamily)
 })
 
-test("color scheme and font rehydrate after reload", async ({ page, gotoSession }) => {
+test("clearing the code font field restores the default placeholder and stack", async ({ page, gotoSession }) => {
+  await gotoSession()
+
+  const dialog = await openSettings(page)
+  const input = dialog.locator(settingsCodeFontSelector)
+  await expect(input).toBeVisible()
+
+  await input.click()
+  await input.clear()
+  await input.pressSequentially("Reset Mono")
+
+  await expect
+    .poll(async () => {
+      return await page.evaluate((key) => {
+        const raw = localStorage.getItem(key)
+        return raw ? JSON.parse(raw) : null
+      }, settingsKey)
+    })
+    .toMatchObject({
+      appearance: {
+        font: "Reset Mono",
+      },
+    })
+
+  await input.clear()
+  await input.press("Space")
+  await expect(input).toHaveValue("")
+  await expect(input).toHaveAttribute("placeholder", "IBM Plex Mono")
+
+  await expect
+    .poll(async () => {
+      return await page.evaluate((key) => {
+        const raw = localStorage.getItem(key)
+        return raw ? JSON.parse(raw) : null
+      }, settingsKey)
+    })
+    .toMatchObject({
+      appearance: {
+        font: "",
+      },
+    })
+
+  const fontFamily = await page.evaluate(() =>
+    getComputedStyle(document.documentElement).getPropertyValue("--font-family-mono").trim(),
+  )
+  expect(fontFamily).toContain("IBM Plex Mono")
+  expect(fontFamily).not.toContain("Reset Mono")
+})
+
+test("clearing the UI font field restores the default placeholder and stack", async ({ page, gotoSession }) => {
+  await gotoSession()
+
+  const dialog = await openSettings(page)
+  const input = dialog.locator(settingsUIFontSelector)
+  await expect(input).toBeVisible()
+
+  await input.click()
+  await input.clear()
+  await input.pressSequentially("Reset Sans")
+
+  await expect
+    .poll(async () => {
+      return await page.evaluate((key) => {
+        const raw = localStorage.getItem(key)
+        return raw ? JSON.parse(raw) : null
+      }, settingsKey)
+    })
+    .toMatchObject({
+      appearance: {
+        uiFont: "Reset Sans",
+      },
+    })
+
+  await input.clear()
+  await input.press("Space")
+  await expect(input).toHaveValue("")
+  await expect(input).toHaveAttribute("placeholder", "Inter")
+
+  await expect
+    .poll(async () => {
+      return await page.evaluate((key) => {
+        const raw = localStorage.getItem(key)
+        return raw ? JSON.parse(raw) : null
+      }, settingsKey)
+    })
+    .toMatchObject({
+      appearance: {
+        uiFont: "",
+      },
+    })
+
+  const fontFamily = await page.evaluate(() =>
+    getComputedStyle(document.documentElement).getPropertyValue("--font-family-sans").trim(),
+  )
+  expect(fontFamily).toContain("Inter")
+  expect(fontFamily).not.toContain("Reset Sans")
+})
+
+test("color scheme, code font, and UI font rehydrate after reload", async ({ page, gotoSession }) => {
   await gotoSession()
 
   const dialog = await openSettings(page)
@@ -195,31 +356,35 @@ test("color scheme and font rehydrate after reload", async ({ page, gotoSession
   await page.locator('[data-slot="select-select-item"]').filter({ hasText: "Dark" }).click()
   await expect(page.locator("html")).toHaveAttribute("data-color-scheme", "dark")
 
-  const fontSelect = dialog.locator(settingsFontSelector)
-  await expect(fontSelect).toBeVisible()
+  const code = dialog.locator(settingsCodeFontSelector)
+  const ui = dialog.locator(settingsUIFontSelector)
+  await expect(code).toBeVisible()
+  await expect(ui).toBeVisible()
 
-  const initialFontFamily = await page.evaluate(() => {
-    return getComputedStyle(document.documentElement).getPropertyValue("--font-family-mono").trim()
-  })
+  const initialMono = await page.evaluate(() =>
+    getComputedStyle(document.documentElement).getPropertyValue("--font-family-mono").trim(),
+  )
+  const initialSans = await page.evaluate(() =>
+    getComputedStyle(document.documentElement).getPropertyValue("--font-family-sans").trim(),
+  )
 
   const initialSettings = await page.evaluate((key) => {
     const raw = localStorage.getItem(key)
     return raw ? JSON.parse(raw) : null
   }, settingsKey)
 
-  const currentFont =
-    (await fontSelect.locator('[data-slot="select-select-trigger-value"]').textContent())?.trim() ?? ""
-  await fontSelect.locator('[data-slot="select-select-trigger"]').click()
+  const mono = initialSettings?.appearance?.font === "Reload Mono" ? "Reload Mono 2" : "Reload Mono"
+  const sans = initialSettings?.appearance?.uiFont === "Reload Sans" ? "Reload Sans 2" : "Reload Sans"
 
-  const fontItems = page.locator('[data-slot="select-select-item"]')
-  expect(await fontItems.count()).toBeGreaterThan(1)
+  await code.click()
+  await code.clear()
+  await code.pressSequentially(mono)
+  await expect(code).toHaveValue(mono)
 
-  if (currentFont) {
-    await fontItems.filter({ hasNotText: currentFont }).first().click()
-  }
-  if (!currentFont) {
-    await fontItems.nth(1).click()
-  }
+  await ui.click()
+  await ui.clear()
+  await ui.pressSequentially(sans)
+  await expect(ui).toHaveValue(sans)
 
   await expect
     .poll(async () => {
@@ -230,7 +395,8 @@ test("color scheme and font rehydrate after reload", async ({ page, gotoSession
     })
     .toMatchObject({
       appearance: {
-        font: expect.any(String),
+        font: mono,
+        uiFont: sans,
       },
     })
 
@@ -239,11 +405,18 @@ test("color scheme and font rehydrate after reload", async ({ page, gotoSession
     return raw ? JSON.parse(raw) : null
   }, settingsKey)
 
-  const updatedFontFamily = await page.evaluate(() => {
-    return getComputedStyle(document.documentElement).getPropertyValue("--font-family-mono").trim()
-  })
-  expect(updatedFontFamily).not.toBe(initialFontFamily)
-  expect(updatedSettings?.appearance?.font).not.toBe(initialSettings?.appearance?.font)
+  const updatedMono = await page.evaluate(() =>
+    getComputedStyle(document.documentElement).getPropertyValue("--font-family-mono").trim(),
+  )
+  const updatedSans = await page.evaluate(() =>
+    getComputedStyle(document.documentElement).getPropertyValue("--font-family-sans").trim(),
+  )
+  expect(updatedMono).toContain(mono)
+  expect(updatedMono).not.toBe(initialMono)
+  expect(updatedSans).toContain(sans)
+  expect(updatedSans).not.toBe(initialSans)
+  expect(updatedSettings?.appearance?.font).toBe(mono)
+  expect(updatedSettings?.appearance?.uiFont).toBe(sans)
 
   await closeDialog(page, dialog)
   await page.reload()
@@ -259,7 +432,8 @@ test("color scheme and font rehydrate after reload", async ({ page, gotoSession
     })
     .toMatchObject({
       appearance: {
-        font: updatedSettings?.appearance?.font,
+        font: mono,
+        uiFont: sans,
       },
     })
 
@@ -270,17 +444,32 @@ test("color scheme and font rehydrate after reload", async ({ page, gotoSession
 
   await expect
     .poll(async () => {
-      return await page.evaluate(() => {
-        return getComputedStyle(document.documentElement).getPropertyValue("--font-family-mono").trim()
-      })
+      return await page.evaluate(() =>
+        getComputedStyle(document.documentElement).getPropertyValue("--font-family-mono").trim(),
+      )
     })
-    .not.toBe(initialFontFamily)
+    .toContain(mono)
 
-  const rehydratedFontFamily = await page.evaluate(() => {
-    return getComputedStyle(document.documentElement).getPropertyValue("--font-family-mono").trim()
-  })
-  expect(rehydratedFontFamily).not.toBe(initialFontFamily)
-  expect(rehydratedSettings?.appearance?.font).toBe(updatedSettings?.appearance?.font)
+  await expect
+    .poll(async () => {
+      return await page.evaluate(() =>
+        getComputedStyle(document.documentElement).getPropertyValue("--font-family-sans").trim(),
+      )
+    })
+    .toContain(sans)
+
+  const rehydratedMono = await page.evaluate(() =>
+    getComputedStyle(document.documentElement).getPropertyValue("--font-family-mono").trim(),
+  )
+  const rehydratedSans = await page.evaluate(() =>
+    getComputedStyle(document.documentElement).getPropertyValue("--font-family-sans").trim(),
+  )
+  expect(rehydratedMono).toContain(mono)
+  expect(rehydratedMono).not.toBe(initialMono)
+  expect(rehydratedSans).toContain(sans)
+  expect(rehydratedSans).not.toBe(initialSans)
+  expect(rehydratedSettings?.appearance?.font).toBe(mono)
+  expect(rehydratedSettings?.appearance?.uiFont).toBe(sans)
 })
 
 test("toggling notification agent switch updates localStorage", async ({ page, gotoSession }) => {

+ 52 - 46
packages/app/src/components/settings-general.tsx

@@ -4,12 +4,21 @@ import { Button } from "@opencode-ai/ui/button"
 import { Icon } from "@opencode-ai/ui/icon"
 import { Select } from "@opencode-ai/ui/select"
 import { Switch } from "@opencode-ai/ui/switch"
+import { TextField } from "@opencode-ai/ui/text-field"
 import { Tooltip } from "@opencode-ai/ui/tooltip"
 import { useTheme, type ColorScheme } from "@opencode-ai/ui/theme/context"
 import { showToast } from "@opencode-ai/ui/toast"
 import { useLanguage } from "@/context/language"
 import { usePlatform } from "@/context/platform"
-import { useSettings, monoFontFamily } from "@/context/settings"
+import {
+  monoDefault,
+  monoFontFamily,
+  monoInput,
+  sansDefault,
+  sansFontFamily,
+  sansInput,
+  useSettings,
+} from "@/context/settings"
 import { playSoundById, SOUND_OPTIONS } from "@/utils/sound"
 import { Link } from "./link"
 import { SettingsList } from "./settings-list"
@@ -25,13 +34,6 @@ type ThemeOption = {
   name: string
 }
 
-let font: Promise<typeof import("@opencode-ai/ui/font-loader")> | undefined
-
-function loadFont() {
-  font ??= import("@opencode-ai/ui/font-loader")
-  return font
-}
-
 // To prevent audio from overlapping/playing very quickly when navigating the settings menus,
 // delay the playback by 100ms during quick selection changes and pause existing sounds.
 const stopDemoSound = () => {
@@ -149,25 +151,10 @@ export const SettingsGeneral: Component = () => {
     })),
   )
 
-  const fontOptions = [
-    { value: "ibm-plex-mono", label: "font.option.ibmPlexMono" },
-    { value: "cascadia-code", label: "font.option.cascadiaCode" },
-    { value: "fira-code", label: "font.option.firaCode" },
-    { value: "hack", label: "font.option.hack" },
-    { value: "inconsolata", label: "font.option.inconsolata" },
-    { value: "intel-one-mono", label: "font.option.intelOneMono" },
-    { value: "iosevka", label: "font.option.iosevka" },
-    { value: "jetbrains-mono", label: "font.option.jetbrainsMono" },
-    { value: "meslo-lgs", label: "font.option.mesloLgs" },
-    { value: "roboto-mono", label: "font.option.robotoMono" },
-    { value: "source-code-pro", label: "font.option.sourceCodePro" },
-    { value: "ubuntu-mono", label: "font.option.ubuntuMono" },
-    { value: "geist-mono", label: "font.option.geistMono" },
-  ] as const
-  const fontOptionsList = [...fontOptions]
-
   const noneSound = { id: "none", label: "sound.option.none" } as const
   const soundOptions = [noneSound, ...SOUND_OPTIONS]
+  const mono = () => monoInput(settings.appearance.font())
+  const sans = () => sansInput(settings.appearance.uiFont())
 
   const soundSelectProps = (
     enabled: () => boolean,
@@ -334,31 +321,50 @@ export const SettingsGeneral: Component = () => {
           />
         </SettingsRow>
 
+        <SettingsRow
+          title={language.t("settings.general.row.uiFont.title")}
+          description={language.t("settings.general.row.uiFont.description")}
+        >
+          <div class="w-full sm:w-[220px]">
+            <TextField
+              data-action="settings-ui-font"
+              label={language.t("settings.general.row.uiFont.title")}
+              hideLabel
+              type="text"
+              value={sans()}
+              onChange={(value) => settings.appearance.setUIFont(value)}
+              placeholder={sansDefault}
+              spellcheck={false}
+              autocorrect="off"
+              autocomplete="off"
+              autocapitalize="off"
+              class="text-12-regular"
+              style={{ "font-family": sansFontFamily(settings.appearance.uiFont()) }}
+            />
+          </div>
+        </SettingsRow>
+
         <SettingsRow
           title={language.t("settings.general.row.font.title")}
           description={language.t("settings.general.row.font.description")}
         >
-          <Select
-            data-action="settings-font"
-            options={fontOptionsList}
-            current={fontOptionsList.find((o) => o.value === settings.appearance.font())}
-            value={(o) => o.value}
-            label={(o) => language.t(o.label)}
-            onHighlight={(option) => {
-              void loadFont().then((x) => x.ensureMonoFont(option?.value))
-            }}
-            onSelect={(option) => option && settings.appearance.setFont(option.value)}
-            variant="secondary"
-            size="small"
-            triggerVariant="settings"
-            triggerStyle={{ "font-family": monoFontFamily(settings.appearance.font()), "min-width": "180px" }}
-          >
-            {(option) => (
-              <span style={{ "font-family": monoFontFamily(option?.value) }}>
-                {option ? language.t(option.label) : ""}
-              </span>
-            )}
-          </Select>
+          <div class="w-full sm:w-[220px]">
+            <TextField
+              data-action="settings-code-font"
+              label={language.t("settings.general.row.font.title")}
+              hideLabel
+              type="text"
+              value={mono()}
+              onChange={(value) => settings.appearance.setFont(value)}
+              placeholder={monoDefault}
+              spellcheck={false}
+              autocorrect="off"
+              autocomplete="off"
+              autocapitalize="off"
+              class="text-12-regular"
+              style={{ "font-family": monoFontFamily(settings.appearance.font()) }}
+            />
+          </div>
         </SettingsRow>
       </SettingsList>
     </div>

+ 54 - 37
packages/app/src/context/settings.tsx

@@ -33,6 +33,7 @@ export interface Settings {
   appearance: {
     fontSize: number
     font: string
+    uiFont: string
   }
   keybinds: Record<string, string>
   permissions: {
@@ -42,6 +43,49 @@ export interface Settings {
   sounds: SoundSettings
 }
 
+export const monoDefault = "IBM Plex Mono"
+export const sansDefault = "Inter"
+
+const monoFallback =
+  'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
+const sansFallback = 'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'
+
+const monoBase = `"${monoDefault}", "IBM Plex Mono Fallback", ${monoFallback}`
+const sansBase = `"${sansDefault}", "Inter Fallback", ${sansFallback}`
+const monoKey = "ibm-plex-mono"
+
+function input(font: string | undefined, key?: string) {
+  if (!font || font === key || !font.trim()) return ""
+  return font
+}
+
+function family(font: string) {
+  if (/^[\w-]+$/.test(font)) return font
+  return `"${font.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`
+}
+
+function stack(font: string | undefined, base: string, key?: string) {
+  const value = input(font, key).trim()
+  if (!value) return base
+  return `${family(value)}, ${base}`
+}
+
+export function monoInput(font: string | undefined) {
+  return input(font, monoKey)
+}
+
+export function sansInput(font: string | undefined) {
+  return input(font)
+}
+
+export function monoFontFamily(font: string | undefined) {
+  return stack(font, monoBase, monoKey)
+}
+
+export function sansFontFamily(font: string | undefined) {
+  return stack(font, sansBase)
+}
+
 const defaultSettings: Settings = {
   general: {
     autoSave: true,
@@ -56,7 +100,8 @@ const defaultSettings: Settings = {
   },
   appearance: {
     fontSize: 14,
-    font: "ibm-plex-mono",
+    font: "",
+    uiFont: "",
   },
   keybinds: {},
   permissions: {
@@ -77,40 +122,10 @@ const defaultSettings: Settings = {
   },
 }
 
-const monoFallback =
-  'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
-
-const monoFonts: Record<string, string> = {
-  "ibm-plex-mono": `"IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
-  "cascadia-code": `"Cascadia Code Nerd Font", "Cascadia Code NF", "Cascadia Mono NF", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
-  "fira-code": `"Fira Code Nerd Font", "FiraMono Nerd Font", "FiraMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
-  hack: `"Hack Nerd Font", "Hack Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
-  inconsolata: `"Inconsolata Nerd Font", "Inconsolata Nerd Font Mono","IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
-  "intel-one-mono": `"Intel One Mono Nerd Font", "IntoneMono Nerd Font", "IntoneMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
-  iosevka: `"Iosevka Nerd Font", "Iosevka Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
-  "jetbrains-mono": `"JetBrains Mono Nerd Font", "JetBrainsMono Nerd Font Mono", "JetBrainsMonoNL Nerd Font", "JetBrainsMonoNL Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
-  "meslo-lgs": `"Meslo LGS Nerd Font", "MesloLGS Nerd Font", "MesloLGM Nerd Font", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
-  "roboto-mono": `"Roboto Mono Nerd Font", "RobotoMono Nerd Font", "RobotoMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
-  "source-code-pro": `"Source Code Pro Nerd Font", "SauceCodePro Nerd Font", "SauceCodePro Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
-  "ubuntu-mono": `"Ubuntu Mono Nerd Font", "UbuntuMono Nerd Font", "UbuntuMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
-  "geist-mono": `"GeistMono Nerd Font", "GeistMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
-}
-
-export function monoFontFamily(font: string | undefined) {
-  return monoFonts[font ?? defaultSettings.appearance.font] ?? monoFonts[defaultSettings.appearance.font]
-}
-
 function withFallback<T>(read: () => T | undefined, fallback: T) {
   return createMemo(() => read() ?? fallback)
 }
 
-let font: Promise<typeof import("@opencode-ai/ui/font-loader")> | undefined
-
-function loadFont() {
-  font ??= import("@opencode-ai/ui/font-loader")
-  return font
-}
-
 export const { use: useSettings, provider: SettingsProvider } = createSimpleContext({
   name: "Settings",
   init: () => {
@@ -118,11 +133,9 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
 
     createEffect(() => {
       if (typeof document === "undefined") return
-      const id = store.appearance?.font ?? defaultSettings.appearance.font
-      if (id !== defaultSettings.appearance.font) {
-        void loadFont().then((x) => x.ensureMonoFont(id))
-      }
-      document.documentElement.style.setProperty("--font-family-mono", monoFontFamily(id))
+      const root = document.documentElement
+      root.style.setProperty("--font-family-mono", monoFontFamily(store.appearance?.font))
+      root.style.setProperty("--font-family-sans", sansFontFamily(store.appearance?.uiFont))
     })
 
     return {
@@ -178,7 +191,11 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
         },
         font: withFallback(() => store.appearance?.font, defaultSettings.appearance.font),
         setFont(value: string) {
-          setStore("appearance", "font", value)
+          setStore("appearance", "font", value.trim() ? value : "")
+        },
+        uiFont: withFallback(() => store.appearance?.uiFont, defaultSettings.appearance.uiFont),
+        setUIFont(value: string) {
+          setStore("appearance", "uiFont", value.trim() ? value : "")
         },
       },
       keybinds: {

+ 4 - 15
packages/app/src/i18n/ar.ts

@@ -564,8 +564,10 @@ export const dict = {
   "settings.general.row.colorScheme.description": "اختر ما إذا كان OpenCode يتبع سمة النظام أو الفاتح أو الداكن",
   "settings.general.row.theme.title": "السمة",
   "settings.general.row.theme.description": "تخصيص سمة OpenCode.",
-  "settings.general.row.font.title": "الخط",
-  "settings.general.row.font.description": "تخصيص الخط الأحادي المستخدم في كتل التعليمات البرمجية",
+  "settings.general.row.font.title": "خط الكود",
+  "settings.general.row.font.description": "خصّص الخط المستخدم في كتل التعليمات البرمجية والطرفيات",
+  "settings.general.row.uiFont.title": "خط الواجهة",
+  "settings.general.row.uiFont.description": "خصّص الخط المستخدم في الواجهة بأكملها",
   "settings.general.row.followup.title": "سلوك المتابعة",
   "settings.general.row.followup.description": "اختر ما إذا كانت طلبات المتابعة توجه فورًا أو تنتظر في قائمة انتظار",
   "settings.general.row.followup.option.queue": "قائمة انتظار",
@@ -592,19 +594,6 @@ export const dict = {
   "settings.updates.action.checking": "جارٍ التحقق...",
   "settings.updates.toast.latest.title": "أنت على آخر إصدار",
   "settings.updates.toast.latest.description": "أنت تستخدم أحدث إصدار من OpenCode.",
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
   "sound.option.none": "بلا",
   "sound.option.alert01": "تنبيه 01",
   "sound.option.alert02": "تنبيه 02",

+ 4 - 15
packages/app/src/i18n/br.ts

@@ -571,8 +571,10 @@ export const dict = {
   "settings.general.row.colorScheme.description": "Escolha se o OpenCode segue o tema do sistema, claro ou escuro",
   "settings.general.row.theme.title": "Tema",
   "settings.general.row.theme.description": "Personalize como o OpenCode é tematizado.",
-  "settings.general.row.font.title": "Fonte",
-  "settings.general.row.font.description": "Personalize a fonte monoespaçada usada em blocos de código",
+  "settings.general.row.font.title": "Fonte de código",
+  "settings.general.row.font.description": "Personalize a fonte usada em blocos de código e terminais",
+  "settings.general.row.uiFont.title": "Fonte da interface",
+  "settings.general.row.uiFont.description": "Personalize a fonte usada em toda a interface",
   "settings.general.row.followup.title": "Comportamento de acompanhamento",
   "settings.general.row.followup.description":
     "Escolha se os prompts de acompanhamento orientam imediatamente ou esperam na fila",
@@ -600,19 +602,6 @@ export const dict = {
   "settings.updates.action.checking": "Verificando...",
   "settings.updates.toast.latest.title": "Você está atualizado",
   "settings.updates.toast.latest.description": "Você está usando a versão mais recente do OpenCode.",
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
   "sound.option.none": "Nenhum",
   "sound.option.alert01": "Alerta 01",
   "sound.option.alert02": "Alerta 02",

+ 4 - 15
packages/app/src/i18n/bs.ts

@@ -636,8 +636,10 @@ export const dict = {
   "settings.general.row.colorScheme.description": "Odaberi da li OpenCode prati sistemsku, svijetlu ili tamnu temu",
   "settings.general.row.theme.title": "Tema",
   "settings.general.row.theme.description": "Prilagodi temu OpenCode-a.",
-  "settings.general.row.font.title": "Font",
-  "settings.general.row.font.description": "Prilagodi monospace font koji se koristi u blokovima koda",
+  "settings.general.row.font.title": "Font za kod",
+  "settings.general.row.font.description": "Prilagodi font koji se koristi u blokovima koda i terminalima",
+  "settings.general.row.uiFont.title": "UI font",
+  "settings.general.row.uiFont.description": "Prilagodi font koji se koristi u cijelom interfejsu",
   "settings.general.row.followup.title": "Ponašanje nadovezivanja",
   "settings.general.row.followup.description": "Odaberi da li upiti nadovezivanja usmjeravaju odmah ili čekaju u redu",
   "settings.general.row.followup.option.queue": "Red čekanja",
@@ -667,19 +669,6 @@ export const dict = {
   "settings.updates.action.checking": "Provjera...",
   "settings.updates.toast.latest.title": "Sve je ažurno",
   "settings.updates.toast.latest.description": "Koristiš najnoviju verziju OpenCode-a.",
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
   "sound.option.none": "Nijedan",
   "sound.option.alert01": "Upozorenje 01",
   "sound.option.alert02": "Upozorenje 02",

+ 4 - 15
packages/app/src/i18n/da.ts

@@ -631,8 +631,10 @@ export const dict = {
   "settings.general.row.colorScheme.description": "Vælg om OpenCode følger systemets, lyst eller mørkt tema",
   "settings.general.row.theme.title": "Tema",
   "settings.general.row.theme.description": "Tilpas hvordan OpenCode er temabestemt.",
-  "settings.general.row.font.title": "Skrifttype",
-  "settings.general.row.font.description": "Tilpas mono-skrifttypen brugt i kodeblokke",
+  "settings.general.row.font.title": "Kode-skrifttype",
+  "settings.general.row.font.description": "Tilpas skrifttypen, der bruges i kodeblokke og terminaler",
+  "settings.general.row.uiFont.title": "UI-skrifttype",
+  "settings.general.row.uiFont.description": "Tilpas skrifttypen, der bruges i hele brugerfladen",
   "settings.general.row.followup.title": "Opfølgningsadfærd",
   "settings.general.row.followup.description": "Vælg om opfølgende forespørgsler skal styre straks eller vente i kø",
   "settings.general.row.followup.option.queue": "Kø",
@@ -662,19 +664,6 @@ export const dict = {
   "settings.updates.toast.latest.title": "Du er opdateret",
   "settings.updates.toast.latest.description": "Du kører den nyeste version af OpenCode.",
 
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
   "sound.option.none": "Ingen",
   "sound.option.alert01": "Alarm 01",
   "sound.option.alert02": "Alarm 02",

+ 4 - 15
packages/app/src/i18n/de.ts

@@ -581,8 +581,10 @@ export const dict = {
     "Wählen Sie, ob OpenCode dem System-, hellen oder dunklen Thema folgt",
   "settings.general.row.theme.title": "Thema",
   "settings.general.row.theme.description": "Das Thema von OpenCode anpassen.",
-  "settings.general.row.font.title": "Schriftart",
-  "settings.general.row.font.description": "Die in Codeblöcken verwendete Monospace-Schriftart anpassen",
+  "settings.general.row.font.title": "Code-Schriftart",
+  "settings.general.row.font.description": "Die in Codeblöcken und Terminals verwendete Schriftart anpassen",
+  "settings.general.row.uiFont.title": "UI-Schriftart",
+  "settings.general.row.uiFont.description": "Die im gesamten Interface verwendete Schriftart anpassen",
   "settings.general.row.followup.title": "Verhalten bei Folgefragen",
   "settings.general.row.followup.description":
     "Wählen Sie, ob Folgefragen sofort steuern oder in einer Warteschlange warten",
@@ -611,19 +613,6 @@ export const dict = {
   "settings.updates.action.checking": "Wird geprüft...",
   "settings.updates.toast.latest.title": "Du bist auf dem neuesten Stand",
   "settings.updates.toast.latest.description": "Du verwendest die aktuelle Version von OpenCode.",
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
   "sound.option.none": "Keine",
   "sound.option.alert01": "Alarm 01",
   "sound.option.alert02": "Alarm 02",

+ 4 - 15
packages/app/src/i18n/en.ts

@@ -729,8 +729,10 @@ export const dict = {
   "settings.general.row.colorScheme.description": "Choose whether OpenCode follows the system, light, or dark theme",
   "settings.general.row.theme.title": "Theme",
   "settings.general.row.theme.description": "Customise how OpenCode is themed.",
-  "settings.general.row.font.title": "Font",
-  "settings.general.row.font.description": "Customise the mono font used in code blocks",
+  "settings.general.row.font.title": "Code Font",
+  "settings.general.row.font.description": "Customise the font used in code blocks and terminals",
+  "settings.general.row.uiFont.title": "UI Font",
+  "settings.general.row.uiFont.description": "Customise the font used throughout the interface",
   "settings.general.row.followup.title": "Follow-up behavior",
   "settings.general.row.followup.description": "Choose whether follow-up prompts steer immediately or wait in a queue",
   "settings.general.row.followup.option.queue": "Queue",
@@ -760,19 +762,6 @@ export const dict = {
   "settings.updates.action.checking": "Checking...",
   "settings.updates.toast.latest.title": "You're up to date",
   "settings.updates.toast.latest.description": "You're running the latest version of OpenCode.",
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
   "sound.option.none": "None",
   "sound.option.alert01": "Alert 01",
   "sound.option.alert02": "Alert 02",

+ 4 - 15
packages/app/src/i18n/es.ts

@@ -639,8 +639,10 @@ export const dict = {
   "settings.general.row.colorScheme.description": "Elige si OpenCode sigue el tema del sistema, claro u oscuro",
   "settings.general.row.theme.title": "Tema",
   "settings.general.row.theme.description": "Personaliza el tema de OpenCode.",
-  "settings.general.row.font.title": "Fuente",
-  "settings.general.row.font.description": "Personaliza la fuente monoespaciada usada en bloques de código",
+  "settings.general.row.font.title": "Fuente de código",
+  "settings.general.row.font.description": "Personaliza la fuente usada en bloques de código y terminales",
+  "settings.general.row.uiFont.title": "Fuente de la interfaz",
+  "settings.general.row.uiFont.description": "Personaliza la fuente usada en toda la interfaz",
   "settings.general.row.followup.title": "Comportamiento de seguimiento",
   "settings.general.row.followup.description":
     "Elige si los prompts de seguimiento se dirigen inmediatamente o esperan en una cola",
@@ -672,19 +674,6 @@ export const dict = {
   "settings.updates.action.checking": "Buscando...",
   "settings.updates.toast.latest.title": "Estás al día",
   "settings.updates.toast.latest.description": "Estás usando la última versión de OpenCode.",
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
   "sound.option.none": "Ninguno",
   "sound.option.alert01": "Alerta 01",
   "sound.option.alert02": "Alerta 02",

+ 4 - 15
packages/app/src/i18n/fr.ts

@@ -578,8 +578,10 @@ export const dict = {
   "settings.general.row.colorScheme.description": "Choisissez si OpenCode suit le thème système, clair ou sombre",
   "settings.general.row.theme.title": "Thème",
   "settings.general.row.theme.description": "Personnaliser le thème d'OpenCode.",
-  "settings.general.row.font.title": "Police",
-  "settings.general.row.font.description": "Personnaliser la police mono utilisée dans les blocs de code",
+  "settings.general.row.font.title": "Police de code",
+  "settings.general.row.font.description": "Personnaliser la police utilisée dans les blocs de code et les terminaux",
+  "settings.general.row.uiFont.title": "Police de l'interface",
+  "settings.general.row.uiFont.description": "Personnaliser la police utilisée dans toute l'interface",
   "settings.general.row.followup.title": "Comportement de suivi",
   "settings.general.row.followup.description":
     "Choisissez si les messages de suivi dirigent immédiatement ou attendent dans une file d'attente",
@@ -608,19 +610,6 @@ export const dict = {
   "settings.updates.action.checking": "Vérification...",
   "settings.updates.toast.latest.title": "Vous êtes à jour",
   "settings.updates.toast.latest.description": "Vous utilisez la dernière version d'OpenCode.",
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
   "sound.option.none": "Aucun",
   "sound.option.alert01": "Alerte 01",
   "sound.option.alert02": "Alerte 02",

+ 4 - 15
packages/app/src/i18n/ja.ts

@@ -568,8 +568,10 @@ export const dict = {
   "settings.general.row.colorScheme.description": "OpenCodeがシステム、ライト、またはダークテーマに従うかを選択します",
   "settings.general.row.theme.title": "テーマ",
   "settings.general.row.theme.description": "OpenCodeのテーマをカスタマイズします。",
-  "settings.general.row.font.title": "フォント",
-  "settings.general.row.font.description": "コードブロックで使用する等幅フォントをカスタマイズします",
+  "settings.general.row.font.title": "コードフォント",
+  "settings.general.row.font.description": "コードブロックとターミナルで使用するフォントをカスタマイズします",
+  "settings.general.row.uiFont.title": "UIフォント",
+  "settings.general.row.uiFont.description": "インターフェース全体で使用するフォントをカスタマイズします",
   "settings.general.row.followup.title": "フォローアップの動作",
   "settings.general.row.followup.description":
     "フォローアッププロンプトを即座に実行するか、キューで待機させるかを選択します",
@@ -597,19 +599,6 @@ export const dict = {
   "settings.updates.action.checking": "確認中...",
   "settings.updates.toast.latest.title": "最新です",
   "settings.updates.toast.latest.description": "OpenCode は最新バージョンです。",
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
   "sound.option.none": "なし",
   "sound.option.alert01": "アラート 01",
   "sound.option.alert02": "アラート 02",

+ 4 - 15
packages/app/src/i18n/ko.ts

@@ -569,8 +569,10 @@ export const dict = {
   "settings.general.row.colorScheme.description": "OpenCode가 시스템, 라이트 또는 다크 테마를 따를지 선택하세요",
   "settings.general.row.theme.title": "테마",
   "settings.general.row.theme.description": "OpenCode 테마 사용자 지정",
-  "settings.general.row.font.title": "글꼴",
-  "settings.general.row.font.description": "코드 블록에 사용되는 고정폭 글꼴 사용자 지정",
+  "settings.general.row.font.title": "코드 글꼴",
+  "settings.general.row.font.description": "코드 블록과 터미널에 사용되는 글꼴을 사용자 지정",
+  "settings.general.row.uiFont.title": "UI 글꼴",
+  "settings.general.row.uiFont.description": "인터페이스 전반에 사용되는 글꼴을 사용자 지정",
   "settings.general.row.followup.title": "후속 조치 동작",
   "settings.general.row.followup.description": "후속 프롬프트를 즉시 실행할지 대기열에 넣을지 선택하세요",
   "settings.general.row.followup.option.queue": "대기열",
@@ -597,19 +599,6 @@ export const dict = {
   "settings.updates.action.checking": "확인 중...",
   "settings.updates.toast.latest.title": "최신 상태입니다",
   "settings.updates.toast.latest.description": "현재 최신 버전의 OpenCode를 사용 중입니다.",
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
   "sound.option.none": "없음",
   "sound.option.alert01": "알림 01",
   "sound.option.alert02": "알림 02",

+ 4 - 15
packages/app/src/i18n/no.ts

@@ -639,8 +639,10 @@ export const dict = {
   "settings.general.row.colorScheme.description": "Velg om OpenCode skal følge systemets, lyst eller mørkt tema",
   "settings.general.row.theme.title": "Tema",
   "settings.general.row.theme.description": "Tilpass hvordan OpenCode er tematisert.",
-  "settings.general.row.font.title": "Skrift",
-  "settings.general.row.font.description": "Tilpass mono-skriften som brukes i kodeblokker",
+  "settings.general.row.font.title": "Kodefont",
+  "settings.general.row.font.description": "Tilpass skrifttypen som brukes i kodeblokker og terminaler",
+  "settings.general.row.uiFont.title": "UI-skrift",
+  "settings.general.row.uiFont.description": "Tilpass skrifttypen som brukes i hele grensesnittet",
   "settings.general.row.followup.title": "Oppfølgingsadferd",
   "settings.general.row.followup.description": "Velg om oppfølgingsspørsmål skal kjøres umiddelbart eller vente i kø",
   "settings.general.row.followup.option.queue": "Kø",
@@ -668,19 +670,6 @@ export const dict = {
   "settings.updates.action.checking": "Sjekker...",
   "settings.updates.toast.latest.title": "Du er oppdatert",
   "settings.updates.toast.latest.description": "Du bruker den nyeste versjonen av OpenCode.",
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
   "sound.option.none": "Ingen",
   "sound.option.alert01": "Varsel 01",
   "sound.option.alert02": "Varsel 02",

+ 4 - 15
packages/app/src/i18n/pl.ts

@@ -570,8 +570,10 @@ export const dict = {
     "Wybierz, czy OpenCode ma używać motywu systemowego, jasnego czy ciemnego",
   "settings.general.row.theme.title": "Motyw",
   "settings.general.row.theme.description": "Dostosuj motyw OpenCode.",
-  "settings.general.row.font.title": "Czcionka",
-  "settings.general.row.font.description": "Dostosuj czcionkę mono używaną w blokach kodu",
+  "settings.general.row.font.title": "Czcionka kodu",
+  "settings.general.row.font.description": "Dostosuj czcionkę używaną w blokach kodu i terminalach",
+  "settings.general.row.uiFont.title": "Czcionka interfejsu",
+  "settings.general.row.uiFont.description": "Dostosuj czcionkę używaną w całym interfejsie",
   "settings.general.row.followup.title": "Zachowanie kontynuacji",
   "settings.general.row.followup.description": "Wybierz, czy kontynuacja ma być natychmiastowa, czy czekać w kolejce",
   "settings.general.row.followup.option.queue": "Kolejka",
@@ -598,19 +600,6 @@ export const dict = {
   "settings.updates.action.checking": "Sprawdzanie...",
   "settings.updates.toast.latest.title": "Masz najnowszą wersję",
   "settings.updates.toast.latest.description": "Korzystasz z najnowszej wersji OpenCode.",
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
   "sound.option.none": "Brak",
   "sound.option.alert01": "Alert 01",
   "sound.option.alert02": "Alert 02",

+ 4 - 15
packages/app/src/i18n/ru.ts

@@ -636,8 +636,10 @@ export const dict = {
   "settings.general.row.colorScheme.description": "Выберите, следует ли OpenCode системной, светлой или тёмной теме",
   "settings.general.row.theme.title": "Тема",
   "settings.general.row.theme.description": "Настройте оформление OpenCode.",
-  "settings.general.row.font.title": "Шрифт",
-  "settings.general.row.font.description": "Настройте моноширинный шрифт для блоков кода",
+  "settings.general.row.font.title": "Шрифт кода",
+  "settings.general.row.font.description": "Настройте шрифт, используемый в блоках кода и терминалах",
+  "settings.general.row.uiFont.title": "Шрифт интерфейса",
+  "settings.general.row.uiFont.description": "Настройте шрифт, используемый во всем интерфейсе",
   "settings.general.row.followup.title": "Поведение уточняющих вопросов",
   "settings.general.row.followup.description":
     "Выберите, отправлять ли уточняющие вопросы сразу или помещать их в очередь",
@@ -668,19 +670,6 @@ export const dict = {
   "settings.updates.action.checking": "Проверка...",
   "settings.updates.toast.latest.title": "У вас последняя версия",
   "settings.updates.toast.latest.description": "Вы используете последнюю версию OpenCode.",
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
   "sound.option.none": "Нет",
   "sound.option.alert01": "Alert 01",
   "sound.option.alert02": "Alert 02",

+ 4 - 15
packages/app/src/i18n/th.ts

@@ -630,8 +630,10 @@ export const dict = {
   "settings.general.row.colorScheme.description": "เลือกว่าจะให้ OpenCode ใช้ธีมตามระบบ สว่าง หรือมืด",
   "settings.general.row.theme.title": "ธีม",
   "settings.general.row.theme.description": "ปรับแต่งวิธีการที่ OpenCode มีธีม",
-  "settings.general.row.font.title": "ฟอนต์",
-  "settings.general.row.font.description": "ปรับแต่งฟอนต์โมโนที่ใช้ในบล็อกโค้ด",
+  "settings.general.row.font.title": "ฟอนต์โค้ด",
+  "settings.general.row.font.description": "ปรับแต่งฟอนต์ที่ใช้ในบล็อกโค้ดและเทอร์มินัล",
+  "settings.general.row.uiFont.title": "ฟอนต์ UI",
+  "settings.general.row.uiFont.description": "ปรับแต่งฟอนต์ที่ใช้ทั่วทั้งอินเทอร์เฟซ",
   "settings.general.row.followup.title": "พฤติกรรมการติดตามผล",
   "settings.general.row.followup.description": "เลือกว่าจะให้พร้อมท์ติดตามผลทำงานทันทีหรือรอในคิว",
   "settings.general.row.followup.option.queue": "คิว",
@@ -659,19 +661,6 @@ export const dict = {
   "settings.updates.toast.latest.title": "คุณเป็นเวอร์ชันล่าสุดแล้ว",
   "settings.updates.toast.latest.description": "คุณกำลังใช้งาน OpenCode เวอร์ชันล่าสุด",
 
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
   "sound.option.none": "ไม่มี",
   "sound.option.alert01": "เสียงเตือน 01",
   "sound.option.alert02": "เสียงเตือน 02",

+ 4 - 15
packages/app/src/i18n/tr.ts

@@ -643,8 +643,10 @@ export const dict = {
     "OpenCode'un sistem, açık veya koyu temayı takip etip etmeyeceğini seçin",
   "settings.general.row.theme.title": "Tema",
   "settings.general.row.theme.description": "OpenCode'un temasını özelleştirin.",
-  "settings.general.row.font.title": "Yazı Tipi",
-  "settings.general.row.font.description": "Kod bloklarında kullanılan monospace yazı tipini özelleştirin",
+  "settings.general.row.font.title": "Kod Yazı Tipi",
+  "settings.general.row.font.description": "Kod bloklarında ve terminallerde kullanılan yazı tipini özelleştirin",
+  "settings.general.row.uiFont.title": "Arayüz Yazı Tipi",
+  "settings.general.row.uiFont.description": "Arayüz genelinde kullanılan yazı tipini özelleştirin",
   "settings.general.row.followup.title": "Takip davranışı",
   "settings.general.row.followup.description":
     "Takip komutlarının hemen yönlendirilmesini mi yoksa sırada beklemesini mi istediğinizi seçin",
@@ -677,19 +679,6 @@ export const dict = {
   "settings.updates.toast.latest.title": "Güncelsiniz",
   "settings.updates.toast.latest.description": "OpenCode'un en son sürümünü kullanıyorsunuz.",
 
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
 
   "sound.option.none": "Yok",
   "sound.option.alert01": "Uyarı 01",

+ 4 - 15
packages/app/src/i18n/zh.ts

@@ -630,8 +630,10 @@ export const dict = {
   "settings.general.row.colorScheme.description": "选择 OpenCode 跟随系统、浅色或深色主题",
   "settings.general.row.theme.title": "主题",
   "settings.general.row.theme.description": "自定义 OpenCode 的主题。",
-  "settings.general.row.font.title": "字体",
-  "settings.general.row.font.description": "自定义代码块使用的等宽字体",
+  "settings.general.row.font.title": "代码字体",
+  "settings.general.row.font.description": "自定义代码块和终端使用的字体",
+  "settings.general.row.uiFont.title": "界面字体",
+  "settings.general.row.uiFont.description": "自定义整个界面使用的字体",
   "settings.general.row.followup.title": "跟进消息行为",
   "settings.general.row.followup.description": "选择跟进提示是立即引导还是在队列中等待",
   "settings.general.row.followup.option.queue": "排队",
@@ -657,19 +659,6 @@ export const dict = {
   "settings.updates.toast.latest.title": "已是最新版本",
   "settings.updates.toast.latest.description": "你正在使用最新版本的 OpenCode。",
 
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
 
   "sound.option.none": "无",
   "sound.option.alert01": "警报 01",

+ 4 - 15
packages/app/src/i18n/zht.ts

@@ -625,8 +625,10 @@ export const dict = {
   "settings.general.row.colorScheme.description": "選擇 OpenCode 要跟隨系統、淺色或深色主題",
   "settings.general.row.theme.title": "主題",
   "settings.general.row.theme.description": "自訂 OpenCode 的主題。",
-  "settings.general.row.font.title": "字型",
-  "settings.general.row.font.description": "自訂程式碼區塊使用的等寬字型",
+  "settings.general.row.font.title": "程式碼字型",
+  "settings.general.row.font.description": "自訂程式碼區塊和終端機使用的字型",
+  "settings.general.row.uiFont.title": "介面字型",
+  "settings.general.row.uiFont.description": "自訂整個介面使用的字型",
   "settings.general.row.followup.title": "後續追問行為",
   "settings.general.row.followup.description": "選擇後續追問提示是立即引導還是進入佇列等待",
   "settings.general.row.followup.option.queue": "佇列",
@@ -654,19 +656,6 @@ export const dict = {
   "settings.updates.toast.latest.title": "已是最新版本",
   "settings.updates.toast.latest.description": "你正在使用最新版本的 OpenCode。",
 
-  "font.option.ibmPlexMono": "IBM Plex Mono",
-  "font.option.cascadiaCode": "Cascadia Code",
-  "font.option.firaCode": "Fira Code",
-  "font.option.hack": "Hack",
-  "font.option.inconsolata": "Inconsolata",
-  "font.option.intelOneMono": "Intel One Mono",
-  "font.option.iosevka": "Iosevka",
-  "font.option.jetbrainsMono": "JetBrains Mono",
-  "font.option.mesloLgs": "Meslo LGS",
-  "font.option.robotoMono": "Roboto Mono",
-  "font.option.sourceCodePro": "Source Code Pro",
-  "font.option.ubuntuMono": "Ubuntu Mono",
-  "font.option.geistMono": "Geist Mono",
   "sound.option.none": "無",
   "sound.option.alert01": "警報 01",
   "sound.option.alert02": "警報 02",

+ 0 - 1
packages/ui/package.json

@@ -12,7 +12,6 @@
     "./hooks": "./src/hooks/index.ts",
     "./context": "./src/context/index.ts",
     "./context/*": "./src/context/*.tsx",
-    "./font-loader": "./src/font-loader.ts",
     "./styles": "./src/styles/index.css",
     "./styles/tailwind": "./src/styles/tailwind/index.css",
     "./theme": "./src/theme/index.ts",

BIN
packages/ui/src/assets/fonts/CaskaydiaCoveNerdFontMono-Bold.woff2


BIN
packages/ui/src/assets/fonts/CaskaydiaCoveNerdFontMono-Regular.woff2


BIN
packages/ui/src/assets/fonts/FiraCodeNerdFontMono-Bold.woff2


BIN
packages/ui/src/assets/fonts/FiraCodeNerdFontMono-Regular.woff2


BIN
packages/ui/src/assets/fonts/GeistMonoNerdFontMono-Bold.woff2


BIN
packages/ui/src/assets/fonts/GeistMonoNerdFontMono-Medium.woff2


BIN
packages/ui/src/assets/fonts/GeistMonoNerdFontMono-Regular.woff2


BIN
packages/ui/src/assets/fonts/HackNerdFontMono-Bold.woff2


BIN
packages/ui/src/assets/fonts/HackNerdFontMono-Regular.woff2


BIN
packages/ui/src/assets/fonts/InconsolataNerdFontMono-Bold.woff2


BIN
packages/ui/src/assets/fonts/InconsolataNerdFontMono-Regular.woff2


BIN
packages/ui/src/assets/fonts/IntoneMonoNerdFontMono-Bold.woff2


BIN
packages/ui/src/assets/fonts/IntoneMonoNerdFontMono-Regular.woff2


BIN
packages/ui/src/assets/fonts/JetBrainsMonoNerdFontMono-Bold.woff2


BIN
packages/ui/src/assets/fonts/JetBrainsMonoNerdFontMono-Regular.woff2


BIN
packages/ui/src/assets/fonts/MesloLGSNerdFontMono-Bold.woff2


BIN
packages/ui/src/assets/fonts/MesloLGSNerdFontMono-Regular.woff2


BIN
packages/ui/src/assets/fonts/RobotoMonoNerdFontMono-Bold.woff2


BIN
packages/ui/src/assets/fonts/RobotoMonoNerdFontMono-Regular.woff2


BIN
packages/ui/src/assets/fonts/SauceCodeProNerdFontMono-Bold.woff2


BIN
packages/ui/src/assets/fonts/SauceCodeProNerdFontMono-Regular.woff2


BIN
packages/ui/src/assets/fonts/UbuntuMonoNerdFontMono-Bold.woff2


BIN
packages/ui/src/assets/fonts/UbuntuMonoNerdFontMono-Regular.woff2


+ 0 - 1
packages/ui/src/assets/fonts/cascadia-code-nerd-font-bold.woff2

@@ -1 +0,0 @@
-CaskaydiaCoveNerdFontMono-Bold.woff2

+ 0 - 1
packages/ui/src/assets/fonts/cascadia-code-nerd-font.woff2

@@ -1 +0,0 @@
-CaskaydiaCoveNerdFontMono-Regular.woff2

+ 0 - 1
packages/ui/src/assets/fonts/fira-code-nerd-font-bold.woff2

@@ -1 +0,0 @@
-FiraCodeNerdFontMono-Bold.woff2

+ 0 - 1
packages/ui/src/assets/fonts/fira-code-nerd-font.woff2

@@ -1 +0,0 @@
-FiraCodeNerdFontMono-Regular.woff2

BIN
packages/ui/src/assets/fonts/geist-italic-medium.otf


BIN
packages/ui/src/assets/fonts/geist-italic-regular.otf


BIN
packages/ui/src/assets/fonts/geist-italic.ttf


BIN
packages/ui/src/assets/fonts/geist-italic.woff2


BIN
packages/ui/src/assets/fonts/geist-medium.otf


+ 0 - 1
packages/ui/src/assets/fonts/geist-mono-bold.woff2

@@ -1 +0,0 @@
-GeistMonoNerdFontMono-Bold.woff2

BIN
packages/ui/src/assets/fonts/geist-mono-italic.ttf


BIN
packages/ui/src/assets/fonts/geist-mono-italic.woff2


+ 0 - 1
packages/ui/src/assets/fonts/geist-mono-medium.woff2

@@ -1 +0,0 @@
-GeistMonoNerdFontMono-Medium.woff2

BIN
packages/ui/src/assets/fonts/geist-mono.ttf


+ 0 - 1
packages/ui/src/assets/fonts/geist-mono.woff2

@@ -1 +0,0 @@
-GeistMonoNerdFontMono-Regular.woff2

BIN
packages/ui/src/assets/fonts/geist-regular.otf


BIN
packages/ui/src/assets/fonts/geist.ttf


BIN
packages/ui/src/assets/fonts/geist.woff2


+ 0 - 1
packages/ui/src/assets/fonts/hack-nerd-font-bold.woff2

@@ -1 +0,0 @@
-HackNerdFontMono-Bold.woff2

+ 0 - 1
packages/ui/src/assets/fonts/hack-nerd-font.woff2

@@ -1 +0,0 @@
-HackNerdFontMono-Regular.woff2

BIN
packages/ui/src/assets/fonts/ibm-plex-mono.otf


+ 0 - 1
packages/ui/src/assets/fonts/inconsolata-nerd-font-bold.woff2

@@ -1 +0,0 @@
-InconsolataNerdFontMono-Bold.woff2

+ 0 - 1
packages/ui/src/assets/fonts/inconsolata-nerd-font.woff2

@@ -1 +0,0 @@
-InconsolataNerdFontMono-Regular.woff2

+ 0 - 1
packages/ui/src/assets/fonts/intel-one-mono-nerd-font-bold.woff2

@@ -1 +0,0 @@
-IntoneMonoNerdFontMono-Bold.woff2

+ 0 - 1
packages/ui/src/assets/fonts/intel-one-mono-nerd-font.woff2

@@ -1 +0,0 @@
-IntoneMonoNerdFontMono-Regular.woff2

BIN
packages/ui/src/assets/fonts/inter-italic.otf


BIN
packages/ui/src/assets/fonts/inter-italic.woff2


BIN
packages/ui/src/assets/fonts/inter.otf


BIN
packages/ui/src/assets/fonts/iosevka-nerd-font-bold.woff2


BIN
packages/ui/src/assets/fonts/iosevka-nerd-font.woff2


+ 0 - 1
packages/ui/src/assets/fonts/jetbrains-mono-nerd-font-bold.woff2

@@ -1 +0,0 @@
-JetBrainsMonoNerdFontMono-Bold.woff2

+ 0 - 1
packages/ui/src/assets/fonts/jetbrains-mono-nerd-font.woff2

@@ -1 +0,0 @@
-JetBrainsMonoNerdFontMono-Regular.woff2

+ 0 - 1
packages/ui/src/assets/fonts/meslo-lgs-nerd-font-bold.woff2

@@ -1 +0,0 @@
-MesloLGSNerdFontMono-Bold.woff2

+ 0 - 1
packages/ui/src/assets/fonts/meslo-lgs-nerd-font.woff2

@@ -1 +0,0 @@
-MesloLGSNerdFontMono-Regular.woff2

+ 0 - 1
packages/ui/src/assets/fonts/roboto-mono-nerd-font-bold.woff2

@@ -1 +0,0 @@
-RobotoMonoNerdFontMono-Bold.woff2

+ 0 - 1
packages/ui/src/assets/fonts/roboto-mono-nerd-font.woff2

@@ -1 +0,0 @@
-RobotoMonoNerdFontMono-Regular.woff2

+ 0 - 1
packages/ui/src/assets/fonts/source-code-pro-nerd-font-bold.woff2

@@ -1 +0,0 @@
-SauceCodeProNerdFontMono-Bold.woff2

+ 0 - 1
packages/ui/src/assets/fonts/source-code-pro-nerd-font.woff2

@@ -1 +0,0 @@
-SauceCodeProNerdFontMono-Regular.woff2

+ 0 - 1
packages/ui/src/assets/fonts/ubuntu-mono-nerd-font-bold.woff2

@@ -1 +0,0 @@
-UbuntuMonoNerdFontMono-Bold.woff2

+ 0 - 1
packages/ui/src/assets/fonts/ubuntu-mono-nerd-font.woff2

@@ -1 +0,0 @@
-UbuntuMonoNerdFontMono-Regular.woff2

+ 0 - 133
packages/ui/src/font-loader.ts

@@ -1,133 +0,0 @@
-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
-}