Complete Hubbly theme conversion: all pages rewritten with CSS variable theming

- Converted all views from Dusk components (x-content.content-card, x-form.*) to inline Hubbly style
- All pages use consistent card pattern: rounded-lg, gradient headers, color-mix borders
- Added Hubbly-style homepage with 2-column layout, login card, swiper news carousel
- Rewrote navigation with Alpine.js dropdowns, CSS variable colors, Hubbly assets
- Updated profile page with Hubbly cards, fixed data bugs (friend/guild relationships)
- Rewrote register page to match Hubbly layout: banner header, avatar preview with Frank GIF, 2-column form, avatar carousel selector, border-4 inputs
- Rewrote login, settings, help center, radio, applications, utility pages
- All colors use CSS variables controlled by Filament theme editor
- Added Hubbly assets: banner, Frank GIF, navigation icons, online badge
- Removed all dependencies on x-content.* and x-form.* components
This commit is contained in:
root
2026-06-27 17:01:02 +02:00
parent 61bb70ac1d
commit c53a5a8a2c
68 changed files with 4708 additions and 4608 deletions
@@ -1,45 +1,28 @@
@props(['article', 'forSlider' => false])
<div @class([
'h-[180px] md:h-[210px] rounded w-full shadow-sm relative overflow-hidden transition ease-in-out duration-200',
'hover:scale-[101%]' => !$forSlider,
'swiper-slide group' => $forSlider,
]) style="background-color: var(--color-surface)"
@if (!$forSlider)
onmouseover="slideImage({{ $article->id }})" onmouseleave="unslideImage({{ $article->id }})"
@endif>
<a href="{{ route('article.show', $article->slug) }}">
<div id="article-{{ $article->id }}" style="background: url('/storage/{{ $article->image }}');" class="article-image">
</div>
'group rounded w-full relative overflow-hidden transition ease-in-out duration-200',
'hover:scale-[101%]' => !$forSlider,
'swiper-slide' => $forSlider,
]) style="height: 215px; background-color: var(--color-surface); border: 1px solid color-mix(in srgb, var(--color-text-muted) 15%, transparent);">
<div class="relative w-full h-full overflow-hidden rounded-[6px]">
<a href="{{ route('article.show', $article->slug ?? $article->id) }}" class="block w-full h-full">
<img src="{{ $article->image ? '/storage/' . $article->image : '' }}"
onerror="this.parentElement.style.background='var(--color-surface)';this.style.display='none';"
alt="{{ $article->title }}"
class="object-cover w-full h-full transition-all duration-300 rounded-[6px] hover:scale-105"
loading="lazy">
<div class="mt-3 md:mt-4 px-3 md:px-4">
<p @class([
'font-semibold text-base md:text-lg truncate',
'group-hover:text-[var(--color-primary)] transition duration-200' => $forSlider,
]) >
{{ $article->title }}
</p>
<div class="flex items-center gap-x-2">
<div
class="mt-2 md:mt-3 flex h-8 w-8 md:h-10 md:w-10 items-center justify-center overflow-hidden rounded-full" style="background-color: var(--color-background)">
<img src="{{ setting('avatar_imager') }}{{ $article->user?->look }}&headonly=1" alt="">
</div>
<p class="mt-2 md:mt-4 font-semibold text-sm md:text-base" style="color: var(--color-text-muted)">
{{ $article->user->username ?? setting('hotel_name') }}
</p>
</div>
</div>
</a>
<div class="absolute left-0 w-full p-2" style="bottom: -2px; background: linear-gradient(to top, rgba(0,0,0,0.85) 0%, transparent 100%);">
<h3 class="text-lg font-semibold text-white text-shadow-sm truncate">
{{ $article->title }}
</h3>
@if($article->short_story)
<p class="text-xs font-normal text-white text-shadow-sm truncate">
{{ Str::limit($article->short_story, 80) }}
</p>
@endif
</div>
</a>
</div>
</div>
<script>
function slideImage(articleId) {
document.getElementById('article-' + articleId).classList.add('article-image-slide');
}
function unslideImage(articleId) {
document.getElementById('article-' + articleId).classList.remove('article-image-slide');
}
</script>
@@ -8,22 +8,26 @@
<form class="flex flex-col gap-y-3" action="{{ route('login') }}" method="POST">
@csrf
<div>
<x-form.label for="username">
{{ __('Username') }}
</x-form.label>
<div>
<label for="username" style="color: var(--color-text);">
{{ __('Username') }}
</label>
<x-form.input error-bag="login" name="username" value="{{ old('username') }}" placeholder="{{ __('Username') }}"
:autofocus="true" />
</div>
<input error-bag="login" name="username" value="{{ old('username') }}" placeholder="{{ __('Username') }}"
autofocus
class="w-full rounded-lg px-3 py-2 text-sm border-2 focus:ring-0"
style="background-color: var(--color-background); color: var(--color-text); border-color: color-mix(in srgb, var(--color-text-muted) 15%, transparent);" />
</div>
<div>
<x-form.label for="password">
{{ __('Password') }}
</x-form.label>
<div>
<label for="password" style="color: var(--color-text);">
{{ __('Password') }}
</label>
<x-form.input error-bag="login" name="password" placeholder="{{ __('Password') }}" type="password" />
</div>
<input error-bag="login" name="password" placeholder="{{ __('Password') }}" type="password"
class="w-full rounded-lg px-3 py-2 text-sm border-2 focus:ring-0"
style="background-color: var(--color-background); color: var(--color-text); border-color: color-mix(in srgb, var(--color-text-muted) 15%, transparent);" />
</div>
@if (setting('google_recaptcha_enabled'))
<div class="g-recaptcha" data-sitekey="{{ config('habbo.site.recaptcha_site_key') }}"></div>
@@ -33,9 +37,9 @@
<x-turnstile />
@endif
<x-form.primary-button>
{{ __('Login') }}
</x-form.primary-button>
<button type="submit" class="rounded-lg px-4 py-2 text-sm font-semibold transition-all duration-200 hover:opacity-90" style="background-color: var(--color-primary); color: var(--button-text-color);">
{{ __('Login') }}
</button>
<div class="text-center text-sm font-semibold" style="color: var(--color-text-muted)">
<a href="{{ route('forgot.password.get') }}" class="hover:underline" x-on:click="open = false" style="color: var(--link-color)">
@@ -5,86 +5,54 @@
$rankName = $user->permission?->rank_name ?? 'Staff';
@endphp
<style>
@keyframes sparkle {
0%, 100% { opacity: 0; transform: scale(0) rotate(0deg); }
50% { opacity: 1; transform: scale(1) rotate(180deg); }
}
@keyframes shimmer {
0% { background-position: -200% center; }
100% { background-position: 200% center; }
}
.sparkle-effect {
position: absolute;
width: 4px;
height: 4px;
background: white;
border-radius: 50%;
animation: sparkle 2s infinite;
}
.shimmer-text {
background: linear-gradient(90deg, {{ $staffColor }}, white, {{ $staffColor }});
background-size: 200% auto;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
animation: shimmer 3s linear infinite;
}
</style>
<div class="relative rounded-lg overflow-hidden transition-all duration-300 hover:shadow-lg"
style="background-color: var(--color-surface, #ffffff); border: 2px solid color-mix(in srgb, var(--color-text-muted) 20%, transparent);">
<div class="relative w-full p-4">
<div class="absolute top-3 right-3 z-20 flex flex-col items-center gap-2">
<div class="rounded-md overflow-hidden flex justify-center items-center"
style="width: 40px; height: 40px; border: 2px solid color-mix(in srgb, var(--color-text-muted) 30%, transparent); background-color: color-mix(in srgb, var(--color-surface) 80%, transparent);">
<img src="{{ asset('assets/images/country/default.png') }}" alt="Flag" class="object-cover w-full h-full" />
</div>
<div class="px-2 py-1 rounded-full flex items-center justify-center"
style="background-color: color-mix(in srgb, var(--color-surface) 80%, transparent);">
@if($user->online)
<span class="w-3 h-3 rounded-full bg-green-500 animate-pulse inline-block"></span>
@else
<span class="w-3 h-3 rounded-full bg-gray-400 inline-block"></span>
@endif
</div>
</div>
<div class="group relative bg-white dark:bg-gray-800 rounded-2xl overflow-hidden border-2 transition-all duration-300 hover:scale-[1.02] hover:shadow-2xl cursor-pointer"
style="border-color: {{ $staffColor }}40; box-shadow: 0 4px 15px {{ $staffColor }}10;">
<div class="absolute inset-0 bg-gradient-to-br from-white via-gray-50 to-gray-100 dark:from-gray-800 dark:via-gray-800 dark:to-gray-900 opacity-50"></div>
@php
$sparklePositions = [
['top' => '10%', 'left' => '15%', 'delay' => '0s'],
['top' => '20%', 'right' => '10%', 'delay' => '0.5s'],
['top' => '60%', 'left' => '5%', 'delay' => '1s'],
['top' => '70%', 'right' => '15%', 'delay' => '1.5s'],
];
@endphp
@foreach($sparklePositions as $pos)
<div class="sparkle-effect"
style="{{ $pos['top'] }}; {{ $pos['left'] ?? '' }}; {{ $pos['right'] ?? '' }}; animation-delay: {{ $pos['delay'] }}; box-shadow: 0 0 6px {{ $staffColor }};">
</div>
@endforeach
<div class="relative p-5 flex flex-col items-center text-center">
<div class="relative mb-3">
<div class="w-22 h-22 rounded-full overflow-hidden border-4 transition-all duration-300 group-hover:scale-110 group-hover:rotate-3"
style="border-color: {{ $staffColor }}; box-shadow: 0 0 15px {{ $staffColor }}50, inset 0 0 15px {{ $staffColor }}20;">
<img style="image-rendering: pixelated;"
src="{{ setting('avatar_imager') }}{{ $user->look }}&direction=3&head_direction=3&gesture=sml&action=wlk%2Cwav&size=l&img_format=gif&size=n"
alt="{{ $user->username }}"
class="w-full h-full object-cover">
</div>
@if($user->online)
<div class="absolute bottom-0 right-0 w-4 h-4 rounded-full border-2 border-white dark:border-gray-800 bg-green-500 animate-pulse"
style="box-shadow: 0 0 8px #22c55e;"></div>
@endif
</div>
<div class="flex items-center gap-4">
<div class="flex-shrink-0">
<div class="relative"
style="width: 80px; height: 80px; border-radius: 50%; overflow: hidden; border: 3px solid {{ $staffColor }};">
<img src="{{ setting('avatar_imager') }}{{ $user->look }}&headonly=0&direction=3&size=n&gesture=nrm"
alt="{{ $user->username }}"
class="object-cover object-top absolute inset-0"
style="margin-top: -16px; margin-left: 5px;" />
</div>
</div>
<a href="{{ route('profile.show', $user->username) }}" class="block group/link">
<h3 class="text-lg font-extrabold truncate transition-all duration-300 group-hover/link:scale-105 shimmer-text">
{{ $user->username }}
</h3>
</a>
<div class="mt-1.5 px-3 py-0.5 rounded-full text-xs font-bold uppercase tracking-wide"
style="background-color: {{ $staffColor }}15; color: {{ $staffColor }}; border: 1px solid {{ $staffColor }}30;">
{{ $rankName }}
</div>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-3 line-clamp-2 min-h-[2.5rem] px-2">
{{ $user->motto ?: __('No motto set') }}
</p>
<div class="mt-3 pt-3 border-t border-gray-100 dark:border-gray-700 w-full flex items-center justify-center gap-2 text-xs">
<span class="flex items-center gap-1.5 font-medium {{ $user->online ? 'text-green-500' : 'text-gray-400' }}">
<span class="w-2 h-2 rounded-full {{ $user->online ? 'bg-green-500 animate-pulse' : 'bg-gray-400' }}"></span>
{{ $user->online ? __('Online') : __('Offline') }}
</span>
</div>
<div class="flex flex-col justify-center flex-1 min-w-0">
<div class="flex items-center gap-2 mb-1">
<a href="{{ route('profile.show', $user->username) }}"
class="text-lg font-bold truncate transition hover:opacity-80"
style="color: var(--color-text, #1f2937);">{{ $user->username }}</a>
@if($user->permission?->job_description)
<span class="px-2 py-0.5 text-xs font-medium rounded-full whitespace-nowrap"
style="background-color: color-mix(in srgb, {{ $staffColor }} 20%, transparent); color: {{ $staffColor }};">{{ $user->permission->job_description }}</span>
@endif
</div>
<div class="flex gap-2 flex-wrap">
@if($user->permission?->badge)
<div class="rounded-md overflow-hidden flex justify-center items-center"
style="width: 50px; height: 50px; border: 2px solid color-mix(in srgb, var(--color-text-muted) 30%, transparent); background-color: color-mix(in srgb, var(--color-surface) 80%, transparent);">
<img src="{{ asset(setting('badges_path') . $user->permission->badge . '.gif') }}" alt="Staff Badge" class="object-cover" />
</div>
@endif
</div>
</div>
</div>
</div>
</div>
@@ -1,137 +1,99 @@
<div class="relative hidden h-full w-full flex-col items-center gap-y-2 py-3 md:flex md:flex-row md:gap-x-8 md:gap-y-0 md:py-0" id="mobile-menu" style="color: var(--color-navbar-text)">
@auth
<x-navigation.dropdown icon="home" route-group="user*">
{{ auth()->user()->username }}
<div class="flex flex-col md:flex-row md:items-center md:justify-center w-full gap-y-3 md:gap-x-0 md:gap-y-0" id="mobile-menu"
:class="{ 'show-mobile': dropdownVisible }">
<x-slot:children>
<x-navigation.dropdown-child :route="route('me.show')">
{{ __('Home') }}
</x-navigation.dropdown-child>
<x-navigation.dropdown-child :route="route('draw-badge')">
{{ __('Badge Drawer') }}
</x-navigation.dropdown-child>
<x-navigation.dropdown-child :route="route('profile.show', auth()->user()->username)">
{{ __('My Profile') }}
</x-navigation.dropdown-child>
</x-slot:children>
</x-navigation.dropdown>
@else
<a href="{{ route('welcome') }}"
class="nav-item {{ request()->routeIs('welcome') ? 'border-b-2 border-[var(--color-primary)]' : '' }}">
<i class="mr-1 hidden navigation-icon home lg:inline-flex"></i>
{{ __('Home') }}
</a>
@endauth
@auth
<x-navigation.dropdown icon="community" route-group="community*" :uppercase="true">
{{ __('Community') }}
<x-slot:children>
<x-navigation.dropdown-child :route="route('article.index')">
{{ __('Articles') }}
</x-navigation.dropdown-child>
<x-navigation.dropdown-child :route="route('staff.index')">
{{ __('Staff') }}
</x-navigation.dropdown-child>
<x-navigation.dropdown-child :route="route('teams.index')">
{{ __('Teams') }}
</x-navigation.dropdown-child>
<x-navigation.dropdown-child :route="route('team-applications.index')">
{{ __('Team applications') }}
</x-navigation.dropdown-child>
<x-navigation.dropdown-child :route="route('staff-applications.index')">
{{ __('Staff applications') }}
</x-navigation.dropdown-child>
<x-navigation.dropdown-child :route="route('photos.index')">
{{ __('Photos') }}
</x-navigation.dropdown-child>
</x-slot:children>
</x-navigation.dropdown>
<a href="{{ route('leaderboard.index') }}"
class="nav-item {{ request()->routeIs('leaderboard.*') ? 'border-b-2 border-[var(--color-primary)]' : '' }}">
<i class="navigation-icon leaderboards mr-1 hidden lg:inline-flex"></i>
{{ __('Leaderboards') }}
</a>
<a href="{{ route('values.index') }}"
class="nav-item {{ request()->routeIs('values.*') ? 'border-b-2 border-[var(--color-primary)]' : '' }}">
<i class="navigation-icon leaderboards mr-1 hidden lg:inline-flex"></i>
{{ __('Rare values') }}
</a>
<a data-turbolinks="false" href="{{ route('shop.index') }}"
class="nav-item {{ request()->routeIs('shop.*') ? 'border-b-2 border-[var(--color-primary)]' : '' }}">
<i class="navigation-icon mr-1 hidden lg:inline-flex shop"></i>
{{ __('Shop') }}
</a>
@endauth
<x-navigation.dropdown icon="rules" route-group="help-center*" :uppercase="true">
{{ __('Assistance') }}
<x-slot:children>
@auth
<x-navigation.dropdown-child :route="route('help-center.index')">
{{ __('Help center') }}
</x-navigation.dropdown-child>
@if(hasPermission('manage_website_tickets'))
<x-navigation.dropdown-child :route="route('help-center.ticket.index')">
{{ __('Open tickets') }}
</x-navigation.dropdown-child>
@endif
@else
<x-navigation.dropdown-child :route="route('help-center.rules.index')">
{{ __('Rules') }}
</x-navigation.dropdown-child>
@endauth
</x-slot:children>
</x-navigation.dropdown>
<a href="{{ is_array(setting('discord_invitation_link')) ? '' : setting('discord_invitation_link') }}" target="_blank" class="nav-item">
{{ __('Discord') }}
</a>
<x-navigation.dropdown icon="music" route-group="radio*">
{{ __('Radio') }}
<x-slot:children>
<x-navigation.dropdown-child :route="route('radio.index')">
{{ __('Radio Home') }}
</x-navigation.dropdown-child>
<x-navigation.dropdown-child :route="route('radio.rooster')">
{{ __('DJ Rooster') }}
</x-navigation.dropdown-child>
<x-navigation.dropdown-child :route="route('radio.shouts')">
{{ __('Live Shouts') }}
</x-navigation.dropdown-child>
<x-navigation.dropdown-child :route="route('radio.apply')">
{{ __('Word DJ') }}
</x-navigation.dropdown-child>
<x-navigation.dropdown-child :route="route('radio.leaderboard')">
{{ __('Radio punten') }}
</x-navigation.dropdown-child>
</x-slot:children>
</x-navigation.dropdown>
<div class="w-full flex md:hidden gap-x-1 justify-center">
<x-navigation.language-selector>
<img src="/assets/images/icons/flags/{{ session()->has('locale') ? session()->get('locale') : config('habbo.site.default_language') }}.png"
alt="">
</x-navigation.language-selector>
<div x-data="{ open: false }" class="w-full py-1 md:py-0 md:w-auto md:relative" x-on:click.outside="open = false">
@auth
<a href="#" class="flex gap-2 px-1 h-auto md:h-[60px] items-center text-[14px] font-semibold uppercase transition duration-200 ease-in-out md:border-b-4 md:border-transparent md:hover:border-b-[var(--color-primary)] md:px-4"
style="color: var(--color-navbar-text);"
x-on:click.prevent="open = !open">
<img src="{{ asset('assets/images/icons/navigation/me.png') }}" alt="me" />
<span>{{ auth()->user()->username }}</span>
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" viewBox="0 0 20 20" fill="currentColor" style="color: var(--color-text-muted);"><path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/></svg>
</a>
@else
<a href="{{ route('welcome') }}" class="flex gap-2 px-1 h-auto md:h-[60px] items-center text-[14px] font-semibold uppercase transition duration-200 ease-in-out md:border-b-4 md:border-transparent md:hover:border-b-[var(--color-primary)] md:px-4"
style="color: var(--color-navbar-text);">
<img src="{{ asset('assets/images/icons/navigation/me.png') }}" alt="home" />
<span>{{ __('Home') }}</span>
</a>
@endauth
@auth
<div x-show="open" x-cloak x-transition.duration.200ms
class="w-full md:absolute md:top-full md:left-0 md:z-50 md:min-w-[220px] md:py-2 md:mt-1 rounded-xl"
style="background-color: var(--color-dropdown); color: var(--color-text); border: 1px solid color-mix(in srgb, var(--color-primary) 30%, transparent); box-shadow: 0 4px 24px rgba(0,0,0,0.25);">
<a href="{{ route('me.show') }}" class="block py-4 px-8 font-semibold text-base transition hover:opacity-80 rounded-xl" style="color: var(--color-text);">{{ __('Home') }}</a>
<a href="{{ route('draw-badge') }}" class="block py-4 px-8 font-semibold text-base transition hover:opacity-80 rounded-xl" style="color: var(--color-text);">{{ __('Badge Drawer') }}</a>
<a href="{{ route('profile.show', auth()->user()->username) }}" class="block py-4 px-8 font-semibold text-base transition hover:opacity-80 rounded-xl" style="color: var(--color-text);">{{ __('My Profile') }}</a>
</div>
@endauth
</div>
</div>
<div x-data="{ open: false }" class="w-full py-1 md:py-0 md:w-auto md:relative" x-on:click.outside="open = false">
<a href="#" class="flex gap-2 px-1 h-auto md:h-[60px] items-center text-[14px] font-semibold uppercase transition duration-200 ease-in-out md:border-b-4 md:border-transparent md:hover:border-b-[var(--color-primary)] md:px-4"
style="color: var(--color-navbar-text);"
x-on:click.prevent="open = !open">
<img src="{{ asset('assets/images/icons/navigation/community.png') }}" alt="community" />
<span>{{ __('Community') }}</span>
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" viewBox="0 0 20 20" fill="currentColor" style="color: var(--color-text-muted);"><path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/></svg>
</a>
<div x-show="open" x-cloak x-transition.duration.200ms
class="w-full md:absolute md:top-full md:left-0 md:z-50 md:min-w-[220px] md:py-2 md:mt-1 rounded-xl"
style="background-color: var(--color-dropdown); color: var(--color-text); border: 1px solid color-mix(in srgb, var(--color-primary) 30%, transparent); box-shadow: 0 4px 24px rgba(0,0,0,0.25);">
<a href="{{ route('article.index') }}" class="block py-4 px-8 font-semibold text-base transition hover:opacity-80 rounded-xl" style="color: var(--color-text);">{{ __('News') }}</a>
<a href="{{ route('photos.index') }}" class="block py-4 px-8 font-semibold text-base transition hover:opacity-80 rounded-xl" style="color: var(--color-text);">{{ __('Photos') }}</a>
<a href="{{ route('staff.index') }}" class="block py-4 px-8 font-semibold text-base transition hover:opacity-80 rounded-xl" style="color: var(--color-text);">{{ __('Staff') }}</a>
<a href="{{ route('teams.index') }}" class="block py-4 px-8 font-semibold text-base transition hover:opacity-80 rounded-xl" style="color: var(--color-text);">{{ __('Teams') }}</a>
<a href="{{ route('help-center.rules.index') }}" class="block py-4 px-8 font-semibold text-base transition hover:opacity-80 rounded-xl" style="color: var(--color-text);">{{ __('Rules') }}</a>
</div>
</div>
<div x-data="{ open: false }" class="w-full py-1 md:py-0 md:w-auto md:relative" x-on:click.outside="open = false">
<a href="#" class="flex gap-2 px-1 h-auto md:h-[60px] items-center text-[14px] font-semibold uppercase transition duration-200 ease-in-out md:border-b-4 md:border-transparent md:hover:border-b-[var(--color-primary)] md:px-4"
style="color: var(--color-navbar-text);"
x-on:click.prevent="open = !open">
<img src="{{ asset('assets/images/icons/navigation/goody.png') }}" alt="goodies" />
<span>{{ __('Goodies') }}</span>
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" viewBox="0 0 20 20" fill="currentColor" style="color: var(--color-text-muted);"><path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/></svg>
</a>
<div x-show="open" x-cloak x-transition.duration.200ms
class="w-full md:absolute md:top-full md:left-0 md:z-50 md:min-w-[220px] md:py-2 md:mt-1 rounded-xl"
style="background-color: var(--color-dropdown); color: var(--color-text); border: 1px solid color-mix(in srgb, var(--color-primary) 30%, transparent); box-shadow: 0 4px 24px rgba(0,0,0,0.25);">
<a href="{{ route('shop.index') }}" class="block py-4 px-8 font-semibold text-base transition hover:opacity-80 rounded-xl" style="color: var(--color-text);">{{ __('Marketplace') }}</a>
</div>
</div>
<div x-data class="w-full py-1 md:py-0 md:w-auto md:relative">
<a href="{{ route('leaderboard.index') }}" class="flex gap-2 px-1 h-auto md:h-[60px] items-center text-[14px] font-semibold uppercase transition duration-200 ease-in-out md:border-b-4 md:border-transparent md:hover:border-b-[var(--color-primary)] md:px-4"
style="color: var(--color-navbar-text);">
<img src="{{ asset('assets/images/icons/navigation/leaderboards.png') }}" alt="leaderboards" />
<span>{{ __('Leaderboards') }}</span>
</a>
</div>
<div x-data class="w-full py-1 md:py-0 md:w-auto md:relative">
<a href="{{ route('shop.index') }}" class="flex gap-2 px-1 h-auto md:h-[60px] items-center text-[14px] font-semibold uppercase transition duration-200 ease-in-out md:border-b-4 md:border-transparent md:hover:border-b-[var(--color-primary)] md:px-4"
style="color: var(--color-navbar-text);">
<img src="{{ asset('assets/images/icons/navigation/shop.png') }}" alt="store" />
<span>{{ __('Store') }}</span>
</a>
</div>
<div x-data="{ open: false }" class="w-full py-1 md:py-0 md:w-auto md:relative" x-on:click.outside="open = false">
<a href="#" class="flex gap-2 px-1 h-auto md:h-[60px] items-center text-[14px] font-semibold uppercase transition duration-200 ease-in-out md:border-b-4 md:border-transparent md:hover:border-b-[var(--color-primary)] md:px-4"
style="color: var(--color-navbar-text);"
x-on:click.prevent="open = !open">
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" /></svg>
<span>{{ __('Radio') }}</span>
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" viewBox="0 0 20 20" fill="currentColor" style="color: var(--color-text-muted);"><path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/></svg>
</a>
<div x-show="open" x-cloak x-transition.duration.200ms
class="w-full md:absolute md:top-full md:left-0 md:z-50 md:min-w-[220px] md:py-2 md:mt-1 rounded-xl"
style="background-color: var(--color-dropdown); color: var(--color-text); border: 1px solid color-mix(in srgb, var(--color-primary) 30%, transparent); box-shadow: 0 4px 24px rgba(0,0,0,0.25);">
<a href="{{ route('radio.index') }}" class="block py-4 px-8 font-semibold text-base transition hover:opacity-80 rounded-xl" style="color: var(--color-text);">{{ __('Listen') }}</a>
<a href="{{ route('radio.rooster') }}" class="block py-4 px-8 font-semibold text-base transition hover:opacity-80 rounded-xl" style="color: var(--color-text);">{{ __('Schedule') }}</a>
<a href="{{ route('radio.leaderboard') }}" class="block py-4 px-8 font-semibold text-base transition hover:opacity-80 rounded-xl" style="color: var(--color-text);">{{ __('Points') }}</a>
<a href="{{ route('radio.shouts') }}" class="block py-4 px-8 font-semibold text-base transition hover:opacity-80 rounded-xl" style="color: var(--color-text);">{{ __('Shouts') }}</a>
</div>
</div>
</div>
@@ -1,5 +1,30 @@
<button id="theme-switcher"
type="button"
class="mr-3 cursor-pointer items-center justify-center rounded-lg bg-gray-200 p-1 shadow-inner dark:bg-gray-800 hidden md:flex">
<x-icons.moon class="h-5 w-5 text-gray-600 dark:text-white" />
<button
x-data="{
toggle() {
const currentTheme = localStorage.getItem('theme') || 'light';
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
localStorage.setItem('theme', newTheme);
document.cookie = 'theme=' + newTheme + ';path=/;max-age=31536000;SameSite=Lax';
if (newTheme === 'dark') {
document.documentElement.classList.add('dark');
document.body.classList.add('dark', 'dark-mode');
document.documentElement.style.cssText = 'background-color: #1a1d29 !important; color-scheme: dark;';
} else {
document.documentElement.classList.remove('dark');
document.body.classList.remove('dark', 'dark-mode');
document.documentElement.style.cssText = 'color-scheme: light;';
}
}
}"
@click="toggle()"
class="relative flex items-center justify-center text-gray-700 dark:text-white bg-white dark:bg-gray-900 rounded-full shadow-sm border border-gray-200 dark:border-gray-700 active:scale-95 transition-transform"
style="width: 40px; height: 40px; min-width: 40px;"
aria-label="Toggle theme">
<svg class="w-5 h-5 hidden dark:block" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
</svg>
<svg class="w-5 h-5 block dark:hidden" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
</svg>
</button>
@@ -3,32 +3,33 @@
<div class="grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-4 xl:grid-cols-5">
@forelse ($photos as $photo)
<a href="{{ $photo->url }}" data-fancybox="gallery" class="group cursor-pointer block">
<div class="relative rounded-lg overflow-hidden shadow-md border border-gray-600 hover:border-[#eeb425] transition-all duration-300">
<div class="aspect-[4/3] relative overflow-hidden">
<img class="h-full w-full object-cover object-center transition-transform duration-300 group-hover:scale-110"
src="{{ $photo->url }}"
alt="Photo by {{ $photo->user?->username ?? 'Unknown' }}">
<div class="absolute inset-0 bg-gradient-to-t from-black/70 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
</div>
<div class="absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/90 to-transparent">
<div class="flex items-center gap-2">
<div class="flex h-7 w-7 items-center justify-center overflow-hidden rounded-full bg-gray-700 border border-gray-500">
<img src="{{ setting('avatar_imager') }}{{ $photo->user?->look ?? '' }}&direction=2&headonly=1&head_direction=2&gesture=sml"
alt="{{ $photo->user?->username ?? 'Unknown' }}"
class="h-full w-full object-cover">
</div>
<div class="flex-1 min-w-0">
<p class="text-white text-sm font-semibold truncate ">{{ $photo->user?->username ?? __('Unknown') }}</p>
</div>
</div>
</div>
<div class="relative rounded-lg overflow-hidden shadow-md transition-all duration-300 group-hover:shadow-lg"
style="border: 1px solid color-mix(in srgb, var(--color-text-muted) 20%, transparent);">
<div class="aspect-[4/3] relative overflow-hidden">
<img class="h-full w-full object-cover object-center transition-transform duration-300 group-hover:scale-110"
src="{{ $photo->url }}"
alt="Photo by {{ $photo->user?->username ?? 'Unknown' }}">
<div class="absolute inset-0 bg-gradient-to-t from-black/70 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
</div>
<div class="absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/90 to-transparent">
<div class="flex items-center gap-2">
<div class="flex h-7 w-7 items-center justify-center overflow-hidden rounded-full" style="border: 1px solid color-mix(in srgb, var(--color-text-muted) 30%, transparent); background-color: color-mix(in srgb, var(--color-surface) 50%, transparent);">
<img src="{{ setting('avatar_imager') }}{{ $photo->user?->look ?? '' }}&direction=2&headonly=1&head_direction=2&gesture=sml"
alt="{{ $photo->user?->username ?? 'Unknown' }}"
class="h-full w-full object-cover">
</div>
<div class="flex-1 min-w-0">
<p class="text-white text-sm font-semibold truncate">{{ $photo->user?->username ?? __('Unknown') }}</p>
</div>
</div>
</div>
</div>
</a>
@empty
<div class="col-span-full text-center py-8">
<p class="text-gray-500 dark:text-gray-400">No photos available</p>
<p style="color: var(--color-text-muted);">{{ __('No photos available') }}</p>
</div>
@endforelse
</div>
@@ -90,9 +90,9 @@
@if($article->is_giftable)
<x-modals.modal-wrapper>
<div x-on:click="open = true">
<x-form.primary-button type="button" classes="px-10">
<x-icons.gift />
</x-form.primary-button>
<button type="button" class="rounded-lg px-4 py-2 text-sm font-semibold transition-all duration-200 hover:opacity-90 px-10" style="background-color: var(--color-primary); color: var(--button-text-color);">
<x-icons.gift />
</button>
</div>
<x-modals.regular-modal>
@@ -106,7 +106,7 @@
<form action="{{ route('shop.buy', $article) }}" method="POST" class="w-full">
@csrf
<x-form.input name="receiver" type="text" placeholder="Enter the name of the recipient you want to gift" classes="mb-2"/>
<input type="text" name="receiver" placeholder="Enter the name of the recipient you want to gift" class="w-full rounded-lg px-3 py-2 text-sm border-2 focus:ring-0 mb-2" style="background-color: var(--color-background); color: var(--color-text); border-color: color-mix(in srgb, var(--color-text-muted) 15%, transparent);" />
<button type="submit"
class="w-full rounded bg-green-600 hover:bg-green-700 text-white p-2 border-2 border-green-500 transition ease-in-out duration-150 font-semibold">
@@ -1,5 +1,5 @@
<div class="relative flex min-h-[13rem] h-52 w-full items-center justify-center header-bg"
style="background: url({{ setting('cms_header') }});">
<div class="relative flex min-h-[13rem] h-52 w-full items-center justify-center"
style="background-image: url({{ asset('assets/images/mybobba_banner.png') }}); background-size: cover; background-position: center; background-repeat: no-repeat;">
<div class="absolute h-full w-full bg-black/50"></div>
@auth
@@ -51,37 +51,27 @@
@endauth
@guest
<x-modals.modal-wrapper>
<div class="flex justify-center">
<div class="font-semibold flex-col md:w-[600px]" style="color: #ffffff; text-shadow: 0 1px 4px rgba(0,0,0,0.7);">
<p class="hidden text-center text-xl md:block" style="color: #ffffff; text-shadow: 0 1px 4px rgba(0,0,0,0.7);">
{{ __('An online virtual world where you can create your own avatar, make friends, chat, create rooms and much more!') }}
</p>
<div x-data="{ open: false }" class="relative">
<div class="flex flex-col items-center justify-center md:w-[600px] mx-auto">
<a href="{{ route('welcome') }}" class="transition-all duration-300 hover:scale-110 mb-2.5">
<img src="{{ setting('cms_logo') }}" alt="{{ setting('hotel_name') }}" class="drop-shadow block" />
</a>
<div class="flex flex-col items-center justify-center gap-x-6 gap-y-4 md:mt-6 md:flex-row md:gap-y-0">
<button type="button" x-on:click="open = true"
class="rounded-full border-2 px-8! py-2! uppercase transition! duration-200! ease-in-out!"
style="border-color: var(--color-primary); background-color: var(--color-primary); color: var(--button-text-color)">
{{ __('Login') }}
</button>
<div class="relative flex items-center rounded-md h-[50px] px-4 mt-2 md:mt-0"
style="margin-top: 5px; cursor: pointer; background-color: var(--color-surface, #ffffff); color: var(--color-text, #1f2937);" x-on:click="open = true">
<div class="absolute w-6 h-6 z-0 diamond" aria-hidden="true" style="background-color: var(--color-surface, #ffffff);"></div>
<div class="flex items-center space-x-2 relative z-10">
<img src="{{ asset('assets/images/user-online.png') }}" alt="Online Icon" class="p-1"
style="margin-top: -2px;" />
<span class="whitespace-nowrap text-m text-gray-800 dark:text-white">{{ cache()->remember('online_user_count', 30, fn() => DB::table('users')->where('online', '1')->count()) }} {{ __('users online') }}</span>
</div>
</div>
</div>
<p class="text-sm uppercase" style="color: #ffffff; text-shadow: 0 1px 4px rgba(0,0,0,0.7);">{{ __('Or') }}</p>
<x-modals.regular-modal x-model="show {{ session()->get('wrong-auth') }}">
<x-auth.login-form />
</x-modals.regular-modal>
</div>
<a data-turbolinks="false" href="{{ route('register') }}">
<button
class="uppercase px-8! py-2.5! rounded-full transition! ease-in-out! duration-200!"
style="background-color: var(--color-accent); color: var(--button-text-color, #ffffff);">
{{ __('Create an account') }}
</button>
</a>
</div>
</div>
</div>
<x-modals.regular-modal x-model="show {{ session()->get('wrong-auth') }}">
<x-auth.login-form />
</x-modals.regular-modal>
</x-modals.modal-wrapper>
@endguest
@endguest
</div>
@@ -1,21 +1,20 @@
<x-content.content-card icon="discord-icon" classes="border dark:border-gray-900">
<x-slot:title>
{{ __('Discord') }}
</x-slot:title>
<x-slot:under-title>
<span id="guildName"></span>
</x-slot:under-title>
<div class="text-sm dark:text-gray-200">
<div id="guildUsers" class="h-[129px] overflow-auto"> </div>
<a id="guildInvite" target="blank">
<x-form.secondary-button classes="mt-3">
{{ __('Join server') }}
</x-form.secondary-button>
</a>
<div class="rounded-lg overflow-hidden" style="background-color: var(--color-surface); border: 1px solid color-mix(in srgb, var(--color-text-muted) 15%, transparent);">
<div class="relative w-full h-12" style="background: linear-gradient(140deg, var(--color-primary) 0%, color-mix(in srgb, var(--color-primary) 80%, black) 100%);">
<div class="flex items-center h-full px-4">
<h2 class="text-white font-bold text-lg">{{ __('Discord') }}</h2>
</div>
</div>
</x-content.content-card>
<div class="p-4">
<p class="text-sm mb-3" style="color: var(--color-text-muted);"><span id="guildName"></span></p>
<div id="guildUsers" class="h-[129px] overflow-auto text-sm" style="color: var(--color-text);"> </div>
<a id="guildInvite" target="blank">
<button class="mt-3 w-full rounded-lg px-4 py-2 text-sm font-semibold transition-all duration-200 hover:opacity-90"
style="background-color: var(--color-primary); color: var(--button-text-color);">
{{ __('Join server') }}
</button>
</a>
</div>
</div>
@push('javascript')
<script>
@@ -27,10 +26,8 @@
mode: 'cors',
cache: 'reload'
}
//gets discord widget json from url with in settings specifed id
fetch("https://discordapp.com/api/guilds/{{ setting('discord_widget_id') }}/widget.json", init).then(
function(res) {
//if there is a problem with discord or id sends an error message in console
if (res.status != 200) {
console.error("Discord widget cant connect to discord (" + res.status + ")");
return;
@@ -39,10 +36,8 @@
res.json().then(function(data) {
let users = data.members;
let guildName = data.name;
//sets the subtitle of the card to the guild name
document.getElementById('guildName').innerText = guildName;
//loops over every user in json array and display them in the widget
for (let i = 0; i < data.members.length; i++) {
let container = document.createElement('div')
let leftContainer = document.createElement('div')
@@ -53,7 +48,6 @@
let name = document.createElement('p')
let motto = document.createElement('p')
//sets styleing
container.classList.add('flex', 'items-center', 'gap-x-2')
leftContainer.classList.add('relative')
imgContainer.classList.add('h-9', 'w-9', 'bg-gray-100', 'dark:bg-gray-800',
@@ -63,7 +57,6 @@
name.classList.add('font-semibold')
motto.classList.add('dark:text-gray-400')
//sets styling for exceptions
if (i === 0) {
name.classList.add('mt-1')
}
@@ -81,7 +74,6 @@
status.style.backgroundColor = "#9c0017";
}
//adds attributes to elements
img.setAttribute('src', data.members[i].avatar_url);
if (users[i].nick === undefined) {
@@ -93,7 +85,6 @@
motto.innerText = users[i].game.name;
}
//append all elements to each other
container.appendChild(leftContainer)
leftContainer.appendChild(imgContainer)
imgContainer.appendChild(img)
@@ -105,13 +96,10 @@
document.getElementById('guildUsers').appendChild(container)
}
//Checks if join server link is null and removes btn form webpage
if (data.instant_invite === null) {
document.getElementById('guildInvite').remove()
document.getElementById('guildUsers').style.height = "176px"
} else {
//Gives the "Join server" button a href to the default selected channel in the server
//link is recived from widget json
document.getElementById('guildInvite').setAttribute('href', data.instant_invite)
}
})
@@ -1,15 +1,15 @@
@props(['colSpan'])
<div class="col-span-2 lg:col-span-{{ $colSpan }}">
{{ $image }}
{{ $image }}
<div class="shadow">
<div class="flex gap-x-2 rounded-t border-b p-3" style="background-color: var(--color-surface); border-color: var(--color-text-muted);">
<p class="font-semibold" style="color: var(--color-text)">{{ $title }}</p>
</div>
<div class="rounded-lg overflow-hidden" style="background-color: var(--color-surface); border: 1px solid color-mix(in srgb, var(--color-text-muted) 15%, transparent);">
<div class="flex gap-x-2 border-b p-3" style="background-color: var(--color-surface); border-color: color-mix(in srgb, var(--color-text-muted) 15%, transparent);">
<p class="font-semibold" style="color: var(--color-text)">{{ $title }}</p>
</div>
<section class="rounded-b p-3" style="background-color: var(--color-surface); color: var(--color-text);">
{{ $slot }}
</section>
</div>
<section class="p-3" style="color: var(--color-text);">
{{ $slot }}
</section>
</div>
</div>