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;
+30 -15
View File
@@ -1,17 +1,19 @@
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">
<div className="flex flex-col w-1/2 min-w-[468px] gap-12 items-center">
<Typography variant="h4">Welcome to Gameyfin 👋</Typography> <Typography variant="h4">Welcome to Gameyfin 👋</Typography>
<p className="place-content-center text-justify"> <p className="place-content-center text-justify">
Gameyfin is a cutting-edge software tailored for gamers seeking efficient management of their Gameyfin is a cutting-edge software tailored for gamers seeking efficient management of their
@@ -28,13 +30,26 @@ function WelcomeStep() {
</p> </p>
<Typography variant="h5">Let's get started!</Typography> <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">
<div className="size-full grid grid-cols-3 grid-rows-2 w-1/2 min-w-[468px] gap-12 items-center">
{Themes.all.map((theme => (
<ThemePreview key={theme.name} theme={theme}/>
)))}
</div>
</div>
)
}
function UserStep() {
return (
<div className="flex flex-col size-full items-center">
<div className="flex flex-col w-1/2 min-w-[468px] gap-12 items-center">
<Typography variant="h4">Create your account</Typography> <Typography variant="h4">Create your account</Typography>
<Typography className="-mt-8">This will set up the initial admin user account.</Typography> <Typography className="-mt-8">This will set up the initial admin user account.</Typography>
<div className="mb-1 flex flex-col w-full gap-6"> <div className="mb-1 flex flex-col w-full gap-6">
@@ -55,15 +70,18 @@ function UserStep() {
/> />
</div> </div>
</div> </div>
</div>
); );
} }
function SettingsStep() { function SettingsStep() {
return ( return (
<div className="flex flex-col items-center"> <div className="flex flex-col size-full items-center">
<div className="flex flex-col w-1/2 min-w-[468px] gap-12 items-center">
<Typography variant="h4">Settings</Typography> <Typography variant="h4">Settings</Typography>
<Typography>Configure your 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"
} }
} }
+8 -3
View File
@@ -1,7 +1,8 @@
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: {
@@ -9,7 +10,11 @@ export default withMT({
'gf-primary': '#2332c8', 'gf-primary': '#2332c8',
'gf-secondary': '#6441a5' 'gf-secondary': '#6441a5'
}, },
}, }
}, },
plugins: [], plugins: [],
}); }),
{
primary: "#2332c8"
}
);