ProductionGame/frontend/js/ui/productionView.js

101 lines
3.9 KiB
JavaScript

// Production - The Idle Game: Production Floor View
// Clean modular orchestrator connecting sector toolbar, facility cards, and fine-grained DOM updating
import { PRODUCTS } from '../data/products.js';
import { renderSectorBarHtml, renderSectorSummariesHtml, updateSectorBarDom } from './production/sectorBar.js';
import { renderFacilityCardHtml, updateFacilityCardDom } from './production/facilityCard.js';
export { calculateMultiCost, getProductOutputRates } from './production/ratesCalculator.js';
/**
* Mounts the production floor DOM structure ONCE
*/
export function mountProductionFloor(container, state, onAction, engine) {
const selectedSector = state.selectedSector || 'all';
const buyMode = state.buyMode || '1';
const filteredProducts = PRODUCTS.filter(p => {
if (selectedSector === 'all') return true;
return p.sector === selectedSector;
});
let html = renderSectorSummariesHtml(selectedSector, engine);
html += `<div class="production-grid">`;
for (const p of filteredProducts) {
const pState = state.products[p.id] || { unlocked: false, lines: 0, stock: 0, cycleProgress: 0, isBottlenecked: false };
html += renderFacilityCardHtml(p, pState, state, buyMode);
}
html += `</div>`;
container.innerHTML = html;
// Attach event listeners ONCE
container.querySelectorAll('.sector-pill').forEach(btn => {
btn.onclick = () => onAction({ type: 'SELECT_SECTOR', sector: btn.dataset.sector });
});
container.querySelectorAll('.sector-mini-card').forEach(card => {
card.onclick = () => onAction({ type: 'SELECT_SECTOR', sector: card.dataset.sector });
});
container.querySelectorAll('.facility-card').forEach(card => {
card.onclick = (e) => {
if (e.target.closest('button')) return;
onAction({ type: 'SELECT_PRODUCT', productId: card.dataset.product });
};
});
container.querySelectorAll('.btn-unlock').forEach(btn => {
btn.onclick = () => onAction({ type: 'UNLOCK_PRODUCT', productId: btn.dataset.product });
});
container.querySelectorAll('.btn-cycle').forEach(btn => {
btn.onclick = () => onAction({ type: 'MANUAL_CYCLE', productId: btn.dataset.product });
});
container.querySelectorAll('.btn-expand').forEach(btn => {
btn.onclick = () => onAction({ type: 'BUY_LINES', productId: btn.dataset.product });
});
container.querySelectorAll('.btn-hire-mgr').forEach(btn => {
btn.onclick = () => onAction({ type: 'HIRE_MANAGER', productId: btn.dataset.product });
});
container.querySelectorAll('.btn-expand-logistics').forEach(btn => {
btn.onclick = () => onAction({ type: 'BUY_LOGISTICS', productId: btn.dataset.product });
});
container.querySelectorAll('.btn-toggle-logistics').forEach(btn => {
btn.onclick = () => onAction({ type: 'TOGGLE_LOGISTICS', productId: btn.dataset.product });
});
container.querySelectorAll('.btn-toggle-downstream').forEach(btn => {
btn.onclick = () => onAction({ type: 'TOGGLE_DOWNSTREAM_SUPPLY', productId: btn.dataset.product });
});
container.querySelectorAll('.btn-throttle-pill').forEach(btn => {
btn.onclick = () => onAction({
type: 'SET_PRODUCTION_TARGET',
productId: btn.dataset.product,
target: parseFloat(btn.dataset.target)
});
});
}
/**
* Fine-grained in-place DOM updates (0% layout thrashing, 0% DOM teardown)
*/
export function updateProductionFloor(container, state, engine) {
const buyMode = state.buyMode || '1';
const selectedSector = state.selectedSector || 'all';
// 1. Update Sector Navigation Pills & Summaries
updateSectorBarDom(selectedSector, engine);
// 2. Update Facility Cards
for (const p of PRODUCTS) {
const pState = state.products[p.id];
if (!pState) continue;
updateFacilityCardDom(p, pState, state, buyMode);
}
}