372 lines
13 KiB
PHP
372 lines
13 KiB
PHP
@extends('layouts.app')
|
|
|
|
@push('head')
|
|
<!-- Open Graph / WhatsApp / Facebook / Twitter Preview -->
|
|
<meta property="og:title" content="{{ $video->title }}">
|
|
<meta property="og:description" content="{{ $video->description ? Str::limit($video->description, 200) : 'Check out this video on ' . config('app.name') }}">
|
|
<meta property="og:image" content="{{ $video->thumbnail_url }}">
|
|
<meta property="og:url" content="{{ $video->share_url }}">
|
|
<meta property="og:type" content="video.other">
|
|
<meta property="og:site_name" content="{{ config('app.name') }}">
|
|
|
|
<!-- Twitter Card -->
|
|
<meta name="twitter:card" content="summary_large_image">
|
|
<meta name="twitter:title" content="{{ $video->title }}">
|
|
<meta name="twitter:description" content="{{ $video->description ? Str::limit($video->description, 200) : 'Check out this video on ' . config('app.name') }}">
|
|
<meta name="twitter:image" content="{{ $video->thumbnail_url }}">
|
|
@endpush
|
|
|
|
@section('title', $video->title . ' | ' . config('app.name'))
|
|
|
|
@section('extra_styles')
|
|
<style>
|
|
/* Video Section */
|
|
.yt-video-section { flex: 1; min-width: 0; }
|
|
|
|
/* Video Player */
|
|
.video-container {
|
|
position: relative;
|
|
aspect-ratio: 16/9;
|
|
background: #000;
|
|
border-radius: 12px;
|
|
overflow: hidden;
|
|
max-height: 70vh;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
width: 100%;
|
|
}
|
|
|
|
.video-container.portrait,
|
|
.video-container.square,
|
|
.video-container.ultrawide {
|
|
margin: 0 auto;
|
|
width: auto;
|
|
}
|
|
|
|
.video-container.portrait { aspect-ratio: 9/16; max-width: 50vh; }
|
|
.video-container.square { aspect-ratio: 1/1; max-width: 70vh; }
|
|
.video-container.ultrawide { aspect-ratio: 21/9; max-width: 100%; }
|
|
|
|
.video-container video { width: 100%; height: 100%; object-fit: contain; }
|
|
|
|
/* Video Info */
|
|
.video-title {
|
|
font-size: 20px;
|
|
font-weight: 500;
|
|
margin: 16px 0 8px;
|
|
line-height: 1.3;
|
|
}
|
|
|
|
.video-stats-row {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding-bottom: 12px;
|
|
border-bottom: 1px solid var(--border-color);
|
|
flex-wrap: wrap;
|
|
gap: 12px;
|
|
}
|
|
|
|
.video-stats-left { display: flex; align-items: center; gap: 16px; color: var(--text-secondary); }
|
|
|
|
.video-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.yt-action-btn {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 8px 16px;
|
|
border-radius: 20px;
|
|
border: none;
|
|
background: var(--bg-secondary);
|
|
color: var(--text-primary);
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.yt-action-btn:hover { background: var(--border-color); }
|
|
|
|
.yt-action-btn.liked { color: var(--brand-red); }
|
|
|
|
/* Channel Row */
|
|
.channel-row {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 16px 0;
|
|
}
|
|
|
|
.channel-info {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
|
|
.channel-avatar {
|
|
width: 48px; height: 48px; border-radius: 50%; background: #555;
|
|
}
|
|
|
|
.channel-name {
|
|
font-size: 16px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.channel-subs {
|
|
font-size: 14px;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.subscribe-btn {
|
|
background: var(--brand-red);
|
|
color: white;
|
|
border: none;
|
|
padding: 10px 20px;
|
|
border-radius: 20px;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
}
|
|
|
|
/* Description */
|
|
.video-description {
|
|
background: var(--bg-secondary);
|
|
border-radius: 12px;
|
|
padding: 16px;
|
|
margin-top: 16px;
|
|
}
|
|
|
|
.description-text {
|
|
white-space: pre-wrap;
|
|
font-size: 14px;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
/* Sidebar */
|
|
.yt-sidebar-container {
|
|
width: 400px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.sidebar-video-card {
|
|
display: flex;
|
|
gap: 8px;
|
|
margin-bottom: 8px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.sidebar-thumb {
|
|
width: 168px;
|
|
aspect-ratio: 16/9;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
background: #1a1a1a;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.sidebar-thumb img { width: 100%; height: 100%; object-fit: cover; }
|
|
|
|
.sidebar-info { flex: 1; min-width: 0; }
|
|
|
|
.sidebar-title {
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
margin-bottom: 4px;
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 2;
|
|
-webkit-box-orient: vertical;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.sidebar-meta { font-size: 12px; color: var(--text-secondary); }
|
|
|
|
/* Responsive */
|
|
@media (max-width: 1300px) {
|
|
.yt-sidebar-container { width: 300px; }
|
|
}
|
|
|
|
@media (max-width: 991px) {
|
|
.yt-main { margin-left: 0; flex-direction: column; }
|
|
.yt-sidebar-container { width: 100%; }
|
|
.yt-header-center { display: none; }
|
|
.sidebar-video-card { flex-direction: column; }
|
|
.sidebar-thumb { width: 100%; }
|
|
|
|
/* Video Layout Container - Stack vertically on tablet/mobile */
|
|
.video-layout-container {
|
|
flex-direction: column !important;
|
|
}
|
|
.yt-video-section {
|
|
width: 100% !important;
|
|
flex: none !important;
|
|
}
|
|
.yt-sidebar-container {
|
|
width: 100% !important;
|
|
margin-top: 16px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 576px) {
|
|
.video-stats-row { flex-direction: column; align-items: flex-start; }
|
|
.video-actions { width: 100%; overflow-x: auto; justify-content: flex-start; }
|
|
.yt-main { padding: 12px !important; }
|
|
|
|
/* Mobile video player fixes */
|
|
.video-container {
|
|
max-height: 50vh !important;
|
|
border-radius: 0 !important;
|
|
}
|
|
.video-container video {
|
|
object-fit: contain !important;
|
|
}
|
|
.video-title {
|
|
font-size: 16px !important;
|
|
margin: 12px 0 6px !important;
|
|
}
|
|
.channel-row {
|
|
flex-direction: column;
|
|
align-items: flex-start !important;
|
|
gap: 12px;
|
|
}
|
|
.channel-info {
|
|
width: 100%;
|
|
}
|
|
.subscribe-btn {
|
|
width: 100%;
|
|
}
|
|
.video-description {
|
|
padding: 12px !important;
|
|
}
|
|
}
|
|
</style>
|
|
@endsection
|
|
|
|
@section('content')
|
|
<!-- Video Layout Container -->
|
|
<div class="video-layout-container" style="display: flex; gap: 24px; max-width: 1800px; margin: 0 auto;">
|
|
<!-- Video Section -->
|
|
<div class="yt-video-section">
|
|
<!-- Video Player -->
|
|
<div class="video-container @if($video->orientation === 'portrait') portrait @elseif($video->orientation === 'square') square @elseif($video->orientation === 'ultrawide') ultrawide @endif" id="videoContainer">
|
|
<video id="videoPlayer" controls playsinline preload="metadata" autoplay>
|
|
<source src="{{ route('videos.stream', $video->id) }}" type="video/mp4">
|
|
</video>
|
|
</div>
|
|
|
|
<!-- Video Title -->
|
|
<h1 class="video-title">{{ $video->title }}</h1>
|
|
|
|
<!-- Stats Row -->
|
|
<div class="video-stats-row">
|
|
<div class="video-stats-left">
|
|
<span>{{ number_format($video->size / 1024 / 1024, 0) }} MB</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
|
|
<!-- Like Button -->
|
|
<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 ? $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
|
|
@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>
|
|
|
|
<!-- 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 }}">
|
|
@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>
|
|
</div>
|
|
|
|
<!-- Description -->
|
|
@if($video->description)
|
|
<div class="video-description">
|
|
<p class="description-text">{{ $video->description }}</p>
|
|
</div>
|
|
@endif
|
|
</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>
|
|
</div>
|
|
|
|
@include('layouts.partials.share-modal')
|
|
@include('layouts.partials.edit-video-modal')
|
|
|
|
@if(Session::has('openEditModal') && Session::get('openEditModal'))
|
|
@auth
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Auto-open edit modal when redirected from /videos/{id}/edit
|
|
openEditVideoModal({{ $video->id }});
|
|
});
|
|
</script>
|
|
@endauth
|
|
@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');
|
|
});
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
@endsection
|
|
|