Use Filament tabs for user panel navs
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,3 +21,4 @@ yarn-error.log
|
||||
CLAUDE.md
|
||||
/jabali-panel_*.deb
|
||||
/jabali-deps_*.deb
|
||||
.git-credentials
|
||||
|
||||
@@ -29,7 +29,8 @@ use Filament\Pages\Page;
|
||||
use Filament\Schemas\Components\Actions as FormActions;
|
||||
use Filament\Schemas\Components\Grid;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Components\View;
|
||||
use Filament\Schemas\Components\Tabs;
|
||||
use Filament\Schemas\Components\Tabs\Tab;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\IconColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
@@ -115,7 +116,18 @@ class Backups extends Page implements HasActions, HasForms, HasTable
|
||||
->description(__('Create and manage backups of your account data. Backups include your websites, databases, and mailboxes. You can restore from any backup at any time.'))
|
||||
->icon('heroicon-o-information-circle')
|
||||
->iconColor('info'),
|
||||
View::make('filament.jabali.components.backup-tabs-nav'),
|
||||
Tabs::make(__('Backup Sections'))
|
||||
->livewireProperty('activeTab')
|
||||
->tabs([
|
||||
'local' => Tab::make(__('My Backups'))
|
||||
->icon('heroicon-o-archive-box'),
|
||||
'remote' => Tab::make(__('Server Backups'))
|
||||
->icon('heroicon-o-cloud'),
|
||||
'destinations' => Tab::make(__('SFTP Destinations'))
|
||||
->icon('heroicon-o-server-stack'),
|
||||
'history' => Tab::make(__('Restore History'))
|
||||
->icon('heroicon-o-arrow-path'),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@ use Filament\Infolists\Components\TextEntry;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Pages\Page;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Components\View;
|
||||
use Filament\Schemas\Components\Tabs;
|
||||
use Filament\Schemas\Components\Tabs\Tab;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Concerns\InteractsWithTable;
|
||||
@@ -134,7 +135,22 @@ class Email extends Page implements HasActions, HasForms, HasTable
|
||||
public function emailForm(Schema $schema): Schema
|
||||
{
|
||||
return $schema->schema([
|
||||
View::make('filament.jabali.components.email-tabs-nav'),
|
||||
Tabs::make(__('Email Sections'))
|
||||
->livewireProperty('activeTab')
|
||||
->tabs([
|
||||
'mailboxes' => Tab::make(__('Mailboxes'))
|
||||
->icon('heroicon-o-envelope'),
|
||||
'forwarders' => Tab::make(__('Forwarders'))
|
||||
->icon('heroicon-o-arrow-right'),
|
||||
'autoresponders' => Tab::make(__('Autoresponders'))
|
||||
->icon('heroicon-o-clock'),
|
||||
'catchall' => Tab::make(__('Catch-All'))
|
||||
->icon('heroicon-o-inbox-stack'),
|
||||
'logs' => Tab::make(__('Logs'))
|
||||
->icon('heroicon-o-document-text'),
|
||||
'spam' => Tab::make(__('Spam Settings'))
|
||||
->icon('heroicon-o-shield-check'),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,9 @@ use Filament\Forms\Concerns\InteractsWithForms;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Pages\Page;
|
||||
use Filament\Schemas\Components\Tabs;
|
||||
use Filament\Schemas\Components\Tabs\Tab;
|
||||
use Filament\Schemas\Schema;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Attributes\Url;
|
||||
@@ -90,6 +93,27 @@ class Logs extends Page implements HasActions, HasForms
|
||||
$this->activeTab = $this->normalizeTab($tab);
|
||||
}
|
||||
|
||||
protected function getForms(): array
|
||||
{
|
||||
return ['tabsForm'];
|
||||
}
|
||||
|
||||
public function tabsForm(Schema $schema): Schema
|
||||
{
|
||||
return $schema->schema([
|
||||
Tabs::make(__('Log Sections'))
|
||||
->livewireProperty('activeTab')
|
||||
->tabs([
|
||||
'logs' => Tab::make(__('Logs'))
|
||||
->icon('heroicon-o-document-text'),
|
||||
'stats' => Tab::make(__('Statistics'))
|
||||
->icon('heroicon-o-chart-bar'),
|
||||
'activity' => Tab::make(__('Activity Log'))
|
||||
->icon('heroicon-o-clipboard-document-list'),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
protected function normalizeTab(?string $tab): string
|
||||
{
|
||||
return match ($tab) {
|
||||
|
||||
@@ -16,6 +16,9 @@ use Filament\Forms\Concerns\InteractsWithForms;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Pages\Page;
|
||||
use Filament\Schemas\Components\Tabs;
|
||||
use Filament\Schemas\Components\Tabs\Tab;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Concerns\InteractsWithTable;
|
||||
use Filament\Tables\Contracts\HasTable;
|
||||
@@ -71,6 +74,25 @@ class PostgreSQL extends Page implements HasActions, HasForms, HasTable
|
||||
$this->resetTable();
|
||||
}
|
||||
|
||||
protected function getForms(): array
|
||||
{
|
||||
return ['tabsForm'];
|
||||
}
|
||||
|
||||
public function tabsForm(Schema $schema): Schema
|
||||
{
|
||||
return $schema->schema([
|
||||
Tabs::make(__('PostgreSQL Sections'))
|
||||
->livewireProperty('activeTab')
|
||||
->tabs([
|
||||
'databases' => Tab::make(__('Databases'))
|
||||
->icon('heroicon-o-circle-stack'),
|
||||
'users' => Tab::make(__('Users'))
|
||||
->icon('heroicon-o-users'),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
protected function normalizeTab(string $tab): string
|
||||
{
|
||||
return in_array($tab, ['databases', 'users'], true) ? $tab : 'databases';
|
||||
|
||||
@@ -16,7 +16,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
if [[ -f "$SCRIPT_DIR/VERSION" ]]; then
|
||||
JABALI_VERSION="$(sed -n 's/^VERSION=//p' "$SCRIPT_DIR/VERSION")"
|
||||
fi
|
||||
JABALI_VERSION="${JABALI_VERSION:-0.9-rc39}"
|
||||
JABALI_VERSION="${JABALI_VERSION:-0.9-rc40}"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
@php
|
||||
$tabs = [
|
||||
'local' => ['label' => __('My Backups'), 'icon' => 'heroicon-o-archive-box'],
|
||||
'remote' => ['label' => __('Server Backups'), 'icon' => 'heroicon-o-cloud'],
|
||||
'destinations' => ['label' => __('SFTP Destinations'), 'icon' => 'heroicon-o-server-stack'],
|
||||
'history' => ['label' => __('Restore History'), 'icon' => 'heroicon-o-arrow-path'],
|
||||
];
|
||||
@endphp
|
||||
|
||||
<nav class="fi-tabs flex max-w-full gap-x-1 overflow-x-auto mx-auto rounded-xl bg-white p-2 shadow-sm ring-1 ring-gray-950/5 dark:bg-white/5 dark:ring-white/10" role="tablist">
|
||||
@foreach($tabs as $key => $tab)
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-selected="{{ $this->activeTab === $key ? 'true' : 'false' }}"
|
||||
wire:click="setTab('{{ $key }}')"
|
||||
@class([
|
||||
'fi-tabs-item group flex items-center gap-x-2 rounded-lg px-3 py-2 text-sm font-medium outline-none transition duration-75',
|
||||
'fi-active bg-gray-50 dark:bg-white/5' => $this->activeTab === $key,
|
||||
'hover:bg-gray-50 focus-visible:bg-gray-50 dark:hover:bg-white/5 dark:focus-visible:bg-white/5' => $this->activeTab !== $key,
|
||||
])
|
||||
>
|
||||
<x-filament::icon
|
||||
:icon="$tab['icon']"
|
||||
@class([
|
||||
'fi-tabs-item-icon h-5 w-5 shrink-0 transition duration-75',
|
||||
'text-primary-600 dark:text-primary-400' => $this->activeTab === $key,
|
||||
'text-gray-400 group-hover:text-gray-500 group-focus-visible:text-gray-500 dark:text-gray-500 dark:group-hover:text-gray-400 dark:group-focus-visible:text-gray-400' => $this->activeTab !== $key,
|
||||
])
|
||||
/>
|
||||
<span @class([
|
||||
'fi-tabs-item-label transition duration-75',
|
||||
'text-primary-600 dark:text-primary-400' => $this->activeTab === $key,
|
||||
'text-gray-500 group-hover:text-gray-700 group-focus-visible:text-gray-700 dark:text-gray-400 dark:group-hover:text-gray-200 dark:group-focus-visible:text-gray-200' => $this->activeTab !== $key,
|
||||
])>
|
||||
{{ $tab['label'] }}
|
||||
</span>
|
||||
</button>
|
||||
@endforeach
|
||||
</nav>
|
||||
@@ -1,42 +0,0 @@
|
||||
@php
|
||||
$tabs = [
|
||||
'mailboxes' => ['label' => __('Mailboxes'), 'icon' => 'heroicon-o-envelope'],
|
||||
'forwarders' => ['label' => __('Forwarders'), 'icon' => 'heroicon-o-arrow-right'],
|
||||
'autoresponders' => ['label' => __('Autoresponders'), 'icon' => 'heroicon-o-clock'],
|
||||
'catchall' => ['label' => __('Catch-All'), 'icon' => 'heroicon-o-inbox-stack'],
|
||||
'logs' => ['label' => __('Logs'), 'icon' => 'heroicon-o-document-text'],
|
||||
'spam' => ['label' => __('Spam Settings'), 'icon' => 'heroicon-o-shield-check'],
|
||||
];
|
||||
@endphp
|
||||
|
||||
<nav class="fi-tabs flex max-w-full gap-x-1 overflow-x-auto mx-auto rounded-xl bg-white p-2 shadow-sm ring-1 ring-gray-950/5 dark:bg-white/5 dark:ring-white/10" role="tablist">
|
||||
@foreach($tabs as $key => $tab)
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-selected="{{ $this->activeTab === $key ? 'true' : 'false' }}"
|
||||
wire:click="setTab('{{ $key }}')"
|
||||
@class([
|
||||
'fi-tabs-item group flex items-center gap-x-2 rounded-lg px-3 py-2 text-sm font-medium outline-none transition duration-75',
|
||||
'fi-active bg-gray-50 dark:bg-white/5' => $this->activeTab === $key,
|
||||
'hover:bg-gray-50 focus-visible:bg-gray-50 dark:hover:bg-white/5 dark:focus-visible:bg-white/5' => $this->activeTab !== $key,
|
||||
])
|
||||
>
|
||||
<x-filament::icon
|
||||
:icon="$tab['icon']"
|
||||
@class([
|
||||
'fi-tabs-item-icon h-5 w-5 shrink-0 transition duration-75',
|
||||
'text-primary-600 dark:text-primary-400' => $this->activeTab === $key,
|
||||
'text-gray-400 group-hover:text-gray-500 group-focus-visible:text-gray-500 dark:text-gray-500 dark:group-hover:text-gray-400 dark:group-focus-visible:text-gray-400' => $this->activeTab !== $key,
|
||||
])
|
||||
/>
|
||||
<span @class([
|
||||
'fi-tabs-item-label transition duration-75',
|
||||
'text-primary-600 dark:text-primary-400' => $this->activeTab === $key,
|
||||
'text-gray-500 group-hover:text-gray-700 group-focus-visible:text-gray-700 dark:text-gray-400 dark:group-hover:text-gray-200 dark:group-focus-visible:text-gray-200' => $this->activeTab !== $key,
|
||||
])>
|
||||
{{ $tab['label'] }}
|
||||
</span>
|
||||
</button>
|
||||
@endforeach
|
||||
</nav>
|
||||
@@ -1,43 +1,5 @@
|
||||
<x-filament-panels::page>
|
||||
@php
|
||||
$tabs = [
|
||||
'logs' => ['label' => __('Logs'), 'icon' => 'heroicon-o-document-text'],
|
||||
'stats' => ['label' => __('Statistics'), 'icon' => 'heroicon-o-chart-bar'],
|
||||
'activity' => ['label' => __('Activity Log'), 'icon' => 'heroicon-o-clipboard-document-list'],
|
||||
];
|
||||
@endphp
|
||||
|
||||
<nav class="fi-tabs flex max-w-full gap-x-1 overflow-x-auto mx-auto rounded-xl bg-white p-2 shadow-sm ring-1 ring-gray-950/5 dark:bg-white/5 dark:ring-white/10" role="tablist">
|
||||
@foreach($tabs as $key => $tab)
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-selected="{{ $activeTab === $key ? 'true' : 'false' }}"
|
||||
wire:click="setTab('{{ $key }}')"
|
||||
@class([
|
||||
'fi-tabs-item group flex items-center gap-x-2 rounded-lg px-3 py-2 text-sm font-medium outline-none transition duration-75',
|
||||
'fi-active bg-gray-50 dark:bg-white/5' => $activeTab === $key,
|
||||
'hover:bg-gray-50 focus-visible:bg-gray-50 dark:hover:bg-white/5 dark:focus-visible:bg-white/5' => $activeTab !== $key,
|
||||
])
|
||||
>
|
||||
<x-filament::icon
|
||||
:icon="$tab['icon']"
|
||||
@class([
|
||||
'fi-tabs-item-icon h-5 w-5 shrink-0 transition duration-75',
|
||||
'text-primary-600 dark:text-primary-400' => $activeTab === $key,
|
||||
'text-gray-400 group-hover:text-gray-500 group-focus-visible:text-gray-500 dark:text-gray-500 dark:group-hover:text-gray-400 dark:group-focus-visible:text-gray-400' => $activeTab !== $key,
|
||||
])
|
||||
/>
|
||||
<span @class([
|
||||
'fi-tabs-item-label transition duration-75',
|
||||
'text-primary-600 dark:text-primary-400' => $activeTab === $key,
|
||||
'text-gray-500 group-hover:text-gray-700 group-focus-visible:text-gray-700 dark:text-gray-400 dark:group-hover:text-gray-200 dark:group-focus-visible:text-gray-200' => $activeTab !== $key,
|
||||
])>
|
||||
{{ $tab['label'] }}
|
||||
</span>
|
||||
</button>
|
||||
@endforeach
|
||||
</nav>
|
||||
{{ $this->tabsForm }}
|
||||
|
||||
@if(in_array($activeTab, ['logs', 'stats'], true))
|
||||
@if(count($this->getDomainOptions()) > 0)
|
||||
|
||||
@@ -1,42 +1,5 @@
|
||||
<x-filament-panels::page>
|
||||
@php
|
||||
$tabs = [
|
||||
'databases' => ['label' => __('Databases'), 'icon' => 'heroicon-o-circle-stack'],
|
||||
'users' => ['label' => __('Users'), 'icon' => 'heroicon-o-users'],
|
||||
];
|
||||
@endphp
|
||||
|
||||
<nav class="fi-tabs flex max-w-full gap-x-1 overflow-x-auto mx-auto rounded-xl bg-white p-2 shadow-sm ring-1 ring-gray-950/5 dark:bg-white/5 dark:ring-white/10" role="tablist">
|
||||
@foreach($tabs as $key => $tab)
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-selected="{{ $activeTab === $key ? 'true' : 'false' }}"
|
||||
wire:click="$set('activeTab', '{{ $key }}')"
|
||||
@class([
|
||||
'fi-tabs-item group flex items-center gap-x-2 rounded-lg px-3 py-2 text-sm font-medium outline-none transition duration-75',
|
||||
'fi-active bg-gray-50 dark:bg-white/5' => $activeTab === $key,
|
||||
'hover:bg-gray-50 focus-visible:bg-gray-50 dark:hover:bg-white/5 dark:focus-visible:bg-white/5' => $activeTab !== $key,
|
||||
])
|
||||
>
|
||||
<x-filament::icon
|
||||
:icon="$tab['icon']"
|
||||
@class([
|
||||
'fi-tabs-item-icon h-5 w-5 shrink-0 transition duration-75',
|
||||
'text-primary-600 dark:text-primary-400' => $activeTab === $key,
|
||||
'text-gray-400 group-hover:text-gray-500 group-focus-visible:text-gray-500 dark:text-gray-500 dark:group-hover:text-gray-400 dark:group-focus-visible:text-gray-400' => $activeTab !== $key,
|
||||
])
|
||||
/>
|
||||
<span @class([
|
||||
'fi-tabs-item-label transition duration-75',
|
||||
'text-primary-600 dark:text-primary-400' => $activeTab === $key,
|
||||
'text-gray-500 group-hover:text-gray-700 group-focus-visible:text-gray-700 dark:text-gray-400 dark:group-hover:text-gray-200 dark:group-focus-visible:text-gray-200' => $activeTab !== $key,
|
||||
])>
|
||||
{{ $tab['label'] }}
|
||||
</span>
|
||||
</button>
|
||||
@endforeach
|
||||
</nav>
|
||||
{{ $this->tabsForm }}
|
||||
|
||||
<div class="mt-4">
|
||||
{{ $this->table }}
|
||||
|
||||
Reference in New Issue
Block a user