Clean up the UI. Boring easy stuff honestly

This commit is contained in:
Gabriel Brown 2025-03-19 15:09:06 -05:00
parent 329ee9dc0a
commit f5e3cb6234
12 changed files with 333 additions and 76 deletions

View File

@ -21,6 +21,7 @@
"@radix-ui/react-dropdown-menu": "^2.1.6",
"@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-scroll-area": "^1.2.3",
"@radix-ui/react-separator": "^1.1.2",
"@radix-ui/react-slot": "^1.1.2",
"@sentry/nextjs": "^9",
"@supabase/ssr": "^0.6.1",

25
pnpm-lock.yaml generated
View File

@ -23,6 +23,9 @@ importers:
'@radix-ui/react-scroll-area':
specifier: ^1.2.3
version: 1.2.3(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-separator':
specifier: ^1.1.2
version: 1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-slot':
specifier: ^1.1.2
version: 1.1.2(@types/react@18.3.18)(react@18.3.1)
@ -890,6 +893,19 @@ packages:
'@types/react-dom':
optional: true
'@radix-ui/react-separator@1.1.2':
resolution: {integrity: sha512-oZfHcaAp2Y6KFBX6I5P1u7CQoy4lheCGiYj+pGFrHy8E/VNRb5E39TkTr3JrV520csPBTZjkuKFdEsjS5EUNKQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-slot@1.1.2':
resolution: {integrity: sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==}
peerDependencies:
@ -4144,6 +4160,15 @@ snapshots:
'@types/react': 18.3.18
'@types/react-dom': 18.3.5(@types/react@18.3.18)
'@radix-ui/react-separator@1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@radix-ui/react-primitive': 2.0.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.18
'@types/react-dom': 18.3.5(@types/react@18.3.18)
'@radix-ui/react-slot@1.1.2(@types/react@18.3.18)(react@18.3.1)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.18)(react@18.3.1)

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="814" height="1000">
<path d="M788.1 340.9c-5.8 4.5-108.2 62.2-108.2 190.5 0 148.4 130.3 200.9 134.2 202.2-.6 3.2-20.7 71.9-68.7 141.9-42.8 61.6-87.5 123.1-155.5 123.1s-85.5-39.5-164-39.5c-76.5 0-103.7 40.8-165.9 40.8s-105.6-57-155.5-127C46.7 790.7 0 663 0 541.8c0-194.4 126.4-297.5 250.8-297.5 66.1 0 121.2 43.4 162.7 43.4 39.5 0 101.1-46 176.3-46 28.5 0 130.9 2.6 198.3 99.2zm-234-181.5c31.1-36.9 53.1-88.1 53.1-139.3 0-7.1-.6-14.3-1.9-20.1-50.6 1.9-110.8 33.7-147.1 75.8-28.5 32.4-55.1 83.6-55.1 135.5 0 7.8 1.3 15.6 1.9 18.1 3.2.6 8.4 1.3 13.6 1.3 45.4 0 102.5-30.4 135.5-71.3z"/>
</svg>

After

Width:  |  Height:  |  Size: 660 B

View File

@ -8,9 +8,11 @@ const HomePage = async () => {
const { data: { session } } = await supabase.auth.getSession();
if (!session) {
return (
<main>
<main className="min-h-screen">
<Header />
<LoginForm />
<div className="flex flex-col items-center justify-center md:min-h-[80vh]">
<LoginForm />
</div>
</main>
);
}

View File

@ -15,6 +15,17 @@ import {
FormItem,
} from '@/components/ui/form';
import { useRef } from 'react';
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { Separator } from '@/components/ui/separator';
import MicrosoftSignIn from '@/components/auth/microsoft/SignIn';
import AppleSignIn from './apple/SignIn';
const formSchema = z.object({
fullName: z.string().optional(),
@ -50,68 +61,107 @@ const LoginForm = () => {
};
return (
<div className="flex flex-col items-center justify-center">
<Form {...form}>
<form ref={formRef} className="space-y-4">
<FormField
control={form.control}
name="fullName"
render={({ field }) => (
<FormItem>
<FormLabel htmlFor='fullName'>
Full Name
</FormLabel>
<FormControl>
<Input id='fullName' type='text' {...field} />
</FormControl>
<FormDescription>
Full name is only required when signing up.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel htmlFor='email'>
Email
</FormLabel>
<FormControl>
<Input id='email' type='email' {...field} required />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>
Password
</FormLabel>
<FormControl>
<Input id='password' type='password' {...field} required />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex gap-4 pt-2">
<Button type="button" onClick={handleLogin}>
Log in
</Button>
<Button type="button" onClick={handleSignup}>
Sign up
</Button>
<Card
className='flex flex-col items-center justify-center
bg-gradient-to-br from-background via-zinc-50 to-gray-50
dark:via-gray-950 dark:to-slate-950'
>
<CardHeader className='flex items-center justify-center'>
<CardTitle>Sign In</CardTitle>
<CardDescription>
Log in or create an account.
</CardDescription>
</CardHeader>
<CardContent>
<Form {...form}>
<form ref={formRef} className="space-y-4">
<FormField
control={form.control}
name="fullName"
render={({ field }) => (
<FormItem>
<FormLabel htmlFor='fullName'>
Full Name
</FormLabel>
<FormControl>
<Input id='fullName' type='text' {...field} />
</FormControl>
<FormDescription>
Full name is only required when signing up.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel htmlFor='email'>
Email
</FormLabel>
<FormControl>
<Input id='email' type='email' {...field} required />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>
Password
</FormLabel>
<FormControl>
<Input id='password' type='password' {...field} required />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex gap-4 justify-center items-center">
<Button
type='button'
className='w-5/12 font-semibold bg-gradient-to-r
from-primary via-primary to-primarydark
hover:from-primary hover:via-primarydark hover:to-primarydark'
onClick={handleLogin}
>
Log in
</Button>
<Button
type='button'
className='w-5/12 font-semibold bg-gradient-to-l
from-primary via-primary to-primarydark
hover:from-primary hover:via-primarydark hover:to-primarydark'
onClick={handleSignup}
>
Sign up
</Button>
</div>
</form>
</Form>
</CardContent>
<CardFooter className='flex flex-col items-center justify-center w-full'>
<div className='flex flex-row items-center justify-between w-5/6'>
<Separator className='w-5/12 h-0.5 rounded-3xl' />
<p className='text-center text-muted-foreground font-semibold'>
or
</p>
<Separator className='w-5/12 h-0.5 rounded-3xl' />
</div>
<div className='m-1'>
< MicrosoftSignIn />
<div className='my-2'>
<AppleSignIn />
</div>
</form>
</Form>
</div>
</div>
</CardFooter>
</Card>
);
};

View File

@ -0,0 +1,23 @@
import { Button } from '@/components/ui/button';
import Image from 'next/image';
const AppleSignIn = () => {
return (
<Button
className='flex flex-row items-center justify-center
dark:bg-white bg-slate-950 m-1 dark:hover:bg-slate-200
hover:bg-slate-700 w-full my-auto'
>
<Image
src='/images/apple_black.svg'
alt='Apple Logo'
width={16} height={16}
className='invert dark:invert-0'
/>
<p className='font-semibold dark:text-slate-950'>
Sign in with Apple
</p>
</Button>
);
};
export default AppleSignIn;

View File

@ -0,0 +1,22 @@
import { Button } from '@/components/ui/button';
import Image from 'next/image';
const MicrosoftSignIn = () => {
return (
<Button
className='flex flex-row items-center justify-center
dark:bg-white bg-slate-950 m-1 dark:hover:bg-slate-200
hover:bg-slate-700 w-full'
>
<Image
src='/images/microsoft_logo.png'
alt='Microsoft Logo'
width={20} height={20}
/>
<p className='font-semibold dark:text-slate-950'>
Sign in with Microsoft
</p>
</Button>
);
};
export default MicrosoftSignIn;

View File

@ -8,25 +8,34 @@ const Header = () => {
const { tvMode } = useTVMode();
if (tvMode) {
return (
<div className='absolute top-4 right-2'>
<div className='flex flex-row my-auto items-center pt-2 pr-0 md:pt-4'>
<TVToggle />
<div className='w-full flex flex-row items-end justify-end'>
<div className='flex flex-row my-auto items-center pt-2 pr-0 sm:pr-8 sm:pt-4'>
<AvatarDropdown />
<div className='mb-0.5'>
<TVToggle />
</div>
<ThemeToggle />
</div>
</div>
);
} else {
return (
<header className='w-full py-2 pt-6 md:py-5'>
<div className='absolute top-4 right-6'>
<div className='flex flex-row my-auto items-center pt-2 pr-0 md:pt-4 md:pr-8'>
<TVToggle />
<ThemeToggle />
<header className='w-full min-h-[10vh]'>
<div className='w-full flex flex-row items-end justify-end'>
<div
className='flex flex-row my-auto items-center
pt-2 pr-0 sm:pt-4 sm:pr-8'
>
<AvatarDropdown />
<div className='mb-0.5'>
<TVToggle />
</div>
<ThemeToggle />
</div>
</div>
<div
className='flex flex-row items-center text-center
justify-center sm:ml-0 p-4 mt-10 sm:mt-0'
justify-center'
>
<Image
src='/images/tech_tracker_logo.png'
@ -36,8 +45,9 @@ const Header = () => {
className='max-w-[40px] md:max-w-[120px]'
/>
<h1
className='title-text text-sm md:text-4xl lg:text-8xl
bg-gradient-to-r from-[#bec8e6] via-[#F0EEE4] to-[#FFF8E7]
className='title-text text-xl sm:text-4xl md:text-6xl lg:text-8xl
bg-gradient-to-r dark:from-[#bec8e6] dark:via-[#F0EEE4]
dark:to-[#FFF8E7] from-[#2e3266] via-slate-600 to-zinc-700
font-bold pl-2 md:pl-12 text-transparent bg-clip-text'
>
Tech Tracker

View File

@ -0,0 +1,76 @@
import * as React from "react"
import { cn } from "@/lib/utils"
const Card = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"rounded-xl border bg-card text-card-foreground shadow",
className
)}
{...props}
/>
))
Card.displayName = "Card"
const CardHeader = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props}
/>
))
CardHeader.displayName = "CardHeader"
const CardTitle = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("font-semibold leading-none tracking-tight", className)}
{...props}
/>
))
CardTitle.displayName = "CardTitle"
const CardDescription = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
CardDescription.displayName = "CardDescription"
const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
))
CardContent.displayName = "CardContent"
const CardFooter = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex items-center p-6 pt-0", className)}
{...props}
/>
))
CardFooter.displayName = "CardFooter"
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }

