use global modal for popup messages
All checks were successful
delpoy / build-and-deploy (push) Successful in 51s

This commit is contained in:
bytedream 2024-12-02 21:02:23 +01:00
parent a1965c62e2
commit e30446598c
14 changed files with 252 additions and 284 deletions

View File

@ -32,8 +32,6 @@ export default ts.config(
},
{
rules: {
// expressions are often used to check if a props function is defined before calling it
'@typescript-eslint/no-unused-expressions': 'off',
'@typescript-eslint/no-explicit-any': 'off'
}
}

View File

@ -14,7 +14,7 @@
required = false,
disabled = false,
readonly = false,
checked = false,
checked = $bindable(false),
size = 'md',
pickyWidth = true,
containerClass = '',
@ -109,10 +109,15 @@
{readonly}
bind:this={inputElement}
autocomplete="off"
onchange={() => {
if (type === 'checkbox') {
checked = !checked;
}
}}
oninput={(e: Event & { currentTarget: EventTarget & HTMLInputElement }) => {
value = e.currentTarget.value;
if (pattern && !pattern.test(value)) return;
oninput && oninput(e);
oninput?.(e);
}}
onpaste={(e) => {
if (pattern && e.clipboardData && !pattern.test(e.clipboardData.getData('text'))) {

View File

@ -63,14 +63,14 @@
value = searchSuggestion.value;
searchSuggestions = [];
e.currentTarget.setCustomValidity('');
onsubmit && onsubmit(Object.assign(e, { input: inputValue, value: value }));
onsubmit?.(Object.assign(e, { input: inputValue, value: value }));
} else if (inputValue === '' && emptyAllowed) {
onsubmit && onsubmit(Object.assign(e, { input: '', value: '' }));
onsubmit?.(Object.assign(e, { input: '', value: '' }));
}
});
}}
oninvalid={(e: Event & { currentTarget: EventTarget & HTMLInputElement }) => {
invalidMessage && e.currentTarget.setCustomValidity(invalidMessage);
if (invalidMessage) e.currentTarget.setCustomValidity(invalidMessage);
}}
pattern={suggestionRequired
? `${value ? inputValue : 'a^' + (emptyAllowed ? '|$^' : '')}`
@ -89,7 +89,7 @@
inputValue = searchSuggestion.name;
value = searchSuggestion.value;
searchSuggestions = [];
onsubmit && onsubmit(Object.assign(e, { input: inputValue, value: value }));
onsubmit?.(Object.assign(e, { input: inputValue, value: value }));
}}>{searchSuggestion.name}</button
>
</li>

18
src/lib/context.ts Normal file
View File

@ -0,0 +1,18 @@
import { getContext } from 'svelte';
export type PopupModalContextArgs = {
title: string;
text?: string;
actions?: { text: string; action?: (modal: Event) => void }[];
onClose?: () => void;
};
export function getPopupModalShowFn(): ({
title,
text,
actions,
onClose
}: PopupModalContextArgs) => void {
const { set }: { set: ({ title, text, actions, onClose }: PopupModalContextArgs) => void } =
getContext('globalPopupModal');
return set;
}

View File

