Files
hexifyer/src/ui/terrain-picker.ts
Axel Meyer f302932ea8 Phase 1: Core hex engine, Leaflet overlay, terrain painting UI
- core/: Pure TS hex engine (axial coords, hex grid, terrain types,
  edge connectivity with constraint solver, HexMap state model)
- src/map/: Leaflet L.CRS.Simple map init, Canvas-based hex overlay
  layer (L.GridLayer), click/edge interaction detection
- src/ui/: Sidebar with toolbar (Select/Paint/Feature modes),
  terrain picker, hex inspector, map settings (hex size, grid, opacity)
- pipeline/: Tile pyramid generator (sharp, from source image)
- tests/: 32 passing tests for coords, hex-grid, edge-connectivity
- Uses Kiepenkerl tiles (symlinked) for development

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:32:52 +00:00

81 lines
2.3 KiB
TypeScript

import type { TerrainType } from '../../core/types.js';
import { getAreaTerrains, getLinearTerrains } from '../../core/terrain.js';
import type { ToolMode } from './toolbar.js';
export function createTerrainPicker(
container: HTMLElement,
onChange: (terrain: TerrainType) => void,
): {
setMode: (mode: ToolMode) => void;
getSelected: () => TerrainType | null;
} {
let selected: TerrainType | null = null;
let currentMode: ToolMode = 'select';
function render() {
container.innerHTML = '';
if (currentMode === 'select') {
container.innerHTML = '<div style="color:#666;font-size:12px">Click a hex to inspect it</div>';
return;
}
const terrains = currentMode === 'paint' ? getAreaTerrains() : getLinearTerrains();
const label = currentMode === 'paint' ? 'Area Terrain' : 'Linear Features';
const sectionLabel = document.createElement('div');
sectionLabel.className = 'terrain-section-label';
sectionLabel.textContent = label;
container.appendChild(sectionLabel);
const grid = document.createElement('div');
grid.className = 'terrain-grid';
for (const terrain of terrains) {
const btn = document.createElement('button');
btn.className = 'terrain-btn';
if (selected?.id === terrain.id) btn.classList.add('selected');
const swatch = document.createElement('span');
swatch.className = 'terrain-swatch';
swatch.style.backgroundColor = terrain.color;
const name = document.createElement('span');
name.textContent = terrain.name;
btn.appendChild(swatch);
btn.appendChild(name);
btn.addEventListener('click', () => {
selected = terrain;
onChange(terrain);
render();
});
grid.appendChild(btn);
}
container.appendChild(grid);
// Auto-select first if nothing selected
if (!selected || !terrains.find(t => t.id === selected!.id)) {
selected = terrains[0] ?? null;
if (selected) onChange(selected);
// Re-render to show selection
const firstBtn = grid.querySelector('.terrain-btn');
firstBtn?.classList.add('selected');
}
}
render();
return {
setMode(mode: ToolMode) {
currentMode = mode;
selected = null;
render();
},
getSelected: () => selected,
};
}