components([ Section::make() ->columns(2) ->schema([ TextInput::make('name') ->label(__('panel.technologies.fields.name')) ->required() ->maxLength(120) ->live(onBlur: true) ->afterStateUpdated(function (?string $state, callable $get, callable $set) { if (blank($get('slug'))) { $set('slug', Str::slug((string) $state)); } }), TextInput::make('slug') ->label(__('panel.technologies.fields.slug')) ->required() ->maxLength(120) ->rules(fn ($record) => [Rule::unique('technologies', 'slug')->ignore($record?->id)]), Select::make('category') ->label(__('panel.technologies.fields.category')) ->options(TechnologyCategory::class) ->default(TechnologyCategory::Tool) ->required(), // Leaving the ring empty keeps a technology usable as a tag // without putting it on the public radar. Select::make('radar_ring') ->label(__('panel.technologies.fields.radar_ring')) ->options(RadarRing::class) ->helperText(__('panel.technologies.fields.radar_ring_hint')) ->placeholder(__('panel.technologies.off_radar')), ColorPicker::make('color')->label(__('panel.technologies.fields.color')), // A file rather than the name of an icon from a set the // frontend may or may not bundle. FileUpload::make('logo') ->label(__('panel.technologies.fields.logo')) ->helperText(__('panel.technologies.fields.logo_hint')) ->image() ->disk(config('media.disk')) ->directory('technologies') ->columnSpanFull(), TextInput::make('website') ->label(__('panel.technologies.fields.website')) ->url() ->maxLength(2048), TextInput::make('position') ->label(__('panel.technologies.fields.position')) ->numeric() ->default(0), ]), Section::make(__('panel.technologies.sections.prose')) ->collapsed() ->schema([ TranslatableTabs::make(fn (string $locale) => [ Textarea::make("description.{$locale}") ->label(__('panel.technologies.fields.description')) ->rows(3) ->columnSpanFull(), // Why this sits in that ring. The part of a tech radar // people actually read. Textarea::make("radar_note.{$locale}") ->label(__('panel.technologies.fields.radar_note')) ->helperText(__('panel.technologies.fields.radar_note_hint')) ->rows(3) ->columnSpanFull(), ], label: __('panel.technologies.sections.prose')), ]), ]); } public static function table(Table $table): Table { return $table ->defaultSort('name') ->columns([ ImageColumn::make('logo') ->label('') ->disk(config('media.disk')) ->height(24), ColorColumn::make('color')->label(''), TextColumn::make('name') ->label(__('panel.technologies.fields.name')) ->weight('medium') ->searchable() ->sortable(), TextColumn::make('category') ->label(__('panel.technologies.fields.category')) ->badge() ->sortable(), TextColumn::make('radar_ring') ->label(__('panel.technologies.fields.radar_ring')) ->badge() ->placeholder(__('panel.technologies.off_radar')) ->sortable(), TextColumn::make('projects_count') ->label(__('panel.technologies.fields.projects')) ->counts('projects') ->badge() ->color('gray'), TextColumn::make('members_count') ->label(__('panel.technologies.fields.members')) ->counts('members') ->badge() ->color('gray'), ]) ->filters([ SelectFilter::make('category') ->label(__('panel.technologies.fields.category')) ->options(TechnologyCategory::options()) ->multiple(), SelectFilter::make('radar_ring') ->label(__('panel.technologies.fields.radar_ring')) ->options(RadarRing::options()) ->multiple(), ]) ->recordActions([ EditAction::make(), DeleteAction::make(), ]) ->toolbarActions([ BulkActionGroup::make([DeleteBulkAction::make()]), ]); } /** * @return array */ public static function getGloballySearchableAttributes(): array { return ['name']; } public static function getRelations(): array { return [ RevisionsRelationManager::class, ]; } public static function getPages(): array { return [ 'index' => ListTechnologies::route('/'), 'create' => CreateTechnology::route('/create'), 'edit' => EditTechnology::route('/{record}/edit'), ]; } }