Add modal component
This commit is contained in:
parent
689614ee93
commit
4da1e01296
|
@ -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