Updates to the stack for performance
All checks were successful
Deploy to production / build (push) Successful in 18s
All checks were successful
Deploy to production / build (push) Successful in 18s
This commit is contained in:
@@ -119,8 +119,6 @@ sudo pm2 start server.cjs
|
|||||||
- New Carosel on weather description
|
- New Carosel on weather description
|
||||||
- Updates to weather modal
|
- Updates to weather modal
|
||||||
- Add mantine-led for monitoring status (https://gfazioli.github.io/mantine-led)
|
- 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-scene/
|
||||||
- Explore https://gfazioli.github.io/mantine-window/
|
- Explore https://gfazioli.github.io/mantine-window/
|
||||||
- Upgrade spinners/loaders (https://gfazioli.github.io/mantine-spinner#example-random)
|
- Upgrade spinners/loaders (https://gfazioli.github.io/mantine-spinner#example-random)
|
||||||
@@ -1,14 +1,15 @@
|
|||||||
import { Parallax } from '@gfazioli/mantine-parallax';
|
import { Parallax } from '@gfazioli/mantine-parallax';
|
||||||
import { Reflection } from '@gfazioli/mantine-reflection';
|
import { Reflection } from '@gfazioli/mantine-reflection';
|
||||||
import { ActionIcon, Box, Group, Stack, Text } from '@mantine/core';
|
import { ActionIcon, Box, Group, Overlay, Popover, Stack, Text } from '@mantine/core';
|
||||||
import { useDebouncedCallback, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedCallback, useDisclosure, useLongPress } from '@mantine/hooks';
|
||||||
import { DeleteItemModal } from 'components';
|
import { DeleteItemModal } from 'components';
|
||||||
import { useCommonHooks } from 'hooks';
|
import { useCommonHooks } from 'hooks';
|
||||||
import { useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { FiEdit, FiTrash } from 'react-icons/fi';
|
import { FiEdit, FiTrash } from 'react-icons/fi';
|
||||||
import { textClasses } from 'styles';
|
import { textClasses } from 'styles';
|
||||||
import type { Theme, ThemePlaylist } from 'types';
|
import type { Theme, ThemePlaylist } from 'types';
|
||||||
import { ThemeCardPreview } from '../../Themes/ThemeCard';
|
import { ThemeCardPreview } from '../../Themes/ThemeCard';
|
||||||
|
import { ThemeModalContent } from '../../Themes/ThemeModal/components/ThemeModalContent';
|
||||||
|
|
||||||
export function ThemePlaylistStack({
|
export function ThemePlaylistStack({
|
||||||
cardPlaylist,
|
cardPlaylist,
|
||||||
@@ -19,16 +20,14 @@ export function ThemePlaylistStack({
|
|||||||
handleOpen: (cardPlaylist: ThemePlaylist) => void;
|
handleOpen: (cardPlaylist: ThemePlaylist) => void;
|
||||||
allThemes: Theme[];
|
allThemes: Theme[];
|
||||||
}) {
|
}) {
|
||||||
|
const [pressed, setPressed] = useState<boolean>(false);
|
||||||
|
const handlers = useLongPress(() => {
|
||||||
|
setPressed(true);
|
||||||
|
});
|
||||||
const [hover, setHover] = useState(false);
|
const [hover, setHover] = useState(false);
|
||||||
const { setThemeName, setCurrentThemePlaylist, handleDelete, currentUser } =
|
const { setThemeName, setCurrentThemePlaylist, handleDelete, currentUser } =
|
||||||
useCommonHooks();
|
useCommonHooks();
|
||||||
const [indexOffset, setIndexOffset] = useState(0);
|
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 = {
|
const missingTheme = {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
name: 'default',
|
name: 'default',
|
||||||
@@ -43,6 +42,12 @@ export function ThemePlaylistStack({
|
|||||||
appShadowsEnabled: 0,
|
appShadowsEnabled: 0,
|
||||||
themeFont: currentUser.defaultFont,
|
themeFont: currentUser.defaultFont,
|
||||||
};
|
};
|
||||||
|
const [topTheme, setTopTheme] = useState<Theme>(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 = {
|
const presentationProps = {
|
||||||
initialRotationX: 60,
|
initialRotationX: 60,
|
||||||
@@ -62,7 +67,75 @@ export function ThemePlaylistStack({
|
|||||||
}
|
}
|
||||||
}, 75);
|
}, 75);
|
||||||
|
|
||||||
|
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 (
|
return (
|
||||||
|
<Box
|
||||||
|
key={theme.id}
|
||||||
|
style={{
|
||||||
|
transition: 'all 0.3s ease-in-out',
|
||||||
|
position: 'absolute',
|
||||||
|
top: 16 * (spot + 1),
|
||||||
|
zIndex: themeList.length - spot,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Parallax {...presentationProps}>
|
||||||
|
<ThemeCardPreview key={theme.id} cardTheme={theme} />
|
||||||
|
</Parallax>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
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 (
|
||||||
|
<Popover
|
||||||
|
withArrow
|
||||||
|
opened={pressed}
|
||||||
|
{...handlers}
|
||||||
|
arrowSize={16}
|
||||||
|
transitionProps={{ duration: 200, timingFunction: 'ease' }}
|
||||||
|
>
|
||||||
|
<Popover.Target>
|
||||||
<Reflection reflectionStart={75} reflectionEnd={100} shadowOpacity={0.25}>
|
<Reflection reflectionStart={75} reflectionEnd={100} shadowOpacity={0.25}>
|
||||||
<Stack
|
<Stack
|
||||||
gap={0}
|
gap={0}
|
||||||
@@ -100,61 +173,6 @@ export function ThemePlaylistStack({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{cardPlaylist?.name === 'Time of Day' ? (
|
|
||||||
<Stack
|
|
||||||
w='100%'
|
|
||||||
h='200px'
|
|
||||||
justify='center'
|
|
||||||
pos='relative'
|
|
||||||
gap={16}
|
|
||||||
style={{ overflow: 'hidden' }}
|
|
||||||
>
|
|
||||||
<Parallax
|
|
||||||
{...presentationProps}
|
|
||||||
style={{ position: 'absolute', top: -60, zIndex: 3 }}
|
|
||||||
>
|
|
||||||
<ThemeCardPreview
|
|
||||||
cardTheme={
|
|
||||||
allThemes.find((theme: Theme) => theme.id === Number(themeList[0])) ||
|
|
||||||
missingTheme
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Parallax>
|
|
||||||
<Parallax
|
|
||||||
{...presentationProps}
|
|
||||||
style={{ position: 'absolute', top: -60, zIndex: 2 }}
|
|
||||||
>
|
|
||||||
<ThemeCardPreview
|
|
||||||
cardTheme={
|
|
||||||
allThemes.find((theme: Theme) => theme.id === Number(themeList[1])) ||
|
|
||||||
missingTheme
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Parallax>
|
|
||||||
<Parallax
|
|
||||||
{...presentationProps}
|
|
||||||
style={{ position: 'absolute', top: -60, zIndex: 1 }}
|
|
||||||
>
|
|
||||||
<ThemeCardPreview
|
|
||||||
cardTheme={
|
|
||||||
allThemes.find((theme: Theme) => theme.id === Number(themeList[2])) ||
|
|
||||||
missingTheme
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Parallax>
|
|
||||||
<Parallax
|
|
||||||
{...presentationProps}
|
|
||||||
style={{ position: 'absolute', top: -60, zIndex: 0 }}
|
|
||||||
>
|
|
||||||
<ThemeCardPreview
|
|
||||||
cardTheme={
|
|
||||||
allThemes.find((theme: Theme) => theme.id === Number(themeList[3])) ||
|
|
||||||
missingTheme
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Parallax>
|
|
||||||
</Stack>
|
|
||||||
) : (
|
|
||||||
<Stack
|
<Stack
|
||||||
w='100%'
|
w='100%'
|
||||||
h='200px'
|
h='200px'
|
||||||
@@ -168,36 +186,61 @@ export function ThemePlaylistStack({
|
|||||||
}}
|
}}
|
||||||
onWheel={handleMouseWheel}
|
onWheel={handleMouseWheel}
|
||||||
>
|
>
|
||||||
{themeList
|
{cardPlaylist?.name === 'Time of Day' ? (
|
||||||
.sort((a: number, b: number) => (a > b ? 1 : -1))
|
<>
|
||||||
.map((item: number, index: number) => {
|
<Parallax
|
||||||
let spot = index + indexOffset;
|
{...presentationProps}
|
||||||
if (spot <= -1) {
|
style={{ position: 'absolute', top: 16 * 1, zIndex: 3 }}
|
||||||
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 (
|
|
||||||
<Box
|
|
||||||
key={theme.id}
|
|
||||||
style={{
|
|
||||||
transition: 'all 0.3s ease-in-out',
|
|
||||||
position: 'absolute',
|
|
||||||
top: 16 * (spot + 1),
|
|
||||||
zIndex: themeList.length - spot,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Parallax {...presentationProps}>
|
<ThemeCardPreview
|
||||||
<ThemeCardPreview key={theme.id} cardTheme={theme} />
|
cardTheme={
|
||||||
|
allThemes.find(
|
||||||
|
(theme: Theme) => theme.id === Number(themeList[0]),
|
||||||
|
) || missingTheme
|
||||||
|
}
|
||||||
|
/>
|
||||||
</Parallax>
|
</Parallax>
|
||||||
</Box>
|
<Parallax
|
||||||
);
|
{...presentationProps}
|
||||||
})}
|
style={{ position: 'absolute', top: 16 * 2, zIndex: 2 }}
|
||||||
</Stack>
|
>
|
||||||
|
<ThemeCardPreview
|
||||||
|
cardTheme={
|
||||||
|
allThemes.find(
|
||||||
|
(theme: Theme) => theme.id === Number(themeList[1]),
|
||||||
|
) || missingTheme
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Parallax>
|
||||||
|
<Parallax
|
||||||
|
{...presentationProps}
|
||||||
|
style={{ position: 'absolute', top: 16 * 3, zIndex: 1 }}
|
||||||
|
>
|
||||||
|
<ThemeCardPreview
|
||||||
|
cardTheme={
|
||||||
|
allThemes.find(
|
||||||
|
(theme: Theme) => theme.id === Number(themeList[2]),
|
||||||
|
) || missingTheme
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Parallax>
|
||||||
|
<Parallax
|
||||||
|
{...presentationProps}
|
||||||
|
style={{ position: 'absolute', top: 16 * 4, zIndex: 0 }}
|
||||||
|
>
|
||||||
|
<ThemeCardPreview
|
||||||
|
cardTheme={
|
||||||
|
allThemes.find(
|
||||||
|
(theme: Theme) => theme.id === Number(themeList[3]),
|
||||||
|
) || missingTheme
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Parallax>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
items
|
||||||
)}
|
)}
|
||||||
|
</Stack>
|
||||||
|
|
||||||
<Group
|
<Group
|
||||||
w={'100%'}
|
w={'100%'}
|
||||||
@@ -253,5 +296,29 @@ export function ThemePlaylistStack({
|
|||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Reflection>
|
</Reflection>
|
||||||
|
</Popover.Target>
|
||||||
|
<Popover.Dropdown
|
||||||
|
bg={'var(--mantine-color-primary-0)'}
|
||||||
|
p={0}
|
||||||
|
style={{ border: 'none' }}
|
||||||
|
onClick={() => {
|
||||||
|
pressed && setPressed(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Overlay
|
||||||
|
w={'calc(300%)'}
|
||||||
|
h={'calc(300%)'}
|
||||||
|
pos={'absolute'}
|
||||||
|
left={'-100%'}
|
||||||
|
top={'-100%'}
|
||||||
|
zIndex={-1}
|
||||||
|
opacity={0.8}
|
||||||
|
bg={
|
||||||
|
'radial-gradient(circle, var(--mantine-color-primary-0) 0%, transparent 60%)'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ThemeModalContent selectedTheme={topTheme} />
|
||||||
|
</Popover.Dropdown>
|
||||||
|
</Popover>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ export function ThemePreviewMiddleware({
|
|||||||
bg={'var(--mantine-color-primary-0)'}
|
bg={'var(--mantine-color-primary-0)'}
|
||||||
p={0}
|
p={0}
|
||||||
style={{ border: 'none' }}
|
style={{ border: 'none' }}
|
||||||
|
onClick={() => {
|
||||||
|
pressed && setPressed(false);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Overlay
|
<Overlay
|
||||||
w={'calc(300%)'}
|
w={'calc(300%)'}
|
||||||
|
|||||||
Reference in New Issue
Block a user