diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
new file mode 100644
index 000000000..d862b38e4
--- /dev/null
+++ b/.github/workflows/docker.yml
@@ -0,0 +1,64 @@
+name: Demo Push
+
+on:
+ push:
+ tags:
+ - v*
+
+env:
+ IMAGE_NAME: mhp
+
+jobs:
+ # Push image to GitHub Packages.
+ # See also https://docs.docker.com/docker-hub/builds/
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/setup-node@v3
+ - uses: actions/checkout@v3
+ - run: yarn install --frozen-lockfile
+ - run: yarn export
+ - uses: actions/cache@v2
+ id: restore-build
+ with:
+ path: ./out/
+ key: ${{ github.sha }}
+
+ push:
+ runs-on: ubuntu-latest
+ needs: [build]
+ permissions:
+ packages: write
+ contents: read
+
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/cache@v2
+ id: restore-build
+ with:
+ path: ./out/
+ key: ${{ github.sha }}
+ - name: Build image
+ run: docker build . --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}"
+
+ - name: Log in to registry
+
+ run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
+ - name: Push image
+ run: |
+ IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
+
+ # Change all uppercase to lowercase
+ IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
+ # Strip git ref prefix from version
+ VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
+ # Strip "v" prefix from tag name
+ [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
+ # Use Docker `latest` tag convention
+ [ "$VERSION" == "master" ] && VERSION=latest
+ echo IMAGE_ID=$IMAGE_ID
+ echo VERSION=$VERSION
+ docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
+ docker push $IMAGE_ID:$VERSION
+ docker tag $IMAGE_NAME $IMAGE_ID:latest
+ docker push $IMAGE_ID:latest
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index ed587db1f..ca782c441 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,13 +1,2 @@
-FROM node:16.15.0-alpine3.15 as build
-
-WORKDIR /app
-
-COPY ./package.json /app/package.json
-COPY ./yarn.lock /app/yarn.lock
-
-COPY . .
-RUN yarn install
-RUN yarn export
-
FROM nginx:1.21.6
-COPY --from=build /app/out /usr/share/nginx/html
+COPY ./out /usr/share/nginx/html
\ No newline at end of file
diff --git a/components/AppShelf/AddAppShelfItem.tsx b/components/AppShelf/AddAppShelfItem.tsx
index 3627e8c1c..d8e619a9d 100644
--- a/components/AppShelf/AddAppShelfItem.tsx
+++ b/components/AppShelf/AddAppShelfItem.tsx
@@ -18,6 +18,7 @@ import { useState } from 'react';
import { Apps } from 'tabler-icons-react';
import { useConfig } from '../../tools/state';
import { ServiceTypeList } from '../../tools/types';
+import { AppShelfItemWrapper } from './AppShelfItemWrapper';
export default function AddItemShelfItem(props: any) {
const { addService } = useConfig();
@@ -34,30 +35,39 @@ export default function AddItemShelfItem(props: any) {
>
-
-
-
-
- setOpened(true)} size={60} />
-
- Add Service
+
+
+
+
+ Add a service
+
-
-
+
+
+
+
+ setOpened(true)} size={60} />
+
+
+
+
>
);
}
diff --git a/components/AppShelf/AppShelf.tsx b/components/AppShelf/AppShelf.tsx
index bf47a7c4c..509d3f676 100644
--- a/components/AppShelf/AppShelf.tsx
+++ b/components/AppShelf/AppShelf.tsx
@@ -3,7 +3,6 @@ import { motion } from 'framer-motion';
import {
Text,
AspectRatio,
- createStyles,
SimpleGrid,
Card,
useMantineTheme,
@@ -11,20 +10,12 @@ import {
Group,
Space,
} from '@mantine/core';
-import AppShelfMenu from './AppShelfMenu';
-import AddItemShelfItem from './AddAppShelfItem';
import { useConfig } from '../../tools/state';
import { pingQbittorrent } from '../../tools/api';
import { serviceItem } from '../../tools/types';
-
-const useStyles = createStyles((theme) => ({
- main: {
- backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[1],
- //TODO: #3 Fix this temporary fix and make the width and height dynamic / responsive
- width: 200,
- height: 180,
- },
-}));
+import AddItemShelfItem from './AddAppShelfItem';
+import { AppShelfItemWrapper } from './AppShelfItemWrapper';
+import AppShelfMenu from './AppShelfMenu';
const AppShelf = (props: any) => {
const { config, addService, removeService, setConfig } = useConfig();
@@ -58,7 +49,6 @@ export function AppShelfItem(props: any) {
const { service }: { service: serviceItem } = props;
const theme = useMantineTheme();
const { removeService } = useConfig();
- const { classes } = useStyles();
const [hovering, setHovering] = useState(false);
return (
-
+
@@ -128,7 +112,7 @@ export function AppShelfItem(props: any) {
-
+
);
}
diff --git a/components/AppShelf/AppShelfItemWrapper.tsx b/components/AppShelf/AppShelfItemWrapper.tsx
new file mode 100644
index 000000000..a305661e6
--- /dev/null
+++ b/components/AppShelf/AppShelfItemWrapper.tsx
@@ -0,0 +1,21 @@
+import { useMantineTheme, Card } from '@mantine/core';
+
+export function AppShelfItemWrapper(props: any) {
+ const { children, hovering } = props;
+ const theme = useMantineTheme();
+ return (
+
+ {children}
+
+ );
+}
diff --git a/components/layout/Aside.tsx b/components/layout/Aside.tsx
new file mode 100644
index 000000000..679e35862
--- /dev/null
+++ b/components/layout/Aside.tsx
@@ -0,0 +1,18 @@
+import { Aside as MantineAside } from '@mantine/core';
+import { CalendarModule } from '../modules/calendar/CalendarModule';
+import ModuleWrapper from '../modules/moduleWrapper';
+
+export default function Aside() {
+ return (
+
+
+
+ );
+}
diff --git a/components/layout/Layout.tsx b/components/layout/Layout.tsx
index 5e4d45cdd..bfb1a2dc3 100644
--- a/components/layout/Layout.tsx
+++ b/components/layout/Layout.tsx
@@ -1,7 +1,8 @@
-import { AppShell, Aside, Center, createStyles } from '@mantine/core';
+import { AppShell, Center, createStyles } from '@mantine/core';
import { Header } from './Header';
import { Footer } from './Footer';
-import CalendarComponent from '../modules/calendar/CalendarModule';
+import Aside from './Aside';
+import Navbar from './Navbar';
const useStyles = createStyles((theme) => ({
main: {
@@ -15,18 +16,8 @@ export default function Layout({ children, style }: any) {
const { classes, cx } = useStyles();
return (
-
-
- }
+ navbar={}
+ aside={}
header={}
footer={}
>
diff --git a/components/layout/Navbar.tsx b/components/layout/Navbar.tsx
new file mode 100644
index 000000000..2f9b26f0b
--- /dev/null
+++ b/components/layout/Navbar.tsx
@@ -0,0 +1,18 @@
+import { Navbar as MantineNavbar } from '@mantine/core';
+import { DateModule } from '../modules/date/DateModule';
+import ModuleWrapper from '../modules/moduleWrapper';
+
+export default function Navbar() {
+ return (
+
+
+
+ );
+}
diff --git a/components/modules/calendar/CalendarModule.tsx b/components/modules/calendar/CalendarModule.tsx
index bf66a47b6..c48124e13 100644
--- a/components/modules/calendar/CalendarModule.tsx
+++ b/components/modules/calendar/CalendarModule.tsx
@@ -1,14 +1,13 @@
/* eslint-disable react/no-children-prop */
import { Popover, Box, ScrollArea, Divider, Indicator } from '@mantine/core';
-import { useEffect, useState } from 'react';
+import React, { useEffect, useState } from 'react';
import { Calendar } from '@mantine/dates';
import { CalendarIcon } from '@modulz/radix-icons';
import { RadarrMediaDisplay, SonarrMediaDisplay } from './MediaDisplay';
import { useConfig } from '../../../tools/state';
-import { MHPModule } from '../modules';
-import React from 'react';
+import { IModule } from '../modules';
-export const CalendarModule: MHPModule = {
+export const CalendarModule: IModule = {
title: 'Calendar',
description:
'A calendar module for displaying upcoming releases. It interacts with the Sonarr and Radarr API.',
@@ -94,12 +93,8 @@ function DayComponent(props: any) {
setOpened(true);
}}
>
- {radarrFiltered.length > 0 && (
-
- )}
- {sonarrFiltered.length > 0 && (
-
- )}
+ {radarrFiltered.length > 0 && }
+ {sonarrFiltered.length > 0 && }
- {sonarrFiltered.map((media: any, index: number) => {
- return (
-
-
- {index < sonarrFiltered.length - 1 && }
-
- );
- })}
+ {sonarrFiltered.map((media: any, index: number) => (
+
+
+ {index < sonarrFiltered.length - 1 && }
+
+ ))}
{radarrFiltered.length > 0 && sonarrFiltered.length > 0 && (
)}
- {radarrFiltered.map((media: any, index: number) => {
- return (
-
-
- {index < radarrFiltered.length - 1 && }
-
- );
- })}
+ {radarrFiltered.map((media: any, index: number) => (
+
+
+ {index < radarrFiltered.length - 1 && }
+
+ ))}
diff --git a/components/modules/date/DateModule.story.tsx b/components/modules/date/DateModule.story.tsx
new file mode 100644
index 000000000..159777187
--- /dev/null
+++ b/components/modules/date/DateModule.story.tsx
@@ -0,0 +1,7 @@
+import DateComponent from './DateModule';
+
+export default {
+ title: 'Date module',
+};
+
+export const Default = (args: any) => ;
diff --git a/components/modules/date/DateModule.tsx b/components/modules/date/DateModule.tsx
new file mode 100644
index 000000000..e6373adf2
--- /dev/null
+++ b/components/modules/date/DateModule.tsx
@@ -0,0 +1,41 @@
+import { Group, Text, Title } from '@mantine/core';
+import dayjs from 'dayjs';
+import { useEffect, useState } from 'react';
+import { Clock } from 'tabler-icons-react';
+import { IModule } from '../modules';
+
+export const DateModule: IModule = {
+ title: 'Date',
+ description: 'Show the current time and date in a card',
+ icon: Clock,
+ component: DateComponent,
+};
+
+export default function DateComponent(props: any) {
+ const [date, setDate] = useState(new Date());
+ const hours = date.getHours();
+ const minutes = date.getMinutes();
+
+ // Change date on minute change
+ // Note: Using 10 000ms instead of 1000ms to chill a little :)
+ useEffect(() => {
+ setInterval(() => {
+ setDate(new Date());
+ }, 10000);
+ }, []);
+
+ return (
+
+
+ {hours < 10 ? `0${hours}` : hours}:{minutes < 10 ? `0${minutes}` : minutes}
+
+
+ {
+ // Use dayjs to format the date
+ // https://day.js.org/en/getting-started/installation/
+ dayjs(date).format('dddd, MMMM D YYYY')
+ }
+
+
+ );
+}
diff --git a/components/modules/moduleWrapper.tsx b/components/modules/moduleWrapper.tsx
new file mode 100644
index 000000000..3828b0090
--- /dev/null
+++ b/components/modules/moduleWrapper.tsx
@@ -0,0 +1,20 @@
+import { Card, useMantineTheme } from '@mantine/core';
+import { IModule } from './modules';
+
+export default function ModuleWrapper(props: any) {
+ const { module }: { module: IModule } = props;
+ const theme = useMantineTheme();
+ return (
+
+
+
+ );
+}
diff --git a/components/modules/modules.tsx b/components/modules/modules.tsx
index 11da5b84e..60ce7d55d 100644
--- a/components/modules/modules.tsx
+++ b/components/modules/modules.tsx
@@ -2,7 +2,7 @@
// Each module should have its own interface and call the following function:
// TODO: Add a function to register a module
// Note: Maybe use context to keep track of the modules
-export interface MHPModule {
+export interface IModule {
title: string;
description: string;
icon: React.ReactNode;
diff --git a/pages/_app.tsx b/pages/_app.tsx
index 40824fc6a..48877263c 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -7,6 +7,7 @@ import { MantineProvider, ColorScheme, ColorSchemeProvider } from '@mantine/core
import { NotificationsProvider } from '@mantine/notifications';
import Layout from '../components/layout/Layout';
import { ConfigProvider } from '../tools/state';
+import { theme } from '../tools/theme';
export default function App(props: AppProps & { colorScheme: ColorScheme }) {
const { Component, pageProps } = props;
@@ -27,7 +28,14 @@ export default function App(props: AppProps & { colorScheme: ColorScheme }) {
-
+
diff --git a/tools/theme.ts b/tools/theme.ts
new file mode 100644
index 000000000..69d7b9643
--- /dev/null
+++ b/tools/theme.ts
@@ -0,0 +1,3 @@
+import { MantineProviderProps } from '@mantine/core';
+
+export const theme: MantineProviderProps['theme'] = {};
diff --git a/yarn.lock b/yarn.lock
index b417903d3..221e7a8d4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8853,16 +8853,11 @@ minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.2:
dependencies:
brace-expansion "^1.1.7"
-minimist@^1.1.1, minimist@^1.2.5, minimist@^1.2.6:
+minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@~1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
-minimist@^1.2.0, minimist@~1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
- integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
-
minipass-collect@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617"