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\Hentai;
|
||||||
use App\Models\PopularMonthly;
|
use App\Models\PopularMonthly;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
@@ -46,6 +47,8 @@ class HentaiApiController extends Controller
|
|||||||
// Cache for 60 minutes
|
// Cache for 60 minutes
|
||||||
$data = Cache::remember('api_monthly_views', now()->addMinutes(60), function () {
|
$data = Cache::remember('api_monthly_views', now()->addMinutes(60), function () {
|
||||||
return PopularMonthly::selectRaw('DATE(created_at) as date, COUNT(*) as count')
|
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')
|
->groupBy('date')
|
||||||
->orderBy('date', 'asc')
|
->orderBy('date', 'asc')
|
||||||
->get();
|
->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\WithPagination;
|
||||||
use Livewire\Attributes\Url;
|
use Livewire\Attributes\Url;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class AdminUserSearch extends Component
|
class AdminUserSearch extends Component
|
||||||
{
|
{
|
||||||
use WithPagination;
|
use WithPagination;
|
||||||
@@ -24,6 +26,18 @@ class AdminUserSearch extends Component
|
|||||||
#[Url(history: true)]
|
#[Url(history: true)]
|
||||||
public $banned = [];
|
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()
|
public function render()
|
||||||
{
|
{
|
||||||
$users = User::when($this->filtered !== [], fn ($query) => $query->where('id', '>=', 10000))
|
$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: {
|
plugins: {
|
||||||
title: {
|
title: {
|
||||||
display: true,
|
display: true,
|
||||||
text: 'Views the last 30 days',
|
text: 'Views the last 28 days',
|
||||||
font: {
|
font: {
|
||||||
size: 18
|
size: 18
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,3 +20,45 @@ if(localStorage.theme) {
|
|||||||
// Default Dark Theme
|
// Default Dark Theme
|
||||||
localStorage.theme = 'dark';
|
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>
|
<span class="ms-3">Users</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</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>
|
<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">
|
<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>
|
<i class="fa-solid fa-message"></i>
|
||||||
|
|||||||
@@ -59,11 +59,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</x-dropdown-link>
|
</x-dropdown-link>
|
||||||
|
|
||||||
|
{{-- Expiremental --}}
|
||||||
|
<x-dropdown-link>
|
||||||
|
@include('partials.blurswitcher')
|
||||||
|
</x-dropdown-link>
|
||||||
</x-slot>
|
</x-slot>
|
||||||
</x-dropdown>
|
</x-dropdown>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center invisible sm:visible">
|
<div class="items-center hidden md:flex">
|
||||||
@livewire('nav-live-search')
|
@livewire('nav-live-search')
|
||||||
<div class="hidden lg:block pl-4">
|
<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">
|
<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">
|
<td class="px-6 py-4">
|
||||||
{{ $user->updated_at->format('Y-m-d') }}
|
{{ $user->updated_at->format('Y-m-d') }}
|
||||||
</td>
|
</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') }}">
|
<form method="POST" action="{{ route('admin.user.update') }}">
|
||||||
@csrf
|
@csrf
|
||||||
<input type="hidden" value="{{ $user->id }}" name="id">
|
<input type="hidden" value="{{ $user->id }}" name="id">
|
||||||
<input type="hidden" value="{{ $user->is_banned ? 'unban' : 'ban' }}" name="action">
|
<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' }}
|
{{ $user->is_banned ? 'Unban' : 'Ban' }}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@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>
|
<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">
|
<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-eye mr-1"></i> {{ $episode->viewCountFormatted() }}
|
||||||
<i class="fa-regular fa-heart ml-2"></i> {{ count($episode->likes) }}
|
<i class="fa-regular fa-heart ml-2"></i> {{ $episode->likeCount() }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-3">
|
<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::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');
|
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
|
// Contact page overview
|
||||||
Route::get('/admin/contact', [App\Http\Controllers\Admin\ContactController::class, 'index'])->name('admin.contact.index');
|
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');
|
Route::delete('/admin/contact/{contact_id}', [App\Http\Controllers\Admin\ContactController::class, 'delete'])->name('admin.contact.delete');
|
||||||
|
|||||||
Reference in New Issue
Block a user