- {{-- Mobile logo --}}
-
-
 }})
-
-
-
Entrar
-
Acesse sua conta He4rt Developers
+
+
Entrar
+
Acesse sua conta He4rt Developers
+
- {{-- OAuth --}}
-
diff --git a/app-modules/panel-app/src/Pages/LoginPage.php b/app-modules/panel-app/src/Pages/LoginPage.php
index 8c8203579..13ef45e28 100644
--- a/app-modules/panel-app/src/Pages/LoginPage.php
+++ b/app-modules/panel-app/src/Pages/LoginPage.php
@@ -12,6 +12,8 @@ class LoginPage extends Login
{
protected string $view = 'panel-app::auth.login';
+ protected static string $layout = 'filament-panels::components.layout.base';
+
public function mount(): void
{
parent::mount();
@@ -24,6 +26,13 @@ public function mount(): void
}
}
+ protected function getViewData(): array
+ {
+ return [
+ 'panelId' => 'app',
+ ];
+ }
+
public function getMaxWidth(): Width|string|null
{
return Width::Full;
@@ -43,4 +52,26 @@ public function getSubHeading(): string|Htmlable|null
{
return null;
}
+
+ protected function getAuthenticateFormAction(): \Filament\Actions\Action
+ {
+ return parent::getAuthenticateFormAction()
+ ->label('Entrar na conta')
+ ->color('primary')
+ ->size('lg')
+ ->extraAttributes([
+ 'class' => 'w-full rounded-xl shadow-lg shadow-purple-900/20 transition-all hover:scale-[1.02] active:scale-[0.98]',
+ ]);
+ }
+
+ public function form(\Filament\Schemas\Schema $form): \Filament\Schemas\Schema
+ {
+ return $form
+ ->components([
+ $this->getEmailFormComponent()->label('E-mail'),
+ $this->getPasswordFormComponent()->label('Senha'),
+ $this->getRememberFormComponent()->label('Lembrar de mim'),
+ ])
+ ->statePath('data');
+ }
}
diff --git a/app/Filament/Pages/Login.php b/app/Filament/Pages/Login.php
index 6dae45c04..ead404147 100644
--- a/app/Filament/Pages/Login.php
+++ b/app/Filament/Pages/Login.php
@@ -4,8 +4,15 @@
namespace App\Filament\Pages;
+use Filament\Actions\Action;
+use Illuminate\Contracts\Support\Htmlable;
+
class Login extends \Filament\Auth\Pages\Login
{
+ protected string $view = 'panel-app::auth.login';
+
+ protected static string $layout = 'filament-panels::components.layout.base';
+
public function mount(): void
{
parent::mount();
@@ -17,4 +24,43 @@ public function mount(): void
]);
}
}
+
+ public function getHeading(): string|Htmlable|null
+ {
+ return null;
+ }
+
+ public function getSubHeading(): string|Htmlable|null
+ {
+ return null;
+ }
+
+ protected function getAuthenticateFormAction(): Action
+ {
+ return parent::getAuthenticateFormAction()
+ ->label('Entrar no Admin')
+ ->color('primary')
+ ->size('lg')
+ ->extraAttributes([
+ 'class' => 'w-full rounded-xl shadow-lg shadow-purple-900/20 transition-all hover:scale-[1.02] active:scale-[0.98]',
+ ]);
+ }
+
+ protected function getViewData(): array
+ {
+ return [
+ 'panelId' => 'admin',
+ ];
+ }
+
+ public function form(\Filament\Schemas\Schema $form): \Filament\Schemas\Schema
+ {
+ return $form
+ ->components([
+ $this->getEmailFormComponent()->label('E-mail'),
+ $this->getPasswordFormComponent()->label('Senha'),
+ $this->getRememberFormComponent()->label('Lembrar de mim'),
+ ])
+ ->statePath('data');
+ }
}
diff --git a/app/Providers/Filament/AdminPanelProvider.php b/app/Providers/Filament/AdminPanelProvider.php
index 97dab652a..80af458fb 100644
--- a/app/Providers/Filament/AdminPanelProvider.php
+++ b/app/Providers/Filament/AdminPanelProvider.php
@@ -12,8 +12,10 @@
use Filament\Panel;
use Filament\PanelProvider;
use Filament\Support\Colors\Color;
+use Filament\View\PanelsRenderHook;
use He4rt\Identity\Tenant\Models\Tenant;
use He4rt\PanelAdmin\Http\Middleware\ApplyTenantScopes;
+use He4rt\PanelAdmin\Http\Middleware\SetProviderScope;
use He4rt\PanelAdmin\Pages\Dashboard;
use He4rt\PanelAdmin\Tenant\EditTenantProfilePage;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
@@ -32,6 +34,7 @@ public function panel(Panel $panel): Panel
->id('admin')
->path('admin')
->login(Login::class)
+ ->brandName('')
->colors(function (): array {
$colors = Color::all();
@@ -44,7 +47,12 @@ public function panel(Panel $panel): Panel
];
})
->sidebarCollapsibleOnDesktop()
+ ->tenantMenu(false)
->tenant(Tenant::class, slugAttribute: 'slug')
+ ->renderHook(
+ PanelsRenderHook::TOPBAR_START,
+ fn () => view('filament.admin.components.topbar-content'),
+ )
->tenantProfile(EditTenantProfilePage::class)
->viteTheme('resources/css/filament/admin/theme.css')
->middleware([
@@ -66,6 +74,7 @@ public function panel(Panel $panel): Panel
])
->tenantMiddleware([
ApplyTenantScopes::class,
+ SetProviderScope::class,
]);
return $panel;
diff --git a/app/Providers/Filament/AppPanelProvider.php b/app/Providers/Filament/AppPanelProvider.php
index a11c6adaf..9079c1c85 100644
--- a/app/Providers/Filament/AppPanelProvider.php
+++ b/app/Providers/Filament/AppPanelProvider.php
@@ -31,10 +31,10 @@ class AppPanelProvider extends PanelProvider
public function panel(Panel $panel): Panel
{
$panel
+ ->default()
->id($this->panelId->value)
->path($this->panelId->value)
->login(LoginPage::class)
- ->topbar(false)
->colors([
'primary' => Color::Purple,
'gray' => Color::Zinc,
diff --git a/resources/css/filament/admin/theme.css b/resources/css/filament/admin/theme.css
index 6b2c0eb56..bf04e22e9 100644
--- a/resources/css/filament/admin/theme.css
+++ b/resources/css/filament/admin/theme.css
@@ -6,6 +6,118 @@
@source '../../../../app-modules/**/resources/**/*';
@source '../../../../app-modules/**/src/**/*';
+:root {
+ --sidebar-width: 280px;
+ --topbar-height: 64px;
+}
+
+/* 1. Sidebar Position & Style */
.fi-sidebar {
- @apply bg-gray-100 dark:bg-gray-900;
+ @apply bg-white dark:bg-zinc-950 !border-r !border-slate-200/70 dark:!border-white/5 !shadow-xl !transition-all !duration-300;
+}
+
+.fi-sidebar-header {
+ display: none !important; /* Hide native sidebar brand */
+}
+
+/* 2. Topbar Styling */
+.fi-topbar {
+ @apply !bg-white/80 dark:!bg-zinc-950/80 !backdrop-blur-xl !border-b !border-slate-200/70 dark:!border-white/5 !sticky !top-0 !z-30 !shadow-sm;
+ height: var(--topbar-height) !important;
+}
+
+.fi-topbar > div {
+ @apply !h-full !px-6;
+}
+
+/* Hide ALL native brand elements in topbar to avoid duplicate with custom block */
+.fi-topbar-brand,
+.fi-topbar-header-cell,
+.fi-topbar-brand-link,
+[class*="fi-topbar-brand"],
+.fi-topbar > div > a {
+ display: none !important;
+}
+
+/* Hide Sidebar Collapse Button (Arrow/Hamburger) */
+.fi-topbar button[aria-controls="sidebar"],
+.fi-topbar-collapse-btn,
+.fi-topbar button:has(.fi-icon.fi-size-lg) {
+ display: none !important;
+}
+
+/* 3. Global Search Customization */
+.fi-global-search {
+ @apply !block;
+}
+
+.fi-global-search-input-ctn {
+ position: relative !important;
+}
+
+.fi-global-search-input {
+ @apply !bg-slate-50 dark:!bg-white/5 !border-slate-200/70 dark:!border-white/10 !rounded-xl !text-[12px] !pl-9 !pr-10 !py-2 !transition-all !shadow-none !ring-0 !outline-none focus:!bg-white dark:focus:!bg-white/10 focus:!border-purple-300;
+}
+
+.fi-global-search-input-ctn::after {
+ content: '⌘K';
+ position: absolute !important;
+ right: 0.75rem !important;
+ top: 50% !important;
+ transform: translateY(-50%) !important;
+ font-size: 10px !important;
+ @apply text-slate-400 bg-white dark:bg-zinc-800 px-1.5 py-0.5 rounded border border-slate-200 dark:border-white/10 pointer-events-none hidden md:block;
+}
+
+/* 4. Dropdowns & Panels */
+.fi-dropdown-panel {
+ @apply !bg-white dark:!bg-zinc-900 !border !border-slate-200/70 dark:!border-white/10 !shadow-2xl !rounded-2xl !backdrop-blur-xl !z-50;
+ border-radius: 1rem !important;
+ backdrop-filter: blur(24px) !important;
+ padding: 0.375rem !important; /* This creates the safe area for hover */
+ overflow: hidden !important; /* This ensures nothing leaks out */
+}
+
+.fi-dropdown-list {
+ @apply !p-0; /* Reset internal list padding to let the panel padding rule */
+}
+
+.dark .fi-dropdown-panel {
+ background-color: var(--color-zinc-900) !important;
+ border-color: rgba(255, 255, 255, 0.1) !important;
+}
+
+/* 5. Sidebar Item Adjustments */
+.fi-sidebar-item-button {
+ @apply !rounded-xl !transition-all !duration-200 !py-2.5 !px-4;
+ border-radius: 0.75rem !important;
+}
+
+.fi-sidebar-item-button:hover {
+ background-color: #f8fafc !important;
+}
+
+.fi-sidebar-item-active .fi-sidebar-item-button {
+ background-color: #f5f3ff !important;
+ color: #6d28d9 !important;
+ box-shadow: none !important;
+}
+
+/* 6. Page Spacing & Typography */
+.fi-main {
+ @apply p-8 lg:p-12;
+}
+
+/* Animations */
+@keyframes heartbeat {
+ 0% { transform: scale(1); }
+ 10% { transform: scale(1.05); }
+ 20% { transform: scale(1); }
+ 30% { transform: scale(1.05); }
+ 40% { transform: scale(1); }
+ 100% { transform: scale(1); }
+}
+
+.animate-heartbeat {
+ animation: heartbeat 3s ease-in-out infinite;
}
diff --git a/resources/css/filament/app/theme.css b/resources/css/filament/app/theme.css
index 8bc6c0311..0280ccb88 100644
--- a/resources/css/filament/app/theme.css
+++ b/resources/css/filament/app/theme.css
@@ -1,33 +1,10 @@
@import '../../../../vendor/filament/filament/resources/css/theme.css';
-@source '../../../../app/Filament/**/*';
@source '../../../../app/Filament/**/*';
@source '../../../../resources/views/**/*';
@source '../../../../app-modules/**/src/Filament/**/*';
@source '../../../../app-modules/**/resources/views/**/*';
-/* Login split layout — strip Filament's card wrapper */
-.fi-simple-layout:has(.fi-login-split) {
- .fi-simple-main-ctn {
- align-items: stretch;
- }
-
- .fi-simple-main {
- margin: 0;
- padding: 0;
- max-width: none;
- background: transparent;
- box-shadow: none;
- border-radius: 0;
- --tw-ring-shadow: 0 0 #0000;
- }
-
- .fi-simple-page,
- .fi-simple-page-content {
- display: contents;
- }
-}
-
@keyframes login-float {
0%,
100% {
@@ -47,3 +24,16 @@
opacity: 0.35;
}
}
+
+@keyframes heartbeat {
+ 0% { transform: scale(1); }
+ 10% { transform: scale(1.05); }
+ 20% { transform: scale(1); }
+ 30% { transform: scale(1.05); }
+ 40% { transform: scale(1); }
+ 100% { transform: scale(1); }
+}
+
+.animate-heartbeat {
+ animation: heartbeat 3s ease-in-out infinite;
+}
diff --git a/resources/views/filament/admin/components/brand.blade.php b/resources/views/filament/admin/components/brand.blade.php
new file mode 100644
index 000000000..dde185bac
--- /dev/null
+++ b/resources/views/filament/admin/components/brand.blade.php
@@ -0,0 +1,7 @@
+
+
+
+
He4rt Hub
+
Admin Console
+
+
diff --git a/resources/views/filament/admin/components/topbar-content.blade.php b/resources/views/filament/admin/components/topbar-content.blade.php
new file mode 100644
index 000000000..986c60a1a
--- /dev/null
+++ b/resources/views/filament/admin/components/topbar-content.blade.php
@@ -0,0 +1,44 @@
+
+ {{-- Brand Block: Fixed width to match sidebar & Acts as Sidebar Toggle --}}
+
+
+ {{-- Pickers Block --}}
+
+ @include('filament.admin.components.topbar-tenant-menu')
+
+
diff --git a/resources/views/filament/admin/components/topbar-tenant-menu.blade.php b/resources/views/filament/admin/components/topbar-tenant-menu.blade.php
new file mode 100644
index 000000000..56631ec83
--- /dev/null
+++ b/resources/views/filament/admin/components/topbar-tenant-menu.blade.php
@@ -0,0 +1,112 @@
+@php
+ $currentTenant = \Filament\Facades\Filament::getTenant();
+ $tenants = \Filament\Facades\Filament::getUserTenants(\Filament\Facades\Filament::auth()->user());
+ $panelId = \Filament\Facades\Filament::getCurrentPanel()->getId();
+
+ $providers = \He4rt\Identity\ExternalIdentity\Enums\IdentityProvider::supportedProviders();
+ $activeProviderValue = session('active_provider', \He4rt\Identity\ExternalIdentity\Enums\IdentityProvider::Discord->value);
+ $currentProvider = \He4rt\Identity\ExternalIdentity\Enums\IdentityProvider::tryFrom($activeProviderValue) ?? $providers[1];
+@endphp
+
+
+ {{-- Tenant Picker --}}
+
+
+
+
+
+
+ Trocar escopo de tenant
+
+ @foreach ($tenants as $tenant)
+ @php
+ $isActive = $tenant->id === $currentTenant->id;
+ @endphp
+
+
+
+
+
+
+
+
+ {{ $tenant->name }}
+
+ @if ($isActive)
+ Ativo
+ @endif
+
+
{{ $tenant->domain ?? $tenant->slug }}
+
+
+
+ @endforeach
+
+
+
+
+ Gerenciar Tenant
+
+
+
+
+
·
+
+ {{-- Provider Picker --}}
+
+
+
+
+
+
+ @foreach ($providers as $p)
+ @php
+ $isActive = $p->value === $currentProvider->value;
+ @endphp
+
+
+
+ @svg($p->getIcon(), 'w-3.5 h-3.5')
+
+
+ {{ $p->getLabel() }}
+ @if ($isActive)
+ Ativo
+ @endif
+
+
+
+ @endforeach
+
+
+