From b948abad48b50fe134a416615d8d866bc471eac6 Mon Sep 17 00:00:00 2001 From: Sean Edmunds Date: Tue, 22 Jul 2025 14:19:36 -0500 Subject: [PATCH] Default Search Provider support; Style updates --- package-lock.json | 8 +- package.json | 2 +- src/components/HelpModal/HelpModal.tsx | 12 +- src/components/ManagementPill.tsx | 4 +- src/components/WeatherModal/WeatherModal.tsx | 12 +- src/hooks/useAPI.tsx | 4 + src/hooks/useCommonHooks.ts | 34 +++- .../homepage/components/Search/Search.tsx | 46 +++-- .../Applications/DebouncedApplication.tsx | 6 +- .../Search/DebouncedSearchProvider.tsx | 34 ++-- .../Search/SearchProviderSettingsItem.tsx | 31 ++- .../components/Search/SearchProviders.tsx | 49 ++++- .../Theming/Backgrounds/AddBackground.tsx | 144 ++++++++++++++ .../Theming/Backgrounds/BackgroundModal.tsx | 183 ++++-------------- .../Theming/Backgrounds/DeleteBackground.tsx | 29 +-- .../Theming/Backgrounds/EditBackground.tsx | 25 +-- .../components/Theming/Backgrounds/index.ts | 2 + .../components/Theming/Themes/ThemeModal.tsx | 24 ++- .../components/Theming/Themes/Themes.tsx | 6 +- src/types/index.ts | 1 + src/types/provider.ts | 1 + src/types/theme.ts | 12 ++ 22 files changed, 391 insertions(+), 278 deletions(-) create mode 100644 src/pages/settings/components/Theming/Backgrounds/AddBackground.tsx diff --git a/package-lock.json b/package-lock.json index fc14285..913fe23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,7 @@ "recharts": "^3.1.0" }, "devDependencies": { - "@types/node": "^24.0.15", + "@types/node": "^24.1.0", "@types/react": "^19.1.8", "@types/react-dom": "^19.1.6", "@vitejs/plugin-react": "^4.7.0", @@ -1846,9 +1846,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.0.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.15.tgz", - "integrity": "sha512-oaeTSbCef7U/z7rDeJA138xpG3NuKc64/rZ2qmUFkFJmnMsAPaluIifqyWd8hSSMxyP9oie3dLAqYPblag9KgA==", + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz", + "integrity": "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index d407c09..5eb9e92 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "recharts": "^3.1.0" }, "devDependencies": { - "@types/node": "^24.0.15", + "@types/node": "^24.1.0", "@types/react": "^19.1.8", "@types/react-dom": "^19.1.6", "@vitejs/plugin-react": "^4.7.0", diff --git a/src/components/HelpModal/HelpModal.tsx b/src/components/HelpModal/HelpModal.tsx index 267862b..8628b90 100644 --- a/src/components/HelpModal/HelpModal.tsx +++ b/src/components/HelpModal/HelpModal.tsx @@ -5,17 +5,13 @@ import type { Application, Provider } from 'types'; import HelpSection from './HelpSection'; export function HelpModal({ - setSearchValue, - setProviderLabel, - setProviderURL, + handleResetSearch, providerModalOpened, closeProviderModal, applicationData, providerData, }: { - setSearchValue: (value: string) => void; - setProviderLabel: (label: string) => void; - setProviderURL: (url: string) => void; + handleResetSearch: () => void; providerModalOpened: boolean; closeProviderModal: () => void; applicationData: Application[]; @@ -31,10 +27,8 @@ export function HelpModal({ fullScreen={isMobile} centered onClose={() => { - setSearchValue(''); - setProviderLabel('Google Search'); - setProviderURL('https://www.google.com/search?q='); closeProviderModal(); + handleResetSearch(); }} closeOnEscape closeOnClickOutside diff --git a/src/components/ManagementPill.tsx b/src/components/ManagementPill.tsx index 88e9020..0e040ae 100644 --- a/src/components/ManagementPill.tsx +++ b/src/components/ManagementPill.tsx @@ -6,10 +6,12 @@ export function ManagementPill({ enabled, onChange, openModal, + label = ['Disabled', 'Enabled'], }: { enabled: number; onChange: any; openModal: () => void; + label?: [string, string]; }) { return ( void; - setProviderLabel: (label: string) => void; - setProviderURL: (url: string) => void; + handleResetSearch: () => void; closeWeatherModal: () => void; }) { const { isMobile, currentUser, currentLocation } = useCommonHooks(); @@ -48,9 +44,7 @@ export function WeatherModal({ opened={weatherModalOpened} centered onClose={() => { - setSearchValue(''); - setProviderLabel('Google Search'); - setProviderURL('https://www.google.com/search?q='); + handleResetSearch(); closeWeatherModal(); }} closeOnEscape diff --git a/src/hooks/useAPI.tsx b/src/hooks/useAPI.tsx index 0a7a0e6..8761aab 100644 --- a/src/hooks/useAPI.tsx +++ b/src/hooks/useAPI.tsx @@ -133,6 +133,8 @@ export function useMutationAPI() { queryClient.refetchQueries({ queryKey: ['GET', 'api/applicationOrder'] }); endpoint === 'api/bookmarks' && queryClient.refetchQueries({ queryKey: ['GET', 'api/themes'] }); + endpoint === 'api/providers' && + queryClient.refetchQueries({ queryKey: ['GET', 'api/providers/default'] }); }, onSuccess: (_, { endpoint }) => { queryClient.refetchQueries({ @@ -146,6 +148,8 @@ export function useMutationAPI() { queryClient.refetchQueries({ queryKey: ['GET', 'api/applicationOrder'] }); endpoint === 'api/bookmarks' && queryClient.refetchQueries({ queryKey: ['GET', 'api/themes'] }); + endpoint === 'api/providers' && + queryClient.refetchQueries({ queryKey: ['GET', 'api/providers/default'] }); }, }); } diff --git a/src/hooks/useCommonHooks.ts b/src/hooks/useCommonHooks.ts index 66dc536..98d7121 100644 --- a/src/hooks/useCommonHooks.ts +++ b/src/hooks/useCommonHooks.ts @@ -1,7 +1,7 @@ import { useLocalStorage } from '@mantine/hooks'; import { appTheme } from 'contexts'; import { useAtom } from 'jotai'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import type { Location, Theme, User } from 'types'; import { useMutationAPI } from './useAPI'; @@ -53,11 +53,29 @@ export function useCommonHooks() { key: 'themePlaylist', defaultValue: 'All', }); - + const [defaultProviderLabel, setDefaultProviderLabel] = useLocalStorage({ + key: 'providerLabel', + defaultValue: 'Google Search', + }); + const [defaultProviderURL, setDefaultProviderURL] = useLocalStorage({ + key: 'providerURL', + defaultValue: 'https://www.google.com/search?q=', + }); + const [defaultProviderPrefix, setDefaultProviderPrefix] = useLocalStorage({ + key: 'providerPrefix', + defaultValue: '/g', + }); const [searchValue, setSearchValue] = useState(''); - const [providerLabel, setProviderLabel] = useState('Google Search'); - const [providerURL, setProviderURL] = useState('https://www.google.com/search?q='); - const [providerPrefix, setProviderPrefix] = useState('/g'); + const [providerLabel, setProviderLabel] = useState(defaultProviderLabel); + const [providerURL, setProviderURL] = useState(defaultProviderURL); + const [providerPrefix, setProviderPrefix] = useState(defaultProviderPrefix); + + useEffect(() => { + setProviderLabel(defaultProviderLabel); + setProviderURL(defaultProviderURL); + setProviderPrefix(defaultProviderPrefix); + }, [defaultProviderLabel, defaultProviderURL, defaultProviderPrefix]); + const [currentUser, setCurrentUser] = useLocalStorage({ key: 'user', defaultValue: { @@ -207,6 +225,12 @@ export function useCommonHooks() { setProviderURL, providerPrefix, setProviderPrefix, + defaultProviderLabel, + setDefaultProviderLabel, + defaultProviderURL, + setDefaultProviderURL, + defaultProviderPrefix, + setDefaultProviderPrefix, currentUser, setCurrentUser, currentLocation, diff --git a/src/pages/homepage/components/Search/Search.tsx b/src/pages/homepage/components/Search/Search.tsx index 7c81e52..2d8b9c0 100644 --- a/src/pages/homepage/components/Search/Search.tsx +++ b/src/pages/homepage/components/Search/Search.tsx @@ -37,6 +37,10 @@ export default function Search({ const { data: applicationData, isFetching: isApplicationDataFetching } = useQueryAPI({ endpoint: 'api/enabledApplications', }); + const { data: defaultProviderData, isFetched: defaultProviderDataIsFetched } = + useQueryAPI({ + endpoint: 'api/providers/default', + }); const [applications, setApplications] = useState([]); const searchEndpoint = 'api/searchHistory'; const { data: historyData, isFetched: historyDataIsFetched } = useQueryAPI({ @@ -60,14 +64,26 @@ export default function Search({ setProviderPrefix, searchValue, setSearchValue, + defaultProviderURL, + setDefaultProviderURL, + defaultProviderLabel, + setDefaultProviderLabel, + defaultProviderPrefix, + setDefaultProviderPrefix, } = useCommonHooks(); const [placeholderValue, setPlaceholderValue] = useState(''); const [value, setValue] = useState(0); + const handleResetSearch = () => { + setSearchValue(''); + setProviderLabel(defaultProviderLabel); + setProviderURL(defaultProviderURL); + }; + const handleSearchHistoryItem = ({ option }: { option: SearchHistoryItem }) => { const url = providerData.find((provider: Provider) => provider.prefix === option.prefix)?.url ?? - 'https://www.google.com/search?q='; + defaultProviderURL; open(`${url}${option.searchTerm}`, '_self'); }; @@ -136,9 +152,7 @@ export default function Search({ const handleKeyUp = (item: any) => { if (item.code === 'Escape') { setListIndex(0); - setSearchValue(''); - setProviderLabel('Google Search'); - setProviderPrefix('/g'); + handleResetSearch(); setPlaceholderValue(''); if (dropdownOpened) { closeDropdown(); @@ -242,9 +256,9 @@ export default function Search({ setProviderLabel('Invalid function'); } } else { - setProviderLabel('Google Search'); - setProviderURL('https://www.google.com/search?q='); - setProviderPrefix('/g'); + setProviderLabel(defaultProviderLabel); + setProviderURL(defaultProviderURL); + setProviderPrefix(defaultProviderPrefix); } }; @@ -321,6 +335,16 @@ export default function Search({ setFilteredHistory(filtered); }, [searchValue]); + useEffect(() => { + if (defaultProviderData && defaultProviderDataIsFetched) { + setDefaultProviderURL( + defaultProviderData[0]?.url ?? 'https://www.google.com/search?q=', + ); + setDefaultProviderPrefix(defaultProviderData[0]?.prefix ?? '/g'); + setDefaultProviderLabel(defaultProviderData[0]?.name ?? 'Google Search'); + } + }, [defaultProviderData, defaultProviderDataIsFetched]); + return ( <> {dropdownOpened && } @@ -423,9 +447,7 @@ export default function Search({ onKeyUp={handleKeyUp} /> diff --git a/src/pages/settings/components/Applications/DebouncedApplication.tsx b/src/pages/settings/components/Applications/DebouncedApplication.tsx index 94ebddd..14fcfbf 100644 --- a/src/pages/settings/components/Applications/DebouncedApplication.tsx +++ b/src/pages/settings/components/Applications/DebouncedApplication.tsx @@ -85,11 +85,7 @@ function DebouncedApplication({ }} openModal={openModal} /> - + } /> - - { - setIsOpen(true); - openModal(); - }} - > - - - + ) => { + setUpdate({ + ...provider, + default: event.target.checked ? 1 : 0, + }); + }} + openModal={openModal} + label={['Non-Default', 'Default']} + /> + + {provider.default === 1 && ( + + DEFAULT + + )} + { name: '', url: '', prefix: '', + default: 0, }; const form = useForm({ initialValues: defaultProvider, @@ -139,6 +143,43 @@ const SearchProviderSettings = () => { } /> + + + } + /> + + + + + + + ); +} diff --git a/src/pages/settings/components/Theming/Backgrounds/BackgroundModal.tsx b/src/pages/settings/components/Theming/Backgrounds/BackgroundModal.tsx index a844b0c..79b583c 100644 --- a/src/pages/settings/components/Theming/Backgrounds/BackgroundModal.tsx +++ b/src/pages/settings/components/Theming/Backgrounds/BackgroundModal.tsx @@ -2,9 +2,7 @@ import { ActionIcon, Button, Card, - FileInput, Group, - Image, Modal, ScrollArea, SimpleGrid, @@ -14,7 +12,6 @@ import { } from '@mantine/core'; import { useDebouncedValue, useDisclosure, useElementSize } from '@mantine/hooks'; import { useCommonHooks } from 'hooks'; -import { useFileUploadAPI } from 'hooks/useAPI'; import { useEffect, useState } from 'react'; import { FiEdit, FiLoader, FiPlus, FiTrash, FiX } from 'react-icons/fi'; import { @@ -24,18 +21,19 @@ import { scrollAreaClasses, textInputClasses, } from 'styles'; +import { AddBackground } from './AddBackground'; import { BackgroundLightbox } from './BackgroundLightbox'; import { DeleteBackground } from './DeleteBackground'; import { EditBackground } from './EditBackground'; export function BackgroundModal({ backgroundModalOpened, - handleBackgroundModalClose, + closeModal, backgroundList, inUseBackgrounds, }: { backgroundModalOpened: boolean; - handleBackgroundModalClose: () => void; + closeModal: () => void; backgroundList: string[]; inUseBackgrounds: string[]; }) { @@ -54,12 +52,23 @@ export function BackgroundModal({ const [searchValue, setSearchValue] = useState(''); const [debouncedSearch] = useDebouncedValue(searchValue, 500); const { isMobile, theme } = useCommonHooks(); - const { mutateAsync: uploadAsync } = useFileUploadAPI(); - const fd = new FormData(); - const handleFileUpload = (e: any) => { + + const handleAddBackgroundModalClose = () => { + setAdding(false); + setFileName(''); + setNewFileName(''); + setBackground(null); setErr(false); - setBackground(e); - setFileName(e?.name); + }; + const handleEditBackgroundModalClose = () => { + setEditing(false); + setFileName(''); + setNewFileName(''); + setBackground(null); + }; + const handleDeleteBackgroundModalClose = () => { + setConfirm(false); + setFileName(''); }; useEffect(() => { if (debouncedSearch === searchValue) { @@ -78,12 +87,13 @@ export function BackgroundModal({ classNames={modalClasses} opened={backgroundModalOpened} onClose={() => { - setBackground(null); + closeModal(); + setAdding(false); + setEditing(false); + setConfirm(false); setFileName(''); setNewFileName(''); - handleBackgroundModalClose(); - setConfirm(false); - setEditing(false); + setBackground(null); }} fullScreen={isMobile} centered @@ -160,21 +170,15 @@ export function BackgroundModal({ {confirm && ( )} {editing && ( )} {!editing && !confirm && !adding && ( @@ -292,130 +296,17 @@ export function BackgroundModal({ )} {adding && ( - - - - - setNewFileName(e.target.value)} - pr={'xl'} - pl={0} - styles={{ - input: { - color: 'var(--mantine-color-primary-0)', - borderColor: 'var(--mantine-color-primary-0)', - }, - }} - /> - - - {background ? ( - - ) : ( - - )} - - - - - - - + )} diff --git a/src/pages/settings/components/Theming/Backgrounds/DeleteBackground.tsx b/src/pages/settings/components/Theming/Backgrounds/DeleteBackground.tsx index a0ff898..059dbe0 100644 --- a/src/pages/settings/components/Theming/Backgrounds/DeleteBackground.tsx +++ b/src/pages/settings/components/Theming/Backgrounds/DeleteBackground.tsx @@ -3,18 +3,12 @@ import { useMutationAPI } from 'hooks'; export function DeleteBackground({ fileName, - setFileName, inUseBackgrounds, - setBackground, - setNewFileName, - setConfirm, + handleDeleteBackgroundModalClose, }: { fileName: string; - setFileName: (searchValue: string) => void; inUseBackgrounds: string[]; - setBackground: React.Dispatch>; - setNewFileName: (searchValue: string) => void; - setConfirm: (value: boolean) => void; + handleDeleteBackgroundModalClose: () => void; }) { const { mutateAsync } = useMutationAPI(); return ( @@ -57,14 +51,9 @@ export function DeleteBackground({ - diff --git a/src/pages/settings/components/Theming/Backgrounds/EditBackground.tsx b/src/pages/settings/components/Theming/Backgrounds/EditBackground.tsx index 95c780c..f9772a7 100644 --- a/src/pages/settings/components/Theming/Backgrounds/EditBackground.tsx +++ b/src/pages/settings/components/Theming/Backgrounds/EditBackground.tsx @@ -5,18 +5,12 @@ import { textInputClasses } from 'styles'; export function EditBackground({ fileName, - setFileName, inUseBackgrounds, - setBackground, - setNewFileName, - setEditing, + handleEditBackgroundModalClose, }: { fileName: string; - setFileName: (searchValue: string) => void; inUseBackgrounds: string[]; - setBackground: React.Dispatch>; - setNewFileName: (searchValue: string) => void; - setEditing: React.Dispatch>; + handleEditBackgroundModalClose: () => void; }) { const [rename, setRename] = useState(''); const { mutateAsync } = useMutationAPI(); @@ -60,7 +54,6 @@ export function EditBackground({ diff --git a/src/pages/settings/components/Theming/Backgrounds/index.ts b/src/pages/settings/components/Theming/Backgrounds/index.ts index 75335ed..ddfe0eb 100644 --- a/src/pages/settings/components/Theming/Backgrounds/index.ts +++ b/src/pages/settings/components/Theming/Backgrounds/index.ts @@ -1,3 +1,5 @@ +export { AddBackground } from './AddBackground'; +export { BackgroundLightbox } from './BackgroundLightbox'; export { BackgroundModal } from './BackgroundModal'; export { DeleteBackground } from './DeleteBackground'; export { EditBackground } from './EditBackground'; diff --git a/src/pages/settings/components/Theming/Themes/ThemeModal.tsx b/src/pages/settings/components/Theming/Themes/ThemeModal.tsx index 65e0430..0594d78 100644 --- a/src/pages/settings/components/Theming/Themes/ThemeModal.tsx +++ b/src/pages/settings/components/Theming/Themes/ThemeModal.tsx @@ -19,7 +19,7 @@ import { useCommonHooks } from 'hooks'; 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 { BackgroundProperties, type Theme } from 'types'; import { ThemeModalContent } from './ThemeModalContent'; export function ThemeModal({ @@ -304,7 +304,8 @@ export function ThemeModal({ : undefined, }} > - Change {colorId} + Change{' '} + {BackgroundProperties[colorId as keyof typeof BackgroundProperties]} {colorId === 'backgroundColor' && ( - {key} + + { + BackgroundProperties[ + key as keyof typeof BackgroundProperties + ] + } + {key === 'name' && ( {defaultTheme[key as keyof Theme]} @@ -568,14 +575,18 @@ export function ThemeModal({ None → None )} @@ -621,6 +632,7 @@ export function ThemeModal({ onClick={() => { setSelectedTheme({ ...defaultTheme }); }} + mih={'36px'} > Reset Changes diff --git a/src/pages/settings/components/Theming/Themes/Themes.tsx b/src/pages/settings/components/Theming/Themes/Themes.tsx index a96354a..cbde821 100644 --- a/src/pages/settings/components/Theming/Themes/Themes.tsx +++ b/src/pages/settings/components/Theming/Themes/Themes.tsx @@ -85,10 +85,6 @@ export function Themes() { }); }; - const handleBackgroundModalClose = () => { - closeBackgroundModal(); - }; - const handleSaveTheme = () => { mutateAsync({ method: selectedTheme?.id === undefined ? 'POST' : 'PATCH', @@ -154,7 +150,7 @@ export function Themes() { /> diff --git a/src/types/index.ts b/src/types/index.ts index 88e9f9f..f7b86c4 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -7,6 +7,7 @@ export type { PersonalData } from './personalData'; export type { Provider } from './provider'; export type { SearchHistoryItem, SearchShortcut } from './search'; export type { Theme, ThemePlaylist } from './theme'; +export { BackgroundProperties } from './theme'; export type { User } from './user'; export type { CurrentWeather, diff --git a/src/types/provider.ts b/src/types/provider.ts index c1a0d2a..6dce4e9 100644 --- a/src/types/provider.ts +++ b/src/types/provider.ts @@ -3,4 +3,5 @@ export interface Provider { name: string; url: string; prefix: string; + default: number; } diff --git a/src/types/theme.ts b/src/types/theme.ts index 4a1f8c4..ca28ec4 100644 --- a/src/types/theme.ts +++ b/src/types/theme.ts @@ -18,3 +18,15 @@ export interface ThemePlaylist { default: number; themeList: string; } + +export enum BackgroundProperties { + backgroundImage = 'Background Image', + backgroundColor = 'Background Color', + searchColor = 'Search Color', + primaryColor = 'Primary Color', + accentColor = 'Accent Color', + borderColor = 'Border Color', + randomEnabled = 'Random', + textShadowsEnabled = 'Text Shadows', + appShadowsEnabled = 'App Shadows', +}