components([ Section::make() ->columns(2) ->schema([ TextInput::make('name') ->label(__('panel.members.fields.name')) ->required() ->maxLength(255) ->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.members.fields.slug')) ->required() ->maxLength(255) ->rules(fn ($record) => [Rule::unique('members', 'slug')->ignore($record?->id)]), FileUpload::make('avatar') ->label(__('panel.members.fields.avatar')) ->image() ->avatar() // Explicit: the default disk is private, and the // frontend runs on another host. ->disk(config('media.disk')) ->directory('members') ->imageEditor() // A portrait is described by the person's name, so // there is no alt field here to fill in wrong. ->helperText(__('panel.members.fields.avatar_hint')), // The link that makes commit attribution and the git // integration line up with a real person. TextInput::make('github_username') ->label(__('panel.members.fields.github_username')) ->prefix('github.com/') ->maxLength(120), Select::make('user_id') ->label(__('panel.members.fields.user')) ->relationship('user', 'name') ->searchable() ->preload() ->helperText(__('panel.members.fields.user_hint')), Select::make('technologies') ->label(__('panel.members.fields.technologies')) ->relationship('technologies', 'name') ->multiple() ->preload() ->searchable(), ]), Section::make(__('panel.members.sections.profile')) ->description(__('panel.members.sections.profile_hint')) ->schema([ TranslatableTabs::make(fn (string $locale, bool $isDefault) => [ TextInput::make("headline.{$locale}") ->label(__('panel.members.fields.headline')) ->maxLength(255) ->columnSpanFull(), Textarea::make("bio.{$locale}") ->label(__('panel.members.fields.bio')) ->rows(5) ->columnSpanFull(), ]), ]), Section::make(__('panel.members.sections.membership')) ->columns(3) ->schema([ Toggle::make('is_public') ->label(__('panel.members.fields.is_public')) ->default(true), Toggle::make('is_founder') ->label(__('panel.members.fields.is_founder')), TextInput::make('position') ->label(__('panel.members.fields.position')) ->numeric() ->default(0), DatePicker::make('joined_at') ->label(__('panel.members.fields.joined_at')), // Leaving hides them from the current roster without // erasing the work they did. DatePicker::make('left_at') ->label(__('panel.members.fields.left_at')) ->helperText(__('panel.members.fields.left_at_hint')), ]), ]); } }