Panels
Hewcode includes a complete panel system for building sophisticated application interfaces. Panels provide navigation, resource management, and layout components out of the box.
Quick Start
Register the default panel in your service provider AppServiceProvider.
use Hewcode\Hewcode\Hewcode;
public function register(): void
{
Hewcode::panel(); // By default this is the 'app' panel
}If you pass a name to the panel() method, it will register the panel with that name, and you can register multiple panels:
Hewcode::panel('admin'); // Registers custom 'admin' panel
Hewcode::panel('dashboard'); // Registers custom 'dashboard' panelAccessing Panels: Once registered, panels are accessible at /{panel-name}:
- Default panel:
/app - Admin panel:
/admin - Dashboard panel:
/dashboard
Panel
Layout
Panels support two layout styles: sidebar layout (default) and header layout. You can configure the layout using the sidebarLayout() or headerLayout() methods:
// Sidebar layout (default)
Hewcode::panel('admin');
// Header layout
Hewcode::panel('admin')->headerLayout();
// Chain with other configurations
Hewcode::panel('admin')
->title('Admin Panel')
->headerLayout();The sidebar layout displays navigation in a collapsible sidebar, while the header layout displays navigation in a top header bar.
Logo
Customize the panel logo and icon using the logo() and logoIcon() methods:
Hewcode::panel('admin')
->logo(asset('images/logo.svg'))
->logoIcon(asset('images/icon.svg'));Both methods support lazy evaluation with closures:
Hewcode::panel('admin')
->logo(fn () => asset('images/logo.svg'))
->logoIcon(fn () => asset('images/icon.svg'));How it works:
logo()- Full logo image displayed in the sidebar/header. When set, it replaces the default logo completely.logoIcon()- Icon displayed alongside the panel title. Only shown whenlogo()is not set.
If neither is set, the default Hewcode logo and icon are used.
Features
Panels include built-in authentication and settings features that can be toggled on or off. All features are enabled by default.
Hewcode::panel('admin')
->login(false) // Disable login
->registration(false) // Disable registration
->passwordReset(false) // Disable password reset
->emailVerification(false) // Disable email verification
->profileSettings(false) // Disable profile settings page
->passwordSettings(false) // Disable password settings page
->appearanceSettings(false); // Disable appearance settings pageAvailable Features:
login()- Login and logout functionalityregistration()- User registrationpasswordReset()- Forgot password and reset passwordemailVerification()- Email verification flowprofileSettings()- Profile edit and delete accountpasswordSettings()- Change passwordappearanceSettings()- Theme/appearance preferences
Middleware
You can customize the middleware stack for each panel.
Replacing Middleware
Replace the middleware stack by passing an array to middleware():
Hewcode::panel('admin')
->middleware([
\App\Http\Middleware\CustomAuth::class,
\App\Http\Middleware\CheckSubscription::class,
]);Appending Middleware
Add middleware using the append parameter:
Hewcode::panel('admin')
->middleware(append: [
\App\Http\Middleware\CheckSubscription::class,
\App\Http\Middleware\LogActivity::class,
]);
// Or append multiple times
Hewcode::panel('admin')
->middleware(append: [\App\Http\Middleware\CheckSubscription::class])
->middleware(append: [\App\Http\Middleware\TwoFactorAuth::class]);Note: The middleware applies to all protected routes including dashboard, resources, settings, and authenticated auth routes (email verification, password confirmation, logout). Guest routes (login, register, password reset) are not affected.
Dashboard
Each panel includes a default dashboard page. You can customize the dashboard by creating a custom controller that extends DashboardController:
Step 1: Create your custom dashboard controller:
// app/Panel/CustomDashboardController.php
namespace App\Panel;
use Hewcode\Hewcode\Panel\Controllers\DashboardController;
use Hewcode\Hewcode\Widgets;
class CustomDashboardController extends DashboardController
{
#[Widgets\Expose]
public function widgets(): Widgets\Widgets
{
return Widgets\Widgets::make([
$this->hewcodeInfoWidget(), // Inherited from parent
$this->customWidget(),
])->visible();
}
protected function customWidget(): Widgets\StatsWidget
{
return Widgets\StatsWidget::make('total_users')
->label('Total Users')
->value(\App\Models\User::count())
->icon('lucide-users');
}
// Specify which panels this dashboard belongs to
public function panels(): array
{
return ['admin'];
}
}Step 2: Register the custom dashboard with your panel:
use App\Panel\CustomDashboardController;
Hewcode::panel('admin')
->dashboard(CustomDashboardController::class);How it works:
- Your custom controller must extend
DashboardController - It can be placed anywhere in your application (not limited to discovery paths)
- If discovered automatically (e.g., in
app/Hewcode/Controllers/), the default dashboard is skipped - If not discovered, it's registered manually
- Inherits all base dashboard functionality including the Hewcode info widget
Note: The custom dashboard controller will replace the default panel dashboard. You can still call $this->hewcodeInfoWidget() to include the default Hewcode version widget.
Resources
You can create resources to quickly get started with managing records in your panels.
php artisan hew:resource ProductResourceYou can pass:
--model=Productto specify the model explicitly.--panels=admin,appto assign the resource to specific panels.--generateto auto-generate form fields and listing columns based on your model's table structure.
This will output the following resource class:
<?php
namespace App\Hewcode\Resources;
use App\Models\Product;
use Hewcode\Hewcode\Actions;
use Hewcode\Hewcode\Forms;
use Hewcode\Hewcode\Lists;
use Hewcode\Hewcode\Panel;
class ProductResource extends Panel\Resource
{
protected string $model = Product::class;
public function pages(): array
{
return [
Panel\Controllers\Resources\IndexController::page(),
Panel\Controllers\Resources\CreateController::page(),
Panel\Controllers\Resources\EditController::page(),
];
}
public function form(Forms\Form $form): Forms\Form
{
return $form
->visible(auth()->check())
->schema([
Forms\Schema\TextInput::make('name')
->required(),
]);
}
public function listing(Lists\Listing $listing): Lists\Listing
{
return $listing
->visible(auth()->check())
->query(Product::query())
->columns([
Lists\Schema\TextColumn::make('id')
->sortable(),
Lists\Schema\TextColumn::make('name')
->sortable()
->searchable(),
Lists\Schema\TextColumn::make('created_at')
->datetime()
->sortable(),
])
->actions([
Actions\Eloquent\EditAction::make(),
Actions\Eloquent\DeleteAction::make(),
])
->defaultSort('created_at', 'desc');
}
}INFO
Resources include form() and listing() methods for inline configuration. For reusable definitions across multiple resources, see Listing Definition and Form Definition.
Advanced Usage
Optionally, if you need more flexibility, you can create custom page controllers that use your listing and form definitions.
Resource Page Controllers
INFO
The examples below reference UserListing and UserForm definition classes. Learn how to create these at Listing Definition and Form Definition.
You can create custom resource page controllers that extend the base resource controllers to use your listing and form definitions.
For a listing page controller use the following command:
php artisan hew:resource-page ListUsersController --indexclass ListUsersController extends Resources\IndexController
{
public static string $listing = UserListing::class;
protected function props(Props\Props $props): Props\Props
{
return $props->appendData([
// Additional data for this page
]);
}
protected function getHeaderActions(): array
{
return [
Actions\Eloquent\CreateAction::make(),
];
}
}For an edit page controller use the following command:
php artisan hew:resource-page EditUserController --editclass EditUserController extends Resources\EditController
{
public static string $form = UserForm::class;
protected function props(Props\Props $props): Props\Props
{
return $props->appendData([
// Additional data for this page
]);
}
protected function getHeaderActions(): array
{
return [
Actions\Eloquent\DeleteAction::make(),
];
}
}For a create page controller use the following command:
php artisan hew:resource-page CreateUserController --createclass CreateUserController extends Resources\CreateController
{
public static string $form = UserForm::class;
protected function props(Props\Props $props): Props\Props
{
return $props->appendData([
// Additional data for this page
]);
}
protected function getHeaderActions(): array
{
return [
Actions\Eloquent\CancelAction::make(),
];
}
}Finally, you can also create a custom form controller:
php artisan hew:page CustomFormController --formclass CustomFormController extends Panel\Controllers\Resources\FormController
{
public static string $form = UserForm::class;
protected function props(Props\Props $props): Props\Props
{
return $props->appendData([
// Additional data for this page
]);
}
protected function getHeaderActions(): array
{
return [
Actions\Eloquent\SaveAction::make(),
Actions\Eloquent\CancelAction::make(),
];
}
}Page Controllers
You can create custom panel page controllers outside of resources to build custom pages.
php artisan hew:page CustomPageControlleruse Hewcode\Hewcode\Panel;
class CustomPageController extends Panel\Controllers\PageController
{
protected string $icon = 'lucide-dashboard';
protected ?int $navigationSort = 10;
protected bool $shouldRegisterNavigation = true;
protected function getNavigationTitle(): string
{
return 'Dashboard';
}
}Navigation
Resources and resource controllers are automatically registered in the panel navigation. You can also manually add navigation items or groups.
Manual Navigation
You can add navigation items to specific panels using the navigation() method:
use Hewcode\Hewcode\Hewcode;
use Hewcode\Hewcode\Panel\Navigation;
public function boot(): void
{
Hewcode::panel('admin')
->navigation(function (Navigation\Navigation $navigation) {
return $navigation
->item(
NavigationItem::make('Dashboard')
->url('/admin')
->icon('lucide-home')
->order(10)
)
->item(
NavigationGroup::make('Content Management')
->order(20)
->items([
NavigationItem::make('Posts')
->url('/admin/posts')
->icon('lucide-file-text'),
NavigationItem::make('Categories')
->url('/admin/categories')
->icon('lucide-tag'),
])
);
});
Hewcode::panel('app')
->navigation(function (Navigation\Navigation $navigation) {
return $navigation
->item(
NavigationItem::make('My Dashboard')
->url('/app')
->icon('lucide-home')
);
});
}Automatic Navigation
Controllers automatically register navigation items in the panels they're assigned to:
class CustomPageController extends PageController
{
protected string $icon = 'lucide-settings';
protected ?int $navigationSort = 100;
protected bool $shouldRegisterNavigation = true; // Default is true
protected function getNavigationTitle(): string
{
return 'Custom Page';
}
}You can override the automatic navigation registration method registerNavigation. This is useful if you want to add more items or groups or conditionally register navigation.
public function registerNavigation(Navigation\Navigation $navigation): void
{
if (! $this->getShouldRegisterNavigation()) {
return;
}
$navigation->item(
Navigation\NavigationItem::make()
->url(fn () => Hewcode::route($this->getRouteName()))
->label($this->getNavigationTitle())
->icon($this->getNavigationIcon())
->order($this->navigationSort)
);
}Frontend Integration
Panel pages use default frontend components automatically. You can optionally override them by setting the view property on page controllers:
class ListUsersController extends Resources\IndexController
{
public static string $listing = UserListing::class;
// Optional: Override the default view
public function view(): string
{
return 'custom/users/index'; // Uses resources/js/pages/custom/users/index.tsx
}
}
class EditUserController extends Resources\EditController
{
public static string $form = UserForm::class;
// Optional: Override the default view
public function view(): string
{
return 'custom/users/edit'; // Uses resources/js/pages/custom/users/edit.tsx
}
}The default frontend components are:
- Index pages:
@hewcode/react/pages/hewcode/resources/index(renders DataTable) - Form pages:
@hewcode/react/pages/hewcode/resources/form(renders Form) - Dashboard:
@hewcode/react/pages/hewcode/dashboard
If you create custom views, they should follow this pattern:
// Custom index page
import { usePage } from '@inertiajs/react';
import DataTable from '@hewcode/react/components/data-table/DataTable';
import PageLayout from '@/layouts/pages/page-layout';
export default function CustomIndex() {
const { listing } = usePage().props;
return (
<PageLayout>
<DataTable {...listing} />
</PageLayout>
);
}// Custom form page
import { usePage, router } from '@inertiajs/react';
import Form from '@hewcode/react/components/form/Form';
import PageLayout from '@/layouts/pages/page-layout';
export default function CustomForm() {
const { form } = usePage().props;
return (
<PageLayout>
<Form {...form} onCancel={() => router.visit('/users')} />
</PageLayout>
);
}