mirror of
https://github.com/pawelmalak/flame.git
synced 2026-03-10 06:23:11 +08:00
Added custom theme creator
This commit is contained in:
@@ -1,21 +1,69 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
// Redux
|
||||
import { useSelector } from 'react-redux';
|
||||
import { State } from '../../../../store/reducers';
|
||||
|
||||
// Other
|
||||
import { Theme } from '../../../../interfaces';
|
||||
import { Button } from '../../../UI';
|
||||
|
||||
// UI
|
||||
import { Button, Modal } from '../../../UI';
|
||||
import { ThemeGrid } from '../ThemeGrid/ThemeGrid';
|
||||
import classes from './ThemeBuilder.module.css';
|
||||
import { ThemeCreator } from './ThemeCreator';
|
||||
import { ThemeEditor } from './ThemeEditor';
|
||||
|
||||
interface Props {
|
||||
themes: Theme[];
|
||||
}
|
||||
|
||||
export const ThemeBuilder = ({ themes }: Props): JSX.Element => {
|
||||
const {
|
||||
auth: { isAuthenticated },
|
||||
} = useSelector((state: State) => state);
|
||||
|
||||
const [showModal, toggleShowModal] = useState(false);
|
||||
const [isInEdit, toggleIsInEdit] = useState(false);
|
||||
|
||||
return (
|
||||
<div className={classes.ThemeBuilder}>
|
||||
{/* MODALS */}
|
||||
<Modal isOpen={showModal} setIsOpen={() => toggleShowModal(!showModal)}>
|
||||
{isInEdit ? (
|
||||
<ThemeEditor modalHandler={() => toggleShowModal(!showModal)} />
|
||||
) : (
|
||||
<ThemeCreator modalHandler={() => toggleShowModal(!showModal)} />
|
||||
)}
|
||||
</Modal>
|
||||
|
||||
{/* USER THEMES */}
|
||||
<ThemeGrid themes={themes} />
|
||||
|
||||
<div className={classes.Buttons}>
|
||||
<Button>Create new theme</Button>
|
||||
{themes.length && <Button>Edit user themes</Button>}
|
||||
</div>
|
||||
{/* BUTTONS */}
|
||||
{isAuthenticated && (
|
||||
<div className={classes.Buttons}>
|
||||
<Button
|
||||
click={() => {
|
||||
toggleIsInEdit(false);
|
||||
toggleShowModal(!showModal);
|
||||
}}
|
||||
>
|
||||
Create new theme
|
||||
</Button>
|
||||
|
||||
{themes.length && (
|
||||
<Button
|
||||
click={() => {
|
||||
toggleIsInEdit(true);
|
||||
toggleShowModal(!showModal);
|
||||
}}
|
||||
>
|
||||
Edit user themes
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
.ColorsContainer {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
import { ChangeEvent, FormEvent, useState } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { actionCreators } from '../../../../store';
|
||||
import { Theme } from '../../../../interfaces';
|
||||
import { Button, InputGroup, ModalForm } from '../../../UI';
|
||||
|
||||
import classes from './ThemeCreator.module.css';
|
||||
|
||||
interface Props {
|
||||
modalHandler: () => void;
|
||||
}
|
||||
|
||||
export const ThemeCreator = ({ modalHandler }: Props): JSX.Element => {
|
||||
const { addTheme } = bindActionCreators(actionCreators, useDispatch());
|
||||
|
||||
const [formData, setFormData] = useState<Theme>({
|
||||
name: '',
|
||||
isCustom: true,
|
||||
colors: {
|
||||
primary: '#ffffff',
|
||||
accent: '#ffffff',
|
||||
background: '#ffffff',
|
||||
},
|
||||
});
|
||||
|
||||
const inputChangeHandler = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const { name, value } = e.target;
|
||||
|
||||
setFormData({
|
||||
...formData,
|
||||
[name]: value,
|
||||
});
|
||||
};
|
||||
|
||||
const setColor = ({
|
||||
target: { value, name },
|
||||
}: ChangeEvent<HTMLInputElement>) => {
|
||||
setFormData({
|
||||
...formData,
|
||||
colors: {
|
||||
...formData.colors,
|
||||
[name]: value,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const formHandler = (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
// add new theme
|
||||
addTheme(formData);
|
||||
|
||||
// close modal
|
||||
modalHandler();
|
||||
|
||||
// clear theme name
|
||||
setFormData({ ...formData, name: '' });
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalForm formHandler={formHandler} modalHandler={modalHandler}>
|
||||
<InputGroup>
|
||||
<label htmlFor="name">Theme name</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
id="name"
|
||||
placeholder="my_theme"
|
||||
required
|
||||
value={formData.name}
|
||||
onChange={(e) => inputChangeHandler(e)}
|
||||
/>
|
||||
</InputGroup>
|
||||
|
||||
<div className={classes.ColorsContainer}>
|
||||
<InputGroup>
|
||||
<label htmlFor="primary">Primary color</label>
|
||||
<input
|
||||
type="color"
|
||||
name="primary"
|
||||
id="primary"
|
||||
required
|
||||
value={formData.colors.primary}
|
||||
onChange={(e) => setColor(e)}
|
||||
/>
|
||||
</InputGroup>
|
||||
|
||||
<InputGroup>
|
||||
<label htmlFor="accent">Accent color</label>
|
||||
<input
|
||||
type="color"
|
||||
name="accent"
|
||||
id="accent"
|
||||
required
|
||||
value={formData.colors.accent}
|
||||
onChange={(e) => setColor(e)}
|
||||
/>
|
||||
</InputGroup>
|
||||
|
||||
<InputGroup>
|
||||
<label htmlFor="background">Background color</label>
|
||||
<input
|
||||
type="color"
|
||||
name="background"
|
||||
id="background"
|
||||
required
|
||||
value={formData.colors.background}
|
||||
onChange={(e) => setColor(e)}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
|
||||
<Button>Add theme</Button>
|
||||
</ModalForm>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
import { ModalForm } from '../../../UI';
|
||||
|
||||
interface Props {
|
||||
modalHandler: () => void;
|
||||
}
|
||||
|
||||
export const ThemeEditor = (props: Props): JSX.Element => {
|
||||
return (
|
||||
<ModalForm formHandler={() => {}} modalHandler={props.modalHandler}>
|
||||
<h1>edit</h1>
|
||||
</ModalForm>
|
||||
);
|
||||
};
|
||||
@@ -4,6 +4,7 @@ import { ChangeEvent, FormEvent, Fragment, useEffect, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { actionCreators } from '../../../store';
|
||||
import { State } from '../../../store/reducers';
|
||||
|
||||
// Typescript
|
||||
import { Theme, ThemeSettingsForm } from '../../../interfaces';
|
||||
@@ -14,7 +15,6 @@ import { ThemeBuilder } from './ThemeBuilder/ThemeBuilder';
|
||||
import { ThemeGrid } from './ThemeGrid/ThemeGrid';
|
||||
|
||||
// Other
|
||||
import { State } from '../../../store/reducers';
|
||||
import {
|
||||
inputHandler,
|
||||
parseThemeToPAB,
|
||||
@@ -82,7 +82,7 @@ export const Themer = (): JSX.Element => {
|
||||
<form onSubmit={formSubmitHandler}>
|
||||
<SettingsHeadline text="Other settings" />
|
||||
<InputGroup>
|
||||
<label htmlFor="defaultTheme">Default theme (for new users)</label>
|
||||
<label htmlFor="defaultTheme">Default theme for new users</label>
|
||||
<select
|
||||
id="defaultTheme"
|
||||
name="defaultTheme"
|
||||
|
||||
@@ -38,3 +38,7 @@
|
||||
resize: none;
|
||||
height: 50vh;
|
||||
}
|
||||
|
||||
.InputGroup input[type='color'] {
|
||||
all: unset;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user