Added styled-components + various

Includes changes due to NextJS version bump and attempts at storing theme via cookie
This commit is contained in:
Neshura 2022-12-14 19:35:27 +01:00
parent 8a763ee72e
commit 21e613891e
No known key found for this signature in database
GPG key ID: ACDF5B6EBECF6B0A
13 changed files with 325 additions and 102 deletions

76
app/layout.tsx Normal file
View file

@ -0,0 +1,76 @@
'use client'
import Script from "next/script"
import Footer from "../components/footer"
import Navbar from "../components/navbar"
import StyleSelector from "../components/themeselector"
import styles from "../styles/Home.module.css"
import { Page } from '../components/styles/generic'
import { DefaultTheme, ThemeProvider } from 'styled-components';
import { createContext, useContext, useEffect, useState } from "react"
import { setCookie } from "cookies-next"
import { darkTheme } from "../components/themes"
const ThemeUpdateContext = createContext(
(theme: DefaultTheme) => console.error("attempted to set theme outside of a ThemeUpdateContext.Provider")
)
// eslint-disable-next-line react-hooks/rules-of-hooks
export const useUpdateTheme = () => useContext(ThemeUpdateContext);
export default function Layout({ children, }: { children: React.ReactNode }) {
const [selectedTheme, setselectedTheme] = useState(darkTheme);
console.log("Selected Theme: ", selectedTheme); // DEBUG
return (
<html lang="en">
<ThemeProvider theme={selectedTheme}>
<ThemeUpdateContext.Provider value={setselectedTheme}>
<Page>
<Navbar />
<StyleSelector></StyleSelector>
<body className={styles.main}>
{children}
</body>
</Page>
</ThemeUpdateContext.Provider>
</ThemeProvider>
</html >
)
}
{/* <Page>
<Navbar />
<StyleSelector></StyleSelector>
<body className={styles.main}>
{children}
</body>
<Footer />
</Page> */}
/* <html>
<head />
<body>{children}</body>
</html> */
{/* <Script id="matomo_analytics">
{`
var _paq = window._paq = window._paq || []; */}
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
/* _paq.push(["setDocumentTitle", document.domain + "/" + document.title]);
_paq.push(["setCookieDomain", "www.neshweb.net"]);
_paq.push(["disableCookies"]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//tracking.neshweb.net/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '2']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
`}
</Script> */

View file

