diff --git a/README.md b/README.md index 02d40c4..151192b 100644 --- a/README.md +++ b/README.md @@ -119,8 +119,6 @@ sudo pm2 start server.cjs - New Carosel on weather description - Updates to weather modal - Add mantine-led for monitoring status (https://gfazioli.github.io/mantine-led) -- Update Theme playlists - - Include mantine-reflection (https://gfazioli.github.io/mantine-reflection#example-complex-components) - Explore https://gfazioli.github.io/mantine-scene/ - Explore https://gfazioli.github.io/mantine-window/ - Upgrade spinners/loaders (https://gfazioli.github.io/mantine-spinner#example-random) \ No newline at end of file diff --git a/src/pages/settings/components/Theming/ThemePlaylists/components/ThemePlaylistStack.tsx b/src/pages/settings/components/Theming/ThemePlaylists/components/ThemePlaylistStack.tsx index 7a4dcee..afae879 100644 --- a/src/pages/settings/components/Theming/ThemePlaylists/components/ThemePlaylistStack.tsx +++ b/src/pages/settings/components/Theming/ThemePlaylists/components/ThemePlaylistStack.tsx @@ -1,14 +1,15 @@ import { Parallax } from '@gfazioli/mantine-parallax'; import { Reflection } from '@gfazioli/mantine-reflection'; -import { ActionIcon, Box, Group, Stack, Text } from '@mantine/core'; -import { useDebouncedCallback, useDisclosure } from '@mantine/hooks'; +import { ActionIcon, Box, Group, Overlay, Popover, Stack, Text } from '@mantine/core'; +import { useDebouncedCallback, useDisclosure, useLongPress } from '@mantine/hooks'; import { DeleteItemModal } from 'components'; import { useCommonHooks } from 'hooks'; -import { useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { FiEdit, FiTrash } from 'react-icons/fi'; import { textClasses } from 'styles'; import type { Theme, ThemePlaylist } from 'types'; import { ThemeCardPreview } from '../../Themes/ThemeCard'; +import { ThemeModalContent } from '../../Themes/ThemeModal/components/ThemeModalContent'; export function ThemePlaylistStack({ cardPlaylist, @@ -19,16 +20,14 @@ export function ThemePlaylistStack({ handleOpen: (cardPlaylist: ThemePlaylist) => void; allThemes: Theme[]; }) { + const [pressed, setPressed] = useState(false); + const handlers = useLongPress(() => { + setPressed(true); + }); const [hover, setHover] = useState(false); const { setThemeName, setCurrentThemePlaylist, handleDelete, currentUser } = useCommonHooks(); const [indexOffset, setIndexOffset] = useState(0); - const defaultLists = ['All', 'Backgrounds', 'No Backgrounds']; - const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); - const themeList = JSON.parse( - cardPlaylist?.themeList?.name === 'Time of Day' ? '[]' : cardPlaylist.themeList, - ); - const missingTheme = { id: undefined, name: 'default', @@ -43,6 +42,12 @@ export function ThemePlaylistStack({ appShadowsEnabled: 0, themeFont: currentUser.defaultFont, }; + const [topTheme, setTopTheme] = useState(missingTheme); + const defaultLists = ['All', 'Backgrounds', 'No Backgrounds']; + const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); + const themeList = JSON.parse( + cardPlaylist?.themeList?.name === 'Time of Day' ? '[]' : cardPlaylist.themeList, + ); const presentationProps = { initialRotationX: 60, @@ -62,196 +67,258 @@ export function ThemePlaylistStack({ } }, 75); - return ( - - setHover(true)} - onMouseLeave={() => setHover(false)} + const sortedItems = useMemo( + () => + (themeList.length > 0 && + themeList.sort((a: number, b: number) => (a > b ? 1 : -1))) || + [], + [themeList], + ); + + const items = sortedItems?.map((item: number, index: number) => { + let spot = index + indexOffset; + if (spot <= -1) { + spot = index + indexOffset + themeList.length; + } else if (spot >= themeList.length) { + spot = index + indexOffset - themeList.length; + } else { + spot = index + indexOffset; + } + const theme: any = allThemes.find((theme: Theme) => theme.id === item); + return ( + { - setCurrentThemePlaylist(cardPlaylist.name); - setThemeName('random'); + transition: 'all 0.3s ease-in-out', + position: 'absolute', + top: 16 * (spot + 1), + zIndex: themeList.length - spot, }} > - {modalOpened && ( - handleDelete(cardPlaylist, 'api/themePlaylists')} - title='Delete Theme Playlist' - body={ - - Are you sure you want to delete this Theme Playlist? - {`"${cardPlaylist.name}"`} - This action cannot be undone! - - } - /> - )} - {cardPlaylist?.name === 'Time of Day' ? ( - - - theme.id === Number(themeList[0])) || - missingTheme - } - /> - - - theme.id === Number(themeList[1])) || - missingTheme - } - /> - - - theme.id === Number(themeList[2])) || - missingTheme - } - /> - - - theme.id === Number(themeList[3])) || - missingTheme - } - /> - - - ) : ( - - {themeList - .sort((a: number, b: number) => (a > b ? 1 : -1)) - .map((item: number, index: number) => { - let spot = index + indexOffset; - if (spot <= -1) { - spot = index + indexOffset + themeList.length; - } else if (spot >= themeList.length) { - spot = index + indexOffset - themeList.length; - } else { - spot = index + indexOffset; - } - const theme: any = allThemes.find((theme: Theme) => theme.id === item); - return ( - - - - - - ); - })} - - )} + + + + + ); + }); - - { + if (cardPlaylist.name === 'Time of Day') { + setTopTheme( + allThemes.find( + (t: Theme) => t.id === Number(themeList[Math.floor(new Date().getHours() / 6)]), + ) || missingTheme, + ); + } else if (indexOffset > 0 && indexOffset < themeList.length) { + setTopTheme( + allThemes.find( + (theme: Theme) => theme.id === themeList[themeList.length - indexOffset], + ) || missingTheme, + ); + } else if (indexOffset < 0 && Math.abs(indexOffset) < themeList.length) { + setTopTheme( + allThemes.find((theme: Theme) => theme.id === themeList[Math.abs(indexOffset)]) || + missingTheme, + ); + } else if (indexOffset === 0) { + setTopTheme( + allThemes.find((theme: Theme) => theme.id === themeList[0]) || missingTheme, + ); + } + }, [indexOffset]); + + return ( + + + + setHover(true)} + onMouseLeave={() => setHover(false)} style={{ - paddingRight: '.25rem', - paddingLeft: '.25rem', - backgroundColor: 'var(--mantine-color-border-0)', - borderRadius: '4px', - color: 'var(--mantine-color-primary-0)', + background: hover + ? 'radial-gradient(var(--mantine-color-search-0), transparent)' + : undefined, + cursor: 'pointer', + borderRadius: '100%', + }} + onClick={() => { + setCurrentThemePlaylist(cardPlaylist.name); + setThemeName('random'); }} > - {cardPlaylist.name} - - - {!defaultLists.includes(cardPlaylist.name) && ( - handleDelete(cardPlaylist, 'api/themePlaylists')} + title='Delete Theme Playlist' + body={ + + Are you sure you want to delete this Theme Playlist? + {`"${cardPlaylist.name}"`} + This action cannot be undone! + + } + /> + )} + + {cardPlaylist?.name === 'Time of Day' ? ( + <> + + theme.id === Number(themeList[0]), + ) || missingTheme + } + /> + + + theme.id === Number(themeList[1]), + ) || missingTheme + } + /> + + + theme.id === Number(themeList[2]), + ) || missingTheme + } + /> + + + theme.id === Number(themeList[3]), + ) || missingTheme + } + /> + + + ) : ( + items + )} + + + + { - handleOpen(cardPlaylist); + color: 'var(--mantine-color-primary-0)', }} > - - - )} - {cardPlaylist.default === 0 && ( - { - openModal(); - }} - > - - - )} - - - - + {cardPlaylist.name} + + + {!defaultLists.includes(cardPlaylist.name) && ( + { + handleOpen(cardPlaylist); + }} + > + + + )} + {cardPlaylist.default === 0 && ( + { + openModal(); + }} + > + + + )} + + + + + + { + pressed && setPressed(false); + }} + > + + + + ); } diff --git a/src/pages/settings/components/Theming/Themes/ThemePreviewMiddleware.tsx b/src/pages/settings/components/Theming/Themes/ThemePreviewMiddleware.tsx index 8341238..1f6aecb 100644 --- a/src/pages/settings/components/Theming/Themes/ThemePreviewMiddleware.tsx +++ b/src/pages/settings/components/Theming/Themes/ThemePreviewMiddleware.tsx @@ -61,6 +61,9 @@ export function ThemePreviewMiddleware({ bg={'var(--mantine-color-primary-0)'} p={0} style={{ border: 'none' }} + onClick={() => { + pressed && setPressed(false); + }} >