Auth: convert auth views and verification email to Nova layout

This commit is contained in:
2026-02-21 07:37:08 +01:00
parent 93b009d42a
commit 795c7a835f
117 changed files with 5385 additions and 1291 deletions

View File

@@ -1,51 +0,0 @@
@extends('layouts.legacy')
@php
use Carbon\Carbon;
@endphp
@section('content')
<div class="container-fluid legacy-page">
<div class="effect2 page-header-wrap">
<header class="page-heading">
<h1 class="page-header">Forum</h1>
<p>Latest threads</p>
</header>
</div>
<div class="panel panel-default effect2">
<div class="panel-heading"><strong>Forum Threads</strong></div>
<div class="panel-body">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>Thread</th>
<th class="text-center">Posts</th>
<th class="text-center">Topics</th>
<th class="text-right">Last Update</th>
</tr>
</thead>
<tbody>
@forelse ($topics as $topic)
<tr>
<td>
<h4 style="margin:0;">
<a href="/forum/{{ $topic->topic_id }}/{{ Str::slug($topic->topic ?? '') }}">{{ $topic->topic }}</a>
</h4>
<div class="text-muted">{!! $topic->discuss !!}</div>
</td>
<td class="text-center">{{ $topic->num_posts ?? 0 }}</td>
<td class="text-center">{{ $topic->num_subtopics ?? 0 }}</td>
<td class="text-right">{{ $topic->last_update ? Carbon::parse($topic->last_update)->format('H:i @ d.m') : '' }}</td>
</tr>
@empty
<tr><td colspan="4">No threads available.</td></tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
</div>
@endsection

View File

@@ -1,51 +0,0 @@
@extends('layouts.legacy')
@php
use Carbon\Carbon;
@endphp
@section('content')
<div class="container-fluid legacy-page">
<div class="effect2 page-header-wrap">
<header class="page-heading">
<div class="navigation"><a class="badge" href="/forum">Forum</a></div>
<h1 class="page-header">{{ $topic->topic }}</h1>
@if (!empty($topic->discuss))
<p>{!! $topic->discuss !!}</p>
@endif
</header>
</div>
<div class="panel panel-default effect2">
<div class="panel-heading"><strong>Posts</strong></div>
<div class="panel-body">
@forelse ($posts as $post)
<div class="panel panel-default effect2" style="overflow:hidden;">
<div class="panel-heading clearfix">
<div class="pull-right text-muted">{{ $post->post_date ? Carbon::parse($post->post_date)->format('d.m.Y H:i') : '' }}</div>
<strong>{{ $post->uname ?? 'Anonymous' }}</strong>
</div>
<div class="panel-body" style="display:flex; gap:12px;">
<div style="min-width:52px;">
@if (!empty($post->user_id) && !empty($post->icon))
<img src="{{ \App\Support\AvatarUrl::forUser((int) $post->user_id, null, 50) }}" alt="{{ $post->uname }}" width="50" height="50" class="img-thumbnail">
@else
<div class="img-thumbnail" style="width:50px;height:50px;"></div>
@endif
</div>
<div style="flex:1;">
{!! $post->message !!}
</div>
</div>
</div>
@empty
<p>No posts yet.</p>
@endforelse
<div class="paginationMenu text-center">
{{ $posts->withQueryString()->links('pagination::bootstrap-4') }}
</div>
</div>
</div>
</div>
@endsection

View File

@@ -1,56 +0,0 @@
@extends('layouts.legacy')
@php
use Carbon\Carbon;
use Illuminate\Support\Str;
@endphp
@section('content')
<div class="container-fluid legacy-page">
<div class="effect2 page-header-wrap">
<header class="page-heading">
<div class="navigation"><a class="badge" href="/forum">Forum</a></div>
<h1 class="page-header">{{ $topic->topic }}</h1>
@if (!empty($topic->discuss))
<p>{!! $topic->discuss !!}</p>
@endif
</header>
</div>
<div class="panel panel-default effect2">
<div class="panel-heading"><strong>Topics</strong></div>
<div class="panel-body">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>Topic</th>
<th class="text-center">Opened By</th>
<th class="text-right">Posted</th>
</tr>
</thead>
<tbody>
@forelse ($subtopics as $sub)
<tr>
<td>{{ $sub->topic_id }}</td>
<td>
<a href="/forum/{{ $sub->topic_id }}/{{ Str::slug($sub->topic ?? '') }}">{{ $sub->topic }}</a>
<div class="text-muted small">{!! Str::limit(strip_tags($sub->discuss ?? ''), 160) !!}</div>
</td>
<td class="text-center">{{ $sub->uname ?? 'Unknown' }}</td>
<td class="text-right">{{ $sub->last_update ? Carbon::parse($sub->last_update)->format('d.m.Y H:i') : '' }}</td>
</tr>
@empty
<tr><td colspan="4">No topics yet.</td></tr>
@endforelse
</tbody>
</table>
</div>
<div class="paginationMenu text-center">
{{ $subtopics->withQueryString()->links('pagination::bootstrap-4') }}
</div>
</div>
</div>
</div>
@endsection

View File

