Tailwind CSS 4 Migration (#100)

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 123 KiB

View File

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

View File

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

View File

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

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

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

View File

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

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

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

View File

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

View File

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