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
|
|
@ -1,7 +1,10 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { MapTransformProvider } from '../../contexts/MapTransformContext';
|
||||
import { WindowManagerProvider } from '../../contexts/WindowManagerContext';
|
||||
import { MapView } from './MapView';
|
||||
import { Sidebar } from './Sidebar';
|
||||
import { WindowRenderer } from '../windows/WindowRenderer';
|
||||
import { RareNotification } from '../effects/RareNotification';
|
||||
import { usePlayerColors } from '../../hooks/usePlayerColors';
|
||||
import type { DashboardState } from '../../hooks/useLiveData';
|
||||
|
||||
|
|
@ -12,43 +15,52 @@ interface Props {
|
|||
|
||||
export const MapLayout: React.FC<Props> = ({ data, onViewToggle }) => {
|
||||
const getColor = usePlayerColors();
|
||||
const [showHeatmap, setShowHeatmap] = useState(false);
|
||||
const [showPortals, setShowPortals] = useState(false);
|
||||
|
||||
// Build flat players array from characters map
|
||||
const players = Array.from(data.characters.values())
|
||||
.filter(c => c.telemetry)
|
||||
.map(c => c.telemetry!);
|
||||
|
||||
// Build vitals map
|
||||
const vitalsMap = new Map(
|
||||
Array.from(data.characters.values())
|
||||
.filter(c => c.vitals)
|
||||
.map(c => [c.name, c.vitals!])
|
||||
);
|
||||
|
||||
const handleSelectPlayer = useCallback((name: string) => {
|
||||
const handleSelectPlayer = useCallback((_name: string) => {
|
||||
// TODO: zoom map to player position
|
||||
console.log('Select player:', name);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<MapTransformProvider>
|
||||
<div className="ml-layout">
|
||||
<Sidebar
|
||||
players={players}
|
||||
vitals={vitalsMap}
|
||||
serverHealth={data.serverHealth}
|
||||
totalRares={data.totalRares}
|
||||
totalKills={data.totalKills}
|
||||
getColor={getColor}
|
||||
onSelectPlayer={handleSelectPlayer}
|
||||
onViewToggle={onViewToggle}
|
||||
/>
|
||||
<MapView
|
||||
players={players}
|
||||
getColor={getColor}
|
||||
onSelectPlayer={handleSelectPlayer}
|
||||
/>
|
||||
</div>
|
||||
<WindowManagerProvider>
|
||||
<div className="ml-layout">
|
||||
<Sidebar
|
||||
players={players}
|
||||
vitals={vitalsMap}
|
||||
serverHealth={data.serverHealth}
|
||||
totalRares={data.totalRares}
|
||||
totalKills={data.totalKills}
|
||||
getColor={getColor}
|
||||
onSelectPlayer={handleSelectPlayer}
|
||||
onViewToggle={onViewToggle}
|
||||
showHeatmap={showHeatmap}
|
||||
showPortals={showPortals}
|
||||
onToggleHeatmap={setShowHeatmap}
|
||||
onTogglePortals={setShowPortals}
|
||||
/>
|
||||
<MapView
|
||||
players={players}
|
||||
getColor={getColor}
|
||||
onSelectPlayer={handleSelectPlayer}
|
||||
showHeatmap={showHeatmap}
|
||||
showPortals={showPortals}
|
||||
/>
|
||||
<WindowRenderer characters={data.characters} chatMessages={data.chatMessages} />
|
||||
<RareNotification recentRares={data.recentRares} />
|
||||
</div>
|
||||
</WindowManagerProvider>
|
||||
</MapTransformProvider>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue