import { Box, Button, Divider, Group, LoadingOverlay, Overlay, Stack, Switch, Text, Tooltip, } from '@mantine/core'; import { useDebouncedValue, useDisclosure } from '@mantine/hooks'; import { NoItemsFound, SettingsHeader } from 'components'; import { useCommonHooks, useQueryAPI } from 'hooks'; import { useEffect, useState } from 'react'; import { FaDice } from 'react-icons/fa'; import { FiChevronRight, FiEdit, FiMousePointer, FiStopCircle } from 'react-icons/fi'; import { useNavigate } from 'react-router-dom'; import { switchClasses, textClasses, toolTipClasses } from 'styles'; import type { Theme, ThemePlaylist } from 'types'; import { BackgroundModal } from '../Backgrounds'; import { ThemeCard } from './ThemeCard'; import { ThemeModal } from './ThemeModal'; export function Themes() { const { settings, updateSetting, theme, isMobile } = useCommonHooks(); const backgroundsEndpoint = 'api/backgrounds'; const { data: allThemeData, isFetching: allThemeDataIsFetching } = useQueryAPI({ endpoint: 'api/themes', }); const [searchValue, setSearchValue] = useState(''); const [debouncedSearch] = useDebouncedValue(searchValue, 500); const allThemes: Theme[] = allThemeData ?.filter((a: Theme) => a.name.toLowerCase().includes((debouncedSearch as string).toLowerCase()), ) .sort((a: Theme, b: Theme) => { switch (settings.themesSettingsSort) { case 'A>Z': return a.name.toLocaleLowerCase() > b.name.toLocaleLowerCase() ? 1 : -1; case 'Z>A': return a.name.toLocaleLowerCase() < b.name.toLocaleLowerCase() ? 1 : -1; case 'Newest': if (a.id && b.id) { return a.id < b.id ? 1 : -1; } return -1; case 'Oldest': if (a.id && b.id) { return a.id > b.id ? 1 : -1; } return -1; default: return 0; } }); const { data: backgroundData, isFetching: backgroundDataIsFetching } = useQueryAPI({ endpoint: backgroundsEndpoint, }); const { data: themePlaylistData } = useQueryAPI({ endpoint: 'api/themePlaylists', }); const themePlaylists: ThemePlaylist[] = themePlaylistData || []; const [themeModalOpened, { open: openThemeModal, close: closeThemeModal }] = useDisclosure(false); const [ backgroundModalOpened, { open: openBackgroundModal, close: closeBackgroundModal }, ] = useDisclosure(false); const backgroundList = backgroundData ? ['None', ...backgroundData.sort((a: string, b: string) => a.localeCompare(b))] : ['None']; const inUseBackgrounds: string[] = [ ...new Set( allThemes ?.filter((t) => { if (t.backgroundImage !== 'none') { return t.backgroundImage; } return undefined; }) .map((t) => t.backgroundImage), ), ] as string[]; const [selectedTheme, setSelectedTheme] = useState({ id: undefined, name: 'default', backgroundImage: 'none', backgroundColor: '#EEEEEE', searchColor: '#00000033', primaryColor: '#222222', accentColor: '#5c5c5c', borderColor: '#5c5c5c', randomEnabled: 1, textShadowsEnabled: 0, appShadowsEnabled: 0, themeFont: settings.defaultFont, }); const [isLoading, setIsLoading] = useState(false); const [isNew, setIsNew] = useState(false); const navigate = useNavigate(); const handleNewTheme = () => { setIsNew(true); openThemeModal(); }; useEffect(() => { if (debouncedSearch === searchValue) { setIsLoading(false); } }, [debouncedSearch]); return ( {themeModalOpened && ( )} {backgroundModalOpened && ( )} { updateSetting('themesSettingsSort', value); }} customSearchEnabled={false} /> {allThemes?.length > 0 ? ( allThemes.map((cardTheme: Theme) => ( {cardTheme.name === settings.theme && ( )} t.name.toLowerCase() === settings.currentThemePlaylist.toLowerCase(), ) ?.themeList.includes(`${cardTheme.id}`) || cardTheme.name === theme.name) ? 195 : 0, }} > )) ) : ( )} Current Settings: Active Playlist: {settings.currentThemePlaylist === 'All' ? 'All' : settings.currentThemePlaylist} ) : ( Shuffle Enabled ) } labelPosition='left' checked={settings.theme === 'random'} onChange={(e) => { updateSetting('theme', e.target.checked ? 'random' : theme.name); updateSetting('currentThemePlaylist', 'All'); }} className={switchClasses.default} classNames={switchClasses} style={{ zIndex: 250, }} /> ); }