@ -3,6 +3,9 @@
import { env } from '$env/dynamic/public';
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import Input from '$lib/components/Input/Input.svelte';
import { setContext, tick } from 'svelte';
import type { PopupModalContextArgs } from '$lib/context';
let { children } = $props();
@ -60,7 +63,20 @@
}
});
let popupModalState: PopupModalContextArgs | null = $state(null);
// eslint-disable-next-line no-undef
let popupModalNullTimeout: number | NodeJS.Timeout | null = null;
setContext('globalPopupModal', {
set: async ({ title, text, actions, onClose }: PopupModalContextArgs) => {
if (popupModalNullTimeout) clearTimeout(popupModalNullTimeout);
popupModalState = { title, text, actions, onClose };
await tick();
popupModalElem.showModal();
}
});
let navElem: HTMLDivElement;
let popupModalElem: HTMLDialogElement;
</script>
<svelte:window bind:innerHeight={windowHeight} />
@ -179,6 +195,48 @@
</footer>
{/if}
<dialog class="modal" bind:this={popupModalElem}>
{#if popupModalState}
<form
method="dialog"
class="modal-box z-50"
onsubmit={() => {
popupModalNullTimeout = setTimeout(() => {
popupModalState = null;
popupModalNullTimeout = null;
}, 200);
popupModalState?.onClose?.();
}}
>
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
<h3 class="font-bold text-2xl">{popupModalState.title}</h3>
{#if popupModalState.text}
<p class="py-4 whitespace-pre-line">{popupModalState.text}</p>
{/if}
{#if popupModalState.actions}
<div class="flex flex-row space-x-1 mt-4">
{#each popupModalState.actions as action}
<Input type="submit" value={action.text} onclick={(e) => action.action?.(e)} />
{/each}
</div>
{/if}
</form>
<form
method="dialog"
class="modal-backdrop bg-[rgba(0,0,0,.2)]"
onsubmit={() => {
popupModalNullTimeout = setTimeout(() => {
popupModalState = null;
popupModalNullTimeout = null;
}, 200);
popupModalState?.onClose?.();
}}
>
<button>close</button>
</form>
{/if}
</dialog>
<style lang="scss">
@media (max-height: 450px) {
.main-menu {

View File

@ -16,9 +16,12 @@
import Search from '$lib/components/Input/Search.svelte';
import { usernameSuggestions } from '$lib/utils';
import PaginationTableBody from '$lib/components/PaginationTable/PaginationTableBody.svelte';
import { getPopupModalShowFn } from '$lib/context';
let { data } = $props();
let showPopupModal = getPopupModalShowFn();
let reports: (typeof Report.prototype.dataValues)[] = $state([]);
let reportsPerRequest = 25;
let reportFilter = $state({ draft: false, status: null, reporter: null, reported: null });
@ -91,7 +94,6 @@
});
}
let saveActiveReportChangesModal: HTMLDialogElement;
let newReportModal: HTMLDialogElement;
</script>
@ -327,49 +329,45 @@
<Input
type="submit"
value="Speichern"
onclick={() => saveActiveReportChangesModal.show()}
onclick={() => {
showPopupModal({
title: 'Änderungen Speichern?',
actions: [
{
text: 'Speichern',
action: async () => {
await updateActiveReport();
if (activeReport.reported?.username) {
if (activeReport.reported?.id === undefined) {
activeReport.reported.id = -1;
}
} else {
activeReport.reported = undefined;
}
reports = [...reports];
if (
activeReport.originalStatus !== 'reviewed' &&
activeReport.status === 'reviewed'
) {
$reportCount -= 1;
} else if (
activeReport.originalStatus === 'reviewed' &&
activeReport.status !== 'reviewed'
) {
$reportCount += 1;
}
}
},
{ text: 'Abbrechen' }
]
});
}}
/>
</div>
</div>
{/if}
</div>
<dialog class="modal" bind:this={saveActiveReportChangesModal}>
<form method="dialog" class="modal-box">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
<h3 class="font-roboto text-xl">Änderungen Speichern?</h3>
<div class="flex flex-row space-x-2 mt-6">
<Input
type="submit"
value="Speichern"
onclick={async () => {
await updateActiveReport();
if (activeReport.reported?.username) {
if (activeReport.reported?.id === undefined) {
activeReport.reported.id = -1;
}
} else {
activeReport.reported = undefined;
}
reports = [...reports];
if (activeReport.originalStatus !== 'reviewed' && activeReport.status === 'reviewed') {
$reportCount -= 1;
} else if (
activeReport.originalStatus === 'reviewed' &&
activeReport.status !== 'reviewed'
) {
$reportCount += 1;
}
}}
/>
<Input type="submit" value="Abbrechen" />
</div>
</form>
<form method="dialog" class="modal-backdrop bg-[rgba(0,0,0,.3)]">
<button>close</button>
</form>
</dialog>
<dialog class="modal" bind:this={newReportModal}>
<NewReportModal
onSubmit={(e) => {

View File

@ -5,9 +5,12 @@
import Search from '$lib/components/Input/Search.svelte';
import { usernameSuggestions } from '$lib/utils';
import type { Report } from '$lib/server/database';
import { getPopupModalShowFn } from '$lib/context';
let { onSubmit }: { onSubmit: (data: typeof Report.prototype.dataValues) => void } = $props();
let showPopupModal = getPopupModalShowFn();
let reporter: string | undefined = $state();
let reported: string | undefined = $state();
let reason = $state('');
@ -29,7 +32,6 @@
let globalCloseForm: HTMLFormElement;
let reportForm: HTMLFormElement;
let confirmDialog: HTMLDialogElement;
</script>
<form method="dialog" class="modal-box" bind:this={reportForm}>
@ -79,7 +81,22 @@
onclick={(e) => {
if (reportForm.checkValidity()) {
e.preventDefault();
confirmDialog.show();
showPopupModal({
title: 'Report Erstellen?',
text: body
? 'Dadurch, dass bereits Details über den Report Grund hinzugefügt wurden, ist es nach dem Erstellen nicht mehr möglich, den Report Inhalt zu ändern'
: 'Der Report wird als Entwurf gespeichert und kann nach dem Erstellen über den Report-Link bearbeitet werden',
actions: [
{
text: 'Erstellen',
action: async () => {
await newReport();
globalCloseForm.submit();
}
},
{ text: 'Abbrechen' }
]
});
}
}}
/>
@ -96,35 +113,3 @@
<form method="dialog" class="modal-backdrop bg-[rgba(0,0,0,.3)]" bind:this={globalCloseForm}>
<button>close</button>
</form>
<dialog class="modal" bind:this={confirmDialog}>
<form method="dialog" class="modal-box">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
<h3 class="font-roboto text-xl mb-2">Report Erstellen?</h3>
{#if body}
<p>
Dadurch, dass bereits Details über den Report Grund hinzugefügt wurden, ist es nach dem
Erstellen nicht mehr möglich, den Report Inhalt zu ändern
</p>
{:else}
<p>
Der Report wird als Entwurf gespeichert und kann nach dem Erstellen über den Report-Link
bearbeitet werden
</p>
{/if}
<div class="flex flex-row space-x-2 mt-6">
<Input
type="submit"
value="Erstellen"
onclick={async () => {
await newReport();
globalCloseForm.submit();
}}
/>
<Input type="submit" value="Abbrechen" />
</div>
</form>
<form method="dialog" class="modal-backdrop bg-[rgba(0,0,0,.3)]">
<button>close</button>
</form>
</dialog>

View File

@ -64,6 +64,7 @@
let userFilterEffectAlreadyRan = false;
$effect(() => {
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
userFilter;
if (!userFilterEffectAlreadyRan) {

View File

@ -3,6 +3,7 @@
import { env } from '$env/dynamic/public';
import Select from '$lib/components/Input/Select.svelte';
import { errorMessage } from '$lib/stores';
import { getPopupModalShowFn } from '$lib/context';
let {
onSubmit
@ -24,6 +25,8 @@
}) => void;
} = $props();
let showPopupModal = getPopupModalShowFn();
let firstname: string = $state('');
let lastname: string = $state('');
let birthday: string = $state('');
@ -61,7 +64,6 @@
let globalCloseForm: HTMLFormElement;
let reportForm: HTMLFormElement;
let confirmDialog: HTMLDialogElement;
</script>
<form method="dialog" class="modal-box" bind:this={reportForm}>
@ -111,7 +113,10 @@
onclick={(e) => {
if (reportForm.checkValidity()) {
e.preventDefault();
confirmDialog.show();
showPopupModal({
title: 'Spieler hinzufügen?',
actions: [{ text: 'Hinzufügen', action: newUser }, { text: 'Abbrechen' }]
});
}
}}
/>
@ -128,17 +133,3 @@
<form method="dialog" class="modal-backdrop bg-[rgba(0,0,0,.3)]" bind:this={globalCloseForm}>
<button>close</button>
</form>
<dialog class="modal" bind:this={confirmDialog}>
<form method="dialog" class="modal-box">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
<h3 class="font-roboto text-xl mb-2">Spieler hinzufügen?</h3>
<div class="flex flex-row space-x-2 mt-6">
<Input type="submit" value="Hinzufügen" onclick={newUser} />
<Input type="submit" value="Abbrechen" />
</div>
</form>
<form method="dialog" class="modal-backdrop bg-[rgba(0,0,0,.3)]">
<button>close</button>
</form>
</dialog>

View File

@ -3,13 +3,13 @@
import Textarea from '$lib/components/Input/Textarea.svelte';
import { env } from '$env/dynamic/public';
import Select from '$lib/components/Input/Select.svelte';
import { getPopupModalShowFn } from '$lib/context';
let showPopupModal = getPopupModalShowFn();
let content = $state('');
let type = $state('feedback');
let submitModal: HTMLDialogElement;
let sentModal: HTMLDialogElement;
async function submitFeedback() {
await fetch(`${env.PUBLIC_BASE_PATH}/feedback`, {
method: 'POST',
@ -30,7 +30,37 @@
<form
onsubmit={(e) => {
e.preventDefault();
submitModal.show();
showPopupModal({
title: `${type === 'feedback' ? 'Feedback' : 'Kontaktanfrage'} abschicken?`,
text:
type === 'feedback'
? 'Nach dem Abschicken des Feedbacks lässt es sich nicht mehr bearbeiten.'
: 'Bitte hinterlege eine Rückmeldemöglichkeit in deiner Anfrage. Nachdem sie abgeschickt wurde, kannst du die Nachricht nicht mehr bearbeiten.',
actions: [
{
text: 'Abschicken',
action: () =>
setTimeout(async () => {
await submitFeedback();
showPopupModal({
title: `${type === 'feedback' ? 'Feedback' : 'Kontaktanfrage'} abgeschickt`,
text:
type === 'feedback'
? 'Dein Feedback wurde abgeschickt.'
: 'Deine Kontaktanfrage wurde abgeschickt. Jemand aus dem Team wird sich nächstmöglich bei Dir melden.',
actions: [{ text: 'Schließen' }],
onClose: () => {
content = '';
type = 'feedback';
}
});
}, 200)
},
{ text: 'Abbrechen' }
]
});
}}
>
<div class="space-y-4 mt-6 mb-4">
@ -50,77 +80,3 @@
</div>
</form>
</div>
<dialog class="modal" bind:this={submitModal}>
<form method="dialog" class="modal-box">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
<div>
<h3 class="font-roboto font-medium text-xl">
{type === 'feedback' ? 'Feedback' : 'Kontaktanfrage'} abschicken?
</h3>
<div class="my-4">
{#if type === 'feedback'}
<p>Nach dem Abschicken des Feedbacks lässt es sich nicht mehr bearbeiten.</p>
{:else}
<p>
Bitte hinterlege eine Rückmeldemöglichkeit in deiner Anfrage. Nachdem sie abgeschickt
wurde, kannst du die Nachricht nicht mehr bearbeiten.
</p>
{/if}
</div>
<div class="flex flex-row space-x-1">
<Input
type="submit"
value="Abschicken"
onclick={async () => {
await submitFeedback();
sentModal.show();
}}
/>
<Input type="submit" value="Abbrechen" />
</div>
</div>
</form>
<form method="dialog" class="modal-backdrop bg-[rgba(0,0,0,.3)]">
<button>close</button>
</form>
</dialog>
<dialog class="modal" bind:this={sentModal}>
<form
method="dialog"
class="modal-box"
onsubmit={() => {
content = '';
type = 'feedback';
}}
>
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
<div>
<h3 class="font-roboto font-medium text-xl">
{type === 'feedback' ? 'Feedback' : 'Kontaktanfrage'} abgeschickt
</h3>
<div class="my-4">
{#if type === 'feedback'}
<p>Dein Feedback wurde abgeschickt.</p>
{:else}
<p>
Deine Kontaktanfrage wurde abgeschickt. Jemand aus dem Team wird sich nächstmöglich bei
Dir melden.
</p>
{/if}
</div>
<Input type="submit" value="Schließen" />
</div>
</form>
<form
method="dialog"
class="modal-backdrop bg-[rgba(0,0,0,.3)]"
onsubmit={() => {
content = '';
type = 'feedback';
}}
>
<button>close</button>
</form>
</dialog>

View File

@ -4,6 +4,8 @@
import FeedbackSent from './FeedbackSent.svelte';
let { data } = $props();
let draft = $state(data.draft);
</script>
<svelte:head>
@ -12,13 +14,9 @@
<meta name="robots" content="noindex" />
</svelte:head>
{#if data.draft}
{#if draft}
<div class="col-[1] row-[1]" transition:fly={{ x: -200, duration: 300 }}>
<FeedbackDraft
event={data.event}
anonymous={data.anonymous}
on:submit={() => (data.draft = false)}
/>
<FeedbackDraft event={data.event} anonymous={data.anonymous} onSubmit={() => (draft = false)} />
</div>
{:else}
<div class="col-[1] row-[1]" transition:fly={{ x: 200, duration: 300 }}>

View File

@ -3,14 +3,15 @@
import Textarea from '$lib/components/Input/Textarea.svelte';
import { env } from '$env/dynamic/public';
import { page } from '$app/stores';
import { getPopupModalShowFn } from '$lib/context';
let { event, anonymous, onSubmit }: { event: string; anonymous: false; onSubmit?: () => void } =
let { event, anonymous, onSubmit }: { event: string; anonymous: boolean; onSubmit?: () => void } =
$props();
let content = $state('');
let sendAnonymous = $state(true);
let showPopupModal = getPopupModalShowFn();
let submitModal: HTMLDialogElement;
let content = $state('');
let sendAnonymous = $state(false);
async function submitFeedback() {
await fetch(`${env.PUBLIC_BASE_PATH}/feedback/${$page.params.url_hash}`, {
@ -28,7 +29,21 @@
<form
onsubmit={(e) => {
e.preventDefault();
submitModal.show();
showPopupModal({
title: 'Feedback abschicken?',
text: 'Nach dem Abschicken des Feedbacks lässt es sich nicht mehr bearbeiten.',
actions: [
{
text: 'Abschicken',
action: async () => {
await submitFeedback();
onSubmit?.();
}
},
{ text: 'Abbrechen' }
]
});
}}
>
<div class="space-y-4 my-4">
@ -38,45 +53,19 @@
{/snippet}
</Input>
<Textarea required={true} rows={4} label="Feedback" bind:value={content} />
{#if !anonymous}
<div class="flex items-center gap-2 mt-2">
<Input type="checkbox" id="anonymous" size="xs" bind:checked={sendAnonymous} />
<label
for="anonymous"
title="Dein Spielername wird nach dem Abschicken nicht mit dem Feedback zusammen gespeichert"
>Anonym senden</label
>
</div>
{/if}
<div>
<Input type="submit" disabled={content === ''} value="Feedback senden" />
</div>
</div>
</form>
</div>
<dialog class="modal" bind:this={submitModal}>
<form method="dialog" class="modal-box">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
<div>
<h3 class="font-roboto font-medium text-xl">Feedback abschicken?</h3>
<div class="my-4">
<p>Nach dem Abschicken des Feedbacks lässt es sich nicht mehr bearbeiten.</p>
{#if !anonymous}
<div class="flex items-center gap-2 mt-2">
<Input type="checkbox" id="anonymous" size="xs" checked />
<label
for="anonymous"
title="Dein Spielername wird nach dem Abschicken nicht mit dem Feedback zusammen gespeichert"
>Anonym senden</label
>
</div>
{/if}
</div>
<div class="flex flex-row space-x-1">
<Input
type="submit"
value="Abschicken"
onclick={async () => {
await submitFeedback();
onSubmit && onSubmit();
}}
/>
<Input type="submit" value="Abbrechen" />
</div>
</div>
</form>
<form method="dialog" class="modal-backdrop bg-[rgba(0,0,0,.3)]">
<button>close</button>
</form>
</dialog>

View File

@ -6,6 +6,7 @@
import { rulesShort } from '$lib/rules';
import { RegisterSchema } from './schema';
import { dev } from '$app/environment';
import { getPopupModalShowFn } from '$lib/context';
let {
submit
@ -27,6 +28,8 @@
}) => void;
} = $props();
let showPopupModal = getPopupModalShowFn();
const modalTimeoutSeconds = dev ? 0 : 30;
let checkInputs = $state(() => {});
@ -76,7 +79,7 @@
);
if (!parseResult.success) {
reject(Error(parseResult.error.issues.map((i) => i.message).join('\n\n')));
reject(Error(parseResult.error.issues.map((i) => i.message).join('\n')));
return;
}
@ -114,6 +117,14 @@
let inputsInvalidMessage: string | null = $state('Bitte fülle alle erforderlichen Felder aus');
let registerRequest: Promise<void> | null = $state(null);
let errorMessage: string = $state('');
$effect(() => {
if (!errorMessage) return;
showPopupModal({
title: 'Fehler',
text: errorMessage
});
});
</script>
<h1 class="text-center text-3xl lg:text-5xl">Anmeldung</h1>
@ -371,16 +382,3 @@
<button>close</button>
</form>
</dialog>
{#if errorMessage}
<dialog class="modal" onclose={() => setTimeout(() => (errorMessage = ''), 200)} open>
<form method="dialog" class="modal-box z-50">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
<h3 class="font-bold text-2xl">Achtung</h3>
<p class="py-4 whitespace-pre-line">{errorMessage}</p>
</form>
<form method="dialog" class="modal-backdrop bg-[rgba(0,0,0,.2)]">
<button>close</button>
</form>
</dialog>
{/if}

View File

@ -5,6 +5,7 @@
import { page } from '$app/stores';
import Search from '$lib/components/Input/Search.svelte';
import Select from '$lib/components/Input/Select.svelte';
import { getPopupModalShowFn } from '$lib/context';
let {
reporterName,
@ -20,12 +21,11 @@
onsubmit: () => void;
} = $props();
let showPopupModal = getPopupModalShowFn();
let reported = $state(reportedName);
let content = $state('');
let userErrorModal: HTMLDialogElement;
let submitModal: HTMLDialogElement;
async function submitReport() {
await fetch(`${env.PUBLIC_BASE_PATH}/report/${$page.params.url_hash}`, {
method: 'POST',
@ -56,9 +56,26 @@
onsubmit={(e) => {
e.preventDefault();
if (reported != null && users.findIndex((u) => u === reported) === -1) {
userErrorModal.show();
showPopupModal({
title: 'Fehler',
text: 'Der zu reportende Spieler existiert nicht.',
actions: [{ text: 'Schließen' }]
});
} else {
submitModal.show();
showPopupModal({
title: 'Report abschicken?',
text: 'Nach dem Abschicken des Reports wird sich ein Admin schnellstmöglich darum kümmern.',
actions: [
{
text: 'Abschicken',
action: async () => {
await submitReport();
onsubmit();
}
},
{ text: 'Abbrechen' }
]
});
}
}}
>
@ -100,47 +117,3 @@
</div>
</form>
</div>
<dialog class="modal" bind:this={userErrorModal}>
<form method="dialog" class="modal-box">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
<div>
<h3 class="font-roboto font-medium text-xl">Fehler</h3>
<div class="my-4">
<p>Der zu reportende Spieler existiert nicht</p>
</div>
<div class="flex flex-row space-x-1">
<Input type="submit" value="Schließen" />
</div>
</div>
</form>
<form method="dialog" class="modal-backdrop bg-[rgba(0,0,0,.3)]">
<button>close</button>
</form>
</dialog>
<dialog class="modal" bind:this={submitModal}>
<form method="dialog" class="modal-box">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
<div>
<h3 class="font-roboto font-medium text-xl">Report abschicken?</h3>
<div class="my-4">
<p>Nach dem Abschicken des Reports wird sich ein Admin schnellstmöglich darum kümmern.</p>
</div>
<div class="flex flex-row space-x-1">
<Input
type="submit"
value="Abschicken"
onclick={async () => {
await submitReport();
onsubmit();
}}
/>
<Input type="submit" value="Abbrechen" />
</div>
</div>
</form>
<form method="dialog" class="modal-backdrop bg-[rgba(0,0,0,.3)]">
<button>close</button>
</form>
</dialog>