Bug fixes and new biome lint update
This commit is contained in:
27
biome.json
27
biome.json
@@ -1,9 +1,7 @@
|
|||||||
{
|
{
|
||||||
"organizeImports": {
|
"assist": { "actions": { "source": { "organizeImports": "on" } } },
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
"files": {
|
"files": {
|
||||||
"ignore": ["./node_modules/", "./dist/", "./.nx/"],
|
"includes": ["./src/**/*.{ts,tsx,js,jsx}"],
|
||||||
"ignoreUnknown": true
|
"ignoreUnknown": true
|
||||||
},
|
},
|
||||||
"linter": {
|
"linter": {
|
||||||
@@ -11,8 +9,7 @@
|
|||||||
"rules": {
|
"rules": {
|
||||||
"recommended": true,
|
"recommended": true,
|
||||||
"a11y": {
|
"a11y": {
|
||||||
"noSvgWithoutTitle": "off",
|
"noSvgWithoutTitle": "off"
|
||||||
"all": true
|
|
||||||
},
|
},
|
||||||
"complexity": {
|
"complexity": {
|
||||||
"noUselessTypeConstraint": "off",
|
"noUselessTypeConstraint": "off",
|
||||||
@@ -20,9 +17,9 @@
|
|||||||
},
|
},
|
||||||
"suspicious": {
|
"suspicious": {
|
||||||
"noExplicitAny": "off",
|
"noExplicitAny": "off",
|
||||||
"noConsoleLog": "error",
|
|
||||||
"noImplicitAnyLet": "off",
|
"noImplicitAnyLet": "off",
|
||||||
"recommended": true
|
"recommended": true,
|
||||||
|
"noConsole": { "level": "error", "options": { "allow": ["error", "log"] } }
|
||||||
},
|
},
|
||||||
"correctness": {
|
"correctness": {
|
||||||
"useExhaustiveDependencies": "off",
|
"useExhaustiveDependencies": "off",
|
||||||
@@ -32,12 +29,24 @@
|
|||||||
"performance": {
|
"performance": {
|
||||||
"noDelete": "off",
|
"noDelete": "off",
|
||||||
"recommended": true
|
"recommended": true
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"noParameterAssign": "error",
|
||||||
|
"useAsConstAssertion": "error",
|
||||||
|
"useDefaultParameterLast": "error",
|
||||||
|
"useEnumInitializers": "error",
|
||||||
|
"useSelfClosingElements": "error",
|
||||||
|
"useSingleVarDeclarator": "error",
|
||||||
|
"noUnusedTemplateLiteral": "error",
|
||||||
|
"useNumberNamespace": "error",
|
||||||
|
"noInferrableTypes": "error",
|
||||||
|
"noUselessElse": "error"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"formatWithErrors": false,
|
"formatWithErrors": true,
|
||||||
"indentStyle": "tab",
|
"indentStyle": "tab",
|
||||||
"indentWidth": 2,
|
"indentWidth": 2,
|
||||||
"lineWidth": 90
|
"lineWidth": 90
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import {
|
import {
|
||||||
DEFAULT_THEME,
|
|
||||||
MantineProvider,
|
|
||||||
colorsTuple,
|
colorsTuple,
|
||||||
createTheme,
|
createTheme,
|
||||||
|
DEFAULT_THEME,
|
||||||
|
MantineProvider,
|
||||||
mergeMantineTheme,
|
mergeMantineTheme,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { Notifications } from '@mantine/notifications';
|
import { Notifications } from '@mantine/notifications';
|
||||||
import { useCommonHooks, useQueryAPI } from 'hooks';
|
import { useCommonHooks, useQueryAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
|
createBrowserRouter,
|
||||||
|
createRoutesFromElements,
|
||||||
Navigate,
|
Navigate,
|
||||||
Route,
|
Route,
|
||||||
RouterProvider,
|
RouterProvider,
|
||||||
createBrowserRouter,
|
|
||||||
createRoutesFromElements,
|
|
||||||
} from 'react-router-dom';
|
} from 'react-router-dom';
|
||||||
import { Loading, MainLayout } from './components';
|
import { Loading, MainLayout } from './components';
|
||||||
import '@mantine/core/styles.css';
|
import '@mantine/core/styles.css';
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { QueryClient } from '@tanstack/react-query';
|
import { QueryClient } from '@tanstack/react-query';
|
||||||
import {
|
import {
|
||||||
PersistQueryClientProvider,
|
|
||||||
type PersistedClient,
|
type PersistedClient,
|
||||||
type Persister,
|
type Persister,
|
||||||
|
PersistQueryClientProvider,
|
||||||
} from '@tanstack/react-query-persist-client';
|
} from '@tanstack/react-query-persist-client';
|
||||||
import { del, get, set } from 'idb-keyval';
|
import { del, get, set } from 'idb-keyval';
|
||||||
import React, { type ComponentType } from 'react';
|
import React, { type ComponentType } from 'react';
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default function CurrentWeather({ current }: { current: CW }) {
|
|||||||
}, [sunStateData]);
|
}, [sunStateData]);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{current ? (
|
{current && (
|
||||||
<Stack
|
<Stack
|
||||||
gap={0}
|
gap={0}
|
||||||
justify='space-between'
|
justify='space-between'
|
||||||
@@ -250,8 +250,6 @@ export default function CurrentWeather({ current }: { current: CW }) {
|
|||||||
</Stack>
|
</Stack>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ import WeatherIcon from './WeatherIcon';
|
|||||||
|
|
||||||
export default function ExtendedForecastCard({
|
export default function ExtendedForecastCard({
|
||||||
forecast,
|
forecast,
|
||||||
}: { forecast: ExtendedForecast[] }) {
|
}: {
|
||||||
|
forecast: ExtendedForecast[];
|
||||||
|
}) {
|
||||||
const { isMobile } = useCommonHooks();
|
const { isMobile } = useCommonHooks();
|
||||||
const day = forecast.slice(2, 14).filter((item: ExtendedForecast) => item.isDaytime);
|
const day = forecast.slice(2, 14).filter((item: ExtendedForecast) => item.isDaytime);
|
||||||
const night = forecast.slice(2, 14).filter((item: ExtendedForecast) => !item.isDaytime);
|
const night = forecast.slice(2, 14).filter((item: ExtendedForecast) => !item.isDaytime);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Stack, Text } from '@mantine/core';
|
import { Stack } from '@mantine/core';
|
||||||
import {
|
import {
|
||||||
Area,
|
Area,
|
||||||
AreaChart,
|
AreaChart,
|
||||||
@@ -12,34 +12,15 @@ import {
|
|||||||
YAxis,
|
YAxis,
|
||||||
} from 'recharts';
|
} from 'recharts';
|
||||||
import type { HourlyForecast } from 'types';
|
import type { HourlyForecast } from 'types';
|
||||||
|
import WeatherTooltip from './WeatherTooltip';
|
||||||
|
|
||||||
export default function WeatherGraphs({
|
export default function WeatherGraphs({
|
||||||
hourlyForecast,
|
hourlyForecast,
|
||||||
}: { hourlyForecast: HourlyForecast[] }) {
|
}: {
|
||||||
function CustomTooltip({ payload, active }: any) {
|
hourlyForecast: HourlyForecast[];
|
||||||
if (active) {
|
}) {
|
||||||
return (
|
const colorPrecipitation = 'colorPrecipitation';
|
||||||
<Stack
|
const colorHumidity = 'colorHumidity';
|
||||||
style={{
|
|
||||||
backgroundColor: 'var(--mantine-color-background-0)',
|
|
||||||
padding: '1rem',
|
|
||||||
borderRadius: '8px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{payload.map((item: any) => (
|
|
||||||
<Text
|
|
||||||
key={item.name}
|
|
||||||
size='md'
|
|
||||||
c={item.stroke}
|
|
||||||
>{`${item.name} - ${item.value}${item.unit}`}</Text>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack
|
<Stack
|
||||||
style={{
|
style={{
|
||||||
@@ -68,7 +49,7 @@ export default function WeatherGraphs({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<CartesianGrid stroke='#f5f5f522' />
|
<CartesianGrid stroke='#f5f5f522' />
|
||||||
<Tooltip content={<CustomTooltip />} />
|
<Tooltip content={<WeatherTooltip />} />
|
||||||
<Line
|
<Line
|
||||||
unit={'°F'}
|
unit={'°F'}
|
||||||
type='monotone'
|
type='monotone'
|
||||||
@@ -103,7 +84,7 @@ export default function WeatherGraphs({
|
|||||||
<ResponsiveContainer width={'100%'} height={150}>
|
<ResponsiveContainer width={'100%'} height={150}>
|
||||||
<AreaChart data={hourlyForecast}>
|
<AreaChart data={hourlyForecast}>
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id='colorPrecipitation' x1='0' y1='0' x2='0' y2='1'>
|
<linearGradient id={colorPrecipitation} x1='0' y1='0' x2='0' y2='1'>
|
||||||
<stop
|
<stop
|
||||||
offset='40%'
|
offset='40%'
|
||||||
stopColor='var(--mantine-color-primary-0)'
|
stopColor='var(--mantine-color-primary-0)'
|
||||||
@@ -115,7 +96,7 @@ export default function WeatherGraphs({
|
|||||||
stopOpacity={0}
|
stopOpacity={0}
|
||||||
/>
|
/>
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
<linearGradient id='colorHumidity' x1='0' y1='0' x2='0' y2='1'>
|
<linearGradient id={colorHumidity} x1='0' y1='0' x2='0' y2='1'>
|
||||||
<stop
|
<stop
|
||||||
offset='20%'
|
offset='20%'
|
||||||
stopColor='var(--mantine-color-accent-0)'
|
stopColor='var(--mantine-color-accent-0)'
|
||||||
@@ -140,7 +121,7 @@ export default function WeatherGraphs({
|
|||||||
/>
|
/>
|
||||||
<YAxis stroke={'var(--mantine-color-primary-0)'} unit={'%'} domain={[0, 100]} />
|
<YAxis stroke={'var(--mantine-color-primary-0)'} unit={'%'} domain={[0, 100]} />
|
||||||
<CartesianGrid stroke='#f5f5f522' />
|
<CartesianGrid stroke='#f5f5f522' />
|
||||||
<Tooltip content={<CustomTooltip />} />
|
<Tooltip content={<WeatherTooltip />} />
|
||||||
<Area
|
<Area
|
||||||
unit={'%'}
|
unit={'%'}
|
||||||
type='monotone'
|
type='monotone'
|
||||||
@@ -150,7 +131,7 @@ export default function WeatherGraphs({
|
|||||||
}}
|
}}
|
||||||
stroke={'var(--mantine-color-primary-0)'}
|
stroke={'var(--mantine-color-primary-0)'}
|
||||||
strokeWidth={2}
|
strokeWidth={2}
|
||||||
fill={'url(#colorPrecipitation)'}
|
fill={`url(#${colorPrecipitation})`}
|
||||||
dot={{
|
dot={{
|
||||||
stroke: 'var(--mantine-color-primary-0)',
|
stroke: 'var(--mantine-color-primary-0)',
|
||||||
strokeWidth: 0,
|
strokeWidth: 0,
|
||||||
@@ -166,7 +147,7 @@ export default function WeatherGraphs({
|
|||||||
}}
|
}}
|
||||||
stroke={'var(--mantine-color-accent-0)'}
|
stroke={'var(--mantine-color-accent-0)'}
|
||||||
strokeWidth={2}
|
strokeWidth={2}
|
||||||
fill={'url(#colorHumidity)'}
|
fill={`url(#${colorHumidity})`}
|
||||||
dot={{
|
dot={{
|
||||||
stroke: 'var(--mantine-color-accent-0)',
|
stroke: 'var(--mantine-color-accent-0)',
|
||||||
strokeWidth: 0,
|
strokeWidth: 0,
|
||||||
|
|||||||
@@ -15,259 +15,167 @@ export default function WeatherIcon({ textDescription }: { textDescription: stri
|
|||||||
? textDescription.substring(0, textDescription.trim().indexOf('then'))
|
? textDescription.substring(0, textDescription.trim().indexOf('then'))
|
||||||
: textDescription;
|
: textDescription;
|
||||||
|
|
||||||
const Icon = () => {
|
const lookupSource = (icon: any) => {
|
||||||
switch (icon.trim()) {
|
switch (icon.trim()) {
|
||||||
case 'Ash':
|
case 'Ash':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: HazeIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'HazeIcon',
|
||||||
src={HazeIcon}
|
};
|
||||||
alt='HazeIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Broken Clouds':
|
case 'Broken Clouds':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: PartlyCloudyIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'PartlyCloudyIcon',
|
||||||
src={PartlyCloudyIcon}
|
};
|
||||||
alt='PartlyCloudyIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Chance Rain Showers':
|
case 'Chance Rain Showers':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: RainIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'RainIcon',
|
||||||
src={RainIcon}
|
};
|
||||||
alt='RainIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Chance Showers':
|
case 'Chance Showers':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: RainIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'RainIcon',
|
||||||
src={RainIcon}
|
};
|
||||||
alt='RainIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Slight Chance Showers':
|
case 'Slight Chance Showers':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: RainIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'RainIcon',
|
||||||
src={RainIcon}
|
};
|
||||||
alt='RainIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Clear':
|
|
||||||
return (
|
|
||||||
<Image
|
|
||||||
style={{ width: '75px', height: '75px' }}
|
|
||||||
src={SunnyIcon}
|
|
||||||
alt='SunnyIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Cloudy':
|
case 'Cloudy':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: CloudyIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'CloudyIcon',
|
||||||
src={CloudyIcon}
|
};
|
||||||
alt='CloudyIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Dust':
|
case 'Dust':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: HazeIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'HazeIcon',
|
||||||
src={HazeIcon}
|
};
|
||||||
alt='HazeIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Drizzle':
|
case 'Drizzle':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: RainIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'RainIcon',
|
||||||
src={RainIcon}
|
};
|
||||||
alt='RainIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Fog':
|
case 'Fog':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: HazeIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'HazeIcon',
|
||||||
src={HazeIcon}
|
};
|
||||||
alt='HazeIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Freezing Rain':
|
case 'Freezing Rain':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: SleetIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'SleetIcon',
|
||||||
src={SleetIcon}
|
};
|
||||||
alt='SleetIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Haze':
|
case 'Haze':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: HazeIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'HazeIcon',
|
||||||
src={HazeIcon}
|
};
|
||||||
alt='HazeIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Heavy Rain':
|
case 'Heavy Rain':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: HeavyRainIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'HeavyRainIcon',
|
||||||
src={HeavyRainIcon}
|
};
|
||||||
alt='HeavyRainIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Heavy Snow':
|
case 'Heavy Snow':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: SnowIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'SnowIcon',
|
||||||
src={SnowIcon}
|
};
|
||||||
alt='SnowIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Light Rain':
|
case 'Light Rain':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: RainIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'RainIcon',
|
||||||
src={RainIcon}
|
};
|
||||||
alt='RainIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Mist':
|
case 'Mist':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: HazeIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'HazeIcon',
|
||||||
src={HazeIcon}
|
};
|
||||||
alt='HazeIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Moderate Rain':
|
case 'Moderate Rain':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: RainIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'RainIcon',
|
||||||
src={RainIcon}
|
};
|
||||||
alt='RainIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Mostly Cloudy':
|
case 'Mostly Cloudy':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: CloudyIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'CloudyIcon',
|
||||||
src={CloudyIcon}
|
};
|
||||||
alt='CloudyIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Overcast Clouds':
|
case 'Overcast Clouds':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: PartlyCloudyIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'PartlyCloudyIcon',
|
||||||
src={PartlyCloudyIcon}
|
};
|
||||||
alt='PartlyCloudyIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Patchy Fog':
|
case 'Patchy Fog':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: HazeIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'HazeIcon',
|
||||||
src={HazeIcon}
|
};
|
||||||
alt='HazeIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Partly Sunny':
|
case 'Partly Sunny':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: PartlyCloudyIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'PartlyCloudyIcon',
|
||||||
src={PartlyCloudyIcon}
|
};
|
||||||
alt='PartlyCloudyIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Rain':
|
case 'Rain':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: RainIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'RainIcon',
|
||||||
src={RainIcon}
|
};
|
||||||
alt='RainIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Scattered Clouds':
|
case 'Scattered Clouds':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: PartlyCloudyIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'PartlyCloudyIcon',
|
||||||
src={PartlyCloudyIcon}
|
};
|
||||||
alt='PartlyCloudyIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Showers':
|
case 'Showers':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: RainIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'RainIcon',
|
||||||
src={RainIcon}
|
};
|
||||||
alt='RainIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Sleet':
|
case 'Sleet':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: SleetIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'SleetIcon',
|
||||||
src={SleetIcon}
|
};
|
||||||
alt='SleetIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Smoke':
|
case 'Smoke':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: HazeIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'HazeIcon',
|
||||||
src={HazeIcon}
|
};
|
||||||
alt='HazeIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Snow':
|
case 'Snow':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: SnowIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'SnowIcon',
|
||||||
src={SnowIcon}
|
};
|
||||||
alt='SnowIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Squall':
|
case 'Squall':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: WindyIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'WindyIcon',
|
||||||
src={WindyIcon}
|
};
|
||||||
alt='WindyIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Thunderstorm':
|
case 'Thunderstorm':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: ThunderstormIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'ThunderstormIcon',
|
||||||
src={ThunderstormIcon}
|
};
|
||||||
alt='ThunderstormIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'Tornado':
|
case 'Tornado':
|
||||||
return (
|
return {
|
||||||
<Image
|
src: WindyIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'WindyIcon',
|
||||||
src={WindyIcon}
|
};
|
||||||
alt='WindyIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return (
|
return {
|
||||||
<Image
|
src: SunnyIcon,
|
||||||
style={{ width: '75px', height: '75px' }}
|
alt: 'SunnyIcon',
|
||||||
src={SunnyIcon}
|
};
|
||||||
alt='SunnyIcon'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Icon />;
|
return (
|
||||||
|
<Image
|
||||||
|
style={{ width: '75px', height: '75px' }}
|
||||||
|
src={lookupSource(icon).src}
|
||||||
|
alt={lookupSource(icon).alt}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { Center, Group, Modal, Stack, Text } from '@mantine/core';
|
import { Center, Group, Modal, Stack, Text } from '@mantine/core';
|
||||||
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 { modalClasses } from 'styles';
|
||||||
|
|
||||||
import type { CurrentWeather as CW, ExtendedForecast, HourlyForecast } from 'types';
|
import type { CurrentWeather as CW, ExtendedForecast, HourlyForecast } from 'types';
|
||||||
import CurrentWeather from './CurrentWeather';
|
import CurrentWeather from './CurrentWeather';
|
||||||
|
|||||||
27
src/components/WeatherModal/WeatherTooltip.tsx
Normal file
27
src/components/WeatherModal/WeatherTooltip.tsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { Stack, Text } from '@mantine/core';
|
||||||
|
|
||||||
|
function WeatherTooltip({ payload, active }: any) {
|
||||||
|
if (active) {
|
||||||
|
return (
|
||||||
|
<Stack
|
||||||
|
style={{
|
||||||
|
backgroundColor: 'var(--mantine-color-background-0)',
|
||||||
|
padding: '1rem',
|
||||||
|
borderRadius: '8px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{payload.map((item: any) => (
|
||||||
|
<Text
|
||||||
|
key={item.name}
|
||||||
|
size='md'
|
||||||
|
c={item.stroke}
|
||||||
|
>{`${item.name} - ${item.value}${item.unit}`}</Text>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WeatherTooltip;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
export { HelpModal } from './HelpModal/HelpModal';
|
export { HelpModal } from './HelpModal/HelpModal';
|
||||||
export { WeatherModal } from './WeatherModal/WeatherModal';
|
|
||||||
export { MainLayout } from './MainLayout';
|
|
||||||
export { Loading } from './Loading';
|
export { Loading } from './Loading';
|
||||||
|
export { MainLayout } from './MainLayout';
|
||||||
|
export { WeatherModal } from './WeatherModal/WeatherModal';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export {
|
export {
|
||||||
useQueryAPI,
|
|
||||||
useWeatherAPI,
|
|
||||||
useMutationAPI,
|
useMutationAPI,
|
||||||
useOSMAPI,
|
useOSMAPI,
|
||||||
|
useQueryAPI,
|
||||||
|
useWeatherAPI,
|
||||||
} from './useAPI';
|
} from './useAPI';
|
||||||
export { useCommonHooks } from './useCommonHooks';
|
export { useCommonHooks } from './useCommonHooks';
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ import BookmarkItem from './BookmarkItem';
|
|||||||
function BookmarkGroups({
|
function BookmarkGroups({
|
||||||
bookmarks,
|
bookmarks,
|
||||||
category,
|
category,
|
||||||
}: { bookmarks: Bookmark[]; category: string }) {
|
}: {
|
||||||
|
bookmarks: Bookmark[];
|
||||||
|
category: string;
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<Stack
|
<Stack
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -1,17 +1,9 @@
|
|||||||
import {
|
import { type OptionsFilter, Select, Stack, Text } from '@mantine/core';
|
||||||
ActionIcon,
|
|
||||||
Group,
|
|
||||||
type OptionsFilter,
|
|
||||||
Select,
|
|
||||||
Stack,
|
|
||||||
Text,
|
|
||||||
} from '@mantine/core';
|
|
||||||
import { useDisclosure } from '@mantine/hooks';
|
import { useDisclosure } from '@mantine/hooks';
|
||||||
import { HelpModal, WeatherModal } from 'components';
|
import { HelpModal, WeatherModal } from 'components';
|
||||||
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { FiEdit, FiTrash } from 'react-icons/fi';
|
import { selectClasses } from 'styles';
|
||||||
import { actionIconClasses, selectClasses } from 'styles';
|
|
||||||
import type {
|
import type {
|
||||||
Application,
|
Application,
|
||||||
CurrentWeather,
|
CurrentWeather,
|
||||||
@@ -19,6 +11,7 @@ import type {
|
|||||||
Provider,
|
Provider,
|
||||||
SearchHistoryItem,
|
SearchHistoryItem,
|
||||||
} from 'types';
|
} from 'types';
|
||||||
|
import SearchSelectItem from './SearchHistoryItem';
|
||||||
|
|
||||||
export default function Search({
|
export default function Search({
|
||||||
current,
|
current,
|
||||||
@@ -53,7 +46,6 @@ export default function Search({
|
|||||||
const [dropdownOpened, { open: openDropdown, close: closeDropdown }] = useDisclosure();
|
const [dropdownOpened, { open: openDropdown, close: closeDropdown }] = useDisclosure();
|
||||||
const [listIndex, setListIndex] = useState(0);
|
const [listIndex, setListIndex] = useState(0);
|
||||||
const {
|
const {
|
||||||
theme,
|
|
||||||
isMobile,
|
isMobile,
|
||||||
urlPattern,
|
urlPattern,
|
||||||
providerLabel,
|
providerLabel,
|
||||||
@@ -272,112 +264,6 @@ export default function Search({
|
|||||||
.slice(0, 10);
|
.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(() => {
|
useEffect(() => {
|
||||||
if (providerData && providerDataIsFetched) {
|
if (providerData && providerDataIsFetched) {
|
||||||
setProviders(providerData);
|
setProviders(providerData);
|
||||||
@@ -460,7 +346,13 @@ export default function Search({
|
|||||||
autoFocus={!isMobile}
|
autoFocus={!isMobile}
|
||||||
leftSection={providerLabel}
|
leftSection={providerLabel}
|
||||||
rightSection={<Stack />}
|
rightSection={<Stack />}
|
||||||
renderOption={RenderOption}
|
renderOption={(item: any) => (
|
||||||
|
<SearchSelectItem
|
||||||
|
item={item}
|
||||||
|
handleSearchHistoryItem={handleSearchHistoryItem}
|
||||||
|
searchEndpoint={searchEndpoint}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
onBlur={() => {
|
onBlur={() => {
|
||||||
setPlaceholderValue('');
|
setPlaceholderValue('');
|
||||||
setListIndex(0);
|
setListIndex(0);
|
||||||
|
|||||||
115
src/pages/homepage/components/Search/SearchHistoryItem.tsx
Normal file
115
src/pages/homepage/components/Search/SearchHistoryItem.tsx
Normal 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;
|
||||||
@@ -23,7 +23,11 @@ function DebouncedApplication({
|
|||||||
application,
|
application,
|
||||||
setIsOpen,
|
setIsOpen,
|
||||||
allIcons,
|
allIcons,
|
||||||
}: { application: Application; setIsOpen: (isOpen: boolean) => void; allIcons: any }) {
|
}: {
|
||||||
|
application: Application;
|
||||||
|
setIsOpen: (isOpen: boolean) => void;
|
||||||
|
allIcons: any;
|
||||||
|
}) {
|
||||||
const { handleDelete, isMobile } = useCommonHooks();
|
const { handleDelete, isMobile } = useCommonHooks();
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import AddItemModal from '../Shared/AddItemModal';
|
|||||||
import NoItemsFound from '../Shared/NoItemsFound';
|
import NoItemsFound from '../Shared/NoItemsFound';
|
||||||
import SettingsHeader from '../Shared/SettingsHeader';
|
import SettingsHeader from '../Shared/SettingsHeader';
|
||||||
import DebouncedGroupSettingsItem from './DebouncedGroupSettingsItem';
|
import DebouncedGroupSettingsItem from './DebouncedGroupSettingsItem';
|
||||||
|
|
||||||
const BookmarkSettings = () => {
|
const BookmarkSettings = () => {
|
||||||
const defaultGroup = {
|
const defaultGroup = {
|
||||||
id: null,
|
id: null,
|
||||||
|
|||||||
@@ -10,7 +10,10 @@ import DeleteItemModal from '../Shared/DeleteItemModal';
|
|||||||
function DebouncedBookmarkItem({
|
function DebouncedBookmarkItem({
|
||||||
bookmarkItem,
|
bookmarkItem,
|
||||||
setIsOpen,
|
setIsOpen,
|
||||||
}: { bookmarkItem: Bookmark; setIsOpen: (isOpen: boolean) => void }) {
|
}: {
|
||||||
|
bookmarkItem: Bookmark;
|
||||||
|
setIsOpen: (isOpen: boolean) => void;
|
||||||
|
}) {
|
||||||
const { handleDelete, isMobile } = useCommonHooks();
|
const { handleDelete, isMobile } = useCommonHooks();
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
|
|||||||
@@ -33,7 +33,11 @@ function DebouncedGroupSettingsItem({
|
|||||||
bookmarkGroup,
|
bookmarkGroup,
|
||||||
bookmarks,
|
bookmarks,
|
||||||
searchTerm,
|
searchTerm,
|
||||||
}: { bookmarkGroup: BookmarkGroup; bookmarks: Bookmark[]; searchTerm: string }) {
|
}: {
|
||||||
|
bookmarkGroup: BookmarkGroup;
|
||||||
|
bookmarks: Bookmark[];
|
||||||
|
searchTerm: string;
|
||||||
|
}) {
|
||||||
const { isMobile, handleDelete, reorder } = useCommonHooks();
|
const { 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);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import { cardClasses, textInputClasses } from 'styles';
|
import { cardClasses, textInputClasses } from 'styles';
|
||||||
import type { PersonalData } from 'types';
|
import type { PersonalData } from 'types';
|
||||||
import SettingsHeader from '../Shared/SettingsHeader';
|
import SettingsHeader from '../Shared/SettingsHeader';
|
||||||
|
|
||||||
const PersonalizationSettings = () => {
|
const PersonalizationSettings = () => {
|
||||||
const endpoint = 'api/personalData';
|
const endpoint = 'api/personalData';
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useCommonHooks } from 'hooks';
|
import { useCommonHooks } from 'hooks';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { FiHelpCircle, FiLoader, FiPlus } from 'react-icons/fi';
|
import { FiHelpCircle, FiLoader, FiPlus, FiX } from 'react-icons/fi';
|
||||||
import {
|
import {
|
||||||
actionIconClasses,
|
actionIconClasses,
|
||||||
buttonClasses,
|
buttonClasses,
|
||||||
@@ -137,13 +137,23 @@ function SettingsHeader({
|
|||||||
zIndex: 100,
|
zIndex: 100,
|
||||||
}}
|
}}
|
||||||
rightSection={
|
rightSection={
|
||||||
isLoading && (
|
isLoading ? (
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
className={actionIconClasses.loadingSpinner}
|
className={actionIconClasses.loadingSpinner}
|
||||||
classNames={actionIconClasses}
|
classNames={actionIconClasses}
|
||||||
>
|
>
|
||||||
<FiLoader />
|
<FiLoader />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
|
) : (
|
||||||
|
searchValue && (
|
||||||
|
<ActionIcon
|
||||||
|
className={actionIconClasses.settingsTooltip}
|
||||||
|
classNames={actionIconClasses}
|
||||||
|
onClick={() => setSearchValue('')}
|
||||||
|
>
|
||||||
|
<FiX />
|
||||||
|
</ActionIcon>
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
69
src/pages/settings/components/Theming/ThemeExampleApp.tsx
Normal file
69
src/pages/settings/components/Theming/ThemeExampleApp.tsx
Normal 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;
|
||||||
@@ -1,12 +1,7 @@
|
|||||||
import { Group, Text } from '@mantine/core';
|
import { Group, Text } from '@mantine/core';
|
||||||
import type { Theme } from 'types';
|
import type { Theme } from 'types';
|
||||||
function ThemeMiniCard({
|
|
||||||
allThemes,
|
function ThemeMiniCard({ allThemes, item }: { allThemes: Theme[]; item: number }) {
|
||||||
item,
|
|
||||||
}: {
|
|
||||||
allThemes: Theme[];
|
|
||||||
item: number;
|
|
||||||
}) {
|
|
||||||
const theme = allThemes?.find((theme: Theme) => theme.id === item);
|
const theme = allThemes?.find((theme: Theme) => theme.id === item);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -19,9 +14,10 @@ function ThemeMiniCard({
|
|||||||
w={'175px'}
|
w={'175px'}
|
||||||
h={'60px'}
|
h={'60px'}
|
||||||
style={{
|
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',
|
backgroundSize: 'cover',
|
||||||
backgroundColor: theme?.backgroundColor,
|
backgroundColor: theme?.backgroundColor,
|
||||||
|
backgroundPosition: 'center',
|
||||||
border: `solid ${theme?.borderColor}`,
|
border: `solid ${theme?.borderColor}`,
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,84 +1,22 @@
|
|||||||
import { Box, Group, Stack, Text } from '@mantine/core';
|
import { Group, Stack, Text } from '@mantine/core';
|
||||||
import { useState } from 'react';
|
|
||||||
import { FiCheck } from 'react-icons/fi';
|
|
||||||
import { stackClasses } from 'styles';
|
|
||||||
import type { Theme } from 'types';
|
import type { Theme } from 'types';
|
||||||
|
import ThemeExampleApp from './ThemeExampleApp';
|
||||||
|
|
||||||
export default function ThemeModalContent({ selectedTheme }: { selectedTheme: Theme }) {
|
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 (
|
return (
|
||||||
<Stack
|
<Stack
|
||||||
style={{
|
style={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
background:
|
backgroundImage:
|
||||||
selectedTheme.backgroundImage !== 'none'
|
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,
|
: undefined,
|
||||||
backgroundSize: selectedTheme.backgroundImage !== 'none' ? 'cover' : undefined,
|
backgroundSize: selectedTheme.backgroundImage !== 'none' ? 'cover' : undefined,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
selectedTheme.backgroundImage === 'none'
|
selectedTheme.backgroundImage === 'none'
|
||||||
? selectedTheme.backgroundColor
|
? selectedTheme.backgroundColor
|
||||||
: undefined,
|
: undefined,
|
||||||
|
backgroundPosition: 'center',
|
||||||
borderRadius: '10px',
|
borderRadius: '10px',
|
||||||
border: '2px solid',
|
border: '2px solid',
|
||||||
}}
|
}}
|
||||||
@@ -124,9 +62,9 @@ export default function ThemeModalContent({ selectedTheme }: { selectedTheme: Th
|
|||||||
alignContent: 'center',
|
alignContent: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ExampleApp />
|
<ThemeExampleApp selectedTheme={selectedTheme} />
|
||||||
<ExampleApp />
|
<ThemeExampleApp selectedTheme={selectedTheme} />
|
||||||
<ExampleApp />
|
<ThemeExampleApp selectedTheme={selectedTheme} />
|
||||||
</Stack>
|
</Stack>
|
||||||
<Text
|
<Text
|
||||||
pl={'1.5rem'}
|
pl={'1.5rem'}
|
||||||
|
|||||||
@@ -57,8 +57,10 @@ function ThemePlaylists() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (themePlaylistData && isThemePlaylistDataFetched) {
|
if (themePlaylistData && isThemePlaylistDataFetched) {
|
||||||
setThemePlaylists(
|
setThemePlaylists(
|
||||||
themePlaylistData.filter((a: ThemePlaylist) =>
|
themePlaylistData.filter(
|
||||||
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()),
|
(a: ThemePlaylist) =>
|
||||||
|
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()) ||
|
||||||
|
a.name.includes('Time of Day'),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -95,7 +97,7 @@ function ThemePlaylists() {
|
|||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
setIsLoading={setIsLoading}
|
setIsLoading={setIsLoading}
|
||||||
/>
|
/>
|
||||||
{allThemeData ? (
|
{allThemeData && (
|
||||||
<>
|
<>
|
||||||
<Group mt={'6rem'} justify='center' align='center' pos={'relative'}>
|
<Group mt={'6rem'} justify='center' align='center' pos={'relative'}>
|
||||||
<Text
|
<Text
|
||||||
@@ -293,8 +295,6 @@ function ThemePlaylists() {
|
|||||||
)}
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
</>
|
</>
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ function ThemesSettings() {
|
|||||||
currentThemePlaylist,
|
currentThemePlaylist,
|
||||||
setCurrentThemePlaylist,
|
setCurrentThemePlaylist,
|
||||||
} = useCommonHooks();
|
} = useCommonHooks();
|
||||||
|
|
||||||
const handleOpen = (theme: Theme) => {
|
const handleOpen = (theme: Theme) => {
|
||||||
setSelectedTheme(theme);
|
setSelectedTheme(theme);
|
||||||
open();
|
open();
|
||||||
@@ -267,7 +266,7 @@ function ThemesSettings() {
|
|||||||
navigate(`/${import.meta.env.VITE_BASE_URL}/settings/themePlaylists`);
|
navigate(`/${import.meta.env.VITE_BASE_URL}/settings/themePlaylists`);
|
||||||
} else {
|
} else {
|
||||||
setCurrentThemePlaylist('All');
|
setCurrentThemePlaylist('All');
|
||||||
setCurrentTheme('random');
|
setCurrentTheme(theme.name);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
export type {
|
export type { AppCategory, Application } from './application';
|
||||||
CurrentWeather,
|
|
||||||
OutlookWeather,
|
|
||||||
ExtendedForecast,
|
|
||||||
HourlyForecast,
|
|
||||||
SunState,
|
|
||||||
} from './weather';
|
|
||||||
export type { Application, AppCategory } from './application';
|
|
||||||
export type { Bookmark } from './bookmark';
|
export type { Bookmark } from './bookmark';
|
||||||
export type { BookmarkGroup } from './bookmarkGroup';
|
export type { BookmarkGroup } from './bookmarkGroup';
|
||||||
export type { PersonalData } from './personalData';
|
|
||||||
export type { Message } from './message';
|
|
||||||
export type { Provider } from './provider';
|
|
||||||
export type { Theme, ThemePlaylist } from './theme';
|
|
||||||
export type { WolClient } from './wolClient';
|
|
||||||
export type { SearchHistoryItem, SearchShortcut } from './search';
|
|
||||||
export type { User } from './user';
|
|
||||||
export type { Location } from './location';
|
export type { Location } from './location';
|
||||||
|
export type { Message } from './message';
|
||||||
|
export type { PersonalData } from './personalData';
|
||||||
|
export type { Provider } from './provider';
|
||||||
|
export type { SearchHistoryItem, SearchShortcut } from './search';
|
||||||
|
export type { Theme, ThemePlaylist } from './theme';
|
||||||
|
export type { User } from './user';
|
||||||
|
export type {
|
||||||
|
CurrentWeather,
|
||||||
|
ExtendedForecast,
|
||||||
|
HourlyForecast,
|
||||||
|
OutlookWeather,
|
||||||
|
SunState,
|
||||||
|
} from './weather';
|
||||||
|
export type { WolClient } from './wolClient';
|
||||||
|
|||||||
Reference in New Issue
Block a user