UI: Finalized sidebar compaction, collapsible handle, dropdown fixes, and owner status filtering
Deploy Bürgerwind / deploy (push) Successful in 17s Details

This commit is contained in:
Johannes Baumeister 2026-05-13 09:13:48 +02:00
parent a47047d34d
commit 0d9306741e
3 changed files with 133 additions and 19 deletions

78
app.js
View File

@ -594,20 +594,30 @@ document.addEventListener('DOMContentLoaded', async () => {
variantTabs.forEach(tab => { variantTabs.forEach(tab => {
tab.addEventListener('click', () => { tab.addEventListener('click', () => {
if (state.activeVariant === tab.dataset.variant) return; if (state.activeVariant === tab.dataset.variant) return;
variantTabs.forEach(t => t.classList.remove('active')); variantTabs.forEach(t => t.classList.remove('active'));
tab.classList.add('active'); tab.classList.add('active');
const newVariant = tab.dataset.variant;
state.map.removeLayer(variantLayers[state.activeVariant]); state.map.removeLayer(variantLayers[state.activeVariant]);
state.activeVariant = newVariant; state.activeVariant = tab.dataset.variant;
variantLayers[state.activeVariant].addTo(state.map); variantLayers[state.activeVariant].addTo(state.map);
updateProximityLines();
document.getElementById('statusInfo').innerText = `Variante ${newVariant} aktiv.`; closeEditPanel();
document.getElementById('statusInfo').innerText = `Variante ${state.activeVariant} aktiv.`;
}); });
}); });
// Sidebar Toggle Logic
const btnToggleSidebar = document.getElementById('btnToggleSidebar');
const sidebar = document.querySelector('.sidebar');
if (btnToggleSidebar && sidebar) {
btnToggleSidebar.onclick = () => {
sidebar.classList.toggle('collapsed');
// Give the transition time to finish before invalidating map size
setTimeout(() => {
state.map.invalidateSize();
}, 300);
};
}
// Hilfsgeometrien Toggle // Hilfsgeometrien Toggle
const checkShowAux = document.getElementById('checkShowAux'); const checkShowAux = document.getElementById('checkShowAux');
if (checkShowAux) { if (checkShowAux) {
@ -627,6 +637,21 @@ document.addEventListener('DOMContentLoaded', async () => {
}; };
} }
// Eigentümerzustimmung Toggle
const checkShowOwners = document.getElementById('checkShowOwners');
if (checkShowOwners) {
checkShowOwners.onchange = () => {
const ownerLayer = overlays["Eigentümer (ALKIS DB)"];
if (ownerLayer) {
if (checkShowOwners.checked) {
state.map.addLayer(ownerLayer);
} else {
state.map.removeLayer(ownerLayer);
}
}
};
}
// UTM Creation Logic // UTM Creation Logic
const btnCreateAtUTM = document.getElementById('btnCreateAtUTM'); const btnCreateAtUTM = document.getElementById('btnCreateAtUTM');
const inputUtmE = document.getElementById('utm-e'); const inputUtmE = document.getElementById('utm-e');
@ -923,7 +948,7 @@ document.addEventListener('DOMContentLoaded', async () => {
}); });
} }
const layerControl = L.control.layers(baseLayers, overlays, { collapsed: false }).addTo(state.map); const layerControl = L.control.layers(baseLayers, overlays, { collapsed: true }).addTo(state.map);
// Update proximity lines when layers are toggled in legend // Update proximity lines when layers are toggled in legend
state.map.on('overlayadd overlayremove', () => { state.map.on('overlayadd overlayremove', () => {
@ -1425,7 +1450,13 @@ document.addEventListener('DOMContentLoaded', async () => {
}); });
overlays[layerName] = layer; overlays[layerName] = layer;
state.map.addLayer(layer);
// Only add to map if checkbox is checked
const checkShowOwners = document.getElementById('checkShowOwners');
if (!checkShowOwners || checkShowOwners.checked) {
state.map.addLayer(layer);
}
layerControl.addOverlay(layer, layerName); layerControl.addOverlay(layer, layerName);
layer.bringToFront(); // Ensure it's on top of local shapefiles layer.bringToFront(); // Ensure it's on top of local shapefiles
} }
@ -1470,6 +1501,16 @@ document.addEventListener('DOMContentLoaded', async () => {
const btnConfirmMapping = document.getElementById('btnConfirmMapping'); const btnConfirmMapping = document.getElementById('btnConfirmMapping');
const ownerTableBody = document.querySelector('#ownerTable tbody'); const ownerTableBody = document.querySelector('#ownerTable tbody');
const ownerSearch = document.getElementById('ownerSearch'); const ownerSearch = document.getElementById('ownerSearch');
const ownerStatusFilter = document.getElementById('ownerStatusFilter');
// Populate Status Filter Options
if (ownerStatusFilter) {
ownerStatusFilter.innerHTML = `
<option value="">Alle Status</option>
<option value="HAS_STATUS">Nur mit Status</option>
${Object.keys(STATUS_MAP).map(s => `<option value="${s}">${s}</option>`).join('')}
`;
}
btnManageOwners.onclick = () => { btnManageOwners.onclick = () => {
const ownerLayer = Object.keys(overlays).find(k => k.toLowerCase().includes('eigentümer')); const ownerLayer = Object.keys(overlays).find(k => k.toLowerCase().includes('eigentümer'));
@ -1595,17 +1636,32 @@ document.addEventListener('DOMContentLoaded', async () => {
renderOwnerRows(owners); renderOwnerRows(owners);
ownerSearch.oninput = () => { const runFilter = () => {
const query = ownerSearch.value.toLowerCase(); const query = ownerSearch.value.toLowerCase();
const statusFilter = ownerStatusFilter.value;
const filtered = {}; const filtered = {};
for (let name in owners) { for (let name in owners) {
const o = owners[name]; const o = owners[name];
if (name.toLowerCase().includes(query) || (o.address && o.address.toLowerCase().includes(query))) { const stored = state.ownerStatuses[name.toLowerCase()] || { status: 'none' };
const currentStatus = typeof stored === 'object' ? (stored.status || 'none') : (stored || 'none');
const matchesQuery = name.toLowerCase().includes(query) || (o.address && o.address.toLowerCase().includes(query));
let matchesStatus = !statusFilter || currentStatus === statusFilter;
if (statusFilter === 'HAS_STATUS') {
matchesStatus = currentStatus !== 'none' && currentStatus !== '';
}
if (matchesQuery && matchesStatus) {
filtered[name] = o; filtered[name] = o;
} }
} }
renderOwnerRows(filtered); renderOwnerRows(filtered);
}; };
ownerSearch.oninput = runFilter;
ownerStatusFilter.onchange = runFilter;
} }
function renderOwnerRows(owners) { function renderOwnerRows(owners) {

View File

@ -35,9 +35,12 @@
<div class="variant-tab" data-variant="B">Var B</div> <div class="variant-tab" data-variant="B">Var B</div>
<div class="variant-tab" data-variant="C">Var C</div> <div class="variant-tab" data-variant="C">Var C</div>
</div> </div>
<div style="margin-top: 12px; padding: 0 5px;"> <div style="margin-top: 8px; padding: 0 5px; display: flex; flex-direction: column; gap: 4px;">
<label style="cursor: pointer; display: flex; align-items: center; gap: 8px; font-size: 0.85rem; color: var(--text-dim);"> <label style="cursor: pointer; display: flex; align-items: center; gap: 8px; font-size: 0.8rem; color: var(--text-dim);">
<input type="checkbox" id="checkShowAux" checked> Hilfsgeometrien anzeigen <input type="checkbox" id="checkShowAux" checked> Hilfsgeometrien
</label>
<label style="cursor: pointer; display: flex; align-items: center; gap: 8px; font-size: 0.8rem; color: var(--text-dim);">
<input type="checkbox" id="checkShowOwners" checked> Eigentümerzustimmung
</label> </label>
</div> </div>
</div> </div>
@ -127,6 +130,9 @@
Bereit. (v1.0.3 - Mirrored Nordex Default) Bereit. (v1.0.3 - Mirrored Nordex Default)
</div> </div>
</div> </div>
<button class="sidebar-toggle" id="btnToggleSidebar" title="Sidebar einklappen/ausklappen">
<span class="toggle-icon"></span>
</button>
</aside> </aside>
<!-- Floating Edit Panel --> <!-- Floating Edit Panel -->
@ -225,8 +231,12 @@
<!-- Stage 2: Owner List --> <!-- Stage 2: Owner List -->
<div id="ownerListSection" style="display: none;"> <div id="ownerListSection" style="display: none;">
<div style="padding: 15px; border-bottom: 1px solid var(--border-color);"> <div style="padding: 15px; border-bottom: 1px solid var(--border-color); display: flex; gap: 10px;">
<input type="text" id="ownerSearch" class="input-styled" placeholder="Eigentümer suchen..."> <input type="text" id="ownerSearch" class="input-styled" placeholder="Eigentümer suchen..." style="flex: 2;">
<select id="ownerStatusFilter" class="input-styled" style="flex: 1;">
<option value="">Alle Status</option>
<!-- Options filled via JS -->
</select>
</div> </div>
<div class="owner-table-container"> <div class="owner-table-container">
<table id="ownerTable"> <table id="ownerTable">

View File

@ -43,6 +43,13 @@ body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
box-shadow: 4px 0 15px rgba(0, 0, 0, 0.5); box-shadow: 4px 0 15px rgba(0, 0, 0, 0.5);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
flex-shrink: 0;
}
.sidebar.collapsed {
margin-left: -260px;
} }
.sidebar-header { .sidebar-header {
@ -97,7 +104,7 @@ body {
.input-styled { .input-styled {
width: 100%; width: 100%;
background: rgba(255, 255, 255, 0.05); background: #0a2d2d; /* Solid dark blue-green */
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
padding: 6px 8px; padding: 6px 8px;
border-radius: 6px; border-radius: 6px;
@ -112,7 +119,7 @@ body {
} }
.input-styled option { .input-styled option {
background: #1e1e1e; background: #0a2d2d;
color: white; color: white;
} }
@ -405,7 +412,7 @@ body {
.edit-input { .edit-input {
flex: 1; flex: 1;
background: rgba(255, 255, 255, 0.1); background: #0a2d2d;
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
padding: 4px 8px; padding: 4px 8px;
border-radius: 4px; border-radius: 4px;
@ -415,6 +422,11 @@ body {
width: 100px; width: 100px;
} }
.edit-input option {
background: #0a2d2d;
color: white;
}
.btn-primary-mini { .btn-primary-mini {
background: var(--primary-color); background: var(--primary-color);
color: #000; color: #000;
@ -528,6 +540,42 @@ body {
transition: transform 0.2s ease; transition: transform 0.2s ease;
} }
/* Sidebar Toggle Handle (Lasche) */
.sidebar-toggle {
position: absolute;
right: -24px;
top: 50%;
transform: translateY(-50%);
width: 24px;
height: 60px;
background: var(--panel-bg);
border: 1px solid var(--border-color);
border-left: none;
border-radius: 0 8px 8px 0;
color: var(--primary-color);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
z-index: 101;
transition: all 0.3s ease;
box-shadow: 4px 0 8px rgba(0, 0, 0, 0.3);
}
.sidebar-toggle:hover {
background: var(--bg-dark);
color: white;
}
.sidebar.collapsed .toggle-icon {
transform: rotate(180deg);
}
.toggle-icon {
font-size: 0.7rem;
transition: transform 0.3s ease;
}
.turbine-icon-container svg { .turbine-icon-container svg {
filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.5)); filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.5));
width: 100%; width: 100%;