Start theming implementation

This commit is contained in:
grimsi
2024-03-17 17:54:40 +01:00
parent 4ad0914b17
commit 87a4d50190
9 changed files with 259 additions and 67 deletions
+9
View File
@@ -0,0 +1,9 @@
export class Theme {
constructor(
public readonly name: string,
public readonly primary: string,
public readonly secondary?: string,
public readonly tertiary?: string
) {
}
}
@@ -0,0 +1,19 @@
import {Theme} from "Frontend/components/theming/Theme";
import {Typography} from "@material-tailwind/react";
export default function ThemePreview({theme}: { theme: Theme }) {
return (
<div className={`
size-full bg-background
grid grid-rows-3
rounded-lg
border-2 border-on-background
p-4 gap-4
`}>
<div className="bg-primary flex grow rounded-lg"></div>
<div className="bg-secondary flex grow rounded-lg"></div>
<div className="bg-tertiary flex grow rounded-lg"></div>
<Typography variant="paragraph" className="text-center">{theme.name}</Typography>
</div>
);
}
+18
View File
@@ -0,0 +1,18 @@
import {Theme} from "Frontend/components/theming/Theme";
export class Themes {
public static LIGHT_DEFAULT = new Theme(
"Light default",
"#000000"
)
public static DARK_DEFAULT = new Theme(
"Dark default",
"#ffffff"
)
public static all = [
Themes.LIGHT_DEFAULT,
Themes.DARK_DEFAULT
];
}
+7 -3
View File
@@ -1,9 +1,13 @@
import React, {useState} from "react"; import React, {ReactNode, useState} from "react";
import {Form, Formik, FormikBag, FormikHelpers} from "formik"; import {Form, Formik, FormikBag, FormikHelpers} from "formik";
import {Button, Spinner, Step, Stepper} from "@material-tailwind/react"; import {Button, Spinner, Step, Stepper} from "@material-tailwind/react";
import {ArrowLeft, ArrowRight, Check} from "@phosphor-icons/react"; import {ArrowLeft, ArrowRight, Check} from "@phosphor-icons/react";
const Wizard = ({children, initialValues, onSubmit}: { children: any, initialValues: any, onSubmit: any }) => { const Wizard = ({children, initialValues, onSubmit}: {
children: ReactNode,
initialValues: any,
onSubmit: (values: any, bag: FormikHelpers<any> | FormikBag<any, any>) => Promise<void>
}) => {
const [stepNumber, setStepNumber] = useState(0); const [stepNumber, setStepNumber] = useState(0);
const steps = React.Children.toArray(children); const steps = React.Children.toArray(children);
const [snapshot, setSnapshot] = useState(initialValues); const [snapshot, setSnapshot] = useState(initialValues);
@@ -73,7 +77,7 @@ const Wizard = ({children, initialValues, onSubmit}: { children: any, initialVal
type="submit" type="submit"
> >
{formik.isSubmitting ? {formik.isSubmitting ?
<Spinner className="h-5 w-5"/> : isLastStep ? <Check/> : <ArrowRight/> <Spinner className="size-5"/> : isLastStep ? <Check/> : <ArrowRight/>
} }
</Button> </Button>
</div> </div>
+13 -2
View File
@@ -1,3 +1,14 @@
const WizardStep = ({children}: { children: any }) => children; import {JSX, ReactNode} from "react";
import * as Yup from 'yup';
export default WizardStep; export default function WizardStep({children, icon, validationSchema}: {
children: ReactNode,
icon: JSX.Element,
validationSchema?: Yup.Schema,
onSubmit?: (...values: any) => Promise<void>
}) {
return children;
}
//const WizardStep = ({children}: { children: Component }) => children;
//export default WizardStep;
+65 -50
View File
@@ -1,58 +1,74 @@
import React from 'react'; import React from 'react';
import {useFormikContext} from 'formik';
import * as Yup from 'yup'; import * as Yup from 'yup';
import Wizard from "Frontend/components/wizard/Wizard"; import Wizard from "Frontend/components/wizard/Wizard";
import WizardStep from "Frontend/components/wizard/WizardStep"; import WizardStep from "Frontend/components/wizard/WizardStep";
import {Card, Typography} from "@material-tailwind/react"; import {Card, Typography} from "@material-tailwind/react";
import Input from "Frontend/components/Input"; import Input from "Frontend/components/Input";
import {GearFine, HandWaving, User} from "@phosphor-icons/react"; import {GearFine, HandWaving, Palette, User} from "@phosphor-icons/react";
import {Themes} from "Frontend/components/theming/Themes";
import ThemePreview from "Frontend/components/theming/ThemePreview";
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
function WelcomeStep() { function WelcomeStep() {
return ( return (
<div className="flex flex-col size-full gap-12 items-center"> <div className="flex flex-col size-full items-center">
<Typography variant="h4">Welcome to Gameyfin 👋</Typography> <div className="flex flex-col w-1/2 min-w-[468px] gap-12 items-center">
<p className="place-content-center text-justify"> <Typography variant="h4">Welcome to Gameyfin 👋</Typography>
Gameyfin is a cutting-edge software tailored for gamers seeking efficient management of their <p className="place-content-center text-justify">
video Gameyfin is a cutting-edge software tailored for gamers seeking efficient management of their
game collections. <br/><br/> With its intuitive interface and comprehensive features, Gameyfin video
simplifies the organization of game libraries. Users can effortlessly add games through manual game collections. <br/><br/> With its intuitive interface and comprehensive features, Gameyfin
input simplifies the organization of game libraries. Users can effortlessly add games through manual
or input
automated recognition, categorize them based on various criteria like genre or platform, track or
in-game automated recognition, categorize them based on various criteria like genre or platform, track
progress, and share achievements with friends. <br/><br/> Notably, Gameyfin stands out for its in-game
user-friendly progress, and share achievements with friends. <br/><br/> Notably, Gameyfin stands out for its
design and adaptability, offering ample customization options to meet diverse user preferences. user-friendly
</p> design and adaptability, offering ample customization options to meet diverse user preferences.
<Typography variant="h5">Let's get started!</Typography> </p>
<Typography variant="h5">Let's get started!</Typography>
</div>
</div> </div>
); );
} }
function UserStep() { function ThemeStep() {
const formik = useFormikContext();
return ( return (
<div className="flex flex-col size-full gap-12 items-center"> <div className="flex flex-col size-full items-center">
<Typography variant="h4">Create your account</Typography> <div className="size-full grid grid-cols-3 grid-rows-2 w-1/2 min-w-[468px] gap-12 items-center">
<Typography className="-mt-8">This will set up the initial admin user account.</Typography> {Themes.all.map((theme => (
<div className="mb-1 flex flex-col w-full gap-6"> <ThemePreview key={theme.name} theme={theme}/>
<Input )))}
label="Username" </div>
name="username" </div>
type="text" )
/> }
<Input
label="Password" function UserStep() {
name="password" return (
type="password" <div className="flex flex-col size-full items-center">
/> <div className="flex flex-col w-1/2 min-w-[468px] gap-12 items-center">
<Input <Typography variant="h4">Create your account</Typography>
label="Password (repeat)" <Typography className="-mt-8">This will set up the initial admin user account.</Typography>
name="passwordRepeat" <div className="mb-1 flex flex-col w-full gap-6">
type="password" <Input
/> label="Username"
name="username"
type="text"
/>
<Input
label="Password"
name="password"
type="password"
/>
<Input
label="Password (repeat)"
name="passwordRepeat"
type="password"
/>
</div>
</div> </div>
</div> </div>
); );
@@ -60,9 +76,11 @@ function UserStep() {
function SettingsStep() { function SettingsStep() {
return ( return (
<div className="flex flex-col items-center"> <div className="flex flex-col size-full items-center">
<Typography variant="h4">Settings</Typography> <div className="flex flex-col w-1/2 min-w-[468px] gap-12 items-center">
<Typography>Configure your settings</Typography> <Typography variant="h4">Settings</Typography>
<Typography>Configure your settings</Typography>
</div>
</div> </div>
); );
} }
@@ -77,13 +95,13 @@ const SetupView = () => (
sleep(300).then(() => alert(JSON.stringify(values, null, 2))) sleep(300).then(() => alert(JSON.stringify(values, null, 2)))
} }
> >
<WizardStep <WizardStep icon={<HandWaving/>}>
// @ts-ignore
icon={<HandWaving/>}>
<WelcomeStep/> <WelcomeStep/>
</WizardStep> </WizardStep>
<WizardStep icon={<Palette/>}>
<ThemeStep/>
</WizardStep>
<WizardStep <WizardStep
// @ts-ignore
validationSchema={Yup.object({ validationSchema={Yup.object({
username: Yup.string() username: Yup.string()
.required('Required'), .required('Required'),
@@ -98,10 +116,7 @@ const SetupView = () => (
> >
<UserStep/> <UserStep/>
</WizardStep> </WizardStep>
<WizardStep <WizardStep icon={<GearFine/>}>
//@ts-ignore
icon={<GearFine/>}
>
<SettingsStep/> <SettingsStep/>
</WizardStep> </WizardStep>
</Wizard> </Wizard>
+110
View File
@@ -53,6 +53,7 @@
"rollup-plugin-brotli": "3.1.0", "rollup-plugin-brotli": "3.1.0",
"rollup-plugin-visualizer": "5.9.2", "rollup-plugin-visualizer": "5.9.2",
"strip-css-comments": "5.0.0", "strip-css-comments": "5.0.0",
"tailwind-material-colors": "^2.0.2",
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"transform-ast": "2.4.4", "transform-ast": "2.4.4",
"typescript": "5.3.3", "typescript": "5.3.3",
@@ -2829,6 +2830,12 @@
"react-dom": "^16 || ^17 || ^18" "react-dom": "^16 || ^17 || ^18"
} }
}, },
"node_modules/@material/material-color-utilities": {
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/@material/material-color-utilities/-/material-color-utilities-0.2.7.tgz",
"integrity": "sha512-0FCeqG6WvK4/Cc06F/xXMd/pv4FeisI0c1tUpBbfhA2n9Y8eZEv4Karjbmf2ZqQCPUWMrGp8A571tCjizxoTiQ==",
"dev": true
},
"node_modules/@motionone/animation": { "node_modules/@motionone/animation": {
"version": "10.17.0", "version": "10.17.0",
"resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.17.0.tgz", "resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.17.0.tgz",
@@ -5597,6 +5604,19 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1" "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
} }
}, },
"node_modules/color": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1",
"color-string": "^1.9.0"
},
"engines": {
"node": ">=12.5.0"
}
},
"node_modules/color-convert": { "node_modules/color-convert": {
"version": "1.9.3", "version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -5612,6 +5632,34 @@
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"dev": true "dev": true
}, },
"node_modules/color-string": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
"dev": true,
"dependencies": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
}
},
"node_modules/color/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/colorette": { "node_modules/colorette": {
"version": "2.0.20", "version": "2.0.20",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
@@ -9247,6 +9295,21 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
"dev": true,
"dependencies": {
"is-arrayish": "^0.3.1"
}
},
"node_modules/simple-swizzle/node_modules/is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
"dev": true
},
"node_modules/sonic-boom": { "node_modules/sonic-boom": {
"version": "3.8.0", "version": "3.8.0",
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.0.tgz", "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.0.tgz",
@@ -9703,11 +9766,49 @@
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
"integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="
}, },
"node_modules/tailwind-material-colors": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/tailwind-material-colors/-/tailwind-material-colors-2.0.2.tgz",
"integrity": "sha512-T2Nf+o8MOCRBFFYAtt0Ddi3paXNzxwIHuHAawZXNOzCA2ZkcMtxhd+fbPExLyxtM4Y8P0cLY0lWHU46fiB9IaQ==",
"dev": true,
"dependencies": {
"@material/material-color-utilities": "^0.2.0",
"tailwind-material-surfaces": "^3.0.2",
"tailwind-mode-aware-colors": "1.4.2"
},
"peerDependencies": {
"tailwindcss": "^3.0.0"
}
},
"node_modules/tailwind-material-surfaces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/tailwind-material-surfaces/-/tailwind-material-surfaces-3.0.2.tgz",
"integrity": "sha512-ZElG3IPbSrFr2nzxQ++JvNYtJ2ffDfCc/9idAezXYznHrf9vpO0rV9gH1dPUVmXVSkhHerL34Boz14FGZ2H8uw==",
"dev": true,
"dependencies": {
"tailwindcss-color-mix": "0.0.8"
},
"peerDependencies": {
"tailwindcss": "^3.0.0"
}
},
"node_modules/tailwind-merge": { "node_modules/tailwind-merge": {
"version": "1.8.1", "version": "1.8.1",
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.8.1.tgz", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.8.1.tgz",
"integrity": "sha512-+fflfPxvHFr81hTJpQ3MIwtqgvefHZFUHFiIHpVIRXvG/nX9+gu2P7JNlFu2bfDMJ+uHhi/pUgzaYacMoXv+Ww==" "integrity": "sha512-+fflfPxvHFr81hTJpQ3MIwtqgvefHZFUHFiIHpVIRXvG/nX9+gu2P7JNlFu2bfDMJ+uHhi/pUgzaYacMoXv+Ww=="
}, },
"node_modules/tailwind-mode-aware-colors": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/tailwind-mode-aware-colors/-/tailwind-mode-aware-colors-1.4.2.tgz",
"integrity": "sha512-9PbWN/glpWZypyJvtTgerfDI8XS300hgNTFLheoFFm51ZLNly/tFE2oCtMFm9DkIVGwS3tBn3STTUXdRQYX1SA==",
"dev": true,
"dependencies": {
"color": "^4.2.3"
},
"peerDependencies": {
"tailwindcss": "^3.1.0"
}
},
"node_modules/tailwindcss": { "node_modules/tailwindcss": {
"version": "3.4.1", "version": "3.4.1",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz",
@@ -9745,6 +9846,15 @@
"node": ">=14.0.0" "node": ">=14.0.0"
} }
}, },
"node_modules/tailwindcss-color-mix": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/tailwindcss-color-mix/-/tailwindcss-color-mix-0.0.8.tgz",
"integrity": "sha512-agTN7BAA9eny2WABRX6jpHciQoBoSYGkZfLM1PpHAyNBPErQKFWUm1o1HjwNsZkilJL3hhUi2+H9MoCg+HT89A==",
"dev": true,
"peerDependencies": {
"tailwindcss": "^3.0.0"
}
},
"node_modules/temp-dir": { "node_modules/temp-dir": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz",
+2 -1
View File
@@ -48,6 +48,7 @@
"rollup-plugin-brotli": "3.1.0", "rollup-plugin-brotli": "3.1.0",
"rollup-plugin-visualizer": "5.9.2", "rollup-plugin-visualizer": "5.9.2",
"strip-css-comments": "5.0.0", "strip-css-comments": "5.0.0",
"tailwind-material-colors": "^2.0.2",
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"transform-ast": "2.4.4", "transform-ast": "2.4.4",
"typescript": "5.3.3", "typescript": "5.3.3",
@@ -130,6 +131,6 @@
"workbox-core": "7.0.0", "workbox-core": "7.0.0",
"workbox-precaching": "7.0.0" "workbox-precaching": "7.0.0"
}, },
"hash": "4a15d7e79e5a115970b30fcf67cfdd2edab987a6419ed93f8f80f6969d884b1d" "hash": "9223d4c6f4cf3a6fd28b853d824fddc00718dbc1a3474e986f4dc2d69f294b6e"
} }
} }
+16 -11
View File
@@ -1,15 +1,20 @@
import withMT from "@material-tailwind/react/utils/withMT"; import withMT from "@material-tailwind/react/utils/withMT";
import {withMaterialColors} from "tailwind-material-colors";
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
export default withMT({ export default withMaterialColors(withMT({
content: ["./frontend/index.html", "./frontend/**/*.{js,ts,jsx,tsx}"], content: ["./frontend/index.html", "./frontend/**/*.{js,ts,jsx,tsx}"],
theme: { theme: {
extend: { extend: {
colors: { colors: {
'gf-primary': '#2332c8', 'gf-primary': '#2332c8',
'gf-secondary': '#6441a5' 'gf-secondary': '#6441a5'
}, },
}
}, },
}, plugins: [],
plugins: [], }),
}); {
primary: "#2332c8"
}
);