Prepare 1.0 docs and style migration

This commit is contained in:
Ronan Berder
2026-06-17 11:19:31 +08:00
parent 815e3ffffe
commit 1d33827162
183 changed files with 8805 additions and 13225 deletions
-14
View File
@@ -1,14 +0,0 @@
---
const { site } = Astro.props;
const logo = site.logo?.svg || '';
---
<a href="/" class="btn-ghost h-12 w-full justify-start p-2">
<div class="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg">
{logo && <Fragment set:html={logo} />}
</div>
<div class="grid flex-1 text-left text-sm leading-tight">
<span class="truncate font-semibold">{site.title}</span>
{site.subtitle && <span class="truncate text-xs text-muted-foreground">{site.subtitle}</span>}
</div>
</a>
+32 -6
View File
@@ -36,9 +36,10 @@
--sidebar-width: 16rem;
--sidebar-mobile-width: 18rem;
--scrollbar-track: transparent;
--scrollbar-thumb: rgba(0, 0, 0, 0.3);
--scrollbar-width: 6px;
--scrollbar-radius: 6px;
--scrollbar-thumb: var(--border);
--scrollbar-width: 0.625rem;
--scrollbar-thin-width: 0.375rem;
--scrollbar-radius: 9999px;
--chevron-down-icon: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="oklch(0.556 0 0)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-down-icon lucide-chevron-down"><path d="m6 9 6 6 6-6"/></svg>'); /* --muted-foreground */
--chevron-down-icon-50: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="oklch(0.556 0 0 / 0.5)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-down-icon lucide-chevron-down"><path d="m6 9 6 6 6-6"/></svg>'); /* --muted-foreground + 50% opacity */
--check-icon: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="oklch(0.556 0 0)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-check-icon lucide-check"><path d="M20 6 9 17l-5-5"/></svg>'); /* --muted-foreground */
@@ -76,7 +77,6 @@
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.439 0 0);
--scrollbar-thumb: rgba(255, 255, 255, 0.3);
--chevron-down-icon: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="oklch(0.708 0 0)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-down-icon lucide-chevron-down"><path d="m6 9 6 6 6-6"/></svg>'); /* --muted-foreground */
--chevron-down-icon-50: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="oklch(0.708 0 0 / 0.5)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-down-icon lucide-chevron-down"><path d="m6 9 6 6 6-6"/></svg>'); /* --muted-foreground + 50% opacity */
--check-icon: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="oklch(0.708 0 0)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-check-icon lucide-check"><path d="M20 6 9 17l-5-5"/></svg>');/* --muted-foreground */
@@ -132,11 +132,12 @@
@apply bg-background text-foreground overscroll-none antialiased;
}
.scrollbar {
scrollbar-width: thin;
scrollbar-width: auto;
scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
&::-webkit-scrollbar {
width: var(--scrollbar-width);
height: var(--scrollbar-width);
}
&::-webkit-scrollbar-track {
background: var(--scrollbar-track);
@@ -144,7 +145,32 @@
&::-webkit-scrollbar-thumb {
background: var(--scrollbar-thumb);
border-radius: var(--scrollbar-radius);
border: 1px solid transparent;
background-clip: padding-box;
}
&::-webkit-scrollbar-corner {
background: var(--scrollbar-track);
}
}
.scrollbar-thin {
scrollbar-width: thin;
scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
&::-webkit-scrollbar {
width: var(--scrollbar-thin-width);
height: var(--scrollbar-thin-width);
}
&::-webkit-scrollbar-track {
background: var(--scrollbar-track);
}
&::-webkit-scrollbar-thumb {
background: var(--scrollbar-thumb);
border-radius: var(--scrollbar-radius);
border: 1px solid transparent;
background-clip: padding-box;
}
&::-webkit-scrollbar-corner {
background: var(--scrollbar-track);
}
}
}
+2
View File
@@ -1,9 +1,11 @@
/* Components */
@import "./components/alert.css";
@import "./components/avatar.css";
@import "./components/badge.css";
@import "./components/button.css";
@import "./components/button-group.css";
@import "./components/card.css";
@import "./components/chart.css";
@import "./components/collapsible.css";
@import "./components/command.css";
@import "./components/combobox.css";
+10
View File
@@ -5,6 +5,11 @@
@apply relative w-full;
}
.alert:has(> footer),
.alert-destructive:has(> footer) {
@apply pe-18;
}
.alert > :is(h2, h3, h4, h5, h6, strong, [data-title]),
.alert-destructive > :is(h2, h3, h4, h5, h6, strong, [data-title]) {
@apply min-h-4;
@@ -18,4 +23,9 @@
@apply list-inside list-disc;
}
}
.alert > footer,
.alert-destructive > footer {
@apply absolute;
}
}
+55
View File
@@ -0,0 +1,55 @@
/* Avatar */
@layer components {
.avatar,
.avatar-sm,
.avatar-lg {
@apply relative inline-flex shrink-0 select-none appearance-none border-0 bg-transparent p-0 align-middle outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 after:absolute after:inset-0 after:rounded-[inherit] after:border after:border-border after:mix-blend-darken dark:after:mix-blend-lighten;
}
.avatar > img,
.avatar-sm > img,
.avatar-lg > img {
@apply absolute inset-0 aspect-square size-full rounded-[inherit] object-cover;
}
.avatar > span:not([data-badge]),
.avatar-sm > span:not([data-badge]),
.avatar-lg > span:not([data-badge]) {
@apply flex size-full items-center justify-center rounded-[inherit] text-sm;
}
.avatar-sm > span:not([data-badge]) {
@apply text-xs;
}
.avatar > [data-badge],
.avatar-sm > [data-badge],
.avatar-lg > [data-badge] {
@apply absolute end-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-blend-color ring-2 select-none;
}
.avatar-sm > [data-badge] {
@apply size-2 [&>svg]:hidden;
}
.avatar > [data-badge] {
@apply size-2.5 [&>svg]:size-2;
}
.avatar-lg > [data-badge] {
@apply size-3 [&>svg]:size-2;
}
.avatar-group {
@apply flex -space-x-2;
}
.avatar-group > :is(.avatar, .avatar-sm, .avatar-lg),
.avatar-group > [data-count] {
@apply ring-2 ring-background;
}
.avatar-group > [data-count] {
@apply relative flex shrink-0 items-center justify-center;
}
}
+5 -1
View File
@@ -2,6 +2,10 @@
@layer components {
.button-group {
@apply isolate inline-flex w-fit items-stretch;
&:has(> :is(.dropdown-menu, .popover, .select) > [data-popover][aria-hidden='false']) {
@apply relative z-50;
}
> .input {
@apply flex-1;
@@ -44,7 +48,7 @@
}
}
.button-group-text {
.button-group > :is(span, label, output) {
@apply flex items-center [&_svg]:pointer-events-none;
}
+2 -1
View File
@@ -1,6 +1,7 @@
/* Card */
@layer components {
.card {
.card,
.card-sm {
@apply flex flex-col;
> header {
+56
View File
@@ -0,0 +1,56 @@
/* Chart */
@layer components {
.chart {
@apply relative flex aspect-video w-full justify-center text-xs;
}
.chart > canvas {
@apply block size-full;
}
.chart-tooltip {
@apply pointer-events-none fixed z-50 grid min-w-32 -translate-x-1/2 translate-y-2 items-start transition-[left,top,opacity] duration-150 ease-out;
}
.chart-tooltip[hidden] {
@apply opacity-0;
}
.chart-tooltip-items {
@apply grid gap-1.5;
}
.chart-tooltip-item {
@apply flex w-full flex-wrap items-center gap-2;
}
.chart-tooltip-indicator {
@apply size-2.5 shrink-0 rounded-[2px];
background-color: var(--chart-indicator-color);
}
.chart-legend-indicator {
@apply size-2 shrink-0 rounded-[2px];
background-color: var(--chart-indicator-color);
}
.chart-tooltip-label {
@apply text-muted-foreground leading-none;
}
.chart-tooltip-value {
@apply ms-auto font-mono font-medium leading-none tabular-nums;
}
.chart-legend {
@apply flex flex-wrap items-center justify-center gap-4 pt-3;
}
.chart-legend-item {
@apply flex items-center gap-1.5 text-xs;
}
.chart-legend-item[aria-pressed='false'] {
@apply opacity-70;
}
}
+105 -14
View File
@@ -272,7 +272,7 @@
}
}
.button-group-text {
.button-group > :is(span, label, output) {
@apply bg-muted gap-2 rounded-4xl border px-2.5 text-sm font-medium [&_svg:not([class*='size-'])]:size-4;
}
@@ -391,7 +391,7 @@
/* Alert */
.alert,
.alert-destructive {
@apply grid gap-0.5 rounded-2xl border px-4 py-3 text-start text-sm has-[>[data-action]]:relative has-[>[data-action]]:pe-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2.5 [&>svg]:row-span-2 [&>svg]:translate-y-0.5 [&>svg]:text-current [&>svg:not([class*='size-'])]:size-4;
@apply grid gap-0.5 rounded-2xl border px-4 py-3 text-start text-sm has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2.5 [&>svg]:row-span-2 [&>svg]:translate-y-0.5 [&>svg]:text-current [&>svg:not([class*='size-'])]:size-4;
}
.alert {
@@ -419,9 +419,57 @@
@apply text-destructive/90 text-sm text-balance md:text-pretty [&_p:not(:last-child)]:mb-4;
}
.alert > [data-action],
.alert-destructive > [data-action] {
@apply absolute top-2.5 end-3;
.alert > footer,
.alert-destructive > footer {
@apply top-2.5 end-3;
}
/* Avatar */
.avatar,
.avatar-sm,
.avatar-lg {
@apply rounded-full after:rounded-[inherit];
}
.avatar {
@apply size-8;
}
.avatar-sm {
@apply size-6;
}
.avatar-lg {
@apply size-10;
}
.avatar > span:not([data-badge]),
.avatar-sm > span:not([data-badge]),
.avatar-lg > span:not([data-badge]) {
@apply bg-muted text-muted-foreground rounded-[inherit];
}
.avatar > img,
.avatar-sm > img,
.avatar-lg > img {
@apply rounded-[inherit];
}
.avatar > [data-badge],
.avatar-sm > [data-badge],
.avatar-lg > [data-badge] {
@apply bg-primary text-primary-foreground ring-background;
}
.avatar-group > [data-count] {
@apply bg-muted text-muted-foreground size-8 rounded-full text-sm [&>svg]:size-4;
}
.avatar-group:has(> .avatar-sm) > [data-count] {
@apply size-6 [&>svg]:size-3;
}
.avatar-group:has(> .avatar-lg) > [data-count] {
@apply size-10 [&>svg]:size-5;
}
/* Badge */
@@ -732,28 +780,71 @@
}
/* Card */
.card,
.card-sm {
@apply bg-card text-card-foreground ring-foreground/5 dark:ring-foreground/10 overflow-hidden rounded-4xl text-sm shadow-md ring-1 has-[>img:first-child]:pt-0 [&>img:first-child]:rounded-t-4xl [&>img:last-child]:rounded-b-4xl;
}
.card {
@apply bg-card text-card-foreground ring-foreground/5 dark:ring-foreground/10 gap-6 overflow-hidden rounded-4xl py-6 text-sm shadow-md ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-4 data-[size=sm]:py-4 [&>img:first-child]:rounded-t-4xl [&>img:last-child]:rounded-b-4xl;
@apply gap-6 py-6;
}
.card > header {
@apply gap-1.5 rounded-t-4xl px-6 in-data-[size=sm]:px-4 [.border-b]:pb-6 in-data-[size=sm]:[.border-b]:pb-4;
.card-sm {
@apply gap-4 py-4;
}
.card > header > :is(h2, h3, [data-title], .card-title) {
.card > header,
.card-sm > header {
@apply gap-1.5 rounded-t-4xl px-6 [.border-b]:pb-6;
}
.card-sm > header {
@apply px-4 [.border-b]:pb-4;
}
.card > header > :is(h2, h3, [data-title], .card-title),
.card-sm > header > :is(h2, h3, [data-title], .card-title) {
@apply text-base font-medium;
}
.card > header > :is(p, [data-description], .card-description) {
.card > header > :is(p, [data-description], .card-description),
.card-sm > header > :is(p, [data-description], .card-description) {
@apply text-muted-foreground text-sm;
}
.card > section {
@apply px-6 in-data-[size=sm]:px-4;
.card > section,
.card-sm > section {
@apply px-6;
}
.card > footer {
@apply rounded-b-4xl px-6 in-data-[size=sm]:px-4 [.border-t]:pt-6 in-data-[size=sm]:[.border-t]:pt-4;
.card-sm > section {
@apply px-4;
}
.card > footer,
.card-sm > footer {
@apply rounded-b-4xl px-6 [.border-t]:pt-6;
}
.card-sm > footer {
@apply px-4 [.border-t]:pt-4;
}
/* Chart */
.chart-tooltip {
@apply border-border/50 bg-background text-foreground gap-1.5 rounded-2xl border px-2.5 py-1.5 text-xs shadow-xl;
}
.chart-tooltip-title {
@apply font-medium;
}
.chart-legend-item {
@apply text-foreground;
}
.chart-legend-item[aria-pressed='false'] {
@apply text-muted-foreground;
}
/* Checkbox */
+110 -15
View File
@@ -264,7 +264,7 @@
}
}
.button-group-text {
.button-group > :is(span, label, output) {
@apply bg-muted gap-2 rounded-none border px-2.5 text-xs font-medium [&_svg:not([class*='size-'])]:size-4;
}
@@ -383,7 +383,7 @@
/* Alert */
.alert,
.alert-destructive {
@apply grid gap-0.5 rounded-none border px-2.5 py-2 text-start text-xs has-[>[data-action]]:relative has-[>[data-action]]:pe-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 [&>svg]:row-span-2 [&>svg]:translate-y-0 [&>svg]:text-current [&>svg:not([class*='size-'])]:size-4;
@apply grid gap-0.5 rounded-none border px-2.5 py-2 text-start text-xs has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 [&>svg]:row-span-2 [&>svg]:translate-y-0 [&>svg]:text-current [&>svg:not([class*='size-'])]:size-4;
}
.alert {
@@ -411,9 +411,57 @@
@apply text-destructive/90 text-xs/relaxed text-balance md:text-pretty [&_p:not(:last-child)]:mb-2;
}
.alert > [data-action],
.alert-destructive > [data-action] {
@apply absolute top-[calc(--spacing(1.25))] end-[calc(--spacing(1.25))];
.alert > footer,
.alert-destructive > footer {
@apply top-[calc(--spacing(1.25))] end-[calc(--spacing(1.25))];
}
/* Avatar */
.avatar,
.avatar-sm,
.avatar-lg {
@apply rounded-full after:rounded-[inherit];
}
.avatar {
@apply size-8;
}
.avatar-sm {
@apply size-6;
}
.avatar-lg {
@apply size-10;
}
.avatar > span:not([data-badge]),
.avatar-sm > span:not([data-badge]),
.avatar-lg > span:not([data-badge]) {
@apply bg-muted text-muted-foreground rounded-[inherit];
}
.avatar > img,
.avatar-sm > img,
.avatar-lg > img {
@apply rounded-[inherit];
}
.avatar > [data-badge],
.avatar-sm > [data-badge],
.avatar-lg > [data-badge] {
@apply bg-primary text-primary-foreground ring-background;
}
.avatar-group > [data-count] {
@apply bg-muted text-muted-foreground size-8 rounded-full text-xs [&>svg]:size-4;
}
.avatar-group:has(> .avatar-sm) > [data-count] {
@apply size-6 [&>svg]:size-3;
}
.avatar-group:has(> .avatar-lg) > [data-count] {
@apply size-10 [&>svg]:size-5;
}
/* Badge */
@@ -716,28 +764,75 @@
}
/* Card */
.card,
.card-sm {
@apply ring-foreground/10 bg-card text-card-foreground overflow-hidden rounded-none text-xs/relaxed ring-1 has-[>footer]:pb-0 has-[>img:first-child]:pt-0 [&>img:first-child]:rounded-none [&>img:last-child]:rounded-none;
}
.card {
@apply ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-none py-4 text-xs/relaxed ring-1 has-[>footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-2 data-[size=sm]:py-3 data-[size=sm]:has-[>footer]:pb-0 [&>img:first-child]:rounded-none [&>img:last-child]:rounded-none;
@apply gap-4 py-4;
}
.card > header {
@apply gap-1 rounded-none px-4 in-data-[size=sm]:px-3 [.border-b]:pb-4 in-data-[size=sm]:[.border-b]:pb-3;
.card-sm {
@apply gap-2 py-3;
}
.card > header > :is(h2, h3, [data-title], .card-title) {
@apply text-sm font-medium in-data-[size=sm]:text-sm;
.card > header,
.card-sm > header {
@apply gap-1 rounded-none px-4 [.border-b]:pb-4;
}
.card > header > :is(p, [data-description], .card-description) {
.card-sm > header {
@apply px-3 [.border-b]:pb-3;
}
.card > header > :is(h2, h3, [data-title], .card-title),
.card-sm > header > :is(h2, h3, [data-title], .card-title) {
@apply text-sm font-medium;
}
.card-sm > header > :is(h2, h3, [data-title], .card-title) {
@apply text-sm;
}
.card > header > :is(p, [data-description], .card-description),
.card-sm > header > :is(p, [data-description], .card-description) {
@apply text-muted-foreground text-xs/relaxed;
}
.card > section {
@apply px-4 in-data-[size=sm]:px-3;
.card > section,
.card-sm > section {
@apply px-4;
}
.card > footer {
@apply rounded-none border-t p-4 in-data-[size=sm]:p-3;
.card-sm > section {
@apply px-3;
}
.card > footer,
.card-sm > footer {
@apply rounded-none border-t p-4;
}
.card-sm > footer {
@apply p-3;
}
/* Chart */
.chart-tooltip {
@apply border-border/50 bg-background text-foreground gap-1.5 rounded-none border px-2.5 py-1.5 text-xs shadow-xl;
}
.chart-tooltip-title {
@apply font-medium;
}
.chart-legend-item {
@apply text-foreground;
}
.chart-legend-item[aria-pressed='false'] {
@apply text-muted-foreground;
}
/* Checkbox */
+105 -14
View File
@@ -264,7 +264,7 @@
}
}
.button-group-text {
.button-group > :is(span, label, output) {
@apply bg-muted gap-2 rounded-4xl border px-2.5 text-sm font-medium [&_svg:not([class*='size-'])]:size-4;
}
@@ -383,7 +383,7 @@
/* Alert */
.alert,
.alert-destructive {
@apply grid gap-0.5 rounded-lg border px-4 py-3 text-start text-sm has-[>[data-action]]:relative has-[>[data-action]]:pe-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2.5 [&>svg]:row-span-2 [&>svg]:translate-y-0.5 [&>svg]:text-current [&>svg:not([class*='size-'])]:size-4;
@apply grid gap-0.5 rounded-lg border px-4 py-3 text-start text-sm has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2.5 [&>svg]:row-span-2 [&>svg]:translate-y-0.5 [&>svg]:text-current [&>svg:not([class*='size-'])]:size-4;
}
.alert {
@@ -411,9 +411,57 @@
@apply text-destructive/90 text-sm text-balance md:text-pretty [&_p:not(:last-child)]:mb-4;
}
.alert > [data-action],
.alert-destructive > [data-action] {
@apply absolute top-2.5 end-3;
.alert > footer,
.alert-destructive > footer {
@apply top-2.5 end-3;
}
/* Avatar */
.avatar,
.avatar-sm,
.avatar-lg {
@apply rounded-full after:rounded-[inherit];
}
.avatar {
@apply size-8;
}
.avatar-sm {
@apply size-6;
}
.avatar-lg {
@apply size-10;
}
.avatar > span:not([data-badge]),
.avatar-sm > span:not([data-badge]),
.avatar-lg > span:not([data-badge]) {
@apply bg-muted text-muted-foreground rounded-[inherit];
}
.avatar > img,
.avatar-sm > img,
.avatar-lg > img {
@apply rounded-[inherit];
}
.avatar > [data-badge],
.avatar-sm > [data-badge],
.avatar-lg > [data-badge] {
@apply bg-primary text-primary-foreground ring-background;
}
.avatar-group > [data-count] {
@apply bg-muted text-muted-foreground size-8 rounded-full text-sm [&>svg]:size-4;
}
.avatar-group:has(> .avatar-sm) > [data-count] {
@apply size-6 [&>svg]:size-3;
}
.avatar-group:has(> .avatar-lg) > [data-count] {
@apply size-10 [&>svg]:size-5;
}
/* Badge */
@@ -720,28 +768,71 @@
}
/* Card */
.card,
.card-sm {
@apply ring-foreground/10 bg-card text-card-foreground overflow-hidden rounded-2xl text-sm ring-1 has-[>img:first-child]:pt-0 [&>img:first-child]:rounded-t-xl [&>img:last-child]:rounded-b-xl;
}
.card {
@apply ring-foreground/10 bg-card text-card-foreground gap-6 overflow-hidden rounded-2xl py-6 text-sm ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-4 data-[size=sm]:py-4 [&>img:first-child]:rounded-t-xl [&>img:last-child]:rounded-b-xl;
@apply gap-6 py-6;
}
.card > header {
@apply gap-2 rounded-t-xl px-6 in-data-[size=sm]:px-4 [.border-b]:pb-6 in-data-[size=sm]:[.border-b]:pb-4;
.card-sm {
@apply gap-4 py-4;
}
.card > header > :is(h2, h3, [data-title], .card-title) {
.card > header,
.card-sm > header {
@apply gap-2 rounded-t-xl px-6 [.border-b]:pb-6;
}
.card-sm > header {
@apply px-4 [.border-b]:pb-4;
}
.card > header > :is(h2, h3, [data-title], .card-title),
.card-sm > header > :is(h2, h3, [data-title], .card-title) {
@apply text-base font-medium;
}
.card > header > :is(p, [data-description], .card-description) {
.card > header > :is(p, [data-description], .card-description),
.card-sm > header > :is(p, [data-description], .card-description) {
@apply text-muted-foreground text-sm;
}
.card > section {
@apply px-6 in-data-[size=sm]:px-4;
.card > section,
.card-sm > section {
@apply px-6;
}
.card > footer {
@apply rounded-b-xl px-6 in-data-[size=sm]:px-4 [.border-t]:pt-6 in-data-[size=sm]:[.border-t]:pt-4;
.card-sm > section {
@apply px-4;
}
.card > footer,
.card-sm > footer {
@apply rounded-b-xl px-6 [.border-t]:pt-6;
}
.card-sm > footer {
@apply px-4 [.border-t]:pt-4;
}
/* Chart */
.chart-tooltip {
@apply border-border/50 bg-background text-foreground gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl;
}
.chart-tooltip-title {
@apply font-medium;
}
.chart-legend-item {
@apply text-foreground;
}
.chart-legend-item[aria-pressed='false'] {
@apply text-muted-foreground;
}
/* Checkbox */
+105 -14
View File
@@ -264,7 +264,7 @@
}
}
.button-group-text {
.button-group > :is(span, label, output) {
@apply bg-muted gap-2 rounded-md border px-2.5 text-xs/relaxed font-medium [&_svg:not([class*='size-'])]:size-4;
}
@@ -383,7 +383,7 @@
/* Alert */
.alert,
.alert-destructive {
@apply grid gap-0.5 rounded-lg border px-2 py-1.5 text-start text-xs/relaxed has-[>[data-action]]:relative has-[>[data-action]]:pe-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-1.5 [&>svg]:row-span-2 [&>svg]:translate-y-0.5 [&>svg]:text-current [&>svg:not([class*='size-'])]:size-3.5;
@apply grid gap-0.5 rounded-lg border px-2 py-1.5 text-start text-xs/relaxed has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-1.5 [&>svg]:row-span-2 [&>svg]:translate-y-0.5 [&>svg]:text-current [&>svg:not([class*='size-'])]:size-3.5;
}
.alert {
@@ -411,9 +411,57 @@
@apply text-destructive/90 text-xs/relaxed text-balance md:text-pretty [&_p:not(:last-child)]:mb-4;
}
.alert > [data-action],
.alert-destructive > [data-action] {
@apply absolute top-1.5 end-2;
.alert > footer,
.alert-destructive > footer {
@apply top-1.5 end-2;
}
/* Avatar */
.avatar,
.avatar-sm,
.avatar-lg {
@apply rounded-full after:rounded-[inherit];
}
.avatar {
@apply size-8;
}
.avatar-sm {
@apply size-6;
}
.avatar-lg {
@apply size-10;
}
.avatar > span:not([data-badge]),
.avatar-sm > span:not([data-badge]),
.avatar-lg > span:not([data-badge]) {
@apply bg-muted text-muted-foreground rounded-[inherit];
}
.avatar > img,
.avatar-sm > img,
.avatar-lg > img {
@apply rounded-[inherit];
}
.avatar > [data-badge],
.avatar-sm > [data-badge],
.avatar-lg > [data-badge] {
@apply bg-primary text-primary-foreground ring-background;
}
.avatar-group > [data-count] {
@apply bg-muted text-muted-foreground size-8 rounded-full text-xs/relaxed [&>svg]:size-4;
}
.avatar-group:has(> .avatar-sm) > [data-count] {
@apply size-6 [&>svg]:size-3;
}
.avatar-group:has(> .avatar-lg) > [data-count] {
@apply size-10 [&>svg]:size-5;
}
/* Badge */
@@ -724,28 +772,71 @@
}
/* Card */
.card,
.card-sm {
@apply ring-foreground/10 bg-card text-card-foreground overflow-hidden rounded-lg text-xs/relaxed ring-1 has-[>img:first-child]:pt-0 [&>img:first-child]:rounded-t-lg [&>img:last-child]:rounded-b-lg;
}
.card {
@apply ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-lg py-4 text-xs/relaxed ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 [&>img:first-child]:rounded-t-lg [&>img:last-child]:rounded-b-lg;
@apply gap-4 py-4;
}
.card > header {
@apply gap-1 rounded-t-lg px-4 in-data-[size=sm]:px-3 [.border-b]:pb-4 in-data-[size=sm]:[.border-b]:pb-3;
.card-sm {
@apply gap-3 py-3;
}
.card > header > :is(h2, h3, [data-title], .card-title) {
.card > header,
.card-sm > header {
@apply gap-1 rounded-t-lg px-4 [.border-b]:pb-4;
}
.card-sm > header {
@apply px-3 [.border-b]:pb-3;
}
.card > header > :is(h2, h3, [data-title], .card-title),
.card-sm > header > :is(h2, h3, [data-title], .card-title) {
@apply text-sm font-medium;
}
.card > header > :is(p, [data-description], .card-description) {
.card > header > :is(p, [data-description], .card-description),
.card-sm > header > :is(p, [data-description], .card-description) {
@apply text-muted-foreground text-xs/relaxed;
}
.card > section {
@apply px-4 in-data-[size=sm]:px-3;
.card > section,
.card-sm > section {
@apply px-4;
}
.card > footer {
@apply rounded-b-lg px-4 in-data-[size=sm]:px-3 [.border-t]:pt-4 in-data-[size=sm]:[.border-t]:pt-3;
.card-sm > section {
@apply px-3;
}
.card > footer,
.card-sm > footer {
@apply rounded-b-lg px-4 [.border-t]:pt-4;
}
.card-sm > footer {
@apply px-3 [.border-t]:pt-3;
}
/* Chart */
.chart-tooltip {
@apply border-border/50 bg-background text-foreground gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl;
}
.chart-tooltip-title {
@apply font-medium;
}
.chart-legend-item {
@apply text-foreground;
}
.chart-legend-item[aria-pressed='false'] {
@apply text-muted-foreground;
}
/* Checkbox */
+110 -15
View File
@@ -264,7 +264,7 @@
}
}
.button-group-text {
.button-group > :is(span, label, output) {
@apply bg-muted gap-2 rounded-lg border px-2.5 text-sm font-medium [&_svg:not([class*='size-'])]:size-4;
}
@@ -383,7 +383,7 @@
/* Alert */
.alert,
.alert-destructive {
@apply grid gap-0.5 rounded-lg border px-2.5 py-2 text-start text-sm has-[>[data-action]]:relative has-[>[data-action]]:pe-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 [&>svg]:row-span-2 [&>svg]:translate-y-0.5 [&>svg]:text-current [&>svg:not([class*='size-'])]:size-4;
@apply grid gap-0.5 rounded-lg border px-2.5 py-2 text-start text-sm has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 [&>svg]:row-span-2 [&>svg]:translate-y-0.5 [&>svg]:text-current [&>svg:not([class*='size-'])]:size-4;
}
.alert {
@@ -411,9 +411,57 @@
@apply text-destructive/90 text-sm text-balance md:text-pretty [&_p:not(:last-child)]:mb-4;
}
.alert > [data-action],
.alert-destructive > [data-action] {
@apply absolute top-2 end-2;
.alert > footer,
.alert-destructive > footer {
@apply top-2 end-2;
}
/* Avatar */
.avatar,
.avatar-sm,
.avatar-lg {
@apply rounded-full after:rounded-[inherit];
}
.avatar {
@apply size-8;
}
.avatar-sm {
@apply size-6;
}
.avatar-lg {
@apply size-10;
}
.avatar > span:not([data-badge]),
.avatar-sm > span:not([data-badge]),
.avatar-lg > span:not([data-badge]) {
@apply bg-muted text-muted-foreground rounded-[inherit];
}
.avatar > img,
.avatar-sm > img,
.avatar-lg > img {
@apply rounded-[inherit];
}
.avatar > [data-badge],
.avatar-sm > [data-badge],
.avatar-lg > [data-badge] {
@apply bg-primary text-primary-foreground ring-background;
}
.avatar-group > [data-count] {
@apply bg-muted text-muted-foreground size-8 rounded-full text-sm [&>svg]:size-4;
}
.avatar-group:has(> .avatar-sm) > [data-count] {
@apply size-6 [&>svg]:size-3;
}
.avatar-group:has(> .avatar-lg) > [data-count] {
@apply size-10 [&>svg]:size-5;
}
/* Badge */
@@ -720,28 +768,75 @@
}
/* Card */
.card,
.card-sm {
@apply ring-foreground/10 bg-card text-card-foreground overflow-hidden rounded-xl text-sm ring-1 has-[>footer]:pb-0 has-[>img:first-child]:pt-0 [&>img:first-child]:rounded-t-xl [&>img:last-child]:rounded-b-xl;
}
.card {
@apply ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-xl py-4 text-sm ring-1 has-[>footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-[>footer]:pb-0 [&>img:first-child]:rounded-t-xl [&>img:last-child]:rounded-b-xl;
@apply gap-4 py-4;
}
.card > header {
@apply gap-1 rounded-t-xl px-4 in-data-[size=sm]:px-3 [.border-b]:pb-4 in-data-[size=sm]:[.border-b]:pb-3;
.card-sm {
@apply gap-3 py-3;
}
.card > header > :is(h2, h3, [data-title], .card-title) {
@apply text-base leading-snug font-medium in-data-[size=sm]:text-sm;
.card > header,
.card-sm > header {
@apply gap-1 rounded-t-xl px-4 [.border-b]:pb-4;
}
.card > header > :is(p, [data-description], .card-description) {
.card-sm > header {
@apply px-3 [.border-b]:pb-3;
}
.card > header > :is(h2, h3, [data-title], .card-title),
.card-sm > header > :is(h2, h3, [data-title], .card-title) {
@apply text-base leading-snug font-medium;
}
.card-sm > header > :is(h2, h3, [data-title], .card-title) {
@apply text-sm;
}
.card > header > :is(p, [data-description], .card-description),
.card-sm > header > :is(p, [data-description], .card-description) {
@apply text-muted-foreground text-sm;
}
.card > section {
@apply px-4 in-data-[size=sm]:px-3;
.card > section,
.card-sm > section {
@apply px-4;
}
.card > footer {
@apply bg-muted/50 rounded-b-xl border-t p-4 in-data-[size=sm]:p-3;
.card-sm > section {
@apply px-3;
}
.card > footer,
.card-sm > footer {
@apply bg-muted/50 rounded-b-xl border-t p-4;
}
.card-sm > footer {
@apply p-3;
}
/* Chart */
.chart-tooltip {
@apply border-border/50 bg-background text-foreground gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl;
}
.chart-tooltip-title {
@apply font-medium;
}
.chart-legend-item {
@apply text-foreground;
}
.chart-legend-item[aria-pressed='false'] {
@apply text-muted-foreground;
}
/* Checkbox */
+105 -14
View File
@@ -272,7 +272,7 @@
}
}
.button-group-text {
.button-group > :is(span, label, output) {
@apply bg-muted gap-2 rounded-2xl border px-2.5 text-sm font-medium [&_svg:not([class*='size-'])]:size-4;
}
@@ -391,7 +391,7 @@
/* Alert */
.alert,
.alert-destructive {
@apply grid gap-0.5 rounded-2xl border px-4 py-3 text-start text-sm has-[>[data-action]]:relative has-[>[data-action]]:pe-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2.5 [&>svg]:row-span-2 [&>svg]:translate-y-0.5 [&>svg]:text-current [&>svg:not([class*='size-'])]:size-4;
@apply grid gap-0.5 rounded-2xl border px-4 py-3 text-start text-sm has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2.5 [&>svg]:row-span-2 [&>svg]:translate-y-0.5 [&>svg]:text-current [&>svg:not([class*='size-'])]:size-4;
}
.alert {
@@ -419,9 +419,57 @@
@apply text-destructive/90 text-sm text-balance md:text-pretty [&_p:not(:last-child)]:mb-4;
}
.alert > [data-action],
.alert-destructive > [data-action] {
@apply absolute top-2.5 end-3;
.alert > footer,
.alert-destructive > footer {
@apply top-2.5 end-3;
}
/* Avatar */
.avatar,
.avatar-sm,
.avatar-lg {
@apply rounded-full after:rounded-[inherit];
}
.avatar {
@apply size-8;
}
.avatar-sm {
@apply size-6;
}
.avatar-lg {
@apply size-10;
}
.avatar > span:not([data-badge]),
.avatar-sm > span:not([data-badge]),
.avatar-lg > span:not([data-badge]) {
@apply bg-muted text-muted-foreground rounded-[inherit];
}
.avatar > img,
.avatar-sm > img,
.avatar-lg > img {
@apply rounded-[inherit];
}
.avatar > [data-badge],
.avatar-sm > [data-badge],
.avatar-lg > [data-badge] {
@apply bg-primary text-primary-foreground ring-background;
}
.avatar-group > [data-count] {
@apply bg-muted text-muted-foreground size-8 rounded-full text-sm [&>svg]:size-4;
}
.avatar-group:has(> .avatar-sm) > [data-count] {
@apply size-6 [&>svg]:size-3;
}
.avatar-group:has(> .avatar-lg) > [data-count] {
@apply size-10 [&>svg]:size-5;
}
/* Badge */
@@ -732,28 +780,71 @@
}
/* Card */
.card,
.card-sm {
@apply bg-card text-card-foreground ring-foreground/5 dark:ring-foreground/10 overflow-hidden rounded-[min(var(--radius-4xl),24px)] text-sm shadow-sm ring-1 has-[>img:first-child]:pt-0 [&>img:first-child]:rounded-t-[min(var(--radius-4xl),24px)] [&>img:last-child]:rounded-b-[min(var(--radius-4xl),24px)];
}
.card {
@apply bg-card text-card-foreground ring-foreground/5 dark:ring-foreground/10 gap-5 overflow-hidden rounded-[min(var(--radius-4xl),24px)] py-5 text-sm shadow-sm ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-4 data-[size=sm]:py-4 [&>img:first-child]:rounded-t-[min(var(--radius-4xl),24px)] [&>img:last-child]:rounded-b-[min(var(--radius-4xl),24px)];
@apply gap-5 py-5;
}
.card > header {
@apply gap-1.5 rounded-t-[min(var(--radius-4xl),24px)] px-5 in-data-[size=sm]:px-4 [.border-b]:pb-5 in-data-[size=sm]:[.border-b]:pb-4;
.card-sm {
@apply gap-4 py-4;
}
.card > header > :is(h2, h3, [data-title], .card-title) {
.card > header,
.card-sm > header {
@apply gap-1.5 rounded-t-[min(var(--radius-4xl),24px)] px-5 [.border-b]:pb-5;
}
.card-sm > header {
@apply px-4 [.border-b]:pb-4;
}
.card > header > :is(h2, h3, [data-title], .card-title),
.card-sm > header > :is(h2, h3, [data-title], .card-title) {
@apply text-base font-medium;
}
.card > header > :is(p, [data-description], .card-description) {
.card > header > :is(p, [data-description], .card-description),
.card-sm > header > :is(p, [data-description], .card-description) {
@apply text-muted-foreground text-sm;
}
.card > section {
@apply px-5 in-data-[size=sm]:px-4;
.card > section,
.card-sm > section {
@apply px-5;
}
.card > footer {
@apply rounded-b-[min(var(--radius-4xl),24px)] px-5 in-data-[size=sm]:px-4 [.border-t]:pt-5 in-data-[size=sm]:[.border-t]:pt-4;
.card-sm > section {
@apply px-4;
}
.card > footer,
.card-sm > footer {
@apply rounded-b-[min(var(--radius-4xl),24px)] px-5 [.border-t]:pt-5;
}
.card-sm > footer {
@apply px-4 [.border-t]:pt-4;
}
/* Chart */
.chart-tooltip {
@apply border-border/50 bg-background text-foreground gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl;
}
.chart-tooltip-title {
@apply font-medium;
}
.chart-legend-item {
@apply text-foreground;
}
.chart-legend-item[aria-pressed='false'] {
@apply text-muted-foreground;
}
/* Checkbox */
+106 -15
View File
@@ -261,7 +261,7 @@
@apply border-border focus-visible:border-ring;
}
> .button-group-text {
> :is(span, label, output) {
@apply border-border;
}
}
@@ -280,7 +280,7 @@
}
}
.button-group-text {
.button-group > :is(span, label, output) {
@apply gap-2 border border-transparent border-b-input bg-transparent px-2.5 text-xs font-semibold uppercase [&_svg:not([class*='size-'])]:size-3.5;
}
@@ -399,7 +399,7 @@
/* Alert */
.alert,
.alert-destructive {
@apply grid gap-1 bg-background border px-4 py-3 text-start text-sm has-[>[data-action]]:relative has-[>[data-action]]:pe-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2.5 [&>svg]:row-span-2 [&>svg]:translate-y-0.5 [&>svg]:text-current [&>svg:not([class*='size-'])]:size-4 relative after:-inset-y-px after:-start-px after:w-0.5 after:absolute;
@apply grid gap-1 bg-background border px-4 py-3 text-start text-sm has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2.5 [&>svg]:row-span-2 [&>svg]:translate-y-0.5 [&>svg]:text-current [&>svg:not([class*='size-'])]:size-4 relative after:-inset-y-px after:-start-px after:w-0.5 after:absolute;
}
.alert {
@@ -427,9 +427,57 @@
@apply text-destructive/90 text-sm text-balance md:text-pretty [&_p:not(:last-child)]:mb-4;
}
.alert > [data-action],
.alert-destructive > [data-action] {
@apply absolute top-2.5 end-3;
.alert > footer,
.alert-destructive > footer {
@apply top-2.5 end-3;
}
/* Avatar */
.avatar,
.avatar-sm,
.avatar-lg {
@apply rounded-full after:rounded-[inherit];
}
.avatar {
@apply size-8;
}
.avatar-sm {
@apply size-6;
}
.avatar-lg {
@apply size-10;
}
.avatar > span:not([data-badge]),
.avatar-sm > span:not([data-badge]),
.avatar-lg > span:not([data-badge]) {
@apply bg-muted text-muted-foreground rounded-[inherit];
}
.avatar > img,
.avatar-sm > img,
.avatar-lg > img {
@apply rounded-[inherit];
}
.avatar > [data-badge],
.avatar-sm > [data-badge],
.avatar-lg > [data-badge] {
@apply bg-primary text-primary-foreground ring-background;
}
.avatar-group > [data-count] {
@apply bg-muted text-muted-foreground size-8 rounded-full text-sm [&>svg]:size-4;
}
.avatar-group:has(> .avatar-sm) > [data-count] {
@apply size-6 [&>svg]:size-3;
}
.avatar-group:has(> .avatar-lg) > [data-count] {
@apply size-10 [&>svg]:size-5;
}
/* Badge */
@@ -740,28 +788,71 @@
}
/* Card */
.card,
.card-sm {
@apply bg-card text-card-foreground ring-foreground/5 overflow-hidden text-sm shadow-sm ring-1 has-[>img:first-child]:pt-0 [&>img:first-child]:rounded-none [&>img:last-child]:rounded-none;
}
.card {
@apply bg-card text-card-foreground ring-foreground/5 gap-8 overflow-hidden py-8 text-sm shadow-sm ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-5 data-[size=sm]:py-5 [&>img:first-child]:rounded-none [&>img:last-child]:rounded-none;
@apply gap-8 py-8;
}
.card > header {
@apply gap-1.5 rounded-none px-8 in-data-[size=sm]:px-5 [.border-b]:pb-8 in-data-[size=sm]:[.border-b]:pb-5;
.card-sm {
@apply gap-5 py-5;
}
.card > header > :is(h2, h3, [data-title], .card-title) {
.card > header,
.card-sm > header {
@apply gap-1.5 rounded-none px-8 [.border-b]:pb-8;
}
.card-sm > header {
@apply px-5 [.border-b]:pb-5;
}
.card > header > :is(h2, h3, [data-title], .card-title),
.card-sm > header > :is(h2, h3, [data-title], .card-title) {
@apply text-lg font-semibold tracking-wider uppercase;
}
.card > header > :is(p, [data-description], .card-description) {
.card > header > :is(p, [data-description], .card-description),
.card-sm > header > :is(p, [data-description], .card-description) {
@apply text-muted-foreground text-sm leading-relaxed;
}
.card > section {
@apply px-8 in-data-[size=sm]:px-5;
.card > section,
.card-sm > section {
@apply px-8;
}
.card > footer {
@apply px-8 in-data-[size=sm]:px-5 [.border-t]:pt-8 in-data-[size=sm]:[.border-t]:pt-5;
.card-sm > section {
@apply px-5;
}
.card > footer,
.card-sm > footer {
@apply px-8 [.border-t]:pt-8;
}
.card-sm > footer {
@apply px-5 [.border-t]:pt-5;
}
/* Chart */
.chart-tooltip {
@apply border-border/50 bg-background text-foreground gap-1.5 rounded-none border px-2.5 py-1.5 text-xs shadow-xl;
}
.chart-tooltip-title {
@apply font-medium;
}
.chart-legend-item {
@apply text-foreground;
}
.chart-legend-item[aria-pressed='false'] {
@apply text-muted-foreground;
}
/* Checkbox */
+110 -15
View File
@@ -264,7 +264,7 @@
}
}
.button-group-text {
.button-group > :is(span, label, output) {
@apply bg-muted gap-2 rounded-md border px-2.5 text-sm font-medium shadow-xs [&_svg:not([class*='size-'])]:size-4;
}
@@ -383,7 +383,7 @@
/* Alert */
.alert,
.alert-destructive {
@apply grid gap-0.5 rounded-lg border px-4 py-3 text-start text-sm has-[>[data-action]]:relative has-[>[data-action]]:pe-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2.5 [&>svg]:row-span-2 [&>svg]:translate-y-0.5 [&>svg]:text-current [&>svg:not([class*='size-'])]:size-4;
@apply grid gap-0.5 rounded-lg border px-4 py-3 text-start text-sm has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2.5 [&>svg]:row-span-2 [&>svg]:translate-y-0.5 [&>svg]:text-current [&>svg:not([class*='size-'])]:size-4;
}
.alert {
@@ -411,9 +411,57 @@
@apply text-destructive/90 text-sm text-balance md:text-pretty [&_p:not(:last-child)]:mb-4;
}
.alert > [data-action],
.alert-destructive > [data-action] {
@apply absolute top-2.5 end-3;
.alert > footer,
.alert-destructive > footer {
@apply top-2.5 end-3;
}
/* Avatar */
.avatar,
.avatar-sm,
.avatar-lg {
@apply rounded-full after:rounded-[inherit];
}
.avatar {
@apply size-8;
}
.avatar-sm {
@apply size-6;
}
.avatar-lg {
@apply size-10;
}
.avatar > span:not([data-badge]),
.avatar-sm > span:not([data-badge]),
.avatar-lg > span:not([data-badge]) {
@apply bg-muted text-muted-foreground rounded-[inherit];
}
.avatar > img,
.avatar-sm > img,
.avatar-lg > img {
@apply rounded-[inherit];
}
.avatar > [data-badge],
.avatar-sm > [data-badge],
.avatar-lg > [data-badge] {
@apply bg-primary text-primary-foreground ring-background;
}
.avatar-group > [data-count] {
@apply bg-muted text-muted-foreground size-8 rounded-full text-sm [&>svg]:size-4;
}
.avatar-group:has(> .avatar-sm) > [data-count] {
@apply size-6 [&>svg]:size-3;
}
.avatar-group:has(> .avatar-lg) > [data-count] {
@apply size-10 [&>svg]:size-5;
}
/* Badge */
@@ -720,28 +768,75 @@
}
/* Card */
.card,
.card-sm {
@apply ring-foreground/10 bg-card text-card-foreground overflow-hidden rounded-xl text-sm shadow-xs ring-1 has-[>img:first-child]:pt-0 [&>img:first-child]:rounded-t-xl [&>img:last-child]:rounded-b-xl;
}
.card {
@apply ring-foreground/10 bg-card text-card-foreground gap-6 overflow-hidden rounded-xl py-6 text-sm shadow-xs ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-4 data-[size=sm]:py-4 [&>img:first-child]:rounded-t-xl [&>img:last-child]:rounded-b-xl;
@apply gap-6 py-6;
}
.card > header {
@apply gap-1 rounded-t-xl px-6 in-data-[size=sm]:px-4 [.border-b]:pb-6 in-data-[size=sm]:[.border-b]:pb-4;
.card-sm {
@apply gap-4 py-4;
}
.card > header > :is(h2, h3, [data-title], .card-title) {
@apply text-base leading-normal font-medium in-data-[size=sm]:text-sm;
.card > header,
.card-sm > header {
@apply gap-1 rounded-t-xl px-6 [.border-b]:pb-6;
}
.card > header > :is(p, [data-description], .card-description) {
.card-sm > header {
@apply px-4 [.border-b]:pb-4;
}
.card > header > :is(h2, h3, [data-title], .card-title),
.card-sm > header > :is(h2, h3, [data-title], .card-title) {
@apply text-base leading-normal font-medium;
}
.card-sm > header > :is(h2, h3, [data-title], .card-title) {
@apply text-sm;
}
.card > header > :is(p, [data-description], .card-description),
.card-sm > header > :is(p, [data-description], .card-description) {
@apply text-muted-foreground text-sm;
}
.card > section {
@apply px-6 in-data-[size=sm]:px-4;
.card > section,
.card-sm > section {
@apply px-6;
}
.card > footer {
@apply rounded-b-xl px-6 in-data-[size=sm]:px-4 [.border-t]:pt-6 in-data-[size=sm]:[.border-t]:pt-4;
.card-sm > section {
@apply px-4;
}
.card > footer,
.card-sm > footer {
@apply rounded-b-xl px-6 [.border-t]:pt-6;
}
.card-sm > footer {
@apply px-4 [.border-t]:pt-4;
}
/* Chart */
.chart-tooltip {
@apply border-border/50 bg-background text-foreground gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl;
}
.chart-tooltip-title {
@apply font-medium;
}
.chart-legend-item {
@apply text-foreground;
}
.chart-legend-item[aria-pressed='false'] {
@apply text-muted-foreground;
}
/* Checkbox */
-39
View File
@@ -1,39 +0,0 @@
@import "../docs/css/fonts.css";
@import "../docs/css/themes/claude.css";
@import "../docs/css/themes/doom-64.css";
@import "../docs/css/themes/supabase.css";
:root {
--font-sans: "Geist Sans", ui-sans-serif, system-ui, sans-serif;
--font-heading: "Geist Sans", ui-sans-serif, system-ui, sans-serif;
--font-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}
.preview {
@apply flex min-h-[350px] w-full items-center justify-center p-10;
}
.prose {
> .relative.my-6 {
@apply my-6;
}
pre.scrollbar {
@apply grid max-h-[650px] overflow-y-auto rounded-lg bg-muted/40 text-sm;
}
pre.scrollbar > code {
@apply block rounded-[inherit] bg-transparent p-3.5 font-mono;
}
}
.htmx-indicator {
@apply invisible opacity-0 transition-discrete transition-all;
}
.htmx-indicator:not(.htmx-request) {
@apply hidden;
}
.htmx-request,
.htmx-request.htmx-indicator {
@apply visible opacity-100;
}
+2 -2
View File
@@ -50,7 +50,7 @@
id="{{ id }}-menu"
aria-orientation="vertical"
data-empty="{{ empty_text }}"
class="scrollbar {{ menu_attrs.class }}"
class="scrollbar-thin {{ menu_attrs.class }}"
{% for key, value in menu_attrs.items() %}
{% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
{% endfor %}
@@ -121,7 +121,7 @@
id="{{ id }}-menu"
aria-orientation="vertical"
data-empty="{{ empty_text }}"
class="scrollbar {{ menu_attrs.class }}"
class="scrollbar-thin {{ menu_attrs.class }}"
{% for key, value in menu_attrs.items() %}
{% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
{% endfor %}
+351
View File
@@ -0,0 +1,351 @@
(() => {
const instances = new WeakMap();
const defaultColors = ['var(--chart-1)', 'var(--chart-2)', 'var(--chart-3)', 'var(--chart-4)', 'var(--chart-5)'];
const isChartJsData = (data) => {
return data && typeof data === 'object' && Array.isArray(data.datasets);
};
const resolveTarget = (target) => {
if (typeof target === 'string') {
const elements = Array.from(document.querySelectorAll(target));
if (elements.length === 0) {
throw new Error(`Chart target not found: ${target}`);
}
return elements;
}
if (target instanceof HTMLCanvasElement) return [target];
if (target instanceof Element) {
const canvas = target.matches('canvas') ? target : target.querySelector('canvas');
if (canvas) return [canvas];
}
if (target instanceof NodeList || Array.isArray(target)) {
return Array.from(target).flatMap(resolveTarget);
}
throw new Error('Chart target must be a selector, canvas, element, NodeList, or array.');
};
const readOption = (canvas, config, key, dataName) => {
if (config[key] !== undefined) return config[key];
return canvas.dataset[dataName];
};
const readBoolean = (canvas, config, key, dataName, defaultValue) => {
const value = readOption(canvas, config, key, dataName);
if (value === undefined) return defaultValue;
if (typeof value === 'boolean') return value;
return value !== 'false';
};
const readJsonAttribute = (canvas, name) => {
const value = canvas.getAttribute(name);
if (!value) return undefined;
try {
return JSON.parse(value);
} catch (error) {
console.error(`Invalid JSON in ${name}:`, error);
return undefined;
}
};
const colorForIndex = (index) => defaultColors[index % defaultColors.length];
const resolveColor = (color, element) => {
if (Array.isArray(color)) return color.map(item => resolveColor(item, element));
if (typeof color !== 'string') return color;
const probe = document.createElement('span');
probe.style.color = color;
probe.style.display = 'none';
(element.parentElement || document.body).appendChild(probe);
const resolved = getComputedStyle(probe).color;
probe.remove();
return resolved || color;
};
const resolveDatasetColors = (chartData, element) => {
chartData.datasets?.forEach((dataset) => {
dataset.borderColor = resolveColor(dataset.borderColor, element);
dataset.backgroundColor = resolveColor(dataset.backgroundColor, element);
dataset.hoverBorderColor = resolveColor(dataset.hoverBorderColor, element);
dataset.hoverBackgroundColor = resolveColor(dataset.hoverBackgroundColor, element);
});
return chartData;
};
const chartColor = (element, token) => resolveColor(`var(${token})`, element);
const colorMix = (color, opacity) => `color-mix(in oklab, ${color} ${opacity * 100}%, transparent)`;
const ensureContainer = (canvas) => {
if (canvas.parentElement?.classList.contains('chart')) {
canvas.parentElement.dataset.basecoatChartContainer = 'true';
return canvas.parentElement;
}
const container = document.createElement('div');
container.className = 'chart';
container.dataset.basecoatChartContainer = 'true';
canvas.insertAdjacentElement('beforebegin', container);
container.append(canvas);
return container;
};
const seriesEntries = (series) => Object.entries(series || {});
const valueFor = (row, key) => {
if (row && typeof row === 'object') return row[key];
return undefined;
};
const toChartData = ({ type, labelKey, data, series }) => {
if (isChartJsData(data)) return data;
const rows = Array.isArray(data) ? data : [];
const entries = seriesEntries(series);
const labels = rows.map((row) => valueFor(row, labelKey));
if (type === 'pie' || type === 'doughnut' || type === 'polarArea') {
const [firstKey, firstSeries = {}] = entries[0] || [];
return {
labels,
datasets: [{
label: firstSeries.label || firstKey || 'Value',
data: rows.map((row) => valueFor(row, firstKey)),
backgroundColor: rows.map((row, index) => row?.color || row?.fill || colorForIndex(index)),
borderColor: rows.map((row, index) => row?.color || row?.fill || colorForIndex(index)),
...(firstSeries.dataset || {}),
}],
};
}
return {
labels,
datasets: entries.map(([key, item], index) => {
const color = item.color || colorForIndex(index);
return {
label: item.label || key,
data: rows.map((row) => valueFor(row, key)),
borderColor: color,
backgroundColor: item.backgroundColor || color,
fill: type === 'line' ? false : undefined,
type: item.type,
yAxisID: item.axis,
hidden: item.hidden,
...(item.dataset || {}),
};
}),
};
};
const formatValue = (value) => {
return typeof value === 'number' ? value.toLocaleString() : String(value);
};
const ensureTooltip = (canvas) => {
let tooltip = canvas._basecoatChartTooltip;
if (tooltip) return tooltip;
tooltip = document.createElement('div');
tooltip.className = 'chart-tooltip';
tooltip.hidden = true;
tooltip.setAttribute('role', 'status');
tooltip.setAttribute('aria-live', 'polite');
document.body.appendChild(tooltip);
canvas._basecoatChartTooltip = tooltip;
return tooltip;
};
const renderTooltip = (context) => {
const { chart, tooltip } = context;
const element = ensureTooltip(chart.canvas);
if (tooltip.opacity === 0) {
element.hidden = true;
return;
}
const children = [];
if (tooltip.title?.length) {
const title = document.createElement('div');
title.className = 'chart-tooltip-title';
title.textContent = tooltip.title.join(', ');
children.push(title);
}
const items = document.createElement('div');
items.className = 'chart-tooltip-items';
tooltip.dataPoints.forEach((item) => {
const color = item.dataset.borderColor || item.dataset.backgroundColor || colorForIndex(item.datasetIndex);
const value = item.formattedValue || formatValue(item.raw);
const row = document.createElement('div');
row.className = 'chart-tooltip-item';
const indicator = document.createElement('span');
indicator.className = 'chart-tooltip-indicator';
indicator.style.setProperty('--chart-indicator-color', color);
const label = document.createElement('span');
label.className = 'chart-tooltip-label';
label.textContent = item.dataset.label || item.label;
const tooltipValue = document.createElement('span');
tooltipValue.className = 'chart-tooltip-value';
tooltipValue.textContent = value;
row.append(indicator, label, tooltipValue);
items.append(row);
});
children.push(items);
const rect = chart.canvas.getBoundingClientRect();
element.replaceChildren(...children);
element.hidden = false;
element.style.left = `${rect.left + window.scrollX + tooltip.caretX}px`;
element.style.top = `${rect.top + window.scrollY + tooltip.caretY}px`;
};
const createLegendPlugin = (canvas, enabled) => ({
id: `basecoatLegend-${Math.random().toString(36).slice(2)}`,
afterUpdate(chart) {
if (!enabled) return;
let legend = canvas._basecoatChartLegend;
if (!legend) {
legend = document.createElement('ul');
legend.className = 'chart-legend';
canvas._basecoatChartContainer.insertAdjacentElement('afterend', legend);
canvas._basecoatChartLegend = legend;
}
const items = chart.options.plugins.legend.labels.generateLabels(chart);
legend.replaceChildren(...items.map((item) => {
const content = document.createElement('span');
content.className = 'chart-legend-item';
const indicator = document.createElement('span');
indicator.className = 'chart-legend-indicator';
indicator.style.setProperty('--chart-indicator-color', item.fillStyle || item.strokeStyle || colorForIndex(item.datasetIndex || item.index || 0));
const label = document.createElement('span');
label.textContent = item.text;
content.append(indicator, label);
const listItem = document.createElement('li');
listItem.append(content);
return listItem;
}));
},
});
const removeGeneratedElements = (canvas) => {
canvas._basecoatChartTooltip?.remove();
canvas._basecoatChartLegend?.remove();
delete canvas._basecoatChartTooltip;
delete canvas._basecoatChartLegend;
};
const initChart = (canvas, config = {}) => {
const Chart = config.Chart || window.Chart;
if (!Chart) {
throw new Error('Chart.js is required before calling basecoat.chart().');
}
const previous = instances.get(canvas);
if (previous) previous.destroy();
removeGeneratedElements(canvas);
const type = readOption(canvas, config, 'type', 'chartType') || 'bar';
const labelKey = readOption(canvas, config, 'labelKey', 'chartLabelKey') || 'label';
const legend = readBoolean(canvas, config, 'legend', 'chartLegend', false);
const tooltip = readBoolean(canvas, config, 'tooltip', 'chartTooltip', true);
const data = config.data || readJsonAttribute(canvas, 'data-chart-data') || [];
const series = config.series || readJsonAttribute(canvas, 'data-chart-series') || {};
const chartData = config.chartData || toChartData({ type, labelKey, data, series });
const userOptions = config.options || {};
const legendPlugin = createLegendPlugin(canvas, legend);
const container = ensureContainer(canvas);
const borderColor = chartColor(canvas, '--border');
const gridColor = resolveColor(colorMix('var(--border)', 0.5), canvas);
const mutedColor = chartColor(canvas, '--muted-foreground');
canvas.classList.remove('chart');
canvas._basecoatChartContainer = container;
canvas.dataset.chartLegend = String(legend);
const chart = new Chart(canvas, {
type,
data: resolveDatasetColors(chartData, canvas),
options: {
responsive: true,
maintainAspectRatio: false,
interaction: {
mode: 'index',
intersect: false,
},
...userOptions,
scales: {
x: {
border: { display: false, color: borderColor },
grid: { display: false, color: gridColor },
ticks: { color: mutedColor, padding: 8 },
...(userOptions.scales?.x || {}),
},
y: {
border: { display: false, color: borderColor },
grid: { color: gridColor },
ticks: { display: false, color: mutedColor },
...(userOptions.scales?.y || {}),
},
...(Object.fromEntries(Object.entries(userOptions.scales || {}).filter(([key]) => key !== 'x' && key !== 'y'))),
},
plugins: {
...userOptions.plugins,
legend: {
display: false,
...(userOptions.plugins?.legend || {}),
},
tooltip: {
enabled: false,
external: tooltip ? renderTooltip : undefined,
...(userOptions.plugins?.tooltip || {}),
},
},
},
plugins: [legendPlugin, ...(config.plugins || [])],
});
instances.set(canvas, chart);
canvas.dataset.chartInitialized = 'true';
canvas.chart = chart;
canvas._destroy = () => {
chart.destroy();
removeGeneratedElements(canvas);
instances.delete(canvas);
canvas.removeAttribute('data-chart-initialized');
delete canvas._basecoatChartContainer;
delete canvas.chart;
delete canvas._destroy;
};
return chart;
};
const chart = (target, config = {}) => {
const canvases = resolveTarget(target);
const charts = canvases.map((canvas) => initChart(canvas, config));
return charts.length === 1 ? charts[0] : charts;
};
if (window.basecoat) {
window.basecoat.chart = chart;
}
})();
+5 -1
View File
@@ -115,7 +115,11 @@
} else {
const option = optionOrOptions;
if (!option) return;
state.selectedLabel.innerHTML = option.innerHTML;
if (option.dataset.label) {
state.selectedLabel.textContent = option.dataset.label;
} else {
state.selectedLabel.innerHTML = option.innerHTML;
}
selectedDetail = toSelected(option);
value = selectedDetail.value;
state.input.value = serializeSelection(state, [selectedDetail]);
+2 -2
View File
@@ -50,7 +50,7 @@
id="{{ id }}-menu"
aria-orientation="vertical"
data-empty="{{ empty_text }}"
class="scrollbar {{ menu_attrs.class }}"
class="scrollbar-thin {{ menu_attrs.class }}"
{% for key, value in menu_attrs %}
{% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
{% endfor %}
@@ -121,7 +121,7 @@
id="{{ id }}-menu"
aria-orientation="vertical"
data-empty="{{ empty_text }}"
class="scrollbar {{ menu_attrs.class }}"
class="scrollbar-thin {{ menu_attrs.class }}"
{% for key, value in menu_attrs %}
{% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
{% endfor %}
+10 -1
View File
@@ -1,7 +1,15 @@
import fs from 'node:fs';
import path from 'node:path';
import Nunjucks from 'nunjucks';
const types = ['success', 'error', 'info', 'warning'];
const env = new Nunjucks.Environment(
new Nunjucks.FileSystemLoader([
path.resolve('src/nunjucks'),
path.resolve('docs/src/fragments/toast'),
]),
{ autoescape: true },
);
export function getStaticPaths() {
return types.map((type) => ({ params: { type } }));
@@ -10,6 +18,7 @@ export function getStaticPaths() {
export function GET({ params }) {
const type = String(params.type || '');
if (!types.includes(type)) return new Response('Not found', { status: 404 });
const html = fs.readFileSync(path.resolve('docs/generated/fragments/toast', `${type}.html`), 'utf8');
const source = fs.readFileSync(path.resolve('docs/src/fragments/toast', `${type}.njk`), 'utf8');
const html = env.renderString(source).trim();
return new Response(html, { headers: { 'content-type': 'text/html; charset=utf-8' } });
}
+1 -1
View File
@@ -18,7 +18,7 @@ function flatten(menu) {
export function GET({ site }) {
const origin = site?.toString().replace(/\/$/, '') || 'https://basecoatui.com';
const manifest = JSON.parse(fs.readFileSync(path.resolve('docs/generated/docs.json'), 'utf8'));
const manifest = JSON.parse(fs.readFileSync(path.resolve('docs/src/docs.json'), 'utf8'));
const urls = flatten(manifest.menu).map((slug) => ` <url><loc>${origin}${routePath(slug)}</loc></url>`).join('\n');
return new Response(`<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${urls}\n</urlset>\n`, {
headers: { 'content-type': 'application/xml; charset=utf-8' },