104 lines
4.3 KiB
HTML
104 lines
4.3 KiB
HTML
{#
|
|
The shell every full page extends. A page template overrides `title`,
|
|
optionally `head` (extra scripts) and `body_class`, and always `content`.
|
|
|
|
Every page struct must carry a `nav: crate::ui::Nav` field, because the
|
|
navbar component below reads it.
|
|
#}
|
|
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>{% block title %}Komp Accounting{% endblock %} · Komp Accounting</title>
|
|
{#
|
|
Cascade order, declared before anything ships CSS so that it is this line
|
|
that decides it. `app` is static/app.css, which is wrapped in that layer:
|
|
it sits above Tailwind's preflight — so the reset cannot touch the site's
|
|
own look — and below Tailwind's utilities, so a utility class put on an
|
|
element still wins. That is what makes Tailwind usable here one element at
|
|
a time, without converting the stylesheet.
|
|
#}
|
|
<style>@layer theme, base, app, components, utilities;</style>
|
|
<link rel="stylesheet" href="/static/app.css">
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2/dist/htmx.min.js"></script>
|
|
|
|
{#
|
|
Penguin UI (https://www.penguinui.com) is Tailwind + Alpine, and its
|
|
components are what this app uses for anything the user has to be told:
|
|
ui/alert.html and ui/dialog.html. The focus plugin is what x-trap in the
|
|
dialog needs, and it has to load before Alpine itself.
|
|
#}
|
|
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
|
<style type="text/tailwindcss">
|
|
/* Penguin UI's "modern" theme setup: its semantic names, this app's palette. */
|
|
@theme {
|
|
--color-surface: #ffffff;
|
|
--color-surfaceAlt: #f3f5f7;
|
|
--color-surfaceDark: #152238;
|
|
--color-onSurface: #465267;
|
|
--color-onSurfaceStrong: #17202a;
|
|
--color-outline: #d9dfe7;
|
|
--color-primary: #2563eb;
|
|
--color-onPrimary: #ffffff;
|
|
--color-danger: #9d342d;
|
|
--color-success: #21643a;
|
|
|
|
/*
|
|
The same palette again under the names penguinui-components/style.css
|
|
declares, for the component files this app includes from the library
|
|
unmodified rather than copying — currently the toast. The copies above
|
|
renamed these; a file used as the library ships it cannot be renamed,
|
|
so the theme answers to both spellings.
|
|
*/
|
|
--color-surface-alt: #f3f5f7;
|
|
--color-on-surface: #465267;
|
|
--color-on-surface-strong: #17202a;
|
|
--color-on-primary: #ffffff;
|
|
--color-info: #1d4e89;
|
|
--color-on-info: #ffffff;
|
|
--color-on-success: #ffffff;
|
|
--color-warning: #8a5a08;
|
|
--color-on-warning: #ffffff;
|
|
--color-on-danger: #ffffff;
|
|
--radius-radius: 6px;
|
|
}
|
|
</style>
|
|
<script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/focus@3/dist/cdn.min.js"></script>
|
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3/dist/cdn.min.js"></script>
|
|
|
|
<script>
|
|
// htmx only swaps 2xx responses. Every form in this app answers a failure
|
|
// with a status that says so — 422 for a rejected draft, 403 for a lost
|
|
// session, 502 for an unreachable backend — so the markup explaining the
|
|
// failure was rendered, returned, and then thrown away, and the page did
|
|
// nothing at all. Swap it instead; the response body is the explanation.
|
|
document.addEventListener('htmx:beforeSwap', function (event) {
|
|
if (event.detail.xhr.status >= 400) {
|
|
event.detail.shouldSwap = true;
|
|
event.detail.isError = false;
|
|
}
|
|
});
|
|
</script>
|
|
{% block head %}{% endblock %}
|
|
</head>
|
|
<body>
|
|
{% include "ui/navbar.html" %}
|
|
{% block content %}{% endblock %}
|
|
{#
|
|
Penguin UI's stacking toast notification, straight out of the library and
|
|
unmodified — askama.toml puts penguinui-components on the template path, so
|
|
this is the library's file, not a copy of it.
|
|
|
|
Mounted once per page and deliberately outside the block every fragment
|
|
swaps into: a success is announced by a fragment dispatching `notify` (see
|
|
ui/toast.html), and the toast showing it has to outlive the swap that
|
|
follows. The component file also ships the demo buttons that trigger it in
|
|
the library's own preview; `.penguin-toast > button` in static/app.css is
|
|
what keeps those off the page.
|
|
#}
|
|
<div class="penguin-toast">{% include "toast-notification/stacking-toast-notification.html" %}</div>
|
|
</body>
|
|
</html>
|