axonhub / frontend /src /features /settings /appearance /appearance-form.tsx
llzai's picture
Upload 1793 files
9853396 verified
import { z } from 'zod';
import { useForm } from 'react-hook-form';
import { ChevronDownIcon } from '@radix-ui/react-icons';
import { zodResolver } from '@hookform/resolvers/zod';
import { fonts } from '@/config/fonts';
import { cn } from '@/lib/utils';
import { showSubmittedData } from '@/utils/show-submitted-data';
import { useFont } from '@/context/font-context';
import { useTheme } from '@/context/theme-context';
import { Button, buttonVariants } from '@/components/ui/button';
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
const colorSchemes = ['blue', 'green', 'purple', 'orange', 'red', 'black', 'cream'] as const;
const appearanceFormSchema = z.object({
theme: z.enum(['light', 'dark'], {
required_error: 'Please select a theme.',
}),
colorScheme: z.enum(colorSchemes, {
required_error: 'Please select a color scheme.',
}),
font: z.enum(fonts, {
invalid_type_error: 'Select a font',
required_error: 'Please select a font.',
}),
});
type AppearanceFormValues = z.infer<typeof appearanceFormSchema>;
export function AppearanceForm() {
const { font, setFont } = useFont();
const { theme, setTheme, colorScheme, setColorScheme } = useTheme();
// This can come from your database or API.
const defaultValues: Partial<AppearanceFormValues> = {
theme: theme as 'light' | 'dark',
colorScheme,
font,
};
const form = useForm<AppearanceFormValues>({
resolver: zodResolver(appearanceFormSchema),
defaultValues,
});
function onSubmit(data: AppearanceFormValues) {
if (data.font != font) setFont(data.font);
if (data.theme != theme) setTheme(data.theme);
if (data.colorScheme != colorScheme) setColorScheme(data.colorScheme);
showSubmittedData(data);
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className='space-y-8'>
<FormField
control={form.control}
name='font'
render={({ field }) => (
<FormItem>
<FormLabel>Font</FormLabel>
<div className='relative w-max'>
<FormControl>
<select
className={cn(
buttonVariants({ variant: 'outline' }),
'w-[200px] appearance-none font-normal capitalize',
'dark:bg-background dark:hover:bg-background'
)}
{...field}
>
{fonts.map((font) => (
<option key={font} value={font}>
{font}
</option>
))}
</select>
</FormControl>
<ChevronDownIcon className='absolute top-2.5 right-3 h-4 w-4 opacity-50' />
</div>
<FormDescription className='font-manrope'>Set the font you want to use in the dashboard.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='colorScheme'
render={({ field }) => (
<FormItem>
<FormLabel>Color Scheme</FormLabel>
<div className='relative w-max'>
<FormControl>
<select
className={cn(
buttonVariants({ variant: 'outline' }),
'w-[200px] appearance-none font-normal capitalize',
'dark:bg-background dark:hover:bg-background'
)}
{...field}
>
{colorSchemes.map((scheme) => (
<option key={scheme} value={scheme}>
{scheme}
</option>
))}
</select>
</FormControl>
<ChevronDownIcon className='absolute top-2.5 right-3 h-4 w-4 opacity-50' />
</div>
<FormDescription className='font-manrope'>Choose your preferred color scheme for the interface.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name='theme'
render={({ field }) => (
<FormItem className='space-y-1'>
<FormLabel>Theme</FormLabel>
<FormDescription>Select the theme for the dashboard.</FormDescription>
<FormMessage />
<RadioGroup onValueChange={field.onChange} defaultValue={field.value} className='grid max-w-md grid-cols-2 gap-8 pt-2'>
<FormItem>
<FormLabel className='[&:has([data-state=checked])>div]:border-primary'>
<FormControl>
<RadioGroupItem value='light' className='sr-only' />
</FormControl>
<div className='border-muted hover:border-accent items-center rounded-md border-2 p-1 transition-colors'>
<div className='space-y-2 rounded-sm bg-[#f8f9fa] p-2'>
<div className='space-y-2 rounded-md bg-white p-2 shadow-sm'>
<div className='h-2 w-[80px] rounded-lg bg-[#e9ecef]' />
<div className='h-2 w-[100px] rounded-lg bg-[#e9ecef]' />
</div>
<div className='flex items-center space-x-2 rounded-md bg-white p-2 shadow-sm'>
<div className='bg-primary/20 h-4 w-4 rounded-full' />
<div className='h-2 w-[100px] rounded-lg bg-[#e9ecef]' />
</div>
<div className='flex items-center space-x-2 rounded-md bg-white p-2 shadow-sm'>
<div className='h-4 w-4 rounded-full bg-[#e9ecef]' />
<div className='h-2 w-[100px] rounded-lg bg-[#e9ecef]' />
</div>
</div>
</div>
<span className='block w-full p-2 text-center font-normal'>Light</span>
</FormLabel>
</FormItem>
<FormItem>
<FormLabel className='[&:has([data-state=checked])>div]:border-primary'>
<FormControl>
<RadioGroupItem value='dark' className='sr-only' />
</FormControl>
<div className='border-muted hover:border-accent items-center rounded-md border-2 p-1 transition-colors'>
<div className='space-y-2 rounded-sm bg-slate-950 p-2'>
<div className='space-y-2 rounded-md bg-slate-800 p-2 shadow-sm'>
<div className='h-2 w-[80px] rounded-lg bg-slate-600' />
<div className='h-2 w-[100px] rounded-lg bg-slate-600' />
</div>
<div className='flex items-center space-x-2 rounded-md bg-slate-800 p-2 shadow-sm'>
<div className='bg-primary/30 h-4 w-4 rounded-full' />
<div className='h-2 w-[100px] rounded-lg bg-slate-600' />
</div>
<div className='flex items-center space-x-2 rounded-md bg-slate-800 p-2 shadow-sm'>
<div className='h-4 w-4 rounded-full bg-slate-600' />
<div className='h-2 w-[100px] rounded-lg bg-slate-600' />
</div>
</div>
</div>
<span className='block w-full p-2 text-center font-normal'>Dark</span>
</FormLabel>
</FormItem>
</RadioGroup>
</FormItem>
)}
/>
<Button type='submit'>Update preferences</Button>
</form>
</Form>
);
}