feat: add customizable Nitro client loading overlay with Filament settings

Add full Client Login Effect section to Theme & Buttons page with:
- Enable toggle, 30+ animation effects, customizable colors/logo/text
- 6 loading bar styles (sliding, dots, pulse, double, spinner, skeleton)
- Optimized to single DB query via WebsiteSetting::whereIn
- Overlay covers Nitro v3 internal loading (5s min, 15s fallback)
This commit is contained in:
root
2026-05-22 21:09:33 +02:00
parent c53d1bca45
commit 76bce1d092
5 changed files with 875 additions and 31 deletions
@@ -185,6 +185,19 @@ final class ThemeSettings extends Page implements HasForms
// Page transition
'page_transition' => $this->getSettingBool('page_transition', true),
// Login Effect settings
'login_effect_enabled' => $this->getSettingBool('login_effect_enabled', false),
'login_effect_animation' => $this->getSetting('login_effect_animation', 'none'),
'login_effect_background' => $this->getSetting('login_effect_background', '#0f1922'),
'login_effect_icon_color' => $this->getSetting('login_effect_icon_color', '#eeb425'),
'login_effect_text_color' => $this->getSetting('login_effect_text_color', '#ffffff'),
'login_effect_bar_color' => $this->getSetting('login_effect_bar_color', '#eeb425'),
'login_effect_bar_style' => $this->getSetting('login_effect_bar_style', 'bar'),
'login_effect_show_logo' => $this->getSettingBool('login_effect_show_logo', true),
'login_effect_show_name' => $this->getSettingBool('login_effect_show_name', true),
'login_effect_icon_size' => $this->getSetting('login_effect_icon_size', '120'),
'login_effect_custom_text' => $this->getSetting('login_effect_custom_text', ''),
// Header/Footer colors
'header_background' => $this->getSetting('header_background', '#2d2d44'),
'header_text_color' => $this->getSetting('header_text_color', '#ffffff'),
@@ -1995,6 +2008,100 @@ final class ThemeSettings extends Page implements HasForms
])
->columns(2),
// LOGIN EFFECT
Section::make(__('Client Login Effect'))
->description(__('Fully customize the loading screen shown before the Nitro client loads'))
->icon('heroicon-o-sparkles')
->schema([
Toggle::make('login_effect_enabled')
->label(__('Enable client login effect'))
->default(false)
->helperText(__('Show a loading screen on the Nitro client page')),
Select::make('login_effect_animation')
->label(__('Animation effect'))
->options([
'none' => __('None'),
'sparkle' => '✨ ' . __('Sparkle'),
'glow' => '💡 ' . __('Glow'),
'float' => '🎈 ' . __('Float'),
'bounce' => '⚡ ' . __('Bounce'),
'pulse' => '💓 ' . __('Pulse'),
'shine' => '✨ ' . __('Shine'),
'shake' => '📳 ' . __('Shake'),
'wobble' => '🌀 ' . __('Wobble'),
'heartbeat' => '❤️ ' . __('Heartbeat'),
'rubber-band' => '🎯 ' . __('Rubber Band'),
'flip' => '🔄 ' . __('Flip'),
'swing' => '🎪 ' . __('Swing'),
'jello' => '🍮 Jello',
'color-cycle' => '🌈 ' . __('Color Cycle'),
'rotate' => '🔄 ' . __('Rotate'),
'scale-pulse' => '💫 ' . __('Scale Pulse'),
'fade-in' => '👻 ' . __('Fade In'),
'fade-out' => '🌫️ ' . __('Fade Out'),
'slide-up' => '⬆️ ' . __('Slide Up'),
'slide-down' => '⬇️ ' . __('Slide Down'),
'slide-left' => '⬅️ ' . __('Slide Left'),
'slide-right' => '➡️ ' . __('Slide Right'),
'zoom-in' => '🔍 ' . __('Zoom In'),
'zoom-out' => '🔎 ' . __('Zoom Out'),
'neon-pulse' => '💡 ' . __('Neon Pulse'),
'rainbow' => '🌈 ' . __('Rainbow'),
'wave' => '〰️ ' . __('Wave'),
'ripple' => '💧 ' . __('Ripple'),
'fire' => '🔥 ' . __('Fire'),
'ice' => '🧊 ' . __('Ice'),
'glitch' => '👾 ' . __('Glitch'),
'pop' => '🎉 ' . __('Pop'),
])
->default('none')
->helperText(__('Animation for the icon during loading')),
ColorPicker::make('login_effect_background')
->label(__('Background color'))
->default('#0f1922'),
ColorPicker::make('login_effect_icon_color')
->label(__('Icon background color'))
->default('#eeb425'),
ColorPicker::make('login_effect_text_color')
->label(__('Text color'))
->default('#ffffff'),
ColorPicker::make('login_effect_bar_color')
->label(__('Loading bar color'))
->default('#eeb425'),
Select::make('login_effect_bar_style')
->label(__('Loading bar style'))
->options([
'bar' => '━ ' . __('Sliding bar'),
'dots' => '● ' . __('Bouncing dots'),
'pulse' => '◉ ' . __('Pulsing circle'),
'double' => '═ ' . __('Double bar'),
'spinner' => '◌ ' . __('Spinning circle'),
'skeleton' => '▯ ' . __('Skeleton glow'),
])
->default('bar')
->helperText(__('Style of the loading indicator')),
TextInput::make('login_effect_icon_size')
->label(__('Icon size (px)'))
->numeric()
->minValue(60)
->maxValue(300)
->default(120)
->helperText(__('Diameter of the icon circle in pixels')),
Toggle::make('login_effect_show_logo')
->label(__('Show logo'))
->default(true)
->helperText(__('Show the generated logo from the logo generator')),
Toggle::make('login_effect_show_name')
->label(__('Show hotel name'))
->default(true)
->helperText(__('Show the hotel name below the icon')),
TextInput::make('login_effect_custom_text')
->label(__('Custom subtitle text'))
->placeholder(__('Leave empty to use default'))
->helperText(__('Optional text shown below the hotel name')),
])
->columns(2),
// v1.3 PWA (PROGRESSIVE WEB APP)
Section::make(__('PWA - Progressive Web App'))
->description(__('Make your hotel installable as an app'))
@@ -2048,6 +2155,9 @@ final class ThemeSettings extends Page implements HasForms
'nav_icon_radio',
'avatar_border',
'page_transition',
'login_effect_enabled',
'login_effect_show_logo',
'login_effect_show_name',
]);
$this->saveSettings([
'preset',
@@ -2170,6 +2280,14 @@ final class ThemeSettings extends Page implements HasForms
'pwa_description',
'pwa_theme_color',
'pwa_background_color',
'login_effect_animation',
'login_effect_background',
'login_effect_icon_color',
'login_effect_text_color',
'login_effect_bar_color',
'login_effect_icon_size',
'login_effect_bar_style',
'login_effect_custom_text',
]);
SettingsService::clearCache();
@@ -3,6 +3,7 @@
namespace App\Http\Controllers\Client;
use App\Http\Controllers\Controller;
use App\Models\Miscellaneous\WebsiteSetting;
use Illuminate\View\View;
class NitroController extends Controller
@@ -23,8 +24,34 @@ class NitroController extends Controller
$sso = $user->ssoTicket();
$keys = [
'login_effect_enabled', 'login_effect_animation', 'login_effect_background',
'login_effect_icon_color', 'login_effect_text_color', 'login_effect_bar_color',
'login_effect_bar_style', 'login_effect_icon_size', 'login_effect_show_logo',
'login_effect_show_name', 'login_effect_custom_text',
];
$settings = WebsiteSetting::whereIn('key', $keys)->pluck('value', 'key');
$loginData = null;
if (($settings['login_effect_enabled'] ?? '0') === '1') {
$loginData = [
'animation' => $settings['login_effect_animation'] ?? 'none',
'background' => $settings['login_effect_background'] ?? '#0f1922',
'icon_color' => $settings['login_effect_icon_color'] ?? '#eeb425',
'text_color' => $settings['login_effect_text_color'] ?? '#ffffff',
'bar_color' => $settings['login_effect_bar_color'] ?? '#eeb425',
'bar_style' => $settings['login_effect_bar_style'] ?? 'bar',
'icon_size' => $settings['login_effect_icon_size'] ?? '120',
'show_logo' => ($settings['login_effect_show_logo'] ?? '0') === '1',
'show_name' => ($settings['login_effect_show_name'] ?? '0') === '1',
'custom_text' => $settings['login_effect_custom_text'] ?? '',
];
}
return view('client.' . $view, [
'sso' => $sso,
'loginData' => $loginData,
]);
}
}