From 56b42668a850c50f251d07760bf46b2060a5009b Mon Sep 17 00:00:00 2001 From: Aj - Thomas Date: Mon, 25 Apr 2022 00:11:32 +0200 Subject: [PATCH] Add project base --- README.md | 50 ++--- components/AppShelf/AppShelf.tsx | 134 ++++++++++++ .../ColorSchemeToggle/ColorSchemeToggle.tsx | 24 ++- components/layout/Footer.tsx | 82 ++++++++ components/layout/Header.tsx | 146 +++++++++++++ components/layout/Layout.tsx | 32 +++ components/layout/Logo.tsx | 15 ++ package.json | 6 +- pages/_app.tsx | 5 +- pages/index.tsx | 5 +- yarn.lock | 193 +++++++++++------- 11 files changed, 568 insertions(+), 124 deletions(-) create mode 100644 components/AppShelf/AppShelf.tsx create mode 100644 components/layout/Footer.tsx create mode 100644 components/layout/Header.tsx create mode 100644 components/layout/Layout.tsx create mode 100644 components/layout/Logo.tsx diff --git a/README.md b/README.md index 15048f337..9de7bf914 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,13 @@ -# Mantine Next Template +# HomePage, a home page for your home server +## What is HomePage ? +HomePage is a web page for your home server, it provides a user friendly interface to access docker containers or other services. +## How to use HomePage ? +### 1. Install HomePage +### 2. Configure HomePage +### 3. Start HomePage -Get started with Mantine + Next with just a few button clicks. -Click `Use this template` button at the header of repository or [follow this link](https://github.com/mantinedev/mantine-next-template/generate) and -create new repository with `@mantine` packages. Note that you have to be logged in to GitHub to generate template. - -## Features - -This template comes with several essential features: - -- Server side rendering setup for Mantine -- Color scheme is stored in cookie to avoid color scheme mismatch after hydration -- Storybook with color scheme toggle -- Jest with react testing library -- ESLint setup with [eslint-config-mantine](https://github.com/mantinedev/eslint-config-mantine) - -## npm scripts - -### Build and dev scripts - -- `dev` – start dev server -- `build` – bundle application for production -- `export` – exports static website to `out` folder -- `analyze` – analyzes application bundle with [@next/bundle-analyzer](https://www.npmjs.com/package/@next/bundle-analyzer) - -### Testing scripts - -- `typecheck` – checks TypeScript types -- `lint` – runs ESLint -- `prettier:check` – checks files with Prettier -- `jest` – runs jest tests -- `jest:watch` – starts jest watch -- `test` – runs `jest`, `prettier:check`, `lint` and `typecheck` scripts - -### Other scripts - -- `storybook` – starts storybook dev server -- `storybook:build` – build production storybook bundle to `storybook-static` -- `prettier:write` – formats all files with Prettier +# Notes +## On page load ? +# Ping all connected services to check if they are up and running +# If not, display a warning message +# Update the bubble of each connected service \ No newline at end of file diff --git a/components/AppShelf/AppShelf.tsx b/components/AppShelf/AppShelf.tsx new file mode 100644 index 000000000..4375ca367 --- /dev/null +++ b/components/AppShelf/AppShelf.tsx @@ -0,0 +1,134 @@ +import React, { useState } from 'react'; +import { motion, AnimatePresence } from 'framer-motion'; +import { + ActionIcon, + createStyles, + Grid, + Group, + Text, + Title, + Paper, + Tooltip, + Image, + ThemeIcon, + useMantineTheme, + Anchor, + Box, + Menu, + AspectRatio, +} from '@mantine/core'; +import { ArrowBack, Trash } from 'tabler-icons-react'; + +const AppShelf = () => { + const Services = loadServices(); + const [hovering, setHovering] = useState('none'); + const theme = useMantineTheme(); + return ( + + {Services.map((service, i) => ( + + { + setHovering(service.name); + }} + onHoverEnd={(e) => { + setHovering('none'); + }} + > + + ({ + backgroundColor: + theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0], + textAlign: 'center', + padding: theme.spacing.xl, + borderRadius: theme.radius.md, + + '&:hover': { + backgroundColor: + theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[1], + }, + })} + > + + + Settings + + Danger zone + }> + Delete + + + + + + + {service.name} + + + {service.name} + + + + + + ))} + + ); +}; + +export default AppShelf; +function loadServices() { + return [ + { + name: 'Radarr', + icon: 'https://cdn.jsdelivr.net/gh/IceWhaleTech/CasaOS-AppStore@main/Apps/Radarr/icon.png', + url: 'http://server:7878/', + }, + { + name: 'Sonarr', + icon: 'https://cdn.jsdelivr.net/gh/IceWhaleTech/CasaOS-AppStore@main/Apps/Sonarr/icon.png', + url: 'http://server:8989/', + }, + { + name: 'Sonarr', + icon: 'https://cdn.jsdelivr.net/gh/IceWhaleTech/CasaOS-AppStore@main/Apps/Sonarr/icon.png', + url: 'http://server:8989/', + }, + { + name: 'Sonarr', + icon: 'https://cdn.jsdelivr.net/gh/IceWhaleTech/CasaOS-AppStore@main/Apps/Sonarr/icon.png', + url: 'http://server:8989/', + }, + { + name: 'Sonarr', + icon: 'https://cdn.jsdelivr.net/gh/IceWhaleTech/CasaOS-AppStore@main/Apps/Sonarr/icon.png', + url: 'http://server:8989/', + }, + { + name: 'Sonarr', + icon: 'https://cdn.jsdelivr.net/gh/IceWhaleTech/CasaOS-AppStore@main/Apps/Sonarr/icon.png', + url: 'http://server:8989/', + }, + { + name: 'Sonarr', + icon: 'https://cdn.jsdelivr.net/gh/IceWhaleTech/CasaOS-AppStore@main/Apps/Sonarr/icon.png', + url: 'http://server:8989/', + }, + { + name: 'Sonarr', + icon: 'https://cdn.jsdelivr.net/gh/IceWhaleTech/CasaOS-AppStore@main/Apps/Sonarr/icon.png', + url: 'http://server:8989/', + }, + { + name: 'Sonarr', + icon: 'https://cdn.jsdelivr.net/gh/IceWhaleTech/CasaOS-AppStore@main/Apps/Sonarr/icon.png', + url: 'http://server:8989/', + }, + { + name: 'Sonarr', + icon: 'https://cdn.jsdelivr.net/gh/IceWhaleTech/CasaOS-AppStore@main/Apps/Sonarr/icon.png', + url: 'http://server:8989/', + }, + ]; +} diff --git a/components/ColorSchemeToggle/ColorSchemeToggle.tsx b/components/ColorSchemeToggle/ColorSchemeToggle.tsx index bef4488dd..0cb616e3b 100644 --- a/components/ColorSchemeToggle/ColorSchemeToggle.tsx +++ b/components/ColorSchemeToggle/ColorSchemeToggle.tsx @@ -1,26 +1,28 @@ -import { ActionIcon, Group, useMantineColorScheme } from '@mantine/core'; -import { SunIcon, MoonIcon } from '@modulz/radix-icons'; +import { ActionIcon, useMantineColorScheme } from '@mantine/core'; +import { Sun, MoonStars } from 'tabler-icons-react'; +import { motion } from 'framer-motion'; export function ColorSchemeToggle() { const { colorScheme, toggleColorScheme } = useMantineColorScheme(); return ( - + toggleColorScheme()} size="xl" sx={(theme) => ({ - backgroundColor: - theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0], color: theme.colorScheme === 'dark' ? theme.colors.yellow[4] : theme.colors.blue[6], })} > - {colorScheme === 'dark' ? ( - - ) : ( - - )} + {colorScheme === 'dark' ? : } - + ); } diff --git a/components/layout/Footer.tsx b/components/layout/Footer.tsx new file mode 100644 index 000000000..f31202c6e --- /dev/null +++ b/components/layout/Footer.tsx @@ -0,0 +1,82 @@ +import React from 'react'; +import { createStyles, Anchor, Text, Group, ActionIcon } from '@mantine/core'; +import { BrandGithub, Phone, BrandGmail } from 'tabler-icons-react'; +import { posix } from 'path'; + +const useStyles = createStyles((theme) => ({ + footer: { + borderTop: `1px solid ${ + theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[2] + }`, + }, + + inner: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + padding: `${theme.spacing.md}px ${theme.spacing.md}px`, + + [theme.fn.smallerThan('sm')]: { + flexDirection: 'column', + }, + }, + + links: { + [theme.fn.smallerThan('sm')]: { + marginTop: theme.spacing.lg, + marginBottom: theme.spacing.sm, + }, + }, +})); + +interface FooterCenteredProps { + links: { link: string; label: string }[]; +} + +export function Footer({ links }: FooterCenteredProps) { + const { classes } = useStyles(); + const items = links.map((link) => ( + + color="dimmed" + key={link.label} + href={link.link} + sx={{ lineHeight: 1 }} + onClick={(event) => event.preventDefault()} + size="sm" + > + {link.label} + + )); + + return ( + + {items} + + component="a" href={`https://github.com/ajnart/myhomepage`} size="lg"> + + + + + Made with ❤️ by @ + + ajnart + + + + ); +} diff --git a/components/layout/Header.tsx b/components/layout/Header.tsx new file mode 100644 index 000000000..ef785c388 --- /dev/null +++ b/components/layout/Header.tsx @@ -0,0 +1,146 @@ +import React, { useState } from 'react'; +import { + createStyles, + Header as Head, + Container, + Group, + Burger, + Paper, + Transition, +} from '@mantine/core'; +import { useBooleanToggle } from '@mantine/hooks'; +import { NextLink } from '@mantine/next'; +import { Logo } from './Logo'; +import { ColorSchemeToggle } from '../ColorSchemeToggle/ColorSchemeToggle'; + +const HEADER_HEIGHT = 60; + +const useStyles = createStyles((theme) => ({ + root: { + position: 'relative', + zIndex: 1, + }, + + dropdown: { + position: 'absolute', + top: HEADER_HEIGHT, + left: 0, + right: 0, + zIndex: 0, + borderTopRightRadius: 0, + borderTopLeftRadius: 0, + borderTopWidth: 0, + overflow: 'hidden', + + [theme.fn.largerThan('sm')]: { + display: 'none', + }, + }, + + header: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + height: '100%', + }, + + links: { + [theme.fn.smallerThan('sm')]: { + display: 'none', + }, + }, + + burger: { + [theme.fn.largerThan('sm')]: { + display: 'none', + }, + }, + + link: { + display: 'block', + lineHeight: 1, + padding: '8px 12px', + borderRadius: theme.radius.sm, + textDecoration: 'none', + color: theme.colorScheme === 'dark' ? theme.colors.dark[0] : theme.colors.gray[7], + fontSize: theme.fontSizes.sm, + fontWeight: 500, + + '&:hover': { + backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0], + }, + + [theme.fn.smallerThan('sm')]: { + borderRadius: 0, + padding: theme.spacing.md, + }, + }, + + linkActive: { + '&, &:hover': { + backgroundColor: + theme.colorScheme === 'dark' + ? theme.fn.rgba(theme.colors[theme.primaryColor][9], 0.25) + : theme.colors[theme.primaryColor][0], + color: theme.colors[theme.primaryColor][theme.colorScheme === 'dark' ? 3 : 7], + }, + }, +})); + +interface HeaderResponsiveProps { + links: { link: string; label: string }[]; +} + +export function Header({ links }: HeaderResponsiveProps) { + const [opened, toggleOpened] = useBooleanToggle(false); + const [active, setActive] = useState('/'); + const { classes, cx } = useStyles(); + + const items = ( + <> + {links.map((link) => ( + { + setActive(link.link); + toggleOpened(false); + }} + > + {link.label} + + ))} + + ); + return ( + + + + + + + + + + {items} + + + toggleOpened()} + className={classes.burger} + size="sm" + /> + + + {(styles) => ( + + {items} + + )} + + + + ); +} diff --git a/components/layout/Layout.tsx b/components/layout/Layout.tsx new file mode 100644 index 000000000..704f7303a --- /dev/null +++ b/components/layout/Layout.tsx @@ -0,0 +1,32 @@ +import { AppShell, Center, createStyles } from '@mantine/core'; +import { Header } from './Header'; +import { Footer } from './Footer'; + +const useStyles = createStyles((theme) => ({ + main: { + [theme.fn.smallerThan('md')]: { + maxWidth: '90vw', + }, + [theme.fn.largerThan('md')]: { + width: 1200, + }, + }, +})); + +export default function Layout({ children, style }: any) { + const { classes, cx } = useStyles(); + return ( + } footer={