admin panel added and comments are working and likes are working
This commit is contained in:
1 parent
72e9439727
commit
a28023c29b
32 files changed
+5077
-2999
No files matched your search
@@ -123,13 +123,15 @@
|
||||
}
|
||||
|
||||
.subscribe-btn {
|
||||
background: var(--brand-red);
|
||||
color: white;
|
||||
background: white;
|
||||
color: black;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 20px;
|
||||
font-weight: 500;
|
||||
padding: 8px 16px;
|
||||
border-radius: 18px;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Description */
|
||||
@@ -259,19 +261,26 @@
|
||||
</video>
|
||||
</div>
|
||||
|
||||
<!-- Video Title -->
|
||||
<h1 class="video-title">{{ $video->title }}</h1>
|
||||
@php
|
||||
$typeIcon = match($video->type) {
|
||||
'music' => 'bi-music-note',
|
||||
'match' => 'bi-trophy',
|
||||
default => 'bi-film',
|
||||
};
|
||||
@endphp
|
||||
|
||||
<!-- Video Title with Type Icon -->
|
||||
<h1 class="video-title" style="display: flex; align-items: center; gap: 10px;">
|
||||
<i class="bi {{ $typeIcon }}" style="color: #ef4444;"></i>
|
||||
<span>{{ $video->title }}</span>
|
||||
</h1>
|
||||
|
||||
<!-- Stats Row -->
|
||||
<div class="video-stats-row">
|
||||
<div class="video-stats-left">
|
||||
<span>{{ number_format($video->size / 1024 / 1024, 0) }} MB</span>
|
||||
<span>{{ number_format($video->view_count) }} views</span>
|
||||
<span>•</span>
|
||||
<span>{{ $video->created_at->format('M d, Y') }}</span>
|
||||
@if($video->width && $video->height)
|
||||
<span>•</span>
|
||||
<span>{{ $video->width }}x{{ $video->height }}</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="video-actions">
|
||||
@auth
|
||||
@@ -280,7 +289,7 @@
|
||||
@csrf
|
||||
<button type="submit" class="yt-action-btn {{ $video->isLikedBy(Auth::user()) ? 'liked' : '' }}">
|
||||
<i class="bi {{ $video->isLikedBy(Auth::user()) ? 'bi-hand-thumbs-up-fill' : 'bi-hand-thumbs-up' }}"></i>
|
||||
{{ $video->like_count > 0 ? $video->like_count : 'Like' }}
|
||||
{{ $video->like_count > 0 ? number_format($video->like_count) : 'Like' }}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -302,32 +311,156 @@
|
||||
</div>
|
||||
|
||||
<!-- Channel Row -->
|
||||
<div class="channel-row">
|
||||
<a href="{{ route('channel', $video->user_id) }}" class="channel-info text-decoration-none" style="color: inherit;">
|
||||
@if($video->user)
|
||||
<img src="{{ $video->user->avatar_url }}" class="channel-avatar" alt="{{ $video->user->name }}">
|
||||
<div class="channel-row" style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px;">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<a href="{{ route('channel', $video->user_id) }}" class="channel-info text-decoration-none" style="color: inherit; display: flex; align-items: center; gap: 12px;">
|
||||
@if($video->user)
|
||||
<img src="{{ $video->user->avatar_url }}" class="channel-avatar" style="width: 36px; height: 36px;" alt="{{ $video->user->name }}">
|
||||
@else
|
||||
<div class="channel-avatar" style="width: 36px; height: 36px;"></div>
|
||||
@endif
|
||||
<div>
|
||||
<div class="channel-name">{{ $video->user->name ?? 'Unknown' }}</div>
|
||||
<div class="channel-subs">{{ number_format($video->user->subscriber_count ?? 0) }} subscribers</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{{-- Subscribe Button --}}
|
||||
@auth
|
||||
@if(Auth::id() !== $video->user_id)
|
||||
<button class="subscribe-btn">Subscribe</button>
|
||||
@endif
|
||||
@else
|
||||
<div class="channel-avatar"></div>
|
||||
@endif
|
||||
<div>
|
||||
<div class="channel-name">{{ $video->user->name ?? 'Unknown' }}</div>
|
||||
<div class="channel-subs">Video Creator</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="{{ route('login') }}" class="subscribe-btn">Subscribe</a>
|
||||
@endauth
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Description -->
|
||||
@if($video->description)
|
||||
<div class="video-description">
|
||||
<p class="description-text">{{ $video->description }}</p>
|
||||
@php
|
||||
$fullDescription = $video->description;
|
||||
$shortDescription = Str::limit($fullDescription, 200);
|
||||
$needsExpand = strlen($fullDescription) > 200;
|
||||
@endphp
|
||||
|
||||
<div class="video-description-box" style="background: var(--bg-secondary); border-radius: 12px; padding: 12px; margin-top: 12px;">
|
||||
<div class="description-stats" style="font-size: 14px; font-weight: 500; margin-bottom: 8px;">
|
||||
<span>{{ number_format($video->view_count) }} views</span>
|
||||
<span>•</span>
|
||||
<span>{{ $video->created_at->format('M d, Y') }}</span>
|
||||
</div>
|
||||
<div style="border-bottom: 1px solid var(--border-color); margin: 8px 0;"></div>
|
||||
<div class="description-content">
|
||||
@if($needsExpand)
|
||||
<div class="description-short">
|
||||
<span class="description-text">{!! Str::markdown($shortDescription) !!}</span>
|
||||
<span style="color: var(--text-secondary);">... </span>
|
||||
</div>
|
||||
<div class="description-full" style="display: none;">
|
||||
<span class="description-text">{!! Str::markdown($fullDescription) !!}</span>
|
||||
</div>
|
||||
<button onclick="toggleDescription()" style="background: none; border: none; color: var(--text-primary); font-weight: 600; font-size: 14px; cursor: pointer; padding: 0; margin-top: 4px;">Show more</button>
|
||||
@else
|
||||
<span class="description-text">{!! Str::markdown($fullDescription) !!}</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleDescription() {
|
||||
const short = document.querySelector('.description-short');
|
||||
const full = document.querySelector('.description-full');
|
||||
const btn = document.querySelector('.video-description-box button');
|
||||
if (short.style.display !== 'none') {
|
||||
short.style.display = 'none';
|
||||
full.style.display = 'block';
|
||||
btn.textContent = 'Show less';
|
||||
} else {
|
||||
short.style.display = 'block';
|
||||
full.style.display = 'none';
|
||||
btn.textContent = 'Show more';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.video-description-box .description-text { font-size: 14px; line-height: 1.5; color: var(--text-primary); }
|
||||
.video-description-box .description-text p { margin-bottom: 8px; }
|
||||
.video-description-box .description-text a { color: #3ea6ff; }
|
||||
</style>
|
||||
@endif
|
||||
|
||||
<!-- Comments Section -->
|
||||
<div class="comments-section" style="margin-top: 24px; padding-top: 16: 1px solid var(--borderpx; border-top-color);">
|
||||
<h3 style="font-size: 18px; font-weight: 600; margin-bottom: 16px;">
|
||||
Comments <span style="color: var(--text-secondary); font-weight: 400;">({{ $video->comment_count }})</span>
|
||||
</h3>
|
||||
|
||||
@auth
|
||||
<div class="comment-form" style="display: flex; gap: 12px; margin-bottom: 24px;">
|
||||
<img src="{{ Auth::user()->avatar_url }}" class="channel-avatar" style="width: 40px; height: 40px;" alt="{{ Auth::user()->name }}">
|
||||
<div style="flex: 1;">
|
||||
<textarea id="commentBody" class="form-control" placeholder="Add a comment... Use @ to mention someone" rows="3" style="background: var(--bg-secondary); border: 1px solid var(--border-color); color: var(--text-primary); border-radius: 8px; padding: 12px; width: 100%; resize: none;"></textarea>
|
||||
<div style="display: flex; gap: 8px; margin-top: 8px; justify-content: flex-end;">
|
||||
<button type="button" class="yt-action-btn" onclick="document.getElementById('commentBody').value = ''">Cancel</button>
|
||||
<button type="button" class="yt-action-btn" style="background: var(--brand-red); color: white;" onclick="submitComment({{ $video->id }})">Comment</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div style="margin-bottom: 24px; padding: 16px; background: var(--bg-secondary); border-radius: 8px; text-align: center;">
|
||||
<a href="{{ route('login') }}" style="color: var(--brand-red);">Sign in</a> to comment
|
||||
</div>
|
||||
@endauth
|
||||
|
||||
<div id="commentsList">
|
||||
@forelse($video->comments()->whereNull('parent_id')->with('user', 'replies.user')->latest()->get() as $comment)
|
||||
@include('videos.partials.comment', ['comment' => $comment])
|
||||
@empty
|
||||
<p style="color: var(--text-secondary); text-align: center; padding: 20px;">No comments yet. Be the first to comment!</p>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function submitComment(videoId) {
|
||||
const body = document.getElementById('commentBody').value.trim();
|
||||
if (!body) return;
|
||||
fetch(`/videos/${videoId}/comments`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': '{{ csrf_token() }}' },
|
||||
body: JSON.stringify({ body: body })
|
||||
}).then(r => r.json()).then(data => {
|
||||
if (data.success) { document.getElementById('commentBody').value = ''; location.reload(); }
|
||||
});
|
||||
}
|
||||
function deleteComment(commentId) {
|
||||
if (!confirm('Delete this comment?')) return;
|
||||
fetch(`/comments/${commentId}`, { method: 'DELETE', headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' }})
|
||||
.then(r => r.json()).then(data => { if (data.success) location.reload(); });
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll('.comment-body').forEach(text => {
|
||||
text.innerHTML = text.innerHTML.replace(/@(\w+)/g, '<span style="color: #3ea6ff; font-weight: 500;">@$1</span>');
|
||||
});
|
||||
});
|
||||
function submitReply(videoId, parentId) {
|
||||
const textarea = document.querySelector(`#replyForm${parentId} textarea`);
|
||||
const body = textarea.value.trim();
|
||||
if (!body) return;
|
||||
fetch(`/videos/${videoId}/comments`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': '{{ csrf_token() }}' },
|
||||
body: JSON.stringify({ body: body, parent_id: parentId })
|
||||
}).then(r => r.json()).then(data => { if (data.success) location.reload(); });
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div class="yt-sidebar-container">
|
||||
<h3 style="font-size: 16px; font-weight: 500; margin-bottom: 12px;">Up Next</h3>
|
||||
<!-- Placeholder for recommended videos - would be dynamic in full implementation -->
|
||||
<div class="text-secondary">More videos coming soon...</div>
|
||||
</div>
|
||||
|
||||
@@ -340,7 +473,6 @@
|
||||
@auth
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Auto-open edit modal when redirected from /videos/{id}/edit
|
||||
openEditVideoModal({{ $video->id }});
|
||||
});
|
||||
</script>
|
||||
@@ -348,24 +480,13 @@
|
||||
@endif
|
||||
|
||||
<script>
|
||||
// Auto-play video with sound when page loads
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var videoPlayer = document.getElementById('videoPlayer');
|
||||
if (videoPlayer) {
|
||||
// Set volume to 50%
|
||||
videoPlayer.volume = 0.5;
|
||||
|
||||
// Try to autoplay with sound
|
||||
var playPromise = videoPlayer.play();
|
||||
|
||||
if (playPromise !== undefined) {
|
||||
playPromise.then(function() {
|
||||
// Autoplay started successfully
|
||||
console.log('Video autoplayed with sound at 50% volume');
|
||||
}).catch(function(error) {
|
||||
// Autoplay was prevented
|
||||
console.log('Autoplay blocked');
|
||||
});
|
||||
playPromise.then(function() { console.log('Video autoplayed'); }).catch(function(error) { console.log('Autoplay blocked'); });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user