@@ -1,6 +1,10 @@
{{-- News and forum columns --}}
<div class="row news-row">
<div class="col-sm-6">
@php
use Carbon\Carbon;
use Illuminate\Support\Str;
@endphp
@forelse ($forumNews as $item)
<div class="panel panel-skinbase effect2">
<div class="panel-heading"><h4 class="panel-title">{{ $item->topic }}</h4></div>
@@ -10,7 +14,7 @@
</div>
{!! Str::limit(strip_tags($item->preview ?? ''), 240, '...') !!}
<br>
<a class="clearfix btn btn-xs btn-info" href="/forum/{{ $item->topic_id }}/{{ Str::slug($item->topic ?? '') }}" title="{{ strip_tags($item->topic) }}">More</a>
<a class="clearfix btn btn-xs btn-info" href="{{ route('forum.thread.show', ['thread' => $item->topic_id, 'slug' => Str::slug($item->topic ?? '')]) }}" title="{{ strip_tags($item->topic) }}">More</a>
</div>
</div>
@empty
@@ -67,7 +71,7 @@
<div class="panel-body">
<div class="list-group effect2">
@forelse ($latestForumActivity as $topic)
<a class="list-group-item" href="/forum/{{ $topic->topic_id }}/{{ Str::slug($topic->topic ?? '') }}">
<a class="list-group-item" href="{{ route('forum.thread.show', ['thread' => $topic->topic_id, 'slug' => Str::slug($topic->topic ?? '')]) }}">
{{ $topic->topic }} <span class="badge badge-info">{{ $topic->numPosts }}</span>
</a>
@empty

View File

@@ -2,6 +2,19 @@
@section('content')
@php
$birthDay = $birthDay ?? null;
$birthMonth = $birthMonth ?? null;
$birthYear = $birthYear ?? null;
$avatarUserId = (int) ($user->id ?? auth()->id() ?? 0);
$avatarHash = $user->icon
?? optional(auth()->user())->profile->avatar_hash
?? null;
$currentAvatarUrl = !empty($avatarHash)
? \App\Support\AvatarUrl::forUser($avatarUserId, $avatarHash, 128)
: \App\Support\AvatarUrl::default();
@endphp
<div class="min-h-screen bg-deep text-white py-12">
<!-- Container -->
@@ -146,7 +159,30 @@
<!-- Avatar -->
<div>
<label class="form-label">Avatar</label>
<input type="file" name="avatar" class="form-file">
<div class="rounded-xl border border-sb-line bg-black/10 p-4">
<div class="flex items-center gap-4">
<img
id="avatarPreviewImage"
src="{{ $currentAvatarUrl }}"
alt="{{ $user->name ?? $user->username ?? 'Avatar' }}"
class="w-24 h-24 rounded-full object-cover ring-1 ring-white/10"
loading="lazy"
decoding="async"
>
<div class="min-w-0 flex-1">
<button
type="button"
id="avatarDropzone"
class="w-full rounded-lg border border-dashed border-sb-line px-4 py-4 text-left hover:bg-white/5 focus:outline-none focus:ring-2 focus:ring-sb-blue/50"
>
<div class="text-sm text-white/90">Drag & drop a new avatar here</div>
<div class="text-xs text-soft mt-1">or click to browse (JPG, PNG, WEBP)</div>
<div id="avatarFileName" class="text-xs text-sb-muted mt-2 truncate">No file selected</div>
</button>
<input id="avatarInput" type="file" name="avatar" class="sr-only" accept="image/jpeg,image/png,image/webp">
</div>
</div>
</div>
</div>
<!-- Emoticon -->
@@ -245,3 +281,65 @@
</div>
@endsection
@push('scripts')
<script>
(() => {
const input = document.getElementById('avatarInput');
const dropzone = document.getElementById('avatarDropzone');
const preview = document.getElementById('avatarPreviewImage');
const fileName = document.getElementById('avatarFileName');
if (!input || !dropzone || !preview || !fileName) {
return;
}
const updatePreview = (file) => {
if (!file || !file.type || !file.type.startsWith('image/')) {
return;
}
const objectUrl = URL.createObjectURL(file);
preview.src = objectUrl;
fileName.textContent = file.name;
preview.onload = () => URL.revokeObjectURL(objectUrl);
};
dropzone.addEventListener('click', () => input.click());
input.addEventListener('change', () => {
const file = input.files && input.files[0] ? input.files[0] : null;
if (file) {
updatePreview(file);
}
});
['dragenter', 'dragover'].forEach((eventName) => {
dropzone.addEventListener(eventName, (event) => {
event.preventDefault();
event.stopPropagation();
dropzone.classList.add('ring-2', 'ring-sb-blue/50');
});
});
['dragleave', 'drop'].forEach((eventName) => {
dropzone.addEventListener(eventName, (event) => {
event.preventDefault();
event.stopPropagation();
dropzone.classList.remove('ring-2', 'ring-sb-blue/50');
});
});
dropzone.addEventListener('drop', (event) => {
const file = event.dataTransfer && event.dataTransfer.files ? event.dataTransfer.files[0] : null;
if (!file) {
return;
}
const dt = new DataTransfer();
dt.items.add(file);
input.files = dt.files;
updatePreview(file);
});
})();
</script>
@endpush