Reworked the tile panel header and collapsed the GDP/capita modifiers

This commit is contained in:
2026-09-19 00:43:32 +02:00
parent 8a7db56b59
commit aa2a8f6e69
4 changed files with 88 additions and 19 deletions
+7
View File
@@ -479,6 +479,12 @@ input:focus, select:focus { border-color: var(--accent); }
}
.info-section.hidden { display: none !important; }
.info-title { font-size: 17px; font-weight: 600; margin-bottom: 4px; }
.tile-coords { font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; margin-bottom: 2px; }
.tile-gdp-head { font-size: 13px; font-variant-numeric: tabular-nums; }
.tile-gdp-toggle { cursor: pointer; }
.tile-gdp-toggle:hover { color: #fff; }
.tile-gdp-caret { margin-left: 6px; color: var(--muted); font-size: 11px; }
.tile-gdp-mods { margin-top: 2px; }
.tile-gdp-mod { font-size: 12px; color: var(--muted); padding-left: 12px; font-variant-numeric: tabular-nums; }
#bottom-panel .row { justify-content: flex-start; margin-top: 10px; }
.health-row { display: flex; align-items: center; gap: 8px; }
@@ -933,6 +939,7 @@ input:focus, select:focus { border-color: var(--accent); }
.trend-up { color: #6ee787; }
.trend-down { color: #f27272; }
#tile-ethnicity { margin-top: 6px; }
#tile-ethnicity .tile-population { font-size: 13px; font-variant-numeric: tabular-nums; }
#tile-ethnicity .ethnic-chart { margin-top: 4px; gap: 10px; }
#tile-ethnicity .ethnic-legend { font-size: 12px; }
.politics-row-actions { display: flex; justify-content: flex-end; margin-top: 4px; }
+2 -4
View File
@@ -135,10 +135,8 @@
<div id="bottom-panel" class="panel hidden">
<div id="tile-info" class="info-section hidden">
<div id="tile-coords" class="info-title"></div>
<div id="tile-owner"></div>
<div id="tile-terrain"></div>
<div id="tile-population"></div>
<div id="tile-desc" class="info-title"></div>
<div id="tile-coords" class="tile-coords"></div>
<div id="tile-ethnicity"></div>
<div id="tile-gdp"></div>
<div id="tile-improvements"></div>
+1
View File
@@ -32,6 +32,7 @@ export class GameScreen {
this._tileBattleGdpDeficits = new Map();
this._territoryOwner = new Map();
this._tileRegion = new Map();
this._gdpExpanded = false;
this._battles = new Set();
this._researched = new Set();
this._wars = new Set();
+78 -15
View File
@@ -574,16 +574,16 @@ export const panelMethods = {
_renderTileInfo(coords) {
const k = `${coords.x},${coords.y}`;
const owner = this._territoryOwner.has(k) ? this._territoryOwner.get(k) : -1;
const civ = this.civilisations[owner];
const tile = this.map.getTile(coords);
const city = (this.snapshot.cities || []).find(
(c) => c.coords[0] === coords.x && c.coords[1] === coords.y
);
const regionCity = (this.snapshot.cities || []).find(
(c) => c.id === this._tileRegion.get(k)
);
$("#tile-desc").text(this._tileDescription(coords, owner, tile, regionCity));
$("#tile-coords").text(`Tile (${coords.x}, ${coords.y})`);
$("#tile-owner").text(`Owner: ${civ ? civ.name : "Unclaimed"}`);
$("#tile-terrain").text(`Terrain: ${tile ? tile.terrainType : "Unknown"}`);
$("#tile-population").text(`Population: ${groupDigits(this._population.get(k) || 0)}`);
this._renderTileEthnicity(k);
this._renderTilePeople(k);
this._renderTileGdp(owner >= 0 ? this._tileGdpBreakdown(coords, owner, city, tile) : null);
const roads = this.map.roads && this.map.roads.has(k) ? [ROADS.improvementName] : [];
const improvements = city
@@ -592,15 +592,61 @@ export const panelMethods = {
$("#tile-improvements").text(`Improvements: ${fmtImprovements(improvements)}`);
},
// The tile's people, by ethnicity, as a small donut plus a legend with head
// counts and last-day migration arrows.
_renderTileEthnicity(k) {
// A short, readable label for the tile: its owner's demonym, the terrain and
// where it sits relative to the city whose region claims it.
_tileDescription(coords, owner, tile, regionCity) {
const civ = owner >= 0 ? this.civilisations[owner] : null;
const terrain = tile ? tile.terrainType.toLowerCase() : "unknown terrain";
const parts = [];
if (civ) parts.push(civ.demonym || civ.name);
parts.push(terrain);
if (regionCity) {
const sameTile =
regionCity.coords[0] === coords.x && regionCity.coords[1] === coords.y;
if (sameTile) {
parts.push(`around ${regionCity.name}`);
} else {
const direction = this._compassDirection(
{ x: regionCity.coords[0], y: regionCity.coords[1] },
coords
);
if (direction) parts.push(`${direction} of ${regionCity.name}`);
}
}
const text = parts.join(" ");
return text.charAt(0).toUpperCase() + text.slice(1);
},
// The eight-point compass direction from `origin` to `coords`, measured in
// screen space so the label matches what the player sees on the map.
_compassDirection(origin, coords) {
const topology = this.map.topology;
if (!topology) return "";
const delta = topology.pixelDelta(origin, coords);
if (delta.x === 0 && delta.y === 0) return "";
const names = [
"east", "southeast", "south", "southwest",
"west", "northwest", "north", "northeast",
];
const index = Math.round(Math.atan2(delta.y, delta.x) / (Math.PI / 4));
return names[((index % 8) + 8) % 8];
},
// The tile's people: the head count up top, then a small donut and legend of
// its ethnicities with last-day migration arrows.
_renderTilePeople(k) {
const $container = $("#tile-ethnicity");
if (!$container || !$container.length) return;
$container.empty();
const population = this._population.get(k) || 0;
$container.append($("<div class='info-title'></div>").text("People"));
$container.append(
$("<div class='tile-population'></div>").text(
`Population: ${groupDigits(population)}`
)
);
const entries = this._tileEthnicity.get(k) || [];
if (entries.length === 0) return;
const population = this._population.get(k) || 0;
const makeup = entries
.map(([ethnicity, share, trend]) => ({
ethnicity,
@@ -609,7 +655,6 @@ export const panelMethods = {
trend,
}))
.sort((a, b) => b.count - a.count);
$container.append($("<div class='info-title'></div>").text("People"));
$container.append(ethnicityChart(makeup, this.civilisations, 104));
},
@@ -693,12 +738,12 @@ export const panelMethods = {
$container.text("GDP/capita: —");
return;
}
$container.append(
$("<div></div>").text(`GDP/capita: €${groupDigits(Math.round(breakdown.total))}`)
);
$container.append(
const $mods = $("<div class='tile-gdp-mods'></div>");
if (!this._gdpExpanded) $mods.addClass("hidden");
$mods.append(
$("<div class='tile-gdp-mod'></div>").text(`Base €${groupDigits(breakdown.base)}`)
);
let modifierCount = 0;
for (const factor of breakdown.factors) {
// A modifier that changes nothing (×1 or ±€0) is left out.
if (factor.amount !== undefined) {
@@ -710,9 +755,27 @@ export const panelMethods = {
factor.amount !== undefined
? `−€${groupDigits(Math.round(Math.abs(factor.amount)))}`
: `×${factor.multiplier.toFixed(2)}`;
$container.append(
$mods.append(
$("<div class='tile-gdp-mod'></div>").text(`${factor.label} ${value}`)
);
modifierCount += 1;
}
const $head = $("<div class='tile-gdp-head'></div>").text(
`GDP/capita: €${groupDigits(Math.round(breakdown.total))}`
);
if (modifierCount > 0) {
$head.addClass("tile-gdp-toggle");
$head.append(
$("<span class='tile-gdp-caret'></span>").text(this._gdpExpanded ? "▾" : "▸")
);
$head.on("click", () => {
this._gdpExpanded = !this._gdpExpanded;
$mods.toggleClass("hidden", !this._gdpExpanded);
$head.find(".tile-gdp-caret").text(this._gdpExpanded ? "▾" : "▸");
});
$container.append($head, $mods);
} else {
$container.append($head);
}
},