Initial baseline: LaraBlog core with plugin commerce surface.

Captures the current working tree after theme slots, ArticleAccess, and the payment / paid-content plugins so subsequent work has a reviewable git history.
This commit is contained in:
ak
2026-08-12 01:15:38 +08:00
commit 263b98b218
337 changed files with 31393 additions and 0 deletions
@@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Articles;
use App\Filament\Resources\Articles\Pages\CreateArticle;
use App\Filament\Resources\Articles\Pages\EditArticle;
use App\Filament\Resources\Articles\Pages\ListArticles;
use App\Filament\Resources\Articles\Schemas\ArticleForm;
use App\Filament\Resources\Articles\Tables\ArticlesTable;
use App\Models\Article;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use UnitEnum;
use App\Filament\Concerns\HasTranslatedLabels;
class ArticleResource extends Resource
{
use HasTranslatedLabels;
protected static ?string $model = Article::class;
protected static function navKey(): string
{
return 'articles';
}
protected static function modelKey(): string
{
return 'article';
}
protected static function groupKey(): string
{
return 'content';
}
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedDocumentText;
public static function form(Schema $schema): Schema
{
return ArticleForm::configure($schema);
}
public static function table(Table $table): Table
{
return ArticlesTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListArticles::route('/'),
'create' => CreateArticle::route('/create'),
'edit' => EditArticle::route('/{record}/edit'),
];
}
}
@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Articles\Pages;
use App\Domain\Plugin\Hook;
use App\Filament\Resources\Articles\ArticleResource;
use Filament\Resources\Pages\CreateRecord;
class CreateArticle extends CreateRecord
{
protected static string $resource = ArticleResource::class;
/**
* @param array<string, mixed> $data
* @return array<string, mixed>
*/
protected function mutateFormDataBeforeCreate(array $data): array
{
$filtered = Hook::filter('filament.article.mutate_before_save', $data, null);
return is_array($filtered) ? $filtered : $data;
}
protected function afterCreate(): void
{
Hook::dispatch('filament.article.after_save', $this->record, $this->form->getState());
}
}
@@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Articles\Pages;
use App\Domain\Ai\Jobs\OptimizeArticleContentJob;
use App\Domain\Plugin\Hook;
use App\Filament\Resources\Articles\ArticleResource;
use Filament\Actions\Action;
use Filament\Actions\DeleteAction;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord;
class EditArticle extends EditRecord
{
protected static string $resource = ArticleResource::class;
protected function getHeaderActions(): array
{
return [
Action::make('aiOptimize')
->label(__('admin.messages.ai_optimize'))
->action(function (): void {
OptimizeArticleContentJob::dispatch($this->record->getKey());
Notification::make()
->title(__('admin.messages.ai_optimize_queued'))
->body(__('admin.messages.ai_optimize_queue_hint'))
->success()
->send();
}),
DeleteAction::make(),
...Hook::collect('filament.article.actions'),
];
}
/**
* @param array<string, mixed> $data
* @return array<string, mixed>
*/
protected function mutateFormDataBeforeFill(array $data): array
{
$filtered = Hook::filter('filament.article.mutate_before_fill', $data, $this->record);
return is_array($filtered) ? $filtered : $data;
}
/**
* @param array<string, mixed> $data
* @return array<string, mixed>
*/
protected function mutateFormDataBeforeSave(array $data): array
{
$filtered = Hook::filter('filament.article.mutate_before_save', $data, $this->record);
return is_array($filtered) ? $filtered : $data;
}
protected function afterSave(): void
{
Hook::dispatch('filament.article.after_save', $this->record, $this->form->getState());
}
}
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Articles\Pages;
use App\Filament\Resources\Articles\ArticleResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListArticles extends ListRecords
{
protected static string $resource = ArticleResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}
@@ -0,0 +1,87 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Articles\Schemas;
use App\Domain\Blog\ContentFormat;
use App\Domain\Plugin\Hook;
use App\Settings\GeneralSettings;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Schemas\Schema;
class ArticleForm
{
public static function configure(Schema $schema): Schema
{
$defaultFormat = ContentFormat::MARKDOWN;
try {
$defaultFormat = ContentFormat::normalize(app(GeneralSettings::class)->default_content_format, ContentFormat::MARKDOWN);
} catch (\Throwable) {
//
}
return $schema
->components([
Select::make('category_id')
->label(__('admin.fields.category'))
->relationship('category', 'name')
->required(),
Select::make('user_id')
->label(__('admin.fields.author'))
->relationship('user', 'name')
->required(),
TextInput::make('title')
->label(__('admin.fields.title'))
->required()
->columnSpanFull(),
Select::make('content_format')
->label(__('admin.fields.content_format'))
->options([
ContentFormat::MARKDOWN => __('admin.options.markdown_recommended'),
ContentFormat::HTML => __('admin.options.html_legacy'),
])
->default($defaultFormat)
->required()
->live()
->helperText(__('admin.helpers.article_content')),
Textarea::make('content')
->label(fn (Get $get): string => $get('content_format') === ContentFormat::MARKDOWN
? __('admin.fields.content_markdown')
: __('admin.fields.content_html'))
->required()
->rows(18)
->columnSpanFull(),
TextInput::make('description')
->label(__('admin.fields.description')),
TextInput::make('keywords')
->label(__('admin.fields.keywords')),
TextInput::make('slug')
->label(__('admin.fields.slug')),
DateTimePicker::make('published_at')
->label(__('admin.fields.published_at'))
->default(now()),
Toggle::make('stick')
->label(__('admin.fields.stick'))
->default(false),
Toggle::make('visible')
->label(__('admin.fields.visible'))
->default(true),
Toggle::make('close_comment')
->label(__('admin.fields.close_comment'))
->default(false),
TextInput::make('read_password')
->label(__('admin.fields.read_password'))
->password(),
Textarea::make('ai_summary')
->label(__('admin.fields.ai_summary'))
->columnSpanFull(),
...Hook::collect('filament.article.form'),
]);
}
}
@@ -0,0 +1,88 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Articles\Tables;
use App\Domain\Plugin\Hook;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class ArticlesTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('category.name')
->label(__('admin.fields.category'))
->searchable(),
TextColumn::make('user.name')
->label(__('admin.fields.author'))
->searchable(),
TextColumn::make('title')
->label(__('admin.fields.title'))
->searchable(),
TextColumn::make('description')
->label(__('admin.fields.description'))
->searchable(),
TextColumn::make('keywords')
->label(__('admin.fields.keywords'))
->searchable(),
TextColumn::make('published_at')
->label(__('admin.fields.published_at'))
->dateTime()
->sortable(),
TextColumn::make('views')
->label(__('admin.fields.views'))
->numeric()
->sortable(),
TextColumn::make('comments_count')
->label(__('admin.fields.comments_count'))
->numeric()
->sortable(),
IconColumn::make('stick')
->label(__('admin.fields.stick'))
->boolean(),
IconColumn::make('visible')
->label(__('admin.fields.visible'))
->boolean(),
IconColumn::make('close_comment')
->label(__('admin.fields.close_comment'))
->boolean(),
TextColumn::make('created_at')
->label(__('admin.fields.created_at'))
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->label(__('admin.fields.updated_at'))
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('slug')
->label(__('admin.fields.slug'))
->searchable(),
TextColumn::make('content_format')
->label(__('admin.fields.content_format'))
->searchable(),
...Hook::collect('filament.article.table.columns'),
])
->filters([
//
])
->recordActions([
EditAction::make(),
...Hook::collect('filament.article.actions'),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}
@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Attachments;
use App\Filament\Resources\Attachments\Pages\CreateAttachment;
use App\Filament\Resources\Attachments\Pages\EditAttachment;
use App\Filament\Resources\Attachments\Pages\ListAttachments;
use App\Filament\Resources\Attachments\Schemas\AttachmentForm;
use App\Filament\Resources\Attachments\Tables\AttachmentsTable;
use App\Models\Attachment;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use App\Filament\Concerns\HasTranslatedLabels;
class AttachmentResource extends Resource
{
use HasTranslatedLabels;
protected static ?string $model = Attachment::class;
protected static function navKey(): string
{
return 'attachments';
}
protected static function modelKey(): string
{
return 'attachment';
}
protected static function groupKey(): string
{
return 'content';
}
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
public static function form(Schema $schema): Schema
{
return AttachmentForm::configure($schema);
}
public static function table(Table $table): Table
{
return AttachmentsTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListAttachments::route('/'),
'create' => CreateAttachment::route('/create'),
'edit' => EditAttachment::route('/{record}/edit'),
];
}
}
@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Attachments\Pages;
use App\Filament\Resources\Attachments\AttachmentResource;
use Filament\Resources\Pages\CreateRecord;
use Illuminate\Support\Facades\Storage;
class CreateAttachment extends CreateRecord
{
protected static string $resource = AttachmentResource::class;
/**
* @param array<string, mixed> $data
* @return array<string, mixed>
*/
protected function mutateFormDataBeforeCreate(array $data): array
{
$disk = config('larablog.attachments_disk', 'attachments');
$path = $data['upload'] ?? null;
unset($data['upload']);
if (! is_string($path) || $path === '') {
throw new \InvalidArgumentException(__('admin.messages.upload_required'));
}
$storage = Storage::disk($disk);
$mime = method_exists($storage, 'mimeType') ? ($storage->mimeType($path) ?: null) : null;
$allowed = config('larablog.allowed_attachment_mimes', []);
if (is_string($mime) && $allowed !== [] && ! in_array($mime, $allowed, true)) {
$storage->delete($path);
throw new \InvalidArgumentException(__('admin.messages.mime_not_allowed', ['mime' => $mime]));
}
$data['disk'] = $disk;
$data['path'] = $path;
$data['filename'] = $data['filename'] ?: basename($path);
$data['mime'] = $mime;
$data['size'] = $storage->size($path) ?: 0;
$data['checksum'] = hash('sha256', (string) $storage->get($path));
$data['synced_at'] = now();
$data['visibility'] = $data['visibility'] ?? 'public';
$data['downloads'] = (int) ($data['downloads'] ?? 0);
return $data;
}
}
@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Attachments\Pages;
use App\Domain\Media\AttachmentStorageService;
use App\Filament\Resources\Attachments\AttachmentResource;
use App\Models\Attachment;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditAttachment extends EditRecord
{
protected static string $resource = AttachmentResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make()
->before(function (Attachment $record, AttachmentStorageService $storage): void {
$storage->deleteFromDisk($record);
}),
];
}
}
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Attachments\Pages;
use App\Filament\Resources\Attachments\AttachmentResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListAttachments extends ListRecords
{
protected static string $resource = AttachmentResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}
@@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Attachments\Schemas;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;
class AttachmentForm
{
public static function configure(Schema $schema): Schema
{
$disk = config('larablog.attachments_disk', 'attachments');
$mimes = config('larablog.allowed_attachment_mimes', []);
return $schema
->components([
Select::make('article_id')
->label(__('admin.fields.article'))
->relationship('article', 'title')
->searchable()
->preload(),
FileUpload::make('upload')
->label(__('admin.fields.upload'))
->disk($disk)
->directory(fn (): string => 'uploads/'.now()->format('Y/m'))
->visibility('public')
->acceptedFileTypes($mimes)
->maxSize(20480)
->required(fn (string $operation): bool => $operation === 'create')
->dehydrated(fn ($state): bool => filled($state))
->helperText(__('admin.helpers.attachment_upload')),
TextInput::make('filename')
->label(__('admin.fields.filename'))
->maxLength(255),
TextInput::make('visibility')
->label(__('admin.fields.visibility'))
->default('public')
->required(),
TextInput::make('legacy_filepath')
->label(__('admin.fields.legacy_filepath'))
->maxLength(255),
TextInput::make('downloads')
->label(__('admin.fields.downloads'))
->numeric()
->default(0)
->disabled()
->dehydrated(),
]);
}
}
@@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Attachments\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class AttachmentsTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('article.title')
->label(__('admin.fields.article'))
->searchable(),
TextColumn::make('disk')
->label(__('admin.fields.disk'))
->searchable(),
TextColumn::make('path')
->label(__('admin.fields.path'))
->searchable(),
TextColumn::make('thumb_path')
->label(__('admin.fields.thumb_path'))
->searchable(),
TextColumn::make('filename')
->label(__('admin.fields.filename'))
->searchable(),
TextColumn::make('mime')
->label(__('admin.fields.mime'))
->searchable(),
TextColumn::make('size')
->label(__('admin.fields.size'))
->numeric()
->sortable(),
TextColumn::make('checksum')
->label(__('admin.fields.checksum'))
->searchable(),
TextColumn::make('visibility')
->label(__('admin.fields.visibility'))
->searchable(),
TextColumn::make('legacy_filepath')
->label(__('admin.fields.legacy_filepath'))
->searchable(),
TextColumn::make('synced_at')
->label(__('admin.fields.synced_at'))
->dateTime()
->sortable(),
TextColumn::make('downloads')
->label(__('admin.fields.downloads'))
->numeric()
->sortable(),
TextColumn::make('created_at')
->label(__('admin.fields.created_at'))
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->label(__('admin.fields.updated_at'))
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}
@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Categories;
use App\Filament\Resources\Categories\Pages\CreateCategory;
use App\Filament\Resources\Categories\Pages\EditCategory;
use App\Filament\Resources\Categories\Pages\ListCategories;
use App\Filament\Resources\Categories\Schemas\CategoryForm;
use App\Filament\Resources\Categories\Tables\CategoriesTable;
use App\Models\Category;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use App\Filament\Concerns\HasTranslatedLabels;
class CategoryResource extends Resource
{
use HasTranslatedLabels;
protected static ?string $model = Category::class;
protected static function navKey(): string
{
return 'categories';
}
protected static function modelKey(): string
{
return 'category';
}
protected static function groupKey(): string
{
return 'content';
}
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
public static function form(Schema $schema): Schema
{
return CategoryForm::configure($schema);
}
public static function table(Table $table): Table
{
return CategoriesTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListCategories::route('/'),
'create' => CreateCategory::route('/create'),
'edit' => EditCategory::route('/{record}/edit'),
];
}
}
@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Categories\Pages;
use App\Filament\Resources\Categories\CategoryResource;
use Filament\Resources\Pages\CreateRecord;
class CreateCategory extends CreateRecord
{
protected static string $resource = CategoryResource::class;
}
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Categories\Pages;
use App\Filament\Resources\Categories\CategoryResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditCategory extends EditRecord
{
protected static string $resource = CategoryResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Categories\Pages;
use App\Filament\Resources\Categories\CategoryResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListCategories extends ListRecords
{
protected static string $resource = CategoryResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Categories\Schemas;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;
class CategoryForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')
->label(__('admin.fields.name'))
->required(),
TextInput::make('display_order')
->label(__('admin.fields.display_order'))
->required()
->numeric()
->default(0),
TextInput::make('articles_count')
->label(__('admin.fields.articles_count'))
->required()
->numeric()
->default(0),
]);
}
}
@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Categories\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class CategoriesTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->label(__('admin.fields.name'))
->searchable(),
TextColumn::make('display_order')
->label(__('admin.fields.display_order'))
->numeric()
->sortable(),
TextColumn::make('articles_count')
->label(__('admin.fields.articles_count'))
->numeric()
->sortable(),
TextColumn::make('created_at')
->label(__('admin.fields.created_at'))
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->label(__('admin.fields.updated_at'))
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}
@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Comments;
use App\Filament\Resources\Comments\Pages\CreateComment;
use App\Filament\Resources\Comments\Pages\EditComment;
use App\Filament\Resources\Comments\Pages\ListComments;
use App\Filament\Resources\Comments\Schemas\CommentForm;
use App\Filament\Resources\Comments\Tables\CommentsTable;
use App\Models\Comment;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use App\Filament\Concerns\HasTranslatedLabels;
class CommentResource extends Resource
{
use HasTranslatedLabels;
protected static ?string $model = Comment::class;
protected static function navKey(): string
{
return 'comments';
}
protected static function modelKey(): string
{
return 'comment';
}
protected static function groupKey(): string
{
return 'content';
}
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
public static function form(Schema $schema): Schema
{
return CommentForm::configure($schema);
}
public static function table(Table $table): Table
{
return CommentsTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListComments::route('/'),
'create' => CreateComment::route('/create'),
'edit' => EditComment::route('/{record}/edit'),
];
}
}
@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Comments\Pages;
use App\Filament\Resources\Comments\CommentResource;
use Filament\Resources\Pages\CreateRecord;
class CreateComment extends CreateRecord
{
protected static string $resource = CommentResource::class;
}
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Comments\Pages;
use App\Filament\Resources\Comments\CommentResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditComment extends EditRecord
{
protected static string $resource = CommentResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Comments\Pages;
use App\Filament\Resources\Comments\CommentResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListComments extends ListRecords
{
protected static string $resource = CommentResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}
@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Comments\Schemas;
use App\Models\Comment;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Textarea;
use Filament\Schemas\Schema;
class CommentForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
Select::make('article_id')
->label(__('admin.fields.article'))
->relationship('article', 'title')
->required(),
TextInput::make('author')
->label(__('admin.fields.author'))
->required(),
TextInput::make('url')
->label(__('admin.fields.url'))
->url(),
Textarea::make('content')
->label(__('admin.fields.content'))
->required()
->columnSpanFull(),
TextInput::make('ip')
->label(__('admin.fields.ip')),
Select::make('moderation_status')
->label(__('admin.fields.moderation_status'))
->options([
Comment::STATUS_PENDING => __('admin.options.moderation.pending'),
Comment::STATUS_PENDING_AI => __('admin.options.moderation.pending_ai'),
Comment::STATUS_APPROVED => __('admin.options.moderation.approved'),
Comment::STATUS_REJECTED => __('admin.options.moderation.rejected'),
Comment::STATUS_NEEDS_HUMAN => __('admin.options.moderation.needs_human'),
])
->required()
->default(Comment::STATUS_PENDING),
DateTimePicker::make('published_at')
->label(__('admin.fields.published_at')),
]);
}
}
@@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Comments\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class CommentsTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('article.title')
->label(__('admin.fields.article'))
->searchable(),
TextColumn::make('author')
->label(__('admin.fields.author'))
->searchable(),
TextColumn::make('url')
->label(__('admin.fields.url'))
->searchable(),
TextColumn::make('ip')
->label(__('admin.fields.ip'))
->searchable(),
TextColumn::make('moderation_status')
->label(__('admin.fields.moderation_status'))
->searchable(),
TextColumn::make('published_at')
->label(__('admin.fields.published_at'))
->dateTime()
->sortable(),
TextColumn::make('created_at')
->label(__('admin.fields.created_at'))
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->label(__('admin.fields.updated_at'))
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}
@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Links;
use App\Filament\Resources\Links\Pages\CreateLink;
use App\Filament\Resources\Links\Pages\EditLink;
use App\Filament\Resources\Links\Pages\ListLinks;
use App\Filament\Resources\Links\Schemas\LinkForm;
use App\Filament\Resources\Links\Tables\LinksTable;
use App\Models\Link;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use App\Filament\Concerns\HasTranslatedLabels;
class LinkResource extends Resource
{
use HasTranslatedLabels;
protected static ?string $model = Link::class;
protected static function navKey(): string
{
return 'links';
}
protected static function modelKey(): string
{
return 'link';
}
protected static function groupKey(): string
{
return 'content';
}
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
public static function form(Schema $schema): Schema
{
return LinkForm::configure($schema);
}
public static function table(Table $table): Table
{
return LinksTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListLinks::route('/'),
'create' => CreateLink::route('/create'),
'edit' => EditLink::route('/{record}/edit'),
];
}
}
@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Links\Pages;
use App\Filament\Resources\Links\LinkResource;
use Filament\Resources\Pages\CreateRecord;
class CreateLink extends CreateRecord
{
protected static string $resource = LinkResource::class;
}
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Links\Pages;
use App\Filament\Resources\Links\LinkResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditLink extends EditRecord
{
protected static string $resource = LinkResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Links\Pages;
use App\Filament\Resources\Links\LinkResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListLinks extends ListRecords
{
protected static string $resource = LinkResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}
@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Links\Schemas;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Schema;
class LinkForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')
->label(__('admin.fields.name'))
->required(),
TextInput::make('url')
->label(__('admin.fields.url'))
->url()
->required(),
Textarea::make('note')
->label(__('admin.fields.note'))
->columnSpanFull(),
TextInput::make('display_order')
->label(__('admin.fields.display_order'))
->required()
->numeric()
->default(0),
Toggle::make('visible')
->label(__('admin.fields.visible'))
->required(),
]);
}
}
@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Links\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class LinksTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->label(__('admin.fields.name'))
->searchable(),
TextColumn::make('url')
->label(__('admin.fields.url'))
->searchable(),
TextColumn::make('display_order')
->label(__('admin.fields.display_order'))
->numeric()
->sortable(),
IconColumn::make('visible')
->label(__('admin.fields.visible'))
->boolean(),
TextColumn::make('created_at')
->label(__('admin.fields.created_at'))
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->label(__('admin.fields.updated_at'))
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}
@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Plugins\Pages;
use App\Filament\Resources\Plugins\PluginResource;
use Filament\Resources\Pages\CreateRecord;
class CreatePlugin extends CreateRecord
{
protected static string $resource = PluginResource::class;
}
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Plugins\Pages;
use App\Filament\Resources\Plugins\PluginResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditPlugin extends EditRecord
{
protected static string $resource = PluginResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Plugins\Pages;
use App\Filament\Resources\Plugins\PluginResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListPlugins extends ListRecords
{
protected static string $resource = PluginResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}
@@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Plugins;
use App\Filament\Resources\Plugins\Pages\CreatePlugin;
use App\Filament\Resources\Plugins\Pages\EditPlugin;
use App\Filament\Resources\Plugins\Pages\ListPlugins;
use App\Filament\Resources\Plugins\Schemas\PluginForm;
use App\Filament\Resources\Plugins\Tables\PluginsTable;
use App\Models\Plugin;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
class PluginResource extends Resource
{
protected static ?string $model = Plugin::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedPuzzlePiece;
protected static bool $shouldRegisterNavigation = false;
public static function canCreate(): bool
{
return false;
}
public static function form(Schema $schema): Schema
{
return PluginForm::configure($schema);
}
public static function table(Table $table): Table
{
return PluginsTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListPlugins::route('/'),
'create' => CreatePlugin::route('/create'),
'edit' => EditPlugin::route('/{record}/edit'),
];
}
}
@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Plugins\Schemas;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Schema;
class PluginForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')
->label(__('admin.fields.name'))
->required(),
TextInput::make('version')
->label(__('admin.fields.version'))
->required()
->default('1.0.0'),
Toggle::make('enabled')
->label(__('admin.fields.enabled'))
->required(),
TextInput::make('path')
->label(__('admin.fields.path'))
->required(),
Textarea::make('config')
->label(__('admin.fields.config'))
->columnSpanFull(),
]);
}
}
@@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Plugins\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class PluginsTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->label(__('admin.fields.name'))
->searchable(),
TextColumn::make('version')
->label(__('admin.fields.version'))
->searchable(),
IconColumn::make('enabled')
->label(__('admin.fields.enabled'))
->boolean(),
TextColumn::make('path')
->label(__('admin.fields.path'))
->searchable(),
TextColumn::make('created_at')
->label(__('admin.fields.created_at'))
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->label(__('admin.fields.updated_at'))
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}
@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Stylevars\Pages;
use App\Filament\Resources\Stylevars\StylevarResource;
use Filament\Resources\Pages\CreateRecord;
class CreateStylevar extends CreateRecord
{
protected static string $resource = StylevarResource::class;
}
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Stylevars\Pages;
use App\Filament\Resources\Stylevars\StylevarResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditStylevar extends EditRecord
{
protected static string $resource = StylevarResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Stylevars\Pages;
use App\Filament\Resources\Stylevars\StylevarResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListStylevars extends ListRecords
{
protected static string $resource = StylevarResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Stylevars\Schemas;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Schema;
class StylevarForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('title')
->label(__('admin.fields.title'))
->required()
->maxLength(120),
Textarea::make('value')
->label(__('admin.fields.value'))
->rows(8)
->columnSpanFull(),
Toggle::make('visible')
->label(__('admin.fields.visible'))
->default(true),
]);
}
}
@@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Stylevars;
use App\Filament\Resources\Stylevars\Pages\CreateStylevar;
use App\Filament\Resources\Stylevars\Pages\EditStylevar;
use App\Filament\Resources\Stylevars\Pages\ListStylevars;
use App\Filament\Resources\Stylevars\Schemas\StylevarForm;
use App\Filament\Resources\Stylevars\Tables\StylevarsTable;
use App\Models\Stylevar;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use UnitEnum;
use App\Filament\Concerns\HasTranslatedLabels;
class StylevarResource extends Resource
{
use HasTranslatedLabels;
protected static ?string $model = Stylevar::class;
protected static function navKey(): string
{
return 'stylevars';
}
protected static function modelKey(): string
{
return 'stylevar';
}
protected static function groupKey(): string
{
return 'content';
}
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedDocumentText;
public static function form(Schema $schema): Schema
{
return StylevarForm::configure($schema);
}
public static function table(Table $table): Table
{
return StylevarsTable::configure($table);
}
public static function getPages(): array
{
return [
'index' => ListStylevars::route('/'),
'create' => CreateStylevar::route('/create'),
'edit' => EditStylevar::route('/{record}/edit'),
];
}
}
@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Stylevars\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class StylevarsTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('id')
->label(__('admin.fields.id'))
->sortable(),
TextColumn::make('title')
->label(__('admin.fields.title'))
->searchable()
->sortable(),
TextColumn::make('value')
->label(__('admin.fields.value'))
->limit(60),
IconColumn::make('visible')
->label(__('admin.fields.visible'))
->boolean(),
TextColumn::make('updated_at')
->label(__('admin.fields.updated_at'))
->dateTime()
->sortable(),
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}
@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Tags\Pages;
use App\Filament\Resources\Tags\TagResource;
use Filament\Resources\Pages\CreateRecord;
class CreateTag extends CreateRecord
{
protected static string $resource = TagResource::class;
}
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Tags\Pages;
use App\Filament\Resources\Tags\TagResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditTag extends EditRecord
{
protected static string $resource = TagResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Tags\Pages;
use App\Filament\Resources\Tags\TagResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListTags extends ListRecords
{
protected static string $resource = TagResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}
@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Tags\Schemas;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;
class TagForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')
->label(__('admin.fields.name'))
->required(),
TextInput::make('use_count')
->label(__('admin.fields.use_count'))
->required()
->numeric()
->default(0),
]);
}
}
@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Tags\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class TagsTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->label(__('admin.fields.name'))
->searchable(),
TextColumn::make('use_count')
->label(__('admin.fields.use_count'))
->numeric()
->sortable(),
TextColumn::make('created_at')
->label(__('admin.fields.created_at'))
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->label(__('admin.fields.updated_at'))
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}
@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Tags;
use App\Filament\Resources\Tags\Pages\CreateTag;
use App\Filament\Resources\Tags\Pages\EditTag;
use App\Filament\Resources\Tags\Pages\ListTags;
use App\Filament\Resources\Tags\Schemas\TagForm;
use App\Filament\Resources\Tags\Tables\TagsTable;
use App\Models\Tag;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use App\Filament\Concerns\HasTranslatedLabels;
class TagResource extends Resource
{
use HasTranslatedLabels;
protected static ?string $model = Tag::class;
protected static function navKey(): string
{
return 'tags';
}
protected static function modelKey(): string
{
return 'tag';
}
protected static function groupKey(): string
{
return 'content';
}
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
public static function form(Schema $schema): Schema
{
return TagForm::configure($schema);
}
public static function table(Table $table): Table
{
return TagsTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListTags::route('/'),
'create' => CreateTag::route('/create'),
'edit' => EditTag::route('/{record}/edit'),
];
}
}
@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Users\Pages;
use App\Filament\Resources\Users\UserResource;
use Filament\Resources\Pages\CreateRecord;
class CreateUser extends CreateRecord
{
protected static string $resource = UserResource::class;
}
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Users\Pages;
use App\Filament\Resources\Users\UserResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditUser extends EditRecord
{
protected static string $resource = UserResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}
@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Users\Pages;
use App\Filament\Resources\Users\UserResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListUsers extends ListRecords
{
protected static string $resource = UserResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}
@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Users\Schemas;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;
class UserForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')
->label(__('admin.fields.display_name'))
->required()
->maxLength(120),
TextInput::make('username')
->label(__('admin.fields.username'))
->required()
->maxLength(40)
->unique(ignoreRecord: true),
TextInput::make('email')
->label(__('admin.fields.email'))
->email()
->maxLength(120)
->unique(ignoreRecord: true),
TextInput::make('url')
->label(__('admin.fields.website'))
->url()
->maxLength(255),
TextInput::make('password')
->label(__('admin.fields.password'))
->password()
->revealable()
->dehydrated(fn (?string $state): bool => filled($state))
->required(fn (string $operation): bool => $operation === 'create'),
Select::make('roles')
->label(__('admin.fields.roles'))
->multiple()
->relationship('roles', 'name')
->preload(),
]);
}
}
@@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Users\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class UsersTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('id')
->label(__('admin.fields.id'))
->sortable(),
TextColumn::make('username')
->label(__('admin.fields.username'))
->searchable()
->sortable(),
TextColumn::make('name')
->label(__('admin.fields.display_name'))
->searchable(),
TextColumn::make('email')
->label(__('admin.fields.email'))
->searchable(),
TextColumn::make('roles.name')
->badge()
->label(__('admin.fields.roles')),
TextColumn::make('login_at')
->label(__('admin.fields.login_at'))
->dateTime()
->sortable(),
TextColumn::make('created_at')
->label(__('admin.fields.created_at'))
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}
@@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
namespace App\Filament\Resources\Users;
use App\Filament\Resources\Users\Pages\CreateUser;
use App\Filament\Resources\Users\Pages\EditUser;
use App\Filament\Resources\Users\Pages\ListUsers;
use App\Filament\Resources\Users\Schemas\UserForm;
use App\Filament\Resources\Users\Tables\UsersTable;
use App\Models\User;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use UnitEnum;
use App\Filament\Concerns\HasTranslatedLabels;
class UserResource extends Resource
{
use HasTranslatedLabels;
protected static ?string $model = User::class;
protected static function navKey(): string
{
return 'users';
}
protected static function modelKey(): string
{
return 'user';
}
protected static function groupKey(): string
{
return 'system';
}
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedUsers;
public static function form(Schema $schema): Schema
{
return UserForm::configure($schema);
}
public static function table(Table $table): Table
{
return UsersTable::configure($table);
}
public static function getPages(): array
{
return [
'index' => ListUsers::route('/'),
'create' => CreateUser::route('/create'),
'edit' => EditUser::route('/{record}/edit'),
];
}
}