Add ability to edit the playlist name and visibility #5
This commit is contained in:
@@ -95,6 +95,34 @@ class PlaylistController extends Controller
|
|||||||
return to_route('profile.playlists');
|
return to_route('profile.playlists');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update user playlist.
|
||||||
|
*/
|
||||||
|
public function updatePlaylist(Request $request, $playlist_id): RedirectResponse
|
||||||
|
{
|
||||||
|
if (! is_numeric($playlist_id)) {
|
||||||
|
abort(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$validated = $request->validate([
|
||||||
|
'name' => 'required|max:30',
|
||||||
|
'is_private' => 'required|boolean',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = $request->user();
|
||||||
|
|
||||||
|
$playlist = Playlist::where('user_id', $user->id)
|
||||||
|
->where('id', $playlist_id)
|
||||||
|
->firstOrFail();
|
||||||
|
|
||||||
|
$playlist->update([
|
||||||
|
'name' => $request->input('name'),
|
||||||
|
'is_private' => $request->input('is_private'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return back()->with('status', 'playlist-updated');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete user playlist.
|
* Delete user playlist.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ class PlaylistOverview extends Component
|
|||||||
|
|
||||||
public Collection $playlistEpisodes;
|
public Collection $playlistEpisodes;
|
||||||
|
|
||||||
|
public bool $editingName = false;
|
||||||
|
|
||||||
|
public string $editingPlaylistName = '';
|
||||||
|
|
||||||
public function boot(PlaylistService $playlistService)
|
public function boot(PlaylistService $playlistService)
|
||||||
{
|
{
|
||||||
$this->playlistService = $playlistService;
|
$this->playlistService = $playlistService;
|
||||||
@@ -112,6 +116,53 @@ class PlaylistOverview extends Component
|
|||||||
$this->refreshEpisodes();
|
$this->refreshEpisodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function editName()
|
||||||
|
{
|
||||||
|
if (! Auth::check() || Auth::user()->id !== $this->playlist->user->id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->editingPlaylistName = $this->playlist->name;
|
||||||
|
$this->editingName = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cancelEditName()
|
||||||
|
{
|
||||||
|
$this->editingName = false;
|
||||||
|
$this->editingPlaylistName = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateName()
|
||||||
|
{
|
||||||
|
if (! Auth::check() || Auth::user()->id !== $this->playlist->user->id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->validate([
|
||||||
|
'editingPlaylistName' => 'required|max:30',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->playlist->update([
|
||||||
|
'name' => $this->editingPlaylistName,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->editingName = false;
|
||||||
|
$this->editingPlaylistName = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toggleVisibility()
|
||||||
|
{
|
||||||
|
if (! Auth::check() || Auth::user()->id !== $this->playlist->user->id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->playlist->update([
|
||||||
|
'is_private' => ! $this->playlist->is_private,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->playlist->refresh();
|
||||||
|
}
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.playlist-overview', [
|
return view('livewire.playlist-overview', [
|
||||||
|
|||||||
@@ -7,6 +7,26 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
|||||||
|
|
||||||
class Playlist extends Model
|
class Playlist extends Model
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The attributes that are mass assignable.
|
||||||
|
*
|
||||||
|
* @var array<int, string>
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'user_id',
|
||||||
|
'name',
|
||||||
|
'is_private',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
|
protected $casts = [
|
||||||
|
'is_private' => 'boolean',
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Belongs To A User.
|
* Belongs To A User.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
if (document.getElementById("playlist-add")) {
|
if (document.getElementById("playlist-add")) {
|
||||||
function createPlaylist() {
|
function addToPlaylist() {
|
||||||
console.log('Adding to Playlist: ' + document.querySelector("#playlist").value)
|
|
||||||
|
|
||||||
window.axios.post('/hentai/add-to-playlist', {
|
window.axios.post('/hentai/add-to-playlist', {
|
||||||
playlist: document.getElementById('playlist').value,
|
playlist: document.getElementById('playlist').value,
|
||||||
episode_id: document.getElementById('e_id').value
|
episode_id: document.getElementById('e_id').value
|
||||||
}).then(function (response) {
|
}).then(function (response) {
|
||||||
if (response.status == 200) {
|
if (response.status == 200) {
|
||||||
document.getElementById("playlist-cancel").click();
|
|
||||||
|
|
||||||
if (response.data.message == 'already-added') {
|
if (response.data.message == 'already-added') {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Already added!",
|
title: "Already added!",
|
||||||
@@ -18,6 +14,8 @@ if (document.getElementById("playlist-add")) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (response.data.message == 'success') {
|
if (response.data.message == 'success') {
|
||||||
|
document.getElementById("playlist-cancel").click();
|
||||||
|
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
text: "Added episode to the playlist!",
|
text: "Added episode to the playlist!",
|
||||||
@@ -27,33 +25,66 @@ if (document.getElementById("playlist-add")) {
|
|||||||
}
|
}
|
||||||
}).catch(function (error) {
|
}).catch(function (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
Swal.fire({
|
||||||
|
title: "Error!",
|
||||||
|
text: "Could not add episode to playlist.",
|
||||||
|
icon: "error"
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelector("#playlist-add").addEventListener("click", createPlaylist);
|
document.querySelector("#playlist-add").addEventListener("click", addToPlaylist);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.getElementById("playlist-create-and-add")) {
|
if (document.getElementById("playlist-create-and-add")) {
|
||||||
function createAndAddPlaylist() {
|
function createAndAddPlaylist() {
|
||||||
|
const nameField = document.getElementById('playlist-name');
|
||||||
|
const visibilityField = document.getElementById('playlist-visibility');
|
||||||
|
|
||||||
|
if (!nameField.value.trim()) {
|
||||||
|
Swal.fire({
|
||||||
|
title: "Name required!",
|
||||||
|
text: "Please enter a playlist name.",
|
||||||
|
icon: "warning"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
window.axios.post('/hentai/create-playlist', {
|
window.axios.post('/hentai/create-playlist', {
|
||||||
name: document.getElementById('name').value,
|
name: nameField.value,
|
||||||
visiblity: document.getElementById('visiblity').value
|
visiblity: visibilityField.value
|
||||||
}).then(function (response) {
|
}).then(function (response) {
|
||||||
window.axios.post('/hentai/add-to-playlist', {
|
window.axios.post('/hentai/add-to-playlist', {
|
||||||
playlist: response.data.playlist_id,
|
playlist: response.data.playlist_id,
|
||||||
episode_id: document.getElementById('e_id').value
|
episode_id: document.getElementById('e_id').value
|
||||||
}).then(function (response) {
|
}).then(function (addResponse) {
|
||||||
if (response.status == 200) {
|
if (addResponse.status == 200) {
|
||||||
document.getElementById("playlist-cancel").click();
|
const cancelBtn = document.getElementById("playlist-cancel");
|
||||||
|
if (cancelBtn) cancelBtn.click();
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: "Success!",
|
||||||
|
text: "Playlist created and episode added!",
|
||||||
|
icon: "success"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}).catch(function (error) {
|
}).catch(function (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
Swal.fire({
|
||||||
|
title: "Error!",
|
||||||
|
text: "Could not add episode to the new playlist.",
|
||||||
|
icon: "error"
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
}).catch(function (error) {
|
}).catch(function (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
Swal.fire({
|
||||||
|
title: "Error!",
|
||||||
|
text: "Could not create playlist.",
|
||||||
|
icon: "error"
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelector("#playlist-create-and-add").addEventListener("click", createAndAddPlaylist);
|
document.querySelector("#playlist-create-and-add").addEventListener("click", createAndAddPlaylist);
|
||||||
}
|
}
|
||||||
@@ -9,9 +9,55 @@
|
|||||||
src="{{ $playlist->user->getAvatar() }}">
|
src="{{ $playlist->user->getAvatar() }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col justify-center flex-1 pl-4">
|
<div class="flex flex-col justify-center flex-1 pl-4">
|
||||||
<h1 class="font-bold text-3xl">{{ $playlist->name }}</h1>
|
@if ($editingName)
|
||||||
|
<div class="flex items-center gap-2 mb-1">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
wire:model="editingPlaylistName"
|
||||||
|
maxlength="30"
|
||||||
|
class="rounded-lg border border-neutral-400 bg-neutral-800 px-3 py-1.5 text-xl font-bold text-white focus:border-rose-500 focus:outline-none focus:ring-1 focus:ring-rose-500"
|
||||||
|
/>
|
||||||
|
<button wire:click="updateName" class="rounded-lg bg-rose-600 px-3 py-1.5 text-sm font-semibold text-white transition hover:bg-rose-700">
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
<button wire:click="cancelEditName" class="rounded-lg border border-neutral-500 px-3 py-1.5 text-sm text-neutral-300 transition hover:bg-neutral-700">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
@error('editingPlaylistName')
|
||||||
|
<p class="text-rose-400 text-sm mb-1">{{ $message }}</p>
|
||||||
|
@enderror
|
||||||
|
@else
|
||||||
|
<h1 class="font-bold text-3xl">
|
||||||
|
{{ $playlist->name }}
|
||||||
|
@auth
|
||||||
|
@if (Auth::id() === $playlist->user->id)
|
||||||
|
<button wire:click="editName" class="ml-2 text-xl text-neutral-400 transition hover:text-white" title="Edit playlist name">
|
||||||
|
<i class="fa-solid fa-pen-to-square"></i>
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
@endauth
|
||||||
|
</h1>
|
||||||
|
@endif
|
||||||
<p class="font-light text-lg text-neutral-200">Episodes: {{ count($playlistEpisodes) }}</p>
|
<p class="font-light text-lg text-neutral-200">Episodes: {{ count($playlistEpisodes) }}</p>
|
||||||
<p class="font-light text-lg text-neutral-200">Creator: {{ $playlist->user->name }}</p>
|
<p class="font-light text-lg text-neutral-200">
|
||||||
|
Creator: {{ $playlist->user->name }}
|
||||||
|
@auth
|
||||||
|
@if (Auth::id() === $playlist->user->id)
|
||||||
|
<span class="ml-3">
|
||||||
|
<button wire:click="toggleVisibility" class="cursor-pointer rounded-full px-3 py-0.5 text-xs font-semibold transition {{ $playlist->is_private ? 'bg-neutral-600 text-neutral-300 hover:bg-neutral-500' : 'bg-green-600 text-white hover:bg-green-500' }}">
|
||||||
|
<i class="fa-solid {{ $playlist->is_private ? 'fa-lock' : 'fa-earth-americas' }} mr-1"></i>
|
||||||
|
{{ $playlist->is_private ? 'Private' : 'Public' }}
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
@else
|
||||||
|
<span class="ml-3 rounded-full px-3 py-0.5 text-xs font-semibold {{ $playlist->is_private ? 'bg-neutral-600 text-neutral-300' : 'bg-green-600 text-white' }}">
|
||||||
|
<i class="fa-solid {{ $playlist->is_private ? 'fa-lock' : 'fa-earth-americas' }} mr-1"></i>
|
||||||
|
{{ $playlist->is_private ? 'Private' : 'Public' }}
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
@endauth
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col justify-center pl-4">
|
<div class="flex flex-col justify-center pl-4">
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
|
|||||||
@@ -13,96 +13,71 @@
|
|||||||
|
|
||||||
<!--Modal body-->
|
<!--Modal body-->
|
||||||
<div class="relative p-4">
|
<div class="relative p-4">
|
||||||
<!-- Add to existing playlist -->
|
|
||||||
@php $playlists = Auth::user()->playlists; @endphp
|
@php $playlists = Auth::user()->playlists; @endphp
|
||||||
|
|
||||||
@if (count($playlists) > 0)
|
@if (count($playlists) > 0)
|
||||||
|
<!-- Add to existing playlist -->
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<label class="mb-2 leading-tight text-gray-800 dark:text-gray-200 w-full" for="playlist">Select Playlist:</label>
|
<label class="mb-2 leading-tight text-gray-800 dark:text-gray-200 w-full" for="playlist">Select Playlist:</label>
|
||||||
<select name="playlist" id="playlist" class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-rose-800 focus:border-rose-900 dark:bg-neutral-900 dark:border-neutral-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-rose-800 dark:focus:border-rose-900">
|
<select name="playlist" id="playlist" class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-rose-800 focus:border-rose-900 dark:bg-neutral-900 dark:border-neutral-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-rose-800 dark:focus:border-rose-900">
|
||||||
@foreach($playlists as $playlist)
|
@foreach($playlists as $playlist)
|
||||||
<option value="{{ $playlist->id }}">
|
<option value="{{ $playlist->id }}">
|
||||||
{{ $playlist->name }} -
|
{{ $playlist->name }} -
|
||||||
{{ $playlist->is_private == 1 ? 'Private' : 'Public' }} -
|
{{ $playlist->is_private == 1 ? 'Private' : 'Public' }} -
|
||||||
{{ $playlist->episodes->count() }} Episodes
|
{{ $playlist->episodes->count() }} Episodes
|
||||||
{{ $playlist->episodes->contains('episode_id', $episode->id) ? '- Episode Already Added' : '' }}
|
{{ $playlist->episodes->contains('episode_id', $episode->id) ? '- Episode Already Added' : '' }}
|
||||||
</option>
|
</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
<x-input-error :messages="$errors->get('playlist')" class="mt-2" />
|
<x-input-error :messages="$errors->get('playlist')" class="mt-2" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-shrink-0 flex-wrap items-center justify-end rounded-b-md p-4 gap-3">
|
<div class="flex flex-shrink-0 flex-wrap items-center justify-end rounded-b-md p-4 gap-3">
|
||||||
<a
|
<a
|
||||||
data-te-modal-dismiss
|
data-te-modal-dismiss
|
||||||
id="playlist-cancel"
|
id="playlist-cancel"
|
||||||
class="cursor-pointer rounded-xl border border-neutral-300 px-5 py-2.5 text-sm font-medium text-neutral-700 transition hover:bg-neutral-100 dark:border-neutral-600 dark:text-neutral-200 dark:hover:bg-neutral-800">
|
class="cursor-pointer rounded-xl border border-neutral-300 px-5 py-2.5 text-sm font-medium text-neutral-700 transition hover:bg-neutral-100 dark:border-neutral-600 dark:text-neutral-200 dark:hover:bg-neutral-800">
|
||||||
Cancel
|
Cancel
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
id="playlist-add"
|
id="playlist-add"
|
||||||
class="cursor-pointer rounded-xl bg-rose-600 px-5 py-2.5 text-sm font-semibold text-white shadow-lg shadow-rose-600/20 transition hover:bg-rose-700">
|
class="cursor-pointer rounded-xl bg-rose-600 px-5 py-2.5 text-sm font-semibold text-white shadow-lg shadow-rose-600/20 transition hover:bg-rose-700">
|
||||||
Add
|
Add
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<hr class="my-4 border-neutral-200 dark:border-neutral-700">
|
||||||
|
|
||||||
|
<p class="px-4 text-sm font-semibold text-neutral-500 dark:text-neutral-400 uppercase tracking-wide">Or Create a New Playlist</p>
|
||||||
|
@else
|
||||||
|
<p class="px-4 text-sm text-neutral-600 dark:text-neutral-400">
|
||||||
|
No Playlists found. Create one below!
|
||||||
|
</p>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- Create new playlist -->
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<label class="mb-2 leading-tight text-gray-800 dark:text-gray-200 w-full" for="name">Enter Playlist Name Here:</label>
|
<label class="mb-2 leading-tight text-gray-800 dark:text-gray-200 w-full" for="playlist-name">Playlist Name:</label>
|
||||||
<x-text-input id="name" class="block mt-1 w-full" type="text" name="name" required autofocus/>
|
<x-text-input id="playlist-name" class="block mt-1 w-full" type="text" name="name" maxlength="30" required />
|
||||||
<x-input-error :messages="$errors->get('name')" class="mt-2" />
|
<x-input-error :messages="$errors->get('name')" class="mt-2" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<label class="mb-2 leading-tight text-gray-800 dark:text-gray-200 w-full" for="visiblity">Visiblity:</label>
|
<label class="mb-2 leading-tight text-gray-800 dark:text-gray-200 w-full" for="playlist-visibility">Visibility:</label>
|
||||||
<select name="visiblity" id="visiblity" class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-rose-800 focus:border-rose-900 dark:bg-neutral-900 dark:border-neutral-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-rose-800 dark:focus:border-rose-900">
|
<select name="visiblity" id="playlist-visibility" class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-rose-800 focus:border-rose-900 dark:bg-neutral-900 dark:border-neutral-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-rose-800 dark:focus:border-rose-900">
|
||||||
<option value="public">Public</option>
|
<option value="public">Public</option>
|
||||||
<option value="private" selected>Private</option>
|
<option value="private" selected>Private</option>
|
||||||
</select>
|
</select>
|
||||||
<x-input-error :messages="$errors->get('visiblity')" class="mt-2" />
|
<x-input-error :messages="$errors->get('visiblity')" class="mt-2" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-shrink-0 flex-wrap items-center justify-end rounded-b-md p-4">
|
<div class="flex flex-shrink-0 flex-wrap items-center justify-end rounded-b-md p-4">
|
||||||
<a
|
<a
|
||||||
id="playlist-create-and-add"
|
id="playlist-create-and-add"
|
||||||
class="cursor-pointer rounded-xl bg-rose-600 px-5 py-2.5 text-sm font-semibold text-white shadow-lg shadow-rose-600/20 transition hover:bg-rose-700">
|
class="cursor-pointer rounded-xl bg-rose-600 px-5 py-2.5 text-sm font-semibold text-white shadow-lg shadow-rose-600/20 transition hover:bg-rose-700">
|
||||||
Create and Add Episode
|
Create and Add Episode
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@else
|
|
||||||
|
|
||||||
<!-- Create Playlist -->
|
|
||||||
<a class="font-semibold text-gray-800 dark:text-gray-200 leading-tight">
|
|
||||||
No Playlists found. Please create a Playlist first!
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div class="p-4">
|
|
||||||
<label class="mb-2 leading-tight text-gray-800 dark:text-gray-200 w-full" for="name">Enter Playlist Name Here:</label>
|
|
||||||
<x-text-input id="name" class="block mt-1 w-full" type="text" name="name" required autofocus/>
|
|
||||||
<x-input-error :messages="$errors->get('name')" class="mt-2" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-5 p-4">
|
|
||||||
<label class="mb-2 leading-tight text-gray-800 dark:text-gray-200 w-full" for="visiblity">Visiblity:</label>
|
|
||||||
<select name="visiblity" id="visiblity" class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-rose-800 focus:border-rose-900 dark:bg-neutral-900 dark:border-neutral-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-rose-800 dark:focus:border-rose-900">
|
|
||||||
<option value="public">Public</option>
|
|
||||||
<option value="private" selected>Private</option>
|
|
||||||
</select>
|
|
||||||
<x-input-error :messages="$errors->get('visiblity')" class="mt-2" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-shrink-0 flex-wrap items-center justify-end rounded-b-md p-4">
|
|
||||||
<a id="playlist-cancel" class="inline-block cursor-pointer rounded bg-primary-100 px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-primary-700 transition duration-150 ease-in-out hover:bg-primary-accent-100 focus:bg-primary-accent-100 focus:outline-none focus:ring-0 active:bg-primary-accent-200" data-te-modal-dismiss data-te-ripple-init data-te-ripple-color="light">
|
|
||||||
Cancel
|
|
||||||
</a>
|
|
||||||
<a id="playlist-create-and-add" class="ml-1 cursor-pointer inline-block rounded bg-rose-600 px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white transition duration-150 ease-in-out hover:bg-rose-700 focus:bg-rose-600" data-te-ripple-init data-te-ripple-color="light">
|
|
||||||
Create and Add Episode
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@endif
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
class="fixed inset-0 z-[1055] hidden overflow-y-auto bg-black/60 backdrop-blur-sm"
|
class="fixed inset-0 z-[1055] hidden overflow-y-auto bg-black/60 backdrop-blur-sm"
|
||||||
>
|
>
|
||||||
<div data-te-modal-dialog-ref class="flex min-h-screen items-center justify-center p-4">
|
<div data-te-modal-dialog-ref class="flex min-h-screen items-center justify-center p-4">
|
||||||
<div class="relative w-full max-w-4xl overflow-hidden rounded-2xl border border-neutral-200 bg-white shadow-2xl dark:border-neutral-700 dark:bg-neutral-900">
|
<div class="relative w-full max-w-2xl overflow-hidden rounded-2xl border border-neutral-200 bg-white shadow-2xl dark:border-neutral-700 dark:bg-neutral-900">
|
||||||
<x-modal-header :title="__('Create Playlist')" />
|
<x-modal-header :title="__('Create Playlist')" />
|
||||||
|
|
||||||
<!--Modal body-->
|
<!--Modal body-->
|
||||||
@@ -17,25 +17,30 @@
|
|||||||
@csrf
|
@csrf
|
||||||
|
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<label class="mb-2 leading-tight text-gray-800 dark:text-gray-200 w-full" for="name">Enter Playlist Name Here:</label>
|
<label class="mb-2 leading-tight text-gray-800 dark:text-gray-200 w-full" for="name">Playlist Name:</label>
|
||||||
<x-text-input id="name" class="block mt-1 w-full" type="text" name="name" required autofocus/>
|
<x-text-input id="name" class="block mt-1 w-full" type="text" name="name" maxlength="30" required autofocus />
|
||||||
<x-input-error :messages="$errors->get('name')" class="mt-2" />
|
<x-input-error :messages="$errors->get('name')" class="mt-2" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-5 p-4">
|
<div class="p-4">
|
||||||
<label class="mb-2 leading-tight text-gray-800 dark:text-gray-200 w-full" for="visiblity">Visiblity:</label>
|
<label class="mb-2 leading-tight text-gray-800 dark:text-gray-200 w-full" for="visiblity">Visibility:</label>
|
||||||
<select name="visiblity" id="visiblity" class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-rose-800 focus:border-rose-900 dark:bg-neutral-900 dark:border-neutral-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-rose-800 dark:focus:border-rose-900">
|
<select name="visiblity" id="visiblity" class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-rose-800 focus:border-rose-900 dark:bg-neutral-900 dark:border-neutral-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-rose-800 dark:focus:border-rose-900">
|
||||||
<option value="public">Public</option>
|
<option value="public">Public</option>
|
||||||
<option value="private" selected>Private</option>
|
<option value="private" selected>Private</option>
|
||||||
</select>
|
</select>
|
||||||
<x-input-error :messages="$errors->get('visiblity')" class="mt-2" />
|
<x-input-error :messages="$errors->get('visiblity')" class="mt-2" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-shrink-0 flex-wrap items-center justify-end rounded-b-md p-4">
|
<div class="flex flex-shrink-0 flex-wrap items-center justify-end rounded-b-md p-4 gap-3">
|
||||||
<button type="button" class="inline-block rounded bg-primary-100 px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-primary-700 transition duration-150 ease-in-out hover:bg-primary-accent-100 focus:bg-primary-accent-100 focus:outline-none focus:ring-0 active:bg-primary-accent-200" data-te-modal-dismiss data-te-ripple-init data-te-ripple-color="light">
|
<button
|
||||||
|
type="button"
|
||||||
|
data-te-modal-dismiss
|
||||||
|
class="cursor-pointer rounded-xl border border-neutral-300 px-5 py-2.5 text-sm font-medium text-neutral-700 transition hover:bg-neutral-100 dark:border-neutral-600 dark:text-neutral-200 dark:hover:bg-neutral-800">
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" class="ml-1 inline-block rounded bg-rose-600 px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white transition duration-150 ease-in-out hover:bg-rose-700 focus:bg-rose-600" data-te-ripple-init data-te-ripple-color="light">
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="cursor-pointer rounded-xl bg-rose-600 px-5 py-2.5 text-sm font-semibold text-white shadow-lg shadow-rose-600/20 transition hover:bg-rose-700">
|
||||||
Create
|
Create
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -43,4 +48,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -20,17 +20,65 @@
|
|||||||
<img src="/images/hentai/sukebe-elf-tanbouki/gallery-ep-1-0.webp" class="rounded-t-lg opacity-50 dark:opacity-20" alt="..." />
|
<img src="/images/hentai/sukebe-elf-tanbouki/gallery-ep-1-0.webp" class="rounded-t-lg opacity-50 dark:opacity-20" alt="..." />
|
||||||
@endif
|
@endif
|
||||||
</a>
|
</a>
|
||||||
<div class="p-6">
|
<div class="p-6" x-data="{ editing: false, name: '{{ $playlist->name }}', isPrivate: {{ $playlist->is_private ? 'true' : 'false' }} }">
|
||||||
<h5 class="mb-2 text-xl font-medium leading-tight text-neutral-800 dark:text-neutral-50">
|
<!-- Edit mode -->
|
||||||
{{ $playlist->name }}
|
<template x-if="editing">
|
||||||
</h5>
|
<div>
|
||||||
<p class="mb-2 text-sm leading-tight text-neutral-800 dark:text-neutral-50">
|
<form method="POST" action="{{ route('profile.playlist.update', $playlist->id) }}" class="space-y-3">
|
||||||
{{ $count }} Episodes - {{ $playlist->is_private == 1 ? 'Private' : 'Public' }}
|
@csrf
|
||||||
@if($count > 0)
|
@method('PATCH')
|
||||||
<a href="{{ route('hentai.index', ['title' => $playlist->episodes->first()->episode->slug, 'playlist' => $playlist->id]) }}" class="cursor-pointer float-right text-white bg-rose-700 hover:bg-rose-800 focus:ring-4 focus:outline-none focus:ring-rose-300 font-medium rounded-lg text-sm px-4 py-2 dark:bg-rose-600 dark:hover:bg-rose-700 dark:focus:ring-rose-800">{{ __('playlist.play') }}</a>
|
<div>
|
||||||
@endif
|
<label class="mb-1 block text-xs font-medium text-neutral-600 dark:text-neutral-400">Name:</label>
|
||||||
</p>
|
<input
|
||||||
<a href="{{ route('profile.playlist.delete', $playlist->id) }}" class="inline-flex items-center cursor-pointer text-xs text-red-600" data-confirm-delete="true">Delete</a>
|
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-600 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 class="flex gap-2">
|
||||||
|
<button type="submit" class="cursor-pointer rounded-lg bg-rose-600 px-4 py-2 text-xs font-semibold text-white transition hover:bg-rose-700">
|
||||||
|
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-4 py-2 text-xs font-medium text-neutral-700 transition hover:bg-neutral-100 dark:border-neutral-600 dark:text-neutral-200 dark:hover:bg-neutral-800">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Display mode -->
|
||||||
|
<template x-if="!editing">
|
||||||
|
<div>
|
||||||
|
<h5 class="mb-2 text-xl font-medium leading-tight text-neutral-800 dark:text-neutral-50">
|
||||||
|
{{ $playlist->name }}
|
||||||
|
</h5>
|
||||||
|
<p class="mb-2 text-sm leading-tight text-neutral-800 dark:text-neutral-50">
|
||||||
|
{{ $count }} Episodes - {{ $playlist->is_private == 1 ? 'Private' : 'Public' }}
|
||||||
|
@if($count > 0)
|
||||||
|
<a href="{{ route('hentai.index', ['title' => $playlist->episodes->first()->episode->slug, 'playlist' => $playlist->id]) }}" class="cursor-pointer float-right text-white bg-rose-700 hover:bg-rose-800 focus:ring-4 focus:outline-none focus:ring-rose-300 font-medium rounded-lg text-sm px-4 py-2 dark:bg-rose-600 dark:hover:bg-rose-700 dark:focus:ring-rose-800">{{ __('playlist.play') }}</a>
|
||||||
|
@endif
|
||||||
|
</p>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<a href="{{ route('profile.playlist.delete', $playlist->id) }}" class="inline-flex items-center cursor-pointer text-xs text-red-600" data-confirm-delete="true">Delete</a>
|
||||||
|
<button @click="editing = true" class="inline-flex items-center cursor-pointer text-xs text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300">Edit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ Route::middleware('auth')->group(function () {
|
|||||||
Route::get('/user/playlists', [PlaylistController::class, 'playlists'])->name('profile.playlists');
|
Route::get('/user/playlists', [PlaylistController::class, 'playlists'])->name('profile.playlists');
|
||||||
Route::get('/user/playlist/{playlist_id}', [PlaylistController::class, 'showPlaylist'])->name('profile.playlist.show');
|
Route::get('/user/playlist/{playlist_id}', [PlaylistController::class, 'showPlaylist'])->name('profile.playlist.show');
|
||||||
Route::post('/create-playlist', [PlaylistController::class, 'createPlaylist'])->name('profile.playlists.create');
|
Route::post('/create-playlist', [PlaylistController::class, 'createPlaylist'])->name('profile.playlists.create');
|
||||||
|
Route::patch('/user/playlist/{playlist_id}', [PlaylistController::class, 'updatePlaylist'])->name('profile.playlist.update');
|
||||||
Route::delete('/user/playlist/{playlist_id}', [PlaylistController::class, 'deletePlaylist'])->name('profile.playlist.delete');
|
Route::delete('/user/playlist/{playlist_id}', [PlaylistController::class, 'deletePlaylist'])->name('profile.playlist.delete');
|
||||||
Route::post('/user/playlist-episode', [PlaylistController::class, 'deleteEpisodeFromPlaylist'])->name('playlist.delete.episode');
|
Route::post('/user/playlist-episode', [PlaylistController::class, 'deleteEpisodeFromPlaylist'])->name('playlist.delete.episode');
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user