151 lines
11 KiB
PHP
151 lines
11 KiB
PHP
<div>
|
|
@if(count($playlists) > 0)
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-5">
|
|
@foreach($playlists as $playlist)
|
|
@php
|
|
$count = $playlist->episodes->count();
|
|
@endphp
|
|
<div class="group rounded-xl bg-white/40 dark:bg-neutral-950/40 backdrop-blur shadow-sm ring-1 ring-black/5 dark:ring-white/5 overflow-hidden hover:shadow-md hover:ring-rose-300/50 dark:hover:ring-rose-700/30 transition-all duration-200 flex flex-col">
|
|
{{-- Thumbnail --}}
|
|
@if($count > 0)
|
|
<a href="{{ route('profile.playlist.show', $playlist->id) }}" class="block overflow-hidden">
|
|
@php
|
|
$pe = \App\Models\PlaylistEpisode::where('playlist_id', $playlist->id)->orderBy('position', 'desc')->first();
|
|
@endphp
|
|
<img class="w-full aspect-video object-cover transition-transform duration-300 group-hover:scale-105"
|
|
src="{{ $pe->episode->gallery->first()->thumbnail_url }}"
|
|
alt="{{ $playlist->name }}"
|
|
loading="lazy" />
|
|
</a>
|
|
@else
|
|
<div class="w-full aspect-video bg-gray-200 dark:bg-neutral-800 flex items-center justify-center">
|
|
<img src="/images/hentai/sukebe-elf-tanbouki/gallery-ep-1-0.webp"
|
|
class="w-full aspect-video object-cover opacity-30 dark:opacity-15"
|
|
alt="Empty playlist" />
|
|
</div>
|
|
@endif
|
|
|
|
{{-- Content --}}
|
|
<div class="p-4 flex-1 flex flex-col"
|
|
x-data="{ editing: false, name: '{{ $playlist->name }}', isPrivate: {{ $playlist->is_private ? 'true' : 'false' }} }">
|
|
|
|
{{-- Edit mode --}}
|
|
<template x-if="editing">
|
|
<div class="flex-1 flex flex-col">
|
|
<form method="POST" action="{{ route('profile.playlist.update', $playlist->id) }}" class="flex-1 flex flex-col">
|
|
@csrf
|
|
@method('PATCH')
|
|
<div class="space-y-3 flex-1">
|
|
<div>
|
|
<label class="mb-1 block text-xs font-medium text-neutral-500 dark:text-neutral-400">Name</label>
|
|
<input
|
|
type="text"
|
|
name="name"
|
|
x-model="name"
|
|
maxlength="30"
|
|
required
|
|
class="block w-full rounded-lg border border-neutral-300 bg-white px-3 py-2 text-sm dark:border-neutral-600 dark:bg-neutral-800 dark:text-white focus:border-rose-500 focus:ring-rose-500"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label class="mb-1 block text-xs font-medium text-neutral-500 dark:text-neutral-400">Visibility</label>
|
|
<select
|
|
name="is_private"
|
|
x-model="isPrivate"
|
|
class="block w-full rounded-lg border border-neutral-300 bg-white px-3 py-2 text-sm dark:border-neutral-600 dark:bg-neutral-800 dark:text-white focus:border-rose-500 focus:ring-rose-500"
|
|
>
|
|
<option value="0">Public</option>
|
|
<option value="1">Private</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="flex gap-2 mt-3 pt-3 border-t border-neutral-200 dark:border-neutral-700">
|
|
<button type="submit" class="cursor-pointer rounded-lg bg-rose-600 px-3 py-1.5 text-xs font-semibold text-white transition hover:bg-rose-700 flex-1">
|
|
Save
|
|
</button>
|
|
<button type="button" @click="editing = false; name = '{{ $playlist->name }}'; isPrivate = {{ $playlist->is_private ? 'true' : 'false' }}" class="cursor-pointer rounded-lg border border-neutral-300 px-3 py-1.5 text-xs font-medium text-neutral-600 transition hover:bg-neutral-100 dark:border-neutral-600 dark:text-neutral-200 dark:hover:bg-neutral-800 flex-1">
|
|
Cancel
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- Display mode --}}
|
|
<template x-if="!editing">
|
|
<div class="flex-1 flex flex-col">
|
|
<div class="flex-1">
|
|
<h5 class="text-base font-semibold text-neutral-800 dark:text-neutral-50 truncate">
|
|
{{ $playlist->name }}
|
|
</h5>
|
|
<div class="flex items-center gap-2 mt-1.5">
|
|
<span class="inline-flex items-center gap-1 pl-2 pr-2 pt-1 pb-1 rounded-full bg-neutral-100 dark:bg-neutral-700 px-2 py-0.5 text-[11px] font-medium text-neutral-600 dark:text-neutral-300">
|
|
<i class="fa-solid fa-film text-[9px]"></i>
|
|
{{ $count }} {{ Str::plural('ep', $count) }}
|
|
</span>
|
|
<span class="inline-flex items-center gap-1 pl-2 pr-2 pt-1 pb-1 rounded-full text-[11px] font-medium
|
|
{{ $playlist->is_private ? 'bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-400' : 'bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400' }}">
|
|
<i class="fa-solid fa-{{ $playlist->is_private ? 'lock' : 'globe' }} text-[9px]"></i>
|
|
{{ $playlist->is_private ? 'Private' : 'Public' }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center justify-between mt-3 pt-3 border-t border-neutral-200 dark:border-neutral-700">
|
|
<div class="flex items-center gap-3">
|
|
<a href="{{ route('profile.playlist.delete', $playlist->id) }}"
|
|
class="inline-flex items-center gap-1 text-[11px] text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 transition-colors"
|
|
data-confirm-delete="true">
|
|
<i class="fa-solid fa-trash-can text-[10px]"></i>
|
|
Delete
|
|
</a>
|
|
<button @click="editing = true"
|
|
class="inline-flex items-center gap-1 text-[11px] text-blue-500 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300 transition-colors">
|
|
<i class="fa-solid fa-pen-to-square text-[10px]"></i>
|
|
Edit
|
|
</button>
|
|
</div>
|
|
@if($count > 0)
|
|
<a href="{{ route('hentai.index', ['title' => $playlist->episodes->first()->episode->slug, 'playlist' => $playlist->id]) }}"
|
|
class="inline-flex items-center gap-1 rounded-lg bg-rose-600 px-3 py-1.5 text-[11px] font-semibold text-white hover:bg-rose-700 transition-colors shadow-sm shadow-rose-600/20">
|
|
<i class="fa-solid fa-play text-[9px]"></i>
|
|
Play
|
|
</a>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
|
|
{{-- Add New Playlist Card --}}
|
|
<button
|
|
data-te-toggle="modal"
|
|
data-te-target="#modalCreatePlaylist"
|
|
class="group rounded-xl border-2 border-dashed border-neutral-300 dark:border-neutral-700 bg-white/20 dark:bg-neutral-950/20 backdrop-blur hover:border-rose-400 dark:hover:border-rose-600 hover:bg-rose-50/50 dark:hover:bg-rose-950/20 transition-all duration-200 flex flex-col items-center justify-center p-8 min-h-[200px]">
|
|
<div class="flex h-14 w-14 items-center justify-center rounded-full bg-rose-100 dark:bg-rose-900/30 text-rose-600 dark:text-rose-400 group-hover:scale-110 transition-transform duration-200 mb-3">
|
|
<i class="fa-solid fa-plus text-xl"></i>
|
|
</div>
|
|
<p class="text-sm font-semibold text-neutral-600 dark:text-neutral-300">Create Playlist</p>
|
|
<p class="text-xs text-neutral-400 dark:text-neutral-500 mt-1">Organize your favorites</p>
|
|
</button>
|
|
</div>
|
|
@else
|
|
{{-- Empty State --}}
|
|
<div class="rounded-2xl bg-white/40 dark:bg-neutral-950/40 backdrop-blur shadow-sm ring-1 ring-black/5 dark:ring-white/5 p-12 text-center">
|
|
<div class="inline-flex h-20 w-20 items-center justify-center rounded-full bg-gray-100 dark:bg-neutral-800 mb-4">
|
|
<i class="fa-solid fa-rectangle-list text-3xl text-gray-400 dark:text-gray-500"></i>
|
|
</div>
|
|
<h3 class="text-lg font-semibold text-gray-700 dark:text-gray-300">No playlists yet</h3>
|
|
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400 mb-6">Create your first playlist to organize your favorite episodes.</p>
|
|
<button
|
|
data-te-toggle="modal"
|
|
data-te-target="#modalCreatePlaylist"
|
|
class="inline-flex items-center gap-1.5 rounded-lg bg-rose-600 px-5 py-2.5 text-sm font-semibold text-white hover:bg-rose-700 transition-colors shadow-sm shadow-rose-600/20">
|
|
<i class="fa-solid fa-plus text-xs"></i>
|
|
Create your first playlist
|
|
</button>
|
|
</div>
|
|
@endif
|
|
</div> |