From 42906c3ab53d71f293f90a1e99a8d23af65125d8 Mon Sep 17 00:00:00 2001 From: hided62 Date: Thu, 27 Aug 2026 07:23:13 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=ED=84=B4=20=EC=9E=85=EB=A0=A5=EA=B8=B0?= =?UTF-8?q?=20=EB=B6=88=EA=B0=80=20=EB=AA=85=EB=A0=B9=20=EA=B5=AC=EB=B6=84?= =?UTF-8?q?=20=EA=B0=95=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ref와 같이 현재 실행할 수 없는 명령 이름을 적색 취소선으로 표시한다. 예약 가능 상태와 desktop/mobile Chromium 회귀 검증은 유지한다. --- app/game-frontend/e2e/mainNavigation.spec.ts | 39 +++++++++++++++++++ .../src/components/main/CommandSelectForm.vue | 6 +++ 2 files changed, 45 insertions(+) diff --git a/app/game-frontend/e2e/mainNavigation.spec.ts b/app/game-frontend/e2e/mainNavigation.spec.ts index e2e9206f..cbb375b7 100644 --- a/app/game-frontend/e2e/mainNavigation.spec.ts +++ b/app/game-frontend/e2e/mainNavigation.spec.ts @@ -2412,6 +2412,45 @@ test('main reserved-turn picker renders the Ref category order and raised button await persistArtifact(page, `${basePath.slice(1)}-main-reserved-ref-categories-mobile-500`); }); +test('main reserved-turn picker marks currently unavailable commands like Ref', async ({ page }) => { + const state: NavigationFixture = { + officerLevel: 1, + permission: 0, + nationLevel: 1, + stage: 0, + npcMode: 1, + generalMeCalls: 0, + operations: [], + largeCommandTable: true, + commandBlockedCount: 1, + reservedTurns: Array.from({ length: 30 }, (_, index) => ({ index, action: '휴식', args: {} })), + }; + await installFixture(page, state); + + for (const viewport of [ + { name: 'desktop-1200', width: 1200, height: 900 }, + { name: 'mobile-500', width: 500, height: 900 }, + ]) { + await page.setViewportSize({ width: viewport.width, height: viewport.height }); + await waitForMain(page); + await page.getByRole('button', { name: '1턴 명령 입력', exact: true }).click(); + + const picker = page.getByTestId('command-picker'); + const blockedCommand = picker.getByRole('button', { name: '주민 선정과 장기 도시 개발', exact: true }); + const blockedName = blockedCommand.locator('.command-name'); + await expect(blockedCommand).toBeEnabled(); + await expect(blockedCommand).toHaveClass(/blocked/); + await expect(blockedCommand).toHaveClass(/reservable/); + await expect(blockedName).toHaveCSS('color', 'rgb(231, 76, 60)'); + await expect(blockedName).toHaveCSS('text-decoration-line', 'line-through'); + await expect(blockedName).toHaveCSS('text-decoration-color', 'rgb(231, 76, 60)'); + expect(await picker.evaluate((element) => element.scrollWidth - element.clientWidth)).toBeLessThanOrEqual(0); + await picker.screenshot({ path: test.info().outputPath(`blocked-command-${viewport.name}.png`) }); + + await page.getByRole('button', { name: '명령 입력 닫기', exact: true }).click(); + } +}); + test('main cards and command input stay inside their Ref-sized grid slots', async ({ page }) => { const state: NavigationFixture = { officerLevel: 1, diff --git a/app/game-frontend/src/components/main/CommandSelectForm.vue b/app/game-frontend/src/components/main/CommandSelectForm.vue index 6691dca0..86ee6df5 100644 --- a/app/game-frontend/src/components/main/CommandSelectForm.vue +++ b/app/game-frontend/src/components/main/CommandSelectForm.vue @@ -237,6 +237,12 @@ const commandTitle = (command: CommandAvailability) => cursor: pointer; } +.command-item.blocked .command-name { + color: #e74c3c; + text-decoration-line: line-through; + text-decoration-color: #e74c3c; +} + .command-name { font-weight: 600; }