change layout
This commit is contained in:
@@ -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); }
|
||||
}
|
||||
|
||||
@@ -97,8 +97,8 @@ 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];
|
||||
|
||||
|
||||
@@ -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 = '<option value="" disabled selected>-- Επιλέξτε Κατασκευή --</option>';
|
||||
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;
|
||||
|
||||
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}`;
|
||||
|
||||
// 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 `<div class="bld-card${isSelected ? ' bld-selected' : ''}" onclick="window.selectBuilding('${key}','${nameGr}')">
|
||||
<span class="bld-level">${level}</span>
|
||||
<span class="bld-icon">${icon}</span>
|
||||
<span class="bld-name">${nameGr}</span>
|
||||
<span class="bld-status queue-warn">Αγνωστο</span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
const missingKeys = data.missing_dependencies ? Object.keys(data.missing_dependencies) : [];
|
||||
const isLocked = !data.dependencies || missingKeys.length > 0;
|
||||
const isMaxed = data.has_max_level;
|
||||
|
||||
let statusClass, statusLabel, cardClass = '';
|
||||
if (isMaxed) {
|
||||
statusClass = 'maxed'; statusLabel = '✓ Μέγιστο'; cardClass = 'bld-maxed';
|
||||
} else if (isLocked) {
|
||||
statusClass = 'locked'; statusLabel = '🔒 Κλειδωμένο'; cardClass = 'bld-locked';
|
||||
} else if (data.can_upgrade) {
|
||||
statusClass = 'can-build'; statusLabel = '✅ Αναβάθμιση';
|
||||
} else if (data.enough_resources === false) {
|
||||
statusClass = 'no-resources'; statusLabel = '❌ Λείπουν Πόροι';
|
||||
} else {
|
||||
statusClass = 'queue-warn'; statusLabel = '⚠️ Πληθ./Ουρά';
|
||||
}
|
||||
|
||||
const w = data.wood ? window.fmt(data.wood) : 0;
|
||||
const st = data.stone ? window.fmt(data.stone) : 0;
|
||||
const i = data.iron ? window.fmt(data.iron) : 0;
|
||||
let t = data.build_time || '';
|
||||
if (t.startsWith('00:')) t = t.substring(3);
|
||||
const costStr = (w || st || i) ? `Ξ:${w} Π:${st} Α:${i}${t ? ' · ⏱'+t : ''}` : '';
|
||||
|
||||
const clickable = !isMaxed && !isLocked;
|
||||
const onclick = clickable ? `onclick="window.selectBuilding('${key}','${nameGr}')"` : '';
|
||||
|
||||
return `<div class="bld-card ${cardClass}${isSelected ? ' bld-selected' : ''}" ${onclick}>
|
||||
<span class="bld-level">${level}</span>
|
||||
<span class="bld-icon">${icon}</span>
|
||||
<span class="bld-name">${nameGr}</span>
|
||||
<span class="bld-status ${statusClass}">${statusLabel}</span>
|
||||
${costStr ? `<span class="bld-cost">${costStr}</span>` : ''}
|
||||
</div>`;
|
||||
}).join('');
|
||||
|
||||
// Render current build queue in modal footer
|
||||
const qEl = document.getElementById('building-modal-queue-items');
|
||||
if (town.build_queue && town.build_queue.length) {
|
||||
qEl.innerHTML = town.build_queue.map(o => {
|
||||
const raw = o.building_type || o.name || '';
|
||||
const gr = window.BUILDING_NAMES_GR[raw] || raw;
|
||||
return `<span style="background:rgba(0,0,0,0.3);padding:2px 8px;border-radius:4px;margin-right:4px;font-size:0.8rem;">${gr}</span>`;
|
||||
}).join('');
|
||||
} else {
|
||||
qEl.innerHTML = '<span style="color:#555;font-size:0.8rem;">Κενή</span>';
|
||||
}
|
||||
|
||||
if (currentVal && Array.from(bSelect.options).some(o => o.value === currentVal)) {
|
||||
bSelect.value = currentVal;
|
||||
}
|
||||
document.getElementById('building-modal-overlay').classList.add('open');
|
||||
};
|
||||
|
||||
window.closeBuildingModal = function(e) {
|
||||
// Close only if clicking the overlay background or the X button
|
||||
if (e && e.target !== document.getElementById('building-modal-overlay') && e.target !== document.getElementById('building-modal-close')) return;
|
||||
document.getElementById('building-modal-overlay').classList.remove('open');
|
||||
};
|
||||
|
||||
window.selectBuilding = function(key, nameGr) {
|
||||
window.selectedBuildingId = key;
|
||||
// Update the trigger button label
|
||||
document.getElementById('selected-building-label').textContent = `🏗️ ${nameGr}`;
|
||||
// Re-render grid to show new selection highlight
|
||||
window.openBuildingModal();
|
||||
// Close after brief visual feedback
|
||||
setTimeout(() => document.getElementById('building-modal-overlay').classList.remove('open'), 180);
|
||||
};
|
||||
|
||||
|
||||
|
||||
window.renderUnitDropdown = function() {
|
||||
const town = window.getSelectedTown();
|
||||
if (!town) return;
|
||||
|
||||
@@ -85,6 +85,10 @@ window.renderTowns = function() {
|
||||
|
||||
window.selectTown = function(id) {
|
||||
window.selectedTownId = id;
|
||||
window.selectedBuildingId = null;
|
||||
const lbl = document.getElementById('selected-building-label');
|
||||
if (lbl) lbl.textContent = '-- Επιλέξτε Κατασκευή --';
|
||||
|
||||
window.renderTowns();
|
||||
|
||||
document.getElementById('no-town-selected').style.display = 'none';
|
||||
|
||||
@@ -99,12 +99,12 @@
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Build options -->
|
||||
<!-- Build options - now a button that opens the visual picker -->
|
||||
<div class="form-group" id="build-options">
|
||||
<label>Building</label>
|
||||
<select id="building-select">
|
||||
<option disabled>Επιλέξτε πόλη...</option>
|
||||
</select>
|
||||
<button class="btn btn-gold" id="open-building-modal" onclick="window.openBuildingModal()" style="text-align:left; min-width:200px;">
|
||||
<span id="selected-building-label">-- Επιλέξτε Κατασκευή --</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Recruit options -->
|
||||
@@ -227,5 +227,19 @@
|
||||
<script src="/static/js/components/commandLog.js"></script>
|
||||
<script src="/static/js/api.js"></script>
|
||||
<script src="/static/js/app.js"></script>
|
||||
<!-- ====== Building Picker Modal ====== -->
|
||||
<div id="building-modal-overlay" onclick="window.closeBuildingModal(event)">
|
||||
<div id="building-modal">
|
||||
<div id="building-modal-header">
|
||||
<h3>🏛️ Επιλογή Κατασκευής</h3>
|
||||
<button id="building-modal-close" onclick="window.closeBuildingModal()">✕</button>
|
||||
</div>
|
||||
<div id="building-grid"></div>
|
||||
<div id="building-modal-queue">
|
||||
<div id="building-modal-queue-title">Σειρά Κατασκευών</div>
|
||||
<div id="building-modal-queue-items"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user