From 14b893d8a3518699bf77cf8374bec9dca8f2979c Mon Sep 17 00:00:00 2001 From: hided62 Date: Tue, 15 Sep 2026 16:09:32 +0000 Subject: [PATCH] =?UTF-8?q?refactor:=20=EC=9E=91=EC=9D=80=20=EA=B8=80?= =?UTF-8?q?=EC=9E=90=20=EB=B9=84=EC=9C=A8=EA=B3=BC=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=ED=81=AC=EA=B8=B0=EB=A5=BC=20=EA=B3=B5=ED=86=B5=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=EB=A1=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/game-frontend/src/assets/main.css | 4 +- .../src/assets/styles/tokens.css | 15 +++++++- .../src/components/chief/ChiefTurnCard.vue | 8 ++-- .../src/components/main/NationBasicCard.vue | 2 +- .../personnel/PersonnelSelectionDialog.vue | 2 +- .../tournament/TournamentBracket.vue | 8 ++-- .../src/views/BestGeneralView.vue | 4 +- app/game-frontend/src/views/BettingView.vue | 38 +++++++++---------- .../src/views/ChiefCenterView.vue | 4 +- .../src/views/HallOfFameView.vue | 4 +- .../src/views/NationPersonnelView.vue | 4 +- .../src/views/SelectGeneralView.vue | 4 +- docs/frontend-css-architecture.md | 19 +++++++++- 13 files changed, 71 insertions(+), 45 deletions(-) diff --git a/app/game-frontend/src/assets/main.css b/app/game-frontend/src/assets/main.css index 5bc644d9..72118f1c 100644 --- a/app/game-frontend/src/assets/main.css +++ b/app/game-frontend/src/assets/main.css @@ -143,7 +143,7 @@ input[inputmode='search'] { } .small_war_log .name_plate { - font-size: 0.75em; + font-size: var(--sammo-font-size-war-name); } .small_war_log .name_plate_cover { @@ -152,5 +152,5 @@ input[inputmode='search'] { .small_war_log .crew_plate { color: orangered; - font-size: 90%; + font-size: var(--sammo-font-size-war-crew); } diff --git a/app/game-frontend/src/assets/styles/tokens.css b/app/game-frontend/src/assets/styles/tokens.css index 5e6fbac4..72fc115b 100644 --- a/app/game-frontend/src/assets/styles/tokens.css +++ b/app/game-frontend/src/assets/styles/tokens.css @@ -1,9 +1,22 @@ :root { /* 검증된 화면이 공유하는 네 단계. 콘텐츠 내부 축소/숨김은 별도 계약이다. */ - --sammo-font-size-small: 12px; + --sammo-font-size-small: calc(var(--sammo-font-size-normal) * 12 / 14); --sammo-font-size-normal: 14px; --sammo-font-size-emphasis: 16px; --sammo-font-size-title: 24px; + /* 크기 변경을 보류한 밀집 UI와 콘텐츠의 상대 축소 계약. */ + --sammo-font-size-nation-card: 12px; + --sammo-font-size-chief-compact-base: 0.75rem; + --sammo-font-size-chief-compact-row: 0.55rem; + --sammo-font-size-chief-compact-header: 0.65rem; + --sammo-font-size-chief-compact-name: 0.6rem; + --sammo-font-size-hall-name: 11px; + --sammo-font-size-hall-secondary: 95%; + --sammo-font-size-personnel-mobile-name: 15px; + --sammo-font-size-personnel-mobile-lock: 10px; + --sammo-font-size-bracket-bet-button: 11px; + --sammo-font-size-war-name: 0.75em; + --sammo-font-size-war-crew: 90%; --sammo-font-sans: Pretendard, 'Apple SD Gothic Neo', 'Noto Sans KR', 'Malgun Gothic', sans-serif; --sammo-color-text: #fff; --sammo-color-text-muted: rgba(232, 221, 196, 0.7); diff --git a/app/game-frontend/src/components/chief/ChiefTurnCard.vue b/app/game-frontend/src/components/chief/ChiefTurnCard.vue index ef968764..ebc346e7 100644 --- a/app/game-frontend/src/components/chief/ChiefTurnCard.vue +++ b/app/game-frontend/src/components/chief/ChiefTurnCard.vue @@ -107,7 +107,7 @@ const handleClick = () => { .chief-card.compact { padding: 0; - font-size: 0.75rem; + font-size: var(--sammo-font-size-chief-compact-base); } .chief-header { @@ -175,7 +175,7 @@ const handleClick = () => { height: 13px; min-height: 0; padding: 0 2px; - font-size: 0.55rem; + font-size: var(--sammo-font-size-chief-compact-row); line-height: 11px; } @@ -183,7 +183,7 @@ const handleClick = () => { box-sizing: border-box; height: 20px; min-height: 0; - font-size: 0.65rem; + font-size: var(--sammo-font-size-chief-compact-header); } .compact-name, @@ -210,7 +210,7 @@ const handleClick = () => { .chief-card.compact .chief-level, .chief-card.compact .chief-name { - font-size: 0.6rem; + font-size: var(--sammo-font-size-chief-compact-name); } .chief-row.rest { diff --git a/app/game-frontend/src/components/main/NationBasicCard.vue b/app/game-frontend/src/components/main/NationBasicCard.vue index 0cb01852..2606deb1 100644 --- a/app/game-frontend/src/components/main/NationBasicCard.vue +++ b/app/game-frontend/src/components/main/NationBasicCard.vue @@ -214,7 +214,7 @@ const displayChiefName = (chief: NationChief | undefined): string => { min-width: 0; height: 193px; color: #fff; - font-size: 12px; + font-size: var(--sammo-font-size-nation-card); } .nation-grid { diff --git a/app/game-frontend/src/components/personnel/PersonnelSelectionDialog.vue b/app/game-frontend/src/components/personnel/PersonnelSelectionDialog.vue index c69a5971..5d7387a5 100644 --- a/app/game-frontend/src/components/personnel/PersonnelSelectionDialog.vue +++ b/app/game-frontend/src/components/personnel/PersonnelSelectionDialog.vue @@ -376,7 +376,7 @@ small { place-items: center; color: #d8be79; background: #25271f; - font: 700 24px/1 var(--sammo-font-sans); + font: 700 var(--sammo-font-size-title)/1 var(--sammo-font-sans); } .personnel-picker-card-body, .personnel-picker-card-title, diff --git a/app/game-frontend/src/components/tournament/TournamentBracket.vue b/app/game-frontend/src/components/tournament/TournamentBracket.vue index 9617fbe8..88219153 100644 --- a/app/game-frontend/src/components/tournament/TournamentBracket.vue +++ b/app/game-frontend/src/components/tournament/TournamentBracket.vue @@ -342,7 +342,7 @@ const mobilePairs = computed(() => { border-radius: 3px; color: #fff3cd; background: #59400e; - font: 700 11px/1 var(--sammo-font-sans); + font: 700 var(--sammo-font-size-bracket-bet-button)/1 var(--sammo-font-sans); cursor: pointer; } .bracket-bet-button:hover, @@ -440,7 +440,7 @@ const mobilePairs = computed(() => { /* Betting uses the same paired cards at every viewport; rounds remain selectable. */ .inline-betting-bracket { - font-size: var(--bet-font-normal, 14px); + font-size: var(--sammo-font-size-normal); } .inline-betting-bracket .mobile-bracket { display: block; @@ -471,14 +471,14 @@ const mobilePairs = computed(() => { text-align: left; } .bracket-candidate-identity :deep(.general-identity-name) { - font-size: var(--bet-font-large, 16px); + font-size: var(--sammo-font-size-emphasis); font-weight: 700; white-space: normal; overflow-wrap: anywhere; } .bracket-core-stat { color: #fff; - font-size: var(--bet-font-normal, 14px); + font-size: var(--sammo-font-size-normal); } .bracket-bet-summary { display: grid; diff --git a/app/game-frontend/src/views/BestGeneralView.vue b/app/game-frontend/src/views/BestGeneralView.vue index ad5b0b4a..5bf9fd55 100644 --- a/app/game-frontend/src/views/BestGeneralView.vue +++ b/app/game-frontend/src/views/BestGeneralView.vue @@ -346,7 +346,7 @@ small { .hall-nation, .hall-name { - font-size: 11px; + font-size: var(--sammo-font-size-hall-name); } .hall-name { @@ -357,7 +357,7 @@ small { } .hall-name small { - font-size: 95%; + font-size: var(--sammo-font-size-hall-secondary); } .hall-value { diff --git a/app/game-frontend/src/views/BettingView.vue b/app/game-frontend/src/views/BettingView.vue index aedb7ea8..2e97bcc2 100644 --- a/app/game-frontend/src/views/BettingView.vue +++ b/app/game-frontend/src/views/BettingView.vue @@ -287,10 +287,6 @@ small { } .betting-page { - --bet-font-title: var(--sammo-font-size-title); - --bet-font-large: var(--sammo-font-size-emphasis); - --bet-font-normal: var(--sammo-font-size-normal); - --bet-font-small: var(--sammo-font-size-small); width: 100%; max-width: 1200px; min-width: 0; @@ -298,7 +294,7 @@ small { margin: 0 auto; color: #fff; font-family: var(--sammo-font-sans); - font-size: var(--bet-font-normal); + font-size: var(--sammo-font-size-normal); line-height: 1.3; text-align: center; } @@ -328,7 +324,7 @@ small { --legacy-button-height: 44px; min-width: 72px; padding: 10px 16px; - font-size: var(--bet-font-normal); + font-size: var(--sammo-font-size-normal); } .error { min-height: 32px; @@ -338,7 +334,7 @@ small { .state { min-height: 42px; padding: 5px; - font-size: var(--bet-font-title); + font-size: var(--sammo-font-size-title); } .state span { color: cyan; @@ -347,11 +343,11 @@ small { min-height: 50px; padding: 5px; color: limegreen; - font-size: var(--bet-font-title); + font-size: var(--sammo-font-size-title); } .section-title small { color: orange; - font-size: var(--bet-font-normal); + font-size: var(--sammo-font-size-normal); } select { width: 100%; @@ -413,7 +409,7 @@ select:disabled { border-radius: 3px; color: #fff; background: #201610; - font-size: var(--bet-font-normal); + font-size: var(--sammo-font-size-normal); } .inline-bet .bracket-bet-button { position: static; @@ -427,7 +423,7 @@ select:disabled { } .bet-message { grid-column: 1 / -1; - font-size: var(--bet-font-small); + font-size: var(--sammo-font-size-small); line-height: 16px; color: #b8e6ac; overflow-wrap: anywhere; @@ -439,7 +435,7 @@ select:disabled { min-height: 50px; padding: 8px; color: yellow; - font-size: var(--bet-font-title); + font-size: var(--sammo-font-size-title); } .ranking-placeholder { min-height: 40px; @@ -457,7 +453,7 @@ select:disabled { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; - font-size: var(--bet-font-small); + font-size: var(--sammo-font-size-small); line-height: 14px; } .ranking-table th, @@ -472,7 +468,7 @@ select:disabled { .ranking-table thead tr:first-child th { height: 18px; background: #000; - font-size: var(--bet-font-large); + font-size: var(--sammo-font-size-emphasis); line-height: 18px; font-weight: normal; } @@ -503,14 +499,14 @@ select:disabled { @media (max-width: 800px) { .betting-page { max-width: 100%; - font-size: var(--bet-font-normal); + font-size: var(--sammo-font-size-normal); } .state { - font-size: var(--bet-font-large); + font-size: var(--sammo-font-size-emphasis); } .section-title, .ranking-title { - font-size: var(--bet-font-title); + font-size: var(--sammo-font-size-title); } .ranking-placeholder { display: none; @@ -538,7 +534,7 @@ select:disabled { .ranking-table { display: none; min-width: 390px; - font-size: var(--bet-font-small); + font-size: var(--sammo-font-size-small); } .ranking-table.mobile-active { display: table; @@ -557,7 +553,7 @@ select:disabled { } } .betting-page small { - font-size: var(--bet-font-small); + font-size: var(--sammo-font-size-small); } .bet-preset { position: relative; @@ -587,9 +583,9 @@ select:disabled { display: none; } .betting-page :deep(.tournament-page-title) { - font-size: var(--bet-font-large); + font-size: var(--sammo-font-size-emphasis); } .betting-page :deep(.tournament-page-header button) { - font-size: var(--bet-font-normal); + font-size: var(--sammo-font-size-normal); } diff --git a/app/game-frontend/src/views/ChiefCenterView.vue b/app/game-frontend/src/views/ChiefCenterView.vue index 6f4dbfc0..c0281196 100644 --- a/app/game-frontend/src/views/ChiefCenterView.vue +++ b/app/game-frontend/src/views/ChiefCenterView.vue @@ -832,7 +832,7 @@ const repeatTurns = async (amount: number) => { padding: 0; gap: 0; text-align: center; - font-size: 0.55rem; + font-size: var(--sammo-font-size-chief-compact-row); line-height: 11.25px !important; } .chief-overview :deep(.chief-card.compact .chief-header) { @@ -859,7 +859,7 @@ const repeatTurns = async (amount: number) => { width: 12px; height: 155px; color: #fff; - font-size: 0.55rem; + font-size: var(--sammo-font-size-chief-compact-row); line-height: 11.25px; text-align: center; } diff --git a/app/game-frontend/src/views/HallOfFameView.vue b/app/game-frontend/src/views/HallOfFameView.vue index bfcf7edd..79f6be86 100644 --- a/app/game-frontend/src/views/HallOfFameView.vue +++ b/app/game-frontend/src/views/HallOfFameView.vue @@ -349,7 +349,7 @@ small { .hall-server, .hall-nation, .hall-name { - font-size: 11px; + font-size: var(--sammo-font-size-hall-name); } .hall-name { @@ -360,7 +360,7 @@ small { } .hall-name small { - font-size: 95%; + font-size: var(--sammo-font-size-hall-secondary); } .hall-value { diff --git a/app/game-frontend/src/views/NationPersonnelView.vue b/app/game-frontend/src/views/NationPersonnelView.vue index 86012922..25f05205 100644 --- a/app/game-frontend/src/views/NationPersonnelView.vue +++ b/app/game-frontend/src/views/NationPersonnelView.vue @@ -946,7 +946,7 @@ select { background-size: 48px 48px; } .chief-entry-copy strong { - font-size: 15px; + font-size: var(--sammo-font-size-personnel-mobile-name); } .chief-entry-copy small { font-size: var(--sammo-font-size-small); @@ -958,7 +958,7 @@ select { line-height: 18px; } .personnel-lock-label { - font-size: 10px; + font-size: var(--sammo-font-size-personnel-mobile-lock); } .award-label { font-size: var(--sammo-font-size-small); diff --git a/app/game-frontend/src/views/SelectGeneralView.vue b/app/game-frontend/src/views/SelectGeneralView.vue index 3e3e8587..3738c14c 100644 --- a/app/game-frontend/src/views/SelectGeneralView.vue +++ b/app/game-frontend/src/views/SelectGeneralView.vue @@ -540,7 +540,7 @@ onBeforeUnmount(() => { border-right-color: #000; border-bottom-color: #000; border-spacing: 0; - font-size: 14px; + font-size: var(--sammo-font-size-normal); text-align: center; word-break: break-all; } @@ -578,7 +578,7 @@ onBeforeUnmount(() => { margin: 0; padding: 0; color: inherit; - font-size: 14px; + font-size: var(--sammo-font-size-normal); font-weight: 700; line-height: 18.2px; } diff --git a/docs/frontend-css-architecture.md b/docs/frontend-css-architecture.md index 941252b4..812f9dee 100644 --- a/docs/frontend-css-architecture.md +++ b/docs/frontend-css-architecture.md @@ -139,7 +139,7 @@ The game UI uses four starting sizes from `assets/styles/tokens.css`: | Token suffix (`--sammo-font-size-`) | CSS size | Role | | --- | --- | --- | -| `small` | 12px | Compact controls, metadata, secondary labels | +| `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 | @@ -193,3 +193,20 @@ 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.