|
|
"use client"; |
|
|
|
|
|
import dynamic from "next/dynamic"; |
|
|
import ChatPanel from "@/components/ChatPanel"; |
|
|
import { useState } from "react"; |
|
|
import type { MapLayer } from "@/components/MapViewer"; |
|
|
|
|
|
|
|
|
const MapViewer = dynamic(() => import("@/components/MapViewer"), { |
|
|
ssr: false, |
|
|
loading: () => <div className="w-full h-full bg-slate-100 flex items-center justify-center">Loading Map...</div> |
|
|
}); |
|
|
|
|
|
export default function Home() { |
|
|
const [layers, setLayers] = useState<MapLayer[]>([]); |
|
|
|
|
|
const handleMapUpdate = (newGeojson: any) => { |
|
|
|
|
|
const id = Date.now().toString() + Math.random().toString(36).substr(2, 9); |
|
|
|
|
|
|
|
|
const name = newGeojson.properties?.layer_name || `Layer ${layers.length + 1}`; |
|
|
const recommendedStyle = newGeojson.properties?.style || {}; |
|
|
const choroplethConfig = newGeojson.properties?.choropleth || null; |
|
|
|
|
|
|
|
|
const newLayer: MapLayer = { |
|
|
id, |
|
|
name, |
|
|
data: newGeojson, |
|
|
visible: true, |
|
|
style: { |
|
|
color: recommendedStyle.color || "#6366f1", |
|
|
fillColor: recommendedStyle.fillColor || recommendedStyle.color || "#6366f1", |
|
|
fillOpacity: recommendedStyle.fillOpacity || 0.3, |
|
|
weight: recommendedStyle.weight || 1 |
|
|
}, |
|
|
|
|
|
...(choroplethConfig && { choropleth: choroplethConfig }), |
|
|
|
|
|
|
|
|
pointMarker: newGeojson.properties?.pointMarker |
|
|
}; |
|
|
|
|
|
|
|
|
setLayers(prev => [...prev, newLayer]); |
|
|
}; |
|
|
|
|
|
const handleLayerUpdate = (id: string, updates: Partial<MapLayer>) => { |
|
|
setLayers(prev => prev.map(layer => |
|
|
layer.id === id ? { ...layer, ...updates } : layer |
|
|
)); |
|
|
}; |
|
|
|
|
|
const handleLayerRemove = (id: string) => { |
|
|
setLayers(prev => prev.filter(layer => layer.id !== id)); |
|
|
}; |
|
|
|
|
|
const handleLayerReorder = (fromIndex: number, toIndex: number) => { |
|
|
setLayers(prev => { |
|
|
const newLayers = [...prev]; |
|
|
const [movedLayer] = newLayers.splice(fromIndex, 1); |
|
|
newLayers.splice(toIndex, 0, movedLayer); |
|
|
return newLayers; |
|
|
}); |
|
|
}; |
|
|
|
|
|
return ( |
|
|
<main className="flex h-screen w-full overflow-hidden"> |
|
|
{/* Left Panel: Chat (30-40% width) */} |
|
|
<div className="w-[400px] md:w-[450px] lg:w-[30%] shrink-0 h-full relative z-10"> |
|
|
<ChatPanel onMapUpdate={handleMapUpdate} layers={layers} /> |
|
|
</div> |
|
|
|
|
|
{/* Right Panel: Map (Remaining width) */} |
|
|
<div className="flex-1 h-full relative"> |
|
|
<MapViewer |
|
|
layers={layers} |
|
|
onLayerUpdate={handleLayerUpdate} |
|
|
onLayerRemove={handleLayerRemove} |
|
|
onLayerReorder={handleLayerReorder} |
|
|
/> |
|
|
</div> |
|
|
</main> |
|
|
); |
|
|
} |
|
|
|