mirror of
https://github.com/hunvreus/basecoat.git
synced 2026-11-11 04:38:18 +00:00
Added toasts, fixed some combobox and select issues
This commit is contained in:
Vendored
+226
-214
@@ -311,9 +311,6 @@
|
||||
.mr-auto {
|
||||
margin-right: auto;
|
||||
}
|
||||
.mb-1 {
|
||||
margin-bottom: calc(var(--spacing) * 1);
|
||||
}
|
||||
.ml-\(--sidebar-width\) {
|
||||
margin-left: var(--sidebar-width);
|
||||
}
|
||||
@@ -371,6 +368,9 @@
|
||||
.h-4 {
|
||||
height: calc(var(--spacing) * 4);
|
||||
}
|
||||
.h-6 {
|
||||
height: calc(var(--spacing) * 6);
|
||||
}
|
||||
.h-8 {
|
||||
height: calc(var(--spacing) * 8);
|
||||
}
|
||||
@@ -538,6 +538,9 @@
|
||||
.gap-x-2 {
|
||||
column-gap: calc(var(--spacing) * 2);
|
||||
}
|
||||
.gap-x-3 {
|
||||
column-gap: calc(var(--spacing) * 3);
|
||||
}
|
||||
.-space-x-2 {
|
||||
:where(& > :not(:last-child)) {
|
||||
--tw-space-x-reverse: 0;
|
||||
@@ -554,6 +557,9 @@
|
||||
.gap-y-10 {
|
||||
row-gap: calc(var(--spacing) * 10);
|
||||
}
|
||||
.self-start {
|
||||
align-self: flex-start;
|
||||
}
|
||||
.truncate {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -574,6 +580,9 @@
|
||||
.rounded-md {
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
.rounded-sm {
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
.border {
|
||||
border-style: var(--tw-border-style);
|
||||
border-width: 1px;
|
||||
@@ -674,9 +683,6 @@
|
||||
.px-4 {
|
||||
padding-inline: calc(var(--spacing) * 4);
|
||||
}
|
||||
.py-0\.5 {
|
||||
padding-block: calc(var(--spacing) * 0.5);
|
||||
}
|
||||
.py-1\.5 {
|
||||
padding-block: calc(var(--spacing) * 1.5);
|
||||
}
|
||||
@@ -1366,12 +1372,12 @@
|
||||
display: none !important;
|
||||
}
|
||||
.htmx-indicator {
|
||||
transition-behavior: allow-discrete;
|
||||
visibility: hidden;
|
||||
opacity: 0%;
|
||||
transition-property: all;
|
||||
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
||||
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
||||
transition-behavior: allow-discrete;
|
||||
}
|
||||
.htmx-indicator:not(.htmx-request) {
|
||||
display: none;
|
||||
@@ -1817,6 +1823,59 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
@layer components {
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: calc(var(--spacing) * 6);
|
||||
border-radius: var(--radius-xl);
|
||||
border-style: var(--tw-border-style);
|
||||
border-width: 1px;
|
||||
background-color: var(--color-card);
|
||||
padding-block: calc(var(--spacing) * 6);
|
||||
color: var(--color-card-foreground);
|
||||
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
> header {
|
||||
container-type: inline-size;
|
||||
container-name: card-header;
|
||||
display: grid;
|
||||
grid-auto-rows: min-content;
|
||||
grid-template-rows: auto auto;
|
||||
align-items: flex-start;
|
||||
gap: calc(var(--spacing) * 1.5);
|
||||
padding-inline: calc(var(--spacing) * 6);
|
||||
&:has(*[data-slot="card-action"]) {
|
||||
grid-template-columns: 1fr auto;
|
||||
}
|
||||
&:is(.border-b) {
|
||||
padding-bottom: calc(var(--spacing) * 6);
|
||||
}
|
||||
h2 {
|
||||
--tw-leading: 1;
|
||||
line-height: 1;
|
||||
--tw-font-weight: var(--font-weight-semibold);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
}
|
||||
p {
|
||||
font-size: var(--text-sm);
|
||||
line-height: var(--tw-leading, var(--text-sm--line-height));
|
||||
color: var(--color-muted-foreground);
|
||||
}
|
||||
}
|
||||
> section {
|
||||
padding-inline: calc(var(--spacing) * 6);
|
||||
}
|
||||
> footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-inline: calc(var(--spacing) * 6);
|
||||
&:is(.border-t) {
|
||||
padding-top: calc(var(--spacing) * 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@layer components {
|
||||
.form input[type='checkbox']:not([role='switch']), .input[type='checkbox']:not([role='switch']) {
|
||||
width: calc(var(--spacing) * 4);
|
||||
@@ -2953,6 +3012,105 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
@layer components {
|
||||
.tabs {
|
||||
[role='tablist'] {
|
||||
display: inline-flex;
|
||||
height: calc(var(--spacing) * 9);
|
||||
width: fit-content;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: var(--radius-lg);
|
||||
background-color: var(--color-muted);
|
||||
padding: 3px;
|
||||
color: var(--color-muted-foreground);
|
||||
[role='tab'] {
|
||||
display: inline-flex;
|
||||
height: calc(100% - 1px);
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: calc(var(--spacing) * 1.5);
|
||||
border-radius: var(--radius-md);
|
||||
border-style: var(--tw-border-style);
|
||||
border-width: 1px;
|
||||
border-color: transparent;
|
||||
padding-inline: calc(var(--spacing) * 2);
|
||||
padding-block: calc(var(--spacing) * 1);
|
||||
font-size: var(--text-sm);
|
||||
line-height: var(--tw-leading, var(--text-sm--line-height));
|
||||
--tw-font-weight: var(--font-weight-medium);
|
||||
font-weight: var(--font-weight-medium);
|
||||
white-space: nowrap;
|
||||
color: var(--color-foreground);
|
||||
transition-property: color,box-shadow;
|
||||
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
||||
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
||||
&:focus-visible {
|
||||
border-color: var(--color-ring);
|
||||
}
|
||||
&:focus-visible {
|
||||
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
&:focus-visible {
|
||||
--tw-ring-color: color-mix(in srgb, var(--ring) 50%, transparent);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
--tw-ring-color: color-mix(in oklab, var(--color-ring) 50%, transparent);
|
||||
}
|
||||
}
|
||||
&:focus-visible {
|
||||
outline-style: var(--tw-outline-style);
|
||||
outline-width: 1px;
|
||||
}
|
||||
&:focus-visible {
|
||||
outline-color: var(--color-ring);
|
||||
}
|
||||
&:disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
&:disabled {
|
||||
opacity: 50%;
|
||||
}
|
||||
&:is(.dark *) {
|
||||
color: var(--color-muted-foreground);
|
||||
}
|
||||
& svg {
|
||||
pointer-events: none;
|
||||
}
|
||||
& svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
& svg:not([class*='size-']) {
|
||||
width: calc(var(--spacing) * 4);
|
||||
height: calc(var(--spacing) * 4);
|
||||
}
|
||||
&[aria-selected='true'] {
|
||||
background-color: var(--color-background);
|
||||
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
&:is(.dark *) {
|
||||
border-color: var(--color-input);
|
||||
}
|
||||
&:is(.dark *) {
|
||||
background-color: color-mix(in srgb, var(--input) 30%, transparent);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
background-color: color-mix(in oklab, var(--color-input) 30%, transparent);
|
||||
}
|
||||
}
|
||||
&:is(.dark *) {
|
||||
color: var(--color-foreground);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
[role='tabpanel'] {
|
||||
flex: 1;
|
||||
--tw-outline-style: none;
|
||||
outline-style: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@layer components {
|
||||
.form textarea, .textarea {
|
||||
display: flex;
|
||||
@@ -3026,6 +3184,67 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
@layer components {
|
||||
.toaster {
|
||||
pointer-events: none;
|
||||
position: fixed;
|
||||
right: calc(var(--spacing) * 0);
|
||||
bottom: calc(var(--spacing) * 0);
|
||||
z-index: 50;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: column-reverse;
|
||||
padding: calc(var(--spacing) * 4);
|
||||
@media (width >= 40rem) {
|
||||
max-width: calc(var(--spacing) * 90);
|
||||
}
|
||||
.toast {
|
||||
pointer-events: auto;
|
||||
margin-top: calc(var(--spacing) * 4);
|
||||
display: grid;
|
||||
width: 100%;
|
||||
animation: toast-in 0.3s ease-in-out;
|
||||
grid-template-rows: 1fr;
|
||||
transition-property: grid-template-rows,opacity,margin;
|
||||
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
||||
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
||||
--tw-duration: 300ms;
|
||||
transition-duration: 300ms;
|
||||
--tw-ease: var(--ease-in-out);
|
||||
transition-timing-function: var(--ease-in-out);
|
||||
.toast-content {
|
||||
overflow: hidden;
|
||||
border-radius: var(--radius-lg);
|
||||
border-style: var(--tw-border-style);
|
||||
border-width: 1px;
|
||||
background-color: var(--color-popover);
|
||||
font-size: 13px;
|
||||
color: var(--color-popover-foreground);
|
||||
--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
&[aria-hidden='true'] {
|
||||
margin: calc(var(--spacing) * 0);
|
||||
grid-template-rows: 0fr;
|
||||
overflow: hidden;
|
||||
border-style: var(--tw-border-style);
|
||||
border-width: 0px;
|
||||
padding: calc(var(--spacing) * 0);
|
||||
opacity: 0%;
|
||||
.toast-content {
|
||||
border-style: var(--tw-border-style);
|
||||
border-width: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@keyframes toast-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
}
|
||||
@layer components {
|
||||
[data-tooltip] {
|
||||
position: relative;
|
||||
@@ -3212,213 +3431,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
@layer components {
|
||||
.toasts {
|
||||
pointer-events: none;
|
||||
position: fixed;
|
||||
right: calc(var(--spacing) * 0);
|
||||
bottom: calc(var(--spacing) * 0);
|
||||
z-index: 100;
|
||||
max-width: var(--container-sm);
|
||||
:where(& > :not(:last-child)) {
|
||||
--tw-space-y-reverse: 0;
|
||||
margin-block-start: calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));
|
||||
margin-block-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)));
|
||||
}
|
||||
padding: calc(var(--spacing) * 6);
|
||||
}
|
||||
.toasts > [role='alert'], .toasts > [role='status'] {
|
||||
transition-behavior: allow-discrete;
|
||||
pointer-events: auto;
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
column-gap: calc(var(--spacing) * 2);
|
||||
border-radius: var(--radius-lg);
|
||||
border-style: var(--tw-border-style);
|
||||
border-width: 1px;
|
||||
background-color: var(--color-background);
|
||||
padding: calc(var(--spacing) * 4);
|
||||
--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
.toasts > [aria-hidden='true'] {
|
||||
display: none;
|
||||
--tw-scale-x: 75%;
|
||||
--tw-scale-y: 75%;
|
||||
--tw-scale-z: 75%;
|
||||
scale: var(--tw-scale-x) var(--tw-scale-y);
|
||||
opacity: 0%;
|
||||
transition-property: all;
|
||||
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
||||
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
||||
}
|
||||
.toasts > [role='alert'] > button, .toasts > [role='status'] > button {
|
||||
padding-block: calc(var(--spacing) * 0.5);
|
||||
opacity: 50%;
|
||||
transition-property: opacity;
|
||||
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
||||
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
||||
&:hover {
|
||||
@media (hover: hover) {
|
||||
opacity: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@layer components {
|
||||
.tabs {
|
||||
[role='tablist'] {
|
||||
display: inline-flex;
|
||||
height: calc(var(--spacing) * 9);
|
||||
width: fit-content;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: var(--radius-lg);
|
||||
background-color: var(--color-muted);
|
||||
padding: 3px;
|
||||
color: var(--color-muted-foreground);
|
||||
[role='tab'] {
|
||||
display: inline-flex;
|
||||
height: calc(100% - 1px);
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: calc(var(--spacing) * 1.5);
|
||||
border-radius: var(--radius-md);
|
||||
border-style: var(--tw-border-style);
|
||||
border-width: 1px;
|
||||
border-color: transparent;
|
||||
padding-inline: calc(var(--spacing) * 2);
|
||||
padding-block: calc(var(--spacing) * 1);
|
||||
font-size: var(--text-sm);
|
||||
line-height: var(--tw-leading, var(--text-sm--line-height));
|
||||
--tw-font-weight: var(--font-weight-medium);
|
||||
font-weight: var(--font-weight-medium);
|
||||
white-space: nowrap;
|
||||
color: var(--color-foreground);
|
||||
transition-property: color,box-shadow;
|
||||
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
||||
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
||||
&:focus-visible {
|
||||
border-color: var(--color-ring);
|
||||
}
|
||||
&:focus-visible {
|
||||
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
&:focus-visible {
|
||||
--tw-ring-color: color-mix(in srgb, var(--ring) 50%, transparent);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
--tw-ring-color: color-mix(in oklab, var(--color-ring) 50%, transparent);
|
||||
}
|
||||
}
|
||||
&:focus-visible {
|
||||
outline-style: var(--tw-outline-style);
|
||||
outline-width: 1px;
|
||||
}
|
||||
&:focus-visible {
|
||||
outline-color: var(--color-ring);
|
||||
}
|
||||
&:disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
&:disabled {
|
||||
opacity: 50%;
|
||||
}
|
||||
&:is(.dark *) {
|
||||
color: var(--color-muted-foreground);
|
||||
}
|
||||
& svg {
|
||||
pointer-events: none;
|
||||
}
|
||||
& svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
& svg:not([class*='size-']) {
|
||||
width: calc(var(--spacing) * 4);
|
||||
height: calc(var(--spacing) * 4);
|
||||
}
|
||||
&[aria-selected='true'] {
|
||||
background-color: var(--color-background);
|
||||
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
&:is(.dark *) {
|
||||
border-color: var(--color-input);
|
||||
}
|
||||
&:is(.dark *) {
|
||||
background-color: color-mix(in srgb, var(--input) 30%, transparent);
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
background-color: color-mix(in oklab, var(--color-input) 30%, transparent);
|
||||
}
|
||||
}
|
||||
&:is(.dark *) {
|
||||
color: var(--color-foreground);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
[role='tabpanel'] {
|
||||
flex: 1;
|
||||
--tw-outline-style: none;
|
||||
outline-style: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@layer components {
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: calc(var(--spacing) * 6);
|
||||
border-radius: var(--radius-xl);
|
||||
border-style: var(--tw-border-style);
|
||||
border-width: 1px;
|
||||
background-color: var(--color-card);
|
||||
padding-block: calc(var(--spacing) * 6);
|
||||
color: var(--color-card-foreground);
|
||||
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
> header {
|
||||
container-type: inline-size;
|
||||
container-name: card-header;
|
||||
display: grid;
|
||||
grid-auto-rows: min-content;
|
||||
grid-template-rows: auto auto;
|
||||
align-items: flex-start;
|
||||
gap: calc(var(--spacing) * 1.5);
|
||||
padding-inline: calc(var(--spacing) * 6);
|
||||
&:has(*[data-slot="card-action"]) {
|
||||
grid-template-columns: 1fr auto;
|
||||
}
|
||||
&:is(.border-b) {
|
||||
padding-bottom: calc(var(--spacing) * 6);
|
||||
}
|
||||
h2 {
|
||||
--tw-leading: 1;
|
||||
line-height: 1;
|
||||
--tw-font-weight: var(--font-weight-semibold);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
}
|
||||
p {
|
||||
font-size: var(--text-sm);
|
||||
line-height: var(--tw-leading, var(--text-sm--line-height));
|
||||
color: var(--color-muted-foreground);
|
||||
}
|
||||
}
|
||||
> section {
|
||||
padding-inline: calc(var(--spacing) * 6);
|
||||
}
|
||||
> footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-inline: calc(var(--spacing) * 6);
|
||||
&:is(.border-t) {
|
||||
padding-top: calc(var(--spacing) * 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@property --tw-translate-x {
|
||||
syntax: "*";
|
||||
inherits: false;
|
||||
|
||||
Vendored
+76
-72
@@ -1,4 +1,5 @@
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@@ -161,8 +162,7 @@
|
||||
}
|
||||
/* HTMX */
|
||||
.htmx-indicator {
|
||||
transition-behavior: allow-discrete;
|
||||
@apply invisible opacity-0 transition-all;
|
||||
@apply invisible opacity-0 transition-discrete transition-all;
|
||||
}
|
||||
.htmx-indicator:not(.htmx-request) {
|
||||
@apply hidden;
|
||||
@@ -359,6 +359,30 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Card */
|
||||
@layer components {
|
||||
.card {
|
||||
@apply bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm;
|
||||
|
||||
> header {
|
||||
@apply @container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6;
|
||||
|
||||
h2 {
|
||||
@apply leading-none font-semibold;
|
||||
}
|
||||
p {
|
||||
@apply text-muted-foreground text-sm;
|
||||
}
|
||||
}
|
||||
> section {
|
||||
@apply px-6;
|
||||
}
|
||||
> footer {
|
||||
@apply flex items-center px-6 [.border-t]:pt-6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Checkbox */
|
||||
@layer components {
|
||||
.form input[type='checkbox']:not([role='switch']),
|
||||
@@ -377,8 +401,7 @@
|
||||
details {
|
||||
&::details-content {
|
||||
block-size: 0;
|
||||
@apply block opacity-0 transition-discrete
|
||||
transition-all;
|
||||
@apply block opacity-0 transition-discrete transition-all;
|
||||
}
|
||||
&[open]::details-content {
|
||||
block-size: auto;
|
||||
@@ -720,6 +743,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
@layer components {
|
||||
.tabs {
|
||||
[role='tablist'] {
|
||||
@apply bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px];
|
||||
|
||||
[role='tab'] {
|
||||
@apply focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4;
|
||||
|
||||
&[aria-selected='true'] {
|
||||
@apply bg-background dark:text-foreground dark:border-input dark:bg-input/30 shadow-sm;
|
||||
}
|
||||
}
|
||||
}
|
||||
[role='tabpanel'] {
|
||||
@apply flex-1 outline-none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Textarea */
|
||||
@layer components {
|
||||
.form textarea,
|
||||
@@ -728,6 +771,34 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Toasts */
|
||||
@layer components {
|
||||
.toaster {
|
||||
@apply fixed bottom-0 right-0 p-4 pointer-events-none z-50 w-full sm:max-w-90 flex flex-col-reverse;
|
||||
|
||||
.toast {
|
||||
@apply pointer-events-auto w-full mt-4 animate-[toast-in_0.3s_ease-in-out] grid grid-rows-[1fr] transition-[grid-template-rows,opacity,margin] duration-300 ease-in-out;
|
||||
|
||||
.toast-content {
|
||||
@apply text-popover-foreground text-[13px] bg-popover border shadow-lg rounded-lg overflow-hidden;
|
||||
}
|
||||
&[aria-hidden='true'] {
|
||||
@apply grid-rows-[0fr] opacity-0 m-0 border-0 p-0 overflow-hidden;
|
||||
|
||||
.toast-content {
|
||||
@apply border-0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@keyframes toast-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
}
|
||||
|
||||
/* Tooltip */
|
||||
@layer components {
|
||||
[data-tooltip] {
|
||||
@@ -780,71 +851,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
|
||||
/* Notifications */
|
||||
@layer components {
|
||||
.toasts {
|
||||
@apply fixed bottom-0 right-0 p-6 space-y-2 pointer-events-none z-[100] max-w-sm;
|
||||
}
|
||||
.toasts > [role='alert'],
|
||||
.toasts > [role='status'] {
|
||||
transition-behavior: allow-discrete;
|
||||
@apply bg-background border shadow-lg rounded-lg p-4 pointer-events-auto flex flex-row-reverse items-start justify-between gap-x-2;
|
||||
}
|
||||
.toasts > [aria-hidden='true'] {
|
||||
@apply hidden opacity-0 scale-75 transition-all;
|
||||
}
|
||||
.toasts > [role='alert'] > button,
|
||||
.toasts > [role='status'] > button {
|
||||
@apply opacity-50 hover:opacity-100 transition-opacity py-0.5;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
@layer components {
|
||||
.tabs {
|
||||
[role='tablist'] {
|
||||
@apply bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px];
|
||||
|
||||
[role='tab'] {
|
||||
@apply focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4;
|
||||
|
||||
&[aria-selected='true'] {
|
||||
@apply bg-background dark:text-foreground dark:border-input dark:bg-input/30 shadow-sm;
|
||||
}
|
||||
}
|
||||
}
|
||||
[role='tabpanel'] {
|
||||
@apply flex-1 outline-none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Card */
|
||||
@layer components {
|
||||
.card {
|
||||
@apply bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm;
|
||||
|
||||
> header {
|
||||
@apply @container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6;
|
||||
|
||||
h2 {
|
||||
@apply leading-none font-semibold;
|
||||
}
|
||||
p {
|
||||
@apply text-muted-foreground text-sm;
|
||||
}
|
||||
}
|
||||
> section {
|
||||
@apply px-6;
|
||||
}
|
||||
> footer {
|
||||
@apply flex items-center px-6 [.border-t]:pt-6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+101
-123
@@ -1,155 +1,133 @@
|
||||
{% macro toast(
|
||||
id='toasts',
|
||||
messages=None,
|
||||
main_attrs=None
|
||||
{% macro toaster(
|
||||
id="toaster",
|
||||
toasts=[],
|
||||
main_attrs=None,
|
||||
is_fragment=false
|
||||
) %}
|
||||
{% if registerComponent('toast') %}
|
||||
{% if not is_fragment and registerComponent('toast') %}
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('toast', () => ({
|
||||
Alpine.store('toaster', { isPaused: false });
|
||||
Alpine.data('toast', (category = []) => ({
|
||||
open: false,
|
||||
focusedIndex: -1,
|
||||
menuItems: [],
|
||||
timeoutDuration: null,
|
||||
timeoutId: null,
|
||||
|
||||
init() {
|
||||
this.$nextTick(() => {
|
||||
const menuElement = this.$el.querySelector('[role="menu"]');
|
||||
this.menuItems = Array.from(menuElement.querySelectorAll('[role=menuitem]'));
|
||||
this.timeoutDuration = category === 'error' ? 5000 : 3000;
|
||||
this.timeoutId = setTimeout(() => { this.close() }, this.timeoutDuration);
|
||||
this.open = true;
|
||||
this.$watch('$store.toaster.isPaused', (isPaused) => {
|
||||
if (!this.open) return;
|
||||
if (isPaused) {
|
||||
this.pauseTimeout();
|
||||
} else {
|
||||
this.resumeTimeout();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
$trigger: {
|
||||
'@click'() { this.handleClick() },
|
||||
'@keydown.down.prevent'() { this.open && this.nextItem() },
|
||||
':aria-expanded'() { return this.open },
|
||||
':aria-pressed'() { return this.open }
|
||||
pauseTimeout() {
|
||||
clearTimeout(this.timeoutId);
|
||||
this.timeoutId = null;
|
||||
},
|
||||
|
||||
$menu: {
|
||||
'@click'(e) { this.handleMenuItemClick(e) },
|
||||
'@keydown.escape.window'() { this.handleEscape() },
|
||||
'@keydown.down.prevent'() { this.nextItem() },
|
||||
'@keydown.up.prevent'() { this.prevItem() },
|
||||
'@keydown.home.prevent'() { this.focusItem(0) },
|
||||
'@keydown.end.prevent'() { this.focusItem(this.menuItems.length - 1) },
|
||||
':aria-hidden'() { return !this.open },
|
||||
'x-cloak': ''
|
||||
},
|
||||
|
||||
focusItem(index) {
|
||||
if (index >= 0 && index < this.menuItems.length) {
|
||||
this.focusedIndex = index;
|
||||
this.menuItems[index].focus();
|
||||
resumeTimeout(index) {
|
||||
if (this.open && this.timeoutId === null) {
|
||||
this.timeoutId = setTimeout(() => { this.close() }, this.timeoutDuration);
|
||||
}
|
||||
},
|
||||
|
||||
nextItem() {
|
||||
this.focusItem((this.focusedIndex + 1) % this.menuItems.length);
|
||||
close() {
|
||||
this.pauseTimeout();
|
||||
this.open = false;
|
||||
},
|
||||
|
||||
prevItem() {
|
||||
this.focusItem(this.focusedIndex <= 0 ? this.menuItems.length - 1 : this.focusedIndex - 1);
|
||||
},
|
||||
|
||||
handleClick() {
|
||||
this.open = !this.open;
|
||||
this.$nextTick(() => {
|
||||
if(this.open && this.menuItems.length) this.focusItem(0);
|
||||
});
|
||||
},
|
||||
|
||||
handleEscape() {
|
||||
if (this.open) this.open = false;
|
||||
},
|
||||
|
||||
handleMenuItemClick(event) {
|
||||
const menuItem = event.target.closest('[role=menuitem]');
|
||||
if (menuItem && !menuItem.disabled) {
|
||||
menuItem.blur();
|
||||
this.open = false;
|
||||
}
|
||||
|
||||
$toast: {
|
||||
['@mouseenter']() { this.$store.toaster.isPaused = true },
|
||||
['@mouseleave']() { this.$store.toaster.isPaused = false },
|
||||
['@keydown.escape.window']() { this.close() },
|
||||
},
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
{% set iconMapping = {
|
||||
'error': 'circle-x',
|
||||
'success': 'circle-check',
|
||||
'info': 'info',
|
||||
'warning': 'circle-alert'
|
||||
} %}
|
||||
|
||||
<div
|
||||
id="{{ id }}"
|
||||
class="toasts"
|
||||
x-data="toast"
|
||||
class="toaster"
|
||||
{% for key, value in main_attrs %}
|
||||
{{ key }}="{{ value }}"
|
||||
{% endfor %}
|
||||
{% if is_fragment %}hx-swap-oob="beforeend"{% endif %}
|
||||
>
|
||||
{% for category, message in toasts %}
|
||||
{% for toast in toasts %}
|
||||
<div
|
||||
x-data="{
|
||||
active: true,
|
||||
init() {
|
||||
if ('{{ category }}' !== 'error') setTimeout(() => this.active = false, 3000)
|
||||
}
|
||||
}"
|
||||
role="{{ 'alert' if category == 'error' else 'status' }}"
|
||||
class="toast"
|
||||
role="{{ 'alert' if toast.category == 'error' else 'status' }}"
|
||||
aria-atomic="true"
|
||||
aria-hidden="true"
|
||||
:aria-hidden="!active"
|
||||
:inert="!active"
|
||||
aria-hidden="false"
|
||||
:aria-hidden="!open"
|
||||
{% if toast.category %}data-category="{{ toast.category }}"{% endif %}
|
||||
x-data="toast('{{ toast.category }}')"
|
||||
x-bind="$toast"
|
||||
>
|
||||
<button
|
||||
x-on:click="active = !active"
|
||||
aria-label="{{ _('Dismiss') }}"
|
||||
>
|
||||
{% include "icons/x.svg" %}
|
||||
</button>
|
||||
<section class="w-full text-left flex-1">
|
||||
{% if message is string %}
|
||||
<p class="font-medium w-full text-left flex-1">{{ message }}</p>
|
||||
{% else %}
|
||||
<h4 class="font-medium mb-1">{{ message.title }}</h4>
|
||||
<p class="text-muted-foreground">{{ message.description }}</p>
|
||||
{% if message.action %}
|
||||
<a
|
||||
href="{{ message.action.url }}"
|
||||
class="btn-outline h-8 px-2.5 mt-4"
|
||||
>{{ message.action.label }}</a>
|
||||
<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" %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</section>
|
||||
{% if category in ('error', 'success') %}
|
||||
{% if category == 'error' %}
|
||||
<div class="text-danger py-0.5">
|
||||
{% include "icons/circle-x.svg" %}
|
||||
</div>
|
||||
{% elif category == 'success' %}
|
||||
<div class="text-success py-0.5">
|
||||
{% include "icons/circle-check.svg" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% 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 %}
|
||||
{% endif %}
|
||||
</section>
|
||||
{% if toast.message.action or toast.message.cancel %}
|
||||
<footer class="flex flex-col gap-1 self-start">
|
||||
{% if toast.message.action %}
|
||||
{% if toast.message.action.click %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn h-6 text-xs px-2.5 rounded-sm"
|
||||
@click="{{ toast.message.action.onClick }}"
|
||||
>{{ toast.message.action.label }}</button>
|
||||
{% elif toast.message.action.url %}
|
||||
<a
|
||||
href="{{ toast.message.action.url }}"
|
||||
class="btn h-6 text-xs px-2.5 rounded-sm"
|
||||
>{{ toast.message.action.label }}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if toast.message.cancel %}
|
||||
{% if toast.message.cancel.click %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn-outline h-6 text-xs px-2.5 rounded-sm"
|
||||
@click="{{ toast.message.cancel.onClick }}"
|
||||
>{{ toast.message.cancel.label }}</button>
|
||||
{% elif toast.message.cancel.url %}
|
||||
<a
|
||||
href="{{ toast.message.cancel.url }}"
|
||||
class="btn-outline h-6 text-xs px-2.5 rounded-sm"
|
||||
>{{ toast.message.cancel.label }}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</footer>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
{% macro toasts(
|
||||
id=None,
|
||||
messages=None,
|
||||
flash=True
|
||||
) %}
|
||||
{% if flash %}
|
||||
{% set toasts = (messages or []) + get_flashed_messages(with_categories=true) %}
|
||||
{% else %}
|
||||
{% set toasts = messages or [] %}
|
||||
{% endif %}
|
||||
<div
|
||||
class="toasts"
|
||||
id="{{ id or 'toasts' }}"
|
||||
{}
|
||||
|
||||
>
|
||||
|
||||
</div>
|
||||
{% endmacro %}
|
||||
@@ -48,13 +48,12 @@
|
||||
<div role="group" aria-labelledby="demo-combobox-timezones-group-{{ loop.index0 }}">
|
||||
<span id="demo-combobox-timezones-group-{{ loop.index0 }}" role="heading">{{ group.label }}</span>
|
||||
{% for timezone in group.timezones %}
|
||||
<div role="option" data-value="{{ timezone.value}}">
|
||||
{{ timezone.label }}
|
||||
</div>
|
||||
<div role="option" data-value="{{ timezone.value}}">
|
||||
{{ timezone.label }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<hr role="separator">
|
||||
<div role="option">
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<section id="toast" class="w-full rounded-lg border scroll-mt-16">
|
||||
<header class="border-b px-4 py-3">
|
||||
<h2 class="text-sm font-medium">Toast</h2>
|
||||
</header>
|
||||
<div class="p-4">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<button class="btn-outline" hx-trigger="click" hx-get="/partials/toast/success" hx-target="#toast-htmx">
|
||||
Success
|
||||
</button>
|
||||
<button class="btn-outline" hx-trigger="click" hx-get="/partials/toast/error" hx-target="#toast-htmx">
|
||||
Error
|
||||
</button>
|
||||
<button class="btn-outline" hx-trigger="click" hx-get="/partials/toast/info" hx-target="#toast-htmx">
|
||||
Info
|
||||
</button>
|
||||
<button class="btn-outline" hx-trigger="click" hx-get="/partials/toast/warning" hx-target="#toast-htmx">
|
||||
Warning
|
||||
</button>
|
||||
<div id="toast-htmx"></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -89,6 +89,7 @@
|
||||
{ "id": "table", "name": "Table" },
|
||||
{ "id": "tabs", "name": "Tabs" },
|
||||
{ "id": "textarea", "name": "Textarea" },
|
||||
{ "id": "toast", "name": "Toast" },
|
||||
{ "id": "tooltip", "name": "Tooltip" }
|
||||
] %}
|
||||
{% for component in components %}
|
||||
|
||||
@@ -45,11 +45,13 @@
|
||||
|
||||
<!-- JS -->
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
|
||||
</head>
|
||||
<body>
|
||||
{% from "./_components/dialog.njk" import dialog %}
|
||||
{% from "./_components/popover.njk" import popover %}
|
||||
{% from "./_components/select.njk" import select %}
|
||||
{% from "./_components/toast.njk" import toaster %}
|
||||
|
||||
<div
|
||||
class="fixed inset-y-0 left-0 z-50 h-svh border-r bg-sidebar text-sidebar-foreground flex flex-col w-[var(--sidebar-width)] transition-transform ease-in-out peer aria-[hidden=true]:-translate-x-full"
|
||||
@@ -130,8 +132,10 @@
|
||||
{% include "./_includes/components/table.njk" %}
|
||||
{% include "./_includes/components/tabs.njk" %}
|
||||
{% include "./_includes/components/textarea.njk" %}
|
||||
{% include "./_includes/components/toast.njk" %}
|
||||
{% include "./_includes/components/tooltip.njk" %}
|
||||
</div>
|
||||
</main>
|
||||
{{ toaster() }}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
{% from "../../_components/toast.njk" import toaster %}
|
||||
{% set toasts = [{
|
||||
category: "error",
|
||||
message: {
|
||||
title: "Event has not been created",
|
||||
cancel: { label: "Dismiss", click: "close()" }
|
||||
}
|
||||
}] %}
|
||||
{{ toaster(toasts=toasts, is_fragment=true) }}
|
||||
@@ -0,0 +1,8 @@
|
||||
{% from "../../_components/toast.njk" import toaster %}
|
||||
{% set toasts = [{
|
||||
category: "info",
|
||||
message: {
|
||||
title: "Be at the area 10 minutes before the event time"
|
||||
}
|
||||
}] %}
|
||||
{{ toaster(toasts=toasts, is_fragment=true) }}
|
||||
@@ -0,0 +1,9 @@
|
||||
{% from "../../_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()" }
|
||||
}
|
||||
}] %}
|
||||
{{ toaster(toasts=toasts, is_fragment=true) }}
|
||||
@@ -0,0 +1,8 @@
|
||||
{% from "../../_components/toast.njk" import toaster %}
|
||||
{% set toasts = [{
|
||||
category: "warning",
|
||||
message: {
|
||||
title: "Event start time cannot be earlier than 8am"
|
||||
}
|
||||
}] %}
|
||||
{{ toaster(toasts=toasts, is_fragment=true) }}
|
||||
Reference in New Issue
Block a user