mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-15 08:15:37 +00:00
Added dark/light mode (next: custom themes)
This commit is contained in:
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
];
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user