diff --git a/src/components/layout/Aside.tsx b/src/components/layout/Aside.tsx
index 9154fea10..9d05d196e 100644
--- a/src/components/layout/Aside.tsx
+++ b/src/components/layout/Aside.tsx
@@ -1,4 +1,5 @@
-import { Aside as MantineAside, Group } from '@mantine/core';
+import { Aside as MantineAside, createStyles, Group } from '@mantine/core';
+import { useMediaQuery } from '@mantine/hooks';
import {
WeatherModule,
DateModule,
@@ -8,12 +9,29 @@ import {
} from '../modules';
import { ModuleWrapper } from '../modules/moduleWrapper';
+const useStyles = createStyles((theme) => ({
+ hide: {
+ [theme.fn.smallerThan('xs')]: {
+ display: 'none',
+ },
+ },
+ burger: {
+ [theme.fn.largerThan('sm')]: {
+ display: 'none',
+ },
+ },
+}));
+
export default function Aside(props: any) {
+ const { classes, cx } = useStyles();
+ const matches = useMediaQuery('(min-width: 800px)');
+
return (
-
-
-
-
-
-
-
+ {matches && (
+
+
+
+
+
+
+
+ )}
);
}
diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx
index 28ed95f46..145e89e57 100644
--- a/src/components/layout/Header.tsx
+++ b/src/components/layout/Header.tsx
@@ -1,9 +1,29 @@
import React from 'react';
-import { createStyles, Header as Head, Group, Box } from '@mantine/core';
+import {
+ createStyles,
+ Header as Head,
+ Group,
+ Box,
+ Burger,
+ Drawer,
+ Title,
+ ScrollArea,
+ ActionIcon,
+ Transition,
+} from '@mantine/core';
+import { useBooleanToggle } from '@mantine/hooks';
import { Logo } from './Logo';
import SearchBar from '../modules/search/SearchModule';
import { AddItemShelfButton } from '../AppShelf/AddAppShelfItem';
import { SettingsMenuButton } from '../Settings/SettingsMenu';
+import { ModuleWrapper } from '../modules/moduleWrapper';
+import {
+ CalendarModule,
+ TotalDownloadsModule,
+ WeatherModule,
+ DateModule,
+ SystemModule,
+} from '../modules';
const HEADER_HEIGHT = 60;
@@ -13,10 +33,18 @@ const useStyles = createStyles((theme) => ({
display: 'none',
},
},
+ burger: {
+ [theme.fn.largerThan('sm')]: {
+ display: 'none',
+ },
+ },
}));
export function Header(props: any) {
+ const [opened, toggleOpened] = useBooleanToggle(false);
const { classes, cx } = useStyles();
+ const [hidden, toggleHidden] = useBooleanToggle(true);
+ const drawerModule = CalendarModule;
return (
@@ -28,6 +56,48 @@ export function Header(props: any) {
+
+ {
+ toggleHidden();
+ toggleOpened();
+ }}
+ />
+
+ Modules}
+ opened
+ onClose={() => {
+ toggleHidden();
+ }}
+ >
+ toggleOpened()}
+ >
+ {(styles) => (
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
+
diff --git a/src/components/layout/Layout.tsx b/src/components/layout/Layout.tsx
index ac2c3c742..116c6516f 100644
--- a/src/components/layout/Layout.tsx
+++ b/src/components/layout/Layout.tsx
@@ -1,16 +1,37 @@
-import { AppShell, createStyles } from '@mantine/core';
+import { AppShell, createStyles, Group } from '@mantine/core';
import { Header } from './Header';
import { Footer } from './Footer';
import Aside from './Aside';
+import { ModuleWrapper } from '../modules/moduleWrapper';
+import {
+ CalendarModule,
+ TotalDownloadsModule,
+ WeatherModule,
+ DateModule,
+ SystemModule,
+} from '../modules';
const useStyles = createStyles((theme) => ({
main: {},
}));
export default function Layout({ children, style }: any) {
+ const drawerContent = (
+
+
+
+
+
+
+
+ );
const { classes, cx } = useStyles();
return (
- } header={} footer={}>
+ }
+ header={}
+ footer={}
+ >
)}
setOpened(false)}
opened={opened}
target={day}
@@ -197,12 +197,18 @@ function DayComponent(props: any) {
{index < radarrFiltered.length - 1 && }
))}
+ {sonarrFiltered.length > 0 && lidarrFiltered.length > 0 && (
+
+ )}
{lidarrFiltered.map((media: any, index: number) => (
{index < lidarrFiltered.length - 1 && }
))}
+ {lidarrFiltered.length > 0 && readarrFiltered.length > 0 && (
+
+ )}
{readarrFiltered.map((media: any, index: number) => (
diff --git a/src/components/modules/common/MediaDisplay.tsx b/src/components/modules/common/MediaDisplay.tsx
index d8d945d67..171aea61a 100644
--- a/src/components/modules/common/MediaDisplay.tsx
+++ b/src/components/modules/common/MediaDisplay.tsx
@@ -1,4 +1,14 @@
-import { Image, Group, Title, Badge, Text, ActionIcon, Anchor, ScrollArea } from '@mantine/core';
+import {
+ Image,
+ Group,
+ Title,
+ Badge,
+ Text,
+ ActionIcon,
+ Anchor,
+ ScrollArea,
+ createStyles,
+} from '@mantine/core';
import { IconLink as Link } from '@tabler/icons';
import { useConfig } from '../../../tools/state';
import { serviceItem } from '../../../tools/types';
@@ -14,13 +24,31 @@ export interface IMedia {
episodeNumber?: number;
}
+const useStyles = createStyles((theme) => ({
+ poster: {
+ [theme.fn.smallerThan('sm')]: {
+ maxWidth: '20%',
+ },
+ [theme.fn.largerThan('sm')]: {
+ maxWidth: 300,
+ },
+ },
+ overview: {
+ [theme.fn.largerThan('sm')]: {
+ width: 400,
+ },
+ },
+}));
+
export function MediaDisplay(props: { media: IMedia }) {
const { media }: { media: IMedia } = props;
+ const { classes, cx } = useStyles();
return (
{media.poster && (
)}
-
+
{media.title}
{media.imdbId && (
@@ -65,7 +91,7 @@ export function MediaDisplay(props: { media: IMedia }) {
)}
- {media.overview}
+ {media.overview}
{media.genres.map((genre: string, i: number) => (
diff --git a/src/components/modules/date/DateModule.tsx b/src/components/modules/date/DateModule.tsx
index d84e42b9b..ad5991736 100644
--- a/src/components/modules/date/DateModule.tsx
+++ b/src/components/modules/date/DateModule.tsx
@@ -4,6 +4,7 @@ import { useEffect, useState } from 'react';
import { IconClock as Clock } from '@tabler/icons';
import { useConfig } from '../../../tools/state';
import { IModule } from '../modules';
+import { useSetSafeInterval } from '../../../tools/hooks/useSetSafeInterval';
export const DateModule: IModule = {
title: 'Date',
@@ -20,13 +21,14 @@ export const DateModule: IModule = {
export default function DateComponent(props: any) {
const [date, setDate] = useState(new Date());
+ const setSafeInterval = useSetSafeInterval();
const { config } = useConfig();
const isFullTime = config?.modules?.[DateModule.title]?.options?.full?.value ?? false;
const formatString = isFullTime ? 'HH:mm' : 'h:mm A';
// Change date on minute change
// Note: Using 10 000ms instead of 1000ms to chill a little :)
useEffect(() => {
- setInterval(() => {
+ setSafeInterval(() => {
setDate(new Date());
}, 1000 * 60);
}, []);
diff --git a/src/components/modules/downloads/DownloadsModule.tsx b/src/components/modules/downloads/DownloadsModule.tsx
index a9fc4fe2c..a77ec4976 100644
--- a/src/components/modules/downloads/DownloadsModule.tsx
+++ b/src/components/modules/downloads/DownloadsModule.tsx
@@ -6,6 +6,7 @@ import { NormalizedTorrent } from '@ctrl/shared-torrent';
import { IModule } from '../modules';
import { useConfig } from '../../../tools/state';
import { AddItemShelfButton } from '../../AppShelf/AddAppShelfItem';
+import { useSetSafeInterval } from '../../../tools/hooks/useSetSafeInterval';
export const DownloadsModule: IModule = {
title: 'Torrent',
@@ -31,10 +32,10 @@ export default function DownloadComponent() {
const [delugeTorrents, setDelugeTorrents] = useState([]);
const [qBittorrentTorrents, setqBittorrentTorrents] = useState([]);
-
+ const setSafeInterval = useSetSafeInterval();
useEffect(() => {
if (qBittorrentService) {
- setInterval(() => {
+ setSafeInterval(() => {
axios
.post('/api/modules/downloads?dlclient=qbit', { ...qBittorrentService })
.then((res) => {
@@ -43,7 +44,7 @@ export default function DownloadComponent() {
}, 3000);
}
if (delugeService) {
- setInterval(() => {
+ setSafeInterval(() => {
axios.post('/api/modules/downloads?dlclient=deluge', { ...delugeService }).then((res) => {
setDelugeTorrents(res.data.torrents);
});
diff --git a/src/components/modules/downloads/TotalDownloadsModule.tsx b/src/components/modules/downloads/TotalDownloadsModule.tsx
index 915e46912..6065066e7 100644
--- a/src/components/modules/downloads/TotalDownloadsModule.tsx
+++ b/src/components/modules/downloads/TotalDownloadsModule.tsx
@@ -9,6 +9,7 @@ import { useListState } from '@mantine/hooks';
import { AddItemShelfButton } from '../../AppShelf/AddAppShelfItem';
import { useConfig } from '../../../tools/state';
import { IModule } from '../modules';
+import { useSetSafeInterval } from '../../../tools/hooks/useSetSafeInterval';
/**
* Format bytes as human-readable text.
@@ -74,9 +75,9 @@ export default function TotalDownloadsComponent() {
const totalDownloadSpeed = torrents.reduce((acc, torrent) => acc + torrent.downloadSpeed, 0);
const totalUploadSpeed = torrents.reduce((acc, torrent) => acc + torrent.uploadSpeed, 0);
-
+ const setSafeInterval = useSetSafeInterval();
useEffect(() => {
- const interval = setInterval(() => {
+ setSafeInterval(() => {
// Get the current download speed of qBittorrent.
if (qBittorrentService) {
axios
diff --git a/src/components/modules/system/SystemModule.tsx b/src/components/modules/system/SystemModule.tsx
index 2b84357f2..8201f36cc 100644
--- a/src/components/modules/system/SystemModule.tsx
+++ b/src/components/modules/system/SystemModule.tsx
@@ -1,16 +1,11 @@
-import {
- Center,
- Group,
- RingProgress,
- Title,
- useMantineTheme,
-} from '@mantine/core';
+import { Center, Group, RingProgress, Title, useMantineTheme } from '@mantine/core';
import { IconCpu } from '@tabler/icons';
import { useEffect, useState } from 'react';
import axios from 'axios';
import si from 'systeminformation';
import { useListState } from '@mantine/hooks';
import { IModule } from '../modules';
+import { useSetSafeInterval } from '../../../tools/hooks/useSetSafeInterval';
export const SystemModule: IModule = {
title: 'System info',
@@ -28,13 +23,13 @@ interface ApiResponse {
export default function SystemInfo(args: any) {
const [data, setData] = useState();
-
+ const setSafeInterval = useSetSafeInterval();
// Refresh data every second
useEffect(() => {
- setInterval(() => {
+ setSafeInterval(() => {
axios.get('/api/modules/systeminfo').then((res) => setData(res.data));
}, 1000);
- }, [args]);
+ }, []);
// Update data every time data changes
const [cpuLoadHistory, cpuLoadHistoryHandlers] =