docs: improve contrsat

This commit is contained in:
Bereket Engida
2026-02-28 18:23:39 -08:00
parent fd37e60c70
commit 1906ebfaaa
11 changed files with 190 additions and 181 deletions
+3 -3
View File
@@ -51,7 +51,7 @@ function useCopyButton(
const cache = new Map<string, string>();
const tocAction =
"inline-flex items-center gap-1.5 px-2 py-1 text-[11px] uppercase tracking-wider whitespace-nowrap transition-all duration-200 text-foreground/50 hover:text-foreground border border-transparent hover:border-foreground/10 hover:bg-foreground/5 cursor-pointer select-none [&_svg]:size-3";
"inline-flex items-center gap-1.5 px-2 py-1 text-[11px] uppercase tracking-wider whitespace-nowrap transition-all duration-200 text-foreground/60 hover:text-foreground border border-transparent hover:border-foreground/10 hover:bg-foreground/5 cursor-pointer select-none [&_svg]:size-3";
export function LLMCopyButton() {
const [isLoading, startTransition] = useTransition();
@@ -211,11 +211,11 @@ export function ViewOptions(props: { markdownUrl: string; githubUrl: string }) {
href={item.href}
rel="noreferrer noopener"
target="_blank"
className="flex items-center gap-2.5 px-2.5 py-2 text-[12px] text-foreground/50 hover:text-foreground hover:bg-foreground/5 transition-colors duration-150 [&_svg]:size-3.5 [&_svg]:shrink-0"
className="flex items-center gap-2.5 px-2.5 py-2 text-[12px] text-foreground/60 hover:text-foreground hover:bg-foreground/5 transition-colors duration-150 [&_svg]:size-3.5 [&_svg]:shrink-0"
>
{item.icon}
{item.title}
<ExternalLink className="size-3 text-foreground/20 ms-auto" />
<ExternalLink className="size-3 text-foreground/30 ms-auto" />
</a>
))}
</PopoverContent>
+3 -3
View File
@@ -759,17 +759,17 @@ html:not([data-anchor-scrolling]) {
.docs-layout #nd-page article > div.\@container > a div svg {
width: 12px;
height: 12px;
opacity: 0.3;
opacity: 0.45;
transition: opacity 200ms ease;
}
.docs-layout #nd-page article > div.\@container > a:hover div svg {
opacity: 0.7;
opacity: 0.8;
}
.docs-layout #nd-page article > div.\@container > a > p {
font-size: 11px;
opacity: 0.35;
opacity: 0.5;
font-family: var(--font-sans);
letter-spacing: 0;
}
+47 -47
View File
@@ -239,17 +239,17 @@ function ComparisonCell({ value }: { value: string | boolean }) {
if (value === true)
return (
<span className="inline-flex items-center justify-center w-5 h-5">
<Check className="w-3.5 h-3.5 text-foreground/60" />
<Check className="w-3.5 h-3.5 text-foreground/70" />
</span>
);
if (value === false)
return (
<span className="inline-flex items-center justify-center w-5 h-5">
<Minus className="w-3 h-3 text-foreground/50 " />
<Minus className="w-3 h-3 text-foreground/40 " />
</span>
);
return (
<span className="text-[11px] text-foreground/70 dark:text-foreground/50 font-mono">
<span className="text-[11px] text-foreground/80 dark:text-foreground/60 font-mono">
{value}
</span>
);
@@ -287,7 +287,7 @@ function PricingHero() {
Infrastructure
</span>
</h1>
<p className="text-[11px] text-foreground/60 dark:text-foreground/40 leading-relaxed max-w-[260px]">
<p className="text-[11px] text-foreground/70 dark:text-foreground/50 leading-relaxed max-w-[260px]">
Dashboard, security, audit logs, and more for your auth.
</p>
</div>
@@ -301,15 +301,15 @@ function PricingHero() {
tier.highlight ? "bg-foreground/[0.03]" : ""
}`}
>
<p className="text-[8px] font-mono uppercase tracking-widest text-foreground/50 dark:text-foreground/30 mb-1">
<p className="text-[8px] font-mono uppercase tracking-widest text-foreground/60 dark:text-foreground/40 mb-1">
{tier.name}
</p>
<p className="text-sm font-light text-foreground/80 tabular-nums flex items-baseline justify-center gap-0.5">
<span>{tier.price}</span>
{tier.note && (
<span className="text-[9px] text-foreground/40 dark:text-foreground/50 font-mono">
{tier.note}
</span>
<span className="text-[9px] text-foreground/50 dark:text-foreground/55 font-mono">
{tier.note}
</span>
)}
</p>
</div>
@@ -330,10 +330,10 @@ function PricingHero() {
}}
className="flex items-baseline justify-between py-1.5 border-b border-dashed border-foreground/[0.06] last:border-0"
>
<span className="text-[11px] text-foreground/60 dark:text-foreground/40 uppercase tracking-wider">
{item.label}
</span>
<span className="text-[11px] text-foreground/80 dark:text-foreground/70 font-mono">
<span className="text-[11px] text-foreground/70 dark:text-foreground/50 uppercase tracking-wider">
{item.label}
</span>
<span className="text-[11px] text-foreground/85 dark:text-foreground/75 font-mono">
{item.value}
</span>
</motion.div>
@@ -350,7 +350,7 @@ function PricingHero() {
</Link>
<Link
href="/enterprise"
className="inline-flex items-center gap-1.5 text-[12px] text-foreground/60 dark:text-foreground/40 hover:text-foreground/70 font-mono uppercase tracking-wider transition-colors"
className="inline-flex items-center gap-1.5 text-[12px] text-foreground/70 dark:text-foreground/50 hover:text-foreground/80 font-mono uppercase tracking-wider transition-colors"
>
Contact Sales
<svg
@@ -403,13 +403,13 @@ function PricingCard({
<div className="flex flex-col flex-1 p-5">
{/* Tier name + badge */}
<div className="flex items-center gap-2 mb-4">
<h3 className="text-[10px] font-mono uppercase tracking-widest text-foreground/60 dark:text-foreground/40">
<h3 className="text-[10px] font-mono uppercase tracking-widest text-foreground/70 dark:text-foreground/50">
{tier.name}
</h3>
{isHighlighted && (
<span className="text-[8px] font-mono uppercase tracking-widest text-foreground/60 dark:text-foreground/40 border border-dashed border-foreground/10 px-1.5 py-0.5 leading-none">
popular
</span>
<span className="text-[8px] font-mono uppercase tracking-widest text-foreground/70 dark:text-foreground/50 border border-dashed border-foreground/15 px-1.5 py-0.5 leading-none">
popular
</span>
)}
</div>
@@ -423,24 +423,24 @@ function PricingCard({
{tier.price}
</span>
{tier.priceNote && (
<span className="text-[10px] text-foreground/50 dark:text-foreground/30 font-mono">
{tier.priceNote}
</span>
<span className="text-[10px] text-foreground/60 dark:text-foreground/40 font-mono">
{tier.priceNote}
</span>
)}
</div>
{/* Features */}
<div className="flex-1 mb-5">
<p className="text-[9px] text-foreground/50 dark:text-foreground/30 uppercase tracking-widest font-mono mb-3">
<p className="text-[9px] text-foreground/60 dark:text-foreground/40 uppercase tracking-widest font-mono mb-3">
{tier.featuresPrefix}
</p>
<ul className="space-y-2">
{tier.features.map((feature) => (
<li
key={feature}
className="flex items-start gap-2 text-[11px] text-foreground/70 dark:text-foreground/50 group-hover:text-foreground/75 dark:group-hover:text-foreground/55 transition-colors duration-300"
className="flex items-start gap-2 text-[11px] text-foreground/80 dark:text-foreground/60 group-hover:text-foreground/85 dark:group-hover:text-foreground/65 transition-colors duration-300"
>
<span className="text-foreground/40 dark:text-foreground/50 mt-px font-mono text-[9px] leading-none select-none shrink-0">
<span className="text-foreground/50 dark:text-foreground/55 mt-px font-mono text-[9px] leading-none select-none shrink-0">
+
</span>
<span>{feature}</span>
@@ -456,7 +456,7 @@ function PricingCard({
className={`w-full py-2.5 text-center transition-all duration-200 cursor-pointer ${
isHighlighted
? "bg-foreground text-background hover:opacity-90"
: "border border-dashed border-foreground/[0.12] text-foreground/60 dark:text-foreground/40 hover:text-foreground/70 hover:border-foreground/25 hover:bg-foreground/[0.02]"
: "border border-dashed border-foreground/[0.12] text-foreground/70 dark:text-foreground/50 hover:text-foreground/80 hover:border-foreground/25 hover:bg-foreground/[0.02]"
}`}
>
<span className="font-mono text-[10px] uppercase tracking-widest">
@@ -512,25 +512,25 @@ export function PricingPageClient() {
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, delay: 0.05 }}
>
<p className="text-[10px] uppercase tracking-widest text-foreground/50 dark:text-foreground/30 font-mono mb-5">
<span className="text-foreground/65 dark:text-foreground/50">
# Framework
</span>
</p>
<p className="text-[10px] uppercase tracking-widest text-foreground/55 dark:text-foreground/40 font-mono mb-5">
<span className="text-foreground/75 dark:text-foreground/60">
# Framework
</span>
</p>
<div className="relative border border-dashed border-foreground/[0.12] bg-foreground/[0.02] overflow-hidden">
<div className="px-5 py-5">
<div className="flex items-start justify-between gap-6">
<div className="space-y-2.5 flex-1">
<div className="flex items-center gap-2">
<h3 className="text-[10px] font-mono uppercase tracking-widest text-foreground/80">
Community
</h3>
<span className="text-[8px] font-mono uppercase tracking-widest text-foreground/65 dark:text-foreground/50 border border-dashed border-foreground/10 px-1.5 py-0.5 leading-none">
<h3 className="text-[10px] font-mono uppercase tracking-widest text-foreground/85">
Community
</h3>
<span className="text-[8px] font-mono uppercase tracking-widest text-foreground/75 dark:text-foreground/60 border border-dashed border-foreground/15 px-1.5 py-0.5 leading-none">
open source
</span>
</div>
<p className="text-[11px] text-foreground/70 dark:text-foreground/55 leading-relaxed max-w-md">
<p className="text-[11px] text-foreground/80 dark:text-foreground/65 leading-relaxed max-w-md">
Comprehensive authentication and authorization
framework.
</p>
@@ -538,7 +538,7 @@ export function PricingPageClient() {
<div className="text-right shrink-0 flex flex-col items-end gap-3">
<Link
href="/docs"
className="inline-flex items-center gap-1.5 px-3 py-1.5 border border-foreground/[0.12] text-foreground/60 dark:text-foreground/40 hover:text-foreground/70 hover:border-foreground/25 hover:bg-foreground/[0.02] transition-all"
className="inline-flex items-center gap-1.5 px-3 py-1.5 border border-foreground/[0.12] text-foreground/70 dark:text-foreground/50 hover:text-foreground/80 hover:border-foreground/25 hover:bg-foreground/[0.02] transition-all"
>
<span className="font-mono text-[10px] uppercase tracking-widest">
Read Docs
@@ -567,11 +567,11 @@ export function PricingPageClient() {
animate={{ opacity: 1 }}
transition={{ duration: 0.4, delay: 0.15 }}
>
<p className="text-[10px] uppercase tracking-widest text-foreground/50 dark:text-foreground/30 font-mono mb-5">
<span className="text-foreground/65 dark:text-foreground/50">
# Infrastructure
</span>
</p>
<p className="text-[10px] uppercase tracking-widest text-foreground/55 dark:text-foreground/40 font-mono mb-5">
<span className="text-foreground/75 dark:text-foreground/60">
# Infrastructure
</span>
</p>
{/* Pricing Cards */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-0">
@@ -587,15 +587,15 @@ export function PricingPageClient() {
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, delay: 0.45 }}
>
<p className="text-[10px] uppercase tracking-widest text-foreground/50 dark:text-foreground/30 font-mono mb-5">
# feature comparison
</p>
<p className="text-[10px] uppercase tracking-widest text-foreground/55 dark:text-foreground/40 font-mono mb-5">
# feature comparison
</p>
<div className="border border-dashed border-foreground/[0.08] overflow-x-auto">
<table className="w-full min-w-[600px]">
<thead>
<tr className="border-b border-foreground/[0.08]">
<th className="text-left text-[10px] uppercase tracking-widest text-foreground/50 dark:text-foreground/30 font-mono font-normal py-3 px-5 w-[28%]">
<th className="text-left text-[10px] uppercase tracking-widest text-foreground/60 dark:text-foreground/40 font-mono font-normal py-3 px-5 w-[28%]">
Feature
</th>
{tierLabels.map((name) => (
@@ -603,8 +603,8 @@ export function PricingPageClient() {
key={name}
className={`text-center text-[10px] uppercase tracking-widest font-mono font-normal py-3 px-3 w-[18%] ${
name === "Pro"
? "text-foreground/70 bg-foreground/[0.025]"
: "text-foreground/50 dark:text-foreground/30"
? "text-foreground/80 bg-foreground/[0.025]"
: "text-foreground/60 dark:text-foreground/40"
}`}
>
{name}
@@ -620,7 +620,7 @@ export function PricingPageClient() {
i % 2 === 0 ? "bg-foreground/[0.008]" : ""
}`}
>
<td className="text-[11px] text-foreground/70 dark:text-foreground/50 py-2.5 px-5">
<td className="text-[11px] text-foreground/80 dark:text-foreground/60 py-2.5 px-5">
{row.label}
</td>
{tierKeys.map((tier) => (
+5 -5
View File
@@ -27,7 +27,7 @@ export const CustomItem: FC<{ item: PageTreeItem }> = ({ item }) => {
${
active
? "text-foreground bg-foreground/[0.06] border-l-2 border-foreground font-medium"
: "text-muted-foreground hover:text-foreground hover:bg-foreground/[0.04] border-l-2 border-transparent"
: "text-muted-foreground/80 hover:text-foreground hover:bg-foreground/[0.04] border-l-2 border-transparent"
}
`}
>
@@ -54,7 +54,7 @@ export const CustomFolder: FC<{
<button
type="button"
onClick={() => setOpen((v) => !v)}
className="flex items-center justify-between px-3 py-1.5 text-sm font-mono font-medium text-muted-foreground hover:text-foreground transition-colors cursor-pointer"
className="flex items-center justify-between px-3 py-1.5 text-sm font-mono font-medium text-muted-foreground/80 hover:text-foreground transition-colors cursor-pointer"
>
<span className="flex items-center gap-2">
{item.icon && <span className="shrink-0 size-4">{item.icon}</span>}
@@ -98,7 +98,7 @@ export const CustomSeparator: FC<{ item: PageTreeSeparator }> = ({ item }) => {
return (
<div className="mt-5 mb-1.5 px-3">
{item.name ? (
<span className="text-xs font-mono uppercase tracking-wider text-muted-foreground">
<span className="text-xs font-mono uppercase tracking-wider text-muted-foreground/80">
{item.name}
</span>
) : (
@@ -117,7 +117,7 @@ export const SearchButton: FC = () => {
<button
type="button"
onClick={() => setOpen(true)}
className="flex items-center gap-2 w-full px-3 py-2 mb-2 text-sm font-mono text-muted-foreground border border-border hover:text-foreground hover:bg-foreground/[0.04] transition-colors cursor-pointer"
className="flex items-center gap-2 w-full px-3 py-2 mb-2 text-sm font-mono text-muted-foreground/80 border border-border hover:text-foreground hover:bg-foreground/[0.04] transition-colors cursor-pointer"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -135,7 +135,7 @@ export const SearchButton: FC = () => {
<path d="m21 21-4.3-4.3" />
</svg>
<span className="flex-1 text-left">Search...</span>
<kbd className="hidden sm:inline-flex items-center gap-0.5 px-1.5 py-0.5 text-[10px] font-mono bg-foreground/[0.06] border border-border text-muted-foreground">
<kbd className="hidden sm:inline-flex items-center gap-0.5 px-1.5 py-0.5 text-[10px] font-mono bg-foreground/[0.06] border border-border text-muted-foreground/70">
<span className="text-xs">&#8984;</span>K
</kbd>
</button>
+23 -23
View File
@@ -75,13 +75,13 @@ export function DocsSidebar() {
<button
type="button"
className="flex w-full items-center gap-2 px-4 lg:px-7 py-2.5 border-b border-foreground/5 text-[12px] uppercase tracking-wider text-foreground/45 hover:text-foreground/75 transition-colors"
className="flex w-full items-center gap-2 px-4 lg:px-7 py-2.5 border-b border-foreground/5 text-[12px] uppercase tracking-wider text-foreground/55 hover:text-foreground/80 transition-colors"
onClick={() => setOpen(true)}
>
<Search className="size-3.5 shrink-0" />
<span className="truncate">Search</span>
<span
className="ml-auto flex items-center gap-1 shrink-0 text-foreground/50 hover:text-foreground/55 transition-colors"
className="ml-auto flex items-center gap-1 shrink-0 text-foreground/55 hover:text-foreground/70 transition-colors"
onClick={(e) => {
e.stopPropagation();
openAI();
@@ -114,7 +114,7 @@ export function DocsSidebar() {
"font-medium text-sm tracking-wider",
currentOpen === index
? "text-foreground bg-foreground/3"
: "text-foreground/65 hover:text-foreground hover:bg-foreground/3",
: "text-foreground/70 hover:text-foreground hover:bg-foreground/3",
)}
onClick={() => {
setCurrentOpen((prev) => (prev === index ? -1 : index));
@@ -196,16 +196,16 @@ function BranchSwitcher() {
className="flex w-full items-center gap-2 px-4 lg:px-7 py-3 hover:bg-foreground/[0.02] transition-colors"
onClick={() => setOpen((v) => !v)}
>
<GitBranch className="size-3.5 text-foreground/55 shrink-0" />
<GitBranch className="size-3.5 text-foreground/60 shrink-0" />
<div className="grow text-left min-w-0">
<p className="text-[12px] uppercase tracking-wider text-foreground/55 block">
<p className="text-[12px] uppercase tracking-wider text-foreground/60 block">
{branch}{" "}
<span className="text-[9px] text-foreground/30 ">
<span className="text-[9px] text-foreground/40 ">
{branch === "main" ? "" : "pre-release"}
</span>
</p>
</div>
<div className="flex flex-col items-center shrink-0 text-foreground/35">
<div className="flex flex-col items-center shrink-0 text-foreground/45">
<ChevronDownIcon className="size-3 rotate-180 -mb-[3px]" />
<ChevronDownIcon className="size-3 -mt-[3px]" />
</div>
@@ -226,12 +226,12 @@ function BranchSwitcher() {
"flex w-full items-center gap-2 px-3 py-2 text-[12px] transition-colors",
branch === "main"
? "text-foreground bg-foreground/5"
: "text-foreground/55 hover:text-foreground hover:bg-foreground/3",
)}
onClick={() => switchBranch("main")}
>
<span className="grow text-left">main</span>
<span className="text-[10px] text-foreground/35 uppercase tracking-wider">
: "text-foreground/60 hover:text-foreground hover:bg-foreground/3",
)}
onClick={() => switchBranch("main")}
>
<span className="grow text-left">main</span>
<span className="text-[10px] text-foreground/45 uppercase tracking-wider">
Stable
</span>
</button>
@@ -241,13 +241,13 @@ function BranchSwitcher() {
"flex w-full items-center gap-2 px-3 py-2 text-[12px] transition-colors",
branch === "canary"
? "text-foreground bg-foreground/5"
: "text-foreground/55 hover:text-foreground hover:bg-foreground/3",
)}
onClick={() => switchBranch("canary")}
: "text-foreground/60 hover:text-foreground hover:bg-foreground/3",
)}
onClick={() => switchBranch("canary")}
>
<span className="grow text-left">canary</span>
<Badge
className="pointer-events-none no-underline! border-dashed decoration-transparent! rounded-none px-1.5 py-0 text-[9px] uppercase tracking-wider text-foreground/50 border-foreground/20"
className="pointer-events-none no-underline! border-dashed decoration-transparent! rounded-none px-1.5 py-0 text-[9px] uppercase tracking-wider text-foreground/55 border-foreground/25"
variant="outline"
>
Pre-release
@@ -288,7 +288,7 @@ function SidebarSection({
key={`sep-${item.title}-${i}`}
className="flex flex-row items-center gap-2 mx-4 lg:mx-7 my-2"
>
<p className="text-[10px] text-foreground/35 uppercase tracking-wider">
<p className="text-[10px] text-foreground/45 uppercase tracking-wider">
{item.title}
</p>
<div className="grow h-px bg-border" />
@@ -301,7 +301,7 @@ function SidebarSection({
key={`group-${item.title}-${i}`}
className="flex flex-row items-center gap-2 mx-4 my-1 lg:mx-7"
>
<p className="text-[10px] text-foreground/35 uppercase tracking-wider">
<p className="text-[10px] text-foreground/45 uppercase tracking-wider">
{item.title}
</p>
<div className="grow h-px bg-border" />
@@ -409,7 +409,7 @@ function SubpageLink({
"relative flex items-center pr-4 lg:pr-7 py-1 text-[13px] transition-all duration-150",
active
? "text-foreground bg-foreground/6"
: "text-foreground/45 hover:text-foreground/75 hover:bg-foreground/3",
: "text-foreground/55 hover:text-foreground/80 hover:bg-foreground/3",
)}
>
<span className="truncate">{children}</span>
@@ -441,14 +441,14 @@ function SidebarLink({
${
active
? "text-foreground bg-foreground/6"
: "text-foreground/55 hover:text-foreground/85 hover:bg-foreground/3"
: "text-foreground/65 hover:text-foreground/90 hover:bg-foreground/3"
}
`}
>
{icon && (
<span
className={`transition-colors duration-150 ${
active ? "text-foreground" : "text-foreground/55"
active ? "text-foreground" : "text-foreground/65"
}`}
>
{icon}
@@ -467,7 +467,7 @@ function NewBadge({ isSelected }: { isSelected?: boolean }) {
"pointer-events-none no-underline! border-dashed decoration-transparent! rounded-none px-1.5 py-0 text-[9px] uppercase tracking-wider",
isSelected
? "border-solid! bg-foreground/10 text-foreground"
: "text-foreground/50 border-foreground/20",
: "text-foreground/55 border-foreground/25",
)}
variant="outline"
>
+28 -28
View File
@@ -77,7 +77,7 @@ export function APIMethod({
<span className="rounded bg-primary/10 px-2 py-0.5 text-xs font-semibold uppercase text-primary">
{method}
</span>
<span className="text-muted-foreground">{path}</span>
<span className="text-muted-foreground/80">{path}</span>
</div>
)}
<div className="prose-sm">{children}</div>
@@ -187,7 +187,7 @@ function TypeIcon({ type }: { type: string }) {
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className={cn(className, "text-foreground/30")}
className={cn(className, "text-foreground/40")}
>
<path d="M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5a2 2 0 0 0 2 2h1" />
<path d="M16 3h1a2 2 0 0 1 2 2v5a2 2 0 0 0 2 2 2 2 0 0 0-2 2v5a2 2 0 0 1-2 2h-1" />
@@ -263,7 +263,7 @@ function SchemaCodeBlock({
<div className="relative">
<button
type="button"
className="absolute top-2 right-2 font-mono text-[10px] text-foreground/30 hover:text-foreground/60 transition-colors"
className="absolute top-2 right-2 font-mono text-[10px] text-foreground/40 hover:text-foreground/65 transition-colors"
onClick={() => {
void navigator.clipboard.writeText(code);
setCopied(true);
@@ -272,7 +272,7 @@ function SchemaCodeBlock({
>
{copied ? "copied" : "copy"}
</button>
<pre className="overflow-x-auto p-4 font-mono text-[12px] leading-relaxed text-foreground/70 whitespace-pre">
<pre className="overflow-x-auto p-4 font-mono text-[12px] leading-relaxed text-foreground/80 whitespace-pre">
{code}
</pre>
</div>
@@ -319,24 +319,24 @@ export function DatabaseTable({
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="text-foreground/40"
>
<ellipse cx="12" cy="5" rx="9" ry="3" />
className="text-foreground/50"
>
<ellipse cx="12" cy="5" rx="9" ry="3" />
<path d="M3 5v14a9 3 0 0 0 18 0V5" />
<path d="M3 12a9 3 0 0 0 18 0" />
</svg>
{name ? (
<span className="font-mono text-[13px] text-foreground/70">
<span className="text-foreground/30">table </span>
<span className="font-mono text-[13px] text-foreground/80">
<span className="text-foreground/40">table </span>
{name}
</span>
) : (
<span className="text-[11px] text-foreground/30 font-mono uppercase tracking-widest">
<span className="text-[11px] text-foreground/40 font-mono uppercase tracking-widest">
Table
</span>
)}
{name && (
<span className="text-[10px] text-foreground/20 font-mono">
<span className="text-[10px] text-foreground/35 font-mono">
({fields.length})
</span>
)}
@@ -357,8 +357,8 @@ export function DatabaseTable({
className={cn(
"px-2 py-0.5 font-mono text-[10px] tracking-wide transition-colors cursor-pointer",
view === opt.key
? "text-foreground/70 bg-foreground/[0.05]"
: "text-foreground/50 hover:text-foreground/50",
? "text-foreground/80 bg-foreground/[0.05]"
: "text-foreground/55 hover:text-foreground/65",
)}
>
{opt.label}
@@ -378,8 +378,8 @@ export function DatabaseTable({
className={cn(
"px-1.5 py-0.5 font-mono text-[9px] tracking-wide transition-colors cursor-pointer",
sqlDialect === d.key
? "text-foreground/60 bg-foreground/[0.05]"
: "text-foreground/20 hover:text-foreground/40",
? "text-foreground/70 bg-foreground/[0.05]"
: "text-foreground/35 hover:text-foreground/50",
)}
>
{d.label}
@@ -397,8 +397,8 @@ export function DatabaseTable({
className={cn(
"px-1.5 py-0.5 font-mono text-[9px] tracking-wide transition-colors cursor-pointer",
drizzleProvider === d.key
? "text-foreground/60 bg-foreground/[0.05]"
: "text-foreground/20 hover:text-foreground/40",
? "text-foreground/70 bg-foreground/[0.05]"
: "text-foreground/35 hover:text-foreground/50",
)}
>
{d.label}
@@ -411,16 +411,16 @@ export function DatabaseTable({
<>
{/* Column headers */}
<div className="grid grid-cols-[minmax(120px,1.2fr)_minmax(100px,0.8fr)_minmax(40px,0.4fr)_minmax(150px,2fr)] border-b border-foreground/[0.06] bg-foreground/[0.02]">
<div className="px-4 py-1.5 text-[10px] font-mono uppercase tracking-widest text-foreground/50">
<div className="px-4 py-1.5 text-[10px] font-mono uppercase tracking-widest text-foreground/60">
Field
</div>
<div className="px-4 py-1.5 text-[10px] font-mono uppercase tracking-widest text-foreground/50">
<div className="px-4 py-1.5 text-[10px] font-mono uppercase tracking-widest text-foreground/60">
Type
</div>
<div className="px-4 py-1.5 text-[10px] font-mono uppercase tracking-widest text-foreground/50">
<div className="px-4 py-1.5 text-[10px] font-mono uppercase tracking-widest text-foreground/60">
Key
</div>
<div className="px-4 py-1.5 text-[10px] font-mono uppercase tracking-widest text-foreground/50">
<div className="px-4 py-1.5 text-[10px] font-mono uppercase tracking-widest text-foreground/60">
Description
</div>
</div>
@@ -436,7 +436,7 @@ export function DatabaseTable({
</div>
<div className="px-4 py-2 flex items-center gap-1.5">
<TypeIcon type={field.type} />
<span className="font-mono text-[11px] text-foreground/40">
<span className="font-mono text-[11px] text-foreground/55">
{field.type}
</span>
</div>
@@ -454,17 +454,17 @@ export function DatabaseTable({
</span>
)}
{field.isOptional && (
<span className="font-mono text-[10px] text-foreground/20">
<span className="font-mono text-[10px] text-foreground/35">
?
</span>
)}
{!field.isPrimaryKey &&
!field.isForeignKey &&
!field.isOptional && (
<span className="text-foreground/10">—</span>
<span className="text-foreground/20">—</span>
)}
</div>
<div className="px-4 py-2 text-[11px] text-foreground/40 leading-relaxed">
<div className="px-4 py-2 text-[11px] text-foreground/55 leading-relaxed">
{field.description}
</div>
</div>
@@ -516,7 +516,7 @@ export function Endpoint({
)}
>
<Method method={method || "GET"} />
<span className="font-mono text-sm text-muted-foreground">{path}</span>
<span className="font-mono text-sm text-muted-foreground/80">{path}</span>
</div>
);
}
@@ -590,7 +590,7 @@ export function DividerText({ children }: { children: ReactNode }) {
return (
<div className="flex items-center justify-center w-full">
<div className="w-full border-b border-muted"></div>
<div className="flex items-center justify-center w-full text-muted-foreground">
<div className="flex items-center justify-center w-full text-muted-foreground/80">
{children}
</div>
<div className="w-full border-b border-muted"></div>
@@ -602,7 +602,7 @@ export function DividerText({ children }: { children: ReactNode }) {
export function GenerateAppleJwt() {
return (
<div className="my-4 rounded-lg border bg-card p-4 text-sm text-muted-foreground">
<div className="my-4 rounded-lg border bg-card p-4 text-sm text-muted-foreground/80">
See the Apple documentation for generating a client secret JWT.
</div>
);
+7 -7
View File
@@ -146,7 +146,7 @@ export function StepperTOC({ items, children }: StepperTOCProps) {
? "bg-foreground border-foreground scale-125"
: isVisible
? "bg-foreground/50 border-foreground/50"
: "bg-transparent border-foreground/20 group-hover:border-foreground/40"
: "bg-transparent border-foreground/30 group-hover:border-foreground/50"
}
`}
/>
@@ -157,8 +157,8 @@ export function StepperTOC({ items, children }: StepperTOCProps) {
isActive
? "text-foreground"
: isVisible
? "text-foreground/50"
: "text-foreground/30 group-hover:text-foreground/60"
? "text-foreground/60"
: "text-foreground/40 group-hover:text-foreground/65"
}
`}
>
@@ -167,7 +167,7 @@ export function StepperTOC({ items, children }: StepperTOCProps) {
</a>
{i < headings.length - 1 && (
<span className="mx-2 text-foreground/20 text-[11px] select-none">
<span className="mx-2 text-foreground/30 text-[11px] select-none">
/
</span>
)}
@@ -181,7 +181,7 @@ export function StepperTOC({ items, children }: StepperTOCProps) {
{children && (
<div className="flex items-center gap-3 shrink-0 ml-auto pl-2">
{headings.length > 0 && (
<span className="text-foreground/10 text-[11px] select-none">
<span className="text-foreground/20 text-[11px] select-none">
|
</span>
)}
@@ -229,8 +229,8 @@ export function StepperTOC({ items, children }: StepperTOCProps) {
<span
className={`text-[10px] uppercase tracking-wider whitespace-nowrap transition-colors duration-200 ${
isSubActive
? "text-foreground"
: "text-foreground/30 group-hover:text-foreground/60"
? "text-foreground"
: "text-foreground/40 group-hover:text-foreground/65"
}`}
>
{sub.title}
+2 -2
View File
@@ -17,7 +17,7 @@ export function FloatingToolbar() {
<button
type="button"
onClick={() => setOpen(true)}
className="group flex items-center justify-center size-9 text-foreground/30 hover:text-foreground/60 transition-colors"
className="group flex items-center justify-center size-9 text-foreground/40 hover:text-foreground/70 transition-colors"
>
<kbd className="flex items-center gap-0.5 text-[10px] font-mono">
<span className="text-[11px]">&#8984;</span>K
@@ -25,7 +25,7 @@ export function FloatingToolbar() {
<span className="sr-only">Command menu</span>
</button>
<span className="w-px h-3 bg-foreground/[0.08]" />
<div className="flex items-center justify-center size-9 [&_button]:text-foreground/30 [&_button:hover]:text-foreground/60">
<div className="flex items-center justify-center size-9 [&_button]:text-foreground/40 [&_button:hover]:text-foreground/70">
<ThemeToggle />
</div>
</motion.div>
+16 -7
View File
@@ -1,7 +1,7 @@
// spell-checker:disable
"use client";
import { useEffect, useRef } from "react";
import { useLayoutEffect, useRef } from "react";
const VERTEX_SHADER = `
attribute vec2 a_position;
@@ -139,7 +139,7 @@ export function HalftoneBackground() {
const smoothMouseRef = useRef({ x: -1, y: -1 });
const clickRef = useRef({ strength: 0, x: 0, y: 0 });
useEffect(() => {
useLayoutEffect(() => {
const canvas = canvasRef.current;
const wrapper = wrapperRef.current;
if (!canvas || !wrapper) return;
@@ -225,12 +225,10 @@ export function HalftoneBackground() {
const draw = () => {
const elapsed = (performance.now() - startTime) / 1000;
// Smooth mouse interpolation for fluid feel
const lerp = 0.08;
const target = mouseRef.current;
const smooth = smoothMouseRef.current;
if (target.x < 0) {
// Mouse left - smoothly fade out
smooth.x += (target.x - smooth.x) * 0.02;
smooth.y += (target.y - smooth.y) * 0.02;
} else {
@@ -238,7 +236,6 @@ export function HalftoneBackground() {
smooth.y += (target.y - smooth.y) * lerp;
}
// Decay click strength
clickRef.current.strength *= 0.96;
gl.uniform1f(uTime, elapsed);
@@ -247,9 +244,18 @@ export function HalftoneBackground() {
gl.uniform1f(uClick, clickRef.current.strength);
gl.uniform2f(uClickPos, clickRef.current.x, clickRef.current.y);
gl.drawArrays(gl.TRIANGLES, 0, 6);
frameRef.current = requestAnimationFrame(draw);
};
// Draw the first frame synchronously so the canvas has content before paint
gl.uniform1f(uTime, 0);
gl.uniform2f(uResolution, canvas.width, canvas.height);
gl.uniform2f(uMouse, -1, -1);
gl.uniform1f(uClick, 0);
gl.uniform2f(uClickPos, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, 6);
frameRef.current = requestAnimationFrame(draw);
return () => {
@@ -268,10 +274,13 @@ export function HalftoneBackground() {
return (
<div
ref={wrapperRef}
className="absolute inset-0 overflow-hidden bg-white dark:bg-black"
className="absolute inset-0 overflow-hidden bg-background"
aria-hidden="true"
>
<canvas ref={canvasRef} className="w-full h-full invert dark:invert-0" />
<canvas
ref={canvasRef}
className="w-full h-full invert dark:invert-0"
/>
</div>
);
}
+11 -11
View File
@@ -1530,11 +1530,11 @@ export function HeroReadMe({
transition={{ duration: 0.4, delay: 0.3 }}
className="overflow-y-auto overflow-x-hidden no-scrollbar pt-[30px] pb-0"
>
<h1 className="flex items-center gap-2 text-sm sm:text-[15px] font-mono text-neutral-800 dark:text-neutral-200 pb-2 sm:pb-3 mb-4 sm:mb-5 border-b border-foreground/10">
<h1 className="flex items-center gap-2 text-sm sm:text-[15px] font-mono text-neutral-900 dark:text-neutral-100 pb-2 sm:pb-3 mb-4 sm:mb-5 border-b border-foreground/15">
README
</h1>
<p className="text-sm sm:text-[14px] text-neutral-700 dark:text-neutral-300 leading-[1.8] sm:leading-[1.9] mb-5 sm:mb-6">
<p className="text-sm sm:text-[14px] text-neutral-600 dark:text-neutral-300 leading-[1.8] sm:leading-[1.9] mb-5 sm:mb-6">
Better Auth is an authentication and authorization framework. It provides a comprehensive set of features out of the box and includes a Plugin ecosystem that simplifies adding advanced functionalities and infrastructure to help own your auth at scale.
</p>
@@ -1542,7 +1542,7 @@ export function HeroReadMe({
<div className="flex items-center gap-3 my-4">
<div className="flex-1 border-t border-foreground/6"></div>
<span className="text-[10px] text-foreground/60 dark:text-foreground/40 font-mono tracking-wider uppercase shrink-0">
<span className="text-[10px] text-foreground/70 dark:text-foreground/50 font-mono tracking-wider uppercase shrink-0">
Trusted By
</span>
</div>
@@ -1550,13 +1550,13 @@ export function HeroReadMe({
<TrustedBy />
<div className="flex items-center gap-3 my-4">
<span className="text-[10px] text-foreground/60 dark:text-foreground/40 font-mono tracking-wider uppercase shrink-0">
<span className="text-[10px] text-foreground/70 dark:text-foreground/50 font-mono tracking-wider uppercase shrink-0">
Features
</span>
<div className="flex-1 border-t border-foreground/6"></div>
<div className="flex-1 border-t border-foreground/10"></div>
</div>
<div className="relative grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 mb-2 border border-foreground/10 overflow-hidden">
<div className="relative grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 mb-2 border border-foreground/15 overflow-hidden">
{[
{
label: "Framework Agnostic",
@@ -1643,7 +1643,7 @@ export function HeroReadMe({
}
}}
className={cn(
"group/card relative p-4 lg:p-5 border-foreground/[0.1] min-h-[180px] transition-all duration-200 hover:bg-foreground/[0.02] hover:shadow-[inset_0_1px_0_0_rgba(128,128,128,0.1)] hover:z-10",
"group/card relative p-4 lg:p-5 border-foreground/[0.15] min-h-[180px] transition-all duration-200 hover:bg-foreground/[0.02] hover:shadow-[inset_0_1px_0_0_rgba(128,128,128,0.1)] hover:z-10",
// Bottom border: all except last; 3-col last row starts at 6
i < 8 && "border-b",
i >= 6 && "md:border-b-0",
@@ -1673,16 +1673,16 @@ export function HeroReadMe({
<polyline points="7 7 17 7 17 17" />
</svg>
</span>
<div className="text-[11px] font-mono text-neutral-500 mb-2 uppercase tracking-wider transition-colors duration-200 group-hover/card:text-neutral-400 dark:group-hover/card:text-neutral-400">
<span className="text-foreground/35 dark:text-foreground/20 mr-1.5 transition-colors duration-200 group-hover/card:text-foreground/50 dark:group-hover/card:text-foreground/30">
<div className="text-[11px] font-mono text-neutral-500 dark:text-neutral-400 mb-2 uppercase tracking-wider transition-colors duration-200 group-hover/card:text-neutral-400 dark:group-hover/card:text-neutral-300">
<span className="text-foreground/45 dark:text-foreground/30 mr-1.5 transition-colors duration-200 group-hover/card:text-foreground/60 dark:group-hover/card:text-foreground/40">
{String(i + 1).padStart(2, "0")}
</span>
{feature.label}
</div>
<div className="text-[13px] font-semibold text-neutral-800 dark:text-neutral-200 leading-snug mb-1.5 transition-colors duration-200 group-hover/card:text-neutral-900 dark:group-hover/card:text-neutral-100">
<div className="text-[13px] font-semibold text-neutral-900 dark:text-neutral-100 leading-snug mb-1.5 transition-colors duration-200 group-hover/card:text-neutral-950 dark:group-hover/card:text-white">
{feature.headline}
</div>
<div className="text-[11px] text-neutral-500 leading-relaxed transition-colors duration-200 group-hover/card:text-neutral-400 dark:group-hover/card:text-neutral-400">
<div className="text-[11px] text-neutral-500 dark:text-neutral-400 leading-relaxed transition-colors duration-200 group-hover/card:text-neutral-400 dark:group-hover/card:text-neutral-300">
{feature.desc}
</div>
{"logos" in feature && feature.logos && (
@@ -39,7 +39,7 @@ const resourceFiles: NavFileItem[] = [
function DropdownItem({ item }: { item: NavFileItem }) {
return (
<div className="group/item flex items-center gap-1.5 px-3 py-1.5 hover:bg-foreground/[0.06] transition-colors duration-150 cursor-pointer">
<span className="font-mono text-[10px] uppercase tracking-wider text-foreground/65 dark:text-foreground/50 group-hover/item:text-foreground transition-colors duration-150 whitespace-nowrap">
<span className="font-mono text-[10px] uppercase tracking-wider text-foreground/75 dark:text-foreground/60 group-hover/item:text-foreground transition-colors duration-150 whitespace-nowrap">
{item.name}
</span>
</div>
@@ -197,7 +197,7 @@ export function StaggeredNavFiles() {
}
}
}}
className="flex items-center justify-center px-4 py-3 text-foreground/65 dark:text-foreground/50 hover:text-foreground/80 transition-colors"
className="flex items-center justify-center px-4 py-3 text-foreground/75 dark:text-foreground/60 hover:text-foreground/85 transition-colors"
>
{mobileMenuOpen ? (
<svg
@@ -266,10 +266,10 @@ export function StaggeredNavFiles() {
className={`font-mono text-xs uppercase tracking-wider transition-colors duration-150 whitespace-nowrap ${
active
? "text-foreground"
: "text-foreground/60 dark:text-foreground/40 group-hover/tab:text-foreground/70"
}`}
>
{item.name}
: "text-foreground/65 dark:text-foreground/50 group-hover/tab:text-foreground/75"
}`}
>
{item.name}
</span>
</Link>
</motion.div>
@@ -300,13 +300,13 @@ export function StaggeredNavFiles() {
? "text-foreground"
: resourcesOpen
? "text-foreground/80"
: "text-foreground/60 dark:text-foreground/40 group-hover/tab:text-foreground/70"
}`}
>
resources
: "text-foreground/65 dark:text-foreground/50 group-hover/tab:text-foreground/75"
}`}
>
resources
</span>
<svg
className={`h-2 w-2 text-foreground/50 dark:text-foreground/30 transition-transform duration-200 ${
className={`h-2 w-2 text-foreground/55 dark:text-foreground/40 transition-transform duration-200 ${
resourcesOpen ? "rotate-180" : ""
}`}
viewBox="0 0 10 6"
@@ -352,8 +352,8 @@ export function StaggeredNavFiles() {
href="https://github.com/better-auth/better-auth"
target="_blank"
rel="noreferrer"
className="p-1.5 text-foreground/50 dark:text-foreground/30 hover:text-foreground/70 transition-colors"
aria-label="GitHub"
className="p-1.5 text-foreground/55 dark:text-foreground/40 hover:text-foreground/75 transition-colors"
aria-label="GitHub"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -371,8 +371,8 @@ export function StaggeredNavFiles() {
href="https://discord.gg/better-auth"
target="_blank"
rel="noreferrer"
className="p-1.5 text-foreground/50 dark:text-foreground/30 hover:text-foreground/70 transition-colors"
aria-label="Discord"
className="p-1.5 text-foreground/55 dark:text-foreground/40 hover:text-foreground/75 transition-colors"
aria-label="Discord"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -390,8 +390,8 @@ export function StaggeredNavFiles() {
href="https://reddit.com/r/better_auth"
target="_blank"
rel="noreferrer"
className="p-1.5 text-foreground/50 dark:text-foreground/30 hover:text-foreground/70 transition-colors"
aria-label="Reddit"
className="p-1.5 text-foreground/55 dark:text-foreground/40 hover:text-foreground/75 transition-colors"
aria-label="Reddit"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -411,8 +411,8 @@ export function StaggeredNavFiles() {
href="https://x.com/better_auth"
target="_blank"
rel="noreferrer"
className="p-1.5 text-foreground/50 dark:text-foreground/30 hover:text-foreground/70 transition-colors"
aria-label="X"
className="p-1.5 text-foreground/55 dark:text-foreground/40 hover:text-foreground/75 transition-colors"
aria-label="X"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -430,8 +430,8 @@ export function StaggeredNavFiles() {
href="https://www.npmjs.com/package/better-auth"
target="_blank"
rel="noreferrer"
className="p-1.5 text-foreground/50 dark:text-foreground/30 hover:text-foreground/70 transition-colors"
aria-label="npm"
className="p-1.5 text-foreground/55 dark:text-foreground/40 hover:text-foreground/75 transition-colors"
aria-label="npm"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -499,7 +499,7 @@ export function StaggeredNavFiles() {
<button
type="button"
onClick={() => setMobileView("nav")}
className="flex items-center gap-2 px-5 py-2.5 text-foreground/55 dark:text-foreground/35 hover:text-foreground/60 transition-colors border-b border-foreground/[0.06]"
className="flex items-center gap-2 px-5 py-2.5 text-foreground/65 dark:text-foreground/45 hover:text-foreground/70 transition-colors border-b border-foreground/[0.06]"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -531,10 +531,10 @@ export function StaggeredNavFiles() {
"font-medium text-sm tracking-wider",
mobileDocSection === index
? "text-foreground bg-foreground/3"
: "text-foreground/65 hover:text-foreground hover:bg-foreground/3",
)}
onClick={() =>
setMobileDocSection((prev) =>
: "text-foreground/70 hover:text-foreground hover:bg-foreground/3",
)}
onClick={() =>
setMobileDocSection((prev) =>
prev === index ? -1 : index,
)
}
@@ -568,10 +568,10 @@ export function StaggeredNavFiles() {
"relative flex items-center gap-2.5 px-5 py-1.5 text-[14px] transition-all duration-150",
pathname === section.href
? "text-foreground bg-foreground/6"
: "text-foreground/70 dark:text-foreground/55 hover:text-foreground/85 hover:bg-foreground/3",
)}
>
<span className="truncate">Overview</span>
: "text-foreground/75 dark:text-foreground/60 hover:text-foreground/90 hover:bg-foreground/3",
)}
>
<span className="truncate">Overview</span>
</Link>
)}
{section.list.map((item, i) => {
@@ -581,7 +581,7 @@ export function StaggeredNavFiles() {
key={`sep-${item.title}-${i}`}
className="flex flex-row items-center gap-2 mx-5 my-2"
>
<p className="text-[10px] text-foreground/55 dark:text-foreground/35 uppercase tracking-wider">
<p className="text-[10px] text-foreground/65 dark:text-foreground/45 uppercase tracking-wider">
{item.title}
</p>
<div className="grow h-px bg-border" />
@@ -603,15 +603,15 @@ export function StaggeredNavFiles() {
"relative flex items-center gap-2.5 px-5 py-1.5 text-[14px] transition-all duration-150",
active
? "text-foreground bg-foreground/6"
: "text-foreground/70 dark:text-foreground/55 hover:text-foreground/85 hover:bg-foreground/3",
)}
>
<span
className={cn(
"min-w-5 [&>svg]:size-[14px] transition-colors duration-150",
active
? "text-foreground"
: "text-foreground/70 dark:text-foreground/55",
: "text-foreground/75 dark:text-foreground/60 hover:text-foreground/90 hover:bg-foreground/3",
)}
>
<span
className={cn(
"min-w-5 [&>svg]:size-[14px] transition-colors duration-150",
active
? "text-foreground"
: "text-foreground/75 dark:text-foreground/60",
)}
>
<item.icon className="text-foreground/75" />
@@ -625,7 +625,7 @@ export function StaggeredNavFiles() {
"pointer-events-none border-dashed rounded-none px-1.5 py-0 text-[9px] uppercase tracking-wider",
active
? "border-solid bg-foreground/10 text-foreground"
: "text-foreground/65 dark:text-foreground/50 border-foreground/20",
: "text-foreground/70 dark:text-foreground/55 border-foreground/25",
)}
variant="outline"
>
@@ -651,7 +651,7 @@ export function StaggeredNavFiles() {
<button
type="button"
onClick={() => setMobileView("docs")}
className="flex items-center gap-2 px-5 py-2.5 text-foreground/55 dark:text-foreground/35 hover:text-foreground/60 transition-colors border-b border-foreground/[0.06]"
className="flex items-center gap-2 px-5 py-2.5 text-foreground/65 dark:text-foreground/45 hover:text-foreground/70 transition-colors border-b border-foreground/[0.06]"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -695,14 +695,14 @@ export function StaggeredNavFiles() {
isActive(item.path || item.href) ||
(item.href === "/docs" && isDocs)
? "text-foreground"
: "text-foreground/65 dark:text-foreground/50"
}`}
: "text-foreground/75 dark:text-foreground/60"
}`}
>
{item.name}
</span>
{item.external && (
<svg
className="h-2.5 w-2.5 text-foreground/35 dark:text-foreground/20 ml-auto"
className="h-2.5 w-2.5 text-foreground/45 dark:text-foreground/30 ml-auto"
viewBox="0 0 10 10"
fill="none"
>