View File

@ -0,0 +1,31 @@
"use client"
import * as React from "react"
import * as SeparatorPrimitive from "@radix-ui/react-separator"
import { cn } from "@/lib/utils"
const Separator = React.forwardRef<
React.ElementRef<typeof SeparatorPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
>(
(
{ className, orientation = "horizontal", decorative = true, ...props },
ref
) => (
<SeparatorPrimitive.Root
ref={ref}
decorative={decorative}
orientation={orientation}
className={cn(
"shrink-0 bg-border",
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
className
)}
{...props}
/>
)
)
Separator.displayName = SeparatorPrimitive.Root.displayName
export { Separator }

View File

@ -10,7 +10,10 @@
--card-foreground: 224 71.4% 4.1%;
--popover: 0 0% 100%;
--popover-foreground: 224 71.4% 4.1%;
--primary: 262.1 83.3% 57.8%;
/*--primary: 262.1 83.3% 57.8%;*/
--primary: 231 39% 48%;
--primary-dark: 231 39% 38%;
--primary-light: 231 45% 58%;
--primary-foreground: 210 20% 98%;
--secondary: 220 14.3% 95.9%;
--secondary-foreground: 220.9 39.3% 11%;
@ -37,7 +40,10 @@
--card-foreground: 210 20% 98%;
--popover: 224 71.4% 4.1%;
--popover-foreground: 210 20% 98%;
--primary: 263.4 70% 50.4%;
/*--primary: 263.4 70% 50.4%;*/
--primary: 231 39% 48%;
--primary-dark: 231 39% 38%;
--primary-light: 231 45% 58%;
--primary-foreground: 210 20% 98%;
--secondary: 215 27.9% 16.9%;
--secondary-foreground: 210 20% 98%;

View File

@ -32,6 +32,14 @@ export default {
DEFAULT: 'hsl(var(--primary))',
foreground: 'hsl(var(--primary-foreground))'
},
primarydark: {
DEFAULT: 'hsl(var(--primary-dark))',
foreground: 'hsl(var(--primary-foreground))'
},
primarylight: {
DEFAULT: 'hsl(var(--primary-light))',
foreground: 'hsl(var(--primary-foreground))'
},
secondary: {
DEFAULT: 'hsl(var(--secondary))',
foreground: 'hsl(var(--secondary-foreground))'