fix: UI polish - settings layout, context menu, folder monitor badge

- Ordnerüberwachung panel: proper section layout matching Allgemein style
- Checkbox rows: compact spacing, checkbox before label via CSS order
- Upload inputs: consistent width, stacked vertically
- Backup section: moved to collapsible panel in settings
- Allgemein panel: collapsible
- Context menu: hidden when queue is empty
- Folder monitor badge: instant update on checkbox/path change
- Separator between system and hoster panels

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Administrator 2026-03-12 01:52:30 +01:00
parent b04de4036f
commit 0de9236e42
3 changed files with 87 additions and 35 deletions

View File

@ -1719,18 +1719,16 @@ function renderSettings() {
</div>
<div class="hoster-panel-body" data-panel="global" style="display:block">
<div class="settings-section-label">Uploads</div>
<div class="settings-grid-mini">
<div class="settings-row">
<label>Globale parallele Uploads</label>
<input type="number" class="hs-input settings-autosave" id="parallelUploadCountInput" value="${globalSettings.parallelUploadCount ?? 0}" min="0" max="100">
<label style="min-width:185px">Globale parallele Uploads</label>
<input type="number" class="hs-input settings-autosave" id="parallelUploadCountInput" value="${globalSettings.parallelUploadCount ?? 0}" min="0" max="100" style="width:80px">
<span class="hint">0 = nur pro Hoster</span>
</div>
<div class="settings-row">
<label>Globales Speed-Limit (MB/s)</label>
<input type="number" class="hs-input settings-autosave" id="globalMaxSpeedMbsInput" value="${globalSettings.globalMaxSpeedKbs > 0 ? (globalSettings.globalMaxSpeedKbs / 1024).toFixed(2).replace(/\\.00$/, '') : '0'}" min="0" step="0.1">
<label style="min-width:185px">Globales Speed-Limit (MB/s)</label>
<input type="number" class="hs-input settings-autosave" id="globalMaxSpeedMbsInput" value="${globalSettings.globalMaxSpeedKbs > 0 ? (globalSettings.globalMaxSpeedKbs / 1024).toFixed(2).replace(/\\.00$/, '') : '0'}" min="0" step="0.1" style="width:80px">
<span class="hint">0 = unbegrenzt</span>
</div>
</div>
<div class="settings-section-label">Verhalten</div>
<div class="settings-grid-mini">
<div class="settings-row checkbox-row">
@ -1769,6 +1767,15 @@ function renderSettings() {
`;
container.appendChild(generalPanel);
// Toggle general panel
generalPanel.querySelector('.hoster-panel-header').addEventListener('click', () => {
const body = generalPanel.querySelector('.hoster-panel-body');
const arrow = generalPanel.querySelector('.panel-arrow');
const isOpen = body.style.display !== 'none';
body.style.display = isOpen ? 'none' : 'block';
arrow.innerHTML = isOpen ? '&#9654;' : '&#9660;';
});
// --- Folder Monitor Panel ---
const fm = globalSettings.folderMonitor || {};
const folderMonitorPanel = document.createElement('div');
@ -1780,20 +1787,12 @@ function renderSettings() {
<span class="panel-status" id="folderMonitorStatusBadge">${fm.enabled && fm.folderPath ? 'Aktiv' : 'Inaktiv'}</span>
</div>
<div class="hoster-panel-body" data-panel="folderMonitor" style="display:none">
<div class="settings-grid-mini">
<div class="settings-row checkbox-row">
<label>Aktiviert</label>
<input type="checkbox" class="settings-autosave" id="fmEnabledInput" ${fm.enabled ? 'checked' : ''}>
</div>
<div class="settings-section-label">Ordner</div>
<div class="settings-row">
<label>Ordnerpfad</label>
<input type="text" class="key-input settings-autosave" id="fmFolderPathInput" value="${escapeAttr(fm.folderPath || '')}" placeholder="Ordner wählen...">
<input type="text" class="key-input settings-autosave" id="fmFolderPathInput" value="${escapeAttr(fm.folderPath || '')}" placeholder="Ordner wählen..." style="flex:1">
<button class="btn btn-xs btn-secondary" id="fmChooseFolderBtn">Wählen</button>
</div>
<div class="settings-row checkbox-row">
<label>Unterordner einbeziehen</label>
<input type="checkbox" class="settings-autosave" id="fmRecursiveInput" ${fm.recursive ? 'checked' : ''}>
</div>
<div class="settings-row">
<label>Dateierweiterungen</label>
<select class="hs-input settings-autosave" id="fmFilterModeInput" style="width:auto;margin-right:6px">
@ -1802,15 +1801,25 @@ function renderSettings() {
</select>
<input type="text" class="key-input settings-autosave" id="fmExtensionsInput" value="${escapeAttr(fm.extensions || '')}" placeholder="mp4,mkv,avi" style="flex:1">
</div>
<div class="settings-row">
<label>Verzögerung (Sekunden)</label>
<input type="number" class="hs-input settings-autosave" id="fmDelaySecInput" value="${fm.delaySec ?? 3}" min="1" max="300" style="width:80px">
<span class="hint">Warten bis Datei fertig geschrieben</span>
</div>
<div class="settings-section-label">Verhalten</div>
<div class="settings-grid-mini">
<div class="settings-row checkbox-row">
<label>Aktiviert</label>
<input type="checkbox" class="settings-autosave" id="fmEnabledInput" ${fm.enabled ? 'checked' : ''}>
</div>
<div class="settings-row checkbox-row">
<label>Unterordner einbeziehen</label>
<input type="checkbox" class="settings-autosave" id="fmRecursiveInput" ${fm.recursive ? 'checked' : ''}>
</div>
<div class="settings-row checkbox-row">
<label>Duplikate überspringen</label>
<input type="checkbox" class="settings-autosave" id="fmSkipDuplicatesInput" ${fm.skipDuplicates !== false ? 'checked' : ''}>
</div>
<div class="settings-row">
<label>Verzögerung (Sekunden)</label>
<input type="number" class="hs-input settings-autosave" id="fmDelaySecInput" value="${fm.delaySec ?? 3}" min="1" max="300">
<span class="hint">Warten bis Datei fertig geschrieben</span>
</div>
<div class="settings-row checkbox-row">
<label>Auto-Upload starten</label>
<input type="checkbox" class="settings-autosave" id="fmAutoStartInput" ${fm.autoStart !== false ? 'checked' : ''}>
@ -1829,14 +1838,62 @@ function renderSettings() {
arrow.innerHTML = isOpen ? '&#9654;' : '&#9660;';
});
// Update badge immediately on checkbox/path change
const updateFmBadge = () => {
const b = document.getElementById('folderMonitorStatusBadge');
if (!b) return;
const enabled = document.getElementById('fmEnabledInput')?.checked;
const hasPath = (document.getElementById('fmFolderPathInput')?.value || '').trim();
if (enabled && hasPath) { b.textContent = 'Aktiv'; b.className = 'panel-status active'; }
else { b.textContent = 'Inaktiv'; b.className = 'panel-status'; }
};
document.getElementById('fmEnabledInput')?.addEventListener('change', updateFmBadge);
document.getElementById('fmFolderPathInput')?.addEventListener('input', updateFmBadge);
document.getElementById('fmChooseFolderBtn')?.addEventListener('click', async () => {
const folder = await window.api.folderMonitorSelectFolder();
if (folder) {
document.getElementById('fmFolderPathInput').value = folder;
updateFmBadge();
scheduleSettingsSave();
}
});
// --- Backup Panel ---
const backupPanel = document.createElement('div');
backupPanel.className = 'hoster-settings-panel';
backupPanel.innerHTML = `
<div class="hoster-panel-header" data-hoster="backup">
<span class="panel-arrow">&#9654;</span>
<span class="panel-title">Backup</span>
<span class="panel-status active">System</span>
</div>
<div class="hoster-panel-body" data-panel="backup" style="display:none">
<p class="hint" style="margin:0 0 10px">Alle Accounts, Einstellungen und den Upload-Verlauf verschlüsselt exportieren oder importieren.</p>
<div style="display:flex;gap:8px">
<button class="btn btn-secondary" id="exportBackupBtn">Backup exportieren</button>
<button class="btn btn-secondary" id="importBackupBtn">Backup importieren</button>
</div>
</div>
`;
container.appendChild(backupPanel);
backupPanel.querySelector('.hoster-panel-header').addEventListener('click', () => {
const body = backupPanel.querySelector('.hoster-panel-body');
const arrow = backupPanel.querySelector('.panel-arrow');
const isOpen = body.style.display !== 'none';
body.style.display = isOpen ? 'none' : 'block';
arrow.innerHTML = isOpen ? '&#9654;' : '&#9660;';
});
document.getElementById('exportBackupBtn').addEventListener('click', () => openBackupModal('export'));
document.getElementById('importBackupBtn').addEventListener('click', () => openBackupModal('import'));
// --- Separator before hoster panels ---
const separator = document.createElement('div');
separator.style.cssText = 'height:16px';
container.appendChild(separator);
if (configuredAccounts.length === 0) {
const empty = document.createElement('div');
empty.className = 'settings-empty';
@ -2582,9 +2639,7 @@ function setupListeners() {
});
document.getElementById('saveSettingsBtn').addEventListener('click', saveSettings);
// --- Backup export / import ---
document.getElementById('exportBackupBtn').addEventListener('click', () => openBackupModal('export'));
document.getElementById('importBackupBtn').addEventListener('click', () => openBackupModal('import'));
// --- Backup export / import (modal listeners stay here, button listeners in renderSettings) ---
document.getElementById('closeBackupModalBtn').addEventListener('click', closeBackupModal);
document.getElementById('cancelBackupModalBtn').addEventListener('click', closeBackupModal);
document.getElementById('confirmBackupBtn').addEventListener('click', confirmBackupAction);
@ -2649,6 +2704,7 @@ function setupListeners() {
// Right-click on upload view background
document.getElementById('upload-view').addEventListener('contextmenu', (e) => {
if (e.target.closest('.queue-row')) return; // handled per row
if (queueJobs.length === 0 && selectedFiles.length === 0) return; // nothing in queue
e.preventDefault();
showContextMenu(e.clientX, e.clientY);
});

View File

@ -219,14 +219,6 @@
<span class="save-feedback" id="saveFeedback">Änderungen werden automatisch gespeichert.</span>
<button class="btn btn-secondary" id="saveSettingsBtn">Jetzt speichern</button>
</div>
<div class="settings-backup-section">
<h2>Backup</h2>
<p class="settings-hint">Alle Accounts, Einstellungen und den Upload-Verlauf verschlüsselt exportieren oder importieren.</p>
<div class="settings-backup-buttons">
<button class="btn btn-secondary" id="exportBackupBtn">Backup exportieren</button>
<button class="btn btn-secondary" id="importBackupBtn">Backup importieren</button>
</div>
</div>
</div>
</div>

View File

@ -662,7 +662,11 @@ body {
gap: 8px;
margin-bottom: 6px;
}
.checkbox-row {
margin-bottom: 0;
}
.checkbox-row input[type="checkbox"] {
order: -1;
width: 16px;
height: 16px;
}