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:
parent
b04de4036f
commit
0de9236e42
110
renderer/app.js
110
renderer/app.js
@ -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 ? '▶' : '▼';
|
||||
});
|
||||
|
||||
// --- Folder Monitor Panel ---
|
||||
const fm = globalSettings.folderMonitor || {};
|
||||
const folderMonitorPanel = document.createElement('div');
|
||||
@ -1780,37 +1787,39 @@ 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-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..." style="flex:1">
|
||||
<button class="btn btn-xs btn-secondary" id="fmChooseFolderBtn">Wählen</button>
|
||||
</div>
|
||||
<div class="settings-row">
|
||||
<label>Dateierweiterungen</label>
|
||||
<select class="hs-input settings-autosave" id="fmFilterModeInput" style="width:auto;margin-right:6px">
|
||||
<option value="include" ${fm.filterMode === 'include' ? 'selected' : ''}>Nur diese</option>
|
||||
<option value="exclude" ${fm.filterMode === 'exclude' ? 'selected' : ''}>Alle außer</option>
|
||||
</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">
|
||||
<label>Ordnerpfad</label>
|
||||
<input type="text" class="key-input settings-autosave" id="fmFolderPathInput" value="${escapeAttr(fm.folderPath || '')}" placeholder="Ordner wählen...">
|
||||
<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">
|
||||
<option value="include" ${fm.filterMode === 'include' ? 'selected' : ''}>Nur diese</option>
|
||||
<option value="exclude" ${fm.filterMode === 'exclude' ? 'selected' : ''}>Alle außer</option>
|
||||
</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 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 ? '▶' : '▼';
|
||||
});
|
||||
|
||||
// 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">▶</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 ? '▶' : '▼';
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
@ -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>
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user