fix(frontend): align ref menu structure
This commit is contained in:
@@ -288,6 +288,17 @@ test('desktop menus preserve ref columns, prefix-safe routes, and controlled dro
|
|||||||
await expect(page.locator('.main-mobile-bottom')).toBeHidden();
|
await expect(page.locator('.main-mobile-bottom')).toBeHidden();
|
||||||
await expect(page.locator('.layout-desktop')).toBeVisible();
|
await expect(page.locator('.layout-desktop')).toBeVisible();
|
||||||
await expect(page.locator('.layout-mobile')).toHaveCount(0);
|
await expect(page.locator('.layout-mobile')).toHaveCount(0);
|
||||||
|
const contentOrder = await page
|
||||||
|
.locator('.record-zone, [data-menu-position="middle"], .desktop-message-panel, [data-menu-position="bottom"]')
|
||||||
|
.evaluateAll((elements) =>
|
||||||
|
elements.map((element) => {
|
||||||
|
if (element.classList.contains('record-zone')) return 'records';
|
||||||
|
if (element.getAttribute('data-menu-position') === 'middle') return 'middle-menu';
|
||||||
|
if (element.classList.contains('desktop-message-panel')) return 'messages';
|
||||||
|
return 'bottom-menu';
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expect(contentOrder).toEqual(['records', 'middle-menu', 'messages', 'bottom-menu']);
|
||||||
|
|
||||||
const global = page.locator('.main-global-menu').first();
|
const global = page.locator('.main-global-menu').first();
|
||||||
await expect(global.locator('[data-navigation-id="nation-betting"]')).toHaveAttribute(
|
await expect(global.locator('[data-navigation-id="nation-betting"]')).toHaveAttribute(
|
||||||
@@ -383,8 +394,30 @@ test('the 939/940 boundary and 500px bottom bar match the ref responsive contrac
|
|||||||
expect(popupStyle.overflowY).toBe('auto');
|
expect(popupStyle.overflowY).toBe('auto');
|
||||||
expect(popupStyle.maxHeight).toBe('850px');
|
expect(popupStyle.maxHeight).toBe('850px');
|
||||||
expect(popupStyle.bottom).toBe('47px');
|
expect(popupStyle.bottom).toBe('47px');
|
||||||
|
const globalPopup = page.locator('#mobile-global-menu');
|
||||||
|
await expect(globalPopup.getByText('게시판', { exact: true })).toHaveCount(1);
|
||||||
|
await expect(globalPopup.getByText('공식 오픈 톡', { exact: true })).toHaveCount(1);
|
||||||
|
await expect(globalPopup.getByText('게임정보', { exact: true })).toHaveCount(1);
|
||||||
|
await expect(globalPopup.getByText('기타 정보', { exact: true })).toHaveCount(1);
|
||||||
|
await persistArtifact(page, `${basePath.slice(1)}-mobile-global-open-500`);
|
||||||
await page.keyboard.press('Escape');
|
await page.keyboard.press('Escape');
|
||||||
await expect(externalTrigger).toBeFocused();
|
await expect(externalTrigger).toBeFocused();
|
||||||
|
|
||||||
|
await page.locator('[data-bottom-menu="nation"]').click();
|
||||||
|
const nationPopup = page.locator('#mobile-nation-menu');
|
||||||
|
await expect(nationPopup.getByText('금/쌀 경매장', { exact: true })).toHaveCount(1);
|
||||||
|
await expect(nationPopup.getByText('유니크 경매장', { exact: true })).toHaveCount(1);
|
||||||
|
await page.keyboard.press('Escape');
|
||||||
|
|
||||||
|
await page.locator('[data-bottom-menu="quick"]').click();
|
||||||
|
const quickPopup = page.locator('#mobile-quick-menu');
|
||||||
|
for (const heading of ['국가 정보', '동향 정보', '메시지']) {
|
||||||
|
await expect(quickPopup.locator('.bottom-heading').getByText(heading, { exact: true })).toHaveCount(1);
|
||||||
|
}
|
||||||
|
await expect(quickPopup.locator('.bottom-heading')).toHaveCount(3);
|
||||||
|
await expect(quickPopup.locator('.bottom-divider')).toHaveCount(3);
|
||||||
|
await persistArtifact(page, `${basePath.slice(1)}-mobile-quick-open-500`);
|
||||||
|
await page.keyboard.press('Escape');
|
||||||
await persistArtifact(page, `${basePath.slice(1)}-mobile-500`);
|
await persistArtifact(page, `${basePath.slice(1)}-mobile-500`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -66,21 +66,33 @@ const onQuick = (item: QuickNavigationItem) => {
|
|||||||
@navigate="close()"
|
@navigate="close()"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
<template v-else>
|
<template v-else-if="entry.kind === 'group'">
|
||||||
<li class="bottom-heading" role="presentation">
|
<li class="bottom-heading" role="presentation">
|
||||||
{{ entry.kind === 'group' ? entry.label : entry.main.label }}
|
{{ entry.label }}
|
||||||
</li>
|
</li>
|
||||||
<template v-if="entry.kind === 'split'">
|
<template v-for="item in entry.items" :key="item.id">
|
||||||
<li role="none">
|
<li v-if="item.kind === 'divider'" class="bottom-divider" role="separator"></li>
|
||||||
|
<li v-else role="none">
|
||||||
<MainNavigationLink
|
<MainNavigationLink
|
||||||
:link="entry.main"
|
:link="item"
|
||||||
:enabled="isNavigationConfigured(entry.main)"
|
:enabled="isNavigationConfigured(item)"
|
||||||
compact
|
compact
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
@navigate="close()"
|
@navigate="close()"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="entry.kind === 'split'">
|
||||||
|
<li role="none">
|
||||||
|
<MainNavigationLink
|
||||||
|
:link="entry.main"
|
||||||
|
:enabled="isNavigationConfigured(entry.main)"
|
||||||
|
compact
|
||||||
|
role="menuitem"
|
||||||
|
@navigate="close()"
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
<template v-for="item in entry.items" :key="item.id">
|
<template v-for="item in entry.items" :key="item.id">
|
||||||
<li v-if="item.kind === 'divider'" class="bottom-divider" role="separator"></li>
|
<li v-if="item.kind === 'divider'" class="bottom-divider" role="separator"></li>
|
||||||
<li v-else role="none">
|
<li v-else role="none">
|
||||||
@@ -123,15 +135,6 @@ const onQuick = (item: QuickNavigationItem) => {
|
|||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
<template v-else-if="entry.kind === 'split'">
|
<template v-else-if="entry.kind === 'split'">
|
||||||
<li role="none">
|
|
||||||
<MainNavigationLink
|
|
||||||
:link="entry.main"
|
|
||||||
:enabled="isNationNavigationEnabled(entry.main, access)"
|
|
||||||
compact
|
|
||||||
role="menuitem"
|
|
||||||
@navigate="close()"
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
<li v-for="item in entry.items" :key="item.id" role="none">
|
<li v-for="item in entry.items" :key="item.id" role="none">
|
||||||
<template v-if="item.kind === 'link'">
|
<template v-if="item.kind === 'link'">
|
||||||
<MainNavigationLink
|
<MainNavigationLink
|
||||||
@@ -162,7 +165,10 @@ const onQuick = (item: QuickNavigationItem) => {
|
|||||||
</button>
|
</button>
|
||||||
<ul v-show="openId === 'quick'" id="mobile-quick-menu" class="bottom-popup" role="menu">
|
<ul v-show="openId === 'quick'" id="mobile-quick-menu" class="bottom-popup" role="menu">
|
||||||
<template v-for="item in quickNavigation" :key="item.id">
|
<template v-for="item in quickNavigation" :key="item.id">
|
||||||
<li v-if="'kind' in item" class="bottom-divider" role="separator"></li>
|
<template v-if="'kind' in item">
|
||||||
|
<li class="bottom-heading" role="presentation">{{ item.label }}</li>
|
||||||
|
<li class="bottom-divider" role="separator"></li>
|
||||||
|
</template>
|
||||||
<li v-else role="none">
|
<li v-else role="none">
|
||||||
<button
|
<button
|
||||||
class="quick-link"
|
class="quick-link"
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export type MainNavigationLink = {
|
|||||||
export interface MainNavigationDivider {
|
export interface MainNavigationDivider {
|
||||||
kind: 'divider';
|
kind: 'divider';
|
||||||
id: string;
|
id: string;
|
||||||
|
label?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MainNavigationGroup {
|
export interface MainNavigationGroup {
|
||||||
@@ -317,18 +318,18 @@ export const nationNavigation: MainNavigationEntry[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const quickNavigation: Array<QuickNavigationItem | MainNavigationDivider> = [
|
export const quickNavigation: Array<QuickNavigationItem | MainNavigationDivider> = [
|
||||||
{ kind: 'divider', id: 'quick-nation-heading' },
|
{ kind: 'divider', id: 'quick-nation-heading', label: '국가 정보' },
|
||||||
{ id: 'policy', label: '방침', tab: 'map', selector: '[data-main-target="policy"]' },
|
{ id: 'policy', label: '방침', tab: 'map', selector: '[data-main-target="policy"]' },
|
||||||
{ id: 'commands', label: '명령', tab: 'commands', selector: '[data-main-target="commands"]' },
|
{ id: 'commands', label: '명령', tab: 'commands', selector: '[data-main-target="commands"]' },
|
||||||
{ id: 'nation', label: '국가', tab: 'status', selector: '[data-main-target="nation"]' },
|
{ id: 'nation', label: '국가', tab: 'status', selector: '[data-main-target="nation"]' },
|
||||||
{ id: 'general', label: '장수', tab: 'status', selector: '[data-main-target="general"]' },
|
{ id: 'general', label: '장수', tab: 'status', selector: '[data-main-target="general"]' },
|
||||||
{ id: 'city', label: '도시', tab: 'status', selector: '[data-main-target="city"]' },
|
{ id: 'city', label: '도시', tab: 'status', selector: '[data-main-target="city"]' },
|
||||||
{ kind: 'divider', id: 'quick-record-heading' },
|
{ kind: 'divider', id: 'quick-record-heading', label: '동향 정보' },
|
||||||
{ id: 'map', label: '지도', tab: 'map', selector: '[data-main-target="map"]' },
|
{ id: 'map', label: '지도', tab: 'map', selector: '[data-main-target="map"]' },
|
||||||
{ id: 'global-records', label: '동향', tab: 'world', selector: '[data-main-target="global-records"]' },
|
{ id: 'global-records', label: '동향', tab: 'world', selector: '[data-main-target="global-records"]' },
|
||||||
{ id: 'general-records', label: '개인', tab: 'world', selector: '[data-main-target="general-records"]' },
|
{ id: 'general-records', label: '개인', tab: 'world', selector: '[data-main-target="general-records"]' },
|
||||||
{ id: 'world-history', label: '정세', tab: 'world', selector: '[data-main-target="world-history"]' },
|
{ id: 'world-history', label: '정세', tab: 'world', selector: '[data-main-target="world-history"]' },
|
||||||
{ kind: 'divider', id: 'quick-message-heading' },
|
{ kind: 'divider', id: 'quick-message-heading', label: '메시지' },
|
||||||
{ id: 'public-message', label: '전체', tab: 'messages', selector: '[data-message-type="public"]' },
|
{ id: 'public-message', label: '전체', tab: 'messages', selector: '[data-message-type="public"]' },
|
||||||
{ id: 'national-message', label: '국가', tab: 'messages', selector: '[data-message-type="national"]' },
|
{ id: 'national-message', label: '국가', tab: 'messages', selector: '[data-message-type="national"]' },
|
||||||
{ id: 'private-message', label: '개인', tab: 'messages', selector: '[data-message-type="private"]' },
|
{ id: 'private-message', label: '개인', tab: 'messages', selector: '[data-message-type="private"]' },
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ watch(
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<main class="game-shell main-page">
|
<main class="game-shell main-page">
|
||||||
<MainGlobalMenu :npc-mode="npcMode" :vote-active="voteActive" />
|
<MainGlobalMenu data-menu-position="top" :npc-mode="npcMode" :vote-active="voteActive" />
|
||||||
|
|
||||||
<header class="game-shell__header">
|
<header class="game-shell__header">
|
||||||
<div>
|
<div>
|
||||||
@@ -280,6 +280,13 @@ watch(
|
|||||||
</RecordPanel>
|
</RecordPanel>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<MainGlobalMenu
|
||||||
|
class="common-menu-middle"
|
||||||
|
data-menu-position="middle"
|
||||||
|
:npc-mode="npcMode"
|
||||||
|
:vote-active="voteActive"
|
||||||
|
/>
|
||||||
|
|
||||||
<div v-if="mobileTab === 'messages'" class="mobile-panel">
|
<div v-if="mobileTab === 'messages'" class="mobile-panel">
|
||||||
<MessagePanel
|
<MessagePanel
|
||||||
class="mobile-message-panel"
|
class="mobile-message-panel"
|
||||||
@@ -383,6 +390,12 @@ watch(
|
|||||||
</div>
|
</div>
|
||||||
</RecordPanel>
|
</RecordPanel>
|
||||||
</section>
|
</section>
|
||||||
|
<MainGlobalMenu
|
||||||
|
class="common-menu-middle"
|
||||||
|
data-menu-position="middle"
|
||||||
|
:npc-mode="npcMode"
|
||||||
|
:vote-active="voteActive"
|
||||||
|
/>
|
||||||
<MessagePanel
|
<MessagePanel
|
||||||
class="desktop-message-panel"
|
class="desktop-message-panel"
|
||||||
:messages="messages"
|
:messages="messages"
|
||||||
@@ -405,8 +418,12 @@ watch(
|
|||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<MainGlobalMenu class="common-menu-repeat" :npc-mode="npcMode" :vote-active="voteActive" />
|
<MainGlobalMenu
|
||||||
<MainGlobalMenu class="common-menu-repeat" :npc-mode="npcMode" :vote-active="voteActive" />
|
class="common-menu-repeat"
|
||||||
|
data-menu-position="bottom"
|
||||||
|
:npc-mode="npcMode"
|
||||||
|
:vote-active="voteActive"
|
||||||
|
/>
|
||||||
|
|
||||||
<MainMobileBottomBar
|
<MainMobileBottomBar
|
||||||
:access="nationAccess"
|
:access="nationAccess"
|
||||||
@@ -515,6 +532,10 @@ button {
|
|||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.common-menu-middle {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
.record-zone {
|
.record-zone {
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
Reference in New Issue
Block a user