diff --git a/DECISIONS.md b/DECISIONS.md index 96e8097..6be833c 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -1059,3 +1059,9 @@ Implementation decisions not spelled out in `memory-bank/implementation-plan.md` - **Game-time spans read "4.3 game h"** so they can't be mistaken for real hours next to a real countdown. - **Reduced motion has two sources**: the OS media query (unless the player turned motion back on) and the player's override. The map keeps moving ships but stills its background. - **Pure helpers read preferences directly** (`displayPreferences()`) where they format strings outside React (the dispatch sheet's problem lines); those re-render every second with the clock anyway. + +## Fix: header on phones (user report during Phase 10K) + +- **User report:** "On a phone screen the credits and time line can't be read" (screenshot at about 430 px): the credits chip was drawn over the DEADHEAD wordmark. The wordmark showed from 420 px, and 10K.2's gear plus 10K.3's device-locale clock ("2145-07-11 7:18 PM") made the right side wider than the space left. +- **Fix:** the wordmark now shows from 640 px (`sm`), the logo side clips instead of overflowing, the game clock shows only the time below 640 px (the date returns above), chips sit a little closer, and the gear is 32 px on phones. The gear icon is now a cog (it read as a sun). +- **Checked** in headless Chrome at 375, 390 and 430 px with a 1,234,567 cr balance and a 12-hour clock: no overlapping header items and no horizontal scroll (`docs/screenshots/header-phone-390.png`). diff --git a/apps/web/src/clock/GameClock.tsx b/apps/web/src/clock/GameClock.tsx index aa7d0c5..3afa0dd 100644 --- a/apps/web/src/clock/GameClock.tsx +++ b/apps/web/src/clock/GameClock.tsx @@ -10,5 +10,12 @@ export { formatGameTime }; export function GameClock() { const now = useClock((state) => state.now); const clock = usePreferences((p) => p.clock); - return ; + const [date, ...time] = formatGameTime(realToGame(now, content.config), clock).split(" "); + // Phones show the time only; the date joins it from 640 px (it no longer fit). + return ( + + ); } diff --git a/apps/web/src/layout/Layout.tsx b/apps/web/src/layout/Layout.tsx index 2a33897..fa9260f 100644 --- a/apps/web/src/layout/Layout.tsx +++ b/apps/web/src/layout/Layout.tsx @@ -28,16 +28,17 @@ export function Layout({ return (
-
+ {/* The wordmark only fits beside the chips from 640 px; on phones the mark alone. */} +
- + DEADHEAD Space Freight
-
+
@@ -53,7 +54,7 @@ export function Layout({ diff --git a/apps/web/src/ui/icons.tsx b/apps/web/src/ui/icons.tsx index 8c4dc54..f7cbbab 100644 --- a/apps/web/src/ui/icons.tsx +++ b/apps/web/src/ui/icons.tsx @@ -82,10 +82,11 @@ const PATHS = { ), close: , + // A cog (outline after Lucide "settings", ISC licence). gear: ( <> + - ), plus: , diff --git a/apps/web/test/clock.test.tsx b/apps/web/test/clock.test.tsx index 4bf1464..3c7636b 100644 --- a/apps/web/test/clock.test.tsx +++ b/apps/web/test/clock.test.tsx @@ -1,6 +1,6 @@ import { content } from "@deadhead/content"; import { realToGame } from "@deadhead/sim"; -import { act, render, screen } from "@testing-library/react"; +import { act, render } from "@testing-library/react"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { ApiClient } from "../src/api/client"; import { serverNow, startClockTicker, syncClock, useClock } from "../src/clock/clock"; @@ -51,14 +51,16 @@ describe("server-synced clock", () => { it("shows the in-game time in the game clock and keeps it ticking", async () => { await syncClock(serverAhead(0)); const stop = startClockTicker(); - render(); + const { container } = render(); + // Date and time are separate spans (the date hides on phones). + const clock = () => container.querySelector("time")!; // The default clock follows the device locale (CR-011). const at = (real: number) => formatGameTime(realToGame(real, content.config), "locale"); - expect(screen.getByText(at(DEVICE_NOW))).toBeInTheDocument(); + expect(clock()).toHaveTextContent(at(DEVICE_NOW)); // One real minute is one game hour. act(() => vi.advanceTimersByTime(60_000)); - expect(screen.getByText(at(DEVICE_NOW + 60_000))).toBeInTheDocument(); + expect(clock()).toHaveTextContent(at(DEVICE_NOW + 60_000)); stop(); }); }); diff --git a/docs/screenshots/header-phone-390.png b/docs/screenshots/header-phone-390.png new file mode 100644 index 0000000..0cf6d90 Binary files /dev/null and b/docs/screenshots/header-phone-390.png differ