diff --git a/apps/pyconkr-2026/src/assets/fonts/dosgothic.woff b/apps/pyconkr-2026/src/assets/fonts/dosgothic.woff new file mode 100644 index 00000000..86f75a7a Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/dosgothic.woff differ diff --git a/apps/pyconkr-2026/src/assets/fonts/dosmyungjo.woff b/apps/pyconkr-2026/src/assets/fonts/dosmyungjo.woff new file mode 100644 index 00000000..343fa4f7 Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/dosmyungjo.woff differ diff --git a/apps/pyconkr-2026/src/assets/fonts/dossaemmul.woff b/apps/pyconkr-2026/src/assets/fonts/dossaemmul.woff new file mode 100644 index 00000000..97739f07 Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/dossaemmul.woff differ diff --git a/apps/pyconkr-2026/src/assets/fonts/dunggeunmo.woff b/apps/pyconkr-2026/src/assets/fonts/dunggeunmo.woff new file mode 100644 index 00000000..6e007036 Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/dunggeunmo.woff differ diff --git a/apps/pyconkr-2026/src/assets/fonts/exqt_wide12.ttf b/apps/pyconkr-2026/src/assets/fonts/exqt_wide12.ttf new file mode 100644 index 00000000..d030de90 Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/exqt_wide12.ttf differ diff --git a/apps/pyconkr-2026/src/assets/fonts/exqt_wide135.ttf b/apps/pyconkr-2026/src/assets/fonts/exqt_wide135.ttf new file mode 100644 index 00000000..8ac13c8c Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/exqt_wide135.ttf differ diff --git a/apps/pyconkr-2026/src/assets/fonts/exqt_wide15.ttf b/apps/pyconkr-2026/src/assets/fonts/exqt_wide15.ttf new file mode 100644 index 00000000..51421800 Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/exqt_wide15.ttf differ diff --git a/apps/pyconkr-2026/src/assets/fonts/galmuri-mono11.woff2 b/apps/pyconkr-2026/src/assets/fonts/galmuri-mono11.woff2 new file mode 100644 index 00000000..ff325bb7 Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/galmuri-mono11.woff2 differ diff --git a/apps/pyconkr-2026/src/assets/fonts/galmuri11-condensed.woff2 b/apps/pyconkr-2026/src/assets/fonts/galmuri11-condensed.woff2 new file mode 100644 index 00000000..fd0b1c57 Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/galmuri11-condensed.woff2 differ diff --git a/apps/pyconkr-2026/src/assets/fonts/galmuri11.woff2 b/apps/pyconkr-2026/src/assets/fonts/galmuri11.woff2 new file mode 100644 index 00000000..659863b5 Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/galmuri11.woff2 differ diff --git a/apps/pyconkr-2026/src/assets/fonts/galmuri14.woff2 b/apps/pyconkr-2026/src/assets/fonts/galmuri14.woff2 new file mode 100644 index 00000000..d6cdf5dc Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/galmuri14.woff2 differ diff --git a/apps/pyconkr-2026/src/assets/fonts/galmuri9.woff2 b/apps/pyconkr-2026/src/assets/fonts/galmuri9.woff2 new file mode 100644 index 00000000..336a89c3 Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/galmuri9.woff2 differ diff --git a/apps/pyconkr-2026/src/assets/fonts/maruminya.woff2 b/apps/pyconkr-2026/src/assets/fonts/maruminya.woff2 new file mode 100644 index 00000000..80cb96a3 Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/maruminya.woff2 differ diff --git a/apps/pyconkr-2026/src/assets/fonts/mulmaru.woff2 b/apps/pyconkr-2026/src/assets/fonts/mulmaru.woff2 new file mode 100644 index 00000000..6ecfe354 Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/mulmaru.woff2 differ diff --git a/apps/pyconkr-2026/src/assets/fonts/neodgm.woff2 b/apps/pyconkr-2026/src/assets/fonts/neodgm.woff2 new file mode 100644 index 00000000..efc5cc44 Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/neodgm.woff2 differ diff --git a/apps/pyconkr-2026/src/assets/fonts/pfstardust.woff2 b/apps/pyconkr-2026/src/assets/fonts/pfstardust.woff2 new file mode 100644 index 00000000..d832bf1b Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/pfstardust.woff2 differ diff --git a/apps/pyconkr-2026/src/components/FontSwitcher.tsx b/apps/pyconkr-2026/src/components/FontSwitcher.tsx new file mode 100644 index 00000000..333f3e82 --- /dev/null +++ b/apps/pyconkr-2026/src/components/FontSwitcher.tsx @@ -0,0 +1,126 @@ +import { FC, useState } from "react"; + +/** + * 가독성 비교용 임시 폰트 전환 도구. + * 페이지 최상단에 고정된 select 로 폰트를 바꾸면 --app-font(전역 CSS 변수)를 덮어써 + * 본문(MDX/네이티브 HTML)과 MUI Typography 가 한 번에 전환된다. + * (각 폰트 정의는 main.css 의 @font-face, 기본값은 globalStyles 의 :root 참고) + */ +const FALLBACK = `"Pretendard", -apple-system, BlinkMacSystemFont, system-ui, "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", sans-serif`; + +const FONT_OPTIONS: { label: string; stack: string }[] = [ + // 기본값(:root --app-font)과 동일한 exqt 스택 + { + label: "exqt (현재 기본)", + stack: `"exqtEnglish", "exqtNumber", "exqt", ${FALLBACK}`, + }, + { + label: "exqt 가로 1.2배", + stack: `"exqtWide12", ${FALLBACK}`, + }, + { + label: "exqt 가로 1.35배", + stack: `"exqtWide135", ${FALLBACK}`, + }, + { + label: "exqt 가로 1.5배", + stack: `"exqtWide15", ${FALLBACK}`, + }, + { + label: "둥근모꼴+Fixedsys", + stack: `"RoundedFixedsys", ${FALLBACK}`, + }, + { + label: "PF스타더스트", + stack: `"PFStardust", ${FALLBACK}`, + }, + { + label: "갈무리11 (닌텐도DS풍)", + stack: `"Galmuri11", ${FALLBACK}`, + }, + { + label: "갈무리14 (큰 크기)", + stack: `"Galmuri14", ${FALLBACK}`, + }, + { + label: "갈무리9 (작은 크기)", + stack: `"Galmuri9", ${FALLBACK}`, + }, + { + label: "Neo둥근모", + stack: `"NeoDunggeunmo", ${FALLBACK}`, + }, + { + label: "물마루", + stack: `"Mulmaru", ${FALLBACK}`, + }, + { + label: "마루민야 (둥근고딕)", + stack: `"MaruMinya", ${FALLBACK}`, + }, + { + label: "갈무리Mono11 (고정폭)", + stack: `"GalmuriMono11", ${FALLBACK}`, + }, + { + label: "갈무리11 Condensed (좁게)", + stack: `"Galmuri11Condensed", ${FALLBACK}`, + }, + { + label: "DOS고딕", + stack: `"DOSGothic", ${FALLBACK}`, + }, + { + label: "DOS샘물", + stack: `"DOSSaemmul", ${FALLBACK}`, + }, + { + label: "DOS명조 (픽셀 명조)", + stack: `"DOSMyungjo", ${FALLBACK}`, + }, + { + label: "Pretendard (비교용)", + stack: FALLBACK, + }, +]; + +export const FontSwitcher: FC = () => { + const [index, setIndex] = useState(0); + + return ( + + ); +}; diff --git a/apps/pyconkr-2026/src/main.css b/apps/pyconkr-2026/src/main.css index 57923f13..12c035e8 100644 --- a/apps/pyconkr-2026/src/main.css +++ b/apps/pyconkr-2026/src/main.css @@ -16,3 +16,98 @@ unicode-range: U+0030-0039; /* 숫자 */ size-adjust: 120%; } + +/* exqt 가로 확장본 (글리프를 x축으로만 늘려 ㅏㅓㅑㅕ 곁가지가 길어지도록 재생성. 세로/행간 불변) */ +@font-face { + font-family: "exqtWide12"; + src: url("assets/fonts/exqt_wide12.ttf") format("truetype"); +} + +@font-face { + font-family: "exqtWide135"; + src: url("assets/fonts/exqt_wide135.ttf") format("truetype"); +} + +@font-face { + font-family: "exqtWide15"; + src: url("assets/fonts/exqt_wide15.ttf") format("truetype"); +} + +/* 가독성 비교용 후보 폰트들 (상단 FontSwitcher select에서 전환) */ +@font-face { + font-family: "RoundedFixedsys"; /* 둥근모꼴+Fixedsys, https://noonnu.cc/font_page/250 */ + src: url("assets/fonts/dunggeunmo.woff") format("woff"); + font-display: swap; +} + +@font-face { + font-family: "PFStardust"; /* PF스타더스트 3.0, https://noonnu.cc/font_page/1614 */ + src: url("assets/fonts/pfstardust.woff2") format("woff2"); + font-display: swap; +} + +@font-face { + font-family: "Galmuri9"; /* 갈무리9 (OFL), https://galmuri.quiple.dev */ + src: url("assets/fonts/galmuri9.woff2") format("woff2"); + font-display: swap; +} + +@font-face { + font-family: "Galmuri11"; /* 갈무리11 (OFL, 닌텐도DS 스타일) */ + src: url("assets/fonts/galmuri11.woff2") format("woff2"); + font-display: swap; +} + +@font-face { + font-family: "Galmuri14"; /* 갈무리14 (OFL, 큰 크기) */ + src: url("assets/fonts/galmuri14.woff2") format("woff2"); + font-display: swap; +} + +@font-face { + font-family: "NeoDunggeunmo"; /* Neo둥근모 (OFL), https://github.com/neodgm/neodgm */ + src: url("assets/fonts/neodgm.woff2") format("woff2"); + font-display: swap; +} + +@font-face { + font-family: "Mulmaru"; /* 물마루 (OFL), https://github.com/mushsooni/mulmaru */ + src: url("assets/fonts/mulmaru.woff2") format("woff2"); + font-display: swap; +} + +@font-face { + font-family: "GalmuriMono11"; /* 갈무리Mono11 (OFL, 고정폭) */ + src: url("assets/fonts/galmuri-mono11.woff2") format("woff2"); + font-display: swap; +} + +@font-face { + font-family: "Galmuri11Condensed"; /* 갈무리11 Condensed (OFL, 좁은 폭) */ + src: url("assets/fonts/galmuri11-condensed.woff2") format("woff2"); + font-display: swap; +} + +@font-face { + font-family: "MaruMinya"; /* 마루민야 x12y12 (OFL), https://github.com/quiple/x12y12pxMaruMinyaHangul */ + src: url("assets/fonts/maruminya.woff2") format("woff2"); + font-display: swap; +} + +@font-face { + font-family: "DOSGothic"; /* DOS고딕 (MIT), https://noonnu.cc/font_page/239 */ + src: url("assets/fonts/dosgothic.woff") format("woff"); + font-display: swap; +} + +@font-face { + font-family: "DOSSaemmul"; /* DOS샘물 (MIT), https://noonnu.cc/font_page/240 */ + src: url("assets/fonts/dossaemmul.woff") format("woff"); + font-display: swap; +} + +@font-face { + font-family: "DOSMyungjo"; /* DOS명조 (MIT, 픽셀 명조), https://noonnu.cc/font_page/238 */ + src: url("assets/fonts/dosmyungjo.woff") format("woff"); + font-display: swap; +} diff --git a/apps/pyconkr-2026/src/main.tsx b/apps/pyconkr-2026/src/main.tsx index 1050e5ee..8d0a0a51 100644 --- a/apps/pyconkr-2026/src/main.tsx +++ b/apps/pyconkr-2026/src/main.tsx @@ -14,6 +14,7 @@ import { createRoot } from "react-dom/client"; import { RouterProvider } from "react-router-dom"; import "./main.css"; +import { FontSwitcher } from "./components/FontSwitcher.tsx"; import { IS_DEBUG_ENV } from "./consts"; import { LOCAL_STORAGE_LANGUAGE_KEY } from "./consts/local_stroage.ts"; import { PyConKRMDXComponents } from "./consts/mdx_components.ts"; @@ -98,6 +99,7 @@ export const MainApp: FC = () => { + diff --git a/apps/pyconkr-2026/src/styles/globalStyles.ts b/apps/pyconkr-2026/src/styles/globalStyles.ts index 54067734..9b7a3e83 100644 --- a/apps/pyconkr-2026/src/styles/globalStyles.ts +++ b/apps/pyconkr-2026/src/styles/globalStyles.ts @@ -3,8 +3,13 @@ import { createTheme } from "@mui/material/styles"; export const muiTheme = createTheme({ typography: { - fontFamily: - 'exqtEnglish, exqtNumber, exqt, Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif', + // 실제 폰트 스택은 CSS 변수 --app-font 로 주입(상단 FontSwitcher select에서 전환). 기본값은 :root 에 정의. + fontFamily: "var(--app-font)", + // exqt 폰트의 자간이 좁아 가독성이 떨어지므로 모든 Typography variant의 자간을 통일해 넓힘. + // (line-height는 variant별 기본값을 유지하기 위해 의도적으로 지정하지 않음) + allVariants: { + letterSpacing: "0.04em", + }, }, palette: { mode: "dark", @@ -126,30 +131,23 @@ export const muiTheme = createTheme({ export const globalStyles = css` @import url("https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css"); + /* 기본 폰트 스택. FontSwitcher select가 document.documentElement 의 --app-font 를 덮어써 전환한다. */ + :root { + --app-font: + "exqtEnglish", "exqtNumber", "exqt", "Pretendard", -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", + "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif; + } + html, body { - font-family: - "exqtEnglish", - "exqtNumber", - "exqt", - "Pretendard", - -apple-system, - BlinkMacSystemFont, - system-ui, - Roboto, - "Helvetica Neue", - "Segoe UI", - "Apple SD Gothic Neo", - "Noto Sans KR", - "Malgun Gothic", - "Apple Color Emoji", - "Segoe UI Emoji", - "Segoe UI Symbol", - sans-serif; + font-family: var(--app-font); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; -webkit-touch-callout: none; + letter-spacing: 0.04em; + line-height: 1.7; + overscroll-behavior: none; word-break: keep-all; overflow-wrap: break-all; diff --git a/dotenv/.env.development b/dotenv/.env.development index aebb10a0..5df0335d 100644 --- a/dotenv/.env.development +++ b/dotenv/.env.development @@ -1,7 +1,7 @@ -VITE_PYCONKR_FRONTEND_DOMAIN=https://dev.pycon.kr -VITE_PYCONKR_BACKEND_API_DOMAIN=https://rest-api-dev.pycon.kr -VITE_PYCONKR_ACCOUNTS_DOMAIN=https://accounts-dev.pycon.kr -VITE_PYCONKR_BACKEND_CSRF_COOKIE_NAME=DEBUG_PYCONKR_BACKEND_csrftoken -VITE_PYCONKR_BACKEND_SESSION_COOKIE_NAME=DEBUG_PYCONKR_BACKEND_sessionid -VITE_PYCONKR_SHOP_IMP_ACCOUNT_ID=imp80859147 +VITE_PYCONKR_FRONTEND_DOMAIN=https://2026.pycon.kr +VITE_PYCONKR_BACKEND_API_DOMAIN=https://rest-api.pycon.kr +VITE_PYCONKR_ACCOUNTS_DOMAIN=https://accounts.pycon.kr +VITE_PYCONKR_BACKEND_CSRF_COOKIE_NAME=PYCONKR_BACKEND_csrftoken +VITE_PYCONKR_BACKEND_SESSION_COOKIE_NAME=PYCONKR_BACKEND_sessionid +VITE_PYCONKR_SHOP_IMP_ACCOUNT_ID=imp96676915 VITE_FARO_COLLECTOR_URL=https://faro.mudev.cc/collect