├── LICENSE.md ├── README.md ├── composer.json ├── composer.lock ├── pint.json ├── resources ├── lang │ └── en │ │ └── quick-create.php └── views │ └── components │ └── create-menu.blade.php └── src ├── Components └── QuickCreateMenu.php ├── QuickCreatePlugin.php └── QuickCreateServiceProvider.php /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) awcodes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Quick Create for Filament 2 | 3 | Plugin for [Filament Admin Panel](https://filamentphp.com) that adds a dropdown menu to the header to quickly create new items from anywhere in your app. 4 | 5 | ![quick-create-og](https://res.cloudinary.com/aw-codes/image/upload/w_1200,f_auto,q_auto/plugins/quick-create/awcodes-quick-create.jpg) 6 | 7 | ## Installation 8 | 9 | Install the package via composer 10 | 11 | ```bash 12 | composer require awcodes/filament-quick-create 13 | ``` 14 | 15 | In an effort to align with Filament's theming methodology you will need to use a custom theme to use this plugin. 16 | 17 | > **Note** 18 | > If you have not set up a custom theme and are using a Panel follow the instructions in the [Filament Docs](https://filamentphp.com/docs/3.x/panels/themes#creating-a-custom-theme) first. The following applies to both the Panels Package and the standalone Forms package. 19 | 20 | Add the plugin's views to your `tailwind.config.js` file. 21 | 22 | ```js 23 | content: [ 24 | '/awcodes/filament-quick-create/resources/**/*.blade.php', 25 | ] 26 | ``` 27 | 28 | ## Usage 29 | 30 | By default, Quick Create will use all resources that are registered with current Filament context. All resources will follow the authorization used by Filament, meaning that if a user doesn't have permission to create a record it will not be listed in the dropdown. 31 | 32 | ### Registering the plugin 33 | 34 | ```php 35 | use Awcodes\FilamentQuickCreate\QuickCreatePlugin; 36 | 37 | public function panel(Panel $panel): Panel 38 | { 39 | return $panel 40 | ->plugins([ 41 | QuickCreatePlugin::make(), 42 | ]) 43 | } 44 | ``` 45 | 46 | > **Warning** 47 | > Excludes and includes are not meant to work together. You should use one or the other, but not both. 48 | 49 | ### Excluding Resources 50 | 51 | Excluding resources will filter them out of the registered resources to prevent them from displaying in the dropdown. 52 | 53 | ```php 54 | use Awcodes\FilamentQuickCreate\QuickCreatePlugin; 55 | 56 | public function panel(Panel $panel): Panel 57 | { 58 | return $panel 59 | ->plugins([ 60 | QuickCreatePlugin::make() 61 | ->excludes([ 62 | \App\Filament\Resources\UserResource::class, 63 | ]), 64 | ]) 65 | } 66 | ``` 67 | 68 | ### Including Resources 69 | 70 | Sometimes, it might be easier to only include some resources instead of filtering them out. For instance, you have 30 resources but only want to display 3 to 4 in the dropdown. 71 | 72 | ```php 73 | use Awcodes\FilamentQuickCreate\QuickCreatePlugin; 74 | 75 | public function panel(Panel $panel): Panel 76 | { 77 | return $panel 78 | ->plugins([ 79 | QuickCreatePlugin::make() 80 | ->includes([ 81 | \App\Filament\Resources\UserResource::class, 82 | ]), 83 | ]) 84 | } 85 | ``` 86 | 87 | ### Sorting 88 | 89 | By default, Quick Create will sort all the displayed options in descending order by Label. This can be disabled should you choose. In which case they will be displayed in the order they are registered with Filament. 90 | 91 | ```php 92 | use Awcodes\FilamentQuickCreate\QuickCreatePlugin; 93 | 94 | public function panel(Panel $panel): Panel 95 | { 96 | return $panel 97 | ->plugins([ 98 | QuickCreatePlugin::make() 99 | ->sort(false), 100 | ]) 101 | } 102 | ``` 103 | 104 | ### Sorting by resource navigation 105 | 106 | By default, Quick Create will sort all the displayed options by Label. This can be changed to resource navigation sort should you choose. In which case they will be displayed in the order they are displayed in the navigation. 107 | 108 | ```php 109 | use Awcodes\FilamentQuickCreate\QuickCreatePlugin; 110 | 111 | public function panel(Panel $panel): Panel 112 | { 113 | return $panel 114 | ->plugins([ 115 | QuickCreatePlugin::make() 116 | ->sortBy('navigation'), 117 | ]) 118 | } 119 | ``` 120 | 121 | ### Registering keybindings 122 | 123 | You can attach keyboard shortcuts to trigger the Quick Create dropdown. To configure these, pass the keyBindings() method to the configuration: 124 | 125 | ```php 126 | use Awcodes\FilamentQuickCreate\QuickCreatePlugin; 127 | 128 | public function panel(Panel $panel): Panel 129 | { 130 | return $panel 131 | ->plugins([ 132 | QuickCreatePlugin::make() 133 | ->keyBindings(['command+shift+a', 'ctrl+shift+a']), 134 | ]) 135 | } 136 | ``` 137 | 138 | ### Create Another 139 | 140 | By default, the ability to create another record will respect the settings of your 'create record' or 'list records' create action. This can be overridden to either enable or disable it for all resources with the `createAnother()` method. 141 | 142 | ```php 143 | use Awcodes\FilamentQuickCreate\QuickCreatePlugin; 144 | 145 | public function panel(Panel $panel): Panel 146 | { 147 | return $panel 148 | ->plugins([ 149 | QuickCreatePlugin::make() 150 | ->createAnother(false), 151 | ]) 152 | } 153 | ``` 154 | 155 | ### Appearance 156 | 157 | #### Rounded 158 | 159 | By default, the Quick Create button will be fully rounded if you would like to have a more square button you can disable the rounding with the `rounded()` method. 160 | 161 | ```php 162 | use Awcodes\FilamentQuickCreate\QuickCreatePlugin; 163 | 164 | public function panel(Panel $panel): Panel 165 | { 166 | return $panel 167 | ->plugins([ 168 | QuickCreatePlugin::make() 169 | ->rounded(false), 170 | ]) 171 | } 172 | ``` 173 | 174 | #### Hiding Icons 175 | 176 | If you prefer to not show icons for the items in the menu you can disable them with the `hiddenIcons()` method. 177 | 178 | ```php 179 | use Awcodes\FilamentQuickCreate\QuickCreatePlugin; 180 | 181 | public function panel(Panel $panel): Panel 182 | { 183 | return $panel 184 | ->plugins([ 185 | QuickCreatePlugin::make() 186 | ->hiddenIcons(), 187 | ]) 188 | } 189 | ``` 190 | 191 | #### Setting a label 192 | 193 | If you prefer to show a label with the plus icon you can set it using the `label()` method and passing your label to it. 194 | 195 | ```php 196 | use Awcodes\FilamentQuickCreate\QuickCreatePlugin; 197 | 198 | public function panel(Panel $panel): Panel 199 | { 200 | return $panel 201 | ->plugins([ 202 | QuickCreatePlugin::make() 203 | ->label('New'), 204 | ]) 205 | } 206 | ``` 207 | 208 | ### Slide Overs 209 | 210 | By default, Quick Create will render simple resources in a standard modal. If you would like to render them in a slide over instead you may use the `slideOver()` modifier to do so. 211 | 212 | ```php 213 | use Awcodes\FilamentQuickCreate\QuickCreatePlugin; 214 | 215 | public function panel(Panel $panel): Panel 216 | { 217 | return $panel 218 | ->plugins([ 219 | QuickCreatePlugin::make() 220 | ->slideOver(), 221 | ]) 222 | } 223 | ``` 224 | 225 | ### Hiding Quick Create 226 | 227 | By default, Quick Create is visible if there are registered resources. If you would like to hide it you may use the `hidden()` modifier to do so. 228 | 229 | ```php 230 | use Awcodes\FilamentQuickCreate\QuickCreatePlugin; 231 | 232 | public function panel(Panel $panel): Panel 233 | { 234 | return $panel 235 | ->plugins([ 236 | QuickCreatePlugin::make() 237 | ->hidden(fn() => Filament::getTenant()->requiresOnboarding()), 238 | ]) 239 | } 240 | ``` 241 | 242 | ### Render Plugin on a Custom Panel Hook 243 | 244 | By default, Quick Create plugin renders using `'panels::user-menu.before'` Filament Panel Render Hook. If you would like to customize this to render at a different render hook, you may use the `renderUsingHook(string $panelHook)` modifier to do so. You may read about the available Render Hooks in Filament PHP [here](https://filamentphp.com/docs/3.x/support/render-hooks#available-render-hooks) 245 | 246 | ```php 247 | use Awcodes\FilamentQuickCreate\QuickCreatePlugin; 248 | use Filament\View\PanelsRenderHook; 249 | 250 | public function panel(Panel $panel): Panel 251 | { 252 | return $panel 253 | ->plugins([ 254 | QuickCreatePlugin::make() 255 | ->renderUsingHook(PanelsRenderHook::SIDEBAR_NAV_END), 256 | ]) 257 | } 258 | ``` 259 | 260 | ### Forcing all resources to use modals 261 | 262 | Quick create will automatically determine if it should redirect to a create page or to show the form in a modal based on the resource. If you prefer to force all items to be show in a modal you can do so with the `alwaysShowModal()` modifier. 263 | 264 | ```php 265 | use Awcodes\FilamentQuickCreate\QuickCreatePlugin; 266 | 267 | public function panel(Panel $panel): Panel 268 | { 269 | return $panel 270 | ->plugins([ 271 | QuickCreatePlugin::make() 272 | ->alwaysShowModal(), 273 | ]) 274 | } 275 | ``` 276 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "awcodes/filament-quick-create", 3 | "description": "Plugin for Filament Admin that adds a dropdown menu to the header to quickly create new items.", 4 | "keywords": [ 5 | "framework", 6 | "laravel", 7 | "filament" 8 | ], 9 | "license": "MIT", 10 | "authors": [ 11 | { 12 | "name": "Adam Weston", 13 | "email": "awcodes1@gmail.com", 14 | "role": "Developer" 15 | } 16 | ], 17 | "require": { 18 | "php": "^8.1", 19 | "filament/filament": "^v3.2.23", 20 | "spatie/laravel-package-tools": "^1.15.0" 21 | }, 22 | "require-dev": { 23 | "laravel/pint": "^1.0", 24 | "spatie/laravel-ray": "^1.26" 25 | }, 26 | "autoload": { 27 | "psr-4": { 28 | "Awcodes\\FilamentQuickCreate\\": "src/" 29 | } 30 | }, 31 | "autoload-dev": { 32 | "psr-4": { 33 | "Awcodes\\FilamentQuickCreate\\Tests\\": "tests/" 34 | } 35 | }, 36 | "extra": { 37 | "laravel": { 38 | "providers": [ 39 | "Awcodes\\FilamentQuickCreate\\QuickCreateServiceProvider" 40 | ] 41 | } 42 | }, 43 | "config": { 44 | "optimize-autoloader": true, 45 | "preferred-install": "dist", 46 | "sort-packages": true, 47 | "allow-plugins": { 48 | "phpstan/extension-installer": true 49 | } 50 | }, 51 | "minimum-stability": "dev", 52 | "prefer-stable": true 53 | } 54 | -------------------------------------------------------------------------------- /pint.json: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "laravel", 3 | "rules": { 4 | "blank_line_before_statement": true, 5 | "concat_space": { 6 | "spacing": "one" 7 | }, 8 | "method_argument_space": true, 9 | "single_trait_insert_per_statement": true, 10 | "types_spaces": { 11 | "space": "single" 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /resources/lang/en/quick-create.php: -------------------------------------------------------------------------------- 1 | 'Quick Create', 5 | ]; 6 | -------------------------------------------------------------------------------- /resources/views/components/create-menu.blade.php: -------------------------------------------------------------------------------- 1 | @php 2 | $keyBindings = collect($keyBindings ?? []) 3 | ->map(fn (string $keyBinding): string => str_replace('+', '-', $keyBinding)) 4 | ->implode('.'); 5 | @endphp 6 | 7 |
17 | @if ($resources && $this->shouldBeHidden() === false) 18 | 19 | 20 | 43 | 44 | 45 | 46 | @foreach($resources as $resource) 47 | 53 | {{ $resource['label'] }} 54 | 55 | @endforeach 56 | 57 | 58 | 59 | 60 | @endif 61 |
62 | -------------------------------------------------------------------------------- /src/Components/QuickCreateMenu.php: -------------------------------------------------------------------------------- 1 | resources = QuickCreatePlugin::get()->getResources(); 44 | $this->rounded = QuickCreatePlugin::get()->isRounded(); 45 | $this->hiddenIcons = QuickCreatePlugin::get()->shouldHideIcons(); 46 | $this->label = QuickCreatePlugin::get()->getLabel(); 47 | $this->keyBindings = QuickCreatePlugin::get()->getKeyBindings(); 48 | } 49 | 50 | /** 51 | * @throws Exception 52 | */ 53 | public function bootedInteractsWithActions(): void 54 | { 55 | $this->cacheActions(); 56 | } 57 | 58 | /** 59 | * @throws Exception 60 | */ 61 | protected function cacheActions(): void 62 | { 63 | $actions = Action::configureUsing( 64 | $this->configureAction(...), 65 | fn (): array => $this->getActions(), 66 | ); 67 | 68 | foreach ($actions as $action) { 69 | if (! $action instanceof Action) { 70 | throw new InvalidArgumentException('Header actions must be an instance of ' . Action::class . ', or ' . ActionGroup::class . '.'); 71 | } 72 | $this->cacheAction($action); 73 | $this->cachedActions[$action->getName()] = $action; 74 | } 75 | } 76 | 77 | public function getActions(): array 78 | { 79 | return collect($this->resources) 80 | ->transform(function ($resource, $index) { 81 | $r = App::make($resource['resource_name']); 82 | $canCreateAnother = QuickCreatePlugin::get()->canCreateAnother(); 83 | 84 | if ($canCreateAnother === null) { 85 | $canCreateAnother = true; 86 | 87 | if ($r->hasPage('create')) { 88 | $canCreateAnother = App::make($r->getPages()['create']->getPage())::canCreateAnother(); 89 | } else { 90 | $page = isset($r->getPages()['index']) 91 | ? $r->getPages()['index']->getPage() 92 | : null; 93 | 94 | if ($page) { 95 | $reflectionMethod = new \ReflectionMethod($page, 'getHeaderActions'); 96 | $actions = $reflectionMethod->invoke(new $page()); 97 | $createAction = collect($actions)->filter(function ($action) { 98 | return $action instanceof CreateAction; 99 | })->first(); 100 | 101 | if ($createAction) { 102 | $canCreateAnother = $createAction->canCreateAnother(); 103 | } 104 | } 105 | } 106 | } 107 | 108 | return CreateAction::make($resource['action_name']) 109 | ->authorize($r::canCreate()) 110 | ->model($resource['model']) 111 | ->slideOver(fn (): bool => QuickCreatePlugin::get()->shouldUseSlideOver()) 112 | ->modalWidth(fn (): ?string => QuickCreatePlugin::get()->getModalWidth($index)) 113 | ->modalHeading(fn () => QuickCreatePlugin::get()->getModalHeading($resource['label'])) 114 | ->modalDescription(fn () => QuickCreatePlugin::get()->getModalDescription($resource['label'])) 115 | ->extraModalWindowAttributes(fn () => QuickCreatePlugin::get()->getModalExtraAttributes()) 116 | ->form(function ($arguments, $form) use ($r) { 117 | return $r->form($form->operation('create')->columns()); 118 | }) 119 | ->createAnother($canCreateAnother) 120 | ->action(function (array $arguments, Form $form, CreateAction $action) use ($r): void { 121 | $model = $action->getModel(); 122 | 123 | $record = $action->process(function (array $data, HasActions $livewire) use ($model, $action, $r): Model { 124 | if ($translatableContentDriver = $livewire->makeFilamentTranslatableContentDriver()) { 125 | $record = $translatableContentDriver->makeRecord($model, $data); 126 | } else { 127 | $record = new $model(); 128 | $record->fill($data); 129 | } 130 | 131 | if ($relationship = $action->getRelationship()) { 132 | /** @phpstan-ignore-next-line */ 133 | $relationship->save($record); 134 | 135 | return $record; 136 | } 137 | 138 | if ( 139 | $r::isScopedToTenant() && 140 | ($tenant = Filament::getTenant()) 141 | ) { 142 | $relationship = $r::getTenantRelationship($tenant); 143 | 144 | if ($relationship instanceof HasManyThrough) { 145 | $record->save(); 146 | 147 | return $record; 148 | } 149 | 150 | return $relationship->save($record); 151 | } 152 | 153 | $record->save(); 154 | 155 | return $record; 156 | }); 157 | 158 | $action->record($record); 159 | $form->model($record)->saveRelationships(); 160 | 161 | if ($arguments['another'] ?? false) { 162 | $action->callAfter(); 163 | $action->sendSuccessNotification(); 164 | 165 | $action->record(null); 166 | 167 | // Ensure that the form record is anonymized so that relationships aren't loaded. 168 | $form->model($model); 169 | 170 | $form->fill(); 171 | 172 | $action->halt(); 173 | 174 | return; 175 | } 176 | 177 | $action->success(); 178 | }); 179 | }) 180 | ->values() 181 | ->toArray(); 182 | } 183 | 184 | public function toggleDropdown(): void 185 | { 186 | $this->emit('toggleQuickCreateDropdown'); 187 | } 188 | 189 | public function shouldBeHidden(): bool 190 | { 191 | return QuickCreatePlugin::get()->shouldBeHidden(); 192 | } 193 | 194 | public function render(): View 195 | { 196 | return view('filament-quick-create::components.create-menu') 197 | ->with([ 198 | 'keyBindings' => $this->keyBindings, 199 | ]); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /src/QuickCreatePlugin.php: -------------------------------------------------------------------------------- 1 | getResourcesUsing(fn () => $panel->getResources()); 61 | } 62 | 63 | public function excludes(array $resources): static 64 | { 65 | $this->excludes = $resources; 66 | 67 | return $this; 68 | } 69 | 70 | public function includes(array $resources): static 71 | { 72 | $this->includes = $resources; 73 | 74 | return $this; 75 | } 76 | 77 | public function rounded(bool | Closure $condition = true): static 78 | { 79 | $this->rounded = $condition; 80 | 81 | return $this; 82 | } 83 | 84 | public static function get(): static 85 | { 86 | return filament(app(static::class)->getId()); 87 | } 88 | 89 | public function getId(): string 90 | { 91 | return 'filament-quick-create'; 92 | } 93 | 94 | public function getExcludes(): array 95 | { 96 | return $this->evaluate($this->excludes); 97 | } 98 | 99 | public function getIncludes(): array 100 | { 101 | return $this->evaluate($this->includes); 102 | } 103 | 104 | public function getResources(): array 105 | { 106 | $resources = filled($this->getIncludes()) 107 | ? $this->getIncludes() 108 | : $this->evaluate($this->getResourcesUsing); 109 | 110 | $list = collect($resources) 111 | ->filter(function ($item) { 112 | return ! in_array($item, $this->getExcludes()); 113 | }) 114 | ->map(function ($resourceName): ?array { 115 | $resource = app($resourceName); 116 | 117 | if (Filament::hasTenancy() && ! Filament::getTenant()) { 118 | return null; 119 | } 120 | 121 | if ($resource->canCreate()) { 122 | $actionName = 'create_' . Str::of($resource->getModel())->replace('\\', '')->snake(); 123 | 124 | return [ 125 | 'resource_name' => $resourceName, 126 | 'label' => Str::ucfirst($resource->getModelLabel()), 127 | 'model' => $resource->getModel(), 128 | 'icon' => $resource->getNavigationIcon(), 129 | 'action_name' => $actionName, 130 | 'action' => ! $resource->hasPage('create') || $this->shouldUseModal() ? 'mountAction(\'' . $actionName . '\')' : null, 131 | 'url' => $resource->hasPage('create') && ! $this->shouldUseModal() ? $resource::getUrl('create') : null, 132 | 'navigation' => $resource->getNavigationSort(), 133 | ]; 134 | } 135 | 136 | return null; 137 | }) 138 | ->when($this->isSortable(), fn ($collection) => $collection->sortBy($this->sortBy)) 139 | ->values() 140 | ->toArray(); 141 | 142 | return array_filter($list); 143 | } 144 | 145 | public function getResourcesUsing(Closure $callback): static 146 | { 147 | $this->getResourcesUsing = $callback; 148 | 149 | return $this; 150 | } 151 | 152 | public function isSortable(): bool 153 | { 154 | return $this->evaluate($this->sort); 155 | } 156 | 157 | public function isRounded(): bool 158 | { 159 | return $this->evaluate($this->rounded) ?? true; 160 | } 161 | 162 | public static function make(): static 163 | { 164 | return app(static::class); 165 | } 166 | 167 | public function register(Panel $panel): void 168 | { 169 | $panel 170 | ->renderHook( 171 | name: $this->getRenderHook(), 172 | hook: fn (): string => Blade::render("@livewire('quick-create-menu')") 173 | ); 174 | } 175 | 176 | public function shouldUseSlideOver(): bool 177 | { 178 | return $this->evaluate($this->shouldUseSlideOver) ?? false; 179 | } 180 | 181 | public function slideOver(bool $condition = true): static 182 | { 183 | $this->shouldUseSlideOver = $condition; 184 | 185 | return $this; 186 | } 187 | 188 | public function sort(bool | Closure $condition = true): static 189 | { 190 | $this->sort = $condition; 191 | 192 | return $this; 193 | } 194 | 195 | public function sortBy(string | Closure $sortBy = 'label'): static 196 | { 197 | if (! in_array($sortBy, ['label', 'navigation'])) { 198 | $sortBy = 'label'; 199 | } 200 | $this->sortBy = $sortBy; 201 | 202 | return $this; 203 | } 204 | 205 | public function hidden(bool | Closure $hidden = true): static 206 | { 207 | $this->hidden = $hidden; 208 | 209 | return $this; 210 | } 211 | 212 | public function shouldBeHidden(): bool 213 | { 214 | return $this->evaluate($this->hidden) ?? false; 215 | } 216 | 217 | public function renderUsingHook(string | Closure $panelHook): static 218 | { 219 | $this->renderUsingHook = $panelHook; 220 | 221 | return $this; 222 | } 223 | 224 | public function getRenderHook(): string 225 | { 226 | return $this->evaluate($this->renderUsingHook) ?? PanelsRenderHook::USER_MENU_BEFORE; 227 | } 228 | 229 | public function hiddenIcons(bool | Closure $condition = true): static 230 | { 231 | $this->hiddenIcons = $condition; 232 | 233 | return $this; 234 | } 235 | 236 | public function shouldHideIcons(): bool 237 | { 238 | return $this->evaluate($this->hiddenIcons) ?? false; 239 | } 240 | 241 | public function label(string | Closure $label): static 242 | { 243 | $this->label = $label; 244 | 245 | return $this; 246 | } 247 | 248 | public function getLabel(): ?string 249 | { 250 | return $this->evaluate($this->label) ?? null; 251 | } 252 | 253 | public function shouldUseModal(): bool 254 | { 255 | return $this->evaluate($this->shouldUseModal) ?? false; 256 | } 257 | 258 | public function alwaysShowModal(bool | Closure $condition = true): static 259 | { 260 | $this->shouldUseModal = $condition; 261 | 262 | return $this; 263 | } 264 | 265 | public function keyBindings(string | array | Closure | null $bindings): static 266 | { 267 | $this->keyBindings = $bindings; 268 | 269 | return $this; 270 | } 271 | 272 | public function getKeyBindings(): ?array 273 | { 274 | return collect($this->evaluate($this->keyBindings))->toArray(); 275 | } 276 | 277 | public function createAnother(bool | Closure $condition = true): static 278 | { 279 | $this->createAnother = $condition; 280 | 281 | return $this; 282 | } 283 | 284 | public function canCreateAnother(): ?bool 285 | { 286 | return $this->evaluate($this->createAnother); 287 | } 288 | 289 | public function modalWidths(string | array | Closure $widths): static 290 | { 291 | $this->modalWidths = $widths; 292 | 293 | return $this; 294 | } 295 | 296 | public function getModalWidth(int $index = 0): ?string 297 | { 298 | $widths = $this->evaluate($this->modalWidths); 299 | 300 | if (is_string($widths)) { 301 | return $widths; 302 | } 303 | 304 | if (is_array($widths)) { 305 | return $widths[$index] ?? array_values($widths)[0] ?? null; 306 | } 307 | 308 | return null; 309 | } 310 | 311 | public function modalHeading(string | Closure $heading): static 312 | { 313 | $this->modalHeading = $heading; 314 | 315 | return $this; 316 | } 317 | 318 | public function getModalHeading(string $resourceLabel): ?string 319 | { 320 | $heading = $this->evaluate($this->modalHeading); 321 | 322 | return $heading ? str_replace(':label', $resourceLabel, $heading) : null; 323 | } 324 | 325 | public function modalDescription(string | Closure $description): static 326 | { 327 | $this->modalDescription = $description; 328 | 329 | return $this; 330 | } 331 | 332 | public function getModalDescription(string $resourceLabel): ?string 333 | { 334 | $description = $this->evaluate($this->modalDescription); 335 | 336 | return $description ? str_replace(':label', $resourceLabel, $description) : null; 337 | } 338 | 339 | public function modalExtraAttributes(array | Closure $attributes): static 340 | { 341 | $this->modalExtraAttributes = $attributes; 342 | 343 | return $this; 344 | } 345 | 346 | public function getModalExtraAttributes(): ?array 347 | { 348 | return $this->evaluate($this->modalExtraAttributes); 349 | } 350 | } 351 | -------------------------------------------------------------------------------- /src/QuickCreateServiceProvider.php: -------------------------------------------------------------------------------- 1 | name('filament-quick-create') 14 | ->hasTranslations() 15 | ->hasViews(); 16 | } 17 | } 18 | --------------------------------------------------------------------------------