421 lines
21 KiB
PHP
421 lines
21 KiB
PHP
@extends('layouts.app')
|
|
|
|
@section('main_class', 'upload-page-only upload-page-responsive')
|
|
|
|
@section('title', 'Upload Video | ' . config('app.name'))
|
|
|
|
@section('extra_styles')
|
|
<style>
|
|
/* Hide custom header on mobile */
|
|
.upload-page-header { display: none !important; }
|
|
|
|
@media (max-width: 991px) {
|
|
.upload-page-only .yt-header, .upload-page-only .yt-sidebar { display: block !important; }
|
|
.upload-page-only .yt-main { display: block !important; margin-left: 0; }
|
|
.upload-page-only.upload-page-responsive { display: block; background: transparent; padding: 0; }
|
|
.upload-page-only.upload-page-responsive .upload-page-standalone { max-width: 100%; border-radius: 0; box-shadow: none; background: transparent; border: none; }
|
|
.upload-page-only.upload-page-responsive .upload-page-header { display: none !important; }
|
|
.upload-page-only.upload-page-responsive .upload-page-body { padding: 0; background: transparent; }
|
|
.upload-page-only.upload-page-responsive .form-input, .upload-page-only.upload-page-responsive .form-textarea { background: var(--bg-secondary); border-color: var(--border-color); color: var(--text-primary); }
|
|
.upload-page-only.upload-page-responsive .form-label { color: var(--text-primary); }
|
|
.upload-page-only.upload-page-responsive .visibility-content-modal { background: var(--bg-secondary); border-color: var(--border-color); }
|
|
.upload-page-only.upload-page-responsive .visibility-title { color: var(--text-primary); }
|
|
.upload-page-only.upload-page-responsive .visibility-desc { color: var(--text-secondary); }
|
|
}
|
|
|
|
@media (min-width: 992px) {
|
|
.upload-page-only { min-height: auto; display: block; padding: 20px; background: #121212; }
|
|
}
|
|
|
|
.upload-page-standalone {
|
|
background: #1a1a1a;
|
|
border: none;
|
|
border-radius: 0;
|
|
box-shadow: none;
|
|
overflow: hidden;
|
|
width: 100%;
|
|
max-width: 700px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
}
|
|
|
|
.upload-page-body { padding: 0; background: transparent; }
|
|
|
|
/* Form Groups */
|
|
.form-group { margin-bottom: 20px; }
|
|
.form-label { display: block; margin-bottom: 8px; font-weight: 500; font-size: 14px; color: #e5e5e5; }
|
|
.form-input, .form-textarea { width: 100%; background: #121212; border: 1px solid #333; border-radius: 8px; padding: 12px 16px; color: var(--text-primary); font-size: 14px; }
|
|
.form-input:focus, .form-textarea:focus { outline: none; border-color: var(--brand-red); }
|
|
.form-textarea { resize: vertical; min-height: 100px; }
|
|
|
|
/* Dropzone */
|
|
#dropzone {
|
|
border: 2px dashed var(--border-color);
|
|
border-radius: 12px;
|
|
padding: 60px 20px;
|
|
text-align: center;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
background: #151515;
|
|
}
|
|
#dropzone:hover, #dropzone.dragover { border-color: var(--brand-red); background: rgba(230, 30, 30, 0.05); }
|
|
#dropzone .icon { font-size: 48px; color: var(--text-secondary); margin-bottom: 16px; }
|
|
#dropzone p { color: var(--text-secondary); margin: 8px 0; }
|
|
#dropzone .hint { font-size: 12px; color: var(--text-secondary); opacity: 0.7; }
|
|
|
|
#video { display: none; }
|
|
|
|
#file-info { display: none; }
|
|
#file-info.active { display: flex; align-items: center; gap: 12px; padding: 16px; background: #1f1f1f; border-radius: 12px; border: 1px solid #333; }
|
|
#file-info .file-icon { width: 56px; height: 56px; background: #333; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 24px; color: white; flex-shrink: 0; }
|
|
#file-info .file-details { flex: 1; text-align: left; }
|
|
#file-info .filename { color: #e5e5e5; font-weight: 500; font-size: 14px; margin: 0 0 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
#file-info .filesize { color: #888; font-size: 13px; margin: 0; }
|
|
#file-info .btn-remove { width: 32px; height: 32px; border-radius: 50%; background: #333; border: none; color: #888; cursor: pointer; display: flex; align-items: center; justify-content: center; }
|
|
|
|
/* Options Grid */
|
|
.options-section { margin-bottom: 24px; }
|
|
.options-label { font-size: 14px; font-weight: 500; color: #e5e5e5; margin-bottom: 12px; display: block; }
|
|
.options-grid { display: flex; gap: 8px; flex-wrap: wrap; }
|
|
.option-item { flex: 1; min-width: 100px; cursor: pointer; }
|
|
.option-item input { display: none; }
|
|
.option-content { display: flex; align-items: center; gap: 10px; padding: 12px 14px; background: #1a1a1a; border: 2px solid #333; border-radius: 10px; transition: all 0.2s; }
|
|
.option-item:hover .option-content { border-color: #555; background: #1f1f1f; }
|
|
.option-item.active .option-content { border-color: var(--brand-red); background: rgba(230, 30, 30, 0.1); }
|
|
.option-content i { font-size: 18px; color: #666; width: 20px; text-align: center; }
|
|
.option-item.active .option-content i { color: var(--brand-red); }
|
|
.option-content span { font-size: 13px; color: #aaa; }
|
|
.option-item.active .option-content span { color: #fff; }
|
|
|
|
/* Two Column Layout */
|
|
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
|
|
|
/* Thumbnail Dropzone */
|
|
#thumbnail-dropzone {
|
|
border: 2px dashed #404040;
|
|
border-radius: 10px;
|
|
padding: 20px;
|
|
text-align: center;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
background: #151515;
|
|
position: relative;
|
|
}
|
|
#thumbnail-dropzone:hover { border-color: var(--brand-red); }
|
|
#thumbnail { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
|
|
#thumbnail-default i { font-size: 28px; color: #666; margin-bottom: 6px; }
|
|
#thumbnail-default p { color: #888; font-size: 13px; margin: 0; }
|
|
#thumbnail-info { display: none; }
|
|
#thumbnail-info.active { display: block; }
|
|
#thumbnail-info img { max-width: 100%; max-height: 120px; border-radius: 8px; }
|
|
|
|
/* Progress */
|
|
#progress-container { display: none; margin: 20px 0; }
|
|
#progress-container.active { display: block; }
|
|
.progress-bar-fill { background: var(--brand-red); height: 4px; width: 0%; transition: width 0.3s; border-radius: 2px; }
|
|
.progress-text { text-align: center; color: var(--text-secondary); font-size: 13px; margin-top: 8px; }
|
|
|
|
/* Status */
|
|
#status-message { display: none; padding: 12px 16px; border-radius: 8px; margin-bottom: 16px; font-size: 13px; }
|
|
#status-message.success { display: block; background: rgba(34, 197, 94, 0.2); color: #4ade80; border: 1px solid rgba(34, 197, 94, 0.3); }
|
|
#status-message.error { display: block; background: rgba(239, 68, 68, 0.2); color: #f87171; border: 1px solid rgba(239, 68, 68, 0.3); }
|
|
|
|
/* Submit Button */
|
|
.btn-submit {
|
|
width: 100%;
|
|
background: var(--brand-red);
|
|
color: white;
|
|
border: none;
|
|
padding: 14px 24px;
|
|
border-radius: 8px;
|
|
font-size: 15px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: background 0.2s;
|
|
}
|
|
.btn-submit:hover { background: #cc1a1a; }
|
|
.btn-submit:disabled { background: #555; cursor: not-allowed; }
|
|
|
|
@media (max-width: 600px) {
|
|
.form-row { grid-template-columns: 1fr; }
|
|
.options-grid { flex-direction: column; }
|
|
.option-item { min-width: 100%; }
|
|
}
|
|
</style>
|
|
@endsection
|
|
|
|
@section('content')
|
|
<div class="upload-page-standalone">
|
|
<div class="upload-page-body">
|
|
<form id="upload-form" enctype="multipart/form-data">
|
|
@csrf
|
|
|
|
<!-- Video File Dropzone -->
|
|
<div class="form-group">
|
|
<label class="form-label">Video File *</label>
|
|
<div id="dropzone">
|
|
<input type="file" name="video" id="video" accept="video/*" required>
|
|
<div id="dropzone-default">
|
|
<div class="icon"><i class="bi bi-cloud-arrow-up"></i></div>
|
|
<p>Click to select or drag video here</p>
|
|
<p class="hint">MP4, MOV, AVI, WebM and more</p>
|
|
</div>
|
|
<div id="file-info">
|
|
<div class="file-icon"><i class="bi bi-film"></i></div>
|
|
<div class="file-details">
|
|
<p class="filename" id="filename"></p>
|
|
<p class="filesize" id="filesize"></p>
|
|
</div>
|
|
<button type="button" class="btn-remove" onclick="removeVideo(event)"><i class="bi bi-x-lg"></i></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Title -->
|
|
<div class="form-group">
|
|
<label class="form-label">Title *</label>
|
|
<input type="text" name="title" id="video-title" required class="form-input" placeholder="Enter video title">
|
|
</div>
|
|
|
|
<!-- Description -->
|
|
<div class="form-group">
|
|
<label class="form-label">Description</label>
|
|
<textarea name="description" id="video-description" rows="4" class="form-textarea" placeholder="Tell viewers about your video (Markdown supported)"></textarea>
|
|
</div>
|
|
|
|
<!-- Thumbnail -->
|
|
<div class="form-group">
|
|
<label class="form-label">Thumbnail</label>
|
|
<div id="thumbnail-dropzone">
|
|
<input type="file" name="thumbnail" id="thumbnail" accept="image/*">
|
|
<div id="thumbnail-default">
|
|
<i class="bi bi-card-image"></i>
|
|
<p>Click to select thumbnail (optional)</p>
|
|
</div>
|
|
<div id="thumbnail-info">
|
|
<img id="thumbnail-preview-img" src="" alt="Thumbnail preview">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Video Type -->
|
|
<div class="options-section">
|
|
<span class="options-label">Video Type</span>
|
|
<div class="options-grid" id="type-options">
|
|
<label class="option-item active" data-type="generic">
|
|
<input type="radio" name="type" value="generic" checked>
|
|
<div class="option-content">
|
|
<i class="bi bi-film"></i>
|
|
<span>Generic</span>
|
|
</div>
|
|
</label>
|
|
<label class="option-item" data-type="music">
|
|
<input type="radio" name="type" value="music">
|
|
<div class="option-content">
|
|
<i class="bi bi-music-note"></i>
|
|
<span>Music</span>
|
|
</div>
|
|
</label>
|
|
<label class="option-item" data-type="match">
|
|
<input type="radio" name="type" value="match">
|
|
<div class="option-content">
|
|
<i class="bi bi-trophy"></i>
|
|
<span>Match</span>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Privacy -->
|
|
<div class="options-section">
|
|
<span class="options-label">Privacy</span>
|
|
<div class="options-grid" id="visibility-options">
|
|
<label class="option-item active" data-privacy="public">
|
|
<input type="radio" name="visibility" value="public" checked>
|
|
<div class="option-content">
|
|
<i class="bi bi-globe"></i>
|
|
<span>Public</span>
|
|
</div>
|
|
</label>
|
|
<label class="option-item" data-privacy="unlisted">
|
|
<input type="radio" name="visibility" value="unlisted">
|
|
<div class="option-content">
|
|
<i class="bi bi-link-45deg"></i>
|
|
<span>Unlisted</span>
|
|
</div>
|
|
</label>
|
|
<label class="option-item" data-privacy="private">
|
|
<input type="radio" name="visibility" value="private">
|
|
<div class="option-content">
|
|
<i class="bi bi-lock"></i>
|
|
<span>Private</span>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Hidden Shorts - Auto-detected -->
|
|
<input type="hidden" name="is_shorts" id="is_shorts" value="0">
|
|
|
|
<!-- Progress Bar -->
|
|
<div id="progress-container">
|
|
<div class="progress-bar-wrapper">
|
|
<div id="progress-bar" class="progress-bar-fill"></div>
|
|
</div>
|
|
<p id="progress-text" class="progress-text">Uploading... 0%</p>
|
|
</div>
|
|
|
|
<!-- Status Message -->
|
|
<div id="status-message"></div>
|
|
|
|
<!-- Submit Button -->
|
|
<button type="submit" id="submit-btn" class="btn-submit">
|
|
<i class="bi bi-cloud-arrow-up-fill"></i> Upload Video
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
@endsection
|
|
|
|
@section('scripts')
|
|
<script>
|
|
// Video Dropzone
|
|
const dropzone = document.getElementById('dropzone');
|
|
const fileInput = document.getElementById('video');
|
|
let currentFile = null;
|
|
|
|
fileInput.addEventListener('change', function() { handleFileSelect(this); });
|
|
dropzone.addEventListener('click', function(e) { if (e.target.classList.contains('btn-remove')) return; fileInput.click(); });
|
|
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');
|
|
if (e.dataTransfer.files.length) { fileInput.files = e.dataTransfer.files; handleFileSelect(fileInput); }
|
|
});
|
|
|
|
function handleFileSelect(input) {
|
|
if (input.files && input.files[0]) {
|
|
const file = input.files[0];
|
|
currentFile = file;
|
|
|
|
// Set title from filename
|
|
const fileNameWithoutExt = file.name.replace(/\.[^/.]+$/, '').replace(/[-_]/g, ' ');
|
|
document.getElementById('video-title').value = fileNameWithoutExt;
|
|
|
|
document.getElementById('filename').textContent = file.name;
|
|
document.getElementById('filesize').textContent = formatFileSize(file.size);
|
|
document.getElementById('dropzone-default').style.display = 'none';
|
|
document.getElementById('file-info').classList.add('active');
|
|
}
|
|
}
|
|
|
|
function formatFileSize(bytes) {
|
|
if (bytes === 0) return '0 Bytes';
|
|
const k = 1024;
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
}
|
|
|
|
function removeVideo(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
fileInput.value = '';
|
|
currentFile = null;
|
|
document.getElementById('dropzone-default').style.display = 'block';
|
|
document.getElementById('file-info').classList.remove('active');
|
|
document.getElementById('video-title').value = '';
|
|
}
|
|
|
|
// Thumbnail
|
|
const thumbnailInput = document.getElementById('thumbnail');
|
|
const thumbnailDropzone = document.getElementById('thumbnail-dropzone');
|
|
|
|
thumbnailInput.addEventListener('change', function() {
|
|
if (this.files && this.files[0]) {
|
|
const reader = new FileReader();
|
|
reader.onload = function(e) {
|
|
document.getElementById('thumbnail-preview-img').src = e.target.result;
|
|
};
|
|
reader.readAsDataURL(this.files[0]);
|
|
document.getElementById('thumbnail-default').style.display = 'none';
|
|
document.getElementById('thumbnail-info').classList.add('active');
|
|
}
|
|
});
|
|
|
|
// Option handlers
|
|
document.querySelectorAll('#type-options .option-item').forEach(item => {
|
|
item.querySelector('input').addEventListener('change', function() {
|
|
document.querySelectorAll('#type-options .option-item').forEach(o => o.classList.remove('active'));
|
|
item.classList.add('active');
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('#visibility-options .option-item').forEach(item => {
|
|
item.querySelector('input').addEventListener('change', function() {
|
|
document.querySelectorAll('#visibility-options .option-item').forEach(o => o.classList.remove('active'));
|
|
item.classList.add('active');
|
|
});
|
|
});
|
|
|
|
// Form submission
|
|
document.getElementById('upload-form').addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
if (!currentFile) {
|
|
showError('Please select a video file');
|
|
return;
|
|
}
|
|
|
|
const formData = new FormData(this);
|
|
const xhr = new XMLHttpRequest();
|
|
|
|
document.getElementById('progress-container').classList.add('active');
|
|
document.getElementById('submit-btn').disabled = true;
|
|
document.getElementById('submit-btn').innerHTML = '<i class="bi bi-arrow-repeat"></i> Uploading...';
|
|
document.getElementById('status-message').className = '';
|
|
|
|
xhr.upload.addEventListener('progress', function(e) {
|
|
if (e.lengthComputable) {
|
|
const percent = Math.round((e.loaded / e.total) * 100);
|
|
document.getElementById('progress-bar').style.width = percent + '%';
|
|
document.getElementById('progress-text').textContent = 'Uploading... ' + percent + '%';
|
|
}
|
|
});
|
|
|
|
xhr.addEventListener('load', function() {
|
|
document.getElementById('progress-bar').style.width = '100%';
|
|
document.getElementById('progress-text').textContent = 'Processing...';
|
|
|
|
try {
|
|
const response = JSON.parse(xhr.responseText);
|
|
if (response.success) {
|
|
document.getElementById('progress-text').textContent = 'Done! Redirecting...';
|
|
window.location.href = response.redirect;
|
|
} else {
|
|
showError(response.message || 'Upload failed');
|
|
}
|
|
} catch(e) {
|
|
showError('Invalid response from server');
|
|
}
|
|
});
|
|
|
|
xhr.addEventListener('error', function() { showError('Upload failed. Please try again.'); });
|
|
|
|
xhr.open('POST', '{{ route("videos.store") }}');
|
|
xhr.setRequestHeader('X-CSRF-TOKEN', '{{ csrf_token() }}');
|
|
xhr.send(formData);
|
|
});
|
|
|
|
function showError(message) {
|
|
const status = document.getElementById('status-message');
|
|
status.innerHTML = '<i class="bi bi-exclamation-circle-fill"></i> ' + message;
|
|
status.className = 'error';
|
|
document.getElementById('submit-btn').disabled = false;
|
|
document.getElementById('submit-btn').innerHTML = '<i class="bi bi-cloud-arrow-up-fill"></i> Upload Video';
|
|
document.getElementById('progress-container').classList.remove('active');
|
|
}
|
|
</script>
|
|
@endsection
|