프로필 UI 글자 크기를 네 단계와 공통 축소 규칙으로 통일한다
This commit is contained in:
@@ -132,84 +132,25 @@ The CSS variables contain `/image/game/*` URLs but do not import or copy image
|
||||
files. Caddy continues to own `/image/*`; Vite must not rewrite the image tree
|
||||
as application assets.
|
||||
|
||||
|
||||
## Game typography tiers
|
||||
|
||||
The game UI uses four starting sizes from `assets/styles/tokens.css`:
|
||||
All profile pages share the four sizes in `assets/styles/tokens.css`, applied by
|
||||
page styles and `assets/styles/typography.css`. Gateway is outside this policy.
|
||||
This is an intentional Core UX decision, expanded on 2026-09-29 from the initial
|
||||
2026-09-15 policy. See [the typography contract](frontend-typography.md) for the
|
||||
step-down rule, measured fitting, content exceptions, and browser audit command.
|
||||
|
||||
| Token suffix (`--sammo-font-size-`) | CSS size | Role |
|
||||
| --- | --- | --- |
|
||||
| `small` | `normal × 12 / 14` (12px) | Compact controls, metadata, secondary labels |
|
||||
| `normal` | 14px | Body, tables, ordinary controls |
|
||||
| `emphasis` | 16px | Emphasized names and section labels |
|
||||
| `title` | 24px | Page and major section headings |
|
||||
| Token suffix (`--sammo-font-size-`) | Size | Shared class |
|
||||
| ----------------------------------- | ---- | --------------------- |
|
||||
| `title` | 24px | `sammo-text-title` |
|
||||
| `emphasis` | 16px | `sammo-text-emphasis` |
|
||||
| `normal` | 14px | `sammo-text-normal` |
|
||||
| `small` | 12px | `sammo-text-small` |
|
||||
|
||||
This is an intentional Core UX policy adopted on 2026-09-15. It is a starting
|
||||
policy for verified UI, not a claim that every rendered glyph has one of four
|
||||
computed sizes. Existing geometry and media queries remain owned by each page.
|
||||
A breakpoint can choose another tier (for example, the personnel nation heading
|
||||
uses 16px on its narrow layout and 24px on its wide layout).
|
||||
|
||||
Use the tokens for new UI. Do not round arbitrary content or all remaining
|
||||
relative sizes automatically. Before moving an existing label to a tier, compare
|
||||
actual Chromium screenshots and text geometry at 500px and 1000px, with the
|
||||
same font, data, DPR and zoom. Also check the real mobile viewport modes: a
|
||||
390px-wide device scales a 500px layout to approximately 78% and a 1000px layout
|
||||
to 39%; these do not change the CSS token values. A page with a fixed 1000px
|
||||
minimum width can still render at about 39% in 500px mode because Chromium
|
||||
fits the overflowing content. Record `visualViewport.scale` for each route;
|
||||
do not infer every route's scale from the selected mode alone.
|
||||
|
||||
### Preserved exceptions
|
||||
|
||||
- Battle log `.small_war_log .name_plate` remains `0.75em`, and `.crew_plate`
|
||||
remains `90%`. Legacy inline `0.9em` conversions and zero-sized hidden markers
|
||||
remain unchanged. At a 14px parent these are 10.5px and 12.6px respectively;
|
||||
nested content must be calculated from its actual parent.
|
||||
- NPC possession names retain their existing length rule: 4 and 7 characters
|
||||
render at 16px, and the existing `length >= 9` branch renders at 12px. Do not
|
||||
remove the smaller branch or enlarge long names to match adjacent labels.
|
||||
- Player HTML, editor size choices, and personal CSS remain content/user settings.
|
||||
Scoped `small` rules normalize UI metadata without rewriting injected HTML.
|
||||
|
||||
### Deferred conversions
|
||||
|
||||
| Area | Preserved size | Reason |
|
||||
| --- | --- | --- |
|
||||
| Chief overview compact rows and turn indices | `0.55rem` (8.8px) | 12px text overlaps the existing 11.25px rows |
|
||||
| Chief compact header/name | `0.65rem` / `0.6rem` | Preserve the same dense card contract |
|
||||
| Narrow personnel chief name / lock label | 15px / 10px | Enlarging them reduces visible maximum-length names |
|
||||
| Best generals / hall name and nation cells | 11px; inner `small` 95% | 12px worsens overflow in the fixed name cells |
|
||||
| General selection and main nation basic card | Existing local/inherited sizes | Maximum-width names already overflow; conversion is deferred |
|
||||
|
||||
User-created general names and founded/renamed nation names are limited by
|
||||
legacy width 18 (CJK counts 2, ASCII counts 1): test both 9 CJK characters and
|
||||
18 wide ASCII characters. Selection-pool and scenario names have a different
|
||||
source contract and are not proven bounded by that user-input guard.
|
||||
|
||||
Existing ellipsis, horizontal scrolling, and pre-existing maximum-name overflow
|
||||
are not fixed by these tokens. The deferred areas need a separate layout decision
|
||||
before their fonts are enlarged. The `typographyPolicy.spec.ts` fixture tests
|
||||
protect the safe main labels, personnel breakpoints, dense chief rows, NPC
|
||||
length branches, and battle log ratios. They use mocked read responses and do
|
||||
not constitute live game or public deployment verification.
|
||||
|
||||
|
||||
### Relative small tier and exception variables (2026-09-15)
|
||||
|
||||
`small` is `calc(var(--sammo-font-size-normal) * 12 / 14)`. The reference is the
|
||||
14px normal tier, not the immediate parent. An 80% declaration on nested `small`
|
||||
elements would shrink repeatedly and would yield 12.8px inside a 16px parent;
|
||||
the token keeps UI metadata at 12px regardless of nesting.
|
||||
|
||||
The retained exceptions are also named in `tokens.css`: `nation-card`,
|
||||
`chief-compact-{base,row,header,name}`, `hall-{name,secondary}`,
|
||||
`personnel-mobile-{name,lock}`, `bracket-bet-button`, and `war-{name,crew}`
|
||||
(all with the `--sammo-font-size-` prefix). Their values preserve the previous
|
||||
rendering, including rem/em/% semantics. Zero-sized hidden markers and arbitrary
|
||||
user HTML remain content contracts. The betting page and bracket now reference
|
||||
the shared tier variables directly instead of the redundant `--bet-font-*` aliases.
|
||||
The historical deferral reasons above describe the original 12px proposal.
|
||||
`small`, `sub`, `sup`, and semantic log annotations move down one tier:
|
||||
24 → 16 → 14 → 12 → 10px. The last size is only for subordinate text inside the
|
||||
smallest tier; repeated nesting stops at 10px. Do not reintroduce scoped `small`
|
||||
resets, per-page exception tokens, or implicit percentage reductions.
|
||||
|
||||
## Text alignment on both axes (2026-09-29)
|
||||
|
||||
@@ -218,14 +159,14 @@ height. Horizontal alignment remains independent: numerical values can stay
|
||||
right-aligned and dates or field labels left-aligned. This policy does not change
|
||||
game state, field order, font tiers, cell dimensions, or the meaning of Ref data.
|
||||
|
||||
| Content | Vertical alignment |
|
||||
| --- | --- |
|
||||
| A short heading, status, button/link label, identity or scalar value | Center within its own cell when it fits |
|
||||
| A short label that wraps on a narrow viewport | Center the complete label if it fits; allow natural height and preserve wrapping |
|
||||
| A form label next to one input | Center against the input; if the field also has help/error text, align to the input rather than the entire help block |
|
||||
| Prose, logs, notices, editor content, multi-paragraph detail, card collections | Preserve the reading start at the top |
|
||||
| A table cell with text/numbers/actions | Use table-cell `vertical-align: middle`; retain explicit top alignment for narrative/detail cells |
|
||||
| A column flex container | The vertical axis is `justify-content`, not `align-items` |
|
||||
| Content | Vertical alignment |
|
||||
| ------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
|
||||
| A short heading, status, button/link label, identity or scalar value | Center within its own cell when it fits |
|
||||
| A short label that wraps on a narrow viewport | Center the complete label if it fits; allow natural height and preserve wrapping |
|
||||
| A form label next to one input | Center against the input; if the field also has help/error text, align to the input rather than the entire help block |
|
||||
| Prose, logs, notices, editor content, multi-paragraph detail, card collections | Preserve the reading start at the top |
|
||||
| A table cell with text/numbers/actions | Use table-cell `vertical-align: middle`; retain explicit top alignment for narrative/detail cells |
|
||||
| A column flex container | The vertical axis is `justify-content`, not `align-items` |
|
||||
|
||||
Choose the smallest owner of the text. For a block or grid-item cell with inline
|
||||
markup, `align-content: safe center` preserves inline wrapping, ellipsis and the
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# 전체 프로필 페이지 typography audit
|
||||
|
||||
실제 Chromium에서 router의 모든 페이지와 주요 열린 상태를 조회한다. 기존 E2E의
|
||||
합성 fixture를 재사용하며 실제 게임 API와 계정에는 접속하지 않는다.
|
||||
`load-fixtures.mjs`는 TypeScript compiler로 fixture 선언만 추출한다. test 등록,
|
||||
`beforeEach`, 테스트 본문은 실행하지 않는다. fixture 구조가 바뀌면 audit도 함께
|
||||
수정하고, 빈 화면이나 오류 화면을 정상 페이지 근거로 삼지 않는다.
|
||||
|
||||
## 실행
|
||||
|
||||
Core root에서 Node 24와 설치된 Playwright Chromium을 사용한다. prefix에 맞게
|
||||
production frontend를 build하고 preview를 먼저 띄운다. frontend 준비는
|
||||
[테스트 정책](testing-policy.md)을 따른다.
|
||||
|
||||
```sh
|
||||
VITE_APP_BASE_PATH=/che VITE_GAME_API_URL=/che/api/trpc \
|
||||
VITE_GAME_PROFILE=che:default pnpm --filter @sammo-ts/game-frontend build
|
||||
VITE_APP_BASE_PATH=/che VITE_GAME_API_URL=/che/api/trpc \
|
||||
VITE_GAME_PROFILE=che:default pnpm --filter @sammo-ts/game-frontend preview --host 127.0.0.1 --port 15331
|
||||
```
|
||||
|
||||
다른 terminal에서:
|
||||
|
||||
```sh
|
||||
CAPTURE_ORIGIN=http://127.0.0.1:15331 PHASE=che-cjk \
|
||||
node tools/typography-audit/capture.mjs
|
||||
CAPTURE_ORIGIN=http://127.0.0.1:15331 PHASE=che-ascii NAME_KIND=ascii \
|
||||
node tools/typography-audit/capture.mjs
|
||||
CAPTURE_ORIGIN=http://127.0.0.1:15331 PHASE=che-mobile MOBILE=1 \
|
||||
node tools/typography-audit/capture.mjs
|
||||
```
|
||||
|
||||
HWE는 build의 세 변수를 `/hwe`, `/hwe/api/trpc`, `hwe:default`로 바꾸고,
|
||||
audit에도 `PLAYWRIGHT_GAME_BASE_PATH=hwe PLAYWRIGHT_GAME_PROFILE=hwe:default`를
|
||||
지정한다. 같은 dist를 쓰는 profile build는 직렬로 실행한다. 활성 공개 profile을
|
||||
새로 배포하거나 서버 설정을 바꾸는 명령이 아니다.
|
||||
|
||||
| 환경 변수 | 의미 |
|
||||
| ---------------------------- | ----------------------------------------------------------------- |
|
||||
| `CAPTURE_ORIGIN` | 이미 실행 중인 frontend origin |
|
||||
| `PHASE` | 결과 하위 디렉터리 이름 |
|
||||
| `TYPOGRAPHY_OUTPUT_DIR` | 기본 `test-results/typography-audit` |
|
||||
| `TYPOGRAPHY_FONT_ROOT` | 선택적 Pretendard cache: `source.css`와 CSS가 참조하는 woff2 파일 |
|
||||
| `FRONTEND_PARITY_IMAGE_ROOT` | 기본 workspace의 `image/` |
|
||||
| `NAME_KIND` | 기본 `cjk`, 또는 `ascii`, `short4`, `mid7` |
|
||||
| `WIDTHS` | 기본 `500,1000` CSS px |
|
||||
| `MOBILE` | `1`이면 실제 390×844 touch 기기에서 500/1000 화면 모드 |
|
||||
| `SCENES` | 쉼표로 나눈 일부 scene만 실행; 전체 페이지 검증으로 보고하지 않음 |
|
||||
|
||||
각 실행은 현재 router의 `path` 목록과 전체 scene 목록의 대응을 먼저 검사한다.
|
||||
font 로딩 실패, fixture/page 오류, 설명할 수 없는 computed 크기는 실패로 기록한다.
|
||||
자동 축소는 `data-font-fit-max`와 10px 하한을 함께 검사한다. 원본 screenshot,
|
||||
DOM, computed style, text range, viewport scale, 이미지 natural size/object-fit,
|
||||
canvas font와 합성 응답이 scene별 파일로 남는다. 실패 manifest와 성공 수를 따로
|
||||
확인한다. snapshot 개수만으로 성공이라고 판단하지 않는다.
|
||||
|
||||
`clipped`는 overflow를 가진 조상의 경계를 검사한다. overflow가 visible인 글자가
|
||||
옆 칸을 침범하는 경우까지 자동 판정하지 못하므로 이름의 range와 element bounds,
|
||||
screenshot도 비교한다. 긴 반각 이름의 기존 문제를 숨기려고 glyph mask를 늘리지
|
||||
않는다. 별도의 Playwright interaction suite로 dropdown, dialog, hover/focus,
|
||||
active, disabled 상태를 확인한다.
|
||||
|
||||
## 검증 경계
|
||||
|
||||
이 도구는 fixture production Chromium의 화면 근거다. 운영 DB/계정, 공개 HTTPS,
|
||||
개인 CSS나 임의의 저장 HTML 전체를 검사했다는 뜻이 아니다. 감사 화면의 tab,
|
||||
국가 회의실/기밀실, 동적 왕조 상세, 명령·인사 선택창을 별도 scene으로 포함한다.
|
||||
새 사용자 페이지가 추가되면 router coverage 오류를 해결하며 scene과 fixture를
|
||||
추가한다. 생성물은 Git에 넣지 않는다.
|
||||
@@ -0,0 +1,68 @@
|
||||
# 프로필 UI 글자 크기
|
||||
|
||||
Gateway를 제외한 모든 게임 profile의 공통 정책이다. 2026-09-29 사용자 요청에
|
||||
따른 의도적 Core UX 차이이며 Ref의 작은 글자를 그대로 유지하는 계약을 대체한다.
|
||||
권한, 게임 데이터, 로그 내용·색상, 이미지와 사용자 작성 HTML 저장값은 바꾸지 않는다.
|
||||
|
||||
## 기본 단계와 작은 설명
|
||||
|
||||
| 역할 | 토큰 / 공통 class | 최대 기본 크기 |
|
||||
| ------------------ | ---------------------------------- | -------------- |
|
||||
| 큰 제목 | `title` / `sammo-text-title` | 24px |
|
||||
| 강조, 소제목 | `emphasis` / `sammo-text-emphasis` | 16px |
|
||||
| 본문, 일반 조작 | `normal` / `sammo-text-normal` | 14px |
|
||||
| 보조 정보, 밀집 표 | `small` / `sammo-text-small` | 12px |
|
||||
|
||||
토큰 접두사는 `--sammo-font-size-`이다. 화면 selector도 같은 토큰을 쓴다.
|
||||
반응형 breakpoint는 위 네 단계 중 하나를 선택한다.
|
||||
|
||||
공통 `typography.css`는 `small`, `sub`, `sup`, `.sammo-text-smaller`, 게임 로그의
|
||||
`.legacy-small`에 바로 아래 단계를 적용한다. 24→16→14→12px 순서이며 12px 안의
|
||||
작은 설명만 10px를 허용한다. 중첩해도 10px 아래로 내려가지 않는다. 일반 본문이나
|
||||
조작 버튼에 다섯 번째 단계를 직접 지정하지 않는다. 개별 화면의 `small` reset은
|
||||
추가하지 않는다. 로그 formatter의 semantic 옵션은 game frontend에서만 사용하므로
|
||||
Gateway 등 다른 소비자의 기존 상대 크기는 유지된다.
|
||||
|
||||
사령부 12턴 요약은 12px, 행 높이 16px를 사용한다. 기존 11.25px 행에서 글자만
|
||||
키우면 겹치므로 두 줄 header는 32px, 카드 224px, 전체 요약 448px로 함께 조정했다.
|
||||
인사부 모바일 이름은 16px, 명장·명예의 전당 이름과 토너먼트 작은 조작은 12px다.
|
||||
전투 요약의 이름·병력도 12px로 표시하며 의미와 색상은 유지한다.
|
||||
|
||||
## 칸에 맞춘 축소
|
||||
|
||||
자동 축소의 최대값도 위 네 단계 중 하나여야 한다. 짧은 글자를 임의의 크기로
|
||||
확대하지 않는다. 기존 빙의 이름은 16px를 기본으로 긴 이름을 12px로 낮춘다.
|
||||
|
||||
명장·명예의 전당의 고정 폭 이름칸은 공통 `vFitText` directive와
|
||||
`.sammo-fit-text`를 사용한다. CSS의 12px에서 실제 로드된 폰트의 text range를
|
||||
측정하고 칸보다 길 때만 축소한다. 너비·텍스트·font 로딩이 바뀌면 최대 단계부터
|
||||
다시 계산하므로 짧아진 이름은 원래 크기를 회복한다. 10px에서도 넘치는 극단적인
|
||||
반각 이름은 말줄임하며 원문을 DOM과 `title`에 남긴다. 이 경우 10~12px 사이의
|
||||
실측값은 고정 예외 크기가 아니라 네 단계에 상한을 둔 자동 축소 결과다.
|
||||
|
||||
## 별도 콘텐츠 경계
|
||||
|
||||
- 국가 소개·임관 권유문 등 사용자 작성 HTML의 명시적 크기와 개인 CSS는 사용자
|
||||
설정이다. 저장된 HTML이나 editor의 글자 크기 선택지는 변환하지 않는다.
|
||||
editor의 선택지 UI 자체는 일반 크기를 상속한다.
|
||||
- 위 HTML을 미리 보여 주는 축소 preview의 transform과 사용자가 고른 화면 배율은
|
||||
글자 크기 토큰과 별개다. audit에서 computed 크기와 viewport scale을 함께 기록한다.
|
||||
- 숨김·복사용 marker는 0px를 유지한다. 화면 본문 단계로 세지 않는다.
|
||||
- Canvas 차트의 축·범례·tooltip도 공통 small 토큰과 화면 font family를 사용한다.
|
||||
|
||||
새 고정 크기 예외는 화면 목적과 geometry 근거, 후속 설계 필요성을 문서화한다.
|
||||
단순히 칸이 좁다는 이유로 11px, 15px 같은 별도 토큰을 만들지 않는다.
|
||||
|
||||
## 검증
|
||||
|
||||
`typographyPolicy.spec.ts`는 production Chromium에서 실제 폰트 로딩, 단계별 중첩,
|
||||
최대 이름, 사령부 행 높이, 자동 축소 상한과 말줄임, 로그 크기를 확인한다.
|
||||
|
||||
전체 페이지 audit는 [audit 실행 안내](frontend-typography-audit.md)를 따른다.
|
||||
router의 모든 선언을 scene 목록과 대조하고, 각 scene의 screenshot·DOM·computed
|
||||
style·text range·이미지 크기와 fixture 응답을 남긴다. 500/1000px와 실제 390px
|
||||
기기의 화면 모드를 별도로 실행한다. 9개 전각·18개 반각 이름을 사용한다.
|
||||
|
||||
API 응답을 고정한 frontend 검증이다. 운영 DB, 실제 계정의 임의 HTML, 공개 HTTPS나
|
||||
배포 성공의 증거로 확대하지 않는다. 값이 바뀔 수 있는 예외는 고정 토큰으로
|
||||
위장하지 않고 생성 이유와 상한을 함께 검사한다.
|
||||
Reference in New Issue
Block a user