Added basic mobile Layout
This commit is contained in:
parent
7c7d60bab7
commit
635fd437da
6 changed files with 275 additions and 49 deletions
|
@ -1,4 +1,4 @@
|
||||||
import { Footer } from "../components/styles/generic"
|
import { Footer, MobileFooter } from "../components/styles/generic"
|
||||||
|
|
||||||
const PageFooter = () => {
|
const PageFooter = () => {
|
||||||
return (
|
return (
|
||||||
|
@ -8,4 +8,12 @@ const PageFooter = () => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NavMenuFooter = () => {
|
||||||
|
return (
|
||||||
|
<MobileFooter>
|
||||||
|
Built using Next.js
|
||||||
|
</MobileFooter>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default PageFooter;
|
export default PageFooter;
|
|
@ -2,9 +2,14 @@ import PageFooter from './footer';
|
||||||
import PageNavbar from './navbar';
|
import PageNavbar from './navbar';
|
||||||
import Script from 'next/script';
|
import Script from 'next/script';
|
||||||
import { Page, Main } from './styles/generic';
|
import { Page, Main } from './styles/generic';
|
||||||
|
import useWindowSize from './windowsize';
|
||||||
|
|
||||||
const Layout = ({ children }: { children: React.ReactNode }) => {
|
const Layout = ({ children }: { children: React.ReactNode }) => {
|
||||||
return (
|
const isMobile = useWindowSize();
|
||||||
|
|
||||||
|
let ret: JSX.Element;
|
||||||
|
if(isMobile) {
|
||||||
|
ret = (
|
||||||
<Page>
|
<Page>
|
||||||
<Script id="matomo_analytics"
|
<Script id="matomo_analytics"
|
||||||
defer src='https://static.cloudflareinsights.com/beacon.min.js'
|
defer src='https://static.cloudflareinsights.com/beacon.min.js'
|
||||||
|
@ -29,7 +34,40 @@ const Layout = ({ children }: { children: React.ReactNode }) => {
|
||||||
`}
|
`}
|
||||||
</Script>
|
</Script>
|
||||||
|
|
||||||
<PageNavbar />
|
<PageNavbar mobile={isMobile}/>
|
||||||
|
<Main>
|
||||||
|
{children}
|
||||||
|
</Main>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ret = (
|
||||||
|
<Page>
|
||||||
|
<Script id="matomo_analytics"
|
||||||
|
defer src='https://static.cloudflareinsights.com/beacon.min.js'
|
||||||
|
data-cf-beacon='{"token": "826fc083aa86417890c0ceb3e0a597fa"}'>
|
||||||
|
</Script>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<PageNavbar mobile={isMobile}/>
|
||||||
<Main>
|
<Main>
|
||||||
{children}
|
{children}
|
||||||
</Main>
|
</Main>
|
||||||
|
@ -37,5 +75,7 @@ const Layout = ({ children }: { children: React.ReactNode }) => {
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
export default Layout;
|
export default Layout;
|
|
@ -1,12 +1,57 @@
|
||||||
import { usePathname } from 'next/navigation'
|
import { usePathname } from 'next/navigation'
|
||||||
import { NavBar, NavLink, NavWrap } from './styles/navbar';
|
import { NavBar, NavBarMobile, NavIndicator, NavIndicators, NavLink, NavSideMenu, NavSideMenuButton, NavSideMenuPanel, NavSideMenuButtonPlaceholder, NavWrap, NavWrapMobile, NavWrapMobileGhost, NavSideMenuGhost } from './styles/navbar';
|
||||||
import { StyleSelector, StyleSelectorPlaceholder } from './themeselector';
|
import { StyleSelector, StyleSelectorPlaceholder } from './themeselector';
|
||||||
import Links from '../public/data/navbar.json';
|
import Links from '../public/data/navbar.json';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import NavMenuFooter from './footer';
|
||||||
|
|
||||||
const PageNavbar = () => {
|
const PageNavbar = ({ mobile }: { mobile: number }) => {
|
||||||
const path = usePathname();
|
const path = usePathname();
|
||||||
|
const [sideBarActive, setSideBarActive] = useState(true); //DEBUG: set to false
|
||||||
|
|
||||||
return (
|
function handleSidebar(event: any) {
|
||||||
|
if (!event.currentTarget.contains(event.relatedTarget)) {
|
||||||
|
setSideBarActive(false);
|
||||||
|
console.log(event.relatedTarget); // DEBUG
|
||||||
|
}
|
||||||
|
else { console.log("nah") } // DEBUG
|
||||||
|
}
|
||||||
|
|
||||||
|
let navbar: JSX.Element;
|
||||||
|
if (mobile) {
|
||||||
|
navbar = (
|
||||||
|
<>
|
||||||
|
<NavSideMenu onBlur={(event) => handleSidebar(event)} active={+sideBarActive}>
|
||||||
|
<NavBarMobile>
|
||||||
|
{Links.links.map((item) => (
|
||||||
|
<NavLink active={path === item.href ? +true : +false} key={item.name} href={item.href}>
|
||||||
|
{item.name}
|
||||||
|
</NavLink>
|
||||||
|
))}
|
||||||
|
<NavLink key="Mastodon_Verify" rel="me" href="https://mastodon.neshweb.net/@neshura">
|
||||||
|
Mastodon
|
||||||
|
</NavLink>
|
||||||
|
</NavBarMobile>
|
||||||
|
<NavSideMenuGhost/>
|
||||||
|
<StyleSelector />
|
||||||
|
<NavSideMenuGhost/>
|
||||||
|
<NavMenuFooter />
|
||||||
|
</NavSideMenu>
|
||||||
|
<NavWrapMobile>
|
||||||
|
<NavSideMenuButton onClick={() => setSideBarActive(!sideBarActive)} active={+sideBarActive}>Menu</NavSideMenuButton>
|
||||||
|
<NavIndicators>
|
||||||
|
{Links.links.map((item) => (
|
||||||
|
<NavIndicator active={path === item.href ? +true : +false} key={item.name} href={item.href} />
|
||||||
|
))}
|
||||||
|
</NavIndicators>
|
||||||
|
<NavSideMenuButtonPlaceholder />
|
||||||
|
</NavWrapMobile>
|
||||||
|
<NavWrapMobileGhost/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
navbar = (
|
||||||
<NavWrap>
|
<NavWrap>
|
||||||
<StyleSelector></StyleSelector>
|
<StyleSelector></StyleSelector>
|
||||||
<NavBar>
|
<NavBar>
|
||||||
|
@ -23,5 +68,7 @@ const PageNavbar = () => {
|
||||||
</NavWrap>
|
</NavWrap>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return navbar;
|
||||||
|
}
|
||||||
|
|
||||||
export default PageNavbar;
|
export default PageNavbar;
|
|
@ -43,3 +43,8 @@ export const Footer = styled.footer`
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const MobileFooter = styled(Footer)`
|
||||||
|
position: absolute;
|
||||||
|
bottom: 100%;
|
||||||
|
`
|
||||||
|
|
|
@ -13,6 +13,61 @@ export const NavWrap = styled.div`
|
||||||
border-bottom: 1px solid ${({ theme }) => theme.colors.primary};
|
border-bottom: 1px solid ${({ theme }) => theme.colors.primary};
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
||||||
|
export const NavWrapMobile = styled(NavWrap)`
|
||||||
|
width: 100%;
|
||||||
|
flex-direction: row;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 100;
|
||||||
|
`
|
||||||
|
|
||||||
|
export const NavWrapMobileGhost = styled.div`
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 57px;
|
||||||
|
`
|
||||||
|
|
||||||
|
export const NavSideMenu = styled.div <ActivePropType>`
|
||||||
|
position: fixed;
|
||||||
|
top: 0%; left: 0%; right: 0%; bottom: 0%;
|
||||||
|
max-width: ${ props => props.active ? "60%" : "0%"};
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
|
background-color: ${({ theme }) => theme.colors.background};
|
||||||
|
visibility: ${ props => props.active ? "visible" : "hidden"};
|
||||||
|
width: ${ props => props.active ? "360px" : "0%"};
|
||||||
|
transition-delay: ${ props => props.active ? "0s, 0s" : "0s, 0.3s"};
|
||||||
|
`
|
||||||
|
|
||||||
|
export const NavSideMenuPanel = styled.div <ActivePropType>`
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
export const NavSideMenuButton = styled.button <ActivePropType>`
|
||||||
|
z-index: 100;
|
||||||
|
margin: 16px;
|
||||||
|
color: ${ props => props.active ? ({ theme }) => theme.colors.background : ({ theme }) => theme.colors.primary };
|
||||||
|
background-color: ${ props => props.active ? ({ theme }) => theme.colors.secondary : ({ theme }) => theme.colors.background };
|
||||||
|
`
|
||||||
|
|
||||||
|
export const NavSideMenuButtonPlaceholder = styled.div`
|
||||||
|
width: 48px;
|
||||||
|
margin: 16px;
|
||||||
|
`
|
||||||
|
|
||||||
|
export const NavSideMenuGhost = styled.div`
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
export const NavBar = styled.nav`
|
export const NavBar = styled.nav`
|
||||||
margin-right: 1%;
|
margin-right: 1%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -23,6 +78,10 @@ export const NavBar = styled.nav`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const NavBarMobile = styled(NavBar)`
|
||||||
|
flex-direction: column;
|
||||||
|
`
|
||||||
|
|
||||||
export const NavLink = styled(Link) <ActivePropType>`
|
export const NavLink = styled(Link) <ActivePropType>`
|
||||||
color: ${props => props.active ?
|
color: ${props => props.active ?
|
||||||
({ theme }) => theme.invertButtons ?
|
({ theme }) => theme.invertButtons ?
|
||||||
|
@ -54,3 +113,36 @@ export const NavLink = styled(Link) <ActivePropType>`
|
||||||
theme.colors.background};
|
theme.colors.background};
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const NavIndicators = styled.nav`
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
padding: 1rem 0;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
`
|
||||||
|
|
||||||
|
export const NavIndicator = styled(Link) <ActivePropType>`
|
||||||
|
margin: 0.2rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
width: 10px;
|
||||||
|
border: 1px solid ${({ theme }) => theme.colors.primary};
|
||||||
|
|
||||||
|
background-color: ${props => props.active ?
|
||||||
|
({ theme }) => theme.invertButtons ?
|
||||||
|
theme.colors.secondary : theme.colors.background :
|
||||||
|
({ theme }) => theme.colors.background};
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: ${({ theme }) => theme.invertButtons ?
|
||||||
|
theme.colors.text ? theme.colors.text : theme.colors.primary :
|
||||||
|
theme.colors.secondary};
|
||||||
|
|
||||||
|
background-color: ${({ theme }) => theme.invertButtons ?
|
||||||
|
theme.colors.secondary :
|
||||||
|
theme.colors.background};
|
||||||
|
}
|
||||||
|
`
|
34
components/windowsize.tsx
Normal file
34
components/windowsize.tsx
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
interface ScreenSize {
|
||||||
|
width: number | undefined;
|
||||||
|
height: number | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useWindowSize(): number {
|
||||||
|
const [windowSize, setWindowSize] = useState<ScreenSize>({
|
||||||
|
width: undefined,
|
||||||
|
height: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function handleResize() {
|
||||||
|
setWindowSize({
|
||||||
|
width: window.innerWidth,
|
||||||
|
height: window.innerHeight,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("resize", handleResize);
|
||||||
|
|
||||||
|
handleResize();
|
||||||
|
|
||||||
|
return () => window.removeEventListener("resize", handleResize);
|
||||||
|
}, []);
|
||||||
|
if(typeof(windowSize.width) === "number") {
|
||||||
|
return windowSize.width <= 1080 ? 1 : 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue