Initialize project and port basics

This commit is contained in:
Kevin Kandlbinder 2020-12-21 18:23:28 +01:00
commit ebb4f4d515
31 changed files with 20401 additions and 0 deletions

5
src/_variables.scss Normal file
View file

@ -0,0 +1,5 @@
$layoutWidth: 900px;
$accentColor: #e5502b;
$background: #0d0d0d;
$textColor: white;

View file

@ -0,0 +1,21 @@
import React from "react"
import {Link, Trans, useI18next} from 'gatsby-plugin-react-i18next';
export default function LanguageSwitcher() {
const {languages, originalPath} = useI18next();
return (
<div class="languageModalInner">
<h2>Languages (<a href="#" class="modalCloseLink">&times;</a>)</h2>
<ul>
{languages.map((lng) => (
<li key={lng}>
<Link to={originalPath} language={lng}>
<Trans>{lng}</Trans>
</Link>
</li>
))}
</ul>
</div>
);
}

View file

@ -0,0 +1,17 @@
import React from "react"
import { Trans, Link } from "gatsby-plugin-react-i18next"
export default class Navigation extends React.Component {
render() {
return (
<div className={"topBar" + (this.props.isHome ? " homeBar" : "")}>
<nav className="topBarInner">
<Link to="/" className={"logo" + (this.props.module == "home" ? " active" : "")}>KevinK.dev</Link>
<div className="flexSpacer"></div>
<Link id="navBtnProjects" to="/projects" className={(this.props.module == "projects" ? "active" : "")}><Trans>projects</Trans></Link>
<Link id="navBtnSocial" to="/social" className={(this.props.module == "social" ? "active" : "")}><Trans>social</Trans></Link>
</nav>
</div>
);
}
}

82
src/components/seo.js Normal file
View file

@ -0,0 +1,82 @@
import React from "react"
import PropTypes from "prop-types"
import { Helmet } from "gatsby-plugin-react-i18next"
import { useStaticQuery, graphql } from "gatsby"
function SEO({ description, lang, meta, title }) {
const { site } = useStaticQuery(
graphql`
query {
site {
siteMetadata {
title
description
author
}
}
}
`
)
const metaDescription = description || site.siteMetadata.description
return (
<Helmet
title={title}
titleTemplate={`%s | ${site.siteMetadata.title}`}
meta={[
{
name: `description`,
content: metaDescription,
},
{
property: `og:title`,
content: title,
},
{
property: `og:description`,
content: metaDescription,
},
{
property: `og:type`,
content: `website`,
},
{
name: `twitter:card`,
content: `summary`,
},
{
name: `twitter:creator`,
content: site.siteMetadata.author,
},
{
name: `twitter:title`,
content: title,
},
{
name: `twitter:description`,
content: metaDescription,
},
{
name: "keywords",
content: "Kevin Kandlbinder, Kevin, Kandlbinder, Web, Web Developer, Developer, JavaScript, PHP, Java, Photos, Fotos"
}
].concat(meta)}
>
<script src="https://kit.fontawesome.com/1377f925e0.js" crossorigin="anonymous"></script>
</Helmet>
)
}
SEO.defaultProps = {
meta: [],
description: ``,
}
SEO.propTypes = {
description: PropTypes.string,
meta: PropTypes.arrayOf(PropTypes.object),
title: PropTypes.string.isRequired,
}
export default SEO

View file

