schema([ Section::make('Basic Information') ->schema([ FileUpload::make('hero_section.background') ->image() ->disk('public') ->directory('product-pages/hero') ->required() ->label('Background Image'), TextInput::make('hero_section.title') ->required() ->live(onBlur: true) ->label('Title') ->afterStateUpdated(function ($state, callable $set) { $set('hero_section.slug', \Str::slug($state)); $set('seo.title', $state); }), TextInput::make('hero_section.slug') ->required() ->unique( table: 'ext_product_page_builder', column: 'hero_section->slug', ignorable: fn ($record) => $record ) ->label('URL Slug'), RichEditor::make('hero_section.description') ->required() ->label('Description') ->afterStateUpdated(function ($state, callable $set) { $set('seo.description', strip_tags($state)); }), Select::make('category_id') ->label('Category') ->options(Category::all()->pluck('name', 'id')) ->required(), ]) ->collapsible(), Section::make('SEO Settings') ->schema([ TextInput::make('seo.title') ->label('SEO Title') ->placeholder('Will use Basic Information title if left empty'), TextInput::make('seo.url') ->label('Canonical URL') ->placeholder('Auto-generated from slug') ->dehydrated(false) ->disabled() ->formatStateUsing(fn ($record) => $record ? url('/product/' . ($record->hero_section['slug'] ?? '')) : '' ), FileUpload::make('seo.banner') ->image() ->disk('public') ->directory('product-pages/seo') ->label('Social Media Banner'), Textarea::make('seo.description') ->label('SEO Description') ->placeholder('Will use Basic Information description if left empty') ->rows(3), /* ================================================================================== This only work if you inside themes/default/views/layouts/app.blade.php {{-- @isset($keywords) @endisset --}} delete {{-- and --}} and also in extension/Others/ProductPageBuilder/resources/views/show.blade.php {{-- {{ is_array($page->seo['keywords'] ?? null) ? implode(', ', $page->seo['keywords']) : ($page->seo['keywords'] ?? '') }} --}} delete {{-- and --}} TagsInput::make('seo.keywords') ->label('SEO Keywords') ->placeholder('Add keywords and press enter') ->separator(','), ================================================================================== */ ]) ->collapsible(), Section::make('Features') ->schema([ Repeater::make('features') ->collapsible() ->schema([ Select::make('icon_type') ->label('Icon Type') ->options([ 'image' => 'Image', 'svg' => 'SVG', ]) ->default('image') ->required() ->reactive() ->formatStateUsing(function ($state, $record) { if (!empty($state)) { return $state; } if (!empty($record['icon_svg'])) { return 'svg'; } if (!empty($record['icon'])) { return 'image'; } return 'image'; }), Textarea::make('icon_svg') ->label('SVG Code') ->rows(5) ->placeholder('...') ->visible(fn ($get) => $get('icon_type') === 'svg'), FileUpload::make('icon') ->directory('product-pages/features') ->visible(fn ($get) => $get('icon_type') === 'image'), TextInput::make('title'), // ->required(), RichEditor::make('description'), // ->required(), Toggle::make('is_active') ->default(true), ]), // ->required() ]) ->collapsible(), Section::make('Game Preview') ->schema([ Repeater::make('game_preview') ->maxItems(1) ->schema([ TextInput::make('title'), // ->required(), RichEditor::make('description'), // ->required(), TextInput::make('youtube_embed') // ->required() ->placeholder('e.g. https://www.youtube.com/embed/xxxxx'), Toggle::make('is_active') ->default(true), ]), // ->required() ]) ->collapsible(), Section::make('Game Panel') ->schema([ Repeater::make('game_panel') ->maxItems(1) ->schema([ TextInput::make('title'), // ->required(), RichEditor::make('description'), // ->required(), FileUpload::make('gallery') // ->required() ->multiple() ->directory('product-pages/gallery'), TagsInput::make('features') ->label('Panel Features') ->placeholder('Add feature and press enter') ->separator(','), Toggle::make('is_active') ->default(true), ]), // ->required() ]) ->collapsible(), Section::make('FAQs') ->schema([ Repeater::make('faqs') ->collapsible() ->schema([ TextInput::make('question'), // ->required(), RichEditor::make('answer'), // ->required(), Toggle::make('is_active') ->default(true), ]), // ->required() ]) ->collapsible(), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('updated_at') ->label('Last Updated') ->dateTime() ->sortable(), Tables\Columns\TextColumn::make('hero_section.title') ->label('Title'), Tables\Columns\TextColumn::make('hero_section.slug') ->label('Slug'), ]) ->actions([ Tables\Actions\EditAction::make(), Tables\Actions\ViewAction::make() ->url(fn ($record) => "/games/{$record->hero_section['slug']}") ->openUrlInNewTab(), Tables\Actions\DeleteAction::make(), ]) /* ->headerActions([ Tables\Actions\CreateAction::make() ->label('Create Product Page') ])*/ ->defaultSort('updated_at', 'desc'); } public static function getPages(): array { return [ 'index' => Pages\ListProductPages::route('/'), 'create' => Pages\CreateProductPage::route('/create'), 'edit' => Pages\EditProductPage::route('/{record}/edit'), ]; } }