More typing

This commit is contained in:
2025-04-15 22:16:27 -05:00
parent 78dec160b6
commit 4e9df7256b
27 changed files with 235 additions and 110 deletions

View File

@@ -30,7 +30,7 @@ function App() {
}); });
const { theme, setTheme, themeName, handleThemeChange, currentThemePlaylist } = const { theme, setTheme, themeName, handleThemeChange, currentThemePlaylist } =
useCommonHooks(); useCommonHooks();
const [loaded, setLoaded] = useState(false); const [loaded, setLoaded] = useState<boolean>(false);
const overrides = createTheme({ const overrides = createTheme({
white: theme?.backgroundColor, white: theme?.backgroundColor,
fontFamily: '-apple-system,Jost,BlinkMacSystemFont,Helvetica Neue,Roboto,sans-serif', fontFamily: '-apple-system,Jost,BlinkMacSystemFont,Helvetica Neue,Roboto,sans-serif',

View File

@@ -1,7 +1,7 @@
import { Stack } from '@mantine/core'; import { Stack } from '@mantine/core';
import { stackClasses } from 'styles'; import { stackClasses } from 'styles';
export function Loading({ loaded }: any) { export function Loading({ loaded }: { loaded: boolean }) {
return ( return (
<Stack <Stack
className={stackClasses.fadeAway} className={stackClasses.fadeAway}

View File

@@ -1,9 +1,10 @@
import { Box } from '@mantine/core'; import { Box } from '@mantine/core';
import type { Theme } from 'types';
export function ThemeProvider({ export function ThemeProvider({
theme, theme,
children, children,
}: { theme: any; children: React.ReactNode }) { }: { theme: Theme; children: React.ReactNode }) {
return ( return (
<Box <Box
style={{ style={{

View File

@@ -2,6 +2,7 @@ import { useLocalStorage } from '@mantine/hooks';
import { appTheme } from 'contexts'; import { appTheme } from 'contexts';
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import { useState } from 'react'; import { useState } from 'react';
import type { Theme } from 'types';
import { useMutationAPI } from './useAPI'; import { useMutationAPI } from './useAPI';
export function useCommonHooks() { export function useCommonHooks() {
@@ -80,17 +81,17 @@ export function useCommonHooks() {
'i', 'i',
); // fragment locator ); // fragment locator
const reorder = (list: any, startIndex: any, endIndex: any) => { const reorder = (list: any, startIndex: number, endIndex: number) => {
const result = Array.from(list); const result = Array.from(list);
const [removed]: any = result.splice(startIndex, 1); const [removed]: any = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed); result.splice(endIndex, 0, removed);
return result; return result;
}; };
const handleThemeChange = (themes: any, save: any) => { const handleThemeChange = (themes: Theme[], save: boolean) => {
const enabled = themes const enabled = themes
.filter((t: any) => t.randomEnabled) .filter((t: Theme) => t.randomEnabled)
.filter((t: any) => t.name !== theme.name); .filter((t: Theme) => t.name !== theme.name);
if (enabled.length === 0) { if (enabled.length === 0) {
setTheme(themes[0]); setTheme(themes[0]);
save && setThemeName(themes[0].name); save && setThemeName(themes[0].name);
@@ -105,11 +106,11 @@ export function useCommonHooks() {
} }
}; };
const handleDelete = (item: any, endpoint: any) => { const handleDelete = (item: any, endpoint: string) => {
mutateAsync({ method: 'DELETE', endpoint: endpoint, body: item }); mutateAsync({ method: 'DELETE', endpoint: endpoint, body: item });
}; };
function fixDigits(k: any) { function fixDigits(k: number) {
if (k < 10) { if (k < 10) {
return `0${k}`; return `0${k}`;
} }

View File

@@ -63,8 +63,8 @@ export default function Search({
const handleSearchHistoryItem = (item: any) => { const handleSearchHistoryItem = (item: any) => {
const url = const url =
providers.find((provider: any) => provider.prefix === item.option.prefix)?.url ?? providers.find((provider: Provider) => provider.prefix === item.option.prefix)
'https://www.google.com/search?q='; ?.url ?? 'https://www.google.com/search?q=';
open(`${url}${item.option.searchTerm}`, '_self'); open(`${url}${item.option.searchTerm}`, '_self');
}; };

View File

@@ -4,7 +4,19 @@ import { useState } from 'react';
import { FiAlertCircle } from 'react-icons/fi'; import { FiAlertCircle } from 'react-icons/fi';
import { actionIconClasses, boxClasses, textClasses } from 'styles'; import { actionIconClasses, boxClasses, textClasses } from 'styles';
function AppSettingsItem({ url, icon, name, enabled, allIcons }: any) { function AppSettingsItem({
url,
icon,
name,
enabled,
allIcons,
}: {
url: string;
icon: string;
name: string;
enabled: number;
allIcons: any;
}) {
const Icon = allIcons[icon]; const Icon = allIcons[icon];
const [textDecoration, setTextDecoration] = useState<string>('none'); const [textDecoration, setTextDecoration] = useState<string>('none');
const [hover, setHover] = useState<boolean>(false); const [hover, setHover] = useState<boolean>(false);

View File

@@ -22,7 +22,7 @@ function DebouncedApplication({
application, application,
setIsOpen, setIsOpen,
allIcons, allIcons,
}: { application: Application; setIsOpen: any; allIcons: any }) { }: { application: Application; setIsOpen: (isOpen: boolean) => void; allIcons: any }) {
const { theme, handleDelete } = useCommonHooks(); const { theme, handleDelete } = useCommonHooks();
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
const { mutateAsync } = useMutationAPI(); const { mutateAsync } = useMutationAPI();

View File

@@ -1,8 +1,9 @@
import { ActionIcon, Box, Group, Text } from '@mantine/core'; import { ActionIcon, Box, Group, Text } from '@mantine/core';
import { useState } from 'react'; import { useState } from 'react';
import { FiEdit } from 'react-icons/fi'; import { FiEdit } from 'react-icons/fi';
import type { Bookmark } from 'types';
function BookmarkSettingsItem({ bookmark }: any) { function BookmarkSettingsItem({ bookmark }: { bookmark: Bookmark }) {
const [hover, setHover] = useState(false); const [hover, setHover] = useState(false);
return ( return (
<Box <Box

View File

@@ -19,7 +19,7 @@ import DeleteItemModal from '../Shared/DeleteItemModal';
function DebouncedBookmarkItem({ function DebouncedBookmarkItem({
bookmarkItem, bookmarkItem,
setIsOpen, setIsOpen,
}: { bookmarkItem: Bookmark; setIsOpen: any }) { }: { bookmarkItem: Bookmark; setIsOpen: (isOpen: boolean) => void }) {
const { theme, handleDelete } = useCommonHooks(); const { theme, handleDelete } = useCommonHooks();
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
const { mutateAsync } = useMutationAPI(); const { mutateAsync } = useMutationAPI();

View File

@@ -1,4 +1,10 @@
import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd'; import {
DragDropContext,
Draggable,
type DraggableProvided,
Droppable,
type DroppableProvided,
} from '@hello-pangea/dnd';
import { import {
ActionIcon, ActionIcon,
Box, Box,
@@ -212,7 +218,7 @@ function DebouncedGroupSettingsItem({
<Stack> <Stack>
<DragDropContext onDragEnd={onDragEnd}> <DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId={`${bookmarkGroup.id}`}> <Droppable droppableId={`${bookmarkGroup.id}`}>
{(provided) => ( {(provided: DroppableProvided) => (
<Stack ref={provided.innerRef} {...provided.droppableProps}> <Stack ref={provided.innerRef} {...provided.droppableProps}>
{bookmarks.map((bookmark: Bookmark) => ( {bookmarks.map((bookmark: Bookmark) => (
<Draggable <Draggable
@@ -220,7 +226,7 @@ function DebouncedGroupSettingsItem({
draggableId={`${bookmark.id}`} draggableId={`${bookmark.id}`}
index={bookmark.index} index={bookmark.index}
> >
{(provided: any) => ( {(provided: DraggableProvided) => (
<Box <Box
ref={provided.innerRef} ref={provided.innerRef}
{...provided.draggableProps} {...provided.draggableProps}
@@ -272,12 +278,10 @@ function DebouncedGroupSettingsItem({
/> />
</Popover.Dropdown> </Popover.Dropdown>
</Popover> </Popover>
{provided.placeholder}
</Box> </Box>
)} )}
</Draggable> </Draggable>
))} ))}
{provided.placeholder} {provided.placeholder}
</Stack> </Stack>
)} )}

View File

@@ -12,9 +12,18 @@ import { useDisclosure } from '@mantine/hooks';
import { useCommonHooks } from 'hooks'; import { useCommonHooks } from 'hooks';
import { FiTrash } from 'react-icons/fi'; import { FiTrash } from 'react-icons/fi';
import { cardClasses, textInputClasses } from 'styles'; import { cardClasses, textInputClasses } from 'styles';
import type { Message } from 'types';
import DeleteItemModal from '../Shared/DeleteItemModal'; import DeleteItemModal from '../Shared/DeleteItemModal';
function DebouncedMessage({ label, message, setMessage }: any) { function DebouncedMessage({
label,
message,
setMessage,
}: {
label: string;
message: Message;
setMessage: (message: Message) => void;
}) {
const { theme, handleDelete } = useCommonHooks(); const { theme, handleDelete } = useCommonHooks();
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
return ( return (

View File

@@ -1,12 +1,13 @@
import { Button, Divider, Grid, GridCol, Group, Stack, TextInput } from '@mantine/core'; import { Button, Divider, Grid, GridCol, Group, Stack, TextInput } from '@mantine/core';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks'; import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks'; import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import DebouncedMessage from 'pages/settings/components/Messages/DebouncedMessage';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { textInputClasses } from 'styles'; import { textInputClasses } from 'styles';
import type { Message } from 'types'; import type { Message } from 'types';
import AddItemModal from '../Shared/AddItemModal'; import AddItemModal from '../Shared/AddItemModal';
import SettingsHeader from '../Shared/SettingsHeader'; import SettingsHeader from '../Shared/SettingsHeader';
import DebouncedMessage from './DebouncedMessage';
const MessageSettings = () => { const MessageSettings = () => {
const endpoint = 'api/messages'; const endpoint = 'api/messages';
const { data: messageData, isFetched: isMessagesFetched } = useQueryAPI({ const { data: messageData, isFetched: isMessagesFetched } = useQueryAPI({

View File

@@ -16,7 +16,13 @@ import { cardClasses, textInputClasses } from 'styles';
import type { Provider } from 'types'; import type { Provider } from 'types';
import DeleteItemModal from '../Shared/DeleteItemModal'; import DeleteItemModal from '../Shared/DeleteItemModal';
function DebouncedSearchProvider({ searchProvider, setIsOpen }: any) { function DebouncedSearchProvider({
searchProvider,
setIsOpen,
}: {
searchProvider: Provider;
setIsOpen: (isOpen: boolean) => void;
}) {
const { theme, handleDelete } = useCommonHooks(); const { theme, handleDelete } = useCommonHooks();
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
const { mutateAsync } = useMutationAPI(); const { mutateAsync } = useMutationAPI();

View File

@@ -1,8 +1,9 @@
import { Card, Stack, Text } from '@mantine/core'; import { Card, Stack, Text } from '@mantine/core';
import HintItem from 'components/HelpModal/HintItem'; import HintItem from 'components/HelpModal/HintItem';
import { cardClasses } from 'styles'; import { cardClasses } from 'styles';
import type { Provider } from 'types';
function SearchProviderSettingsItem({ provider }: any) { function SearchProviderSettingsItem({ provider }: { provider: Provider }) {
return ( return (
<Card className={cardClasses.settingsItemHover} classNames={cardClasses}> <Card className={cardClasses.settingsItemHover} classNames={cardClasses}>
<Stack gap={0} w={'100%'} align='center'> <Stack gap={0} w={'100%'} align='center'>

View File

@@ -1,8 +1,19 @@
import { Card, Modal } from '@mantine/core'; import { Card, Modal } from '@mantine/core';
import { useCommonHooks } from 'hooks'; import { useCommonHooks } from 'hooks';
import type React from 'react';
import { cardClasses, modalClasses } from 'styles'; import { cardClasses, modalClasses } from 'styles';
function AddItemModal({ modalOpened, handleClose, body, title }: any) { function AddItemModal({
modalOpened,
handleClose,
body,
title,
}: {
modalOpened: boolean;
handleClose: () => void;
body: React.ReactNode;
title: string;
}) {
const { isMobile, modalStyle } = useCommonHooks(); const { isMobile, modalStyle } = useCommonHooks();
return ( return (
<Modal.Root <Modal.Root
@@ -25,8 +36,11 @@ function AddItemModal({ modalOpened, handleClose, body, title }: any) {
</Modal.Header> </Modal.Header>
<Modal.Body <Modal.Body
h={isMobile ? '90%' : undefined} h={isMobile ? '90%' : undefined}
pb={'2rem'} style={{
style={{ justifyContent: 'center', alignContent: 'center' }} justifyContent: 'center',
alignContent: 'center',
paddingBottom: '2rem',
}}
> >
<Card <Card
style={{ alignContent: 'center', justifyContent: 'center' }} style={{ alignContent: 'center', justifyContent: 'center' }}

View File

@@ -2,7 +2,17 @@ import { Card, Modal } from '@mantine/core';
import { useCommonHooks } from 'hooks'; import { useCommonHooks } from 'hooks';
import { cardClasses, modalClasses } from 'styles'; import { cardClasses, modalClasses } from 'styles';
function DeleteItemModal({ modalOpened, handleClose, body, title }: any) { function DeleteItemModal({
modalOpened,
handleClose,
body,
title,
}: {
modalOpened: boolean;
handleClose: () => void;
body: React.ReactNode;
title: string;
}) {
const { isMobile, modalStyle } = useCommonHooks(); const { isMobile, modalStyle } = useCommonHooks();
return ( return (
<Modal.Root <Modal.Root

View File

@@ -28,19 +28,31 @@ function SettingsHeader({
searchValue, searchValue,
setSearchValue, setSearchValue,
searchPlaceholder, searchPlaceholder,
}: any) { }: {
setDragging: any;
openModal: () => void;
title: string;
tooltip: any;
searchValue: string;
setSearchValue: (searchValue: string) => void;
searchPlaceholder: string;
}) {
const { isMobile, theme, modalStyle } = useCommonHooks(); const { isMobile, theme, modalStyle } = useCommonHooks();
return ( return (
<Group <Group
py={'1.5rem'}
pl={'1rem'}
h={'min-content'}
w={'100%'}
align='center' align='center'
mt={0}
justify='center' justify='center'
pos={'absolute'} style={{
style={{ backdropFilter: 'blur(10px) brightness(.75)', zIndex: 199 }} backdropFilter: 'blur(10px) brightness(.75)',
zIndex: 199,
paddingTop: '1.5rem',
paddingBottom: '1.5rem',
paddingLeft: '1rem',
height: 'min-content',
width: '100%',
marginTop: 0,
position: 'absolute',
}}
> >
<Group w={isMobile ? undefined : '100%'}> <Group w={isMobile ? undefined : '100%'}>
<Text <Text

View File

@@ -4,10 +4,20 @@ import { useCommonHooks, useMutationAPI } from 'hooks';
import { useState } from 'react'; import { useState } from 'react';
import { FiEdit, FiShuffle, FiTrash, FiX } from 'react-icons/fi'; import { FiEdit, FiShuffle, FiTrash, FiX } from 'react-icons/fi';
import { actionIconClasses } from 'styles'; import { actionIconClasses } from 'styles';
import type { ThemePlaylist } from 'types'; import type { Theme, ThemePlaylist } from 'types';
import DeleteItemModal from '../Shared/DeleteItemModal'; import DeleteItemModal from '../Shared/DeleteItemModal';
function ThemeCard({ cardTheme, handleOpen, allThemes, themePlaylists }: any) { function ThemeCard({
cardTheme,
handleOpen,
allThemes,
themePlaylists,
}: {
cardTheme: Theme;
handleOpen: (cardTheme: Theme) => void;
allThemes: Theme[];
themePlaylists: any;
}) {
const [hover, setHover] = useState(false); const [hover, setHover] = useState(false);
const [shiftEdit, setShiftEdit] = useState<number>(0); const [shiftEdit, setShiftEdit] = useState<number>(0);
const [shiftShuffle, setShiftShuffle] = useState<number>(0); const [shiftShuffle, setShiftShuffle] = useState<number>(0);
@@ -263,11 +273,11 @@ function ThemeCard({ cardTheme, handleOpen, allThemes, themePlaylists }: any) {
<FiShuffle <FiShuffle
onClick={() => { onClick={() => {
const themeList = JSON.parse( const themeList = JSON.parse(
themePlaylists.find( themePlaylists?.find(
(t: ThemePlaylist) => t.name === currentThemePlaylist, (t: ThemePlaylist) => t.name === currentThemePlaylist,
).themeList, ).themeList,
); );
const filteredThemes = allThemes.filter((t: any) => const filteredThemes = allThemes.filter((t: Theme) =>
themeList.includes(t.id), themeList.includes(t.id),
); );
handleThemeChange(filteredThemes, false); handleThemeChange(filteredThemes, false);

View File

@@ -1,6 +1,13 @@
import { Group, Text } from '@mantine/core'; import { Group, Text } from '@mantine/core';
function ThemeMiniCard({ allThemes, item }: any) { import type { Theme } from 'types';
const theme = allThemes.find((theme: any) => theme.id === item); function ThemeMiniCard({
allThemes,
item,
}: {
allThemes: Theme[];
item: number;
}) {
const theme = allThemes.find((theme: Theme) => theme.id === item);
return ( return (
<Group <Group
@@ -12,23 +19,23 @@ function ThemeMiniCard({ allThemes, item }: any) {
w={'175px'} w={'175px'}
h={'60px'} h={'60px'}
style={{ style={{
background: `linear-gradient(${theme.backgroundColor}33, ${theme.backgroundColor}33), no-repeat center url(/backgrounds/${theme.backgroundImage})`, background: `linear-gradient(${theme?.backgroundColor}33, ${theme?.backgroundColor}33), no-repeat center url(/backgrounds/${theme?.backgroundImage})`,
backgroundSize: 'cover', backgroundSize: 'cover',
backgroundColor: theme.backgroundColor, backgroundColor: theme?.backgroundColor,
border: `solid ${theme.borderColor}`, border: `solid ${theme?.borderColor}`,
borderRadius: '8px', borderRadius: '8px',
}} }}
> >
<Text <Text
bg={theme.backgroundColor} bg={theme?.backgroundColor}
c={theme.primaryColor} c={theme?.primaryColor}
size='md' size='md'
style={{ style={{
padding: 4, padding: 4,
borderRadius: '8px', borderRadius: '8px',
}} }}
> >
{allThemes.find((theme: any) => theme.id === item)?.name} {allThemes.find((theme: Theme) => theme.id === item)?.name}
</Text> </Text>
</Group> </Group>
); );

View File

@@ -15,6 +15,7 @@ import { useCommonHooks } from 'hooks';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { FiSave, FiX } from 'react-icons/fi'; import { FiSave, FiX } from 'react-icons/fi';
import { modalClasses, textClasses, textInputClasses } from 'styles'; import { modalClasses, textClasses, textInputClasses } from 'styles';
import type { Theme } from 'types';
import ThemeModalContent from './ThemeModalContent'; import ThemeModalContent from './ThemeModalContent';
function ThemeModal({ function ThemeModal({
@@ -22,38 +23,40 @@ function ThemeModal({
handleClose, handleClose,
selectedTheme, selectedTheme,
setSelectedTheme, setSelectedTheme,
setColorId,
colorId, colorId,
setColorId,
colorValue,
setColorValue, setColorValue,
openPicker, openPicker,
backgroundList, backgroundList,
pickerOpen, pickerOpen,
colorValue,
closePicker, closePicker,
handleSaveTheme, handleSaveTheme,
}: any) { }: {
opened: boolean;
handleClose: () => void;
selectedTheme: Theme;
setSelectedTheme: (selectedTheme: Theme) => void;
colorId: string;
setColorId: (colorId: string) => void;
colorValue: string;
setColorValue: (colorValue: string) => void;
openPicker: () => void;
backgroundList: string[];
pickerOpen: boolean;
closePicker: () => void;
handleSaveTheme: () => void;
}) {
const { theme, isMobile } = useCommonHooks(); const { theme, isMobile } = useCommonHooks();
const viewportRef = useRef<HTMLDivElement>(null); const viewportRef = useRef<HTMLDivElement>(null);
const [query, setQuery] = useState(''); const [query, setQuery] = useState('');
const [hovered, setHovered] = useState(-1); const [hovered, setHovered] = useState(-1);
const filtered = backgroundList.filter((item: any) => const filtered = backgroundList.filter((item: string) =>
item.toLowerCase().includes(query.toLowerCase()), item.toLowerCase().includes(query.toLowerCase()),
); );
if (selectedTheme.name === undefined) {
setSelectedTheme({
id: undefined,
name: 'default',
backgroundImage: 'none',
backgroundColor: '#EEEEEE',
searchColor: '#00000033',
primaryColor: '#222222',
accentColor: '#5c5c5c',
borderColor: '#5c5c5c',
});
}
const re = /(?:\.([^.]+))?$/; const re = /(?:\.([^.]+))?$/;
const items = filtered.map((item: any, index: any) => ( const items = filtered.map((item: string, index: number) => (
<UnstyledButton <UnstyledButton
data-list-item data-list-item
key={item} key={item}

View File

@@ -2,9 +2,10 @@ import { Box, Group, Stack, Text } from '@mantine/core';
import { useState } from 'react'; import { useState } from 'react';
import { FiCheck } from 'react-icons/fi'; import { FiCheck } from 'react-icons/fi';
import { stackClasses } from 'styles'; import { stackClasses } from 'styles';
import type { Theme } from 'types';
export default function ThemeModalContent({ selectedTheme }: any) { export default function ThemeModalContent({ selectedTheme }: { selectedTheme: Theme }) {
const ExampleApp = (previewTheme: any) => { const ExampleApp = ({ theme }: { theme: Theme }) => {
const [textDecoration, setTextDecoration] = useState<string>('none'); const [textDecoration, setTextDecoration] = useState<string>('none');
return ( return (
@@ -22,11 +23,7 @@ export default function ThemeModalContent({ selectedTheme }: any) {
paddingTop: '15px', paddingTop: '15px',
}} }}
> >
<FiCheck <FiCheck style={{ color: theme.primaryColor }} height={32} width={32} />
style={{ color: previewTheme.theme.primaryColor }}
height={32}
width={32}
/>
</Stack> </Stack>
<Stack <Stack
style={{ style={{
@@ -43,7 +40,7 @@ export default function ThemeModalContent({ selectedTheme }: any) {
fontWeight: 400, fontWeight: 400,
fontSize: 11, fontSize: 11,
fontStyle: 'normal', fontStyle: 'normal',
color: previewTheme.theme.primaryColor, color: theme.primaryColor,
fontFamily: fontFamily:
'-apple-system, Jost, BlinkMacSystemFont, Helvetica Neue, Roboto, sans-serif !important', '-apple-system, Jost, BlinkMacSystemFont, Helvetica Neue, Roboto, sans-serif !important',
margin: 0, margin: 0,
@@ -56,7 +53,7 @@ export default function ThemeModalContent({ selectedTheme }: any) {
fontWeight: 400, fontWeight: 400,
fontSize: 11, fontSize: 11,
fontStyle: 'italic', fontStyle: 'italic',
color: previewTheme.theme.accentColor, color: theme.accentColor,
fontFamily: fontFamily:
'-apple-system, Jost, BlinkMacSystemFont, Helvetica Neue, Roboto, sans-serif !important', '-apple-system, Jost, BlinkMacSystemFont, Helvetica Neue, Roboto, sans-serif !important',
margin: 0, margin: 0,

View File

@@ -11,10 +11,19 @@ import { useDisclosure } from '@mantine/hooks';
import { useCommonHooks, useMutationAPI } from 'hooks'; import { useCommonHooks, useMutationAPI } from 'hooks';
import { useState } from 'react'; import { useState } from 'react';
import { FiEdit, FiRefreshCcw, FiTrash } from 'react-icons/fi'; import { FiEdit, FiRefreshCcw, FiTrash } from 'react-icons/fi';
import type { Theme, ThemePlaylist } from 'types';
import DeleteItemModal from '../Shared/DeleteItemModal'; import DeleteItemModal from '../Shared/DeleteItemModal';
import ThemeMiniCard from './ThemeMiniCard'; import ThemeMiniCard from './ThemeMiniCard';
function ThemePlaylistCard({ cardPlaylist, handleOpen, allThemes }: any) { function ThemePlaylistCard({
cardPlaylist,
handleOpen,
allThemes,
}: {
cardPlaylist: any;
handleOpen: (cardPlaylist: ThemePlaylist) => void;
allThemes: Theme[];
}) {
const [hover, setHover] = useState(false); const [hover, setHover] = useState(false);
const { setThemeName, setCurrentThemePlaylist, theme, handleDelete } = useCommonHooks(); const { setThemeName, setCurrentThemePlaylist, theme, handleDelete } = useCommonHooks();
const syncableLists = ['All', 'Backgrounds', 'No Backgrounds']; const syncableLists = ['All', 'Backgrounds', 'No Backgrounds'];
@@ -36,7 +45,7 @@ function ThemePlaylistCard({ cardPlaylist, handleOpen, allThemes }: any) {
> >
<DeleteItemModal <DeleteItemModal
modalOpened={modalOpened} modalOpened={modalOpened}
closeModal={closeModal} handleClose={closeModal}
title='Delete Theme Playlist' title='Delete Theme Playlist'
body={ body={
<Stack gap={0} w={'100%'} h={'150px'} align='center'> <Stack gap={0} w={'100%'} h={'150px'} align='center'>
@@ -120,7 +129,7 @@ function ThemePlaylistCard({ cardPlaylist, handleOpen, allThemes }: any) {
body: { body: {
id: cardPlaylist.id, id: cardPlaylist.id,
name: 'All', name: 'All',
themeList: JSON.stringify(allThemes.map((theme: any) => theme.id)), themeList: JSON.stringify(allThemes.map((theme: Theme) => theme.id)),
}, },
}); });
} }
@@ -134,9 +143,9 @@ function ThemePlaylistCard({ cardPlaylist, handleOpen, allThemes }: any) {
themeList: JSON.stringify( themeList: JSON.stringify(
allThemes allThemes
.filter( .filter(
(theme: any) => theme.backgroundImage.toLowerCase() !== 'none', (theme: Theme) => theme.backgroundImage.toLowerCase() !== 'none',
) )
.map((theme: any) => theme.id), .map((theme: Theme) => theme.id),
), ),
}, },
}); });
@@ -151,9 +160,9 @@ function ThemePlaylistCard({ cardPlaylist, handleOpen, allThemes }: any) {
themeList: JSON.stringify( themeList: JSON.stringify(
allThemes allThemes
.filter( .filter(
(theme: any) => theme.backgroundImage.toLowerCase() === 'none', (theme: Theme) => theme.backgroundImage.toLowerCase() === 'none',
) )
.map((theme: any) => theme.id), .map((theme: Theme) => theme.id),
), ),
}, },
}); });
@@ -243,7 +252,7 @@ function ThemePlaylistCard({ cardPlaylist, handleOpen, allThemes }: any) {
<ScrollArea h={'255px'} w={'100%'} style={{ zIndex: 2 }}> <ScrollArea h={'255px'} w={'100%'} style={{ zIndex: 2 }}>
<Stack gap={4}> <Stack gap={4}>
{themeList.length > 0 && {themeList.length > 0 &&
themeList.map((item: any) => { themeList.map((item: number) => {
return ( return (
<ThemeMiniCard key={item} item={item} allThemes={allThemes} /> <ThemeMiniCard key={item} item={item} allThemes={allThemes} />
); );

View File

@@ -12,6 +12,7 @@ import {
import { useCommonHooks } from 'hooks'; import { useCommonHooks } from 'hooks';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { modalClasses, selectClasses, textInputClasses } from 'styles'; import { modalClasses, selectClasses, textInputClasses } from 'styles';
import type { Theme } from 'types';
import ThemeMiniCard from './ThemeMiniCard'; import ThemeMiniCard from './ThemeMiniCard';
function ThemePlaylistModal({ function ThemePlaylistModal({
@@ -22,8 +23,16 @@ function ThemePlaylistModal({
setSelectedPlaylist, setSelectedPlaylist,
handleSavePlaylist, handleSavePlaylist,
allThemes, allThemes,
}: any) { }: {
const { theme, isMobile } = useCommonHooks(); opened: boolean;
handleClose: () => void;
createPlaylist: any;
selectedPlaylist: any;
setSelectedPlaylist: (selectedPlaylist: any) => void;
handleSavePlaylist: () => void;
allThemes: Theme[];
}) {
const { theme, isMobile, modalStyle } = useCommonHooks();
const [themeList, setThemeList] = useState<any>('[]'); const [themeList, setThemeList] = useState<any>('[]');
useEffect(() => { useEffect(() => {
if (selectedPlaylist.themeList) { if (selectedPlaylist.themeList) {
@@ -50,14 +59,7 @@ function ThemePlaylistModal({
handleClose(); handleClose();
setThemeList('[]'); setThemeList('[]');
}} }}
style={{ style={modalStyle}
'--color-text-pri': theme.primaryColor,
'--color-text-acc': theme.accentColor,
'--color-background': theme.backgroundColor,
'--color-border': theme.borderColor,
'--color-search-background': theme.searchColor,
'--image-background': `url("${theme.backgroundImage}")`,
}}
> >
<Modal.Overlay style={{ backdropFilter: 'blur(5px)' }} /> <Modal.Overlay style={{ backdropFilter: 'blur(5px)' }} />
<Modal.Content> <Modal.Content>
@@ -95,7 +97,7 @@ function ThemePlaylistModal({
labelProps={{ display: 'none' }} labelProps={{ display: 'none' }}
placeholder='Select Theme' placeholder='Select Theme'
defaultValue={themeList['0']} defaultValue={themeList['0']}
data={allThemes?.map((theme: any) => { data={allThemes?.map((theme: Theme) => {
return { return {
value: `${theme.id}`, value: `${theme.id}`,
label: theme.name, label: theme.name,
@@ -128,7 +130,7 @@ function ThemePlaylistModal({
labelProps={{ display: 'none' }} labelProps={{ display: 'none' }}
placeholder='Select Theme' placeholder='Select Theme'
defaultValue={themeList['1']} defaultValue={themeList['1']}
data={allThemes?.map((theme: any) => { data={allThemes?.map((theme: Theme) => {
return { return {
value: `${theme.id}`, value: `${theme.id}`,
label: theme.name, label: theme.name,
@@ -161,7 +163,7 @@ function ThemePlaylistModal({
labelProps={{ display: 'none' }} labelProps={{ display: 'none' }}
placeholder='Select Theme' placeholder='Select Theme'
defaultValue={themeList['2']} defaultValue={themeList['2']}
data={allThemes?.map((theme: any) => { data={allThemes?.map((theme: Theme) => {
return { return {
value: `${theme.id}`, value: `${theme.id}`,
label: theme.name, label: theme.name,
@@ -194,7 +196,7 @@ function ThemePlaylistModal({
labelProps={{ display: 'none' }} labelProps={{ display: 'none' }}
placeholder='Select Theme' placeholder='Select Theme'
defaultValue={themeList['3']} defaultValue={themeList['3']}
data={allThemes?.map((theme: any) => { data={allThemes?.map((theme: Theme) => {
return { return {
value: `${theme.id}`, value: `${theme.id}`,
label: theme.name, label: theme.name,
@@ -225,7 +227,7 @@ function ThemePlaylistModal({
) : ( ) : (
<SimpleGrid cols={3}> <SimpleGrid cols={3}>
{selectedPlaylist.name !== 'Time of Day' && {selectedPlaylist.name !== 'Time of Day' &&
allThemes?.map((miniTheme: any) => { allThemes.map((miniTheme: Theme) => {
const newThemeList = themeList; const newThemeList = themeList;
return ( return (
<Group <Group
@@ -248,7 +250,7 @@ function ThemePlaylistModal({
setSelectedPlaylist(newSelectedPlaylist); setSelectedPlaylist(newSelectedPlaylist);
}} }}
> >
<ThemeMiniCard allThemes={allThemes} item={miniTheme.id} /> <ThemeMiniCard allThemes={allThemes} item={Number(miniTheme.id)} />
</Group> </Group>
); );
})} })}

View File

@@ -21,12 +21,11 @@ function ThemePlaylists() {
const { mutateAsync } = useMutationAPI(); const { mutateAsync } = useMutationAPI();
const [opened, { open, close }] = useDisclosure(false); const [opened, { open, close }] = useDisclosure(false);
const [selectedPlaylist, setSelectedPlaylist] = useState<any>({}); const [selectedPlaylist, setSelectedPlaylist] = useState<any>({});
const { currentThemePlaylist, setCurrentThemePlaylist, theme, isMobile } = const { currentThemePlaylist, theme, isMobile } = useCommonHooks();
useCommonHooks();
const [searchValue, setSearchValue] = useState(''); const [searchValue, setSearchValue] = useState('');
const [debouncedSearch] = useDebouncedValue(searchValue, 500); const [debouncedSearch] = useDebouncedValue(searchValue, 500);
const handleOpen = (playlist: any) => { const handleOpen = (playlist: ThemePlaylist) => {
setSelectedPlaylist(playlist); setSelectedPlaylist(playlist);
open(); open();
}; };
@@ -106,8 +105,6 @@ function ThemePlaylists() {
<ThemePlaylistCard <ThemePlaylistCard
cardPlaylist={cardPlaylist} cardPlaylist={cardPlaylist}
handleOpen={handleOpen} handleOpen={handleOpen}
currentThemePlaylist={currentThemePlaylist}
setCurrentThemePlaylist={setCurrentThemePlaylist}
allThemes={allThemes} allThemes={allThemes}
/> />
</Box> </Box>
@@ -131,7 +128,7 @@ function ThemePlaylists() {
?.filter((a: ThemePlaylist) => ?.filter((a: ThemePlaylist) =>
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()), a.name.toLowerCase().includes(debouncedSearch.toLowerCase()),
) )
.sort((a: any, b: any) => (a.name > b.name ? 1 : -1)) .sort((a: ThemePlaylist, b: ThemePlaylist) => (a.name > b.name ? 1 : -1))
.map((cardPlaylist: ThemePlaylist) => { .map((cardPlaylist: ThemePlaylist) => {
return ( return (
<Group key={cardPlaylist.name} pos={'relative'}> <Group key={cardPlaylist.name} pos={'relative'}>

View File

@@ -9,6 +9,7 @@ import type { Theme } from 'types';
import SettingsHeader from '../Shared/SettingsHeader'; import SettingsHeader from '../Shared/SettingsHeader';
import ThemeCard from './ThemeCard'; import ThemeCard from './ThemeCard';
import ThemeModal from './ThemeModal'; import ThemeModal from './ThemeModal';
function ThemesSettings() { function ThemesSettings() {
const themesEndpoint = 'api/themes'; const themesEndpoint = 'api/themes';
const backgroundsEndpoint = 'api/backgrounds'; const backgroundsEndpoint = 'api/backgrounds';
@@ -26,7 +27,17 @@ function ThemesSettings() {
const [colorId, setColorId] = useState<string>(''); const [colorId, setColorId] = useState<string>('');
const [colorValue, setColorValue] = useState('#000000'); const [colorValue, setColorValue] = useState('#000000');
const [backgroundList, setBackgroundList] = useState<string[]>(['None']); const [backgroundList, setBackgroundList] = useState<string[]>(['None']);
const [selectedTheme, setSelectedTheme] = useState<any>({}); const [selectedTheme, setSelectedTheme] = useState<Theme>({
id: undefined,
name: 'default',
backgroundImage: 'none',
backgroundColor: '#EEEEEE',
searchColor: '#00000033',
primaryColor: '#222222',
accentColor: '#5c5c5c',
borderColor: '#5c5c5c',
randomEnabled: 0,
});
const [pickerOpen, { open: openPicker, close: closePicker }] = useDisclosure(false); const [pickerOpen, { open: openPicker, close: closePicker }] = useDisclosure(false);
const [searchValue, setSearchValue] = useState(''); const [searchValue, setSearchValue] = useState('');
const [debouncedSearch] = useDebouncedValue(searchValue, 500); const [debouncedSearch] = useDebouncedValue(searchValue, 500);
@@ -41,12 +52,22 @@ function ThemesSettings() {
const handleClose = () => { const handleClose = () => {
close(); close();
closePicker(); closePicker();
setSelectedTheme({}); setSelectedTheme({
id: undefined,
name: 'default',
backgroundImage: 'none',
backgroundColor: '#EEEEEE',
searchColor: '#00000033',
primaryColor: '#222222',
accentColor: '#5c5c5c',
borderColor: '#5c5c5c',
randomEnabled: 0,
});
}; };
const handleSaveTheme = () => { const handleSaveTheme = () => {
mutateAsync({ mutateAsync({
method: selectedTheme.id === undefined ? 'POST' : 'PATCH', method: selectedTheme?.id === undefined ? 'POST' : 'PATCH',
endpoint: themesEndpoint, endpoint: themesEndpoint,
body: selectedTheme, body: selectedTheme,
}); });
@@ -65,7 +86,6 @@ function ThemesSettings() {
handleClose={handleClose} handleClose={handleClose}
selectedTheme={selectedTheme} selectedTheme={selectedTheme}
setSelectedTheme={setSelectedTheme} setSelectedTheme={setSelectedTheme}
theme={theme}
setColorId={setColorId} setColorId={setColorId}
colorId={colorId} colorId={colorId}
setColorValue={setColorValue} setColorValue={setColorValue}

View File

@@ -13,9 +13,16 @@ import { useCommonHooks, useMutationAPI } from 'hooks';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { FiTrash } from 'react-icons/fi'; import { FiTrash } from 'react-icons/fi';
import { cardClasses, textInputClasses } from 'styles'; import { cardClasses, textInputClasses } from 'styles';
import type { WolClient } from 'types';
import DeleteItemModal from '../Shared/DeleteItemModal'; import DeleteItemModal from '../Shared/DeleteItemModal';
function DebouncedWolClient({ wolClient, setIsOpen }: any) { function DebouncedWolClient({
wolClient,
setIsOpen,
}: {
wolClient: WolClient;
setIsOpen: (isOpen: boolean) => void;
}) {
const { theme, handleDelete } = useCommonHooks(); const { theme, handleDelete } = useCommonHooks();
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false); const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
const { mutateAsync } = useMutationAPI(); const { mutateAsync } = useMutationAPI();

View File

@@ -1,8 +1,9 @@
import { Card, Stack, Text } from '@mantine/core'; import { Card, Stack, Text } from '@mantine/core';
import { FaLaptop } from 'react-icons/fa'; import { FaLaptop } from 'react-icons/fa';
import { cardClasses } from 'styles'; import { cardClasses } from 'styles';
import type { WolClient } from 'types';
function WolClientSettingsItem({ client }: any) { function WolClientSettingsItem({ client }: { client: WolClient }) {
return ( return (
<Card <Card
className={cardClasses.settingsItemHover} className={cardClasses.settingsItemHover}