Tailwind CSS 4 Migration (#100)

* Updated to TailwindCSS v4
* Moved CSS module to its own CSS file because of lightingcss strict validation
* Respect next parameter in middleware
* Updated all packages. 
* Split CSSs for better organization.
* Redesigned theme and auth pages
* Improved pill and header design
* Formatted files using Prettier
* Better footer layout
* Better auth layout
* Bump version of the repository to 2.0.0
This commit is contained in:
Giancarlo Buomprisco
2025-01-28 13:19:52 +07:00
committed by GitHub
parent d799f54ede
commit 4e91f267e0
109 changed files with 1347 additions and 1178 deletions

View File

@@ -1,3 +1,3 @@
# Your Application
Write here everything about your application.
Write here everything about your application.

View File

@@ -5,8 +5,6 @@ import Link from 'next/link';
import type { User } from '@supabase/supabase-js';
import { ArrowRightIcon } from 'lucide-react';
import { PersonalAccountDropdown } from '@kit/accounts/personal-account-dropdown';
import { useSignOut } from '@kit/supabase/hooks/use-sign-out';
import { useUser } from '@kit/supabase/hooks/use-user';
@@ -65,30 +63,26 @@ function SuspendedPersonalAccountDropdown(props: { user: User | null }) {
function AuthButtons() {
return (
<div className={'flex space-x-2'}>
<div className={'hidden space-x-0.5 md:flex'}>
<div className={'flex gap-x-2.5'}>
<div className={'hidden md:flex'}>
<If condition={features.enableThemeToggle}>
<ModeToggle />
</If>
</div>
<Button asChild variant={'ghost'}>
<div className={'flex gap-x-2.5'}>
<Button className={'hidden md:block'} asChild variant={'ghost'}>
<Link href={pathsConfig.auth.signIn}>
<Trans i18nKey={'auth:signIn'} />
</Link>
</Button>
<Button asChild className="group" variant={'default'}>
<Link href={pathsConfig.auth.signUp}>
<Trans i18nKey={'auth:signUp'} />
</Link>
</Button>
</div>
<Button asChild className="group" variant={'default'}>
<Link href={pathsConfig.auth.signUp}>
<Trans i18nKey={'auth:signUp'} />
<ArrowRightIcon
className={
'ml-1 hidden h-4 w-4 transition-transform duration-500 group-hover:translate-x-1 lg:block'
}
/>
</Link>
</Button>
</div>
);
}

View File

@@ -48,8 +48,8 @@ export function SiteNavigation() {
return (
<>
<div className={'hidden items-center justify-center md:flex'}>
<NavigationMenu className={'px-4 py-2'}>
<NavigationMenuList className={'space-x-5'}>
<NavigationMenu>
<NavigationMenuList className={'gap-x-2.5'}>
{NavItems}
</NavigationMenuList>
</NavigationMenu>

View File

@@ -15,12 +15,10 @@ export function SitePageHeader({
return (
<div className={cn('border-b py-8 xl:py-10 2xl:py-12', className)}>
<div
className={cn('flex flex-col space-y-2 lg:space-y-4', containerClass)}
>
<div className={cn('flex flex-col gap-y-3 lg:gap-y-4', containerClass)}>
<h1
className={
'font-heading text-3xl font-medium tracking-tighter dark:text-white xl:text-5xl'
'font-heading text-3xl font-medium tracking-tighter xl:text-5xl dark:text-white'
}
>
{title}
@@ -28,7 +26,7 @@ export function SitePageHeader({
<h2
className={
'text-lg tracking-tight text-muted-foreground 2xl:text-2xl'
'text-muted-foreground text-lg tracking-tight 2xl:text-2xl'
}
>
{subtitle}

View File

@@ -1,126 +0,0 @@
.HTML {
@apply text-secondary-foreground;
}
.HTML h1 {
@apply mt-14 text-4xl font-semibold font-heading tracking-tight;
}
.HTML h2 {
@apply mb-6 mt-12 font-semibold text-2xl font-heading tracking-tight;
}
.HTML h3 {
@apply mt-12 text-xl font-semibold font-heading tracking-tight;
}
.HTML h4 {
@apply mt-8 text-lg font-medium tracking-tight;
}
.HTML h5 {
@apply mt-6 text-base font-medium tracking-tight;
}
.HTML h6 {
@apply mt-2 text-sm font-normal tracking-tight;
}
/**
Tailwind "dark" variants do not work with CSS Modules
We work it around using :global(.dark)
For more info: https://github.com/tailwindlabs/tailwindcss/issues/3258#issuecomment-770215347
*/
:global(.dark) .HTML h1,
:global(.dark) .HTML h2,
:global(.dark) .HTML h3,
:global(.dark) .HTML h4,
:global(.dark) .HTML h5,
:global(.dark) .HTML h6 {
@apply text-white;
}
.HTML p {
@apply mb-6 mt-4 text-base leading-7 text-muted-foreground;
}
.HTML li {
@apply relative my-1.5 text-base leading-7 text-muted-foreground;
}
.HTML ul > li:before {
content: '-';
@apply mr-2;
}
.HTML ol > li:before {
@apply inline-flex font-medium text-muted-foreground;
content: counters(counts, '.') '. ';
font-feature-settings: 'tnum';
}
.HTML b,
.HTML strong {
@apply font-semibold text-secondary-foreground;
}
:global(.dark) .HTML b,
:global(.dark) .HTML strong {
@apply text-white;
}
.HTML img,
.HTML video {
@apply rounded-md;
}
.HTML ul,
.HTML ol {
@apply pl-1;
}
.HTML ol > li {
counter-increment: counts;
}
.HTML ol > li:before {
@apply mr-2 inline-flex font-semibold;
content: counters(counts, '.') '. ';
font-feature-settings: 'tnum';
}
.HTML p > code, .HTML li > code {
@apply p-0.5 text-sm font-semibold bg-muted/50 border font-mono text-secondary-foreground;
}
.HTML blockquote {
@apply my-4 border-l-8 border border-primary px-6 py-4 text-lg font-medium text-muted-foreground;
}
.HTML a {
@apply border-b-black border-b hover:border-b-2 pb-0.5 text-secondary-foreground font-semibold;
}
:global(.dark) .HTML a {
@apply border-yellow-300;
}
.HTML hr {
@apply mt-8 mb-6 border-border;
}
.HTML [role='alert'] {
@apply py-4 m-0 my-8;
}
.HTML [role='alert'] * {
color: inherit;
@apply m-0 p-0 text-sm;
}
.HTML [role='alert'] h5 {
color: inherit;
}

View File

@@ -25,7 +25,7 @@ export function PostPreview({
const slug = `/blog/${post.slug}`;
return (
<div className="flex flex-col space-y-4 rounded-lg transition-shadow duration-500">
<div className="transition-shadow-sm flex flex-col gap-y-4 rounded-lg duration-500">
<If condition={image}>
{(imageUrl) => (
<div className="relative mb-2 w-full" style={{ height }}>
@@ -42,13 +42,13 @@ export function PostPreview({
<div className={'flex flex-col space-y-4 px-1'}>
<div className={'flex flex-col space-y-2'}>
<h2 className="text-2xl font-semibold leading-snug tracking-tight">
<h2 className="text-xl leading-snug font-semibold tracking-tight">
<Link href={slug} className="hover:underline">
{title}
</Link>
</h2>
<div className="flex flex-row items-center space-x-2 text-sm">
<div className="flex flex-row items-center gap-x-3 text-sm">
<div className="text-muted-foreground">
<DateFormatter dateString={publishedAt} />
</div>
@@ -56,7 +56,7 @@ export function PostPreview({
</div>
<p
className="mb-4 text-sm leading-relaxed text-muted-foreground"
className="text-muted-foreground mb-4 text-sm leading-relaxed"
dangerouslySetInnerHTML={{ __html: description ?? '' }}
/>
</div>

View File

@@ -1,7 +1,6 @@
import type { Cms } from '@kit/cms';
import { ContentRenderer } from '@kit/cms';
import styles from './html-renderer.module.css';
import { PostHeader } from './post-header';
export function Post({
@@ -16,7 +15,7 @@ export function Post({
<PostHeader post={post} />
<div className={'mx-auto flex max-w-3xl flex-col space-y-6 py-8'}>
<article className={styles.HTML}>
<article className="markdoc">
<ContentRenderer content={content} />
</article>
</div>

View File

@@ -9,8 +9,6 @@ import { cn } from '@kit/ui/utils';
import { withI18n } from '~/lib/i18n/with-i18n';
// styles
import styles from '../../blog/_components/html-renderer.module.css';
// local imports
import { DocsCards } from '../_components/docs-cards';
import { DocsTableOfContents } from '../_components/docs-table-of-contents';
@@ -61,20 +59,18 @@ async function DocumentationPage({ params }: DocumentationPageProps) {
);
return (
<div className={'flex flex-1 flex-col space-y-4 overflow-y-hidden'}>
<div className={'flex flex-1 flex-col gap-y-4 overflow-y-hidden py-5'}>
<div className={'flex overflow-y-hidden'}>
<article
className={cn(styles.HTML, 'container space-y-12 overflow-y-auto')}
>
<section className={'flex flex-col space-y-4 pt-6'}>
<h1 className={'!my-0'}>{page.title}</h1>
<article className={cn('gap-y-12 overflow-y-auto px-6')}>
<section className={'flex flex-col gap-y-2.5'}>
<h1 className={'text-3xl font-semibold text-foreground'}>{page.title}</h1>
<h2 className={'!mb-0 !font-normal !text-muted-foreground'}>
{description}
</h2>
<h2 className={'text-muted-foreground text-lg'}>{description}</h2>
</section>
<ContentRenderer content={page.content} />
<div className={'markdoc'}>
<ContentRenderer content={page.content} />
</div>
</article>
<DocsTableOfContents data={headings} />

View File

@@ -17,14 +17,14 @@ export function DocsCard({
return (
<div className="flex flex-col">
<div
className={`flex grow flex-col space-y-2.5 border bg-background p-6 ${link ? 'rounded-t-2xl border-b-0' : 'rounded-2xl'}`}
className={`bg-background flex grow flex-col gap-y-2 border p-6 ${link ? 'rounded-t-lg border-b-0' : 'rounded-lg'}`}
>
<h3 className="mt-0 text-lg font-semibold hover:underline dark:text-white">
<Link href={link.url}>{title}</Link>
</h3>
{subtitle && (
<div className="text-sm text-muted-foreground">
<div className="text-muted-foreground text-sm">
<p dangerouslySetInnerHTML={{ __html: subtitle }}></p>
</div>
)}
@@ -33,17 +33,19 @@ export function DocsCard({
</div>
{link && (
<div className="rounded-b-2xl border bg-muted p-6 py-4 dark:bg-background">
<span className={'flex items-center space-x-2'}>
<Link
className={'text-sm font-medium hover:underline'}
href={link.url}
>
<div className="bg-muted/50 rounded-b-lg border p-6 py-4">
<Link
className={
'flex items-center space-x-2 text-sm font-medium hover:underline'
}
href={link.url}
>
<span>
{link.label ?? <Trans i18nKey={'marketing:readMore'} />}
</Link>
</span>
<ChevronRight className={'h-4'} />
</span>
</Link>
</div>
)}
</div>

View File

@@ -22,8 +22,8 @@ export function DocsNavLink({
<SidebarMenuButton
asChild
isActive={isCurrent}
className={cn('border-l-3 transition-background !font-normal', {
'font-bold text-secondary-foreground': isCurrent,
className={cn('transition-background font-normal!', {
'text-secondary-foreground font-bold': isCurrent,
})}
>
<Link href={url}>

View File

@@ -116,7 +116,7 @@ export function DocsNavigation({
<>
<Sidebar
variant={'ghost'}
className={'z-1 sticky max-h-full overflow-y-auto'}
className={'sticky z-1 mt-4 max-h-full overflow-y-auto'}
>
<SidebarGroup>
<SidebarGroupContent>

View File

@@ -13,7 +13,7 @@ export function DocsTableOfContents(props: { data: NavItem[] }) {
const navData = props.data;
return (
<div className="sticky inset-y-0 hidden h-svh max-h-full min-w-[14em] border-l bg-background p-4 lg:block">
<div className="bg-background sticky inset-y-0 hidden h-svh max-h-full min-w-[14em] border-l p-4 lg:block">
<ol
role="list"
className="relative text-sm text-gray-600 dark:text-gray-400"
@@ -22,7 +22,7 @@ export function DocsTableOfContents(props: { data: NavItem[] }) {
<li key={item.href} className="group/item relative mt-3 first:mt-0">
<a
href={item.href}
className="block transition-colors hover:text-gray-950 dark:hover:text-white [&_*]:[font:inherit]"
className="block transition-colors **:[font:inherit] hover:text-gray-950 dark:hover:text-white"
>
{item.text}
</a>
@@ -35,7 +35,7 @@ export function DocsTableOfContents(props: { data: NavItem[] }) {
>
<Link
href={child.href}
className="block transition-colors hover:text-gray-950 dark:hover:text-white [&_*]:[font:inherit]"
className="block transition-colors **:[font:inherit] hover:text-gray-950 dark:hover:text-white"
>
{child.text}
</Link>

View File

@@ -14,7 +14,7 @@ async function DocsLayout({ children }: React.PropsWithChildren) {
return (
<SidebarProvider
style={{ '--sidebar-width': '20em' } as React.CSSProperties}
style={{ '--sidebar-width': '18em' } as React.CSSProperties}
className={'h-[calc(100vh-72px)] overflow-y-hidden lg:container'}
>
<DocsNavigation pages={tree} />

View File

@@ -21,7 +21,7 @@ async function DocsPage() {
const cards = items.filter((item) => !item.parentId);
return (
<div className={'flex flex-col space-y-6 xl:space-y-10'}>
<div className={'flex flex-col gap-y-6 xl:gap-y-10'}>
<SitePageHeader
title={t('marketing:documentation')}
subtitle={t('marketing:documentationSubtitle')}

View File

@@ -135,7 +135,7 @@ function FaqItem({
</div>
</summary>
<div className={'flex flex-col space-y-2 py-1 text-muted-foreground'}>
<div className={'text-muted-foreground flex flex-col gap-y-3 py-1'}>
<Trans i18nKey={item.answer} defaults={item.answer} />
</div>
</details>

View File

@@ -2,7 +2,6 @@ import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { SiteFooter } from '~/(marketing)/_components/site-footer';
import { SiteHeader } from '~/(marketing)/_components/site-header';
import { BackgroundHue } from '~/components/background-hue';
import { withI18n } from '~/lib/i18n/with-i18n';
async function SiteLayout(props: React.PropsWithChildren) {
@@ -18,7 +17,6 @@ async function SiteLayout(props: React.PropsWithChildren) {
{props.children}
<BackgroundHue />
<SiteFooter />
</div>
);

View File

@@ -12,6 +12,7 @@ import {
FeatureShowcaseIconContainer,
Hero,
Pill,
PillActionButton,
SecondaryHero,
} from '@kit/ui/marketing';
import { Trans } from '@kit/ui/trans';
@@ -27,7 +28,12 @@ function Home() {
<Hero
pill={
<Pill label={'New'}>
<span>The leading SaaS Starter Kit for ambitious developers</span>
<span>The SaaS Starter Kit for ambitious developers</span>
<PillActionButton asChild>
<Link href={'/auth/sign-up'}>
<ArrowRightIcon className={'h-4 w-4'} />
</Link>
</PillActionButton>
</Pill>
}
title={
@@ -47,7 +53,7 @@ function Home() {
<Image
priority
className={
'rounded-2xl border border-gray-200 dark:border-primary/10'
'dark:border-primary/10 rounded-xl border border-gray-200'
}
width={3558}
height={2222}
@@ -65,11 +71,11 @@ function Home() {
<FeatureShowcase
heading={
<>
<b className="font-semibold dark:text-white">
<b className="font-medium tracking-tighter dark:text-white">
The ultimate SaaS Starter Kit
</b>
.{' '}
<span className="font-normal text-muted-foreground">
<span className="text-muted-foreground font-normal tracking-tighter">
Unleash your creativity and build your SaaS faster than ever
with Makerkit.
</span>
@@ -84,64 +90,36 @@ function Home() {
>
<FeatureGrid>
<FeatureCard
className={'relative col-span-2 overflow-hidden lg:h-96'}
className={'relative col-span-1 overflow-hidden'}
label={'Beautiful Dashboard'}
description={`Makerkit provides a beautiful dashboard to manage your SaaS business.`}
>
<Image
className="absolute right-0 top-0 hidden h-full w-full rounded-tl-2xl border border-border lg:top-36 lg:flex lg:h-auto lg:w-10/12"
src={'/images/dashboard-header.webp'}
width={'2061'}
height={'800'}
alt={'Dashboard Header'}
/>
</FeatureCard>
></FeatureCard>
<FeatureCard
className={
'relative col-span-2 w-full overflow-hidden lg:col-span-1'
'relative col-span-1 w-full overflow-hidden lg:col-span-1'
}
label={'Authentication'}
description={`Makerkit provides a variety of providers to allow your users to sign in.`}
>
<Image
className="absolute left-16 top-32 hidden h-auto w-8/12 rounded-l-2xl lg:flex"
src={'/images/sign-in.webp'}
width={'1760'}
height={'1680'}
alt={'Sign In'}
/>
</FeatureCard>
></FeatureCard>
<FeatureCard
className={
'relative col-span-2 overflow-hidden lg:col-span-1 lg:h-96'
}
className={'relative col-span-2 overflow-hidden lg:col-span-1'}
label={'Multi Tenancy'}
description={`Multi tenant memberships for your SaaS business.`}
>
<Image
className="absolute right-0 top-0 hidden h-full w-full rounded-tl-2xl border lg:top-28 lg:flex lg:h-auto lg:w-8/12"
src={'/images/multi-tenancy.webp'}
width={'2061'}
height={'800'}
alt={'Multi Tenancy'}
/>
</FeatureCard>
/>
<FeatureCard
className={'relative col-span-2 overflow-hidden lg:h-96'}
className={'relative col-span-1 overflow-hidden lg:col-span-2'}
label={'Billing'}
description={`Makerkit supports multiple payment gateways to charge your customers.`}
>
<Image
className="absolute right-0 top-0 hidden h-full w-full rounded-tl-2xl border border-border lg:top-36 lg:flex lg:h-auto lg:w-11/12"
src={'/images/billing.webp'}
width={'2061'}
height={'800'}
alt={'Billing'}
/>
</FeatureCard>
/>
<FeatureCard
className={'relative col-span-1 overflow-hidden'}
label={'Plugins'}
description={`Extend your SaaS with plugins that you can install using the CLI.`}
/>
</FeatureGrid>
</FeatureShowcase>
</div>
@@ -188,8 +166,8 @@ function MainCallToActionButton() {
<ArrowRightIcon
className={
'h-4 animate-in fade-in slide-in-from-left-8' +
' delay-1000 duration-1000 zoom-in fill-mode-both'
'animate-in fade-in slide-in-from-left-8 h-4' +
' zoom-in fill-mode-both delay-1000 duration-1000'
}
/>
</span>

View File

@@ -1,16 +1,9 @@
import { AuthLayoutShell } from '@kit/auth/shared';
import { AppLogo } from '~/components/app-logo';
import { BackgroundHue } from '~/components/background-hue';
function AuthLayout({ children }: React.PropsWithChildren) {
return (
<AuthLayoutShell Logo={AppLogo}>
{children}
<BackgroundHue />
</AuthLayoutShell>
);
return <AuthLayoutShell Logo={AppLogo}>{children}</AuthLayoutShell>;
}
export default AuthLayout;

View File

@@ -23,9 +23,15 @@ const redirectPath = `${callback}?next=${passwordUpdate}`;
function PasswordResetPage() {
return (
<>
<Heading level={5} className={'tracking-tight'}>
<Trans i18nKey={'auth:passwordResetLabel'} />
</Heading>
<div className={'flex flex-col items-center gap-1'}>
<Heading level={4} className={'tracking-tight'}>
<Trans i18nKey={'auth:passwordResetLabel'} />
</Heading>
<p className={'text-muted-foreground text-sm'}>
<Trans i18nKey={'auth:passwordResetSubheading'} />
</p>
</div>
<div className={'flex flex-col space-y-4'}>
<PasswordResetRequestContainer redirectPath={redirectPath} />

View File

@@ -39,9 +39,15 @@ async function SignInPage({ searchParams }: SignInPageProps) {
return (
<>
<Heading level={5} className={'tracking-tight'}>
<Trans i18nKey={'auth:signInHeading'} />
</Heading>
<div className={'flex flex-col items-center gap-1'}>
<Heading level={4} className={'tracking-tight'}>
<Trans i18nKey={'auth:signInHeading'} />
</Heading>
<p className={'text-muted-foreground text-sm'}>
<Trans i18nKey={'auth:signInSubheading'} />
</p>
</div>
<SignInMethodsContainer
inviteToken={inviteToken}

View File

@@ -38,9 +38,15 @@ async function SignUpPage({ searchParams }: Props) {
return (
<>
<Heading level={5} className={'tracking-tight'}>
<Trans i18nKey={'auth:signUpHeading'} />
</Heading>
<div className={'flex flex-col items-center gap-1'}>
<Heading level={4} className={'tracking-tight'}>
<Trans i18nKey={'auth:signUpHeading'} />
</Heading>
<p className={'text-muted-foreground text-sm'}>
<Trans i18nKey={'auth:signUpSubheading'} />
</p>
</div>
<SignUpMethodsContainer
providers={authConfig.providers}
@@ -49,7 +55,7 @@ async function SignUpPage({ searchParams }: Props) {
paths={paths}
/>
<div className={'justify-centers flex'}>
<div className={'flex justify-center'}>
<Button asChild variant={'link'} size={'sm'}>
<Link href={signInPath}>
<Trans i18nKey={'auth:alreadyHaveAnAccount'} />

View File

@@ -39,7 +39,7 @@ const ErrorPage = ({
<div className={'flex flex-col items-center space-y-8'}>
<div
className={
'flex max-w-xl flex-col items-center space-y-1 text-center'
'flex max-w-xl flex-col items-center gap-y-2 text-center'
}
>
<div>
@@ -48,7 +48,7 @@ const ErrorPage = ({
</Heading>
</div>
<p className={'text-lg text-muted-foreground'}>
<p className={'text-muted-foreground text-lg'}>
<Trans i18nKey={'common:genericErrorSubHeading'} />
</p>
</div>

View File

@@ -41,7 +41,7 @@ const GlobalErrorPage = ({
<div className={'flex flex-col items-center space-y-8'}>
<div
className={
'flex max-w-xl flex-col items-center space-y-1 text-center'
'flex max-w-xl flex-col items-center gap-y-2 text-center'
}
>
<div>
@@ -50,7 +50,7 @@ const GlobalErrorPage = ({
</Heading>
</div>
<p className={'text-lg text-muted-foreground'}>
<p className={'text-muted-foreground text-lg'}>
<Trans i18nKey={'common:genericErrorSubHeading'} />
</p>
</div>

View File

@@ -29,7 +29,7 @@ export function HomeSidebar(props: HomeSidebarProps) {
return (
<Sidebar>
<SidebarHeader className={'h-16 justify-center'}>
<div className={'flex items-center justify-between space-x-2'}>
<div className={'flex items-center justify-between gap-x-3'}>
<If
condition={featuresFlagConfig.enableTeamAccounts}
fallback={

View File

@@ -47,7 +47,7 @@ export default function DashboardDemo() {
return (
<div
className={
'flex flex-col space-y-4 pb-36 duration-500 animate-in fade-in'
'animate-in fade-in flex flex-col space-y-4 pb-36 duration-500'
}
>
<div
@@ -189,11 +189,11 @@ function Chart(
const chartConfig = {
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
color: 'var(--chart-1)',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
color: 'var(--chart-2)',
},
} satisfies ChartConfig;
@@ -423,7 +423,7 @@ function CustomersTable() {
<TableRow key={customer.name}>
<TableCell className={'flex flex-col'}>
<span>{customer.name}</span>
<span className={'text-sm text-muted-foreground'}>
<span className={'text-muted-foreground text-sm'}>
{customer.email}
</span>
</TableCell>
@@ -482,7 +482,7 @@ function Trend(
case 'up':
return <ArrowUp className={'h-3 w-3 text-green-500'} />;
case 'down':
return <ArrowDown className={'h-3 w-3 text-destructive'} />;
return <ArrowDown className={'text-destructive h-3 w-3'} />;
case 'stale':
return <Menu className={'h-3 w-3 text-orange-500'} />;
}
@@ -604,11 +604,11 @@ export function VisitorsChart() {
},
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
color: 'var(--chart-1)',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
color: 'var(--chart-2)',
},
} satisfies ChartConfig;
@@ -685,10 +685,10 @@ export function VisitorsChart() {
<CardFooter>
<div className="flex w-full items-start gap-2 text-sm">
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium leading-none">
<div className="flex items-center gap-2 leading-none font-medium">
Trending up by 5.2% this month <TrendingUp className="h-4 w-4" />
</div>
<div className="flex items-center gap-2 leading-none text-muted-foreground">
<div className="text-muted-foreground flex items-center gap-2 leading-none">
January - June 2024
</div>
</div>
@@ -802,11 +802,11 @@ export function PageViewsChart() {
},
desktop: {
label: 'Desktop',
color: 'hsl(var(--chart-1))',
color: 'var(--chart-1)',
},
mobile: {
label: 'Mobile',
color: 'hsl(var(--chart-2))',
color: 'var(--chart-2)',
},
} satisfies ChartConfig;
@@ -836,13 +836,13 @@ export function PageViewsChart() {
<button
key={chart}
data-active={activeChart === chart}
className="relative z-30 flex flex-1 flex-col justify-center gap-1 border-t px-6 py-4 text-left even:border-l data-[active=true]:bg-muted/50 sm:border-l sm:border-t-0 sm:px-8 sm:py-6"
className="data-[active=true]:bg-muted/50 relative z-30 flex flex-1 flex-col justify-center gap-1 border-t px-6 py-4 text-left even:border-l sm:border-t-0 sm:border-l sm:px-8 sm:py-6"
onClick={() => setActiveChart(chart)}
>
<span className="text-xs text-muted-foreground">
<span className="text-muted-foreground text-xs">
{chartConfig[chart].label}
</span>
<span className="text-lg font-bold leading-none sm:text-3xl">
<span className="text-lg leading-none font-bold sm:text-3xl">
{total[key as keyof typeof total].toLocaleString()}
</span>
</button>

View File

@@ -98,7 +98,7 @@ function DropdownLink(
<DropdownMenuItem asChild>
<Link
href={props.path}
className={'flex h-12 w-full items-center space-x-2 px-3'}
className={'flex h-12 w-full items-center gap-x-3 px-3'}
>
{props.Icon}

View File

@@ -1,52 +0,0 @@
const DEFAULT_COLORS_SCALE = {
0: 'hsl(var(--primary))',
1: 'hsl(var(--primary))',
2: 'hsl(var(--primary))',
};
export function BackgroundHue({
className,
opacity = 0.03,
colorsScale = DEFAULT_COLORS_SCALE,
}: {
className?: string;
opacity?: number;
colorsScale?: Record<number, string>;
}) {
const colors = Object.values(colorsScale).map((color, index, array) => {
const offset = array.length > 1 ? index / (array.length - 1) : 0;
const stopOpacity = 1 - index / (array.length - 1);
return (
<stop
offset={offset}
key={index}
style={{ stopColor: color, stopOpacity }}
/>
);
});
return (
<svg
className={`pointer-events-none fixed left-0 top-0 !m-0 hidden h-full w-full dark:block ${className}`}
style={{ opacity }}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 100 100"
preserveAspectRatio="none"
>
<defs>
<linearGradient
id="purpleGradient"
x1="10%"
y1="70%"
x2="50%"
y2="20%"
gradientUnits="userSpaceOnUse"
>
{colors}
</linearGradient>
</defs>
<rect width="100" height="100" fill="url(#purpleGradient)" />
</svg>
);
}

View File

@@ -42,7 +42,7 @@ export function getFontsClassName(theme?: string) {
[],
);
return cn('min-h-screen bg-background antialiased', ...font, {
return cn('bg-background min-h-screen antialiased', ...font, {
dark,
light,
});

View File

@@ -153,8 +153,11 @@ function getPatterns() {
// If user is logged in and does not need to verify MFA,
// redirect to home page.
if (!isVerifyMfa) {
const nextPath =
req.nextUrl.searchParams.get('next') ?? pathsConfig.app.home;
return NextResponse.redirect(
new URL(pathsConfig.app.home, req.nextUrl.origin).href,
new URL(nextPath, req.nextUrl.origin).href,
);
}
},

View File

@@ -91,7 +91,8 @@
"prettier": "^3.4.2",
"require-in-the-middle": "7.5.0",
"supabase": "^2.9.6",
"tailwindcss": "3.4.17",
"tailwindcss": "4.0.0",
"tailwindcss-animate": "^1.0.7",
"typescript": "^5.7.3"
},
"eslintConfig": {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 123 KiB

View File

@@ -1,7 +1,9 @@
{
"signUpHeading": "Create an account",
"signUp": "Sign Up",
"signUpSubheading": "Fill the form below to create an account.",
"signInHeading": "Sign in to your account",
"signInSubheading": "Welcome back! Please enter your details",
"signIn": "Sign In",
"getStarted": "Get started",
"updatePassword": "Update Password",
@@ -65,6 +67,7 @@
"acceptTermsAndConditions": "I accept the <TermsOfServiceLink /> and <PrivacyPolicyLink />",
"termsOfService": "Terms of Service",
"privacyPolicy": "Privacy Policy",
"orContinueWith": "Or continue with",
"errors": {
"Invalid login credentials": "The credentials entered are invalid",
"User already registered": "This credential is already in use. Please try with another one.",

View File

@@ -1,127 +1,211 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
/*
* global.css
*
* Global styles for the entire application
*/
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
--card: 0 0% 100%;
--card-foreground: 224 71.4% 4.1%;
--popover: 0 0% 100%;
--popover-foreground: 224 71.4% 4.1%;
--primary: 220.9 39.3% 11%;
--primary-foreground: 210 20% 98%;
--secondary: 220 14.3% 95.9%;
--secondary-foreground: 220.9 39.3% 11%;
--muted: 220 14.3% 95.9%;
--muted-foreground: 220 8.9% 46.1%;
--accent: 220 14.3% 95.9%;
--accent-foreground: 220.9 39.3% 11%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 20% 98%;
--border: 214.3 31.8% 94.4%;
--input: 214.3 31.8% 91.4%;
--ring: 224 71.4% 4.1%;
--radius: 0.5rem;
/* Tailwind CSS */
@import 'tailwindcss';
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
/* local styles - update the below if you add a new style */
@import './theme.css';
@import './theme.utilities.css';
@import './shadcn-ui.css';
@import './markdoc.css';
@import './makerkit.css';
--sidebar-background: 0 0% 98%;
--sidebar-foreground: 240 5.3% 26.1%;
--sidebar-primary: 240 5.9% 10%;
--sidebar-primary-foreground: 0 0% 98%;
--sidebar-accent: 240 4.8% 95.9%;
--sidebar-accent-foreground: 240 5.9% 10%;
--sidebar-border: 220 13% 91%;
--sidebar-ring: 217.2 91.2% 59.8%;
/* plugins - update the below if you add a new plugin */
@plugin "tailwindcss-animate";
/* content sources - update the below if you add a new path */
@source "../../../packages/*/src/**/*.{ts,tsx}";
@source "../../../packages/features/*/src/**/*.{ts,tsx}";
@source "../../../packages/billing/*/src/**/*.{ts,tsx}";
@source "../../../packages/plugins/*/src/**/*.{ts,tsx}";
@source "../../../packages/cms/*/src/**/*.{ts,tsx}";
@source "../{app,components,config,lib}/**/*.{ts,tsx}";
@theme {
--font-cal: var(--font-cal);
--font-sans: -apple-system, var(--font-sans);
--font-heading: var(--font-heading);
--animate-fade-up: fade-up 0.5s;
--animate-fade-down: fade-down 0.5s;
--animate-accordion-down: accordion-down 0.2s ease-out;
--animate-accordion-up: accordion-up 0.2s ease-out;
@keyframes fade-up {
0% {
opacity: 0;
transform: translateY(10px);
}
80% {
opacity: 0.6;
}
100% {
opacity: 1;
transform: translateY(0px);
}
}
.dark {
--background: 224 71.4% 4.1%;
--foreground: 210 20% 98%;
--card: 224 71.4% 4.1%;
--card-foreground: 210 20% 98%;
--popover: 224 71.4% 4.1%;
--popover-foreground: 210 20% 98%;
--primary: 210 20% 98%;
--primary-foreground: 220.9 39.3% 11%;
--secondary: 215 27.9% 13%;
--secondary-foreground: 210 20% 98%;
--muted: 215 27.9% 13%;
--muted-foreground: 217.9 10.6% 64.9%;
--accent: 215 27.9% 13%;
--accent-foreground: 210 20% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 20% 98%;
--border: 215 27.9% 13%;
--input: 215 27.9% 13%;
--ring: 216 12.2% 83.9%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
--sidebar-background: 224 71.4% 4.1%;
--sidebar-foreground: 240 4.8% 95.9%;
--sidebar-primary: 224.3 76.3% 48%;
--sidebar-primary-foreground: 0 0% 100%;
--sidebar-accent: 215 27.9% 13%;
--sidebar-accent-foreground: 240 4.8% 95.9%;
--sidebar-border: 240 3.7% 15.9%;
--sidebar-ring: 217.2 91.2% 59.8%;
@keyframes fade-down {
0% {
opacity: 0;
transform: translateY(-10px);
}
80% {
opacity: 0.6;
}
100% {
opacity: 1;
transform: translateY(0px);
}
}
@keyframes accordion-down {
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
}
@keyframes accordion-up {
from {
height: var(--radix-accordion-content-height);
}
to {
height: 0;
}
}
}
@theme {
--font-cal: var(--font-cal);
--font-sans: -apple-system, var(--font-sans);
--font-heading: var(--font-heading);
--animate-fade-up: fade-up 0.5s;
--animate-fade-down: fade-down 0.5s;
--animate-accordion-down: accordion-down 0.2s ease-out;
--animate-accordion-up: accordion-up 0.2s ease-out;
@keyframes fade-up {
0% {
opacity: 0;
transform: translateY(10px);
}
80% {
opacity: 0.6;
}
100% {
opacity: 1;
transform: translateY(0px);
}
}
@keyframes fade-down {
0% {
opacity: 0;
transform: translateY(-10px);
}
80% {
opacity: 0.6;
}
100% {
opacity: 1;
transform: translateY(0px);
}
}
@keyframes accordion-down {
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
}
@keyframes accordion-up {
from {
height: var(--radix-accordion-content-height);
}
to {
height: 0;
}
}
}
/*
The default border color has changed to `currentColor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}
/*
The default border color has changed to `currentColor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}
/*
The default border color has changed to `currentColor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}
/* variants - update the below if you add a new variant */
@variant dark (&:where(.dark, .dark *));
@layer base {
body {
@apply bg-background text-foreground;
font-feature-settings: "rlig" 1, "calt" 1;
}
.container {
@apply max-sm:px-4;
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--border, currentColor);
}
}
/*
Optimize dropdowns for mobile
*/
[data-radix-popper-content-wrapper] {
@apply w-full md:w-auto;
}
[data-radix-menu-content] {
@apply rounded-none md:rounded-lg w-full md:w-auto;
}
[data-radix-menu-content] [role="menuitem"] {
@apply md:min-h-0 min-h-12;
}
.site-header > .container:before,
.site-footer > .container:before {
background: radial-gradient(62.87% 100% at 50% 100%, theme('colors.gray.200') 0%, rgba(255, 255, 255, 0) 100%);
bottom: 0;
content: "";
height: 1px;
left: 0;
position: absolute;
width: 100%;
}
.dark .site-header > .container:before,
.dark .site-footer > .container:before {
background: radial-gradient(62.87% 100% at 50% 100%, rgba(255, 255, 255, .16) 0%, rgba(255, 255, 255, 0) 100%);
}
.site-footer > .container:before {
top: 0;
input::placeholder,
textarea::placeholder {
color: theme(--color-muted-foreground);
}
}

View File

@@ -0,0 +1,42 @@
/*
* makerkit.css
*
* Makerkit-specific global styles
* Use this file to add any global styles that are specific to Makerkit's components
*/
/*
Optimize dropdowns for mobile
*/
[data-radix-popper-content-wrapper] {
@apply w-full md:w-auto;
}
[data-radix-menu-content] {
@apply rounded-none md:rounded-lg w-full md:w-auto;
}
[data-radix-menu-content] [role="menuitem"] {
@apply md:min-h-0 min-h-12;
}
.site-header > .container:before,
.site-footer > .container:before {
background: radial-gradient(62.87% 100% at 50% 100%, var(--color-gray-200) 0%, rgba(255, 255, 255, 0) 100%);
bottom: 0;
content: "";
height: 1px;
left: 0;
position: absolute;
width: 100%;
}
.dark .site-header > .container:before,
.dark .site-footer > .container:before {
background: radial-gradient(62.87% 100% at 50% 100%, rgba(255, 255, 255, .10) 0%, rgba(255, 255, 255, 0) 100%);
}
.site-footer > .container:before {
top: 0;
}

114
apps/web/styles/markdoc.css Normal file
View File

@@ -0,0 +1,114 @@
/*
* markdoc.css
*
* Styles for Markdoc Markdown files. Update this to customize the stylesheet for Markdoc content, such as
* the blog post, documentation, etc.
*/
.markdoc {
@apply text-foreground;
}
.markdoc h1 {
@apply mt-14 text-4xl font-semibold font-heading tracking-tight dark:text-white text-foreground;
}
.markdoc h2 {
@apply mb-6 mt-12 font-semibold text-2xl font-heading tracking-tight dark:text-white text-foreground;
}
.markdoc h3 {
@apply mt-12 text-xl font-semibold font-heading tracking-tight dark:text-white text-foreground;
}
.markdoc h4 {
@apply mt-8 text-lg font-medium tracking-tight dark:text-white text-foreground;
}
.markdoc h5 {
@apply mt-6 text-base font-medium tracking-tight dark:text-white text-foreground;
}
.markdoc h6 {
@apply mt-2 text-sm font-normal tracking-tight dark:text-white text-foreground;
}
.markdoc p {
@apply mb-6 mt-4 text-base leading-7 text-muted-foreground;
}
.markdoc li {
@apply relative my-1.5 text-base leading-7 text-muted-foreground;
}
.markdoc ul > li:before {
content: '-';
@apply mr-2;
}
.markdoc ol > li:before {
@apply inline-flex font-medium text-muted-foreground;
content: counters(counts, '.') '. ';
font-feature-settings: 'tnum';
}
.markdoc b,
.markdoc strong {
@apply font-semibold text-secondary-foreground dark:text-white;
}
.markdoc img,
.markdoc video {
@apply rounded-md;
}
.markdoc ul,
.markdoc ol {
@apply pl-1;
}
.markdoc ol > li {
counter-increment: counts;
}
.markdoc ol > li:before {
@apply mr-2 inline-flex font-semibold;
content: counters(counts, '.') '. ';
font-feature-settings: 'tnum';
}
.markdoc p > code, .markdoc li > code {
@apply p-0.5 text-sm font-semibold bg-muted/50 border font-mono text-secondary-foreground;
}
.markdoc pre {
@apply overflow-x-auto bg-muted/50 rounded-md border border-border p-4 text-sm font-mono text-foreground;
}
.markdoc blockquote {
@apply my-4 border-l-8 border border-primary px-6 py-4 text-lg font-medium text-muted-foreground;
}
.markdoc a {
@apply border-b-black border-b hover:border-b-2 pb-0.5 text-secondary-foreground font-semibold dark:border-yellow-300;
}
.markdoc hr {
@apply mt-8 mb-6 border-border;
}
.markdoc [role='alert'] {
@apply py-4 m-0 my-8;
}
.markdoc [role='alert'] * {
color: inherit;
@apply m-0 p-0 text-sm;
}
.markdoc [role='alert'] h5 {
color: inherit;
}

View File

@@ -0,0 +1,104 @@
/*
* shadcn-ui.css
*
* Update the below to customize your Shadcn UI CSS Colors.
* Refer to https://ui.shadcn.com/themes for applying new colors.
* NB: apply the hsl function to the colors copied from the theme.
*/
@layer base {
:root {
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
--font-heading: var(--font-sans);
--background: var(--color-white);
--foreground: var(--color-neutral-950);
--card: var(--color-white);
--card-foreground: var(--color-neutral-950);
--popover: var(--color-white);
--popover-foreground: var(--color-neutral-950);
--primary: var(--color-neutral-950);
--primary-foreground: var(--color-white);
--secondary: oklch(96.76% 0.0013 286.38);
--secondary-foreground: oklch(21.03% 0.0318 264.65);
--muted: oklch(96.71% 0.0029 264.54);
--muted-foreground: oklch(55.13% 0.0233 264.36);
--accent: oklch(96.76% 0.0013 286.38);
--accent-foreground: oklch(21.03% 0.0318 264.65);
--destructive: var(--color-red-500);
--destructive-foreground: var(--color-white);
--border: var(--color-gray-100);
--input: var(--color-gray-200);
--ring: var(--color-neutral-800);
--radius: 0.5rem;
--chart-1: var(--color-orange-400);
--chart-2: var(--color-teal-600);
--chart-3: var(--color-green-800);
--chart-4: var(--color-yellow-200);
--chart-5: var(--color-orange-200);
--sidebar-background: var(--color-neutral-50);
--sidebar-foreground: oklch(37.05% 0.012 285.8);
--sidebar-primary: var(--color-neutral-950);
--sidebar-primary-foreground: var(--color-white);
--sidebar-accent: var(--color-neutral-100);
--sidebar-accent-foreground: var(--color-neutral-950);
--sidebar-border: var(--border);
--sidebar-ring: var(--color-blue-500);
}
.dark {
--background: var(--color-neutral-900);
--foreground: var(--color-white);
--card: var(--color-neutral-900);
--card-foreground: var(--color-white);
--popover: var(--color-neutral-900);
--popover-foreground: var(--color-white);
--primary: var(--color-white);
--primary-foreground: var(--color-neutral-900);
--secondary: var(--color-neutral-800);
--secondary-foreground: oklch(98.43% 0.0017 247.84);
--muted: var(--color-neutral-800);
--muted-foreground: oklch(71.19% 0.0129 286.07);
--accent: var(--color-neutral-800);
--accent-foreground: oklch(98.48% 0 0);
--destructive: var(--color-red-700);
--destructive-foreground: var(--color-white);
--border: var(--color-neutral-800);
--input: var(--color-neutral-700);
--ring: oklch(87.09% 0.0055 286.29);
--chart-1: var(--color-blue-600);
--chart-2: var(--color-emerald-400);
--chart-3: var(--color-orange-400);
--chart-4: var(--color-purple-500);
--chart-5: var(--color-pink-500);
--sidebar-background: var(--color-neutral-900);
--sidebar-foreground: var(--color-white);
--sidebar-primary: var(--color-blue-500);
--sidebar-primary-foreground: var(--color-white);
--sidebar-accent: var(--color-neutral-800);
--sidebar-accent-foreground: var(--color-white);
--sidebar-border: var(--border);
--sidebar-ring: var(--color-blue-500);
}
}

133
apps/web/styles/theme.css Normal file
View File

@@ -0,0 +1,133 @@
/*
* theme.css
*
* Shadcn UI theme
* Use this file to add any custom styles or override existing Shadcn UI styles
*/
/* container utility */
/* Shadcn UI theme */
@theme {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--radius-radius: var(--radius);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--font-heading: var(--font-sans);
--color-sidebar: var(--sidebar-background);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
--animate-accordion-down: accordion-down 0.2s ease-out;
--animate-accordion-up: accordion-up 0.2s ease-out;
@keyframes accordion-down {
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
}
@keyframes accordion-up {
from {
height: var(--radix-accordion-content-height);
}
to {
height: 0;
}
}
--animate-fade-up: fade-up 0.5s;
--animate-fade-down: fade-down 0.5s;
--animate-accordion-down: accordion-down 0.2s ease-out;
--animate-accordion-up: accordion-up 0.2s ease-out;
@keyframes fade-up {
0% {
opacity: 0;
transform: translateY(10px);
}
80% {
opacity: 0.6;
}
100% {
opacity: 1;
transform: translateY(0px);
}
}
@keyframes fade-down {
0% {
opacity: 0;
transform: translateY(-10px);
}
80% {
opacity: 0.6;
}
100% {
opacity: 1;
transform: translateY(0px);
}
}
@keyframes accordion-down {
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
}
@keyframes accordion-up {
from {
height: var(--radix-accordion-content-height);
}
to {
height: 0;
}
}
}

View File

@@ -0,0 +1,5 @@
@utility container {
margin-inline: auto;
@apply xl:max-w-[80rem] px-8;
}

View File

@@ -1,10 +0,0 @@
import type { Config } from 'tailwindcss';
import baseConfig from '@kit/tailwind-config';
export default {
// We need to append the path to the UI package to the content array so that
// those classes are included correctly.
content: [...baseConfig.content, './components/**/*.tsx', './app/**/*.tsx', './lib/fonts.ts'],
presets: [baseConfig],
} satisfies Config;

View File

@@ -1,6 +1,6 @@
{
"name": "next-supabase-saas-kit-turbo",
"version": "1.0.0",
"version": "2.0.0",
"private": true,
"sideEffects": false,
"engines": {

View File

@@ -61,9 +61,9 @@ export function CurrentLifetimeOrderCard({
</CardDescription>
</CardHeader>
<CardContent className={'space-y-3 text-sm'}>
<CardContent className={'gap-y-4 text-sm'}>
<div className={'flex flex-col space-y-1'}>
<div className={'flex items-center space-x-2 text-lg font-semibold'}>
<div className={'flex items-center gap-x-3 text-lg font-semibold'}>
<BadgeCheck
className={
's-6 fill-green-500 text-white dark:fill-white dark:text-black'
@@ -77,7 +77,7 @@ export function CurrentLifetimeOrderCard({
</div>
<div>
<div className="flex flex-col space-y-0.5">
<div className="flex flex-col gap-y-1">
<span className="font-semibold">
<Trans i18nKey="billing:detailsLabel" />
</span>

View File

@@ -67,7 +67,7 @@ export function CurrentSubscriptionCard({
<CardContent className={'space-y-4 border-t pt-4 text-sm'}>
<div className={'flex flex-col space-y-1'}>
<div className={'flex items-center space-x-2 text-lg font-semibold'}>
<div className={'flex items-center gap-x-3 text-lg font-semibold'}>
<BadgeCheck
className={
's-6 fill-green-500 text-white dark:fill-white dark:text-black'
@@ -102,7 +102,7 @@ export function CurrentSubscriptionCard({
</If>
<If condition={subscription.status === 'trialing'}>
<div className="flex flex-col space-y-0.5">
<div className="flex flex-col gap-y-1">
<span className="font-semibold">
<Trans i18nKey="billing:trialEndsOn" />
</span>
@@ -132,7 +132,7 @@ export function CurrentSubscriptionCard({
</Alert>
</If>
<div className="flex flex-col space-y-0.5">
<div className="flex flex-col gap-y-1">
<span className="font-semibold">
<Trans i18nKey="billing:detailsLabel" />
</span>

View File

@@ -110,7 +110,7 @@ export function LineItemDetails(
<span className={'flex items-center space-x-1.5'}>
<PlusSquare className={'w-3'} />
<span className={'flex space-x-1 text-sm'}>
<span className={'flex gap-x-2 text-sm'}>
<span>
<Trans
i18nKey={'billing:perUnit'}
@@ -243,7 +243,7 @@ function Tiers({
return (
<span
className={'text-secondary-foreground flex space-x-1 text-xs'}
className={'text-secondary-foreground flex gap-x-2 text-xs'}
key={index}
>
<span>-</span>

View File

@@ -113,12 +113,10 @@ export function PlanPicker(
return (
<Form {...form}>
<div
className={
'flex flex-col space-y-4 lg:flex-row lg:space-x-4 lg:space-y-0'
}
className={'flex flex-col gap-y-4 lg:flex-row lg:gap-x-4 lg:gap-y-0'}
>
<form
className={'flex w-full max-w-xl flex-col space-y-4'}
className={'flex w-full max-w-xl flex-col gap-y-8'}
onSubmit={form.handleSubmit(props.onSubmit)}
>
<If condition={intervals.length}>
@@ -131,7 +129,7 @@ export function PlanPicker(
name={'interval'}
render={({ field }) => {
return (
<FormItem className={'rounded-md border p-4'}>
<FormItem className={'flex flex-col gap-4'}>
<FormLabel htmlFor={'plan-picker-id'}>
<Trans i18nKey={'common:billingInterval.label'} />
</FormLabel>
@@ -147,10 +145,11 @@ export function PlanPicker(
htmlFor={interval}
key={interval}
className={cn(
'flex items-center space-x-2 rounded-md border border-transparent px-4 py-2 transition-colors',
'focus-within:border-primary flex items-center gap-x-2.5 rounded-md border px-2.5 py-2 transition-colors',
{
['border-primary']: selected,
['hover:border-primary']: !selected,
['bg-muted border-input']: selected,
['hover:border-input border-transparent']:
!selected,
},
)}
>
@@ -207,7 +206,7 @@ export function PlanPicker(
<FormField
name={'planId'}
render={({ field }) => (
<FormItem>
<FormItem className={'flex flex-col gap-4'}>
<FormLabel>
<Trans i18nKey={'common:planPickerLabel'} />
</FormLabel>
@@ -259,7 +258,9 @@ export function PlanPicker(
primaryLineItem.tiers[0],
);
const tierTranslationKey = isMultiTier ? 'billing:startingAtPriceUnit' : 'billing:priceUnit';
const tierTranslationKey = isMultiTier
? 'billing:startingAtPriceUnit'
: 'billing:priceUnit';
return (
<RadioGroupItemLabel
@@ -288,7 +289,7 @@ export function PlanPicker(
<div
className={
'flex w-full flex-col content-center space-y-2 lg:flex-row lg:items-center lg:justify-between lg:space-y-0'
'flex w-full flex-col content-center gap-y-3 lg:flex-row lg:items-center lg:justify-between lg:space-y-0'
}
>
<Label
@@ -336,7 +337,7 @@ export function PlanPicker(
<div
className={
'flex flex-col space-y-2 lg:flex-row lg:items-center lg:space-x-4 lg:space-y-0 lg:text-right'
'flex flex-col gap-y-3 lg:flex-row lg:items-center lg:space-x-4 lg:space-y-0 lg:text-right'
}
>
<div>
@@ -517,7 +518,7 @@ function PlanDetails({
{selectedProduct.features.map((item) => {
return (
<div key={item} className={'flex items-center space-x-1 text-sm'}>
<div key={item} className={'flex items-center gap-x-2 text-sm'}>
<CheckCircle className={'h-4 text-green-500'} />
<span className={'text-secondary-foreground'}>

View File

@@ -168,7 +168,7 @@ function PricingItem(
data-cy={'subscription-plan'}
className={cn(
props.className,
`s-full relative flex flex-1 grow flex-col items-stretch justify-between self-stretch rounded-xl border p-8 lg:w-4/12 xl:max-w-[20rem]`,
`s-full relative flex flex-1 grow flex-col items-stretch justify-between self-stretch rounded-lg border p-8 lg:w-4/12 xl:max-w-[20rem]`,
{
['border-primary']: highlighted,
['border-border']: !highlighted,
@@ -230,7 +230,7 @@ function PricingItem(
<If condition={props.plan.name}>
<span
className={cn(
`animate-in slide-in-from-left-4 fade-in text-muted-foreground flex items-center space-x-0.5 text-sm capitalize`,
`animate-in slide-in-from-left-4 fade-in text-muted-foreground flex items-center gap-x-1 text-sm capitalize`,
)}
>
<span>
@@ -397,7 +397,7 @@ function PlanIntervalSwitcher(
const selected = plan === props.interval;
const className = cn(
'animate-in fade-in rounded-full !outline-none transition-all focus:!ring-0',
'animate-in fade-in !outline-hidden rounded-full transition-all focus:!ring-0',
{
'border-r-transparent': index === 0,
['hover:text-primary text-muted-foreground']: !selected,
@@ -472,7 +472,7 @@ function DefaultCheckoutButton(
<Link className={'w-full'} href={linkHref}>
<Button
size={'lg'}
className={'border-primary w-full rounded-lg border'}
className={'w-full rounded-lg border'}
variant={props.highlighted ? 'default' : 'outline'}
>
<span>

View File

@@ -7,7 +7,7 @@ export function CtaButton(
) {
return (
<Button
className="w-full rounded bg-[#000000] py-3 text-center text-[14px] font-semibold text-white no-underline"
className="rounded-smbg-[#000000] w-full py-3 text-center text-[14px] font-semibold text-white no-underline"
href={props.href}
>
{props.children}

View File

@@ -111,7 +111,12 @@ export function AccountSelector({
<If
condition={selected}
fallback={
<span className={'flex max-w-full items-center space-x-4'}>
<span
className={cn('flex max-w-full items-center', {
'justify-center gap-x-0': collapsed,
'gap-x-4': !collapsed,
})}
>
<PersonalAccountAvatar />
<span
@@ -125,12 +130,17 @@ export function AccountSelector({
}
>
{(account) => (
<span className={'flex max-w-full items-center space-x-4'}>
<Avatar className={'h-6 w-6 rounded-sm'}>
<span
className={cn('flex max-w-full items-center', {
'justify-center gap-x-0': collapsed,
'gap-x-4': !collapsed,
})}
>
<Avatar className={'rounded-xs h-6 w-6'}>
<AvatarImage src={account.image ?? undefined} />
<AvatarFallback
className={'group-hover:bg-background rounded-sm'}
className={'group-hover:bg-background rounded-xs'}
>
{account.label ? account.label[0] : ''}
</AvatarFallback>
@@ -212,11 +222,11 @@ export function AccountSelector({
}}
>
<div className={'flex items-center'}>
<Avatar className={'mr-2 h-6 w-6 rounded-sm'}>
<Avatar className={'rounded-xs mr-2 h-6 w-6'}>
<AvatarImage src={account.image ?? undefined} />
<AvatarFallback
className={cn('rounded-sm', {
className={cn('rounded-xs', {
['bg-background']: value === account.value,
['group-hover:bg-background']:
value !== account.value,
@@ -276,7 +286,7 @@ export function AccountSelector({
function UserAvatar(props: { pictureUrl?: string }) {
return (
<Avatar className={'h-6 w-6 rounded-sm'}>
<Avatar className={'rounded-xs h-6 w-6'}>
<AvatarImage src={props.pictureUrl} />
</Avatar>
);

View File

@@ -88,7 +88,7 @@ export function PersonalAccountDropdown({
'animate-in fade-in focus:outline-primary flex cursor-pointer items-center duration-500 group-data-[minimized=true]:px-0',
className ?? '',
{
['active:bg-secondary/50 items-center space-x-4 rounded-md' +
['active:bg-secondary/50 items-center gap-4 rounded-md' +
' hover:bg-secondary p-2 transition-colors']: showProfileName,
},
)}
@@ -129,8 +129,8 @@ export function PersonalAccountDropdown({
</If>
</DropdownMenuTrigger>
<DropdownMenuContent className={'xl:!min-w-[15rem]'}>
<DropdownMenuItem className={'!h-10 rounded-none'}>
<DropdownMenuContent className={'xl:min-w-[15rem]!'}>
<DropdownMenuItem className={'h-10! rounded-none'}>
<div
className={'flex flex-col justify-start truncate text-left text-xs'}
>

View File

@@ -70,8 +70,8 @@ async function PersonalAccountPage(props: { account: Account }) {
/>
<div className={'flex items-center justify-between'}>
<div className={'flex items-center space-x-4'}>
<div className={'flex items-center space-x-2.5'}>
<div className={'flex items-center gap-x-4'}>
<div className={'flex items-center gap-x-2.5'}>
<ProfileAvatar
pictureUrl={props.account.picture_url}
displayName={props.account.name}
@@ -89,7 +89,7 @@ async function PersonalAccountPage(props: { account: Account }) {
</If>
</div>
<div className={'flex space-x-1'}>
<div className={'flex gap-x-1'}>
<If condition={isBanned}>
<AdminReactivateUserDialog userId={props.account.id}>
<Button size={'sm'} variant={'ghost'}>
@@ -124,10 +124,10 @@ async function PersonalAccountPage(props: { account: Account }) {
</div>
</div>
<div className={'flex flex-col space-y-8'}>
<div className={'flex flex-col gap-y-8'}>
<SubscriptionsTable accountId={props.account.id} />
<div className={'divider-divider-x flex flex-col space-y-2.5'}>
<div className={'divider-divider-x flex flex-col gap-y-2.5'}>
<Heading level={6}>Teams</Heading>
<div>
@@ -145,7 +145,7 @@ async function TeamAccountPage(props: {
const members = await getMembers(props.account.slug ?? '');
return (
<div className={'flex flex-col space-y-4'}>
<div className={'flex flex-col gap-y-4'}>
<AppBreadcrumbs
values={{
[props.account.id]:
@@ -154,8 +154,8 @@ async function TeamAccountPage(props: {
/>
<div className={'flex justify-between'}>
<div className={'flex items-center space-x-4'}>
<div className={'flex items-center space-x-2.5'}>
<div className={'flex items-center gap-x-4'}>
<div className={'flex items-center gap-x-2.5'}>
<ProfileAvatar
pictureUrl={props.account.picture_url}
displayName={props.account.name}
@@ -178,10 +178,10 @@ async function TeamAccountPage(props: {
</div>
<div>
<div className={'flex flex-col space-y-8'}>
<div className={'flex flex-col gap-y-8'}>
<SubscriptionsTable accountId={props.account.id} />
<div className={'flex flex-col space-y-2.5'}>
<div className={'flex flex-col gap-y-2.5'}>
<Heading level={6}>Team Members</Heading>
<AdminMembersTable members={members} />

View File

@@ -2,20 +2,20 @@ export function AuthLayoutShell({
children,
Logo,
}: React.PropsWithChildren<{
Logo: React.ComponentType;
Logo?: React.ComponentType;
}>) {
return (
<div
className={
'flex h-screen flex-col items-center justify-center' +
' dark:lg:bg-background space-y-10 lg:space-y-12 lg:bg-gray-50' +
' animate-in fade-in slide-in-from-top-8 zoom-in-95 duration-1000'
' bg-background lg:bg-muted/30 gap-y-10 lg:gap-y-8' +
' animate-in fade-in slide-in-from-top-16 zoom-in-95 duration-1000'
}
>
{Logo && <Logo />}
{Logo ? <Logo /> : null}
<div
className={`bg-background dark:border-border flex w-full max-w-sm flex-col items-center space-y-5 rounded-lg border-transparent px-6 md:w-8/12 md:border md:px-8 md:py-6 md:shadow lg:w-5/12 lg:px-6 xl:w-4/12 xl:py-8 2xl:w-3/12 dark:shadow`}
className={`bg-background flex w-full max-w-[23rem] flex-col gap-y-6 rounded-lg px-6 md:w-8/12 md:px-8 md:py-6 lg:w-5/12 lg:px-8 xl:w-4/12 xl:gap-y-8 xl:py-8`}
>
{children}
</div>

View File

@@ -12,7 +12,7 @@ export function AuthProviderButton({
}>) {
return (
<Button
className={'flex w-full space-x-2 text-center'}
className={'flex w-full gap-x-3 text-center'}
data-provider={providerId}
data-test={'auth-provider-button'}
variant={'outline'}

View File

@@ -75,13 +75,7 @@ export function PasswordResetRequestContainer(params: {
})}
className={'w-full'}
>
<div className={'flex flex-col space-y-4'}>
<div>
<p className={'text-muted-foreground text-sm'}>
<Trans i18nKey={'auth:passwordResetSubheading'} />
</p>
</div>
<div className={'flex flex-col gap-y-4'}>
<AuthErrorAlert error={error} />
<FormField

View File

@@ -43,7 +43,7 @@ export function PasswordSignInForm({
return (
<Form {...form}>
<form
className={'w-full space-y-2.5'}
className={'flex w-full flex-col gap-y-4'}
onSubmit={form.handleSubmit(onSubmit)}
>
<FormField
@@ -91,17 +91,19 @@ export function PasswordSignInForm({
<FormMessage />
<Button
asChild
type={'button'}
size={'sm'}
variant={'link'}
className={'text-xs'}
>
<Link href={'/auth/password-reset'}>
<Trans i18nKey={'auth:passwordForgottenQuestion'} />
</Link>
</Button>
<div>
<Button
asChild
type={'button'}
size={'sm'}
variant={'link'}
className={'text-xs'}
>
<Link href={'/auth/password-reset'}>
<Trans i18nKey={'auth:passwordForgottenQuestion'} />
</Link>
</Button>
</div>
</FormItem>
)}
/>

View File

@@ -55,7 +55,7 @@ export function PasswordSignUpForm({
return (
<Form {...form}>
<form
className={'w-full space-y-2.5'}
className={'flex w-full flex-col gap-y-4'}
onSubmit={form.handleSubmit(onSubmit)}
>
<FormField

View File

@@ -7,6 +7,7 @@ import type { Provider } from '@supabase/supabase-js';
import { isBrowser } from '@kit/shared/utils';
import { If } from '@kit/ui/if';
import { Separator } from '@kit/ui/separator';
import { Trans } from '@kit/ui/trans';
import { MagicLinkAuthContainer } from './magic-link-auth-container';
import { OauthProviders } from './oauth-providers';
@@ -63,7 +64,17 @@ export function SignInMethodsContainer(props: {
</If>
<If condition={props.providers.oAuth.length}>
<Separator />
<div className="relative">
<div className="absolute inset-0 flex items-center">
<Separator />
</div>
<div className="relative flex justify-center text-xs uppercase">
<span className="bg-background text-muted-foreground px-2">
<Trans i18nKey="auth:orContinueWith" />
</span>
</div>
</div>
<OauthProviders
enabledProviders={props.providers.oAuth}

View File

@@ -55,7 +55,17 @@ export function SignUpMethodsContainer(props: {
</If>
<If condition={props.providers.oAuth.length}>
<Separator />
<div className="relative">
<div className="absolute inset-0 flex items-center">
<Separator />
</div>
<div className="relative flex justify-center text-xs uppercase">
<span className="bg-background text-muted-foreground px-2">
<Trans i18nKey="auth:orContinueWith" />
</span>
</div>
</div>
<OauthProviders
enabledProviders={props.providers.oAuth}

View File

@@ -16,7 +16,7 @@ export function TermsAndConditionsFormField(
return (
<FormItem>
<FormControl>
<label className={'flex items-start space-x-2 py-2'}>
<label className={'flex items-start gap-x-3 py-2'}>
<Checkbox required name={field.name} />
<div className={'text-xs'}>

View File

@@ -186,7 +186,7 @@ export function NotificationsPopover(params: {
<div
key={notification.id.toString()}
className={cn(
'min-h-18 flex flex-col items-start justify-center space-y-0.5 px-3 py-2',
'min-h-18 flex flex-col items-start justify-center gap-y-1 px-3 py-2',
)}
onClick={() => {
if (params.onClick) {
@@ -196,7 +196,7 @@ export function NotificationsPopover(params: {
>
<div className={'flex w-full items-start justify-between'}>
<div
className={'flex items-start justify-start space-x-2 py-2'}
className={'flex items-start justify-start gap-x-3 py-2'}
>
<div className={'py-0.5'}>
<Icon />

View File

@@ -138,7 +138,7 @@ function InviteMembersForm({
data-test={'invite-members-form'}
onSubmit={form.handleSubmit(onSubmit)}
>
<div className="flex flex-col space-y-4">
<div className="flex flex-col gap-y-4">
{fieldArray.fields.map((field, index) => {
const isFirst = index === 0;
@@ -147,7 +147,7 @@ function InviteMembersForm({
return (
<div data-test={'invite-member-form-item'} key={field.id}>
<div className={'flex items-end space-x-0.5 md:space-x-2'}>
<div className={'flex items-end gap-x-1 md:space-x-2'}>
<div className={'w-7/12'}>
<FormField
name={emailInputName}
@@ -189,6 +189,7 @@ function InviteMembersForm({
<FormControl>
<MembershipRoleSelector
triggerClassName={'m-0'}
roles={roles}
value={field.value}
onChange={(role) => {
@@ -204,7 +205,7 @@ function InviteMembersForm({
/>
</div>
<div className={'flex w-[40px] justify-end'}>
<div className={'flex w-[40px] items-end justify-end'}>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>

View File

@@ -14,15 +14,20 @@ export function MembershipRoleSelector({
value,
currentUserRole,
onChange,
triggerClassName,
}: {
roles: Role[];
value: Role;
currentUserRole?: Role;
onChange: (role: Role) => unknown;
triggerClassName?: string;
}) {
return (
<Select value={value} onValueChange={onChange}>
<SelectTrigger data-test={'role-selector-trigger'}>
<SelectTrigger
className={triggerClassName}
data-test={'role-selector-trigger'}
>
<SelectValue />
</SelectTrigger>

View File

@@ -58,7 +58,7 @@
"react-hook-form": "^7.54.2",
"react-i18next": "^15.4.0",
"sonner": "^1.7.2",
"tailwindcss": "3.4.17",
"tailwindcss": "4.0.0",
"tailwindcss-animate": "^1.0.7",
"typescript": "^5.7.3",
"zod": "^3.24.1"

View File

@@ -39,7 +39,7 @@ export function BorderedNavigationMenuItem(props: {
<Button
asChild
variant={'ghost'}
className={cn('relative active:shadow-sm', props.buttonClassName)}
className={cn('relative active:shadow-xs', props.buttonClassName)}
>
<Link
href={props.path}
@@ -58,7 +58,7 @@ export function BorderedNavigationMenuItem(props: {
{active ? (
<span
className={cn(
'absolute -bottom-2.5 left-0 h-0.5 w-full bg-primary animate-in fade-in zoom-in-90',
'bg-primary animate-in fade-in zoom-in-90 absolute -bottom-2.5 left-0 h-0.5 w-full',
)}
/>
) : null}

View File

@@ -17,7 +17,7 @@ export const CardButton: React.FC<
return (
<Comp
className={cn(
'group relative flex h-36 flex-col rounded-lg border transition-all hover:bg-secondary/20 hover:shadow active:bg-secondary active:bg-secondary/50 active:shadow-lg dark:shadow-primary/20',
'group hover:bg-secondary/20 active:bg-secondary active:bg-secondary/50 dark:shadow-primary/20 relative flex h-36 flex-col rounded-lg border transition-all hover:shadow-xs active:shadow-lg',
className,
)}
{...props}
@@ -39,7 +39,7 @@ export const CardButtonTitle: React.FC<
<Comp
className={cn(
className,
'align-super text-sm font-medium text-muted-foreground transition-colors group-hover:text-secondary-foreground',
'text-muted-foreground group-hover:text-secondary-foreground align-super text-sm font-medium transition-colors',
)}
{...props}
>
@@ -69,7 +69,7 @@ export const CardButtonHeader: React.FC<
<ChevronRight
className={cn(
'absolute right-2 top-4 h-4 text-muted-foreground transition-colors group-hover:text-secondary-foreground',
'text-muted-foreground group-hover:text-secondary-foreground absolute top-4 right-2 h-4 transition-colors',
{
hidden: !displayArrow,
},

View File

@@ -188,7 +188,7 @@ function Pagination<T>({
table: ReactTable<T>;
}>) {
return (
<div className="flex items-center justify-end space-x-4">
<div className="flex items-center justify-end gap-x-4">
<span className="flex items-center text-sm">
<Trans
i18nKey={'common:pageOfPages'}
@@ -199,7 +199,7 @@ function Pagination<T>({
/>
</span>
<div className="flex items-center justify-end space-x-1">
<div className="flex items-center justify-end gap-x-2">
<Button
size={'icon'}
variant={'ghost'}

View File

@@ -18,7 +18,7 @@ const EmptyStateText: React.FC<React.HTMLAttributes<HTMLParagraphElement>> = ({
className,
...props
}) => (
<p className={cn('text-sm text-muted-foreground', className)} {...props} />
<p className={cn('text-muted-foreground text-sm', className)} {...props} />
);
EmptyStateText.displayName = 'EmptyStateText';
@@ -60,7 +60,7 @@ const EmptyState: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({
return (
<div
className={cn(
'flex flex-1 items-center justify-center rounded-lg border border-dashed shadow-sm',
'flex flex-1 items-center justify-center rounded-lg border border-dashed shadow-xs',
className,
)}
{...props}

View File

@@ -138,14 +138,14 @@ export const ImageUploadInput: React.FC<Props> =
return (
<label
id={'image-upload-input'}
className={`relative flex h-10 w-full cursor-pointer rounded-md border border-dashed border-input bg-background px-3 py-2 text-sm outline-none ring-primary ring-offset-2 ring-offset-background transition-all file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus:ring-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50`}
className={`border-input bg-background ring-primary ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring relative flex h-10 w-full cursor-pointer rounded-md border border-dashed px-3 py-2 text-sm ring-offset-2 outline-hidden transition-all file:border-0 file:bg-transparent file:text-sm file:font-medium focus:ring-2 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50`}
>
<Input />
<div className={'flex items-center space-x-4'}>
<div className={'flex'}>
<If condition={!state.image}>
<UploadCloud className={'h-5 text-muted-foreground'} />
<UploadCloud className={'text-muted-foreground h-5'} />
</If>
<If condition={state.image}>
@@ -188,7 +188,7 @@ export const ImageUploadInput: React.FC<Props> =
<If condition={state.image}>
<Button
size={'icon'}
className={'!h-5 !w-5'}
className={'h-5! w-5!'}
onClick={imageRemoved}
>
<X className="h-4" />

View File

@@ -20,14 +20,14 @@ export function LoadingOverlay({
'flex flex-col items-center justify-center space-y-4',
className,
{
[`fixed left-0 top-0 z-[100] h-screen w-screen bg-background`]:
[`bg-background fixed top-0 left-0 z-100 h-screen w-screen`]:
fullPage,
},
)}
>
<Spinner className={spinnerClassName} />
<div className={'text-sm text-muted-foreground'}>{children}</div>
<div className={'text-muted-foreground text-sm'}>{children}</div>
</div>
);
}

View File

@@ -1,45 +1,28 @@
import React from 'react';
import { cn } from '../../lib/utils';
import {
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '../../shadcn/card';
import { CardDescription, CardHeader, CardTitle } from '../../shadcn/card';
interface FeatureCardProps extends React.HTMLAttributes<HTMLDivElement> {
label: string;
description: string;
image?: React.ReactNode;
}
export const FeatureCard: React.FC<FeatureCardProps> = ({
className,
label,
description,
image,
children,
...props
}) => {
return (
<div
className={cn(
'rounded-3xl p-2 ring-2 ring-gray-100 dark:ring-primary/10',
className,
)}
{...props}
>
<div className={cn('rounded-xl border p-4', className)} {...props}>
<CardHeader>
<CardTitle className="text-xl font-semibold">{label}</CardTitle>
<CardDescription className="max-w-xs text-sm font-semibold tracking-tight text-muted-foreground">
<CardTitle className="text-xl font-medium">{label}</CardTitle>
<CardDescription className="text-muted-foreground max-w-xs text-sm font-normal">
{description}
</CardDescription>
</CardHeader>
<CardContent>
{image}
{children}
</CardContent>
</div>
);
};

View File

@@ -20,7 +20,7 @@ export const FeatureShowcase: React.FC<FeatureShowcaseProps> =
className={cn('flex flex-col justify-between space-y-8', className)}
{...props}
>
<div className="flex w-full max-w-5xl flex-col space-y-4">
<div className="flex w-full max-w-5xl flex-col gap-y-4">
{icon && <div className="flex">{icon}</div>}
<h3 className="text-3xl font-normal tracking-tight xl:text-5xl">
{heading}
@@ -40,7 +40,7 @@ export function FeatureShowcaseIconContainer(
<div className={'flex'}>
<div
className={cn(
'flex items-center justify-center space-x-4 rounded-lg p-3 font-semibold',
'flex items-center justify-center space-x-4 rounded-lg p-3 font-medium',
props.className,
)}
>

View File

@@ -26,31 +26,35 @@ export const Footer: React.FC<FooterProps> = ({
return (
<footer
className={cn(
'site-footer relative mt-auto w-full py-8 2xl:py-16',
'site-footer relative mt-auto w-full py-8 2xl:py-20',
className,
)}
{...props}
>
<div className="container">
<div className="flex flex-col space-y-8 lg:flex-row lg:space-y-0">
<div className="flex w-full space-x-2 lg:w-4/12 xl:w-4/12 xl:space-x-6 2xl:space-x-8">
<div className="flex flex-col space-y-4">
<div className="flex w-full gap-x-3 lg:w-4/12 xl:w-4/12 xl:space-x-6 2xl:space-x-8">
<div className="flex flex-col gap-y-4">
<div>{logo}</div>
<div className="flex flex-col space-y-4">
<div className="flex flex-col gap-y-4">
<div>
<p className="text-sm text-muted-foreground">{description}</p>
<p className="text-muted-foreground text-sm tracking-tight">
{description}
</p>
</div>
<div className="flex text-xs text-muted-foreground">
<div className="text-muted-foreground flex text-xs">
<p>{copyright}</p>
</div>
</div>
</div>
</div>
<div className="flex w-full flex-col space-y-8 lg:flex-row lg:justify-end lg:space-x-6 lg:space-y-0 xl:space-x-16">
<div className="flex w-full flex-col gap-y-4 lg:flex-row lg:justify-end lg:gap-x-6 lg:gap-y-0 xl:gap-x-12">
{sections.map((section, index) => (
<div key={index}>
<div className="flex flex-col space-y-2.5">
<div className="flex flex-col gap-y-2.5">
<FooterSectionHeading>{section.heading}</FooterSectionHeading>
<FooterSectionList>
@@ -71,11 +75,15 @@ export const Footer: React.FC<FooterProps> = ({
};
function FooterSectionHeading(props: React.PropsWithChildren) {
return <span className="font-heading">{props.children}</span>;
return (
<span className="font-heading text-sm font-semibold tracking-tight">
{props.children}
</span>
);
}
function FooterSectionList(props: React.PropsWithChildren) {
return <ul className="flex flex-col space-y-2.5">{props.children}</ul>;
return <ul className="flex flex-col gap-y-2">{props.children}</ul>;
}
function FooterLink({
@@ -83,7 +91,7 @@ function FooterLink({
children,
}: React.PropsWithChildren<{ href: string }>) {
return (
<li className="text-sm text-muted-foreground hover:underline [&>a]:transition-colors">
<li className="text-muted-foreground text-sm tracking-tight hover:underline [&>a]:transition-colors">
<a href={href}>{children}</a>
</li>
);

View File

@@ -12,7 +12,7 @@ export const GradientSecondaryText: React.FC<
return (
<Comp
className={cn(
'bg-gradient-to-r from-foreground/50 to-foreground bg-clip-text text-transparent',
'dark:from-foreground/60 dark:to-foreground text-secondary-foreground dark:bg-linear-to-r dark:bg-clip-text dark:text-transparent',
className,
)}
{...props}

View File

@@ -7,7 +7,7 @@ export const GradientText: React.FC<React.HTMLAttributes<HTMLSpanElement>> =
return (
<span
className={cn(
'bg-gradient-to-r bg-clip-text text-transparent',
'bg-linear-to-r bg-clip-text text-transparent',
className,
)}
{...props}

View File

@@ -16,7 +16,7 @@ export const Header: React.FC<HeaderProps> = function ({
return (
<div
className={cn(
'site-header sticky top-0 z-10 w-full bg-background/80 py-2 backdrop-blur-md dark:bg-background/50',
'site-header bg-background/80 dark:bg-background/50 sticky top-0 z-10 w-full py-1 backdrop-blur-md',
className,
)}
{...props}
@@ -25,9 +25,7 @@ export const Header: React.FC<HeaderProps> = function ({
<div className="grid h-14 grid-cols-3 items-center">
<div className={'mx-auto lg:mx-0'}>{logo}</div>
<div className="order-first md:order-none">{navigation}</div>
<div className="flex items-center justify-end space-x-1">
{actions}
</div>
<div className="flex items-center justify-end gap-x-2">{actions}</div>
</div>
</div>
</div>

View File

@@ -12,7 +12,7 @@ export const HeroTitle: React.FC<
return (
<Comp
className={cn(
'hero-title flex flex-col text-center font-sans text-4xl font-semibold tracking-tighter dark:text-white sm:text-6xl lg:max-w-5xl lg:text-7xl xl:text-[4.85rem]',
'hero-title flex flex-col text-center font-sans text-4xl font-semibold tracking-tighter sm:text-6xl lg:max-w-5xl lg:text-7xl xl:text-[4.5rem] dark:text-white',
className,
)}
{...props}

View File

@@ -29,17 +29,17 @@ export function Hero({
MozAnimationDuration: '100ms',
}}
className={cn(
'mx-auto flex flex-1 flex-col items-center justify-center duration-1000 md:flex-row',
'mx-auto flex flex-1 flex-col items-center justify-center duration-800 md:flex-row',
{
['animate-in fade-in zoom-in-90 slide-in-from-top-36']: animate,
['animate-in fade-in zoom-in-90 slide-in-from-top-24']: animate,
},
)}
>
<div className="flex w-full flex-1 flex-col items-center space-y-6 xl:space-y-8 2xl:space-y-10">
<div className="flex w-full flex-1 flex-col items-center gap-y-6 xl:gap-y-8 2xl:gap-y-12">
{pill && (
<div
className={cn({
['delay-300 duration-700 animate-in fade-in fill-mode-both']:
['animate-in fade-in fill-mode-both delay-300 duration-700']:
animate,
})}
>
@@ -47,12 +47,12 @@ export function Hero({
</div>
)}
<div className="flex flex-col items-center space-y-8">
<div className="flex flex-col items-center gap-y-6">
<HeroTitle>{title}</HeroTitle>
{subtitle && (
<div className="flex max-w-2xl flex-col space-y-1">
<h3 className="p-0 text-center font-sans text-xl font-normal tracking-tight text-muted-foreground">
<div className="flex max-w-lg">
<h3 className="text-muted-foreground p-0 text-center font-sans text-2xl font-normal tracking-tight">
{subtitle}
</h3>
</div>
@@ -62,7 +62,7 @@ export function Hero({
{cta && (
<div
className={cn({
['delay-500 duration-1000 animate-in fade-in fill-mode-both']:
['animate-in fade-in fill-mode-both delay-500 duration-1000']:
animate,
})}
>
@@ -78,7 +78,7 @@ export function Hero({
MozAnimationDuration: '100ms',
}}
className={cn('container mx-auto flex justify-center py-8', {
['delay-1000 duration-1000 animate-in fade-in zoom-in-95 slide-in-from-top-32 fill-mode-both']:
['animate-in fade-in zoom-in-90 slide-in-from-top-32 fill-mode-both delay-600 duration-1000']:
animate,
})}
>

View File

@@ -46,7 +46,7 @@ export function NewsletterSignup({
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSignup)}
className="flex flex-col space-y-2"
className="flex flex-col gap-y-3"
>
<FormField
control={form.control}

View File

@@ -1,6 +1,7 @@
import { Slot, Slottable } from '@radix-ui/react-slot';
import { cn } from '../../lib/utils';
import { GradientSecondaryText } from './gradient-secondary-text';
export const Pill: React.FC<
React.HTMLAttributes<HTMLHeadingElement> & {
@@ -13,7 +14,7 @@ export const Pill: React.FC<
return (
<Comp
className={cn(
'space-x-2.5 rounded-full border border-gray-100 px-2 py-2.5 text-center text-sm font-medium text-transparent dark:border-primary/10',
'bg-muted/50 flex items-center gap-x-1.5 rounded-full border px-2 py-1.5 pr-2 text-center text-sm font-medium text-transparent',
className,
)}
{...props}
@@ -21,15 +22,38 @@ export const Pill: React.FC<
{props.label && (
<span
className={
'rounded-2xl bg-primary px-2.5 py-1.5 text-sm font-semibold text-primary-foreground'
'text-primary-foreground bg-primary rounded-2xl border px-1.5 py-0.5 text-xs font-bold tracking-tight'
}
>
{props.label}
</span>
)}
<Slottable>
<span className={'text-secondary-foreground'}>{props.children}</span>
<GradientSecondaryText
className={'flex items-center gap-x-2 font-semibold tracking-tight'}
>
{props.children}
</GradientSecondaryText>
</Slottable>
</Comp>
);
};
export const PillActionButton: React.FC<
React.HTMLAttributes<HTMLButtonElement> & {
asChild?: boolean;
}
> = ({ asChild, ...props }) => {
const Comp = asChild ? Slot : 'button';
return (
<Comp
{...props}
className={
'text-secondary-foreground bg-input active:bg-primary active:text-primary-foreground hover:ring-muted-foreground/50 rounded-full px-1.5 py-1.5 text-center text-sm font-medium ring ring-transparent transition-colors'
}
>
{props.children}
</Comp>
);
};

View File

@@ -53,8 +53,8 @@ export function ModeToggle(props: { className?: string }) {
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className={props.className}>
<Sun className="h-[0.9rem] w-[0.9rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-[0.9rem] w-[0.9rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<Sun className="h-[0.9rem] w-[0.9rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" />
<Moon className="absolute h-[0.9rem] w-[0.9rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" />
<span className="sr-only">Toggle theme</span>
</Button>
</DropdownMenuTrigger>
@@ -99,7 +99,7 @@ export function SubMenuModeToggle() {
<DropdownMenuSub>
<DropdownMenuSubTrigger
className={
'hidden w-full items-center justify-between space-x-2 lg:flex'
'hidden w-full items-center justify-between gap-x-3 lg:flex'
}
>
<span className={'flex space-x-2'}>

View File

@@ -42,7 +42,7 @@ function PageWithSidebar(props: PageProps) {
<div
className={
'flex flex-1 flex-col overflow-y-auto bg-background px-4 lg:px-0'
'bg-background flex flex-1 flex-col overflow-y-auto px-4 lg:px-0'
}
>
{Children}
@@ -81,7 +81,7 @@ function PageWithHeader(props: PageProps) {
>
<div
className={cn(
'flex h-14 items-center justify-between bg-muted/40 px-4 dark:border-border dark:shadow-primary/10 lg:justify-start lg:shadow-sm',
'bg-muted/40 dark:border-border dark:shadow-primary/10 flex h-14 items-center justify-between px-4 lg:justify-start lg:shadow-xs',
{
'sticky top-0 z-10 backdrop-blur-md': props.sticky ?? true,
},
@@ -119,7 +119,7 @@ export function PageNavigation(props: React.PropsWithChildren) {
export function PageDescription(props: React.PropsWithChildren) {
return (
<div className={'h-6'}>
<div className={'text-xs font-normal leading-none text-muted-foreground'}>
<div className={'text-muted-foreground text-xs leading-none font-normal'}>
{props.children}
</div>
</div>
@@ -130,7 +130,7 @@ export function PageTitle(props: React.PropsWithChildren) {
return (
<h1
className={
'h-6 font-heading font-bold leading-none tracking-tight dark:text-white'
'font-heading text-xl leading-none font-bold tracking-tight dark:text-white'
}
>
{props.children}
@@ -155,7 +155,7 @@ export function PageHeader({
return (
<div
className={cn(
'flex items-center justify-between py-4 lg:px-4',
'flex items-center justify-between py-5 lg:px-4',
className,
)}
>

View File

@@ -144,7 +144,7 @@ export function SidebarGroup({
}
return (
<span className={'text-xs font-semibold uppercase text-muted-foreground'}>
<span className={'text-muted-foreground text-xs font-semibold uppercase'}>
{props.children}
</span>
);
@@ -189,7 +189,7 @@ export function SidebarGroup({
return (
<div
className={cn('flex flex-col', {
'space-y-1 py-1': !collapsed,
'gap-y-2 py-1': !collapsed,
})}
>
<Wrapper />
@@ -232,7 +232,7 @@ export function SidebarItem({
<Button
asChild
className={cn(
'flex w-full text-sm shadow-none active:bg-secondary/60',
'active:bg-secondary/60 flex w-full text-sm shadow-none',
{
'justify-start space-x-2.5': !collapsed,
'hover:bg-initial': active,
@@ -267,7 +267,7 @@ export function SidebarItem({
function getClassNameBuilder(className: string) {
return cva([
cn(
'group/sidebar transition-width fixed box-content flex h-screen w-2/12 flex-col bg-inherit backdrop-blur-sm duration-200',
'group/sidebar transition-width fixed box-content flex h-screen w-2/12 flex-col bg-inherit backdrop-blur-xs duration-200',
className,
),
]);

View File

@@ -75,7 +75,7 @@ export function Stepper(props: {
const containerClassName = cn('w-full', {
['flex justify-between']: variant === 'numbers',
['flex space-x-0.5']: variant === 'default',
['flex space-x-2.5 self-center']: variant === 'dots',
['flex gap-x-4 self-center']: variant === 'dots',
});
return (
@@ -92,7 +92,7 @@ function getClassNameBuilder() {
default: `flex h-[2.5px] w-full flex-col transition-all duration-500`,
numbers:
'flex h-9 w-9 items-center justify-center rounded-full border text-sm font-bold',
dots: 'h-2.5 w-2.5 rounded-full bg-muted transition-colors',
dots: 'bg-muted h-2.5 w-2.5 rounded-full transition-colors',
},
selected: {
true: '',
@@ -183,7 +183,7 @@ function StepDivider({
complete: boolean;
}>) {
const spanClassName = cn('min-w-max text-sm font-medium', {
['hidden text-muted-foreground sm:flex']: !selected,
['text-muted-foreground hidden sm:flex']: !selected,
['text-secondary-foreground']: selected || complete,
['font-medium']: selected,
});
@@ -200,7 +200,7 @@ function StepDivider({
<div
className={
'divider h-[1px] w-full bg-gray-200 transition-colors' +
' hidden group-last:hidden dark:bg-border sm:flex'
' dark:bg-border hidden group-last:hidden sm:flex'
}
/>
</div>

View File

@@ -18,7 +18,7 @@ const AlertDialogOverlay: React.FC<
> = ({ className, ...props }) => (
<AlertDialogPrimitive.Overlay
className={cn(
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80',
className,
)}
{...props}
@@ -33,7 +33,7 @@ const AlertDialogContent: React.FC<
<AlertDialogOverlay />
<AlertDialogPrimitive.Content
className={cn(
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg',
className,
)}
{...props}
@@ -47,10 +47,7 @@ const AlertDialogHeader = ({
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
'flex flex-col space-y-2 text-center sm:text-left',
className,
)}
className={cn('flex flex-col gap-y-3 text-center sm:text-left', className)}
{...props}
/>
);
@@ -84,7 +81,7 @@ const AlertDialogDescription: React.FC<
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
> = ({ className, ...props }) => (
<AlertDialogPrimitive.Description
className={cn('text-sm text-muted-foreground', className)}
className={cn('text-muted-foreground text-sm', className)}
{...props}
/>
);

View File

@@ -5,18 +5,18 @@ import { type VariantProps, cva } from 'class-variance-authority';
import { cn } from '../lib/utils';
const alertVariants = cva(
'relative w-full rounded-lg border bg-gradient-to-r px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7',
'[&>svg]:text-foreground relative flex w-full flex-col gap-y-2 rounded-lg border bg-linear-to-r px-4 py-3.5 text-sm [&>svg]:absolute [&>svg]:top-4 [&>svg]:left-4 [&>svg+div]:translate-y-[-3px] [&>svg~*]:pl-7',
{
variants: {
variant: {
default: 'bg-background text-foreground',
destructive:
'border-destructive/50 from-red-50 from-10% via-background to-background text-destructive dark:border-destructive dark:from-red-500/10 [&>svg]:text-destructive',
'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive',
success:
'border-green-600/50 from-green-50 from-10% via-background to-background text-green-600 dark:border-green-600 dark:from-green-500/10 [&>svg]:text-green-600',
'border-green-600/50 text-green-600 dark:border-green-600 [&>svg]:text-green-600',
warning:
'border-orange-600/50 from-orange-50 from-10% via-background to-background text-orange-600 dark:border-orange-600 dark:from-orange-500/10 [&>svg]:text-orange-600',
info: 'border-blue-600/50 from-blue-50 from-10% via-background to-background text-blue-600 dark:border-blue-600 dark:from-blue-500/10 [&>svg]:text-blue-600',
'border-orange-600/50 text-orange-600 dark:border-orange-600 [&>svg]:text-orange-600',
info: 'border-blue-600/50 text-blue-600 dark:border-blue-600 [&>svg]:text-blue-600',
},
},
defaultVariants: {
@@ -41,7 +41,7 @@ const AlertTitle: React.FC<React.HTMLAttributes<HTMLHeadingElement>> = ({
...props
}) => (
<h5
className={cn('mb-1 font-bold leading-none tracking-tight', className)}
className={cn('leading-none font-bold tracking-tight', className)}
{...props}
/>
);

View File

@@ -5,16 +5,16 @@ import { type VariantProps, cva } from 'class-variance-authority';
import { cn } from '../lib/utils';
const badgeVariants = cva(
'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
'focus:ring-ring inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:ring-2 focus:ring-offset-2 focus:outline-hidden',
{
variants: {
variant: {
default:
'border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80',
'bg-primary text-primary-foreground hover:bg-primary/80 border-transparent shadow-xs',
secondary:
'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
'bg-secondary text-secondary-foreground hover:bg-secondary/80 border-transparent',
destructive:
'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80',
'bg-destructive text-destructive-foreground hover:bg-destructive/80 border-transparent shadow-xs',
outline: 'text-foreground',
success:
'border-transparent bg-green-50 text-green-500 hover:bg-green-50 dark:bg-green-500/20 dark:hover:bg-green-500/20',

View File

@@ -7,18 +7,18 @@ import type { VariantProps } from 'class-variance-authority';
import { cn } from '../lib/utils';
const buttonVariants = cva(
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
'focus-visible:ring-ring inline-flex items-center justify-center rounded-md text-sm font-medium whitespace-nowrap transition-colors focus-visible:ring-1 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50',
{
variants: {
variant: {
default:
'bg-primary text-primary-foreground shadow hover:bg-primary/90',
'bg-primary text-primary-foreground hover:bg-primary/90 shadow-xs',
destructive:
'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
'bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-xs',
outline:
'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
'border-input bg-background hover:bg-accent hover:text-accent-foreground border shadow-xs',
secondary:
'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
'bg-secondary text-secondary-foreground hover:bg-secondary/80 shadow-xs',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'decoration-primary underline-offset-4 hover:underline',
},

View File

@@ -26,7 +26,7 @@ function Calendar({
month: 'space-y-4',
caption: 'flex justify-center pt-1 relative items-center',
caption_label: 'text-sm font-medium',
nav: 'space-x-1 flex items-center',
nav: 'gap-x-2 flex items-center',
nav_button: cn(
buttonVariants({ variant: 'outline' }),
'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',

View File

@@ -52,7 +52,7 @@ const ChartContainer: React.FC<
<div
data-chart={chartId}
className={cn(
"flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
"[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border flex aspect-video justify-center text-xs [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden",
className,
)}
{...props}
@@ -177,7 +177,7 @@ const ChartTooltipContent: React.FC<
<div
ref={ref}
className={cn(
'grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl',
'border-border/50 bg-background grid min-w-[8rem] items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl',
className,
)}
>
@@ -192,7 +192,7 @@ const ChartTooltipContent: React.FC<
<div
key={item.dataKey}
className={cn(
'flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground',
'[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5',
indicator === 'dot' && 'items-center',
)}
>
@@ -206,7 +206,7 @@ const ChartTooltipContent: React.FC<
!hideIndicator && (
<div
className={cn(
'shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]',
'shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)',
{
'h-2.5 w-2.5': indicator === 'dot',
'w-1': indicator === 'line',
@@ -237,7 +237,7 @@ const ChartTooltipContent: React.FC<
</span>
</div>
{item.value && (
<span className="font-mono font-medium tabular-nums text-foreground">
<span className="text-foreground font-mono font-medium tabular-nums">
{item.value.toLocaleString()}
</span>
)}
@@ -294,7 +294,7 @@ const ChartLegendContent: React.FC<
<div
key={item.value}
className={cn(
'flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground',
'[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3',
)}
>
{itemConfig?.icon && !hideIcon ? (

View File

@@ -12,7 +12,7 @@ const Checkbox: React.FC<
> = ({ className, ...props }) => (
<CheckboxPrimitive.Root
className={cn(
'peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
'peer border-primary focus-visible:ring-ring data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground h-4 w-4 shrink-0 rounded-xs border shadow-xs focus-visible:ring-1 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',
className,
)}
{...props}

View File

@@ -14,7 +14,7 @@ const Command: React.FC<
> = ({ className, ...props }) => (
<CommandPrimitive
className={cn(
'flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground',
'bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md',
className,
)}
{...props}
@@ -28,7 +28,7 @@ const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
return (
<Dialog {...props}>
<DialogContent className="overflow-hidden p-0">
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
<Command className="[&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
{children}
</Command>
</DialogContent>
@@ -44,7 +44,7 @@ const CommandInput: React.FC<
<MagnifyingGlassIcon className="mr-2 h-4 w-4 shrink-0 opacity-50" />
<CommandPrimitive.Input
className={cn(
'flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',
'placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50',
className,
)}
{...props}
@@ -58,7 +58,7 @@ const CommandList: React.FC<
React.ComponentPropsWithRef<typeof CommandPrimitive.List>
> = ({ className, ...props }) => (
<CommandPrimitive.List
className={cn('max-h-[300px] overflow-y-auto overflow-x-hidden', className)}
className={cn('max-h-[300px] overflow-x-hidden overflow-y-auto', className)}
{...props}
/>
);
@@ -78,7 +78,7 @@ const CommandGroup: React.FC<
> = ({ className, ...props }) => (
<CommandPrimitive.Group
className={cn(
'overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground',
'text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium',
className,
)}
{...props}
@@ -91,7 +91,7 @@ const CommandSeparator: React.FC<
React.ComponentPropsWithRef<typeof CommandPrimitive.Separator>
> = ({ className, ...props }) => (
<CommandPrimitive.Separator
className={cn('-mx-1 h-px bg-border', className)}
className={cn('bg-border -mx-1 h-px', className)}
{...props}
/>
);
@@ -102,7 +102,7 @@ const CommandItem: React.FC<
> = ({ className, ...props }) => (
<CommandPrimitive.Item
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-[selected='true']:bg-accent aria-[selected='true']:text-accent-foreground data-[disabled='true']:pointer-events-none data-[disabled='true']:opacity-50",
"aria-selected:bg-accent aria-selected:text-accent-foreground relative flex cursor-default items-center rounded-xs px-2 py-1.5 text-sm outline-hidden select-none data-[disabled='true']:pointer-events-none data-[disabled='true']:opacity-50",
className,
)}
{...props}
@@ -118,7 +118,7 @@ const CommandShortcut = ({
return (
<span
className={cn(
'ml-auto text-xs tracking-widest text-muted-foreground',
'text-muted-foreground ml-auto text-xs tracking-widest',
className,
)}
{...props}

View File

@@ -20,7 +20,7 @@ const DialogOverlay: React.FC<
> = ({ className, ...props }) => (
<DialogPrimitive.Overlay
className={cn(
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80',
className,
)}
{...props}
@@ -35,13 +35,13 @@ const DialogContent: React.FC<
<DialogOverlay />
<DialogPrimitive.Content
className={cn(
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg',
className,
)}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none">
<Cross2Icon className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
@@ -83,7 +83,7 @@ const DialogTitle: React.FC<
> = ({ className, ...props }) => (
<DialogPrimitive.Title
className={cn(
'text-lg font-semibold leading-none tracking-tight',
'text-lg leading-none font-semibold tracking-tight',
className,
)}
{...props}
@@ -95,7 +95,7 @@ const DialogDescription: React.FC<
React.ComponentPropsWithRef<typeof DialogPrimitive.Description>
> = ({ className, ...props }) => (
<DialogPrimitive.Description
className={cn('text-sm text-muted-foreground', className)}
className={cn('text-muted-foreground text-sm', className)}
{...props}
/>
);

View File

@@ -30,7 +30,7 @@ const DropdownMenuSubTrigger: React.FC<
> = ({ className, inset, children, ...props }) => (
<DropdownMenuPrimitive.SubTrigger
className={cn(
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent',
'focus:bg-accent data-[state=open]:bg-accent flex cursor-default items-center rounded-xs px-2 py-1.5 text-sm outline-hidden select-none',
inset && 'pl-8',
className,
)}
@@ -48,7 +48,7 @@ const DropdownMenuSubContent: React.FC<
> = ({ className, ...props }) => (
<DropdownMenuPrimitive.SubContent
className={cn(
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg',
className,
)}
{...props}
@@ -64,7 +64,7 @@ const DropdownMenuContent: React.FC<
<DropdownMenuPrimitive.Content
sideOffset={sideOffset}
className={cn(
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md',
'bg-popover text-popover-foreground z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-md',
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className,
)}
@@ -81,7 +81,7 @@ const DropdownMenuItem: React.FC<
> = ({ className, inset, ...props }) => (
<DropdownMenuPrimitive.Item
className={cn(
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center rounded-xs px-2 py-1.5 text-sm outline-hidden transition-colors select-none data-disabled:pointer-events-none data-disabled:opacity-50',
inset && 'pl-8',
className,
)}
@@ -95,7 +95,7 @@ const DropdownMenuCheckboxItem: React.FC<
> = ({ className, children, checked, ...props }) => (
<DropdownMenuPrimitive.CheckboxItem
className={cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden transition-colors select-none data-disabled:pointer-events-none data-disabled:opacity-50',
className,
)}
checked={checked}
@@ -117,7 +117,7 @@ const DropdownMenuRadioItem: React.FC<
> = ({ className, children, ...props }) => (
<DropdownMenuPrimitive.RadioItem
className={cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden transition-colors select-none data-disabled:pointer-events-none data-disabled:opacity-50',
className,
)}
{...props}
@@ -152,7 +152,7 @@ const DropdownMenuSeparator: React.FC<
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
> = ({ className, ...props }) => (
<DropdownMenuPrimitive.Separator
className={cn('-mx-1 my-1 h-px bg-muted', className)}
className={cn('bg-muted -mx-1 my-1 h-px', className)}
{...props}
/>
);

View File

@@ -76,7 +76,7 @@ const FormItem: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({
return (
<FormItemContext.Provider value={{ id }}>
<div className={cn('space-y-2', className)} {...props} />
<div className={cn('flex flex-col gap-y-2', className)} {...props} />
</FormItemContext.Provider>
);
};
@@ -127,7 +127,7 @@ const FormDescription: React.FC<React.HTMLAttributes<HTMLParagraphElement>> = ({
return (
<p
id={formDescriptionId}
className={cn('text-[0.8rem] text-muted-foreground', className)}
className={cn('text-muted-foreground text-[0.8rem]', className)}
{...props}
/>
);
@@ -149,7 +149,7 @@ const FormMessage: React.FC<React.HTMLAttributes<HTMLParagraphElement>> = ({
return (
<p
id={formMessageId}
className={cn('text-[0.8rem] font-medium text-destructive', className)}
className={cn('text-destructive text-[0.8rem] font-medium', className)}
{...props}
>
{typeof body === 'string' ? (

View File

@@ -14,7 +14,7 @@ const InputOTP: React.FC<React.ComponentPropsWithoutRef<typeof OTPInput>> = ({
}) => (
<OTPInput
containerClassName={cn(
'flex items-center gap-2 has-[:disabled]:opacity-50',
'flex items-center gap-2 has-disabled:opacity-50',
containerClassName,
)}
className={cn('disabled:cursor-not-allowed', className)}
@@ -45,8 +45,8 @@ const InputOTPSlot: React.FC<
return (
<div
className={cn(
'relative flex h-9 w-9 items-center justify-center border-y border-r border-input text-sm shadow-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md',
isActive && 'z-10 ring-1 ring-ring',
'border-input relative flex h-9 w-9 items-center justify-center border-y border-r text-sm shadow-xs transition-all first:rounded-l-md first:border-l last:rounded-r-md',
isActive && 'ring-ring z-10 ring-1',
className,
)}
{...props}
@@ -54,7 +54,7 @@ const InputOTPSlot: React.FC<
{char}
{hasFakeCaret && (
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
<div className="animate-caret-blink h-4 w-px bg-foreground duration-1000" />
<div className="animate-caret-blink bg-foreground h-4 w-px duration-1000" />
</div>
)}
</div>

View File

@@ -13,7 +13,7 @@ const Input: React.FC<InputProps> = ({
<input
type={type}
className={cn(
'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
'border-input file:text-foreground hover:border-ring/50 placeholder:text-muted-foreground focus-visible:ring-ring flex h-9 w-full rounded-md border bg-transparent px-3 py-1 text-base shadow-2xs transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-1 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
className,
)}
{...props}

View File

@@ -40,7 +40,7 @@ NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
const NavigationMenuItem = NavigationMenuPrimitive.Item;
const navigationMenuTriggerStyle = cva(
'group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50',
'group bg-background hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground data-active:bg-accent/50 data-[state=open]:bg-accent/50 inline-flex h-9 w-max items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-colors focus:outline-hidden disabled:pointer-events-none disabled:opacity-50',
);
const NavigationMenuTrigger: React.FC<
@@ -64,7 +64,7 @@ const NavigationMenuContent: React.FC<
> = ({ className, ...props }) => (
<NavigationMenuPrimitive.Content
className={cn(
'left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto',
'data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 top-0 left-0 w-full md:absolute md:w-auto',
className,
)}
{...props}
@@ -77,10 +77,10 @@ const NavigationMenuLink = NavigationMenuPrimitive.Link;
const NavigationMenuViewport: React.FC<
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
> = ({ className, ...props }) => (
<div className={cn('absolute left-0 top-full flex justify-center')}>
<div className={cn('absolute top-full left-0 flex justify-center')}>
<NavigationMenuPrimitive.Viewport
className={cn(
'origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]',
'origin-top-center bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border shadow-xs md:w-[var(--radix-navigation-menu-viewport-width)]',
className,
)}
{...props}
@@ -95,12 +95,12 @@ const NavigationMenuIndicator: React.FC<
> = ({ className, ...props }) => (
<NavigationMenuPrimitive.Indicator
className={cn(
'top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in',
'data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in top-full z-1 flex h-1.5 items-end justify-center overflow-hidden',
className,
)}
{...props}
>
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
<div className="bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md" />
</NavigationMenuPrimitive.Indicator>
);
NavigationMenuIndicator.displayName =

View File

@@ -20,7 +20,7 @@ const PopoverContent: React.FC<
align={align}
sideOffset={sideOffset}
className={cn(
'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-hidden',
className,
)}
{...props}

View File

@@ -25,13 +25,13 @@ const RadioGroupItem: React.FC<
return (
<RadioGroupPrimitive.Item
className={cn(
'aspect-square h-4 w-4 rounded-full border border-primary text-primary shadow focus:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
'border-primary text-primary focus-visible:ring-ring aspect-square h-4 w-4 rounded-full border shadow-xs focus:outline-hidden focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50',
className,
)}
{...props}
>
<RadioGroupPrimitive.Indicator className="flex items-center justify-center">
<CheckIcon className="h-3.5 w-3.5 fill-primary" />
<CheckIcon className="fill-primary h-3.5 w-3.5" />
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
);
@@ -49,11 +49,11 @@ const RadioGroupItemLabel = (
className={cn(
props.className,
'flex cursor-pointer rounded-md' +
' items-center space-x-4 border border-input' +
' transition-duration-500 p-4 text-sm transition-all focus-within:border-primary',
' border-input items-center space-x-4 border' +
' transition-duration-500 focus-within:border-primary p-4 text-sm transition-all',
{
[`border-primary`]: props.selected,
[`hover:border-primary`]: !props.selected,
[`bg-muted`]: props.selected,
[`hover:bg-muted`]: !props.selected,
},
)}
>

View File

@@ -23,7 +23,7 @@ const SelectTrigger: React.FC<
> = ({ className, children, ...props }) => (
<SelectPrimitive.Trigger
className={cn(
'flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
'border-input ring-offset-background placeholder:text-muted-foreground focus:ring-ring flex h-9 w-full items-center justify-between rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-2xs focus:ring-1 focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
className,
)}
{...props}
@@ -73,7 +73,7 @@ const SelectContent: React.FC<
<SelectPrimitive.Portal>
<SelectPrimitive.Content
className={cn(
'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border shadow-md',
position === 'popper' &&
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
className,
@@ -112,7 +112,7 @@ const SelectItem: React.FC<
> = ({ className, children, ...props }) => (
<SelectPrimitive.Item
className={cn(
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
'focus:bg-accent focus:text-accent-foreground relative flex w-full cursor-default items-center rounded-xs py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50',
className,
)}
{...props}
@@ -131,7 +131,7 @@ const SelectSeparator: React.FC<
React.ComponentPropsWithRef<typeof SelectPrimitive.Separator>
> = ({ className, ...props }) => (
<SelectPrimitive.Separator
className={cn('-mx-1 my-1 h-px bg-muted', className)}
className={cn('bg-muted -mx-1 my-1 h-px', className)}
{...props}
/>
);

View File

@@ -21,7 +21,7 @@ const SheetOverlay: React.FC<
> = ({ className, ...props }) => (
<SheetPrimitive.Overlay
className={cn(
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80',
className,
)}
{...props}
@@ -30,16 +30,16 @@ const SheetOverlay: React.FC<
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
'fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out',
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 gap-4 p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
{
variants: {
side: {
top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
top: 'data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 border-b',
bottom:
'inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',
left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm',
'data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 border-t',
left: 'data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm',
right:
'inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm',
'data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm',
},
},
defaultVariants: {
@@ -64,7 +64,7 @@ const SheetContent: React.FC<SheetContentProps> = ({
className={cn(sheetVariants({ side }), className)}
{...props}
>
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none">
<Cross2Icon className="h-4 w-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
@@ -79,10 +79,7 @@ const SheetHeader = ({
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
'flex flex-col space-y-2 text-center sm:text-left',
className,
)}
className={cn('flex flex-col gap-y-3 text-center sm:text-left', className)}
{...props}
/>
);
@@ -106,7 +103,7 @@ const SheetTitle: React.FC<
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
> = ({ className, ...props }) => (
<SheetPrimitive.Title
className={cn('text-lg font-semibold text-foreground', className)}
className={cn('text-foreground text-lg font-semibold', className)}
{...props}
/>
);
@@ -116,7 +113,7 @@ const SheetDescription: React.FC<
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
> = ({ className, ...props }) => (
<SheetPrimitive.Description
className={cn('text-sm text-muted-foreground', className)}
className={cn('text-muted-foreground text-sm', className)}
{...props}
/>
);

View File

@@ -182,7 +182,7 @@ const SidebarProvider: React.FC<
}
data-minimized={minimized}
className={cn(
'group flex min-h-svh w-full text-sidebar-foreground has-[[data-variant=inset]]:bg-sidebar',
'group text-sidebar-foreground has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full',
className,
)}
ref={ref}
@@ -253,7 +253,7 @@ const Sidebar: React.FC<
return (
<div
className={cn(
'flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground',
'bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col',
className,
{
[SIDEBAR_MINIMIZED_WIDTH]: minimized,
@@ -274,7 +274,7 @@ const Sidebar: React.FC<
data-sidebar="sidebar"
data-mobile="true"
className={cn(
'w-[--sidebar-width] p-0 text-sidebar-foreground [&>button]:hidden',
'text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden',
{
'bg-background': variant === 'ghost',
'bg-sidebar': variant !== 'ghost',
@@ -307,12 +307,12 @@ const Sidebar: React.FC<
{/* This is what handles the sidebar gap on desktop */}
<div
className={cn(
'relative w-[--sidebar-width] bg-transparent transition-[width] duration-200 ease-linear',
'relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear',
'group-data-[collapsible=offcanvas]:w-0',
'group-data-[side=right]:rotate-180',
variant === 'floating' || variant === 'inset'
? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]'
: 'group-data-[collapsible=icon]:w-[--sidebar-width-icon]',
? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]'
: 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)',
{
'h-svh': variant !== 'ghost',
},
@@ -320,14 +320,14 @@ const Sidebar: React.FC<
/>
<div
className={cn(
'fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex',
'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex',
side === 'left'
? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
: 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
// Adjust the padding for floating and inset variants.
variant === 'floating' || variant === 'inset'
? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]'
: 'group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l',
? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]'
: 'group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l',
className,
)}
{...props}
@@ -335,9 +335,9 @@ const Sidebar: React.FC<
<div
data-sidebar="sidebar"
className={cn(
'flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow',
'bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm',
{
'bg-background': variant === 'ghost',
'bg-transparent': variant === 'ghost',
},
)}
>
@@ -390,10 +390,10 @@ const SidebarRail: React.FC<React.ComponentProps<'button'>> = ({
onClick={toggleSidebar}
title="Toggle Sidebar"
className={cn(
'absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border group-data-[side=left]:-right-4 group-data-[side=right]:left-0 sm:flex',
'[[data-side=left]_&]:cursor-w-resize [[data-side=right]_&]:cursor-e-resize',
'hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex',
'in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize',
'[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize',
'group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full group-data-[collapsible=offcanvas]:hover:bg-sidebar',
'hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full',
'[[data-side=left][data-collapsible=offcanvas]_&]:-right-2',
'[[data-side=right][data-collapsible=offcanvas]_&]:-left-2',
className,
@@ -411,8 +411,8 @@ const SidebarInset: React.FC<React.ComponentProps<'main'>> = ({
return (
<main
className={cn(
'relative flex min-h-svh flex-1 flex-col bg-background',
'peer-data-[variant=inset]:min-h-[calc(100svh-theme(spacing.4))] md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow',
'bg-background relative flex min-h-svh flex-1 flex-col',
'peer-data-[variant=inset]:min-h-[calc(100svh-(--spacing(4)))] md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2',
className,
)}
{...props}
@@ -429,7 +429,7 @@ const SidebarInput: React.FC<React.ComponentPropsWithRef<typeof Input>> = ({
<Input
data-sidebar="input"
className={cn(
'h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring',
'bg-background focus-visible:ring-sidebar-ring h-8 w-full shadow-none focus-visible:ring-2',
className,
)}
{...props}
@@ -473,7 +473,7 @@ const SidebarSeparator: React.FC<React.ComponentProps<typeof Separator>> = ({
return (
<Separator
data-sidebar="separator"
className={cn('mx-2 w-auto bg-sidebar-border', className)}
className={cn('bg-sidebar-border mx-2 w-auto', className)}
{...props}
/>
);
@@ -520,7 +520,7 @@ const SidebarGroupLabel: React.FC<
<Comp
data-sidebar="group-label"
className={cn(
'flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-muted-foreground outline-none ring-sidebar-ring transition-[margin,opa] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
'text-muted-foreground ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opa] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
'group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0',
className,
)}
@@ -539,9 +539,9 @@ const SidebarGroupAction: React.FC<
<Comp
data-sidebar="group-action"
className={cn(
'absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
// Increases the hit area of the button on mobile.
'after:absolute after:-inset-2 after:md:hidden',
'after:absolute after:-inset-2 md:after:hidden',
'group-data-[collapsible=icon]:hidden',
className,
)}
@@ -588,18 +588,18 @@ const SidebarMenuItem: React.FC<React.ComponentProps<'li'>> = ({
SidebarMenuItem.displayName = 'SidebarMenuItem';
const sidebarMenuButtonVariants = cva(
'peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus:ring-primary focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
'peer/menu-button ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus:ring-primary active:bg-sidebar-accent active:text-sidebar-accent-foreground data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:font-medium [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
{
variants: {
variant: {
default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',
outline:
'bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]',
'bg-background hover:bg-sidebar-accent hover:text-sidebar-accent-foreground shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]',
},
size: {
default: 'h-8 text-sm',
sm: 'h-7 text-xs',
lg: 'h-12 text-sm group-data-[collapsible=icon]:!p-0',
lg: 'h-12 text-sm group-data-[collapsible=icon]:p-0!',
},
},
defaultVariants: {
@@ -677,15 +677,15 @@ const SidebarMenuAction: React.FC<
<Comp
data-sidebar="menu-action"
className={cn(
'absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0',
'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
// Increases the hit area of the button on mobile.
'after:absolute after:-inset-2 after:md:hidden',
'after:absolute after:-inset-2 md:after:hidden',
'peer-data-[size=sm]/menu-button:top-1',
'peer-data-[size=default]/menu-button:top-1.5',
'peer-data-[size=lg]/menu-button:top-2.5',
'group-data-[collapsible=icon]:hidden',
showOnHover &&
'group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0',
'peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0',
className,
)}
{...props}
@@ -701,7 +701,7 @@ const SidebarMenuBadge: React.FC<React.ComponentProps<'div'>> = ({
<div
data-sidebar="menu-badge"
className={cn(
'pointer-events-none absolute right-1 flex h-5 min-w-5 select-none items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums text-sidebar-foreground',
'text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none',
'peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground',
'peer-data-[size=sm]/menu-button:top-1',
'peer-data-[size=default]/menu-button:top-1.5',
@@ -737,7 +737,7 @@ const SidebarMenuSkeleton: React.FC<
/>
)}
<Skeleton
className="h-4 max-w-[--skeleton-width] flex-1"
className="h-4 max-w-(--skeleton-width) flex-1"
data-sidebar="menu-skeleton-text"
style={
{
@@ -757,7 +757,7 @@ const SidebarMenuSub: React.FC<React.ComponentProps<'ul'>> = ({
<ul
data-sidebar="menu-sub"
className={cn(
'mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5',
'border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5',
'group-data-[collapsible=icon]:hidden',
className,
)}
@@ -787,7 +787,7 @@ const SidebarMenuSubButton: React.FC<
data-size={size}
data-active={isActive}
className={cn(
'flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground outline-none ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground',
'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
'data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground',
size === 'sm' && 'text-xs',
size === 'md' && 'text-sm',
@@ -966,7 +966,7 @@ export function SidebarNavigation({
>
<Link
className={cn('flex items-center', {
'mx-auto w-full !gap-0 [&>svg]:flex-1':
'mx-auto w-full gap-0! [&>svg]:flex-1':
minimized,
})}
href={path}
@@ -1030,7 +1030,7 @@ export function SidebarNavigation({
className={cn(
'flex items-center',
{
'mx-auto w-full !gap-0 [&>svg]:flex-1':
'mx-auto w-full gap-0! [&>svg]:flex-1':
minimized,
},
)}

Some files were not shown because too many files have changed in this diff Show More