292 lines
11 KiB
PHP

{{-- Video Type Icon (using Bootstrap Icons like video-card.blade.php) --}}
@php
$typeIcon = match($video->type) {
'music' => 'bi-music-note',
'match' => 'bi-trophy',
default => 'bi-film',
};
@endphp
{{-- Video Title with Type Icon Inline --}}
<h1 class="video-title" style="display: flex; align-items: center; gap: 10px; margin: 8px 0 6px;">
<i class="bi {{ $typeIcon }}" style="color: #ef4444; margin-right: 6px;"></i>
<span>{{ $video->title }}</span>
</h1>
{{-- Channel Row with Actions Inline --}}
<div class="channel-row" style="display: flex; align-items: center; justify-content: space-between; padding: 6px 0; flex-wrap: wrap; gap: 12px;">
{{-- Left: Channel Info --}}
<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" style="background: white; color: black; border: none; padding: 8px 16px; border-radius: 18px; font-weight: 600; font-size: 14px; cursor: pointer; white-space: nowrap;">
Subscribe
</button>
@endif
@else
<a href="{{ route('login') }}" class="subscribe-btn" style="background: white; color: black; border: none; padding: 8px 16px; border-radius: 18px; font-weight: 600; font-size: 14px; text-decoration: none; white-space: nowrap; display: inline-block;">
Subscribe
</a>
@endauth
</div>
{{-- Right: Action Buttons (Like, Edit, Share) --}}
<div class="video-actions">
@auth
{{-- Like Button with Icon and Count --}}
<form method="POST" action="{{ $video->isLikedBy(Auth::user()) ? route('videos.unlike', $video->id) : route('videos.like', $video->id) }}" class="d-inline">
@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 ? number_format($video->like_count) : 'Like' }}
</button>
</form>
{{-- Edit Button - Only for video owner --}}
@if(Auth::id() === $video->user_id)
<button class="yt-action-btn" onclick="openEditVideoModal({{ $video->id }})">
<i class="bi bi-pencil"></i> Edit
</button>
@endif
@else
<a href="{{ route('login') }}" class="yt-action-btn">
<i class="bi bi-hand-thumbs-up"></i> Like
</a>
@endauth
{{-- Share Button --}}
@if($video->isShareable())
<button class="yt-action-btn" onclick="openShareModal('{{ $video->share_url }}', '{{ addslashes($video->title) }}')">
<i class="bi bi-share"></i> Share
</button>
@endif
</div>
</div>
{{-- Description Box (Expandable) --}}
@if($video->description)
@php
// Parse markdown description
$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-bottom: 16px;">
{{-- Fixed Stats Row (views + date - cannot be manipulated) --}}
<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>
{{-- Separator Line --}}
<div style="border-bottom: 1px solid var(--border-color); margin: 8px 0;"></div>
{{-- Description Content --}}
<div class="description-content" id="descriptionContent">
@if($needsExpand)
<div class="description-short" id="descShort">
<span class="description-text">{!! Str::markdown($shortDescription) !!}</span>
<span class="description-ellipsis" style="color: var(--text-secondary);">... </span>
</div>
<div class="description-full" id="descFull" style="display: none;">
<span class="description-text">{!! Str::markdown($fullDescription) !!}</span>
</div>
<button onclick="toggleDescription()" id="descToggleBtn" 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 descShort = document.getElementById('descShort');
const descFull = document.getElementById('descFull');
const toggleBtn = document.getElementById('descToggleBtn');
if (descShort.style.display !== 'none') {
descShort.style.display = 'none';
descFull.style.display = 'block';
toggleBtn.textContent = 'Show less';
} else {
descShort.style.display = 'block';
descFull.style.display = 'none';
toggleBtn.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 p:last-child {
margin-bottom: 0;
}
.video-description-box .description-text a {
color: #3ea6ff;
}
.video-description-box .description-text code {
background: rgba(255,255,255,0.1);
padding: 2px 6px;
border-radius: 4px;
font-family: monospace;
}
.video-description-box .description-text pre {
background: rgba(255,255,255,0.1);
padding: 12px;
border-radius: 8px;
overflow-x: auto;
}
.video-description-box .description-text ul,
.video-description-box .description-text ol {
padding-left: 20px;
margin-bottom: 8px;
}
.video-description-box .description-text strong {
font-weight: 600;
}
</style>
@endif
{{-- Comment Section --}}
<div class="comments-section" style="margin-top: 24px; padding-top: 16px; border-top: 1px solid var(--border-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>
{{-- Comment Form --}}
@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
{{-- Comments List --}}
<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(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('commentBody').value = '';
loadComments(videoId);
}
});
}
function loadComments(videoId) {
fetch(`/videos/${videoId}/comments`)
.then(response => response.json())
.then(data => {
// Reload page to show new comments
location.reload();
});
}
function deleteComment(commentId) {
if (!confirm('Are you sure you want to delete this comment?')) return;
fetch(`/comments/${commentId}`, {
method: 'DELETE',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
}
});
}
// Highlight @mentions in comments
document.addEventListener('DOMContentLoaded', function() {
const commentTexts = document.querySelectorAll('.comment-body');
commentTexts.forEach(text => {
const html = text.innerHTML.replace(/@(\w+)/g, '<span style="color: #3ea6ff; font-weight: 500;">@$1</span>');
text.innerHTML = html;
});
});
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(response => response.json())
.then(data => {
if (data.success) {
location.reload();
}
});
}
</script>