merge: 다이얼로그 화면 중앙 배치를 main에 반영한다
This commit is contained in:
@@ -1356,6 +1356,7 @@ test('desktop menus preserve ref columns, prefix-safe routes, and controlled dro
|
|||||||
codeColor: codeStyle.color,
|
codeColor: codeStyle.color,
|
||||||
codeFontFamily: codeStyle.fontFamily,
|
codeFontFamily: codeStyle.fontFamily,
|
||||||
viewportWidth: window.innerWidth,
|
viewportWidth: window.innerWidth,
|
||||||
|
viewportHeight: window.innerHeight,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
expect(versionGeometry.dialog.width).toBeLessThanOrEqual(versionGeometry.viewportWidth - 32);
|
expect(versionGeometry.dialog.width).toBeLessThanOrEqual(versionGeometry.viewportWidth - 32);
|
||||||
@@ -1364,11 +1365,18 @@ test('desktop menus preserve ref columns, prefix-safe routes, and controlled dro
|
|||||||
expect(versionGeometry.dialogBackground).toBe('rgb(32, 32, 32)');
|
expect(versionGeometry.dialogBackground).toBe('rgb(32, 32, 32)');
|
||||||
expect(versionGeometry.dialogColor).toBe('rgb(255, 255, 255)');
|
expect(versionGeometry.dialogColor).toBe('rgb(255, 255, 255)');
|
||||||
expect(versionGeometry.codeColor).toBe('rgb(215, 215, 215)');
|
expect(versionGeometry.codeColor).toBe('rgb(215, 215, 215)');
|
||||||
|
expect(
|
||||||
|
Math.abs(versionGeometry.dialog.left + versionGeometry.dialog.width / 2 - versionGeometry.viewportWidth / 2)
|
||||||
|
).toBeLessThanOrEqual(1);
|
||||||
|
expect(
|
||||||
|
Math.abs(versionGeometry.dialog.top + versionGeometry.dialog.height / 2 - versionGeometry.viewportHeight / 2)
|
||||||
|
).toBeLessThanOrEqual(1);
|
||||||
await writeFile(
|
await writeFile(
|
||||||
testInfo.outputPath('desktop-game-version-dialog.json'),
|
testInfo.outputPath('desktop-game-version-dialog.json'),
|
||||||
`${JSON.stringify(versionGeometry, null, 2)}\n`
|
`${JSON.stringify(versionGeometry, null, 2)}\n`
|
||||||
);
|
);
|
||||||
await versionDialog.screenshot({ path: testInfo.outputPath('desktop-game-version-dialog.png') });
|
await versionDialog.screenshot({ path: testInfo.outputPath('desktop-game-version-dialog.png') });
|
||||||
|
await page.screenshot({ path: testInfo.outputPath('desktop-game-version-dialog-viewport.png') });
|
||||||
await versionDialog.getByRole('button', { name: '닫기' }).click();
|
await versionDialog.getByRole('button', { name: '닫기' }).click();
|
||||||
await expect(versionDialog).toBeHidden();
|
await expect(versionDialog).toBeHidden();
|
||||||
|
|
||||||
@@ -1737,6 +1745,7 @@ test('the repeated bottom global menu opens upward on the mobile document', asyn
|
|||||||
dialog: dialog.getBoundingClientRect().toJSON(),
|
dialog: dialog.getBoundingClientRect().toJSON(),
|
||||||
code: code.getBoundingClientRect().toJSON(),
|
code: code.getBoundingClientRect().toJSON(),
|
||||||
viewportWidth: window.innerWidth,
|
viewportWidth: window.innerWidth,
|
||||||
|
viewportHeight: window.innerHeight,
|
||||||
documentScrollWidth: document.documentElement.scrollWidth,
|
documentScrollWidth: document.documentElement.scrollWidth,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -1744,11 +1753,18 @@ test('the repeated bottom global menu opens upward on the mobile document', asyn
|
|||||||
expect(versionGeometry.code.left).toBeGreaterThanOrEqual(versionGeometry.dialog.left);
|
expect(versionGeometry.code.left).toBeGreaterThanOrEqual(versionGeometry.dialog.left);
|
||||||
expect(versionGeometry.code.right).toBeLessThanOrEqual(versionGeometry.dialog.right);
|
expect(versionGeometry.code.right).toBeLessThanOrEqual(versionGeometry.dialog.right);
|
||||||
expect(versionGeometry.documentScrollWidth).toBe(500);
|
expect(versionGeometry.documentScrollWidth).toBe(500);
|
||||||
|
expect(
|
||||||
|
Math.abs(versionGeometry.dialog.left + versionGeometry.dialog.width / 2 - versionGeometry.viewportWidth / 2)
|
||||||
|
).toBeLessThanOrEqual(1);
|
||||||
|
expect(
|
||||||
|
Math.abs(versionGeometry.dialog.top + versionGeometry.dialog.height / 2 - versionGeometry.viewportHeight / 2)
|
||||||
|
).toBeLessThanOrEqual(1);
|
||||||
await writeFile(
|
await writeFile(
|
||||||
testInfo.outputPath('mobile-game-version-dialog.json'),
|
testInfo.outputPath('mobile-game-version-dialog.json'),
|
||||||
`${JSON.stringify(versionGeometry, null, 2)}\n`
|
`${JSON.stringify(versionGeometry, null, 2)}\n`
|
||||||
);
|
);
|
||||||
await versionDialog.screenshot({ path: testInfo.outputPath('mobile-game-version-dialog.png') });
|
await versionDialog.screenshot({ path: testInfo.outputPath('mobile-game-version-dialog.png') });
|
||||||
|
await page.screenshot({ path: testInfo.outputPath('mobile-game-version-dialog-viewport.png') });
|
||||||
await persistArtifact(page, `${basePath.slice(1)}-mobile-bottom-dropup`);
|
await persistArtifact(page, `${basePath.slice(1)}-mobile-bottom-dropup`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { expect, test, type Page, type Route } from '@playwright/test';
|
import { expect, test, type Page, type Route } from '@playwright/test';
|
||||||
import { mkdir, readFile } from 'node:fs/promises';
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
||||||
import { dirname, resolve } from 'node:path';
|
import { dirname, resolve } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { gameProfile, gameTrpcRoute } from './gameTestPaths.js';
|
import { gameProfile, gameTrpcRoute } from './gameTestPaths.js';
|
||||||
@@ -967,6 +967,28 @@ test('mobile betting rankings use tabs and keep dedicated icons beside general n
|
|||||||
await firstBetButton.click();
|
await firstBetButton.click();
|
||||||
const dialog = page.getByRole('dialog', { name: '베팅하기' });
|
const dialog = page.getByRole('dialog', { name: '베팅하기' });
|
||||||
await expect(dialog).toBeVisible();
|
await expect(dialog).toBeVisible();
|
||||||
|
const dialogGeometry = await dialog.evaluate((element) => ({
|
||||||
|
dialog: element.getBoundingClientRect().toJSON(),
|
||||||
|
viewportWidth: window.innerWidth,
|
||||||
|
viewportHeight: window.innerHeight,
|
||||||
|
documentScrollWidth: document.documentElement.scrollWidth,
|
||||||
|
position: getComputedStyle(element).position,
|
||||||
|
}));
|
||||||
|
expect(
|
||||||
|
Math.abs(dialogGeometry.dialog.left + dialogGeometry.dialog.width / 2 - dialogGeometry.viewportWidth / 2)
|
||||||
|
).toBeLessThanOrEqual(1);
|
||||||
|
expect(
|
||||||
|
Math.abs(dialogGeometry.dialog.top + dialogGeometry.dialog.height / 2 - dialogGeometry.viewportHeight / 2)
|
||||||
|
).toBeLessThanOrEqual(1);
|
||||||
|
expect(dialogGeometry.dialog.left).toBeGreaterThanOrEqual(0);
|
||||||
|
expect(dialogGeometry.dialog.right).toBeLessThanOrEqual(dialogGeometry.viewportWidth);
|
||||||
|
expect(dialogGeometry.dialog.top).toBeGreaterThanOrEqual(0);
|
||||||
|
expect(dialogGeometry.dialog.bottom).toBeLessThanOrEqual(dialogGeometry.viewportHeight);
|
||||||
|
expect(dialogGeometry.documentScrollWidth).toBeLessThanOrEqual(dialogGeometry.viewportWidth);
|
||||||
|
expect(dialogGeometry.position).toBe('fixed');
|
||||||
|
await writeFile(testInfo.outputPath('mobile-betting-dialog.json'), `${JSON.stringify(dialogGeometry, null, 2)}\n`);
|
||||||
|
await dialog.screenshot({ path: testInfo.outputPath('mobile-betting-dialog.png') });
|
||||||
|
await page.screenshot({ path: testInfo.outputPath('mobile-betting-dialog-viewport.png') });
|
||||||
await expect(dialog.getByText('배당 28.00')).toBeVisible();
|
await expect(dialog.getByText('배당 28.00')).toBeVisible();
|
||||||
await expect(dialog.getByText('예상 환수금 280')).toBeVisible();
|
await expect(dialog.getByText('예상 환수금 280')).toBeVisible();
|
||||||
await dialog.getByLabel('베팅 금액').selectOption('50');
|
await dialog.getByLabel('베팅 금액').selectOption('50');
|
||||||
@@ -1043,6 +1065,28 @@ test('desktop betting presents icon-and-name cards and all four rankings without
|
|||||||
expect(firstCardCorner.rightOffset).toBeGreaterThanOrEqual(2);
|
expect(firstCardCorner.rightOffset).toBeGreaterThanOrEqual(2);
|
||||||
expect(firstCardCorner.rightOffset).toBeLessThanOrEqual(4);
|
expect(firstCardCorner.rightOffset).toBeLessThanOrEqual(4);
|
||||||
expect(firstCardCorner.contained).toBe(true);
|
expect(firstCardCorner.contained).toBe(true);
|
||||||
|
const firstBetButton = page.getByRole('button', { name: '관우에게 베팅하기' });
|
||||||
|
await firstBetButton.click();
|
||||||
|
const dialog = page.getByRole('dialog', { name: '베팅하기' });
|
||||||
|
await expect(dialog).toBeVisible();
|
||||||
|
const dialogGeometry = await dialog.evaluate((element) => ({
|
||||||
|
dialog: element.getBoundingClientRect().toJSON(),
|
||||||
|
viewportWidth: window.innerWidth,
|
||||||
|
viewportHeight: window.innerHeight,
|
||||||
|
position: getComputedStyle(element).position,
|
||||||
|
}));
|
||||||
|
expect(
|
||||||
|
Math.abs(dialogGeometry.dialog.left + dialogGeometry.dialog.width / 2 - dialogGeometry.viewportWidth / 2)
|
||||||
|
).toBeLessThanOrEqual(1);
|
||||||
|
expect(
|
||||||
|
Math.abs(dialogGeometry.dialog.top + dialogGeometry.dialog.height / 2 - dialogGeometry.viewportHeight / 2)
|
||||||
|
).toBeLessThanOrEqual(1);
|
||||||
|
expect(dialogGeometry.position).toBe('fixed');
|
||||||
|
await writeFile(testInfo.outputPath('desktop-betting-dialog.json'), `${JSON.stringify(dialogGeometry, null, 2)}\n`);
|
||||||
|
await dialog.screenshot({ path: testInfo.outputPath('desktop-betting-dialog.png') });
|
||||||
|
await page.screenshot({ path: testInfo.outputPath('desktop-betting-dialog-viewport.png') });
|
||||||
|
await dialog.getByRole('button', { name: '취소' }).click();
|
||||||
|
await expect(dialog).toBeHidden();
|
||||||
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(1365);
|
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(1365);
|
||||||
await persistScreenshot(page, 'tournament-ranking-desktop', testInfo.outputPath('tournament-ranking-desktop.webp'));
|
await persistScreenshot(page, 'tournament-ranking-desktop', testInfo.outputPath('tournament-ranking-desktop.webp'));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -64,6 +64,17 @@ textarea {
|
|||||||
font: inherit;
|
font: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tailwind's reset removes the native dialog's auto margins. Dialogs that are
|
||||||
|
* meant to float over the current screen opt back into explicit viewport
|
||||||
|
* centring instead of inheriting the document's 500px legacy canvas.
|
||||||
|
*/
|
||||||
|
.viewport-centered-dialog {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Firefox for Android may zoom to a focused search field. `manipulation`
|
* Firefox for Android may zoom to a focused search field. `manipulation`
|
||||||
* suppresses that focus-only zoom while retaining ordinary pan and pinch zoom.
|
* suppresses that focus-only zoom while retaining ordinary pan and pinch zoom.
|
||||||
|
|||||||
@@ -150,7 +150,12 @@ const placeBet = async () => {
|
|||||||
@request-bet="openBetDialog"
|
@request-bet="openBetDialog"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<dialog ref="betDialog" class="bet-dialog" aria-labelledby="bet-dialog-title" @close="selectedTarget = null">
|
<dialog
|
||||||
|
ref="betDialog"
|
||||||
|
class="bet-dialog viewport-centered-dialog"
|
||||||
|
aria-labelledby="bet-dialog-title"
|
||||||
|
@close="selectedTarget = null"
|
||||||
|
>
|
||||||
<form v-if="selectedTarget" class="bet-dialog-content" @submit.prevent="placeBet">
|
<form v-if="selectedTarget" class="bet-dialog-content" @submit.prevent="placeBet">
|
||||||
<header>
|
<header>
|
||||||
<h2 id="bet-dialog-title">베팅하기</h2>
|
<h2 id="bet-dialog-title">베팅하기</h2>
|
||||||
|
|||||||
@@ -585,7 +585,11 @@ watch(
|
|||||||
@quick="moveQuick"
|
@quick="moveQuick"
|
||||||
@action="handleNavigationAction"
|
@action="handleNavigationAction"
|
||||||
/>
|
/>
|
||||||
<dialog ref="versionDialog" class="game-version-dialog" aria-labelledby="game-version-title">
|
<dialog
|
||||||
|
ref="versionDialog"
|
||||||
|
class="game-version-dialog viewport-centered-dialog"
|
||||||
|
aria-labelledby="game-version-title"
|
||||||
|
>
|
||||||
<h2 id="game-version-title">게임 정보</h2>
|
<h2 id="game-version-title">게임 정보</h2>
|
||||||
<p>{{ lobbyInfo?.scenarioTitle || 'Core2026' }}</p>
|
<p>{{ lobbyInfo?.scenarioTitle || 'Core2026' }}</p>
|
||||||
<p>삼국지 모의전투 Core2026</p>
|
<p>삼국지 모의전투 Core2026</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user