@ -0,0 +1 @@
<svg id="Ebene_1" data-name="Ebene 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120"><defs><style>.cls-1{fill:#000710;}.cls-2{font-size:82px;}.cls-2,.cls-3{fill:#fff;font-family:AnonymousPro-Regular, Anonymous Pro;}.cls-3{font-size:27px;}</style></defs><title>fullbglogo</title><rect class="cls-1" width="120" height="120"/><text class="cls-2" transform="translate(15.24 85.23)">KK</text><text class="cls-3" transform="translate(58.6 103.2)">.dev</text></svg>

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
src/images/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

1
src/images/nobglogo.svg Normal file
View file

@ -0,0 +1 @@
<svg id="Ebene_1" data-name="Ebene 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120"><defs><style>.cls-1{font-size:82px;}.cls-1,.cls-2{fill:#fff;font-family:AnonymousPro-Regular, Anonymous Pro;}.cls-2{font-size:27px;}</style></defs><title>nobglogo</title><text class="cls-1" transform="translate(15.24 85.23)">KK</text><text class="cls-2" transform="translate(58.6 103.2)">.dev</text></svg>

After

Width:  |  Height:  |  Size: 400 B

BIN
src/images/nobglogo@10x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View file

@ -0,0 +1 @@
<svg id="Ebene_1" data-name="Ebene 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120"><defs><style>.cls-1{fill:#000710;}.cls-2{font-size:82px;}.cls-2,.cls-3{fill:#fff;font-family:AnonymousPro-Regular, Anonymous Pro;}.cls-3{font-size:27px;}</style></defs><title>roundedbglogo</title><rect class="cls-1" width="120" height="120" rx="12"/><text class="cls-2" transform="translate(15.24 85.23)">KK</text><text class="cls-3" transform="translate(58.6 103.2)">.dev</text></svg>

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

42
src/layouts/default.js Normal file
View file

@ -0,0 +1,42 @@
import React from "react"
import PropTypes from "prop-types"
import Navigation from "../components/navigation"
import SEO from "../components/seo";
import "./default.scss";
import {Link, Trans, useTranslation} from 'gatsby-plugin-react-i18next';
import LanguageSwitcher from "../components/languageSwitcher";
class Layout extends React.Component {
render() {
return (
<>
<SEO description={this.props.description} lang={this.props.lang} meta={this.props.meta} title={this.props.title} />
<Navigation isHome={this.props.module == "home"} module={this.props.module} />
<div id="content" role="main">
{this.props.children}
</div>
<footer role="contentinfo">CC-BY 4.0 Kevin Kandlbinder, <Link to="/legal/about" class="spf-link"><Trans i18nKey="imprint">Imprint</Trans></Link> | <Link to="/legal/datasec" class="spf-link"><Trans i18nKey="datasec">Data Protection</Trans></Link> | <Link to="/legal/disclaimer" class="spf-link"><Trans i18nKey="disclaimer">Disclaimer</Trans></Link> | <a href="#languageChooser">Language</a></footer>
<div class="languageModal" id="languageChooser">
<LanguageSwitcher />
</div>
</>
);
}
}
Layout.defaultProps = {
module: `none`,
meta: [],
description: ``,
}
Layout.propTypes = {
description: PropTypes.string,
lang: PropTypes.string,
meta: PropTypes.arrayOf(PropTypes.object),
title: PropTypes.string.isRequired,
module: PropTypes.string.isRequired
}
export default Layout;

146
src/layouts/default.scss Normal file
View file

@ -0,0 +1,146 @@
@import "../variables";
* {
box-sizing: border-box;
}
body, html, #___gatsby, #gatsby-focus-wrapper {
margin: 0;
padding: 0;
width: 100%;
min-height: 100vh;
font-family: 'Anonymous Pro', monospace;
}
#gatsby-focus-wrapper {
background: $background;
color: $textColor;
transition: background .25s, color .25s;
display: flex;
flex-direction: column;
}
footer {
background: #000710;
width: 100%;
color: white;
padding: 5px;
text-align: center;
}
footer a {
color: white;
text-decoration: underline dotted currentColor;
}
#content {
/*min-height: calc(100vh - 26px);*/
flex-grow: 1;
display: flex;
flex-direction: column;
}
.topBar {
position: fixed;
top: 0;
left: 0;
display: flex;
width: 100%;
background: #000710;
z-index: 999;
transition: background .25s;
}
.homeBar.homeBarTransparent {
background: transparent;
}
.topBarInner {
display: flex;
width: 90%;
max-width: 900px;
margin: auto;
}
.topBar a {
display: block;
padding: 10px 15px;
color: white;
/*text-decoration: underline dotted white;*/
text-decoration: none;
border-top: 2px solid transparent;
}
.topBar a:hover {
border-color: rgba(255, 255, 255, .25);
}
.topBar a.active {
border-color: white;
}
.flexSpacer {
flex-grow: 1;
text-align: center;
}
section > div:not(.profile), section > article, .section > div:not(.profile), .section > article {
max-width: $layoutWidth;
width: 100%;
padding: 39px 20px;
margin: 0 auto;
}
article p {
text-align: justify;
}
article h1, section > div > h1 {
font-size: 2em;
}
article a {
color: $accentColor;
text-decoration: underline dotted currentColor;
text-decoration-skip: none;
}.languageModal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, .7);
z-index: 1000;
opacity: 0;
pointer-events: none;
-webkit-transition: opacity .25s;
-moz-transition: opacity .25s;
-ms-transition: opacity .25s;
-o-transition: opacity .25s;
transition: opacity .25s;
}
.languageModal:target {
opacity: 1;
pointer-events: auto;
}
.languageModalInner {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
background: black;
font-family: 'Anonymous Pro', monospace;
padding: 20px;
border-radius: 5px;
}
.languageModalInner a {
color: white;
text-decoration-style: dotted;
}
.modalCloseLink {
text-decoration: none;
}

