Typing
This commit is contained in:
22
package-lock.json
generated
22
package-lock.json
generated
@@ -15,7 +15,6 @@
|
|||||||
"@tanstack/react-query-devtools": "^5.74.3",
|
"@tanstack/react-query-devtools": "^5.74.3",
|
||||||
"@tanstack/react-query-persist-client": "^5.74.3",
|
"@tanstack/react-query-persist-client": "^5.74.3",
|
||||||
"idb-keyval": "^6.2.1",
|
"idb-keyval": "^6.2.1",
|
||||||
"jotai": "^2.12.3",
|
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
@@ -3801,27 +3800,6 @@
|
|||||||
"integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==",
|
"integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/jotai": {
|
|
||||||
"version": "2.12.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/jotai/-/jotai-2.12.3.tgz",
|
|
||||||
"integrity": "sha512-DpoddSkmPGXMFtdfnoIHfueFeGP643nqYUWC6REjUcME+PG2UkAtYnLbffRDw3OURI9ZUTcRWkRGLsOvxuWMCg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12.20.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@types/react": ">=17.0.0",
|
|
||||||
"react": ">=17.0.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"@types/react": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"react": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/js-sha3": {
|
"node_modules/js-sha3": {
|
||||||
"version": "0.8.0",
|
"version": "0.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
"@tanstack/react-query-devtools": "^5.74.3",
|
"@tanstack/react-query-devtools": "^5.74.3",
|
||||||
"@tanstack/react-query-persist-client": "^5.74.3",
|
"@tanstack/react-query-persist-client": "^5.74.3",
|
||||||
"idb-keyval": "^6.2.1",
|
"idb-keyval": "^6.2.1",
|
||||||
"jotai": "^2.12.3",
|
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
|
|||||||
@@ -13,11 +13,10 @@ import {
|
|||||||
createBrowserRouter,
|
createBrowserRouter,
|
||||||
createRoutesFromElements,
|
createRoutesFromElements,
|
||||||
} from 'react-router-dom';
|
} from 'react-router-dom';
|
||||||
import { MainLayout, ThemeProvider } from './components';
|
import { Loading, MainLayout, ThemeProvider } from './components';
|
||||||
import '@mantine/core/styles.css'; //import Mantine V7 styles needed by MRT
|
import '@mantine/core/styles.css'; //import Mantine V7 styles needed by MRT
|
||||||
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
|
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
import Loading from 'components/Loading';
|
|
||||||
import { Homepage, Settings } from 'pages';
|
import { Homepage, Settings } from 'pages';
|
||||||
import { ToastContainer } from 'react-toastify';
|
import { ToastContainer } from 'react-toastify';
|
||||||
import type { Theme, ThemePlaylist } from 'types';
|
import type { Theme, ThemePlaylist } from 'types';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Divider, Modal, Stack } from '@mantine/core';
|
import { Divider, Modal, Stack } from '@mantine/core';
|
||||||
import { useCommonHooks } from 'hooks';
|
import { useCommonHooks } from 'hooks';
|
||||||
import { modalClasses } from 'styles';
|
import { modalClasses } from 'styles';
|
||||||
import type { Provider } from 'types';
|
import type { Application, Provider } from 'types';
|
||||||
import HelpSection from './HelpSection';
|
import HelpSection from './HelpSection';
|
||||||
|
|
||||||
export function HelpModal({
|
export function HelpModal({
|
||||||
@@ -12,8 +12,16 @@ export function HelpModal({
|
|||||||
closeProviderModal,
|
closeProviderModal,
|
||||||
applicationData,
|
applicationData,
|
||||||
providerData,
|
providerData,
|
||||||
}: any) {
|
}: {
|
||||||
const { theme, isMobile } = useCommonHooks();
|
setSearchValue: (value: string) => void;
|
||||||
|
setProviderLabel: (label: string) => void;
|
||||||
|
setProviderURL: (url: string) => void;
|
||||||
|
providerModalOpened: boolean;
|
||||||
|
closeProviderModal: () => void;
|
||||||
|
applicationData: Application[];
|
||||||
|
providerData: Provider[];
|
||||||
|
}) {
|
||||||
|
const { theme, isMobile, modalStyle } = useCommonHooks();
|
||||||
return (
|
return (
|
||||||
<Modal.Root
|
<Modal.Root
|
||||||
size={'60%'}
|
size={'60%'}
|
||||||
@@ -28,14 +36,7 @@ export function HelpModal({
|
|||||||
setProviderURL('https://www.google.com/search?q=');
|
setProviderURL('https://www.google.com/search?q=');
|
||||||
closeProviderModal();
|
closeProviderModal();
|
||||||
}}
|
}}
|
||||||
style={{
|
style={modalStyle}
|
||||||
'--color-text-pri': theme.primaryColor,
|
|
||||||
'--color-text-acc': theme.accentColor,
|
|
||||||
'--color-background': theme.backgroundColor,
|
|
||||||
'--color-border': theme.borderColor,
|
|
||||||
'--color-search-background': theme.searchColor,
|
|
||||||
'--image-background': `url(${theme.backgroundImage})`,
|
|
||||||
}}
|
|
||||||
closeOnEscape
|
closeOnEscape
|
||||||
closeOnClickOutside
|
closeOnClickOutside
|
||||||
>
|
>
|
||||||
@@ -59,7 +60,7 @@ export function HelpModal({
|
|||||||
<Divider my={8} color={theme.accentColor} />
|
<Divider my={8} color={theme.accentColor} />
|
||||||
<HelpSection
|
<HelpSection
|
||||||
name={'Available Applications'}
|
name={'Available Applications'}
|
||||||
items={applicationData.map((application: any) => {
|
items={applicationData.map((application: Application) => {
|
||||||
return {
|
return {
|
||||||
name: application.url,
|
name: application.url,
|
||||||
command: `!${application.baseUrl.substring(1).toLowerCase()}`,
|
command: `!${application.baseUrl.substring(1).toLowerCase()}`,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Divider, Group } from '@mantine/core';
|
|||||||
import { useCommonHooks } from 'hooks';
|
import { useCommonHooks } from 'hooks';
|
||||||
import HintItem from './HintItem';
|
import HintItem from './HintItem';
|
||||||
|
|
||||||
function HelpSection({ name, items }: any) {
|
function HelpSection({ name, items }: { name: string; items: object[] }) {
|
||||||
const { theme } = useCommonHooks();
|
const { theme } = useCommonHooks();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -30,7 +30,7 @@ function HelpSection({ name, items }: any) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{items
|
{items
|
||||||
?.sort((a: any, b: any) => (a.command > b.command ? 1 : -1))
|
?.toSorted((a: any, b: any) => (a.command > b.command ? 1 : -1))
|
||||||
.map((item: any) => (
|
.map((item: any) => (
|
||||||
<HintItem key={item.command} command={item.command} name={item.name} />
|
<HintItem key={item.command} command={item.command} name={item.name} />
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Group, Text } from '@mantine/core';
|
import { Group, Text } from '@mantine/core';
|
||||||
|
|
||||||
function HintItem({ command, name }: any) {
|
function HintItem({ command, name }: { command: string; name: string }) {
|
||||||
return (
|
return (
|
||||||
<Group
|
<Group
|
||||||
gap={0}
|
gap={0}
|
||||||
|
|||||||
@@ -1,17 +1,12 @@
|
|||||||
import { Stack } from '@mantine/core';
|
import { Stack } from '@mantine/core';
|
||||||
import { stackClasses } from 'styles';
|
import { stackClasses } from 'styles';
|
||||||
|
|
||||||
function Loading({ loaded }: any) {
|
export function Loading({ loaded }: any) {
|
||||||
return (
|
return (
|
||||||
<Stack
|
<Stack
|
||||||
align='center'
|
|
||||||
justify='center'
|
|
||||||
pos={'fixed'}
|
|
||||||
className={stackClasses.fadeAway}
|
className={stackClasses.fadeAway}
|
||||||
classNames={stackClasses}
|
classNames={stackClasses}
|
||||||
data-loaded={loaded}
|
data-loaded={loaded}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Loading;
|
|
||||||
|
|||||||
@@ -15,53 +15,9 @@ export function ThemeProvider({
|
|||||||
'--image-background': `linear-gradient(${theme.backgroundColor}33, ${theme.backgroundColor}33), url(/backgrounds/${theme.backgroundImage})`,
|
'--image-background': `linear-gradient(${theme.backgroundColor}33, ${theme.backgroundColor}33), url(/backgrounds/${theme.backgroundImage})`,
|
||||||
'--toastify-color-light': `hwb(from ${theme.primaryColor} h w b / 0.25)`,
|
'--toastify-color-light': `hwb(from ${theme.primaryColor} h w b / 0.25)`,
|
||||||
'--toastify-color-dark': `hwb(from ${theme.primaryColor} h w b / 0.25)`,
|
'--toastify-color-dark': `hwb(from ${theme.primaryColor} h w b / 0.25)`,
|
||||||
'--toastify-color-info': '#3498db',
|
|
||||||
'--toastify-color-success': '#07bc0c',
|
|
||||||
'--toastify-color-warning': '#f1c40f',
|
|
||||||
'--toastify-color-error': 'hsl(6, 78%, 57%)',
|
|
||||||
'--toastify-color-transparent': 'rgba(255, 255, 255, 0.7)',
|
|
||||||
'--toastify-icon-color-info': 'var(--toastify-color-info)',
|
|
||||||
'--toastify-icon-color-success': 'var(--toastify-color-success)',
|
|
||||||
'--toastify-icon-color-warning': 'var(--toastify-color-warning)',
|
|
||||||
'--toastify-icon-color-error': 'var(--toastify-color-error)',
|
|
||||||
|
|
||||||
'--toastify-container-width': 'fit-content',
|
|
||||||
'--toastify-toast-width': '320px',
|
|
||||||
'--toastify-toast-offset': '16px',
|
|
||||||
'--toastify-toast-top':
|
|
||||||
'max(var(--toastify-toast-offset), env(safe-area-inset-top))',
|
|
||||||
'--toastify-toast-right':
|
|
||||||
'max(var(--toastify-toast-offset), env(safe-area-inset-right))',
|
|
||||||
'--toastify-toast-left':
|
|
||||||
'max(var(--toastify-toast-offset), env(safe-area-inset-left))',
|
|
||||||
'--toastify-toast-bottom':
|
|
||||||
'max(var(--toastify-toast-offset), env(safe-area-inset-bottom))',
|
|
||||||
'--toastify-toast-background': '#fff',
|
|
||||||
'--toastify-toast-padding': '14px',
|
|
||||||
'--toastify-toast-min-height': '64px',
|
|
||||||
'--toastify-toast-max-height': '800px',
|
|
||||||
'--toastify-toast-bd-radius': '6px',
|
|
||||||
'--toastify-toast-shadow': '0px 4px 12px rgba(0, 0, 0, 0.1)',
|
|
||||||
'--toastify-font-family': 'sans-serif',
|
|
||||||
'--toastify-z-index': '9999',
|
|
||||||
'--toastify-text-color-light': theme.primaryColor,
|
'--toastify-text-color-light': theme.primaryColor,
|
||||||
'--toastify-text-color-dark': theme.primaryColor,
|
'--toastify-text-color-dark': theme.primaryColor,
|
||||||
|
|
||||||
/* Used only for colored theme */
|
|
||||||
'--toastify-text-color-info': '#fff',
|
|
||||||
'--toastify-text-color-success': '#fff',
|
|
||||||
'--toastify-text-color-warning': '#fff',
|
|
||||||
'--toastify-text-color-error': '#fff',
|
|
||||||
|
|
||||||
'--toastify-spinner-color': '#616161',
|
|
||||||
'--toastify-spinner-color-empty-area': '#e0e0e0',
|
|
||||||
'--toastify-color-progress-light': theme.accentColor,
|
'--toastify-color-progress-light': theme.accentColor,
|
||||||
'--toastify-color-progress-dark': '#bb86fc',
|
|
||||||
'--toastify-color-progress-info': 'var(--toastify-color-info)',
|
|
||||||
'--toastify-color-progress-success': 'var(--toastify-color-success)',
|
|
||||||
'--toastify-color-progress-warning': 'var(--toastify-color-warning)',
|
|
||||||
'--toastify-color-progress-error': 'var(--toastify-color-error)',
|
|
||||||
/* used to control the opacity of the progress trail */
|
|
||||||
'--toastify-color-progress-bgo': 0.2,
|
'--toastify-color-progress-bgo': 0.2,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import { useSunStateAPI } from 'hooks/useAPI';
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { FaLongArrowAltDown, FaLongArrowAltUp, FaWind } from 'react-icons/fa';
|
import { FaLongArrowAltDown, FaLongArrowAltUp, FaWind } from 'react-icons/fa';
|
||||||
import { WiBarometer, WiHumidity, WiSunrise, WiSunset } from 'react-icons/wi';
|
import { WiBarometer, WiHumidity, WiSunrise, WiSunset } from 'react-icons/wi';
|
||||||
|
import { themeIconClasses } from 'styles';
|
||||||
|
import type { CurrentWeather as CW } from 'types';
|
||||||
import WeatherIcon from './WeatherIcon';
|
import WeatherIcon from './WeatherIcon';
|
||||||
|
|
||||||
export default function CurrentWeather({ current }: any) {
|
export default function CurrentWeather({ current }: { current: CW }) {
|
||||||
const { currentLocation, isMobile } = useCommonHooks();
|
const { currentLocation, isMobile } = useCommonHooks();
|
||||||
const { data: sunStateData } = useSunStateAPI({
|
const { data: sunStateData } = useSunStateAPI({
|
||||||
lat: currentLocation.lat,
|
lat: currentLocation.lat,
|
||||||
@@ -34,19 +36,21 @@ export default function CurrentWeather({ current }: any) {
|
|||||||
{current ? (
|
{current ? (
|
||||||
<Stack
|
<Stack
|
||||||
gap={0}
|
gap={0}
|
||||||
w={'100%'}
|
|
||||||
justify='space-between'
|
justify='space-between'
|
||||||
style={{
|
style={{
|
||||||
|
width: '100%',
|
||||||
backgroundColor: 'var(--color-search-background)',
|
backgroundColor: 'var(--color-search-background)',
|
||||||
padding: '1rem',
|
padding: '1rem',
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
paddingBottom: '.5rem',
|
paddingBottom: '.5rem',
|
||||||
}}
|
}}
|
||||||
c={'var(--color-text-pri)'}
|
|
||||||
>
|
>
|
||||||
<Group gap={0} px={16} w={'100%'} justify='space-between'>
|
<Group
|
||||||
|
gap={0}
|
||||||
|
justify='space-between'
|
||||||
|
style={{ width: '100%', paddingLeft: 16 }}
|
||||||
|
>
|
||||||
<Text
|
<Text
|
||||||
c={'var(--color-text-pri)'}
|
|
||||||
style={{
|
style={{
|
||||||
fontSize: '1.375rem',
|
fontSize: '1.375rem',
|
||||||
textAlign: 'right',
|
textAlign: 'right',
|
||||||
@@ -55,7 +59,7 @@ export default function CurrentWeather({ current }: any) {
|
|||||||
Current Weather
|
Current Weather
|
||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
<Group gap={8} w={'100%'} justify='space-between'>
|
<Group gap={8} justify='space-between'>
|
||||||
<Stack gap={0} w={isMobile ? '40%' : '45%'}>
|
<Stack gap={0} w={isMobile ? '40%' : '45%'}>
|
||||||
<Group gap={0} justify='flex-end'>
|
<Group gap={0} justify='flex-end'>
|
||||||
<WeatherIcon
|
<WeatherIcon
|
||||||
@@ -78,7 +82,6 @@ export default function CurrentWeather({ current }: any) {
|
|||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
<Text
|
<Text
|
||||||
c={'var(--color-text-pri)'}
|
|
||||||
style={{
|
style={{
|
||||||
fontSize: '1.375rem',
|
fontSize: '1.375rem',
|
||||||
textAlign: 'right',
|
textAlign: 'right',
|
||||||
@@ -97,10 +100,8 @@ export default function CurrentWeather({ current }: any) {
|
|||||||
<Grid align='center'>
|
<Grid align='center'>
|
||||||
<Grid.Col span={1}>
|
<Grid.Col span={1}>
|
||||||
<ThemeIcon
|
<ThemeIcon
|
||||||
h={'auto'}
|
className={themeIconClasses.weatherIcon}
|
||||||
w={'auto'}
|
classNames={themeIconClasses}
|
||||||
variant='subtle'
|
|
||||||
c={'var(--color-text-pri)'}
|
|
||||||
>
|
>
|
||||||
<FaLongArrowAltUp size={32} />
|
<FaLongArrowAltUp size={32} />
|
||||||
</ThemeIcon>
|
</ThemeIcon>
|
||||||
@@ -117,10 +118,8 @@ export default function CurrentWeather({ current }: any) {
|
|||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
<Grid.Col span={1}>
|
<Grid.Col span={1}>
|
||||||
<ThemeIcon
|
<ThemeIcon
|
||||||
h={'auto'}
|
className={themeIconClasses.weatherIcon}
|
||||||
w={'auto'}
|
classNames={themeIconClasses}
|
||||||
variant='subtle'
|
|
||||||
c={'var(--color-text-pri)'}
|
|
||||||
>
|
>
|
||||||
<FaLongArrowAltDown size={32} />
|
<FaLongArrowAltDown size={32} />
|
||||||
</ThemeIcon>
|
</ThemeIcon>
|
||||||
@@ -139,10 +138,8 @@ export default function CurrentWeather({ current }: any) {
|
|||||||
<Grid align='center'>
|
<Grid align='center'>
|
||||||
<Grid.Col span={1}>
|
<Grid.Col span={1}>
|
||||||
<ThemeIcon
|
<ThemeIcon
|
||||||
h={'auto'}
|
className={themeIconClasses.weatherIcon}
|
||||||
w={'auto'}
|
classNames={themeIconClasses}
|
||||||
variant='subtle'
|
|
||||||
c={'var(--color-text-pri)'}
|
|
||||||
>
|
>
|
||||||
<WiSunrise size={32} />
|
<WiSunrise size={32} />
|
||||||
</ThemeIcon>
|
</ThemeIcon>
|
||||||
@@ -157,10 +154,8 @@ export default function CurrentWeather({ current }: any) {
|
|||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
<Grid.Col span={1}>
|
<Grid.Col span={1}>
|
||||||
<ThemeIcon
|
<ThemeIcon
|
||||||
h={'auto'}
|
className={themeIconClasses.weatherIcon}
|
||||||
w={'auto'}
|
classNames={themeIconClasses}
|
||||||
variant='subtle'
|
|
||||||
c={'var(--color-text-pri)'}
|
|
||||||
>
|
>
|
||||||
<WiSunset size={32} />
|
<WiSunset size={32} />
|
||||||
</ThemeIcon>
|
</ThemeIcon>
|
||||||
@@ -177,10 +172,8 @@ export default function CurrentWeather({ current }: any) {
|
|||||||
<Grid align='center'>
|
<Grid align='center'>
|
||||||
<Grid.Col span={1}>
|
<Grid.Col span={1}>
|
||||||
<ThemeIcon
|
<ThemeIcon
|
||||||
h={'auto'}
|
className={themeIconClasses.weatherIcon}
|
||||||
w={'auto'}
|
classNames={themeIconClasses}
|
||||||
variant='subtle'
|
|
||||||
c={'var(--color-text-pri)'}
|
|
||||||
>
|
>
|
||||||
<WiHumidity size={32} />
|
<WiHumidity size={32} />
|
||||||
</ThemeIcon>
|
</ThemeIcon>
|
||||||
@@ -205,10 +198,8 @@ export default function CurrentWeather({ current }: any) {
|
|||||||
<Grid align='center'>
|
<Grid align='center'>
|
||||||
<Grid.Col span={1}>
|
<Grid.Col span={1}>
|
||||||
<ThemeIcon
|
<ThemeIcon
|
||||||
h={'auto'}
|
className={themeIconClasses.weatherIcon}
|
||||||
w={'auto'}
|
classNames={themeIconClasses}
|
||||||
variant='subtle'
|
|
||||||
c={'var(--color-text-pri)'}
|
|
||||||
>
|
>
|
||||||
<FaWind size={32} />
|
<FaWind size={32} />
|
||||||
</ThemeIcon>
|
</ThemeIcon>
|
||||||
@@ -233,10 +224,8 @@ export default function CurrentWeather({ current }: any) {
|
|||||||
<Grid align='center'>
|
<Grid align='center'>
|
||||||
<Grid.Col span={1}>
|
<Grid.Col span={1}>
|
||||||
<ThemeIcon
|
<ThemeIcon
|
||||||
h={'auto'}
|
className={themeIconClasses.weatherIcon}
|
||||||
w={'auto'}
|
classNames={themeIconClasses}
|
||||||
variant='subtle'
|
|
||||||
c={'var(--color-text-pri)'}
|
|
||||||
>
|
>
|
||||||
<WiBarometer size={32} />
|
<WiBarometer size={32} />
|
||||||
</ThemeIcon>
|
</ThemeIcon>
|
||||||
|
|||||||
@@ -19,9 +19,8 @@ export default function ExtendedForecast({ forecast }: any) {
|
|||||||
paddingBottom: '.5rem',
|
paddingBottom: '.5rem',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Group gap={0} px={16} mb={8} w={'100%'}>
|
<Group gap={0} style={{ width: '100%', marginBottom: '8px', paddingLeft: '16px' }}>
|
||||||
<Text
|
<Text
|
||||||
c={'var(--color-text-pri)'}
|
|
||||||
style={{
|
style={{
|
||||||
fontSize: '1.375rem',
|
fontSize: '1.375rem',
|
||||||
textAlign: 'left',
|
textAlign: 'left',
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Stack, Text } from '@mantine/core';
|
import { Stack, Text } from '@mantine/core';
|
||||||
import { useCommonHooks } from 'hooks';
|
|
||||||
import {
|
import {
|
||||||
Area,
|
Area,
|
||||||
CartesianGrid,
|
CartesianGrid,
|
||||||
@@ -13,8 +12,6 @@ import {
|
|||||||
} from 'recharts';
|
} from 'recharts';
|
||||||
|
|
||||||
export default function WeatherGraphs({ hourlyForecast }: any) {
|
export default function WeatherGraphs({ hourlyForecast }: any) {
|
||||||
const { theme } = useCommonHooks();
|
|
||||||
|
|
||||||
function CustomTooltip({ payload, active }: any) {
|
function CustomTooltip({ payload, active }: any) {
|
||||||
if (active) {
|
if (active) {
|
||||||
return (
|
return (
|
||||||
@@ -50,7 +47,7 @@ export default function WeatherGraphs({ hourlyForecast }: any) {
|
|||||||
<ComposedChart data={hourlyForecast}>
|
<ComposedChart data={hourlyForecast}>
|
||||||
<XAxis
|
<XAxis
|
||||||
type='category'
|
type='category'
|
||||||
stroke={theme.primaryColor}
|
stroke={'var(--color-text-pri)'}
|
||||||
dataKey={(data: any) => {
|
dataKey={(data: any) => {
|
||||||
return new Date(data.startTime).toLocaleTimeString('en-US', {
|
return new Date(data.startTime).toLocaleTimeString('en-US', {
|
||||||
hour: 'numeric',
|
hour: 'numeric',
|
||||||
@@ -59,7 +56,7 @@ export default function WeatherGraphs({ hourlyForecast }: any) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<YAxis
|
<YAxis
|
||||||
stroke={theme.primaryColor}
|
stroke={'var(--color-text-pri)'}
|
||||||
unit={'°F'}
|
unit={'°F'}
|
||||||
domain={['dataMin', 'dataMax']}
|
domain={['dataMin', 'dataMax']}
|
||||||
/>
|
/>
|
||||||
@@ -70,8 +67,8 @@ export default function WeatherGraphs({ hourlyForecast }: any) {
|
|||||||
type='monotone'
|
type='monotone'
|
||||||
name='Temperature'
|
name='Temperature'
|
||||||
dataKey='temperature'
|
dataKey='temperature'
|
||||||
stroke={theme.primaryColor}
|
stroke={'var(--color-text-pri)'}
|
||||||
dot={{ stroke: theme.primaryColor, strokeWidth: 1 }}
|
dot={{ stroke: 'var(--color-text-pri)', strokeWidth: 1 }}
|
||||||
/>
|
/>
|
||||||
<Line
|
<Line
|
||||||
unit={'°F'}
|
unit={'°F'}
|
||||||
@@ -80,8 +77,8 @@ export default function WeatherGraphs({ hourlyForecast }: any) {
|
|||||||
dataKey={(data: any) => {
|
dataKey={(data: any) => {
|
||||||
return (data.dewpoint.value * 9) / 5 + 32;
|
return (data.dewpoint.value * 9) / 5 + 32;
|
||||||
}}
|
}}
|
||||||
stroke={theme.accentColor}
|
stroke={'var(--color-text-acc)'}
|
||||||
dot={{ stroke: theme.primaryColor, strokeWidth: 1 }}
|
dot={{ stroke: 'var(--color-text-pri)', strokeWidth: 1 }}
|
||||||
/>
|
/>
|
||||||
<Legend style={{ background: 'var(--color-search-background)' }} />
|
<Legend style={{ background: 'var(--color-search-background)' }} />
|
||||||
</ComposedChart>
|
</ComposedChart>
|
||||||
@@ -90,7 +87,7 @@ export default function WeatherGraphs({ hourlyForecast }: any) {
|
|||||||
<ComposedChart data={hourlyForecast}>
|
<ComposedChart data={hourlyForecast}>
|
||||||
<XAxis
|
<XAxis
|
||||||
type='category'
|
type='category'
|
||||||
stroke={theme.primaryColor}
|
stroke={'var(--color-text-pri)'}
|
||||||
dataKey={(data: any) => {
|
dataKey={(data: any) => {
|
||||||
return new Date(data.startTime).toLocaleTimeString('en-US', {
|
return new Date(data.startTime).toLocaleTimeString('en-US', {
|
||||||
hour: 'numeric',
|
hour: 'numeric',
|
||||||
@@ -98,7 +95,7 @@ export default function WeatherGraphs({ hourlyForecast }: any) {
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<YAxis stroke={theme.primaryColor} unit={'%'} domain={[0, 100]} />
|
<YAxis stroke={'var(--color-text-pri)'} unit={'%'} domain={[0, 100]} />
|
||||||
<CartesianGrid stroke='#f5f5f522' />
|
<CartesianGrid stroke='#f5f5f522' />
|
||||||
<Tooltip content={<CustomTooltip />} />
|
<Tooltip content={<CustomTooltip />} />
|
||||||
<Area
|
<Area
|
||||||
@@ -108,9 +105,9 @@ export default function WeatherGraphs({ hourlyForecast }: any) {
|
|||||||
dataKey={(data: any) => {
|
dataKey={(data: any) => {
|
||||||
return data.probabilityOfPrecipitation.value;
|
return data.probabilityOfPrecipitation.value;
|
||||||
}}
|
}}
|
||||||
stroke={theme.primaryColor}
|
stroke={'var(--color-text-pri)'}
|
||||||
fill={theme.primaryColor}
|
fill={'var(--color-text-pri)'}
|
||||||
dot={{ stroke: theme.primaryColor, strokeWidth: 1 }}
|
dot={{ stroke: 'var(--color-text-pri)', strokeWidth: 1 }}
|
||||||
/>
|
/>
|
||||||
<Area
|
<Area
|
||||||
unit={'%'}
|
unit={'%'}
|
||||||
@@ -119,9 +116,9 @@ export default function WeatherGraphs({ hourlyForecast }: any) {
|
|||||||
dataKey={(data: any) => {
|
dataKey={(data: any) => {
|
||||||
return data.relativeHumidity.value;
|
return data.relativeHumidity.value;
|
||||||
}}
|
}}
|
||||||
stroke={theme.accentColor}
|
stroke={'var(--color-text-acc)'}
|
||||||
fill={theme.accentColor}
|
fill={'var(--color-text-acc)'}
|
||||||
dot={{ stroke: theme.primaryColor, strokeWidth: 1 }}
|
dot={{ stroke: 'var(--color-text-pri)', strokeWidth: 1 }}
|
||||||
/>
|
/>
|
||||||
<Legend style={{ background: 'var(--color-search-background)' }} />
|
<Legend style={{ background: 'var(--color-search-background)' }} />
|
||||||
</ComposedChart>
|
</ComposedChart>
|
||||||
|
|||||||
@@ -4,20 +4,29 @@ import { modalClasses } from 'styles';
|
|||||||
import { useCommonHooks, useWeatherAPI } from 'hooks';
|
import { useCommonHooks, useWeatherAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import type { CurrentWeather as CW, ExtendedForecast as EF } from 'types';
|
||||||
import CurrentWeather from './CurrentWeather';
|
import CurrentWeather from './CurrentWeather';
|
||||||
import ExtendedForecast from './ExtendedForecast';
|
import ExtendedForecast from './ExtendedForecast';
|
||||||
import WeatherGraphs from './WeatherGraphs';
|
import WeatherGraphs from './WeatherGraphs';
|
||||||
|
|
||||||
export function WeatherModal({
|
export function WeatherModal({
|
||||||
|
current,
|
||||||
|
extendedForecast,
|
||||||
|
weatherModalOpened,
|
||||||
setSearchValue,
|
setSearchValue,
|
||||||
setProviderLabel,
|
setProviderLabel,
|
||||||
setProviderURL,
|
setProviderURL,
|
||||||
current,
|
|
||||||
extendedForecast,
|
|
||||||
closeWeatherModal,
|
closeWeatherModal,
|
||||||
weatherModalOpened,
|
}: {
|
||||||
}: any) {
|
current: CW;
|
||||||
const { theme, isMobile, currentUser, currentLocation } = useCommonHooks();
|
extendedForecast: EF[];
|
||||||
|
weatherModalOpened: boolean;
|
||||||
|
setSearchValue: (value: string) => void;
|
||||||
|
setProviderLabel: (label: string) => void;
|
||||||
|
setProviderURL: (url: string) => void;
|
||||||
|
closeWeatherModal: () => void;
|
||||||
|
}) {
|
||||||
|
const { isMobile, currentUser, currentLocation, modalStyle } = useCommonHooks();
|
||||||
const { data: hourly } = useWeatherAPI({
|
const { data: hourly } = useWeatherAPI({
|
||||||
endpoint: 'hourly',
|
endpoint: 'hourly',
|
||||||
office: currentLocation.office,
|
office: currentLocation.office,
|
||||||
@@ -46,14 +55,7 @@ export function WeatherModal({
|
|||||||
setProviderURL('https://www.google.com/search?q=');
|
setProviderURL('https://www.google.com/search?q=');
|
||||||
closeWeatherModal();
|
closeWeatherModal();
|
||||||
}}
|
}}
|
||||||
style={{
|
style={modalStyle}
|
||||||
'--color-text-pri': theme.primaryColor,
|
|
||||||
'--color-text-acc': theme.accentColor,
|
|
||||||
'--color-background': theme.backgroundColor,
|
|
||||||
'--color-border': theme.borderColor,
|
|
||||||
'--color-search-background': theme.searchColor,
|
|
||||||
'--image-background': `url(${theme.backgroundImage})`,
|
|
||||||
}}
|
|
||||||
closeOnEscape
|
closeOnEscape
|
||||||
closeOnClickOutside
|
closeOnClickOutside
|
||||||
>
|
>
|
||||||
@@ -61,7 +63,7 @@ export function WeatherModal({
|
|||||||
<Modal.Content>
|
<Modal.Content>
|
||||||
<Modal.Header>
|
<Modal.Header>
|
||||||
<Modal.Title>
|
<Modal.Title>
|
||||||
<Group gap={8} style={{ borderBottom: `1px solid ${theme.borderColor}` }}>
|
<Group gap={8} style={{ borderBottom: '1px solid var(--color-border)' }}>
|
||||||
<Text fz={18} fw={200}>
|
<Text fz={18} fw={200}>
|
||||||
Weather Forecast for{' '}
|
Weather Forecast for{' '}
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ export { HelpModal } from './HelpModal/HelpModal';
|
|||||||
export { WeatherModal } from './WeatherModal/WeatherModal';
|
export { WeatherModal } from './WeatherModal/WeatherModal';
|
||||||
export { ThemeProvider } from './ThemeProvider';
|
export { ThemeProvider } from './ThemeProvider';
|
||||||
export { MainLayout } from './MainLayout';
|
export { MainLayout } from './MainLayout';
|
||||||
|
export { Loading } from './Loading';
|
||||||
|
|||||||
@@ -1,22 +1,29 @@
|
|||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
import { useCallback, useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { Flip, toast } from 'react-toastify';
|
import { Flip, toast } from 'react-toastify';
|
||||||
|
|
||||||
const url = `${import.meta.env.PROD ? import.meta.env.VITE_DOMAIN_PROD : import.meta.env.VITE_DOMAIN_DEV}/${import.meta.env.VITE_BASE_URL}`;
|
const url = `${import.meta.env.PROD ? import.meta.env.VITE_DOMAIN_PROD : import.meta.env.VITE_DOMAIN_DEV}/${import.meta.env.VITE_BASE_URL}`;
|
||||||
|
const headers = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
'Access-Control-Allow-Headers': '*',
|
||||||
|
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
|
||||||
|
'Access-Control-Allow-Credentials': true,
|
||||||
|
'Sec-Fetch-Mode': 'no-cors',
|
||||||
|
'Sec-Fetch-Site': 'same-site',
|
||||||
|
};
|
||||||
|
const callEndpoint = async (url: string) => {
|
||||||
|
const response = await fetch(url);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
return await response.json();
|
||||||
|
};
|
||||||
export function useQueryAPI({ endpoint }: { endpoint: string }) {
|
export function useQueryAPI({ endpoint }: { endpoint: string }) {
|
||||||
const callEndpoint = async (endpoint: string) => {
|
const callEndpoint = async (endpoint: string) => {
|
||||||
const options: object = {
|
const options: object = {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: headers,
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Access-Control-Allow-Origin': '*',
|
|
||||||
'Access-Control-Allow-Headers': '*',
|
|
||||||
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
|
|
||||||
'Access-Control-Allow-Credentials': true,
|
|
||||||
'Sec-Fetch-Mode': 'no-cors',
|
|
||||||
'Sec-Fetch-Site': 'same-site',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetch(`${url}/${endpoint}`, options);
|
const response = await fetch(`${url}/${endpoint}`, options);
|
||||||
@@ -44,15 +51,7 @@ export function useMutationAPI() {
|
|||||||
) => {
|
) => {
|
||||||
const options: any = {
|
const options: any = {
|
||||||
method: method,
|
method: method,
|
||||||
headers: {
|
headers: headers,
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Access-Control-Allow-Origin': '*',
|
|
||||||
'Access-Control-Allow-Headers': '*',
|
|
||||||
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
|
|
||||||
'Access-Control-Allow-Credentials': true,
|
|
||||||
'Sec-Fetch-Mode': 'no-cors',
|
|
||||||
'Sec-Fetch-Site': 'same-site',
|
|
||||||
},
|
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
};
|
};
|
||||||
notify();
|
notify();
|
||||||
@@ -124,7 +123,7 @@ export function useMutationAPI() {
|
|||||||
endpoint: string;
|
endpoint: string;
|
||||||
body: object | undefined | null;
|
body: object | undefined | null;
|
||||||
}) => callEndpoint(method, endpoint, body),
|
}) => callEndpoint(method, endpoint, body),
|
||||||
onMutate: ({ method, endpoint }) => {
|
onMutate: ({ endpoint }) => {
|
||||||
queryClient.refetchQueries({
|
queryClient.refetchQueries({
|
||||||
queryKey: ['GET', endpoint],
|
queryKey: ['GET', endpoint],
|
||||||
});
|
});
|
||||||
@@ -135,7 +134,7 @@ export function useMutationAPI() {
|
|||||||
endpoint === 'api/applicationOrder' &&
|
endpoint === 'api/applicationOrder' &&
|
||||||
queryClient.refetchQueries({ queryKey: ['GET', 'api/applicationOrder'] });
|
queryClient.refetchQueries({ queryKey: ['GET', 'api/applicationOrder'] });
|
||||||
},
|
},
|
||||||
onSuccess: (data, { method, endpoint }) => {
|
onSuccess: (_, { endpoint }) => {
|
||||||
queryClient.refetchQueries({
|
queryClient.refetchQueries({
|
||||||
queryKey: ['GET', endpoint],
|
queryKey: ['GET', endpoint],
|
||||||
});
|
});
|
||||||
@@ -180,17 +179,10 @@ export function useWeatherAPI({
|
|||||||
} else if (endpoint === 'stations') {
|
} else if (endpoint === 'stations') {
|
||||||
url = `https://api.weather.gov/gridpoints/${office}/${x},${y}/stations`;
|
url = `https://api.weather.gov/gridpoints/${office}/${x},${y}/stations`;
|
||||||
}
|
}
|
||||||
const callEndpoint = async () => {
|
|
||||||
const response = await fetch(url);
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`${response.status} ${response.statusText}`);
|
|
||||||
}
|
|
||||||
return await response.json();
|
|
||||||
};
|
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ['GET', url],
|
queryKey: ['GET', url],
|
||||||
queryFn: () => callEndpoint(),
|
queryFn: () => callEndpoint(url),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,16 +192,10 @@ export function useSunStateAPI({ lat, lon }: { lat: number; lon: number }) {
|
|||||||
date.setDate(date.getDate() + 1);
|
date.setDate(date.getDate() + 1);
|
||||||
const tomorrow = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
|
const tomorrow = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
|
||||||
const url = `https://api.sunrisesunset.io/json?lat=${lat}&lng=${lon}&date_start=${today}&date_end=${tomorrow}`;
|
const url = `https://api.sunrisesunset.io/json?lat=${lat}&lng=${lon}&date_start=${today}&date_end=${tomorrow}`;
|
||||||
const callEndpoint = async () => {
|
|
||||||
const response = await fetch(url);
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`${response.status} ${response.statusText}`);
|
|
||||||
}
|
|
||||||
return await response.json();
|
|
||||||
};
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ['GET', url],
|
queryKey: ['GET', url],
|
||||||
queryFn: () => callEndpoint(),
|
queryFn: () => callEndpoint(url),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,15 +224,7 @@ export function useFileUploadAPI() {
|
|||||||
) => {
|
) => {
|
||||||
const options = {
|
const options = {
|
||||||
method: method,
|
method: method,
|
||||||
headers: {
|
headers: headers,
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Access-Control-Allow-Origin': '*',
|
|
||||||
'Access-Control-Allow-Headers': '*',
|
|
||||||
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
|
|
||||||
'Access-Control-Allow-Credentials': true,
|
|
||||||
'Sec-Fetch-Mode': 'no-cors',
|
|
||||||
'Sec-Fetch-Site': 'same-site',
|
|
||||||
},
|
|
||||||
body: body ?? undefined,
|
body: body ?? undefined,
|
||||||
};
|
};
|
||||||
const response = await fetch(url, options as unknown as Body);
|
const response = await fetch(url, options as unknown as Body);
|
||||||
@@ -300,115 +278,3 @@ export function useFileUploadAPI() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useFetchAllRecordsAPI({ endpoint }: { endpoint: string }) {
|
|
||||||
const pageSize = 500;
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
|
|
||||||
const fetchPage = async (page: number, retryCount = 0): Promise<any> => {
|
|
||||||
// Start building the URL
|
|
||||||
const urlObject = new URL(`${url}/${endpoint}`);
|
|
||||||
|
|
||||||
// Check and append custom query parameters from the endpoint
|
|
||||||
const customParams = new URLSearchParams(endpoint.split('?')[1]);
|
|
||||||
for (const [key, value] of customParams) {
|
|
||||||
if (!urlObject.searchParams.has(key)) {
|
|
||||||
urlObject.searchParams.append(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add 'page' and 'size' parameters
|
|
||||||
urlObject.searchParams.set('page', page.toString()); // Use 'set' to ensure uniqueness
|
|
||||||
urlObject.searchParams.set('size', pageSize.toString());
|
|
||||||
|
|
||||||
const options: any = {
|
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Access-Control-Allow-Origin': '*',
|
|
||||||
'Access-Control-Allow-Headers': '*',
|
|
||||||
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
|
|
||||||
'Access-Control-Allow-Credentials': true,
|
|
||||||
'Sec-Fetch-Mode': 'no-cors',
|
|
||||||
'Sec-Fetch-Site': 'same-site',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch(url.toString(), options);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
// If the response is not ok and status is 401 (not authorized), reload the page
|
|
||||||
if (response.status === 401) {
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
throw new Error(
|
|
||||||
`Error fetching page ${page}: ${response.status} ${response.statusText}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
} catch (err) {
|
|
||||||
if (retryCount < 3) {
|
|
||||||
// Retry up to 3 times with a random delay
|
|
||||||
const delay = Math.floor(Math.random() * 3000) + 1000; // Random delay between 1 to 3 seconds
|
|
||||||
console.error(
|
|
||||||
`Retrying page ${page}, attempt ${retryCount + 1} after ${delay} ms`,
|
|
||||||
);
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
||||||
return fetchPage(page, retryCount + 1);
|
|
||||||
}
|
|
||||||
console.error(`Error fetching page ${page} after 3 retries:`, err);
|
|
||||||
throw err; // Re-throw the error to handle it in the calling function
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const callEndpoint = async () => {
|
|
||||||
try {
|
|
||||||
// Fetch the first page to get the total number of items and pages
|
|
||||||
const firstPageData = await fetchPage(1);
|
|
||||||
// If the first page doesn't have a 'pages' property, return the data as-is
|
|
||||||
if (firstPageData?.pages === undefined) {
|
|
||||||
return firstPageData;
|
|
||||||
}
|
|
||||||
if (firstPageData?.pages === 1) {
|
|
||||||
return firstPageData.items;
|
|
||||||
}
|
|
||||||
|
|
||||||
let totalPages = firstPageData.pages;
|
|
||||||
const allItems = [...firstPageData.items];
|
|
||||||
// Fetch each page sequentially
|
|
||||||
for (let page = 2; page <= totalPages; page++) {
|
|
||||||
try {
|
|
||||||
const pageData = await fetchPage(page);
|
|
||||||
allItems.push(...pageData.items);
|
|
||||||
|
|
||||||
// Check and update the totalPages if it has increased
|
|
||||||
if (pageData.pages > totalPages) {
|
|
||||||
totalPages = pageData.pages;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(`Final error fetching page ${page}:`, err);
|
|
||||||
// Continue to the next page even if the current page fails
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return allItems;
|
|
||||||
} catch (error) {
|
|
||||||
// Handling errors in fetching the first page
|
|
||||||
console.error('Error fetching the first page:', error);
|
|
||||||
return []; // Return empty array on error
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const invalidate = useCallback(() => {
|
|
||||||
queryClient.invalidateQueries({ queryKey: ['GET', endpoint] });
|
|
||||||
}, [queryClient, endpoint]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
...useQuery({
|
|
||||||
queryKey: ['GET', endpoint],
|
|
||||||
queryFn: callEndpoint,
|
|
||||||
}),
|
|
||||||
invalidate,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ export function useCommonHooks() {
|
|||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const isMobile = window.matchMedia('(max-width: 600px)').matches;
|
const isMobile = window.matchMedia('(max-width: 600px)').matches;
|
||||||
const [theme, setTheme] = useAtom(appTheme);
|
const [theme, setTheme] = useAtom(appTheme);
|
||||||
const [themeName, setThemeName] = useLocalStorage<any>({
|
const [themeName, setThemeName] = useLocalStorage<string>({
|
||||||
key: 'theme',
|
key: 'theme',
|
||||||
defaultValue: 'blackboard',
|
defaultValue: 'blackboard',
|
||||||
});
|
});
|
||||||
const [appFilter, setAppFilter] = useLocalStorage<[any]>({
|
const [appFilter, setAppFilter] = useLocalStorage<[string]>({
|
||||||
key: 'appFilter',
|
key: 'appFilter',
|
||||||
defaultValue: ['All'],
|
defaultValue: ['All'],
|
||||||
});
|
});
|
||||||
@@ -24,16 +24,16 @@ export function useCommonHooks() {
|
|||||||
key: 'bookmarkSort',
|
key: 'bookmarkSort',
|
||||||
defaultValue: 'A-Z',
|
defaultValue: 'A-Z',
|
||||||
});
|
});
|
||||||
const [bookmarkFilter, setBookmarkFilter] = useLocalStorage<[any]>({
|
const [bookmarkFilter, setBookmarkFilter] = useLocalStorage<[string]>({
|
||||||
key: 'bookmarkFilter',
|
key: 'bookmarkFilter',
|
||||||
defaultValue: ['All'],
|
defaultValue: ['All'],
|
||||||
});
|
});
|
||||||
const [currentTheme, setCurrentTheme] = useLocalStorage<any>({
|
const [currentTheme, setCurrentTheme] = useLocalStorage<string>({
|
||||||
key: 'theme',
|
key: 'theme',
|
||||||
defaultValue: 'blackboard',
|
defaultValue: 'blackboard',
|
||||||
});
|
});
|
||||||
|
|
||||||
const [currentThemePlaylist, setCurrentThemePlaylist] = useLocalStorage<any>({
|
const [currentThemePlaylist, setCurrentThemePlaylist] = useLocalStorage<string>({
|
||||||
key: 'themePlaylist',
|
key: 'themePlaylist',
|
||||||
defaultValue: 'All',
|
defaultValue: 'All',
|
||||||
});
|
});
|
||||||
@@ -80,6 +80,13 @@ export function useCommonHooks() {
|
|||||||
'i',
|
'i',
|
||||||
); // fragment locator
|
); // fragment locator
|
||||||
|
|
||||||
|
const reorder = (list: any, startIndex: any, endIndex: any) => {
|
||||||
|
const result = Array.from(list);
|
||||||
|
const [removed]: any = result.splice(startIndex, 1);
|
||||||
|
result.splice(endIndex, 0, removed);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
const handleThemeChange = (themes: any, save: any) => {
|
const handleThemeChange = (themes: any, save: any) => {
|
||||||
const enabled = themes
|
const enabled = themes
|
||||||
.filter((t: any) => t.randomEnabled)
|
.filter((t: any) => t.randomEnabled)
|
||||||
@@ -116,6 +123,7 @@ export function useCommonHooks() {
|
|||||||
modalStyle,
|
modalStyle,
|
||||||
urlPattern,
|
urlPattern,
|
||||||
fixDigits,
|
fixDigits,
|
||||||
|
reorder,
|
||||||
handleThemeChange,
|
handleThemeChange,
|
||||||
handleDelete,
|
handleDelete,
|
||||||
themeName,
|
themeName,
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import type {
|
|||||||
CurrentWeather as CW,
|
CurrentWeather as CW,
|
||||||
ExtendedForecast as EF,
|
ExtendedForecast as EF,
|
||||||
Message,
|
Message,
|
||||||
OutlookWeather,
|
|
||||||
PersonalData,
|
PersonalData,
|
||||||
} from 'types';
|
} from 'types';
|
||||||
import Applications from './components/Applications/Applications';
|
import Applications from './components/Applications/Applications';
|
||||||
@@ -85,31 +84,31 @@ export function Homepage() {
|
|||||||
const { data: weatherMetadata } = useOSMAPI({ address: personal?.[0].physicalAddress });
|
const { data: weatherMetadata } = useOSMAPI({ address: personal?.[0].physicalAddress });
|
||||||
const { data: points } = useWeatherAPI({
|
const { data: points } = useWeatherAPI({
|
||||||
endpoint: 'points',
|
endpoint: 'points',
|
||||||
lat: weatherMetadata?.[0].lat || currentLocation.lat,
|
lat: weatherMetadata?.[0].lat ?? currentLocation.lat,
|
||||||
lon: weatherMetadata?.[0].lon || currentLocation.lon,
|
lon: weatherMetadata?.[0].lon ?? currentLocation.lon,
|
||||||
});
|
});
|
||||||
const { data: basicWeather } = useWeatherAPI({
|
const { data: basicWeather } = useWeatherAPI({
|
||||||
endpoint: 'baseline',
|
endpoint: 'baseline',
|
||||||
office: points?.properties.gridId || currentLocation.office,
|
office: points?.properties.gridId ?? currentLocation.office,
|
||||||
x: points?.properties.gridX || currentLocation.x,
|
x: points?.properties.gridX ?? currentLocation.x,
|
||||||
y: points?.properties.gridY || currentLocation.y,
|
y: points?.properties.gridY ?? currentLocation.y,
|
||||||
});
|
});
|
||||||
const { data: stations } = useWeatherAPI({
|
const { data: stations } = useWeatherAPI({
|
||||||
endpoint: 'stations',
|
endpoint: 'stations',
|
||||||
office: points?.properties.gridId || currentLocation.office,
|
office: points?.properties.gridId ?? currentLocation.office,
|
||||||
x: points?.properties.gridX || currentLocation.x,
|
x: points?.properties.gridX ?? currentLocation.x,
|
||||||
y: points?.properties.gridY || currentLocation.y,
|
y: points?.properties.gridY ?? currentLocation.y,
|
||||||
});
|
});
|
||||||
const { data: weather } = useWeatherAPI({
|
const { data: weather } = useWeatherAPI({
|
||||||
endpoint: 'current',
|
endpoint: 'current',
|
||||||
station:
|
station:
|
||||||
stations?.features[0].properties.stationIdentifier || currentLocation.station,
|
stations?.features[0].properties.stationIdentifier ?? currentLocation.station,
|
||||||
});
|
});
|
||||||
const { data: forecast } = useWeatherAPI({
|
const { data: forecast } = useWeatherAPI({
|
||||||
endpoint: 'forecast',
|
endpoint: 'forecast',
|
||||||
office: points?.properties.gridId || currentLocation.office,
|
office: points?.properties.gridId ?? currentLocation.office,
|
||||||
x: points?.properties.gridX || currentLocation.x,
|
x: points?.properties.gridX ?? currentLocation.x,
|
||||||
y: points?.properties.gridY || currentLocation.y,
|
y: points?.properties.gridY ?? currentLocation.y,
|
||||||
});
|
});
|
||||||
const [current, setCurrent] = useState<CW>({
|
const [current, setCurrent] = useState<CW>({
|
||||||
icon: '',
|
icon: '',
|
||||||
@@ -125,17 +124,7 @@ export function Homepage() {
|
|||||||
windDirection: 0,
|
windDirection: 0,
|
||||||
pressure: 0,
|
pressure: 0,
|
||||||
});
|
});
|
||||||
const [outlook, setOutlook] = useState<OutlookWeather[]>([
|
|
||||||
{
|
|
||||||
name: '',
|
|
||||||
icon: '',
|
|
||||||
isDayTime: true,
|
|
||||||
temperature: 0,
|
|
||||||
precipitation: 0,
|
|
||||||
windSpeed: '0 mph',
|
|
||||||
windDirection: 'N',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
const [extendedForecast, setExtendedForecast] = useState<EF[]>([
|
const [extendedForecast, setExtendedForecast] = useState<EF[]>([
|
||||||
{
|
{
|
||||||
detailedForecast: '',
|
detailedForecast: '',
|
||||||
@@ -150,7 +139,7 @@ export function Homepage() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (weather !== undefined && basicWeather !== undefined) {
|
if (weather !== undefined && basicWeather !== undefined) {
|
||||||
setCurrent({
|
setCurrent({
|
||||||
icon: weather.features[0]?.properties.icon?.replace('medium', 'large') || '',
|
icon: weather.features[0]?.properties.icon?.replace('medium', 'large') ?? '',
|
||||||
textDescription: weather.features[0]?.properties.textDescription,
|
textDescription: weather.features[0]?.properties.textDescription,
|
||||||
temperature: Math.round(
|
temperature: Math.round(
|
||||||
(weather.features[0]?.properties.temperature.value * 9) / 5 + 32,
|
(weather.features[0]?.properties.temperature.value * 9) / 5 + 32,
|
||||||
@@ -162,7 +151,7 @@ export function Homepage() {
|
|||||||
(basicWeather.properties.minTemperature.values[0].value * 9) / 5 + 32,
|
(basicWeather.properties.minTemperature.values[0].value * 9) / 5 + 32,
|
||||||
),
|
),
|
||||||
precipitation:
|
precipitation:
|
||||||
weather.features[0]?.properties.precipitationLastHour.value || 'N/A',
|
weather.features[0]?.properties.precipitationLastHour.value ?? 'N/A',
|
||||||
humidity: Math.round(weather.features[0]?.properties.relativeHumidity.value),
|
humidity: Math.round(weather.features[0]?.properties.relativeHumidity.value),
|
||||||
heatIndex:
|
heatIndex:
|
||||||
basicWeather.properties.heatIndex?.values[0].value === null
|
basicWeather.properties.heatIndex?.values[0].value === null
|
||||||
@@ -186,30 +175,6 @@ export function Homepage() {
|
|||||||
}, [weather, basicWeather]);
|
}, [weather, basicWeather]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (forecast) {
|
if (forecast) {
|
||||||
setOutlook([
|
|
||||||
{
|
|
||||||
name: forecast.properties.periods[0].name,
|
|
||||||
icon: forecast.properties.periods[0].icon.replace('medium', 'large'),
|
|
||||||
isDayTime: forecast.properties.periods[0].isDaytime,
|
|
||||||
temperature: forecast.properties.periods[0].temperature,
|
|
||||||
precipitation: Math.round(
|
|
||||||
forecast.properties.periods[0].probabilityOfPrecipitation.value,
|
|
||||||
),
|
|
||||||
windSpeed: forecast.properties.periods[0].windSpeed,
|
|
||||||
windDirection: forecast.properties.periods[0].windDirection,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: forecast.properties.periods[1].name,
|
|
||||||
icon: forecast.properties.periods[1].icon.replace('medium', 'large'),
|
|
||||||
isDayTime: forecast.properties.periods[1].isDaytime,
|
|
||||||
temperature: forecast.properties.periods[1].temperature,
|
|
||||||
precipitation: Math.round(
|
|
||||||
forecast.properties.periods[1].probabilityOfPrecipitation.value,
|
|
||||||
),
|
|
||||||
windSpeed: forecast.properties.periods[1].windSpeed,
|
|
||||||
windDirection: forecast.properties.periods[1].windDirection,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
setExtendedForecast(
|
setExtendedForecast(
|
||||||
forecast.properties.periods.map((item: any) => ({
|
forecast.properties.periods.map((item: any) => ({
|
||||||
detailedForecast: item.detailedForecast,
|
detailedForecast: item.detailedForecast,
|
||||||
@@ -241,25 +206,18 @@ export function Homepage() {
|
|||||||
<>
|
<>
|
||||||
<Search
|
<Search
|
||||||
current={current}
|
current={current}
|
||||||
outlook={outlook}
|
|
||||||
extendedForecast={extendedForecast}
|
extendedForecast={extendedForecast}
|
||||||
weather={weather}
|
|
||||||
basicWeather={basicWeather}
|
|
||||||
weatherModalOpened={weatherModalOpened}
|
weatherModalOpened={weatherModalOpened}
|
||||||
closeWeatherModal={closeWeatherModal}
|
closeWeatherModal={closeWeatherModal}
|
||||||
openWeatherModal={openWeatherModal}
|
openWeatherModal={openWeatherModal}
|
||||||
/>
|
/>
|
||||||
<Header
|
<Header
|
||||||
date={date}
|
|
||||||
greet={displayedGreeting}
|
greet={displayedGreeting}
|
||||||
|
date={date}
|
||||||
current={current}
|
current={current}
|
||||||
setCurrent={setCurrent}
|
setCurrent={setCurrent}
|
||||||
outlook={outlook}
|
|
||||||
extendedForecast={extendedForecast}
|
|
||||||
weather={weather}
|
weather={weather}
|
||||||
basicWeather={basicWeather}
|
basicWeather={basicWeather}
|
||||||
weatherModalOpened={weatherModalOpened}
|
|
||||||
closeWeatherModal={closeWeatherModal}
|
|
||||||
openWeatherModal={openWeatherModal}
|
openWeatherModal={openWeatherModal}
|
||||||
/>
|
/>
|
||||||
<Applications contentType={appFilter} />
|
<Applications contentType={appFilter} />
|
||||||
@@ -269,28 +227,19 @@ export function Homepage() {
|
|||||||
<>
|
<>
|
||||||
<Stack align='center'>
|
<Stack align='center'>
|
||||||
<LargeHeader
|
<LargeHeader
|
||||||
date={date}
|
|
||||||
greet={displayedGreeting}
|
greet={displayedGreeting}
|
||||||
current={current}
|
date={date}
|
||||||
setCurrent={setCurrent}
|
|
||||||
outlook={outlook}
|
|
||||||
extendedForecast={extendedForecast}
|
|
||||||
weather={weather}
|
weather={weather}
|
||||||
basicWeather={basicWeather}
|
basicWeather={basicWeather}
|
||||||
weatherModalOpened={weatherModalOpened}
|
setCurrent={setCurrent}
|
||||||
closeWeatherModal={closeWeatherModal}
|
|
||||||
openWeatherModal={openWeatherModal}
|
|
||||||
/>
|
/>
|
||||||
<Grid grow columns={24} pos={'absolute'} bottom={'1rem'} w={'50%'}>
|
<Grid grow columns={24} pos={'absolute'} bottom={'1rem'} w={'50%'}>
|
||||||
<CurrentWeather span={18} current={current} />
|
<CurrentWeather current={current} />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Search
|
<Search
|
||||||
current={current}
|
current={current}
|
||||||
outlook={outlook}
|
|
||||||
extendedForecast={extendedForecast}
|
extendedForecast={extendedForecast}
|
||||||
weather={weather}
|
|
||||||
basicWeather={basicWeather}
|
|
||||||
weatherModalOpened={weatherModalOpened}
|
weatherModalOpened={weatherModalOpened}
|
||||||
closeWeatherModal={closeWeatherModal}
|
closeWeatherModal={closeWeatherModal}
|
||||||
openWeatherModal={openWeatherModal}
|
openWeatherModal={openWeatherModal}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import * as si from 'react-icons/si';
|
|||||||
import * as vsc from 'react-icons/vsc';
|
import * as vsc from 'react-icons/vsc';
|
||||||
import { stackClasses, textClasses } from 'styles';
|
import { stackClasses, textClasses } from 'styles';
|
||||||
|
|
||||||
function AppItem({ url, icon, name }: any) {
|
function AppItem({ url, icon, name }: { url: string; icon: string; name: string }) {
|
||||||
const allIcons: any = { ...fa6, ...vsc, ...si };
|
const allIcons: any = { ...fa6, ...vsc, ...si };
|
||||||
const Icon = allIcons[icon];
|
const Icon = allIcons[icon];
|
||||||
const { isMobile } = useCommonHooks();
|
const { isMobile } = useCommonHooks();
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { textClasses } from 'styles';
|
|||||||
import type { Application } from 'types';
|
import type { Application } from 'types';
|
||||||
import AppItem from './AppItem';
|
import AppItem from './AppItem';
|
||||||
|
|
||||||
function Applications({ contentType }: any) {
|
function Applications({ contentType }: { contentType: [string] }) {
|
||||||
const { data: apps, isFetching: isAppsFetching } = useQueryAPI({
|
const { data: apps, isFetching: isAppsFetching } = useQueryAPI({
|
||||||
endpoint: 'api/apps',
|
endpoint: 'api/apps',
|
||||||
});
|
});
|
||||||
@@ -59,14 +59,13 @@ function Applications({ contentType }: any) {
|
|||||||
contentType.includes(application.filterName) ||
|
contentType.includes(application.filterName) ||
|
||||||
contentType.includes('All'),
|
contentType.includes('All'),
|
||||||
)
|
)
|
||||||
.map((application: any) => {
|
.map((application: Application) => {
|
||||||
return (
|
return (
|
||||||
<AppItem
|
<AppItem
|
||||||
key={application.name}
|
key={application.name}
|
||||||
name={application.name}
|
name={application.name}
|
||||||
url={application.url}
|
url={application.url}
|
||||||
icon={application.icon}
|
icon={application.icon}
|
||||||
category={application.category}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { textClasses } from 'styles';
|
|||||||
import type { Bookmark, BookmarkGroup } from 'types';
|
import type { Bookmark, BookmarkGroup } from 'types';
|
||||||
import LinkGroups from './LinkGroups';
|
import LinkGroups from './LinkGroups';
|
||||||
|
|
||||||
function Links({ contentType }: any) {
|
function Links({ contentType }: { contentType: [string] }) {
|
||||||
const { data: linkData, isFetched: linksIsFetched } = useQueryAPI({
|
const { data: linkData, isFetched: linksIsFetched } = useQueryAPI({
|
||||||
endpoint: 'api/links',
|
endpoint: 'api/links',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { Stack, Text } from '@mantine/core';
|
import { Stack, Text } from '@mantine/core';
|
||||||
import { textClasses } from 'styles';
|
import { textClasses } from 'styles';
|
||||||
|
import type { Bookmark } from 'types';
|
||||||
import LinkItem from './LinkItem';
|
import LinkItem from './LinkItem';
|
||||||
|
|
||||||
function LinkGroups({ links, category }: any) {
|
function LinkGroups({ links, category }: { links: Bookmark[]; category: string }) {
|
||||||
return (
|
return (
|
||||||
<Stack
|
<Stack
|
||||||
style={{
|
style={{
|
||||||
@@ -17,8 +18,8 @@ function LinkGroups({ links, category }: any) {
|
|||||||
{category}
|
{category}
|
||||||
</Text>
|
</Text>
|
||||||
{links
|
{links
|
||||||
?.sort((a: any, b: any) => (a.index > b.index ? 1 : -1))
|
?.toSorted((a: Bookmark, b: Bookmark) => (a.index > b.index ? 1 : -1))
|
||||||
.map((link: any) => (
|
.map((link: Bookmark) => (
|
||||||
<LinkItem key={link.name} link={link} />
|
<LinkItem key={link.name} link={link} />
|
||||||
))}
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { Text } from '@mantine/core';
|
import { Text } from '@mantine/core';
|
||||||
import { textClasses } from 'styles';
|
import { textClasses } from 'styles';
|
||||||
|
import type { Bookmark } from 'types';
|
||||||
|
|
||||||
function LinkItem({ link }: any) {
|
function LinkItem({ link }: { link: Bookmark }) {
|
||||||
return (
|
return (
|
||||||
<Text
|
<Text
|
||||||
className={textClasses.linkItem}
|
className={textClasses.linkItem}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Group, Stack, Text } from '@mantine/core';
|
|||||||
import { useCommonHooks } from 'hooks';
|
import { useCommonHooks } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { textClasses } from 'styles';
|
import { textClasses } from 'styles';
|
||||||
|
import type { CurrentWeather as CW } from 'types';
|
||||||
|
|
||||||
function Header({
|
function Header({
|
||||||
greet,
|
greet,
|
||||||
@@ -11,7 +12,15 @@ function Header({
|
|||||||
weather,
|
weather,
|
||||||
basicWeather,
|
basicWeather,
|
||||||
openWeatherModal,
|
openWeatherModal,
|
||||||
}: any) {
|
}: {
|
||||||
|
greet: string;
|
||||||
|
date: string;
|
||||||
|
current: CW;
|
||||||
|
setCurrent: (current: CW) => void;
|
||||||
|
weather: any;
|
||||||
|
basicWeather: any;
|
||||||
|
openWeatherModal: () => void;
|
||||||
|
}) {
|
||||||
const [time, setTime] = useState(new Date());
|
const [time, setTime] = useState(new Date());
|
||||||
const { isMobile, currentUser, fixDigits } = useCommonHooks();
|
const { isMobile, currentUser, fixDigits } = useCommonHooks();
|
||||||
|
|
||||||
@@ -25,7 +34,7 @@ function Header({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (weather !== undefined && basicWeather !== undefined) {
|
if (weather !== undefined && basicWeather !== undefined) {
|
||||||
setCurrent({
|
setCurrent({
|
||||||
icon: weather.features[0]?.properties.icon?.replace('medium', 'large') || '',
|
icon: weather.features[0]?.properties.icon?.replace('medium', 'large') ?? '',
|
||||||
textDescription: weather.features[0]?.properties.textDescription,
|
textDescription: weather.features[0]?.properties.textDescription,
|
||||||
temperature: Math.round(
|
temperature: Math.round(
|
||||||
(weather.features[0]?.properties.temperature.value * 9) / 5 + 32,
|
(weather.features[0]?.properties.temperature.value * 9) / 5 + 32,
|
||||||
@@ -37,7 +46,7 @@ function Header({
|
|||||||
(basicWeather.properties.minTemperature.values[0].value * 9) / 5 + 32,
|
(basicWeather.properties.minTemperature.values[0].value * 9) / 5 + 32,
|
||||||
),
|
),
|
||||||
precipitation:
|
precipitation:
|
||||||
weather.features[0]?.properties.precipitationLastHour.value || 'N/A',
|
weather.features[0]?.properties.precipitationLastHour.value ?? 'N/A',
|
||||||
humidity: Math.round(weather.features[0]?.properties.relativeHumidity.value),
|
humidity: Math.round(weather.features[0]?.properties.relativeHumidity.value),
|
||||||
heatIndex:
|
heatIndex:
|
||||||
basicWeather.properties.heatIndex?.values[0].value === null
|
basicWeather.properties.heatIndex?.values[0].value === null
|
||||||
@@ -128,17 +137,17 @@ function Header({
|
|||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
component='h2'
|
component='h2'
|
||||||
mr={4}
|
|
||||||
className={textClasses.dateTime}
|
className={textClasses.dateTime}
|
||||||
classNames={textClasses}
|
classNames={textClasses}
|
||||||
|
mr={4}
|
||||||
>
|
>
|
||||||
{current.temperature}°F
|
{current.temperature}°F
|
||||||
</Text>
|
</Text>
|
||||||
<Text
|
<Text
|
||||||
mb={6}
|
|
||||||
className={textClasses.dateTime}
|
className={textClasses.dateTime}
|
||||||
classNames={textClasses}
|
classNames={textClasses}
|
||||||
fz={14}
|
fz={14}
|
||||||
|
mb={6}
|
||||||
>
|
>
|
||||||
{current.highTemp}°F/{current.lowTemp}°F
|
{current.highTemp}°F/{current.lowTemp}°F
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -2,8 +2,21 @@ import { Stack, Text } from '@mantine/core';
|
|||||||
import { useCommonHooks } from 'hooks';
|
import { useCommonHooks } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { textClasses } from 'styles';
|
import { textClasses } from 'styles';
|
||||||
|
import type { CurrentWeather as CW } from 'types';
|
||||||
|
|
||||||
function LargeHeader({ greet, date, setCurrent, weather, basicWeather }: any) {
|
function LargeHeader({
|
||||||
|
greet,
|
||||||
|
date,
|
||||||
|
setCurrent,
|
||||||
|
weather,
|
||||||
|
basicWeather,
|
||||||
|
}: {
|
||||||
|
greet: string;
|
||||||
|
date: string;
|
||||||
|
weather: any;
|
||||||
|
basicWeather: any;
|
||||||
|
setCurrent: (current: CW) => void;
|
||||||
|
}) {
|
||||||
const [time, setTime] = useState(new Date());
|
const [time, setTime] = useState(new Date());
|
||||||
const { isMobile, currentUser, fixDigits } = useCommonHooks();
|
const { isMobile, currentUser, fixDigits } = useCommonHooks();
|
||||||
|
|
||||||
@@ -17,7 +30,7 @@ function LargeHeader({ greet, date, setCurrent, weather, basicWeather }: any) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (weather !== undefined && basicWeather !== undefined) {
|
if (weather !== undefined && basicWeather !== undefined) {
|
||||||
setCurrent({
|
setCurrent({
|
||||||
icon: weather.features[0]?.properties.icon?.replace('medium', 'large') || '',
|
icon: weather.features[0]?.properties.icon?.replace('medium', 'large') ?? '',
|
||||||
textDescription: weather.features[0]?.properties.textDescription,
|
textDescription: weather.features[0]?.properties.textDescription,
|
||||||
temperature: Math.round(
|
temperature: Math.round(
|
||||||
(weather.features[0]?.properties.temperature.value * 9) / 5 + 32,
|
(weather.features[0]?.properties.temperature.value * 9) / 5 + 32,
|
||||||
@@ -29,7 +42,7 @@ function LargeHeader({ greet, date, setCurrent, weather, basicWeather }: any) {
|
|||||||
(basicWeather.properties.minTemperature.values[0].value * 9) / 5 + 32,
|
(basicWeather.properties.minTemperature.values[0].value * 9) / 5 + 32,
|
||||||
),
|
),
|
||||||
precipitation:
|
precipitation:
|
||||||
weather.features[0]?.properties.precipitationLastHour.value || 'N/A',
|
weather.features[0]?.properties.precipitationLastHour.value ?? 'N/A',
|
||||||
humidity: Math.round(weather.features[0]?.properties.relativeHumidity.value),
|
humidity: Math.round(weather.features[0]?.properties.relativeHumidity.value),
|
||||||
heatIndex:
|
heatIndex:
|
||||||
basicWeather.properties.heatIndex?.values[0].value === null
|
basicWeather.properties.heatIndex?.values[0].value === null
|
||||||
|
|||||||
@@ -12,16 +12,21 @@ import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { FiEdit, FiTrash } from 'react-icons/fi';
|
import { FiEdit, FiTrash } from 'react-icons/fi';
|
||||||
import { actionIconClasses, selectClasses } from 'styles';
|
import { actionIconClasses, selectClasses } from 'styles';
|
||||||
import type { Application, Provider } from 'types';
|
import type { Application, CurrentWeather, ExtendedForecast, Provider } from 'types';
|
||||||
|
|
||||||
export default function Search({
|
export default function Search({
|
||||||
current,
|
current,
|
||||||
outlook,
|
|
||||||
extendedForecast,
|
extendedForecast,
|
||||||
weatherModalOpened,
|
weatherModalOpened,
|
||||||
closeWeatherModal,
|
closeWeatherModal,
|
||||||
openWeatherModal,
|
openWeatherModal,
|
||||||
}: any) {
|
}: {
|
||||||
|
current: CurrentWeather;
|
||||||
|
extendedForecast: ExtendedForecast[];
|
||||||
|
weatherModalOpened: boolean;
|
||||||
|
closeWeatherModal: () => void;
|
||||||
|
openWeatherModal: () => void;
|
||||||
|
}) {
|
||||||
const { data: providers, isFetched: providersIsFetched } = useQueryAPI({
|
const { data: providers, isFetched: providersIsFetched } = useQueryAPI({
|
||||||
endpoint: 'api/providers',
|
endpoint: 'api/providers',
|
||||||
});
|
});
|
||||||
@@ -29,14 +34,13 @@ export default function Search({
|
|||||||
const { data: apps, isFetching: isAppsFetching } = useQueryAPI({
|
const { data: apps, isFetching: isAppsFetching } = useQueryAPI({
|
||||||
endpoint: 'api/apps',
|
endpoint: 'api/apps',
|
||||||
});
|
});
|
||||||
const [applicationData, setApplicationData] = useState<any>([]);
|
const [applicationData, setApplicationData] = useState<Application[]>([]);
|
||||||
const { data: history, isFetched: historyIsFetched } = useQueryAPI({
|
const { data: history, isFetched: historyIsFetched } = useQueryAPI({
|
||||||
endpoint: 'api/searchHistory',
|
endpoint: 'api/searchHistory',
|
||||||
});
|
});
|
||||||
const [searchHistory, setSearchHistory] = useState<any>([]);
|
const [searchHistory, setSearchHistory] = useState<any>([]);
|
||||||
const [filteredHistory, setFilteredHistory] = useState<any>([]);
|
const [filteredHistory, setFilteredHistory] = useState<any>([]);
|
||||||
const { mutateAsync: createHistoryItem } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const { mutateAsync: deleteHistoryItem } = useMutationAPI();
|
|
||||||
const [providerModalOpened, { open: openProviderModal, close: closeProviderModal }] =
|
const [providerModalOpened, { open: openProviderModal, close: closeProviderModal }] =
|
||||||
useDisclosure(false);
|
useDisclosure(false);
|
||||||
const [dropdownOpened, { open: openDropdown, close: closeDropdown }] = useDisclosure();
|
const [dropdownOpened, { open: openDropdown, close: closeDropdown }] = useDisclosure();
|
||||||
@@ -59,7 +63,7 @@ export default function Search({
|
|||||||
|
|
||||||
const handleSearchHistoryItem = (item: any) => {
|
const handleSearchHistoryItem = (item: any) => {
|
||||||
const url =
|
const url =
|
||||||
providers.find((provider: any) => provider.prefix === item.option.prefix)?.url ||
|
providers.find((provider: any) => provider.prefix === item.option.prefix)?.url ??
|
||||||
'https://www.google.com/search?q=';
|
'https://www.google.com/search?q=';
|
||||||
open(`${url}${item.option.searchTerm}`, '_self');
|
open(`${url}${item.option.searchTerm}`, '_self');
|
||||||
};
|
};
|
||||||
@@ -73,7 +77,7 @@ export default function Search({
|
|||||||
let subtext = '';
|
let subtext = '';
|
||||||
if (item.target.value.startsWith('/')) {
|
if (item.target.value.startsWith('/')) {
|
||||||
option =
|
option =
|
||||||
item.target.value.substr(1, item.target.value.indexOf(' ') - 1) ||
|
item.target.value.substr(1, item.target.value.indexOf(' ') - 1) ??
|
||||||
item.target.value.substr(1);
|
item.target.value.substr(1);
|
||||||
subtext = item.target.value.substr(2 + option.length);
|
subtext = item.target.value.substr(2 + option.length);
|
||||||
} else if (item.target.value.startsWith('!')) {
|
} else if (item.target.value.startsWith('!')) {
|
||||||
@@ -87,7 +91,7 @@ export default function Search({
|
|||||||
if (providerLabel === 'Show help') {
|
if (providerLabel === 'Show help') {
|
||||||
openProviderModal();
|
openProviderModal();
|
||||||
} else if (item.target.value.startsWith('/')) {
|
} else if (item.target.value.startsWith('/')) {
|
||||||
createHistoryItem({
|
mutateAsync({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
endpoint: 'api/searchHistory',
|
endpoint: 'api/searchHistory',
|
||||||
body: { prefix: providerPrefix, provider: providerLabel, searchTerm: subtext },
|
body: { prefix: providerPrefix, provider: providerLabel, searchTerm: subtext },
|
||||||
@@ -100,16 +104,18 @@ export default function Search({
|
|||||||
const url = applicationData.find(
|
const url = applicationData.find(
|
||||||
(app: Application) =>
|
(app: Application) =>
|
||||||
app.baseUrl.substring(1).toLowerCase() === item.target.value.substr(1),
|
app.baseUrl.substring(1).toLowerCase() === item.target.value.substr(1),
|
||||||
).url;
|
)?.url;
|
||||||
const validUrl =
|
const validUrl =
|
||||||
url.startsWith('http://') || url.startsWith('https://') ? url : `http://${url}`;
|
url?.startsWith('http://') || url?.startsWith('https://')
|
||||||
|
? url
|
||||||
|
: `http://${url}`;
|
||||||
open(validUrl, '_self');
|
open(validUrl, '_self');
|
||||||
} else if (urlPattern.test(item.target.value)) {
|
} else if (urlPattern.test(item.target.value)) {
|
||||||
if (/^(https?:\/\/).*/i.test(item.target.value))
|
if (/^(https?:\/\/).*/i.test(item.target.value))
|
||||||
window.location = item.target.value;
|
window.location = item.target.value;
|
||||||
else open(`https://${item.target.value}`, '_self');
|
else open(`https://${item.target.value}`, '_self');
|
||||||
} else {
|
} else {
|
||||||
createHistoryItem({
|
mutateAsync({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
endpoint: 'api/searchHistory',
|
endpoint: 'api/searchHistory',
|
||||||
body: { prefix: providerPrefix, provider: providerLabel, searchTerm: subtext },
|
body: { prefix: providerPrefix, provider: providerLabel, searchTerm: subtext },
|
||||||
@@ -220,8 +226,8 @@ export default function Search({
|
|||||||
setProviderLabel('Show weather');
|
setProviderLabel('Show weather');
|
||||||
} else if (
|
} else if (
|
||||||
applicationData?.find(
|
applicationData?.find(
|
||||||
(app: any) =>
|
(app: Application) =>
|
||||||
app.baseUrl.substr(1).toLowerCase() === item.target.value.substr(1),
|
app.baseUrl.substring(1).toLowerCase() === item.target.value.substr(1),
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
setProviderLabel(`Launch ${item.target.value.substr(1)}`);
|
setProviderLabel(`Launch ${item.target.value.substr(1)}`);
|
||||||
@@ -239,10 +245,10 @@ export default function Search({
|
|||||||
const splittedSearch = search.toLowerCase().trim().split(' ');
|
const splittedSearch = search.toLowerCase().trim().split(' ');
|
||||||
if (splittedSearch[0].startsWith('!')) {
|
if (splittedSearch[0].startsWith('!')) {
|
||||||
return apps
|
return apps
|
||||||
.filter((app: any) =>
|
.filter((app: Application) =>
|
||||||
app.name.toLowerCase().includes(splittedSearch[0].substring(1).toLowerCase()),
|
app.name.toLowerCase().includes(splittedSearch[0].substring(1).toLowerCase()),
|
||||||
)
|
)
|
||||||
.map((app: any) => {
|
.map((app: Application) => {
|
||||||
return {
|
return {
|
||||||
label: app.name,
|
label: app.name,
|
||||||
value: app.baseUrl,
|
value: app.baseUrl,
|
||||||
@@ -257,7 +263,7 @@ export default function Search({
|
|||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.trim()
|
.trim()
|
||||||
.split(' ')
|
.split(' ')
|
||||||
.some((word: any) => word.includes(searchWord)),
|
.some((word: string) => word.includes(searchWord)),
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.slice(0, 10);
|
.slice(0, 10);
|
||||||
@@ -327,7 +333,7 @@ export default function Search({
|
|||||||
classNames={actionIconClasses}
|
classNames={actionIconClasses}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
deleteHistoryItem({
|
mutateAsync({
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
endpoint: 'api/searchHistory',
|
endpoint: 'api/searchHistory',
|
||||||
body: { id: item.option.id },
|
body: { id: item.option.id },
|
||||||
@@ -417,7 +423,7 @@ export default function Search({
|
|||||||
const option = `${item.prefix} ${item.searchTerm}`;
|
const option = `${item.prefix} ${item.searchTerm}`;
|
||||||
const words = option.toLowerCase().trim().split(' ');
|
const words = option.toLowerCase().trim().split(' ');
|
||||||
return splittedSearch.every((searchWord) =>
|
return splittedSearch.every((searchWord) =>
|
||||||
words.some((word: any) => word.includes(searchWord)),
|
words.some((word: string) => word.includes(searchWord)),
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.slice(0, 10);
|
.slice(0, 10);
|
||||||
@@ -482,20 +488,19 @@ export default function Search({
|
|||||||
setSearchValue={setSearchValue}
|
setSearchValue={setSearchValue}
|
||||||
setProviderLabel={setProviderLabel}
|
setProviderLabel={setProviderLabel}
|
||||||
setProviderURL={setProviderURL}
|
setProviderURL={setProviderURL}
|
||||||
providerModalOpened={providerModalOpened}
|
|
||||||
applicationData={applicationData}
|
applicationData={applicationData}
|
||||||
providerData={providerData}
|
providerData={providerData}
|
||||||
|
providerModalOpened={providerModalOpened}
|
||||||
closeProviderModal={closeProviderModal}
|
closeProviderModal={closeProviderModal}
|
||||||
/>
|
/>
|
||||||
<WeatherModal
|
<WeatherModal
|
||||||
|
current={current}
|
||||||
|
extendedForecast={extendedForecast}
|
||||||
|
weatherModalOpened={weatherModalOpened}
|
||||||
setSearchValue={setSearchValue}
|
setSearchValue={setSearchValue}
|
||||||
setProviderLabel={setProviderLabel}
|
setProviderLabel={setProviderLabel}
|
||||||
setProviderURL={setProviderURL}
|
setProviderURL={setProviderURL}
|
||||||
current={current}
|
|
||||||
outlook={outlook}
|
|
||||||
extendedForecast={extendedForecast}
|
|
||||||
closeWeatherModal={closeWeatherModal}
|
closeWeatherModal={closeWeatherModal}
|
||||||
weatherModalOpened={weatherModalOpened}
|
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ function SettingsButton() {
|
|||||||
const { data: themePlaylists } = useQueryAPI({
|
const { data: themePlaylists } = useQueryAPI({
|
||||||
endpoint: 'api/themePlaylists',
|
endpoint: 'api/themePlaylists',
|
||||||
});
|
});
|
||||||
const { mutateAsync: wakeRequest } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const [allThemeData, setAllThemeData] = useState<Theme[]>([]);
|
const [allThemeData, setAllThemeData] = useState<Theme[]>([]);
|
||||||
const [categories, setCategories] = useState([{ value: 'All', label: 'All' }]);
|
const [categories, setCategories] = useState([{ value: 'All', label: 'All' }]);
|
||||||
const [selectedClient, setSelectedClient] = useState<WolClient>(wolClients?.[0]);
|
const [selectedClient, setSelectedClient] = useState<WolClient>(wolClients?.[0]);
|
||||||
@@ -64,7 +64,7 @@ function SettingsButton() {
|
|||||||
setCurrentThemePlaylist,
|
setCurrentThemePlaylist,
|
||||||
} = useCommonHooks();
|
} = useCommonHooks();
|
||||||
const handleWakeRequest = () => {
|
const handleWakeRequest = () => {
|
||||||
wakeRequest({
|
mutateAsync({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
endpoint: 'api/wakeClient',
|
endpoint: 'api/wakeClient',
|
||||||
body: selectedClient || wolClients?.[0],
|
body: selectedClient || wolClients?.[0],
|
||||||
@@ -151,7 +151,7 @@ function SettingsButton() {
|
|||||||
defaultValue={wolClientsData?.[0]?.hostname}
|
defaultValue={wolClientsData?.[0]?.hostname}
|
||||||
data={
|
data={
|
||||||
wolClientsData
|
wolClientsData
|
||||||
?.map((wolClient: any) => {
|
?.map((wolClient: WolClient) => {
|
||||||
return {
|
return {
|
||||||
value: wolClient.hostname,
|
value: wolClient.hostname,
|
||||||
label: `${wolClient.hostname} (${wolClient.macAddress})`,
|
label: `${wolClient.hostname} (${wolClient.macAddress})`,
|
||||||
@@ -241,7 +241,7 @@ function SettingsButton() {
|
|||||||
label: playlist.name,
|
label: playlist.name,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.toSorted((a: any, b: any) => a.label.localeCompare(b.label)) || []
|
.toSorted((a: any, b: any) => a.label.localeCompare(b.label)) ?? []
|
||||||
}
|
}
|
||||||
w='92%'
|
w='92%'
|
||||||
classNames={{
|
classNames={{
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export function Settings() {
|
|||||||
const { tabValue } = useParams();
|
const { tabValue } = useParams();
|
||||||
return (
|
return (
|
||||||
<Stack h={'100%'} gap={0}>
|
<Stack h={'100%'} gap={0}>
|
||||||
<Group pos={'relative'} gap={0} pb={'1rem'}>
|
<Group gap={0} style={{ position: 'relative', paddingBottom: '1rem' }}>
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
className={actionIconClasses.backButton}
|
className={actionIconClasses.backButton}
|
||||||
classNames={actionIconClasses}
|
classNames={actionIconClasses}
|
||||||
@@ -51,9 +51,6 @@ export function Settings() {
|
|||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
navigate(`/${import.meta.env.VITE_BASE_URL}/settings/${value}`)
|
navigate(`/${import.meta.env.VITE_BASE_URL}/settings/${value}`)
|
||||||
}
|
}
|
||||||
style={{
|
|
||||||
overflow: 'hidden',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Tabs.List style={{ justifyContent: isMobile ? 'space-between' : undefined }}>
|
<Tabs.List style={{ justifyContent: isMobile ? 'space-between' : undefined }}>
|
||||||
<Tabs.Tab px={isMobile ? '.9rem' : undefined} value='personalization'>
|
<Tabs.Tab px={isMobile ? '.9rem' : undefined} value='personalization'>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const ApplicationSettings = () => {
|
|||||||
});
|
});
|
||||||
const [applicationData, setApplicationData] = useState<Application[]>([]);
|
const [applicationData, setApplicationData] = useState<Application[]>([]);
|
||||||
const [applicationList, setApplicationList] = useState<Application[]>([]);
|
const [applicationList, setApplicationList] = useState<Application[]>([]);
|
||||||
const { theme, isMobile } = useCommonHooks();
|
const { theme, isMobile, reorder } = useCommonHooks();
|
||||||
const [newApplication, setNewApplication] = useState<Application>(defaultApplication);
|
const [newApplication, setNewApplication] = useState<Application>(defaultApplication);
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
@@ -53,13 +53,6 @@ const ApplicationSettings = () => {
|
|||||||
const [dragging, setDragging] = useState(false);
|
const [dragging, setDragging] = useState(false);
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
const reorder = (list: any, startIndex: any, endIndex: any) => {
|
|
||||||
const result = Array.from(list);
|
|
||||||
const [removed]: any = result.splice(startIndex, 1);
|
|
||||||
result.splice(endIndex, 0, removed);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
function onDragEnd(result: any) {
|
function onDragEnd(result: any) {
|
||||||
if (!result.destination) {
|
if (!result.destination) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -28,19 +28,12 @@ const BookmarkSettings = () => {
|
|||||||
const [groups, setGroups] = useState<BookmarkGroup[]>([]);
|
const [groups, setGroups] = useState<BookmarkGroup[]>([]);
|
||||||
const [newGroup, setNewGroup] = useState<BookmarkGroup>(defaultGroup);
|
const [newGroup, setNewGroup] = useState<BookmarkGroup>(defaultGroup);
|
||||||
const [groupList, setGroupList] = useState<BookmarkGroup[]>([]);
|
const [groupList, setGroupList] = useState<BookmarkGroup[]>([]);
|
||||||
const { theme, isMobile } = useCommonHooks();
|
const { theme, isMobile, reorder } = useCommonHooks();
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [debouncedGroupSearch] = useDebouncedValue(searchValue, 500);
|
const [debouncedGroupSearch] = useDebouncedValue(searchValue, 500);
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
|
|
||||||
const reorder = (list: any, startIndex: any, endIndex: any) => {
|
|
||||||
const result = Array.from(list);
|
|
||||||
const [removed]: any = result.splice(startIndex, 1);
|
|
||||||
result.splice(endIndex, 0, removed);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setNewGroup(defaultGroup);
|
setNewGroup(defaultGroup);
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ function DebouncedGroupSettingsItem({
|
|||||||
bookmarks,
|
bookmarks,
|
||||||
searchTerm,
|
searchTerm,
|
||||||
}: { bookmarkGroup: BookmarkGroup; bookmarks: Bookmark[]; searchTerm: string }) {
|
}: { bookmarkGroup: BookmarkGroup; bookmarks: Bookmark[]; searchTerm: string }) {
|
||||||
const { theme, isMobile, handleDelete } = useCommonHooks();
|
const { theme, isMobile, handleDelete, reorder } = useCommonHooks();
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
const [popoverOpened, setPopoverOpened] = useState(false);
|
const [popoverOpened, setPopoverOpened] = useState(false);
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
@@ -44,12 +44,6 @@ function DebouncedGroupSettingsItem({
|
|||||||
const [bookmarkList, setBookmarkList] = useState<Bookmark[]>(bookmarks);
|
const [bookmarkList, setBookmarkList] = useState<Bookmark[]>(bookmarks);
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
const reorder = (list: any, startIndex: any, endIndex: any) => {
|
|
||||||
const result = Array.from(list);
|
|
||||||
const [removed]: any = result.splice(startIndex, 1);
|
|
||||||
result.splice(endIndex, 0, removed);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
function onDragEnd(result: any) {
|
function onDragEnd(result: any) {
|
||||||
if (!result.destination) {
|
if (!result.destination) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -62,7 +62,10 @@ const PersonalizationSettings = () => {
|
|||||||
setSearchValue={() => {}}
|
setSearchValue={() => {}}
|
||||||
searchPlaceholder={undefined}
|
searchPlaceholder={undefined}
|
||||||
/>
|
/>
|
||||||
<Stack mt={'6rem'} mb={'1rem'} w={'100%'} align='center'>
|
<Stack
|
||||||
|
align='center'
|
||||||
|
style={{ marginTop: '6rem', marginBottom: '1rem', width: '100%' }}
|
||||||
|
>
|
||||||
<Grid w={'75%'} pos={'relative'}>
|
<Grid w={'75%'} pos={'relative'}>
|
||||||
{personalIsFetching && (
|
{personalIsFetching && (
|
||||||
<Overlay
|
<Overlay
|
||||||
|
|||||||
@@ -55,6 +55,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.fadeAway {
|
.fadeAway {
|
||||||
|
position: fixed;
|
||||||
background-color: #1c1b22;
|
background-color: #1c1b22;
|
||||||
transition: all .5s ease-in-out;
|
transition: all .5s ease-in-out;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
@@ -62,7 +63,7 @@
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
backdrop-filter: blur(5px);
|
backdrop-filter: blur(15px);
|
||||||
&[data-loaded="true"] {
|
&[data-loaded="true"] {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
background-color: var(--color-background);
|
background-color: var(--color-background);
|
||||||
|
|||||||
@@ -31,4 +31,7 @@
|
|||||||
.list::before {
|
.list::before {
|
||||||
border-color: var(--color-text-acc);
|
border-color: var(--color-text-acc);
|
||||||
}
|
}
|
||||||
|
&.root {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
src/styles/ThemeIcon.module.css
Normal file
6
src/styles/ThemeIcon.module.css
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
.weatherIcon {
|
||||||
|
height: auto !important;
|
||||||
|
width: auto !important;
|
||||||
|
color: var(--color-text-pri) !important;
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ import switchClasses from './Switch.module.css';
|
|||||||
import tabClasses from './Tabs.module.css';
|
import tabClasses from './Tabs.module.css';
|
||||||
import textClasses from './Text.module.css';
|
import textClasses from './Text.module.css';
|
||||||
import textInputClasses from './TextInput.module.css';
|
import textInputClasses from './TextInput.module.css';
|
||||||
|
import themeIconClasses from './ThemeIcon.module.css';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
actionIconClasses,
|
actionIconClasses,
|
||||||
@@ -28,4 +29,5 @@ export {
|
|||||||
tabClasses,
|
tabClasses,
|
||||||
textClasses,
|
textClasses,
|
||||||
textInputClasses,
|
textInputClasses,
|
||||||
|
themeIconClasses,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user