From e9c559c001c5ee173eb052fe73698598e29d28ab Mon Sep 17 00:00:00 2001 From: truetype Date: Sun, 28 Jun 2026 23:35:36 +0200 Subject: [PATCH] feat(ui): mappa aree nella sidebar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Aggiunto current_area_id allo stato WS - Mappa ordinata per ID area (1.1-1.9) - Area corrente evidenziata con ✧ e bordo dorato - Aree visitate con pallino pieno, non visitate vuoto - Connessioni mostrate con nomi (non ID) - CSS rinnovato per area-item --- src/web/server.py | 2 ++ src/web/static/index.html | 64 +++++++++++++++++++++++++++++++-------- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/web/server.py b/src/web/server.py index 4d7a690..71205eb 100644 --- a/src/web/server.py +++ b/src/web/server.py @@ -230,6 +230,8 @@ def _build_state(campaign_id: int) -> dict: "characters": ctx.characters, "quests": ctx.quests, "areas": enriched, + "current_area_id": ctx.current_area_id, + "current_area_name": ctx.current_area_name, } diff --git a/src/web/static/index.html b/src/web/static/index.html index 45338c6..538a074 100644 --- a/src/web/static/index.html +++ b/src/web/static/index.html @@ -236,24 +236,52 @@ html, body { /* Area map */ .area-item { display: flex; - align-items: center; - gap: 8px; - padding: 4px 0; + flex-wrap: wrap; + align-items: baseline; + gap: 4px 6px; + padding: 5px 6px; font-size: 13px; color: var(--text-muted); + border-left: 2px solid transparent; + transition: border-color 0.2s, background 0.2s; +} +.area-item.visited { color: var(--text-secondary); } +.area-item.current { + color: var(--gold-bright); + border-left-color: var(--gold); + background: rgba(201,168,76,0.06); } -.area-item.visited { color: var(--text-primary); } .area-marker { width: 6px; height: 6px; border-radius: 50%; background: var(--text-muted); flex-shrink: 0; + margin-top: 5px; +} +.area-item.visited .area-marker { background: var(--text-secondary); } +.area-item.current .area-marker { background: var(--gold); box-shadow: 0 0 6px var(--gold); } +.area-id { + font-family: var(--font-display); + font-size: 10px; + color: var(--gold-dim); + min-width: 24px; + font-weight: 700; +} +.area-name { + flex: 1; + font-size: 13px; +} +.area-here { + font-size: 12px; + color: var(--gold); + margin-left: auto; } -.area-item.visited .area-marker { background: var(--gold); box-shadow: 0 0 4px var(--gold); } .area-conns { + width: 100%; font-size: 11px; color: var(--text-muted); - margin-left: 14px; + padding-left: 36px; + opacity: 0.7; } /* Zone vuote */ @@ -592,6 +620,7 @@ let campaignId = null; let ws = null; let turn = 0; let reconnectTimer = null; +let currentAreaId = ''; let state = { characters: [], quests: [], areas: [] }; const HOST = window.location.host; @@ -773,6 +802,7 @@ function applyState(s) { turn = s.turn; turnCounter.textContent = turn; } + if (s.current_area_id) currentAreaId = s.current_area_id; renderChar(s.characters); renderQuests(s.quests); renderAreas(s.areas); @@ -832,13 +862,21 @@ function renderAreas(areas) { areaDisplay.innerHTML = '
Nessuna area
'; return; } - areaDisplay.innerHTML = areas.map(a => ` -
- - ${escapeHtml(a.name)} -
- ${a.connections && a.connections.length ? `
→ ${a.connections.join(', ')}
` : ''} - `).join(''); + // Sort by area id (1.1, 1.2, ..., 1.9) + const sorted = [...areas].sort((a, b) => (a.id || '').localeCompare(b.id || '')); + areaDisplay.innerHTML = sorted.map(a => { + const isCurrent = a.id === currentAreaId; + const status = isCurrent ? 'current' : (a.visited ? 'visited' : 'unvisited'); + const conns = (a.connections || []).join(' → '); + return ` +
+ + ${escapeHtml(a.id)} + ${escapeHtml(a.name)} + ${isCurrent ? '✧' : ''} + ${conns ? `
→ ${escapeHtml(conns)}
` : ''} +
`; + }).join(''); } // ================================================================