feat: add drop target overlay and statusbar colons
- Full-window drop overlay with large "+" icon when dragging files over the app - Works from any tab, not just the upload view - Added colons to all statusbar labels for consistency Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a5c1ec362d
commit
c0b9ec9d17
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "multi-hoster-uploader",
|
"name": "multi-hoster-uploader",
|
||||||
"version": "1.9.5",
|
"version": "1.9.6",
|
||||||
"description": "Upload files to doodstream, voe, vidmoly, byse simultaneously",
|
"description": "Upload files to doodstream, voe, vidmoly, byse simultaneously",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -414,11 +414,39 @@ function setupDragDrop() {
|
|||||||
const dropZone = document.getElementById('dropZone');
|
const dropZone = document.getElementById('dropZone');
|
||||||
// Allow drop on the entire upload view
|
// Allow drop on the entire upload view
|
||||||
const uploadView = document.getElementById('upload-view');
|
const uploadView = document.getElementById('upload-view');
|
||||||
|
const dropOverlay = document.getElementById('dropOverlay');
|
||||||
|
|
||||||
|
// Window-level drag overlay
|
||||||
|
let dragCounter = 0;
|
||||||
|
window.addEventListener('dragenter', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!e.dataTransfer.types.includes('Files')) return;
|
||||||
|
dragCounter++;
|
||||||
|
dropOverlay.classList.add('visible');
|
||||||
|
});
|
||||||
|
window.addEventListener('dragleave', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
dragCounter--;
|
||||||
|
if (dragCounter <= 0) { dragCounter = 0; dropOverlay.classList.remove('visible'); }
|
||||||
|
});
|
||||||
|
window.addEventListener('dragover', (e) => { e.preventDefault(); });
|
||||||
|
let _dropHandled = false;
|
||||||
|
window.addEventListener('drop', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
dragCounter = 0;
|
||||||
|
dropOverlay.classList.remove('visible');
|
||||||
|
// Process files dropped anywhere (fallback if no specific handler caught it)
|
||||||
|
if (!_dropHandled && e.dataTransfer.files.length > 0) {
|
||||||
|
addDroppedFiles(e.dataTransfer.files).catch(console.error);
|
||||||
|
}
|
||||||
|
_dropHandled = false;
|
||||||
|
});
|
||||||
|
|
||||||
dropZone.addEventListener('dragover', (e) => { e.preventDefault(); e.stopPropagation(); dropZone.classList.add('drag-over'); });
|
dropZone.addEventListener('dragover', (e) => { e.preventDefault(); e.stopPropagation(); dropZone.classList.add('drag-over'); });
|
||||||
dropZone.addEventListener('dragleave', (e) => { e.preventDefault(); dropZone.classList.remove('drag-over'); });
|
dropZone.addEventListener('dragleave', (e) => { e.preventDefault(); dropZone.classList.remove('drag-over'); });
|
||||||
dropZone.addEventListener('drop', (e) => {
|
dropZone.addEventListener('drop', (e) => {
|
||||||
e.preventDefault(); e.stopPropagation(); dropZone.classList.remove('drag-over');
|
e.preventDefault(); e.stopPropagation(); dropZone.classList.remove('drag-over');
|
||||||
|
_dropHandled = true;
|
||||||
addDroppedFiles(e.dataTransfer.files).catch(console.error);
|
addDroppedFiles(e.dataTransfer.files).catch(console.error);
|
||||||
});
|
});
|
||||||
dropZone.addEventListener('click', () => pickFiles());
|
dropZone.addEventListener('click', () => pickFiles());
|
||||||
@ -428,6 +456,7 @@ function setupDragDrop() {
|
|||||||
uploadView.addEventListener('drop', (e) => {
|
uploadView.addEventListener('drop', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (e.target.closest('.drop-zone')) return; // handled above
|
if (e.target.closest('.drop-zone')) return; // handled above
|
||||||
|
_dropHandled = true;
|
||||||
addDroppedFiles(e.dataTransfer.files).catch(console.error);
|
addDroppedFiles(e.dataTransfer.files).catch(console.error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1636,12 +1665,12 @@ function updateStatusBar() {
|
|||||||
const uploadedSize = Math.max(0, stats.totalSize - stats.remainingSize);
|
const uploadedSize = Math.max(0, stats.totalSize - stats.remainingSize);
|
||||||
document.getElementById('sbTotal').textContent = `${formatSize(uploadedSize)} / ${formatSize(stats.totalSize)}`;
|
document.getElementById('sbTotal').textContent = `${formatSize(uploadedSize)} / ${formatSize(stats.totalSize)}`;
|
||||||
document.getElementById('sbEta').textContent = `ETA ${etaSeconds > 0 ? formatTime(etaSeconds) : '--:--'}`;
|
document.getElementById('sbEta').textContent = `ETA ${etaSeconds > 0 ? formatTime(etaSeconds) : '--:--'}`;
|
||||||
document.getElementById('sbConnections').textContent = `Aktive Verbindungen ${lastUploadStats.activeJobs || 0}`;
|
document.getElementById('sbConnections').textContent = `Aktive Verbindungen: ${lastUploadStats.activeJobs || 0}`;
|
||||||
document.getElementById('sbQueueCount').textContent = `Gesamt ${stats.total}`;
|
document.getElementById('sbQueueCount').textContent = `Gesamt: ${stats.total}`;
|
||||||
document.getElementById('sbRemainingCount').textContent = `Remaining ${stats.remaining}`;
|
document.getElementById('sbRemainingCount').textContent = `Remaining: ${stats.remaining}`;
|
||||||
document.getElementById('sbInProgressCount').textContent = `In Progress ${stats.inProgress}`;
|
document.getElementById('sbInProgressCount').textContent = `In Progress: ${stats.inProgress}`;
|
||||||
document.getElementById('sbDoneCount').textContent = `Done ${stats.done}`;
|
document.getElementById('sbDoneCount').textContent = `Done: ${stats.done}`;
|
||||||
document.getElementById('sbErrorCount').textContent = `Error ${stats.errors}`;
|
document.getElementById('sbErrorCount').textContent = `Error: ${stats.errors}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Health Check ---
|
// --- Health Check ---
|
||||||
|
|||||||
@ -7,6 +7,13 @@
|
|||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div id="dropOverlay" class="drop-overlay">
|
||||||
|
<div class="drop-overlay-content">
|
||||||
|
<div class="drop-overlay-icon">+</div>
|
||||||
|
<p>Dateien hier ablegen</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<nav class="tab-bar">
|
<nav class="tab-bar">
|
||||||
<button class="tab active" data-view="upload">Upload</button>
|
<button class="tab active" data-view="upload">Upload</button>
|
||||||
<button class="tab" data-view="accounts">Accounts</button>
|
<button class="tab" data-view="accounts">Accounts</button>
|
||||||
|
|||||||
@ -169,6 +169,36 @@ body {
|
|||||||
box-shadow: var(--panel-shadow);
|
box-shadow: var(--panel-shadow);
|
||||||
}
|
}
|
||||||
.drop-zone:hover, .drop-zone.drag-over { border-color: rgba(126, 220, 255, 0.6); background-color: rgba(62, 167, 255, 0.06); }
|
.drop-zone:hover, .drop-zone.drag-over { border-color: rgba(126, 220, 255, 0.6); background-color: rgba(62, 167, 255, 0.06); }
|
||||||
|
|
||||||
|
/* Drop overlay (full-window drop target) */
|
||||||
|
.drop-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 9999;
|
||||||
|
background: rgba(16, 18, 22, 0.92);
|
||||||
|
backdrop-filter: blur(6px);
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.drop-overlay.visible { display: flex; }
|
||||||
|
.drop-overlay-content {
|
||||||
|
text-align: center;
|
||||||
|
color: rgba(126, 220, 255, 0.9);
|
||||||
|
}
|
||||||
|
.drop-overlay-icon {
|
||||||
|
font-size: 120px;
|
||||||
|
font-weight: 200;
|
||||||
|
line-height: 1;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: rgba(126, 220, 255, 0.8);
|
||||||
|
}
|
||||||
|
.drop-overlay-content p {
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
.drop-icon { font-size: 40px; margin-bottom: 8px; }
|
.drop-icon { font-size: 40px; margin-bottom: 8px; }
|
||||||
|
|
||||||
/* Queue Container */
|
/* Queue Container */
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user