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:
committed by
GitHub
parent
d799f54ede
commit
4e91f267e0
@@ -1,3 +1,3 @@
|
||||
# Your Application
|
||||
|
||||
Write here everything about your application.
|
||||
Write here everything about your application.
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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')}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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'} />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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={
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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 |
@@ -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.",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
42
apps/web/styles/makerkit.css
Normal file
42
apps/web/styles/makerkit.css
Normal 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
114
apps/web/styles/markdoc.css
Normal 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;
|
||||
}
|
||||
104
apps/web/styles/shadcn-ui.css
Normal file
104
apps/web/styles/shadcn-ui.css
Normal 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
133
apps/web/styles/theme.css
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
5
apps/web/styles/theme.utilities.css
Normal file
5
apps/web/styles/theme.utilities.css
Normal file
@@ -0,0 +1,5 @@
|
||||
@utility container {
|
||||
margin-inline: auto;
|
||||
|
||||
@apply xl:max-w-[80rem] px-8;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "next-supabase-saas-kit-turbo",
|
||||
"version": "1.0.0",
|
||||
"version": "2.0.0",
|
||||
"private": true,
|
||||
"sideEffects": false,
|
||||
"engines": {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'}>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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'}
|
||||
>
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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'}>
|
||||
|
||||
@@ -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 />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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'}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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,
|
||||
})}
|
||||
>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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'}>
|
||||
|
||||
@@ -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,
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
]);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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 ? (
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -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' ? (
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user