Update theme & stuff

This commit is contained in:
2025-07-02 15:03:16 -05:00
parent d9dd83b8c1
commit 489009d35d
17 changed files with 534 additions and 189 deletions

BIN
bun.lockb

Binary file not shown.

View File

@@ -48,12 +48,12 @@
"@radix-ui/react-toggle": "^1.1.9",
"@radix-ui/react-toggle-group": "^1.1.10",
"@radix-ui/react-tooltip": "^1.2.7",
"@sentry/nextjs": "^9.32.0",
"@sentry/nextjs": "^9.34.0",
"@supabase-cache-helpers/postgrest-react-query": "^1.13.4",
"@supabase/ssr": "^0.6.1",
"@supabase/supabase-js": "^2.50.2",
"@t3-oss/env-nextjs": "^0.12.0",
"@tanstack/react-query": "^5.81.2",
"@tanstack/react-query": "^5.81.5",
"@tanstack/react-table": "^8.21.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
@@ -71,9 +71,10 @@
"react": "^19.1.0",
"react-day-picker": "^9.7.0",
"react-dom": "^19.1.0",
"react-hook-form": "^7.58.1",
"react-hook-form": "^7.59.0",
"react-icons": "^5.5.0",
"react-resizable-panels": "^3.0.3",
"recharts": "^3.0.1",
"recharts": "^3.0.2",
"sonner": "^2.0.5",
"tailwind-merge": "^3.3.1",
"vaul": "^1.1.2",
@@ -84,22 +85,22 @@
"@tailwindcss/postcss": "^4.1.11",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.3",
"@types/node": "^20.19.1",
"@types/node": "^20.19.4",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"drizzle-kit": "^0.30.6",
"eslint": "^9.29.0",
"eslint": "^9.30.1",
"eslint-config-next": "^15.3.4",
"eslint-config-prettier": "^10.1.5",
"eslint-plugin-drizzle": "^0.2.3",
"eslint-plugin-prettier": "^5.5.1",
"postcss": "^8.5.6",
"prettier": "^3.6.1",
"prettier": "^3.6.2",
"prettier-plugin-tailwindcss": "^0.6.13",
"tailwindcss": "^4.1.11",
"tw-animate-css": "^1.3.4",
"typescript": "^5.8.3",
"typescript-eslint": "^8.35.0"
"typescript-eslint": "^8.35.1"
},
"ct3aMetadata": {
"initVersion": "7.39.3"

View File

@@ -1,6 +1,7 @@
import '@/styles/globals.css';
import { type Metadata } from 'next';
import { Geist } from 'next/font/google';
import { Inter } from 'next/font/google';
import { cn } from '@/lib/utils';
import {
AuthContextProvider,
ThemeProvider,
@@ -204,16 +205,20 @@ export const generateMetadata = (): Metadata => {
};
};
const geist = Geist({
const fontSans = Inter({
subsets: ['latin'],
variable: '--font-geist-sans',
});
variable: '--font-sans',
})
export default function RootLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
return (
<html lang='en' className={`${geist.variable}`} suppressHydrationWarning>
<html
lang='en'
className={cn('font-sans antialiased', fontSans.variable)}
suppressHydrationWarning
>
<body>
<ThemeProvider
attribute='class'
@@ -229,10 +234,10 @@ export default function RootLayout({
trackOutboundLinks
selfHosted
>
<TVModeProvider>
{children}
<Toaster />
</TVModeProvider>
<TVModeProvider>
{children}
<Toaster />
</TVModeProvider>
</PlausibleProvider>
</AuthContextProvider>
</QueryClientProvider>

View File

@@ -1,36 +1,15 @@
import Link from 'next/link';
import { SignInCard } from '@/components/default/auth/cards/client/sign-in';
import { ThemeToggle } from '@/lib/hooks/context';
export default function HomePage() {
return (
<main className='flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white'>
<main className='flex min-h-screen flex-col items-center justify-center'>
<div className='container flex flex-col items-center justify-center gap-12 px-4 py-16'>
<h1 className='text-5xl font-extrabold tracking-tight text-white sm:text-[5rem]'>
Create <span className='text-[hsl(280,100%,70%)]'>T3</span> App
</h1>
<div className='grid grid-cols-1 gap-4 sm:grid-cols-2 md:gap-8'>
<Link
className='flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20'
href='https://create.t3.gg/en/usage/first-steps'
target='_blank'
>
<h3 className='text-2xl font-bold'>First Steps </h3>
<div className='text-lg'>
Just the basics - Everything you need to know to set up your
database and authentication.
</div>
</Link>
<Link
className='flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20'
href='https://create.t3.gg/en/introduction'
target='_blank'
>
<h3 className='text-2xl font-bold'>Documentation </h3>
<div className='text-lg'>
Learn more about Create T3 App, the libraries it uses, and how to
deploy it.
</div>
</Link>
</div>
<ThemeToggle />
<SignInCard/>
</div>
</main>
);

View File

@@ -1,3 +1,3 @@
export { SignInWithApple } from './sign-in-with-apple';
export { SignInWithMicrosoft } from './sign-in-with-microsoft';
export { SignInButton } from './sign-in';
export { SignInLinkButton } from './sign-in-link';

View File

@@ -6,7 +6,7 @@ import { type VariantProps } from 'class-variance-authority';
type SignInProps = ComponentProps<'button'> & VariantProps<typeof buttonVariants>;
export const SignInButton = (props: SignInProps) => {
export const SignInLinkButton = (props: SignInProps) => {
return (
<Button asChild {...props}>
<Link href='/sign-in'>Sign In</Link>

View File

@@ -4,27 +4,17 @@ import { StatusMessage, SubmitButton } from '@/components/default/forms';
import { useAuth } from '@/lib/hooks/context';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import Image from 'next/image';
import { useSupabaseClient } from '@/utils/supabase';
import { FaApple } from 'react-icons/fa';
import { type buttonVariants } from '@/components/ui';
import { type ComponentProps } from 'react';
import { type VariantProps } from 'class-variance-authority';
import { useSupabaseClient } from '@/utils/supabase';
type ButtonProps = ComponentProps<'button'> & VariantProps<typeof buttonVariants>;
type ImageProps = {
src: string;
alt: string;
className?: string;
width?: number;
height?: number;
}
type FormProps = ComponentProps<'form'>;
type TextProps = ComponentProps<'p'>;
type SignInWithAppleProps = {
buttonProps?: ButtonProps;
imageProps?: ImageProps;
formProps?: FormProps;
textProps?: TextProps;
buttonProps?: ComponentProps<'button'> & VariantProps<typeof buttonVariants>;
formProps?: ComponentProps<'form'>;
textProps?: ComponentProps<'p'>;
iconProps?: ComponentProps<'svg'>;
};
export const SignInWithApple = ({
@@ -32,19 +22,15 @@ export const SignInWithApple = ({
className: 'w-full cursor-pointer',
type: 'submit',
},
imageProps = {
src: '/icons/auth/apple.svg',
alt: 'Apple',
className: 'invert-75 dark:invert-25',
width: 24,
height: 24,
},
formProps = {
className: 'my-4',
},
textProps = {
className: 'text-[1.0rem]',
},
iconProps = {
className: 'size-5',
}
} : SignInWithAppleProps) => {
const router = useRouter();
const { loading, refreshUser } = useAuth();
@@ -78,13 +64,7 @@ export const SignInWithApple = ({
{...buttonProps}
>
<div className='flex items-center gap-2'>
<Image
src={imageProps.src}
alt={imageProps.alt}
className={imageProps.className}
width={imageProps.width}
height={imageProps.height}
/>
<FaApple {...iconProps} />
<p className={textProps.className} {...textProps}>Sign In with Apple</p>
</div>
</SubmitButton>

View File

@@ -4,27 +4,17 @@ import { StatusMessage, SubmitButton } from '@/components/default/forms';
import { useAuth } from '@/lib/hooks/context';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import Image from 'next/image';
import { useSupabaseClient } from '@/utils/supabase';
import { FaMicrosoft } from 'react-icons/fa';
import { type buttonVariants } from '@/components/ui';
import { type ComponentProps } from 'react';
import { type VariantProps } from 'class-variance-authority';
import { useSupabaseClient } from '@/utils/supabase';
type ButtonProps = ComponentProps<'button'> & VariantProps<typeof buttonVariants>;
type ImageProps = {
src: string;
alt: string;
className?: string;
width?: number;
height?: number;
}
type FormProps = ComponentProps<'form'>;
type TextProps = ComponentProps<'p'>;
type SignInWithMicrosoftProps = {
buttonProps?: ButtonProps;
imageProps?: ImageProps;
formProps?: FormProps;
textProps?: TextProps;
buttonProps?: ComponentProps<'button'> & VariantProps<typeof buttonVariants>;
formProps?: ComponentProps<'form'>;
textProps?: ComponentProps<'p'>;
iconProps?: ComponentProps<'svg'>;
};
export const SignInWithMicrosoft = ({
@@ -32,19 +22,15 @@ export const SignInWithMicrosoft = ({
className: 'w-full cursor-pointer',
type: 'submit',
},
imageProps = {
src: '/icons/auth/microsoft.svg',
alt: 'Apple',
className: '',
width: 24,
height: 24,
},
formProps = {
className: 'my-4',
},
textProps = {
className: 'text-[1.0rem]',
},
iconProps = {
className: 'size-5',
}
} : SignInWithMicrosoftProps) => {
const router = useRouter();
const { loading, refreshUser } = useAuth();
@@ -60,7 +46,7 @@ export const SignInWithMicrosoft = ({
setIsLoading(true);
const result = await signInWithMicrosoft(supabase);
if (result.data.url) window.location.href = result.data.url;
else setStatusMessage(`There was a problem signing in with Apple!`);
else setStatusMessage(`There was a problem signing in with Microsoft!`);
} catch (error) {
setStatusMessage(`Error signing in: ${error as string}`);
} finally {
@@ -75,17 +61,12 @@ export const SignInWithMicrosoft = ({
<SubmitButton
disabled={isLoading || loading}
pendingText='Signing in...'
pendingTextClassName={textProps.className}
{...buttonProps}
>
<div className='flex items-center gap-2'>
<Image
src={imageProps.src}
alt={imageProps.alt}
className={imageProps.className}
width={imageProps.width}
height={imageProps.height}
/>
<p className={textProps.className} {...textProps}>Sign In with Apple</p>
<FaMicrosoft {...iconProps} />
<p className={textProps.className} {...textProps}>Sign In with Microsoft</p>
</div>
</SubmitButton>
{statusMessage && <StatusMessage message={{ error: statusMessage }} />}

View File

@@ -0,0 +1,3 @@
export { SignInLinkButton } from './sign-in-link';
export { SignInWithApple } from './sign-in-with-apple';
export { SignInWithMicrosoft } from './sign-in-with-microsoft';

View File

@@ -0,0 +1,15 @@
'use server';
import Link from 'next/link';
import { Button, type buttonVariants } from '@/components/ui';
import { type ComponentProps } from 'react';
import { type VariantProps } from 'class-variance-authority';
type SignInProps = ComponentProps<'button'> & VariantProps<typeof buttonVariants>;
export const SignInLinkButton = async (props: SignInProps) => {
return (
<Button asChild {...props}>
<Link href='/sign-in'>Sign In</Link>
</Button>
);
};

View File

@@ -0,0 +1,78 @@
'use server';
import { signInWithApple } from '@/lib/queries';
import { SubmitButton } from '@/components/default/forms';
import Image from 'next/image';
import { type buttonVariants } from '@/components/ui';
import { type ComponentProps } from 'react';
import { type VariantProps } from 'class-variance-authority';
import { SupabaseServer } from '@/utils/supabase';
type ButtonProps = ComponentProps<'button'> & VariantProps<typeof buttonVariants>;
type ImageProps = {
src: string;
alt: string;
className?: string;
width?: number;
height?: number;
}
type FormProps = ComponentProps<'form'>;
type TextProps = ComponentProps<'p'>;
type SignInWithAppleProps = {
buttonProps?: ButtonProps;
imageProps?: ImageProps;
formProps?: FormProps;
textProps?: TextProps;
};
export const SignInWithApple = async ({
buttonProps = {
className: 'w-full cursor-pointer',
type: 'submit',
},
imageProps = {
src: '/icons/auth/apple.svg',
alt: 'Apple',
className: 'invert-75 dark:invert-25',
width: 24,
height: 24,
},
formProps = {
className: 'my-4',
},
textProps = {
className: 'text-[1.0rem]',
},
} : SignInWithAppleProps) => {
const supabase = await SupabaseServer();
const handleSignInWithApple = async () => {
try {
if (!supabase) throw new Error('Supabase client not found');
const result = await signInWithApple(supabase);
if (result.error) throw new Error(`Error Signing in with Apple: ${result.error.message}`);
if (result.data.url) window.location.href = result.data.url;
} catch (error) {
console.error(error);
}
};
return (
<form action={handleSignInWithApple} {...formProps}>
<SubmitButton
pendingText='Signing in...'
{...buttonProps}
>
<div className='flex items-center gap-2'>
<Image
src={imageProps.src}
alt={imageProps.alt}
className={imageProps.className}
width={imageProps.width}
height={imageProps.height}
/>
<p className={textProps.className} {...textProps}>Sign In with Apple</p>
</div>
</SubmitButton>
</form>
);
};

View File

@@ -0,0 +1,78 @@
'use server';
import { signInWithMicrosoft } from '@/lib/queries';
import { SubmitButton } from '@/components/default/forms';
import Image from 'next/image';
import { type buttonVariants } from '@/components/ui';
import { type ComponentProps } from 'react';
import { type VariantProps } from 'class-variance-authority';
import { SupabaseServer } from '@/utils/supabase';
type ButtonProps = ComponentProps<'button'> & VariantProps<typeof buttonVariants>;
type ImageProps = {
src: string;
alt: string;
className?: string;
width?: number;
height?: number;
}
type FormProps = ComponentProps<'form'>;
type TextProps = ComponentProps<'p'>;
type SignInWithMicrosoftProps = {
buttonProps?: ButtonProps;
imageProps?: ImageProps;
formProps?: FormProps;
textProps?: TextProps;
};
export const SignInWithMicrosoft = async ({
buttonProps = {
className: 'w-full cursor-pointer',
type: 'submit',
},
imageProps = {
src: '/icons/auth/microsoft.svg',
alt: 'Microsoft',
className: 'invert-75 dark:invert-25',
width: 24,
height: 24,
},
formProps = {
className: 'my-4',
},
textProps = {
className: 'text-[1.0rem]',
},
} : SignInWithMicrosoftProps) => {
const supabase = await SupabaseServer();
const handleSignInWithMicrosoft = async () => {
try {
if (!supabase) throw new Error('Supabase client not found');
const result = await signInWithMicrosoft(supabase);
if (result.error) throw new Error(`Error Signing in with Microsoft: ${result.error.message}`);
if (result.data.url) window.location.href = result.data.url;
} catch (error) {
console.error(error);
}
};
return (
<form action={handleSignInWithMicrosoft} {...formProps}>
<SubmitButton
pendingText='Signing in...'
{...buttonProps}
>
<div className='flex items-center gap-2'>
<Image
src={imageProps.src}
alt={imageProps.alt}
className={imageProps.className}
width={imageProps.width}
height={imageProps.height}
/>
<p className={textProps.className} {...textProps}>Sign In with Microsoft</p>
</div>
</SubmitButton>
</form>
);
};

View File

@@ -43,7 +43,7 @@ const signInFormSchema = z.object({
}),
});
const signUpformSchema = z
const signUpFormSchema = z
.object({
name: z.string().min(2, {
message: 'Name must be at least 2 characters.',
@@ -77,8 +77,8 @@ export const SignInCard = () => {
},
});
const signUpForm = useForm<z.infer<typeof signUpformSchema>>({
resolver: zodResolver(signUpformSchema),
const signUpForm = useForm<z.infer<typeof signUpFormSchema>>({
resolver: zodResolver(signUpFormSchema),
defaultValues: {
name: '',
email: '',
@@ -100,11 +100,9 @@ export const SignInCard = () => {
if (!supabase) throw new Error('Supabase client not found');
const result = await signIn(supabase, formData);
if (result.error) throw new Error(result.error.message);
else if (result.data) {
await refreshUser();
signInForm.reset();
router.push('');
}
await refreshUser();
signInForm.reset();
router.push('');
} catch (error) {
setStatusMessage(`Error signing in: ${error as string}`);
}
@@ -112,14 +110,214 @@ export const SignInCard = () => {
const handleSignUp = async (values: z.infer<typeof signUpFormSchema>) => {
try {
} catch {
setStatusMessage('');
const formData = new FormData();
formData.append('name', values.name);
formData.append('email', values.email);
formData.append('password', values.password);
if (!supabase) throw new Error('Supabase client not found');
const result = await signUp(supabase, formData);
if (result.error) throw new Error(result.error.message);
await refreshUser();
signUpForm.reset();
router.push('');
} catch (error) {
setStatusMessage(`Error signing up: ${error as string}`);
}
};
return (
<Tabs defaultValue='sign-in'>
<TabsList>
<TabsTrigger value='sign-in'>Sign In</TabsTrigger>
<TabsTrigger value='sign-up'>Sign Up</TabsTrigger>
</TabsList>
<TabsContent value='sign-in'>
<Card className='min-w-xs md:min-w-sm max-w-lg'>
<CardHeader>
<CardTitle className=''>
Sign In
</CardTitle>
</CardHeader>
<CardContent>
<Form {...signInForm}>
<form
onSubmit={signInForm.handleSubmit(handleSignIn)}
className=''
>
<FormField
control={signInForm.control}
name='email'
render={({ field }) => (
<FormItem>
<FormLabel className=''>Email</FormLabel>
<FormControl>
<Input
type='email'
placeholder='you@example.com'
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={signInForm.control}
name='password'
render={({ field }) => (
<FormItem>
<div className='flex justify-between'>
<FormLabel className=''>Password</FormLabel>
<Link
href='/forgot-password'
>
Forgot Password?
</Link>
</div>
<FormControl>
<Input
type='password'
placeholder='Your password'
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{statusMessage &&
(statusMessage.includes('Error') ||
statusMessage.includes('error') ||
statusMessage.includes('failed') ||
statusMessage.includes('invalid') ? (
<StatusMessage message={{ error: statusMessage }} />
) : (
<StatusMessage message={{ message: statusMessage }} />
))}
<SubmitButton
disabled={loading}
pendingText='Signing In...'
>
Sign In
</SubmitButton>
</form>
</Form>
<div className='flex items-center w-full gap-4'>
<Separator className='flex-1 bg-accent py-0.5' />
<span className='text-sm text-muted-foreground'>or</span>
<Separator className='flex-1 bg-accent py-0.5' />
</div>
<SignInWithMicrosoft />
<SignInWithApple />
</CardContent>
</Card>
</TabsContent>
<TabsContent value='sign-up'>
<Card className='min-w-xs md:min-w-sm max-w-lg'>
<CardHeader>
<CardTitle className=''>
Sign Up
</CardTitle>
</CardHeader>
<CardContent>
<Form {...signUpForm}>
<form
onSubmit={signUpForm.handleSubmit(handleSignUp)}
className=''
>
<FormField
control={signUpForm.control}
name='name'
render={({ field }) => (
<FormItem>
<FormLabel className=''>Name</FormLabel>
<FormControl>
<Input
type='text'
placeholder='Full Name'
{...field}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={signUpForm.control}
name='email'
render={({ field }) => (
<FormItem>
<FormLabel className=''>Email</FormLabel>
<FormControl>
<Input
type='email'
placeholder='you@example.com'
{...field}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={signUpForm.control}
name='password'
render={({ field }) => (
<FormItem>
<FormLabel className=''>Password</FormLabel>
<FormControl>
<Input
type='password'
placeholder='Your password'
{...field}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={signUpForm.control}
name='confirmPassword'
render={({ field }) => (
<FormItem>
<FormLabel className=''>Confirm Passsword</FormLabel>
<FormControl>
<Input
type='password'
placeholder='Confirm your password'
{...field}
/>
</FormControl>
</FormItem>
)}
/>
{statusMessage &&
(statusMessage.includes('Error') ||
statusMessage.includes('error') ||
statusMessage.includes('failed') ||
statusMessage.includes('invalid') ? (
<StatusMessage message={{ error: statusMessage }} />
) : (
<StatusMessage message={{ success: statusMessage }} />
))}
<SubmitButton
disabled={loading}
pendingText='Signing Up...'
>
Sign Up
</SubmitButton>
</form>
</Form>
<div className='flex items-center w-full gap-4'>
<Separator className='flex-1 bg-accent py-0.5' />
<span className='text-sm text-muted-foreground'>or</span>
<Separator className='flex-1 bg-accent py-0.5' />
</div>
<SignInWithMicrosoft />
<SignInWithApple />
</CardContent>
</Card>
</TabsContent>
</Tabs>
);
};

View File

@@ -9,14 +9,14 @@ type SubmitButtonProps = ComponentProps<'button'> &
VariantProps<typeof buttonVariants> & {
pendingText?: string;
loaderClassName?: ComponentProps<'div'>['className'];
textClassName?: ComponentProps<'p'>['className'];
pendingTextClassName?: ComponentProps<'p'>['className'];
};
export const SubmitButton = ({
children,
pendingText = 'Submitting...',
loaderClassName = 'mr-2 h-4 w-4 animate-spin',
textClassName = 'text-sm font-medium',
pendingTextClassName = 'text-sm font-medium',
...props
}: SubmitButtonProps) => {
const { pending } = useFormStatus();
@@ -30,7 +30,7 @@ export const SubmitButton = ({
{pending || props.disabled ? (
<>
<Loader2 className={loaderClassName} />
<p className={textClassName}>{pendingText}</p>
<p className={pendingTextClassName}>{pendingText}</p>
</>
) : (
children

View File

@@ -4,7 +4,7 @@
@custom-variant dark (&:is(.dark *));
@theme {
--font-sans: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif,
--font-sans: var(--font-sans), ui-sans-serif, system-ui, sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
}
@@ -47,72 +47,99 @@
}
:root {
--radius: 0.65rem;
--background: oklch(1 0 0);
--foreground: oklch(0.141 0.005 285.823);
--card: oklch(1 0 0);
--card-foreground: oklch(0.141 0.005 285.823);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.141 0.005 285.823);
--primary: oklch(0.645 0.246 16.439);
--primary-foreground: oklch(0.969 0.015 12.422);
--secondary: oklch(0.967 0.001 286.375);
--secondary-foreground: oklch(0.21 0.006 285.885);
--muted: oklch(0.967 0.001 286.375);
--muted-foreground: oklch(0.552 0.016 285.938);
--accent: oklch(0.967 0.001 286.375);
--accent-foreground: oklch(0.21 0.006 285.885);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.92 0.004 286.32);
--input: oklch(0.92 0.004 286.32);
--ring: oklch(0.645 0.246 16.439);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.141 0.005 285.823);
--sidebar-primary: oklch(0.645 0.246 16.439);
--sidebar-primary-foreground: oklch(0.969 0.015 12.422);
--sidebar-accent: oklch(0.967 0.001 286.375);
--sidebar-accent-foreground: oklch(0.21 0.006 285.885);
--sidebar-border: oklch(0.92 0.004 286.32);
--sidebar-ring: oklch(0.645 0.246 16.439);
--background: oklch(0.9785 0.0045 314.8050);
--foreground: oklch(0.3710 0.0333 301.6287);
--card: oklch(0.9940 0 0);
--card-foreground: oklch(0.3710 0.0333 301.6287);
--popover: oklch(0.9940 0 0);
--popover-foreground: oklch(0.3710 0.0333 301.6287);
--primary: oklch(0.4868 0.1488 286.5771);
--primary-foreground: oklch(0.9785 0.0045 314.8050);
--secondary: oklch(0.9139 0.0448 291.0467);
--secondary-foreground: oklch(0.3008 0.0773 288.1551);
--muted: oklch(0.8930 0.0149 312.2335);
--muted-foreground: oklch(0.5361 0.0391 305.8579);
--accent: oklch(0.8514 0.0535 342.1042);
--accent-foreground: oklch(0.3328 0.0528 311.4628);
--destructive: oklch(0.6984 0.1170 47.0382);
--destructive-foreground: oklch(0.9785 0.0045 314.8050);
--border: oklch(0.8488 0.0244 313.1102);
--input: oklch(0.9352 0.0136 314.7562);
--ring: oklch(0.4868 0.1488 286.5771);
--chart-1: oklch(0.4868 0.1488 286.5771);
--chart-2: oklch(0.8514 0.0535 342.1042);
--chart-3: oklch(0.7388 0.0664 194.5709);
--chart-4: oklch(0.9197 0.1140 104.6226);
--chart-5: oklch(0.7409 0.0895 280.3986);
--sidebar: oklch(0.9569 0.0090 314.7812);
--sidebar-foreground: oklch(0.3710 0.0333 301.6287);
--sidebar-primary: oklch(0.4868 0.1488 286.5771);
--sidebar-primary-foreground: oklch(0.9785 0.0045 314.8050);
--sidebar-accent: oklch(0.8514 0.0535 342.1042);
--sidebar-accent-foreground: oklch(0.3328 0.0528 311.4628);
--sidebar-border: oklch(0.8759 0.0218 316.4501);
--sidebar-ring: oklch(0.4868 0.1488 286.5771);
--font-sans: Inter, sans-serif;
--font-serif: "Lora", Georgia, serif;
--font-mono: "Fira Code", "Courier New", monospace;
--radius: 0.5rem;
--shadow-2xs: 1px 2px 5px 1px hsl(0 0% 10.1961% / 0.03);
--shadow-xs: 1px 2px 5px 1px hsl(0 0% 10.1961% / 0.03);
--shadow-sm: 1px 2px 5px 1px hsl(0 0% 10.1961% / 0.06), 1px 1px 2px 0px hsl(0 0% 10.1961% / 0.06);
--shadow: 1px 2px 5px 1px hsl(0 0% 10.1961% / 0.06), 1px 1px 2px 0px hsl(0 0% 10.1961% / 0.06);
--shadow-md: 1px 2px 5px 1px hsl(0 0% 10.1961% / 0.06), 1px 2px 4px 0px hsl(0 0% 10.1961% / 0.06);
--shadow-lg: 1px 2px 5px 1px hsl(0 0% 10.1961% / 0.06), 1px 4px 6px 0px hsl(0 0% 10.1961% / 0.06);
--shadow-xl: 1px 2px 5px 1px hsl(0 0% 10.1961% / 0.06), 1px 8px 10px 0px hsl(0 0% 10.1961% / 0.06);
--shadow-2xl: 1px 2px 5px 1px hsl(0 0% 10.1961% / 0.15);
--tracking-normal: 0em;
--spacing: 0.25rem;
}
.dark {
--background: oklch(0.141 0.005 285.823);
--foreground: oklch(0.985 0 0);
--card: oklch(0.21 0.006 285.885);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.21 0.006 285.885);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.645 0.246 16.439);
--primary-foreground: oklch(0.969 0.015 12.422);
--secondary: oklch(0.274 0.006 286.033);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.274 0.006 286.033);
--muted-foreground: oklch(0.705 0.015 286.067);
--accent: oklch(0.274 0.006 286.033);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.645 0.246 16.439);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.21 0.006 285.885);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.645 0.246 16.439);
--sidebar-primary-foreground: oklch(0.969 0.015 12.422);
--sidebar-accent: oklch(0.274 0.006 286.033);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.645 0.246 16.439);
--background: oklch(0.2213 0.0228 309.2819);
--foreground: oklch(0.9100 0.0260 308.1435);
--card: oklch(0.2671 0.0372 295.2445);
--card-foreground: oklch(0.9100 0.0260 308.1435);
--popover: oklch(0.2671 0.0372 295.2445);
--popover-foreground: oklch(0.9100 0.0260 308.1435);
--primary: oklch(0.6405 0.1338 286.4998);
--primary-foreground: oklch(0.2213 0.0228 309.2819);
--secondary: oklch(0.4071 0.0776 288.3025);
--secondary-foreground: oklch(0.9100 0.0260 308.1435);
--muted: oklch(0.2630 0.0340 310.8818);
--muted-foreground: oklch(0.7026 0.0304 313.2720);
--accent: oklch(0.3328 0.0528 311.4628);
--accent-foreground: oklch(0.8076 0.0881 341.1289);
--destructive: oklch(0.7501 0.1053 47.2117);
--destructive-foreground: oklch(0.2213 0.0228 309.2819);
--border: oklch(0.3139 0.0379 309.3053);
--input: oklch(0.2913 0.0360 305.8978);
--ring: oklch(0.6405 0.1338 286.4998);
--chart-1: oklch(0.6405 0.1338 286.4998);
--chart-2: oklch(0.8076 0.0881 341.1289);
--chart-3: oklch(0.7388 0.0664 194.5709);
--chart-4: oklch(0.9197 0.1140 104.6226);
--chart-5: oklch(0.4868 0.1488 286.5771);
--sidebar: oklch(0.2039 0.0232 309.1750);
--sidebar-foreground: oklch(0.9100 0.0260 308.1435);
--sidebar-primary: oklch(0.6405 0.1338 286.4998);
--sidebar-primary-foreground: oklch(0.2213 0.0228 309.2819);
--sidebar-accent: oklch(0.3328 0.0528 311.4628);
--sidebar-accent-foreground: oklch(0.8076 0.0881 341.1289);
--sidebar-border: oklch(0.2913 0.0360 305.8978);
--sidebar-ring: oklch(0.6405 0.1338 286.4998);
--font-sans: Inter, sans-serif;
--font-serif: "Lora", Georgia, serif;
--font-mono: "Fira Code", "Courier New", monospace;
--radius: 0.5rem;
--shadow-2xs: 1px 2px 5px 1px hsl(0 0% 10.1961% / 0.03);
--shadow-xs: 1px 2px 5px 1px hsl(0 0% 10.1961% / 0.03);
--shadow-sm: 1px 2px 5px 1px hsl(0 0% 10.1961% / 0.06), 1px 1px 2px 0px hsl(0 0% 10.1961% / 0.06);
--shadow: 1px 2px 5px 1px hsl(0 0% 10.1961% / 0.06), 1px 1px 2px 0px hsl(0 0% 10.1961% / 0.06);
--shadow-md: 1px 2px 5px 1px hsl(0 0% 10.1961% / 0.06), 1px 2px 4px 0px hsl(0 0% 10.1961% / 0.06);
--shadow-lg: 1px 2px 5px 1px hsl(0 0% 10.1961% / 0.06), 1px 4px 6px 0px hsl(0 0% 10.1961% / 0.06);
--shadow-xl: 1px 2px 5px 1px hsl(0 0% 10.1961% / 0.06), 1px 8px 10px 0px hsl(0 0% 10.1961% / 0.06);
--shadow-2xl: 1px 2px 5px 1px hsl(0 0% 10.1961% / 0.15);
}
@layer base {

View File

@@ -1,5 +1,5 @@
export { useSupabaseClient } from './client';
export { updateSession } from './middleware';
export { useSupabaseServer } from './server';
export { SupabaseServer } from './server';
export type { Database } from './database.types';
export type * from './types';

View File

@@ -2,10 +2,10 @@
import 'server-only';
import { createServerClient } from '@supabase/ssr';
import type { Database, SupabaseClient } from '@/utils/supabase';
import type { Database } from '@/utils/supabase';
import { cookies } from 'next/headers';
export const useSupabaseServer = async (): Promise<SupabaseClient | undefined> => {
export const SupabaseServer = async () => {
const cookieStore = await cookies();
return createServerClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,