Small refactoring
All checks were successful
Deploy to production / build (push) Successful in 1m1s

This commit is contained in:
Sean Edmunds
2026-02-10 12:59:54 -06:00
parent 28802c8698
commit dd5e3dd4f3
38 changed files with 968 additions and 974 deletions

View File

@@ -5,7 +5,7 @@ import type { SearchHistoryItem } from 'types';
const columnHelper = createColumnHelper<SearchHistoryItem>(); const columnHelper = createColumnHelper<SearchHistoryItem>();
export const SearchHistoryColumns = ( export const SearchHistoryColumns = (
setSelectedItem: React.Dispatch<React.SetStateAction<any>>, setSelectedItem: React.Dispatch<React.SetStateAction<SearchHistoryItem | undefined>>,
deleteItemOpen: () => void, deleteItemOpen: () => void,
filtersEnabled: boolean, filtersEnabled: boolean,
setFiltersEnabled: React.Dispatch<React.SetStateAction<boolean>>, setFiltersEnabled: React.Dispatch<React.SetStateAction<boolean>>,

View File

@@ -6,14 +6,14 @@ import HelpSection from './HelpSection';
export function HelpModal({ export function HelpModal({
handleResetSearch, handleResetSearch,
providerModalOpened, modalOpened,
closeProviderModal, closeProviderModal,
applicationData, applicationData,
providerData, providerData,
clientData, clientData,
}: { }: {
handleResetSearch: () => void; handleResetSearch: () => void;
providerModalOpened: boolean; modalOpened: boolean;
closeProviderModal: () => void; closeProviderModal: () => void;
applicationData: Application[]; applicationData: Application[];
providerData: Provider[]; providerData: Provider[];
@@ -25,7 +25,7 @@ export function HelpModal({
size={'60%'} size={'60%'}
className={modalClasses.helpModal} className={modalClasses.helpModal}
classNames={modalClasses} classNames={modalClasses}
opened={providerModalOpened} opened={modalOpened}
fullScreen={isMobile} fullScreen={isMobile}
centered centered
onClose={() => { onClose={() => {

View File

@@ -1,5 +1,6 @@
export { AddItemModal } from './AddItemModal'; export { AddItemModal } from './AddItemModal';
export { AppItem } from './Applications/AppItem'; export { AppItem } from './Applications/AppItem';
export { SearchHistoryColumns } from './Columns/SearchHistoryColumns';
export { DataTable } from './DataTable/DataTable'; export { DataTable } from './DataTable/DataTable';
export { DebouncedInput } from './DebouncedInput'; export { DebouncedInput } from './DebouncedInput';
export { DeleteItemModal } from './DeleteItemModal'; export { DeleteItemModal } from './DeleteItemModal';

View File

@@ -10,12 +10,14 @@ import type {
Message, Message,
PersonalData, PersonalData,
} from 'types'; } from 'types';
import Applications from './components/Applications/Applications'; import {
import Bookmarks from './components/Bookmarks/Bookmarks'; Applications,
import Header from './components/Header/Header'; Bookmarks,
import LargeHeader from './components/Header/LargeHeader'; Header,
import Search from './components/Search/Search'; LargeHeader,
import SettingsButton from './components/SettingsButton/SettingsButton'; Search,
SettingsButton,
} from './components';
export function Homepage() { export function Homepage() {
const { const {

View File

@@ -4,7 +4,7 @@ import { useCommonHooks, useQueryAPI } from 'hooks';
import { textClasses } from 'styles'; import { textClasses } from 'styles';
import type { Application } from 'types'; import type { Application } from 'types';
function Applications({ contentType }: { contentType: string[] }) { export function Applications({ contentType }: { contentType: string[] }) {
const { data: applicationData } = useQueryAPI({ const { data: applicationData } = useQueryAPI({
endpoint: 'api/enabledApplications', endpoint: 'api/enabledApplications',
}); });
@@ -76,5 +76,3 @@ function Applications({ contentType }: { contentType: string[] }) {
</> </>
); );
} }
export default Applications;

View File

@@ -4,7 +4,7 @@ import { textClasses } from 'styles';
import type { Bookmark, BookmarkGroup } from 'types'; import type { Bookmark, BookmarkGroup } from 'types';
import BookmarkGroups from './BookmarkGroups'; import BookmarkGroups from './BookmarkGroups';
function Bookmarks({ contentType }: { contentType: string[] }) { export function Bookmarks({ contentType }: { contentType: string[] }) {
const { data: bookmarkData, isFetched: bookmarksIsFetched } = useQueryAPI({ const { data: bookmarkData, isFetched: bookmarksIsFetched } = useQueryAPI({
endpoint: 'api/bookmarks', endpoint: 'api/bookmarks',
}); });
@@ -95,5 +95,3 @@ function Bookmarks({ contentType }: { contentType: string[] }) {
</> </>
); );
} }
export default Bookmarks;

View File

@@ -4,7 +4,7 @@ import { useEffect, useState } from 'react';
import { textClasses } from 'styles'; import { textClasses } from 'styles';
import type { CurrentWeather } from 'types'; import type { CurrentWeather } from 'types';
function Header({ export function Header({
greet, greet,
date, date,
current, current,
@@ -140,5 +140,3 @@ function Header({
</Stack> </Stack>
); );
} }
export default Header;

View File

@@ -3,7 +3,13 @@ import { useCommonHooks } from 'hooks';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { textClasses } from 'styles'; import { textClasses } from 'styles';
function LargeHeader({ greet, date }: { greet: string | undefined; date: string }) { export function LargeHeader({
greet,
date,
}: {
greet: string | undefined;
date: string;
}) {
const [time, setTime] = useState(new Date()); const [time, setTime] = useState(new Date());
const { const {
isMobile, isMobile,
@@ -79,5 +85,3 @@ function LargeHeader({ greet, date }: { greet: string | undefined; date: string
</Stack> </Stack>
); );
} }
export default LargeHeader;

View File

@@ -30,7 +30,7 @@ import RecommendedBookmarks from './components/RecommendedBookmarks';
import RecommendedClients from './components/RecommendedClients'; import RecommendedClients from './components/RecommendedClients';
import RenderItem from './components/RenderItem'; import RenderItem from './components/RenderItem';
export default function Search({ export function Search({
current, current,
extendedForecast, extendedForecast,
weatherModalOpened, weatherModalOpened,
@@ -634,14 +634,17 @@ export default function Search({
</Card> </Card>
)} )}
</Stack> </Stack>
{providerModalOpened && (
<HelpModal <HelpModal
handleResetSearch={handleResetSearch} handleResetSearch={handleResetSearch}
applicationData={applications} applicationData={applications}
providerData={providers} providerData={providers}
clientData={guacamoleClients} clientData={guacamoleClients}
providerModalOpened={providerModalOpened} modalOpened={providerModalOpened}
closeProviderModal={closeProviderModal} closeProviderModal={closeProviderModal}
/> />
)}
{weatherModalOpened && (
<WeatherModal <WeatherModal
current={current} current={current}
extendedForecast={extendedForecast} extendedForecast={extendedForecast}
@@ -649,6 +652,7 @@ export default function Search({
handleResetSearch={handleResetSearch} handleResetSearch={handleResetSearch}
closeWeatherModal={closeWeatherModal} closeWeatherModal={closeWeatherModal}
/> />
)}
</> </>
); );
} }

View File

@@ -9,7 +9,7 @@ import SettingsCard from './SettingsCard';
import ThemingCard from './ThemingCard'; import ThemingCard from './ThemingCard';
import WakeOnLan from './WakeOnLanCard'; import WakeOnLan from './WakeOnLanCard';
function SettingsButton({ openProviderModal }: { openProviderModal: () => void }) { export function SettingsButton({ openProviderModal }: { openProviderModal: () => void }) {
const { data: appCategoryData } = useQueryAPI({ const { data: appCategoryData } = useQueryAPI({
endpoint: 'api/appCategories', endpoint: 'api/appCategories',
}); });
@@ -171,5 +171,3 @@ function SettingsButton({ openProviderModal }: { openProviderModal: () => void }
</Menu> </Menu>
); );
} }
export default SettingsButton;

View File

@@ -0,0 +1,6 @@
export { Applications } from './Applications/Applications';
export { Bookmarks } from './Bookmarks/Bookmarks';
export { Header } from './Header/Header';
export { LargeHeader } from './Header/LargeHeader';
export { Search } from './Search/Search';
export { SettingsButton } from './SettingsButton/SettingsButton';

View File

@@ -13,16 +13,18 @@ import {
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { actionIconClasses, scrollAreaClasses, tabClasses, textClasses } from 'styles'; import { actionIconClasses, scrollAreaClasses, tabClasses, textClasses } from 'styles';
import type { PersonalData } from 'types'; import type { PersonalData } from 'types';
import Applications from './components/Applications/Applications'; import {
import Bookmarks from './components/Bookmarks/Bookmarks'; Applications,
import GuacamoleClients from './components/GuacamoleClients/GuacamoleClients'; Bookmarks,
import Messages from './components/Messages/Messages'; GuacamoleClients,
import Personalization from './components/Personalization/Personalization'; Messages,
import SearchHistory from './components/Search/SearchHistory'; Personalization,
import SearchProviders from './components/Search/SearchProviders'; SearchHistory,
import { ThemePlaylists } from './components/Theming/ThemePlaylists'; SearchProviders,
import { Themes } from './components/Theming/Themes'; ThemePlaylists,
import WolClients from './components/WoL/WolClients'; Themes,
WolClients,
} from './components';
export function Settings() { export function Settings() {
const endpoint = 'api/personalData'; const endpoint = 'api/personalData';

View File

@@ -26,7 +26,7 @@ import { buttonClasses, popoverClasses, selectClasses, textInputClasses } from '
import type { Application } from 'types'; import type { Application } from 'types';
import DebouncedApplication from './DebouncedApplication'; import DebouncedApplication from './DebouncedApplication';
const ApplicationSettings = () => { export function Applications() {
const allIcons: any = { ...fa6, ...vsc, ...si }; const allIcons: any = { ...fa6, ...vsc, ...si };
const defaultApplication: Application = { const defaultApplication: Application = {
id: null, id: null,
@@ -141,6 +141,7 @@ const ApplicationSettings = () => {
isLoading={isLoading} isLoading={isLoading}
setIsLoading={setIsLoading} setIsLoading={setIsLoading}
/> />
{modalOpened && (
<AddItemModal <AddItemModal
modalOpened={modalOpened} modalOpened={modalOpened}
handleClose={handleClose} handleClose={handleClose}
@@ -300,6 +301,7 @@ const ApplicationSettings = () => {
</form> </form>
} }
/> />
)}
<DragDropContext onDragEnd={onDragEnd}> <DragDropContext onDragEnd={onDragEnd}>
<Stack <Stack
mt={isMobile ? '10rem' : '6rem'} mt={isMobile ? '10rem' : '6rem'}
@@ -410,5 +412,4 @@ const ApplicationSettings = () => {
</DragDropContext> </DragDropContext>
</Stack> </Stack>
); );
}; }
export default ApplicationSettings;

View File

@@ -30,7 +30,7 @@ function DebouncedApplication({
const { mutateAsync } = useMutationAPI(); const { mutateAsync } = useMutationAPI();
const [app, setApp] = useState<Application>(application); const [app, setApp] = useState<Application>(application);
const [update, setUpdate] = useState<any>(); const [update, setUpdate] = useState<Application>();
const [debounced] = useDebouncedValue(update, 1000); const [debounced] = useDebouncedValue(update, 1000);
const handleClose = () => { const handleClose = () => {
setIsOpen(false); setIsOpen(false);
@@ -53,6 +53,7 @@ function DebouncedApplication({
className={cardClasses.settingsItem} className={cardClasses.settingsItem}
classNames={cardClasses} classNames={cardClasses}
> >
{modalOpened && (
<DeleteItemModal <DeleteItemModal
modalOpened={modalOpened} modalOpened={modalOpened}
handleClose={handleClose} handleClose={handleClose}
@@ -69,6 +70,7 @@ function DebouncedApplication({
</Stack> </Stack>
} }
/> />
)}
<Box <Box
style={{ style={{
position: 'absolute', position: 'absolute',
@@ -192,7 +194,7 @@ function DebouncedApplication({
onChange={(value: string | null) => { onChange={(value: string | null) => {
setUpdate({ setUpdate({
...app, ...app,
icon: value, icon: value as Application['icon'],
}); });
}} }}
renderOption={(item: ComboboxLikeRenderOptionInput<ComboboxItem>) => { renderOption={(item: ComboboxLikeRenderOptionInput<ComboboxItem>) => {

View File

@@ -18,7 +18,7 @@ import { buttonClasses, textInputClasses } from 'styles';
import type { Bookmark, BookmarkGroup } from 'types'; import type { Bookmark, BookmarkGroup } from 'types';
import DebouncedGroupSettingsItem from './DebouncedGroupSettingsItem'; import DebouncedGroupSettingsItem from './DebouncedGroupSettingsItem';
const BookmarkSettings = () => { export function Bookmarks() {
const defaultGroup = { const defaultGroup = {
id: null, id: null,
categoryName: '', categoryName: '',
@@ -68,7 +68,7 @@ const BookmarkSettings = () => {
), ),
), ),
]; ];
const foundGroups: BookmarkGroup[] = groupData.filter((a: BookmarkGroup) => const foundGroups: BookmarkGroup[] = groupData?.filter((a: BookmarkGroup) =>
a.categoryName.toLowerCase().includes((debouncedGroupSearch as string).toLowerCase()), a.categoryName.toLowerCase().includes((debouncedGroupSearch as string).toLowerCase()),
); );
const handleClose = () => { const handleClose = () => {
@@ -121,6 +121,7 @@ const BookmarkSettings = () => {
return ( return (
<Stack> <Stack>
{modalOpened && (
<AddItemModal <AddItemModal
modalOpened={modalOpened} modalOpened={modalOpened}
handleClose={handleClose} handleClose={handleClose}
@@ -194,6 +195,7 @@ const BookmarkSettings = () => {
</form> </form>
} }
/> />
)}
<SettingsHeader <SettingsHeader
setDragging={groups.length > 0 ? setDragging : undefined} setDragging={groups.length > 0 ? setDragging : undefined}
openModal={openModal} openModal={openModal}
@@ -337,5 +339,4 @@ const BookmarkSettings = () => {
)} )}
</Stack> </Stack>
); );
}; }
export default BookmarkSettings;

View File

@@ -25,20 +25,20 @@ function DebouncedBookmarkItem({
(a: BookmarkGroup, b: BookmarkGroup) => (a: BookmarkGroup, b: BookmarkGroup) =>
a.categoryName.toLocaleLowerCase() > b.categoryName.toLocaleLowerCase(), a.categoryName.toLocaleLowerCase() > b.categoryName.toLocaleLowerCase(),
) || []; ) || [];
const [update, setUpdate] = useState<any>({}); const [update, setUpdate] = useState<Bookmark>();
const [debounced] = useDebouncedValue(update, 1000); const [debounced] = useDebouncedValue(update, 1000);
const handleClose = () => { const handleClose = () => {
setIsOpen(false); setIsOpen(false);
closeModal(); closeModal();
}; };
useEffect(() => { useEffect(() => {
if (Object.keys(debounced).length) { if (debounced && Object.keys(debounced).length) {
mutateAsync({ method: 'PATCH', endpoint: 'api/bookmarks', body: debounced }); mutateAsync({ method: 'PATCH', endpoint: 'api/bookmarks', body: debounced });
} }
}, [debounced]); }, [debounced]);
useEffect(() => { useEffect(() => {
if (update !== bookmark && Object.keys(update).length) { if (update && update !== bookmark && Object.keys(update).length) {
setBookmark(update); setBookmark(update);
} }
}, [update]); }, [update]);
@@ -49,6 +49,7 @@ function DebouncedBookmarkItem({
className={cardClasses.settingsItem} className={cardClasses.settingsItem}
classNames={cardClasses} classNames={cardClasses}
> >
{modalOpened && (
<DeleteItemModal <DeleteItemModal
modalOpened={modalOpened} modalOpened={modalOpened}
handleClose={handleClose} handleClose={handleClose}
@@ -65,6 +66,7 @@ function DebouncedBookmarkItem({
} }
title='Delete Bookmark' title='Delete Bookmark'
/> />
)}
<Box <Box
style={{ style={{
position: 'absolute', position: 'absolute',
@@ -142,7 +144,7 @@ function DebouncedBookmarkItem({
onChange={(value: string | null) => { onChange={(value: string | null) => {
setUpdate({ setUpdate({
...bookmark, ...bookmark,
category: value, category: value as BookmarkGroup['categoryName'],
}); });
}} }}
searchable searchable

View File

@@ -48,7 +48,7 @@ function DebouncedGroupSettingsItem({
const [popoverOpened, setPopoverOpened] = useState(false); const [popoverOpened, setPopoverOpened] = useState(false);
const { mutateAsync } = useMutationAPI(); const { mutateAsync } = useMutationAPI();
const [group, setGroup] = useState<BookmarkGroup>(bookmarkGroup); const [group, setGroup] = useState<BookmarkGroup>(bookmarkGroup);
const [update, setUpdate] = useState<any>({}); const [update, setUpdate] = useState<BookmarkGroup>();
const [debounced] = useDebouncedValue(update, 1000); const [debounced] = useDebouncedValue(update, 1000);
const [newBookmark, setNewBookmark] = useState<Bookmark>({ const [newBookmark, setNewBookmark] = useState<Bookmark>({
id: undefined, id: undefined,
@@ -89,18 +89,18 @@ function DebouncedGroupSettingsItem({
} }
useEffect(() => { useEffect(() => {
if (Object.keys(debounced).length) { if (debounced && Object.keys(debounced).length) {
mutateAsync({ mutateAsync({
method: 'PATCH', method: 'PATCH',
endpoint: 'api/bookmarkCategories', endpoint: 'api/bookmarkCategories',
body: debounced, body: debounced,
}); });
setUpdate({}); setUpdate(undefined);
} }
}, [debounced]); }, [debounced]);
useEffect(() => { useEffect(() => {
if (update !== group && Object.keys(update).length) { if (update && update !== group && Object.keys(update).length) {
setGroup(update); setGroup(update);
} }
}, [update]); }, [update]);
@@ -113,6 +113,7 @@ function DebouncedGroupSettingsItem({
return ( return (
<Card w={'400px'} className={cardClasses.settingsItem} classNames={cardClasses}> <Card w={'400px'} className={cardClasses.settingsItem} classNames={cardClasses}>
{modalOpened && (
<DeleteItemModal <DeleteItemModal
modalOpened={modalOpened} modalOpened={modalOpened}
handleClose={closeModal} handleClose={closeModal}
@@ -135,6 +136,7 @@ function DebouncedGroupSettingsItem({
</Stack> </Stack>
} }
/> />
)}
<Card.Section <Card.Section
p={'1rem'} p={'1rem'}
pt={0} pt={0}

View File

@@ -38,7 +38,7 @@ function DebouncedGuacamoleClient({
const { mutateAsync } = useMutationAPI(); const { mutateAsync } = useMutationAPI();
const types: string[] = ['SSH', 'RDP', 'VNC']; const types: string[] = ['SSH', 'RDP', 'VNC'];
const [client, setClient] = useState<GuacamoleClient>(guacamoleClient); const [client, setClient] = useState<GuacamoleClient>(guacamoleClient);
const [update, setUpdate] = useState<any>({}); const [update, setUpdate] = useState<GuacamoleClient>();
const [debounced] = useDebouncedValue(update, 1000); const [debounced] = useDebouncedValue(update, 1000);
const handleClose = () => { const handleClose = () => {
setIsOpen(false); setIsOpen(false);
@@ -46,13 +46,13 @@ function DebouncedGuacamoleClient({
}; };
useEffect(() => { useEffect(() => {
if (Object.keys(debounced).length) { if (debounced && Object.keys(debounced).length) {
mutateAsync({ method: 'PATCH', endpoint: 'api/guacamoleClients', body: debounced }); mutateAsync({ method: 'PATCH', endpoint: 'api/guacamoleClients', body: debounced });
} }
}, [debounced]); }, [debounced]);
useEffect(() => { useEffect(() => {
if (update !== client && Object.keys(update).length) { if (update && update !== client && Object.keys(update).length) {
setClient(update); setClient(update);
} }
}, [update]); }, [update]);
@@ -62,6 +62,7 @@ function DebouncedGuacamoleClient({
className={cardClasses.settingsItem} className={cardClasses.settingsItem}
classNames={cardClasses} classNames={cardClasses}
> >
{modalOpened && (
<DeleteItemModal <DeleteItemModal
modalOpened={modalOpened} modalOpened={modalOpened}
handleClose={handleClose} handleClose={handleClose}
@@ -78,6 +79,7 @@ function DebouncedGuacamoleClient({
</Stack> </Stack>
} }
/> />
)}
<Tooltip <Tooltip
className={toolTipClasses.default} className={toolTipClasses.default}
classNames={toolTipClasses} classNames={toolTipClasses}
@@ -177,7 +179,7 @@ function DebouncedGuacamoleClient({
onChange={(value: string | null) => { onChange={(value: string | null) => {
setUpdate({ setUpdate({
...guacamoleClient, ...guacamoleClient,
type: value, type: value as GuacamoleClient['type'],
}); });
}} }}
searchable searchable

View File

@@ -1,6 +1,5 @@
import { Card, Stack, Text } from '@mantine/core'; import { Card, Stack, Text } from '@mantine/core';
import { FaDesktop, FaTerminal } from 'react-icons/fa'; import { FaComputer, FaDesktop, FaTerminal } from 'react-icons/fa6';
import { FaComputer } from 'react-icons/fa6';
import { cardClasses } from 'styles'; import { cardClasses } from 'styles';
import type { GuacamoleClient } from 'types'; import type { GuacamoleClient } from 'types';

View File

@@ -16,14 +16,13 @@ import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { AddItemModal, NoItemsFound, SettingsHeader } from 'components'; import { AddItemModal, NoItemsFound, SettingsHeader } from 'components';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks'; import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { FaTerminal } from 'react-icons/fa'; import { FaComputer, FaDesktop, FaTerminal } from 'react-icons/fa6';
import { FaComputer, FaDesktop } from 'react-icons/fa6';
import { buttonClasses, popoverClasses, selectClasses, textInputClasses } from 'styles'; import { buttonClasses, popoverClasses, selectClasses, textInputClasses } from 'styles';
import type { GuacamoleClient } from 'types'; import type { GuacamoleClient } from 'types';
import DebouncedGuacamoleClient from './DebouncedGuacamoleClient'; import DebouncedGuacamoleClient from './DebouncedGuacamoleClient';
import GuacamoleClientSettingsItem from './GuacamoleClientSettingsItem'; import GuacamoleClientSettingsItem from './GuacamoleClientSettingsItem';
const GuacamoleClients = () => { export function GuacamoleClients() {
const defaultGuacamoleClient: GuacamoleClient = { const defaultGuacamoleClient: GuacamoleClient = {
id: undefined, id: undefined,
clientName: '', clientName: '',
@@ -73,6 +72,7 @@ const GuacamoleClients = () => {
return ( return (
<Stack> <Stack>
{modalOpened && (
<AddItemModal <AddItemModal
modalOpened={modalOpened} modalOpened={modalOpened}
handleClose={handleClose} handleClose={handleClose}
@@ -194,6 +194,7 @@ const GuacamoleClients = () => {
</form> </form>
} }
/> />
)}
<SettingsHeader <SettingsHeader
setDragging={undefined} setDragging={undefined}
openModal={openModal} openModal={openModal}
@@ -267,5 +268,4 @@ const GuacamoleClients = () => {
</Stack> </Stack>
</Stack> </Stack>
); );
}; }
export default GuacamoleClients;

View File

@@ -23,6 +23,7 @@ function DebouncedMessage({
w={'100%'} w={'100%'}
style={{ alignItems: 'center' }} style={{ alignItems: 'center' }}
> >
{modalOpened && (
<DeleteItemModal <DeleteItemModal
modalOpened={modalOpened} modalOpened={modalOpened}
handleClose={closeModal} handleClose={closeModal}
@@ -39,6 +40,7 @@ function DebouncedMessage({
</Stack> </Stack>
} }
/> />
)}
<Box <Box
style={{ style={{
position: 'absolute', position: 'absolute',

View File

@@ -16,7 +16,7 @@ import { buttonClasses, textInputClasses } from 'styles';
import type { Message } from 'types'; import type { Message } from 'types';
import DebouncedMessage from './DebouncedMessage'; import DebouncedMessage from './DebouncedMessage';
const MessageSettings = () => { export function Messages() {
const endpoint = 'api/messages'; const endpoint = 'api/messages';
const { data: messageData, isFetching: messageDataIsFetching } = useQueryAPI({ const { data: messageData, isFetching: messageDataIsFetching } = useQueryAPI({
endpoint: endpoint, endpoint: endpoint,
@@ -83,6 +83,7 @@ const MessageSettings = () => {
isLoading={isLoading} isLoading={isLoading}
setIsLoading={setIsLoading} setIsLoading={setIsLoading}
/> />
{modalOpened && (
<AddItemModal <AddItemModal
modalOpened={modalOpened} modalOpened={modalOpened}
handleClose={handleClose} handleClose={handleClose}
@@ -137,6 +138,7 @@ const MessageSettings = () => {
</form> </form>
} }
/> />
)}
<Stack <Stack
mt={isMobile ? '10rem' : '6rem'} mt={isMobile ? '10rem' : '6rem'}
mb={isMobile ? '6rem' : undefined} mb={isMobile ? '6rem' : undefined}
@@ -173,5 +175,4 @@ const MessageSettings = () => {
</Stack> </Stack>
</Stack> </Stack>
); );
}; }
export default MessageSettings;

View File

@@ -16,7 +16,7 @@ import FontPicker from 'react-fontpicker-ts';
import { cardClasses, switchClasses, textClasses, textInputClasses } from 'styles'; import { cardClasses, switchClasses, textClasses, textInputClasses } from 'styles';
import type { PersonalData } from 'types'; import type { PersonalData } from 'types';
const PersonalizationSettings = () => { export function Personalization() {
const endpoint = 'api/personalData'; const endpoint = 'api/personalData';
const { data: personalData, isFetching: personalDataIsFetching } = useQueryAPI({ const { data: personalData, isFetching: personalDataIsFetching } = useQueryAPI({
endpoint: endpoint, endpoint: endpoint,
@@ -27,14 +27,14 @@ const PersonalizationSettings = () => {
personal?.enableGuacamole === 1, personal?.enableGuacamole === 1,
); );
const [defaultFont, setDefaultFont] = useState<string>(personal?.defaultFont); const [defaultFont, setDefaultFont] = useState<string>(personal?.defaultFont);
const [update, setUpdate] = useState<any>({}); const [update, setUpdate] = useState<PersonalData>();
const [debounced] = useDebouncedValue(update, 1000); const [debounced] = useDebouncedValue(update, 1000);
const { mutateAsync } = useMutationAPI(); const { mutateAsync } = useMutationAPI();
const { isMobile, theme } = useCommonHooks(); const { isMobile, theme } = useCommonHooks();
useEffect(() => { useEffect(() => {
if (Object.keys(debounced).length) { if (debounced && Object.keys(debounced).length) {
mutateAsync({ method: 'PATCH', endpoint: endpoint, body: debounced }); mutateAsync({ method: 'PATCH', endpoint: endpoint, body: debounced });
setUpdate({}); setUpdate(undefined);
} }
}, [debounced]); }, [debounced]);
@@ -322,5 +322,4 @@ const PersonalizationSettings = () => {
</Stack> </Stack>
</Stack> </Stack>
); );
}; }
export default PersonalizationSettings;

View File

@@ -30,7 +30,7 @@ function DebouncedSearchProvider({
const { mutateAsync } = useMutationAPI(); const { mutateAsync } = useMutationAPI();
const [provider, setProvider] = useState<Provider>(searchProvider); const [provider, setProvider] = useState<Provider>(searchProvider);
const [update, setUpdate] = useState<any>({}); const [update, setUpdate] = useState<Provider>();
const [debounced] = useDebouncedValue(update, 1000); const [debounced] = useDebouncedValue(update, 1000);
const handleClose = () => { const handleClose = () => {
@@ -39,13 +39,13 @@ function DebouncedSearchProvider({
}; };
useEffect(() => { useEffect(() => {
if (Object.keys(debounced).length) { if (debounced && Object.keys(debounced).length) {
mutateAsync({ method: 'PATCH', endpoint: 'api/providers', body: debounced }); mutateAsync({ method: 'PATCH', endpoint: 'api/providers', body: debounced });
} }
}, [debounced]); }, [debounced]);
useEffect(() => { useEffect(() => {
if (update !== provider && Object.keys(update).length) { if (update && update !== provider && Object.keys(update).length) {
setProvider(update); setProvider(update);
} }
}, [update]); }, [update]);
@@ -56,6 +56,7 @@ function DebouncedSearchProvider({
className={cardClasses.settingsItem} className={cardClasses.settingsItem}
classNames={cardClasses} classNames={cardClasses}
> >
{modalOpened && (
<DeleteItemModal <DeleteItemModal
modalOpened={modalOpened} modalOpened={modalOpened}
handleClose={handleClose} handleClose={handleClose}
@@ -72,6 +73,7 @@ function DebouncedSearchProvider({
</Stack> </Stack>
} }
/> />
)}
<Box <Box
style={{ style={{
position: 'absolute', position: 'absolute',

View File

@@ -1,13 +1,17 @@
import { Group, Stack, Text } from '@mantine/core'; import { Group, Stack, Text } from '@mantine/core';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks'; import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { DataTable, DeleteItemModal, SettingsHeader } from 'components'; import {
import { SearchHistoryColumns } from 'components/Columns/SearchHistoryColumns'; DataTable,
DeleteItemModal,
SearchHistoryColumns,
SettingsHeader,
} from 'components';
import { useCommonHooks, useQueryAPI } from 'hooks'; import { useCommonHooks, useQueryAPI } from 'hooks';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { textClasses } from 'styles'; import { textClasses } from 'styles';
import type { SearchHistoryItem } from 'types'; import type { SearchHistoryItem } from 'types';
const SearchHistory = () => { export function SearchHistory() {
const searchEndpoint = 'api/searchHistory'; const searchEndpoint = 'api/searchHistory';
const { data: historyData, isFetching: historyDataIsFetching } = useQueryAPI({ const { data: historyData, isFetching: historyDataIsFetching } = useQueryAPI({
endpoint: searchEndpoint, endpoint: searchEndpoint,
@@ -41,6 +45,7 @@ const SearchHistory = () => {
return ( return (
<Stack w={'100%'}> <Stack w={'100%'}>
{modalOpened && (
<DeleteItemModal <DeleteItemModal
modalOpened={modalOpened} modalOpened={modalOpened}
handleClose={handleClose} handleClose={handleClose}
@@ -63,6 +68,7 @@ const SearchHistory = () => {
</Stack> </Stack>
} }
/> />
)}
<SettingsHeader <SettingsHeader
setDragging={undefined} setDragging={undefined}
openModal={undefined} openModal={undefined}
@@ -107,6 +113,4 @@ const SearchHistory = () => {
</Stack> </Stack>
</Stack> </Stack>
); );
}; }
export default SearchHistory;

View File

@@ -35,7 +35,7 @@ import type { Provider } from 'types';
import DebouncedSearchProvider from './DebouncedSearchProvider'; import DebouncedSearchProvider from './DebouncedSearchProvider';
import SearchProviderSettingsItem from './SearchProviderSettingsItem'; import SearchProviderSettingsItem from './SearchProviderSettingsItem';
const SearchProviderSettings = () => { export function SearchProviders() {
const allIcons: any = { ...fa6, ...vsc, ...si }; const allIcons: any = { ...fa6, ...vsc, ...si };
const defaultProvider: Provider = { const defaultProvider: Provider = {
id: undefined, id: undefined,
@@ -88,6 +88,7 @@ const SearchProviderSettings = () => {
return ( return (
<Stack> <Stack>
{modalOpened && (
<AddItemModal <AddItemModal
modalOpened={modalOpened} modalOpened={modalOpened}
handleClose={handleClose} handleClose={handleClose}
@@ -117,7 +118,9 @@ const SearchProviderSettings = () => {
styles={ styles={
theme.textShadowsEnabled theme.textShadowsEnabled
? { ? {
label: { boxShadow: '2px 2px var(--mantine-color-border-0)' }, label: {
boxShadow: '2px 2px var(--mantine-color-border-0)',
},
} }
: undefined : undefined
} }
@@ -134,7 +137,9 @@ const SearchProviderSettings = () => {
styles={ styles={
theme.textShadowsEnabled theme.textShadowsEnabled
? { ? {
label: { boxShadow: '2px 2px var(--mantine-color-border-0)' }, label: {
boxShadow: '2px 2px var(--mantine-color-border-0)',
},
} }
: undefined : undefined
} }
@@ -166,11 +171,15 @@ const SearchProviderSettings = () => {
styles={ styles={
theme.textShadowsEnabled theme.textShadowsEnabled
? { ? {
label: { boxShadow: '2px 2px var(--mantine-color-border-0)' }, label: {
boxShadow: '2px 2px var(--mantine-color-border-0)',
},
} }
: undefined : undefined
} }
renderOption={(item: ComboboxLikeRenderOptionInput<ComboboxItem>) => { renderOption={(
item: ComboboxLikeRenderOptionInput<ComboboxItem>,
) => {
const Icon = allIcons[item.option.value]; const Icon = allIcons[item.option.value];
return ( return (
<Group> <Group>
@@ -256,6 +265,7 @@ const SearchProviderSettings = () => {
</form> </form>
} }
/> />
)}
<SettingsHeader <SettingsHeader
setDragging={undefined} setDragging={undefined}
openModal={openModal} openModal={openModal}
@@ -333,5 +343,4 @@ const SearchProviderSettings = () => {
</Stack> </Stack>
</Stack> </Stack>
); );
}; }
export default SearchProviderSettings;

View File

@@ -67,6 +67,7 @@ export function ThemePlaylists() {
return ( return (
<Stack> <Stack>
{opened && (
<ThemePlaylistModal <ThemePlaylistModal
opened={opened} opened={opened}
handleClose={handleClose} handleClose={handleClose}
@@ -77,6 +78,7 @@ export function ThemePlaylists() {
allThemes={allThemeData} allThemes={allThemeData}
createPlaylist={mutateAsync} createPlaylist={mutateAsync}
/> />
)}
<SettingsHeader <SettingsHeader
setDragging={undefined} setDragging={undefined}
openModal={open} openModal={open}

View File

@@ -42,6 +42,7 @@ export function ThemePlaylistCard({
onMouseEnter={() => setHover(true)} onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)} onMouseLeave={() => setHover(false)}
> >
{modalOpened && (
<DeleteItemModal <DeleteItemModal
modalOpened={modalOpened} modalOpened={modalOpened}
handleClose={closeModal} handleClose={closeModal}
@@ -58,6 +59,7 @@ export function ThemePlaylistCard({
</Stack> </Stack>
} }
/> />
)}
<Text <Text
style={{ style={{
position: 'absolute', position: 'absolute',

View File

@@ -28,7 +28,6 @@ export function ThemePlaylistModal({
}) { }) {
const { isMobile } = useCommonHooks(); const { isMobile } = useCommonHooks();
const [themeList, setThemeList] = useState<any>([]); const [themeList, setThemeList] = useState<any>([]);
useEffect(() => { useEffect(() => {
if (selectedPlaylist?.themeList) { if (selectedPlaylist?.themeList) {
setThemeList(JSON.parse(selectedPlaylist?.themeList)); setThemeList(JSON.parse(selectedPlaylist?.themeList));
@@ -49,7 +48,7 @@ export function ThemePlaylistModal({
centered centered
onClose={() => { onClose={() => {
handleClose(); handleClose();
setThemeList('[]'); setThemeList([]);
}} }}
keepMounted={false} keepMounted={false}
> >

View File

@@ -1,8 +1,7 @@
import { ActionIcon, Group, isLightColor, Stack, Text } from '@mantine/core'; import { ActionIcon, Group, isLightColor, Stack, Text } from '@mantine/core';
import { useCommonHooks, useMutationAPI } from 'hooks'; import { useCommonHooks, useMutationAPI } from 'hooks';
import { useState } from 'react'; import { useState } from 'react';
import { FaTrashAlt } from 'react-icons/fa'; import { FaPencil, FaTrash } from 'react-icons/fa6';
import { FaPencil } from 'react-icons/fa6';
import { FiEdit, FiPower, FiShuffle } from 'react-icons/fi'; import { FiEdit, FiPower, FiShuffle } from 'react-icons/fi';
import { actionIconClasses } from 'styles'; import { actionIconClasses } from 'styles';
import type { Theme, ThemePlaylist } from 'types'; import type { Theme, ThemePlaylist } from 'types';
@@ -238,7 +237,7 @@ export function ThemeManagementPill({
onClick={openModal} onClick={openModal}
disabled={cardTheme.name === theme.name} disabled={cardTheme.name === theme.name}
> >
<FaTrashAlt <FaTrash
style={{ padding: '.25rem', filter: 'brightness(1.25)' }} style={{ padding: '.25rem', filter: 'brightness(1.25)' }}
color='Brown' color='Brown'
/> />

View File

@@ -27,7 +27,7 @@ export function NewThemeStarter({
setSelectedTheme: (selectedTheme: Theme) => void; setSelectedTheme: (selectedTheme: Theme) => void;
setDefaultTheme: (selectedTheme: Theme) => void; setDefaultTheme: (selectedTheme: Theme) => void;
}) { }) {
const [pressed, setPressed] = useState<any>(false); const [pressed, setPressed] = useState<boolean>(false);
const handlers = useLongPress(() => { const handlers = useLongPress(() => {
setPressed(true); setPressed(true);
}); });

View File

@@ -10,8 +10,7 @@ import {
} from '@mantine/core'; } from '@mantine/core';
import { notifications } from '@mantine/notifications'; import { notifications } from '@mantine/notifications';
import { useCommonHooks } from 'hooks'; import { useCommonHooks } from 'hooks';
import { FaClipboard } from 'react-icons/fa'; import { FaClipboard, FaX } from 'react-icons/fa6';
import { FiX } from 'react-icons/fi';
import { scrollAreaClasses, toolTipClasses } from 'styles'; import { scrollAreaClasses, toolTipClasses } from 'styles';
import { type Theme, ThemeProperties } from 'types'; import { type Theme, ThemeProperties } from 'types';
@@ -104,7 +103,7 @@ export default function ThemeChanges({
pos={'absolute'} pos={'absolute'}
right={0} right={0}
> >
<FiX /> <FaX />
</ActionIcon> </ActionIcon>
</Tooltip> </Tooltip>
</Group> </Group>

View File

@@ -1,55 +0,0 @@
import { Box, Stack, Text } from '@mantine/core';
import { useState } from 'react';
import { FiCheck } from 'react-icons/fi';
import { boxClasses, textClasses } from 'styles';
import type { Theme } from 'types';
export function ThemeExampleApp({ selectedTheme }: { selectedTheme: Theme }) {
const [textDecoration, setTextDecoration] = useState<string>('none');
return (
<Box
component='a'
onMouseOver={() => setTextDecoration('underline')}
onMouseOut={() => setTextDecoration('none')}
className={boxClasses.appItemBox}
h={'64px'}
>
<Stack
style={{
marginRight: '1rem',
marginLeft: '1rem',
}}
justify='center'
>
<FiCheck style={{ color: selectedTheme?.primaryColor }} />
</Stack>
<Stack
style={{
justifyContent: 'center',
overflow: 'hidden',
textOverflow: 'ellipsis',
gap: 0,
}}
>
<Text
c={selectedTheme?.primaryColor}
className={textClasses.appName}
classNames={textClasses}
>
{'Example App'}
</Text>
<Text
c={selectedTheme?.accentColor}
className={textClasses.appUrl}
classNames={textClasses}
style={{
textDecoration: textDecoration,
}}
>
{'https://www.example.com'}
</Text>
</Stack>
</Box>
);
}

View File

@@ -11,9 +11,7 @@ import {
} from '@mantine/core'; } from '@mantine/core';
import { useCommonHooks } from 'hooks'; import { useCommonHooks } from 'hooks';
import FontPicker from 'react-fontpicker-ts'; import FontPicker from 'react-fontpicker-ts';
import { FaFont, FaGoogle } from 'react-icons/fa'; import { FaFont, FaGoogle, FaShuffle, FaX } from 'react-icons/fa6';
import { FaShuffle } from 'react-icons/fa6';
import { FiX } from 'react-icons/fi';
import { textClasses, toolTipClasses } from 'styles'; import { textClasses, toolTipClasses } from 'styles';
import type { Theme } from 'types'; import type { Theme } from 'types';
import ThemeChanges from './ThemeChanges'; import ThemeChanges from './ThemeChanges';
@@ -192,7 +190,7 @@ export default function ThemeOptions({
borderRadius: '0px', borderRadius: '0px',
}} }}
> >
<FiX /> <FaX />
</ActionIcon> </ActionIcon>
</Tooltip> </Tooltip>
</Group> </Group>

View File

@@ -17,7 +17,7 @@ export function ThemePreviewMiddleware({
selectedPlaylist: any; selectedPlaylist: any;
setSelectedPlaylist: (selectedPlaylist: any) => void; setSelectedPlaylist: (selectedPlaylist: any) => void;
}) { }) {
const [pressed, setPressed] = useState<any>(false); const [pressed, setPressed] = useState<boolean>(false);
const handlers = useLongPress(() => { const handlers = useLongPress(() => {
setPressed(true); setPressed(true);
}); });

View File

@@ -3,7 +3,7 @@ import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { DeleteItemModal } from 'components'; import { DeleteItemModal } from 'components';
import { useCommonHooks, useMutationAPI } from 'hooks'; import { useCommonHooks, useMutationAPI } from 'hooks';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { FiTrash } from 'react-icons/fi'; import { FaTrash } from 'react-icons/fa';
import { cardClasses, textClasses, textInputClasses, toolTipClasses } from 'styles'; import { cardClasses, textClasses, textInputClasses, toolTipClasses } from 'styles';
import type { WolClient } from 'types'; import type { WolClient } from 'types';
@@ -19,7 +19,7 @@ function DebouncedWolClient({
const { mutateAsync } = useMutationAPI(); const { mutateAsync } = useMutationAPI();
const [client, setClient] = useState<WolClient>(wolClient); const [client, setClient] = useState<WolClient>(wolClient);
const [update, setUpdate] = useState<any>({}); const [update, setUpdate] = useState<WolClient>();
const [debounced] = useDebouncedValue(update, 1000); const [debounced] = useDebouncedValue(update, 1000);
const handleClose = () => { const handleClose = () => {
setIsOpen(false); setIsOpen(false);
@@ -27,13 +27,13 @@ function DebouncedWolClient({
}; };
useEffect(() => { useEffect(() => {
if (Object.keys(debounced).length) { if (debounced && Object.keys(debounced).length) {
mutateAsync({ method: 'PATCH', endpoint: 'api/WolClients', body: debounced }); mutateAsync({ method: 'PATCH', endpoint: 'api/WolClients', body: debounced });
} }
}, [debounced]); }, [debounced]);
useEffect(() => { useEffect(() => {
if (update !== client && Object.keys(update).length) { if (update && update !== client && Object.keys(update).length) {
setClient(update); setClient(update);
} }
}, [update]); }, [update]);
@@ -44,6 +44,7 @@ function DebouncedWolClient({
className={cardClasses.settingsItem} className={cardClasses.settingsItem}
classNames={cardClasses} classNames={cardClasses}
> >
{modalOpened && (
<DeleteItemModal <DeleteItemModal
modalOpened={modalOpened} modalOpened={modalOpened}
handleClose={handleClose} handleClose={handleClose}
@@ -60,6 +61,7 @@ function DebouncedWolClient({
</Stack> </Stack>
} }
/> />
)}
<Tooltip <Tooltip
className={toolTipClasses.default} className={toolTipClasses.default}
classNames={toolTipClasses} classNames={toolTipClasses}
@@ -73,7 +75,7 @@ function DebouncedWolClient({
openModal(); openModal();
}} }}
> >
<FiTrash color='black' /> <FaTrash color='black' />
</ActionIcon> </ActionIcon>
</Tooltip> </Tooltip>
<Group w={'100%'} justify='center'> <Group w={'100%'} justify='center'>

View File

@@ -18,7 +18,7 @@ import type { WolClient } from 'types';
import DebouncedWolClient from './DebouncedWolClient'; import DebouncedWolClient from './DebouncedWolClient';
import WolClientSettingsItem from './WolClientSettingsItem'; import WolClientSettingsItem from './WolClientSettingsItem';
const WolClientSettings = () => { export function WolClients() {
const defaultWolClient: WolClient = { const defaultWolClient: WolClient = {
id: undefined, id: undefined,
hostname: '', hostname: '',
@@ -65,6 +65,7 @@ const WolClientSettings = () => {
return ( return (
<Stack> <Stack>
{modalOpened && (
<AddItemModal <AddItemModal
modalOpened={modalOpened} modalOpened={modalOpened}
handleClose={handleClose} handleClose={handleClose}
@@ -135,6 +136,7 @@ const WolClientSettings = () => {
</form> </form>
} }
/> />
)}
<SettingsHeader <SettingsHeader
setDragging={undefined} setDragging={undefined}
openModal={openModal} openModal={openModal}
@@ -204,5 +206,4 @@ const WolClientSettings = () => {
</Stack> </Stack>
</Stack> </Stack>
); );
}; }
export default WolClientSettings;

View File

@@ -0,0 +1,10 @@
export { Applications } from './Applications/Applications';
export { Bookmarks } from './Bookmarks/Bookmarks';
export { GuacamoleClients } from './GuacamoleClients/GuacamoleClients';
export { Messages } from './Messages/Messages';
export { Personalization } from './Personalization/Personalization';
export { SearchHistory } from './Search/SearchHistory';
export { SearchProviders } from './Search/SearchProviders';
export { ThemePlaylists } from './Theming/ThemePlaylists';
export { Themes } from './Theming/Themes';
export { WolClients } from './WoL/WolClients';