diff --git a/static/css/styles.css b/static/css/styles.css index 6d3d2c1..f3b67a5 100644 --- a/static/css/styles.css +++ b/static/css/styles.css @@ -312,3 +312,127 @@ tr:hover td { background: #1e1e40; } font-size: 0.72rem; } } + +/* ========================================================================== + Building Picker Modal + ========================================================================== */ +#building-modal-overlay { + display: none; + position: fixed; + inset: 0; + background: rgba(0,0,0,0.75); + z-index: 1000; + align-items: center; + justify-content: center; +} +#building-modal-overlay.open { display: flex; } + +#building-modal { + background: #16213e; + border: 2px solid #c8a44a; + border-radius: 10px; + padding: 20px 24px; + width: min(860px, 96vw); + max-height: 88vh; + overflow-y: auto; + position: relative; + animation: modalIn 0.18s ease-out; +} +@keyframes modalIn { + from { transform: scale(0.92); opacity: 0; } + to { transform: scale(1); opacity: 1; } +} +#building-modal-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 16px; + padding-bottom: 10px; + border-bottom: 1px solid #2a4a6a; +} +#building-modal-header h3 { + color: #c8a44a; + font-size: 1rem; + letter-spacing: 0.5px; +} +#building-modal-close { + background: none; + border: none; + color: #888; + font-size: 1.4rem; + cursor: pointer; + line-height: 1; + padding: 0 4px; +} +#building-modal-close:hover { color: #fff; } + +#building-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 10px; +} + +.bld-card { + background: #0f2a50; + border: 2px solid #2a4a6a; + border-radius: 8px; + padding: 10px 8px 8px; + cursor: pointer; + transition: border-color 0.15s, transform 0.1s; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + gap: 4px; + position: relative; +} +.bld-card:hover { border-color: #c8a44a; transform: translateY(-2px); } +.bld-card.bld-selected { border-color: #c8a44a; background: #1a4070; } +.bld-card.bld-maxed { border-color: #2a6a2a; opacity: 0.7; cursor: default; } +.bld-card.bld-locked { border-color: #6a2a2a; opacity: 0.6; cursor: default; } + +.bld-level { + position: absolute; + top: 6px; + left: 8px; + font-size: 0.7rem; + font-weight: 700; + background: #1a1a2e; + color: #c8a44a; + border-radius: 3px; + padding: 1px 5px; +} +.bld-icon { font-size: 1.6rem; line-height: 1; margin-top: 4px; } +.bld-name { font-size: 0.72rem; font-weight: 600; color: #ddd; margin-top: 2px; } +.bld-status { + font-size: 0.65rem; + padding: 2px 6px; + border-radius: 8px; + margin-top: 2px; + font-weight: 600; + white-space: nowrap; +} +.bld-status.can-build { background: #1a4a1a; color: #6fcf6f; } +.bld-status.no-resources { background: #4a2a00; color: #ffaa44; } +.bld-status.queue-warn { background: #3a3a00; color: #cccc44; } +.bld-status.locked { background: #4a0a0a; color: #ff6666; } +.bld-status.maxed { background: #1a3a1a; color: #44aa44; } +.bld-cost { font-size: 0.62rem; color: #666; margin-top: 2px; } + +#building-modal-queue { + margin-top: 16px; + padding-top: 10px; + border-top: 1px solid #2a4a6a; + font-size: 0.75rem; + color: #888; +} +#building-modal-queue-title { + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: 6px; +} + +/* Responsive: 2 columns on small screens */ +@media (max-width: 600px) { + #building-grid { grid-template-columns: repeat(2, 1fr); } +} diff --git a/static/js/api.js b/static/js/api.js index ee24f3d..4e14fb9 100644 --- a/static/js/api.js +++ b/static/js/api.js @@ -97,9 +97,9 @@ window.sendCommand = async function() { let payload = {}; if (type === 'build') { - const building_id = document.getElementById('building-select').value; - if (!building_id) return alert('Παρακαλώ επιλέξτε Κατασκευή πρώτα.'); - + const building_id = window.selectedBuildingId; + if (!building_id) return alert('Παρακαλώ επιλέξτε Κατασκευή από τον πίνακα.'); + const bData = town.build_data?.[building_id]; // UI Validation logic diff --git a/static/js/components/commandForm.js b/static/js/components/commandForm.js index 3f8cdaa..5b6b70e 100644 --- a/static/js/components/commandForm.js +++ b/static/js/components/commandForm.js @@ -10,71 +10,111 @@ window.onCmdTypeChange = function() { document.getElementById('market-options').style.display = type === 'market_offer' ? '' : 'none'; }; +// Building emoji icons for the visual grid +const BUILDING_ICONS = { + main: '🏛️', storage: '🏚️', farm: '🌾', academy: '📜', + temple: '⛩️', barracks: '⚔️', docks: '⚓', market: '🛒', + hide: '🕳️', lumber: '🪵', stoner: '🪨', ironer: '⛏️', wall: '🧱' +}; + +window.selectedBuildingId = null; + window.renderBuildingDropdown = function() { + // No-op — selection now happens via the modal +}; + +window.openBuildingModal = function() { const town = window.getSelectedTown(); if (!town) return; - const bSelect = document.getElementById('building-select'); + + const grid = document.getElementById('building-grid'); const bLevels = town.buildings || {}; const bData = town.build_data || {}; - - const currentVal = bSelect.value; - bSelect.innerHTML = ''; - - for (const [key, nameGr] of Object.entries(window.BUILDING_NAMES_GR)) { - const level = bLevels[key] !== undefined ? bLevels[key] : "?"; - const data = bData[key]; - - let text = `${nameGr} [Επίπεδο ${level}]`; - if (data) { - const w = window.fmt(data.wood || 0); - const st = window.fmt(data.stone || 0); - const i = window.fmt(data.iron || 0); - const pop = data.pop || 0; - let t = data.build_time || ''; - if (t.startsWith('00:')) t = t.substring(3); // make '00:06:00' cleaner as '06:00' - - const popStr = pop > 0 ? ` 🧔:${pop} ` : ' '; - const costStr = `Ξ:${w} Π:${st} Α:${i}${popStr}· ⏱ ${t}`; + grid.innerHTML = Object.entries(window.BUILDING_NAMES_GR).map(([key, nameGr]) => { + const level = bLevels[key] !== undefined ? bLevels[key] : '?'; + const data = bData[key]; + const icon = BUILDING_ICONS[key] || '🏗️'; + const isSelected = key === window.selectedBuildingId; - // Figure out the state - missing_dependencies is an Object! - const missingKeys = data.missing_dependencies ? Object.keys(data.missing_dependencies) : []; - const isLocked = (!data.dependencies) || (missingKeys.length > 0); - - const option = document.createElement('option'); - option.value = key; - - if (data.has_max_level) { - option.textContent = `${text} — (Μέγιστο Επίπεδο)`; - option.style.color = '#33aa33'; - } else if (isLocked) { - option.textContent = `${text} — 🔒 Κλειδωμένο (Προϋποθέσεις)`; - option.style.color = '#ff4444'; // Red as requested - } else if (data.can_upgrade === true) { - option.textContent = `${text} — ✅ ${costStr}`; - } else if (data.enough_resources === false) { - option.textContent = `${text} — ❌ ${costStr} (Λείπουν Πόροι)`; - option.style.color = '#aa5555'; - } else { - // can_upgrade is false, but resources are fine = Population limit or Queue full - option.textContent = `${text} — ⚠️ ${costStr} (Πληθυσμός / Ουρά)`; - option.style.color = '#aa8855'; - } - - bSelect.appendChild(option); - } else { - const option = document.createElement('option'); - option.value = key; - option.textContent = text; - bSelect.appendChild(option); + if (!data) { + return `