Add video platform features: authentication, video management, user profiles, likes/views tracking

- Added authentication controllers (Login, Register)
- Added UserController for user profile management
- Added VideoController with full CRUD operations
- Added Video model with relationships (user, likes, views)
- Added User model enhancements (avatar, video relationships)
- Added database migrations for video_likes, video_views, user_avatar, video_visibility
- Added CompressVideoJob for video processing
- Added VideoUploaded mail notification
- Added authentication routes
- Updated web routes with video and user routes
- Added layout templates (app, plain, partials)
- Added user views (profile, settings, channel, history, liked)
- Added video views (create, edit, index, show)
- Added email templates
This commit is contained in:
ghassan committed 2026-02-25 00:03:02 +00:00
1 parent 6a2026df4b
commit 5253f89b63
35 files changed
+5092 -849

No files matched your search

@@ -0,0 +1,62 @@
<!-- Header -->
<header class="yt-header">
<div class="yt-header-left">
<button class="yt-menu-btn" onclick="toggleSidebar()">
<i class="bi bi-list fs-5"></i>
</button>
<a href="/videos" class="yt-logo">
<span class="yt-logo-text">TAKEONE</span>
</a>
</div>
<div class="yt-header-center d-none d-md-flex">
<form action="{{ route('videos.search') }}" method="GET" class="yt-search">
<input type="text" name="q" class="yt-search-input" placeholder="Search" value="{{ request('q') }}">
<button type="submit" class="yt-search-btn">
<i class="bi bi-search"></i>
</button>
</form>
<button class="yt-search-voice">
<i class="bi bi-mic-fill"></i>
</button>
</div>
<div class="yt-header-right">
@auth
<button type="button" class="yt-upload-btn" onclick="openUploadModal()">
<i class="bi bi-plus-lg"></i>
<span>Upload</span>
</button>
<!-- User Dropdown -->
<div class="dropdown">
<button class="yt-icon-btn" data-bs-toggle="dropdown" aria-expanded="false">
@if(Auth::user()->avatar)
<img src="{{ asset('storage/avatars/' . Auth::user()->avatar) }}" class="yt-user-avatar" alt="User">
@else
<img src="https://i.pravatar.cc/150?u={{ Auth::user()->id }}" class="yt-user-avatar" alt="User">
@endif
</button>
<ul class="dropdown-menu dropdown-menu-end dropdown-menu-dark">
<li><a class="dropdown-item" href="{{ route('profile') }}"><i class="bi bi-person"></i> Profile</a></li>
<li><a class="dropdown-item" href="{{ route('channel', Auth::user()->id) }}"><i class="bi bi-play-btn"></i> My Channel</a></li>
<li><a class="dropdown-item" href="{{ route('settings') }}"><i class="bi bi-gear"></i> Settings</a></li>
<li><hr class="dropdown-divider"></li>
<li>
<form method="POST" action="{{ route('logout') }}" class="m-0">
@csrf
<button type="submit" class="dropdown-item text-danger"><i class="bi bi-box-arrow-right"></i> Logout</button>
</form>
</li>
</ul>
</div>
@else
<!-- Login/Register for visitors -->
<a href="{{ route('login') }}" class="yt-upload-btn">
<i class="bi bi-box-arrow-in-right"></i>
<span>Login</span>
</a>
@endauth
</div>
</header>
@@ -0,0 +1,124 @@
<!-- Share Modal -->
<div class="modal fade" id="shareModal" tabindex="-1" aria-labelledby="shareModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content" style="background: var(--bg-secondary); border: 1px solid var(--border-color); border-radius: 16px;">
<div class="modal-header" style="border-bottom: 1px solid var(--border-color); padding: 20px 24px;">
<h5 class="modal-title" id="shareModalLabel" style="font-weight: 600; color: var(--text-primary);">
<i class="bi bi-share me-2"></i>Share Video
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body" style="padding: 24px;">
<p style="color: var(--text-secondary); margin-bottom: 16px;">Share this video with your friends:</p>
<div class="share-link-container" style="display: flex; gap: 8px; align-items: center;">
<input type="text" id="shareLinkInput" class="form-control" readonly
style="background: var(--bg-primary); border: 1px solid var(--border-color); color: var(--text-primary); padding: 12px 16px; border-radius: 8px;">
<button type="button" id="copyLinkBtn" class="btn-copy"
style="background: var(--brand-red); color: white; border: none; padding: 12px 20px; border-radius: 8px; font-weight: 500; cursor: pointer; white-space: nowrap; transition: background 0.2s;">
<i class="bi bi-clipboard me-1"></i> Copy
</button>
</div>
<div id="copySuccess" class="copy-success" style="display: none; margin-top: 12px; color: #4caf50; font-size: 14px; text-align: center;">
<i class="bi bi-check-circle-fill me-1"></i> Link copied to clipboard!
</div>
<div style="margin-top: 24px; padding-top: 16px; border-top: 1px solid var(--border-color);">
<p style="color: var(--text-secondary); font-size: 13px; margin-bottom: 12px;">Share on social media:</p>
<div style="display: flex; gap: 12px;">
<a href="#" id="shareFacebook" class="social-share-btn" target="_blank"
style="display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 50%; background: #1877f2; color: white; text-decoration: none;">
<i class="bi bi-facebook"></i>
</a>
<a href="#" id="shareTwitter" class="social-share-btn" target="_blank"
style="display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 50%; background: #1da1f2; color: white; text-decoration: none;">
<i class="bi bi-twitter-x"></i>
</a>
<a href="#" id="shareWhatsApp" class="social-share-btn" target="_blank"
style="display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 50%; background: #25d366; color: white; text-decoration: none;">
<i class="bi bi-whatsapp"></i>
</a>
<a href="#" id="shareTelegram" class="social-share-btn" target="_blank"
style="display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 50%; background: #0088cc; color: white; text-decoration: none;">
<i class="bi bi-telegram"></i>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
.social-share-btn {
transition: transform 0.2s, opacity 0.2s;
}
.social-share-btn:hover {
transform: scale(1.1);
opacity: 0.9;
}
.btn-copy:hover {
background: #cc1a1a !important;
}
.btn-copy.copied {
background: #4caf50 !important;
}
</style>
<script>
function openShareModal(videoUrl, videoTitle) {
document.getElementById('shareLinkInput').value = videoUrl;
// Update social share links
var encodedUrl = encodeURIComponent(videoUrl);
var encodedTitle = encodeURIComponent(videoTitle);
document.getElementById('shareFacebook').href = 'https://www.facebook.com/sharer/sharer.php?u=' + encodedUrl;
document.getElementById('shareTwitter').href = 'https://twitter.com/intent/tweet?url=' + encodedUrl + '&text=' + encodedTitle;
document.getElementById('shareWhatsApp').href = 'https://wa.me/?text=' + encodedTitle + ' ' + encodedUrl;
document.getElementById('shareTelegram').href = 'https://t.me/share/url?url=' + encodedUrl + '&text=' + encodedTitle;
// Reset copy button state
var copyBtn = document.getElementById('copyLinkBtn');
copyBtn.innerHTML = '<i class="bi bi-clipboard me-1"></i> Copy';
copyBtn.classList.remove('copied');
document.getElementById('copySuccess').style.display = 'none';
// Show modal
var modal = new bootstrap.Modal(document.getElementById('shareModal'));
modal.show();
}
document.addEventListener('DOMContentLoaded', function() {
var copyBtn = document.getElementById('copyLinkBtn');
var shareInput = document.getElementById('shareLinkInput');
var copySuccess = document.getElementById('copySuccess');
if (copyBtn && shareInput) {
copyBtn.addEventListener('click', function() {
shareInput.select();
shareInput.setSelectionRange(0, 99999);
navigator.clipboard.writeText(shareInput.value).then(function() {
copyBtn.innerHTML = '<i class="bi bi-check-lg me-1"></i> Copied!';
copyBtn.classList.add('copied');
copySuccess.style.display = 'block';
setTimeout(function() {
copyBtn.innerHTML = '<i class="bi bi-clipboard me-1"></i> Copy';
copyBtn.classList.remove('copied');
copySuccess.style.display = 'none';
}, 2000);
}).catch(function(err) {
console.error('Failed to copy: ', err);
// Fallback for older browsers
document.execCommand('copy');
copyBtn.innerHTML = '<i class="bi bi-check-lg me-1"></i> Copied!';
copySuccess.style.display = 'block';
});
});
}
});
</script>
@@ -0,0 +1,37 @@
<!-- Sidebar -->
<nav class="yt-sidebar" id="sidebar">
<div class="yt-sidebar-section">
<a href="/videos" class="yt-sidebar-link {{ request()->is('/') || request()->is('videos') ? 'active' : '' }}">
<i class="bi bi-house-door-fill"></i>
<span>Home</span>
</a>
<a href="#" class="yt-sidebar-link">
<i class="bi bi-play-btn"></i>
<span>Shorts</span>
</a>
@auth
<a href="#" class="yt-sidebar-link">
<i class="bi bi-collection-play"></i>
<span>Subscriptions</span>
</a>
@endauth
</div>
@auth
<div class="yt-sidebar-section">
<a href="{{ route('channel', Auth::user()->id) }}" class="yt-sidebar-link">
<i class="bi bi-person-video"></i>
<span>Your Channel</span>
</a>
<a href="{{ route('history') }}" class="yt-sidebar-link">
<i class="bi bi-clock-history"></i>
<span>History</span>
</a>
<a href="{{ route('liked') }}" class="yt-sidebar-link">
<i class="bi bi-hand-thumbs-up"></i>
<span>Liked Videos</span>
</a>
</div>
@endauth
</nav>
File diff suppressed because it is too large. Load diff