Style updates and bugfixes

This commit is contained in:
Sean Edmunds
2025-07-17 17:01:31 -05:00
parent ea216e9da2
commit 5e5a077ec3
48 changed files with 565 additions and 524 deletions

View File

@@ -29,6 +29,7 @@ function BookmarkGroups({
</Text>
{bookmarks
?.toSorted((a: Bookmark, b: Bookmark) => (a.index > b.index ? 1 : -1))
.filter((bookmark: Bookmark) => bookmark.enabled === 1)
.map((bookmark: Bookmark) => (
<BookmarkItem
key={bookmark.name}

View File

@@ -28,7 +28,7 @@ function WakeOnLan({
<Button
classNames={buttonClasses}
className={buttonClasses.wakeButton}
disabled={!wolClients?.length || selectedClient?.macAddress === undefined}
disabled={!wolClients?.length && selectedClient?.macAddress === undefined}
onClick={() => {
handleWakeRequest();
}}

View File

@@ -17,8 +17,8 @@ import Bookmarks from './components/Bookmarks/Bookmarks';
import Messages from './components/Messages/Messages';
import Personalization from './components/Personalization/Personalization';
import SearchProviders from './components/Search/SearchProviders';
import ThemePlaylists from './components/Theming/ThemePlaylists';
import Themes from './components/Theming/Themes';
import { ThemePlaylists } from './components/Theming/ThemePlaylists';
import { Themes } from './components/Theming/Themes';
import WolClients from './components/WoL/WolClients';
export function Settings() {

View File

@@ -15,7 +15,7 @@ import {
} from '@mantine/core';
import { isNotEmpty, useForm } from '@mantine/form';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { AppItem } from 'components';
import { AddItemModal, AppItem, NoItemsFound, SettingsHeader } from 'components';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useEffect, useState } from 'react';
import * as fa6 from 'react-icons/fa6';
@@ -23,9 +23,6 @@ import * as si from 'react-icons/si';
import * as vsc from 'react-icons/vsc';
import { popoverClasses, selectClasses, textInputClasses } from 'styles';
import type { Application } from 'types';
import AddItemModal from '../Shared/AddItemModal';
import NoItemsFound from '../Shared/NoItemsFound';
import SettingsHeader from '../Shared/SettingsHeader';
import DebouncedApplication from './DebouncedApplication';
const ApplicationSettings = () => {

View File

@@ -9,12 +9,11 @@ import {
TextInput,
} from '@mantine/core';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { DeleteItemModal, ManagementPill } from 'components';
import { useCommonHooks, useMutationAPI } from 'hooks';
import { useEffect, useState } from 'react';
import { cardClasses, selectClasses, textInputClasses } from 'styles';
import type { Application } from 'types';
import DeleteItemModal from '../Shared/DeleteItemModal';
import ManagementPill from '../Shared/ManagementPill';
function DebouncedApplication({
application,

View File

@@ -13,12 +13,14 @@ function BookmarkSettingsItem({ bookmark }: { bookmark: Bookmark }) {
color: 'var(--mantine-color-primary-0)',
backgroundColor: 'var(--mantine-color-search-0)',
padding: '.5rem',
filter: bookmark.enabled ? '' : 'grayscale(100%)',
}}
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
>
<Group>
<Group justify='space-between'>
<Text>{bookmark.name}</Text>
{!bookmark.enabled && !hover && <Text opacity={0.25}>Disabled</Text>}
{hover && (
<ActionIcon
variant='subtle'

View File

@@ -2,13 +2,11 @@ import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd';
import { Box, Button, Card, Group, Stack, Text, TextInput } from '@mantine/core';
import { isNotEmpty, useForm } from '@mantine/form';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { AddItemModal, NoItemsFound, SettingsHeader } from 'components';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useEffect, useState } from 'react';
import { textInputClasses } from 'styles';
import type { Bookmark, BookmarkGroup } from 'types';
import AddItemModal from '../Shared/AddItemModal';
import NoItemsFound from '../Shared/NoItemsFound';
import SettingsHeader from '../Shared/SettingsHeader';
import DebouncedGroupSettingsItem from './DebouncedGroupSettingsItem';
const BookmarkSettings = () => {

View File

@@ -1,11 +1,10 @@
import { ActionIcon, Card, Group, Stack, Text, TextInput, Tooltip } from '@mantine/core';
import { Card, Group, Stack, Text, TextInput } from '@mantine/core';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { DeleteItemModal, ManagementPill } from 'components';
import { useCommonHooks, useMutationAPI } from 'hooks';
import { useEffect, useState } from 'react';
import { FiTrash } from 'react-icons/fi';
import { cardClasses, textInputClasses } from 'styles';
import type { Bookmark } from 'types';
import DeleteItemModal from '../Shared/DeleteItemModal';
function DebouncedBookmarkItem({
bookmarkItem,
@@ -66,25 +65,16 @@ function DebouncedBookmarkItem({
}
title='Delete Bookmark'
/>
<Tooltip
c={'var(--mantine-color-primary-0)'}
bg={'var(--mantine-color-background-0)'}
bd={'solid 1px var(--mantine-color-border-0)'}
label={'Delete'}
>
<ActionIcon
pos={'absolute'}
right={'1rem'}
top={'1rem'}
color='red'
onClick={() => {
setIsOpen(true);
openModal();
}}
>
<FiTrash color='black' />
</ActionIcon>
</Tooltip>
<ManagementPill
enabled={bookmark.enabled}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
setUpdate({
...bookmark,
enabled: event.target.checked ? 1 : 0,
});
}}
openModal={openModal}
/>
<Group justify='center' style={{ flexDirection: isMobile ? 'column' : 'row' }}>
<TextInput
label={'Name'}

View File

@@ -19,13 +19,13 @@ import {
} from '@mantine/core';
import { isNotEmpty, useForm } from '@mantine/form';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { DeleteItemModal } from 'components';
import { useCommonHooks, useMutationAPI } from 'hooks';
import { useEffect, useState } from 'react';
import { FaChevronLeft } from 'react-icons/fa';
import { FiPlus, FiTrash } from 'react-icons/fi';
import { buttonClasses, cardClasses, popoverClasses, textInputClasses } from 'styles';
import type { Bookmark, BookmarkGroup } from 'types';
import DeleteItemModal from '../Shared/DeleteItemModal';
import BookmarkSettingsItem from './BookmarkSettingsItem';
import DebouncedBookmarkItem from './DebouncedBookmarkItem';
@@ -51,6 +51,7 @@ function DebouncedGroupSettingsItem({
url: '',
category: group.categoryName,
index: 0,
enabled: 1,
});
const form = useForm({
initialValues: newBookmark,
@@ -111,7 +112,7 @@ function DebouncedGroupSettingsItem({
modalOpened={modalOpened}
handleClose={closeModal}
handleDelete={() => {
handleDelete(bookmarks, 'api/bookmarks');
bookmarks.length > 0 && handleDelete(bookmarks, 'api/bookmarks');
handleDelete(group, 'api/bookmarkCategories');
}}
title='Delete message'
@@ -141,12 +142,13 @@ function DebouncedGroupSettingsItem({
pt={0}
bg={'var(--mantine-color-search-0)'}
c={'var(--mantine-color-background-0)'}
mt={'-1.5rem'}
>
<Stack gap={0}>
<Group gap={0} align='center' justify='space-between'>
<Group gap={0} align='end' justify='space-between'>
<TextInput
label={'Name'}
w={isMobile ? undefined : '58%'}
w={isMobile ? undefined : '56%'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
defaultValue={group.categoryName}
@@ -187,9 +189,8 @@ function DebouncedGroupSettingsItem({
label={'Delete'}
>
<ActionIcon
mt={'2.5rem'}
size={'lg'}
color='red'
size={'2.75rem'}
onClick={() => {
openModal();
}}
@@ -206,8 +207,8 @@ function DebouncedGroupSettingsItem({
borderRadius: '100%',
backgroundColor: 'var(--mantine-color-accent-0)',
position: 'absolute',
top: isMobile ? 170 : 92,
right: 18,
top: isMobile ? 156 : 78,
right: 22,
zIndex: 10,
fontSize: '1.25rem',
textAlign: 'center',

View File

@@ -1,10 +1,9 @@
import { Card, Stack, Text, TextInput } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { DeleteItemModal, ManagementPill } from 'components';
import { useCommonHooks } from 'hooks';
import { cardClasses, textInputClasses } from 'styles';
import type { Message } from 'types';
import DeleteItemModal from '../Shared/DeleteItemModal';
import ManagementPill from '../Shared/ManagementPill';
function DebouncedMessage({
label,

View File

@@ -1,12 +1,10 @@
import { Button, Grid, GridCol, Group, Stack, TextInput } from '@mantine/core';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { AddItemModal, NoItemsFound, SettingsHeader } from 'components';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useEffect, useState } from 'react';
import { textInputClasses } from 'styles';
import type { Message } from 'types';
import AddItemModal from '../Shared/AddItemModal';
import NoItemsFound from '../Shared/NoItemsFound';
import SettingsHeader from '../Shared/SettingsHeader';
import DebouncedMessage from './DebouncedMessage';
const MessageSettings = () => {

View File

@@ -1,10 +1,10 @@
import { Card, Grid, GridCol, Overlay, Stack, TextInput } from '@mantine/core';
import { useDebouncedValue } from '@mantine/hooks';
import { SettingsHeader } from 'components';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useEffect, useState } from 'react';
import { cardClasses, textInputClasses } from 'styles';
import type { PersonalData } from 'types';
import SettingsHeader from '../Shared/SettingsHeader';
const PersonalizationSettings = () => {
const endpoint = 'api/personalData';

View File

@@ -1,11 +1,11 @@
import { ActionIcon, Card, Group, Stack, Text, TextInput, Tooltip } from '@mantine/core';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { DeleteItemModal } from 'components';
import { useCommonHooks, useMutationAPI } from 'hooks';
import { useEffect, useState } from 'react';
import { FiTrash } from 'react-icons/fi';
import { cardClasses, textInputClasses } from 'styles';
import type { Provider } from 'types';
import DeleteItemModal from '../Shared/DeleteItemModal';
function DebouncedSearchProvider({
searchProvider,

View File

@@ -10,13 +10,11 @@ import {
} from '@mantine/core';
import { isNotEmpty, useForm } from '@mantine/form';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { AddItemModal, NoItemsFound, SettingsHeader } from 'components';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useEffect, useState } from 'react';
import { popoverClasses, textInputClasses } from 'styles';
import type { Provider } from 'types';
import AddItemModal from '../Shared/AddItemModal';
import NoItemsFound from '../Shared/NoItemsFound';
import SettingsHeader from '../Shared/SettingsHeader';
import DebouncedSearchProvider from './DebouncedSearchProvider';
import SearchProviderSettingsItem from './SearchProviderSettingsItem';

View File

@@ -1,57 +0,0 @@
import { Card, Modal } from '@mantine/core';
import { useCommonHooks } from 'hooks';
import type React from 'react';
import { cardClasses, modalClasses } from 'styles';
function AddItemModal({
modalOpened,
handleClose,
body,
title,
}: {
modalOpened: boolean;
handleClose: () => void;
body: React.ReactNode;
title: string;
}) {
const { isMobile } = useCommonHooks();
return (
<Modal.Root
size={'60%'}
className={modalClasses.helpModal}
classNames={modalClasses}
opened={modalOpened}
fullScreen={isMobile}
onClose={handleClose}
closeOnEscape
closeOnClickOutside
centered
>
<Modal.Overlay />
<Modal.Content h={'auto'}>
<Modal.Header>
<Modal.Title>{title}</Modal.Title>
<Modal.CloseButton />
</Modal.Header>
<Modal.Body
h={isMobile ? '90%' : undefined}
style={{
justifyContent: 'center',
alignContent: 'center',
paddingBottom: '2rem',
}}
>
<Card
style={{ alignContent: 'center', justifyContent: 'center' }}
className={cardClasses.settingsItem}
classNames={cardClasses}
>
{body}
</Card>
</Modal.Body>
</Modal.Content>
</Modal.Root>
);
}
export default AddItemModal;

View File

@@ -1,60 +0,0 @@
import { Button, Card, Group, Modal } from '@mantine/core';
import { useCommonHooks } from 'hooks';
import { cardClasses, modalClasses } from 'styles';
function DeleteItemModal({
modalOpened,
handleClose,
handleDelete,
body,
title,
}: {
modalOpened: boolean;
handleClose: () => void;
handleDelete: () => void;
body: React.ReactNode;
title: string;
}) {
const { isMobile } = useCommonHooks();
return (
<Modal.Root
size={'60%'}
className={modalClasses.helpModal}
classNames={modalClasses}
opened={modalOpened}
fullScreen={isMobile}
onClose={handleClose}
closeOnEscape
closeOnClickOutside
centered
>
<Modal.Overlay />
<Modal.Content style={{ zIndex: 1000 }} h={'auto'}>
<Modal.Header>
<Modal.Title>{title}</Modal.Title>
<Modal.CloseButton />
</Modal.Header>
<Modal.Body pb={'2rem'}>
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
{body}
<Group justify='center' mt={'-1.5rem'}>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
handleDelete();
handleClose();
}}
>
Delete
</Button>
<Button onClick={handleClose}>Cancel</Button>
</Group>
</Card>
</Modal.Body>
</Modal.Content>
</Modal.Root>
);
}
export default DeleteItemModal;

View File

@@ -1,76 +0,0 @@
import { ActionIcon, Group, Switch, Tooltip } from '@mantine/core';
import { FiPower, FiTrash } from 'react-icons/fi';
import { switchClasses } from 'styles';
function ManagementPill({
enabled,
onChange,
openModal,
}: {
enabled: number;
onChange: any;
openModal: () => void;
}) {
return (
<Group
style={{
position: 'absolute',
right: '1rem',
top: '.5rem',
width: 'fit-content',
backgroundColor:
'color-mix(in srgb, var(--mantine-color-background-0), transparent 50%)',
padding: '.5rem',
borderRadius: '10px',
color: 'var(--mantine-color-search-0)',
backdropFilter: 'brightness(0.5)',
}}
>
<Tooltip
c={'var(--mantine-color-primary-0)'}
bg={'var(--mantine-color-background-0)'}
bd={'solid 1px var(--mantine-color-border-0)'}
label={enabled === 1 ? 'Enabled' : 'Disabled'}
refProp='rootRef'
styles={{
tooltip: { marginTop: '-.5rem' },
arrow: { border: 'solid 1px var(--mantine-color-accent-0)' },
}}
withArrow
>
<Switch
className={switchClasses.enable}
classNames={switchClasses}
defaultChecked={enabled === 1}
defaultValue={enabled}
thumbIcon={
<FiPower
style={{
color: enabled === 1 ? 'var(--mantine-color-accent-0)' : 'red',
}}
/>
}
onChange={onChange}
/>
</Tooltip>
|
<Tooltip
c={'var(--mantine-color-primary-0)'}
bg={'var(--mantine-color-background-0)'}
bd={'solid 1px var(--mantine-color-border-0)'}
label={'Delete'}
>
<ActionIcon
color='red'
onClick={() => {
openModal();
}}
>
<FiTrash color='black' />
</ActionIcon>
</Tooltip>
</Group>
);
}
export default ManagementPill;

View File

@@ -1,22 +0,0 @@
import { Card, Text } from '@mantine/core';
import { cardClasses } from 'styles';
function NoItemsFound() {
return (
<Card
className={cardClasses.settingsItem}
classNames={cardClasses}
w={'40rem'}
h={'10rem'}
p={'xl'}
m={'xl'}
style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}
>
<Text fw={300} size={'xl'}>
No items found
</Text>
</Card>
);
}
export default NoItemsFound;

View File

@@ -1,185 +0,0 @@
import {
ActionIcon,
Button,
Group,
Highlight,
Popover,
Stack,
Switch,
Text,
TextInput,
} from '@mantine/core';
import { useCommonHooks } from 'hooks';
import { useState } from 'react';
import { FiHelpCircle, FiLoader, FiPlus, FiX } from 'react-icons/fi';
import {
actionIconClasses,
buttonClasses,
popoverClasses,
switchClasses,
textClasses,
textInputClasses,
} from 'styles';
function SettingsHeader({
setDragging,
openModal,
title,
tooltip,
searchValue,
setSearchValue,
searchPlaceholder,
isLoading,
setIsLoading,
}: {
setDragging: undefined | ((dragging: boolean) => void);
openModal: () => void;
title: string;
tooltip: {
title: string;
highlightList: string[];
description: string;
};
searchValue: string | undefined;
setSearchValue: (searchValue: string) => void;
searchPlaceholder: string | undefined;
isLoading: boolean;
setIsLoading: (isLoading: boolean) => void;
}) {
const { isMobile, theme } = useCommonHooks();
const [disabled, setDisabled] = useState(false);
return (
<Group
align='center'
justify='center'
style={{
backdropFilter: 'blur(5px) 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%'}>
<Text
miw={isMobile ? 100 : undefined}
className={textClasses.settingsSubTitle}
classNames={textClasses}
>
{title}
</Text>
<Popover withArrow withOverlay classNames={popoverClasses}>
<Popover.Target>
<ActionIcon
className={actionIconClasses.settingsTooltip}
classNames={actionIconClasses}
>
<FiHelpCircle />
</ActionIcon>
</Popover.Target>
<Popover.Dropdown
style={{
color: 'var(--mantine-color-primary-0)',
backgroundColor: 'var(--mantine-color-background-0)',
width: isMobile ? '95%' : '500px',
}}
>
<Stack>
<Text className={textClasses.settingsTooltip} classNames={textClasses}>
{tooltip.title}
</Text>
<Highlight
highlight={tooltip.highlightList}
className={textClasses.settingsTooltip}
classNames={textClasses}
highlightStyles={{
backgroundImage:
'linear-gradient(45deg, var(--mantine-color-accent-0), var(--mantine-color-primary-0))',
fontWeight: 700,
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
}}
>
{tooltip.description}
</Highlight>
</Stack>
</Popover.Dropdown>
</Popover>
{searchValue !== undefined && (
<Button
className={buttonClasses.newItemButton}
classNames={buttonClasses}
onClick={openModal}
>
<FiPlus />
</Button>
)}
</Group>
{searchValue !== undefined && (
<TextInput
disabled={disabled}
w={isMobile ? undefined : '35%'}
pos={isMobile ? undefined : 'absolute'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
autoFocus={!isMobile}
placeholder={searchPlaceholder ?? 'Search...'}
value={searchValue}
onInput={(event: any) => {
setIsLoading(true);
setSearchValue(event.target.value);
}}
style={{
zIndex: 100,
}}
styles={
theme.textShadowsEnabled && {
label: { boxShadow: '2px 2px var(--mantine-color-border-0)' },
}
}
rightSection={
isLoading ? (
<ActionIcon
className={actionIconClasses.loadingSpinner}
classNames={actionIconClasses}
>
<FiLoader />
</ActionIcon>
) : (
searchValue && (
<ActionIcon
className={actionIconClasses.settingsTooltip}
classNames={actionIconClasses}
onClick={() => setSearchValue('')}
>
<FiX />
</ActionIcon>
)
)
}
/>
)}
{setDragging && (
<Switch
className={switchClasses.default}
classNames={switchClasses}
label={'Reorder'}
labelPosition='left'
pos={'absolute'}
right={isMobile ? '2rem' : '1rem'}
top={isMobile ? '3.5rem' : undefined}
onChange={(e) => {
setDragging(e.target.checked);
setDisabled(e.target.checked);
}}
/>
)}
</Group>
);
}
export default SettingsHeader;

View File

@@ -24,10 +24,10 @@ import {
scrollAreaClasses,
textInputClasses,
} from 'styles';
import DeleteBackground from './DeleteBackground';
import EditBackground from './EditBackground';
import { DeleteBackground } from './DeleteBackground';
import { EditBackground } from './EditBackground';
function BackgroundModal({
export function BackgroundModal({
backgroundModalOpened,
handleBackgroundModalClose,
backgroundList,
@@ -97,7 +97,7 @@ function BackgroundModal({
<Group w={'100%'} justify='center'>
<TextInput
w={'50%'}
className={textInputClasses.settingsItem}
className={textInputClasses.default}
classNames={textInputClasses}
autoFocus={!isMobile}
placeholder={'Search...'}
@@ -385,4 +385,3 @@ function BackgroundModal({
</Modal.Root>
);
}
export default BackgroundModal;

View File

@@ -1,7 +1,7 @@
import { Button, Card, Group, Stack, Text } from '@mantine/core';
import { useMutationAPI } from 'hooks';
function DeleteBackground({
export function DeleteBackground({
fileName,
setFileName,
inUseBackgrounds,
@@ -91,5 +91,3 @@ function DeleteBackground({
</Stack>
);
}
export default DeleteBackground;

View File

@@ -3,7 +3,7 @@ import { useCommonHooks, useMutationAPI } from 'hooks';
import { useState } from 'react';
import { textInputClasses } from 'styles';
function EditBackground({
export function EditBackground({
fileName,
setFileName,
inUseBackgrounds,
@@ -125,5 +125,3 @@ function EditBackground({
</Stack>
);
}
export default EditBackground;

View File

@@ -0,0 +1,3 @@
export { BackgroundModal } from './BackgroundModal';
export { DeleteBackground } from './DeleteBackground';
export { EditBackground } from './EditBackground';

View File

@@ -1,360 +0,0 @@
import { ActionIcon, Box, Button, Group, Overlay, Stack, Text } from '@mantine/core';
import { useDisclosure, useElementSize } from '@mantine/hooks';
import { useCommonHooks, useMutationAPI } from 'hooks';
import { useState } from 'react';
import { FiEdit, FiShuffle, FiTrash, FiX } from 'react-icons/fi';
import { actionIconClasses, boxClasses } from 'styles';
import type { Theme, ThemePlaylist } from 'types';
import DeleteItemModal from '../Shared/DeleteItemModal';
function ThemeCard({
cardTheme,
handleOpen,
allThemes,
themePlaylists,
}: {
cardTheme: Theme;
handleOpen: (cardTheme: Theme) => void;
allThemes: Theme[];
themePlaylists: ThemePlaylist[];
}) {
const { ref, width } = useElementSize();
const [hover, setHover] = useState(false);
const [shiftEdit, setShiftEdit] = useState<number>(0);
const [shiftShuffle, setShiftShuffle] = useState<number>(0);
const { mutateAsync } = useMutationAPI();
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
const {
handleThemeChange,
currentTheme,
setCurrentTheme,
theme,
currentThemePlaylist,
setCurrentThemePlaylist,
handleDelete,
} = useCommonHooks();
return (
<Group
gap={0}
align='center'
justify='center'
display={'grid'}
pos={'relative'}
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
>
<DeleteItemModal
modalOpened={modalOpened}
handleClose={closeModal}
handleDelete={() => handleDelete(cardTheme, 'api/themes')}
title={'Delete Theme'}
body={
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
<Text>Are you sure you want to delete this theme?</Text>
<Text
style={{
fontWeight: 'bold',
fontSize: '1.25rem',
padding: '.5rem',
margin: '.5rem',
borderRadius: '10px',
backgroundColor: 'var(--mantine-color-accent-0)',
color: 'var(--mantine-color-background-0)',
}}
>{`"${cardTheme.name}"`}</Text>
<Text c='red'>This action cannot be undone!</Text>
</Stack>
}
/>
<Text
style={{
position: 'absolute',
top: -10,
left: 6,
paddingRight: '.25rem',
paddingLeft: '.25rem',
backgroundColor: cardTheme.backgroundColor,
borderRadius: '4px',
color:
cardTheme.borderColor === cardTheme.primaryColor
? cardTheme.accentColor
: cardTheme.primaryColor,
zIndex: 3,
boxShadow: `2px -2px ${cardTheme.borderColor}`,
textOverflow: 'ellipsis',
overflow: 'hidden',
whiteSpace: 'nowrap',
maxWidth: width,
}}
>
{cardTheme.name}
</Text>
<Button
ref={ref}
w={'275px'}
h={'115px'}
disabled={currentTheme === 'random'}
style={{
backgroundImage:
cardTheme?.backgroundImage.toLocaleLowerCase() !== 'none'
? `linear-gradient(${cardTheme?.backgroundColor}33, ${cardTheme?.backgroundColor}33), url(../../api/backgroundImages/${cardTheme?.backgroundImage})`
: undefined,
backgroundSize:
cardTheme?.backgroundImage.toLocaleLowerCase() !== 'none'
? 'cover'
: undefined,
backgroundColor:
cardTheme?.backgroundImage.toLocaleLowerCase() === 'none'
? cardTheme?.backgroundColor
: undefined,
backgroundPosition: 'center',
border: `solid ${cardTheme.borderColor}`,
filter: cardTheme.randomEnabled === 0 ? 'saturate(0)' : undefined,
}}
onClick={() => {
setCurrentTheme(cardTheme.name);
setCurrentThemePlaylist('All');
}}
>
{hover && currentTheme !== 'random' && <Overlay opacity={0.5} zIndex={1} />}
<Group w={'100%'} gap={0} display={'flex'} align='center' justify='center'>
<Stack align='center'>
<Box
style={{
height: '10px',
width: '100px',
backgroundColor: cardTheme.searchColor,
borderRadius: '4px',
borderBottom: `solid 1px ${cardTheme.borderColor}`,
}}
/>
<Group justify='space-between'>
<Box
style={{
height: '.5rem',
width: '100px',
backgroundColor: cardTheme.accentColor,
borderRadius: '4px',
}}
/>
<Box
style={{
height: '.5rem',
width: '50px',
backgroundColor: cardTheme.primaryColor,
borderRadius: '4px',
}}
/>
</Group>
<Group w={'100%'}>
<Box
style={{
height: '.25rem',
width: '40px',
backgroundColor: cardTheme.primaryColor,
borderRadius: '4px',
}}
/>
</Group>
<Group w={'100%'}>
<Box
className={boxClasses.appItemExampleText}
style={{
color: cardTheme.primaryColor,
}}
>
lorem ipsum
</Box>
<Box
className={boxClasses.appItemExampleText}
style={{
color: cardTheme.primaryColor,
}}
>
lorem ipsum
</Box>
<Box
className={boxClasses.appItemExampleText}
style={{
color: cardTheme.primaryColor,
}}
>
lorem ipsum
</Box>
</Group>
</Stack>
</Group>
</Button>
{currentTheme === 'random' && cardTheme.name === theme.name ? (
<Group>
<Group
onMouseEnter={() => {
setShiftEdit(2);
}}
onMouseLeave={() => {
setShiftEdit(0);
}}
onClick={() => {
handleOpen(cardTheme);
}}
gap={0}
style={{
zIndex: 300,
position: 'absolute',
left: 0,
top: 27 - shiftEdit,
backgroundColor:
shiftEdit === 0 ? 'white' : 'var(--mantine-color-background-0)',
borderRadius: '50%',
padding: '.5rem',
margin: '.25rem',
border: 'solid 2px',
borderColor: shiftEdit === 0 ? 'black' : 'var(--mantine-color-primary-0)',
transition: 'all 0.2s',
}}
>
<FiEdit
style={{
fontSize: '2rem',
fontWeight: 'bold',
color: shiftEdit === 0 ? 'black' : 'var(--mantine-color-primary-0)',
cursor: 'pointer',
}}
/>
</Group>
<Group
onMouseEnter={() => {
setShiftShuffle(2);
}}
onMouseLeave={() => {
setShiftShuffle(0);
}}
onClick={() => {
if (currentThemePlaylist === 'All') {
handleThemeChange(allThemes, false);
} else if (currentThemePlaylist === 'Backgrounds') {
handleThemeChange(
allThemes.filter(
(a: any) => !a.backgroundImage.toLowerCase().includes('none'),
),
false,
);
} else if (currentThemePlaylist === 'No Backgrounds') {
handleThemeChange(
allThemes.filter((a: any) =>
a.backgroundImage.toLowerCase().includes('none'),
),
false,
);
} else {
const themeList = JSON.parse(
themePlaylists?.find(
(t: ThemePlaylist) => t?.name === currentThemePlaylist,
)?.themeList ?? '[]',
);
const filteredThemes = allThemes.filter((t: Theme) =>
themeList.includes(t.id),
);
handleThemeChange(filteredThemes, false);
}
}}
gap={0}
style={{
zIndex: 300,
position: 'absolute',
right: 0,
top: 27 - shiftShuffle,
backgroundColor:
shiftShuffle === 0 ? 'white' : 'var(--mantine-color-background-0)',
borderRadius: '50%',
padding: '.5rem',
margin: '.25rem',
border: 'solid 2px',
borderColor:
shiftShuffle === 0 ? 'black' : 'var(--mantine-color-primary-0)',
transition: 'all 0.2s',
}}
>
<FiShuffle
style={{
fontSize: '2rem',
fontWeight: 'bold',
color: shiftShuffle === 0 ? 'black' : 'var(--mantine-color-primary-0)',
cursor: 'pointer',
}}
/>
</Group>
</Group>
) : (
<Stack
gap={0}
style={{
zIndex: 2,
padding: '.25rem',
paddingRight: 0,
position: 'absolute',
right: 3,
backgroundColor: '#ffffff88',
borderTopLeftRadius: '10px',
borderBottomLeftRadius: '10px',
}}
align='center'
justify='center'
display={
currentTheme === 'random' && cardTheme.name === theme.name ? 'none' : 'flex'
}
>
<ActionIcon
style={{
background: cardTheme.randomEnabled
? 'rgba(255,255,255,1)'
: 'rgba(255,255,255,0.5)',
margin: '.125rem',
}}
styles={{
root: {
height: '10px',
width: '10px',
},
icon: {
height: '20px',
width: '20px',
fontSize: '1.5rem',
margin: 0,
padding: 0,
},
}}
onClick={() => {
mutateAsync({
method: 'PATCH',
endpoint: 'api/themes',
body: { ...cardTheme, randomEnabled: !cardTheme.randomEnabled },
});
}}
>
{cardTheme.randomEnabled ? <FiShuffle color='green' /> : <FiX color='red' />}
</ActionIcon>
<ActionIcon
className={actionIconClasses.themeEditButton}
classNames={actionIconClasses}
onClick={() => handleOpen(cardTheme)}
mb={'.125rem'}
>
<FiEdit color='green' />
</ActionIcon>
<ActionIcon
className={actionIconClasses.themeEditButton}
classNames={actionIconClasses}
onClick={openModal}
disabled={cardTheme.name === theme.name}
>
<FiTrash color='red' />
</ActionIcon>
</Stack>
)}
</Group>
);
}
export default ThemeCard;

View File

@@ -8,15 +8,15 @@ import {
Text,
} from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { DeleteItemModal } from 'components';
import { useCommonHooks } from 'hooks';
import { useState } from 'react';
import { FiEdit, FiTrash } from 'react-icons/fi';
import { scrollAreaClasses } from 'styles';
import type { Theme, ThemePlaylist } from 'types';
import DeleteItemModal from '../Shared/DeleteItemModal';
import ThemeMiniCard from './ThemeMiniCard';
import { ThemeMiniCard } from '../Themes';
function ThemePlaylistCard({
export function ThemePlaylistCard({
cardPlaylist,
handleOpen,
allThemes,
@@ -220,5 +220,3 @@ function ThemePlaylistCard({
</Group>
);
}
export default ThemePlaylistCard;

View File

@@ -3,10 +3,9 @@ import { useCommonHooks } from 'hooks';
import { useEffect, useState } from 'react';
import { modalClasses, textInputClasses } from 'styles';
import type { Theme, ThemePlaylist } from 'types';
import ThemePreviewMiddleware from './ThemePreivewMiddleware';
import TimeOfDay from './TimeOfDay';
import { ThemePreviewMiddleware, TimeOfDay } from '../Themes';
function ThemePlaylistModal({
export function ThemePlaylistModal({
opened,
handleClose,
createPlaylist,
@@ -127,5 +126,3 @@ function ThemePlaylistModal({
</Modal.Root>
);
}
export default ThemePlaylistModal;

View File

@@ -1,16 +1,15 @@
import { Box, Group, SimpleGrid, Stack, Text } from '@mantine/core';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { NoItemsFound, SettingsHeader } from 'components';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useEffect, useState } from 'react';
import { FiChevronRight } from 'react-icons/fi';
import { textClasses } from 'styles';
import type { Theme, ThemePlaylist } from 'types';
import NoItemsFound from '../Shared/NoItemsFound';
import SettingsHeader from '../Shared/SettingsHeader';
import ThemePlaylistCard from './ThemePlaylistCard';
import ThemePlaylistModal from './ThemePlaylistModal';
import { ThemePlaylistCard } from './ThemePlaylistCard';
import { ThemePlaylistModal } from './ThemePlaylistModal';
function ThemePlaylists() {
export function ThemePlaylists() {
const themesEndpoint = 'api/themes';
const { data: allThemeData } = useQueryAPI({
endpoint: themesEndpoint,
@@ -303,5 +302,3 @@ function ThemePlaylists() {
</Stack>
);
}
export default ThemePlaylists;

View File

@@ -0,0 +1,3 @@
export { ThemePlaylistCard } from './ThemePlaylistCard';
export { ThemePlaylistModal } from './ThemePlaylistModal';
export { ThemePlaylists } from './ThemePlaylists';

View File

@@ -0,0 +1,205 @@
import { Box, Button, Group, Overlay, Stack, Text } from '@mantine/core';
import {
useDebouncedState,
useDisclosure,
useElementSize,
useHover,
} from '@mantine/hooks';
import { DeleteItemModal } from 'components';
import { useCommonHooks } from 'hooks';
import { boxClasses } from 'styles';
import type { Theme, ThemePlaylist } from 'types';
import { ThemeManagementPill } from '.';
export function ThemeCard({
cardTheme,
handleOpen,
allThemes,
themePlaylists,
}: {
cardTheme: Theme;
handleOpen: (cardTheme: Theme) => void;
allThemes: Theme[];
themePlaylists: ThemePlaylist[];
}) {
const { hovered, ref: hoverRef } = useHover();
const { ref, width } = useElementSize();
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
const { currentTheme, setCurrentTheme, setCurrentThemePlaylist, handleDelete } =
useCommonHooks();
const [hoverPreview, setHoverPreview] = useDebouncedState(false, 1000);
return (
<Group
gap={0}
align='center'
justify='center'
display={'grid'}
pos={'relative'}
ref={hoverRef}
>
<DeleteItemModal
modalOpened={modalOpened}
handleClose={closeModal}
handleDelete={() => handleDelete(cardTheme, 'api/themes')}
title={'Delete Theme'}
body={
<Stack gap={0} w={'100%'} h={'150px'} align='center'>
<Text>Are you sure you want to delete this theme?</Text>
<Text
style={{
fontWeight: 'bold',
fontSize: '1.25rem',
padding: '.5rem',
margin: '.5rem',
borderRadius: '10px',
backgroundColor: 'var(--mantine-color-accent-0)',
color: 'var(--mantine-color-background-0)',
}}
>{`"${cardTheme.name}"`}</Text>
<Text c='red'>This action cannot be undone!</Text>
</Stack>
}
/>
<Text
style={{
position: 'absolute',
top: -10,
left: 6,
paddingRight: '.25rem',
paddingLeft: '.25rem',
backgroundColor: cardTheme.backgroundColor,
borderRadius: '4px',
color:
cardTheme.borderColor === cardTheme.primaryColor
? cardTheme.accentColor
: cardTheme.primaryColor,
zIndex: 3,
boxShadow: `2px -2px ${cardTheme.borderColor}`,
textOverflow: 'ellipsis',
overflow: 'hidden',
whiteSpace: 'nowrap',
maxWidth: width,
}}
>
{cardTheme.name}
</Text>
<Group
style={{
width: '100%',
height: '100%',
overflow: 'hidden',
transition: 'all .2s ease',
position: 'absolute',
}}
>
<ThemeManagementPill
allThemes={allThemes}
cardTheme={cardTheme}
handleOpen={handleOpen}
themePlaylists={themePlaylists}
openModal={openModal}
hovered={hovered}
setHoverPreview={setHoverPreview}
/>
</Group>
<Button
ref={ref}
w={'275px'}
h={'115px'}
disabled={currentTheme === 'random'}
style={{
backgroundImage:
cardTheme?.backgroundImage.toLocaleLowerCase() !== 'none'
? `linear-gradient(${cardTheme?.backgroundColor}33, ${cardTheme?.backgroundColor}33), url(../../api/backgroundImages/${cardTheme?.backgroundImage})`
: undefined,
backgroundSize:
cardTheme?.backgroundImage.toLocaleLowerCase() !== 'none'
? 'cover'
: undefined,
backgroundColor:
cardTheme?.backgroundImage.toLocaleLowerCase() === 'none'
? cardTheme?.backgroundColor
: undefined,
backgroundPosition: 'center',
border: `solid ${cardTheme.borderColor}`,
filter:
cardTheme.randomEnabled === 0 && !hoverPreview ? 'saturate(0)' : undefined,
transition: 'all .2s ease',
}}
onClick={() => {
setCurrentTheme(cardTheme.name);
setCurrentThemePlaylist('All');
}}
>
{hovered && currentTheme !== 'random' && <Overlay opacity={0.5} zIndex={1} />}
<Group w={'100%'} gap={0} display={'flex'} align='center' justify='center'>
<Stack align='center'>
<Box
style={{
height: '10px',
width: '100px',
backgroundColor: cardTheme.searchColor,
borderRadius: '4px',
borderBottom: `solid 1px ${cardTheme.borderColor}`,
}}
/>
<Group justify='space-between'>
<Box
style={{
height: '.5rem',
width: '100px',
backgroundColor: cardTheme.accentColor,
borderRadius: '4px',
}}
/>
<Box
style={{
height: '.5rem',
width: '50px',
backgroundColor: cardTheme.primaryColor,
borderRadius: '4px',
}}
/>
</Group>
<Group w={'100%'}>
<Box
style={{
height: '.25rem',
width: '40px',
backgroundColor: cardTheme.primaryColor,
borderRadius: '4px',
}}
/>
</Group>
<Group w={'100%'}>
<Box
className={boxClasses.appItemExampleText}
style={{
color: cardTheme.primaryColor,
}}
>
lorem ipsum
</Box>
<Box
className={boxClasses.appItemExampleText}
style={{
color: cardTheme.primaryColor,
}}
>
lorem ipsum
</Box>
<Box
className={boxClasses.appItemExampleText}
style={{
color: cardTheme.primaryColor,
}}
>
lorem ipsum
</Box>
</Group>
</Stack>
</Group>
</Button>
</Group>
);
}

View File

@@ -4,7 +4,7 @@ import { FiCheck } from 'react-icons/fi';
import { boxClasses, textClasses } from 'styles';
import type { Theme } from 'types';
function ExampleApp({ selectedTheme }: { selectedTheme: Theme }) {
export function ThemeExampleApp({ selectedTheme }: { selectedTheme: Theme }) {
const [textDecoration, setTextDecoration] = useState<string>('none');
return (
@@ -53,5 +53,3 @@ function ExampleApp({ selectedTheme }: { selectedTheme: Theme }) {
</Box>
);
}
export default ExampleApp;

View File

@@ -0,0 +1,227 @@
import { ActionIcon, Group, isLightColor, Stack, Text } from '@mantine/core';
import { useCommonHooks, useMutationAPI } from 'hooks';
import { useState } from 'react';
import { FaTrashAlt } from 'react-icons/fa';
import { FaPencil } from 'react-icons/fa6';
import { FiEdit, FiPower, FiShuffle } from 'react-icons/fi';
import { actionIconClasses } from 'styles';
import type { Theme, ThemePlaylist } from 'types';
export function ThemeManagementPill({
allThemes,
cardTheme,
handleOpen,
themePlaylists,
openModal,
hovered,
setHoverPreview,
}: {
allThemes: Theme[];
cardTheme: Theme;
handleOpen: (cardTheme: Theme) => void;
themePlaylists: ThemePlaylist[];
openModal: () => void;
hovered: boolean;
setHoverPreview: (hoverPreview: boolean) => void;
}) {
const { currentTheme, currentThemePlaylist, handleThemeChange, theme } =
useCommonHooks();
const [shiftEdit, setShiftEdit] = useState<number>(0);
const [shiftShuffle, setShiftShuffle] = useState<number>(0);
const { mutateAsync } = useMutationAPI();
return (
<>
{currentTheme === 'random' && cardTheme.name === theme.name ? (
<Group>
<Group
onMouseEnter={() => {
setShiftEdit(2);
}}
onMouseLeave={() => {
setShiftEdit(0);
}}
onClick={() => {
handleOpen(cardTheme);
}}
gap={0}
style={{
zIndex: 300,
position: 'absolute',
left: 0,
top: 27 - shiftEdit,
backgroundColor:
shiftEdit === 0 ? 'white' : 'var(--mantine-color-background-0)',
borderRadius: '50%',
padding: '.5rem',
margin: '.25rem',
border: 'solid 2px',
borderColor: shiftEdit === 0 ? 'black' : 'var(--mantine-color-primary-0)',
transition: 'all 0.2s',
}}
>
<FiEdit
style={{
fontSize: '2rem',
fontWeight: 'bold',
color: shiftEdit === 0 ? 'black' : 'var(--mantine-color-primary-0)',
cursor: 'pointer',
}}
/>
</Group>
<Group
onMouseEnter={() => {
setShiftShuffle(2);
}}
onMouseLeave={() => {
setShiftShuffle(0);
}}
onClick={() => {
if (currentThemePlaylist === 'All') {
handleThemeChange(allThemes, false);
} else if (currentThemePlaylist === 'Backgrounds') {
handleThemeChange(
allThemes.filter(
(a: any) => !a.backgroundImage.toLowerCase().includes('none'),
),
false,
);
} else if (currentThemePlaylist === 'No Backgrounds') {
handleThemeChange(
allThemes.filter((a: any) =>
a.backgroundImage.toLowerCase().includes('none'),
),
false,
);
} else {
const themeList = JSON.parse(
themePlaylists?.find(
(t: ThemePlaylist) => t?.name === currentThemePlaylist,
)?.themeList ?? '[]',
);
const filteredThemes = allThemes.filter((t: Theme) =>
themeList.includes(t.id),
);
handleThemeChange(filteredThemes, false);
}
}}
gap={0}
style={{
zIndex: 300,
position: 'absolute',
right: 0,
top: 27 - shiftShuffle,
backgroundColor:
shiftShuffle === 0 ? 'white' : 'var(--mantine-color-background-0)',
borderRadius: '50%',
padding: '.5rem',
margin: '.25rem',
border: 'solid 2px',
borderColor:
shiftShuffle === 0 ? 'black' : 'var(--mantine-color-primary-0)',
transition: 'all 0.2s',
}}
>
<FiShuffle
style={{
fontSize: '2rem',
fontWeight: 'bold',
color: shiftShuffle === 0 ? 'black' : 'var(--mantine-color-primary-0)',
cursor: 'pointer',
}}
/>
</Group>
</Group>
) : (
<>
<Stack
gap={0}
style={{
zIndex: 2,
paddingRight: 0,
position: 'absolute',
right: 3,
top: 3,
marginRight: !hovered ? 0 : '-2.5rem',
transition: 'all 0.2s',
}}
align='center'
justify='center'
h={'100%'}
>
{!cardTheme.randomEnabled && (
<Text
style={{
writingMode: 'sideways-lr',
color: isLightColor(cardTheme.backgroundColor) ? 'black' : 'white',
opacity: 0.5,
}}
>
DISABLED
</Text>
)}
</Stack>
<Stack
gap={0}
style={{
zIndex: 2,
padding: '.25rem',
paddingRight: 0,
position: 'absolute',
right: 3,
backgroundColor: '#ffffff33',
borderTopLeftRadius: '10px',
borderBottomLeftRadius: '10px',
marginRight: hovered ? 0 : '-2.5rem',
transition: 'all 0.2s',
backdropFilter: 'blur(10px)',
}}
align='center'
justify='center'
>
<ActionIcon
className={actionIconClasses.themeEditButton}
classNames={actionIconClasses}
onMouseEnter={() => setHoverPreview(true)}
onMouseLeave={() => setHoverPreview(false)}
onClick={() => {
mutateAsync({
method: 'PATCH',
endpoint: 'api/themes',
body: { ...cardTheme, randomEnabled: !cardTheme.randomEnabled },
});
}}
mb={'.125rem'}
>
<FiPower
color={cardTheme.randomEnabled ? 'DarkOliveGreen' : '#33333388'}
style={{ strokeWidth: 4, filter: 'brightness(1.5)' }}
/>
</ActionIcon>
<ActionIcon
className={actionIconClasses.themeEditButton}
classNames={actionIconClasses}
onClick={() => handleOpen(cardTheme)}
mb={'.125rem'}
>
<FaPencil
style={{ padding: '.25rem', filter: 'brightness(1.5)' }}
color='DarkOliveGreen'
/>
</ActionIcon>
<ActionIcon
className={actionIconClasses.themeEditButton}
classNames={actionIconClasses}
onClick={openModal}
disabled={cardTheme.name === theme.name}
>
<FaTrashAlt
style={{ padding: '.25rem', filter: 'brightness(1.25)' }}
color='Brown'
/>
</ActionIcon>
</Stack>
</>
)}
</>
);
}

View File

@@ -1,7 +1,7 @@
import { Group, Text } from '@mantine/core';
import type { Theme } from 'types';
function ThemeMiniCard({ miniTheme }: { miniTheme: Theme | undefined }) {
export function ThemeMiniCard({ miniTheme }: { miniTheme: Theme | undefined }) {
return (
<Group
gap={0}
@@ -41,5 +41,3 @@ function ThemeMiniCard({ miniTheme }: { miniTheme: Theme | undefined }) {
</Group>
);
}
export default ThemeMiniCard;

View File

@@ -19,9 +19,9 @@ import { useEffect, useRef, useState } from 'react';
import { FiImage, FiSave, FiX } from 'react-icons/fi';
import { modalClasses, scrollAreaClasses, textClasses, textInputClasses } from 'styles';
import type { Theme } from 'types';
import ThemeModalContent from './ThemeModalContent';
import { ThemeModalContent } from './ThemeModalContent';
function ThemeModal({
export function ThemeModal({
opened,
handleClose,
selectedTheme,
@@ -547,5 +547,3 @@ function ThemeModal({
</Modal.Root>
);
}
export default ThemeModal;

View File

@@ -2,7 +2,7 @@ import { ColorSwatch, Group, Stack, Text } from '@mantine/core';
import { colorSwatchClasses, textClasses } from 'styles';
import type { Theme } from 'types';
function ThemeModalColorSwatches({
export function ThemeModalColorSwatches({
selectedTheme,
openPicker,
setColorId,
@@ -93,5 +93,3 @@ function ThemeModalColorSwatches({
</Stack>
);
}
export default ThemeModalColorSwatches;

View File

@@ -2,9 +2,9 @@ import { Select, Stack, Text } from '@mantine/core';
import SearchSelectItem from 'pages/homepage/components/Search/SearchSelectItem';
import { selectClasses } from 'styles';
import type { Theme } from 'types';
import ThemeExampleApp from './ThemeExampleApp';
import { ThemeExampleApp } from './ThemeExampleApp';
export default function ThemeModalContent({ selectedTheme }: { selectedTheme: Theme }) {
export function ThemeModalContent({ selectedTheme }: { selectedTheme: Theme }) {
return (
<Stack
style={{

View File

@@ -1,10 +1,10 @@
import { Group, Overlay, Popover } from '@mantine/core';
import { useLongPress } from '@mantine/hooks';
import { useState } from 'react';
import ThemeMiniCard from './ThemeMiniCard';
import ThemeModalContent from './ThemeModalContent';
import { ThemeMiniCard } from './ThemeMiniCard';
import { ThemeModalContent } from './ThemeModalContent';
function ThemePreviewMiddleware({
export function ThemePreviewMiddleware({
newThemeList,
miniTheme,
themeList,
@@ -79,5 +79,3 @@ function ThemePreviewMiddleware({
</Popover>
);
}
export default ThemePreviewMiddleware;

View File

@@ -7,7 +7,7 @@ import {
} from '@mantine/core';
import type { Theme, ThemePlaylist } from 'types';
function ThemeSelect({
export function ThemeSelect({
allThemes,
createPlaylist,
themeList,
@@ -124,5 +124,3 @@ function ThemeSelect({
</Group>
);
}
export default ThemeSelect;

View File

@@ -1,5 +1,6 @@
import { Box, Button, 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 { useEffect, useState } from 'react';
import { FaDice } from 'react-icons/fa';
@@ -7,13 +8,11 @@ import { FiChevronRight, FiEdit, FiMousePointer, FiStopCircle } from 'react-icon
import { useNavigate } from 'react-router-dom';
import { switchClasses, textClasses } from 'styles';
import type { Theme, ThemePlaylist } from 'types';
import NoItemsFound from '../Shared/NoItemsFound';
import SettingsHeader from '../Shared/SettingsHeader';
import BackgroundModal from './BackgroundModal';
import ThemeCard from './ThemeCard';
import ThemeModal from './ThemeModal';
import { BackgroundModal } from '../Backgrounds';
import { ThemeCard } from './ThemeCard';
import { ThemeModal } from './ThemeModal';
function ThemesSettings() {
export function Themes() {
const themesEndpoint = 'api/themes';
const backgroundsEndpoint = 'api/backgrounds';
const { data: allThemeData, isFetched: isAllThemeDataFetched } = useQueryAPI({
@@ -62,6 +61,7 @@ function ThemesSettings() {
currentThemePlaylist,
setCurrentThemePlaylist,
} = useCommonHooks();
const handleOpen = (theme: Theme) => {
setSelectedTheme(theme);
openThemeModal();
@@ -379,4 +379,3 @@ function ThemesSettings() {
</Stack>
);
}
export default ThemesSettings;

View File

@@ -1,8 +1,8 @@
import { Stack } from '@mantine/core';
import type { Theme, ThemePlaylist } from 'types';
import ThemeSelect from './ThemeSelect';
import { ThemeSelect } from './ThemeSelect';
function TimeOfDay({
export function TimeOfDay({
createPlaylist,
themeList,
allThemes,
@@ -50,5 +50,3 @@ function TimeOfDay({
</Stack>
);
}
export default TimeOfDay;

View File

@@ -0,0 +1,11 @@
export { ThemeCard } from './ThemeCard';
export { ThemeExampleApp } from './ThemeExampleApp';
export { ThemeManagementPill } from './ThemeManagementPill';
export { ThemeMiniCard } from './ThemeMiniCard';
export { ThemeModal } from './ThemeModal';
export { ThemeModalColorSwatches } from './ThemeModalColorSwatches';
export { ThemeModalContent } from './ThemeModalContent';
export { ThemePreviewMiddleware } from './ThemePreviewMiddleware';
export { ThemeSelect } from './ThemeSelect';
export { Themes } from './Themes';
export { TimeOfDay } from './TimeOfDay';

View File

@@ -1,11 +1,11 @@
import { ActionIcon, Card, Group, Stack, Text, TextInput, Tooltip } from '@mantine/core';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { DeleteItemModal } from 'components';
import { useCommonHooks, useMutationAPI } from 'hooks';
import { useEffect, useState } from 'react';
import { FiTrash } from 'react-icons/fi';
import { cardClasses, textInputClasses } from 'styles';
import type { WolClient } from 'types';
import DeleteItemModal from '../Shared/DeleteItemModal';
function DebouncedWolClient({
wolClient,

View File

@@ -1,13 +1,11 @@
import { Button, Grid, GridCol, Group, Popover, Stack, TextInput } from '@mantine/core';
import { isNotEmpty, matches, useForm } from '@mantine/form';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { AddItemModal, NoItemsFound, SettingsHeader } from 'components';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useEffect, useState } from 'react';
import { popoverClasses, textInputClasses } from 'styles';
import type { WolClient } from 'types';
import AddItemModal from '../Shared/AddItemModal';
import NoItemsFound from '../Shared/NoItemsFound';
import SettingsHeader from '../Shared/SettingsHeader';
import DebouncedWolClient from './DebouncedWolClient';
import WolClientSettingsItem from './WolClientSettingsItem';