172 lines
5.2 KiB
TypeScript
172 lines
5.2 KiB
TypeScript
import { Box, Group, Overlay, Stack, Switch, Text } from '@mantine/core';
|
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
|
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
|
import { useEffect, useState } from 'react';
|
|
import { FaDice } from 'react-icons/fa';
|
|
import { FiChevronRight } from 'react-icons/fi';
|
|
import type { Theme } from 'types';
|
|
import SettingsHeader from '../Shared/SettingsHeader';
|
|
import ThemeCard from './ThemeCard';
|
|
import ThemeModal from './ThemeModal';
|
|
function ThemesSettings() {
|
|
const themesEndpoint = 'api/themes';
|
|
const backgroundsEndpoint = 'api/backgrounds';
|
|
const { data: allThemes } = useQueryAPI({
|
|
endpoint: 'api/themes',
|
|
});
|
|
const { data: backgroundData, isFetched: isBackgroundFetched } = useQueryAPI({
|
|
endpoint: backgroundsEndpoint,
|
|
});
|
|
const { data: themePlaylists } = useQueryAPI({
|
|
endpoint: 'api/themePlaylists',
|
|
});
|
|
const { mutateAsync } = useMutationAPI();
|
|
const [opened, { open, close }] = useDisclosure(false);
|
|
const [colorId, setColorId] = useState<string>('');
|
|
const [colorValue, setColorValue] = useState('#000000');
|
|
const [backgroundList, setBackgroundList] = useState<string[]>(['None']);
|
|
const [selectedTheme, setSelectedTheme] = useState<any>({});
|
|
const [pickerOpen, { open: openPicker, close: closePicker }] = useDisclosure(false);
|
|
const [searchValue, setSearchValue] = useState('');
|
|
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
|
const { currentTheme, setCurrentTheme, theme, isMobile, setCurrentThemePlaylist } =
|
|
useCommonHooks();
|
|
|
|
const handleOpen = (theme: Theme) => {
|
|
setSelectedTheme(theme);
|
|
open();
|
|
};
|
|
|
|
const handleClose = () => {
|
|
close();
|
|
closePicker();
|
|
setSelectedTheme({});
|
|
};
|
|
|
|
const handleSaveTheme = () => {
|
|
mutateAsync({
|
|
method: selectedTheme.id === undefined ? 'POST' : 'PATCH',
|
|
endpoint: themesEndpoint,
|
|
body: selectedTheme,
|
|
});
|
|
close();
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (backgroundData && isBackgroundFetched) {
|
|
setBackgroundList(['None', ...backgroundData]);
|
|
}
|
|
}, [backgroundData, isBackgroundFetched]);
|
|
return (
|
|
<Stack>
|
|
<ThemeModal
|
|
opened={opened}
|
|
handleClose={handleClose}
|
|
selectedTheme={selectedTheme}
|
|
setSelectedTheme={setSelectedTheme}
|
|
theme={theme}
|
|
setColorId={setColorId}
|
|
colorId={colorId}
|
|
setColorValue={setColorValue}
|
|
openPicker={openPicker}
|
|
backgroundList={backgroundList}
|
|
pickerOpen={pickerOpen}
|
|
colorValue={colorValue}
|
|
closePicker={closePicker}
|
|
handleSaveTheme={handleSaveTheme}
|
|
/>
|
|
<Stack h={'100%'} w={'100%'}>
|
|
<SettingsHeader
|
|
setDragging={undefined}
|
|
openModal={open}
|
|
title={'Themes'}
|
|
tooltip={{
|
|
title: 'Themes can be created here and applied to the homepage.',
|
|
highlightList: ['Clients', 'homepage'],
|
|
description:
|
|
'Themes are combinations of 5 colors and a background image, and can be added to a playlist. If a theme has been disabled, it will only be disabled with random/shuffle is enabled. If a theme is part of a playlist, it will appear while the playlist is active, regardless of random/shuffle.',
|
|
}}
|
|
searchValue={searchValue}
|
|
setSearchValue={setSearchValue}
|
|
/>
|
|
<Switch
|
|
label={
|
|
isMobile ? (
|
|
<FaDice size={20} color={theme.primaryColor} />
|
|
) : (
|
|
<Text c={theme.primaryColor}>Random Theme</Text>
|
|
)
|
|
}
|
|
labelPosition='left'
|
|
pos={'absolute'}
|
|
right={isMobile ? '2rem' : '1rem'}
|
|
top={isMobile ? '9.5rem' : '2rem'}
|
|
checked={currentTheme === 'random'}
|
|
onChange={(e) => {
|
|
setCurrentTheme(e.target.checked ? 'random' : theme.name);
|
|
setCurrentThemePlaylist('All');
|
|
}}
|
|
color={theme.primaryColor}
|
|
style={{
|
|
zIndex: 1,
|
|
}}
|
|
/>
|
|
<Group justify='center' align='center' pos={'relative'} mt={'10rem'}>
|
|
<Overlay
|
|
display={currentTheme === 'random' ? 'flex' : 'none'}
|
|
blur={5}
|
|
style={{
|
|
borderRadius: '10px',
|
|
marginTop: '-15px',
|
|
marginBottom: '-10px',
|
|
boxShadow: '0px 0px 10px 3px rgba(0, 0, 0, .8)',
|
|
}}
|
|
pos={'absolute'}
|
|
/>
|
|
{allThemes
|
|
?.filter((a: Theme) =>
|
|
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()),
|
|
)
|
|
.map((cardTheme: Theme) => (
|
|
<Group key={cardTheme.name} pos={'relative'}>
|
|
{cardTheme.name === currentTheme && (
|
|
<FiChevronRight
|
|
style={{
|
|
position: 'absolute',
|
|
left: -14,
|
|
zIndex: 1,
|
|
fontSize: '2em',
|
|
fontWeight: 'bold',
|
|
borderRadius: '50%',
|
|
backgroundColor: cardTheme.borderColor,
|
|
color:
|
|
cardTheme.borderColor === cardTheme.primaryColor
|
|
? cardTheme.accentColor
|
|
: cardTheme.primaryColor,
|
|
}}
|
|
/>
|
|
)}
|
|
<Box
|
|
style={{
|
|
zIndex:
|
|
currentTheme === 'random' && cardTheme.name === theme.name
|
|
? 200
|
|
: 0,
|
|
}}
|
|
>
|
|
<ThemeCard
|
|
allThemes={allThemes}
|
|
cardTheme={cardTheme}
|
|
handleOpen={handleOpen}
|
|
themePlaylists={themePlaylists}
|
|
/>
|
|
</Box>
|
|
</Group>
|
|
))}
|
|
</Group>
|
|
</Stack>
|
|
</Stack>
|
|
);
|
|
}
|
|
export default ThemesSettings;
|