54
src/pages/404.js Normal file
View file

@ -0,0 +1,54 @@
import * as React from "react"
import { Link } from "gatsby"
// styles
const pageStyles = {
color: "#232129",
padding: "96px",
fontFamily: "-apple-system, Roboto, sans-serif, serif",
}
const headingStyles = {
marginTop: 0,
marginBottom: 64,
maxWidth: 320,
}
const paragraphStyles = {
marginBottom: 48,
}
const codeStyles = {
color: "#8A6534",
padding: 4,
backgroundColor: "#FFF4DB",
fontSize: "1.25rem",
borderRadius: 4,
}
// markup
const NotFoundPage = () => {
return (
<main style={pageStyles}>
<title>Not found</title>
<h1 style={headingStyles}>Page not found</h1>
<p style={paragraphStyles}>
Sorry{" "}
<span role="img" aria-label="Pensive emoji">
😔
</span>{" "}
we couldnt find what you were looking for.
<br />
{process.env.NODE_ENV === "development" ? (
<>
<br />
Try creating a page in <code style={codeStyles}>src/pages/</code>.
<br />
</>
) : null}
<br />
<Link to="/">Go home</Link>.
</p>
</main>
)
}
export default NotFoundPage

55
src/pages/index.js Normal file
View file

@ -0,0 +1,55 @@
import * as React from "react"
import Layout from "../layouts/default"
import styles from "./index.module.scss"
import { Trans, Link } from "gatsby-plugin-react-i18next"
// markup
class IndexPage extends React.Component {
render() {
return (
<Layout title="Kevin Kandlbinder" module="home">
<section className={styles.heroSection}>
<div className={styles.profile + " profile"}>
<div data-bg="url(https://cdn.kevink.dev/images/kevin/kevin-kandlbinder-03.jpg)" style={{backgroundImage: "url(https://cdn.kevink.dev/images/kevin/kevin-kandlbinder-03.jpg)"}} className={styles.profileImage + " lazy"}></div>
<div className={styles.profileImageDummy}></div>
<div className={styles.profileCard}>
<span className={styles.hello}><Trans>homeHello</Trans></span>
<span className={styles.name}>Kevin Kandlbinder</span>
<span className={styles.description}><Trans>homeMe</Trans> <span id="descriptionType"><Trans>homeWebDeveloper</Trans></span>.</span>
<div className={styles.contactLinks}>
<a className={styles.contactLink} href="tel:+4941068068004"><i className="fas fa-fw fa-phone"></i>+49 4106 8068004</a>
<a className={styles.contactLink} href="mailto:kevin@kevink.dev?subject=%5Bkevink.dev%5D%20"><i className="far fa-fw fa-envelope"></i>kevin@kevink.dev</a>
<a className={styles.contactLink} href="https://goo.gl/maps/KVq9z1PVaVP2" rel="noopener" target="_blank"><i className="fas fa-fw fa-map-marker-alt"></i><Trans>homeMyLocation</Trans></a>
<a className={styles.contactLink} href="https://twitter.com/unkn0wnkevin" rel="noopener" target="_blank"><i className="fab fa-fw fa-twitter"></i>@Unkn0wnKevin</a>
<a className={styles.contactLink} href="https://github.com/unkn0wncat" rel="noopener" target="_blank"><i className="fab fa-fw fa-github"></i>Unkn0wnCat</a>
</div>
</div>
</div>
</section>
<section className="aboutSection">
<article>
<h1><Trans>homeAboutMe</Trans></h1>
<p><Trans>homeAboutMeHello</Trans><br/><Trans>homeAboutMeText</Trans></p>
</article>
</section>
<a className={styles.section + " " + styles.creditSection} href="https://unsplash.com/@jannikkiel" target="_blank" rel="noopener">
<div>
<span><i className="fas fa-fw fa-camera"></i> <Trans>homeImageCredit</Trans></span>
<i className="fas fa-fw fa-chevron-right"></i>
</div>
</a>
<a className={styles.section + " " + styles.donationSection} href="TODO: Path">
<div>
<span><Trans>donationCatchphrase</Trans></span>
<i className="fas fa-fw fa-chevron-right"></i>
</div>
</a>
</Layout>
)
}
}
export default IndexPage

