diff --git a/docs/design-system/foundations.md b/docs/design-system/foundations.md index a3b38f9eae5..c3f3dbb39f7 100644 --- a/docs/design-system/foundations.md +++ b/docs/design-system/foundations.md @@ -24,7 +24,7 @@ ### Font families -- `--font-ui`: 일반 UI, 제목, 본문, 버튼, 입력. Pretendard/Noto Sans KR/Apple SD Gothic Neo/Malgun Gothic을 포함해 한글 fallback을 보장한다. +- `--font-ui`: 일반 UI, 제목, 본문, 버튼, 입력. 제품 서체를 우선하고, 그 뒤에는 시스템 UI 폰트를 영문도 지원하는 한글 fallback보다 먼저 선언한다. 그래야 한글 fallback이 시스템 UI 폰트의 영문·숫자 글리프까지 대신 표시하지 않는다. 한글은 앞선 서체의 지원 여부에 따라 시스템의 언어별 fallback 또는 뒤에 선언된 한글 글꼴로 표시한다. - `--font-code`: 모델 ID, URL, 버전, 토큰 수, 로그, 코드. 숫자는 tabular 형태로 정렬한다. 외부 CDN 폰트를 사용하지 않는다. 프록시 관리 화면은 오프라인에서도 열려야 하고, 폰트 diff --git a/gui/src/styles.css b/gui/src/styles.css index 28c9277c1ed..9bdd757f6ae 100644 --- a/gui/src/styles.css +++ b/gui/src/styles.css @@ -87,8 +87,8 @@ --radius-round: 50%; --radius-pill: 999px; - /* typography: product UI first, Korean-safe fallbacks, mono only for machine data */ - --font-ui: "OpenAI Sans", "Pretendard Variable", Pretendard, "Noto Sans KR", "Apple SD Gothic Neo", "Malgun Gothic", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, sans-serif; + /* Keep product fonts first, then system UI fonts before Korean fallbacks that also cover Latin. */ + --font-ui: "OpenAI Sans", "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", sans-serif; --font-code: ui-monospace, "SFMono-Regular", "Cascadia Code", "JetBrains Mono", "Noto Sans Mono CJK KR", Menlo, Consolas, monospace; --font: var(--font-ui); --mono: var(--font-code); diff --git a/gui/tests/ui-font-fallback.test.ts b/gui/tests/ui-font-fallback.test.ts new file mode 100644 index 00000000000..a5ec926f219 --- /dev/null +++ b/gui/tests/ui-font-fallback.test.ts @@ -0,0 +1,26 @@ +import { expect, test } from "bun:test"; + +const css = await Bun.file(new URL("../src/styles.css", import.meta.url)).text(); +const fontStack = css.replace(/\/\*[\s\S]*?\*\//g, "") + .match(/--font-ui\s*:\s*([^;]+);/)?.[1]; +if (!fontStack) throw new Error("The UI font stack is missing."); +const families = fontStack.split(",").map(family => + family.trim().replace(/^(["'])(.*)\1$/, "$2"), +); + +test("product fonts retain priority in the UI font stack", () => { + expect(families.slice(0, 3)).toEqual(["OpenAI Sans", "Pretendard Variable", "Pretendard"]); +}); + +// Keep system fonts ahead of Apple SD Gothic Neo, which also covers Latin. +// This guards fallback order; actual glyph selection requires a browser check. +test.each(["-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto", "system-ui"])( + "%s precedes Apple SD Gothic Neo in the UI font stack", + systemFont => { + const systemIndex = families.indexOf(systemFont); + const koreanIndex = families.indexOf("Apple SD Gothic Neo"); + expect(systemIndex).toBeGreaterThanOrEqual(0); + expect(koreanIndex).toBeGreaterThanOrEqual(0); + expect(systemIndex).toBeLessThan(koreanIndex); + }, +);