메인 연결 페이지의 탭 종료와 복귀 동작 통일
This commit is contained in:
@@ -209,6 +209,22 @@ const installApi = async (page: Page, state: BoardFixture) => {
|
||||
});
|
||||
return response({ id: 22 });
|
||||
}
|
||||
if (operation === 'dashboard.getContextBundleDelta') {
|
||||
const snapshot = (data: unknown, revision: string) => ({
|
||||
kind: 'snapshot',
|
||||
revision,
|
||||
sourceRevision: revision,
|
||||
data,
|
||||
});
|
||||
return response({
|
||||
context: snapshot(generalContext, 'board-context'),
|
||||
commandTable: snapshot({ general: [], nation: [] }, 'board-commands'),
|
||||
boardAccess: snapshot(
|
||||
{ permission: state.permission, canMeeting: state.canMeeting, canSecret: state.canSecret },
|
||||
'board-access'
|
||||
),
|
||||
});
|
||||
}
|
||||
if (operation === 'general.me') return response(generalContext);
|
||||
if (operation === 'world.getMapLayout') {
|
||||
return response({ mapName: 'che', cityList: [], regionMap: {}, levelMap: {} });
|
||||
@@ -498,7 +514,8 @@ test('denies direct secret-room rendering and disables its in-game menu for an o
|
||||
expect(state.requests).not.toContain('board.getArticles');
|
||||
|
||||
state.requests.length = 0;
|
||||
await page.goto('');
|
||||
await page.getByRole('button', { name: '돌아가기', exact: true }).click();
|
||||
await expect(page).toHaveURL(new URL(gamePath('/'), page.url()).href);
|
||||
const nationMenu = page.locator('.main-nation-menu').first();
|
||||
await expect(nationMenu.locator('[data-navigation-id="meeting"]')).toHaveAttribute('href', gamePath('/board'));
|
||||
await expect(nationMenu.locator('[data-navigation-id="secret-board"]')).toHaveAttribute('aria-disabled', 'true');
|
||||
|
||||
@@ -807,7 +807,7 @@ test('nation directory reuses only the public general-directory row on hover and
|
||||
expect(await foreignTrigger.getAttribute('aria-expanded')).toBe('true');
|
||||
expect(await foreignTrigger.evaluate((element) => getComputedStyle(element).outlineStyle)).toBe('dashed');
|
||||
|
||||
await page.getByRole('button', { name: '창 닫기' }).first().focus();
|
||||
await page.getByRole('button', { name: '돌아가기' }).first().focus();
|
||||
await expect(preview).toHaveCount(0);
|
||||
|
||||
if (artifactRoot) {
|
||||
|
||||
@@ -273,6 +273,8 @@ test('왕조 일람과 상세는 현재 profile의 이전 서버 기록만 조
|
||||
expect(state.dynastyRequests.some((request) => request.includes('legacy'))).toBe(true);
|
||||
expect(state.dynastyRequests.every((request) => !request.includes('sourceProfile'))).toBe(true);
|
||||
await page.screenshot({ path: testInfo.outputPath('dynasty-detail-profile-scope-desktop.png'), fullPage: true });
|
||||
await page.getByRole('button', { name: '돌아가기', exact: true }).last().click();
|
||||
await expect(page).toHaveURL(new URL('./', testInfo.project.use.baseURL as string).href);
|
||||
});
|
||||
|
||||
test('연감 국가 라벨은 밝은 배경에 검정, 어두운 배경에 흰 글자를 사용한다', async ({ page }, testInfo) => {
|
||||
|
||||
@@ -6,6 +6,9 @@ import { buildEquipmentTradeItemOptions, loadEquipmentTradeItemOrder } from '../
|
||||
import { loadScenarioDefinitionById } from '@sammo-ts/game-engine/scenario/scenarioLoader.js';
|
||||
import { ITEM_KEYS, loadItemModules } from '@sammo-ts/logic/items/index.js';
|
||||
|
||||
// 브라우저 보조키로 생성한 탭까지 검증하므로 경량 headless shell 대신 전체 Chromium을 사용한다.
|
||||
test.use({ channel: 'chromium' });
|
||||
|
||||
const response = (data: unknown) => ({ result: { data } });
|
||||
const runtimeNavigation = JSON.parse(
|
||||
await readFile(new URL('../../../resources/navigation.json', import.meta.url), 'utf8')
|
||||
@@ -29,6 +32,7 @@ const operationNames = (route: Route) =>
|
||||
decodeURIComponent(new URL(route.request().url()).pathname.split('/trpc/')[1] ?? '').split(',');
|
||||
|
||||
type NavigationFixture = {
|
||||
pageExitAudit?: boolean;
|
||||
decoratedNpcChiefs?: boolean;
|
||||
officerLevel: number;
|
||||
permission: number;
|
||||
@@ -567,6 +571,7 @@ const generalContext = (state: NavigationFixture) => ({
|
||||
const installFixture = async (page: Page | BrowserContext, state: NavigationFixture) => {
|
||||
await page.addInitScript(
|
||||
({ profile }) => {
|
||||
if (!window.location.protocol.startsWith('http')) return;
|
||||
localStorage.setItem('sammo-game-token', 'ga_navigation');
|
||||
localStorage.setItem('sammo-game-profile', profile);
|
||||
},
|
||||
@@ -838,6 +843,12 @@ const installFixture = async (page: Page | BrowserContext, state: NavigationFixt
|
||||
winnerId: state.tournamentWinnerId,
|
||||
});
|
||||
}
|
||||
if (state.pageExitAudit) return errorResponse(operation, 'Navigation audit fixture: data unavailable');
|
||||
if (operation === 'tournament.getRankings') return response([]);
|
||||
if (operation === 'tournament.getSnapshot') return response({ state: null, participants: [], matches: [] });
|
||||
if (operation === 'tournament.getBettingSummary')
|
||||
return response({ totals: {}, myTotals: {}, totalAmount: 0, myAmount: 0 });
|
||||
if (operation === 'tournament.getAdminStatus') return response({ ok: false });
|
||||
return response({ ok: true });
|
||||
});
|
||||
operations.forEach((operation, index) => {
|
||||
@@ -6881,3 +6892,246 @@ test('NPC prefixes stay single in the main nation card', async ({ page }, testIn
|
||||
await card.screenshot({ path: testInfo.outputPath(`npc-main-prefix-${width}.png`) });
|
||||
}
|
||||
});
|
||||
|
||||
test.describe('page exit navigation', () => {
|
||||
for (const width of [1000, 500]) {
|
||||
test(`page exit policy distinguishes ordinary, modifier, copied and same-tab links at ${width}`, async ({
|
||||
page,
|
||||
context,
|
||||
}, testInfo) => {
|
||||
await page.setViewportSize({ width, height: 900 });
|
||||
await installFixture(context, {
|
||||
officerLevel: 12,
|
||||
permission: 4,
|
||||
nationLevel: 1,
|
||||
stage: 0,
|
||||
npcMode: 1,
|
||||
generalMeCalls: 0,
|
||||
operations: [],
|
||||
});
|
||||
await waitForMain(page);
|
||||
const mainUrl = page.url();
|
||||
const survey = page.locator('[data-menu-position="top"] [data-navigation-id="survey"]');
|
||||
const href = await survey.getAttribute('href');
|
||||
for (const method of ['control', 'middle', 'copy'] as const) {
|
||||
const created = context.waitForEvent('page');
|
||||
if (method === 'copy') {
|
||||
const copied = await context.newPage();
|
||||
await copied.goto(href!);
|
||||
} else {
|
||||
await survey.click(method === 'control' ? { modifiers: ['Control'] } : { button: 'middle' });
|
||||
}
|
||||
const tab = await created;
|
||||
await tab.bringToFront();
|
||||
await tab.waitForLoadState('domcontentloaded');
|
||||
await expect(tab).toHaveURL(`${basePath}/survey`);
|
||||
await expect(tab.locator('.back_bar .back_btn')).toHaveText('돌아가기');
|
||||
await tab.reload();
|
||||
await expect(tab.locator('.bottom_bar .back_btn')).toHaveText('돌아가기');
|
||||
expect(context.pages()).toHaveLength(2);
|
||||
await tab.locator('.bottom_bar .back_btn').click();
|
||||
await expect(tab).toHaveURL(mainUrl);
|
||||
expect(context.pages()).toHaveLength(2);
|
||||
await tab.close();
|
||||
}
|
||||
// The status title intentionally uses the current tab, unlike its menu entry.
|
||||
await page.locator('.tournament-status a').click();
|
||||
await expect(page).toHaveURL(`${basePath}/tournament`);
|
||||
expect(context.pages()).toHaveLength(1);
|
||||
await expect(page.getByRole('button', { name: '돌아가기', exact: true }).first()).toBeVisible();
|
||||
await page.screenshot({ path: testInfo.outputPath(`same-tab-${width}.png`), fullPage: true });
|
||||
await page.getByRole('button', { name: '돌아가기', exact: true }).last().click();
|
||||
await expect(page).toHaveURL(mainUrl);
|
||||
expect(context.pages()).toHaveLength(1);
|
||||
|
||||
// Retain the auxiliary identity through SPA navigation and a reload.
|
||||
const opened = page.waitForEvent('popup');
|
||||
await page.locator('[data-navigation-id="tournament"]').click();
|
||||
const tab = await opened;
|
||||
await expect(tab.getByRole('button', { name: '창 닫기', exact: true }).first()).toBeVisible();
|
||||
await tab.getByRole('tab', { name: '베팅장', exact: true }).click();
|
||||
await expect(tab).toHaveURL(`${basePath}/betting`);
|
||||
await tab.reload();
|
||||
await expect(tab.getByRole('button', { name: '창 닫기', exact: true }).last()).toBeVisible();
|
||||
const closed = tab.waitForEvent('close');
|
||||
await tab
|
||||
.getByRole('button', { name: '창 닫기', exact: true })
|
||||
.last()
|
||||
.click()
|
||||
.catch((error: unknown) => {
|
||||
if (!tab.isClosed()) throw error;
|
||||
});
|
||||
await closed;
|
||||
expect(context.pages()).toHaveLength(1);
|
||||
expect(page.url()).toBe(mainUrl);
|
||||
});
|
||||
}
|
||||
|
||||
const exitAuditEntries = [
|
||||
'nation-betting',
|
||||
'nation-list',
|
||||
'general-list',
|
||||
'best-general',
|
||||
'yearbook',
|
||||
'battle-simulator',
|
||||
'hall-of-fame',
|
||||
'dynasty',
|
||||
'traffic',
|
||||
'npc-list',
|
||||
'survey',
|
||||
'meeting',
|
||||
'secret-board',
|
||||
'troop',
|
||||
'diplomacy',
|
||||
'personnel',
|
||||
'finance',
|
||||
'chief-center',
|
||||
'npc-control',
|
||||
'nation-secret',
|
||||
'tournament',
|
||||
'tournament-menu',
|
||||
'betting',
|
||||
'nation-info',
|
||||
'nation-cities',
|
||||
'nation-generals',
|
||||
'global-info',
|
||||
'current-city',
|
||||
'battle-center',
|
||||
'inherit',
|
||||
'my-page',
|
||||
'auction-resource',
|
||||
'auction-resource-menu',
|
||||
'auction-unique',
|
||||
'my-settings',
|
||||
];
|
||||
for (const width of [1000, 500]) {
|
||||
test(`all main page exits obey tab policy even when page data fails at ${width}`, async ({
|
||||
page,
|
||||
context,
|
||||
}, testInfo) => {
|
||||
test.setTimeout(180_000);
|
||||
await page.setViewportSize({ width, height: 900 });
|
||||
await installFixture(context, {
|
||||
pageExitAudit: true,
|
||||
officerLevel: 12,
|
||||
permission: 4,
|
||||
nationLevel: 1,
|
||||
stage: 0,
|
||||
npcMode: 1,
|
||||
generalMeCalls: 0,
|
||||
operations: [],
|
||||
});
|
||||
await waitForMain(page);
|
||||
const mainUrl = page.url();
|
||||
const evidence: unknown[] = [];
|
||||
for (const id of exitAuditEntries) {
|
||||
let link = page.locator(`[data-navigation-id="${id}"]`).first();
|
||||
if (!(await link.isVisible())) {
|
||||
const group = ['tournament-menu', 'betting'].includes(id)
|
||||
? 'tournament-betting'
|
||||
: ['auction-resource-menu', 'auction-unique'].includes(id)
|
||||
? 'auction'
|
||||
: 'game-info';
|
||||
await page.locator(`[data-menu-id="${group}"]`).first().click();
|
||||
}
|
||||
link = page.locator(`[data-navigation-id="${id}"]`).first();
|
||||
const href = await link.getAttribute('href');
|
||||
const newTab = (await link.getAttribute('target')) === '_blank';
|
||||
const opened = newTab ? page.waitForEvent('popup') : null;
|
||||
await link.click();
|
||||
const target = opened ? await opened : page;
|
||||
await target.setViewportSize({ width, height: 900 });
|
||||
await target.waitForURL(new URL(href!, mainUrl).href);
|
||||
const exit = target.getByRole('button', { name: newTab ? '창 닫기' : '돌아가기', exact: true }).first();
|
||||
await expect(exit, id).toBeVisible();
|
||||
expect(context.pages(), id).toHaveLength(newTab ? 2 : 1);
|
||||
await target.evaluate(() => document.fonts.ready);
|
||||
await exit.focus();
|
||||
await exit.hover();
|
||||
evidence.push({
|
||||
id,
|
||||
href,
|
||||
newTab,
|
||||
width,
|
||||
...(await exit.evaluate((el) => ({
|
||||
viewportWidth: window.innerWidth,
|
||||
rect: el.getBoundingClientRect().toJSON(),
|
||||
font: getComputedStyle(el).font,
|
||||
border: getComputedStyle(el).border,
|
||||
text: el.textContent,
|
||||
}))),
|
||||
});
|
||||
await target.screenshot({ path: testInfo.outputPath(`${id}-${width}.png`), fullPage: true });
|
||||
await writeFile(
|
||||
testInfo.outputPath(`${id}-${width}.html`),
|
||||
await target.locator('#app').evaluate((el) => el.outerHTML)
|
||||
);
|
||||
if (newTab) {
|
||||
const closed = target.waitForEvent('close');
|
||||
await exit.click().catch((error: unknown) => {
|
||||
if (!target.isClosed()) throw error;
|
||||
});
|
||||
await closed;
|
||||
// Opening the original href from the browser does not inherit auxiliary identity.
|
||||
const direct = await context.newPage();
|
||||
await direct.setViewportSize({ width, height: 900 });
|
||||
await direct.goto(href!);
|
||||
const back = direct.getByRole('button', { name: '돌아가기', exact: true }).first();
|
||||
await expect(back, id).toBeVisible();
|
||||
await back.click();
|
||||
await expect(direct).toHaveURL(mainUrl);
|
||||
expect(context.pages()).toHaveLength(2);
|
||||
await direct.close();
|
||||
} else {
|
||||
await exit.click();
|
||||
await expect(page).toHaveURL(mainUrl);
|
||||
}
|
||||
expect(context.pages(), id).toHaveLength(1);
|
||||
expect(page.url(), id).toBe(mainUrl);
|
||||
}
|
||||
await writeFile(testInfo.outputPath(`exit-audit-${width}.json`), JSON.stringify(evidence, null, 2));
|
||||
});
|
||||
}
|
||||
|
||||
test('keyboard activation opens a closable tab and blocked popups use the current tab', async ({
|
||||
page,
|
||||
context,
|
||||
}) => {
|
||||
await installFixture(context, {
|
||||
officerLevel: 0,
|
||||
permission: 0,
|
||||
nationLevel: 0,
|
||||
stage: 0,
|
||||
npcMode: 1,
|
||||
generalMeCalls: 0,
|
||||
operations: [],
|
||||
});
|
||||
await waitForMain(page);
|
||||
const mainUrl = page.url();
|
||||
const link = page.locator('[data-menu-position="top"] [data-navigation-id="survey"]');
|
||||
await link.focus();
|
||||
const opened = page.waitForEvent('popup');
|
||||
await link.press('Enter');
|
||||
const tab = await opened;
|
||||
await expect(tab.getByRole('button', { name: '창 닫기', exact: true }).first()).toBeVisible();
|
||||
expect(await tab.evaluate(() => document.referrer)).toBe('');
|
||||
const closed = tab.waitForEvent('close');
|
||||
await tab
|
||||
.getByRole('button', { name: '창 닫기', exact: true })
|
||||
.first()
|
||||
.click()
|
||||
.catch((error: unknown) => {
|
||||
if (!tab.isClosed()) throw error;
|
||||
});
|
||||
await closed;
|
||||
expect(context.pages()).toHaveLength(1);
|
||||
await page.evaluate(() => {
|
||||
window.open = () => null;
|
||||
});
|
||||
await link.click();
|
||||
await expect(page).toHaveURL(`${basePath}/survey`);
|
||||
await page.getByRole('button', { name: '돌아가기', exact: true }).first().click();
|
||||
await expect(page).toHaveURL(mainUrl);
|
||||
expect(context.pages()).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -536,7 +536,7 @@ test('join refresh shows the assigned preliminary group immediately with accessi
|
||||
|
||||
const refresh = page.getByRole('button', { name: '갱신' });
|
||||
const join = page.getByRole('button', { name: '참가' });
|
||||
const close = page.getByRole('button', { name: '창 닫기' }).first();
|
||||
const close = page.getByRole('button', { name: '돌아가기' }).first();
|
||||
await expect(join).toBeEnabled();
|
||||
await expect(page.getByText('조별 예선 순위')).toBeVisible();
|
||||
await expect(page.getByText('조별 본선 순위')).toHaveCount(0);
|
||||
@@ -797,7 +797,7 @@ test('tournament and betting pages expose same-row navigation tabs beside close'
|
||||
const navigation = page.getByRole('tablist', { name: '토너먼트와 베팅장 이동' });
|
||||
const tournamentTab = navigation.getByRole('tab', { name: '토너먼트' });
|
||||
const bettingTab = navigation.getByRole('tab', { name: '베팅장' });
|
||||
const close = page.getByRole('button', { name: '창 닫기' }).first();
|
||||
const close = page.getByRole('button', { name: '돌아가기' }).first();
|
||||
await expect(tournamentTab).toHaveAttribute('aria-selected', 'true');
|
||||
|
||||
const headerCenters = await Promise.all(
|
||||
@@ -945,29 +945,7 @@ test('betting realtime refresh is shared across tabs and preserves local interac
|
||||
await expect(follower.locator('.mobile-bracket').getByLabel('관우 베팅 금액', { exact: true })).toHaveValue('50');
|
||||
});
|
||||
|
||||
test('tournament and betting close only their script-opened popup window', async ({ page }, testInfo) => {
|
||||
const baseURL = testInfo.project.use.baseURL;
|
||||
expect(typeof baseURL).toBe('string');
|
||||
await page.goto('about:blank');
|
||||
|
||||
for (const route of ['tournament', 'betting'] as const) {
|
||||
const popupPromise = page.waitForEvent('popup');
|
||||
await page.evaluate(() => window.open('about:blank', '_blank', 'noopener'));
|
||||
const popup = await popupPromise;
|
||||
await installFixture(popup, { tournamentStage: route === 'betting' ? 6 : 1 });
|
||||
await popup.goto(new URL(route, baseURL as string).href);
|
||||
|
||||
await expect(popup.getByRole('button', { name: '창 닫기' }).first()).toBeVisible();
|
||||
expect(await popup.evaluate(() => window.opener)).toBeNull();
|
||||
|
||||
const closed = popup.waitForEvent('close');
|
||||
await popup.getByRole('button', { name: '창 닫기' }).first().click();
|
||||
await closed;
|
||||
|
||||
expect(page.isClosed()).toBe(false);
|
||||
expect(page.url()).toBe('about:blank');
|
||||
}
|
||||
});
|
||||
// Actual main-link popup closure and tab counts are covered in mainNavigation.spec.ts.
|
||||
|
||||
test('betting bracket shows intelligence for debate tournament candidates', async ({ page }) => {
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../../composables/usePageExit';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
defineProps<{
|
||||
activePage: 'tournament' | 'betting';
|
||||
title: string;
|
||||
}>();
|
||||
|
||||
const closeWindow = (): void => window.close();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -40,9 +42,9 @@ const closeWindow = (): void => window.close();
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height close-button"
|
||||
type="button"
|
||||
@click="closeWindow"
|
||||
@click="exitPage"
|
||||
>
|
||||
창 닫기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { useRouter } from 'vue-router';
|
||||
import { isAuxiliaryWindow } from '../utils/auxiliaryNavigation';
|
||||
|
||||
export const usePageExit = (): { pageExitLabel: '창 닫기' | '돌아가기'; exitPage: () => void } => {
|
||||
const router = useRouter();
|
||||
const canClose = isAuxiliaryWindow();
|
||||
const pageExitLabel = canClose ? '창 닫기' : '돌아가기';
|
||||
const exitPage = (): void => {
|
||||
if (canClose) {
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
void router.push('/');
|
||||
};
|
||||
return { pageExitLabel, exitPage };
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
import { installAuxiliaryNavigation } from './utils/auxiliaryNavigation';
|
||||
import { createApp } from 'vue';
|
||||
import { createPinia } from 'pinia';
|
||||
import App from './App.vue';
|
||||
@@ -7,6 +8,7 @@ import { applyStoredCustomCss } from './utils/customCss';
|
||||
import { installImageAssetCssVariables } from './utils/imageAssets';
|
||||
import { installScreenModeViewport } from './utils/screenModeViewport';
|
||||
|
||||
installAuxiliaryNavigation();
|
||||
installImageAssetCssVariables();
|
||||
installScreenModeViewport();
|
||||
applyStoredCustomCss();
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { gameFrontendRuntimeConfig } from '../config/runtimeConfig';
|
||||
|
||||
// 이름은 앱이 직접 연 탭에만 부여한다. URL/sessionStorage 표식은 링크 복사나
|
||||
// 브라우저의 새 탭 열기에도 전달될 수 있으므로 닫기 권한 판정에 사용하지 않는다.
|
||||
const auxiliaryWindowPrefix = 'sammo-auxiliary:';
|
||||
|
||||
export const isAuxiliaryWindow = (): boolean => window.name.startsWith(auxiliaryWindowPrefix);
|
||||
|
||||
export const installAuxiliaryNavigation = (): void => {
|
||||
document.addEventListener(
|
||||
'click',
|
||||
(event: MouseEvent) => {
|
||||
if (
|
||||
event.defaultPrevented ||
|
||||
event.button !== 0 ||
|
||||
event.ctrlKey ||
|
||||
event.metaKey ||
|
||||
event.shiftKey ||
|
||||
event.altKey
|
||||
)
|
||||
return;
|
||||
const link = event.target instanceof Element ? event.target.closest('a') : null;
|
||||
if (!link || link.target !== '_blank' || link.hasAttribute('download')) return;
|
||||
const url = new URL(link.href, window.location.href);
|
||||
const basePath = gameFrontendRuntimeConfig.appBasePath;
|
||||
if (url.origin !== window.location.origin || !url.pathname.startsWith(basePath)) return;
|
||||
|
||||
event.preventDefault();
|
||||
const child = window.open('about:blank', '_blank');
|
||||
if (!child) {
|
||||
// 팝업 차단 시 현재 탭에서 열어 돌아가기 동작을 제공한다.
|
||||
window.location.assign(url.href);
|
||||
return;
|
||||
}
|
||||
child.name = `${auxiliaryWindowPrefix}${crypto.randomUUID()}`;
|
||||
child.opener = null;
|
||||
// 새 문서 소유의 링크로 이동해야 원본 링크의 referrer 정책도 적용된다.
|
||||
const destination = child.document.createElement('a');
|
||||
destination.href = url.href;
|
||||
destination.rel = link.rel;
|
||||
destination.referrerPolicy = link.referrerPolicy;
|
||||
child.document.body.append(destination);
|
||||
destination.click();
|
||||
},
|
||||
true
|
||||
);
|
||||
};
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { useClockDisplay } from '../composables/useClockDisplay';
|
||||
const { formatTime: formatGameTime } = useClockDisplay();
|
||||
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||
@@ -9,6 +11,8 @@ import { formatLog } from '../utils/formatLog';
|
||||
import { trpc } from '../utils/trpc';
|
||||
import { useGameFeedback } from '../composables/useGameFeedback';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type AuctionOverview = Awaited<ReturnType<typeof trpc.auction.getOverview.query>>;
|
||||
type ResourceAuction = AuctionOverview['resourceAuctions'][number];
|
||||
type UniqueAuction = AuctionOverview['uniqueAuctions'][number];
|
||||
@@ -177,8 +181,6 @@ const bidUniqueAuction = (): Promise<void> =>
|
||||
showSuccessToast('입찰이 완료되었습니다.');
|
||||
});
|
||||
|
||||
const closeWindow = (): void => window.close();
|
||||
|
||||
watch(activeTab, (tab) => {
|
||||
error.value = null;
|
||||
if (tab === 'unique' && !selectedUnique.value && ongoingUnique.value[0]) {
|
||||
@@ -201,9 +203,9 @@ onMounted(() => {
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height close-button"
|
||||
type="button"
|
||||
@click="closeWindow"
|
||||
@click="exitPage"
|
||||
>
|
||||
창 닫기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height reload-button"
|
||||
@@ -499,9 +501,9 @@ onMounted(() => {
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height close-button"
|
||||
type="button"
|
||||
@click="closeWindow"
|
||||
@click="exitPage"
|
||||
>
|
||||
창 닫기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { useClockDisplay } from '../composables/useClockDisplay';
|
||||
const { formatTime: formatGameTime } = useClockDisplay();
|
||||
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||
@@ -16,6 +18,8 @@ import { trpc } from '../utils/trpc';
|
||||
import { getNpcColor } from '../utils/npcColor';
|
||||
import { formatLog } from '../utils/formatLog';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type BattleCenterResponse = Awaited<ReturnType<typeof trpc.nation.getBattleCenter.query>>;
|
||||
type GeneralEntry = BattleCenterResponse['generals'][number];
|
||||
|
||||
@@ -237,15 +241,13 @@ onMounted(() => {
|
||||
<template>
|
||||
<main class="ref-shell battle-page">
|
||||
<header class="battle-top legacy-bg0">
|
||||
<RouterLink v-slot="{ navigate }" custom to="/">
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height battle-nav"
|
||||
type="button"
|
||||
@click="navigate"
|
||||
>
|
||||
창 닫기
|
||||
</button>
|
||||
</RouterLink>
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height battle-nav"
|
||||
type="button"
|
||||
@click="exitPage"
|
||||
>
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height battle-nav"
|
||||
@click="loadBattleCenter"
|
||||
@@ -318,15 +320,13 @@ onMounted(() => {
|
||||
</div>
|
||||
</section>
|
||||
<footer class="battle-footer legacy-bg0">
|
||||
<RouterLink v-slot="{ navigate }" custom to="/">
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height battle-nav"
|
||||
type="button"
|
||||
@click="navigate"
|
||||
>
|
||||
창 닫기
|
||||
</button>
|
||||
</RouterLink>
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height battle-nav"
|
||||
type="button"
|
||||
@click="exitPage"
|
||||
>
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</footer>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
import { computed, onBeforeUnmount, onMounted, reactive, ref, shallowRef } from 'vue';
|
||||
import type { BattleSimRequestPayload, BattleSimResultPayload } from '@sammo-ts/game-api';
|
||||
import PanelCard from '../components/ui/PanelCard.vue';
|
||||
@@ -12,6 +13,8 @@ import type { BattleSimOptions, GeneralDraft, InheritBuff } from '../utils/battl
|
||||
import { BattleSimulatorWorkerClient } from '../utils/battleSimulatorWorkerClient';
|
||||
import { formatSeoulDateTime } from '../utils/legacyDateTime';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type GeneralExport = Omit<GeneralDraft, 'id'>;
|
||||
|
||||
type BattleExport = {
|
||||
@@ -1015,6 +1018,9 @@ const shouldShowUI = computed(() => !loading.value && !!options.value);
|
||||
|
||||
<template>
|
||||
<main class="battle-simulator">
|
||||
<button class="legacy-button legacy-button--navigation" type="button" @click="exitPage">
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<!-- Ref renders several equivalent controls as input/button tags. Keep
|
||||
that DOM signature without duplicating the visible Vue controls. -->
|
||||
<div class="legacy-control-signature" hidden>
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import RichTooltip from '../components/ui/RichTooltip.vue';
|
||||
import { resolveGeneralIconUrl, useDefaultGeneralIcon } from '../utils/generalIcon';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type RankEntry = {
|
||||
id: number;
|
||||
name: string;
|
||||
@@ -43,7 +46,6 @@ type BestGeneralPayload = {
|
||||
uniqueItems: UniqueItemSection[];
|
||||
};
|
||||
|
||||
const router = useRouter();
|
||||
const viewMode = ref<'user' | 'npc'>('user');
|
||||
const loading = ref(false);
|
||||
const errorMessage = ref('');
|
||||
@@ -51,14 +53,6 @@ const data = ref<BestGeneralPayload | null>(null);
|
||||
|
||||
const imageUrl = (entry: { picture: string | null; imageServer: number }): string => resolveGeneralIconUrl(entry);
|
||||
|
||||
const closePage = async (): Promise<void> => {
|
||||
if (window.opener) {
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
await router.push('/');
|
||||
};
|
||||
|
||||
const refresh = async (): Promise<void> => {
|
||||
loading.value = true;
|
||||
errorMessage.value = '';
|
||||
@@ -84,7 +78,7 @@ watch(viewMode, () => {
|
||||
<main id="best-general-container" class="legacy-ranking-page legacy-bg0">
|
||||
<div class="legacy-ranking-title">
|
||||
명 장 일 람<br />
|
||||
<button class="legacy-button" type="button" @click="closePage">창 닫기</button>
|
||||
<button class="legacy-button" type="button" @click="exitPage">{{ pageExitLabel }}</button>
|
||||
</div>
|
||||
|
||||
<div class="view-selector" role="group" aria-label="장수 유형">
|
||||
@@ -175,7 +169,7 @@ watch(viewMode, () => {
|
||||
</section>
|
||||
|
||||
<div class="legacy-ranking-bottom">
|
||||
<button class="legacy-button" type="button" @click="closePage">창 닫기</button>
|
||||
<button class="legacy-button" type="button" @click="exitPage">{{ pageExitLabel }}</button>
|
||||
</div>
|
||||
<footer class="legacy-banner">
|
||||
삼국지 모의전투 HiDCHe / KOEI의 이미지를 사용, 응용하였습니다 / 제작 : HideD /
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { useClockDisplay } from '../composables/useClockDisplay';
|
||||
const { formatTime: formatGameTime } = useClockDisplay();
|
||||
import { storeToRefs } from 'pinia';
|
||||
@@ -10,6 +12,8 @@ import { useTournamentPagesStore } from '../stores/tournamentPages';
|
||||
import type { TournamentBracketSlot } from '../utils/tournamentBracket';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
const tournamentPages = useTournamentPagesStore();
|
||||
const { snapshot, betting: summary, rankings, loading, error } = storeToRefs(tournamentPages);
|
||||
const amounts = ref<Record<number, number | string>>({});
|
||||
@@ -266,11 +270,9 @@ const placeBet = async (target: TournamentBracketSlot) => {
|
||||
ㆍ소지금 500원 이하일땐 베팅이 불가능합니다.
|
||||
</section>
|
||||
<footer class="betting-footer bg0">
|
||||
<RouterLink v-slot="{ navigate }" custom to="/">
|
||||
<button class="legacy-button legacy-button--navigation close-button" type="button" @click="navigate">
|
||||
창 닫기
|
||||
</button>
|
||||
</RouterLink>
|
||||
<button class="legacy-button legacy-button--navigation close-button" type="button" @click="exitPage">
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<small>
|
||||
삼국지 모의전투 HiDCHe / KOEI의 이미지를 사용, 응용하였습니다 / 제작 : HideD(hided62@gmail.com) / Credit
|
||||
</small>
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||
import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import { useGameFeedback } from '../composables/useGameFeedback';
|
||||
import { resolveGeneralIconUrl, useDefaultGeneralIcon } from '../utils/generalIcon';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type BoardArticle = Awaited<ReturnType<typeof trpc.board.getArticles.query>>[number];
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const { error: showErrorToast } = useGameFeedback();
|
||||
const isSecretBoard = computed(() => route.name === 'board-secret');
|
||||
const title = computed(() => (isSecretBoard.value ? '기밀실' : '회의실'));
|
||||
const closeBoard = () => router.push('/');
|
||||
|
||||
const loading = ref(false);
|
||||
const accessChecked = ref(false);
|
||||
@@ -123,15 +125,20 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="accessChecked && !canAccess" class="legacy-raw-access-error" role="alert">{{ errorMessage }}</div>
|
||||
<div v-if="accessChecked && !canAccess" class="legacy-raw-access-error">
|
||||
<span role="alert">{{ errorMessage }}</span>
|
||||
<button class="legacy-button legacy-button--navigation" type="button" @click="exitPage">
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</div>
|
||||
<main v-else id="container" class="legacy-board-page">
|
||||
<header class="top-back-bar bg0">
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height back-button"
|
||||
type="button"
|
||||
@click="closeBoard"
|
||||
@click="exitPage"
|
||||
>
|
||||
돌아가기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<div></div>
|
||||
<h1>{{ title }}</h1>
|
||||
@@ -244,9 +251,9 @@ onMounted(() => {
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height back-button"
|
||||
type="button"
|
||||
@click="closeBoard"
|
||||
@click="exitPage"
|
||||
>
|
||||
돌아가기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { useClockDisplay } from '../composables/useClockDisplay';
|
||||
const { formatTime: formatGameTime } = useClockDisplay();
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { useMediaQuery } from '@vueuse/core';
|
||||
import { addMinutes } from 'date-fns';
|
||||
import { useRouter } from 'vue-router';
|
||||
import SkeletonLines from '../components/ui/SkeletonLines.vue';
|
||||
import ChiefTurnCard from '../components/chief/ChiefTurnCard.vue';
|
||||
import ChiefCommandEditor from '../components/chief/ChiefCommandEditor.vue';
|
||||
@@ -13,6 +14,8 @@ import { formatOfficerLevelText } from '../utils/nationFormat';
|
||||
import { formatReservedCommandBrief } from '../components/command/reservedCommandBrief';
|
||||
import type { CommandMapData, CommandMapLayout, CommandPatternEntry, CommandTable } from '../components/command/types';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type ReservationCompletion = (success: boolean) => void;
|
||||
|
||||
type ChiefTurn = {
|
||||
@@ -91,7 +94,6 @@ const worldMap = ref<CommandMapData | null>(null);
|
||||
const mapLayout = ref<CommandMapLayout | null>(null);
|
||||
|
||||
const selectedChiefLevel = ref<number | null>(null);
|
||||
const router = useRouter();
|
||||
|
||||
const isMobile = useMediaQuery('(max-width: 1024px)');
|
||||
|
||||
@@ -330,9 +332,9 @@ const repeatTurns = async (amount: number) => {
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height chief-nav"
|
||||
type="button"
|
||||
@click="router.push('/')"
|
||||
@click="exitPage"
|
||||
>
|
||||
돌아가기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height chief-nav"
|
||||
@@ -465,9 +467,9 @@ const repeatTurns = async (amount: number) => {
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height chief-nav"
|
||||
type="button"
|
||||
@click="router.push('/')"
|
||||
@click="exitPage"
|
||||
>
|
||||
돌아가기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { formatReservedCommandBrief } from '../components/command/reservedCommandBrief';
|
||||
@@ -9,6 +11,8 @@ import { resolveGeneralIconUrl, useDefaultGeneralIcon } from '../utils/generalIc
|
||||
import { legacyNationTextColor } from '../utils/legacyNationColor';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type Result = Awaited<ReturnType<typeof trpc.world.getCurrentCity.query>>;
|
||||
type General = Result['generals'][number];
|
||||
type ReservedCommand = General['turns'][number];
|
||||
@@ -95,9 +99,9 @@ const commandBrief = (command: ReservedCommand): string =>
|
||||
도 시 정 보<br /><button
|
||||
class="legacy-button legacy-button--navigation back-link"
|
||||
type="button"
|
||||
@click="router.push('/')"
|
||||
@click="exitPage"
|
||||
>
|
||||
돌아가기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -313,9 +317,9 @@ const commandBrief = (command: ReservedCommand): string =>
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation back-link"
|
||||
type="button"
|
||||
@click="router.push('/')"
|
||||
@click="exitPage"
|
||||
>
|
||||
돌아가기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
|
||||
import { EditorContent, useEditor } from '@tiptap/vue-3';
|
||||
import StarterKit from '@tiptap/starter-kit';
|
||||
@@ -6,12 +8,13 @@ import Image from '@tiptap/extension-image';
|
||||
import Link from '@tiptap/extension-link';
|
||||
import Placeholder from '@tiptap/extension-placeholder';
|
||||
import Underline from '@tiptap/extension-underline';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { trpc } from '../utils/trpc';
|
||||
import { resolveGeneralIconUrl } from '../utils/generalIcon';
|
||||
import { formatSeoulDateTime } from '../utils/legacyDateTime';
|
||||
import { legacyLuminanceTextColor } from '../utils/legacyNationColor';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type DiplomacyResponse = Awaited<ReturnType<typeof trpc.diplomacy.getLetters.query>>;
|
||||
type DiplomacyLetter = DiplomacyResponse['letters'][number];
|
||||
|
||||
@@ -19,7 +22,6 @@ const loading = ref(false);
|
||||
const errorMessage = ref<string | null>(null);
|
||||
const data = ref<DiplomacyResponse | null>(null);
|
||||
const historyOpen = ref<Record<number, boolean>>({});
|
||||
const router = useRouter();
|
||||
|
||||
const editable = computed(() => (data.value?.permission ?? 0) >= 4);
|
||||
|
||||
@@ -263,9 +265,9 @@ onBeforeUnmount(() => {
|
||||
외 교 부<br /><button
|
||||
class="legacy-button legacy-button--navigation"
|
||||
type="button"
|
||||
@click="router.push('/')"
|
||||
@click="exitPage"
|
||||
>
|
||||
돌아가기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -634,8 +636,8 @@ onBeforeUnmount(() => {
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<button class="legacy-button legacy-button--navigation" type="button" @click="router.push('/')">
|
||||
돌아가기</button
|
||||
<button class="legacy-button legacy-button--navigation" type="button" @click="exitPage">
|
||||
{{ pageExitLabel }}</button
|
||||
><br /><br />
|
||||
삼국지 모의전투 HiDCHe / KOEI의 이미지를 사용, 응용하였습니다 / 제작 : HideD(hided62@gmail.com)
|
||||
/
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import { formatLog } from '../utils/formatLog';
|
||||
import { legacyNationTextColor } from '../utils/legacyNationColor';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type DynastyDetailPayload = Awaited<ReturnType<typeof trpc.dynasty.getDetail.query>>;
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const loading = ref(false);
|
||||
const errorMessage = ref('');
|
||||
const data = ref<DynastyDetailPayload | null>(null);
|
||||
@@ -23,14 +26,6 @@ const emperorId = computed(() => {
|
||||
return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
|
||||
});
|
||||
|
||||
const closePage = async (): Promise<void> => {
|
||||
if (window.opener) {
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
await router.push('/');
|
||||
};
|
||||
|
||||
const loadDetail = async (): Promise<void> => {
|
||||
if (emperorId.value === null) {
|
||||
data.value = null;
|
||||
@@ -62,7 +57,7 @@ onMounted(loadDetail);
|
||||
<tr>
|
||||
<td>
|
||||
역 대 왕 조<br />
|
||||
<button class="native-button" type="button" @click="closePage">창 닫기</button>
|
||||
<button class="native-button" type="button" @click="exitPage">{{ pageExitLabel }}</button>
|
||||
<span class="all-link">
|
||||
<RouterLink
|
||||
:to="{ path: '/dynasty', query: source === 'legacy' ? { source: 'legacy' } : {} }"
|
||||
@@ -290,7 +285,9 @@ onMounted(loadDetail);
|
||||
<table class="legacy-table legacy-bg0 footer-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><button class="native-button" type="button" @click="closePage">창 닫기</button><br /></td>
|
||||
<td>
|
||||
<button class="native-button" type="button" @click="exitPage">{{ pageExitLabel }}</button><br />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="banner">삼국지 모의전투 HiDCHe / KOEI의 이미지를 사용, 응용하였습니다 / 제작 : HideD</td>
|
||||
|
||||
@@ -1,27 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import { legacyNationTextColor } from '../utils/legacyNationColor';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type DynastyListPayload = Awaited<ReturnType<typeof trpc.dynasty.getList.query>>;
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const loading = ref(false);
|
||||
const errorMessage = ref('');
|
||||
const data = ref<DynastyListPayload | null>(null);
|
||||
const selectedSource = ref<'current' | 'legacy'>(route.query.source === 'legacy' ? 'legacy' : 'current');
|
||||
|
||||
const closePage = async (): Promise<void> => {
|
||||
if (window.opener) {
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
await router.push('/');
|
||||
};
|
||||
|
||||
const loadDynasty = async (): Promise<void> => {
|
||||
loading.value = true;
|
||||
errorMessage.value = '';
|
||||
@@ -45,7 +40,7 @@ watch(selectedSource, loadDynasty);
|
||||
<tr>
|
||||
<td>
|
||||
역 대 왕 조<br />
|
||||
<button class="native-button" type="button" @click="closePage">창 닫기</button><br />
|
||||
<button class="native-button" type="button" @click="exitPage">{{ pageExitLabel }}</button><br />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -162,7 +157,9 @@ watch(selectedSource, loadDynasty);
|
||||
<table class="legacy-table legacy-bg0 footer-table spaced-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><button class="native-button" type="button" @click="closePage">창 닫기</button><br /></td>
|
||||
<td>
|
||||
<button class="native-button" type="button" @click="exitPage">{{ pageExitLabel }}</button><br />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="banner">삼국지 모의전투 HiDCHe / KOEI의 이미지를 사용, 응용하였습니다 / 제작 : HideD</td>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import GeneralDirectoryTable from '../components/directory/GeneralDirectoryTable.vue';
|
||||
import LegacySortControls from '../components/ui/LegacySortControls.vue';
|
||||
@@ -14,6 +15,8 @@ import {
|
||||
} from '../utils/generalDirectorySort';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
const sortOptions: Array<{ value: GeneralDirectorySortKey; label: string }> = [
|
||||
{ value: 0, label: '이름' },
|
||||
{ value: 1, label: '국가' },
|
||||
@@ -38,7 +41,6 @@ const sourceGenerals = ref<GeneralDirectoryGeneral[]>([]);
|
||||
const sortCriteria = ref<GeneralDirectorySortCriterion[]>([]);
|
||||
const loading = ref(false);
|
||||
const error = ref('');
|
||||
const router = useRouter();
|
||||
const { info: showInfoToast } = useGameFeedback();
|
||||
|
||||
const generals = computed(() => sortGeneralDirectory(sourceGenerals.value, sortCriteria.value));
|
||||
@@ -81,7 +83,7 @@ onMounted(() => {
|
||||
<tr>
|
||||
<td>
|
||||
장 수 일 람<br />
|
||||
<button class="legacy-button" type="button" @click="router.push('/')">창 닫기</button>
|
||||
<button class="legacy-button" type="button" @click="exitPage">{{ pageExitLabel }}</button>
|
||||
<button
|
||||
class="legacy-button"
|
||||
type="button"
|
||||
@@ -118,7 +120,9 @@ onMounted(() => {
|
||||
<table class="directory-table title-table legacy-bg0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><button class="legacy-button" type="button" @click="router.push('/')">창 닫기</button></td>
|
||||
<td>
|
||||
<button class="legacy-button" type="button" @click="exitPage">{{ pageExitLabel }}</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><small>삼국지 모의전투 HiDCHe</small></td>
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import MapViewer from '../components/main/MapViewer.vue';
|
||||
import { trpc } from '../utils/trpc';
|
||||
import { legacyLuminanceTextColor } from '../utils/legacyNationColor';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type Result = Awaited<ReturnType<typeof trpc.world.getGlobalInfo.query>>;
|
||||
type Layout = Awaited<ReturnType<typeof trpc.world.getMapLayout.query>>;
|
||||
const data = ref<Result | null>(null);
|
||||
@@ -12,8 +15,6 @@ const layout = ref<Layout | null>(null);
|
||||
const error = ref('');
|
||||
const matrixElement = ref<HTMLTableElement | null>(null);
|
||||
const matrixHeight = ref<number | null>(null);
|
||||
const router = useRouter();
|
||||
const goBack = () => router.push('/');
|
||||
const state = (value: number) => ({ 0: '★', 1: '▲', 2: '', 7: '@' })[value] ?? 'ㆍ';
|
||||
const stateClass = (value: number) => `state-${value}`;
|
||||
const nationMap = computed(() => new Map(data.value?.nations.map((nation) => [nation.id, nation]) ?? []));
|
||||
@@ -56,9 +57,9 @@ onMounted(async () => {
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height"
|
||||
type="button"
|
||||
@click="goBack"
|
||||
@click="exitPage"
|
||||
>
|
||||
돌아가기</button
|
||||
{{ pageExitLabel }}</button
|
||||
><strong>중원 정보</strong>
|
||||
</header>
|
||||
<p v-if="error" class="error">{{ error }}</p>
|
||||
@@ -157,9 +158,9 @@ onMounted(async () => {
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height"
|
||||
type="button"
|
||||
@click="goBack"
|
||||
@click="exitPage"
|
||||
>
|
||||
돌아가기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</footer>
|
||||
<button class="legacy-compat-button" type="button" tabindex="-1" aria-hidden="true" />
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { resolveGeneralIconUrl, useDefaultGeneralIcon } from '../utils/generalIcon';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type HallOption = {
|
||||
sourceProfile: string;
|
||||
season: number;
|
||||
@@ -39,7 +42,6 @@ type HallPayload = {
|
||||
sections: HallSection[];
|
||||
};
|
||||
|
||||
const router = useRouter();
|
||||
const loading = ref(false);
|
||||
const errorMessage = ref('');
|
||||
const options = ref<HallOption[]>([]);
|
||||
@@ -64,14 +66,6 @@ const selection = computed({
|
||||
|
||||
const imageUrl = (entry: HallEntry): string => resolveGeneralIconUrl(entry);
|
||||
|
||||
const closePage = async (): Promise<void> => {
|
||||
if (window.opener) {
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
await router.push('/');
|
||||
};
|
||||
|
||||
const loadOptions = async (): Promise<void> => {
|
||||
try {
|
||||
options.value = await trpc.ranking.getHallOfFameOptions.query({ source: selectedSource.value });
|
||||
@@ -121,7 +115,7 @@ onMounted(loadOptions);
|
||||
<main id="container" class="legacy-hall-page legacy-bg0">
|
||||
<div class="legacy-hall-title">
|
||||
명 예 의 전 당<br />
|
||||
<button class="legacy-button" type="button" @click="closePage">창 닫기</button>
|
||||
<button class="legacy-button" type="button" @click="exitPage">{{ pageExitLabel }}</button>
|
||||
</div>
|
||||
|
||||
<label class="archive-source">
|
||||
@@ -189,7 +183,7 @@ onMounted(loadOptions);
|
||||
</section>
|
||||
|
||||
<div class="legacy-hall-bottom">
|
||||
<button class="legacy-button" type="button" @click="closePage">창 닫기</button>
|
||||
<button class="legacy-button" type="button" @click="exitPage">{{ pageExitLabel }}</button>
|
||||
</div>
|
||||
<footer class="legacy-banner">
|
||||
삼국지 모의전투 HiDCHe / KOEI의 이미지를 사용, 응용하였습니다 / 제작 : HideD /
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||
import { JosaUtil } from '@sammo-ts/common/util/JosaUtil';
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import { trpc } from '../utils/trpc';
|
||||
import { useGameFeedback } from '../composables/useGameFeedback';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type InheritStatus = Awaited<ReturnType<typeof trpc.inherit.getStatus.query>>;
|
||||
type InheritLog = Awaited<ReturnType<typeof trpc.inherit.getLogs.query>>[number];
|
||||
type JoinConfig = Awaited<ReturnType<typeof trpc.join.getConfig.query>>;
|
||||
@@ -452,9 +456,13 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<header class="top-back-bar legacy-bg0">
|
||||
<RouterLink class="top-button legacy-button legacy-button--navigation legacy-button--fixed-height" to="/"
|
||||
>돌아가기</RouterLink
|
||||
<button
|
||||
class="top-button legacy-button legacy-button--navigation legacy-button--fixed-height"
|
||||
type="button"
|
||||
@click="exitPage"
|
||||
>
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<strong>유산 관리</strong>
|
||||
<button
|
||||
class="top-button legacy-button legacy-button--navigation legacy-button--fixed-height"
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { JosaUtil } from '@sammo-ts/common/util/JosaUtil';
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import { trpc } from '../utils/trpc';
|
||||
@@ -11,6 +13,8 @@ import GeneralInformationPanel from '../components/main/GeneralInformationPanel.
|
||||
import { useGameFeedback } from '../composables/useGameFeedback';
|
||||
import { gameFrontendRuntimeConfig } from '../config/runtimeConfig';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
const PENDING_DIE_ON_PRESTART_KEY = 'sam.pending.dieOnPrestart';
|
||||
const { error: showErrorToast, showDialog } = useGameFeedback();
|
||||
type LogType = 'generalHistory' | 'battleDetail' | 'battleResult' | 'generalAction';
|
||||
@@ -340,7 +344,9 @@ onMounted(() => {
|
||||
<span>내 정 보</span>
|
||||
<div class="title-actions">
|
||||
<div class="navigation-actions">
|
||||
<RouterLink class="legacy-button legacy-button--navigation" to="/">돌아가기</RouterLink>
|
||||
<button class="legacy-button legacy-button--navigation" type="button" @click="exitPage">
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<button class="legacy-button legacy-button--navigation" type="button" @click="() => loadPage()">
|
||||
새로고침
|
||||
</button>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { useClockDisplay } from '../composables/useClockDisplay';
|
||||
const { mode: clockDisplayMode } = useClockDisplay();
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
@@ -23,6 +25,8 @@ import {
|
||||
type ScreenMode,
|
||||
} from '../utils/screenModeViewport';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
const { success: showSuccessToast, error: showErrorToast } = useGameFeedback();
|
||||
type MyGeneralResponse = Awaited<ReturnType<typeof trpc.general.me.query>>;
|
||||
const data = ref<MyGeneralResponse | null>(null);
|
||||
@@ -134,7 +138,9 @@ onBeforeUnmount(() => {
|
||||
<main id="interface-settings" class="legacy-page bg0 interface-settings-page">
|
||||
<div class="title-row">
|
||||
<span>환 경 설 정</span>
|
||||
<RouterLink class="legacy-button legacy-button--navigation" to="/">돌아가기</RouterLink>
|
||||
<button class="legacy-button legacy-button--navigation" type="button" @click="exitPage">
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<section class="settings-grid">
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
|
||||
import { useGameFeedback } from '../composables/useGameFeedback';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type BettingListItem = {
|
||||
id: number;
|
||||
type: string;
|
||||
@@ -333,15 +337,13 @@ onMounted(() => {
|
||||
<template>
|
||||
<main id="nation-betting-container" class="nation-betting-page legacy-bg0">
|
||||
<header class="legacy-top-bar">
|
||||
<RouterLink v-slot="{ navigate }" custom to="/">
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height"
|
||||
type="button"
|
||||
@click="navigate"
|
||||
>
|
||||
돌아가기
|
||||
</button>
|
||||
</RouterLink>
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height"
|
||||
type="button"
|
||||
@click="exitPage"
|
||||
>
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<div></div>
|
||||
<h1>국가 베팅장</h1>
|
||||
<div></div>
|
||||
@@ -441,7 +443,9 @@ onMounted(() => {
|
||||
</section>
|
||||
|
||||
<footer class="betting-footer">
|
||||
<RouterLink class="legacy-button legacy-button--navigation" to="/">돌아가기</RouterLink>
|
||||
<button class="legacy-button legacy-button--navigation" type="button" @click="exitPage">
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</footer>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { useClockDisplay } from '../composables/useClockDisplay';
|
||||
const { formatTime: formatGameTime } = useClockDisplay();
|
||||
import { JosaUtil } from '@sammo-ts/common/util/JosaUtil';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { formatReservedCommandBrief } from '../components/command/reservedCommandBrief';
|
||||
import type { CommandTable } from '../components/command/types';
|
||||
import LegacySortControls from '../components/ui/LegacySortControls.vue';
|
||||
@@ -14,6 +15,8 @@ import { legacyNationTextColor } from '../utils/legacyNationColor';
|
||||
import { cityLevelMap, regionMap } from '../utils/nationFormat';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type Result = Awaited<ReturnType<typeof trpc.nation.getCityOverview.query>>;
|
||||
type SecretResult = Awaited<ReturnType<typeof trpc.nation.getSecretGeneralList.query>>;
|
||||
type PersonnelResult = Awaited<ReturnType<typeof trpc.nation.getPersonnelInfo.query>>;
|
||||
@@ -45,7 +48,6 @@ const extraSort = ref<
|
||||
| 'generalCount'
|
||||
| null
|
||||
>(null);
|
||||
const router = useRouter();
|
||||
const { error: showErrorToast, info: showInfoToast, success: showSuccessToast } = useGameFeedback();
|
||||
const sortOptions = [
|
||||
'기본',
|
||||
@@ -303,9 +305,9 @@ onMounted(async () => {
|
||||
세 력 도 시<br /><button
|
||||
class="legacy-button legacy-button--navigation back-button"
|
||||
type="button"
|
||||
@click="router.push('/')"
|
||||
@click="exitPage"
|
||||
>
|
||||
돌아가기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -716,9 +718,9 @@ onMounted(async () => {
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation back-button"
|
||||
type="button"
|
||||
@click="router.push('/')"
|
||||
@click="exitPage"
|
||||
>
|
||||
돌아가기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { useClockDisplay } from '../composables/useClockDisplay';
|
||||
const { formatTime: formatGameTime } = useClockDisplay();
|
||||
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { formatReservedCommandBrief } from '../components/command/reservedCommandBrief';
|
||||
import type { CommandTable } from '../components/command/types';
|
||||
import { formatOfficerLevelText } from '../utils/nationFormat';
|
||||
@@ -33,6 +34,8 @@ import {
|
||||
} from '../utils/nationGeneralGrid';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type Result = Awaited<ReturnType<typeof trpc.nation.getGeneralList.query>>;
|
||||
type General = Result['generals'][number];
|
||||
type CellValue = string | number | null;
|
||||
@@ -218,7 +221,6 @@ const layout: LayoutItem[] = [
|
||||
const columnById = new Map(columns.map((column) => [column.id, column]));
|
||||
const data = ref<Result | null>(null);
|
||||
const commandTable = ref<CommandTable | null>(null);
|
||||
const router = useRouter();
|
||||
const error = ref('');
|
||||
const loading = ref(false);
|
||||
const viewMenuOpen = ref(false);
|
||||
@@ -709,9 +711,9 @@ onBeforeUnmount(() => {
|
||||
<span class="left-actions">
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height top-button nation-button"
|
||||
@click="router.push('/')"
|
||||
@click="exitPage"
|
||||
>
|
||||
돌아가기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height top-button nation-button"
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { formatLog } from '../utils/formatLog';
|
||||
import { legacyNationTextColor } from '../utils/legacyNationColor';
|
||||
import { formatNationLevelText } from '../utils/nationFormat';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type Result = Awaited<ReturnType<typeof trpc.nation.getNationInfo.query>>;
|
||||
const data = ref<Result | null>(null);
|
||||
const router = useRouter();
|
||||
const error = ref('');
|
||||
const number = (value: number) => value.toLocaleString('ko-KR');
|
||||
const diff = (value: number) => `${value > 0 ? '+' : ''}${number(value)}`;
|
||||
@@ -31,9 +33,9 @@ onMounted(async () => {
|
||||
세 력 정 보<br /><button
|
||||
class="legacy-button legacy-button--navigation"
|
||||
type="button"
|
||||
@click="router.push('/')"
|
||||
@click="exitPage"
|
||||
>
|
||||
돌아가기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -119,8 +121,8 @@ onMounted(async () => {
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<button class="legacy-button legacy-button--navigation" type="button" @click="router.push('/')">
|
||||
돌아가기
|
||||
<button class="legacy-button legacy-button--navigation" type="button" @click="exitPage">
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue';
|
||||
|
||||
import GeneralDirectoryTable from '../components/directory/GeneralDirectoryTable.vue';
|
||||
@@ -9,6 +11,8 @@ import { getNpcColor } from '../utils/npcColor';
|
||||
import { legacyNationTextColor } from '../utils/legacyNationColor';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type Directory = Awaited<ReturnType<typeof trpc.world.getNationDirectory.query>>;
|
||||
type Nation = Directory[number];
|
||||
|
||||
@@ -58,7 +62,6 @@ const displayAmbassadorName = (nation: Nation, name: string) => {
|
||||
return general ? displayGeneralName(general) : name;
|
||||
};
|
||||
|
||||
const closeWindow = () => window.close();
|
||||
const officerLevelAt = (row: number, column: number, columns: number) => 13 - ((row - 1) * columns + column);
|
||||
|
||||
const positionGeneralPreview = async (): Promise<void> => {
|
||||
@@ -165,8 +168,8 @@ onBeforeUnmount(() => {
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
세 력 일 람<br /><button class="legacy-button" type="button" @click="closeWindow">
|
||||
창 닫기
|
||||
세 력 일 람<br /><button class="legacy-button" type="button" @click="exitPage">
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -400,7 +403,9 @@ onBeforeUnmount(() => {
|
||||
<table class="directory-table title-table footer-table legacy-bg0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><button class="legacy-button" type="button" @click="closeWindow">창 닫기</button></td>
|
||||
<td>
|
||||
<button class="legacy-button" type="button" @click="exitPage">{{ pageExitLabel }}</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { computed, nextTick, onMounted, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { JosaUtil } from '@sammo-ts/common/util/JosaUtil';
|
||||
|
||||
@@ -13,6 +14,8 @@ import { trpc } from '../utils/trpc';
|
||||
import { cityLevelMap, formatOfficerLevelText, getNationChiefLevel, regionMap } from '../utils/nationFormat';
|
||||
import { legacyNationTextColor } from '../utils/legacyNationColor';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type PersonnelResponse = Awaited<ReturnType<typeof trpc.nation.getPersonnelInfo.query>>;
|
||||
type GeneralEntry = PersonnelResponse['generals'][number];
|
||||
type OfficerLevel = 2 | 3 | 4;
|
||||
@@ -41,7 +44,6 @@ const selectionContext = ref<SelectionContext | null>(null);
|
||||
const kickTargetId = ref(0);
|
||||
const ambassadorSelection = ref<number[]>([]);
|
||||
const auditorSelection = ref<number[]>([]);
|
||||
const router = useRouter();
|
||||
const { success: showSuccessToast, error: showErrorToast, confirm: showConfirm } = useGameFeedback();
|
||||
|
||||
const resolveErrorMessage = (value: unknown): string =>
|
||||
@@ -311,9 +313,9 @@ onMounted(() => void loadPersonnel());
|
||||
인 사 부<br /><button
|
||||
class="legacy-button legacy-button--navigation"
|
||||
type="button"
|
||||
@click="router.push('/')"
|
||||
@click="exitPage"
|
||||
>
|
||||
돌아가기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -569,12 +571,8 @@ onMounted(() => void loadPersonnel());
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation"
|
||||
type="button"
|
||||
@click="router.push('/')"
|
||||
>
|
||||
돌아가기
|
||||
<button class="legacy-button legacy-button--navigation" type="button" @click="exitPage">
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { useClockDisplay } from '../composables/useClockDisplay';
|
||||
const { formatTime: formatGameTime } = useClockDisplay();
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
@@ -9,6 +11,8 @@ import DirectoryTooltip from '../components/directory/DirectoryTooltip.vue';
|
||||
import { getNpcColor } from '../utils/npcColor';
|
||||
import { generalInjuryPresentation } from '../utils/generalInjury';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
type Result = Awaited<ReturnType<typeof trpc.nation.getSecretGeneralList.query>>;
|
||||
type ReservedCommand = Result['generals'][number]['reservedCommands'][number];
|
||||
type Sort = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
|
||||
@@ -48,7 +52,6 @@ const generals = computed(() =>
|
||||
return b.troopId - a.troopId || a.id - b.id;
|
||||
})
|
||||
);
|
||||
const closeWindow = () => window.close();
|
||||
const displayName = (general: { name: string; npcState: number }) =>
|
||||
general.npcState > 0 && !/^[ⓜⓝⓖ㉥ⓤⓞⓧ]/u.test(general.name) ? `ⓝ${general.name}` : general.name;
|
||||
const injuryInfo = (injury: number) => generalInjuryPresentation(injury);
|
||||
@@ -86,7 +89,9 @@ onMounted(load);
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
암 행 부<br /><button class="close-button" type="button" @click="closeWindow">창 닫기</button>
|
||||
암 행 부<br /><button class="close-button" type="button" @click="exitPage">
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -343,7 +348,9 @@ onMounted(load);
|
||||
<table class="layout legacy-bg0 footer">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><button class="close-button" type="button" @click="closeWindow">창 닫기</button></td>
|
||||
<td>
|
||||
<button class="close-button" type="button" @click="exitPage">{{ pageExitLabel }}</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="legacy-banner">
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
|
||||
import { trpc } from '../utils/trpc';
|
||||
@@ -7,6 +9,8 @@ import { legacyNationTextColor } from '../utils/legacyNationColor';
|
||||
import LegacyHtmlEditor from '../components/ui/LegacyHtmlEditor.vue';
|
||||
import { useGameFeedback } from '../composables/useGameFeedback';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type StratFinanResponse = Awaited<ReturnType<typeof trpc.nation.getStratFinan.query>>;
|
||||
type NationEntry = StratFinanResponse['nationsList'][number];
|
||||
|
||||
@@ -172,9 +176,13 @@ onMounted(() => void loadStratFinan());
|
||||
<template>
|
||||
<main id="finance-container" class="page-finance">
|
||||
<nav class="top-back-bar">
|
||||
<RouterLink class="legacy-button legacy-button--navigation legacy-button--fixed-height" to="/"
|
||||
>돌아가기</RouterLink
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height"
|
||||
type="button"
|
||||
@click="exitPage"
|
||||
>
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<span />
|
||||
<strong>내무부</strong>
|
||||
<span />
|
||||
@@ -451,7 +459,9 @@ onMounted(() => void loadStratFinan());
|
||||
<input v-for="index in 4" :key="`compat-input-${index}`" type="hidden" />
|
||||
</div>
|
||||
<footer class="bottom-bar">
|
||||
<RouterLink class="legacy-button legacy-button--navigation" to="/">돌아가기</RouterLink>
|
||||
<button class="legacy-button legacy-button--navigation" type="button" @click="exitPage">
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</footer>
|
||||
</template>
|
||||
</main>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
|
||||
import SortableStringList from '../components/ui/SortableStringList';
|
||||
@@ -6,6 +8,8 @@ import { useGameFeedback } from '../composables/useGameFeedback';
|
||||
import { npcPriorityHelp } from '../utils/npcPriorityHelp';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type NpcPolicyResponse = Awaited<ReturnType<typeof trpc.npc.getPolicy.query>>;
|
||||
type NationPolicy = NpcPolicyResponse['currentNationPolicy'];
|
||||
type NumericPolicyKey = Exclude<keyof NationPolicy, 'CombatForce' | 'SupportForce' | 'DevelopForce'>;
|
||||
@@ -363,9 +367,13 @@ const submitPriority = async (section: PrioritySectionKey) => {
|
||||
<template>
|
||||
<main id="npc-policy-page" class="npc-page">
|
||||
<nav class="top-back-bar legacy-bg0">
|
||||
<RouterLink class="legacy-button legacy-button--navigation legacy-button--fixed-height back-button" to="/"
|
||||
>돌아가기</RouterLink
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height back-button"
|
||||
type="button"
|
||||
@click="exitPage"
|
||||
>
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<strong>NPC 정책</strong>
|
||||
</nav>
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { onMounted, ref } from 'vue';
|
||||
|
||||
import LegacySortControls from '../components/ui/LegacySortControls.vue';
|
||||
import { getNpcColor } from '../utils/npcColor';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type NpcList = Awaited<ReturnType<typeof trpc.public.getNpcList.query>>;
|
||||
type NpcListSort = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
|
||||
|
||||
@@ -40,7 +44,6 @@ const load = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const closeWindow = () => window.close();
|
||||
const updateSort = (value: number): void => {
|
||||
sort.value = value as NpcListSort;
|
||||
};
|
||||
@@ -63,7 +66,7 @@ onMounted(() => {
|
||||
<tr>
|
||||
<td>
|
||||
빙 의 일 람<br />
|
||||
<button class="legacy-close" type="button" @click="closeWindow">창닫기</button>
|
||||
<button class="legacy-close" type="button" @click="exitPage">{{ pageExitLabel }}</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -226,7 +229,9 @@ onMounted(() => {
|
||||
<table class="legacy-table footer-table legacy-bg0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><button class="legacy-close" type="button" @click="closeWindow">창닫기</button></td>
|
||||
<td>
|
||||
<button class="legacy-close" type="button" @click="exitPage">{{ pageExitLabel }}</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="banner">
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
|
||||
import {
|
||||
@@ -20,6 +22,8 @@ import SkeletonLines from '../components/ui/SkeletonLines.vue';
|
||||
import { legacyLuminanceTextColor } from '../utils/legacyNationColor';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type Archive = Awaited<ReturnType<typeof trpc.archive.myPastPlays.query>>;
|
||||
type ArchiveSeason = Archive['seasons'][number] & {
|
||||
sourceProfile?: string;
|
||||
@@ -233,7 +237,7 @@ onMounted(() => {
|
||||
<header class="title-row legacy-bg1">
|
||||
<h1>내 지난 플레이 보기</h1>
|
||||
<nav>
|
||||
<RouterLink class="legacy-button" to="/">돌아가기</RouterLink>
|
||||
<button class="legacy-button" type="button" @click="exitPage">{{ pageExitLabel }}</button>
|
||||
<button class="legacy-button" type="button" :disabled="loading" @click="loadArchive">새로고침</button>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
@@ -10,6 +11,8 @@ import { resolveGeneralIconUrl, useDefaultGeneralIcon } from '../utils/generalIc
|
||||
import { legacyLuminanceTextColor } from '../utils/legacyNationColor';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type JoinConfig = Awaited<ReturnType<typeof trpc.join.getConfig.query>>;
|
||||
type Reservation = Awaited<ReturnType<typeof trpc.join.getSelectionPool.mutate>>;
|
||||
type Candidate = Reservation['candidates'][number];
|
||||
@@ -235,6 +238,10 @@ async function loadPage(): Promise<void> {
|
||||
}
|
||||
|
||||
const goBack = (): void => {
|
||||
if (hasGeneral.value) {
|
||||
exitPage();
|
||||
return;
|
||||
}
|
||||
if (window.history.length > 1) {
|
||||
router.back();
|
||||
return;
|
||||
@@ -260,7 +267,9 @@ onBeforeUnmount(() => {
|
||||
<main class="select-pool-page legacy-bg0">
|
||||
<header class="page-title with-border">
|
||||
장 수 선 택<br />
|
||||
<button class="legacy-button" type="button" @click="goBack">돌아가기</button>
|
||||
<button class="legacy-button" type="button" @click="goBack">
|
||||
{{ hasGeneral ? pageExitLabel : '돌아가기' }}
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<table v-if="serverInfo" class="server-info-table legacy-bg0">
|
||||
@@ -479,7 +488,9 @@ onBeforeUnmount(() => {
|
||||
|
||||
<footer class="page-footer">
|
||||
<div class="footer-back with-border">
|
||||
<button class="legacy-button" type="button" @click="goBack">돌아가기</button>
|
||||
<button class="legacy-button" type="button" @click="goBack">
|
||||
{{ hasGeneral ? pageExitLabel : '돌아가기' }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="footer-banner with-border">
|
||||
<small>
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
|
||||
import { useGameFeedback } from '../composables/useGameFeedback';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type VoteListResponse = Awaited<ReturnType<typeof trpc.vote.getVoteList.query>>;
|
||||
type VoteDetail = Awaited<ReturnType<typeof trpc.vote.getVoteDetail.query>>;
|
||||
type PollSummary = VoteListResponse['polls'][number];
|
||||
@@ -24,7 +28,6 @@ const myComment = ref('');
|
||||
const newVoteTitle = ref('');
|
||||
const newVoteOptionsText = ref('');
|
||||
const newVoteMultipleOptions = ref(1);
|
||||
const closeWindow = (): void => window.close();
|
||||
const { success: showSuccessToast, error: showErrorToast } = useGameFeedback();
|
||||
|
||||
const getErrorMessage = (error: unknown): string => {
|
||||
@@ -208,9 +211,9 @@ onMounted(() => {
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height back_btn"
|
||||
type="button"
|
||||
@click="closeWindow"
|
||||
@click="exitPage"
|
||||
>
|
||||
창 닫기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height reload_btn"
|
||||
@@ -408,9 +411,9 @@ onMounted(() => {
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height back_btn"
|
||||
type="button"
|
||||
@click="closeWindow"
|
||||
@click="exitPage"
|
||||
>
|
||||
창 닫기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { useClockDisplay } from '../composables/useClockDisplay';
|
||||
const { formatTime: formatGameTime } = useClockDisplay();
|
||||
import { storeToRefs } from 'pinia';
|
||||
@@ -12,6 +14,8 @@ import { formatLog } from '../utils/formatLog';
|
||||
import { trpc } from '../utils/trpc';
|
||||
import { resolveTournamentSectionVisibility, resolveTournamentStageName } from '../utils/tournamentStatus';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
const tournamentPages = useTournamentPagesStore();
|
||||
const { snapshot, betting, loading, error } = storeToRefs(tournamentPages);
|
||||
type Snapshot = NonNullable<typeof snapshot.value>;
|
||||
@@ -354,11 +358,9 @@ const start = async () => {
|
||||
</section>
|
||||
<input type="hidden" name="tournamentAction" value="join" />
|
||||
<footer class="tournament-footer bg0">
|
||||
<RouterLink v-slot="{ navigate }" custom to="/">
|
||||
<button class="legacy-button legacy-button--navigation close-button" type="button" @click="navigate">
|
||||
창 닫기
|
||||
</button>
|
||||
</RouterLink>
|
||||
<button class="legacy-button legacy-button--navigation close-button" type="button" @click="exitPage">
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<small>
|
||||
삼국지 모의전투 HiDCHe / KOEI의 이미지를 사용, 응용하였습니다 / 제작 : HideD(hided62@gmail.com) / Credit
|
||||
</small>
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { formatServerDateTime } from '@sammo-ts/common/time/ServerDateTime';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type TrafficData = Awaited<ReturnType<typeof trpc.public.getTraffic.query>>;
|
||||
|
||||
const data = ref<TrafficData | null>(null);
|
||||
const loading = ref(false);
|
||||
const errorMessage = ref('');
|
||||
const router = useRouter();
|
||||
|
||||
const getErrorMessage = (error: unknown): string => {
|
||||
if (error instanceof Error) {
|
||||
@@ -73,7 +75,7 @@ onMounted(() => {
|
||||
<tr>
|
||||
<td>
|
||||
트 래 픽 정 보<br />
|
||||
<button class="legacy-close" type="button" @click="router.push('/')">돌아가기</button>
|
||||
<button class="legacy-close" type="button" @click="exitPage">{{ pageExitLabel }}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -198,7 +200,9 @@ onMounted(() => {
|
||||
<table class="legacy-table footer-table legacy-bg0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><button class="legacy-close" type="button" @click="router.push('/')">돌아가기</button></td>
|
||||
<td>
|
||||
<button class="legacy-close" type="button" @click="exitPage">{{ pageExitLabel }}</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="banner">
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { useClockDisplay } from '../composables/useClockDisplay';
|
||||
const { formatTime: formatGameTime } = useClockDisplay();
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { resolveGeneralIconUrl, useDefaultGeneralIcon } from '../utils/generalIcon';
|
||||
import { trpc } from '../utils/trpc';
|
||||
@@ -10,6 +11,8 @@ import LegacyGeneralProgress from '../components/ui/LegacyGeneralProgress.vue';
|
||||
import GeneralInformationPanel from '../components/main/GeneralInformationPanel.vue';
|
||||
import { useGameFeedback } from '../composables/useGameFeedback';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type TroopList = Awaited<ReturnType<typeof trpc.troop.getList.query>>;
|
||||
type Troop = TroopList['troops'][number];
|
||||
type Member = Troop['members'][number];
|
||||
@@ -25,7 +28,6 @@ const dialogKind = ref<DialogKind>(null);
|
||||
const dialogTroopId = ref(0);
|
||||
const popupMember = ref<Member | null>(null);
|
||||
const popupTop = ref(0);
|
||||
const router = useRouter();
|
||||
const { success: showSuccessToast, error: showErrorToast, confirm: showConfirm } = useGameFeedback();
|
||||
|
||||
const me = computed(() => data.value?.me ?? null);
|
||||
@@ -185,9 +187,9 @@ onMounted(() => {
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height legacyNavButton backLink"
|
||||
type="button"
|
||||
@click="router.push('/')"
|
||||
@click="exitPage"
|
||||
>
|
||||
돌아가기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height legacyNavButton reloadButton"
|
||||
@@ -335,9 +337,9 @@ onMounted(() => {
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacyNavButton backLink"
|
||||
type="button"
|
||||
@click="router.push('/')"
|
||||
@click="exitPage"
|
||||
>
|
||||
돌아가기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<div></div>
|
||||
</footer>
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageExit } from '../composables/usePageExit';
|
||||
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import MapViewer from '../components/main/MapViewer.vue';
|
||||
import { formatLog } from '../utils/formatLog';
|
||||
import { legacyLuminanceTextColor } from '../utils/legacyNationColor';
|
||||
import { trpc } from '../utils/trpc';
|
||||
|
||||
const { pageExitLabel, exitPage } = usePageExit();
|
||||
|
||||
type YearbookRange = Awaited<ReturnType<typeof trpc.yearbook.getRange.query>>;
|
||||
type MapLayout = Awaited<ReturnType<typeof trpc.public.getMapLayout.query>>;
|
||||
type HistoryData = {
|
||||
@@ -26,7 +30,6 @@ type HistoryData = {
|
||||
globalAction: string[];
|
||||
};
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const loading = ref(false);
|
||||
const errorMessage = ref('');
|
||||
@@ -61,14 +64,6 @@ const availableYearMonths = computed(() => {
|
||||
return values;
|
||||
});
|
||||
|
||||
const closePage = async (): Promise<void> => {
|
||||
if (window.opener) {
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
await router.push('/');
|
||||
};
|
||||
|
||||
const loadHistory = async (): Promise<void> => {
|
||||
if (selectedYearMonth.value === null) {
|
||||
return;
|
||||
@@ -140,9 +135,9 @@ onMounted(async () => {
|
||||
<button
|
||||
class="legacy-button legacy-button--navigation legacy-button--fixed-height close-button"
|
||||
type="button"
|
||||
@click="closePage"
|
||||
@click="exitPage"
|
||||
>
|
||||
창 닫기
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
<span class="settings-menu">
|
||||
<button
|
||||
@@ -242,7 +237,9 @@ onMounted(async () => {
|
||||
</section>
|
||||
|
||||
<footer class="yearbook-footer">
|
||||
<button class="legacy-button legacy-button--navigation" type="button" @click="closePage">창 닫기</button>
|
||||
<button class="legacy-button legacy-button--navigation" type="button" @click="exitPage">
|
||||
{{ pageExitLabel }}
|
||||
</button>
|
||||
</footer>
|
||||
<div class="dropdown-compat-buttons" aria-hidden="true">
|
||||
<button type="button" tabindex="-1" /><button type="button" tabindex="-1" />
|
||||
|
||||
@@ -33,13 +33,13 @@ void describe('shared Lumen button family', () => {
|
||||
nationGenerals,
|
||||
/legacy-button legacy-button--info legacy-button--fixed-height top-button columns-button/u
|
||||
);
|
||||
for (const label of ['돌아가기', '갱신', '보기 모드⌄', '열 선택⌄']) {
|
||||
for (const label of ['pageExitLabel', '갱신', '보기 모드⌄', '열 선택⌄']) {
|
||||
assert.match(nationGenerals, new RegExp(label, 'u'));
|
||||
}
|
||||
for (const label of ['토너먼트', '베팅장', '창 닫기']) {
|
||||
for (const label of ['토너먼트', '베팅장', 'pageExitLabel']) {
|
||||
assert.match(tournamentHeader, new RegExp(`legacy-button[\\s\\S]{0,260}${label}`, 'u'));
|
||||
}
|
||||
assert.match(tournamentHeader, /const closeWindow = \(\): void => window\.close\(\)/u);
|
||||
assert.match(tournamentHeader, /@click="exitPage"/u);
|
||||
assert.doesNotMatch(tournamentHeader, /custom to="\/"/u);
|
||||
assert.match(reservedEditor, /legacy-button legacy-button--info legacy-button--fixed-height select-command/u);
|
||||
assert.match(reservedEditor, /명령 선택 ▾/u);
|
||||
|
||||
Reference in New Issue
Block a user