Merge pull request #33 from ajnart/dev

Merge dev into master for v0.1.4
This commit is contained in:
Aj - Thomas
2022-05-10 19:23:17 +02:00
committed by GitHub
16 changed files with 264 additions and 104 deletions

64
.github/workflows/docker.yml vendored Normal file
View File

@@ -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

View File

@@ -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

View File

@@ -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) {
>
<AddAppShelfItemForm setOpened={setOpened} />
</Modal>
<AspectRatio
style={{
minHeight: 120,
minWidth: 120,
}}
ratio={4 / 3}
>
<Card
style={{
backgroundColor:
theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[1],
width: 200,
height: 180,
}}
radius="md"
>
<Group direction="column" position="center">
<motion.div whileHover={{ scale: 1.2 }}>
<Apps style={{ cursor: 'pointer' }} onClick={() => setOpened(true)} size={60} />
</motion.div>
<Text>Add Service</Text>
<AppShelfItemWrapper>
<Card.Section>
<Group position="center" mx="lg">
<Text
// TODO: #1 Remove this hack to get the text to be centered.
ml={15}
style={{
alignSelf: 'center',
alignContent: 'center',
alignItems: 'center',
justifyContent: 'center',
justifyItems: 'center',
}}
mt="sm"
weight={500}
>
Add a service
</Text>
</Group>
</Card>
</AspectRatio>
</Card.Section>
<Card.Section>
<AspectRatio ratio={5 / 3} m="xl">
<motion.i
whileHover={{
cursor: 'pointer',
scale: 1.1,
}}
>
<Apps style={{ cursor: 'pointer' }} onClick={() => setOpened(true)} size={60} />
</motion.i>
</AspectRatio>
</Card.Section>
</AppShelfItemWrapper>
</>
);
}

View File

@@ -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 (
<motion.div
@@ -70,13 +60,7 @@ export function AppShelfItem(props: any) {
setHovering(false);
}}
>
<Card
className={classes.main}
style={{
boxShadow: hovering ? '0px 0px 3px rgba(0, 0, 0, 0.5)' : '0px 0px 1px rgba(0, 0, 0, 0.5)',
}}
radius="md"
>
<AppShelfItemWrapper hovering={hovering}>
<Card.Section>
<Group position="apart" mx="lg">
<Space />
@@ -128,7 +112,7 @@ export function AppShelfItem(props: any) {
</motion.i>
</AspectRatio>
</Card.Section>
</Card>
</AppShelfItemWrapper>
</motion.div>
);
}

View File

@@ -0,0 +1,21 @@
import { useMantineTheme, Card } from '@mantine/core';
export function AppShelfItemWrapper(props: any) {
const { children, hovering } = props;
const theme = useMantineTheme();
return (
<Card
style={{
boxShadow: hovering ? '0px 0px 3px rgba(0, 0, 0, 0.5)' : '0px 0px 1px rgba(0, 0, 0, 0.5)',
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[1],
//TODO: #3 Fix this temporary fix and make the width and height dynamic / responsive
width: 200,
height: 180,
}}
radius="md"
>
{children}
</Card>
);
}

View File

@@ -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 (
<MantineAside
height="100%"
hiddenBreakpoint="md"
hidden
width={{
base: 'auto',
}}
>
<ModuleWrapper module={CalendarModule} />
</MantineAside>
);
}

View File

@@ -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 (
<AppShell
aside={
<Aside
height="auto"
hiddenBreakpoint="md"
hidden
width={{
base: 'auto',
}}
>
<CalendarComponent />
</Aside>
}
navbar={<Navbar />}
aside={<Aside />}
header={<Header links={[]} />}
footer={<Footer links={[]} />}
>

View File

@@ -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 (
<MantineNavbar
height="100%"
hiddenBreakpoint="md"
hidden
width={{
base: 'auto',
}}
>
<ModuleWrapper module={DateModule} />
</MantineNavbar>
);
}

View File

@@ -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 && (
<Indicator size={7} color="yellow" children={null} />
)}
{sonarrFiltered.length > 0 && (
<Indicator size={7} offset={8} color="blue" children={null} />
)}
{radarrFiltered.length > 0 && <Indicator size={7} color="yellow" children={null} />}
{sonarrFiltered.length > 0 && <Indicator size={7} offset={8} color="blue" children={null} />}
<Popover
position="left"
width={700}
@@ -109,25 +104,21 @@ function DayComponent(props: any) {
target={` ${day}`}
>
<ScrollArea style={{ height: 400 }}>
{sonarrFiltered.map((media: any, index: number) => {
return (
<React.Fragment key={index}>
<SonarrMediaDisplay media={media} />
{index < sonarrFiltered.length - 1 && <Divider variant="dashed" my="xl" />}
</React.Fragment>
);
})}
{sonarrFiltered.map((media: any, index: number) => (
<React.Fragment key={index}>
<SonarrMediaDisplay media={media} />
{index < sonarrFiltered.length - 1 && <Divider variant="dashed" my="xl" />}
</React.Fragment>
))}
{radarrFiltered.length > 0 && sonarrFiltered.length > 0 && (
<Divider variant="dashed" my="xl" />
)}
{radarrFiltered.map((media: any, index: number) => {
return (
<React.Fragment key={index}>
<RadarrMediaDisplay media={media} />
{index < radarrFiltered.length - 1 && <Divider variant="dashed" my="xl" />}
</React.Fragment>
);
})}
{radarrFiltered.map((media: any, index: number) => (
<React.Fragment key={index}>
<RadarrMediaDisplay media={media} />
{index < radarrFiltered.length - 1 && <Divider variant="dashed" my="xl" />}
</React.Fragment>
))}
</ScrollArea>
</Popover>
</Box>

View File

@@ -0,0 +1,7 @@
import DateComponent from './DateModule';
export default {
title: 'Date module',
};
export const Default = (args: any) => <DateComponent {...args} />;

View File

@@ -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 (
<Group p="sm" direction="column">
<Title>
{hours < 10 ? `0${hours}` : hours}:{minutes < 10 ? `0${minutes}` : minutes}
</Title>
<Text size="xl">
{
// Use dayjs to format the date
// https://day.js.org/en/getting-started/installation/
dayjs(date).format('dddd, MMMM D YYYY')
}
</Text>
</Group>
);
}

View File

@@ -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 (
<Card
mx="sm"
radius="lg"
shadow="sm"
style={{
// Make background color of the card depend on the theme
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[6] : 'white',
}}
>
<module.component />
</Card>
);
}

View File

@@ -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;

View File

@@ -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 }) {
</Head>
<ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme}>
<MantineProvider theme={{ colorScheme }} withGlobalStyles withNormalizeCSS>
<MantineProvider
theme={{
...theme,
colorScheme,
}}
withGlobalStyles
withNormalizeCSS
>
<NotificationsProvider position="top-right">
<ConfigProvider>
<Layout>

3
tools/theme.ts Normal file
View File

@@ -0,0 +1,3 @@
import { MantineProviderProps } from '@mantine/core';
export const theme: MantineProviderProps['theme'] = {};

View File

@@ -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"