Added user themes section to Theme settings
This commit is contained in:
parent
89bd921875
commit
48e28b9abd
10 changed files with 136 additions and 44 deletions
|
@ -0,0 +1,7 @@
|
|||
.ThemeBuilder {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.Buttons button:not(:last-child) {
|
||||
margin-right: 10px;
|
||||
}
|
|
@ -1,3 +1,21 @@
|
|||
export const ThemeBuilder = (): JSX.Element => {
|
||||
return <h1>theme builder</h1>;
|
||||
import { Theme } from '../../../../interfaces';
|
||||
import { Button } from '../../../UI';
|
||||
import { ThemeGrid } from '../ThemeGrid/ThemeGrid';
|
||||
import classes from './ThemeBuilder.module.css';
|
||||
|
||||
interface Props {
|
||||
themes: Theme[];
|
||||
}
|
||||
|
||||
export const ThemeBuilder = ({ themes }: Props): JSX.Element => {
|
||||
return (
|
||||
<div className={classes.ThemeBuilder}>
|
||||
<ThemeGrid themes={themes} />
|
||||
|
||||
<div className={classes.Buttons}>
|
||||
<Button>Create new theme</Button>
|
||||
{themes.length && <Button>Edit user themes</Button>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -15,13 +15,17 @@ import { ThemeGrid } from './ThemeGrid/ThemeGrid';
|
|||
|
||||
// Other
|
||||
import { State } from '../../../store/reducers';
|
||||
import { inputHandler, themeSettingsTemplate } from '../../../utility';
|
||||
import {
|
||||
inputHandler,
|
||||
parseThemeToPAB,
|
||||
themeSettingsTemplate,
|
||||
} from '../../../utility';
|
||||
|
||||
export const Themer = (): JSX.Element => {
|
||||
const {
|
||||
auth: { isAuthenticated },
|
||||
config: { loading, config },
|
||||
theme: { themes },
|
||||
theme: { themes, userThemes },
|
||||
} = useSelector((state: State) => state);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
@ -44,7 +48,7 @@ export const Themer = (): JSX.Element => {
|
|||
e.preventDefault();
|
||||
|
||||
// Save settings
|
||||
await updateConfig(formData);
|
||||
await updateConfig({ ...formData });
|
||||
};
|
||||
|
||||
// Input handler
|
||||
|
@ -65,8 +69,14 @@ export const Themer = (): JSX.Element => {
|
|||
<SettingsHeadline text="App themes" />
|
||||
{!themes.length ? <Spinner /> : <ThemeGrid themes={themes} />}
|
||||
|
||||
{/* <SettingsHeadline text="User themes" />
|
||||
<ThemeBuilder /> */}
|
||||
{!userThemes.length ? (
|
||||
isAuthenticated && 'auth and empty'
|
||||
) : (
|
||||
<Fragment>
|
||||
<SettingsHeadline text="User themes" />
|
||||
<ThemeBuilder themes={userThemes} />
|
||||
</Fragment>
|
||||
)}
|
||||
|
||||
{isAuthenticated && (
|
||||
<form onSubmit={formSubmitHandler}>
|
||||
|
@ -79,9 +89,9 @@ export const Themer = (): JSX.Element => {
|
|||
value={formData.defaultTheme}
|
||||
onChange={(e) => inputChangeHandler(e)}
|
||||
>
|
||||
{themes.map((theme: Theme, idx) => (
|
||||
<option key={idx} value={theme.name}>
|
||||
{theme.name}
|
||||
{[...themes, ...userThemes].map((theme: Theme, idx) => (
|
||||
<option key={idx} value={parseThemeToPAB(theme.colors)}>
|
||||
{theme.isCustom && '+'} {theme.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
|
|
@ -7,4 +7,5 @@ export interface ThemeColors {
|
|||
export interface Theme {
|
||||
name: string;
|
||||
colors: ThemeColors;
|
||||
isCustom: boolean;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import { Action } from '../actions';
|
||||
import { ActionType } from '../action-types';
|
||||
import { Theme } from '../../interfaces/Theme';
|
||||
import { arrayPartition } from '../../utility';
|
||||
|
||||
interface ThemeState {
|
||||
themes: Theme[];
|
||||
userThemes: Theme[];
|
||||
}
|
||||
|
||||
const initialState: ThemeState = {
|
||||
themes: [],
|
||||
userThemes: [],
|
||||
};
|
||||
|
||||
export const themeReducer = (
|
||||
|
@ -16,7 +19,16 @@ export const themeReducer = (
|
|||
): ThemeState => {
|
||||
switch (action.type) {
|
||||
case ActionType.fetchThemes: {
|
||||
return { themes: action.payload };
|
||||
const [themes, userThemes] = arrayPartition<Theme>(
|
||||
action.payload,
|
||||
(e) => !e.isCustom
|
||||
);
|
||||
|
||||
return {
|
||||
...state,
|
||||
themes,
|
||||
userThemes,
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
|
|
11
client/src/utility/arrayPartition.ts
Normal file
11
client/src/utility/arrayPartition.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
export const arrayPartition = <T>(
|
||||
arr: T[],
|
||||
isValid: (e: T) => boolean
|
||||
): T[][] => {
|
||||
let pass: T[] = [];
|
||||
let fail: T[] = [];
|
||||
|
||||
arr.forEach((e) => (isValid(e) ? pass : fail).push(e));
|
||||
|
||||
return [pass, fail];
|
||||
};
|
|
@ -13,3 +13,4 @@ export * from './decodeToken';
|
|||
export * from './applyAuth';
|
||||
export * from './escapeRegex';
|
||||
export * from './parseTheme';
|
||||
export * from './arrayPartition';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class Logger {
|
||||
log(message, level = 'INFO') {
|
||||
console.log(`[${this.generateTimestamp()}] [${level}] ${message}`)
|
||||
console.log(`[${this.generateTimestamp()}] [${level}] ${message}`);
|
||||
}
|
||||
|
||||
generateTimestamp() {
|
||||
|
@ -20,7 +20,9 @@ class Logger {
|
|||
// Timezone
|
||||
const tz = -d.getTimezoneOffset() / 60;
|
||||
|
||||
return `${year}-${month}-${day} ${hour}:${minutes}:${seconds}.${miliseconds} UTC${tz >= 0 ? '+' + tz : tz}`;
|
||||
return `${year}-${month}-${day} ${hour}:${minutes}:${seconds}.${miliseconds} UTC${
|
||||
tz >= 0 ? '+' + tz : tz
|
||||
}`;
|
||||
}
|
||||
|
||||
parseDate(date, ms = false) {
|
||||
|
@ -36,4 +38,4 @@ class Logger {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = Logger;
|
||||
module.exports = Logger;
|
||||
|
|
|
@ -46,7 +46,8 @@
|
|||
"background": "#1a1a1a",
|
||||
"primary": "#FFFDEA",
|
||||
"accent": "#5c5c5c"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "gazette",
|
||||
|
@ -54,7 +55,8 @@
|
|||
"background": "#F2F7FF",
|
||||
"primary": "#000000",
|
||||
"accent": "#5c5c5c"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "espresso",
|
||||
|
@ -62,7 +64,8 @@
|
|||
"background": "#21211F",
|
||||
"primary": "#D1B59A",
|
||||
"accent": "#4E4E4E"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "cab",
|
||||
|
@ -70,7 +73,8 @@
|
|||
"background": "#F6D305",
|
||||
"primary": "#1F1F1F",
|
||||
"accent": "#424242"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "cloud",
|
||||
|
@ -78,7 +82,8 @@
|
|||
"background": "#f1f2f0",
|
||||
"primary": "#35342f",
|
||||
"accent": "#37bbe4"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "lime",
|
||||
|
@ -86,7 +91,8 @@
|
|||
"background": "#263238",
|
||||
"primary": "#AABBC3",
|
||||
"accent": "#aeea00"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "white",
|
||||
|
@ -94,7 +100,8 @@
|
|||
"background": "#ffffff",
|
||||
"primary": "#222222",
|
||||
"accent": "#dddddd"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "tron",
|
||||
|
@ -102,7 +109,8 @@
|
|||
"background": "#242B33",
|
||||
"primary": "#EFFBFF",
|
||||
"accent": "#6EE2FF"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "blues",
|
||||
|
@ -110,7 +118,8 @@
|
|||
"background": "#2B2C56",
|
||||
"primary": "#EFF1FC",
|
||||
"accent": "#6677EB"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "passion",
|
||||
|
@ -118,7 +127,8 @@
|
|||
"background": "#f5f5f5",
|
||||
"primary": "#12005e",
|
||||
"accent": "#8e24aa"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "chalk",
|
||||
|
@ -126,7 +136,8 @@
|
|||
"background": "#263238",
|
||||
"primary": "#AABBC3",
|
||||
"accent": "#FF869A"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "paper",
|
||||
|
@ -134,7 +145,8 @@
|
|||
"background": "#F8F6F1",
|
||||
"primary": "#4C432E",
|
||||
"accent": "#AA9A73"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "neon",
|
||||
|
@ -142,7 +154,8 @@
|
|||
"background": "#091833",
|
||||
"primary": "#EFFBFF",
|
||||
"accent": "#ea00d9"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "pumpkin",
|
||||
|
@ -150,7 +163,8 @@
|
|||
"background": "#2d3436",
|
||||
"primary": "#EFFBFF",
|
||||
"accent": "#ffa500"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "onedark",
|
||||
|
@ -158,7 +172,8 @@
|
|||
"background": "#282c34",
|
||||
"primary": "#dfd9d6",
|
||||
"accent": "#98c379"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
"background": "#1a1a1a",
|
||||
"primary": "#FFFDEA",
|
||||
"accent": "#5c5c5c"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "gazette",
|
||||
|
@ -14,7 +15,8 @@
|
|||
"background": "#F2F7FF",
|
||||
"primary": "#000000",
|
||||
"accent": "#5c5c5c"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "espresso",
|
||||
|
@ -22,7 +24,8 @@
|
|||
"background": "#21211F",
|
||||
"primary": "#D1B59A",
|
||||
"accent": "#4E4E4E"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "cab",
|
||||
|
@ -30,7 +33,8 @@
|
|||
"background": "#F6D305",
|
||||
"primary": "#1F1F1F",
|
||||
"accent": "#424242"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "cloud",
|
||||
|
@ -38,7 +42,8 @@
|
|||
"background": "#f1f2f0",
|
||||
"primary": "#35342f",
|
||||
"accent": "#37bbe4"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "lime",
|
||||
|
@ -46,7 +51,8 @@
|
|||
"background": "#263238",
|
||||
"primary": "#AABBC3",
|
||||
"accent": "#aeea00"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "white",
|
||||
|
@ -54,7 +60,8 @@
|
|||
"background": "#ffffff",
|
||||
"primary": "#222222",
|
||||
"accent": "#dddddd"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "tron",
|
||||
|
@ -62,7 +69,8 @@
|
|||
"background": "#242B33",
|
||||
"primary": "#EFFBFF",
|
||||
"accent": "#6EE2FF"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "blues",
|
||||
|
@ -70,7 +78,8 @@
|
|||
"background": "#2B2C56",
|
||||
"primary": "#EFF1FC",
|
||||
"accent": "#6677EB"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "passion",
|
||||
|
@ -78,7 +87,8 @@
|
|||
"background": "#f5f5f5",
|
||||
"primary": "#12005e",
|
||||
"accent": "#8e24aa"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "chalk",
|
||||
|
@ -86,7 +96,8 @@
|
|||
"background": "#263238",
|
||||
"primary": "#AABBC3",
|
||||
"accent": "#FF869A"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "paper",
|
||||
|
@ -94,7 +105,8 @@
|
|||
"background": "#F8F6F1",
|
||||
"primary": "#4C432E",
|
||||
"accent": "#AA9A73"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "neon",
|
||||
|
@ -102,7 +114,8 @@
|
|||
"background": "#091833",
|
||||
"primary": "#EFFBFF",
|
||||
"accent": "#ea00d9"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "pumpkin",
|
||||
|
@ -110,7 +123,8 @@
|
|||
"background": "#2d3436",
|
||||
"primary": "#EFFBFF",
|
||||
"accent": "#ffa500"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
},
|
||||
{
|
||||
"name": "onedark",
|
||||
|
@ -118,7 +132,8 @@
|
|||
"background": "#282c34",
|
||||
"primary": "#dfd9d6",
|
||||
"accent": "#98c379"
|
||||
}
|
||||
},
|
||||
"isCustom": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue