Mobile and style improvements

This commit is contained in:
Sean Edmunds
2025-03-28 14:25:33 -05:00
parent e935b13baf
commit 332c759ed0
23 changed files with 743 additions and 572 deletions

View File

@@ -1,5 +1,4 @@
import { Group, Stack, Text } from '@mantine/core';
import { WeatherModal } from 'components';
import { useCommonHooks } from 'hooks';
import { useEffect, useState } from 'react';
import { textClasses } from 'styles';
@@ -9,12 +8,8 @@ function Header({
date,
current,
setCurrent,
outlook,
extendedForecast,
weather,
basicWeather,
weatherModalOpened,
closeWeatherModal,
openWeatherModal,
}: any) {
const [time, setTime] = useState(new Date());
@@ -127,6 +122,7 @@ function Header({
position: 'absolute',
bottom: isMobile ? -32 : 0,
right: 16,
cursor: 'pointer',
}}
onClick={openWeatherModal}
>
@@ -158,13 +154,6 @@ function Header({
</Text>
</Group>
</Stack>
<WeatherModal
current={current}
outlook={outlook}
extendedForecast={extendedForecast}
closeWeatherModal={closeWeatherModal}
weatherModalOpened={weatherModalOpened}
/>
</Stack>
);
}

View File

@@ -43,6 +43,7 @@ export default function Search({
const [listIndex, setListIndex] = useState(0);
const {
theme,
isMobile,
urlPattern,
providerLabel,
setProviderLabel,
@@ -263,7 +264,13 @@ export default function Search({
const [showFillButton, setShowFillButton] = useState(false);
if (item.option.searchTerm !== undefined) {
const m = new Date(item.option.dateTimeStamp);
const dateString = `${m.getUTCFullYear()}/${`0${m.getUTCMonth() + 1}`.slice(-2)}/${`0${m.getUTCDate()}`.slice(-2)} ${`0${m.getUTCHours()}`.slice(-2)}:${`0${m.getUTCMinutes()}`.slice(-2)}:${`0${m.getUTCSeconds()}`.slice(-2)}`;
const year = m.getUTCFullYear();
const month = `0${m.getUTCMonth() + 1}`.slice(-2);
const day = `0${m.getUTCDate()}`.slice(-2);
const hours = `0${m.getUTCHours()}`.slice(-2);
const minutes = `0${m.getUTCMinutes()}`.slice(-2);
const seconds = `0${m.getUTCSeconds()}`.slice(-2);
const dateString = `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
return (
<Group
w={'100%'}
@@ -446,7 +453,7 @@ export default function Search({
}}
spellCheck='true'
searchable
autoFocus
autoFocus={!isMobile}
leftSection={providerLabel}
rightSection={<Stack />}
renderOption={RenderOption}
@@ -478,6 +485,9 @@ export default function Search({
closeProviderModal={closeProviderModal}
/>
<WeatherModal
setSearchValue={setSearchValue}
setProviderLabel={setProviderLabel}
setProviderURL={setProviderURL}
current={current}
outlook={outlook}
extendedForecast={extendedForecast}

View File

@@ -1,9 +1,9 @@
import { ActionIcon, Group, Stack, Tabs, Text } from '@mantine/core';
import { useCommonHooks } from 'hooks';
import { FaPaintBrush, FaRegListAlt } from 'react-icons/fa';
import {
FiArrowLeftCircle,
FiBookmark,
FiEdit,
FiGlobe,
FiMail,
FiMonitor,
@@ -65,10 +65,10 @@ export function Settings() {
{isMobile ? <FiBookmark /> : 'Bookmarks'}
</Tabs.Tab>
<Tabs.Tab px={isMobile ? '.9rem' : undefined} value='themes'>
{isMobile ? <FiEdit /> : 'Themes'}
{isMobile ? <FaPaintBrush /> : 'Themes'}
</Tabs.Tab>
<Tabs.Tab px={isMobile ? '.9rem' : undefined} value='themePlaylists'>
{isMobile ? <FiEdit /> : 'Theme Playlists'}
{isMobile ? <FaRegListAlt /> : 'Theme Playlists'}
</Tabs.Tab>
<Tabs.Tab px={isMobile ? '.9rem' : undefined} value='providers'>
{isMobile ? <FiSearch /> : 'Search Providers'}

View File

@@ -2,6 +2,7 @@ import {
ActionIcon,
Box,
Button,
Card,
Divider,
Grid,
GridCol,
@@ -20,6 +21,7 @@ import { FiHelpCircle, FiPlus } from 'react-icons/fi';
import {
actionIconClasses,
buttonClasses,
cardClasses,
modalClasses,
textClasses,
textInputClasses,
@@ -81,108 +83,111 @@ const ApplicationSettings = () => {
<Modal.CloseButton />
</Modal.Header>
<Modal.Body pb={'2rem'}>
<Stack gap={0} w={'100%'} align='center'>
<Group w={'100%'} justify='center'>
<TextInput
label={'Name'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newApplication.name}
onChange={(event) => {
setNewApplication({
...newApplication,
name: event.target.value,
});
}}
/>
<TextInput
label={'Base URL'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newApplication.baseUrl}
onChange={(event) => {
setNewApplication({
...newApplication,
baseUrl: event.target.value,
});
}}
/>
</Group>
<Group w={'100%'} justify='center'>
<TextInput
label={'URL'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newApplication.url}
onChange={(event) => {
setNewApplication({
...newApplication,
url: event.target.value,
});
}}
/>
</Group>
<Group w={'100%'} justify='center'>
<TextInput
label={'Icon'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newApplication.icon}
onChange={(event) => {
setNewApplication({
...newApplication,
icon: event.target.value,
});
}}
/>
<TextInput
label={'Filter'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newApplication.filterName}
onChange={(event) => {
setNewApplication({
...newApplication,
filterName: event.target.value,
});
}}
/>
</Group>
<Divider color='black' my='sm' />
<Group pos={'absolute'} bottom={8}>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newApplication) {
mutateAsync({
method: 'POST',
endpoint: endpoint,
body: newApplication,
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
<Stack gap={0} align='center'>
<Group justify='center'>
<TextInput
label={'Name'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newApplication.name}
onChange={(event) => {
setNewApplication({
...newApplication,
name: event.target.value,
});
}}
/>
<TextInput
label={'Base URL'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newApplication.baseUrl}
onChange={(event) => {
setNewApplication({
...newApplication,
baseUrl: event.target.value,
});
}}
/>
</Group>
<Group w={isMobile ? undefined : '60%'} justify='center'>
<TextInput
label={'URL'}
className={textInputClasses.settingsItem}
pt={16}
w={isMobile ? undefined : '91%'}
classNames={textInputClasses}
defaultValue={newApplication.url}
onChange={(event) => {
setNewApplication({
...newApplication,
url: event.target.value,
});
}}
/>
</Group>
<Group justify='center'>
<TextInput
label={'Icon'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newApplication.icon}
onChange={(event) => {
setNewApplication({
...newApplication,
icon: event.target.value,
});
}}
/>
<TextInput
label={'Filter'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newApplication.filterName}
onChange={(event) => {
setNewApplication({
...newApplication,
filterName: event.target.value,
});
}}
/>
</Group>
<Divider color='black' my='lg' />
<Group pos={'absolute'} bottom={8}>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newApplication) {
mutateAsync({
method: 'POST',
endpoint: endpoint,
body: newApplication,
});
closeModal();
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
closeModal();
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
closeModal();
}}
>
Cancel
</Button>
</Group>
</Stack>
}}
>
Cancel
</Button>
</Group>
</Stack>
</Card>
</Modal.Body>
</Modal.Content>
</Modal.Root>
@@ -252,7 +257,7 @@ const ApplicationSettings = () => {
pos={isMobile ? undefined : 'absolute'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
autoFocus
autoFocus={!isMobile}
placeholder='Search...'
value={searchValue}
onInput={(event: any) => {

View File

@@ -26,13 +26,13 @@ function DebouncedApplication({ application }: { application: Application }) {
const [debounced] = useDebouncedValue(update, 1000);
useEffect(() => {
if (Object.keys(debounced).length) {
if (debounced && Object.keys(debounced).length > 0) {
mutateAsync({ method: 'PATCH', endpoint: 'api/apps', body: debounced });
}
}, [debounced]);
useEffect(() => {
if (update !== app && Object.keys(update).length) {
if (update && update !== app && Object.keys(update).length) {
setApp(update);
}
}, [update]);

View File

@@ -21,6 +21,7 @@ import { FiHelpCircle, FiPlus } from 'react-icons/fi';
import {
actionIconClasses,
buttonClasses,
cardClasses,
modalClasses,
textClasses,
textInputClasses,
@@ -125,65 +126,67 @@ const BookmarkSettings = () => {
<Modal.CloseButton />
</Modal.Header>
<Modal.Body pb={'2rem'}>
<Stack gap={0} w={'100%'} align='center'>
<Group w={'100%'} justify='center'>
<TextInput
label={'Category Name'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newGroup.categoryName}
onChange={(event) => {
setNewGroup({
...newGroup,
categoryName: event.target.value,
});
}}
/>
<TextInput
label={'Filter Name'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newGroup.filterName}
onChange={(event) => {
setNewGroup({
...newGroup,
filterName: event.target.value,
});
}}
/>
</Group>
<Divider color='black' my='sm' />
<Group pos={'absolute'} bottom={8}>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newGroup) {
mutateAsync({
method: 'POST',
endpoint: 'api/categories',
body: { ...newGroup, categoryIndex: groups.length },
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
<Stack gap={0} w={'100%'} align='center'>
<Group w={'100%'} justify='center'>
<TextInput
label={'Category Name'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newGroup.categoryName}
onChange={(event) => {
setNewGroup({
...newGroup,
categoryName: event.target.value,
});
}}
/>
<TextInput
label={'Filter Name'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newGroup.filterName}
onChange={(event) => {
setNewGroup({
...newGroup,
filterName: event.target.value,
});
}}
/>
</Group>
<Divider color='black' my='lg' />
<Group pos={'absolute'} bottom={8}>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newGroup) {
mutateAsync({
method: 'POST',
endpoint: 'api/categories',
body: { ...newGroup, categoryIndex: groups.length },
});
closeModal();
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
closeModal();
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
closeModal();
}}
>
Cancel
</Button>
</Group>
</Stack>
}}
>
Cancel
</Button>
</Group>
</Stack>
</Card>
</Modal.Body>
</Modal.Content>
</Modal.Root>
@@ -253,7 +256,7 @@ const BookmarkSettings = () => {
pos={isMobile ? undefined : 'absolute'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
autoFocus
autoFocus={!isMobile}
placeholder='Search...'
value={searchValue}
onInput={(event: any) => {
@@ -261,16 +264,23 @@ const BookmarkSettings = () => {
}}
/>
<Switch
label={'Reorder'}
label={<Text c={theme.primaryColor}>Reorder</Text>}
labelPosition='left'
pos={'absolute'}
right={isMobile ? '2rem' : '1rem'}
top={isMobile ? '9.5rem' : undefined}
top={isMobile ? '10rem' : undefined}
onChange={(e) => {
setDragging(e.target.checked);
}}
color={theme.primaryColor}
styles={{ label: { color: theme.primaryColor } }}
styles={{
label: {
color: theme.primaryColor,
top: isMobile ? -22 : 0,
left: isMobile ? -8 : 0,
position: isMobile ? 'absolute' : undefined,
},
}}
/>
</Group>
{dragging ? (
@@ -352,7 +362,7 @@ const BookmarkSettings = () => {
</DragDropContext>
) : (
<Stack w={'100%'} align='center'>
<Group w={'75%'} align='start'>
<Group w={isMobile ? undefined : '75%'} align='start'>
{groups?.map((group: BookmarkGroup) => (
<DebouncedGroupSettingsItem
key={group.id}

View File

@@ -311,99 +311,101 @@ function DebouncedGroupSettingsItem({
'--image-background': `url(${theme.backgroundImage})`,
}}
>
<Stack w={'100%'} display={'flex'} pos={'relative'}>
<Group w={'100%'} justify='center'>
<TextInput
label={'Name'}
labelProps={{
style: {
color: theme.primaryColor,
},
}}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
onChange={(event) => {
setNewBookmark({
...newBookmark,
name: event.target.value,
});
}}
/>
<TextInput
label={'Category'}
labelProps={{
style: {
color: theme.primaryColor,
},
}}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
disabled
defaultValue={group.categoryName}
onChange={(event) => {
setNewBookmark({
...newBookmark,
category: event.target.value,
});
}}
/>
</Group>
<Group w={'100%'} justify='center' mb={60}>
<TextInput
label={'URL'}
labelProps={{
style: {
color: theme.primaryColor,
},
}}
className={textInputClasses.settingsItem}
w={'100%'}
pt={16}
classNames={textInputClasses}
onChange={(event) => {
setNewBookmark({
...newBookmark,
url: event.target.value,
});
}}
/>
</Group>
<Group
w={'100%'}
pos={'absolute'}
bottom={8}
align='center'
justify='center'
>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newBookmark) {
mutateAsync({
method: 'POST',
endpoint: 'api/links',
body: { ...newBookmark, index: bookmarks.length },
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
<Stack w={'100%'} display={'flex'} pos={'relative'}>
<Group w={'100%'} justify='center'>
<TextInput
label={'Name'}
labelProps={{
style: {
color: theme.primaryColor,
},
}}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
onChange={(event) => {
setNewBookmark({
...newBookmark,
name: event.target.value,
});
}}
/>
<TextInput
label={'Category'}
labelProps={{
style: {
color: theme.primaryColor,
},
}}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
disabled
defaultValue={group.categoryName}
onChange={(event) => {
setNewBookmark({
...newBookmark,
category: event.target.value,
});
}}
/>
</Group>
<Group w={'100%'} justify='center' mb={60}>
<TextInput
label={'URL'}
labelProps={{
style: {
color: theme.primaryColor,
},
}}
className={textInputClasses.settingsItem}
w={'100%'}
pt={16}
classNames={textInputClasses}
onChange={(event) => {
setNewBookmark({
...newBookmark,
url: event.target.value,
});
}}
/>
</Group>
<Group
w={'100%'}
pos={'absolute'}
bottom={8}
align='center'
justify='center'
>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newBookmark) {
mutateAsync({
method: 'POST',
endpoint: 'api/links',
body: { ...newBookmark, index: bookmarks.length },
});
setPopoverOpened(false);
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
setPopoverOpened(false);
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
setPopoverOpened(false);
}}
>
Cancel
</Button>
</Group>
</Stack>
}}
>
Cancel
</Button>
</Group>
</Stack>
</Card>
</Popover.Dropdown>
</Popover>
</Group>

View File

@@ -1,6 +1,7 @@
import {
ActionIcon,
Button,
Card,
Divider,
Grid,
GridCol,
@@ -20,6 +21,7 @@ import { FiHelpCircle, FiPlus } from 'react-icons/fi';
import {
actionIconClasses,
buttonClasses,
cardClasses,
modalClasses,
textClasses,
textInputClasses,
@@ -79,48 +81,51 @@ const MessageSettings = () => {
<Modal.CloseButton />
</Modal.Header>
<Modal.Body pb={'2rem'}>
<Stack gap={0} w={'100%'} align='center'>
<TextInput
autoFocus
w={'75%'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
onChange={(event) => {
setNewMessage(event.target.value);
}}
error={newMessageError}
/>
<Divider color='black' my='sm' />
<Group pos={'absolute'} bottom={8}>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newMessage) {
mutateAsync({
method: 'POST',
endpoint: endpoint,
body: { message: newMessage },
});
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
<Stack gap={0} w={'100%'} align='center'>
<TextInput
label='Message text'
autoFocus={!isMobile}
w={'75%'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
onChange={(event) => {
setNewMessage(event.target.value);
}}
error={newMessageError}
/>
<Divider color='black' my='lg' />
<Group pos={'absolute'} bottom={8}>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newMessage) {
mutateAsync({
method: 'POST',
endpoint: endpoint,
body: { message: newMessage },
});
closeModal();
} else {
setNewMessageError('Please enter a message');
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
closeModal();
} else {
setNewMessageError('Please enter a message');
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
closeModal();
}}
>
Cancel
</Button>
</Group>
</Stack>
}}
>
Cancel
</Button>
</Group>
</Stack>
</Card>
</Modal.Body>
</Modal.Content>
</Modal.Root>
@@ -183,7 +188,7 @@ const MessageSettings = () => {
pos={isMobile ? undefined : 'absolute'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
autoFocus
autoFocus={!isMobile}
placeholder='Search...'
value={searchValue}
onInput={(event: any) => {

View File

@@ -2,6 +2,7 @@ import {
ActionIcon,
Box,
Button,
Card,
Divider,
Grid,
GridCol,
@@ -20,6 +21,7 @@ import { FiHelpCircle, FiPlus } from 'react-icons/fi';
import {
actionIconClasses,
buttonClasses,
cardClasses,
modalClasses,
textClasses,
textInputClasses,
@@ -78,79 +80,81 @@ const SearchProviderSettings = () => {
<Modal.CloseButton />
</Modal.Header>
<Modal.Body pb={'2rem'}>
<Stack gap={0} w={'100%'} align='center'>
<Stack>
<Group w={'100%'} justify='center'>
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
<Stack gap={0} w={'100%'} align='center'>
<Stack>
<Group w={'100%'} justify='center'>
<TextInput
label={'Name'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newProvider.name}
onChange={(event) => {
setNewProvider({
...newProvider,
name: event.target.value,
});
}}
/>
<TextInput
label={'Prefix'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newProvider.prefix}
onChange={(event) => {
setNewProvider({
...newProvider,
prefix: event.target.value,
});
}}
/>
</Group>
<TextInput
label={'Name'}
label={'Url'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newProvider.name}
defaultValue={newProvider.url}
onChange={(event) => {
setNewProvider({
...newProvider,
name: event.target.value,
url: event.target.value,
});
}}
/>
<TextInput
label={'Prefix'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newProvider.prefix}
onChange={(event) => {
setNewProvider({
...newProvider,
prefix: event.target.value,
});
</Stack>
<Divider color='black' my='lg' />
<Group pos={'absolute'} bottom={8}>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newProvider) {
mutateAsync({
method: 'POST',
endpoint: endpoint,
body: newProvider,
});
closeModal();
}
}}
/>
</Group>
<TextInput
label={'Url'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newProvider.url}
onChange={(event) => {
setNewProvider({
...newProvider,
url: event.target.value,
});
}}
/>
</Stack>
<Divider color='black' my='sm' />
<Group pos={'absolute'} bottom={8}>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newProvider) {
mutateAsync({
method: 'POST',
endpoint: endpoint,
body: newProvider,
});
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
closeModal();
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
closeModal();
}}
>
Cancel
</Button>
</Group>
</Stack>
}}
>
Cancel
</Button>
</Group>
</Stack>
</Card>
</Modal.Body>
</Modal.Content>
</Modal.Root>
@@ -211,7 +215,7 @@ const SearchProviderSettings = () => {
pos={isMobile ? undefined : 'absolute'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
autoFocus
autoFocus={!isMobile}
placeholder='Search...'
value={searchValue}
onInput={(event: any) => {

View File

@@ -221,7 +221,7 @@ function ThemeModal({
</Group>
</Group>
) : (
<Stack h={256} justify='center'>
<Stack h={isMobile ? '100%' : 256} justify='center'>
<Group justify='space-between'>
<Text className={textClasses.label} classNames={textClasses}>
Primary Color
@@ -383,7 +383,7 @@ function ThemeModal({
</Stack>
</Group>
<Divider color='black' my='sm' />
<Group pos={'absolute'} bottom={8}>
<Group pos={'absolute'} bottom={isMobile ? -64 : 8}>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}

View File

@@ -249,10 +249,19 @@ function ThemePlaylistCard({ cardPlaylist, handleOpen, allThemes }: any) {
}}
>
{hover && <Overlay opacity={0.5} zIndex={1} />}
<Stack h={'100%'} w={'100%'}>
<Stack h={'100%'} w={'100%'} align='center'>
{cardPlaylist.name !== 'Time of Day' ? (
<>
<Text mt={8} mb={-8}>
<Text
px={8}
mt={8}
mb={-8}
style={{
color: theme.backgroundColor,
backgroundColor: theme.primaryColor,
borderRadius: '4px',
}}
>
Count: {themeList.length}
</Text>
<ScrollArea h={'255px'} w={'100%'} style={{ zIndex: 2 }}>

View File

@@ -126,7 +126,7 @@ function ThemePlaylists() {
pos={isMobile ? undefined : 'absolute'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
autoFocus
autoFocus={!isMobile}
placeholder='Search...'
value={searchValue}
onInput={(event: any) => {

View File

@@ -153,7 +153,7 @@ function ThemesSettings() {
pos={isMobile ? undefined : 'absolute'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
autoFocus
autoFocus={!isMobile}
placeholder='Search...'
value={searchValue}
onInput={(event: any) => {
@@ -180,7 +180,7 @@ function ThemesSettings() {
color={theme.primaryColor}
/>
</Group>
<Group justify='center' align='center' pos={'relative'}>
<Group justify='center' align='center' pos={'relative'} mt={'1rem'}>
<Overlay
display={currentTheme === 'random' ? 'flex' : 'none'}
blur={5}

View File

@@ -1,16 +1,14 @@
import { Card, Stack, Text } from '@mantine/core';
import { useCommonHooks } from 'hooks';
import { FaLaptop } from 'react-icons/fa';
import { cardClasses } from 'styles';
function WolClientSettingsItem({ client }: any) {
const { isMobile } = useCommonHooks();
return (
<Card
className={cardClasses.settingsItemHover}
classNames={cardClasses}
h={200}
w={isMobile ? '100%' : 200}
w={'100%'}
>
<Stack align='center' gap={0}>
<FaLaptop fontSize={100} />

View File

@@ -1,7 +1,7 @@
import {
ActionIcon,
Box,
Button,
Card,
Divider,
Grid,
GridCol,
@@ -20,6 +20,7 @@ import { FiHelpCircle, FiPlus } from 'react-icons/fi';
import {
actionIconClasses,
buttonClasses,
cardClasses,
modalClasses,
textClasses,
textInputClasses,
@@ -77,64 +78,66 @@ const WolClientSettings = () => {
<Modal.CloseButton />
</Modal.Header>
<Modal.Body pb={'2rem'}>
<Stack gap={0} w={'100%'} align='center'>
<Group w={'100%'} justify='center'>
<TextInput
label={'Hostname'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newWolClient.hostname}
onChange={(event) => {
setNewWolClient({
...newWolClient,
hostname: event.target.value,
});
}}
/>
<TextInput
label={'MAC Address'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newWolClient.macAddress}
onChange={(event) => {
setNewWolClient({
...newWolClient,
macAddress: event.target.value,
});
}}
/>
</Group>
<Divider color='black' my='sm' />
<Group pos={'absolute'} bottom={8}>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newWolClient) {
mutateAsync({
method: 'POST',
endpoint: endpoint,
body: newWolClient,
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
<Stack gap={0} w={'100%'} align='center'>
<Group w={'100%'} justify='center'>
<TextInput
label={'Hostname'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newWolClient.hostname}
onChange={(event) => {
setNewWolClient({
...newWolClient,
hostname: event.target.value,
});
}}
/>
<TextInput
label={'MAC Address'}
className={textInputClasses.settingsItem}
pt={16}
classNames={textInputClasses}
defaultValue={newWolClient.macAddress}
onChange={(event) => {
setNewWolClient({
...newWolClient,
macAddress: event.target.value,
});
}}
/>
</Group>
<Divider color='black' my='lg' />
<Group pos={'absolute'} bottom={8}>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newWolClient) {
mutateAsync({
method: 'POST',
endpoint: endpoint,
body: newWolClient,
});
closeModal();
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
closeModal();
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
closeModal();
}}
>
Cancel
</Button>
</Group>
</Stack>
}}
>
Cancel
</Button>
</Group>
</Stack>
</Card>
</Modal.Body>
</Modal.Content>
</Modal.Root>
@@ -193,7 +196,7 @@ const WolClientSettings = () => {
pos={isMobile ? undefined : 'absolute'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
autoFocus
autoFocus={!isMobile}
placeholder='Search...'
value={searchValue}
onInput={(event: any) => {
@@ -204,16 +207,17 @@ const WolClientSettings = () => {
<Stack w={'100%'} align='center'>
<Grid columns={18} w={'75%'}>
{wolClients?.map((client: WolClient) => (
<GridCol span={isMobile ? 18 : 6} key={client.id}>
<GridCol w={'100%'} span={isMobile ? 18 : 6} key={client.id}>
<Popover withArrow withOverlay withinPortal={false}>
<Popover.Target>
<Box
<Group
onClick={(e) => {
e.stopPropagation();
}}
justify='center'
>
<WolClientSettingsItem client={client} />
</Box>
</Group>
</Popover.Target>
<Popover.Dropdown>
<DebouncedWolClient wolClient={client} />