From 2d36685ca043e7a9b912f03991ef13e4b23d8c06 Mon Sep 17 00:00:00 2001 From: Adrien Jaguenet Date: Tue, 22 Sep 2026 23:51:48 +0200 Subject: [PATCH] Moved tile works into a management panel and put every building on one card MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The city buildings tab and the HUD's tile panel now draw the same card: an icon, name and status, a bottom-anchored button carrying the estimated price and build time, a quiet remove control and a hatched locked state, with the produce/consume/cost detail in a hover tooltip. The shared card lives in client/js/ui/card.js. The tile dock is now a summary — description, production, people and their ethnic makeup, GDP and the improvements list — with a Management button that opens a full-size panel like the city and nation panels. Its Improvements tab holds the grouped Military, Transportation and Economic cards, so Road and Railway sit with the other works. City buildings sit in a two-row horizontal scroller with the built ones first, and the city panel now matches the nation panel's size. AGENTS.md now asks for a minimal visual preview to be shown before a player-visible change is committed. --- AGENTS.md | 11 + client/css/style.css | 187 ++++++++++++--- client/index.html | 22 +- client/js/devlog_data.js | 12 +- client/js/game_screen.js | 4 +- client/js/game_screen/panels.js | 387 +++++++++++++++----------------- client/js/modals.js | 1 + client/js/modals/city.js | 170 ++++++++------ client/js/modals/tile.js | 53 +++++ client/js/ui/card.js | 149 ++++++++++++ tests/game_screen_test.js | 82 ++++--- tests/modals_test.js | 24 +- 12 files changed, 741 insertions(+), 361 deletions(-) create mode 100644 client/js/modals/tile.js create mode 100644 client/js/ui/card.js diff --git a/AGENTS.md b/AGENTS.md index 78a286c..4013936 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,6 +26,17 @@ everything else (transport included) is hand-written. There is no linter, formatter, or CI. Do not invent commands beyond these. +### Visual changes + +- A change that alters what the player sees is reviewed by eye before it is + committed. Build a **minimal standalone HTML example** of the change first — + the isolated element and each of its states, not a whole mocked-up screen — + open it in a browser and show it to the user. Only commit once the user has + seen and approved the preview. +- Keep the examples small and self-contained: link the stylesheet and copy in + the few assets they need. A short gallery of one small example per visual + change is the right size. Do not add the examples to the repository. + ### Local testing mode - The server creates its game at startup; add `--testing` to diff --git a/client/css/style.css b/client/css/style.css index 675205c..998cb23 100644 --- a/client/css/style.css +++ b/client/css/style.css @@ -867,13 +867,8 @@ input:focus, select:focus { border-color: var(--accent); } padding: 12px 18px; } -/* Tile improvements, grouped under a category heading. */ -.tile-improvement-actions { - display: flex; - flex-direction: column; - gap: 8px; - margin-top: 8px; -} +/* Tile improvements, grouped under a category heading, in the management + panel. */ .improvement-group { display: flex; flex-direction: column; gap: 4px; } .improvement-category { font-size: 10px; @@ -885,30 +880,145 @@ input:focus, select:focus { border-color: var(--accent); } .improvement-btn { font-size: 12px; } .improvement-btn.current { opacity: 0.6; } .improvement-btn.remove { border-color: rgba(242, 114, 114, 0.6); } -/* Buildable improvements are square icons with the cost written beneath. */ -.improvement-icon-btn { - display: flex; - flex-direction: column; - align-items: center; - gap: 2px; - width: 64px; - padding: 5px 4px; -} -.improvement-icon { width: 40px; height: 40px; display: block; } -.improvement-cost { - display: flex; - flex-wrap: wrap; - justify-content: center; - align-items: center; - gap: 0 3px; - font-size: 10px; - color: var(--muted); - font-variant-numeric: tabular-nums; -} .cost-res { display: inline-flex; align-items: center; gap: 2px; } .cost-icon { width: 12px; height: 12px; vertical-align: middle; } .cost-money { color: var(--muted); } +/* The building and improvement card: icon, name and status up top, a + bottom-anchored action button carrying the estimated price and build time, + and a quiet remove control. What the work produces, consumes and costs is in + the hover tooltip so the card itself stays bare. Shared by the city + buildings tab and the HUD's tile improvement panel. */ +.building-scroller { overflow-x: auto; overflow-y: hidden; padding-bottom: 8px; } +.building-grid { + display: grid; + grid-template-rows: repeat(2, auto); + grid-auto-flow: column; + grid-auto-columns: 178px; + gap: 8px; + width: max-content; +} +.building-tile { + position: relative; + display: flex; + flex-direction: column; + gap: 4px; + width: 178px; + padding: 9px; + border-radius: 9px; + border: 1px solid rgba(150, 190, 240, 0.35); + background: linear-gradient(180deg, rgba(90, 130, 190, 0.3), rgba(35, 55, 90, 0.55)); +} +.building-tile:hover { filter: brightness(1.15); } +.building-tile.built { border-color: rgba(143, 227, 168, 0.6); } +.building-tile.locked { opacity: 0.6; filter: none; } +/* An unavailable work is hatched, so a locked card reads at a glance. */ +.building-tile.locked::after { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; + pointer-events: none; + background: repeating-linear-gradient( + 45deg, + rgba(255, 255, 255, 0.14) 0 2px, + transparent 2px 8px + ); +} +.bt-top { display: flex; align-items: center; gap: 8px; padding-right: 16px; } +.bt-top .building-icon { width: 34px; height: 34px; flex: 0 0 auto; opacity: 0.95; } +.bt-id { min-width: 0; } +.building-tile .bt-name { font-weight: 600; font-size: 12.5px; line-height: 1.15; } +.building-tile .bt-level { font-size: 10.5px; color: var(--muted); } +.building-tile .bt-level.built { color: #8fe3a8; } +.building-tile .bt-upgrade { + display: flex; + justify-content: space-between; + align-items: baseline; + gap: 6px; + width: 100%; + margin-top: auto; + padding: 4px 8px; + font-size: 11.5px; + text-align: left; +} +.building-tile .bt-up-label { font-weight: 600; } +.building-tile .bt-meta { + font-size: 10px; + font-weight: 400; + color: var(--muted); + font-variant-numeric: tabular-nums; + white-space: nowrap; +} +/* The money is an estimate, so it is italic and marked with a tilde. */ +.building-tile .bt-price { font-style: italic; } +.building-tile .bt-free { width: 100%; font-size: 10.5px; padding: 3px 6px; } +.building-tile .bt-downgrade { + position: absolute; + top: 5px; + right: 5px; + display: flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + padding: 0; + line-height: 1; + font-size: 11px; + border-radius: 6px; + background: transparent; + border: 1px solid transparent; + color: var(--muted); + opacity: 0.6; +} +.building-tile .bt-downgrade:hover:not(:disabled) { + opacity: 1; + color: #ff9a9a; + background: rgba(255, 255, 255, 0.06); + border-color: rgba(242, 114, 114, 0.5); +} +.building-tile .bt-downgrade:disabled { opacity: 0.2; } + +/* The card's hover tooltip. Fixed to the body so a scrolling card list never + clips it. */ +.card-tooltip { + position: fixed; + z-index: 1000; + pointer-events: none; + max-width: 300px; + padding: 8px 10px; + border-radius: 9px; + background: var(--panel-bg); + border: 1px solid var(--panel-border); + box-shadow: 0 16px 40px rgba(0, 0, 0, 0.7); + font-size: 11.5px; + color: var(--text); +} +.card-tooltip .tip-section + .tip-section { + margin-top: 6px; + border-top: 1px solid rgba(255, 255, 255, 0.08); + padding-top: 6px; +} +.card-tooltip .tip-head { + font-size: 9.5px; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--muted); + margin-bottom: 2px; +} +.card-tooltip .tip-line { + display: flex; + align-items: center; + gap: 4px; + font-variant-numeric: tabular-nums; +} +.card-tooltip .tip-produce { color: #8fe3a8; } +.card-tooltip .tip-consume, +.card-tooltip .tip-cost { color: #e2c08a; } +.card-tooltip .tip-none { color: var(--muted); } +.card-tooltip .res { display: inline-flex; align-items: center; gap: 3px; } +.card-tooltip .res img { width: 13px; height: 13px; } + /* The tile panel leads with what the tile actually produces. */ #tile-production { margin: 4px 0 6px; display: flex; flex-direction: column; gap: 2px; } .tile-prod-row { @@ -1153,7 +1263,8 @@ input:focus, select:focus { border-color: var(--accent); } instead of covering it, so the approval figure stays in view while they are open. The 104px clears the summary's 12px offset plus its padded height. */ #modal-city, -#modal-nation { +#modal-nation, +#modal-tile { align-items: flex-start; padding: 104px 16px 16px; } @@ -1555,15 +1666,17 @@ input:focus, select:focus { border-color: var(--accent); } .training-queue .queue-row { padding: 8px 12px; } .training-queue .queue-row .actions .aero { min-width: 110px; } -/* The city modal keeps a fixed size whatever tab is open, so switching between - train, buildings, people and budget never resizes the card. The unit buttons - sit in a fixed-height box that scrolls when there are more units than fit; - the queue below is the flexible part and scrolls too, so adding units never - stretches the card or pushes the buttons out of reach. */ -#modal-city .modal-card { - width: 680px; - max-width: calc(100vw - 32px); - height: min(80vh, 740px); +/* The city and tile panels keep a fixed size whatever tab is open, so switching + between train, buildings, people and budget never resizes the card. They match + the nation panel so the three read as the same surface. The unit buttons sit in + a fixed-height box that scrolls when there are more units than fit; the queue + below is the flexible part and scrolls too, so adding units never stretches + the card or pushes the buttons out of reach. */ +#modal-city .modal-card, +#modal-tile .modal-card { + width: 90vw; + max-width: 1600px; + height: min(80vh, 900px); max-height: calc(100vh - 120px); } #modal-city #city-train-list { diff --git a/client/index.html b/client/index.html index d6ba568..c2e87dc 100644 --- a/client/index.html +++ b/client/index.html @@ -151,7 +151,9 @@
-
+
+ +
+ + +