feat(ui): mappa aree nella sidebar

- 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
This commit is contained in:
truetype committed 2026-06-28 23:35:36 +02:00
1 parent 7fcc2927c4
commit e9c559c001
2 files changed
+53 -13

No files matched your search

+2
View File
@@ -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,
}
+51 -13
View File
@@ -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 = '<div class="empty-state">Nessuna area</div>';
return;
}
areaDisplay.innerHTML = areas.map(a => `
<div class="area-item ${a.visited ? 'visited' : ''}">
<span class="area-marker"></span>
<span>${escapeHtml(a.name)}</span>
</div>
${a.connections && a.connections.length ? `<div class="area-conns">→ ${a.connections.join(', ')}</div>` : ''}
`).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 `
<div class="area-item ${status}">
<span class="area-marker"></span>
<span class="area-id">${escapeHtml(a.id)}</span>
<span class="area-name">${escapeHtml(a.name)}</span>
${isCurrent ? '<span class="area-here">✧</span>' : ''}
${conns ? `<div class="area-conns">→ ${escapeHtml(conns)}</div>` : ''}
</div>`;
}).join('');
}
// ================================================================