mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-13 16:40:01 +00:00
Finish theming implementation (finally...)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="UI debug" type="JavascriptDebugType" uri="http://localhost:8080" useFirstLineBreakpoints="true">
|
||||
<configuration default="false" name="UI debug" type="JavascriptDebugType" engineId="37cae5b9-e8b2-4949-9172-aafa37fbc09c" uri="http://localhost:8080" useFirstLineBreakpoints="true">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,16 +0,0 @@
|
||||
import * as React from "react"
|
||||
import {Provider as JotaiProvider} from "jotai"
|
||||
import {ThemeProvider as NextThemesProvider} from "next-themes"
|
||||
import {ThemeProviderProps} from "next-themes/dist/types"
|
||||
import {TooltipProvider} from "Frontend/@/components/ui/tooltip";
|
||||
|
||||
|
||||
export function ThemeProvider({children, ...props}: ThemeProviderProps) {
|
||||
return (
|
||||
<JotaiProvider>
|
||||
<NextThemesProvider {...props}>
|
||||
<TooltipProvider delayDuration={0}>{children}</TooltipProvider>
|
||||
</NextThemesProvider>
|
||||
</JotaiProvider>
|
||||
)
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import * as React from "react"
|
||||
import {cva, type VariantProps} from "class-variance-authority"
|
||||
|
||||
import {cn} from "Frontend/@/lib/utils"
|
||||
import {cn} from "Frontend/util/utils";
|
||||
|
||||
const alertVariants = cva(
|
||||
"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
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-muted",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
|
||||
|
||||
export {Avatar, AvatarImage, AvatarFallback}
|
||||
@@ -1,58 +0,0 @@
|
||||
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 transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-9 px-4 py-2",
|
||||
sm: "h-8 rounded-md px-3 text-xs",
|
||||
lg: "h-10 rounded-md px-8",
|
||||
icon: "h-9 w-9",
|
||||
},
|
||||
},
|
||||
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}
|
||||
type="button"
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Button.displayName = "Button"
|
||||
|
||||
export {Button, buttonVariants}
|
||||
@@ -1,79 +0,0 @@
|
||||
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 bg-card text-card-foreground shadow-sm",
|
||||
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-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}
|
||||
@@ -1,199 +0,0 @@
|
||||
import * as React from "react"
|
||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
||||
import {CheckIcon, ChevronRightIcon, DotFilledIcon,} from "@radix-ui/react-icons"
|
||||
|
||||
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-accent data-[state=open]:bg-accent",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRightIcon 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 bg-popover p-1 text-popover-foreground 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",
|
||||
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 bg-popover p-1 text-popover-foreground 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",
|
||||
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-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-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-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<CheckIcon 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-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<DotFilledIcon className="h-4 w-4 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-muted", 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,
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
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-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Input.displayName = "Input"
|
||||
|
||||
export {Input}
|
||||
@@ -1,24 +0,0 @@
|
||||
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}
|
||||
@@ -1,27 +0,0 @@
|
||||
import * as React from "react"
|
||||
import * as SwitchPrimitives from "@radix-ui/react-switch"
|
||||
|
||||
import {cn} from "Frontend/@/lib/utils"
|
||||
|
||||
const Switch = React.forwardRef<
|
||||
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
||||
>(({className, ...props}, ref) => (
|
||||
<SwitchPrimitives.Root
|
||||
className={cn(
|
||||
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
>
|
||||
<SwitchPrimitives.Thumb
|
||||
className={cn(
|
||||
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
|
||||
)}
|
||||
/>
|
||||
</SwitchPrimitives.Root>
|
||||
))
|
||||
Switch.displayName = SwitchPrimitives.Root.displayName
|
||||
|
||||
export {Switch}
|
||||
@@ -1,28 +0,0 @@
|
||||
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 bg-primary px-3 py-1.5 text-xs text-primary-foreground 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",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TooltipContent.displayName = TooltipPrimitive.Content.displayName
|
||||
|
||||
export {Tooltip, TooltipTrigger, TooltipContent, TooltipProvider}
|
||||
@@ -1,22 +0,0 @@
|
||||
import {useAtom} from "jotai"
|
||||
import {atomWithStorage} from "jotai/utils"
|
||||
|
||||
import {Theme} from "@/registry/themes"
|
||||
|
||||
type Config = {
|
||||
theme: {
|
||||
name: Theme["name"],
|
||||
mode: "light" | "dark" | "system"
|
||||
}
|
||||
}
|
||||
|
||||
const configAtom = atomWithStorage<Config>("config", {
|
||||
theme: {
|
||||
name: "zinc",
|
||||
mode: "system"
|
||||
}
|
||||
})
|
||||
|
||||
export function useConfig() {
|
||||
return useAtom(configAtom)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,478 +0,0 @@
|
||||
export const themes = [
|
||||
{
|
||||
name: "zinc",
|
||||
label: "Zinc",
|
||||
activeColor: {
|
||||
light: "240 5.9% 10%",
|
||||
dark: "240 5.2% 33.9%",
|
||||
},
|
||||
cssVars: {
|
||||
light: {
|
||||
background: "0 0% 100%",
|
||||
foreground: "240 10% 3.9%",
|
||||
card: "0 0% 100%",
|
||||
"card-foreground": "240 10% 3.9%",
|
||||
popover: "0 0% 100%",
|
||||
"popover-foreground": "240 10% 3.9%",
|
||||
primary: "240 5.9% 10%",
|
||||
"primary-foreground": "0 0% 98%",
|
||||
secondary: "240 4.8% 95.9%",
|
||||
"secondary-foreground": "240 5.9% 10%",
|
||||
muted: "240 4.8% 95.9%",
|
||||
"muted-foreground": "240 3.8% 46.1%",
|
||||
accent: "240 4.8% 95.9%",
|
||||
"accent-foreground": "240 5.9% 10%",
|
||||
destructive: "0 84.2% 60.2%",
|
||||
"destructive-foreground": "0 0% 98%",
|
||||
border: "240 5.9% 90%",
|
||||
input: "240 5.9% 90%",
|
||||
ring: "240 5.9% 10%",
|
||||
radius: "0.5rem",
|
||||
},
|
||||
dark: {
|
||||
background: "240 10% 3.9%",
|
||||
foreground: "0 0% 98%",
|
||||
card: "240 10% 3.9%",
|
||||
"card-foreground": "0 0% 98%",
|
||||
popover: "240 10% 3.9%",
|
||||
"popover-foreground": "0 0% 98%",
|
||||
primary: "0 0% 98%",
|
||||
"primary-foreground": "240 5.9% 10%",
|
||||
secondary: "240 3.7% 15.9%",
|
||||
"secondary-foreground": "0 0% 98%",
|
||||
muted: "240 3.7% 15.9%",
|
||||
"muted-foreground": "240 5% 64.9%",
|
||||
accent: "240 3.7% 15.9%",
|
||||
"accent-foreground": "0 0% 98%",
|
||||
destructive: "0 62.8% 30.6%",
|
||||
"destructive-foreground": "0 0% 98%",
|
||||
border: "240 3.7% 15.9%",
|
||||
input: "240 3.7% 15.9%",
|
||||
ring: "240 4.9% 83.9%",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "slate",
|
||||
label: "Slate",
|
||||
activeColor: {
|
||||
light: "215.4 16.3% 46.9%",
|
||||
dark: "215.3 19.3% 34.5%",
|
||||
},
|
||||
cssVars: {
|
||||
light: {
|
||||
background: "0 0% 100%",
|
||||
foreground: "222.2 84% 4.9%",
|
||||
card: "0 0% 100%",
|
||||
"card-foreground": "222.2 84% 4.9%",
|
||||
popover: "0 0% 100%",
|
||||
"popover-foreground": "222.2 84% 4.9%",
|
||||
primary: "222.2 47.4% 11.2%",
|
||||
"primary-foreground": "210 40% 98%",
|
||||
secondary: "210 40% 96.1%",
|
||||
"secondary-foreground": "222.2 47.4% 11.2%",
|
||||
muted: "210 40% 96.1%",
|
||||
"muted-foreground": "215.4 16.3% 46.9%",
|
||||
accent: "210 40% 96.1%",
|
||||
"accent-foreground": "222.2 47.4% 11.2%",
|
||||
destructive: "0 84.2% 60.2%",
|
||||
"destructive-foreground": "210 40% 98%",
|
||||
border: "214.3 31.8% 91.4%",
|
||||
input: "214.3 31.8% 91.4%",
|
||||
ring: "222.2 84% 4.9%",
|
||||
radius: "0.5rem",
|
||||
},
|
||||
dark: {
|
||||
background: "222.2 84% 4.9%",
|
||||
foreground: "210 40% 98%",
|
||||
card: "222.2 84% 4.9%",
|
||||
"card-foreground": "210 40% 98%",
|
||||
popover: "222.2 84% 4.9%",
|
||||
"popover-foreground": "210 40% 98%",
|
||||
primary: "210 40% 98%",
|
||||
"primary-foreground": "222.2 47.4% 11.2%",
|
||||
secondary: "217.2 32.6% 17.5%",
|
||||
"secondary-foreground": "210 40% 98%",
|
||||
muted: "217.2 32.6% 17.5%",
|
||||
"muted-foreground": "215 20.2% 65.1%",
|
||||
accent: "217.2 32.6% 17.5%",
|
||||
"accent-foreground": "210 40% 98%",
|
||||
destructive: "0 62.8% 30.6%",
|
||||
"destructive-foreground": "210 40% 98%",
|
||||
border: "217.2 32.6% 17.5%",
|
||||
input: "217.2 32.6% 17.5%",
|
||||
ring: "212.7 26.8% 83.9",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "red",
|
||||
label: "Red",
|
||||
activeColor: {
|
||||
light: "0 72.2% 50.6%",
|
||||
dark: "0 72.2% 50.6%",
|
||||
},
|
||||
cssVars: {
|
||||
light: {
|
||||
background: "0 0% 100%",
|
||||
foreground: "0 0% 3.9%",
|
||||
card: "0 0% 100%",
|
||||
"card-foreground": "0 0% 3.9%",
|
||||
popover: "0 0% 100%",
|
||||
"popover-foreground": "0 0% 3.9%",
|
||||
primary: "0 72.2% 50.6%",
|
||||
"primary-foreground": "0 85.7% 97.3%",
|
||||
secondary: "0 0% 96.1%",
|
||||
"secondary-foreground": "0 0% 9%",
|
||||
muted: "0 0% 96.1%",
|
||||
"muted-foreground": "0 0% 45.1%",
|
||||
accent: "0 0% 96.1%",
|
||||
"accent-foreground": "0 0% 9%",
|
||||
destructive: "0 84.2% 60.2%",
|
||||
"destructive-foreground": "0 0% 98%",
|
||||
border: "0 0% 89.8%",
|
||||
input: "0 0% 89.8%",
|
||||
ring: "0 72.2% 50.6%",
|
||||
radius: "0.4rem",
|
||||
},
|
||||
dark: {
|
||||
background: "0 0% 3.9%",
|
||||
foreground: "0 0% 98%",
|
||||
card: "0 0% 3.9%",
|
||||
"card-foreground": "0 0% 98%",
|
||||
popover: "0 0% 3.9%",
|
||||
"popover-foreground": "0 0% 98%",
|
||||
primary: "0 72.2% 50.6%",
|
||||
"primary-foreground": "0 85.7% 97.3%",
|
||||
secondary: "0 0% 14.9%",
|
||||
"secondary-foreground": "0 0% 98%",
|
||||
muted: "0 0% 14.9%",
|
||||
"muted-foreground": "0 0% 63.9%",
|
||||
accent: "0 0% 14.9%",
|
||||
"accent-foreground": "0 0% 98%",
|
||||
destructive: "0 62.8% 30.6%",
|
||||
"destructive-foreground": "0 0% 98%",
|
||||
border: "0 0% 14.9%",
|
||||
input: "0 0% 14.9%",
|
||||
ring: "0 72.2% 50.6%",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "rose",
|
||||
label: "Rose",
|
||||
activeColor: {
|
||||
light: "346.8 77.2% 49.8%",
|
||||
dark: "346.8 77.2% 49.8%",
|
||||
},
|
||||
cssVars: {
|
||||
light: {
|
||||
background: "0 0% 100%",
|
||||
foreground: "240 10% 3.9%",
|
||||
card: "0 0% 100%",
|
||||
"card-foreground": "240 10% 3.9%",
|
||||
popover: "0 0% 100%",
|
||||
"popover-foreground": "240 10% 3.9%",
|
||||
primary: "346.8 77.2% 49.8%",
|
||||
"primary-foreground": "355.7 100% 97.3%",
|
||||
secondary: "240 4.8% 95.9%",
|
||||
"secondary-foreground": "240 5.9% 10%",
|
||||
muted: "240 4.8% 95.9%",
|
||||
"muted-foreground": "240 3.8% 46.1%",
|
||||
accent: "240 4.8% 95.9%",
|
||||
"accent-foreground": "240 5.9% 10%",
|
||||
destructive: "0 84.2% 60.2%",
|
||||
"destructive-foreground": "0 0% 98%",
|
||||
border: "240 5.9% 90%",
|
||||
input: "240 5.9% 90%",
|
||||
ring: "346.8 77.2% 49.8%",
|
||||
radius: "0.5rem",
|
||||
},
|
||||
dark: {
|
||||
background: "20 14.3% 4.1%",
|
||||
foreground: "0 0% 95%",
|
||||
popover: "0 0% 9%",
|
||||
"popover-foreground": "0 0% 95%",
|
||||
card: "24 9.8% 10%",
|
||||
"card-foreground": "0 0% 95%",
|
||||
primary: "346.8 77.2% 49.8%",
|
||||
"primary-foreground": "355.7 100% 97.3%",
|
||||
secondary: "240 3.7% 15.9%",
|
||||
"secondary-foreground": "0 0% 98%",
|
||||
muted: "0 0% 15%",
|
||||
"muted-foreground": "240 5% 64.9%",
|
||||
accent: "12 6.5% 15.1%",
|
||||
"accent-foreground": "0 0% 98%",
|
||||
destructive: "0 62.8% 30.6%",
|
||||
"destructive-foreground": "0 85.7% 97.3%",
|
||||
border: "240 3.7% 15.9%",
|
||||
input: "240 3.7% 15.9%",
|
||||
ring: "346.8 77.2% 49.8%",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "orange",
|
||||
label: "Orange",
|
||||
activeColor: {
|
||||
light: "24.6 95% 53.1%",
|
||||
dark: "20.5 90.2% 48.2%",
|
||||
},
|
||||
cssVars: {
|
||||
light: {
|
||||
background: "0 0% 100%",
|
||||
foreground: "20 14.3% 4.1%",
|
||||
card: "0 0% 100%",
|
||||
"card-foreground": "20 14.3% 4.1%",
|
||||
popover: "0 0% 100%",
|
||||
"popover-foreground": "20 14.3% 4.1%",
|
||||
primary: "24.6 95% 53.1%",
|
||||
"primary-foreground": "60 9.1% 97.8%",
|
||||
secondary: "60 4.8% 95.9%",
|
||||
"secondary-foreground": "24 9.8% 10%",
|
||||
muted: "60 4.8% 95.9%",
|
||||
"muted-foreground": "25 5.3% 44.7%",
|
||||
accent: "60 4.8% 95.9%",
|
||||
"accent-foreground": "24 9.8% 10%",
|
||||
destructive: "0 84.2% 60.2%",
|
||||
"destructive-foreground": "60 9.1% 97.8%",
|
||||
border: "20 5.9% 90%",
|
||||
input: "20 5.9% 90%",
|
||||
ring: "24.6 95% 53.1%",
|
||||
radius: "0.95rem",
|
||||
},
|
||||
dark: {
|
||||
background: "20 14.3% 4.1%",
|
||||
foreground: "60 9.1% 97.8%",
|
||||
card: "20 14.3% 4.1%",
|
||||
"card-foreground": "60 9.1% 97.8%",
|
||||
popover: "20 14.3% 4.1%",
|
||||
"popover-foreground": "60 9.1% 97.8%",
|
||||
primary: "20.5 90.2% 48.2%",
|
||||
"primary-foreground": "60 9.1% 97.8%",
|
||||
secondary: "12 6.5% 15.1%",
|
||||
"secondary-foreground": "60 9.1% 97.8%",
|
||||
muted: "12 6.5% 15.1%",
|
||||
"muted-foreground": "24 5.4% 63.9%",
|
||||
accent: "12 6.5% 15.1%",
|
||||
"accent-foreground": "60 9.1% 97.8%",
|
||||
destructive: "0 72.2% 50.6%",
|
||||
"destructive-foreground": "60 9.1% 97.8%",
|
||||
border: "12 6.5% 15.1%",
|
||||
input: "12 6.5% 15.1%",
|
||||
ring: "20.5 90.2% 48.2%",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "green",
|
||||
label: "Green",
|
||||
activeColor: {
|
||||
light: "142.1 76.2% 36.3%",
|
||||
dark: "142.1 70.6% 45.3%",
|
||||
},
|
||||
cssVars: {
|
||||
light: {
|
||||
background: "0 0% 100%",
|
||||
foreground: "240 10% 3.9%",
|
||||
card: "0 0% 100%",
|
||||
"card-foreground": "240 10% 3.9%",
|
||||
popover: "0 0% 100%",
|
||||
"popover-foreground": "240 10% 3.9%",
|
||||
primary: "142.1 76.2% 36.3%",
|
||||
"primary-foreground": "355.7 100% 97.3%",
|
||||
secondary: "240 4.8% 95.9%",
|
||||
"secondary-foreground": "240 5.9% 10%",
|
||||
muted: "240 4.8% 95.9%",
|
||||
"muted-foreground": "240 3.8% 46.1%",
|
||||
accent: "240 4.8% 95.9%",
|
||||
"accent-foreground": "240 5.9% 10%",
|
||||
destructive: "0 84.2% 60.2%",
|
||||
"destructive-foreground": "0 0% 98%",
|
||||
border: "240 5.9% 90%",
|
||||
input: "240 5.9% 90%",
|
||||
ring: "142.1 76.2% 36.3%",
|
||||
},
|
||||
dark: {
|
||||
background: "20 14.3% 4.1%",
|
||||
foreground: "0 0% 95%",
|
||||
popover: "0 0% 9%",
|
||||
"popover-foreground": "0 0% 95%",
|
||||
card: "24 9.8% 10%",
|
||||
"card-foreground": "0 0% 95%",
|
||||
primary: "142.1 70.6% 45.3%",
|
||||
"primary-foreground": "144.9 80.4% 10%",
|
||||
secondary: "240 3.7% 15.9%",
|
||||
"secondary-foreground": "0 0% 98%",
|
||||
muted: "0 0% 15%",
|
||||
"muted-foreground": "240 5% 64.9%",
|
||||
accent: "12 6.5% 15.1%",
|
||||
"accent-foreground": "0 0% 98%",
|
||||
destructive: "0 62.8% 30.6%",
|
||||
"destructive-foreground": "0 85.7% 97.3%",
|
||||
border: "240 3.7% 15.9%",
|
||||
input: "240 3.7% 15.9%",
|
||||
ring: "142.4 71.8% 29.2%",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "blue",
|
||||
label: "Blue",
|
||||
activeColor: {
|
||||
light: "221.2 83.2% 53.3%",
|
||||
dark: "217.2 91.2% 59.8%",
|
||||
},
|
||||
cssVars: {
|
||||
light: {
|
||||
background: "0 0% 100%",
|
||||
foreground: "222.2 84% 4.9%",
|
||||
card: "0 0% 100%",
|
||||
"card-foreground": "222.2 84% 4.9%",
|
||||
popover: "0 0% 100%",
|
||||
"popover-foreground": "222.2 84% 4.9%",
|
||||
primary: "221.2 83.2% 53.3%",
|
||||
"primary-foreground": "210 40% 98%",
|
||||
secondary: "210 40% 96.1%",
|
||||
"secondary-foreground": "222.2 47.4% 11.2%",
|
||||
muted: "210 40% 96.1%",
|
||||
"muted-foreground": "215.4 16.3% 46.9%",
|
||||
accent: "210 40% 96.1%",
|
||||
"accent-foreground": "222.2 47.4% 11.2%",
|
||||
destructive: "0 84.2% 60.2%",
|
||||
"destructive-foreground": "210 40% 98%",
|
||||
border: "214.3 31.8% 91.4%",
|
||||
input: "214.3 31.8% 91.4%",
|
||||
ring: "221.2 83.2% 53.3%",
|
||||
},
|
||||
dark: {
|
||||
background: "222.2 84% 4.9%",
|
||||
foreground: "210 40% 98%",
|
||||
card: "222.2 84% 4.9%",
|
||||
"card-foreground": "210 40% 98%",
|
||||
popover: "222.2 84% 4.9%",
|
||||
"popover-foreground": "210 40% 98%",
|
||||
primary: "217.2 91.2% 59.8%",
|
||||
"primary-foreground": "222.2 47.4% 11.2%",
|
||||
secondary: "217.2 32.6% 17.5%",
|
||||
"secondary-foreground": "210 40% 98%",
|
||||
muted: "217.2 32.6% 17.5%",
|
||||
"muted-foreground": "215 20.2% 65.1%",
|
||||
accent: "217.2 32.6% 17.5%",
|
||||
"accent-foreground": "210 40% 98%",
|
||||
destructive: "0 62.8% 30.6%",
|
||||
"destructive-foreground": "210 40% 98%",
|
||||
border: "217.2 32.6% 17.5%",
|
||||
input: "217.2 32.6% 17.5%",
|
||||
ring: "224.3 76.3% 48%",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "yellow",
|
||||
label: "Yellow",
|
||||
activeColor: {
|
||||
light: "47.9 95.8% 53.1%",
|
||||
dark: "47.9 95.8% 53.1%",
|
||||
},
|
||||
cssVars: {
|
||||
light: {
|
||||
background: "0 0% 100%",
|
||||
foreground: "20 14.3% 4.1%",
|
||||
card: "0 0% 100%",
|
||||
"card-foreground": "20 14.3% 4.1%",
|
||||
popover: "0 0% 100%",
|
||||
"popover-foreground": "20 14.3% 4.1%",
|
||||
primary: "47.9 95.8% 53.1%",
|
||||
"primary-foreground": "26 83.3% 14.1%",
|
||||
secondary: "60 4.8% 95.9%",
|
||||
"secondary-foreground": "24 9.8% 10%",
|
||||
muted: "60 4.8% 95.9%",
|
||||
"muted-foreground": "25 5.3% 44.7%",
|
||||
accent: "60 4.8% 95.9%",
|
||||
"accent-foreground": "24 9.8% 10%",
|
||||
destructive: "0 84.2% 60.2%",
|
||||
"destructive-foreground": "60 9.1% 97.8%",
|
||||
border: "20 5.9% 90%",
|
||||
input: "20 5.9% 90%",
|
||||
ring: "20 14.3% 4.1%",
|
||||
radius: "0.95rem",
|
||||
},
|
||||
dark: {
|
||||
background: "20 14.3% 4.1%",
|
||||
foreground: "60 9.1% 97.8%",
|
||||
card: "20 14.3% 4.1%",
|
||||
"card-foreground": "60 9.1% 97.8%",
|
||||
popover: "20 14.3% 4.1%",
|
||||
"popover-foreground": "60 9.1% 97.8%",
|
||||
primary: "47.9 95.8% 53.1%",
|
||||
"primary-foreground": "26 83.3% 14.1%",
|
||||
secondary: "12 6.5% 15.1%",
|
||||
"secondary-foreground": "60 9.1% 97.8%",
|
||||
muted: "12 6.5% 15.1%",
|
||||
"muted-foreground": "24 5.4% 63.9%",
|
||||
accent: "12 6.5% 15.1%",
|
||||
"accent-foreground": "60 9.1% 97.8%",
|
||||
destructive: "0 62.8% 30.6%",
|
||||
"destructive-foreground": "60 9.1% 97.8%",
|
||||
border: "12 6.5% 15.1%",
|
||||
input: "12 6.5% 15.1%",
|
||||
ring: "35.5 91.7% 32.9%",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "violet",
|
||||
label: "Violet",
|
||||
activeColor: {
|
||||
light: "262.1 83.3% 57.8%",
|
||||
dark: "263.4 70% 50.4%",
|
||||
},
|
||||
cssVars: {
|
||||
light: {
|
||||
background: "0 0% 100%",
|
||||
foreground: "224 71.4% 4.1%",
|
||||
card: "0 0% 100%",
|
||||
"card-foreground": "224 71.4% 4.1%",
|
||||
popover: "0 0% 100%",
|
||||
"popover-foreground": "224 71.4% 4.1%",
|
||||
primary: "262.1 83.3% 57.8%",
|
||||
"primary-foreground": "210 20% 98%",
|
||||
secondary: "220 14.3% 95.9%",
|
||||
"secondary-foreground": "220.9 39.3% 11%",
|
||||
muted: "220 14.3% 95.9%",
|
||||
"muted-foreground": "220 8.9% 46.1%",
|
||||
accent: "220 14.3% 95.9%",
|
||||
"accent-foreground": "220.9 39.3% 11%",
|
||||
destructive: "0 84.2% 60.2%",
|
||||
"destructive-foreground": "210 20% 98%",
|
||||
border: "220 13% 91%",
|
||||
input: "220 13% 91%",
|
||||
ring: "262.1 83.3% 57.8%",
|
||||
},
|
||||
dark: {
|
||||
background: "224 71.4% 4.1%",
|
||||
foreground: "210 20% 98%",
|
||||
card: "224 71.4% 4.1%",
|
||||
"card-foreground": "210 20% 98%",
|
||||
popover: "224 71.4% 4.1%",
|
||||
"popover-foreground": "210 20% 98%",
|
||||
primary: "263.4 70% 50.4%",
|
||||
"primary-foreground": "210 20% 98%",
|
||||
secondary: "215 27.9% 16.9%",
|
||||
"secondary-foreground": "210 20% 98%",
|
||||
muted: "215 27.9% 16.9%",
|
||||
"muted-foreground": "217.9 10.6% 64.9%",
|
||||
accent: "215 27.9% 16.9%",
|
||||
"accent-foreground": "210 20% 98%",
|
||||
destructive: "0 62.8% 30.6%",
|
||||
"destructive-foreground": "210 20% 98%",
|
||||
border: "215 27.9% 16.9%",
|
||||
input: "215 27.9% 16.9%",
|
||||
ring: "263.4 70% 50.4%",
|
||||
},
|
||||
},
|
||||
},
|
||||
] as const
|
||||
|
||||
export type Theme = (typeof themes)[number]
|
||||
+12
-12
@@ -4,22 +4,22 @@ import {RouterProvider} from 'react-router-dom';
|
||||
import "./main.css";
|
||||
import {IconContext} from "@phosphor-icons/react";
|
||||
import {StrictMode} from "react";
|
||||
import {ThemeProvider} from "Frontend/@/components/theme-provider";
|
||||
import {NextUIProvider} from "@nextui-org/react";
|
||||
import {ThemeProvider as NextThemesProvider} from "next-themes";
|
||||
import {themeNames} from "Frontend/theming/themes";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<StrictMode>
|
||||
<AuthProvider>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
>
|
||||
<IconContext.Provider value={{size: 20}}>
|
||||
<RouterProvider router={router}/>
|
||||
</IconContext.Provider>
|
||||
</ThemeProvider>
|
||||
</AuthProvider>
|
||||
<NextUIProvider className="size-full">
|
||||
<NextThemesProvider attribute="class" defaultTheme="green-light" themes={themeNames()}>
|
||||
<AuthProvider>
|
||||
<IconContext.Provider value={{size: 20}}>
|
||||
<RouterProvider router={router}/>
|
||||
</IconContext.Provider>
|
||||
</AuthProvider>
|
||||
</NextThemesProvider>
|
||||
</NextUIProvider>
|
||||
</StrictMode>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {useField} from "formik";
|
||||
import {XCircle} from "@phosphor-icons/react";
|
||||
import {Input as ShadcnInput} from "Frontend/@/components/ui/input";
|
||||
import {Label} from "Frontend/@/components/ui/label";
|
||||
import {Input as NextUiInput} from "@nextui-org/react";
|
||||
|
||||
// @ts-ignore
|
||||
const Input = ({label, ...props}) => {
|
||||
@@ -10,19 +9,17 @@ const Input = ({label, ...props}) => {
|
||||
|
||||
return (
|
||||
<div className="grid w-full max-w-sm items-center gap-1.5">
|
||||
<Label htmlFor={label}>{label}</Label>
|
||||
<ShadcnInput
|
||||
<NextUiInput
|
||||
{...props}
|
||||
{...field}
|
||||
id={label}
|
||||
placeholder={label}
|
||||
isInvalid={meta.touched && !!meta.error}
|
||||
errorMessage={
|
||||
<small className="flex flex-row items-center gap-1 text-danger">
|
||||
<XCircle weight="fill" size={14}/> {meta.error}
|
||||
</small>}
|
||||
/>
|
||||
{(meta.touched && !!meta.error) ?
|
||||
<small
|
||||
className="flex flex-row items-center gap-1 text-red-500"
|
||||
>
|
||||
<XCircle weight="fill" size={14}/> {meta.error}
|
||||
</small> : <></>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
import {useState} from "react";
|
||||
import {useAuth} from "Frontend/util/auth";
|
||||
import {useNavigate} from "react-router-dom";
|
||||
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";
|
||||
import {Avatar, Dropdown, DropdownItem, DropdownMenu, DropdownTrigger} from "@nextui-org/react";
|
||||
|
||||
export default function ProfileMenu() {
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||
const {state, logout} = useAuth();
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -36,28 +28,33 @@ export default function ProfileMenu() {
|
||||
label: "Sign Out",
|
||||
icon: <SignOut/>,
|
||||
onClick: () => logout(),
|
||||
color: "red-500"
|
||||
color: "danger"
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<DropdownMenu open={isMenuOpen}>
|
||||
<DropdownMenuTrigger>
|
||||
<Avatar>
|
||||
<AvatarFallback>{state.user?.name?.substring(0, 2).toUpperCase()}</AvatarFallback>
|
||||
</Avatar>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<Dropdown placement="bottom-end">
|
||||
<DropdownTrigger>
|
||||
<Avatar showFallback radius="full" as="button" className="transition-transform"/>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu>
|
||||
{/* @ts-ignore */}
|
||||
{profileMenuItems.map(({label, icon, onClick, showIf, color}) => {
|
||||
return (
|
||||
(showIf === undefined || showIf === true) ?
|
||||
<DropdownMenuItem key={label} onClick={onClick}>
|
||||
{icon}
|
||||
<p color={color ? color : ""}>{label}</p>
|
||||
</DropdownMenuItem> : null
|
||||
<DropdownItem
|
||||
key={label}
|
||||
onClick={onClick}
|
||||
startContent={<div color={color}>{icon}</div>}
|
||||
/* @ts-ignore */
|
||||
color={color ? color : ""}
|
||||
className={`text-${color}`}
|
||||
>
|
||||
{label}
|
||||
</DropdownItem> : null
|
||||
);
|
||||
})}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
@@ -1,26 +1,16 @@
|
||||
import {hsl} from "Frontend/@/lib/utils";
|
||||
|
||||
export default function GameyfinLogo({primary, secondary, className}: {
|
||||
primary: string,
|
||||
secondary: string,
|
||||
export default function GameyfinLogo({className}: {
|
||||
className?: string
|
||||
}) {
|
||||
const primaryColor = hsl(primary)
|
||||
const secondaryColor = (secondary === null || secondary === undefined) ? primaryColor : hsl(secondary);
|
||||
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 365.58 336.34" className={className}>
|
||||
<polygon points="190.1 49.13 190.1 69.24 207.98 44.13 190.1 49.13" fill={secondaryColor}/>
|
||||
<polygon points="365.58 0 263.22 28.66 205.64 95.97 365.58 51.18 365.58 0" fill={secondaryColor}/>
|
||||
<polygon points="190.1 49.13 190.1 69.24 207.98 44.13 190.1 49.13"/>
|
||||
<polygon points="365.58 0 263.22 28.66 205.64 95.97 365.58 51.18 365.58 0"/>
|
||||
<polygon
|
||||
points="190.1 283.11 248.6 266.73 248.6 149.74 365.58 116.99 365.58 73.12 190.1 122.25 190.1 283.11"
|
||||
fill={secondaryColor}/>
|
||||
points="190.1 283.11 248.6 266.73 248.6 149.74 365.58 116.99 365.58 73.12 190.1 122.25 190.1 283.11"/>
|
||||
<polygon
|
||||
points="58.49 144.48 155.98 117.18 175.48 89.79 175.48 53.23 0 102.36 0 336.34 58.49 254.15 58.49 144.48"
|
||||
fill={primaryColor}/>
|
||||
points="58.49 144.48 155.98 117.18 175.48 89.79 175.48 53.23 0 102.36 0 336.34 58.49 254.15 58.49 144.48"/>
|
||||
<polygon
|
||||
points="116.99 199.59 116.99 245.09 65.81 259.42 0 336.34 175.48 287.2 175.48 170.22 131.61 182.5 116.99 199.59"
|
||||
fill={primaryColor}/>
|
||||
points="116.99 199.59 116.99 245.09 65.81 259.42 0 336.34 175.48 287.2 175.48 170.22 131.61 182.5 116.99 199.59"/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -1,41 +1,25 @@
|
||||
import {Theme} from "Frontend/@/registry/themes";
|
||||
import {Card} from "Frontend/@/components/ui/card";
|
||||
import {Tooltip, TooltipContent, TooltipTrigger} from "Frontend/@/components/ui/tooltip";
|
||||
import {useTheme} from "next-themes";
|
||||
import {Theme} from "Frontend/theming/theme";
|
||||
import {Card, Tooltip} from "@nextui-org/react";
|
||||
import GameyfinLogo from "Frontend/components/theming/GameyfinLogo";
|
||||
import {hsl} from "Frontend/@/lib/utils";
|
||||
|
||||
export default function ThemePreview({theme}: { theme: Theme }) {
|
||||
//@ts-ignore
|
||||
let resolvedTheme: "light" | "dark" = useTheme().resolvedTheme ?? "light";
|
||||
const {setTheme} = useTheme();
|
||||
|
||||
function toggleMode() {
|
||||
resolvedTheme = resolvedTheme === "light" ? "dark" : "light";
|
||||
setTheme(resolvedTheme);
|
||||
}
|
||||
|
||||
export default function ThemePreview({theme, mode, isSelected}: {
|
||||
theme: Theme,
|
||||
mode: "light" | "dark",
|
||||
isSelected?: boolean
|
||||
}) {
|
||||
return (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Card
|
||||
className="overflow-hidden flex place-self-center justify-center p-6"
|
||||
style={{background: hsl(theme.cssVars[resolvedTheme].background)}}>
|
||||
<GameyfinLogo primary={theme.cssVars[resolvedTheme].primary}
|
||||
secondary={theme.cssVars[resolvedTheme].secondary}
|
||||
className="w-1/2"
|
||||
/>
|
||||
</Card>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">
|
||||
<p className="capitalize">{theme.name}</p>
|
||||
</TooltipContent>
|
||||
<Tooltip content={<p className="capitalize">{theme.name?.replace("-", " ")}</p>} placement="bottom">
|
||||
<Card
|
||||
shadow="none"
|
||||
className={`${theme.name}-${mode} flex-row justify-center p-6 border-2 ${isSelected ? "border-focus" : "border-foreground-200 hover:border-focus"}`}
|
||||
>
|
||||
<GameyfinLogo className="w-1/2 fill-primary"/>
|
||||
</Card>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
<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.cssVars[resolvedTheme].background}/>
|
||||
<rect id="background-secondary" x="29" y="54" width="144" height="53" rx="2" fill="#30363D"/>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, {ReactNode, useState} from "react";
|
||||
import {Form, Formik, FormikBag, FormikHelpers} from "formik";
|
||||
import {ArrowLeft, ArrowRight, Check, SpinnerGap} from "@phosphor-icons/react";
|
||||
import {Button} from "Frontend/@/components/ui/button";
|
||||
import {ArrowLeft, ArrowRight, Check} from "@phosphor-icons/react";
|
||||
import {Button} from "@nextui-org/react";
|
||||
import {Step, Stepper} from "@material-tailwind/react";
|
||||
|
||||
const Wizard = ({children, initialValues, onSubmit}: {
|
||||
children: ReactNode,
|
||||
@@ -51,31 +52,34 @@ const Wizard = ({children, initialValues, onSubmit}: {
|
||||
{formik => (
|
||||
<Form className="flex flex-col h-full">
|
||||
<div className="w-full mb-8">
|
||||
<p>Step {stepNumber + 1} of {steps.length}</p>
|
||||
{/*<Stepper activeStep={stepNumber}>
|
||||
{/*<p>Step {stepNumber + 1} of {steps.length}</p>*/}
|
||||
<Stepper activeStep={stepNumber} activeLineClassName="bg-primary"
|
||||
lineClassName="bg-foreground">
|
||||
{steps.map((child, index) => (
|
||||
<Step key={index}>
|
||||
<Step key={index}
|
||||
className="bg-foreground text-background"
|
||||
activeClassName="bg-primary"
|
||||
completedClassName="bg-primary">
|
||||
{/*@ts-ignore*/}
|
||||
{child.props.icon}
|
||||
</Step>
|
||||
))}
|
||||
</Stepper>*/}
|
||||
</Stepper>
|
||||
</div>
|
||||
<div className="flex grow">
|
||||
{step}
|
||||
</div>
|
||||
<div className="bottom-0 w-full">
|
||||
<div className="flex justify-between">
|
||||
<Button onClick={() => previous(formik.values)} disabled={isFirstStep}
|
||||
className="rounded-full">
|
||||
<Button color="primary" onClick={() => previous(formik.values)} disabled={isFirstStep}>
|
||||
<ArrowLeft/>
|
||||
</Button>
|
||||
<Button disabled={formik.isSubmitting}
|
||||
className="rounded-full"
|
||||
type="submit"
|
||||
<Button
|
||||
color="primary"
|
||||
isLoading={formik.isSubmitting}
|
||||
type="submit"
|
||||
>
|
||||
{formik.isSubmitting ?
|
||||
<SpinnerGap className="animate-spin"/> : isLastStep ? <Check/> : <ArrowRight/>
|
||||
}
|
||||
{formik.isSubmitting ? "" : isLastStep ? <Check/> : <ArrowRight/>}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
<!-- index.ts is included here automatically (either by the dev server or during the build) -->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<body class="text-foreground bg-background">
|
||||
<div id="outlet"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+1
-81
@@ -1,83 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 222.2 84% 4.9%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 222.2 84% 4.9%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 222.2 84% 4.9%;
|
||||
|
||||
--primary: 222.2 47.4% 11.2%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
|
||||
--secondary: 210 40% 96.1%;
|
||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--muted: 210 40% 96.1%;
|
||||
--muted-foreground: 215.4 16.3% 46.9%;
|
||||
|
||||
--accent: 210 40% 96.1%;
|
||||
--accent-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--border: 214.3 31.8% 91.4%;
|
||||
--input: 214.3 31.8% 91.4%;
|
||||
--ring: 222.2 84% 4.9%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
|
||||
--warning: 38 92% 50%;
|
||||
--warning-foreground: 48 96% 89%;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 222.2 84% 4.9%;
|
||||
--foreground: 210 40% 98%;
|
||||
|
||||
--card: 222.2 84% 4.9%;
|
||||
--card-foreground: 210 40% 98%;
|
||||
|
||||
--popover: 222.2 84% 4.9%;
|
||||
--popover-foreground: 210 40% 98%;
|
||||
|
||||
--primary: 210 40% 98%;
|
||||
--primary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--secondary: 217.2 32.6% 17.5%;
|
||||
--secondary-foreground: 210 40% 98%;
|
||||
|
||||
--muted: 217.2 32.6% 17.5%;
|
||||
--muted-foreground: 215 20.2% 65.1%;
|
||||
|
||||
--accent: 217.2 32.6% 17.5%;
|
||||
--accent-foreground: 210 40% 98%;
|
||||
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--border: 217.2 32.6% 17.5%;
|
||||
--input: 217.2 32.6% 17.5%;
|
||||
--ring: 212.7 26.8% 83.9%;
|
||||
|
||||
--warning: 48 96% 89%;
|
||||
--warning-foreground: 38 92% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
@tailwind utilities;
|
||||
@@ -0,0 +1,21 @@
|
||||
export type Theme = {
|
||||
name?: string,
|
||||
colors: {
|
||||
background?: string,
|
||||
foreground?: string,
|
||||
primary: {
|
||||
50: string,
|
||||
100: string,
|
||||
200: string,
|
||||
300: string,
|
||||
400: string,
|
||||
500: string,
|
||||
600: string,
|
||||
700: string,
|
||||
800: string,
|
||||
900: string,
|
||||
DEFAULT: string
|
||||
},
|
||||
focus?: string,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import {GameyfinClassic} from "./themes/gameyfin-classic";
|
||||
import {GameyfinBlue} from "./themes/gameyfin-blue";
|
||||
import {GameyfinViolet} from "./themes/gameyfin-violet";
|
||||
import {Purple} from "./themes/purple";
|
||||
import {Neutral} from "./themes/neutral";
|
||||
import {Slate} from "./themes/slate";
|
||||
import {Red} from "./themes/red";
|
||||
import {Rose} from "./themes/rose";
|
||||
import {Blue} from "./themes/blue";
|
||||
import {Yellow} from "./themes/yellow";
|
||||
import {Violet} from "./themes/violet";
|
||||
import {Orange} from "./themes/orange";
|
||||
import {Theme} from "./theme";
|
||||
import {ConfigTheme, ConfigThemes} from "@nextui-org/react";
|
||||
|
||||
|
||||
function light(c: Theme): ConfigTheme {
|
||||
let t: Theme = structuredClone(c);
|
||||
delete t.name;
|
||||
(t as ConfigTheme).extend = "light";
|
||||
return t;
|
||||
}
|
||||
|
||||
function dark(c: Theme): ConfigTheme {
|
||||
let t: Theme = structuredClone(c);
|
||||
delete t.name;
|
||||
(t as ConfigTheme).extend = "dark";
|
||||
return t;
|
||||
}
|
||||
|
||||
export function compileThemes(themes: Theme[]): ConfigThemes {
|
||||
let compiledThemes: any = {};
|
||||
|
||||
themes.forEach((c: Theme) => {
|
||||
compiledThemes[`${c.name}-light`] = light(c);
|
||||
compiledThemes[`${c.name}-dark`] = dark(c);
|
||||
})
|
||||
|
||||
return compiledThemes;
|
||||
}
|
||||
|
||||
export function themeNames(): string[] {
|
||||
return Object.keys(compileThemes(themes));
|
||||
}
|
||||
|
||||
export const themes: Theme[] = [GameyfinBlue, GameyfinViolet, GameyfinClassic, Neutral, Slate, Red, Rose, Orange, Purple, Blue, Yellow, Violet];
|
||||
@@ -0,0 +1,20 @@
|
||||
import {Theme} from '../theme';
|
||||
|
||||
export const Blue: Theme = {
|
||||
name: 'blue',
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#e3eeff',
|
||||
100: '#b6cdfe',
|
||||
200: '#88abf7',
|
||||
300: '#5b8af1',
|
||||
400: '#2d69ec',
|
||||
500: '#134fd2',
|
||||
600: '#0b3da4',
|
||||
700: '#052c77',
|
||||
800: '#001a4a',
|
||||
900: '#00091e',
|
||||
DEFAULT: '#2563EB'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import {Theme} from '../theme';
|
||||
|
||||
export const GameyfinBlue: Theme = {
|
||||
name: 'gameyfin-blue',
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#e7eaff',
|
||||
100: '#bdc3f9',
|
||||
200: '#919bee',
|
||||
300: '#6672e5',
|
||||
400: '#3c4add',
|
||||
500: '#2231c3',
|
||||
600: '#1a2699',
|
||||
700: '#101b6f',
|
||||
800: '#070f45',
|
||||
900: '#02041d',
|
||||
DEFAULT: '#2332c8'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import {Theme} from '../theme';
|
||||
|
||||
export const GameyfinClassic: Theme = {
|
||||
name: 'gameyfin-classic',
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#e1ffec',
|
||||
100: '#b8f7cf',
|
||||
200: '#8ef0b2',
|
||||
300: '#62ea94',
|
||||
400: '#38e476',
|
||||
500: '#20ca5d',
|
||||
600: '#159d47',
|
||||
700: '#0b7032',
|
||||
800: '#02431d',
|
||||
900: '#001804',
|
||||
DEFAULT: '#16A34A'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import {Theme} from '../theme';
|
||||
|
||||
export const GameyfinViolet: Theme = {
|
||||
name: 'gameyfin-violet',
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#f3ebff',
|
||||
100: '#d5c7ed',
|
||||
200: '#b7a4dd',
|
||||
300: '#9a7fce',
|
||||
400: '#7d5abe',
|
||||
500: '#6441a5',
|
||||
600: '#4e3281',
|
||||
700: '#37235d',
|
||||
800: '#21153a',
|
||||
900: '#0d0519',
|
||||
DEFAULT: '#6441a5'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import {Theme} from '../theme';
|
||||
|
||||
export const Neutral: Theme = {
|
||||
name: 'neutral',
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#fceff2',
|
||||
100: '#ddd7d9',
|
||||
200: '#c1bfbf',
|
||||
300: '#a6a6a6',
|
||||
400: '#8c8c8c',
|
||||
500: '#737373',
|
||||
600: '#595959',
|
||||
700: '#413f40',
|
||||
800: '#292526',
|
||||
900: '#16090d',
|
||||
DEFAULT: '#525252'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import {Theme} from '../theme';
|
||||
|
||||
export const Orange: Theme = {
|
||||
name: 'orange',
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#ffedde',
|
||||
100: '#ffcdb2',
|
||||
200: '#fbac84',
|
||||
300: '#f78c54',
|
||||
400: '#f46c25',
|
||||
500: '#da520b',
|
||||
600: '#ab3f07',
|
||||
700: '#7a2d03',
|
||||
800: '#4b1900',
|
||||
900: '#1f0600',
|
||||
DEFAULT: '#EA580C'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import {Theme} from "../theme";
|
||||
|
||||
export const Purple: Theme = {
|
||||
name: 'purple',
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#ffe6ff',
|
||||
100: '#f2b9f9',
|
||||
200: '#e78df3',
|
||||
300: '#dc5fed',
|
||||
400: '#d132e6',
|
||||
500: '#b91acd',
|
||||
600: '#9012a0',
|
||||
700: '#670b73',
|
||||
800: '#3f0547',
|
||||
900: '#19001b',
|
||||
DEFAULT: '#DD62ED'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import {Theme} from '../theme';
|
||||
|
||||
export const Red: Theme = {
|
||||
name: 'red',
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#ffe5e5',
|
||||
100: '#f9bbbb',
|
||||
200: '#ef9090',
|
||||
300: '#e76464',
|
||||
400: '#df3939',
|
||||
500: '#c62020',
|
||||
600: '#9b1718',
|
||||
700: '#6f0f11',
|
||||
800: '#450708',
|
||||
900: '#1e0000',
|
||||
DEFAULT: '#DC2626'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import {Theme} from "../theme";
|
||||
|
||||
export const Rose: Theme = {
|
||||
name: 'rose',
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#ffe4ed',
|
||||
100: '#fbb9c8',
|
||||
200: '#f28da4',
|
||||
300: '#ec607f',
|
||||
400: '#e5345b',
|
||||
500: '#cb1a41',
|
||||
600: '#9f1233',
|
||||
700: '#730b23',
|
||||
800: '#470415',
|
||||
900: '#1e0006',
|
||||
DEFAULT: '#E11D48'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import {Theme} from "../theme";
|
||||
|
||||
export const Slate: Theme = {
|
||||
name: 'slate',
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#eaf3ff',
|
||||
100: '#cfd7e4',
|
||||
200: '#b2bdcd',
|
||||
300: '#95a3b7',
|
||||
400: '#7788a1',
|
||||
500: '#5e6f88',
|
||||
600: '#48566a',
|
||||
700: '#323e4d',
|
||||
800: '#1d2531',
|
||||
900: '#040d17',
|
||||
DEFAULT: '#475569'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import {Theme} from '../theme';
|
||||
|
||||
export const Violet: Theme = {
|
||||
name: 'violet',
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#f2e7ff',
|
||||
100: '#d4bdf8',
|
||||
200: '#b592ee',
|
||||
300: '#9867e5',
|
||||
400: '#7b3cdd',
|
||||
500: '#6122c3',
|
||||
600: '#4b1a99',
|
||||
700: '#36126e',
|
||||
800: '#200944',
|
||||
900: '#0d021c',
|
||||
DEFAULT: '#6D28D9'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import {Theme} from '../theme';
|
||||
|
||||
export const Yellow: Theme = {
|
||||
name: 'yellow',
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#fffadb',
|
||||
100: '#feefae',
|
||||
200: '#fce47f',
|
||||
300: '#fbd94e',
|
||||
400: '#face1e',
|
||||
500: '#e1b505',
|
||||
600: '#af8c00',
|
||||
700: '#7d6400',
|
||||
800: '#4c3c00',
|
||||
900: '#1c1400',
|
||||
DEFAULT: '#FACC15'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -17,4 +17,4 @@ export function rand(min: number, max: number) {
|
||||
const minCeiled = Math.ceil(min);
|
||||
const maxFloored = Math.floor(max);
|
||||
return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
import {useAuth} from "Frontend/util/auth";
|
||||
import {useState} from "react";
|
||||
import {Link, useNavigate} from "react-router-dom";
|
||||
import {SpinnerGap, XCircle} from "@phosphor-icons/react";
|
||||
import {Card} from "Frontend/@/components/ui/card";
|
||||
import {XCircle} from "@phosphor-icons/react";
|
||||
import {Button, Card, CardBody, CardHeader, Input} from "@nextui-org/react";
|
||||
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();
|
||||
@@ -24,11 +22,14 @@ export default function LoginView() {
|
||||
return (
|
||||
<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">
|
||||
<CardHeader>
|
||||
<img
|
||||
className="h-28 w-full content-center"
|
||||
src="/images/Logo.svg"
|
||||
alt="Gameyfin Logo"
|
||||
/>
|
||||
</CardHeader>
|
||||
<CardBody className="mt-8 mb-2 w-80 max-w-screen-lg sm:w-96">
|
||||
{hasError &&
|
||||
<Alert className="mb-4" variant="destructive">
|
||||
<XCircle weight="fill" className="size-4"/>
|
||||
@@ -82,17 +83,12 @@ export default function LoginView() {
|
||||
/>
|
||||
<div className="flex justify-between items-center">
|
||||
<Link to="#">Forgot password?</Link>
|
||||
<Button
|
||||
type="submit"
|
||||
size="lg"
|
||||
className="w-28 h-12 flex justify-center"
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? <SpinnerGap className="size-6 animate-spin"/> : "Log in"}
|
||||
<Button color="primary" type="submit" isLoading={loading}>
|
||||
Log in
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@ import {useRouteMetadata} from 'Frontend/util/routing.js';
|
||||
import {useEffect} from 'react';
|
||||
import ProfileMenu from "Frontend/components/ProfileMenu";
|
||||
import {Outlet} from "react-router-dom";
|
||||
import {Card} from "Frontend/@/components/ui/card";
|
||||
import {Card} from "@nextui-org/react";
|
||||
|
||||
export default function MainLayout() {
|
||||
const currentTitle = `Gameyfin - ${useRouteMetadata()?.title}` ?? 'Gameyfin';
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import React from 'react';
|
||||
import React, {useLayoutEffect, useState} from 'react';
|
||||
import * as Yup from 'yup';
|
||||
import Wizard from "Frontend/components/wizard/Wizard";
|
||||
import WizardStep from "Frontend/components/wizard/WizardStep";
|
||||
import Input from "Frontend/components/Input";
|
||||
import {GearFine, HandWaving, Moon, Palette, SunDim, User} from "@phosphor-icons/react";
|
||||
import ThemePreview from "Frontend/components/theming/ThemePreview";
|
||||
import {Theme, themes} from "Frontend/@/registry/themes";
|
||||
import {Card} from "Frontend/@/components/ui/card";
|
||||
import {Switch} from "Frontend/@/components/ui/switch";
|
||||
import {themes} from "Frontend/theming/themes";
|
||||
import {Card, Switch} from "@nextui-org/react";
|
||||
import {useTheme} from "next-themes";
|
||||
import {Theme} from "Frontend/theming/theme";
|
||||
|
||||
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
@@ -37,23 +37,46 @@ function WelcomeStep() {
|
||||
}
|
||||
|
||||
function ThemeStep() {
|
||||
const {setTheme, theme} = useTheme();
|
||||
const {theme, setTheme} = useTheme();
|
||||
const [isSelected, setIsSelected] = useState(theme ? theme.includes("light") : false);
|
||||
const [currentTheme, setCurrentTheme] = useState(theme?.split('-')[0]);
|
||||
|
||||
function toggleMode() {
|
||||
setTheme(theme === "light" ? "dark" : "light");
|
||||
useLayoutEffect(() => setTheme(`${currentTheme}-${mode()}`), [isSelected]);
|
||||
|
||||
function mode(): "light" | "dark" {
|
||||
return !isSelected ? "dark" : "light"
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col size-full items-center">
|
||||
<div className="w-full flex flex-row items-center justify-center gap-4 mb-16">
|
||||
<SunDim size={32}/>
|
||||
<Switch checked={theme === "dark"} onCheckedChange={() => toggleMode()}></Switch>
|
||||
<Moon size={32}/>
|
||||
<Switch
|
||||
size="lg"
|
||||
startContent={<SunDim size={32}/>}
|
||||
endContent={<Moon size={32}/>}
|
||||
isSelected={isSelected}
|
||||
onValueChange={() => {
|
||||
setIsSelected(!isSelected);
|
||||
}}
|
||||
/>
|
||||
|
||||
</div>
|
||||
<div className="grid grid-cols-3 w-1/2 min-w-[468px] gap-12">
|
||||
{themes.map(((theme: Theme) => (
|
||||
<ThemePreview key={theme.name} theme={theme}/>
|
||||
)))}
|
||||
<div className="grid grid-cols-4 w-3/4 min-w-[468px] gap-12">
|
||||
{
|
||||
themes.map(((t: Theme) => (
|
||||
<div
|
||||
key={t.name}
|
||||
onClick={() => {
|
||||
setCurrentTheme(t.name);
|
||||
setTheme(`${t.name}-${mode()}`);
|
||||
}}>
|
||||
<ThemePreview
|
||||
theme={t}
|
||||
mode={mode()}
|
||||
isSelected={currentTheme === t.name}/>
|
||||
</div>
|
||||
)))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import {Link} from "react-router-dom";
|
||||
|
||||
export default function TestView() {
|
||||
return (
|
||||
<h1>Hello Gameyfin!</h1>
|
||||
<div className="size-full flex justify-center">
|
||||
<Link to="/setup">Setup</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import {NextUIPluginConfig} from "@nextui-org/react";
|
||||
import {compileThemes, themes} from "./frontend/theming/themes"
|
||||
|
||||
export const NextUIConfig: NextUIPluginConfig = {
|
||||
prefix: "gf",
|
||||
themes: compileThemes(themes)
|
||||
};
|
||||
Generated
-12071
File diff suppressed because it is too large
Load Diff
+10
-22
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "Gameyfin",
|
||||
"name": "gameyfin",
|
||||
"version": "2.0.0-ALPHA",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
@@ -18,15 +18,10 @@
|
||||
"@hilla/react-components": "2.3.0",
|
||||
"@hilla/react-crud": "2.5.6",
|
||||
"@hilla/react-form": "2.5.6",
|
||||
"@material-tailwind/react": "^2.1.9",
|
||||
"@nextui-org/react": "^2.3.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-icons": "^1.3.0",
|
||||
"@radix-ui/react-label": "^2.0.2",
|
||||
"@radix-ui/react-slot": "^1.0.2",
|
||||
"@radix-ui/react-switch": "^1.0.3",
|
||||
"@radix-ui/react-tooltip": "^1.0.7",
|
||||
"@vaadin/bundles": "24.3.0",
|
||||
"@vaadin/common-frontend": "0.0.19",
|
||||
"@vaadin/router": "1.7.5",
|
||||
@@ -35,15 +30,13 @@
|
||||
"clsx": "^2.1.0",
|
||||
"construct-style-sheets-polyfill": "3.1.0",
|
||||
"formik": "^2.4.5",
|
||||
"jotai": "^2.7.1",
|
||||
"framer-motion": "^11.1.7",
|
||||
"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",
|
||||
"tailwind-merge": "^2.2.2",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"yup": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -59,6 +52,7 @@
|
||||
"autoprefixer": "^10.4.18",
|
||||
"glob": "10.3.3",
|
||||
"postcss": "^8.4.35",
|
||||
"postcss-import": "^16.1.0",
|
||||
"rollup-plugin-brotli": "3.1.0",
|
||||
"rollup-plugin-visualizer": "5.9.2",
|
||||
"strip-css-comments": "5.0.0",
|
||||
@@ -102,17 +96,11 @@
|
||||
"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",
|
||||
"@radix-ui/react-icons": "$@radix-ui/react-icons"
|
||||
"@nextui-org/react": "$@nextui-org/react",
|
||||
"framer-motion": "$framer-motion",
|
||||
"@material-tailwind/react": "$@material-tailwind/react"
|
||||
},
|
||||
"vaadin": {
|
||||
"dependencies": {
|
||||
@@ -156,6 +144,6 @@
|
||||
"workbox-core": "7.0.0",
|
||||
"workbox-precaching": "7.0.0"
|
||||
},
|
||||
"hash": "5375ee653b483f5c0b565f19670e73ec7e02e2abb121e622411201c6c6cb2431"
|
||||
"hash": "a2234ddab9db9a07cd47eded5c9642efac70874179c7dadb6c6887c4fe6519a7"
|
||||
}
|
||||
}
|
||||
|
||||
+12
-72
@@ -1,84 +1,24 @@
|
||||
import {Config} from "tailwindcss/types/config";
|
||||
import {nextui} from "@nextui-org/react";
|
||||
import {NextUIConfig} from "./nextui";
|
||||
import withMT from "@material-tailwind/react/utils/withMT";
|
||||
|
||||
export default {
|
||||
export default withMT({
|
||||
darkMode: "class",
|
||||
content: [
|
||||
'./frontend/index.html',
|
||||
'./frontend/**/*.{js,ts,jsx,tsx}',
|
||||
'./pages/**/*.{ts,tsx}',
|
||||
'./components/**/*.{ts,tsx}',
|
||||
'./app/**/*.{ts,tsx}',
|
||||
'./src/**/*.{ts,tsx}'
|
||||
'./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||
],
|
||||
prefix: "",
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
padding: "2rem",
|
||||
screens: {
|
||||
"2xl": "1400px",
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
'gf-primary': '#2332c8',
|
||||
'gf-secondary': '#6441a5',
|
||||
warning: "hsl(var(--warning))",
|
||||
"warning-foreground": "hsl(var(--warning-foreground))",
|
||||
border: "hsl(var(--border))",
|
||||
input: "hsl(var(--input))",
|
||||
ring: "hsl(var(--ring))",
|
||||
background: "hsl(var(--background))",
|
||||
foreground: "hsl(var(--foreground))",
|
||||
primary: {
|
||||
DEFAULT: "hsl(var(--primary))",
|
||||
foreground: "hsl(var(--primary-foreground))",
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: "hsl(var(--secondary))",
|
||||
foreground: "hsl(var(--secondary-foreground))",
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: "hsl(var(--destructive))",
|
||||
foreground: "hsl(var(--destructive-foreground))",
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: "hsl(var(--muted))",
|
||||
foreground: "hsl(var(--muted-foreground))",
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: "hsl(var(--accent))",
|
||||
foreground: "hsl(var(--accent-foreground))",
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: "hsl(var(--popover))",
|
||||
foreground: "hsl(var(--popover-foreground))",
|
||||
},
|
||||
card: {
|
||||
DEFAULT: "hsl(var(--card))",
|
||||
foreground: "hsl(var(--card-foreground))",
|
||||
},
|
||||
},
|
||||
borderRadius: {
|
||||
lg: "var(--radius)",
|
||||
md: "calc(var(--radius) - 2px)",
|
||||
sm: "calc(var(--radius) - 4px)",
|
||||
},
|
||||
keyframes: {
|
||||
"accordion-down": {
|
||||
from: {height: "0"},
|
||||
to: {height: "var(--radix-accordion-content-height)"},
|
||||
},
|
||||
"accordion-up": {
|
||||
from: {height: "var(--radix-accordion-content-height)"},
|
||||
to: {height: "0"},
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
"accordion-down": "accordion-down 0.2s ease-out",
|
||||
"accordion-up": "accordion-up 0.2s ease-out",
|
||||
},
|
||||
},
|
||||
'gf-secondary': '#6441a5'
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
} satisfies Config;
|
||||
plugins: [
|
||||
nextui(NextUIConfig)
|
||||
],
|
||||
} satisfies Config);
|
||||
Reference in New Issue
Block a user