Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion config/frontend-panel.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
<?php

return [
//
/*
|--------------------------------------------------------------------------
| Enable/disable guest access
|--------------------------------------------------------------------------
|
| This option controls whether guests can access the frontend panel
| without authentication. When enabled, users can view the panel
| without needing to log in.
|
*/
'guest_access' => (bool) env('FRONTEND_GUEST_ACCESS', true),
];
25 changes: 25 additions & 0 deletions resources/views/filament/components/theme-switcher.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@php
$panel = filament()->getCurrentPanel();
$panelID = $panel ? $panel->getId() : 'null';
@endphp

<div x-data="{ theme: null }" x-init="
['setItem', 'getItem'].forEach(method => {
localStorage[method] = new Proxy(localStorage[method], {
apply(target, thisArg, args) {
if (args[0] === 'theme') args[0] = 'theme_{{ $panelID }}';
return target.apply(thisArg, args);
}
});
});

$watch('theme', () => {
$dispatch('theme-changed', theme)
});

theme = localStorage.getItem('theme') || @js(filament()->getDefaultThemeMode()->value)
" class="fi-theme-switcher grid grid-flow-col gap-x-1">
<x-filament-panels::theme-switcher.button icon="heroicon-m-sun" theme="light" />
<x-filament-panels::theme-switcher.button icon="heroicon-m-moon" theme="dark" />
<x-filament-panels::theme-switcher.button icon="heroicon-m-computer-desktop" theme="system" />
</div>
3 changes: 3 additions & 0 deletions resources/views/filament/pages/home.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<x-filament-panels::page>

</x-filament-panels::page>
24 changes: 24 additions & 0 deletions src/Filament/Pages/Home.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Eclipse\Frontend\Filament\Pages;

use Filament\Pages\Page;

class Home extends Page
{
protected static ?int $navigationSort = -1;

protected static ?string $navigationIcon = '';

protected static string $view = 'frontend-panel::filament.pages.home';

public function getHeading(): string
{
return '';
}

public static function getSlug(): string
{
return '/';
}
}
3 changes: 2 additions & 1 deletion src/FrontendServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public function configurePackage(SpatiePackage|Package $package): void
{
$package->name(static::$name)
->hasConfigFile()
->hasTranslations();
->hasTranslations()
->hasViews();
}

public function register(): self
Expand Down
110 changes: 80 additions & 30 deletions src/Providers/FrontendPanelProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Eclipse\Common\Providers\GlobalSearchProvider;
use Eclipse\Core\Models\Site;
use Eclipse\Core\Services\Registry;
use Eclipse\Frontend\Filament\Pages as CustomPages;
use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\AuthenticateSession;
use Filament\Http\Middleware\DisableBladeIconComponents;
Expand All @@ -15,6 +16,7 @@
use Filament\Support\Colors\Color;
use Filament\Support\Enums\Platform;
use Filament\Support\Facades\FilamentView;
use Filament\View\PanelsRenderHook;
use Filament\Widgets;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Cookie\Middleware\EncryptCookies;
Expand All @@ -27,63 +29,111 @@

class FrontendPanelProvider extends PanelProvider
{
private const PANEL_ID = 'frontend';

public function panel(Panel $panel): Panel
{
return $panel
->id('frontend')
$panel = $panel
->id(self::PANEL_ID)
->path('')
->login()
->passwordReset()
->emailVerification()
->colors([
'primary' => Color::Cyan,
'gray' => Color::Slate,
])
->authGuard(self::PANEL_ID)
->topNavigation()
->brandName(fn () => Registry::getSite()->name)
->discoverResources(in: app_path('Filament/Frontend/Resources'), for: 'App\\Filament\\Frontend\\Resources')
->discoverPages(in: app_path('Filament/Frontend/Pages'), for: 'App\\Filament\\Frontend\\Pages')
->pages([
Pages\Dashboard::class,
])
->discoverWidgets(in: app_path('Filament/Frontend/Widgets'), for: 'App\\Filament\\Frontend\\Widgets')
->widgets([
Widgets\AccountWidget::class,
Widgets\FilamentInfoWidget::class,
])
->middleware([
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
])
->authMiddleware([
Authenticate::class,
])
->globalSearch(GlobalSearchProvider::class)
->globalSearchKeyBindings(['ctrl+k', 'command+k'])
->globalSearchFieldSuffix(fn (): ?string => match (Platform::detect()) {
Platform::Windows, Platform::Linux => 'CTRL+K',
Platform::Mac => '⌘K',
default => null,
})
->tenant(Site::class, slugAttribute: 'domain')
->tenantDomain('{tenant:domain}')
->tenantMenu(false)
->plugins([
EnvironmentIndicatorPlugin::make(),
]);

$middleware = [
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
];

$middleware = match (self::isGuestPanel()) {
true => $middleware,
false => array_merge($middleware, [
AuthenticateSession::class,
])
};

match (self::isGuestPanel()) {
true => $panel
->pages([
CustomPages\Home::class,
])
->widgets([])
->middleware($middleware)
->renderHook(
PanelsRenderHook::TOPBAR_END,
fn () => view('frontend-panel::filament.components.theme-switcher')
),
false => $panel->login()
->passwordReset()
->emailVerification()
->pages([
Pages\Dashboard::class,
])
->widgets([
Widgets\AccountWidget::class,
Widgets\FilamentInfoWidget::class,
])
->middleware($middleware)
->authMiddleware([
Authenticate::class,
])
->tenant(Site::class, slugAttribute: 'domain')
->tenantDomain('{tenant:domain}')
->tenantMenu(false)
->renderHook(
PanelsRenderHook::HEAD_START,
fn (): string => self::getThemeIsolationScript(self::PANEL_ID)
)
};

return $panel;
}

public function register(): void
{
parent::register();

FilamentView::registerRenderHook('panels::body.end', fn (): string => Blade::render("@vite('resources/js/app.js')"));
}

private static function getThemeIsolationScript(string $panelId): string
{
return "<script>
['setItem', 'getItem'].forEach(method => {
localStorage[method] = new Proxy(localStorage[method], {
apply(target, thisArg, args) {
if (args[0] === 'theme') args[0] = 'theme_{$panelId}';
return target.apply(thisArg, args);
}
});
});
</script>";
}

private static function isGuestPanel(): bool
{
return config('frontend-panel.guest_access');
}
}
Loading