feat: complete map and trend frontend flows

This commit is contained in:
2026-07-26 08:39:35 +00:00
parent 8ac1ad4059
commit 477862464e
15 changed files with 645 additions and 36 deletions
@@ -0,0 +1,26 @@
const logRegex = /<([RBGMCLSODYW]1?|1|\/)>/g;
const colorMap: Record<string, string> = {
R: 'red',
B: 'blue',
G: 'green',
M: 'magenta',
C: 'cyan',
L: 'limegreen',
S: 'skyblue',
O: 'orangered',
D: 'orangered',
Y: 'yellow',
W: 'white',
};
export const formatLog = (text: string): string =>
text.replace(logRegex, (_all, tag: string) => {
if (tag === '/') {
return '</span>';
}
const color = colorMap[tag[0] ?? ''];
const small = tag.includes('1');
const styles = [color ? `color: ${color}` : '', small ? 'font-size: 0.9em' : ''].filter(Boolean).join('; ');
return `<span style="${styles}">`;
});
@@ -8,6 +8,7 @@ import MapPreview from '../components/MapPreview.vue';
import DefaultLayout from '../layouts/DefaultLayout.vue';
import { createGameTrpc, type GameRouter } from '../utils/gameTrpc';
import { trpc } from '../utils/trpc';
import { formatLog } from '../utils/formatLog';
type GatewayOutput = inferRouterOutputs<AppRouter>;
type GameOutput = inferRouterOutputs<GameRouter>;
@@ -173,6 +174,11 @@ const handlePasswordReset = async (): Promise<void> => {
<li>유저 {{ info.userCnt }} · NPC {{ info.npcCnt }} · {{ info.nationCnt }} 경쟁중</li>
<li>{{ info.turnTerm }} 서버</li>
</ul>
<div v-if="mapData?.history?.length" class="status-history">
<!-- 레거시 색상 tag만 formatLog가 span으로 변환한다. -->
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-for="entry in mapData.history" :key="entry.id" v-html="formatLog(entry.text)" />
</div>
<button type="button" class="refresh-button" :disabled="statusLoading" @click="loadPublicStatus">
현황 새로고침
</button>
@@ -303,6 +309,15 @@ const handlePasswordReset = async (): Promise<void> => {
background: #000;
}
.status-history {
border-top: 1px solid #444;
padding: 8px 12px;
color: #ddd;
font-family: 'Times New Roman', serif;
font-size: 14px;
line-height: 1.35;
}
.status-card > header {
display: flex;
justify-content: space-between;