Add modal component
This commit is contained in:
		
							parent
							
								
									918449be69
								
							
						
					
					
						commit
						f2b72b85cb
					
				|  | @ -0,0 +1,101 @@ | ||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace App\View\Page; | ||||||
|  | 
 | ||||||
|  | use Livewire\Attributes\On; | ||||||
|  | use Livewire\Component; | ||||||
|  | 
 | ||||||
|  | class Modal extends Component | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  |     public ?string $component = null; | ||||||
|  |     public array $props = []; | ||||||
|  |     public string $key = ''; | ||||||
|  |     public array $actions = []; | ||||||
|  |     public ?string $size = null; | ||||||
|  |     public string $title = ''; | ||||||
|  | 
 | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[On('openModal')]
 | ||||||
|  |     public function onOpenModal(string $component, string $title, array $props = [], array $actions = ['storeable', 'closeable'], string $size = "xl"): void | ||||||
|  |     { | ||||||
|  |         $this->component = $component; | ||||||
|  |         $this->props = $props; | ||||||
|  |         $this->size = $size; | ||||||
|  |         $this->title = $title; | ||||||
|  |         $this->key = md5(json_encode(['component' => $component, 'props' => $props])); | ||||||
|  |         $this->actions = $this->parseActions($actions); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function parseActions(array $actions): array | ||||||
|  |     { | ||||||
|  |         return collect($actions)->map(function ($action) { | ||||||
|  |             if ($action === 'closeable') { | ||||||
|  |                 return ['event' => 'closeModal', 'icon' => 'close', 'label' => 'Schließen']; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if ($action === 'storeable') { | ||||||
|  |                 return ['event' => 'onStoreFromModal', 'icon' => 'save', 'label' => 'Speichern']; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return $action; | ||||||
|  |         })->toArray(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[On('closeModal')]
 | ||||||
|  |     public function onCloseModal(): void | ||||||
|  |     { | ||||||
|  |         $this->reset(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function sizeClass(): string | ||||||
|  |     { | ||||||
|  |         if ($this->size === 'lg') { | ||||||
|  |             return 'max-w-lg'; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if ($this->size === 'xl') { | ||||||
|  |             return 'max-w-xl'; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return ''; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function render() | ||||||
|  |     { | ||||||
|  |         return <<<'HTML' | ||||||
|  |             <div> | ||||||
|  |                 @if($component) | ||||||
|  |                 <div class="fixed z-40 top-0 left-0 w-full h-full flex items-center justify-center p-6 bg-black/60 backdrop-blur-sm" @click.self="$dispatch('closeModal')"> | ||||||
|  |                     <div | ||||||
|  |                         class="relative rounded-lg p-8 bg-zinc-800 shadow-2xl shadow-black border border-zinc-700 border-solid w-full max-h-full flex flex-col overflow-auto {{$this->sizeClass()}}" | ||||||
|  |                     > | ||||||
|  |                         <div class="flex"> | ||||||
|  |                             <h3 class="font-semibold text-primary-200 text-xl grow">{{$title}}</h3> | ||||||
|  |                             <div class="flex space-x-6"> | ||||||
|  |                                 @foreach ($this->actions as $action) | ||||||
|  |                                 <a x-tooltip.raw="{{$action['label']}}" href="#" @click.prevent="$dispatch('{{$action['event']}}')"> | ||||||
|  |                                     <x-ui::sprite :src="$action['icon']" class="text-zinc-400 w-6 h-6"></x-ui::sprite> | ||||||
|  |                                 </a> | ||||||
|  |                                 @endforeach | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  |                         <div class="text-primary-100 group is-popup grow flex flex-col mt-3"> | ||||||
|  |                             <div> | ||||||
|  |                                 @if ($component) | ||||||
|  |                                 @livewire($component, $props, key($key)) | ||||||
|  |                                 @endif | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |                 @else | ||||||
|  |                 <div></div> | ||||||
|  |                 @endif | ||||||
|  |             </div> | ||||||
|  |         HTML; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -1,45 +0,0 @@ | ||||||
| <template> |  | ||||||
|     <div class="fixed z-40 top-0 left-0 w-full h-full flex items-center justify-center p-6 bg-black/60 backdrop-blur-sm"> |  | ||||||
|         <div |  | ||||||
|             class="relative rounded-lg p-8 bg-zinc-800 shadow-2xl shadow-black border border-zinc-700 border-solid w-full max-h-full flex flex-col overflow-auto" |  | ||||||
|             :class="full ? 'h-full' : innerWidth" |  | ||||||
|         > |  | ||||||
|             <div class="absolute top-0 right-0 mt-6 mr-6 flex space-x-6"> |  | ||||||
|                 <slot name="actions"></slot> |  | ||||||
|                 <a href="#" @click.prevent="$emit('close')"> |  | ||||||
|                     <ui-sprite src="close" class="text-zinc-400 w-6 h-6"></ui-sprite> |  | ||||||
|                 </a> |  | ||||||
|             </div> |  | ||||||
|             <h3 v-if="heading" class="font-semibold text-primary-200 text-xl" v-html="heading"></h3> |  | ||||||
|             <div class="text-primary-100 group is-popup grow flex flex-col"> |  | ||||||
|                 <suspense> |  | ||||||
|                     <div> |  | ||||||
|                         <slot></slot> |  | ||||||
|                     </div> |  | ||||||
|                     <template #fallback> |  | ||||||
|                         <ui-loading></ui-loading> |  | ||||||
|                     </template> |  | ||||||
|                 </suspense> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
| </template> |  | ||||||
| 
 |  | ||||||
| <script> |  | ||||||
| export default { |  | ||||||
|     props: { |  | ||||||
|         heading: { |  | ||||||
|             type: String, |  | ||||||
|             default: () => '', |  | ||||||
|         }, |  | ||||||
|         innerWidth: { |  | ||||||
|             default: () => 'max-w-xl', |  | ||||||
|             type: String, |  | ||||||
|         }, |  | ||||||
|         full: { |  | ||||||
|             type: Boolean, |  | ||||||
|             default: () => false, |  | ||||||
|         }, |  | ||||||
|     }, |  | ||||||
| }; |  | ||||||
| </script> |  | ||||||
		Loading…
	
		Reference in New Issue