Added toasts, fixed some combobox and select issues

This commit is contained in:
Ronan Berder
2025-04-22 13:47:19 +08:00
parent 88af4152ab
commit b3e4085fdb
11 changed files with 469 additions and 414 deletions
+226 -214
View File
@@ -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;
+76 -72
View File
@@ -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;
}
}
}
}