web using penguin-ui
This commit is contained in:
@@ -1,54 +1,52 @@
|
||||
{#
|
||||
Blocking modal dialog — Penguin UI's "modal" component
|
||||
(https://www.penguinui.com/components/modal, modern style), with the dark
|
||||
variants dropped because the app has no dark theme.
|
||||
Blocking failure modal — Penguin UI's danger modal, taken from
|
||||
penguinui-components/modal/modal-alerts.html.
|
||||
|
||||
It is Tailwind + Alpine markup, so a page that calls this macro must load
|
||||
both in its `head` block; `pages/add_table/add_table.html` shows the set.
|
||||
The `@theme` block there maps Penguin UI's semantic colour names onto the
|
||||
palette in `static/app.css`.
|
||||
Same deal as ui/alert.html: the component's copy lives in its markup, so this
|
||||
is the library file's danger variant with its text nodes replaced and nothing
|
||||
else changed. Two structural edits, both because the server, not a click,
|
||||
decides when this appears:
|
||||
|
||||
Rendered already open (`modalIsOpen: true`): the server only sends the
|
||||
dialog when there is something the user has to be told, so there is no
|
||||
trigger button — the response itself is the trigger.
|
||||
- the library's trigger button is dropped, and `dangerModalIsOpen` starts
|
||||
`true`. The server only sends the dialog when there is something the user
|
||||
has to be told, so the response itself is the trigger.
|
||||
- the footer button dismisses instead of acting ("Back to the form"): a
|
||||
failure has nothing to confirm.
|
||||
|
||||
It is Tailwind + Alpine markup; x-trap needs the focus plugin, which
|
||||
ui/base.html loads before Alpine itself.
|
||||
|
||||
{% import "ui/dialog.html" as dialog %}
|
||||
{% call dialog::error("Could not add the column", message) %}{% endcall %}
|
||||
#}
|
||||
{% macro error(title, message) %}
|
||||
<div x-data="{ modalIsOpen: true }">
|
||||
<div x-cloak x-show="modalIsOpen" x-transition.opacity.duration.200ms
|
||||
x-trap.inert.noscroll="modalIsOpen"
|
||||
x-on:keydown.esc.window="modalIsOpen = false" x-on:click.self="modalIsOpen = false"
|
||||
class="fixed inset-0 z-30 flex items-end justify-center bg-surfaceDark/20 p-4 pb-8 backdrop-blur-xs sm:items-center lg:p-8"
|
||||
role="dialog" aria-modal="true" aria-labelledby="dialogTitle">
|
||||
<!-- Modal Dialog -->
|
||||
<div x-show="modalIsOpen"
|
||||
x-transition:enter="transition delay-100 duration-200 ease-out motion-reduce:transition-opacity"
|
||||
x-transition:enter-start="scale-50 opacity-0" x-transition:enter-end="scale-100 opacity-100"
|
||||
class="flex max-w-lg flex-col gap-4 overflow-hidden rounded-lg border border-outline bg-surface text-onSurface">
|
||||
<!-- Dialog Header -->
|
||||
<div class="flex items-center justify-between border-b border-outline bg-surfaceAlt/60 p-4">
|
||||
<h3 id="dialogTitle" class="font-semibold tracking-wide text-danger">{{ title }}</h3>
|
||||
<button type="button" x-on:click="modalIsOpen = false" class="cursor-pointer text-onSurface" aria-label="close dialog">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor"
|
||||
fill="none" stroke-width="1.4" class="h-5 w-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Dialog Body -->
|
||||
<div class="px-4 py-4">
|
||||
<p class="text-pretty whitespace-pre-wrap">{{ message }}</p>
|
||||
</div>
|
||||
<!-- Dialog Footer -->
|
||||
<div class="flex flex-col-reverse justify-between gap-2 border-t border-outline bg-surfaceAlt/60 p-4 sm:flex-row sm:items-center md:justify-end">
|
||||
<button type="button" x-on:click="modalIsOpen = false"
|
||||
class="cursor-pointer rounded-md whitespace-nowrap bg-primary px-4 py-2 text-center text-sm font-medium tracking-wide text-onPrimary transition hover:opacity-75 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary active:opacity-100 active:outline-offset-0">
|
||||
Back to the form
|
||||
</button>
|
||||
</div>
|
||||
<div x-data="{ dangerModalIsOpen: true }">
|
||||
<div x-cloak x-show="dangerModalIsOpen" x-transition.opacity.duration.200ms x-trap.inert.noscroll="dangerModalIsOpen" x-on:keydown.esc.window="dangerModalIsOpen = false" x-on:click.self="dangerModalIsOpen = false" class="fixed inset-0 z-30 flex items-end justify-center bg-black/20 p-4 pb-8 backdrop-blur-md sm:items-center lg:p-8" role="dialog" aria-modal="true" aria-labelledby="dangerModalTitle">
|
||||
<!-- Modal Dialog -->
|
||||
<div x-show="dangerModalIsOpen" x-transition:enter="transition ease-out duration-200 delay-100 motion-reduce:transition-opacity" x-transition:enter-start="opacity-0 scale-50" x-transition:enter-end="opacity-100 scale-100" class="flex max-w-lg flex-col gap-4 overflow-hidden rounded-radius border border-outline bg-surface text-on-surface dark:border-outline-dark dark:bg-surface-dark-alt dark:text-on-surface-dark">
|
||||
<!-- Dialog Header -->
|
||||
<div class="flex items-center justify-between border-b border-outline bg-surface-alt/60 px-4 py-2 dark:border-outline-dark dark:bg-surface-dark/20">
|
||||
<div class="flex items-center justify-center rounded-full bg-danger/20 text-danger p-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="size-6" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16ZM8.28 7.22a.75.75 0 0 0-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 1 0 1.06 1.06L10 11.06l1.72 1.72a.75.75 0 1 0 1.06-1.06L11.06 10l1.72-1.72a.75.75 0 0 0-1.06-1.06L10 8.94 8.28 7.22Z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<button x-on:click="dangerModalIsOpen = false" aria-label="close modal">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" stroke="currentColor" fill="none" stroke-width="1.4" class="w-5 h-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Dialog Body -->
|
||||
<div class="px-4 text-center">
|
||||
<h3 id="dangerModalTitle" class="mb-2 font-semibold tracking-wide text-on-surface-strong dark:text-on-surface-dark-strong">{{ title }}</h3>
|
||||
<p class="whitespace-pre-wrap">{{ message }}</p>
|
||||
</div>
|
||||
<!-- Dialog Footer -->
|
||||
<div class="flex items-center justify-center border-outline p-4 dark:border-outline-dark">
|
||||
<button x-on:click="dangerModalIsOpen = false" type="button" class="w-full whitespace-nowrap rounded-radius border border-danger bg-danger px-4 py-2 text-center text-sm font-semibold tracking-wide text-on-danger transition hover:opacity-75 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-danger active:opacity-100 active:outline-offset-0">Back to the form</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
Reference in New Issue
Block a user