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
104
renderer/app.js
104
renderer/app.js
@ -1719,18 +1719,16 @@ function renderSettings() {
|
|||||||
</div>
|
</div>
|
||||||
<div class="hoster-panel-body" data-panel="global" style="display:block">
|
<div class="hoster-panel-body" data-panel="global" style="display:block">
|
||||||
<div class="settings-section-label">Uploads</div>
|
<div class="settings-section-label">Uploads</div>
|
||||||
<div class="settings-grid-mini">
|
|
||||||
<div class="settings-row">
|
<div class="settings-row">
|
||||||
<label>Globale parallele Uploads</label>
|
<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">
|
<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>
|
<span class="hint">0 = nur pro Hoster</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="settings-row">
|
<div class="settings-row">
|
||||||
<label>Globales Speed-Limit (MB/s)</label>
|
<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">
|
<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>
|
<span class="hint">0 = unbegrenzt</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="settings-section-label">Verhalten</div>
|
<div class="settings-section-label">Verhalten</div>
|
||||||
<div class="settings-grid-mini">
|
<div class="settings-grid-mini">
|
||||||
<div class="settings-row checkbox-row">
|
<div class="settings-row checkbox-row">
|
||||||
@ -1769,6 +1767,15 @@ function renderSettings() {
|
|||||||
`;
|
`;
|
||||||
container.appendChild(generalPanel);
|
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 ---
|
// --- Folder Monitor Panel ---
|
||||||
const fm = globalSettings.folderMonitor || {};
|
const fm = globalSettings.folderMonitor || {};
|
||||||
const folderMonitorPanel = document.createElement('div');
|
const folderMonitorPanel = document.createElement('div');
|
||||||
@ -1780,20 +1787,12 @@ function renderSettings() {
|
|||||||
<span class="panel-status" id="folderMonitorStatusBadge">${fm.enabled && fm.folderPath ? 'Aktiv' : 'Inaktiv'}</span>
|
<span class="panel-status" id="folderMonitorStatusBadge">${fm.enabled && fm.folderPath ? 'Aktiv' : 'Inaktiv'}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="hoster-panel-body" data-panel="folderMonitor" style="display:none">
|
<div class="hoster-panel-body" data-panel="folderMonitor" style="display:none">
|
||||||
<div class="settings-grid-mini">
|
<div class="settings-section-label">Ordner</div>
|
||||||
<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">
|
<div class="settings-row">
|
||||||
<label>Ordnerpfad</label>
|
<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>
|
<button class="btn btn-xs btn-secondary" id="fmChooseFolderBtn">Wählen</button>
|
||||||
</div>
|
</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">
|
<div class="settings-row">
|
||||||
<label>Dateierweiterungen</label>
|
<label>Dateierweiterungen</label>
|
||||||
<select class="hs-input settings-autosave" id="fmFilterModeInput" style="width:auto;margin-right:6px">
|
<select class="hs-input settings-autosave" id="fmFilterModeInput" style="width:auto;margin-right:6px">
|
||||||
@ -1802,15 +1801,25 @@ function renderSettings() {
|
|||||||
</select>
|
</select>
|
||||||
<input type="text" class="key-input settings-autosave" id="fmExtensionsInput" value="${escapeAttr(fm.extensions || '')}" placeholder="mp4,mkv,avi" style="flex:1">
|
<input type="text" class="key-input settings-autosave" id="fmExtensionsInput" value="${escapeAttr(fm.extensions || '')}" placeholder="mp4,mkv,avi" style="flex:1">
|
||||||
</div>
|
</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">
|
<div class="settings-row checkbox-row">
|
||||||
<label>Duplikate überspringen</label>
|
<label>Duplikate überspringen</label>
|
||||||
<input type="checkbox" class="settings-autosave" id="fmSkipDuplicatesInput" ${fm.skipDuplicates !== false ? 'checked' : ''}>
|
<input type="checkbox" class="settings-autosave" id="fmSkipDuplicatesInput" ${fm.skipDuplicates !== false ? 'checked' : ''}>
|
||||||
</div>
|
</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">
|
<div class="settings-row checkbox-row">
|
||||||
<label>Auto-Upload starten</label>
|
<label>Auto-Upload starten</label>
|
||||||
<input type="checkbox" class="settings-autosave" id="fmAutoStartInput" ${fm.autoStart !== false ? 'checked' : ''}>
|
<input type="checkbox" class="settings-autosave" id="fmAutoStartInput" ${fm.autoStart !== false ? 'checked' : ''}>
|
||||||
@ -1829,14 +1838,62 @@ function renderSettings() {
|
|||||||
arrow.innerHTML = isOpen ? '▶' : '▼';
|
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 () => {
|
document.getElementById('fmChooseFolderBtn')?.addEventListener('click', async () => {
|
||||||
const folder = await window.api.folderMonitorSelectFolder();
|
const folder = await window.api.folderMonitorSelectFolder();
|
||||||
if (folder) {
|
if (folder) {
|
||||||
document.getElementById('fmFolderPathInput').value = folder;
|
document.getElementById('fmFolderPathInput').value = folder;
|
||||||
|
updateFmBadge();
|
||||||
scheduleSettingsSave();
|
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) {
|
if (configuredAccounts.length === 0) {
|
||||||
const empty = document.createElement('div');
|
const empty = document.createElement('div');
|
||||||
empty.className = 'settings-empty';
|
empty.className = 'settings-empty';
|
||||||
@ -2582,9 +2639,7 @@ function setupListeners() {
|
|||||||
});
|
});
|
||||||
document.getElementById('saveSettingsBtn').addEventListener('click', saveSettings);
|
document.getElementById('saveSettingsBtn').addEventListener('click', saveSettings);
|
||||||
|
|
||||||
// --- Backup export / import ---
|
// --- Backup export / import (modal listeners stay here, button listeners in renderSettings) ---
|
||||||
document.getElementById('exportBackupBtn').addEventListener('click', () => openBackupModal('export'));
|
|
||||||
document.getElementById('importBackupBtn').addEventListener('click', () => openBackupModal('import'));
|
|
||||||
document.getElementById('closeBackupModalBtn').addEventListener('click', closeBackupModal);
|
document.getElementById('closeBackupModalBtn').addEventListener('click', closeBackupModal);
|
||||||
document.getElementById('cancelBackupModalBtn').addEventListener('click', closeBackupModal);
|
document.getElementById('cancelBackupModalBtn').addEventListener('click', closeBackupModal);
|
||||||
document.getElementById('confirmBackupBtn').addEventListener('click', confirmBackupAction);
|
document.getElementById('confirmBackupBtn').addEventListener('click', confirmBackupAction);
|
||||||
@ -2649,6 +2704,7 @@ function setupListeners() {
|
|||||||
// Right-click on upload view background
|
// Right-click on upload view background
|
||||||
document.getElementById('upload-view').addEventListener('contextmenu', (e) => {
|
document.getElementById('upload-view').addEventListener('contextmenu', (e) => {
|
||||||
if (e.target.closest('.queue-row')) return; // handled per row
|
if (e.target.closest('.queue-row')) return; // handled per row
|
||||||
|
if (queueJobs.length === 0 && selectedFiles.length === 0) return; // nothing in queue
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
showContextMenu(e.clientX, e.clientY);
|
showContextMenu(e.clientX, e.clientY);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -219,14 +219,6 @@
|
|||||||
<span class="save-feedback" id="saveFeedback">Änderungen werden automatisch gespeichert.</span>
|
<span class="save-feedback" id="saveFeedback">Änderungen werden automatisch gespeichert.</span>
|
||||||
<button class="btn btn-secondary" id="saveSettingsBtn">Jetzt speichern</button>
|
<button class="btn btn-secondary" id="saveSettingsBtn">Jetzt speichern</button>
|
||||||
</div>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -662,7 +662,11 @@ body {
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
}
|
}
|
||||||
|
.checkbox-row {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
.checkbox-row input[type="checkbox"] {
|
.checkbox-row input[type="checkbox"] {
|
||||||
|
order: -1;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user