diff --git a/package-lock.json b/package-lock.json index 29b0121..3927809 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "react": "^19.1.0", "react-dom": "^19.1.0", "react-icons": "^5.5.0", - "react-router-dom": "^7.7.0", + "react-router-dom": "^7.7.1", "recharts": "^3.1.0" }, "devDependencies": { @@ -3683,9 +3683,9 @@ } }, "node_modules/react-router": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.7.0.tgz", - "integrity": "sha512-3FUYSwlvB/5wRJVTL/aavqHmfUKe0+Xm9MllkYgGo9eDwNdkvwlJGjpPxono1kCycLt6AnDTgjmXvK3/B4QGuw==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.7.1.tgz", + "integrity": "sha512-jVKHXoWRIsD/qS6lvGveckwb862EekvapdHJN/cGmzw40KnJH5gg53ujOJ4qX6EKIK9LSBfFed/xiQ5yeXNrUA==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -3705,12 +3705,12 @@ } }, "node_modules/react-router-dom": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.7.0.tgz", - "integrity": "sha512-wwGS19VkNBkneVh9/YD0pK3IsjWxQUVMDD6drlG7eJpo1rXBtctBqDyBm/k+oKHRAm1x9XWT3JFC82QI9YOXXA==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.7.1.tgz", + "integrity": "sha512-bavdk2BA5r3MYalGKZ01u8PGuDBloQmzpBZVhDLrOOv1N943Wq6dcM9GhB3x8b7AbqPMEezauv4PeGkAJfy7FQ==", "license": "MIT", "dependencies": { - "react-router": "7.7.0" + "react-router": "7.7.1" }, "engines": { "node": ">=20.0.0" diff --git a/package.json b/package.json index 64a791a..791baa6 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "react": "^19.1.0", "react-dom": "^19.1.0", "react-icons": "^5.5.0", - "react-router-dom": "^7.7.0", + "react-router-dom": "^7.7.1", "recharts": "^3.1.0" }, "devDependencies": { diff --git a/src/pages/settings/components/Theming/Themes/ThemeCard.tsx b/src/pages/settings/components/Theming/Themes/ThemeCard.tsx index 4f11d10..71976ad 100644 --- a/src/pages/settings/components/Theming/Themes/ThemeCard.tsx +++ b/src/pages/settings/components/Theming/Themes/ThemeCard.tsx @@ -12,14 +12,16 @@ import { MiniAppItem, MiniGroupItem, ThemeManagementPill } from '.'; export function ThemeCard({ cardTheme, - handleOpen, allThemes, themePlaylists, + setSelectedTheme, + openThemeModal, }: { cardTheme: Theme; - handleOpen: (cardTheme: Theme) => void; allThemes: Theme[]; themePlaylists: ThemePlaylist[]; + setSelectedTheme: (theme: Theme) => void; + openThemeModal: () => void; }) { const { hovered, ref: hoverRef } = useHover(); const { ref, width } = useElementSize(); @@ -29,6 +31,10 @@ export function ThemeCard({ const [hoverPreview, setHoverPreview] = useDebouncedState(false, 1000); const [transition, setTransition] = useDebouncedState(false, 200); + const handleOpen = (theme: Theme) => { + setSelectedTheme(theme); + openThemeModal(); + }; return ( void; - selectedTheme: Theme; - setSelectedTheme: (selectedTheme: Theme) => void; - openPicker: () => void; - backgroundList: string[]; - pickerOpen: boolean; - closePicker: () => void; - handleSaveTheme: () => void; - isNew: boolean; - setIsNew: (isNew: boolean) => void; - allThemes: Theme[]; -}) { - const [pressed, setPressed] = useState(false); - const handlers = useLongPress(() => { - setPressed(true); - }); - const { isMobile, theme, getObjectDiff } = useCommonHooks(); - const viewportRef = useRef(null); - const [query, setQuery] = useState(''); - const [hovered, setHovered] = useState(-1); - const [colorId, setColorId] = useState(''); - const [colorValue, setColorValue] = useState('#000000'); - const [defaultTheme, setDefaultTheme] = useState({ ...selectedTheme }); - const [designerTheme, setDesignerTheme] = useState({ - ...selectedTheme, - }); - const filtered = backgroundList.filter((item: string) => - item.toLowerCase().includes(query.toLowerCase()), - ); - const [duplicate, setDuplicate] = useState(false); - - const [backgroundPicker, { open: openBackgroundPicker, close: closeBackgroundPicker }] = - useDisclosure(false); - - const re = /(?:\.([^.]+))?$/; - const items = filtered.map((item: string, index: number) => { - return ( - - setDesignerTheme({ - ...designerTheme, - backgroundImage: item, - }) - } - > - - - {item.replace(/\.[^/.]+$/, '')} - - {item !== 'None' && ( - - {re.exec(item.toUpperCase())?.[1]} - - )} - - - ); - }); - - const handleSwatchClick = () => { - closeBackgroundPicker(); - openPicker(); - setDesignerTheme(selectedTheme); - }; - - useEffect(() => { - setDesignerTheme(selectedTheme); - if (defaultTheme.id !== selectedTheme.id) { - setDefaultTheme(selectedTheme); - } - }, [selectedTheme]); - - return ( - { - handleClose(); - setDuplicate(false); - }} - fullScreen={isMobile} - centered - keepMounted={false} - > - - - - {!isNew && ( - - Name: - - setSelectedTheme({ ...selectedTheme, name: e.target.value }) - } - styles={{ - label: { - color: 'var(--mantine-color-primary-0)', - }, - input: { - color: selectedTheme.primaryColor, - backgroundColor: selectedTheme.backgroundColor, - border: 'none', - borderBottom: '1px solid var(--mantine-color-primary-0)', - }, - }} - /> - - )} - - - - {isNew ? ( - - {!duplicate ? ( - <> - - Please choose an option: - - - - {}} - allThemes={[]} - themePlaylists={[]} - /> - - - - - {}} - allThemes={[]} - themePlaylists={[]} - /> - - - - - - - ) : ( - - - {allThemes?.map((miniTheme: Theme) => { - return ( - { - !pressed && setSelectedTheme(miniTheme); - setPressed(false); - }} - > - {}} - /> - - ); - })} - - - - - - - - - - )} - - ) : ( - <> - - - - - { - setColorId('primaryColor'); - setColorValue(selectedTheme.primaryColor); - handleSwatchClick(); - }} - color={selectedTheme.primaryColor} - bd={`1px solid ${selectedTheme.primaryColor}`} - pos={'absolute'} - top={'6.25rem'} - left={'1.5rem'} - /> - - - { - setColorId('accentColor'); - setColorValue(selectedTheme.accentColor); - handleSwatchClick(); - }} - color={selectedTheme.accentColor} - bd={`1px solid ${selectedTheme.primaryColor}`} - pos={'absolute'} - bottom={'6rem'} - left={'11rem'} - /> - - - { - setColorId('backgroundColor'); - setColorValue(selectedTheme.backgroundColor); - handleSwatchClick(); - }} - color={selectedTheme.backgroundColor} - bd={`1px solid ${selectedTheme.primaryColor}`} - pos={'absolute'} - bottom={'10rem'} - right={'3.5rem'} - /> - - - { - setColorId('borderColor'); - setColorValue(selectedTheme.borderColor); - handleSwatchClick(); - }} - color={selectedTheme.borderColor} - bd={`1px solid ${selectedTheme.primaryColor}`} - pos={'absolute'} - top={'4.5rem'} - right={'15%'} - /> - - - { - setColorId('searchColor'); - setColorValue(selectedTheme.searchColor); - handleSwatchClick(); - }} - color={selectedTheme.searchColor} - bd={`1px solid ${selectedTheme.primaryColor}`} - pos={'absolute'} - top={'3.25rem'} - left={'6.5rem'} - /> - - - { - closePicker(); - openBackgroundPicker(); - setDesignerTheme(selectedTheme); - }} - pos={'absolute'} - right={0} - > - - - - - - {pickerOpen && ( - - - Change{' '} - { - BackgroundProperties[ - colorId as keyof typeof BackgroundProperties - ] - } - - {colorId === 'backgroundColor' && ( - { - setColorValue(e); - setDesignerTheme({ - ...designerTheme, - backgroundColor: e, - }); - }} - format={'hex'} - w={'90%'} - mb={'1.5rem'} - /> - )} - {colorId !== 'backgroundColor' && ( - { - setColorValue(e); - setDesignerTheme({ - ...designerTheme, - [colorId]: e, - }); - }} - format={'hexa'} - w={'90%'} - /> - )} - setColorValue(e.target.value)} - /> - - - - - - )} - {backgroundPicker && ( - - - { - setQuery(''); - }} - /> - } - onChange={(event) => { - setQuery(event.currentTarget.value); - setHovered(-1); - }} - onKeyDown={(event) => { - if (event.key === 'ArrowDown') { - event.preventDefault(); - setHovered((current) => { - const nextIndex = - current + 1 >= filtered.length ? current : current + 1; - viewportRef.current - ?.querySelectorAll('[data-list-item]') - ?.[nextIndex]?.scrollIntoView({ block: 'nearest' }); - return nextIndex; - }); - } - - if (event.key === 'ArrowUp') { - event.preventDefault(); - setHovered((current) => { - const nextIndex = current - 1 < 0 ? current : current - 1; - viewportRef.current - ?.querySelectorAll('[data-list-item]') - ?.[nextIndex]?.scrollIntoView({ block: 'nearest' }); - return nextIndex; - }); - } - }} - /> - - - - {items} - - - - - - - - )} - {!pickerOpen && !backgroundPicker && ( - - - { - setSelectedTheme({ - ...selectedTheme, - textShadowsEnabled: e.target.checked ? 1 : 0, - }); - }} - styles={{ - root: { width: '50%' }, - body: { - width: '100%', - display: 'flex', - justifyContent: 'space-between', - }, - }} - /> - { - setSelectedTheme({ - ...selectedTheme, - appShadowsEnabled: e.target.checked ? 1 : 0, - }); - }} - styles={{ - root: { width: '50%' }, - body: { - width: '100%', - display: 'flex', - justifyContent: 'space-between', - }, - }} - /> - - {JSON.stringify(defaultTheme) !== JSON.stringify(selectedTheme) && ( - <> - Changes: - - - {getObjectDiff(defaultTheme, designerTheme) !== null && - Object.keys( - getObjectDiff(defaultTheme, designerTheme), - ).map((key: any) => { - return ( - - - { - BackgroundProperties[ - key as keyof typeof BackgroundProperties - ] - } - - {key === 'name' && ( - - {defaultTheme[key as keyof Theme]} - → - {designerTheme[key as keyof Theme]} - - )} - {key === 'backgroundImage' && ( - - - → - - - )} - {key.includes('Color') && ( - - - → - - - )} - {key.includes('Shadow') && ( - - {defaultTheme[key as keyof Theme] === 0 ? ( - Off - ) : ( - On - )} - → - {designerTheme[key as keyof Theme] === 0 ? ( - Off - ) : ( - On - )} - - )} - - ); - })} - - - - )} - - - )} - - - - - - - - )} - - - - ); -} diff --git a/src/pages/settings/components/Theming/Themes/ThemeModal/NewThemeStarter.tsx b/src/pages/settings/components/Theming/Themes/ThemeModal/NewThemeStarter.tsx new file mode 100644 index 0000000..c8b3c16 --- /dev/null +++ b/src/pages/settings/components/Theming/Themes/ThemeModal/NewThemeStarter.tsx @@ -0,0 +1,256 @@ +import { Box, Button, Divider, Group, Overlay, Stack, Text } from '@mantine/core'; +import { useLongPress } from '@mantine/hooks'; +import { useState } from 'react'; +import { FaArrowRight } from 'react-icons/fa'; +import { textClasses } from 'styles'; +import type { Theme } from 'types'; +import { ThemeCard } from '../ThemeCard'; +import { ThemeMiniCard } from '../ThemeMiniCard'; +import { ThemePreviewMiddleware } from '../ThemePreviewMiddleware'; + +export function NewThemeStarter({ + allThemes, + setIsNew, + duplicate, + setDuplicate, + selectedTheme, + setSelectedTheme, +}: { + allThemes: Theme[]; + setIsNew: (isNew: boolean) => void; + duplicate: boolean; + setDuplicate: (duplicate: boolean) => void; + selectedTheme: Theme; + setSelectedTheme: (selectedTheme: Theme) => void; +}) { + const [pressed, setPressed] = useState(false); + const handlers = useLongPress(() => { + setPressed(true); + }); + const randomTheme = { + ...allThemes[Math.floor(Math.random() * allThemes.length)], + randomEnabled: 1, + }; + return ( + + {!duplicate ? ( + <> + + Please choose an option: + + + + {}} + /> + + + + + {}} + /> + + + + + + + ) : ( + + + {allThemes?.map((miniTheme: Theme) => { + return ( + { + !pressed && setSelectedTheme(miniTheme); + setPressed(false); + }} + > + {}} + /> + + ); + })} + + + + + + + + + + )} + + ); +} diff --git a/src/pages/settings/components/Theming/Themes/ThemeModal/ThemeEditor.tsx b/src/pages/settings/components/Theming/Themes/ThemeModal/ThemeEditor.tsx new file mode 100644 index 0000000..98736a0 --- /dev/null +++ b/src/pages/settings/components/Theming/Themes/ThemeModal/ThemeEditor.tsx @@ -0,0 +1,643 @@ +import { + ActionIcon, + Button, + Checkbox, + ColorPicker, + ColorSwatch, + Group, + Image, + ScrollArea, + Stack, + Text, + TextInput, + Tooltip, + UnstyledButton, +} from '@mantine/core'; +import { useDisclosure } from '@mantine/hooks'; +import { useCommonHooks } from 'hooks'; +import { useRef, useState } from 'react'; +import { FaShuffle } from 'react-icons/fa6'; +import { FiImage, FiSave, FiShuffle, FiX } from 'react-icons/fi'; +import { scrollAreaClasses, textClasses, textInputClasses } from 'styles'; +import { BackgroundProperties, type Theme } from 'types'; +import { ThemeModalContent } from '../ThemeModalContent'; + +export function ThemeEditor({ + backgroundList, + defaultTheme, + designerTheme, + setDesignerTheme, + selectedTheme, + setSelectedTheme, + pickerOpen, + openPicker, + closePicker, + handleClose, + handleSaveTheme, + setDuplicate, +}: { + backgroundList: string[]; + defaultTheme: Theme; + designerTheme: Theme; + setDesignerTheme: (theme: Theme) => void; + selectedTheme: Theme; + setSelectedTheme: (theme: Theme) => void; + pickerOpen: boolean; + openPicker: () => void; + closePicker: () => void; + handleClose: () => void; + handleSaveTheme: () => void; + setDuplicate: (duplicate: boolean) => void; +}) { + const [query, setQuery] = useState(''); + const [hovered, setHovered] = useState(-1); + const { isMobile, theme, getObjectDiff } = useCommonHooks(); + const viewportRef = useRef(null); + const [colorId, setColorId] = useState(''); + const [colorValue, setColorValue] = useState('#000000'); + + const re = /(?:\.([^.]+))?$/; + const [backgroundPicker, { open: openBackgroundPicker, close: closeBackgroundPicker }] = + useDisclosure(false); + const filtered = backgroundList.filter((item: string) => + item.toLowerCase().includes(query.toLowerCase()), + ); + const items = filtered.map((item: string, index: number) => { + return ( + + setDesignerTheme({ + ...designerTheme, + backgroundImage: item, + }) + } + > + + + {item.replace(/\.[^/.]+$/, '')} + + {item !== 'None' && ( + + {re.exec(item.toUpperCase())?.[1]} + + )} + + + ); + }); + + const handleSwatchClick = () => { + closeBackgroundPicker(); + openPicker(); + setDesignerTheme(selectedTheme); + }; + + const randomColor = (withAlpha?: boolean) => { + const letters = '0123456789ABCDEF'; + let color = '#'; + for (let i = 0; i < (withAlpha ? 8 : 6); i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; + }; + return ( + <> + + + + + { + setColorId('primaryColor'); + setColorValue(selectedTheme.primaryColor); + handleSwatchClick(); + }} + color={selectedTheme.primaryColor} + bd={`1px solid ${selectedTheme.primaryColor}`} + pos={'absolute'} + top={'6.25rem'} + left={'1.5rem'} + /> + + + { + setColorId('accentColor'); + setColorValue(selectedTheme.accentColor); + handleSwatchClick(); + }} + color={selectedTheme.accentColor} + bd={`1px solid ${selectedTheme.primaryColor}`} + pos={'absolute'} + bottom={'6rem'} + left={'11rem'} + /> + + + { + setColorId('backgroundColor'); + setColorValue(selectedTheme.backgroundColor); + handleSwatchClick(); + }} + color={selectedTheme.backgroundColor} + bd={`1px solid ${selectedTheme.primaryColor}`} + pos={'absolute'} + bottom={'10rem'} + right={'3.5rem'} + /> + + + { + setColorId('borderColor'); + setColorValue(selectedTheme.borderColor); + handleSwatchClick(); + }} + color={selectedTheme.borderColor} + bd={`1px solid ${selectedTheme.primaryColor}`} + pos={'absolute'} + top={'4.5rem'} + right={'15%'} + /> + + + { + setColorId('searchColor'); + setColorValue(selectedTheme.searchColor); + handleSwatchClick(); + }} + color={selectedTheme.searchColor} + bd={`1px solid ${selectedTheme.primaryColor}`} + pos={'absolute'} + top={'3.25rem'} + left={'6.5rem'} + /> + + + { + closePicker(); + openBackgroundPicker(); + setDesignerTheme(selectedTheme); + }} + pos={'absolute'} + right={0} + > + + + + + + {pickerOpen && ( + + + Change{' '} + {BackgroundProperties[colorId as keyof typeof BackgroundProperties]} + + {colorId === 'backgroundColor' && ( + { + setColorValue(e); + setDesignerTheme({ + ...designerTheme, + backgroundColor: e, + }); + }} + format={'hex'} + w={'90%'} + mb={'1.5rem'} + /> + )} + {colorId !== 'backgroundColor' && ( + { + setColorValue(e); + setDesignerTheme({ + ...designerTheme, + [colorId]: e, + }); + }} + format={'hexa'} + w={'90%'} + /> + )} + setColorValue(e.target.value)} + /> + + + + + + + )} + {backgroundPicker && ( + + + { + setQuery(''); + }} + /> + } + onChange={(event) => { + setQuery(event.currentTarget.value); + setHovered(-1); + }} + onKeyDown={(event) => { + if (event.key === 'ArrowDown') { + event.preventDefault(); + setHovered((current) => { + const nextIndex = + current + 1 >= filtered.length ? current : current + 1; + viewportRef.current + ?.querySelectorAll('[data-list-item]') + ?.[nextIndex]?.scrollIntoView({ block: 'nearest' }); + return nextIndex; + }); + } + + if (event.key === 'ArrowUp') { + event.preventDefault(); + setHovered((current) => { + const nextIndex = current - 1 < 0 ? current : current - 1; + viewportRef.current + ?.querySelectorAll('[data-list-item]') + ?.[nextIndex]?.scrollIntoView({ block: 'nearest' }); + return nextIndex; + }); + } + }} + /> + + + + {items} + + + + + + + + )} + {!pickerOpen && !backgroundPicker && ( + + + { + setSelectedTheme({ + ...selectedTheme, + textShadowsEnabled: e.target.checked ? 1 : 0, + }); + }} + styles={{ + root: { width: '50%' }, + body: { + width: '100%', + display: 'flex', + justifyContent: 'space-between', + }, + }} + /> + { + setSelectedTheme({ + ...selectedTheme, + appShadowsEnabled: e.target.checked ? 1 : 0, + }); + }} + styles={{ + root: { width: '50%' }, + body: { + width: '100%', + display: 'flex', + justifyContent: 'space-between', + }, + }} + /> + + {JSON.stringify(defaultTheme) !== JSON.stringify(selectedTheme) && ( + <> + + Changes: + + + + {getObjectDiff(defaultTheme, designerTheme) !== null && + Object.keys(getObjectDiff(defaultTheme, designerTheme)).map( + (key: any) => { + return ( + + + { + BackgroundProperties[ + key as keyof typeof BackgroundProperties + ] + } + + {key === 'name' && ( + + {defaultTheme[key as keyof Theme]} + → + {designerTheme[key as keyof Theme]} + + )} + {key === 'backgroundImage' && ( + + + → + + + )} + {key.includes('Color') && ( + + + → + + + )} + {key.includes('Shadow') && ( + + {defaultTheme[key as keyof Theme] === 0 ? ( + Off + ) : ( + On + )} + → + {designerTheme[key as keyof Theme] === 0 ? ( + Off + ) : ( + On + )} + + )} + + ); + }, + )} + + + + )} + + + + + + + + )} + + + + + + + + ); +} diff --git a/src/pages/settings/components/Theming/Themes/ThemeModal/ThemeModal.tsx b/src/pages/settings/components/Theming/Themes/ThemeModal/ThemeModal.tsx new file mode 100644 index 0000000..472a3fd --- /dev/null +++ b/src/pages/settings/components/Theming/Themes/ThemeModal/ThemeModal.tsx @@ -0,0 +1,148 @@ +import { Group, Modal, Text, TextInput } from '@mantine/core'; +import { useDisclosure } from '@mantine/hooks'; +import { useCommonHooks, useMutationAPI } from 'hooks'; +import { useEffect, useState } from 'react'; +import { modalClasses, textInputClasses } from 'styles'; +import type { Theme } from 'types'; +import { NewThemeStarter } from './NewThemeStarter'; +import { ThemeEditor } from './ThemeEditor'; + +export function ThemeModal({ + opened, + selectedTheme, + setSelectedTheme, + backgroundList, + isNew, + setIsNew, + allThemes, + closeThemeModal, +}: { + opened: boolean; + selectedTheme: Theme; + setSelectedTheme: (selectedTheme: Theme) => void; + backgroundList: string[]; + isNew: boolean; + setIsNew: (isNew: boolean) => void; + allThemes: Theme[]; + closeThemeModal: () => void; +}) { + const themesEndpoint = 'api/themes'; + const { isMobile } = useCommonHooks(); + const [defaultTheme, setDefaultTheme] = useState({ ...selectedTheme }); + const [designerTheme, setDesignerTheme] = useState({ + ...selectedTheme, + }); + const { mutateAsync } = useMutationAPI(); + + const [pickerOpen, { open: openPicker, close: closePicker }] = useDisclosure(false); + const [duplicate, setDuplicate] = useState(false); + + const handleClose = () => { + closeThemeModal(); + closePicker(); + setIsNew(false); + setSelectedTheme({ + id: undefined, + name: 'default', + backgroundImage: 'none', + backgroundColor: '#EEEEEE', + searchColor: '#00000033', + primaryColor: '#222222', + accentColor: '#5c5c5c', + borderColor: '#5c5c5c', + randomEnabled: 1, + textShadowsEnabled: 0, + appShadowsEnabled: 0, + }); + }; + + const handleSaveTheme = () => { + mutateAsync({ + method: selectedTheme?.id === undefined ? 'POST' : 'PATCH', + endpoint: themesEndpoint, + body: selectedTheme, + }); + handleClose(); + }; + + useEffect(() => { + setDesignerTheme(selectedTheme); + if (defaultTheme.id !== selectedTheme.id) { + setDefaultTheme(selectedTheme); + } + }, [selectedTheme]); + + return ( + { + handleClose(); + setDuplicate(false); + }} + fullScreen={isMobile} + centered + keepMounted={true} + > + + + + {!isNew && ( + + Name: + + setSelectedTheme({ ...selectedTheme, name: e.target.value }) + } + styles={{ + label: { + color: 'var(--mantine-color-primary-0)', + }, + input: { + color: selectedTheme.primaryColor, + backgroundColor: selectedTheme.backgroundColor, + border: 'none', + borderBottom: '1px solid var(--mantine-color-primary-0)', + }, + }} + /> + + )} + + + + {isNew ? ( + + ) : ( + + )} + + + + ); +} diff --git a/src/pages/settings/components/Theming/Themes/Themes.tsx b/src/pages/settings/components/Theming/Themes/Themes.tsx index 4ae62cd..1bd5cfb 100644 --- a/src/pages/settings/components/Theming/Themes/Themes.tsx +++ b/src/pages/settings/components/Theming/Themes/Themes.tsx @@ -1,7 +1,17 @@ -import { Box, Button, Group, Overlay, Stack, Switch, Text, Tooltip } from '@mantine/core'; +import { + Box, + Button, + Divider, + Group, + Overlay, + Stack, + Switch, + Text, + Tooltip, +} from '@mantine/core'; import { useDebouncedValue, useDisclosure } from '@mantine/hooks'; import { NoItemsFound, SettingsHeader } from 'components'; -import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks'; +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'; @@ -10,10 +20,9 @@ import { switchClasses, textClasses } from 'styles'; import type { Theme, ThemePlaylist } from 'types'; import { BackgroundModal } from '../Backgrounds'; import { ThemeCard } from './ThemeCard'; -import { ThemeModal } from './ThemeModal'; +import { ThemeModal } from './ThemeModal/ThemeModal'; export function Themes() { - const themesEndpoint = 'api/themes'; const backgroundsEndpoint = 'api/backgrounds'; const { data: allThemeData, isFetched: isAllThemeDataFetched } = useQueryAPI({ endpoint: 'api/themes', @@ -26,7 +35,6 @@ export function Themes() { endpoint: 'api/themePlaylists', }); const [themePlaylists, setThemePlaylists] = useState([]); - const { mutateAsync } = useMutationAPI(); const [themeModalOpened, { open: openThemeModal, close: closeThemeModal }] = useDisclosure(false); const [ @@ -48,7 +56,6 @@ export function Themes() { textShadowsEnabled: 0, appShadowsEnabled: 0, }); - const [pickerOpen, { open: openPicker, close: closePicker }] = useDisclosure(false); const [searchValue, setSearchValue] = useState(''); const [debouncedSearch] = useDebouncedValue(searchValue, 500); const [isLoading, setIsLoading] = useState(false); @@ -63,44 +70,11 @@ export function Themes() { setCurrentThemePlaylist, } = useCommonHooks(); - const handleOpen = (theme: Theme) => { - setSelectedTheme(theme); - openThemeModal(); - }; - - const handleClose = () => { - closeThemeModal(); - closePicker(); - setIsNew(false); - setSelectedTheme({ - id: undefined, - name: 'default', - backgroundImage: 'none', - backgroundColor: '#EEEEEE', - searchColor: '#00000033', - primaryColor: '#222222', - accentColor: '#5c5c5c', - borderColor: '#5c5c5c', - randomEnabled: 1, - textShadowsEnabled: 0, - appShadowsEnabled: 0, - }); - }; - const handleNewTheme = () => { setIsNew(true); openThemeModal(); }; - const handleSaveTheme = () => { - mutateAsync({ - method: selectedTheme?.id === undefined ? 'POST' : 'PATCH', - endpoint: themesEndpoint, - body: selectedTheme, - }); - handleClose(); - }; - useEffect(() => { if (backgroundData && isBackgroundFetched) { setBackgroundList(['None', ...backgroundData]); @@ -146,17 +120,13 @@ export function Themes() { @@ -259,8 +230,8 @@ export function Themes() { style={{ backdropFilter: 'blur(5px) brightness(.75)', zIndex: 199, - paddingTop: isMobile ? '.5rem' : '1.5rem', - paddingBottom: '1.5rem', + paddingTop: '.5rem', + paddingBottom: '.5rem', paddingLeft: '1rem', paddingRight: '1rem', width: '100%', @@ -291,7 +262,16 @@ export function Themes() { > Current Settings: - + +