diff --git a/renderer/app.js b/renderer/app.js index 8309a31..f9697af 100644 --- a/renderer/app.js +++ b/renderer/app.js @@ -24,6 +24,7 @@ let queuePersistTimer = null; let settingsSaveTimer = null; let lastUploadStats = { state: 'idle', globalSpeedKbs: 0, totalBytes: 0, elapsed: 0, activeJobs: 0 }; const AUTO_CHECK_PREF_KEY = 'autoHealthCheckBeforeUpload'; +const QUEUE_COL_WIDTHS_KEY = 'queueColumnWidthsPx'; const STARTABLE_QUEUE_STATUSES = new Set(['preview', 'queued', 'error', 'aborted', 'skipped']); function isStartableQueueStatus(status) { @@ -71,6 +72,7 @@ async function init() { renderAccounts(); setupListeners(); setupDragDrop(); + restoreQueueColumnWidths(); loadHistory(); renderRecentUploadsPanel(); updateUploadView(); @@ -3263,7 +3265,9 @@ function setupListeners() { // Queue table sorting document.querySelectorAll('#queueTable th.sortable').forEach(th => { - th.addEventListener('click', () => { + th.addEventListener('click', (e) => { + // Don't sort if click was on the resizer handle + if (e.target.classList.contains('col-resizer')) return; const key = th.dataset.sort; if (queueSortState.key === key) queueSortState.direction = queueSortState.direction === 'asc' ? 'desc' : 'asc'; else { queueSortState.key = key; queueSortState.direction = 'asc'; } @@ -3272,6 +3276,9 @@ function setupListeners() { }); }); + // Queue table column resizing (JDownloader-style) + setupColumnResizing(); + // Shutdown cancel document.getElementById('cancelShutdownBtn').addEventListener('click', async () => { await window.api.cancelShutdown(); @@ -3516,6 +3523,67 @@ function loadAutoCheckPreference() { catch { return true; } } +// --- Queue table column resizing (JDownloader-style) --- +function restoreQueueColumnWidths() { + try { + const raw = localStorage.getItem(QUEUE_COL_WIDTHS_KEY); + if (!raw) return; + const widths = JSON.parse(raw); + if (!widths || typeof widths !== 'object') return; + for (const [col, px] of Object.entries(widths)) { + const th = document.querySelector(`#queueTable th[data-col="${col}"]`); + if (th && typeof px === 'number' && px > 20) { + th.style.width = px + 'px'; + } + } + } catch {} +} + +function saveQueueColumnWidths() { + try { + const widths = {}; + document.querySelectorAll('#queueTable th[data-col]').forEach(th => { + widths[th.dataset.col] = th.getBoundingClientRect().width; + }); + localStorage.setItem(QUEUE_COL_WIDTHS_KEY, JSON.stringify(widths)); + } catch {} +} + +function setupColumnResizing() { + const headers = document.querySelectorAll('#queueTable th[data-col]'); + headers.forEach(th => { + const resizer = th.querySelector('.col-resizer'); + if (!resizer) return; + + resizer.addEventListener('mousedown', (e) => { + e.preventDefault(); + e.stopPropagation(); + + const startX = e.clientX; + const startWidth = th.getBoundingClientRect().width; + resizer.classList.add('dragging'); + document.body.classList.add('col-resizing'); + + const onMove = (ev) => { + const delta = ev.clientX - startX; + const newWidth = Math.max(40, startWidth + delta); + th.style.width = newWidth + 'px'; + }; + + const onUp = () => { + document.removeEventListener('mousemove', onMove); + document.removeEventListener('mouseup', onUp); + resizer.classList.remove('dragging'); + document.body.classList.remove('col-resizing'); + saveQueueColumnWidths(); + }; + + document.addEventListener('mousemove', onMove); + document.addEventListener('mouseup', onUp); + }); + }); +} + function escapeHtml(str) { if (!str) return ''; return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); diff --git a/renderer/index.html b/renderer/index.html index 803e789..9fc38bb 100644 --- a/renderer/index.html +++ b/renderer/index.html @@ -77,14 +77,14 @@ - - - - - - - - + + + + + + + + diff --git a/renderer/styles.css b/renderer/styles.css index 43426b3..39c7c59 100644 --- a/renderer/styles.css +++ b/renderer/styles.css @@ -267,6 +267,23 @@ body { } .queue-table th.sortable { cursor: pointer; } .queue-table th.sortable:hover { color: var(--text); } +.queue-table th { position: relative; } + +.col-resizer { + position: absolute; + top: 0; + right: 0; + width: 6px; + height: 100%; + cursor: col-resize; + user-select: none; + z-index: 6; + background: transparent; + transition: background 0.15s; +} +.col-resizer:hover { background: rgba(102, 126, 234, 0.4); } +.col-resizer.dragging { background: rgba(102, 126, 234, 0.6); } +body.col-resizing, body.col-resizing * { cursor: col-resize !important; user-select: none !important; } .col-filename { width: 30%; } .col-size { width: 12%; }
FilenameUploaded / SizeHostStatusZeitRestSpeedProgressFilenameUploaded / SizeHostStatusZeitRestSpeedProgress