import { useMemo } from 'react'; import * as THREE from 'three'; import { Html } from '@react-three/drei'; import { BUILDINGS, COLORS } from '../constants'; interface BuildingsProps { detailMode?: boolean; onBuildingClick?: (building: string) => void; } function WindowGrid({ width, height, depth }: { width: number; height: number; depth: number }) { const windows = useMemo(() => { const cols = 4; const rows = 3; const winW = 1.5; const winH = 0.8; const winD = 0.05; const gapX = (width - cols * winW) / (cols + 1); const gapY = (height - rows * winH) / (rows + 1); const items: { pos: [number, number, number] }[] = []; for (let r = 0; r < rows; r++) { for (let c = 0; c < cols; c++) { const x = -width / 2 + gapX + winW / 2 + c * (winW + gapX); const y = -height / 2 + gapY + winH / 2 + r * (winH + gapY); items.push({ pos: [x, y, depth / 2 + winD / 2] }); } } return items; }, [width, height, depth]); return ( {windows.map((w, i) => ( ))} ); } function Building({ label, position, size, opacity, onClick, }: { label: string; position: [number, number, number]; size: [number, number, number]; opacity: number; onClick?: () => void; }) { const [w, h, d] = size; const edgesGeo = useMemo(() => { const box = new THREE.BoxGeometry(w, h, d); return new THREE.EdgesGeometry(box); }, [w, h, d]); const labelStyle: React.CSSProperties = { fontSize: '13px', color: COLORS.text, background: 'rgba(6, 30, 62, 0.8)', padding: '2px 8px', borderRadius: '4px', border: '1px solid rgba(0, 212, 255, 0.2)', whiteSpace: 'nowrap', pointerEvents: 'none', }; return ( { e.stopPropagation(); onClick(); } : undefined}> {/* Main body */} {/* Edge highlight */} {/* Windows on front face */} {/* Label */}
{label}
); } export default function Buildings({ detailMode, onBuildingClick }: BuildingsProps) { const opacity = detailMode ? 0.15 : 0.85; return ( onBuildingClick('east') : undefined} /> onBuildingClick('west') : undefined} /> ); }