183
src/pages/index.module.scss Normal file
View file

@ -0,0 +1,183 @@
@import "../variables";
.heroSection {
width: 100%;
background: #000710;
min-height: 500px;
padding-top: 100px;
overflow: hidden;
background: radial-gradient(ellipse at top left, #1f0ba659, transparent), radial-gradient(ellipse at bottom right, #4a086829, transparent);
.profile {
position: relative;
left: 50%;
width: calc(90% - 40px);
max-width: 600px;
max-height: 400px;
transform: translate(-50%, 0%);
&:hover .profileImage {
transform: translate(4px, -4px);
}
&:hover .profileImageDummy {
transform: translate(-3px, 3px);
}
.hello {
font-weight: 100;
opacity: .75;
display: block;
margin-bottom: -5px;
}
.name {
font-weight: 100;
font-size: 2em;
display: block;
}
.description {
font-weight: 100;
display: block;
}
.contactLinks {
margin-top: 20px;
display: flex;
flex-direction: column;
}
.contactLink {
transition: text-decoration .5s;
text-decoration: underline dotted rgba(0, 0, 0, 0);
padding: 6px 0 6px 25px;
color: $textColor;
}
.contactLink:hover, .contactLink:active {
text-decoration: underline dotted rgba(0, 0, 0, .5);
}
.contactLink > i {
color: $accentColor;
margin-left: -25px;
margin-right: 5px;
}
.profileCard {
width: calc(100% - 40px);
height: calc(100% - 20px);
background: $background;
transform: translate(40px, 20px);
border-radius: 5px;
/*box-shadow: -1px 11px 33px -10px rgba(127,127,127,0.4);*/
box-shadow: -1px 11px 33px -10px #e5502b4b;
padding: 20px 20px 20px 230px;
color: $textColor;
}
.profileImage, .profileImageDummy {
display: inline-block;
width: 250px;
height: 350px;
border-radius: 5px;
position: absolute;
z-index: 100;
background-color: #1c1c1c;
background-size: cover;
background-position: center;
transform: translate(0, 0);
transition: transform .25s;
}
.profileImage {
z-index: 20;
/*box-shadow: -5px 7px 10px -6px rgba(127,127,127,.4);*/
}
.profileImageDummy {
z-index: 10;
background: $accentColor;
opacity: .2;
/*box-shadow: 0 0 10px -10px var(--accent-color);
background: transparent;*/
}
@media (max-width: 590px) {
.profileImage,.profileImageDummy {
display: none;
}
.profileCard {
padding: 20px 20px 20px 20px;
transform: translate(20px, 20px);
}
}
}
}
.amazonAlexaSection, .donationSection, .hireMeSection {
min-height: 90px;
background: #10141e;
cursor: pointer;
display: block;
text-decoration: none;
color: inherit;
}
.amazonAlexaSection img {
height: 50px;
}
.amazonAlexaSection > div, .donationSection > div, .hireMeSection > div {
display: flex;
height: 100%;
padding: 20px !important;
line-height: 50px;
font-size: 1.7em;
color: white;
}
.amazonAlexaSection > div > span, .donationSection > div > span, .hireMeSection > div > span {
margin-left: auto;
margin-right: auto;
}
.amazonAlexaSection > div > i, .donationSection > div > i, .hireMeSection > div > i {
line-height: 50px !important;
}
.creditSection {
background: #060606;
cursor: pointer;
display: block;
text-decoration: none;
color: inherit;
}
.creditSection > div {
display: flex;
height: 100%;
padding: 15px !important;
line-height: 15px;
font-size: 1.2em;
color: white;
}
.creditSection > div > span {
margin-left: auto;
margin-right: auto;
}
.creditSection > div > i {
line-height: 15px !important;
}

26
src/pages/legal/about.js Normal file
View file

@ -0,0 +1,26 @@
import React from "react"
import Layout from "../../layouts/default";
import { Trans, Link, useI18next } from "gatsby-plugin-react-i18next"
export default function ImprintPage() {
const {t} = useI18next();
return (
<Layout module="legal" title={t("imprint")}>
<section>
<article>
<h1><Trans>imprint</Trans></h1>
<p>Angaben gemäß § 5 TMG</p><p>Kevin Kandlbinder<br/>
Eichenweg 48<br/>
25451 Quickborn <br/>
</p><p> <strong>Vertreten durch: </strong><br/>
Kevin Kandlbinder<br/>
</p><p><strong>Kontakt:</strong> <br/>
Telefon: +49 4106 8068004<br/>
E-Mail: <a href='mailto:contact@kevink.dev'>contact@kevink.dev</a><br/></p>
</article>
</section>
</Layout>
);
}

View file

@ -0,0 +1,26 @@
import React from "react"
import Layout from "../../layouts/default";
import { Trans, Link, useI18next } from "gatsby-plugin-react-i18next"
export default function DataSecPage() {
const {t} = useI18next();
return (
<Layout module="legal" title={t("datasec")}>
<section>
<article>
<h1><Trans>datasec</Trans></h1>
<p>Angaben gemäß § 5 TMG</p><p>Kevin Kandlbinder<br/>
Eichenweg 48<br/>
25451 Quickborn <br/>
</p><p> <strong>Vertreten durch: </strong><br/>
Kevin Kandlbinder<br/>
</p><p><strong>Kontakt:</strong> <br/>
Telefon: +49 4106 8068004<br/>
E-Mail: <a href='mailto:contact@kevink.dev'>contact@kevink.dev</a><br/></p>
</article>
</section>
</Layout>
);
}

File diff suppressed because one or more lines are too long

18
src/pages/projects.js Normal file
View file

@ -0,0 +1,18 @@
import React from "react"
import Layout from "../layouts/default";
import { Trans, Link, useI18next } from "gatsby-plugin-react-i18next"
export default function ProjectsPage() {
const {t} = useI18next();
return (
<Layout module="projects" title={t("projects")}>
<section>
<div>
<h1><Trans>projects</Trans></h1>
</div>
</section>
</Layout>
);
}

18
src/pages/social.js Normal file
View file

@ -0,0 +1,18 @@
import React from "react"
import Layout from "../layouts/default";
import { Trans, Link, useI18next } from "gatsby-plugin-react-i18next"
export default function SocialPage() {
const {t} = useI18next();
return (
<Layout module="social" title={t("social")}>
<section>
<div>
<h1><Trans>social</Trans></h1>
</div>
</section>
</Layout>
);
}