fixing upload

This commit is contained in:
x
2026-01-24 01:28:14 +01:00
parent c822a4f4e7
commit 43da214f73
2 changed files with 108 additions and 23 deletions

View File

@@ -5,6 +5,7 @@
const fileInput = document.getElementById('file-input'); const fileInput = document.getElementById('file-input');
const dropZone = document.getElementById('drop-zone'); const dropZone = document.getElementById('drop-zone');
const filePreview = document.getElementById('file-preview'); const filePreview = document.getElementById('file-preview');
// Note: prompt is now a label, but accessible via class
const dropZonePrompt = dropZone.querySelector('.drop-zone-prompt'); const dropZonePrompt = dropZone.querySelector('.drop-zone-prompt');
const fileName = document.getElementById('file-name'); const fileName = document.getElementById('file-name');
const fileSize = document.getElementById('file-size'); const fileSize = document.getElementById('file-size');
@@ -23,6 +24,43 @@
let tags = []; let tags = [];
let selectedFile = null; let selectedFile = null;
// Flash Message Logic
const showFlash = (msg, type = 'success') => {
const existing = document.querySelector('.flash-message');
if (existing) existing.remove();
const flash = document.createElement('div');
flash.className = `flash-message ${type}`;
flash.textContent = msg;
Object.assign(flash.style, {
position: 'fixed',
top: '20px',
left: '50%',
transform: 'translateX(-50%)',
padding: '15px 30px',
borderRadius: '5px',
color: '#fff',
fontWeight: '600',
zIndex: '9999',
boxShadow: '0 4px 12px rgba(0,0,0,0.3)',
background: type === 'success' ? '#51cf66' : '#ff6b6b',
opacity: '0',
transition: 'opacity 0.3s'
});
document.body.appendChild(flash);
// Fade in
requestAnimationFrame(() => flash.style.opacity = '1');
// Remove after 5s
setTimeout(() => {
flash.style.opacity = '0';
setTimeout(() => flash.remove(), 300);
}, 5000);
};
const formatSize = (bytes) => { const formatSize = (bytes) => {
const units = ['B', 'KB', 'MB', 'GB']; const units = ['B', 'KB', 'MB', 'GB'];
let i = 0; let i = 0;
@@ -59,7 +97,11 @@
if (!file) return; if (!file) return;
const validTypes = ['video/mp4', 'video/webm']; const validTypes = ['video/mp4', 'video/webm'];
if (!validTypes.includes(file.type)) { // Check extensions as fallback
const ext = file.name.split('.').pop().toLowerCase();
const validExts = ['mp4', 'webm'];
if (!validTypes.includes(file.type) && !validExts.includes(ext)) {
statusDiv.textContent = 'Only mp4 and webm files are allowed'; statusDiv.textContent = 'Only mp4 and webm files are allowed';
statusDiv.className = 'upload-status error'; statusDiv.className = 'upload-status error';
return; return;
@@ -72,9 +114,56 @@
filePreview.style.display = 'flex'; filePreview.style.display = 'flex';
statusDiv.textContent = ''; statusDiv.textContent = '';
statusDiv.className = 'upload-status'; statusDiv.className = 'upload-status';
// Video Preview
const itemPreview = filePreview.querySelector('.item-preview') || document.createElement('div');
itemPreview.className = 'item-preview';
itemPreview.style.marginRight = '15px';
// Clear previous
const existingVid = filePreview.querySelector('video');
if (existingVid) existingVid.remove();
const vid = document.createElement('video');
vid.src = URL.createObjectURL(file);
vid.controls = false;
vid.autoplay = true;
vid.muted = true;
vid.loop = true;
vid.style.maxHeight = '100px';
vid.style.maxWidth = '150px';
vid.style.borderRadius = '4px';
filePreview.prepend(vid);
updateSubmitButton(); updateSubmitButton();
}; };
const preventDefaults = (e) => {
e.preventDefault();
e.stopPropagation();
};
// Attach drag events only to dropZone now (Input is hidden)
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, preventDefaults, false);
});
['dragenter', 'dragover'].forEach(eventName => {
dropZone.addEventListener(eventName, () => dropZone.classList.add('dragover'), false);
});
['dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, () => dropZone.classList.remove('dragover'), false);
});
dropZone.addEventListener('drop', (e) => {
const dt = e.dataTransfer;
const files = dt.files;
handleFile(files[0]);
});
// Native change listener on hidden input
fileInput.addEventListener('change', (e) => handleFile(e.target.files[0])); fileInput.addEventListener('change', (e) => handleFile(e.target.files[0]));
removeFile.addEventListener('click', (e) => { removeFile.addEventListener('click', (e) => {
@@ -84,24 +173,13 @@
fileInput.value = ''; fileInput.value = '';
dropZonePrompt.style.display = 'block'; dropZonePrompt.style.display = 'block';
filePreview.style.display = 'none'; filePreview.style.display = 'none';
// Clear preview video
const vid = filePreview.querySelector('video');
if (vid) vid.remove();
updateSubmitButton(); updateSubmitButton();
}); });
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.classList.add('dragover');
});
dropZone.addEventListener('dragleave', () => {
dropZone.classList.remove('dragover');
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.classList.remove('dragover');
handleFile(e.dataTransfer.files[0]);
});
const addTag = (tagName) => { const addTag = (tagName) => {
tagName = tagName.trim().toLowerCase(); tagName = tagName.trim().toLowerCase();
if (!tagName || tags.includes(tagName)) return; if (!tagName || tags.includes(tagName)) return;
@@ -215,18 +293,24 @@
if (res.success) { if (res.success) {
statusDiv.innerHTML = '✓ ' + res.msg; statusDiv.innerHTML = '✓ ' + res.msg;
statusDiv.className = 'upload-status success'; statusDiv.className = 'upload-status success';
// Flash Message
showFlash(res.msg, 'success');
form.reset(); form.reset();
tags = []; tags = [];
tagsList.innerHTML = ''; tagsList.innerHTML = '';
selectedFile = null; selectedFile = null;
dropZonePrompt.style.display = 'block'; dropZonePrompt.style.display = 'block'; // label is actually flex/block via CSS
filePreview.style.display = 'none'; filePreview.style.display = 'none';
const vid = filePreview.querySelector('video');
if (vid) vid.remove();
} else { } else {
statusDiv.textContent = '✕ ' + res.msg; statusDiv.textContent = '✕ ' + res.msg;
statusDiv.className = 'upload-status error'; statusDiv.className = 'upload-status error';
if (res.repost) { if (res.repost) {
statusDiv.innerHTML += ' <a href="/' + res.repost + '">View existing</a>'; statusDiv.innerHTML += ' <a href="/' + res.repost + '">View existing</a>';
} }
showFlash('Upload failed: ' + res.msg, 'error');
} }
submitBtn.querySelector('.btn-text').style.display = 'inline'; submitBtn.querySelector('.btn-text').style.display = 'inline';
@@ -239,6 +323,7 @@
xhr.onerror = () => { xhr.onerror = () => {
statusDiv.textContent = '✕ Upload failed. Please try again.'; statusDiv.textContent = '✕ Upload failed. Please try again.';
statusDiv.className = 'upload-status error'; statusDiv.className = 'upload-status error';
showFlash('Upload failed network error', 'error');
submitBtn.querySelector('.btn-text').style.display = 'inline'; submitBtn.querySelector('.btn-text').style.display = 'inline';
submitBtn.querySelector('.btn-loading').style.display = 'none'; submitBtn.querySelector('.btn-loading').style.display = 'none';
progressContainer.style.display = 'none'; progressContainer.style.display = 'none';
@@ -252,6 +337,7 @@
console.error(err); console.error(err);
statusDiv.textContent = '✕ Upload failed: ' + err.message; statusDiv.textContent = '✕ Upload failed: ' + err.message;
statusDiv.className = 'upload-status error'; statusDiv.className = 'upload-status error';
showFlash('Upload failed: ' + err.message, 'error');
submitBtn.querySelector('.btn-text').style.display = 'inline'; submitBtn.querySelector('.btn-text').style.display = 'inline';
submitBtn.querySelector('.btn-loading').style.display = 'none'; submitBtn.querySelector('.btn-loading').style.display = 'none';
updateSubmitButton(); updateSubmitButton();

View File

@@ -36,15 +36,16 @@
<div class="form-section"> <div class="form-section">
<label>Video File <span class="required">*</span></label> <label>Video File <span class="required">*</span></label>
<div class="drop-zone" id="drop-zone"> <div class="drop-zone" id="drop-zone">
<input type="file" id="file-input" name="file" accept="video/mp4,video/webm" required> <input type="file" id="file-input" name="file" accept="video/mp4,video/webm" style="display: none;">
<div class="drop-zone-prompt"> <label for="file-input" class="drop-zone-prompt"
style="cursor: pointer; display: block; width: 100%; height: 100%;">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path> <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
<polyline points="17 8 12 3 7 8"></polyline> <polyline points="17 8 12 3 7 8"></polyline>
<line x1="12" y1="3" x2="12" y2="15"></line> <line x1="12" y1="3" x2="12" y2="15"></line>
</svg> </svg>
<p>Drop your mp4 or webm here<br>or click to browse</p> <p>Drop your mp4 or webm here<br>or click to browse</p>
</div> </label>
<div class="file-preview" id="file-preview" style="display: none;"> <div class="file-preview" id="file-preview" style="display: none;">
<span class="file-name" id="file-name"></span> <span class="file-name" id="file-name"></span>
<span class="file-size" id="file-size"></span> <span class="file-size" id="file-size"></span>
@@ -104,9 +105,7 @@
<style> <style>
.upload-container { .upload-container {
max-width: 700px; margin: 0px 25px 0px 25px
margin: 2rem auto;
padding: 2rem;
} }
.upload-container h2 { .upload-container h2 {