parent
f15b98d09a
commit
2ec2f70772
9 changed files with 103 additions and 168 deletions
|
@ -1,6 +1,8 @@
|
||||||
import Link from 'next/link'
|
import Link from 'next/link';
|
||||||
import styled, { DefaultTheme } from 'styled-components'
|
import Image from 'next/image';
|
||||||
|
import styled, { DefaultTheme } from 'styled-components';
|
||||||
import { CustomLink } from '../../interfaces/LinkTypes';
|
import { CustomLink } from '../../interfaces/LinkTypes';
|
||||||
|
import { Service } from '../../interfaces/Services';
|
||||||
|
|
||||||
// needed for Online Status checks
|
// needed for Online Status checks
|
||||||
// TODO: migrate to shared Status type for Games and Services
|
// TODO: migrate to shared Status type for Games and Services
|
||||||
|
@ -53,7 +55,7 @@ export const PageCard = styled.div`
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 1.25rem;
|
font-size: 1.2rem;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +65,7 @@ export const PageCard = styled.div`
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
// replaces the three status classes
|
||||||
const OnlineStatus = styled.p<OnlinePropType>`
|
const OnlineStatus = styled.p<OnlinePropType>`
|
||||||
color: ${props => {
|
color: ${props => {
|
||||||
let ret;
|
let ret;
|
||||||
|
@ -83,11 +86,54 @@ const OnlineStatus = styled.p<OnlinePropType>`
|
||||||
}};
|
}};
|
||||||
`
|
`
|
||||||
|
|
||||||
|
// replaces .cardwarn
|
||||||
|
const CardContentWarning = styled.p`
|
||||||
|
color: ${({ theme }) => theme.colors.secondary};
|
||||||
|
`
|
||||||
|
|
||||||
|
// replaces .contentIcon
|
||||||
|
const CardContentTitleIcon = styled.div`
|
||||||
|
object-fit: "contain";
|
||||||
|
margin-right: 0.4rem;
|
||||||
|
position: relative;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
height: 1.5rem;
|
||||||
|
`
|
||||||
|
|
||||||
|
// replaces .contentTitle
|
||||||
|
const CardContentTitleWrap = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const CardContentTitle = ({ content }: { content: Service | CustomLink }) => {
|
||||||
|
return (
|
||||||
|
<CardContentTitleWrap>
|
||||||
|
{
|
||||||
|
content.icon ? (
|
||||||
|
<CardContentTitleIcon>
|
||||||
|
<Image alt="icon" src={content.icon} fill></Image>
|
||||||
|
</CardContentTitleIcon>
|
||||||
|
) : (<></>)
|
||||||
|
}
|
||||||
|
<h2>{content.name}</h2>
|
||||||
|
</CardContentTitleWrap>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Card Content Component for Games Page
|
// Card Content Component for Games Page
|
||||||
export const PageCardContentGame = ({ content }: { content: CustomLink }) => {
|
export const CardContentGame = ({ content }: { content: CustomLink }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h2>{content.name}</h2>
|
<CardContentTitle content={content} />
|
||||||
<p>{content.desc}</p>
|
<p>{content.desc}</p>
|
||||||
<p>{content.ip}</p>
|
<p>{content.ip}</p>
|
||||||
<OnlineStatus status={content.status}>{content.status}</OnlineStatus>
|
<OnlineStatus status={content.status}>{content.status}</OnlineStatus>
|
||||||
|
@ -96,3 +142,13 @@ export const PageCardContentGame = ({ content }: { content: CustomLink }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Card Content Component for Services Page
|
// Card Content Component for Services Page
|
||||||
|
export const CardContentService = ({ content }: { content: Service }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CardContentTitle content={content} />
|
||||||
|
<OnlineStatus status={content.status}>{content.status}</OnlineStatus>
|
||||||
|
<p>{content.desc}</p>
|
||||||
|
<CardContentWarning>{content.warn}</CardContentWarning>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,5 +1,11 @@
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
export const StyledBody = styled.body`
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
|
||||||
|
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
||||||
|
`
|
||||||
|
|
||||||
export const Page = styled.div`
|
export const Page = styled.div`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
// Probably a good idea to spread this out into multiple files under a folder once it gets bigger
|
// Probably a good idea to spread this out into multiple files under a folder once it gets bigger
|
||||||
import { createGlobalStyle, DefaultTheme } from 'styled-components'
|
import { createGlobalStyle, DefaultTheme } from 'styled-components'
|
||||||
|
|
||||||
// TODO: unsure whether needed
|
export const GlobalStyle = createGlobalStyle`
|
||||||
/* const GlobalStyle = createGlobalStyle`
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
color: ${({ theme }) => theme.colors.primary};
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
|
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
|
||||||
|
@ -21,8 +19,6 @@ import { createGlobalStyle, DefaultTheme } from 'styled-components'
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export default GlobalStyle; */
|
|
||||||
|
|
||||||
export const lightTheme: DefaultTheme = {
|
export const lightTheme: DefaultTheme = {
|
||||||
themeName: "Light Theme",
|
themeName: "Light Theme",
|
||||||
themeId: 0,
|
themeId: 0,
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import '/styles/globals.css'
|
import '/styles/globals.css'
|
||||||
import type { ReactElement, ReactNode } from 'react'
|
import { Fragment, ReactElement, ReactNode } from 'react'
|
||||||
import Layout from '../components/layout'
|
import Layout from '../components/layout'
|
||||||
import type { NextPage } from 'next'
|
import type { NextPage } from 'next'
|
||||||
import { AppProps } from 'next/app';
|
import { AppProps } from 'next/app';
|
||||||
import { DefaultTheme, ThemeProvider } from 'styled-components';
|
import { DefaultTheme, ThemeProvider } from 'styled-components';
|
||||||
import { createContext, useContext, useEffect, useState } from 'react'
|
import { createContext, useContext, useEffect, useState } from 'react'
|
||||||
import { darkTheme } from '../components/themes';
|
import { darkTheme, GlobalStyle } from '../components/themes';
|
||||||
import { getTheme } from '../components/themeselector';
|
import { getTheme } from '../components/themeselector';
|
||||||
|
|
||||||
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
|
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
|
||||||
|
@ -44,10 +44,14 @@ export default function Website({ Component, pageProps }: AppPropsWithLayout) {
|
||||||
<Layout>{page}</Layout>))
|
<Layout>{page}</Layout>))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={selectedTheme}>
|
<Fragment>
|
||||||
|
<GlobalStyle />
|
||||||
|
<ThemeProvider theme={selectedTheme}>
|
||||||
<ThemeUpdateContext.Provider value={setselectedTheme}>
|
<ThemeUpdateContext.Provider value={setselectedTheme}>
|
||||||
{getLayout(<Component {...pageProps} />)}
|
{getLayout(<Component {...pageProps} />)}
|
||||||
</ThemeUpdateContext.Provider>
|
</ThemeUpdateContext.Provider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
</Fragment>
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import { Html, Head, Main, NextScript, DocumentContext } from 'next/document'
|
import { Html, Head, Main, NextScript } from 'next/document'
|
||||||
|
import { StyledBody } from '../components/styles/generic'
|
||||||
|
|
||||||
|
|
||||||
export default function Document() {
|
export default function Document() {
|
||||||
return (
|
return (
|
||||||
<Html lang='en'>
|
<Html lang='en'>
|
||||||
<Head />
|
<Head />
|
||||||
<body>
|
<StyledBody>
|
||||||
<Main />
|
<Main />
|
||||||
<NextScript />
|
<NextScript />
|
||||||
</body>
|
</StyledBody>
|
||||||
</Html>
|
</Html>
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
import Head from 'next/head'
|
import Head from 'next/head'
|
||||||
import styles from '/styles/Home.module.css'
|
|
||||||
import fsPromises from 'fs/promises'
|
import fsPromises from 'fs/promises'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import type { CustomLink, EntryList } from '../interfaces/LinkTypes'
|
import type { CustomLink, EntryList } from '../interfaces/LinkTypes'
|
||||||
import { PageContentBox, PageCard, PageDescription, PageTitle, PageCardContentGame } from '../components/styles/content'
|
import { PageContentBox, PageCard, PageDescription, PageTitle, CardContentGame } from '../components/styles/content'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
|
||||||
function Servers(props: EntryList) {
|
function Servers(props: EntryList) {
|
||||||
|
@ -30,7 +29,7 @@ function Servers(props: EntryList) {
|
||||||
return (
|
return (
|
||||||
<PageCard key={item.name}>
|
<PageCard key={item.name}>
|
||||||
<Link href={item.href}>
|
<Link href={item.href}>
|
||||||
<PageCardContentGame content={item} />
|
<CardContentGame content={item} />
|
||||||
</Link>
|
</Link>
|
||||||
</PageCard>
|
</PageCard>
|
||||||
)
|
)
|
||||||
|
@ -38,7 +37,7 @@ function Servers(props: EntryList) {
|
||||||
else {
|
else {
|
||||||
return (
|
return (
|
||||||
<PageCard key={item.name}>
|
<PageCard key={item.name}>
|
||||||
<PageCardContentGame content={item} />
|
<CardContentGame content={item} />
|
||||||
</PageCard>
|
</PageCard>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import Head from 'next/head'
|
import Head from 'next/head'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import styles from '/styles/Home.module.css'
|
|
||||||
import { Service, ServiceStatus, ServiceType, ServiceLocation } from '../interfaces/Services';
|
import { Service, ServiceStatus, ServiceType, ServiceLocation } from '../interfaces/Services';
|
||||||
import Dockerode from 'dockerode';
|
import Dockerode from 'dockerode';
|
||||||
import { ReactElement } from 'react'
|
import { ReactElement } from 'react'
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import Image from 'next/image';
|
import { PageCard, CardContentService, PageContentBox, PageDescription, PageTitle } from '../components/styles/content';
|
||||||
|
|
||||||
const fetcher = (url: string) => fetch(url).then((res) => res.json())
|
const fetcher = (url: string) => fetch(url).then((res) => res.json())
|
||||||
|
|
||||||
|
@ -18,51 +17,28 @@ function Services() {
|
||||||
else if (loadingInitial) { content = <div>Loading</div> }
|
else if (loadingInitial) { content = <div>Loading</div> }
|
||||||
else if (loadingFull) {
|
else if (loadingFull) {
|
||||||
content =
|
content =
|
||||||
<div className={styles.grid}>
|
<PageContentBox>
|
||||||
{initialData?.map((item: Service) => (
|
{initialData?.map((item: Service) => (
|
||||||
<Link className={styles.contentcard} key={item.name} href={item.href}>
|
<PageCard key={item.name}>
|
||||||
<div className={styles.contentTitle}>
|
<Link key={item.name} href={item.href}>
|
||||||
{
|
<CardContentService content={item} />
|
||||||
item.icon ? (
|
</Link>
|
||||||
<div className={styles.contentIcon}>
|
</PageCard>
|
||||||
<Image alt="icon" src={item.icon} layout="fill" objectFit="contain"></Image>
|
|
||||||
</div>
|
|
||||||
) : (<></>)
|
|
||||||
}
|
|
||||||
<h2>{item.name}</h2>
|
|
||||||
</div>
|
|
||||||
<div className={item.status === ServiceStatus.online ? styles.statusOnline : item.status === ServiceStatus.offline ? styles.statusOffline : styles.statusLoading}>
|
|
||||||
{item.status}
|
|
||||||
</div>
|
|
||||||
<div><p>{item.desc}</p></div>
|
|
||||||
<div className={styles.cardwarn}><p>{item.warn}</p></div>
|
|
||||||
</Link>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</PageContentBox>
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (fullData) {
|
else if (fullData) {
|
||||||
content =
|
content =
|
||||||
<div className={styles.grid}>
|
<PageContentBox>
|
||||||
{fullData.map((item: Service) => (
|
{fullData.map((item: Service) => (
|
||||||
<Link className={styles.contentcard} key={item.name} href={item.href}>
|
<PageCard key={item.name}>
|
||||||
<div className={styles.contentTitle}>
|
<Link key={item.name} href={item.href}>
|
||||||
{
|
<CardContentService content={item} />
|
||||||
item.icon ? (
|
</Link>
|
||||||
<div className={styles.contentIcon}>
|
</PageCard>
|
||||||
<Image alt="icon" src={item.icon} fill></Image>
|
|
||||||
</div>
|
|
||||||
) : (<></>)
|
|
||||||
}
|
|
||||||
<h2>{item.name}</h2>
|
|
||||||
</div>
|
|
||||||
<div className={item.status === ServiceStatus.online ? styles.statusOnline : item.status === ServiceStatus.offline ? styles.statusOffline : styles.statusLoading}>
|
|
||||||
{item.status}
|
|
||||||
</div>
|
|
||||||
<div><p>{item.desc}</p></div>
|
|
||||||
<div className={styles.cardwarn}><p>{item.warn}</p></div>
|
|
||||||
</Link>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</PageContentBox>
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
content = <div>Error loading data</div>
|
content = <div>Error loading data</div>
|
||||||
|
@ -77,13 +53,13 @@ function Services() {
|
||||||
<meta name="description" content="Lists all available Services, most likely up-to-date" />
|
<meta name="description" content="Lists all available Services, most likely up-to-date" />
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<h1 className={styles.title}>
|
<PageTitle>
|
||||||
Service List
|
Service List
|
||||||
</h1>
|
</PageTitle>
|
||||||
|
|
||||||
<p className={styles.description}>
|
<PageDescription>
|
||||||
Lists all available Services, most likely up-to-date
|
Lists all available Services, most likely up-to-date
|
||||||
</p>
|
</PageDescription>
|
||||||
|
|
||||||
{content}
|
{content}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,78 +1 @@
|
||||||
.container {
|
|
||||||
padding: 0 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title a {
|
|
||||||
color: var(--def-orange);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title a:hover,
|
|
||||||
.title a:focus,
|
|
||||||
.title a:active {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.code {
|
|
||||||
background: var(--black-1e);
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 0.75rem;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
|
|
||||||
Bitstream Vera Sans Mono, Courier New, monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contentcardstatic {
|
|
||||||
margin: 1rem;
|
|
||||||
padding: 1rem;
|
|
||||||
text-align: center;
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
border: 1px solid var(--black-2d);
|
|
||||||
border-radius: 10px;
|
|
||||||
border-color: var(--def-blue);
|
|
||||||
transition: color 0.15s ease, border-color 0.15s ease;
|
|
||||||
max-width: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contentcard:hover,
|
|
||||||
.contentcard:focus,
|
|
||||||
.contentcard:active {
|
|
||||||
color: var(--def-orange);
|
|
||||||
border-color: var(--def-orange);
|
|
||||||
}
|
|
||||||
|
|
||||||
.contentTitle {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contentTitle h2 {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contentIcon {
|
|
||||||
object-fit: "contain";
|
|
||||||
margin-right: 0.4rem;
|
|
||||||
position: relative;
|
|
||||||
aspect-ratio: 1;
|
|
||||||
height: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cardwarn {
|
|
||||||
color: var(--def-orange);
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
height: 1em;
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
.grid {
|
|
||||||
width: 100%;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,27 +1 @@
|
||||||
html,
|
|
||||||
body {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
|
|
||||||
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root {
|
|
||||||
--black-0f: #0f0f0f;
|
|
||||||
--black-1e: #1e1e1e;
|
|
||||||
--black-2d: #2d2d2d;
|
|
||||||
|
|
||||||
--def-blue: #00aaff;
|
|
||||||
--def-orange: #ff5300;
|
|
||||||
--def-red: #ff0000;
|
|
||||||
--def-green: #00ff00;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue