feat(v2): Phases 2-6 — trails, heatmap, portals, windows, effects
Phase 2 — Map overlays: - TrailsSVG: SVG polylines per character from /trails, polled 2s - HeatmapCanvas: canvas radial gradients from /spawns/heatmap - PortalMarkers: emoji markers from /portals - Sidebar toggles for heatmap and portals Phase 3 — Draggable windows: - WindowManagerContext: z-index stack for open windows - DraggableWindow: generic shell with drag-header, close btn, z-stack - ChatWindow: color-coded messages + input form (1000 msg buffer) - CharacterWindow: combat stats with monster damage table - InventoryWindow: item table with material/set/AL/dmg/workmanship - WindowRenderer: reads context, renders all open windows - Action buttons (Chat/Stats/Inv/Char/Radar) now open windows Phase 4 — Window types share same DraggableWindow shell with character-specific content. Combat stats and inventory via API. Phase 5 — Effects: - RareNotification: slide-in/slide-out banner with gold border - Fireworks: 30-particle explosion with CSS custom property animation - Notification queue with 6s display + 0.5s exit animation Phase 6 — Polish: - Window header uses modern blue gradient (not solid purple) - Chat uses monospace font - All overlay layers properly stacked (heatmap → trails → dots → portals) - Mobile: sidebar stacks above map at 768px breakpoint - Chat messages tracked per-character in useLiveData Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
183d662bb9
commit
de7b547349
20 changed files with 1040 additions and 193 deletions
61
frontend/src/components/windows/CharacterWindow.tsx
Normal file
61
frontend/src/components/windows/CharacterWindow.tsx
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { DraggableWindow } from './DraggableWindow';
|
||||
import { apiFetch } from '../../api/client';
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
charName: string;
|
||||
zIndex: number;
|
||||
}
|
||||
|
||||
export const CharacterWindow: React.FC<Props> = ({ id, charName, zIndex }) => {
|
||||
const [stats, setStats] = useState<Record<string, unknown> | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
apiFetch<Record<string, unknown>>(`/combat-stats/${encodeURIComponent(charName)}`)
|
||||
.then(setStats).catch(() => {});
|
||||
}, [charName]);
|
||||
|
||||
const session = (stats as any)?.session;
|
||||
|
||||
return (
|
||||
<DraggableWindow id={id} title={`Character: ${charName}`} zIndex={zIndex} width={500} height={400}>
|
||||
<div style={{ padding: 8, fontSize: '0.8rem', color: '#ccc', overflowY: 'auto', flex: 1 }}>
|
||||
{session ? (
|
||||
<>
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<strong>Session</strong>: {session.total_kills ?? 0} kills, {(session.total_damage_given ?? 0).toLocaleString()} dmg given
|
||||
</div>
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<strong>Monsters fought</strong>: {Object.keys(session.monsters ?? {}).filter((k: string) => k !== '__cloak_surges__').length}
|
||||
</div>
|
||||
<table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.75rem' }}>
|
||||
<thead>
|
||||
<tr style={{ borderBottom: '1px solid #444', color: '#888' }}>
|
||||
<th style={{ textAlign: 'left', padding: '2px 4px' }}>Monster</th>
|
||||
<th style={{ textAlign: 'right', padding: '2px 4px' }}>Kills</th>
|
||||
<th style={{ textAlign: 'right', padding: '2px 4px' }}>Dmg Given</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{Object.values(session.monsters ?? {})
|
||||
.filter((m: any) => m.name !== '__cloak_surges__')
|
||||
.sort((a: any, b: any) => (b.damage_given ?? 0) - (a.damage_given ?? 0))
|
||||
.slice(0, 30)
|
||||
.map((m: any) => (
|
||||
<tr key={m.name} style={{ borderBottom: '1px solid #222' }}>
|
||||
<td style={{ padding: '2px 4px' }}>{m.name}</td>
|
||||
<td style={{ textAlign: 'right', padding: '2px 4px' }}>{m.kill_count}</td>
|
||||
<td style={{ textAlign: 'right', padding: '2px 4px' }}>{(m.damage_given ?? 0).toLocaleString()}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
) : (
|
||||
<div style={{ color: '#666' }}>Loading combat data...</div>
|
||||
)}
|
||||
</div>
|
||||
</DraggableWindow>
|
||||
);
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue