mirror of
https://github.com/filamentphp/filament.git
synced 2026-08-29 03:09:12 +08:00
Support dynamic navigation visibility (#19701)
* support dynamic navigation visibility * clean up and test and docs * simplify --------- Co-authored-by: Dan Harrin <git@danharrin.com>
This commit is contained in:
@@ -552,6 +552,19 @@ public function panel(Panel $panel): Panel
|
||||
|
||||
<AutoScreenshot name="panels/navigation/disabled-navigation" alt="Disabled navigation sidebar" version="4.x" />
|
||||
|
||||
Alternatively, you may pass a closure that returns a boolean to decide dynamically. Returning `false` hides the navigation, while returning `true` renders the default auto-discovered navigation items. This is useful for flows such as onboarding or setup wizards where the navigation should only appear once the user has reached a particular state:
|
||||
|
||||
```php
|
||||
use Filament\Panel;
|
||||
|
||||
public function panel(Panel $panel): Panel
|
||||
{
|
||||
return $panel
|
||||
// ...
|
||||
->navigation(fn (): bool => auth()->user()->hasCompletedOnboarding());
|
||||
}
|
||||
```
|
||||
|
||||
### Disabling the topbar
|
||||
|
||||
You may disable topbar entirely by passing `false` to the `topbar()` method:
|
||||
|
||||
@@ -38,10 +38,9 @@ trait HasNavigation
|
||||
*/
|
||||
public function buildNavigation(): array
|
||||
{
|
||||
/** @var NavigationBuilder $builder */
|
||||
$builder = app()->call($this->navigationBuilder);
|
||||
$resolved = $this->resolveNavigationBuilder();
|
||||
|
||||
return $builder->getNavigation();
|
||||
return $resolved instanceof NavigationBuilder ? $resolved->getNavigation() : [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,12 +97,27 @@ trait HasNavigation
|
||||
|
||||
public function hasNavigation(): bool
|
||||
{
|
||||
return $this->navigationBuilder !== false;
|
||||
return $this->resolveNavigationBuilder() !== false;
|
||||
}
|
||||
|
||||
public function hasNavigationBuilder(): bool
|
||||
{
|
||||
return $this->navigationBuilder instanceof Closure;
|
||||
return $this->resolveNavigationBuilder() instanceof NavigationBuilder;
|
||||
}
|
||||
|
||||
protected function resolveNavigationBuilder(): NavigationBuilder | bool
|
||||
{
|
||||
if (! $this->navigationBuilder instanceof Closure) {
|
||||
return $this->navigationBuilder;
|
||||
}
|
||||
|
||||
$result = app()->call($this->navigationBuilder);
|
||||
|
||||
if ($result instanceof NavigationBuilder) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return (bool) $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -106,3 +106,32 @@ it('can register navigation groups individually', function (): void {
|
||||
->each->toBeInstanceOf(NavigationItem::class),
|
||||
);
|
||||
});
|
||||
|
||||
it('hides navigation when a closure returns `false`', function (): void {
|
||||
Filament::getCurrentOrDefaultPanel()->navigation(fn (): bool => false);
|
||||
|
||||
expect(Filament::hasNavigation())->toBeFalse();
|
||||
});
|
||||
|
||||
it('shows auto-discovered navigation items when a closure returns `true`', function (): void {
|
||||
Filament::getCurrentOrDefaultPanel()->navigation(fn (): bool => true);
|
||||
|
||||
expect(Filament::hasNavigation())->toBeTrue()
|
||||
->and(Filament::getCurrentOrDefaultPanel()->hasNavigationBuilder())->toBeFalse();
|
||||
|
||||
$itemLabels = collect(Filament::getNavigation())
|
||||
->flatMap(fn (NavigationGroup $group) => $group->getItems())
|
||||
->map(fn (NavigationItem $item) => $item->getLabel());
|
||||
|
||||
expect($itemLabels)
|
||||
->toContain('Dashboard')
|
||||
->toContain('Users')
|
||||
->toContain('Posts');
|
||||
});
|
||||
|
||||
it('hides navigation when `navigation(false)` is set', function (): void {
|
||||
Filament::getCurrentOrDefaultPanel()->navigation(false);
|
||||
|
||||
expect(Filament::hasNavigation())->toBeFalse();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user