ghassan 0b2e95ea65 Add NAS file manager integration and all pending platform changes
- Installed p7h/nas-file-manager package via private VCS repo
- Published config/nas-file-manager.php with super_admin middleware restriction
- Added NAS env vars to .env.example
- Created admin/nas-storage page with connection info panel and file browser widget
- Added NAS Storage link to admin sidebar (super_admin only)
- Added SuperAdminController@nasStorage method and admin.nas-storage route
- Includes all accumulated branch changes: profile wall, 2FA, audit logs,
  settings panel, country/phone/timezone components, posts, slideshow,
  playlist shares, video downloads/shares, comment likes, notifications,
  social links, and more

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 13:24:32 +03:00

221 lines
8.8 KiB
PHP

@extends('layouts.app')
@section('title', isset($query) ? 'Search: ' . $query . ' | ' . config('app.name') : config('app.name'))
@section('extra_styles')
<style>
/* ── Regular video grid ── */
.yt-video-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
@media (max-width: 992px) { .yt-video-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 576px) { .yt-video-grid { grid-template-columns: 1fr; gap: 14px; } }
/* ── Playlist count badge (right strip on thumbnail) ── */
.pl-count-badge {
position: absolute; inset: 0 0 0 auto;
width: 72px;
background: rgba(0,0,0,.78);
display: flex; flex-direction: column;
align-items: center; justify-content: center;
gap: 4px; font-size: 12px; font-weight: 600; color: #fff;
pointer-events: none;
}
.pl-count-badge i { font-size: 20px; }
/* ── Playlist type badge (top-left on thumbnail) ── */
.feed-pl-type-badge {
position: absolute; top: 8px; left: 8px;
background: rgba(0,0,0,.75); color: #fff;
font-size: 11px; font-weight: 700;
padding: 3px 8px; border-radius: 4px;
display: flex; align-items: center; gap: 4px;
text-transform: uppercase; letter-spacing: .4px;
pointer-events: none;
}
/* ── Thumbnail orientation fix ── */
.yt-video-card .yt-video-thumb img { object-fit: cover; }
/* ── Search result helpers ── */
.search-info { margin-bottom: 20px; padding: 16px; background: var(--bg-secondary); border-radius: 12px; }
.search-info h2 { font-size: 20px; margin: 0; }
.search-info p { color: var(--text-secondary); margin: 8px 0 0; }
.results-section-title {
font-size: 15px; font-weight: 600; color: var(--text-secondary);
text-transform: uppercase; letter-spacing: .05em;
margin: 28px 0 14px;
display: flex; align-items: center; gap: 8px;
}
.results-section-title::after { content: ''; flex: 1; height: 1px; background: var(--border-color); }
.yt-empty { text-align: center; padding: 80px 20px; }
</style>
@endsection
@section('content')
{{-- ── Filter chip bar ── --}}
@unless(isset($query))
@php $activeFilter = request('filter', 'all'); @endphp
<div class="yt-filter-bar">
<a href="{{ route('videos.index') }}"
class="yt-chip {{ $activeFilter === 'all' ? 'active' : '' }}">All</a>
<a href="{{ route('videos.trending') }}"
class="yt-chip {{ request()->is('trending') ? 'active' : '' }}">Trending</a>
<a href="{{ route('videos.index', ['filter' => 'music']) }}"
class="yt-chip {{ $activeFilter === 'music' ? 'active' : '' }}">Music</a>
<a href="{{ route('videos.index', ['filter' => 'match']) }}"
class="yt-chip {{ $activeFilter === 'match' ? 'active' : '' }}">Sports</a>
<a href="{{ route('videos.shorts') }}"
class="yt-chip {{ request()->is('shorts') ? 'active' : '' }}">Shorts</a>
<a href="{{ route('videos.index', ['filter' => 'playlists']) }}"
class="yt-chip {{ $activeFilter === 'playlists' ? 'active' : '' }}">Playlists</a>
<a href="{{ route('videos.index', ['filter' => 'latest']) }}"
class="yt-chip {{ $activeFilter === 'latest' ? 'active' : '' }}">New to You</a>
</div>
@endunless
{{-- ══════════════════════════════════════════════
SEARCH RESULTS
══════════════════════════════════════════════ --}}
@isset($query)
@php
$searchShorts = $shorts ?? collect();
$searchPlaylists = $playlists ?? collect();
$totalResults = $videos->count() + $searchShorts->count() + $searchPlaylists->count();
@endphp
<div class="search-info">
<h2>Search results for "{{ $query }}"</h2>
<p>
@if($videos->count()) {{ $videos->count() }} video{{ $videos->count() !== 1 ? 's' : '' }} @endif
@if($searchShorts->count()) &nbsp;·&nbsp; {{ $searchShorts->count() }} short{{ $searchShorts->count() !== 1 ? 's' : '' }} @endif
@if($searchPlaylists->count()) &nbsp;·&nbsp; {{ $searchPlaylists->count() }} playlist{{ $searchPlaylists->count() !== 1 ? 's' : '' }} @endif
@if($totalResults === 0) No results found @endif
</p>
</div>
@if($videos->count())
<div class="results-section-title"><i class="bi bi-play-circle"></i> Videos</div>
<div class="yt-video-grid">
@foreach($videos as $video)
@include('components.video-card', ['video' => $video])
@endforeach
</div>
@endif
@if($searchShorts->count())
<div class="results-section-title"><i class="bi bi-lightning-charge-fill"></i> Shorts</div>
<div class="yt-video-grid">
@foreach($searchShorts as $video)
@include('components.video-card', ['video' => $video])
@endforeach
</div>
@endif
@if($searchPlaylists->count())
<div class="results-section-title"><i class="bi bi-collection-play"></i> Playlists</div>
<div class="yt-video-grid">
@foreach($searchPlaylists as $pl)
@include('components.playlist-card', ['playlist' => $pl])
@endforeach
</div>
@endif
@if($totalResults === 0)
<div class="yt-empty">
<i class="bi bi-search" style="font-size:56px;color:var(--text-secondary);display:block;margin-bottom:12px;"></i>
<h2>No results for "{{ $query }}"</h2>
<p style="color:var(--text-secondary);">Try different keywords or browse the gallery.</p>
</div>
@endif
@endisset
{{-- ══════════════════════════════════════════════
PLAYLISTS-ONLY FILTER
══════════════════════════════════════════════ --}}
@if(!isset($query) && isset($filter) && $filter === 'playlists')
@if(isset($playlists) && $playlists->count())
<div class="yt-video-grid">
@foreach($playlists as $pl)
@include('components.playlist-card', ['playlist' => $pl])
@endforeach
</div>
@else
<div class="yt-empty">
<i class="bi bi-collection-play" style="font-size:56px;color:var(--text-secondary);display:block;margin-bottom:12px;"></i>
<h2>No public playlists yet</h2>
</div>
@endif
{{-- ══════════════════════════════════════════════
HOME MIXED FEED
══════════════════════════════════════════════ --}}
@elseif(!isset($query) && (!isset($filter) || $filter === 'all'))
@if(isset($feedItems) && $feedItems->count())
<div class="yt-video-grid">
@foreach($feedItems as $entry)
@if($entry['kind'] === 'video')
@include('components.video-card', ['video' => $entry['item']])
@else
@php $pl = $entry['item']; @endphp
@include('components.playlist-card', ['playlist' => $pl, 'showTypeBadge' => true])
@endif
@endforeach
</div>
@else
<div class="yt-empty">
<h2>No content yet</h2>
@auth
<a href="{{ route('videos.create') }}" class="action-btn action-btn-primary" style="margin-top:12px;">Upload First Video</a>
@endauth
</div>
@endif
{{-- ══════════════════════════════════════════════
SINGLE-TYPE FILTERED VIEWS
══════════════════════════════════════════════ --}}
@elseif(!isset($query))
@if($videos->isEmpty())
<div class="yt-empty">
<i class="bi bi-camera-video" style="font-size:56px;color:var(--text-secondary);display:block;margin-bottom:12px;"></i>
<h2>Nothing here yet</h2>
</div>
@else
<div class="yt-video-grid">
@foreach($videos as $video)
@include('components.video-card', ['video' => $video])
@endforeach
</div>
@endif
@endif
@endsection
@section('scripts')
<script>
(function () {
function adjustPlThumb(img) {
img.style.objectFit = img.naturalWidth < img.naturalHeight ? 'contain' : 'cover';
}
document.querySelectorAll('.yt-video-thumb img').forEach(function (img) {
if (img.complete && img.naturalWidth) {
adjustPlThumb(img);
} else {
img.addEventListener('load', function () { adjustPlThumb(img); });
}
});
})();
</script>
@endsection