feat(shard): Protocol 2.0 boards UI — guilds, governors, houses, players-online
Phase 2: the public UI for the four new boards, following the ChampSpawns live pattern (snapshot via useAsync + merge SSE deltas with useShardFeed). - Players Online widget (components/PlayersOnline.jsx): total + region breakdown rolled up into display buckets (data/regionBuckets.js — the one place to retune the grouping); live via presence.online. Placed on the Shard page, replacing the static players-online stat tile. - Guilds (/site/guilds): searchable board of rosters/alliances/leaders with a "recently joined" strip from guild.join. - Governors (/site/governors): one card per city with a placeholder crest (data/cityCrests.js — swap for real art without touching components), election phase badge + autoPickAt countdown, and an on-demand "past governors" term history (the look-back reads the ledger captured in Phase 1). Clean empty state when City Loyalty isn't enabled. - Houses (/site/houses): searchable registry with decay badges; price labelled "placement value", not a for-sale flag. - API client methods + nav links (Guilds / Governors / Houses). Client build clean (240 modules). Refs .plans/protocol2-integration.md (Phase 2). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
31
client/src/data/cityCrests.js
Normal file
31
client/src/data/cityCrests.js
Normal file
@@ -0,0 +1,31 @@
|
||||
// Placeholder heraldry for the eight City-Loyalty cities. Each entry is a simple
|
||||
// emoji sigil + a ring colour — enough to make the Governors board and the
|
||||
// governor badge read as distinct "crests" today, swappable for real artwork
|
||||
// later WITHOUT touching any component: drop an `img` (an imported asset URL or a
|
||||
// public path) onto an entry and update CityCrest to prefer it.
|
||||
//
|
||||
// Keyed by the exact `city` string the sidecar sends (see INTEGRATION.md §4:
|
||||
// Moonglow, Britain, Jhelom, Yew, Minoc, Trinsic, SkaraBrae, NewMagincia).
|
||||
|
||||
export const CITY_CRESTS = {
|
||||
Britain: { sigil: '⚜', color: '#c9a24b', label: 'Britain' },
|
||||
Moonglow: { sigil: '🔮', color: '#7f8fd0', label: 'Moonglow' },
|
||||
Minoc: { sigil: '⚒', color: '#b0763f', label: 'Minoc' },
|
||||
Trinsic: { sigil: '⚓', color: '#5f9bd0', label: 'Trinsic' },
|
||||
Yew: { sigil: '🌳', color: '#5fb98a', label: 'Yew' },
|
||||
Jhelom: { sigil: '⚔', color: '#c76f6f', label: 'Jhelom' },
|
||||
SkaraBrae: { sigil: '🐎', color: '#9a8bbf', label: 'Skara Brae' },
|
||||
NewMagincia: { sigil: '🕊', color: '#cfc3a0', label: 'New Magincia' },
|
||||
}
|
||||
|
||||
const FALLBACK = { sigil: '🏰', color: '#8c96a5', label: '' }
|
||||
|
||||
// Look up a crest by the raw city key, tolerating spacing variants
|
||||
// ("Skara Brae" / "New Magincia"). `label` falls back to the given name.
|
||||
export function crestFor(city) {
|
||||
if (!city) return FALLBACK
|
||||
const key = String(city).replace(/\s+/g, '')
|
||||
const crest = CITY_CRESTS[city] || CITY_CRESTS[key]
|
||||
if (crest) return crest
|
||||
return { ...FALLBACK, label: String(city) }
|
||||
}
|
||||
Reference in New Issue
Block a user