Added dark/light mode (next: custom themes)

This commit is contained in:
grimsi
2024-03-27 18:26:47 +01:00
parent 9424263c4a
commit d30cd9706d
27 changed files with 1479 additions and 187 deletions
+6
View File
@@ -0,0 +1,6 @@
import {ThemeProvider as NextThemesProvider} from "next-themes"
import {type ThemeProviderProps} from "next-themes/dist/types"
export function ThemeProvider({children, ...props}: ThemeProviderProps) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}
+59
View File
@@ -0,0 +1,59 @@
import * as React from "react"
import {cva, type VariantProps} from "class-variance-authority"
import {cn} from "Frontend/@/lib/utils"
const alertVariants = cva(
"relative w-full rounded-lg border border-slate-200 p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-slate-950 dark:border-slate-800 dark:[&>svg]:text-slate-50",
{
variants: {
variant: {
default: "bg-white text-slate-950 dark:bg-slate-950 dark:text-slate-50",
destructive:
"border-red-500/50 text-red-500 dark:border-red-500 [&>svg]:text-red-500 dark:border-red-900/50 dark:text-red-900 dark:dark:border-red-900 dark:[&>svg]:text-red-900",
},
},
defaultVariants: {
variant: "default",
},
}
)
const Alert = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
>(({className, variant, ...props}, ref) => (
<div
ref={ref}
role="alert"
className={cn(alertVariants({variant}), className)}
{...props}
/>
))
Alert.displayName = "Alert"
const AlertTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({className, ...props}, ref) => (
<h5
ref={ref}
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
{...props}
/>
))
AlertTitle.displayName = "AlertTitle"
const AlertDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({className, ...props}, ref) => (
<div
ref={ref}
className={cn("text-sm [&_p]:leading-relaxed", className)}
{...props}
/>
))
AlertDescription.displayName = "AlertDescription"
export {Alert, AlertTitle, AlertDescription}
+48
View File
@@ -0,0 +1,48 @@
import * as React from "react"
import * as AvatarPrimitive from "@radix-ui/react-avatar"
import {cn} from "Frontend/@/lib/utils"
const Avatar = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
>(({className, ...props}, ref) => (
<AvatarPrimitive.Root
ref={ref}
className={cn(
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
className
)}
{...props}
/>
))
Avatar.displayName = AvatarPrimitive.Root.displayName
const AvatarImage = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Image>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
>(({className, ...props}, ref) => (
<AvatarPrimitive.Image
ref={ref}
className={cn("aspect-square h-full w-full", className)}
{...props}
/>
))
AvatarImage.displayName = AvatarPrimitive.Image.displayName
const AvatarFallback = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Fallback>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
>(({className, ...props}, ref) => (
<AvatarPrimitive.Fallback
ref={ref}
className={cn(
"flex h-full w-full items-center justify-center rounded-full bg-slate-100 dark:bg-slate-800",
className
)}
{...props}
/>
))
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
export {Avatar, AvatarImage, AvatarFallback}
+56
View File
@@ -0,0 +1,56 @@
import * as React from "react"
import {Slot} from "@radix-ui/react-slot"
import {cva, type VariantProps} from "class-variance-authority"
import {cn} from "Frontend/@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-slate-950 dark:focus-visible:ring-slate-300",
{
variants: {
variant: {
default: "bg-slate-900 text-slate-50 hover:bg-slate-900/90 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50/90",
destructive:
"bg-red-500 text-slate-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-slate-50 dark:hover:bg-red-900/90",
outline:
"border border-slate-200 bg-white hover:bg-slate-100 hover:text-slate-900 dark:border-slate-800 dark:bg-slate-950 dark:hover:bg-slate-800 dark:hover:text-slate-50",
secondary:
"bg-slate-100 text-slate-900 hover:bg-slate-100/80 dark:bg-slate-800 dark:text-slate-50 dark:hover:bg-slate-800/80",
ghost: "hover:bg-slate-100 hover:text-slate-900 dark:hover:bg-slate-800 dark:hover:text-slate-50",
link: "text-slate-900 underline-offset-4 hover:underline dark:text-slate-50",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({className, variant, size, asChild = false, ...props}, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({variant, size, className}))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
export {Button, buttonVariants}
+79
View File
@@ -0,0 +1,79 @@
import * as React from "react"
import {cn} from "Frontend/@/lib/utils"
const Card = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({className, ...props}, ref) => (
<div
ref={ref}
className={cn(
"rounded-lg border border-slate-200 bg-white text-slate-950 shadow-sm dark:border-slate-800 dark:bg-slate-950 dark:text-slate-50",
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<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({className, ...props}, ref) => (
<h3
ref={ref}
className={cn(
"text-2xl font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
))
CardTitle.displayName = "CardTitle"
const CardDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({className, ...props}, ref) => (
<p
ref={ref}
className={cn("text-sm text-slate-500 dark:text-slate-400", 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}
+198
View File
@@ -0,0 +1,198 @@
import * as React from "react"
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
import {Check, ChevronRight, Circle} from "lucide-react"
import {cn} from "Frontend/@/lib/utils"
const DropdownMenu = DropdownMenuPrimitive.Root
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
const DropdownMenuGroup = DropdownMenuPrimitive.Group
const DropdownMenuPortal = DropdownMenuPrimitive.Portal
const DropdownMenuSub = DropdownMenuPrimitive.Sub
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
const DropdownMenuSubTrigger = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
inset?: boolean
}
>(({className, inset, children, ...props}, ref) => (
<DropdownMenuPrimitive.SubTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-slate-100 data-[state=open]:bg-slate-100 dark:focus:bg-slate-800 dark:data-[state=open]:bg-slate-800",
inset && "pl-8",
className
)}
{...props}
>
{children}
<ChevronRight className="ml-auto h-4 w-4"/>
</DropdownMenuPrimitive.SubTrigger>
))
DropdownMenuSubTrigger.displayName =
DropdownMenuPrimitive.SubTrigger.displayName
const DropdownMenuSubContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
>(({className, ...props}, ref) => (
<DropdownMenuPrimitive.SubContent
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border border-slate-200 bg-white p-1 text-slate-950 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 dark:border-slate-800 dark:bg-slate-950 dark:text-slate-50",
className
)}
{...props}
/>
))
DropdownMenuSubContent.displayName =
DropdownMenuPrimitive.SubContent.displayName
const DropdownMenuContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
>(({className, sideOffset = 4, ...props}, ref) => (
<DropdownMenuPrimitive.Portal>
<DropdownMenuPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border border-slate-200 bg-white p-1 text-slate-950 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 dark:border-slate-800 dark:bg-slate-950 dark:text-slate-50",
className
)}
{...props}
/>
</DropdownMenuPrimitive.Portal>
))
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
const DropdownMenuItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean
}
>(({className, inset, ...props}, ref) => (
<DropdownMenuPrimitive.Item
ref={ref}
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-slate-100 focus:text-slate-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-800 dark:focus:text-slate-50",
inset && "pl-8",
className
)}
{...props}
/>
))
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
const DropdownMenuCheckboxItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
>(({className, children, checked, ...props}, ref) => (
<DropdownMenuPrimitive.CheckboxItem
ref={ref}
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-slate-100 focus:text-slate-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-800 dark:focus:text-slate-50",
className
)}
checked={checked}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<Check className="h-4 w-4"/>
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.CheckboxItem>
))
DropdownMenuCheckboxItem.displayName =
DropdownMenuPrimitive.CheckboxItem.displayName
const DropdownMenuRadioItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
>(({className, children, ...props}, ref) => (
<DropdownMenuPrimitive.RadioItem
ref={ref}
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-slate-100 focus:text-slate-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-800 dark:focus:text-slate-50",
className
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<Circle className="h-2 w-2 fill-current"/>
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.RadioItem>
))
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
const DropdownMenuLabel = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
inset?: boolean
}
>(({className, inset, ...props}, ref) => (
<DropdownMenuPrimitive.Label
ref={ref}
className={cn(
"px-2 py-1.5 text-sm font-semibold",
inset && "pl-8",
className
)}
{...props}
/>
))
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
const DropdownMenuSeparator = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
>(({className, ...props}, ref) => (
<DropdownMenuPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-slate-100 dark:bg-slate-800", className)}
{...props}
/>
))
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
const DropdownMenuShortcut = ({
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props}
/>
)
}
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
export {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuCheckboxItem,
DropdownMenuRadioItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuGroup,
DropdownMenuPortal,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuRadioGroup,
}
+26
View File
@@ -0,0 +1,26 @@
import * as React from "react"
import {cn} from "Frontend/@/lib/utils"
export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {
}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({className, type, ...props}, ref) => {
return (
<input
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-slate-200 bg-white px-3 py-2 text-sm ring-offset-white file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-slate-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-800 dark:bg-slate-950 dark:ring-offset-slate-950 dark:placeholder:text-slate-400 dark:focus-visible:ring-slate-300",
className
)}
ref={ref}
{...props}
/>
)
}
)
Input.displayName = "Input"
export {Input}
+24
View File
@@ -0,0 +1,24 @@
import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import {cva, type VariantProps} from "class-variance-authority"
import {cn} from "Frontend/@/lib/utils"
const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
)
const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
VariantProps<typeof labelVariants>
>(({className, ...props}, ref) => (
<LabelPrimitive.Root
ref={ref}
className={cn(labelVariants(), className)}
{...props}
/>
))
Label.displayName = LabelPrimitive.Root.displayName
export {Label}
+28
View File
@@ -0,0 +1,28 @@
import * as React from "react"
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
import {cn} from "Frontend/@/lib/utils"
const TooltipProvider = TooltipPrimitive.Provider
const Tooltip = TooltipPrimitive.Root
const TooltipTrigger = TooltipPrimitive.Trigger
const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({className, sideOffset = 4, ...props}, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md border border-slate-200 bg-white px-3 py-1.5 text-sm text-slate-950 shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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 dark:border-slate-800 dark:bg-slate-950 dark:text-slate-50",
className
)}
{...props}
/>
))
TooltipContent.displayName = TooltipPrimitive.Content.displayName
export {Tooltip, TooltipTrigger, TooltipContent, TooltipProvider}
+1 -1
View File
@@ -1,7 +1,7 @@
import {useAtom} from "jotai"
import {atomWithStorage} from "jotai/utils"
import {Theme} from "@/registry/themes"
import {Theme} from "Frontend/@/registry/themes"
type Config = {
theme: Theme["name"]
+7 -2
View File
@@ -2,15 +2,20 @@ import router from 'Frontend/routes.js';
import {AuthProvider} from 'Frontend/util/auth.js';
import {RouterProvider} from 'react-router-dom';
import "./main.css";
import {ThemeProvider} from "@material-tailwind/react";
import {IconContext} from "@phosphor-icons/react";
import {StrictMode} from "react";
import {ThemeProvider} from "Frontend/@/components/theme-provider";
export default function App() {
return (
<StrictMode>
<AuthProvider>
<ThemeProvider>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
<IconContext.Provider value={{size: 20}}>
<RouterProvider router={router}/>
</IconContext.Provider>
+10 -13
View File
@@ -1,6 +1,7 @@
import {useField} from "formik";
import {Input as MaterialInput, Typography} from "@material-tailwind/react";
import {XCircle} from "@phosphor-icons/react";
import {Input as ShadcnInput} from "Frontend/@/components/ui/input";
import {Label} from "Frontend/@/components/ui/label";
// @ts-ignore
const Input = ({label, ...props}) => {
@@ -8,25 +9,21 @@ const Input = ({label, ...props}) => {
const [field, meta] = useField(props);
return (
<>
<MaterialInput
<div className="grid w-full max-w-sm items-center gap-1.5">
<Label htmlFor={label}>{label}</Label>
<ShadcnInput
{...props}
{...field}
label={label}
error={meta.touched && !!meta.error}
success={meta.touched && !meta.error}
crossOrigin=""
id={label}
/>
{(meta.touched && !!meta.error) ?
<Typography
variant="small"
color="red"
className="ml-3 -mt-5 flex flex-row items-center gap-1"
<small
className="flex flex-row items-center gap-1 text-red-500"
>
<XCircle weight="fill" size={14}/> {meta.error}
</Typography> : <></>
</small> : <></>
}
</>
</div>
);
}
+19 -29
View File
@@ -1,9 +1,14 @@
import {useState} from "react";
import {Button, Menu, MenuHandler, MenuItem, MenuList} from "@material-tailwind/react";
import {useAuth} from "Frontend/util/auth";
import {Avatar} from "@hilla/react-components/Avatar";
import {useNavigate} from "react-router-dom";
import {CaretDown, CaretUp, GearFine, IconContext, Question, SignOut, User} from "@phosphor-icons/react";
import {GearFine, Question, SignOut, User} from "@phosphor-icons/react";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger
} from "Frontend/@/components/ui/dropdown-menu";
import {Avatar, AvatarFallback} from "Frontend/@/components/ui/avatar";
export default function ProfileMenu() {
const [isMenuOpen, setIsMenuOpen] = useState(false);
@@ -36,38 +41,23 @@ export default function ProfileMenu() {
];
return (
<Menu open={isMenuOpen} handler={setIsMenuOpen} placement="bottom-end">
<MenuHandler>
<Button
variant="text"
className="flex items-center gap-1 rounded-full py-0.5 pr-2 pl-0.5 lg:ml-auto"
>
<Avatar
name={state.user?.name}
abbr={state.user?.name?.substring(0, 2)}
/>
<IconContext.Provider value={{size: 12}}>
{isMenuOpen ? <CaretUp/> : <CaretDown/>}
</IconContext.Provider>
</Button>
</MenuHandler>
<MenuList className="p-1">
<DropdownMenu open={isMenuOpen}>
<DropdownMenuTrigger>
<Avatar>
<AvatarFallback>{state.user?.name?.substring(0, 2).toUpperCase()}</AvatarFallback>
</Avatar>
</DropdownMenuTrigger>
<DropdownMenuContent>
{profileMenuItems.map(({label, icon, onClick, showIf, color}) => {
return (
(showIf === undefined || showIf === true) ?
<MenuItem
key={label}
onClick={onClick}
className={`flex items-center gap-2 rounded ${
color ? `hover:${color}/10 focus:${color}/10 active:${color}/10` : ""
}`}
>
<DropdownMenuItem key={label} onClick={onClick}>
{icon}
<p color={color ? color : ""}>{label}</p>
</MenuItem> : null
</DropdownMenuItem> : null
);
})}
</MenuList>
</Menu>
</DropdownMenuContent>
</DropdownMenu>
);
}
-10
View File
@@ -1,10 +0,0 @@
export class Theme {
constructor(
public readonly name: string,
public readonly background: string,
public readonly primary: string,
public readonly secondary?: string,
public readonly tertiary?: string
) {
}
}
+3 -4
View File
@@ -1,11 +1,10 @@
import {Theme} from "Frontend/components/theming/Theme";
import {Typography} from "@material-tailwind/react";
import {Theme} from "Frontend/@/registry/themes";
export default function ThemePreview({theme}: { theme: Theme }) {
return (
<div className="flex flex-col items-center">
<svg width="228" height="120" viewBox="0 0 228 120" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="background" d="M0 0H228V120H0V0Z" fill={theme.background}/>
<path id="background" d="M0 0H228V120H0V0Z" fill={theme.cssVars.dark.background}/>
<rect id="background-secondary" x="29" y="54" width="144" height="53" rx="2" fill="#30363D"/>
<rect x="184" y="54" width="32" height="36" rx="2" fill="#30363D"/>
<rect opacity="0.3" x="29" y="59" width="144" height="12" fill="#2EA043"/>
@@ -18,7 +17,7 @@ export default function ThemePreview({theme}: { theme: Theme }) {
<rect x="53" y="9" width="32" height="6" rx="3" fill="#8B949E"/>
<rect x="93" y="9" width="32" height="6" rx="3" fill="#8B949E"/>
</svg>
<Typography variant="paragraph">{theme.name}</Typography>
<p>{theme.name}</p>
</div>
);
}
@@ -1,24 +0,0 @@
"use client"
import * as React from "react"
import {useConfig} from "@/hooks/use-config"
export function ThemeSwitcher() {
const [config] = useConfig()
React.useEffect(() => {
document.body.classList.forEach((className) => {
if (className.match(/^theme.*/)) {
document.body.classList.remove(className)
}
})
const theme = segment === "themes" ? config.theme : null
if (theme) {
return document.body.classList.add(`theme-${theme}`)
}
}, [segment, config])
return null
}
-20
View File
@@ -1,20 +0,0 @@
import {Theme} from "Frontend/components/theming/Theme";
export class Themes {
public static LIGHT_DEFAULT = new Theme(
"Light default",
"#ffffff",
"#000000"
)
public static DARK_DEFAULT = new Theme(
"Dark default",
"#161B22",
"#ffffff"
)
public static all = [
Themes.LIGHT_DEFAULT,
Themes.DARK_DEFAULT
];
}
+6 -8
View File
@@ -1,7 +1,7 @@
import React, {ReactNode, useState} from "react";
import {Form, Formik, FormikBag, FormikHelpers} from "formik";
import {Button, Spinner, Step, Stepper} from "@material-tailwind/react";
import {ArrowLeft, ArrowRight, Check} from "@phosphor-icons/react";
import {ArrowLeft, ArrowRight, Check, SpinnerGap} from "@phosphor-icons/react";
import {Button} from "Frontend/@/components/ui/button";
const Wizard = ({children, initialValues, onSubmit}: {
children: ReactNode,
@@ -51,16 +51,14 @@ const Wizard = ({children, initialValues, onSubmit}: {
{formik => (
<Form className="flex flex-col grow">
<div className="w-full mb-8">
<Stepper
activeStep={stepNumber}
>
<p>Step {stepNumber + 1} of {steps.length}</p>
{/*<Stepper activeStep={stepNumber}>
{steps.map((child, index) => (
<Step key={index}>
{/*// @ts-ignore*/}
{child.props.icon}
</Step>
))}
</Stepper>
</Stepper>*/}
</div>
<div className="flex grow">
{step}
@@ -76,7 +74,7 @@ const Wizard = ({children, initialValues, onSubmit}: {
type="submit"
>
{formik.isSubmitting ?
<Spinner className="size-5"/> : isLastStep ? <Check/> : <ArrowRight/>
<SpinnerGap className="animate-spin"/> : isLastStep ? <Check/> : <ArrowRight/>
}
</Button>
</div>
+1 -4
View File
@@ -8,7 +8,4 @@ export default function WizardStep({children, icon, validationSchema}: {
onSubmit?: (...values: any) => Promise<void>
}) {
return children;
}
//const WizardStep = ({children}: { children: Component }) => children;
//export default WizardStep;
}
+20 -30
View File
@@ -1,8 +1,11 @@
import {useAuth} from "Frontend/util/auth";
import {useState} from "react";
import {Link, useNavigate} from "react-router-dom";
import {Alert, Button, Card, Input, Spinner, Typography} from "@material-tailwind/react";
import {XCircle} from "@phosphor-icons/react";
import {SpinnerGap, XCircle} from "@phosphor-icons/react";
import {Card} from "Frontend/@/components/ui/card";
import {Alert, AlertDescription, AlertTitle} from "Frontend/@/components/ui/alert";
import {Button} from "Frontend/@/components/ui/button";
import {Input} from "Frontend/@/components/ui/input";
export default function LoginView() {
const {state, login} = useAuth();
@@ -19,21 +22,20 @@ export default function LoginView() {
}
return (
<div className="flex h-screen">
<div className="fixed h-full w-full bg-gradient-to-br from-gf-primary to-gf-secondary"></div>
<Card className="m-auto p-12" shadow={true}>
<div className="flex size-full bg-gradient-to-br from-gf-primary to-gf-secondary">
<Card className="m-auto p-12">
<img
className="h-28 w-full content-center"
src="/images/Logo.svg"
/>
<div className="mt-8 mb-2 w-80 max-w-screen-lg sm:w-96">
{hasError &&
<Alert
icon={<XCircle color="white" weight="fill"/>}
className="mb-4 bg-red-500"
>
Wrong username and/or password
</Alert>}
<Alert className="mb-4" variant="destructive">
<XCircle weight="fill" className="size-4"/>
<AlertTitle>Error</AlertTitle>
<AlertDescription>Wrong username and/or password</AlertDescription>
</Alert>
}
<form
className="mb-1 flex flex-col gap-6"
onSubmit={async e => {
@@ -51,44 +53,32 @@ export default function LoginView() {
}}
>
<label htmlFor="username">
<Typography variant="h6" color="blue-gray" className="-mb-3">
<h6 color="blue-gray" className="-mb-3">
Username
</Typography>
</h6>
</label>
<Input
onChange={(event) => {
onChange={(event: any) => {
setUsername(event.target.value);
}}
id="username"
type="text"
autoComplete="username"
placeholder=""
size="lg"
className=" !border-t-blue-gray-200 focus:!border-t-gray-900"
labelProps={{
className: "before:content-none after:content-none",
}}
crossOrigin="" //TODO: see https://github.com/creativetimofficial/material-tailwind/issues/427
/>
<label htmlFor="current-password">
<Typography variant="h6" color="blue-gray" className="-mb-3">
<h6 color="blue-gray" className="-mb-3">
Password
</Typography>
</h6>
</label>
<Input
onChange={(event) => {
onChange={(event: any) => {
setPassword(event.target.value);
}}
id="current-password"
type="password"
autoComplete="current-password"
placeholder=""
size="lg"
className=" !border-t-blue-gray-200 focus:!border-t-gray-900"
labelProps={{
className: "before:content-none after:content-none",
}}
crossOrigin="" //TODO: see https://github.com/creativetimofficial/material-tailwind/issues/427
/>
<div className="flex justify-between items-center">
<Link to="#">Forgot password?</Link>
@@ -98,7 +88,7 @@ export default function LoginView() {
className="w-28 h-12 flex justify-center"
disabled={loading}
>
{loading ? <Spinner className="h-6 w-6"/> : "Log in"}
{loading ? <SpinnerGap className="size-6 animate-spin"/> : "Log in"}
</Button>
</div>
</form>
+3 -3
View File
@@ -1,8 +1,8 @@
import {useRouteMetadata} from 'Frontend/util/routing.js';
import {useEffect} from 'react';
import {Navbar} from "@material-tailwind/react";
import ProfileMenu from "Frontend/components/ProfileMenu";
import {Outlet} from "react-router-dom";
import {Card} from "Frontend/@/components/ui/card";
export default function MainLayout() {
const currentTitle = `Gameyfin - ${useRouteMetadata()?.title}` ?? 'Gameyfin';
@@ -12,7 +12,7 @@ export default function MainLayout() {
return (
<>
<Navbar className="sticky top-0 z-10 h-max max-w-full rounded-none px-4 py-2">
<Card className="sticky top-0 z-10 h-max max-w-full rounded-none px-4 py-2">
<div className="flex items-center justify-end text-blue-gray-900">
<img
className="absolute w-full content-center h-8"
@@ -21,7 +21,7 @@ export default function MainLayout() {
/>
<ProfileMenu/>
</div>
</Navbar>
</Card>
<Outlet/>
</>
+12 -13
View File
@@ -2,11 +2,11 @@ import React from 'react';
import * as Yup from 'yup';
import Wizard from "Frontend/components/wizard/Wizard";
import WizardStep from "Frontend/components/wizard/WizardStep";
import {Card, Typography} from "@material-tailwind/react";
import Input from "Frontend/components/Input";
import {GearFine, HandWaving, Palette, User} from "@phosphor-icons/react";
import {Themes} from "Frontend/components/theming/Themes";
import ThemePreview from "Frontend/components/theming/ThemePreview";
import {Theme, themes} from "Frontend/@/registry/themes";
import {Card} from "Frontend/@/components/ui/card";
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
@@ -14,7 +14,7 @@ function WelcomeStep() {
return (
<div className="flex flex-col size-full items-center">
<div className="flex flex-col w-1/2 min-w-[468px] gap-12 items-center">
<Typography variant="h4">Welcome to Gameyfin 👋</Typography>
<h4>Welcome to Gameyfin 👋</h4>
<p className="place-content-center text-justify">
Gameyfin is a cutting-edge software tailored for gamers seeking efficient management of their
video
@@ -28,7 +28,7 @@ function WelcomeStep() {
user-friendly
design and adaptability, offering ample customization options to meet diverse user preferences.
</p>
<Typography variant="h5">Let's get started!</Typography>
<h5>Let's get started!</h5>
</div>
</div>
);
@@ -38,7 +38,7 @@ function ThemeStep() {
return (
<div className="flex flex-col size-full items-center">
<div className="size-full grid grid-cols-3 grid-rows-2 w-1/2 min-w-[468px] gap-12 items-center">
{Themes.all.map((theme => (
{themes.map(((theme: Theme) => (
<ThemePreview key={theme.name} theme={theme}/>
)))}
</div>
@@ -50,9 +50,9 @@ function UserStep() {
return (
<div className="flex flex-col size-full items-center">
<div className="flex flex-col w-1/2 min-w-[468px] gap-12 items-center">
<Typography variant="h4">Create your account</Typography>
<Typography className="-mt-8">This will set up the initial admin user account.</Typography>
<div className="mb-1 flex flex-col w-full gap-6">
<h4>Create your account</h4>
<p className="-mt-8">This will set up the initial admin user account.</p>
<div className="mb-1 flex flex-col w-full gap-6 items-center">
<Input
label="Username"
name="username"
@@ -78,17 +78,16 @@ function SettingsStep() {
return (
<div className="flex flex-col size-full items-center">
<div className="flex flex-col w-1/2 min-w-[468px] gap-12 items-center">
<Typography variant="h4">Settings</Typography>
<Typography>Configure your settings</Typography>
<h4>Settings</h4>
<p>Configure your settings</p>
</div>
</div>
);
}
const SetupView = () => (
<div className="flex h-screen">
<div className="fixed size-full bg-gradient-to-br from-gf-primary to-gf-secondary"></div>
<Card className="w-3/4 h-3/4 min-w-[500px] m-auto p-8" shadow={true}>
<div className="flex size-full bg-gradient-to-br from-gf-primary to-gf-secondary">
<Card className="w-3/4 h-3/4 min-w-[500px] m-auto p-8">
<Wizard
initialValues={{username: '', password: '', passwordRepeat: ''}}
onSubmit={async (values: any) =>
+824 -8
View File
@@ -25,6 +25,11 @@
"@hilla/react-form": "2.5.6",
"@phosphor-icons/react": "^2.0.15",
"@polymer/polymer": "3.5.1",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tooltip": "^1.0.7",
"@vaadin/bundles": "24.3.0",
"@vaadin/common-frontend": "0.0.19",
"@vaadin/router": "1.7.5",
@@ -36,6 +41,7 @@
"jotai": "^2.7.1",
"lit": "3.1.0",
"lucide-react": "^0.360.0",
"next-themes": "^0.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.4.2",
@@ -2200,6 +2206,40 @@
"node": ">=12"
}
},
"node_modules/@floating-ui/core": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz",
"integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==",
"dependencies": {
"@floating-ui/utils": "^0.2.1"
}
},
"node_modules/@floating-ui/dom": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz",
"integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==",
"dependencies": {
"@floating-ui/core": "^1.0.0",
"@floating-ui/utils": "^0.2.0"
}
},
"node_modules/@floating-ui/react-dom": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz",
"integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==",
"dependencies": {
"@floating-ui/dom": "^1.6.1"
},
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/@floating-ui/utils": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz",
"integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q=="
},
"node_modules/@hilla/form": {
"version": "2.5.6",
"resolved": "https://registry.npmjs.org/@hilla/form/-/form-2.5.6.tgz",
@@ -2814,6 +2854,641 @@
"@webcomponents/shadycss": "^1.9.1"
}
},
"node_modules/@radix-ui/primitive": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz",
"integrity": "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==",
"dependencies": {
"@babel/runtime": "^7.13.10"
}
},
"node_modules/@radix-ui/react-arrow": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.3.tgz",
"integrity": "sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-primitive": "1.0.3"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-avatar": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.0.4.tgz",
"integrity": "sha512-kVK2K7ZD3wwj3qhle0ElXhOjbezIgyl2hVvgwfIdexL3rN6zJmy5AqqIf+D31lxVppdzV8CjAfZ6PklkmInZLw==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-callback-ref": "1.0.1",
"@radix-ui/react-use-layout-effect": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collection": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz",
"integrity": "sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-slot": "1.0.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-compose-refs": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz",
"integrity": "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-context": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.1.tgz",
"integrity": "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-direction": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz",
"integrity": "sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-dismissable-layer": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz",
"integrity": "sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-callback-ref": "1.0.1",
"@radix-ui/react-use-escape-keydown": "1.0.3"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-dropdown-menu": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.6.tgz",
"integrity": "sha512-i6TuFOoWmLWq+M/eCLGd/bQ2HfAX1RJgvrBQ6AQLmzfvsLdefxbWu8G9zczcPFfcSPehz9GcpF6K9QYreFV8hA==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-id": "1.0.1",
"@radix-ui/react-menu": "2.0.6",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-controllable-state": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-focus-guards": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz",
"integrity": "sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-focus-scope": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz",
"integrity": "sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-callback-ref": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-id": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.1.tgz",
"integrity": "sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-use-layout-effect": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-label": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.0.2.tgz",
"integrity": "sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-primitive": "1.0.3"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-menu": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.0.6.tgz",
"integrity": "sha512-BVkFLS+bUC8HcImkRKPSiVumA1VPOOEC5WBMiT+QAVsPzW1FJzI9KnqgGxVDPBcql5xXrHkD3JOVoXWEXD8SYA==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-collection": "1.0.3",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-direction": "1.0.1",
"@radix-ui/react-dismissable-layer": "1.0.5",
"@radix-ui/react-focus-guards": "1.0.1",
"@radix-ui/react-focus-scope": "1.0.4",
"@radix-ui/react-id": "1.0.1",
"@radix-ui/react-popper": "1.1.3",
"@radix-ui/react-portal": "1.0.4",
"@radix-ui/react-presence": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-roving-focus": "1.0.4",
"@radix-ui/react-slot": "1.0.2",
"@radix-ui/react-use-callback-ref": "1.0.1",
"aria-hidden": "^1.1.1",
"react-remove-scroll": "2.5.5"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popper": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.3.tgz",
"integrity": "sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@floating-ui/react-dom": "^2.0.0",
"@radix-ui/react-arrow": "1.0.3",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-callback-ref": "1.0.1",
"@radix-ui/react-use-layout-effect": "1.0.1",
"@radix-ui/react-use-rect": "1.0.1",
"@radix-ui/react-use-size": "1.0.1",
"@radix-ui/rect": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-portal": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.4.tgz",
"integrity": "sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-primitive": "1.0.3"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-presence": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.1.tgz",
"integrity": "sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-use-layout-effect": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-primitive": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz",
"integrity": "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-slot": "1.0.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-roving-focus": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz",
"integrity": "sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-collection": "1.0.3",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-direction": "1.0.1",
"@radix-ui/react-id": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-callback-ref": "1.0.1",
"@radix-ui/react-use-controllable-state": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-slot": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
"integrity": "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-tooltip": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.7.tgz",
"integrity": "sha512-lPh5iKNFVQ/jav/j6ZrWq3blfDJ0OH9R6FlNUHPMqdLuQ9vwDgFsRxvl8b7Asuy5c8xmoojHUxKHQSOAvMHxyw==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-dismissable-layer": "1.0.5",
"@radix-ui/react-id": "1.0.1",
"@radix-ui/react-popper": "1.1.3",
"@radix-ui/react-portal": "1.0.4",
"@radix-ui/react-presence": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-slot": "1.0.2",
"@radix-ui/react-use-controllable-state": "1.0.1",
"@radix-ui/react-visually-hidden": "1.0.3"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-callback-ref": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz",
"integrity": "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-controllable-state": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz",
"integrity": "sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-use-callback-ref": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-escape-keydown": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz",
"integrity": "sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-use-callback-ref": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-layout-effect": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz",
"integrity": "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-rect": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.0.1.tgz",
"integrity": "sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/rect": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-size": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.0.1.tgz",
"integrity": "sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-use-layout-effect": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-visually-hidden": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.3.tgz",
"integrity": "sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-primitive": "1.0.3"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/rect": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.1.tgz",
"integrity": "sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==",
"dependencies": {
"@babel/runtime": "^7.13.10"
}
},
"node_modules/@remix-run/router": {
"version": "1.15.3",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz",
@@ -4871,6 +5546,17 @@
"sprintf-js": "~1.0.2"
}
},
"node_modules/aria-hidden": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz",
"integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==",
"dependencies": {
"tslib": "^2.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/array-buffer-byte-length": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz",
@@ -5334,14 +6020,6 @@
"url": "https://joebell.co.uk"
}
},
"node_modules/class-variance-authority/node_modules/clsx": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
"integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==",
"engines": {
"node": ">=6"
}
},
"node_modules/classnames": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
@@ -5748,6 +6426,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/detect-node-es": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
},
"node_modules/didyoumean": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
@@ -6333,6 +7016,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-nonce": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
"integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
"engines": {
"node": ">=6"
}
},
"node_modules/get-own-enumerable-property-symbols": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz",
@@ -6674,6 +7365,14 @@
"node": ">= 0.4"
}
},
"node_modules/invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/is-array-buffer": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
@@ -7766,6 +8465,15 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/next-themes": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz",
"integrity": "sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==",
"peerDependencies": {
"react": "^16.8 || ^17 || ^18",
"react-dom": "^16.8 || ^17 || ^18"
}
},
"node_modules/node-releases": {
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
@@ -8524,6 +9232,51 @@
"node": ">=0.10.0"
}
},
"node_modules/react-remove-scroll": {
"version": "2.5.5",
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz",
"integrity": "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==",
"dependencies": {
"react-remove-scroll-bar": "^2.3.3",
"react-style-singleton": "^2.2.1",
"tslib": "^2.1.0",
"use-callback-ref": "^1.3.0",
"use-sidecar": "^1.1.2"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/react-remove-scroll-bar": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz",
"integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==",
"dependencies": {
"react-style-singleton": "^2.2.1",
"tslib": "^2.0.0"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/react-router": {
"version": "6.22.3",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz",
@@ -8554,6 +9307,28 @@
"react-dom": ">=16.8"
}
},
"node_modules/react-style-singleton": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz",
"integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==",
"dependencies": {
"get-nonce": "^1.0.0",
"invariant": "^2.2.4",
"tslib": "^2.0.0"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@@ -10017,6 +10792,47 @@
"punycode": "^2.1.0"
}
},
"node_modules/use-callback-ref": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz",
"integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==",
"dependencies": {
"tslib": "^2.0.0"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/use-sidecar": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz",
"integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==",
"dependencies": {
"detect-node-es": "^1.1.0",
"tslib": "^2.0.0"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+20 -2
View File
@@ -20,6 +20,11 @@
"@hilla/react-form": "2.5.6",
"@phosphor-icons/react": "^2.0.15",
"@polymer/polymer": "3.5.1",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tooltip": "^1.0.7",
"@vaadin/bundles": "24.3.0",
"@vaadin/common-frontend": "0.0.19",
"@vaadin/router": "1.7.5",
@@ -31,6 +36,7 @@
"jotai": "^2.7.1",
"lit": "3.1.0",
"lucide-react": "^0.360.0",
"next-themes": "^0.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.4.2",
@@ -90,7 +96,19 @@
"@hilla/generator-typescript-cli": "$@hilla/generator-typescript-cli",
"@phosphor-icons/react": "$@phosphor-icons/react",
"formik": "$formik",
"yup": "$yup"
"yup": "$yup",
"class-variance-authority": "$class-variance-authority",
"clsx": "$clsx",
"jotai": "$jotai",
"lucide-react": "$lucide-react",
"next-themes": "$next-themes",
"tailwind-merge": "$tailwind-merge",
"tailwindcss-animate": "$tailwindcss-animate",
"@radix-ui/react-label": "$@radix-ui/react-label",
"@radix-ui/react-slot": "$@radix-ui/react-slot",
"@radix-ui/react-avatar": "$@radix-ui/react-avatar",
"@radix-ui/react-dropdown-menu": "$@radix-ui/react-dropdown-menu",
"@radix-ui/react-tooltip": "$@radix-ui/react-tooltip"
},
"vaadin": {
"dependencies": {
@@ -134,6 +152,6 @@
"workbox-core": "7.0.0",
"workbox-precaching": "7.0.0"
},
"hash": "9223d4c6f4cf3a6fd28b853d824fddc00718dbc1a3474e986f4dc2d69f294b6e"
"hash": "54c9ffc1de2ff554baf5ced1be2e704d4a354138bf9cbfca2d4fc83f126a4563"
}
}
+5 -4
View File
@@ -1,6 +1,7 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: ["class"],
import {Config} from "tailwindcss/types/config";
export default {
darkMode: "class",
content: [
'./frontend/index.html',
'./frontend/**/*.{js,ts,jsx,tsx}',
@@ -40,4 +41,4 @@ module.exports = {
},
},
plugins: [require("tailwindcss-animate")],
}
} satisfies Config;
+9 -3
View File
@@ -24,9 +24,15 @@
"useDefineForClassFields": false,
"baseUrl": "frontend",
"paths": {
"@vaadin/flow-frontend": ["generated/jar-resources"],
"@vaadin/flow-frontend/*": ["generated/jar-resources/*"],
"Frontend/*": ["*"]
"@vaadin/flow-frontend": [
"generated/jar-resources"
],
"@vaadin/flow-frontend/*": [
"generated/jar-resources/*"
],
"Frontend/*": [
"*"
]
}
},
"include": [
+15 -9
View File
@@ -1,15 +1,21 @@
import reactSwc from '@vitejs/plugin-react-swc';
import type { UserConfigFn } from 'vite';
import { overrideVaadinConfig } from './vite.generated';
import type {UserConfigFn} from 'vite';
import {overrideVaadinConfig} from './vite.generated';
import path from "path";
const customConfig: UserConfigFn = (env) => ({
// Here you can add custom Vite parameters
// https://vitejs.dev/config/
plugins: [
reactSwc({
tsDecorators: true,
}),
],
// Here you can add custom Vite parameters
// https://vitejs.dev/config/
plugins: [
reactSwc({
tsDecorators: true,
}),
],
resolve: {
alias: {
"@": path.resolve(__dirname, "./frontend"),
},
},
});
export default overrideVaadinConfig(customConfig);