columns(3) ->components([ Section::make('Content') ->columnSpan(2) ->components([ TextInput::make('title') ->required() ->live(onBlur: true) ->afterStateUpdated(function (string $operation, $state, callable $set) { if ($operation === 'create') { $set('slug', Str::slug($state)); } }), TextInput::make('slug') ->required() ->unique(Post::class, 'slug', ignoreRecord: true) ->helperText('Used in the URL, e.g. /blog/your-slug'), Textarea::make('excerpt') ->rows(2) ->maxLength(255) ->helperText('Short summary shown in listings. Falls back to the start of the post.'), MarkdownEditor::make('body') ->required() ->columnSpanFull(), ]), Section::make('Publishing') ->columnSpan(1) ->components([ Select::make('status') ->options(PostStatus::class) ->default(PostStatus::Draft) ->required() ->live(), DateTimePicker::make('published_at') ->default(now()) ->helperText('Post is only public once this is in the past.'), Select::make('user_id') ->label('Author') ->relationship('user', 'name') ->searchable() ->preload() ->required(), Select::make('category_id') ->label('Category') ->relationship('category', 'name') ->searchable() ->preload(), Select::make('tags') ->relationship('tags', 'name') ->multiple() ->searchable() ->preload() ->createOptionForm([ TextInput::make('name')->required(), ]), FileUpload::make('featured_image') ->image() ->disk('public') ->directory('posts') ->imageEditor(), ]), Section::make('SEO') ->description('Optional overrides for search engines and social sharing.') ->columnSpan(3) ->columns(2) ->collapsible() ->components([ TextInput::make('meta_title') ->maxLength(60) ->helperText('Falls back to the post title if left blank.'), TextInput::make('meta_description') ->maxLength(160) ->helperText('Falls back to the excerpt if left blank.'), ]), ]); } }