프로필 UI 글자 크기를 네 단계와 공통 축소 규칙으로 통일한다
This commit is contained in:
@@ -1956,8 +1956,8 @@ test('shows all 12 advanced chief turns before the actions and uses the full mob
|
||||
expect(geometry.frameWidth).toBe(500);
|
||||
expect(geometry.rowWidth).toBe(500);
|
||||
expect(geometry.rowEdges).toEqual([
|
||||
{ top: 0, bottom: 155 },
|
||||
{ top: 155, bottom: 310 },
|
||||
{ top: 0, bottom: 224 },
|
||||
{ top: 224, bottom: 448 },
|
||||
]);
|
||||
expect(geometry.gutterWidths).toEqual([12, 12]);
|
||||
expect(geometry.gutterEdges).toEqual([
|
||||
|
||||
@@ -2910,5 +2910,126 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"best": {
|
||||
"lobby.info": {
|
||||
"result": {
|
||||
"data": {
|
||||
"year": 197,
|
||||
"month": 7,
|
||||
"userCnt": 17,
|
||||
"npcCnt": 31,
|
||||
"nationCnt": 5,
|
||||
"maxUserCnt": 50,
|
||||
"turnTerm": 60,
|
||||
"fictionMode": "가상",
|
||||
"otherTextInfo": "표준",
|
||||
"starttime": "0190-01-01T00:00:00.000Z",
|
||||
"myGeneral": {
|
||||
"id": 1,
|
||||
"name": "가나다라마바사아자",
|
||||
"troopId": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth.status": {
|
||||
"result": {
|
||||
"data": {
|
||||
"userId": "frontend-legacy-fixture-user"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ranking.getBestGeneral": {
|
||||
"result": {
|
||||
"data": {
|
||||
"isUnited": true,
|
||||
"sections": [
|
||||
{
|
||||
"title": "명 성",
|
||||
"valueType": "int",
|
||||
"entries": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "가나다라마바사아자",
|
||||
"ownerName": "시각검증",
|
||||
"nationName": "대한민국천하통일국",
|
||||
"bgColor": "#006400",
|
||||
"fgColor": "#ffffff",
|
||||
"picture": "default.jpg",
|
||||
"imageServer": 0,
|
||||
"value": 12000,
|
||||
"printValue": "12,000"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "가나다라마바사아자",
|
||||
"ownerName": "검증계정",
|
||||
"nationName": "대한민국천하통일국",
|
||||
"bgColor": "#8b0000",
|
||||
"fgColor": "#ffffff",
|
||||
"picture": "default.jpg",
|
||||
"imageServer": 0,
|
||||
"value": 11000,
|
||||
"printValue": "11,000"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "계 급",
|
||||
"valueType": "int",
|
||||
"entries": []
|
||||
}
|
||||
],
|
||||
"uniqueItems": [
|
||||
{
|
||||
"title": "명 마",
|
||||
"slot": "horse",
|
||||
"entries": [
|
||||
{
|
||||
"itemKey": "che_명마_15_적토마",
|
||||
"itemName": "적토마",
|
||||
"itemInfo": "최고의 명마",
|
||||
"owner": {
|
||||
"id": 1,
|
||||
"name": "가나다라마바사아자",
|
||||
"nationName": "대한민국천하통일국",
|
||||
"bgColor": "#006400",
|
||||
"fgColor": "#ffffff",
|
||||
"picture": "default.jpg",
|
||||
"imageServer": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"itemKey": "che_명마_15_적토마",
|
||||
"itemName": "적토마",
|
||||
"itemInfo": "최고의 명마",
|
||||
"owner": {
|
||||
"id": 0,
|
||||
"name": "가나다라마바사아자",
|
||||
"nationName": "대한민국천하통일국",
|
||||
"bgColor": "#00582c",
|
||||
"fgColor": "#ffffff",
|
||||
"picture": null,
|
||||
"imageServer": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"join": {
|
||||
"lobby.info": "result",
|
||||
"auth.status": {
|
||||
"result": {
|
||||
"data": {
|
||||
"ok": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"join.getConfig": "result"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,11 +592,17 @@ const install = async (page: Page, state: FixtureState) => {
|
||||
if (type === 'generalHistory') {
|
||||
return response({
|
||||
type,
|
||||
logs: Array.from({ length: 25 }, (_, index) => ({ id: 100 - index, text: `열전-${index}` })),
|
||||
logs: Array.from({ length: 25 }, (_, index) => ({
|
||||
id: 100 - index,
|
||||
text: `열전-${index}`,
|
||||
})),
|
||||
});
|
||||
}
|
||||
if (type === 'generalAction') {
|
||||
const firstPage = Array.from({ length: 24 }, (_, index) => ({ id: 50 - index, text: `행동-${index}` }));
|
||||
const firstPage = Array.from({ length: 24 }, (_, index) => ({
|
||||
id: 50 - index,
|
||||
text: `행동-${index}`,
|
||||
}));
|
||||
return response({
|
||||
type,
|
||||
logs: jsonInput.beforeId ? [{ id: 26, text: '이전 행동' }] : firstPage,
|
||||
@@ -1034,10 +1040,10 @@ test('메인 장수 동향과 개인 전투 기록은 Ref 행 간격·색상·
|
||||
expect(geometry.battle.top).toBeCloseTo(geometry.line.top, 0);
|
||||
expect(geometry.styles).toEqual({
|
||||
diamondColor: 'rgb(135, 206, 235)',
|
||||
namePlateFontSize: '10.5px',
|
||||
namePlateFontSize: '12px',
|
||||
nameCoverColor: 'rgb(255, 255, 0)',
|
||||
crewPlateColor: 'rgb(255, 69, 0)',
|
||||
crewPlateFontSize: '12.6px',
|
||||
crewPlateFontSize: '12px',
|
||||
defenseArrowColor: 'rgb(255, 0, 255)',
|
||||
});
|
||||
};
|
||||
@@ -1317,7 +1323,7 @@ test('메인 개인 기록의 공격·수비 시각은 Ref와 같은 90% 글자
|
||||
expect(measurements.map((entry) => entry.row.fontSize)).toEqual(['14px', '14px', '14px']);
|
||||
expect(measurements.map((entry) => entry.row.lineHeight)).toEqual(['21px', '21px', '21px']);
|
||||
expect(measurements.map((entry) => entry.row.height)).toEqual([21, 21, 21]);
|
||||
expect(measurements.map((entry) => entry.time.fontSize)).toEqual(['12.6px', '12.6px', '12.6px']);
|
||||
expect(measurements.map((entry) => entry.time.fontSize)).toEqual(['12px', '12px', '12px']);
|
||||
expect(measurements.map((entry) => entry.timeSpanCount)).toEqual([1, 1, 1]);
|
||||
expect(measurements[0]?.nameFontSize).toBe('14px');
|
||||
expect(measurements[0]?.actionFontSize).toBe('14px');
|
||||
@@ -1387,7 +1393,12 @@ test('접속량정보 keeps the legacy public 1016px chart geometry', async ({ p
|
||||
|
||||
test('내 정보 열전은 전체 표시 후 종료하고 행동 기록만 다음 페이지를 요청한다', async ({ page }) => {
|
||||
const state: FixtureState = {
|
||||
permission: 'head', myset: 3, settingMutations: [], accessPages: [], pagedMyLogs: true, myLogInputs: [],
|
||||
permission: 'head',
|
||||
myset: 3,
|
||||
settingMutations: [],
|
||||
accessPages: [],
|
||||
pagedMyLogs: true,
|
||||
myLogInputs: [],
|
||||
};
|
||||
await install(page, state);
|
||||
await page.goto('my-page');
|
||||
@@ -1414,7 +1425,8 @@ test('내 정보 열전은 전체 표시 후 종료하고 행동 기록만 다
|
||||
await expect(action.getByRole('button', { name: '이전 로그 불러오기' })).toHaveCount(0);
|
||||
expect(state.myLogInputs?.filter((input) => input.type === 'generalHistory')).toHaveLength(1);
|
||||
expect(state.myLogInputs?.filter((input) => input.type === 'generalAction')).toEqual([
|
||||
{ type: 'generalAction' }, { type: 'generalAction', beforeId: 27 },
|
||||
{ type: 'generalAction' },
|
||||
{ type: 'generalAction', beforeId: 27 },
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ for (const width of [500, 1000]) {
|
||||
await page.screenshot({ path: testInfo.outputPath('main-maximum-name.png'), fullPage: true });
|
||||
});
|
||||
|
||||
test(`네 단계와 밀집 화면 보류 계약 ${width}px ${name.label}`, async ({ page }, testInfo) => {
|
||||
test(`인사부도 공통 네 단계를 사용한다 ${width}px ${name.label}`, async ({ page }, testInfo) => {
|
||||
await page.setViewportSize({ width, height: 900 });
|
||||
await install(page, 'personnel', name.general, name.nation);
|
||||
await page.goto('nation/personnel');
|
||||
@@ -100,11 +100,7 @@ for (const width of [500, 1000]) {
|
||||
await expect(page.locator('.chief-entry-copy strong').first()).toHaveText(name.general);
|
||||
await waitForFonts(page);
|
||||
await expect(page.locator('.nation-heading')).toHaveCSS('font-size', width === 500 ? '16px' : '24px');
|
||||
// 500px의 15px 이름/10px 잠금은 확대 시 표시 이름이 줄어들어 보류했다.
|
||||
await expect(page.locator('.chief-entry-copy strong').first()).toHaveCSS(
|
||||
'font-size',
|
||||
width === 500 ? '15px' : '16px'
|
||||
);
|
||||
await expect(page.locator('.chief-entry-copy strong').first()).toHaveCSS('font-size', '16px');
|
||||
const geometry = await page.locator('#personnel-container').evaluate((element) => ({
|
||||
width: element.getBoundingClientRect().width,
|
||||
scrollWidth: element.scrollWidth,
|
||||
@@ -123,17 +119,17 @@ for (const width of [500, 1000]) {
|
||||
});
|
||||
}
|
||||
|
||||
test(`사령부 12턴 요약의 기존 밀도를 유지한다 ${width}px`, async ({ page }, testInfo) => {
|
||||
test(`사령부 12턴 요약은 12px와 겹치지 않는 행을 사용한다 ${width}px`, async ({ page }, testInfo) => {
|
||||
await page.setViewportSize({ width, height: 900 });
|
||||
await install(page, 'chief', names[0].general, names[0].nation);
|
||||
await page.goto('chief-center');
|
||||
const row = page.locator('.chief-overview .chief-card.compact .chief-row').first();
|
||||
await expect(row).toBeVisible();
|
||||
await waitForFonts(page);
|
||||
await expect(row).toHaveCSS('font-size', '8.8px');
|
||||
await expect(row).toHaveCSS('line-height', '11.25px');
|
||||
await expect(page.locator('.chief-overview .compact-name').first()).toHaveCSS('font-size', '10.4px');
|
||||
expect((await row.boundingBox())?.height).toBe(11.25);
|
||||
await expect(row).toHaveCSS('font-size', '12px');
|
||||
await expect(row).toHaveCSS('line-height', '16px');
|
||||
await expect(page.locator('.chief-overview .compact-name').first()).toHaveCSS('font-size', '12px');
|
||||
expect((await row.boundingBox())?.height).toBe(16);
|
||||
await page.screenshot({ path: testInfo.outputPath('chief-deferred-density.png'), fullPage: true });
|
||||
});
|
||||
|
||||
@@ -187,8 +183,8 @@ for (const width of [500, 1000]) {
|
||||
const summary = page.locator('.small_war_log').first();
|
||||
await expect(summary).toContainText('【경국지색소교】');
|
||||
await expect(summary).toHaveCSS('font-size', '14px');
|
||||
await expect(summary.locator('.name_plate').first()).toHaveCSS('font-size', '10.5px');
|
||||
await expect(summary.locator('.crew_plate').first()).toHaveCSS('font-size', '12.6px');
|
||||
await expect(summary.locator('.name_plate').first()).toHaveCSS('font-size', '12px');
|
||||
await expect(summary.locator('.crew_plate').first()).toHaveCSS('font-size', '12px');
|
||||
await waitForFonts(page);
|
||||
await page.screenshot({ path: testInfo.outputPath('battle-log-exception.png'), fullPage: true });
|
||||
});
|
||||
@@ -219,3 +215,95 @@ for (const width of [500, 1000]) {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Actual page CSS, including the reset and scoped component rules, must implement the ladder.
|
||||
test('small은 부모 단계에서 내려가고 다섯 번째 크기에서 멈춘다', async ({ page }, testInfo) => {
|
||||
await install(page, 'main', names[0].general, names[0].nation);
|
||||
await page.goto('./');
|
||||
await expect(page.locator('.game-shell__title')).toBeVisible();
|
||||
const actual = await page.evaluate(() => {
|
||||
const host = document.createElement('section');
|
||||
host.id = 'typography-ladder-probe';
|
||||
document.body.append(host);
|
||||
const result = ['title', 'emphasis', 'normal', 'small'].map((tier) => {
|
||||
const parent = document.createElement('div');
|
||||
parent.className = `sammo-text-${tier}`;
|
||||
parent.innerHTML = '본문<small>보조<span>상속</span><small>중첩<small>최소</small></small></small>';
|
||||
host.append(parent);
|
||||
return [parent, ...parent.querySelectorAll('small')].map((node) => getComputedStyle(node).fontSize);
|
||||
});
|
||||
host.remove();
|
||||
return result;
|
||||
});
|
||||
expect(actual).toEqual([
|
||||
['24px', '16px', '14px', '12px'],
|
||||
['16px', '14px', '12px', '10px'],
|
||||
['14px', '12px', '10px', '10px'],
|
||||
['12px', '10px', '10px', '10px'],
|
||||
]);
|
||||
await testInfo.attach('small-ladder', { body: JSON.stringify(actual), contentType: 'application/json' });
|
||||
});
|
||||
|
||||
for (const width of [500, 1000]) {
|
||||
for (const general of ['가나다라', names[0].general, names[1].general]) {
|
||||
test(`명장 이름은 12px를 최대로 칸에 맞게 축소한다 ${width}px ${general.length}자`, async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
await page.setViewportSize({ width, height: 900 });
|
||||
await install(page, 'best', general, names[0].nation);
|
||||
await page.goto('best-general');
|
||||
const label = page.locator('.hall-name .sammo-fit-text').first();
|
||||
await expect(label).toHaveText(general);
|
||||
await waitForFonts(page);
|
||||
await expect(label).toHaveAttribute('data-font-fit-max', '12');
|
||||
await expect(label).toHaveAttribute('title', general);
|
||||
const measured = await label.evaluate((element) => {
|
||||
const style = getComputedStyle(element);
|
||||
return {
|
||||
size: Number.parseFloat(style.fontSize),
|
||||
overflow: style.overflow,
|
||||
ellipsis: style.textOverflow,
|
||||
};
|
||||
});
|
||||
expect(measured.size).toBeLessThanOrEqual(12);
|
||||
expect(measured.size).toBeGreaterThanOrEqual(10);
|
||||
if (general.length === 4) expect(measured.size).toBe(12);
|
||||
if (general.length === 18) expect(measured.size).toBeLessThan(12);
|
||||
expect(measured).toMatchObject({ overflow: 'hidden', ellipsis: 'ellipsis' });
|
||||
await page.screenshot({ path: testInfo.outputPath('ranking-fitted-name.png'), fullPage: true });
|
||||
await testInfo.attach('fitted-name', { body: JSON.stringify(measured), contentType: 'application/json' });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const width of [500, 1000]) {
|
||||
test(`장수 생성의 보조 설명 class는 small 단계를 덮어쓰지 않는다 ${width}px`, async ({ page }, testInfo) => {
|
||||
await page.setViewportSize({ width, height: 900 });
|
||||
await install(page, 'join', names[0].general, names[0].nation);
|
||||
await page.goto('join');
|
||||
await expect(page.locator('.create-form')).toBeVisible();
|
||||
await page.locator('.advanced-options > summary').click();
|
||||
await waitForFonts(page);
|
||||
const steps = await page
|
||||
.locator('small')
|
||||
.evaluateAll((elements) =>
|
||||
elements
|
||||
.filter((element) => element.checkVisibility())
|
||||
.map((element) => ({
|
||||
parent: getComputedStyle(element.parentElement!).fontSize,
|
||||
size: getComputedStyle(element).fontSize,
|
||||
}))
|
||||
);
|
||||
expect(steps.length).toBeGreaterThan(0);
|
||||
const next: Record<string, string> = {
|
||||
'24px': '16px',
|
||||
'16px': '14px',
|
||||
'14px': '12px',
|
||||
'12px': '10px',
|
||||
'10px': '10px',
|
||||
};
|
||||
for (const step of steps) expect(step.size).toBe(next[step.parent]);
|
||||
await expect(page.locator('.primary-field small.muted')).toHaveCSS('font-size', '10px');
|
||||
await testInfo.attach('join-small-steps', { body: JSON.stringify(steps), contentType: 'application/json' });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
@import url('https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css');
|
||||
@import 'tailwindcss';
|
||||
@import './styles/tokens.css';
|
||||
@import './styles/typography.css';
|
||||
@import './styles/legacy-controls.css';
|
||||
@import './styles/game-shell.css';
|
||||
@import './styles/ref-shell.css';
|
||||
@@ -144,7 +145,7 @@ input[inputmode='search'] {
|
||||
}
|
||||
|
||||
.small_war_log .name_plate {
|
||||
font-size: var(--sammo-font-size-war-name);
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.small_war_log .name_plate_cover {
|
||||
@@ -153,5 +154,5 @@ input[inputmode='search'] {
|
||||
|
||||
.small_war_log .crew_plate {
|
||||
color: orangered;
|
||||
font-size: var(--sammo-font-size-war-crew);
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
:root {
|
||||
/* 검증된 화면이 공유하는 네 단계. 콘텐츠 내부 축소/숨김은 별도 계약이다. */
|
||||
--sammo-font-size-small: calc(var(--sammo-font-size-normal) * 12 / 14);
|
||||
/* 모든 프로필 UI의 기본 네 단계. smaller는 바로 아래 단계이며 10px에서 멈춘다. */
|
||||
--sammo-font-size-small: 12px;
|
||||
--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-size-minimum: 10px;
|
||||
--sammo-font-size-smaller: calc(
|
||||
clamp(var(--sammo-font-size-minimum), 1em - 2px, var(--sammo-font-size-normal)) +
|
||||
clamp(0px, (1em - var(--sammo-font-size-emphasis)) / 4, 2px)
|
||||
);
|
||||
--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);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/* 페이지와 공통 컴포넌트가 같은 단계 이름을 사용한다. */
|
||||
.sammo-text-title {
|
||||
font-size: var(--sammo-font-size-title);
|
||||
}
|
||||
.sammo-text-emphasis {
|
||||
font-size: var(--sammo-font-size-emphasis);
|
||||
}
|
||||
.sammo-text-normal {
|
||||
font-size: var(--sammo-font-size-normal);
|
||||
}
|
||||
.sammo-text-small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
/* 부모의 단계에서 한 단계 아래. 12px의 보조 설명만 10px, 중첩해도 더 줄지 않는다. */
|
||||
small,
|
||||
sub,
|
||||
sup,
|
||||
.sammo-text-smaller,
|
||||
.legacy-small {
|
||||
font-size: var(--sammo-font-size-smaller);
|
||||
}
|
||||
|
||||
/* v-fit-text measures from the inherited tier; an extreme name keeps its full title. */
|
||||
.sammo-fit-text {
|
||||
display: block;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
@@ -107,7 +107,7 @@ const handleClick = () => {
|
||||
|
||||
.chief-card.compact {
|
||||
padding: 0;
|
||||
font-size: var(--sammo-font-size-chief-compact-base);
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.chief-header {
|
||||
@@ -175,7 +175,7 @@ const handleClick = () => {
|
||||
height: 13px;
|
||||
min-height: 0;
|
||||
padding: 0 2px;
|
||||
font-size: var(--sammo-font-size-chief-compact-row);
|
||||
font-size: var(--sammo-font-size-small);
|
||||
line-height: 11px;
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ const handleClick = () => {
|
||||
box-sizing: border-box;
|
||||
height: 20px;
|
||||
min-height: 0;
|
||||
font-size: var(--sammo-font-size-chief-compact-header);
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.compact-name,
|
||||
@@ -210,7 +210,7 @@ const handleClick = () => {
|
||||
|
||||
.chief-card.compact .chief-level,
|
||||
.chief-card.compact .chief-name {
|
||||
font-size: var(--sammo-font-size-chief-compact-name);
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.chief-row.rest {
|
||||
|
||||
@@ -270,11 +270,6 @@ watch(
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.recruitment-command-form {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
@@ -383,7 +378,6 @@ small {
|
||||
}
|
||||
.crew-name small {
|
||||
display: block;
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
.crew-row small {
|
||||
display: none;
|
||||
@@ -515,12 +509,8 @@ small {
|
||||
}
|
||||
.crew-row small {
|
||||
display: block;
|
||||
font-size: var(--sammo-font-size-small);
|
||||
line-height: 1;
|
||||
}
|
||||
.crew-row .crew-name small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
.crew-header .attack,
|
||||
.crew-header .defence,
|
||||
.crew-header .speed,
|
||||
|
||||
@@ -913,11 +913,6 @@ const clickOutsideMenu = (event: Event) => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.reserved-command-editor {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
@@ -1177,7 +1172,6 @@ small {
|
||||
visibility: visible;
|
||||
}
|
||||
.action-column small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
line-height: 1;
|
||||
}
|
||||
.reserved-command-editor.mobile .action-column > div.autonomous {
|
||||
@@ -1379,7 +1373,7 @@ small {
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
font-size: 18pt;
|
||||
font-size: var(--sammo-font-size-title);
|
||||
font-weight: normal;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
@@ -1388,7 +1382,6 @@ small {
|
||||
.overlay-title small {
|
||||
overflow: hidden;
|
||||
color: #ffe0a0;
|
||||
font-size: var(--sammo-font-size-small);
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.command-picker.argument-overlay .selected-command,
|
||||
@@ -1457,7 +1450,7 @@ small {
|
||||
.argument-overlay-bar > .overlay-title {
|
||||
grid-column: 1 / -1;
|
||||
grid-row: 1;
|
||||
font-size: 14pt;
|
||||
font-size: var(--sammo-font-size-emphasis);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -355,11 +355,6 @@ const sortHelp = (header: Header): string =>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.directory-table {
|
||||
width: 1000px;
|
||||
border-collapse: collapse;
|
||||
|
||||
@@ -631,7 +631,10 @@ watch(
|
||||
>
|
||||
- {{ row.name }}
|
||||
</button>
|
||||
<span>: <span class="nation-type-pros">{{ row.pros }}</span>,</span>
|
||||
<span
|
||||
>: <span class="nation-type-pros">{{ row.pros }}</span
|
||||
>,</span
|
||||
>
|
||||
<span class="nation-type-cons">{{ row.cons }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -967,11 +970,6 @@ watch(
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.target-search {
|
||||
grid-column: 1 / -1;
|
||||
display: flex;
|
||||
@@ -1186,7 +1184,7 @@ small {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
min-height: 2em;
|
||||
font-size: 1.3em;
|
||||
font-size: var(--sammo-font-size-emphasis);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -1467,7 +1465,6 @@ small {
|
||||
}
|
||||
|
||||
.assignment-target-list .target-option small {
|
||||
font-size: inherit;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
|
||||
@@ -174,11 +174,6 @@ const commandTitle = (command: CommandAvailability) =>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.command-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -214,7 +214,7 @@ const displayChiefName = (chief: NationChief | undefined): string => {
|
||||
min-width: 0;
|
||||
height: 193px;
|
||||
color: #fff;
|
||||
font-size: var(--sammo-font-size-nation-card);
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.nation-grid {
|
||||
|
||||
@@ -219,11 +219,6 @@ onBeforeUnmount(() => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.personnel-picker-backdrop {
|
||||
position: fixed;
|
||||
z-index: 2050;
|
||||
@@ -437,7 +432,6 @@ small {
|
||||
.personnel-picker-stats small,
|
||||
.personnel-picker-details small {
|
||||
color: #aaa99f;
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
.personnel-picker-stats strong {
|
||||
color: #f1d47e;
|
||||
|
||||
@@ -22,6 +22,11 @@ let chart: Chart<'line'> | undefined;
|
||||
const render = () => {
|
||||
if (!canvas.value) return;
|
||||
chart?.destroy();
|
||||
const style = getComputedStyle(canvas.value);
|
||||
const font = {
|
||||
family: style.fontFamily,
|
||||
size: Number.parseFloat(style.getPropertyValue('--sammo-font-size-small')),
|
||||
};
|
||||
chart = new Chart(canvas.value, {
|
||||
type: 'line',
|
||||
data: {
|
||||
@@ -42,10 +47,13 @@ const render = () => {
|
||||
maintainAspectRatio: false,
|
||||
animation: false,
|
||||
interaction: { mode: 'index', intersect: false },
|
||||
plugins: { legend: { labels: { color: '#e5eee9' } } },
|
||||
plugins: {
|
||||
legend: { labels: { color: '#e5eee9', font } },
|
||||
tooltip: { titleFont: font, bodyFont: font, footerFont: font },
|
||||
},
|
||||
scales: {
|
||||
x: { ticks: { color: '#c3d0c8', maxTicksLimit: 12 }, grid: { color: '#34473e' } },
|
||||
y: { ticks: { color: '#c3d0c8' }, grid: { color: '#34473e' } },
|
||||
x: { ticks: { color: '#c3d0c8', maxTicksLimit: 12, font }, grid: { color: '#34473e' } },
|
||||
y: { ticks: { color: '#c3d0c8', font }, grid: { color: '#34473e' } },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -342,7 +342,7 @@ const mobilePairs = computed(() => {
|
||||
border-radius: 3px;
|
||||
color: #fff3cd;
|
||||
background: #59400e;
|
||||
font: 700 var(--sammo-font-size-bracket-bet-button)/1 var(--sammo-font-sans);
|
||||
font: 700 var(--sammo-font-size-small)/1 var(--sammo-font-sans);
|
||||
cursor: pointer;
|
||||
}
|
||||
.bracket-bet-button:hover,
|
||||
|
||||
@@ -228,7 +228,7 @@ onBeforeUnmount(() => editor.value?.destroy());
|
||||
<span class="legacy-html-editor__sr-only">크기</span>
|
||||
<select aria-label="글꼴 크기" @change="setFontSize">
|
||||
<option value="">크기</option>
|
||||
<option v-for="size in fontSizes" :key="size" :value="size" :style="{ fontSize: size }">
|
||||
<option v-for="size in fontSizes" :key="size" :value="size">
|
||||
{{ size }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import type { ObjectDirective } from 'vue';
|
||||
|
||||
type FitState = { observer: ResizeObserver; frame: number; alive: boolean };
|
||||
const states = new WeakMap<HTMLElement, FitState>();
|
||||
|
||||
const fit = (element: HTMLElement): void => {
|
||||
// Always measure from the CSS tier, so shorter text and wider cells can grow back.
|
||||
element.style.removeProperty('font-size');
|
||||
const maximum = Number.parseFloat(getComputedStyle(element).fontSize);
|
||||
const available = element.clientWidth;
|
||||
if (!available) return;
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(element);
|
||||
const natural = range.getBoundingClientRect().width;
|
||||
const minimum = Number.parseFloat(getComputedStyle(element).getPropertyValue('--sammo-font-size-minimum'));
|
||||
const size = Math.min(maximum, Math.max(minimum, (maximum * available) / Math.max(natural, 1)));
|
||||
element.dataset.fontFitMax = String(maximum);
|
||||
if (size < maximum) element.style.fontSize = `${Math.floor(size * 100) / 100}px`;
|
||||
};
|
||||
|
||||
const schedule = (element: HTMLElement): void => {
|
||||
const state = states.get(element);
|
||||
if (!state?.alive) return;
|
||||
cancelAnimationFrame(state.frame);
|
||||
state.frame = requestAnimationFrame(() => fit(element));
|
||||
};
|
||||
|
||||
/** One-line UI labels: CSS selects the maximum tier; 10px is the readability floor. */
|
||||
export const vFitText: ObjectDirective<HTMLElement> = {
|
||||
mounted(element) {
|
||||
const observer = new ResizeObserver(() => schedule(element));
|
||||
states.set(element, { observer, frame: 0, alive: true });
|
||||
observer.observe(element);
|
||||
schedule(element);
|
||||
void document.fonts.ready.then(() => schedule(element));
|
||||
},
|
||||
updated: schedule,
|
||||
beforeUnmount(element) {
|
||||
const state = states.get(element);
|
||||
if (!state) return;
|
||||
state.alive = false;
|
||||
cancelAnimationFrame(state.frame);
|
||||
state.observer.disconnect();
|
||||
states.delete(element);
|
||||
},
|
||||
};
|
||||
@@ -1,3 +1,3 @@
|
||||
import { formatLegacyLogHtml } from '@sammo-ts/common/logging/formatLegacyLogHtml';
|
||||
|
||||
export const formatLog = (text?: string): string => formatLegacyLogHtml(text);
|
||||
export const formatLog = (text?: string): string => formatLegacyLogHtml(text, { smallText: 'semantic' });
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { vFitText } from '../directives/fitText';
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
@@ -117,11 +118,18 @@ watch(viewMode, () => {
|
||||
@error="useDefaultGeneralIcon"
|
||||
/>
|
||||
</div>
|
||||
<div class="hall-nation" :style="{ backgroundColor: entry.bgColor, color: entry.fgColor }">
|
||||
<div
|
||||
v-fit-text
|
||||
class="hall-nation sammo-fit-text"
|
||||
:title="entry.nationName || '-'"
|
||||
:style="{ backgroundColor: entry.bgColor, color: entry.fgColor }"
|
||||
>
|
||||
{{ entry.nationName || '-' }}
|
||||
</div>
|
||||
<div class="hall-name" :style="{ backgroundColor: entry.bgColor, color: entry.fgColor }">
|
||||
<span>{{ entry.name || '-' }}</span>
|
||||
<span v-fit-text class="sammo-fit-text" :title="entry.name || '-'">{{
|
||||
entry.name || '-'
|
||||
}}</span>
|
||||
<small v-if="entry.ownerName">({{ entry.ownerName }})</small>
|
||||
</div>
|
||||
<div class="hall-value">{{ entry.printValue }}</div>
|
||||
@@ -152,7 +160,9 @@ watch(viewMode, () => {
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="hall-nation"
|
||||
v-fit-text
|
||||
class="hall-nation sammo-fit-text"
|
||||
:title="entry.owner.nationName || '-'"
|
||||
:style="{ backgroundColor: entry.owner.bgColor, color: entry.owner.fgColor }"
|
||||
>
|
||||
{{ entry.owner.nationName || '-' }}
|
||||
@@ -161,7 +171,9 @@ watch(viewMode, () => {
|
||||
class="hall-name"
|
||||
:style="{ backgroundColor: entry.owner.bgColor, color: entry.owner.fgColor }"
|
||||
>
|
||||
<span>{{ entry.owner.name || '-' }}</span>
|
||||
<span v-fit-text class="sammo-fit-text" :title="entry.owner.name || '-'">{{
|
||||
entry.owner.name || '-'
|
||||
}}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -179,11 +191,6 @@ watch(viewMode, () => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
:global(body:has(.legacy-ranking-page)) {
|
||||
min-width: 500px;
|
||||
overflow-x: hidden;
|
||||
@@ -346,7 +353,7 @@ small {
|
||||
|
||||
.hall-nation,
|
||||
.hall-name {
|
||||
font-size: var(--sammo-font-size-hall-name);
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.hall-name {
|
||||
@@ -356,10 +363,6 @@ small {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.hall-name small {
|
||||
font-size: var(--sammo-font-size-hall-secondary);
|
||||
}
|
||||
|
||||
.hall-value {
|
||||
box-sizing: border-box;
|
||||
padding: 3px 0;
|
||||
|
||||
@@ -281,11 +281,6 @@ const placeBet = async (target: TournamentBracketSlot) => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.betting-page {
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
@@ -347,7 +342,6 @@ small {
|
||||
}
|
||||
.section-title small {
|
||||
color: orange;
|
||||
font-size: var(--sammo-font-size-normal);
|
||||
}
|
||||
select {
|
||||
width: 100%;
|
||||
@@ -552,9 +546,6 @@ select:disabled {
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
.betting-page small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
.bet-preset {
|
||||
position: relative;
|
||||
display: grid;
|
||||
|
||||
@@ -796,27 +796,27 @@ const repeatTurns = async (amount: number) => {
|
||||
}
|
||||
.chief-overview-frame {
|
||||
width: 500px;
|
||||
height: 310px;
|
||||
height: 448px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 11px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.chief-overview {
|
||||
width: 500px;
|
||||
height: 310px;
|
||||
height: 448px;
|
||||
margin-top: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.chief-overview-row {
|
||||
width: 500px;
|
||||
height: 155px;
|
||||
height: 224px;
|
||||
display: grid;
|
||||
grid-template-columns: 12px repeat(4, 119px) 12px;
|
||||
}
|
||||
.chief-overview :deep(.chief-card) {
|
||||
width: 119px;
|
||||
height: 155px;
|
||||
height: 224px;
|
||||
border: 0;
|
||||
border-left: 1px solid #fff;
|
||||
box-shadow: none;
|
||||
@@ -827,26 +827,26 @@ const repeatTurns = async (amount: number) => {
|
||||
}
|
||||
.chief-overview :deep(.chief-card.compact .chief-row) {
|
||||
grid-template-columns: 38px minmax(0, 1fr);
|
||||
height: 11.25px !important;
|
||||
height: 16px !important;
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
gap: 0;
|
||||
text-align: center;
|
||||
font-size: var(--sammo-font-size-chief-compact-row);
|
||||
line-height: 11.25px !important;
|
||||
font-size: var(--sammo-font-size-small);
|
||||
line-height: 16px !important;
|
||||
}
|
||||
.chief-overview :deep(.chief-card.compact .chief-header) {
|
||||
box-sizing: border-box;
|
||||
height: 20px !important;
|
||||
min-height: 20px !important;
|
||||
height: 32px !important;
|
||||
min-height: 32px !important;
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: 10px 10px;
|
||||
line-height: 10px;
|
||||
grid-template-rows: 16px 16px;
|
||||
line-height: 16px;
|
||||
}
|
||||
.chief-overview :deep(.compact-name),
|
||||
.chief-overview :deep(.compact-meta) {
|
||||
height: 10px;
|
||||
line-height: 10px;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
}
|
||||
.chief-overview :deep(.row-time),
|
||||
.chief-overview :deep(.row-action) {
|
||||
@@ -855,12 +855,12 @@ const repeatTurns = async (amount: number) => {
|
||||
}
|
||||
.overview-turn-index {
|
||||
display: grid;
|
||||
grid-template-rows: 20px repeat(12, 11.25px);
|
||||
grid-template-rows: 32px repeat(12, 16px);
|
||||
width: 12px;
|
||||
height: 155px;
|
||||
height: 224px;
|
||||
color: #fff;
|
||||
font-size: var(--sammo-font-size-chief-compact-row);
|
||||
line-height: 11.25px;
|
||||
font-size: var(--sammo-font-size-small);
|
||||
line-height: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
.overview-turn-index span {
|
||||
|
||||
@@ -133,11 +133,6 @@ onMounted(() => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.directory-page {
|
||||
width: 1000px;
|
||||
margin: 0 auto;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { vFitText } from '../directives/fitText';
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
@@ -169,11 +170,18 @@ onMounted(loadOptions);
|
||||
>
|
||||
{{ entry.serverName }}{{ entry.serverIdx }}기
|
||||
</div>
|
||||
<div class="hall-nation" :style="{ backgroundColor: entry.bgColor, color: entry.fgColor }">
|
||||
<div
|
||||
v-fit-text
|
||||
class="hall-nation sammo-fit-text"
|
||||
:title="entry.nationName || '-'"
|
||||
:style="{ backgroundColor: entry.bgColor, color: entry.fgColor }"
|
||||
>
|
||||
{{ entry.nationName || '-' }}
|
||||
</div>
|
||||
<div class="hall-name" :style="{ backgroundColor: entry.bgColor, color: entry.fgColor }">
|
||||
<span>{{ entry.name || '-' }}</span>
|
||||
<span v-fit-text class="sammo-fit-text" :title="entry.name || '-'">{{
|
||||
entry.name || '-'
|
||||
}}</span>
|
||||
<small v-if="entry.ownerName">({{ entry.ownerName }})</small>
|
||||
</div>
|
||||
<div class="hall-value">{{ entry.printValue }}</div>
|
||||
@@ -193,11 +201,6 @@ onMounted(loadOptions);
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
/* Ref's document does not clip; the page column stays 500px wide instead. */
|
||||
:global(body:has(.legacy-hall-page)) {
|
||||
min-width: 500px;
|
||||
@@ -349,7 +352,7 @@ small {
|
||||
.hall-server,
|
||||
.hall-nation,
|
||||
.hall-name {
|
||||
font-size: var(--sammo-font-size-hall-name);
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.hall-name {
|
||||
@@ -359,10 +362,6 @@ small {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.hall-name small {
|
||||
font-size: var(--sammo-font-size-hall-secondary);
|
||||
}
|
||||
|
||||
.hall-value {
|
||||
box-sizing: border-box;
|
||||
padding: 3px 0;
|
||||
|
||||
@@ -787,11 +787,6 @@ onMounted(() => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.top-back-bar {
|
||||
width: min(100%, 1000px);
|
||||
height: 32px;
|
||||
|
||||
@@ -1270,11 +1270,6 @@ onMounted(() => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.join-page {
|
||||
min-height: 100vh;
|
||||
padding: 24px;
|
||||
@@ -1519,7 +1514,6 @@ small {
|
||||
|
||||
.advanced-title small {
|
||||
color: #ccc;
|
||||
font-size: var(--sammo-font-size-small);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
@@ -1871,10 +1865,6 @@ small {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.npc-general-name small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
#btn-print-more-generals {
|
||||
width: 100%;
|
||||
min-height: 28px;
|
||||
@@ -1883,6 +1873,9 @@ small {
|
||||
|
||||
.muted {
|
||||
color: rgba(232, 221, 196, 0.6);
|
||||
}
|
||||
|
||||
.muted:not(small) {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
|
||||
@@ -314,11 +314,6 @@ onBeforeUnmount(() => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.legacy-page {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
|
||||
@@ -1015,11 +1015,6 @@ onBeforeUnmount(() => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.general-page {
|
||||
width: 1000px;
|
||||
min-width: 1000px;
|
||||
|
||||
@@ -422,11 +422,6 @@ onBeforeUnmount(() => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.directory-page {
|
||||
width: 1000px;
|
||||
margin: 0 auto;
|
||||
|
||||
@@ -609,11 +609,6 @@ onMounted(() => void loadPersonnel());
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.legacy-office {
|
||||
width: 1000px;
|
||||
min-height: 100vh;
|
||||
@@ -758,7 +753,6 @@ select {
|
||||
.chief-entry-copy small {
|
||||
overflow: hidden;
|
||||
color: #c8c5bc;
|
||||
font-size: var(--sammo-font-size-small);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -855,9 +849,6 @@ select {
|
||||
.city-identity strong {
|
||||
display: block;
|
||||
}
|
||||
.city-identity small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
.city-officer-cell {
|
||||
padding: 5px !important;
|
||||
vertical-align: middle;
|
||||
@@ -880,7 +871,6 @@ select {
|
||||
}
|
||||
.city-officer-copy small {
|
||||
color: #c9c6bd;
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
.city-change-button {
|
||||
min-width: 70px;
|
||||
@@ -949,10 +939,7 @@ select {
|
||||
height: 48px;
|
||||
}
|
||||
.chief-entry-copy strong {
|
||||
font-size: var(--sammo-font-size-personnel-mobile-name);
|
||||
}
|
||||
.chief-entry-copy small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
font-size: var(--sammo-font-size-emphasis);
|
||||
}
|
||||
.personnel-change-button {
|
||||
min-height: 30px;
|
||||
@@ -961,7 +948,7 @@ select {
|
||||
line-height: 18px;
|
||||
}
|
||||
.personnel-lock-label {
|
||||
font-size: var(--sammo-font-size-personnel-mobile-lock);
|
||||
font-size: var(--sammo-font-size-smaller);
|
||||
}
|
||||
.award-label {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
@@ -995,9 +982,6 @@ select {
|
||||
width: 16%;
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
.city-identity small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
.city-officer-cell {
|
||||
padding: 4px !important;
|
||||
}
|
||||
@@ -1008,9 +992,6 @@ select {
|
||||
.city-officer-copy strong {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
.city-officer-copy small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
.city-change-button {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
|
||||
<template>
|
||||
<main class="min-h-screen px-6 py-8">
|
||||
<h1 class="text-2xl font-semibold">Not Found</h1>
|
||||
<p class="mt-2 text-sm text-amber-200/80">
|
||||
The requested page does not exist.
|
||||
</p>
|
||||
<h1 class="sammo-text-title font-semibold">Not Found</h1>
|
||||
<p class="mt-2 sammo-text-normal text-amber-200/80">The requested page does not exist.</p>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@@ -555,11 +555,6 @@ const submitPriority = async (section: PrioritySectionKey) => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
/*
|
||||
* The document contract belongs to this page only. An unscoped html/body rule
|
||||
* here leaked a 21px line-height and a 500px min-width onto every other screen.
|
||||
@@ -813,7 +808,6 @@ small {
|
||||
}
|
||||
|
||||
.priority-description small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
line-height: 18.375px;
|
||||
}
|
||||
|
||||
|
||||
@@ -363,11 +363,6 @@ const start = async () => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* UI 보조 글자는 부모의 80%가 아니라 공통 소형 크기를 사용한다. */
|
||||
small {
|
||||
font-size: var(--sammo-font-size-small);
|
||||
}
|
||||
|
||||
.legacy-page {
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
|
||||
@@ -57,3 +57,19 @@ void describe('game content font contract', () => {
|
||||
assert.deepEqual(violations, []);
|
||||
});
|
||||
});
|
||||
|
||||
void describe('game typography size contract', () => {
|
||||
void it('keeps page and component size declarations on shared tiers', async () => {
|
||||
const violations: string[] = [];
|
||||
for (const file of await listStyleSources()) {
|
||||
const source = await readFile(file, 'utf8');
|
||||
for (const match of source.matchAll(/\bfont-size\s*:\s*([^;]+);/g)) {
|
||||
const value = match[1]!.trim();
|
||||
if (value === '0' || value === 'inherit') continue;
|
||||
if (/^var\(--sammo-font-size-(?:title|emphasis|normal|small|smaller)\)$/.test(value)) continue;
|
||||
violations.push(`${path.relative(sourceRoot, file)}: ${value}`);
|
||||
}
|
||||
}
|
||||
assert.deepEqual(violations, []);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user