feat(v2): 13 improvements — functional, visual, UX, backend

Functional:
1. Chat: "▼ New messages below" indicator when scrolled up, click to jump
2. Combat stats: "Clear Session" button (red, with confirm dialog)
3. Inventory: live updates via inventory_delta WS (re-fetches on change)
4. Inventory: real mana time from equipment_cantrip_state WS (live
   countdown with state dot: green=active, red=inactive, yellow=unknown)

Visual:
5. Thin separator line between tool links and sort buttons
6. Selected player row highlighted with darker background (#2a3344)
7. Scroll-to-top button (▲) appears when scrolled past 200px in player list

UX:
8. Double-click player dot on map opens their chat window
9. Right-click player dot shows context menu (Chat/Stats/Inv/Char/Combat/Radar)
10. Ctrl+D keyboard shortcut toggles between map and dashboard views
11. Sound notification on rare drops (880Hz sine beep via Web Audio API)

Backend:
12. Deep-merge lifetime offense/defense per element — accumulates
    total_attacks, failed_attacks, crits, damage per AttackType×Element
    instead of overwriting with latest session data
13. Startup cleanup: deletes stale combat_stats records from before
    the lifetime fix (pre-2026-04-14T09:00Z)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-04-14 13:49:40 +02:00
parent 0b64c6ccff
commit 0112c59514
41 changed files with 404 additions and 112 deletions

View file

@ -18,11 +18,12 @@ interface Props {
onToggleHeatmap: (v: boolean) => void;
onTogglePortals: (v: boolean) => void;
version?: string;
selectedPlayer?: string | null;
}
export const Sidebar: React.FC<Props> = ({
players, vitals, serverHealth, totalRares, totalKills, getColor, onSelectPlayer, onViewToggle,
showHeatmap, showPortals, onToggleHeatmap, onTogglePortals, version,
showHeatmap, showPortals, onToggleHeatmap, onTogglePortals, version, selectedPlayer,
}) => {
const [sortKey, setSortKey] = useState<SortKey>('name');
const [filter, setFilter] = useState('');
@ -100,6 +101,7 @@ export const Sidebar: React.FC<Props> = ({
</label>
</div>
<div style={{ borderTop: '1px solid #333', marginTop: 4, paddingTop: 4 }} />
<SortButtons value={sortKey} onChange={setSortKey} />
<input
className="ml-filter"
@ -114,6 +116,7 @@ export const Sidebar: React.FC<Props> = ({
vitals={deferredVitals}
getColor={getColor}
onSelect={onSelectPlayer}
selectedPlayer={selectedPlayer}
/>
</div>
);