Compare commits
6 Commits
7e382ffe1d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ca2f73714 | |||
| 59d63abd79 | |||
| efb3e4197b | |||
| 735dd693ca | |||
| 36f0126a21 | |||
| 50d8704560 |
16
app/Http/Controllers/Admin/CommentsController.php
Normal file
16
app/Http/Controllers/Admin/CommentsController.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class CommentsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display Comments Page.
|
||||
*/
|
||||
public function index(): \Illuminate\View\View
|
||||
{
|
||||
return view('admin.comments.index');
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Hentai;
|
||||
use App\Models\PopularMonthly;
|
||||
use Carbon\Carbon;
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use App\Http\Controllers\Controller;
|
||||
@@ -46,6 +47,8 @@ class HentaiApiController extends Controller
|
||||
// Cache for 60 minutes
|
||||
$data = Cache::remember('api_monthly_views', now()->addMinutes(60), function () {
|
||||
return PopularMonthly::selectRaw('DATE(created_at) as date, COUNT(*) as count')
|
||||
->whereDate('created_at', '<', Carbon::today())
|
||||
->whereDate('created_at', '>=', Carbon::today()->subDays(28))
|
||||
->groupBy('date')
|
||||
->orderBy('date', 'asc')
|
||||
->get();
|
||||
|
||||
40
app/Livewire/AdminCommentSearch.php
Normal file
40
app/Livewire/AdminCommentSearch.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AdminCommentSearch extends Component
|
||||
{
|
||||
use WithPagination;
|
||||
|
||||
public $search = '';
|
||||
|
||||
public $userSearch = '';
|
||||
|
||||
public function updatingSearch(): void
|
||||
{
|
||||
$this->resetPage();
|
||||
}
|
||||
|
||||
public function updatingUserSearch(): void
|
||||
{
|
||||
$this->resetPage();
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
$comments = DB::table('comments')
|
||||
->join('users', 'comments.commenter_id', '=', 'users.id')
|
||||
->select('comments.*', 'users.username')
|
||||
->when($this->search !== '', fn ($query) => $query->where('comment', 'LIKE', "%$this->search%"))
|
||||
->when($this->userSearch !== '', fn ($query) => $query->where('username', 'LIKE', "%$this->userSearch%"))
|
||||
->paginate(12);
|
||||
|
||||
return view('livewire.admin-comment-search', [
|
||||
'comments' => $comments
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
use Livewire\Attributes\Url;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AdminUserSearch extends Component
|
||||
{
|
||||
use WithPagination;
|
||||
@@ -24,6 +26,18 @@ class AdminUserSearch extends Component
|
||||
#[Url(history: true)]
|
||||
public $banned = [];
|
||||
|
||||
public function deleteUserComments(int $userID)
|
||||
{
|
||||
$user = User::where('id', $userID)
|
||||
->firstOrFail();
|
||||
|
||||
DB::table('comments')
|
||||
->where('commenter_id', '=', $user->id)
|
||||
->delete();
|
||||
|
||||
cache()->flush();
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
$users = User::when($this->filtered !== [], fn ($query) => $query->where('id', '>=', 10000))
|
||||
|
||||
@@ -34,7 +34,7 @@ window.axios.get('/v1/monthly-views').then(function (response) {
|
||||
plugins: {
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Views the last 30 days',
|
||||
text: 'Views the last 28 days',
|
||||
font: {
|
||||
size: 18
|
||||
}
|
||||
|
||||
@@ -20,3 +20,45 @@ if(localStorage.theme) {
|
||||
// Default Dark Theme
|
||||
localStorage.theme = 'dark';
|
||||
}
|
||||
|
||||
// Ability to disable blur effects for slower devices
|
||||
const LOCAL_STORAGE_KEY = 'blur';
|
||||
const blurCheckbox = document.querySelector("input[type='checkbox']#toggleBlur");
|
||||
|
||||
function setCSSFilter(selector, value) {
|
||||
document.querySelectorAll(selector).forEach(el => {
|
||||
el.style.backdropFilter = value
|
||||
});
|
||||
}
|
||||
|
||||
function applyBlur(enabled) {
|
||||
if (!enabled) {
|
||||
setCSSFilter('.backdrop-blur, .backdrop-blur-sm, .backdrop-blur-lg', 'none');
|
||||
return;
|
||||
}
|
||||
|
||||
setCSSFilter('.backdrop-blur-lg', 'blur(16px)');
|
||||
setCSSFilter('.backdrop-blur', 'blur(8px)');
|
||||
setCSSFilter('.backdrop-blur-sm', 'blur(4px)');
|
||||
}
|
||||
|
||||
function initBlurToggle() {
|
||||
const storedValue = localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||
const enabled = storedValue === null ? true : storedValue === 'true';
|
||||
|
||||
// initialize UI and DOM
|
||||
applyBlur(enabled);
|
||||
if (blurCheckbox) blurCheckbox.checked = enabled;
|
||||
|
||||
// add event listener
|
||||
if (blurCheckbox) {
|
||||
blurCheckbox.addEventListener('click', (e) => {
|
||||
console.log("Received Event");
|
||||
const isEnabled = e.target.checked;
|
||||
applyBlur(isEnabled);
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY, isEnabled ? 'true' : 'false');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
initBlurToggle();
|
||||
5
resources/views/admin/comments/index.blade.php
Normal file
5
resources/views/admin/comments/index.blade.php
Normal file
@@ -0,0 +1,5 @@
|
||||
@extends('admin.layout')
|
||||
|
||||
@section('content')
|
||||
@livewire('admin-comment-search')
|
||||
@endsection
|
||||
@@ -19,6 +19,12 @@
|
||||
<span class="ms-3">Users</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ route('admin.comments.index') }}" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-pink-700/40 group @if(Route::is('admin.comments.index')) bg-pink-700/40 @endif">
|
||||
<i class="fa-solid fa-comment"></i>
|
||||
<span class="ms-3">Comments</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ route('admin.contact.index') }}" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-pink-700/40 group @if(Route::is('admin.contact.index')) bg-pink-700/40 @endif">
|
||||
<i class="fa-solid fa-message"></i>
|
||||
|
||||
@@ -59,11 +59,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</x-dropdown-link>
|
||||
|
||||
{{-- Expiremental --}}
|
||||
<x-dropdown-link>
|
||||
@include('partials.blurswitcher')
|
||||
</x-dropdown-link>
|
||||
</x-slot>
|
||||
</x-dropdown>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center invisible sm:visible">
|
||||
<div class="items-center hidden md:flex">
|
||||
@livewire('nav-live-search')
|
||||
<div class="hidden lg:block pl-4">
|
||||
<div class="flex flex-col items-center bg-gray-50/20 dark:bg-neutral-900/40 rounded-md">
|
||||
|
||||
57
resources/views/livewire/admin-comment-search.blade.php
Normal file
57
resources/views/livewire/admin-comment-search.blade.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<div>
|
||||
<div class="relative pt-5 text-gray-900 dark:text-white xl:max-w-[95%] 2xl:max-w-[90%]" wire:keydown.right.window="nextPage" wire:keydown.left.window="previousPage">
|
||||
<div class="flex items-center justify-center">
|
||||
<div class="relative overflow-x-auto rounded-lg w-3/6">
|
||||
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-white">
|
||||
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-pink-700 dark:text-neutral-200 ">
|
||||
<tr>
|
||||
<th scope="col" class="px-6 py-3 text-center">
|
||||
User
|
||||
<input
|
||||
wire:model.live.debounce.600ms="userSearch"
|
||||
type="search"
|
||||
id="live-search"
|
||||
class="w-32 h-7 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"
|
||||
placeholder="Search..."
|
||||
>
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-3">
|
||||
Comment
|
||||
<input
|
||||
wire:model.live.debounce.600ms="search"
|
||||
type="search"
|
||||
id="live-search"
|
||||
class="ml-2 w-32 h-7 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"
|
||||
placeholder="Search..."
|
||||
>
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-3">
|
||||
Actions
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($comments as $comment)
|
||||
<tr wire:key="comment-{{ $comment->id }}" class="bg-white border-t dark:bg-neutral-800 dark:border-pink-700">
|
||||
<td class="px-6 py-4">
|
||||
<a href="{{ route('user.index', ['username' => $comment->username]) }}">{{ $comment->username }}</a>
|
||||
</td>
|
||||
<th scope="row" class="px-6 py-4 font-medium text-gray-900 dark:text-white max-w-lg">
|
||||
{{ $comment->comment }}
|
||||
</th>
|
||||
<td class="px-6 py-4">
|
||||
<a href="{{ route('comments.destroy', $comment->id) }}" onclick="event.preventDefault();document.getElementById('comment-delete-form-{{ $comment->id }}').submit();" class="inline-flex items-center px-4 py-2 bg-red-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-red-500 active:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150 mt-2">@lang('comments::comments.delete')</a>
|
||||
<form id="comment-delete-form-{{ $comment->id }}" action="{{ route('comments.destroy', $comment->id) }}" method="POST" style="display: none;">
|
||||
@method('DELETE')
|
||||
@csrf
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{ $comments->links('pagination::tailwind') }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -74,15 +74,18 @@
|
||||
<td class="px-6 py-4">
|
||||
{{ $user->updated_at->format('Y-m-d') }}
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<td class="px-6 py-4 flex flex-col gap-1">
|
||||
<form method="POST" action="{{ route('admin.user.update') }}">
|
||||
@csrf
|
||||
<input type="hidden" value="{{ $user->id }}" name="id">
|
||||
<input type="hidden" value="{{ $user->is_banned ? 'unban' : 'ban' }}" name="action">
|
||||
<button type="submit" class="inline-block rounded bg-rose-600 pl-[4px] pr-[4px] p-[1px] text-xs font-medium uppercase leading-normal text-white transition duration-150 ease-in-out hover:bg-rose-700 focus:bg-rose-600">
|
||||
<button type="submit" class="inline-block w-full rounded bg-rose-600 pl-[4px] pr-[4px] p-[1px] text-xs font-medium uppercase leading-normal text-white transition duration-150 ease-in-out hover:bg-rose-700 focus:bg-rose-600">
|
||||
{{ $user->is_banned ? 'Unban' : 'Ban' }}
|
||||
</button>
|
||||
</form>
|
||||
<button wire:click="deleteUserComments('{{ $user->id }}')" class="inline-block w-full rounded bg-red-600 pl-[4px] pr-[4px] p-[1px] text-xs font-medium uppercase leading-normal text-white transition duration-150 ease-in-out hover:bg-rose-700 focus:bg-rose-600">
|
||||
Delete comments
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
@@ -75,8 +75,8 @@
|
||||
>
|
||||
<span class="absolute right-0 top-0 bg-white/90 dark:bg-neutral-800/80 dark:text-white text-xs font-semibold rounded-tr rounded-bl-xl px-2 py-1">{{ $episode->getResolution() }}</span>
|
||||
<div class="absolute left-0 bottom-0 bg-white/90 dark:bg-neutral-800/80 dark:text-white text-xs rounded-tr-xl px-2 py-1 font-medium">
|
||||
<i class="fa-regular fa-eye mr-1"></i> {{ $episode->view_count }}
|
||||
<i class="fa-regular fa-heart ml-2"></i> {{ count($episode->likes) }}
|
||||
<i class="fa-regular fa-eye mr-1"></i> {{ $episode->viewCountFormatted() }}
|
||||
<i class="fa-regular fa-heart ml-2"></i> {{ $episode->likeCount() }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-3">
|
||||
|
||||
36
resources/views/partials/blurswitcher.blade.php
Normal file
36
resources/views/partials/blurswitcher.blade.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<div class="grid grid-cols-2">
|
||||
<p class="cursor-default">{{ __('Blur effects') }}</p>
|
||||
<div class="flex items-center">
|
||||
<div class="absolute right-6">
|
||||
<label for="toggleBlur" class="flex items-center cursor-pointer">
|
||||
<!-- toggle -->
|
||||
<div class="relative">
|
||||
<!-- input -->
|
||||
<input id="toggleBlur" type="checkbox" class="sr-only" checked />
|
||||
<!-- line -->
|
||||
<div class="w-10 h-4 bg-rose-600 dark:bg-gray-400 rounded-full shadow-inner">
|
||||
</div>
|
||||
<!-- dot -->
|
||||
<div
|
||||
class="dot absolute w-6 h-6 bg-white dark:bg-neutral-950 rounded-full shadow -left-1 -top-1 transition">
|
||||
<div class="items-center ml-[4px] w-6 h-6 font-medium flex">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24"
|
||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-blur">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M12 21a9.01 9.01 0 0 0 2.32 -.302a9 9 0 0 0 1.74 -16.733a9 9 0 1 0 -4.06 17.035z" />
|
||||
<path d="M12 3v17" />
|
||||
<path d="M12 12h9" />
|
||||
<path d="M12 9h8" />
|
||||
<path d="M12 6h6" />
|
||||
<path d="M12 18h6" />
|
||||
<path d="M12 15h8" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -102,6 +102,9 @@ Route::group(['middleware' => ['auth', 'auth.admin']], function () {
|
||||
Route::get('/admin/users', [App\Http\Controllers\Admin\UserController::class, 'index'])->name('admin.user.index');
|
||||
Route::post('/admin/users', [App\Http\Controllers\Admin\UserController::class, 'update'])->name('admin.user.update');
|
||||
|
||||
// Comments
|
||||
Route::get('/admin/comments', [App\Http\Controllers\Admin\CommentsController::class, 'index'])->name('admin.comments.index');
|
||||
|
||||
// Contact page overview
|
||||
Route::get('/admin/contact', [App\Http\Controllers\Admin\ContactController::class, 'index'])->name('admin.contact.index');
|
||||
Route::delete('/admin/contact/{contact_id}', [App\Http\Controllers\Admin\ContactController::class, 'delete'])->name('admin.contact.delete');
|
||||
|
||||
Reference in New Issue
Block a user