Skip to content

Commit

Permalink
added sorting and updated readme
Browse files Browse the repository at this point in the history
  • Loading branch information
bezhanSalleh committed Oct 10, 2024
2 parents 4ddd2c5 + 0032cd2 commit 2e3b281
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 56 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
insert_final_newline = false
trim_trailing_whitespace = true

[*.md]
Expand Down
1 change: 1 addition & 0 deletions .phpunit.cache/test-results
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":"pest_2.35.1","defects":[],"times":{"P\\Tests\\ArchTest::__pest_evaluable_it_will_not_use_debugging_functions":0.051,"P\\Tests\\ExampleTest::__pest_evaluable_it_can_test":0.001}}
32 changes: 26 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@
<a href="#who-can-switch-panels">Who Can Switch Panels?</a>
</li>
<li>
<a href="#panel-exclusion">Panel Exclusion</a>
<a href="#panels">Panel [New 1.1.0]</a>
</li>
<a href="#sort-order">Sort Order [New 1.1.0]</a>
</li>
<li>
<a href="#placement">Placement</a>
Expand Down Expand Up @@ -237,16 +239,33 @@ PanelSwitch::configureUsing(function (PanelSwitch $panelSwitch) {
});
```

### Panel Exclusion
By default all the panels available will be listed in the panel switch menu. But you can exclude some of them by using the `excludes()` method.
### Panels `New(1.1.0)`
By default all the panels available will be listed in the panel switch menu. But by providing an array of panel ids to the `panels()` method you can limit the panels that will be listed.

```php
PanelSwitch::configureUsing(function (PanelSwitch $panelSwitch) {
$panelSwitch->excludes([
'saas'
$panelSwitch->panels([
'admin',
'dev',
'app'
]);
});
```
Then `panels()` method also accepts a closure that returns an array of panel ids. This is useful when you want to dynamically determine the panels that will be listed. The plugin will also validate the panels to ensure that they are valid filament panels. If any of the panels provided are invalid, the plugin will throw an `InvalidArgumentException`.

### Sort Order `New(1.1.0)`
By default the panels will be listed in the order they were registered in `config/app.php`'s `providers` array or in the order they are provided through the `panels()` method. But you can opt-in to sort the panels either in `asc` or `desc` order via `sort()` method.
```php
PanelSwitch::configureUsing(function (PanelSwitch $panelSwitch) {
$panelSwitch
...
->panels(['admin', 'dev', 'app']) // default order if `sort()` method not used
->sort() // ['admin', 'app', 'dev']
// ->sort(order: 'desc') // ['dev', 'app', 'admin']
...
;
});
```

### Placement
You can choose where the panel switch menu should be placed. By default panel switch menu is rendered via 'panels::global-search.before' `Hook`. But you can change it to anyone of the other available Filament [Render Hooks](https://filamentphp.com/docs/3.x/support/render-hooks#available-render-hooks).
Expand All @@ -266,6 +285,7 @@ use BezhanSalleh\PanelSwitch\PanelSwitch;

PanelSwitch::configureUsing(function (PanelSwitch $panelSwitch) {
$panelSwitch
->panels(['admin', 'app', 'dev'])
->heading('Available Panels')
->modalWidth('sm')
->slideOver()
Expand Down Expand Up @@ -344,4 +364,4 @@ Please review [our security policy](../../security/policy) on how to report secu

## License

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
3 changes: 1 addition & 2 deletions pint.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
{
"preset": "laravel",
"rules": {
"blank_line_before_statement": true,
"single_blank_line_at_eof": false,
"concat_space": {
"spacing": "one"
},
"method_argument_space": true,
"single_trait_insert_per_statement": true,
"types_spaces": {
"space": "single"
Expand Down
42 changes: 14 additions & 28 deletions resources/views/panel-switch-menu.blade.php
Original file line number Diff line number Diff line change
@@ -1,17 +1,3 @@
@php
$getPanelPath = function (\Filament\Panel $panel): string {
$filament = app('filament');
$currentPanel = $filament->getCurrentPanel();
$filament->setCurrentPanel($panel);
$url = $panel->getUrl();
$filament->setCurrentPanel($currentPanel);
return $url;
};
$getHref = fn(\Filament\Panel $panel): ?string => $canSwitchPanels ? $getPanelPath($panel) : null;
@endphp

@if ($isSimple)
<x-filament::dropdown teleport placement="bottom-end">
<x-slot name="trigger">
Expand All @@ -34,13 +20,13 @@ class="w-5 h-5 text-white ms-auto shrink-0"
</x-slot>

<x-filament::dropdown.list>
@foreach ($panels as $panel)
@foreach ($panels as $id => $url)
<x-filament::dropdown.list.item
:href="$getHref($panel)"
:badge="str($labels[$panel->getId()] ?? $panel->getId())->substr(0, 2)->upper()"
:href="$url"
:badge="str($labels[$id] ?? $id)->substr(0, 2)->upper()"
tag="a"
>
{{ $labels[$panel->getId()] ?? str($panel->getId())->ucfirst() }}
{{ $labels[$id] ?? str($id)->ucfirst() }}
</x-filament::dropdown.list.item>
@endforeach
</x-filament::dropdown.list>
Expand Down Expand Up @@ -77,43 +63,43 @@ class="panel-switch-modal"
<div
class="flex flex-wrap items-center justify-center gap-4 md:gap-6"
>
@foreach ($panels as $panel)
@foreach ($panels as $id => $url)
<a
href="{{ $getHref($panel) }}"
href="{{ $url }}"
class="flex flex-col items-center justify-center flex-1 hover:cursor-pointer group panel-switch-card"
>
<div
@class([
"p-2 bg-white rounded-lg shadow-md dark:bg-gray-800 panel-switch-card-section",
"group-hover:ring-2 group-hover:ring-primary-600" => $panel->getId() !== $currentPanel->getId(),
"ring-2 ring-primary-600" => $panel->getId() === $currentPanel->getId(),
"group-hover:ring-2 group-hover:ring-primary-600" => $id !== $currentPanel->getId(),
"ring-2 ring-primary-600" => $id === $currentPanel->getId(),
])
>
@if ($renderIconAsImage)
<img
class="rounded-lg panel-switch-card-image"
style="width: {{ $iconSize * 4 }}px; height: {{ $iconSize * 4 }}px;"
src="{{ $icons[$panel->getId()] ?? 'https://raw.githubusercontent.com/bezhanSalleh/filament-panel-switch/3.x/art/banner.jpg' }}"
src="{{ $icons[$id] ?? 'https://raw.githubusercontent.com/bezhanSalleh/filament-panel-switch/3.x/art/banner.jpg' }}"
alt="Panel Image"
>
@else
@php
$iconName = $icons[$panel->getId()] ?? 'heroicon-s-square-2-stack' ;
$iconName = $icons[$id] ?? 'heroicon-s-square-2-stack' ;
@endphp
@svg($iconName, 'text-primary-600 panel-switch-card-icon', ['style' => 'width: ' . ($iconSize * 4) . 'px; height: ' . ($iconSize * 4). 'px;'])
@endif
</div>
<span
@class([
"mt-2 text-sm font-medium text-center text-gray-400 dark:text-gray-200 break-words panel-switch-card-title",
"text-gray-400 dark:text-gray-200 group-hover:text-primary-600 group-hover:dark:text-primary-400" => $panel->getId() !== $currentPanel->getId(),
"text-primary-600 dark:text-primary-400" => $panel->getId() === $currentPanel->getId(),
"text-gray-400 dark:text-gray-200 group-hover:text-primary-600 group-hover:dark:text-primary-400" => $id !== $currentPanel->getId(),
"text-primary-600 dark:text-primary-400" => $id === $currentPanel->getId(),
])
>
{{ $labels[$panel->getId()] ?? str($panel->getId())->ucfirst()}}
{{ $labels[$id] ?? str($id)->ucfirst() }}
</span>
</a>
@endforeach
</div>
</x-filament::modal>
@endif
@endif
7 changes: 3 additions & 4 deletions src/Concerns/HasPanelValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@

namespace BezhanSalleh\PanelSwitch\Concerns;

use Closure;
use InvalidArgumentException;
use Filament\Facades\Filament;
use InvalidArgumentException;

trait HasPanelValidator
{
Expand All @@ -18,7 +17,7 @@ public function areUserProvidedPanelsValid(array $panelIds): void
$validated = collect($panelIds)->diff(collect(Filament::getPanels())->keys()->toArray());

if ($validated->isNotEmpty()) {
throw new InvalidArgumentException("Invalid panel IDs: {$validated->implode(', ')}");
throw new InvalidArgumentException("Invalid Filament Panel. Make sure the panel ids passed to the `Panel Switch`, are valid and do exist. [`{$validated->implode(', ')}`]");
}
}
}
}
2 changes: 1 addition & 1 deletion src/Facades/PanelSwitch.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ protected static function getFacadeAccessor()
{
return \BezhanSalleh\PanelSwitch\PanelSwitch::class;
}
}
}
50 changes: 37 additions & 13 deletions src/PanelSwitch.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@
namespace BezhanSalleh\PanelSwitch;

use Closure;
use Filament\Panel;
use Illuminate\Support\Arr;
use Filament\Facades\Filament;
use Filament\Panel;
use Filament\Support\Components\Component;
use Filament\Support\Facades\FilamentView;

use function PHPUnit\Framework\callback;

class PanelSwitch extends Component
{
use Concerns\HasPanelValidator;
Expand Down Expand Up @@ -41,24 +38,30 @@ class PanelSwitch extends Component

protected string $renderHook = 'panels::global-search.before';

protected null | string $sortOrder = null;

public static function make(): static
{
$static = app(static::class);

$static->visible(function () {
$static->visible(function () use ($static) {
if (($user = auth()->user()) === null) {
return false;
}

if (method_exists($user, 'canAccessPanel')) {
return $user->canAccessPanel(filament()->getCurrentPanel() ?? filament()->getDefaultPanel());
return $user->canAccessPanel($static->getCurrentPanel());
}

return true;
});

$static->configure();

if (count($static->getPanels()) < 2) {
$static->visible(false);
}

return $static;
}

Expand All @@ -69,13 +72,13 @@ public static function boot(): void
FilamentView::registerRenderHook(
name: $static->getRenderHook(),
hook: function () use ($static) {

if (! $static->isVisible()) {
return '';
}

return view('filament-panel-switch::panel-switch-menu', [
'currentPanel' => $static->getCurrentPanel(),
'canSwitchPanels' => $static->isAbleToSwitchPanels(),
'heading' => $static->getModalHeading(),
'icons' => $static->getIcons(),
'iconSize' => $static->getIconSize(),
Expand Down Expand Up @@ -180,6 +183,19 @@ public function simple(bool | Closure $condition = true): static
return $this;
}

/**
* Whether to sort the panels by their order or not.
* 1. null - Default order, provided by the user through the `panels` method.
* 2. 'asc' - Ascending order
* 3. 'desc' - Descending order
*/
public function sort(string $order = 'asc'): static
{
$this->sortOrder = $order;

return $this;
}

public function visible(bool | Closure $visible): static
{
$this->visible = $visible;
Expand Down Expand Up @@ -245,17 +261,20 @@ public function isVisible(): bool
return (bool) $this->evaluate($this->visible);
}

/**
* @return array<string, Panel>
*/
public function getSortOrder(): ?string
{
return $this->evaluate($this->sortOrder);
}

public function getPanels(): array
{
$panelIds = (array) $this->evaluate($this->panels);

return collect(Filament::getPanels())
->reject(fn (Panel $panel) => in_array($panel->getId(), $this->getExcludes()))
->when(
value: filled($panelIds),
callback: function($panelCollection) use($panelIds) {
callback: function ($panelCollection) use ($panelIds) {
$this->areUserProvidedPanelsValid($panelIds);

$withDefaultOrder = $panelCollection->only($panelIds);
Expand All @@ -266,12 +285,17 @@ public function getPanels(): array
},
default: fn ($panelCollection) => $panelCollection
)
->mapWithKeys(fn (Panel $panel) => [$panel->getId() => $this->isAbleToSwitchPanels() ? url($panel->getPath()) : null])
->when(
value: filled($this->getSortOrder()),
callback: fn ($panelCollection) => $panelCollection->sortKeys(descending: $this->getSortOrder() === 'desc')
)
->toArray();
}

public function getCurrentPanel(): Panel
{
return Filament::getCurrentPanel();
return Filament::getCurrentPanel() ?? Filament::getDefaultPanel();
}

public function getRenderHook(): string
Expand All @@ -283,4 +307,4 @@ public function getRenderIconAsImage(): bool
{
return $this->renderIconAsImage;
}
}
}
2 changes: 1 addition & 1 deletion src/PanelSwitchServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ public function packageBooted(): void
{
Filament::serving(fn () => PanelSwitch::boot());
}
}
}

0 comments on commit 2e3b281

Please sign in to comment.