dev #27

Merged
RHPZAdmin merged 3 commits from dev into master 2026-07-01 09:51:49 +00:00
21 changed files with 403 additions and 38 deletions

View File

@@ -64,6 +64,19 @@ class XenForoGuard implements Guard
if ($this->hasUser()) if ($this->hasUser())
return $this->user; return $this->user;
$user = $this->getFromSession();
if( $user )
return $user;
$user = $this->getFromCookie();
if( $user )
return $user;
return null;
}
private function getFromSession(): ?XenForoUser
{
$sessionId = $this->request->cookie('xf_session'); $sessionId = $this->request->cookie('xf_session');
if(!$sessionId) if(!$sessionId)
return null; return null;
@@ -92,6 +105,64 @@ class XenForoGuard implements Guard
return $this->user = new XenForoUser($xfUser); return $this->user = new XenForoUser($xfUser);
} }
private function isCorrectCookieKey(string $key, $record): bool
{
$known = $record->remember_key;
if( !$known )
return false;
$check = hash('sha256', $key, true);
return hash_equals($known, $check);
}
private function getFromCookie(): ?XenForoUser
{
$cookie = $this->request->cookie('xf_user');
if(!$cookie)
return null;
$parts = explode(',', $cookie);
if( count( $parts ) !== 2 )
return null;
[$userId, $key] = $parts;
$userId = (int) $userId;
if( !$userId || !$key )
return null;
$remembers = \DB::connection('xenforo')
->table('user_remember')
->where('user_id', $userId)
->get();
if( !$remembers )
return null;
$valid = false;
foreach( $remembers as $remember )
{
if( $this->isCorrectCookieKey($key, $remember) && $remember->expiry_date >= time() ){
$valid = true;
break;
}
}
if( !$valid )
return null;
$xfUser = \DB::connection('xenforo')
->table('user')
->where('user_id', $userId)
->first();
if(!$xfUser)
return null;
return $this->user = new XenForoUser($xfUser);
}
/** /**
* Unused. * Unused.
* *

View File

@@ -125,4 +125,18 @@ class EntryHelpers {
session(["downloaded_file_{$entryFile->file_uuid}" => 1]); session(["downloaded_file_{$entryFile->file_uuid}" => 1]);
return true; return true;
} }
public static function stripBbCode(?string $text): ?string
{
if ($text === null) return null;
$text = preg_replace('/\[quote\b[^\]]*\](.*?)\[\/quote\]/is', '', $text);
return preg_replace('/\[\/?\w+[^\]]*\]/i', '', $text);
}
public static function stripMarkdown(?string $text): ?string
{
if ($text === null) return null;
$html = Str::markdown($text);
return html_entity_decode(strip_tags($html), ENT_QUOTES, 'UTF-8');
}
} }

View File

@@ -2,6 +2,7 @@
namespace App\Services; namespace App\Services;
use App\Helpers\EntryHelpers;
use App\Models\Entry; use App\Models\Entry;
use App\Models\EntryReview; use App\Models\EntryReview;
use App\Models\News; use App\Models\News;
@@ -65,7 +66,7 @@ class ActivityService
'user_id' => $entry->user_id, 'user_id' => $entry->user_id,
'badge' => EntryCard::ENTRY_TYPES_BADGE[$entry->type], 'badge' => EntryCard::ENTRY_TYPES_BADGE[$entry->type],
'badge_class' => $entry->type, 'badge_class' => $entry->type,
'excerpt' => $entry->description ? \Str::limit(strip_tags($entry->description), 80) : null, 'excerpt' => $entry->description ? \Str::limit(EntryHelpers::stripMarkdown(strip_tags($entry->description)), 80) : null,
'meta' => $entry->getRealPlatform()?->name 'meta' => $entry->getRealPlatform()?->name
]; ];
} }
@@ -82,7 +83,7 @@ class ActivityService
'user_id' => $news->user_id, 'user_id' => $news->user_id,
'badge' => 'News', 'badge' => 'News',
'badge_class' => 'news', 'badge_class' => 'news',
'excerpt' => $news->description ? \Str::limit(strip_tags($news->description), 80) : null, 'excerpt' => $news->description ? \Str::limit(EntryHelpers::stripMarkdown(strip_tags($news->description)), 80) : null,
'meta' => $news->category?->name 'meta' => $news->category?->name
]; ];
} }
@@ -99,7 +100,7 @@ class ActivityService
'user_id' => $message->user_id, 'user_id' => $message->user_id,
'badge' => 'Post', 'badge' => 'Post',
'badge_class' => 'message', 'badge_class' => 'message',
'excerpt' => $message->message ? \Str::limit(strip_tags($message->message), 80) : null, 'excerpt' => $message->message ? \Str::limit(EntryHelpers::stripBbCode(strip_tags($message->message)), 80) : null,
'meta' => null 'meta' => null
]; ];
@@ -117,7 +118,7 @@ class ActivityService
'user_id' => $thread->user_id, 'user_id' => $thread->user_id,
'badge' => 'Thread', 'badge' => 'Thread',
'badge_class' => 'thread', 'badge_class' => 'thread',
'excerpt' => $thread->message ? \Str::limit(strip_tags($thread->message), 80) : null, 'excerpt' => $thread->message ? \Str::limit(EntryHelpers::stripBbCode(strip_tags($thread->message)), 80) : null,
'meta' => null 'meta' => null
]; ];
@@ -152,7 +153,7 @@ class ActivityService
'user_id' => $review->user_id, 'user_id' => $review->user_id,
'badge' => 'Review', 'badge' => 'Review',
'badge_class' => 'review', 'badge_class' => 'review',
'excerpt' => $review->description ? \Str::limit(strip_tags($review->description), 80) : null, 'excerpt' => $review->description ? \Str::limit(EntryHelpers::stripMarkdown(strip_tags($review->description)), 80) : null,
'meta' => $review->entry()->exists() ? ( $review->entry->complete_title ?? $review->entry->title ) : null, 'meta' => $review->entry()->exists() ? ( $review->entry->complete_title ?? $review->entry->title ) : null,
]; ];
} }

View File

@@ -30,6 +30,7 @@
border: 1px solid var(--border); border: 1px solid var(--border);
display: flex; display: flex;
min-width: 0; min-width: 0;
max-width: 100%;
flex-direction: column; flex-direction: column;
transition: transform 0.2s, border-color 0.2s; transition: transform 0.2s, border-color 0.2s;
cursor: pointer; cursor: pointer;
@@ -72,6 +73,7 @@
.entry-card-info { .entry-card-info {
padding: 15px; padding: 15px;
flex-grow: 1; flex-grow: 1;
min-width: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
@@ -82,13 +84,16 @@
font-size: 1.1rem; font-size: 1.1rem;
margin-bottom: 5px; margin-bottom: 5px;
line-height: 1.3; line-height: 1.3;
word-wrap: break-word; overflow-wrap: anywhere;
word-break: break-word;
} }
.entry-card-author { .entry-card-author {
color: var(--rhpz-orange); color: var(--rhpz-orange);
font-size: 0.85rem; font-size: 0.85rem;
margin-bottom: 10px; margin-bottom: 10px;
overflow-wrap: anywhere;
word-break: break-word;
} }
.entry-card-meta { .entry-card-meta {
@@ -148,6 +153,9 @@
.entry-card-meta { .entry-card-meta {
font-size: 0.75rem; font-size: 0.75rem;
flex-direction: column;
align-items: flex-start;
gap: 6px;
} }
} }

View File

@@ -43,6 +43,45 @@
background-color: rgba(129, 199, 132, 0.1); background-color: rgba(129, 199, 132, 0.1);
} }
.back-to-top {
display: none;
}
@media (max-width: 768px) {
.back-to-top {
display: none;
align-items: center;
justify-content: center;
gap: 8px;
position: fixed;
right: 14px;
bottom: 14px;
z-index: 1000;
padding: 10px 14px;
border-radius: 999px;
background-color: var(--bg2);
border: 1px solid var(--border);
color: var(--text);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
opacity: 0;
pointer-events: none;
transform: translateY(10px);
transition: opacity 0.2s ease, transform 0.2s ease;
}
.back-to-top.visible {
display: inline-flex;
opacity: 1;
pointer-events: auto;
transform: translateY(0);
}
.back-to-top span {
font-size: 0.78rem;
font-weight: 600;
}
}
/* BLOCK */ /* BLOCK */
.block { .block {

View File

@@ -227,8 +227,10 @@
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
flex-wrap: wrap;
gap: 4px; gap: 4px;
margin-top: 20px; margin-top: 20px;
width: 100%;
.btn { .btn {
min-width: 36px; min-width: 36px;
@@ -255,18 +257,20 @@
} }
@media (max-width: 900px) { @media (max-width: 900px) {
.database-layout {
flex-direction: column;
}
.database-wrapper { .database-wrapper {
flex-direction: column; flex-direction: column;
width: 100%;
} }
.database-filters { .database-filters {
width: 100%; width: 100%;
display: grid; display: grid;
grid-template-columns: repeat(2,1fr); grid-template-columns: repeat(2, minmax(0, 1fr));
}
.database-results {
width: 100%;
min-width: 0;
} }
.database-filter-group:last-child { .database-filter-group:last-child {
@@ -286,13 +290,32 @@
flex-wrap: wrap; flex-wrap: wrap;
} }
.filter-bar {
flex-direction: column;
align-items: stretch;
}
.filter-bar .filter-bar-search {
max-width: none;
flex: initial;
width: 100%;
}
.filter-bar .btn {
width: 100%;
justify-content: center;
}
.database-wrapper { .database-wrapper {
flex-direction: column; flex-direction: column;
gap: 15px; gap: 15px;
width: 100%;
} }
.database-filters { .database-filters {
width: 100%; width: min(100%, 420px);
max-width: 420px;
margin: 0 auto;
grid-template-columns: 1fr; grid-template-columns: 1fr;
order: -1; order: -1;
margin-bottom: 10px; margin-bottom: 10px;
@@ -303,7 +326,7 @@
} }
.grid-entries { .grid-entries {
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 15px; gap: 15px;
} }
} }
@@ -311,6 +334,20 @@
@media (max-width: 600px) { @media (max-width: 600px) {
.database-search { .database-search {
flex-direction: column; flex-direction: column;
align-items: stretch;
}
.filter-bar {
padding: 12px;
}
.filter-bar .filter-bar-search {
max-width: none;
}
.filter-bar .btn {
width: 100%;
justify-content: center;
} }
.database-filters { .database-filters {
@@ -318,7 +355,7 @@
} }
.grid-entries { .grid-entries {
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px; gap: 12px;
} }

View File

@@ -393,6 +393,37 @@
min-width: 20px; min-width: 20px;
text-align: center; text-align: center;
} }
.gallery-mobile-controls {
display: none;
}
@media (max-width: 1024px) {
.gallery-mobile-controls {
display: flex;
justify-content: flex-end;
gap: 6px;
margin-top: 6px;
}
.gallery-move-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border: 1px solid var(--border);
background-color: var(--bg2);
color: var(--text);
cursor: pointer;
padding: 0;
}
.gallery-move-btn:disabled {
opacity: 0.4;
cursor: not-allowed;
}
}
.authors-list { .authors-list {
display: grid; display: grid;
grid-template-columns: repeat(4, 1fr); grid-template-columns: repeat(4, 1fr);
@@ -510,13 +541,30 @@
} }
@media (max-width: 600px) { @media (max-width: 600px) {
.upload-item-actions { .upload-item {
flex-direction: column; flex-direction: column;
align-items: stretch;
}
.upload-item-info {
width: 100%;
flex: 1 1 auto;
min-width: 0;
}
.upload-item-actions {
flex-direction: row;
justify-content: flex-end;
align-items: center;
gap: 8px; gap: 8px;
width: 100%;
margin-top: 8px;
flex-basis: 100%;
} }
.upload-item-actions .btn { .upload-item-actions .btn {
width: 100%; width: auto;
flex: 0 0 auto;
} }
} }
.file-state-icon { width: 18px; height: 18px; } .file-state-icon { width: 18px; height: 18px; }
@@ -673,10 +721,18 @@
.grid-hashes { .grid-hashes {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
.grid-credits {
grid-template-columns: 1fr;
}
.grid-first {
display: none;
}
.hash-first { .hash-first {
display: none; display: none;
} }
.author-search-selected {
display: none;
}
} }
@media (max-width: 600px) { @media (max-width: 600px) {
@@ -706,4 +762,20 @@
.form-error-text { .form-error-text {
font-size: 0.8rem; font-size: 0.8rem;
} }
.form-type-of-checkboxes {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
label {
box-sizing: border-box;
margin: 0;
}
input[type="checkbox"] {
transform: scale(1.5);
margin-right: 1.33rem;
}
}
} }

View File

@@ -30,8 +30,38 @@
.grid-entries { .grid-entries {
display: grid; display: grid;
grid-template-columns: repeat(6,1fr); grid-template-columns: repeat(6, minmax(0, 1fr));
gap: 20px; gap: 20px;
margin-bottom: 20px; margin-bottom: 20px;
} }
@media (max-width: 1400px) {
.grid-entries {
grid-template-columns: repeat(5, minmax(0, 1fr));
}
}
@media (max-width: 1200px) {
.grid-entries {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
@media (max-width: 900px) {
.grid-entries {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
@media (max-width: 640px) {
.grid-entries {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 420px) {
.grid-entries {
grid-template-columns: 1fr;
}
}

View File

@@ -223,7 +223,7 @@
.activity-tl-card-description { .activity-tl-card-description {
font-size: 0.8rem; font-size: 0.8rem;
color: var(--text2); color: var(--text2);
white-space: nowrap; word-break: break-word;
text-overflow: ellipsis; text-overflow: ellipsis;
line-height: 1.3; line-height: 1.3;
} }
@@ -265,6 +265,8 @@
@media (max-width: 600px) { @media (max-width: 600px) {
.activity-tl-header { flex-direction: column; align-items: flex-start; } .activity-tl-header { flex-direction: column; align-items: flex-start; }
.activity-tl-thumb { display: none; } .activity-tl-thumb { display: none; }
.activity-tl-left { display: none; }
.activity-tl-card-description { display: none; }
.activity-day-sep { padding-left: 44px; } .activity-day-sep { padding-left: 44px; }
.activity-tl-left { width: 44px; } .activity-tl-left { width: 44px; }
@@ -279,7 +281,7 @@
@media (max-width: 768px) { @media (max-width: 768px) {
.activity-timeline { .activity-timeline {
padding-left: 50px; padding-left: 0px;
} }
.activity-tl-left { .activity-tl-left {

View File

@@ -101,6 +101,7 @@
line-height: 1.6; line-height: 1.6;
color: var(--text); color: var(--text);
margin-bottom: 30px; margin-bottom: 30px;
word-break: break-word;
} }
.entry-gallery { .entry-gallery {

View File

@@ -7,6 +7,7 @@
flex-shrink: 0; flex-shrink: 0;
transition: transform 0.3s ease; transition: transform 0.3s ease;
z-index: 100; z-index: 100;
overflow: hidden;
.menu-header { .menu-header {
padding: 10px; padding: 10px;
@@ -44,9 +45,12 @@
} }
.menu-navigation { .menu-navigation {
flex-grow: 1; flex: 1 1 auto;
min-height: 0;
padding: 10px 0; padding: 10px 0;
overflow-y: auto; overflow-y: auto;
-webkit-overflow-scrolling: touch;
overscroll-behavior: contain;
.menu-group { .menu-group {
margin-bottom: 20px; margin-bottom: 20px;
@@ -96,7 +100,9 @@
} }
.menu-user { .menu-user {
padding: 15px 20px; flex-shrink: 0;
margin-top: auto;
padding: 15px 20px calc(15px + env(safe-area-inset-bottom)) 20px;
border-top: 1px solid var(--border); border-top: 1px solid var(--border);
display: flex; display: flex;
align-items: center; align-items: center;
@@ -131,6 +137,7 @@
&.username { &.username {
font-size: 0.9rem; font-size: 0.9rem;
font-weight: 600; font-weight: 600;
text-decoration: none !important;
} }
&.user_role { &.user_role {
font-size: 0.75rem; font-size: 0.75rem;

View File

@@ -8,7 +8,8 @@
position: fixed; position: fixed;
left: 0; left: 0;
top: 60px; top: 60px;
height: calc(100vh - 60px); height: calc(100dvh - 60px);
max-height: calc(100dvh - 60px);
transform: translateX(-100%); transform: translateX(-100%);
transition: transform 0.3s ease-in-out; transition: transform 0.3s ease-in-out;
z-index: 999; z-index: 999;

View File

@@ -131,15 +131,38 @@ export function GalleryManager() {
this.dragSrcI = index; this.dragSrcI = index;
}, },
moveImageUp(index){
if( index <= 0 )
return;
const moved = this.images.splice(index, 1)[0];
this.images.splice(index - 1, 0, moved);
},
moveImageDown(index){
if( index >= this.images.length - 1 )
return;
const moved = this.images.splice(index, 1)[0];
this.images.splice(index + 1, 0, moved);
},
reorderImages(from, to){
if( from === null || to === null || from === to )
return;
const moved = this.images.splice(from, 1)[0];
this.images.splice(to, 0, moved);
this.dragSrcI = to;
},
dragOver(e, index){ dragOver(e, index){
e.preventDefault(); e.preventDefault();
if( this.dragSrcI === null || this.dragSrcI === index ) if( this.dragSrcI === null || this.dragSrcI === index )
return; return;
const moved = this.images.splice(this.dragSrcI, 1)[0]; this.reorderImages(this.dragSrcI, index);
this.images.splice(index, 0, moved);
this.dragSrcI = index;
}, },
dragEnd(){ dragEnd(){

View File

@@ -8,6 +8,7 @@ import notifications from "./notifications.js";
import conversations from "./conversations.js"; import conversations from "./conversations.js";
import settings from "./settings.js"; import settings from "./settings.js";
import { initMobileMenu } from "./mobile-menu.js"; import { initMobileMenu } from "./mobile-menu.js";
import { initMobileBackToTop } from "./mobile-back-to-top.js"
/** /**
* Get config defined in meta.blade.php * Get config defined in meta.blade.php
@@ -47,3 +48,4 @@ Alpine.store('settings', settings() );
// Mobile Menu // Mobile Menu
document.addEventListener('DOMContentLoaded', initMobileMenu); document.addEventListener('DOMContentLoaded', initMobileMenu);
document.addEventListener( 'DOMContentLoaded', initMobileBackToTop );

View File

@@ -72,6 +72,7 @@ export default function hovercard(){
Alpine.nextTick(() => { Alpine.nextTick(() => {
const card = document.querySelector('.hovercard'); const card = document.querySelector('.hovercard');
if (card) window.refreshIcons(card); if (card) window.refreshIcons(card);
this.updatePosition(this.anchorEl);
}); });
} catch( error ){ } catch( error ){
@@ -89,13 +90,26 @@ export default function hovercard(){
const RECT = anchorEl.getBoundingClientRect(); const RECT = anchorEl.getBoundingClientRect();
const SCROLL_X = window.scrollX; const SCROLL_X = window.scrollX;
const SCROLL_Y = window.scrollY; const SCROLL_Y = window.scrollY;
const VIEWPORT_WIDTH = window.innerWidth;
const VIEWPORT_HEIGHT = window.innerHeight;
let x = RECT.left + SCROLL_X; const CARD = document.querySelector('.hovercard');
const WIDTH = CARD?.offsetWidth || 280;
const HEIGHT = CARD?.offsetHeight || 320;
let x = RECT.right + SCROLL_X + 8;
let y = RECT.bottom + SCROLL_Y + 8; let y = RECT.bottom + SCROLL_Y + 8;
const WIDTH = 280; if( x + WIDTH > VIEWPORT_WIDTH - 8 && RECT.left + SCROLL_X - WIDTH - 8 >= 8 ){
if( x + WIDTH > window.innerWidth ){ x = RECT.left + SCROLL_X - WIDTH - 8;
x = window.innerWidth - WIDTH - 16; } else {
x = Math.max(8, Math.min(x, VIEWPORT_WIDTH - WIDTH - 8));
}
if( y + HEIGHT > VIEWPORT_HEIGHT + SCROLL_Y - 8 && RECT.top + SCROLL_Y - HEIGHT - 8 >= 8 ){
y = RECT.top + SCROLL_Y - HEIGHT - 8;
} else {
y = Math.max(8, Math.min(y, VIEWPORT_HEIGHT + SCROLL_Y - HEIGHT - 8));
} }
this.x = x; this.x = x;

View File

@@ -0,0 +1,18 @@
export function initMobileBackToTop(){
const backToTopButton = document.querySelector('.back-to-top');
const content = document.getElementById('content');
if (!backToTopButton || !content) {
return;
}
const toggleBackToTop = () => {
const shouldShow = window.innerWidth <= 768 && content.scrollTop > 320;
backToTopButton.classList.toggle('visible', shouldShow);
};
toggleBackToTop();
content.addEventListener('scroll', toggleBackToTop, { passive: true });
window.addEventListener('resize', toggleBackToTop, { passive: true });
}

View File

@@ -15,7 +15,15 @@
</div> </div>
<div class="form-gallery form-group level" style="flex:4;"> <div class="form-gallery form-group level" style="flex:4;">
<template x-for="(image,i) in images" :key="image.key"> <template x-for="(image,i) in images" :key="image.key">
<div class="gallery-item" :class="{ 'gallery-item--dragging': dragSrcI === i }" draggable="true" @dragstart="dragStart(i)" @dragover="dragOver($event, i)" @dragend="dragEnd()"> <div
class="gallery-item"
:class="{ 'gallery-item--dragging': dragSrcI === i }"
draggable="true"
:data-gallery-index="i"
@dragstart="dragStart(i)"
@dragover="dragOver($event, i)"
@dragend="dragEnd()"
>
<div class="form-image-preview-wrap"> <div class="form-image-preview-wrap">
<div class="gallery-drag-handle" title="Drag to reorder"> <div class="gallery-drag-handle" title="Drag to reorder">
<i data-lucide="grip-vertical" size="14"></i> <i data-lucide="grip-vertical" size="14"></i>
@@ -28,6 +36,14 @@
X X
</button> </button>
</div> </div>
<div class="gallery-mobile-controls" aria-label="Reorder screenshot">
<button type="button" class="gallery-move-btn" @click="moveImageUp(i)" :disabled="i === 0" title="Move up">
<i data-lucide="chevron-up" size="14"></i>
</button>
<button type="button" class="gallery-move-btn" @click="moveImageDown(i)" :disabled="i === images.length - 1" title="Move down">
<i data-lucide="chevron-down" size="14"></i>
</button>
</div>
</div> </div>
</template> </template>
</div> </div>

View File

@@ -2,9 +2,9 @@
<x-form-field-title name="Staff/Credits" /> <x-form-field-title name="Staff/Credits" />
<template x-if="credits.length > 0"> <template x-if="credits.length > 0">
<div class="form-group grid-credits"> <div class="form-group grid-credits">
<div><x-form-field-title name="Name" /></div> <div class="grid-first"><x-form-field-title name="Name" /></div>
<div><x-form-field-title name="Description" /></div> <div class="grid-first"><x-form-field-title name="Description" /></div>
<div><x-form-field-title name="Actions" /></div> <div class="grid-first"><x-form-field-title name="Actions" /></div>
<template x-for="(credit,i) in credits" :key="i"> <template x-for="(credit,i) in credits" :key="i">
<div style="display:contents"> <div style="display:contents">
<div> <div>

View File

@@ -54,7 +54,7 @@
</div> </div>
<div class="comment-body"> <div class="comment-body">
{!! $comment['message'] !!} {!! \App\Helpers\EntryHelpers::stripBbCode($comment['message']) !!}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -33,6 +33,11 @@
</div> </div>
<button type="button" class="back-to-top" aria-label="Back to top" onclick="document.getElementById('content')?.scrollTo({ top: 0, behavior: 'smooth' });">
<i data-lucide="arrow-up"></i>
<span>Top</span>
</button>
@include('components.hovercard') @include('components.hovercard')
@livewireScripts @livewireScripts
@stack('scripts') @stack('scripts')

View File

@@ -38,7 +38,11 @@
</div> </div>
<div class="menu-user-info"> <div class="menu-user-info">
<span class="username"> <span class="username">
{{ $VISITOR->username ?? "Guest" }} @if( $VISITOR->guest() )
Guest
@else
<x-xf-username-link :user-id="$VISITOR->user_id" />
@endif
</span> </span>
<span class="user_role"> <span class="user_role">
<a href="{{ $VISITOR->guest() ? xfRoute('login') : xfRoute('logout') . '?t=' . xfCsrfToken() }}"> <a href="{{ $VISITOR->guest() ? xfRoute('login') : xfRoute('logout') . '?t=' . xfCsrfToken() }}">