mirror of
https://github.com/hunvreus/basecoat.git
synced 2026-11-11 04:38:18 +00:00
Adding front-end
This commit is contained in:
Vendored
+93
-26
@@ -69,6 +69,8 @@
|
||||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
||||
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
||||
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
||||
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
||||
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
--animate-spin: spin 1s linear infinite;
|
||||
--animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
@@ -531,10 +533,21 @@
|
||||
--tw-translate-y: calc(calc(1/2 * 100%) * -1);
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
}
|
||||
.translate-y-0 {
|
||||
--tw-translate-y: calc(var(--spacing) * 0);
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
}
|
||||
.translate-y-0\.5 {
|
||||
--tw-translate-y: calc(var(--spacing) * 0.5);
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
}
|
||||
.translate-y-2 {
|
||||
--tw-translate-y: calc(var(--spacing) * 2);
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
}
|
||||
.transform {
|
||||
transform: var(--tw-rotate-x) var(--tw-rotate-y) var(--tw-rotate-z) var(--tw-skew-x) var(--tw-skew-y);
|
||||
}
|
||||
.animate-pulse {
|
||||
animation: var(--animate-pulse);
|
||||
}
|
||||
@@ -893,12 +906,18 @@
|
||||
.underline-offset-4 {
|
||||
text-underline-offset: 4px;
|
||||
}
|
||||
.opacity-0 {
|
||||
opacity: 0%;
|
||||
}
|
||||
.opacity-50 {
|
||||
opacity: 50%;
|
||||
}
|
||||
.opacity-60 {
|
||||
opacity: 60%;
|
||||
}
|
||||
.opacity-100 {
|
||||
opacity: 100%;
|
||||
}
|
||||
.shadow-none {
|
||||
--tw-shadow: 0 0 #0000;
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
@@ -928,6 +947,11 @@
|
||||
.filter {
|
||||
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
|
||||
}
|
||||
.transition {
|
||||
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter;
|
||||
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
||||
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
||||
}
|
||||
.transition-\[margin-left\] {
|
||||
transition-property: margin-left;
|
||||
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
||||
@@ -957,10 +981,22 @@
|
||||
--tw-duration: 200ms;
|
||||
transition-duration: 200ms;
|
||||
}
|
||||
.duration-300 {
|
||||
--tw-duration: 300ms;
|
||||
transition-duration: 300ms;
|
||||
}
|
||||
.ease-in {
|
||||
--tw-ease: var(--ease-in);
|
||||
transition-timing-function: var(--ease-in);
|
||||
}
|
||||
.ease-in-out {
|
||||
--tw-ease: var(--ease-in-out);
|
||||
transition-timing-function: var(--ease-in-out);
|
||||
}
|
||||
.ease-out {
|
||||
--tw-ease: var(--ease-out);
|
||||
transition-timing-function: var(--ease-out);
|
||||
}
|
||||
.outline-none {
|
||||
--tw-outline-style: none;
|
||||
outline-style: none;
|
||||
@@ -1378,32 +1414,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.\[\&_a\:not\(\[class\]\)\]\:text-muted-foreground {
|
||||
& a:not([class]) {
|
||||
color: var(--color-muted-foreground);
|
||||
}
|
||||
}
|
||||
.\[\&_a\:not\(\[class\]\)\]\:no-underline {
|
||||
& a:not([class]) {
|
||||
text-decoration-line: none;
|
||||
}
|
||||
}
|
||||
.\[\&_a\:not\(\[class\]\)\]\:transition-colors {
|
||||
& a:not([class]) {
|
||||
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;
|
||||
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
||||
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
||||
}
|
||||
}
|
||||
.\[\&_a\:not\(\[class\]\)\]\:hover\:text-foreground {
|
||||
& a:not([class]) {
|
||||
&:hover {
|
||||
@media (hover: hover) {
|
||||
color: var(--color-foreground);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.\[\&_img\]\:size-8 {
|
||||
& img {
|
||||
width: calc(var(--spacing) * 8);
|
||||
@@ -1537,6 +1547,33 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.\[\&\>\[role\=img\]\]\:size-4 {
|
||||
&>[role=img] {
|
||||
width: calc(var(--spacing) * 4);
|
||||
height: calc(var(--spacing) * 4);
|
||||
}
|
||||
}
|
||||
.\[\&\>\[role\=img\]\]\:shrink-0 {
|
||||
&>[role=img] {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
.\[\&\>\[role\=img\]\>svg\]\:size-4 {
|
||||
&>[role=img]>svg {
|
||||
width: calc(var(--spacing) * 4);
|
||||
height: calc(var(--spacing) * 4);
|
||||
}
|
||||
}
|
||||
.\[\&\>\[role\=img\]\>svg\]\:w-full {
|
||||
&>[role=img]>svg {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.\[\&\>\[role\=img\]\>svg\]\:shrink-0 {
|
||||
&>[role=img]>svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
.\[\&\>h2\]\:mt-16 {
|
||||
&>h2 {
|
||||
margin-top: calc(var(--spacing) * 16);
|
||||
@@ -3946,6 +3983,31 @@
|
||||
inherits: false;
|
||||
initial-value: 0;
|
||||
}
|
||||
@property --tw-rotate-x {
|
||||
syntax: "*";
|
||||
inherits: false;
|
||||
initial-value: rotateX(0);
|
||||
}
|
||||
@property --tw-rotate-y {
|
||||
syntax: "*";
|
||||
inherits: false;
|
||||
initial-value: rotateY(0);
|
||||
}
|
||||
@property --tw-rotate-z {
|
||||
syntax: "*";
|
||||
inherits: false;
|
||||
initial-value: rotateZ(0);
|
||||
}
|
||||
@property --tw-skew-x {
|
||||
syntax: "*";
|
||||
inherits: false;
|
||||
initial-value: skewX(0);
|
||||
}
|
||||
@property --tw-skew-y {
|
||||
syntax: "*";
|
||||
inherits: false;
|
||||
initial-value: skewY(0);
|
||||
}
|
||||
@property --tw-space-y-reverse {
|
||||
syntax: "*";
|
||||
inherits: false;
|
||||
@@ -4160,6 +4222,11 @@
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-translate-z: 0;
|
||||
--tw-rotate-x: rotateX(0);
|
||||
--tw-rotate-y: rotateY(0);
|
||||
--tw-rotate-z: rotateZ(0);
|
||||
--tw-skew-x: skewX(0);
|
||||
--tw-skew-y: skewY(0);
|
||||
--tw-space-y-reverse: 0;
|
||||
--tw-space-x-reverse: 0;
|
||||
--tw-border-style: solid;
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
@param open {boolean} [optional] [default=false] - Whether the dialog should be open initially.
|
||||
@param close_button {boolean} [optional] [default=true] - Whether to include a close button.
|
||||
@param close_on_overlay_click {boolean} [optional] [default=true] - Whether clicking the overlay closes the dialog.
|
||||
@param include_html {boolean} [optional] [default=true] - Whether to render the HTML structure.
|
||||
@param include_script {boolean} [optional] [default=true] - Whether to include the Alpine.js component script.
|
||||
@param register_on {array} [optional] [default=["alpine:init"]] - Alpine.js events to register the component on.
|
||||
#}
|
||||
@@ -34,7 +33,6 @@
|
||||
open=false,
|
||||
close_button=true,
|
||||
close_on_overlay_click=true,
|
||||
include_html=true,
|
||||
include_script=false,
|
||||
register_on=["alpine:init"]
|
||||
) %}
|
||||
@@ -42,7 +40,6 @@
|
||||
{% include "components/dialog-script.njk" %}
|
||||
{% endif %}
|
||||
|
||||
{% if include_html %}
|
||||
<div
|
||||
id="{{ id }}"
|
||||
x-data="dialog({{ 'true' if open else 'false' }}, {{ 'true' if close_on_overlay_click else 'false' }})"
|
||||
@@ -55,7 +52,6 @@
|
||||
{% if trigger %}
|
||||
<button
|
||||
type="button"
|
||||
{% if id %}aria-controls="{{ id }}-dialog"{% endif %}
|
||||
aria-expanded="false"
|
||||
aria-controls="{{ id }}-dialog"
|
||||
x-bind="$trigger"
|
||||
@@ -120,5 +116,4 @@
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
@@ -4,7 +4,6 @@
|
||||
main_attrs={},
|
||||
trigger_attrs={},
|
||||
content_attrs={},
|
||||
include_html=true,
|
||||
include_script=false,
|
||||
register_on=["alpine:init"]
|
||||
) %}
|
||||
@@ -12,7 +11,6 @@
|
||||
{% include "components/dropdown-menu-script.njk" %}
|
||||
{% endif %}
|
||||
|
||||
{% if include_html %}
|
||||
<div
|
||||
class="popover {{ main_attrs.class }}"
|
||||
x-data="dropdownMenu"
|
||||
@@ -53,5 +51,4 @@
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% endmacro %}
|
||||
@@ -4,7 +4,6 @@
|
||||
main_attrs=None,
|
||||
trigger_attrs=None,
|
||||
content_attrs=None,
|
||||
include_html=true,
|
||||
include_script=false,
|
||||
register_on=["alpine:init"]
|
||||
) %}
|
||||
@@ -12,7 +11,6 @@
|
||||
{% include "components/popover-script.njk" %}
|
||||
{% endif %}
|
||||
|
||||
{% if include_html %}
|
||||
<div
|
||||
class="popover {{ main_attrs.class }}"
|
||||
x-data="popover"
|
||||
@@ -51,5 +49,4 @@
|
||||
{% if caller %}{{ caller() }}{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
const option = this.options.find(opt => opt.getAttribute('data-value') === initialValue);
|
||||
this.selectOption(option, false);
|
||||
this.focusedIndex = this.options.indexOf(option);
|
||||
this.focusOption();
|
||||
} else {
|
||||
this.selectOption(this.options[0], false);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
input_attrs={},
|
||||
search_placeholder="Search entries...",
|
||||
is_combobox=false,
|
||||
include_html=true,
|
||||
include_script=false,
|
||||
register_on=["alpine:init"]
|
||||
) %}
|
||||
@@ -17,7 +16,6 @@
|
||||
{% include "components/select-script.njk" %}
|
||||
{% endif %}
|
||||
|
||||
{% if include_html %}
|
||||
<div
|
||||
class="popover {{ main_attrs.class }}"
|
||||
x-data="select('{{ name }}', '{{ selected or '' }}')"
|
||||
@@ -99,5 +97,4 @@
|
||||
>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
@@ -4,7 +4,6 @@
|
||||
main_attrs=None,
|
||||
tablist_attrs=None,
|
||||
default_tab_index=1,
|
||||
include_html=true,
|
||||
include_script=false,
|
||||
register_on=["alpine:init"]
|
||||
)
|
||||
@@ -13,7 +12,6 @@
|
||||
{% include "components/tabs-script.njk" %}
|
||||
{% endif %}
|
||||
|
||||
{% if include_html %}
|
||||
<div
|
||||
class="tabs {{ main_attrs.class }}"
|
||||
x-data="tabs({{ default_tab_index - 1 }})"
|
||||
@@ -65,5 +63,4 @@
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
@@ -4,13 +4,14 @@
|
||||
|
||||
const registerToastComponent = () => {
|
||||
Alpine.store('toaster', { isPaused: false });
|
||||
Alpine.data('toast', (category = '', timeoutDuration = null) => ({
|
||||
Alpine.data('toast', (config={}) => ({
|
||||
config: config,
|
||||
open: false,
|
||||
timeoutDuration: null,
|
||||
timeoutId: null,
|
||||
|
||||
init() {
|
||||
this.timeoutDuration = timeoutDuration || (category === 'error' ? 5000 : 3000);
|
||||
this.timeoutDuration = config.duration || (config.category === 'error' ? 5000 : 3000);
|
||||
this.timeoutId = setTimeout(() => { this.close() }, this.timeoutDuration);
|
||||
this.open = true;
|
||||
this.$watch('$store.toaster.isPaused', (isPaused) => {
|
||||
@@ -37,12 +38,34 @@
|
||||
this.$el.blur();
|
||||
},
|
||||
|
||||
$toast: {
|
||||
$toastBindings: {
|
||||
['@mouseenter']() { this.$store.toaster.isPaused = true },
|
||||
['@mouseleave']() { this.$store.toaster.isPaused = false },
|
||||
['@keydown.escape.prevent']() { this.close() },
|
||||
[':aria-hidden']() { return !this.open }
|
||||
},
|
||||
}));
|
||||
|
||||
Alpine.magic('toast', (el) => (config, toasterId='toaster') => {
|
||||
const toaster = document.getElementById(toasterId);
|
||||
const template = document.getElementById('toast-template');
|
||||
|
||||
if (!toaster) {
|
||||
console.error(`Toaster container with id #${targetId} not found.`);
|
||||
return;
|
||||
}
|
||||
if (!template) {
|
||||
console.error('Toast template with id #toast-template not found.');
|
||||
return;
|
||||
}
|
||||
|
||||
const clone = template.content.firstElementChild.cloneNode(true);
|
||||
|
||||
clone.setAttribute('x-data', `toast(${JSON.stringify(config)})`);
|
||||
clone.removeAttribute('id');
|
||||
|
||||
toaster.appendChild(clone);
|
||||
});
|
||||
}
|
||||
|
||||
{% for event in (register_on or ["alpine:init"]) %}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
toasts=[],
|
||||
main_attrs=None,
|
||||
is_fragment=false,
|
||||
include_html=true,
|
||||
include_script=false,
|
||||
register_on=["alpine:init"]
|
||||
) %}
|
||||
@@ -11,12 +10,11 @@
|
||||
{% include "components/toast-script.njk" %}
|
||||
{% endif %}
|
||||
|
||||
{% if include_html %}
|
||||
{% set iconMapping = {
|
||||
'error': 'circle-x',
|
||||
'success': 'circle-check',
|
||||
'info': 'info',
|
||||
'warning': 'circle-alert'
|
||||
{% set icons = {
|
||||
'success': '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-check-icon lucide-circle-check"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>',
|
||||
'error': '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-x-icon lucide-circle-x"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>',
|
||||
'info': '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-info-icon lucide-info"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>',
|
||||
'warning': '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-triangle-alert-icon lucide-triangle-alert"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>'
|
||||
} %}
|
||||
|
||||
<div
|
||||
@@ -33,56 +31,51 @@
|
||||
role="{{ 'alert' if toast.category == 'error' else 'status' }}"
|
||||
aria-atomic="true"
|
||||
aria-hidden="false"
|
||||
:aria-hidden="!open"
|
||||
{% if toast.category %}data-category="{{ toast.category }}"{% endif %}
|
||||
x-data="toast('{{ toast.category }}', {{ toast.timeoutDuration }})"
|
||||
x-bind="$toast"
|
||||
x-data="toast('{{ toast.category }}', {{ toast.duration }})"
|
||||
x-bind="$toastBindings"
|
||||
>
|
||||
<div class="toast-content">
|
||||
<div class="flex items-center justify-between gap-x-3 p-4">
|
||||
{% if toast.category in ["error", "success", "info", "warning"] %}
|
||||
{% lucide iconMapping[toast.category], class="size-4 shrink-0" %}
|
||||
{{ icons[toast.category] | safe }}
|
||||
{% endif %}
|
||||
<section class="flex-1 flex flex-col gap-0.5 items-start">
|
||||
{% if toast.message is string %}
|
||||
<h2 class="font-medium">{{ toast.message }}</h2>
|
||||
{% elif toast.message is mapping %}
|
||||
{% if toast.message.title %}
|
||||
<h2 class="font-medium">{{ toast.message.title }}</h2>
|
||||
{% endif %}
|
||||
{% if toast.message.description %}
|
||||
<p class="text-muted-foreground">{{ toast.message.description }}</p>
|
||||
{% endif %}
|
||||
{% if toast.title %}
|
||||
<h2 class="font-medium">{{ toast.title }}</h2>
|
||||
{% endif %}
|
||||
{% if toast.description %}
|
||||
<p class="text-muted-foreground">{{ toast.description }}</p>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% if toast.message.action or toast.message.cancel %}
|
||||
{% if toast.action or toast.cancel %}
|
||||
<footer class="flex flex-col gap-1 self-start">
|
||||
{% if toast.message.action %}
|
||||
{% if toast.message.action.click %}
|
||||
{% if toast.action %}
|
||||
{% if toast.action.click %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn h-6 text-xs px-2.5 rounded-sm"
|
||||
@click="{{ toast.message.action.click }}"
|
||||
>{{ toast.message.action.label }}</button>
|
||||
{% elif toast.message.action.url %}
|
||||
@click="{{ toast.action.click }}"
|
||||
>{{ toast.action.label }}</button>
|
||||
{% elif toast.action.url %}
|
||||
<a
|
||||
href="{{ toast.message.action.url }}"
|
||||
href="{{ toast.action.url }}"
|
||||
class="btn h-6 text-xs px-2.5 rounded-sm"
|
||||
>{{ toast.message.action.label }}</a>
|
||||
>{{ toast.action.label }}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if toast.message.cancel %}
|
||||
{% if toast.message.cancel.click %}
|
||||
{% if toast.cancel %}
|
||||
{% if toast.cancel.click %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn-outline h-6 text-xs px-2.5 rounded-sm"
|
||||
@click="{{ toast.message.cancel.click }}"
|
||||
>{{ toast.message.cancel.label }}</button>
|
||||
{% elif toast.message.cancel.url %}
|
||||
@click="{{ toast.cancel.click }}"
|
||||
>{{ toast.cancel.label }}</button>
|
||||
{% elif toast.cancel.url %}
|
||||
<a
|
||||
href="{{ toast.message.cancel.url }}"
|
||||
href="{{ toast.cancel.url }}"
|
||||
class="btn-outline h-6 text-xs px-2.5 rounded-sm"
|
||||
>{{ toast.message.cancel.label }}</a>
|
||||
>{{ toast.cancel.label }}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</footer>
|
||||
@@ -92,5 +85,76 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% if not is_fragment %}
|
||||
<template id="toast-template">
|
||||
<div
|
||||
class="toast"
|
||||
role="status"
|
||||
aria-atomic="true"
|
||||
x-bind="$toastBindings"
|
||||
>
|
||||
<div class="toast-content">
|
||||
<div class="flex items-center justify-between gap-x-3 p-4 [&>svg]:size-4 [&>svg]:shrink-0 [&>[role=img]]:size-4 [&>[role=img]]:shrink-0 [&>[role=img]>svg]:size-4">
|
||||
<template x-if="config.icon">
|
||||
<span aria-hidden="true" role="img" x-html="config.icon"></span>
|
||||
</template>
|
||||
<template x-if="!config.icon && config.category === 'success'">
|
||||
{{ icons.success | safe }}
|
||||
</template>
|
||||
<template x-if="!config.icon && config.category === 'error'">
|
||||
{{ icons.error | safe }}
|
||||
</template>
|
||||
<template x-if="!config.icon && config.category === 'info'">
|
||||
{{ icons.info | safe }}
|
||||
</template>
|
||||
<template x-if="!config.icon && config.category === 'warning'">
|
||||
{{ icons.warning | safe }}
|
||||
</template>
|
||||
<section class="flex-1 flex flex-col gap-0.5 items-start">
|
||||
<template x-if="config.title">
|
||||
<h2 class="font-medium" x-text="config.title"></h2>
|
||||
</template>
|
||||
<template x-if="config.description">
|
||||
<p class="text-muted-foreground" x-text="config.description"></p>
|
||||
</template>
|
||||
</section>
|
||||
<template x-if="config.action || config.cancel">
|
||||
<footer class="flex flex-col gap-1 self-start">
|
||||
<template x-if="config.action?.click">
|
||||
<button
|
||||
type="button"
|
||||
class="btn h-6 text-xs px-2.5 rounded-sm"
|
||||
@click="$evaluate(config.action.click)"
|
||||
x-text="config.action.label"
|
||||
></button>
|
||||
</template>
|
||||
<template x-if="config.action?.url">
|
||||
<a
|
||||
:href="config.action.url"
|
||||
class="btn h-6 text-xs px-2.5 rounded-sm"
|
||||
x-text="config.action.label"
|
||||
></a>
|
||||
</template>
|
||||
<template x-if="config.cancel?.click">
|
||||
<button
|
||||
type="button"
|
||||
class="btn-outline h-6 text-xs px-2.5 rounded-sm"
|
||||
@click="$evaluate(config.cancel.click)"
|
||||
x-text="config.cancel.label"
|
||||
></button>
|
||||
</template>
|
||||
<template x-if="config.cancel?.url">
|
||||
<a
|
||||
:href="config.cancel.url"
|
||||
class="btn-outline h-6 text-xs px-2.5 rounded-sm"
|
||||
x-text="config.cancel.label"
|
||||
></a>
|
||||
</template>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
@@ -31,7 +31,7 @@
|
||||
<header class="flex flex-col gap-2 p-2">
|
||||
<a href="/" class="btn-ghost p-2 h-12 w-full justify-start">
|
||||
<div class="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg">
|
||||
{% lucide "paint-roller", { "class": "size-4" } %}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" class="h-4 w-4"><rect width="256" height="256" fill="none"></rect><line x1="208" y1="128" x2="128" y2="208" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></line><line x1="192" y1="40" x2="40" y2="192" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></line></svg>
|
||||
</div>
|
||||
<div class="grid flex-1 text-left text-sm leading-tight">
|
||||
<span class="truncate font-medium">Basecoat</span>
|
||||
|
||||
@@ -5,10 +5,32 @@ description: A succinct message that is displayed temporarily.
|
||||
---
|
||||
|
||||
{% from "macros/code_preview.njk" import code_preview %}
|
||||
{% set code %}<button class="btn-outline" hx-trigger="click" hx-get="/fragments/toast/success" hx-target="#toast-htmx">
|
||||
Success
|
||||
{% set code %}<button
|
||||
class="btn-outline"
|
||||
hx-trigger="click"
|
||||
hx-get="/fragments/toast/success"
|
||||
hx-target="#toast-htmx"
|
||||
>
|
||||
Toast from backend
|
||||
</button>
|
||||
<div id="toast-htmx"></div>{% endset %}
|
||||
{{ code_preview("accordion", code, "max-w-md") }}
|
||||
{{ code_preview("toast-htmx", code, "max-w-md") }}
|
||||
|
||||
<h2>Usage</h2>
|
||||
{% from "macros/code_preview.njk" import code_preview %}
|
||||
{% set code %}<button
|
||||
class="btn-outline"
|
||||
@click='
|
||||
$toast({
|
||||
category: "success",
|
||||
title: "Great success",
|
||||
description: "Tremendous success toast.",
|
||||
action: {
|
||||
label: "Go to Google",
|
||||
url: "https://google.com"
|
||||
}
|
||||
})
|
||||
'>
|
||||
Toast from front-end
|
||||
</button>
|
||||
{% endset %}
|
||||
{{ code_preview("toast-alpine", code, "max-w-md") }}
|
||||
@@ -1,9 +1,7 @@
|
||||
{% from "../../_includes/components/toast.njk" import toaster %}
|
||||
{% set toasts = [{
|
||||
category: "error",
|
||||
message: {
|
||||
title: "Event has not been created",
|
||||
cancel: { label: "Dismiss", click: "close()" }
|
||||
}
|
||||
title: "Event has not been created",
|
||||
cancel: { label: "Dismiss", click: "close()" }
|
||||
}] %}
|
||||
{{ toaster(toasts=toasts, is_fragment=true) }}
|
||||
@@ -1,8 +1,6 @@
|
||||
{% from "../../_includes/components/toast.njk" import toaster %}
|
||||
{% set toasts = [{
|
||||
category: "info",
|
||||
message: {
|
||||
title: "Be at the area 10 minutes before the event time"
|
||||
}
|
||||
title: "Be at the area 10 minutes before the event time"
|
||||
}] %}
|
||||
{{ toaster(toasts=toasts, is_fragment=true) }}
|
||||
@@ -1,9 +1,7 @@
|
||||
{% from "../../_includes/components/toast.njk" import toaster %}
|
||||
{% set toasts = [{
|
||||
message: {
|
||||
title: "Event has been created",
|
||||
description: "Sunday, December 03, 2023 at 9:00 AM",
|
||||
cancel: { label: "Undo", click: "close()" }
|
||||
}
|
||||
title: "Event has been created",
|
||||
description: "Sunday, December 03, 2023 at 9:00 AM",
|
||||
cancel: { label: "Undo", click: "close()" }
|
||||
}] %}
|
||||
{{ toaster(toasts=toasts, is_fragment=true) }}
|
||||
@@ -1,8 +1,6 @@
|
||||
{% from "../../_includes/components/toast.njk" import toaster %}
|
||||
{% set toasts = [{
|
||||
category: "warning",
|
||||
message: {
|
||||
title: "Event start time cannot be earlier than 8am"
|
||||
}
|
||||
title: "Event start time cannot be earlier than 8am"
|
||||
}] %}
|
||||
{{ toaster(toasts=toasts, is_fragment=true) }}
|
||||
Reference in New Issue
Block a user