diff --git a/app/View/Page/Modal.php b/app/View/Page/Modal.php new file mode 100644 index 00000000..072ff59f --- /dev/null +++ b/app/View/Page/Modal.php @@ -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; + } +} diff --git a/resources/js/components/ui/Popup.vue b/resources/js/components/ui/Popup.vue deleted file mode 100644 index 0c84fa42..00000000 --- a/resources/js/components/ui/Popup.vue +++ /dev/null @@ -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>