Updated header and bug fixes

This commit is contained in:
Sean Edmunds
2025-04-03 14:54:24 -05:00
parent d232a7bdb0
commit 8d2700174c
16 changed files with 390 additions and 283 deletions

View File

@@ -1,4 +1,4 @@
import { ActionIcon, Group, Stack, Tabs, Text } from '@mantine/core';
import { ActionIcon, Group, ScrollArea, Stack, Tabs, Text } from '@mantine/core';
import { useCommonHooks } from 'hooks';
import { FaPaintBrush, FaRegListAlt } from 'react-icons/fa';
import {
@@ -26,8 +26,8 @@ export function Settings() {
const navigate = useNavigate();
const { tabValue } = useParams();
return (
<Stack px={'2rem'}>
<Group gap={0}>
<Stack h={'100%'}>
<Group gap={0} pl={'2rem'}>
<ActionIcon
className={actionIconClasses.backButton}
classNames={actionIconClasses}
@@ -47,9 +47,13 @@ export function Settings() {
classNames={tabClasses}
keepMounted={false}
value={tabValue}
h={'100%'}
onChange={(value) =>
navigate(`/${import.meta.env.VITE_BASE_URL}/settings/${value}`)
}
style={{
overflow: 'hidden',
}}
>
<Tabs.List style={{ justifyContent: isMobile ? 'space-between' : undefined }}>
<Tabs.Tab px={isMobile ? '.9rem' : undefined} value='personalization'>
@@ -78,28 +82,44 @@ export function Settings() {
</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value='personalization'>
<Personalization />
<ScrollArea h={'100%'}>
<Personalization />
</ScrollArea>
</Tabs.Panel>
<Tabs.Panel value='messages'>
<Messages />
<ScrollArea h={'100%'}>
<Messages />
</ScrollArea>
</Tabs.Panel>
<Tabs.Panel value='applications'>
<Applications />
<ScrollArea h={'100%'}>
<Applications />
</ScrollArea>
</Tabs.Panel>
<Tabs.Panel value='bookmarks'>
<Bookmarks />
<ScrollArea h={'100%'}>
<Bookmarks />
</ScrollArea>
</Tabs.Panel>
<Tabs.Panel value='themes'>
<Themes />
<ScrollArea h={'100%'}>
<Themes />
</ScrollArea>
</Tabs.Panel>
<Tabs.Panel value='themePlaylists'>
<ThemePlaylists />
<ScrollArea h={'100%'}>
<ThemePlaylists />
</ScrollArea>
</Tabs.Panel>
<Tabs.Panel value='providers'>
<SearchProviders />
<ScrollArea h={'100%'}>
<SearchProviders />
</ScrollArea>
</Tabs.Panel>
<Tabs.Panel value='wolClients'>
<WolClients />
<ScrollArea h={'100%'}>
<WolClients />
</ScrollArea>
</Tabs.Panel>
</Tabs>
</Stack>

View File

@@ -10,7 +10,7 @@ function AppSettingsItem({ url, icon, name, enabled }: any) {
const [hover, setHover] = useState<boolean>(false);
const { isMobile, theme } = useCommonHooks();
return (
<>
<Box pos={'relative'}>
{enabled === 0 && (
<Tooltip label={<Text c={theme.primaryColor}>This app is disabled</Text>}>
<ActionIcon
@@ -85,7 +85,7 @@ function AppSettingsItem({ url, icon, name, enabled }: any) {
</Text>
</Stack>
</Box>
</>
</Box>
);
}

View File

@@ -240,7 +240,7 @@ const ApplicationSettings = () => {
/>
{dragging ? (
<DragDropContext onDragEnd={onDragEnd}>
<Stack w={'100%'} align='center'>
<Stack mt={'6rem'} mb={'1rem'} w={'100%'} align='center'>
<Droppable droppableId={'groupList'}>
{(provided) => (
<Stack
@@ -316,7 +316,7 @@ const ApplicationSettings = () => {
</Stack>
</DragDropContext>
) : (
<Stack w={'100%'} align='center'>
<Stack mt={'6rem'} mb={'1rem'} w={'100%'} align='center'>
<Grid columns={18} w={'75%'}>
{applicationData?.map((application: Application) => (
<GridCol span={6} key={application.id}>

View File

@@ -182,7 +182,7 @@ const BookmarkSettings = () => {
/>
{dragging ? (
<DragDropContext onDragEnd={onDragEnd}>
<Stack w={'100%'} align='center'>
<Stack mt={'6rem'} mb={'1rem'} w={'100%'} align='center'>
<Droppable droppableId={'groupList'}>
{(provided) => (
<Stack
@@ -258,7 +258,7 @@ const BookmarkSettings = () => {
</Stack>
</DragDropContext>
) : (
<Stack w={'100%'} align='center'>
<Stack mt={'6rem'} mb={'1rem'} w={'100%'} align='center'>
<Group w={isMobile ? undefined : '75%'} align='start'>
{groups?.map((group: BookmarkGroup) => (
<DebouncedGroupSettingsItem

View File

@@ -47,6 +47,19 @@ const MessageSettings = () => {
return (
<Stack w={'100%'}>
<SettingsHeader
setDragging={undefined}
openModal={openModal}
title={'Messages'}
tooltip={{
title: 'These custom messages will be displayed in the header on the homepage.',
highlightList: ['$firstName', '$lastName', '$^firstName', '$^lastName'],
description:
'Built-in variables include $firstName and $lastName. To force the text to upper case, use a carat (^), ie, $^firstName. Messages may contain any unicode text.',
}}
searchValue={searchValue}
setSearchValue={setSearchValue}
/>
<AddItemModal
modalOpened={modalOpened}
handleClose={handleClose}
@@ -94,20 +107,7 @@ const MessageSettings = () => {
</Stack>
}
/>
<SettingsHeader
setDragging={undefined}
openModal={openModal}
title={'Messages'}
tooltip={{
title: 'These custom messages will be displayed in the header on the homepage.',
highlightList: ['$firstName', '$lastName', '$^firstName', '$^lastName'],
description:
'Built-in variables include $firstName and $lastName. To force the text to upper case, use a carat (^), ie, $^firstName. Messages may contain any unicode text.',
}}
searchValue={searchValue}
setSearchValue={setSearchValue}
/>
<Stack w={'100%'} align='center'>
<Stack mt={'6rem'} mb={'1rem'} w={'100%'} align='center'>
<Grid w={'75%'}>
{messages?.map((message: Message) => (
<GridCol span={isMobile ? 12 : 6} key={message.id}>

View File

@@ -1,9 +1,10 @@
import { Card, Grid, GridCol, Overlay, Stack, Text, TextInput } from '@mantine/core';
import { Card, Grid, GridCol, Overlay, Stack, TextInput } from '@mantine/core';
import { useDebouncedValue } from '@mantine/hooks';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useEffect, useState } from 'react';
import { cardClasses, textClasses, textInputClasses } from 'styles';
import { cardClasses, textInputClasses } from 'styles';
import type { PersonalData } from 'types';
import SettingsHeader from '../Shared/SettingsHeader';
const PersonalizationSettings = () => {
const endpoint = 'api/personalData';
const {
@@ -39,11 +40,30 @@ const PersonalizationSettings = () => {
}, [update]);
return (
<>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
Personalization
</Text>
<Stack w={'100%'} align='center'>
<Stack>
<SettingsHeader
setDragging={undefined}
openModal={() => {}}
title={'Personalization'}
tooltip={{
title: 'The personalization section allows you to update basic information.',
highlightList: [
'Applications',
'apps',
'application',
'name',
'base url',
'url',
'icon',
'filter',
],
description:
'The first and last name fields will be used for greetings, and the physical address field will be used for weather.',
}}
searchValue={undefined}
setSearchValue={() => {}}
/>
<Stack mt={'6rem'} mb={'1rem'} w={'100%'} align='center'>
<Grid w={'75%'} pos={'relative'}>
{personalIsFetching && (
<Overlay
@@ -124,7 +144,7 @@ const PersonalizationSettings = () => {
</GridCol>
</Grid>
</Stack>
</>
</Stack>
);
};
export default PersonalizationSettings;

View File

@@ -148,7 +148,7 @@ const SearchProviderSettings = () => {
searchValue={searchValue}
setSearchValue={setSearchValue}
/>
<Stack w={'100%'} align='center'>
<Stack mt={'6rem'} mb={'1rem'} w={'100%'} align='center'>
<Grid columns={18} w={'75%'}>
{providerData?.map((provider: Provider) => (
<GridCol span={isMobile ? 18 : 6} key={provider.id}>

View File

@@ -23,12 +23,22 @@ function SettingsHeader({
}: any) {
const { isMobile, theme } = useCommonHooks();
return (
<Group align='center' justify='center' mt={'1rem'}>
<Group
py={'1.5rem'}
pl={'1rem'}
h={'min-content'}
w={'100%'}
align='center'
mt={0}
justify='center'
pos={'absolute'}
style={{ backdropFilter: 'blur(10px) brightness(.5)', zIndex: 1 }}
>
<Group w={isMobile ? undefined : '100%'}>
<Text className={textClasses.settingsSubTitle} classNames={textClasses}>
{title}
</Text>
<Popover withArrow withOverlay withinPortal={false}>
<Popover withArrow withOverlay withinPortal={true}>
<Popover.Target>
<ActionIcon
className={actionIconClasses.settingsTooltip}
@@ -65,26 +75,33 @@ function SettingsHeader({
</Stack>
</Popover.Dropdown>
</Popover>
<Button
className={buttonClasses.tableButton}
classNames={buttonClasses}
onClick={openModal}
>
<FiPlus />
</Button>
{searchValue !== undefined && (
<Button
className={buttonClasses.tableButton}
classNames={buttonClasses}
onClick={openModal}
>
<FiPlus />
</Button>
)}
</Group>
<TextInput
w={isMobile ? undefined : '35%'}
pos={isMobile ? undefined : 'absolute'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
autoFocus={!isMobile}
placeholder='Search...'
value={searchValue}
onInput={(event: any) => {
setSearchValue(event.target.value);
}}
/>
{searchValue !== undefined && (
<TextInput
w={isMobile ? undefined : '35%'}
pos={isMobile ? undefined : 'absolute'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
autoFocus={!isMobile}
placeholder='Search...'
value={searchValue}
onInput={(event: any) => {
setSearchValue(event.target.value);
}}
style={{
zIndex: 100,
}}
/>
)}
{setDragging && (
<Switch
label={<Text c={theme.primaryColor}>Reorder</Text>}

View File

@@ -1,16 +1,13 @@
import { ActionIcon, Box, Button, Group, Overlay, Stack, Text } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useCommonHooks, useMutationAPI } from 'hooks';
import { useState } from 'react';
import { FiEdit, FiShuffle, FiTrash, FiX } from 'react-icons/fi';
import { actionIconClasses } from 'styles';
import type { ThemePlaylist } from 'types';
import DeleteItemModal from '../Shared/DeleteItemModal';
function ThemeCard({ cardTheme, handleOpen, allThemes }: any) {
const { data: themePlaylists } = useQueryAPI({
endpoint: 'api/themePlaylists',
});
function ThemeCard({ cardTheme, handleOpen, allThemes, themePlaylists }: any) {
const [hover, setHover] = useState(false);
const [shiftEdit, setShiftEdit] = useState<number>(0);
const [shiftShuffle, setShiftShuffle] = useState<number>(0);

View File

@@ -69,7 +69,7 @@ function ThemePlaylists() {
searchValue={searchValue}
setSearchValue={setSearchValue}
/>
<Group justify='center' align='center' pos={'relative'}>
<Group mt={'6rem'} justify='center' align='center' pos={'relative'}>
<Text p={0} className={textClasses.settingsSubTitle} classNames={textClasses}>
Defaults
</Text>

View File

@@ -17,6 +17,9 @@ function ThemesSettings() {
const { data: backgroundData, isFetched: isBackgroundFetched } = useQueryAPI({
endpoint: backgroundsEndpoint,
});
const { data: themePlaylists } = useQueryAPI({
endpoint: 'api/themePlaylists',
});
const { mutateAsync } = useMutationAPI();
const [opened, { open, close }] = useDisclosure(false);
const [colorId, setColorId] = useState<string>('');
@@ -97,15 +100,18 @@ function ThemesSettings() {
labelPosition='left'
pos={'absolute'}
right={isMobile ? '2rem' : '1rem'}
top={isMobile ? '9.5rem' : '7rem'}
top={isMobile ? '9.5rem' : '2rem'}
checked={currentTheme === 'random'}
onChange={(e) => {
setCurrentTheme(e.target.checked ? 'random' : theme.name);
setCurrentThemePlaylist('All');
}}
color={theme.primaryColor}
style={{
zIndex: 1,
}}
/>
<Group justify='center' align='center' pos={'relative'} mt={'1rem'}>
<Group justify='center' align='center' pos={'relative'} mt={'10rem'}>
<Overlay
display={currentTheme === 'random' ? 'flex' : 'none'}
blur={5}
@@ -152,6 +158,7 @@ function ThemesSettings() {
allThemes={allThemes}
cardTheme={cardTheme}
handleOpen={handleOpen}
themePlaylists={themePlaylists}
/>
</Box>
</Group>

View File

@@ -131,7 +131,7 @@ const WolClientSettings = () => {
searchValue={searchValue}
setSearchValue={setSearchValue}
/>
<Stack w={'100%'} align='center'>
<Stack mt={'6rem'} mb={'1rem'} w={'100%'} align='center'>
<Grid columns={18} w={'75%'}>
{wolClients?.map((client: WolClient) => (
<GridCol w={'100%'} span={isMobile ? 18 : 6} key={client.id}>

View File

@@ -5,7 +5,7 @@
}
}
.panel {
padding-left: 2rem;
border-top: solid 2px var(--color-text-acc);
}
.tab {
color: var(--color-text-pri);
@@ -18,6 +18,12 @@
border-color: var(--color-text-pri);
}
}
.list {
border-top: solid 2px var(--color-text-acc);
padding-left: 2rem;
padding-top: 2rem;
height: 100%;
}
.list::before {
border-color: var(--color-text-acc);
}