parent
db6d77dced
commit
a8cb979e95
@ -1,23 +1,31 @@ |
|||||||
import { useRouter } from "next/router" |
import { useRouter } from "next/router"; |
||||||
import { ReactNode } from "react" |
import { ReactNode } from "react"; |
||||||
import Link from "next/link" |
import Link from "next/link"; |
||||||
import styled, {css} from "styled-components" |
import styled, { css } from "styled-components"; |
||||||
|
|
||||||
const ALink = styled.a<{active?: boolean}>` |
const ALink = styled.a<{ active?: boolean }>` |
||||||
border-bottom: 1px solid transparent; |
border-bottom: 1px solid transparent; |
||||||
${({active}) => active && css` |
${({ active }) => |
||||||
color: var(--fg) !important; |
active && |
||||||
/*border-bottom-color: currentColor;*/ |
css` |
||||||
`}
|
color: var(--fg) !important; |
||||||
` |
/*border-bottom-color: currentColor;*/ |
||||||
|
`}
|
||||||
|
`;
|
||||||
|
|
||||||
const ActiveLink = ({children, href}: {children: ReactNode, href: string}) => { |
const ActiveLink = ({ |
||||||
const router = useRouter() |
children, |
||||||
return ( |
href, |
||||||
<Link href={href} passHref> |
}: { |
||||||
<ALink active={router.asPath === href}>{children}</ALink> |
children: ReactNode; |
||||||
</Link> |
href: string; |
||||||
) |
}) => { |
||||||
} |
const router = useRouter(); |
||||||
|
return ( |
||||||
|
<Link href={href} passHref> |
||||||
|
<ALink active={router.asPath === href}>{children}</ALink> |
||||||
|
</Link> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
export default ActiveLink |
export default ActiveLink; |
||||||
|
@ -1,134 +1,139 @@ |
|||||||
import styled, {css} from "styled-components" |
import styled, { css } from "styled-components"; |
||||||
import React, {useState} from "react" |
import React, { useState } from "react"; |
||||||
import NavLinks from "./navlinks" |
import NavLinks from "./navlinks"; |
||||||
|
|
||||||
const MenuLine = styled.div` |
const MenuLine = styled.div` |
||||||
width: 1.8rem; |
width: 1.8rem; |
||||||
height: 3px; |
height: 3px; |
||||||
border-radius: 2px; |
border-radius: 2px; |
||||||
background-color: var(--fg); |
background-color: var(--fg); |
||||||
&:not(:last-child) { |
&:not(:last-child) { |
||||||
margin-bottom: .4rem; |
margin-bottom: 0.4rem; |
||||||
} |
} |
||||||
` |
`;
|
||||||
|
|
||||||
const BurgerContainer = styled.div<{open: boolean}>` |
const BurgerContainer = styled.div<{ open: boolean }>` |
||||||
display: none; |
display: none; |
||||||
width: 1.8rem; |
width: 1.8rem; |
||||||
height: 1.8rem; |
height: 1.8rem; |
||||||
flex-direction: column; |
flex-direction: column; |
||||||
justify-content: center; |
justify-content: center; |
||||||
margin-left: auto; |
margin-left: auto; |
||||||
|
|
||||||
div { |
div { |
||||||
transition: .2s; |
transition: 0.2s; |
||||||
} |
} |
||||||
|
|
||||||
&:hover { |
&:hover { |
||||||
cursor: pointer; |
cursor: pointer; |
||||||
} |
} |
||||||
|
|
||||||
@media screen and (max-width: 960px) { |
@media screen and (max-width: 960px) { |
||||||
display: flex; |
display: flex; |
||||||
|
|
||||||
nav { |
nav { |
||||||
display: none !important; |
display: none !important; |
||||||
position: absolute; |
position: absolute; |
||||||
top: 0; |
top: 0; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
${({open}) => open && css` |
${({ open }) => |
||||||
position: fixed; |
open && |
||||||
right: 2rem; |
css` |
||||||
z-index: 99; |
position: fixed; |
||||||
|
right: 2rem; |
||||||
div { |
z-index: 99; |
||||||
position: absolute; |
|
||||||
} |
div { |
||||||
|
position: absolute; |
||||||
div:nth-child(1) { |
} |
||||||
transform: rotate(45deg) translate(.2rem, .2rem); |
|
||||||
} |
div:nth-child(1) { |
||||||
|
transform: rotate(45deg) translate(0.2rem, 0.2rem); |
||||||
div:nth-child(2) { |
} |
||||||
transform: rotate(-45deg) translate(-.18rem, .2rem); |
|
||||||
} |
div:nth-child(2) { |
||||||
|
transform: rotate(-45deg) translate(-0.18rem, 0.2rem); |
||||||
div:last-child { |
} |
||||||
display: none; |
|
||||||
} |
div:last-child { |
||||||
`}
|
display: none; |
||||||
` |
} |
||||||
|
`}
|
||||||
const BNavCont = styled.nav<{show: boolean}>` |
`;
|
||||||
display: flex; |
|
||||||
opacity: 0; |
const BNavCont = styled.nav<{ show: boolean }>` |
||||||
backdrop-filter: blur(25px); |
display: flex; |
||||||
position: fixed; |
opacity: 0; |
||||||
flex-direction: column; |
backdrop-filter: blur(25px); |
||||||
background: #21242baf; |
position: fixed; |
||||||
left: 0; |
flex-direction: column; |
||||||
top: 0; |
background: #21242baf; |
||||||
pointer-events: none; |
left: 0; |
||||||
width: 100vw; |
top: 0; |
||||||
height: 100vh; |
pointer-events: none; |
||||||
z-index: 2; |
width: 100vw; |
||||||
transition: opacity .2s; |
height: 100vh; |
||||||
|
z-index: 2; |
||||||
align-items: center; |
transition: opacity 0.2s; |
||||||
justify-content: center; |
|
||||||
|
align-items: center; |
||||||
gap: 1.5rem; |
justify-content: center; |
||||||
font-size: 1.2rem; |
|
||||||
border: unset; |
gap: 1.5rem; |
||||||
|
font-size: 1.2rem; |
||||||
a { |
border: unset; |
||||||
font-size: 2rem; |
|
||||||
color: var(--fg-button); |
a { |
||||||
transition: var(--trans-time) opacity; |
font-size: 2rem; |
||||||
text-align: center; |
color: var(--fg-button); |
||||||
} |
transition: var(--trans-time) opacity; |
||||||
|
text-align: center; |
||||||
a:hover { |
} |
||||||
opacity: .4; |
|
||||||
} |
a:hover { |
||||||
|
opacity: 0.4; |
||||||
|
} |
||||||
${({show}) => show && css` |
|
||||||
display: flex; |
${({ show }) => |
||||||
opacity: 1; |
show && |
||||||
pointer-events: unset; |
css` |
||||||
`}
|
display: flex; |
||||||
|
opacity: 1; |
||||||
|
pointer-events: unset; |
||||||
@media screen and (min-width: 960px) { |
`}
|
||||||
display: none; |
|
||||||
position: absolute; |
@media screen and (min-width: 960px) { |
||||||
top: 0; |
display: none; |
||||||
} |
position: absolute; |
||||||
` |
top: 0; |
||||||
|
} |
||||||
const BNav: React.FC<{show: boolean, onClick: () => void}> = ({show, onClick}) => { |
`;
|
||||||
return ( |
|
||||||
<BNavCont show={show} onClick={onClick}> |
const BNav: React.FC<{ show: boolean; onClick: () => void }> = ({ |
||||||
<NavLinks /> |
show, |
||||||
</BNavCont> |
onClick, |
||||||
) |
}) => { |
||||||
} |
return ( |
||||||
|
<BNavCont show={show} onClick={onClick}> |
||||||
|
<NavLinks /> |
||||||
|
</BNavCont> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
const Menu = () => { |
const Menu = () => { |
||||||
const [open, setOpen] = useState(false); |
const [open, setOpen] = useState(false); |
||||||
return ( |
return ( |
||||||
<> |
<> |
||||||
<BNav show={open} onClick={() => setOpen(false)}/> |
<BNav show={open} onClick={() => setOpen(false)} /> |
||||||
<BurgerContainer open={open} onClick={() => setOpen(!open)}> |
<BurgerContainer open={open} onClick={() => setOpen(!open)}> |
||||||
<MenuLine /> |
<MenuLine /> |
||||||
<MenuLine /> |
<MenuLine /> |
||||||
<MenuLine /> |
<MenuLine /> |
||||||
</BurgerContainer> |
</BurgerContainer> |
||||||
</> |
</> |
||||||
) |
); |
||||||
} |
}; |
||||||
|
|
||||||
export default Menu |
export default Menu; |
||||||
|
@ -1,42 +1,43 @@ |
|||||||
import styled from "styled-components" |
import styled from "styled-components"; |
||||||
import Nav from "./nav" |
import Nav from "./nav"; |
||||||
import Link from "next/link" |
import Link from "next/link"; |
||||||
import Menu from "./burgermenu" |
import Menu from "./burgermenu"; |
||||||
|
|
||||||
const HeaderCont = styled.header` |
const HeaderCont = styled.header` |
||||||
display: flex; |
display: flex; |
||||||
align-items: center; |
align-items: center; |
||||||
border-bottom: var(--border-size) var(--border-type) var(--border-color); |
border-bottom: var(--border-size) var(--border-type) var(--border-color); |
||||||
padding: .8rem 2rem; |
padding: 0.8rem 2rem; |
||||||
gap: 2rem; |
gap: 2rem; |
||||||
|
|
||||||
h1 { |
h1 { |
||||||
font-weight: normal; |
font-weight: normal; |
||||||
|
|
||||||
a { |
a { |
||||||
color: inherit; |
color: inherit; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
nav { |
nav { |
||||||
margin-left: auto; |
margin-left: auto; |
||||||
float: right; |
float: right; |
||||||
} |
} |
||||||
|
|
||||||
|
@media screen and (max-width: 960px) { |
||||||
@media screen and (max-width: 960px) { |
padding: 1rem 2rem; |
||||||
padding: 1rem 2rem; |
} |
||||||
} |
`;
|
||||||
` |
|
||||||
|
|
||||||
const Header = () => { |
const Header = () => { |
||||||
return ( |
return ( |
||||||
<HeaderCont> |
<HeaderCont> |
||||||
<h1><Link href="/">wych.dev</Link></h1> |
<h1> |
||||||
<Nav /> |
<Link href="/">wych.dev</Link> |
||||||
<Menu /> |
</h1> |
||||||
</HeaderCont> |
<Nav /> |
||||||
) |
<Menu /> |
||||||
} |
</HeaderCont> |
||||||
|
); |
||||||
export default Header |
}; |
||||||
|
|
||||||
|
export default Header; |
||||||
|
@ -1,16 +1,28 @@ |
|||||||
import {IconDefinition} from "@fortawesome/fontawesome-svg-core" |
import { IconDefinition } from "@fortawesome/fontawesome-svg-core"; |
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome" |
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; |
||||||
import styled from "styled-components" |
import styled from "styled-components"; |
||||||
|
|
||||||
const ILink = styled.a` |
const ILink = styled.a` |
||||||
font-size: 1.5rem; |
font-size: 1.5rem; |
||||||
margin: 0 .4rem; |
margin: 0 0.4rem; |
||||||
` |
`;
|
||||||
|
|
||||||
const IconLink = ({href, icon, target, rel}: {href: string, icon: IconDefinition, target: string, rel: string}) => { |
const IconLink = ({ |
||||||
return ( |
href, |
||||||
<ILink href={href} target={target} rel={rel}><FontAwesomeIcon icon={icon}/></ILink> |
icon, |
||||||
) |
target, |
||||||
} |
rel, |
||||||
|
}: { |
||||||
|
href: string; |
||||||
|
icon: IconDefinition; |
||||||
|
target: string; |
||||||
|
rel: string; |
||||||
|
}) => { |
||||||
|
return ( |
||||||
|
<ILink href={href} target={target} rel={rel}> |
||||||
|
<FontAwesomeIcon icon={icon} /> |
||||||
|
</ILink> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
export default IconLink |
export default IconLink; |
||||||
|
@ -1,17 +1,19 @@ |
|||||||
import Header from "./header" |
import Header from "./header"; |
||||||
import Footer from "./footer" |
import Footer from "./footer"; |
||||||
import {ReactNode} from "react" |
import { ReactNode } from "react"; |
||||||
import Head from "next/head" |
import Head from "next/head"; |
||||||
|
|
||||||
const Layout = ({children}: {children: ReactNode}) => { |
const Layout = ({ children }: { children: ReactNode }) => { |
||||||
return (<> |
return ( |
||||||
<Head> |
<> |
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
<Head> |
||||||
<title>wych.dev</title> |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
||||||
</Head> |
<title>wych.dev</title> |
||||||
<main>{children}</main> |
</Head> |
||||||
<Footer /> |
<main>{children}</main> |
||||||
</>) |
<Footer /> |
||||||
} |
</> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
export default Layout |
export default Layout; |
||||||
|
@ -1,34 +1,34 @@ |
|||||||
import styled from "styled-components" |
import styled from "styled-components"; |
||||||
import NavLinks from "./navlinks" |
import NavLinks from "./navlinks"; |
||||||
|
|
||||||
const NavCont = styled.nav` |
const NavCont = styled.nav` |
||||||
display: flex; |
display: flex; |
||||||
gap: 1.5rem; |
gap: 1.5rem; |
||||||
font-size: 1.2rem; |
font-size: 1.2rem; |
||||||
border: unset; |
border: unset; |
||||||
|
|
||||||
a { |
a { |
||||||
color: var(--fg-button); |
color: var(--fg-button); |
||||||
transition: var(--trans-time) opacity; |
transition: var(--trans-time) opacity; |
||||||
} |
} |
||||||
|
|
||||||
a:hover { |
a:hover { |
||||||
opacity: .4; |
opacity: 0.4; |
||||||
} |
} |
||||||
|
|
||||||
@media screen and (max-width: 960px) { |
@media screen and (max-width: 960px) { |
||||||
display: none; |
display: none; |
||||||
position: absolute; |
position: absolute; |
||||||
top: 0; |
top: 0; |
||||||
} |
} |
||||||
` |
`;
|
||||||
|
|
||||||
const Nav = () => { |
const Nav = () => { |
||||||
return ( |
return ( |
||||||
<NavCont> |
<NavCont> |
||||||
<NavLinks /> |
<NavLinks /> |
||||||
</NavCont> |
</NavCont> |
||||||
) |
); |
||||||
} |
}; |
||||||
|
|
||||||
export default Nav |
export default Nav; |
||||||
|
@ -1,15 +1,19 @@ |
|||||||
import ActiveLink from "./activelink" |
import ActiveLink from "./activelink"; |
||||||
|
|
||||||
const NavLinks = () => { |
const NavLinks = () => { |
||||||
return ( |
return ( |
||||||
<> |
<> |
||||||
<ActiveLink href="/">About</ActiveLink> |
<ActiveLink href="/">About</ActiveLink> |
||||||
<ActiveLink href="/#contact">Contact</ActiveLink> |
<ActiveLink href="/#contact">Contact</ActiveLink> |
||||||
<ActiveLink href="/projects">Projects</ActiveLink> |
<ActiveLink href="/projects">Projects</ActiveLink> |
||||||
<a href="https://github.com/E-Almqvist" target="_blank" rel="noreferrer">GitHub</a> |
<a href="https://github.com/E-Almqvist" target="_blank" rel="noreferrer"> |
||||||
<a href="https://git.wych.dev" target="_blank" rel="noreferrer">WychGit</a> |
GitHub |
||||||
</> |
</a> |
||||||
) |
<a href="https://git.wych.dev" target="_blank" rel="noreferrer"> |
||||||
} |
WychGit |
||||||
|
</a> |
||||||
|
</> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
export default NavLinks |
export default NavLinks; |
||||||
|
@ -1,21 +1,25 @@ |
|||||||
import * as React from "react" |
import Link from "next/link"; |
||||||
import { SVGProps } from "react" |
import * as React from "react"; |
||||||
|
import { SVGProps } from "react"; |
||||||
|
|
||||||
const ScrollMe = (props: SVGProps<SVGSVGElement>) => ( |
const ScrollMe = (props: SVGProps<SVGSVGElement> & { href: string }) => ( |
||||||
<svg |
<Link href={props.href}> |
||||||
xmlns="http://www.w3.org/2000/svg" |
<svg |
||||||
width="1em" |
xmlns="http://www.w3.org/2000/svg" |
||||||
height="1em" |
height="1em" |
||||||
stroke="currentColor" |
viewBox="0 0 38 23" |
||||||
{...props} |
stroke="currentColor" |
||||||
> |
fill="none" |
||||||
<path |
{...props} |
||||||
strokeLinecap="round" |
> |
||||||
strokeLinejoin="round" |
<path |
||||||
strokeWidth={2.8} |
strokeLinecap="round" |
||||||
d="m2 2 15.77 17.369a2 2 0 0 0 2.96 0L36.5 2" |
strokeLinejoin="round" |
||||||
/> |
strokeWidth={2.8} |
||||||
</svg> |
d="m2 2 15.77 17.369a2 2 0 0 0 2.96 0L36.5 2" |
||||||
) |
/> |
||||||
|
</svg> |
||||||
|
</Link> |
||||||
|
); |
||||||
|
|
||||||
export default ScrollMe |
export default ScrollMe; |
||||||
|
@ -0,0 +1,194 @@ |
|||||||
|
import type { NextPageWithLayout } from "./_app"; |
||||||
|
import type { ReactElement } from "react"; |
||||||
|
import Layout from "../components/layout"; |
||||||
|
import styled from "styled-components"; |
||||||
|
import IconLink from "components/iconlink"; |
||||||
|
import ScrollMe from "components/scrollme"; |
||||||
|
import { faEnvelope } from "@fortawesome/free-solid-svg-icons"; |
||||||
|
import { faGit, faGithub } from "@fortawesome/free-brands-svg-icons"; |
||||||
|
|
||||||
|
export const Section = styled.section` |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
flex-direction: column; |
||||||
|
padding: 0 1rem; |
||||||
|
/*margin: 2rem 0;*/ |
||||||
|
margin: 0 0; |
||||||
|
min-height: 100vh; |
||||||
|
|
||||||
|
h2, |
||||||
|
h3 { |
||||||
|
font-size: 2rem; |
||||||
|
margin: 8px 0; |
||||||
|
} |
||||||
|
|
||||||
|
p { |
||||||
|
margin: 0; |
||||||
|
color: var(--fg); |
||||||
|
} |
||||||
|
|
||||||
|
.topmargin { |
||||||
|
margin-top: 1rem; |
||||||
|
} |
||||||
|
|
||||||
|
ul li { |
||||||
|
margin: 0.5rem 2.5rem; |
||||||
|
} |
||||||
|
|
||||||
|
#img-container { |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
} |
||||||
|
#img-container img { |
||||||
|
width: 22rem; |
||||||
|
height: auto; |
||||||
|
} |
||||||
|
|
||||||
|
footer { |
||||||
|
margin-top: 1rem; |
||||||
|
opacity: 0.5; |
||||||
|
} |
||||||
|
`; |
||||||
|
|
||||||
|
export const Code = styled.code` |
||||||
|
font-family: monospace; |
||||||
|
font-size: 0.9rem; |
||||||
|
background-color: var(--bg-emph); |
||||||
|
color: var(--fg-code); |
||||||
|
border-radius: 0.4rem; |
||||||
|
padding: 0.1rem 0.4rem; |
||||||
|
`; |
||||||
|
|
||||||
|
export const CList = styled.ul` |
||||||
|
list-style: none; |
||||||
|
|
||||||
|
li { |
||||||
|
margin: 1rem !important; |
||||||
|
} |
||||||
|
`; |
||||||
|
|
||||||
|
export const Nem = styled.span` |
||||||
|
color: var(--fg-faded); |
||||||
|
`; |
||||||
|
|
||||||
|
export const LinkList = styled.div` |
||||||
|
display: flex; |
||||||
|
gap: 1.5rem; |
||||||
|
font-size: 1.2rem; |
||||||
|
border: unset; |
||||||
|
justify-content: center; |
||||||
|
|
||||||
|
a { |
||||||
|
color: var(--fg-button); |
||||||
|
transition: var(--trans-time) opacity; |
||||||
|
} |
||||||
|
|
||||||
|
a:hover { |
||||||
|
opacity: 0.4; |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (max-width: 960px) { |
||||||
|
word-break: break-word; |
||||||
|
} |
||||||
|
`; |
||||||
|
|
||||||
|
function getAge() { |
||||||
|
let birth = 1050019200; |
||||||
|
let now = Math.floor(Date.now() / 1000); |
||||||
|
return now - birth; |
||||||
|
} |
||||||
|
|
||||||
|
function secondsToYears(secs: number) { |
||||||
|
return Math.floor(secs / 31557600.0); |
||||||
|
} |
||||||
|
|
||||||
|
const Page: NextPageWithLayout = () => { |
||||||
|
return ( |
||||||
|
<> |
||||||
|
<Section> |
||||||
|
<h2 id="about">/almqv</h2> |
||||||
|
<p> |
||||||
|
I am a {secondsToYears(getAge())} year old{" "} |
||||||
|
<em>Computer Science & Engineering student</em> with a passion for{" "} |
||||||
|
<em>physics</em>, <em>programming</em>, <em>mathematics</em> and |
||||||
|
anything <em>*NIX</em> <Nem>(Linux, UNIX etc)</Nem> related. |
||||||
|
</p> |
||||||
|
{/*TODO: Add GitHub code frequency/contrib here*/} |
||||||
|
<p className="topmargin"> |
||||||
|
Most of my projects are open-source, and if you are interested, you |
||||||
|
can find all of my projects on my <a href="https://git.wych.dev/elal" target="_blank" rel="noreferrer">git-server</a> or <a href="https://github.com/almqv" target="_blank" rel="GITHUBuuuuuuuu |
||||||
|
</Auuuu> |
||||||
|
. |
||||||
|
</p> |
||||||
|
|
||||||
|
<LinkList className="topmargin"> |
||||||
|
<IconLink |
||||||
|
href="#contact" |
||||||
|
icon={faEnvelope} |
||||||
|
target="_self" |
||||||
|
rel="noreferrer" |
||||||
|
/> |
||||||
|
{/*<IconLink href="/projects" icon={ faFolderOpen } target="_self" rel="noreferrer"/>*/} |
||||||
|
<IconLink |
||||||
|
href="https://github.com/almqv" |
||||||
|
icon={faGithub} |
||||||
|
target="_blank" |
||||||
|
rel="noreferrer" |
||||||
|
/> |
||||||
|
<IconLink |
||||||
|
href="https://git.wych.dev/elal" |
||||||
|
icon={faGit} |
||||||
|
target="_blank" |
||||||
|
rel="noreferrer" |
||||||
|
/> |
||||||
|
</LinkList> |
||||||
|
|
||||||
|
<ScrollMe href="#contact" /> |
||||||
|
</Section> |
||||||
|
|
||||||
|
<Section> |
||||||
|
<h2 id="contact">Contact</h2> |
||||||
|
<p> |
||||||
|
You can contact me through email. And if you prefer it, you can |
||||||
|
contact me using PGP. Do note that my{" "} |
||||||
|
<em>email address below is encrypted</em> as a precaution against bots |
||||||
|
et cetera. <em>Do not worry, it is easy to crack</em>. Alternatively |
||||||
|
you could query for my email with my PGP fingerprint (key-id) on some |
||||||
|
PGP key server (i.e. the{" "} |
||||||
|
<a href="https://pgp.mit.edu/" target="_blank" rel="noreferrer"> |
||||||
|
MIT |
||||||
|
</a>{" "} |
||||||
|
or{" "} |
||||||
|
<a |
||||||
|
href="https://keyserver.ubuntu.com/" |
||||||
|
target="_blank" |
||||||
|
rel="noreferrer" |
||||||
|
> |
||||||
|
Ubuntu |
||||||
|
</a>{" "} |
||||||
|
key-server). |
||||||
|
</p> |
||||||
|
<CList> |
||||||
|
<li> |
||||||
|
PGP fingerprint:{" "} |
||||||
|
<Code>68B2 9768 49F0 3C72 38AE B081 E31A 99CE 3E75 A158</Code> |
||||||
|
</li> |
||||||
|
<li> |
||||||
|
Email: <Code>cnlueXpkaXZmZ0B0em52eS5wYnoK</Code> |
||||||
|
</li> |
||||||
|
<li> |
||||||
|
GitHub:{" "} |
||||||
|
<a href="https://github.com/almqv" target="_blank" rel="noreferrer"> |
||||||
|
github.com/almqv |
||||||
|
</a> |
||||||
|
</li> |
||||||
|
</CList> |
||||||
|
</Section> |
||||||
|
</> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
Page.getLayout = (page: ReactElement) => { |
||||||
|
return <Layout>{page}</Layout>; |
||||||
|
}; |
||||||
|
export default Page; |
@ -1,23 +1,23 @@ |
|||||||
import "../styles/globals.css" |
import "../styles/globals.css"; |
||||||
import type { AppProps } from "next/app" |
import type { AppProps } from "next/app"; |
||||||
import type { ReactElement, ReactNode } from "react" |
import type { ReactElement, ReactNode } from "react"; |
||||||
import type { NextPage } from "next" |
import type { NextPage } from "next"; |
||||||
|
|
||||||
import "@fortawesome/fontawesome-svg-core/styles.css";
|
import "@fortawesome/fontawesome-svg-core/styles.css"; |
||||||
import { config } from "@fortawesome/fontawesome-svg-core"; |
import { config } from "@fortawesome/fontawesome-svg-core"; |
||||||
config.autoAddCss = false;
|
config.autoAddCss = false; |
||||||
|
|
||||||
export type NextPageWithLayout = NextPage & { |
export type NextPageWithLayout = NextPage & { |
||||||
getLayout?: (page: ReactElement) => ReactNode |
getLayout?: (page: ReactElement) => ReactNode; |
||||||
} |
}; |
||||||
|
|
||||||
type AppPropsWithLayout = AppProps & { |
type AppPropsWithLayout = AppProps & { |
||||||
Component: NextPageWithLayout |
Component: NextPageWithLayout; |
||||||
} |
}; |
||||||
|
|
||||||
function MyApp({ Component, pageProps }: AppPropsWithLayout) { |
function MyApp({ Component, pageProps }: AppPropsWithLayout) { |
||||||
const getLayout = Component.getLayout ?? ((page) => page) |
const getLayout = Component.getLayout ?? ((page) => page); |
||||||
return getLayout(<Component {...pageProps}/>) |
return getLayout(<Component {...pageProps} />); |
||||||
} |
} |
||||||
|
|
||||||
export default MyApp |
export default MyApp; |
||||||
|
@ -1,43 +1,49 @@ |
|||||||
import Document, { DocumentContext, Html, Head, Main, NextScript } from "next/document"; |
import Document, { |
||||||
|
DocumentContext, |
||||||
|
Html, |
||||||
|
Head, |
||||||
|
Main, |
||||||
|
NextScript, |
||||||
|
} from "next/document"; |
||||||
import React from "react"; |
import React from "react"; |
||||||
import { ServerStyleSheet } from "styled-components"; |
import { ServerStyleSheet } from "styled-components"; |
||||||
|
|
||||||
|
|
||||||
export default class MyDocument extends Document { |
export default class MyDocument extends Document { |
||||||
static async getInitialProps(ctx: DocumentContext) { |
static async getInitialProps(ctx: DocumentContext) { |
||||||
const sheet = new ServerStyleSheet(); |
const sheet = new ServerStyleSheet(); |
||||||
const originalRenderPage = ctx.renderPage; |
const originalRenderPage = ctx.renderPage; |
||||||
|
|
||||||
try { |
try { |
||||||
ctx.renderPage = () => |
ctx.renderPage = () => |
||||||
originalRenderPage({ |
originalRenderPage({ |
||||||
enhanceApp: App => props => sheet.collectStyles(<App {...props} />), |
enhanceApp: (App) => (props) => |
||||||
}); |
sheet.collectStyles(<App {...props} />), |
||||||
|
}); |
||||||
|
|
||||||
const initialProps = await Document.getInitialProps(ctx); |
const initialProps = await Document.getInitialProps(ctx); |
||||||
return { |
return { |
||||||
...initialProps, |
...initialProps, |
||||||
styles: ( |
styles: ( |
||||||
<> |
<> |
||||||
{initialProps.styles} |
{initialProps.styles} |
||||||
{sheet.getStyleElement()} |
{sheet.getStyleElement()} |
||||||
</> |
</> |
||||||
), |
), |
||||||
}; |
}; |
||||||
} finally { |
} finally { |
||||||
sheet.seal(); |
sheet.seal(); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
render() { |
render() { |
||||||
return ( |
return ( |
||||||
<Html> |
<Html> |
||||||
<Head /> |
<Head /> |
||||||
<body> |
<body> |
||||||
<Main /> |
<Main /> |
||||||
<NextScript /> |
<NextScript /> |
||||||
</body> |
</body> |
||||||
</Html> |
</Html> |
||||||
); |
); |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -1,152 +1,200 @@ |
|||||||
import type {NextPageWithLayout} from "./_app" |
import type { NextPageWithLayout } from "./_app"; |
||||||
import type { ReactElement } from "react" |
import type { ReactElement } from "react"; |
||||||
import Layout from "../components/layout" |
import Layout from "../components/layout"; |
||||||
import styled from "styled-components" |
import styled from "styled-components"; |
||||||
import IconLink from "components/iconlink" |
import IconLink from "components/iconlink"; |
||||||
//import ScrollMe from "components/scrollme"
|
import ScrollMe from "components/scrollme"; |
||||||
import {faEnvelope} from "@fortawesome/free-solid-svg-icons" |
import { faEnvelope } from "@fortawesome/free-solid-svg-icons"; |
||||||
import {faGit, faGithub} from "@fortawesome/free-brands-svg-icons" |
import { faGit, faGithub } from "@fortawesome/free-brands-svg-icons"; |
||||||
|
|
||||||
export const Section = styled.section` |
export const Section = styled.section` |
||||||
display: flex; |
display: flex; |
||||||
justify-content: center; |
justify-content: center; |
||||||
flex-direction: column; |
flex-direction: column; |
||||||
padding: 0 1rem; |
padding: 0 1rem; |
||||||
/*margin: 2rem 0;*/ |
/*margin: 2rem 0;*/ |
||||||
margin: 0 0; |
margin: 0 0; |
||||||
min-height: 100vh; |
min-height: 100vh; |
||||||
|
|
||||||
h2, h3 { |
h2, |
||||||
font-size: 2rem; |
h3 { |
||||||
margin: 8px 0; |
font-size: 2rem; |
||||||
} |
margin: 8px 0; |
||||||
|
} |
||||||
p { |
|
||||||
margin: 0; |
p { |
||||||
color: var(--fg); |
margin: 0; |
||||||
} |
color: var(--fg); |
||||||
|
} |
||||||
.topmargin { |
|
||||||
margin-top: 1rem; |
.topmargin { |
||||||
} |
margin-top: 1rem; |
||||||
|
} |
||||||
ul li { |
|
||||||
margin: .5rem 2.5rem;
|
ul li { |
||||||
} |
margin: 0.5rem 2.5rem; |
||||||
|
} |
||||||
#img-container { |
|
||||||
display: flex; |
#img-container { |
||||||
justify-content: center; |
display: flex; |
||||||
} |
justify-content: center; |
||||||
#img-container img { |
} |
||||||
width: 22rem; |
#img-container img { |
||||||
height: auto; |
width: 22rem; |
||||||
} |
height: auto; |
||||||
|
} |
||||||
footer { |
|
||||||
margin-top: 1rem; |
footer { |
||||||
opacity: .5; |
margin-top: 1rem; |
||||||
} |
opacity: 0.5; |
||||||
` |
} |
||||||
|
`;
|
||||||
|
|
||||||
export const Code = styled.code` |
export const Code = styled.code` |
||||||
font-family: monospace; |
font-family: monospace; |
||||||
font-size: .9rem; |
font-size: 0.9rem; |
||||||
background-color: var(--bg-emph); |
background-color: var(--bg-emph); |
||||||
color: var(--fg-code); |
color: var(--fg-code); |
||||||
border-radius: .4rem; |
border-radius: 0.4rem; |
||||||
padding: .1rem .4rem; |
padding: 0.1rem 0.4rem; |
||||||
` |
`;
|
||||||
|
|
||||||
export const CList = styled.ul` |
export const CList = styled.ul` |
||||||
list-style: none; |
list-style: none; |
||||||
|
|
||||||
li { |
li { |
||||||
margin: 1rem !important; |
margin: 1rem !important; |
||||||
} |
} |
||||||
` |
`;
|
||||||
|
|
||||||
export const Nem = styled.span` |
export const Nem = styled.span` |
||||||
color: var(--fg-faded); |
color: var(--fg-faded); |
||||||
` |
`;
|
||||||
|
|
||||||
export const LinkList = styled.div` |
export const LinkList = styled.div` |
||||||
display: flex; |
display: flex; |
||||||
gap: 1.5rem; |
gap: 1.5rem; |
||||||
font-size: 1.2rem; |
font-size: 1.2rem; |
||||||
border: unset; |
border: unset; |
||||||
justify-content: center; |
justify-content: center; |
||||||
|
|
||||||
a { |
a { |
||||||
color: var(--fg-button); |
color: var(--fg-button); |
||||||
transition: var(--trans-time) opacity; |
transition: var(--trans-time) opacity; |
||||||
} |
} |
||||||
|
|
||||||
a:hover { |
a:hover { |
||||||
opacity: .4; |
opacity: 0.4; |
||||||
} |
} |
||||||
|
|
||||||
@media screen and (max-width: 960px) { |
@media screen and (max-width: 960px) { |
||||||
word-break: break-word; |
word-break: break-word; |
||||||
} |
} |
||||||
` |
`;
|
||||||
|
|
||||||
function getAge() { |
function getAge() { |
||||||
let birth = 1050019200; |
let birth = 1050019200; |
||||||
let now = Math.floor(Date.now() / 1000); |
let now = Math.floor(Date.now() / 1000); |
||||||
return now-birth; |
return now - birth; |
||||||
} |
} |
||||||
|
|
||||||
function secondsToYears(secs: number) { |
function secondsToYears(secs: number) { |
||||||
return Math.floor(secs / 31557600.0); |
return Math.floor(secs / 31557600.0); |
||||||
} |
} |
||||||
|
|
||||||
const Page: NextPageWithLayout = () => { |
const Page: NextPageWithLayout = () => { |
||||||
return ( |
return ( |
||||||
<> |
<> |
||||||
<Section>
|
<Section> |
||||||
<h2 id="about">/almqv</h2>
|
<h2 id="about">/almqv</h2> |
||||||
<p>I am a {secondsToYears(getAge())} year old <em>Computer Science & Engineering student</em> with a passion for <em>physics</em>, <em>programming</em>, <em>mathematics</em> and anything <em>*NIX</em> <Nem>(Linux, UNIX etc)</Nem> related.</p> |
<p> |
||||||
{/*TODO: Add GitHub code frequency/contrib here*/} |
I am a {secondsToYears(getAge())} year old{" "} |
||||||
<p className="topmargin">Most of my projects are open-source, and if you are interested, you can find all of my projects on my <a href="https://git.wych.dev/elal" target="_blank" rel="noreferrer">git-server</a> or <a href="https://github.com/almqv" target="_blank" rel="noreferrer">GitHub</a>.</p>
|
<em>Computer Science & Engineering student</em> with a passion for{" "} |
||||||
|
<em>physics</em>, <em>programming</em>, <em>mathematics</em> and |
||||||
{/* |
anything <em>*NIX</em> <Nem>(Linux, UNIX etc)</Nem> related. |
||||||
<div className="topmargin" id="img-container"> |
</p> |
||||||
<img src="https://github-readme-stats.vercel.app/api/top-langs/?username=almqv&theme=dark&exclude_repo=hsf,the_auctionhouse,dotfiles,scripts,dmenu,dwmblocks,ewm,machinelearning,adventofcode,python-machinelearning,st,scroll,prog1&layout=compact&count_private=true&hide_border=true&bg_color=1d2021" /> |
{/*TODO: Add GitHub code frequency/contrib here*/} |
||||||
</div> |
<p className="topmargin"> |
||||||
*/} |
Most of my projects are open-source, and if you are interested, you |
||||||
|
can find all of my projects on my{" "} |
||||||
<LinkList className="topmargin"> |
<a href="https://git.wych.dev/elal" target="_blank" rel="noreferrer"> |
||||||
<IconLink href="#contact" icon={ faEnvelope } target="_self" rel="noreferrer"/> |
git-server |
||||||
{/*<IconLink href="/projects" icon={ faFolderOpen } target="_self" rel="noreferrer"/>*/} |
</a>{" "} |
||||||
<IconLink href="https://github.com/almqv" icon={ faGithub } target="_blank" rel="noreferrer"/> |
or{" "} |
||||||
<IconLink href="https://git.wych.dev/elal" icon={ faGit } target="_blank" rel="noreferrer"/> |
<a href="https://github.com/almqv" target="_blank" rel="noreferrer"> |
||||||
</LinkList> |
GitHub |
||||||
|
</a> |
||||||
</Section>
|
. |
||||||
|
</p> |
||||||
<Section> |
|
||||||
<h2 id="contact">Contact</h2> |
<LinkList className="topmargin"> |
||||||
<p>You can contact me through email. And if you prefer it, you can contact me using PGP. Do note that my <em>email address below is encrypted</em> as a precaution against bots et cetera. <em>Do not worry, it is easy to crack</em>. Alternatively you could query for my email with my PGP fingerprint (key-id) on some PGP key server (i.e. the <a href="https://pgp.mit.edu/" target="_blank" rel="noreferrer">MIT</a> or <a href="https://keyserver.ubuntu.com/" target="_blank" rel="noreferrer">Ubuntu</a> key-server).</p> |
<IconLink |
||||||
<CList> |
href="#contact" |
||||||
<li> |
icon={faEnvelope} |
||||||
PGP fingerprint: <Code>68B2 9768 49F0 3C72 38AE B081 E31A 99CE 3E75 A158</Code> |
target="_self" |
||||||
</li> |
rel="noreferrer" |
||||||
<li> |
/> |
||||||
Email: <Code>cnlueXpkaXZmZ0B0em52eS5wYnoK</Code> |
{/*<IconLink href="/projects" icon={ faFolderOpen } target="_self" rel="noreferrer"/>*/} |
||||||
</li> |
<IconLink |
||||||
<li> |
href="https://github.com/almqv" |
||||||
GitHub: <a href="https://github.com/almqv" target="_blank" rel="noreferrer">github.com/almqv</a> |
icon={faGithub} |
||||||
</li> |
target="_blank" |
||||||
</CList> |
rel="noreferrer" |
||||||
|
/> |
||||||
</Section> |
<IconLink |
||||||
</> |
href="https://git.wych.dev/elal" |
||||||
) |
icon={faGit} |
||||||
} |
target="_blank" |
||||||
|
rel="noreferrer" |
||||||
|
/> |
||||||
|
</LinkList> |
||||||
|
|
||||||
|
<ScrollMe href="#contact" /> |
||||||
|
</Section> |
||||||
|
|
||||||
|
<Section> |
||||||
|
<h2 id="contact">Contact</h2> |
||||||
|
<p> |
||||||
|
You can contact me through email. And if you prefer it, you can |
||||||
|
contact me using PGP. Do note that my{" "} |
||||||
|
<em>email address below is encrypted</em> as a precaution against bots |
||||||
|
et cetera. <em>Do not worry, it is easy to crack</em>. Alternatively |
||||||
|
you could query for my email with my PGP fingerprint (key-id) on some |
||||||
|
PGP key server (i.e. the{" "} |
||||||
|
<a href="https://pgp.mit.edu/" target="_blank" rel="noreferrer"> |
||||||
|
MIT |
||||||
|
</a>{" "} |
||||||
|
or{" "} |
||||||
|
<a |
||||||
|
href="https://keyserver.ubuntu.com/" |
||||||
|
target="_blank" |
||||||
|
rel="noreferrer" |
||||||
|
> |
||||||
|
Ubuntu |
||||||
|
</a>{" "} |
||||||
|
key-server). |
||||||
|
</p> |
||||||
|
<CList> |
||||||
|
<li> |
||||||
|
PGP fingerprint:{" "} |
||||||
|
<Code>68B2 9768 49F0 3C72 38AE B081 E31A 99CE 3E75 A158</Code> |
||||||
|
</li> |
||||||
|
<li> |
||||||
|
Email: <Code>cnlueXpkaXZmZ0B0em52eS5wYnoK</Code> |
||||||
|
</li> |
||||||
|
<li> |
||||||
|
GitHub:{" "} |
||||||
|
<a href="https://github.com/almqv" target="_blank" rel="noreferrer"> |
||||||
|
github.com/almqv |
||||||
|
</a> |
||||||
|
</li> |
||||||
|
</CList> |
||||||
|
</Section> |
||||||
|
</> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
Page.getLayout = (page: ReactElement) => { |
Page.getLayout = (page: ReactElement) => { |
||||||
return <Layout>{page}</Layout> |
return <Layout>{page}</Layout>; |
||||||
} |
}; |
||||||
export default Page |
export default Page; |
||||||
|
|
||||||
|
@ -1,22 +1,28 @@ |
|||||||
import type {NextPageWithLayout} from './_app' |
import type { NextPageWithLayout } from "./_app"; |
||||||
import type { ReactElement } from 'react' |
import type { ReactElement } from "react"; |
||||||
import Layout from '../components/layout' |
import Layout from "../components/layout"; |
||||||
import { Section } from './index' |
import { Section } from "./index"; |
||||||
import Link from "next/link" |
import Link from "next/link"; |
||||||
|
|
||||||
const Page: NextPageWithLayout = () => { |
const Page: NextPageWithLayout = () => { |
||||||
return ( |
return ( |
||||||
<> |
<> |
||||||
<Section> |
<Section> |
||||||
<h2>Page under development...</h2> |
<h2>Page under development...</h2> |
||||||
<p>While you wait, why not check out my <a href="https://github.com/E-Almqvist">GitHub</a>? Or perhaps my very own <a href="https://git.wych.dev/elal">git-server</a>?</p> |
<p> |
||||||
<p>Or you could also <Link href="/">go back</Link> to the home page.</p> |
While you wait, why not check out my{" "} |
||||||
</Section> |
<a href="https://github.com/E-Almqvist">GitHub</a>? Or perhaps my very |
||||||
</> |
own <a href="https://git.wych.dev/elal">git-server</a>? |
||||||
) |
</p> |
||||||
} |
<p> |
||||||
|
Or you could also <Link href="/">go back</Link> to the home page. |
||||||
|
</p> |
||||||
|
</Section> |
||||||
|
</> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
Page.getLayout = (page: ReactElement) => { |
Page.getLayout = (page: ReactElement) => { |
||||||
return <Layout>{page}</Layout> |
return <Layout>{page}</Layout>; |
||||||
} |
}; |
||||||
export default Page |
export default Page; |
||||||
|
Loading…
Reference in new issue