@ -2,35 +2,39 @@ import Footer from './footer'
import Navbar from './navbar' import Navbar from './navbar'
import styles from '/styles/Home.module.css' import styles from '/styles/Home.module.css'
import Script from 'next/script' import Script from 'next/script'
import { Page } from './styles/generic'
import StyleSelector from './themeselector'
const Layout = ({ children }: { children: React.ReactNode }) => { const Layout = ({ children }: { children: React.ReactNode }) => {
return ( return (
<div className={styles.page}> <Page>
<Script id="matomo_analytics"> <Script id="matomo_analytics">
{` {`
var _paq = window._paq = window._paq || []; var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */ /* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(["setDocumentTitle", document.domain + "/" + document.title]); _paq.push(["setDocumentTitle", document.domain + "/" + document.title]);
_paq.push(["setCookieDomain", "www.neshweb.net"]); _paq.push(["setCookieDomain", "www.neshweb.net"]);
_paq.push(["disableCookies"]); _paq.push(["disableCookies"]);
_paq.push(['trackPageView']); _paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']); _paq.push(['enableLinkTracking']);
(function() { (function() {
var u="//tracking.neshweb.net/"; var u="//tracking.neshweb.net/";
_paq.push(['setTrackerUrl', u+'matomo.php']); _paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '2']); _paq.push(['setSiteId', '2']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})(); })();
`} `}
</Script> </Script>
<Navbar /> <Navbar />
<StyleSelector></StyleSelector>
<main className={styles.main}> <main className={styles.main}>
{children} {children}
</main> </main>
<Footer /> <Footer />
</div> </Page>
); );
} }

View file

@ -1,6 +1,6 @@
import styles from '/styles/Home.module.css' import styles from '/styles/Home.module.css'
import Link from 'next/link' import Link from 'next/link'
import { useRouter } from 'next/router' import { usePathname } from 'next/navigation'
const navLinks = [ const navLinks = [
{ name: "Home", href: "/" }, { name: "Home", href: "/" },
@ -10,19 +10,16 @@ const navLinks = [
] ]
const Navbar = () => { const Navbar = () => {
const router = useRouter(); const path = usePathname();
return ( return (
<nav className={styles.navbar}> <nav className={styles.navbar}>
{navLinks.map((item, index) => ( {navLinks.map((item, index) => (
<Link key={item.name} href={item.href}> <Link className={path == item.href ? styles.navelem_active : styles.navelem} key={item.name} href={item.href}>
<a className={router.pathname == item.href ? styles.navelem_active : styles.navelem}>{item.name}</a> {item.name}
</Link> </Link>
))} ))}
<Link key="Mastodon_Verify" href="https://mastodon.neshweb.net/@neshura"> <Link className={styles.navelem} key="Mastodon_Verify" rel="me" href="https://mastodon.neshweb.net/@neshura">Mastodon</Link>
<a className={styles.navelem} rel="me" href="https://mastodon.neshweb.net/@neshura">Mastodon</a>
</Link>
</nav> </nav>
); );
} }

View file

@ -0,0 +1,8 @@
import styled from 'styled-components'
const Page = styled.div`
width: 100%;
background-color: ${({ theme }) => theme.colors.background};
`
export { Page }

51
components/themes.tsx Normal file
View file

@ -0,0 +1,51 @@
// Probably a good idea to spread this out into multiple files under a folder once it gets bigger
import { createGlobalStyle, DefaultTheme } from 'styled-components'
// unsure whether needed
/* const GlobalStyle = createGlobalStyle`
html,
body {
color: ${({ theme }) => theme.colors.primary};
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}
a {
color: inherit;
text-decoration: none;
}
* {
box-sizing: border-box;
}
`
export default GlobalStyle; */
export const lightTheme: DefaultTheme = {
themeId: 1,
colors: {
background: '#ffffff',
primary: '#00aaff',
secondary:'#ffaa00',
},
}
export const darkTheme: DefaultTheme = {
themeId: 2,
colors: {
background: '#1f1f1f',
primary: '#00aaff',
secondary:'#ffaa00',
},
}
export const amoledTheme: DefaultTheme = {
themeId: 3,
colors: {
background: '#000000',
primary: '#00aaff',
secondary:'#ffaa00',
},
}

View file

@ -0,0 +1,52 @@
import { useUpdateTheme } from "../pages/_app";
import { useContext } from 'react';
import { ThemeContext, DefaultTheme } from "styled-components";
import { darkTheme, amoledTheme, lightTheme } from './themes';
const StyleSelector = () => {
const updateTheme = useUpdateTheme();
const currentTheme = useContext(ThemeContext);
//console.log(currentTheme); // DEBUG
let newTheme: DefaultTheme;
switch(currentTheme.themeId) {
case 1:
newTheme = darkTheme;
break;
case 2:
newTheme = amoledTheme;
break;
case 3:
newTheme = lightTheme;
break;
default:
newTheme = currentTheme;
}
return (
<button onClick={() => updateTheme(newTheme)}>Switch Style</button>
);
}
export function getTheme(themeId: number): DefaultTheme {
let theme: DefaultTheme;
switch(themeId) {
case 1:
theme = lightTheme;
break;
case 2:
theme = darkTheme;
break;
case 3:
theme = amoledTheme;
break;
default:
theme = darkTheme
}
return theme;
}
export default StyleSelector;

View file

@ -3,7 +3,10 @@ import type { 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 { createContext, useContext, useEffect, useState } from 'react'
import { getCookie, getCookies, setCookie } from 'cookies-next'
import { darkTheme } from '../components/themes';
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & { export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
getLayout?: (page: ReactElement) => ReactNode getLayout?: (page: ReactElement) => ReactNode
@ -13,10 +16,41 @@ export type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout Component: NextPageWithLayout
} }
const ThemeUpdateContext = createContext(
(theme: DefaultTheme) => console.error("attempted to set theme outside of a ThemeUpdateContext.Provider")
)
export const useUpdateTheme = () => useContext(ThemeUpdateContext);
export default function Website({ Component, pageProps }: AppPropsWithLayout) { export default function Website({ Component, pageProps }: AppPropsWithLayout) {
const [selectedTheme, setselectedTheme] = useState(darkTheme);
//console.log("Selected Theme: ", selectedTheme); // DEBUG
useEffect(() => {
setCookie('theme', selectedTheme.themeId);
}, [selectedTheme])
// Use the layout defined at the page level, if available // Use the layout defined at the page level, if available
const getLayout = Component.getLayout ?? ((page) => ( const getLayout = Component.getLayout ?? ((page) => (
<Layout>{page}</Layout>)) <Layout>{page}</Layout>))
return getLayout(<Component {...pageProps} />) return (
<ThemeProvider theme={selectedTheme}>
<ThemeUpdateContext.Provider value={setselectedTheme}>
{getLayout(<Component {...pageProps} />)}
</ThemeUpdateContext.Provider>
</ThemeProvider>
)
}
export async function getServerSideProps() {
return {
props: {
token: {},
}
}
} }

View file

@ -1,6 +1,12 @@
import { Html, Head, Main, NextScript } from 'next/document' import { getCookie, getCookies, setCookie } from 'cookies-next';
import { Html, Head, Main, NextScript, DocumentContext } from 'next/document'
import { useUpdateTheme } from './_app';
import { darkTheme } from '../components/themes';
import { GetServerSidePropsContext } from 'next';
export default function Document() { export default function Document(ctx: DocumentContext) {
const updateTheme = useUpdateTheme();
return ( return (
<Html lang='en'> <Html lang='en'>
<Head /> <Head />

View file

@ -26,23 +26,21 @@ function Servers(props: EntryList) {
{Object.values(serverList).map((item: CustomLink) => { {Object.values(serverList).map((item: CustomLink) => {
if (item.href != null) { if (item.href != null) {
return ( return (
<Link key={item.name} href={item.href}> <Link className={styles.contentcard} key={item.name} href={item.href}>
<a className={styles.contentcard}> <div className={styles.contenttitle}><h2>{item.name}</h2></div>
<div className={styles.contenttitle}><h2>{item.name }</h2></div> <div><p>{item.desc}</p></div>
<div><p>{item.desc}</p></div> <div><p>{item.ip}</p></div>
<div><p>{item.ip }</p></div> <div className={item.status == "Online" ? styles.contentonline : styles.contentoffline}><p>{item.status}</p></div>
<div className={item.status == "Online" ? styles.contentonline : styles.contentoffline}><p>{item.status}</p></div>
</a>
</Link> </Link>
) )
} }
else { else {
return ( return (
<a key={item.name} className={styles.contentcardstatic}> <a key={item.name} className={styles.contentcardstatic}>
<div className={styles.contenttitle}><h2>{item.name }</h2></div> <div className={styles.contenttitle}><h2>{item.name}</h2></div>
<div><p>{item.desc}</p></div> <div><p>{item.desc}</p></div>
<div><p>{item.ip}</p></div> <div><p>{item.ip}</p></div>
<div className={item.status == "Online" ? styles.contentonline : styles.contentoffline}><p>{item.status}</p></div> <div className={item.status == "Online" ? styles.contentonline : styles.contentoffline}><p>{item.status}</p></div>
</a> </a>
) )
} }

View file

@ -6,11 +6,10 @@ export default function Home() {
return ( return (
<> <>
<Head> <Head>
<title>Neshura Servers</title> <title>Neshweb - Home</title>
<meta charSet='utf-8' /> <meta charSet='utf-8' />
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
</Head> </Head>
<h1 className={styles.title}> <h1 className={styles.title}>
Welcome to my Servers Webpage Welcome to my Servers Webpage
</h1> </h1>
@ -19,28 +18,22 @@ export default function Home() {
Feel free to look around Feel free to look around
</p> </p>
<div className={styles.grid}> <div className={styles.grid}>
<Link key="about" href="/about"> <Link className={styles.card} key="about" href="/about">
<a className={styles.card}> <h2>About &rarr;</h2>
<h2>About &rarr;</h2> <p>Useless Info, don&apos;t bother</p>
<p>Useless Info, don&apos;t bother</p>
</a>
</Link> </Link>
<Link key="servers" href="/games"> <Link className={styles.card} key="servers" href="/games">
<a className={styles.card}> <h2>Games &rarr;</h2>
<h2>Games &rarr;</h2> <p>List of all available Servers</p>
<p>List of all available Servers</p>
</a>
</Link> </Link>
<Link key="services" href="/services"> <Link className={styles.card} key="services" href="/services">
<a className={styles.card}> <h2>Services &rarr;</h2>
<h2>Services &rarr;</h2> <p>List of available Services</p>
<p>List of available Services</p>
</a>
</Link> </Link>
</div> </div>
</> </>
) )
} }

View file

@ -20,24 +20,22 @@ function Services() {
content = content =
<div className={styles.grid}> <div className={styles.grid}>
{initialData?.map((item: Service) => ( {initialData?.map((item: Service) => (
<Link key={item.name} href={item.href}> <Link className={styles.contentcard} key={item.name} href={item.href}>
<a className={styles.contentcard}> <div className={styles.contentTitle}>
<div className={styles.contentTitle}> {
{ item.icon ? (
item.icon ? ( <div className={styles.contentIcon}>
<div className={styles.contentIcon}> <Image alt="icon" src={item.icon} layout="fill" objectFit="contain"></Image>
<Image alt="icon" src={item.icon} layout="fill" objectFit="contain"></Image> </div>
</div> ) : (<></>)
) : (<></>) }
} <h2>{item.name}</h2>
<h2>{item.name}</h2> </div>
</div> <div className={item.status === ServiceStatus.online ? styles.statusOnline : item.status === ServiceStatus.offline ? styles.statusOffline : styles.statusLoading}>
<div className={item.status === ServiceStatus.online ? styles.statusOnline : item.status === ServiceStatus.offline ? styles.statusOffline : styles.statusLoading}> {item.status}
{item.status} </div>
</div> <div><p>{item.desc}</p></div>
<div><p>{item.desc}</p></div> <div className={styles.cardwarn}><p>{item.warn}</p></div>
<div className={styles.cardwarn}><p>{item.warn}</p></div>
</a>
</Link> </Link>
))} ))}
</div> </div>
@ -46,24 +44,22 @@ function Services() {
content = content =
<div className={styles.grid}> <div className={styles.grid}>
{fullData.map((item: Service) => ( {fullData.map((item: Service) => (
<Link key={item.name} href={item.href}> <Link className={styles.contentcard} key={item.name} href={item.href}>
<a className={styles.contentcard}> <div className={styles.contentTitle}>
<div className={styles.contentTitle}> {
{ item.icon ? (
item.icon ? ( <div className={styles.contentIcon}>
<div className={styles.contentIcon}> <Image alt="icon" src={item.icon} fill></Image>
<Image alt="icon" src={item.icon} layout="fill" objectFit="contain"></Image> </div>
</div> ) : (<></>)
) : (<></>) }
} <h2>{item.name}</h2>
<h2>{item.name}</h2> </div>
</div> <div className={item.status === ServiceStatus.online ? styles.statusOnline : item.status === ServiceStatus.offline ? styles.statusOffline : styles.statusLoading}>
<div className={item.status === ServiceStatus.online ? styles.statusOnline : item.status === ServiceStatus.offline ? styles.statusOffline : styles.statusLoading}> {item.status}
{item.status} </div>
</div> <div><p>{item.desc}</p></div>
<div><p>{item.desc}</p></div> <div className={styles.cardwarn}><p>{item.warn}</p></div>
<div className={styles.cardwarn}><p>{item.warn}</p></div>
</a>
</Link> </Link>
))} ))}
</div> </div>

12
styled.d.ts vendored Normal file
View file

@ -0,0 +1,12 @@
import 'styled-components'
declare module 'styled-components' {
export interface DefaultTheme {
themeId: number,
colors: {
background: string,
primary: string
secondary: string
}
}
}

View file

@ -1,8 +1,3 @@
.page {
width: 100%;
background-color: var(--black-0f);
}
.container { .container {
padding: 0 2rem; padding: 0 2rem;
} }
@ -175,6 +170,7 @@
} }
.contentIcon { .contentIcon {
object-fit: "contain";
margin-right: 0.4rem; margin-right: 0.4rem;
position: relative; position: relative;
aspect-ratio: 1; aspect-ratio: 1;