Bug fixes and new biome lint update

This commit is contained in:
Sean Edmunds
2025-06-17 17:00:29 -05:00
parent 4a77340ba5
commit 7570c287c8
26 changed files with 459 additions and 500 deletions

View File

@@ -6,7 +6,10 @@ import BookmarkItem from './BookmarkItem';
function BookmarkGroups({
bookmarks,
category,
}: { bookmarks: Bookmark[]; category: string }) {
}: {
bookmarks: Bookmark[];
category: string;
}) {
return (
<Stack
style={{

View File

@@ -1,17 +1,9 @@
import {
ActionIcon,
Group,
type OptionsFilter,
Select,
Stack,
Text,
} from '@mantine/core';
import { type OptionsFilter, Select, Stack, Text } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { HelpModal, WeatherModal } from 'components';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useEffect, useState } from 'react';
import { FiEdit, FiTrash } from 'react-icons/fi';
import { actionIconClasses, selectClasses } from 'styles';
import { selectClasses } from 'styles';
import type {
Application,
CurrentWeather,
@@ -19,6 +11,7 @@ import type {
Provider,
SearchHistoryItem,
} from 'types';
import SearchSelectItem from './SearchHistoryItem';
export default function Search({
current,
@@ -53,7 +46,6 @@ export default function Search({
const [dropdownOpened, { open: openDropdown, close: closeDropdown }] = useDisclosure();
const [listIndex, setListIndex] = useState(0);
const {
theme,
isMobile,
urlPattern,
providerLabel,
@@ -272,112 +264,6 @@ export default function Search({
.slice(0, 10);
};
function RenderOption(item: any) {
const [showFillButton, setShowFillButton] = useState(false);
const m = new Date(item.option.dateTimeStamp);
const year = `${m.getUTCFullYear()}`.slice(-2);
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 dateString = isMobile
? `${month}/${day}/${year}`
: `${month}/${day}/${year} ${hours}:${minutes}`;
return (
<Group
w={'100%'}
display={'flex'}
justify={'space-between'}
gap={0}
onClick={() => {
handleSearchHistoryItem(item);
}}
onMouseEnter={() => {
setShowFillButton(true);
}}
onMouseLeave={() => {
setShowFillButton(false);
}}
>
<Group m={0} p={0} miw={'160px'} style={{ overflow: 'hidden' }}>
<Text
style={{
backgroundColor: `${theme.primaryColor}33`,
fontWeight: 600,
borderRadius: '15px',
padding: '.25rem',
}}
>
{item.option.provider}
</Text>
{showFillButton && (
<ActionIcon
className={actionIconClasses.selectOptionActions}
classNames={actionIconClasses}
onClick={(e) => {
e.stopPropagation();
setSearchValue(`${item.option.prefix} ${item.option.searchTerm}`);
}}
>
<FiEdit />
</ActionIcon>
)}
</Group>
<Group
m={0}
p={0}
gap={0}
justify='space-between'
w={'65%'}
style={{
whiteSpace: 'nowrap',
overflow: 'hidden',
boxSizing: 'border-box',
position: 'relative',
}}
>
<Text
w={'75%'}
c={'var(--mantine-color-primary-0)'}
style={{
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
{item.option.searchTerm}
</Text>
<Text
w={'25%'}
style={{
color: `${theme.primaryColor}55`,
textAlign: 'right',
}}
>
{dateString}
</Text>
</Group>
<Group m={0} p={0} right={'1rem'} w={'24px'}>
{showFillButton && (
<ActionIcon
className={actionIconClasses.selectOptionActions}
classNames={actionIconClasses}
onClick={(e) => {
e.stopPropagation();
mutateAsync({
method: 'DELETE',
endpoint: searchEndpoint,
body: { id: item.option.id },
});
}}
>
<FiTrash />
</ActionIcon>
)}
</Group>
</Group>
);
}
useEffect(() => {
if (providerData && providerDataIsFetched) {
setProviders(providerData);
@@ -460,7 +346,13 @@ export default function Search({
autoFocus={!isMobile}
leftSection={providerLabel}
rightSection={<Stack />}
renderOption={RenderOption}
renderOption={(item: any) => (
<SearchSelectItem
item={item}
handleSearchHistoryItem={handleSearchHistoryItem}
searchEndpoint={searchEndpoint}
/>
)}
onBlur={() => {
setPlaceholderValue('');
setListIndex(0);

View File

@@ -0,0 +1,115 @@
import { ActionIcon, Group, Text } from '@mantine/core';
import { useCommonHooks, useMutationAPI } from 'hooks';
import { useState } from 'react';
import { FiEdit, FiTrash } from 'react-icons/fi';
import { actionIconClasses } from 'styles';
function SearchSelectItem({ item, handleSearchHistoryItem, searchEndpoint }: any) {
const { isMobile, theme, setSearchValue } = useCommonHooks();
const { mutateAsync } = useMutationAPI();
const [showFillButton, setShowFillButton] = useState(false);
const m = new Date(item.option.dateTimeStamp);
const year = `${m.getUTCFullYear()}`.slice(-2);
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 dateString = isMobile
? `${month}/${day}/${year}`
: `${month}/${day}/${year} ${hours}:${minutes}`;
return (
<Group
w={'100%'}
display={'flex'}
justify={'space-between'}
gap={0}
onClick={() => {
handleSearchHistoryItem(item);
}}
onMouseEnter={() => {
setShowFillButton(true);
}}
onMouseLeave={() => {
setShowFillButton(false);
}}
>
<Group m={0} p={0} miw={'160px'} style={{ overflow: 'hidden' }}>
<Text
style={{
backgroundColor: `${theme.primaryColor}33`,
fontWeight: 600,
borderRadius: '15px',
padding: '.25rem',
}}
>
{item.option.provider}
</Text>
{showFillButton && (
<ActionIcon
className={actionIconClasses.selectOptionActions}
classNames={actionIconClasses}
onClick={(e) => {
e.stopPropagation();
setSearchValue(`${item.option.prefix} ${item.option.searchTerm}`);
}}
>
<FiEdit />
</ActionIcon>
)}
</Group>
<Group
m={0}
p={0}
gap={0}
justify='space-between'
w={'65%'}
style={{
whiteSpace: 'nowrap',
overflow: 'hidden',
boxSizing: 'border-box',
position: 'relative',
}}
>
<Text
w={'75%'}
c={'var(--mantine-color-primary-0)'}
style={{
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
{item.option.searchTerm}
</Text>
<Text
w={'25%'}
style={{
color: `${theme.primaryColor}55`,
textAlign: 'right',
}}
>
{dateString}
</Text>
</Group>
<Group m={0} p={0} right={'1rem'} w={'24px'}>
{showFillButton && (
<ActionIcon
className={actionIconClasses.selectOptionActions}
classNames={actionIconClasses}
onClick={(e) => {
e.stopPropagation();
mutateAsync({
method: 'DELETE',
endpoint: searchEndpoint,
body: { id: item.option.id },
});
}}
>
<FiTrash />
</ActionIcon>
)}
</Group>
</Group>
);
}
export default SearchSelectItem;

View File

@@ -23,7 +23,11 @@ function DebouncedApplication({
application,
setIsOpen,
allIcons,
}: { application: Application; setIsOpen: (isOpen: boolean) => void; allIcons: any }) {
}: {
application: Application;
setIsOpen: (isOpen: boolean) => void;
allIcons: any;
}) {
const { handleDelete, isMobile } = useCommonHooks();
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
const { mutateAsync } = useMutationAPI();

View File

@@ -10,6 +10,7 @@ import AddItemModal from '../Shared/AddItemModal';
import NoItemsFound from '../Shared/NoItemsFound';
import SettingsHeader from '../Shared/SettingsHeader';
import DebouncedGroupSettingsItem from './DebouncedGroupSettingsItem';
const BookmarkSettings = () => {
const defaultGroup = {
id: null,

View File

@@ -10,7 +10,10 @@ import DeleteItemModal from '../Shared/DeleteItemModal';
function DebouncedBookmarkItem({
bookmarkItem,
setIsOpen,
}: { bookmarkItem: Bookmark; setIsOpen: (isOpen: boolean) => void }) {
}: {
bookmarkItem: Bookmark;
setIsOpen: (isOpen: boolean) => void;
}) {
const { handleDelete, isMobile } = useCommonHooks();
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
const { mutateAsync } = useMutationAPI();

View File

@@ -33,7 +33,11 @@ function DebouncedGroupSettingsItem({
bookmarkGroup,
bookmarks,
searchTerm,
}: { bookmarkGroup: BookmarkGroup; bookmarks: Bookmark[]; searchTerm: string }) {
}: {
bookmarkGroup: BookmarkGroup;
bookmarks: Bookmark[];
searchTerm: string;
}) {
const { isMobile, handleDelete, reorder } = useCommonHooks();
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
const [popoverOpened, setPopoverOpened] = useState(false);

View File

@@ -5,6 +5,7 @@ import { useEffect, useState } from 'react';
import { cardClasses, textInputClasses } from 'styles';
import type { PersonalData } from 'types';
import SettingsHeader from '../Shared/SettingsHeader';
const PersonalizationSettings = () => {
const endpoint = 'api/personalData';
const {

View File

@@ -11,7 +11,7 @@ import {
} from '@mantine/core';
import { useCommonHooks } from 'hooks';
import { useState } from 'react';
import { FiHelpCircle, FiLoader, FiPlus } from 'react-icons/fi';
import { FiHelpCircle, FiLoader, FiPlus, FiX } from 'react-icons/fi';
import {
actionIconClasses,
buttonClasses,
@@ -137,13 +137,23 @@ function SettingsHeader({
zIndex: 100,
}}
rightSection={
isLoading && (
isLoading ? (
<ActionIcon
className={actionIconClasses.loadingSpinner}
classNames={actionIconClasses}
>
<FiLoader />
</ActionIcon>
) : (
searchValue && (
<ActionIcon
className={actionIconClasses.settingsTooltip}
classNames={actionIconClasses}
onClick={() => setSearchValue('')}
>
<FiX />
</ActionIcon>
)
)
}
/>

View File

@@ -0,0 +1,69 @@
import { Box, Stack, Text } from '@mantine/core';
import { useState } from 'react';
import { FiCheck } from 'react-icons/fi';
import { stackClasses } from 'styles';
import type { Theme } from 'types';
function ExampleApp({ selectedTheme }: { selectedTheme: Theme }) {
const [textDecoration, setTextDecoration] = useState<string>('none');
return (
<Box
component='a'
onMouseOver={() => setTextDecoration('underline')}
onMouseOut={() => setTextDecoration('none')}
className={stackClasses.appItemBox}
>
<Stack
style={{
height: '64px',
marginRight: '1rem',
marginLeft: '1rem',
paddingTop: '1rem',
}}
>
<FiCheck style={{ color: selectedTheme.primaryColor }} height={32} width={32} />
</Stack>
<Stack
style={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
flex: 1,
overflow: 'hidden',
gap: 0,
}}
>
<Text
style={{
fontWeight: 400,
fontSize: '.625rem',
fontStyle: 'normal',
color: selectedTheme.primaryColor,
fontFamily:
'-apple-system, Jost, BlinkMacSystemFont, Helvetica Neue, Roboto, sans-serif !important',
margin: 0,
}}
>
{'Example App'}
</Text>
<Text
style={{
fontWeight: 400,
fontSize: '.625rem',
fontStyle: 'italic',
color: selectedTheme.accentColor,
fontFamily:
'-apple-system, Jost, BlinkMacSystemFont, Helvetica Neue, Roboto, sans-serif !important',
margin: 0,
textDecoration: textDecoration,
}}
>
{'https://www.example.com'}
</Text>
</Stack>
</Box>
);
}
export default ExampleApp;

View File

@@ -1,12 +1,7 @@
import { Group, Text } from '@mantine/core';
import type { Theme } from 'types';
function ThemeMiniCard({
allThemes,
item,
}: {
allThemes: Theme[];
item: number;
}) {
function ThemeMiniCard({ allThemes, item }: { allThemes: Theme[]; item: number }) {
const theme = allThemes?.find((theme: Theme) => theme.id === item);
return (
@@ -19,9 +14,10 @@ function ThemeMiniCard({
w={'175px'}
h={'60px'}
style={{
background: `linear-gradient(${theme?.backgroundColor}33, ${theme?.backgroundColor}33), no-repeat center url(/backgrounds/${theme?.backgroundImage})`,
backgroundImage: `linear-gradient(${theme?.backgroundColor}33, ${theme?.backgroundColor}33), url(/backgrounds/${theme?.backgroundImage})`,
backgroundSize: 'cover',
backgroundColor: theme?.backgroundColor,
backgroundPosition: 'center',
border: `solid ${theme?.borderColor}`,
borderRadius: '8px',
}}

View File

@@ -1,84 +1,22 @@
import { Box, Group, Stack, Text } from '@mantine/core';
import { useState } from 'react';
import { FiCheck } from 'react-icons/fi';
import { stackClasses } from 'styles';
import { Group, Stack, Text } from '@mantine/core';
import type { Theme } from 'types';
import ThemeExampleApp from './ThemeExampleApp';
export default function ThemeModalContent({ selectedTheme }: { selectedTheme: Theme }) {
const ExampleApp = () => {
const [textDecoration, setTextDecoration] = useState<string>('none');
return (
<Box
component='a'
onMouseOver={() => setTextDecoration('underline')}
onMouseOut={() => setTextDecoration('none')}
className={stackClasses.appItemBox}
>
<Stack
style={{
height: '64px',
marginRight: '1rem',
marginLeft: '1rem',
paddingTop: '1rem',
}}
>
<FiCheck style={{ color: selectedTheme.primaryColor }} height={32} width={32} />
</Stack>
<Stack
style={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
flex: 1,
overflow: 'hidden',
gap: 0,
}}
>
<Text
style={{
fontWeight: 400,
fontSize: '.625rem',
fontStyle: 'normal',
color: selectedTheme.primaryColor,
fontFamily:
'-apple-system, Jost, BlinkMacSystemFont, Helvetica Neue, Roboto, sans-serif !important',
margin: 0,
}}
>
{'Example App'}
</Text>
<Text
style={{
fontWeight: 400,
fontSize: '.625rem',
fontStyle: 'italic',
color: selectedTheme.accentColor,
fontFamily:
'-apple-system, Jost, BlinkMacSystemFont, Helvetica Neue, Roboto, sans-serif !important',
margin: 0,
textDecoration: textDecoration,
}}
>
{'https://www.example.com'}
</Text>
</Stack>
</Box>
);
};
return (
<Stack
style={{
width: '100%',
background:
backgroundImage:
selectedTheme.backgroundImage !== 'none'
? `linear-gradient(${selectedTheme.backgroundColor}33, ${selectedTheme.backgroundColor}33), no-repeat center url(/backgrounds/${selectedTheme.backgroundImage})`
? `linear-gradient(${selectedTheme?.backgroundColor}33, ${selectedTheme?.backgroundColor}33), url(/backgrounds/${selectedTheme?.backgroundImage})`
: undefined,
backgroundSize: selectedTheme.backgroundImage !== 'none' ? 'cover' : undefined,
backgroundColor:
selectedTheme.backgroundImage === 'none'
? selectedTheme.backgroundColor
: undefined,
backgroundPosition: 'center',
borderRadius: '10px',
border: '2px solid',
}}
@@ -124,9 +62,9 @@ export default function ThemeModalContent({ selectedTheme }: { selectedTheme: Th
alignContent: 'center',
}}
>
<ExampleApp />
<ExampleApp />
<ExampleApp />
<ThemeExampleApp selectedTheme={selectedTheme} />
<ThemeExampleApp selectedTheme={selectedTheme} />
<ThemeExampleApp selectedTheme={selectedTheme} />
</Stack>
<Text
pl={'1.5rem'}

View File

@@ -57,8 +57,10 @@ function ThemePlaylists() {
useEffect(() => {
if (themePlaylistData && isThemePlaylistDataFetched) {
setThemePlaylists(
themePlaylistData.filter((a: ThemePlaylist) =>
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()),
themePlaylistData.filter(
(a: ThemePlaylist) =>
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()) ||
a.name.includes('Time of Day'),
),
);
}
@@ -95,7 +97,7 @@ function ThemePlaylists() {
isLoading={isLoading}
setIsLoading={setIsLoading}
/>
{allThemeData ? (
{allThemeData && (
<>
<Group mt={'6rem'} justify='center' align='center' pos={'relative'}>
<Text
@@ -293,8 +295,6 @@ function ThemePlaylists() {
)}
</Group>
</>
) : (
<></>
)}
</Stack>
</Stack>

View File

@@ -55,7 +55,6 @@ function ThemesSettings() {
currentThemePlaylist,
setCurrentThemePlaylist,
} = useCommonHooks();
const handleOpen = (theme: Theme) => {
setSelectedTheme(theme);
open();
@@ -267,7 +266,7 @@ function ThemesSettings() {
navigate(`/${import.meta.env.VITE_BASE_URL}/settings/themePlaylists`);
} else {
setCurrentThemePlaylist('All');
setCurrentTheme('random');
setCurrentTheme(theme.name);
}
}}
>