merge: 최신 main을 토너먼트 새 창 닫기에 통합한다

This commit is contained in:
2026-08-22 05:00:50 +00:00
15 changed files with 789 additions and 782 deletions
@@ -4,9 +4,9 @@ import { legacyNationTextColor } from '../../utils/legacyNationColor';
import MainNavigationLink from './MainNavigationLink.vue';
import {
buildGlobalNavigation,
buildNationNavigation,
isNationNavigationEnabled,
isNavigationConfigured,
nationNavigation,
quickNavigation,
type MainNavigationLink as MainNavigationLinkItem,
type MainNavigationEntry,
@@ -18,6 +18,7 @@ import { useMenuPopup } from './useMenuPopup';
const props = defineProps<{
access: NationNavigationAccess;
tournamentStage: number;
tournamentType: number | null;
nationColor: string;
npcMode: number;
realtimeEnabled: boolean;
@@ -35,9 +36,12 @@ const emit = defineEmits<{
const { setRoot, openId, close, toggle } = useMenuPopup();
const globalEntries = computed(() => buildGlobalNavigation(props.npcMode, props.entries));
const nationEntries = computed(() => buildNationNavigation(props.tournamentStage, props.tournamentType));
const nationMenuColor = computed(() => props.nationColor || '#000000');
const nationMenuTextColor = computed(() => legacyNationTextColor(nationMenuColor.value));
const isActive = (link: MainNavigationLinkItem) => link.highlightStage === props.tournamentStage;
const isActive = (link: MainNavigationLinkItem) =>
link.highlightStage === props.tournamentStage ||
link.highlightStages?.some((stage) => stage === props.tournamentStage) === true;
const onQuick = (item: QuickNavigationItem) => {
close();
@@ -148,7 +152,7 @@ const onAction = (action: NonNullable<MainNavigationLinkItem['action']>) => {
<span class="dropup-caret" aria-hidden="true"></span>
</button>
<ul v-if="openId === 'nation'" id="mobile-nation-menu" class="bottom-popup" role="menu">
<template v-for="entry in nationNavigation" :key="entry.id">
<template v-for="entry in nationEntries" :key="entry.id">
<li v-if="entry.kind === 'link'" role="none">
<MainNavigationLink
:link="entry"
@@ -165,6 +169,7 @@ const onAction = (action: NonNullable<MainNavigationLinkItem['action']>) => {
<MainNavigationLink
:link="item"
:enabled="isNationNavigationEnabled(item, access)"
:active="isActive(item)"
compact
role="menuitem"
@navigate="close()"
@@ -1,8 +1,9 @@
<script setup lang="ts">
import { computed } from 'vue';
import MainNavigationLink from './MainNavigationLink.vue';
import {
buildNationNavigation,
isNationNavigationEnabled,
nationNavigation,
type MainNavigationLink as MainNavigationLinkItem,
type NationNavigationAccess,
} from './mainNavigation';
@@ -12,11 +13,15 @@ import { legacyNationTextColor } from '../../utils/legacyNationColor';
const props = defineProps<{
access: NationNavigationAccess;
tournamentStage: number;
tournamentType: number | null;
nationColor: string;
}>();
const { setRoot, openId, close, toggle } = useMenuPopup();
const isActive = (link: MainNavigationLinkItem) => link.highlightStage === props.tournamentStage;
const entries = computed(() => buildNationNavigation(props.tournamentStage, props.tournamentType));
const isActive = (link: MainNavigationLinkItem) =>
link.highlightStage === props.tournamentStage ||
link.highlightStages?.some((stage) => stage === props.tournamentStage) === true;
</script>
<template>
@@ -27,7 +32,7 @@ const isActive = (link: MainNavigationLinkItem) => link.highlightStage === props
:class="{ 'dark-label': legacyNationTextColor(nationColor) === '#000000' }"
aria-label="국가 메뉴"
>
<template v-for="entry in nationNavigation" :key="entry.id">
<template v-for="entry in entries" :key="entry.id">
<MainNavigationLink
v-if="entry.kind === 'link'"
:link="entry"
@@ -59,6 +64,7 @@ const isActive = (link: MainNavigationLinkItem) => link.highlightStage === props
<MainNavigationLink
:link="item"
:enabled="isNationNavigationEnabled(item, access)"
:active="isActive(item)"
role="menuitem"
@navigate="close()"
/>
@@ -4,6 +4,7 @@ import type {
RuntimeNavigationLink,
} from '@sammo-ts/common/navigation/menuConfig';
import defaultNavigationJson from '../../../../../resources/navigation.json';
import { resolveTournamentMainPresentation } from '../../utils/tournamentNavigation';
export type NationAccessRule =
'always' | 'meeting' | 'secret' | 'nation-member' | 'nation-established' | 'nation-secret';
@@ -11,7 +12,8 @@ export type NationAccessRule =
export type MainNavigationLink = RuntimeNavigationLink & {
compactLabel?: string;
access?: NationAccessRule;
highlightStage?: 1 | 6;
highlightStage?: number;
highlightStages?: readonly number[];
unavailableReason?: string;
};
@@ -144,14 +146,37 @@ export const nationNavigation: MainNavigationEntry[] = [
access: 'nation-secret',
},
{
kind: 'link',
id: 'tournament',
label: '토 너 먼 트',
compactLabel: '토너먼트',
to: '/tournament',
newTab: true,
access: 'always',
highlightStage: 1,
kind: 'split',
id: 'tournament-betting',
main: {
kind: 'link',
id: 'tournament',
label: '토 너 먼 트',
compactLabel: '토너먼트',
to: '/tournament',
newTab: true,
access: 'always',
},
items: [
{
kind: 'link',
id: 'tournament-menu',
label: '토너먼트',
to: '/tournament',
newTab: true,
access: 'always',
highlightStage: 1,
},
{
kind: 'link',
id: 'betting',
label: '베팅장',
to: '/betting',
newTab: true,
access: 'always',
highlightStage: 6,
},
],
},
{
kind: 'link',
@@ -218,18 +243,42 @@ export const nationNavigation: MainNavigationEntry[] = [
},
],
},
{
kind: 'link',
id: 'betting',
label: '베 팅 장',
compactLabel: '베팅장',
to: '/betting',
newTab: true,
access: 'always',
highlightStage: 6,
},
{ kind: 'link', id: 'my-settings', label: '화면 설정', to: '/my-settings', access: 'always' },
];
export const buildNationNavigation = (
tournamentStage: number,
tournamentType: number | null,
source: MainNavigationEntry[] = nationNavigation
): MainNavigationEntry[] =>
source.map((entry) => {
if (entry.kind !== 'split' || entry.id !== 'tournament-betting') return entry;
const presentation = resolveTournamentMainPresentation(tournamentStage, tournamentType);
const main: MainNavigationLink = {
...entry.main,
label: presentation.label,
compactLabel: presentation.compactLabel,
to: presentation.to,
highlightStage: presentation.active ? tournamentStage : undefined,
highlightStages: undefined,
};
const items = entry.items.map((item) => {
if (item.kind !== 'link') return item;
if (item.id === 'tournament-menu') {
return {
...item,
highlightStage: presentation.active && !presentation.bettingActive ? tournamentStage : undefined,
};
}
if (item.id === 'betting') {
return { ...item, highlightStage: presentation.bettingActive ? tournamentStage : undefined };
}
return item;
});
return { ...entry, main, items };
});
export const quickNavigation: Array<QuickNavigationItem | MainNavigationDivider> = [
{ kind: 'divider', id: 'quick-nation-heading', label: '국가 정보' },
{ id: 'policy', label: '방침', tab: 'map', selector: '[data-main-target="policy"]' },
@@ -249,7 +298,8 @@ export const quickNavigation: Array<QuickNavigationItem | MainNavigationDivider>
{ id: 'diplomacy-message', label: '외교', tab: 'messages', selector: '[data-message-type="diplomacy"]' },
];
export const isNavigationConfigured = (link: MainNavigationLink): boolean => Boolean(link.to || link.href || link.action);
export const isNavigationConfigured = (link: MainNavigationLink): boolean =>
Boolean(link.to || link.href || link.action);
export const isNationNavigationEnabled = (link: MainNavigationLink, access: NationNavigationAccess): boolean => {
const rule = link.access ?? 'always';