1
0
Fork 0
mirror of https://github.com/Unkn0wnCat/KevinK.dev.js.git synced 2025-06-11 15:12:05 +02:00

Configure & Run prettier

This commit is contained in:
Kevin Kandlbinder 2021-07-25 13:03:57 +00:00 committed by GitHub
parent 79ab0bb9af
commit 420f8930fd
66 changed files with 31825 additions and 31500 deletions

View file

@ -28,11 +28,9 @@
"EditorConfig.EditorConfig" "EditorConfig.EditorConfig"
], ],
// Use 'forwardPorts' to make a list of ports inside the container available locally. // Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [ "forwardPorts": [8000],
8000
],
// Use 'postCreateCommand' to run commands after the container is created. // Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "npm install", "postCreateCommand": "npm install",
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "node" "remoteUser": "node"
} }

View file

@ -2,4 +2,4 @@
The contents of this folder will be automatically replaced with a file of the same name in the [vscode-dev-containers](https://github.com/microsoft/vscode-dev-containers) repository's [script-library folder](https://github.com/microsoft/vscode-dev-containers/tree/master/script-library) whenever the repository is packaged. The contents of this folder will be automatically replaced with a file of the same name in the [vscode-dev-containers](https://github.com/microsoft/vscode-dev-containers) repository's [script-library folder](https://github.com/microsoft/vscode-dev-containers/tree/master/script-library) whenever the repository is packaged.
To retain your edits, move the file to a different location. You may also delete the files if they are not needed. To retain your edits, move the file to a different location. You may also delete the files if they are not needed.

View file

@ -1,15 +1,12 @@
{ {
"parser": "babel-eslint", "parser": "babel-eslint",
"rules": { "rules": {
"strict": 0 "strict": 0
}, },
"extends": [ "extends": ["eslint:recommended", "plugin:react/recommended"],
"eslint:recommended", "settings": {
"plugin:react/recommended" "react": {
], "version": "detect"
"settings": { }
"react": {
"version": "detect"
} }
} }
}

View file

@ -1,30 +1,30 @@
name: Build Site name: Build Site
on: on:
push: push:
jobs: jobs:
update: update:
name: Build Site name: Build Site
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
name: Checkout Repo name: Checkout Repo
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v2 uses: actions/setup-node@v2
with: with:
node-version: '12.x' node-version: "12.x"
- run: npm install - run: npm install
name: Install Dependencies name: Install Dependencies
- run: npm run build - run: npm run build
name: Build Site name: Build Site
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
name: Upload Artifacts name: Upload Artifacts
with: with:
name: site name: site
path: public path: public

4
.prettierignore Normal file
View file

@ -0,0 +1,4 @@
/.cache
/.vscode
/node_modules
/public

8
.prettierrc.json Normal file
View file

@ -0,0 +1,8 @@
{
"trailingComma": "es5",
"tabWidth": 4,
"semi": true,
"singleQuote": false,
"jsxBracketSameLine": true,
"endOfLine": "lf"
}

View file

@ -1,7 +1,7 @@
# KevinK.dev.js # KevinK.dev.js
![Build Site](https://github.com/Unkn0wnCat/KevinK.dev.js/workflows/Build%20Site/badge.svg) ![Build Site](https://github.com/Unkn0wnCat/KevinK.dev.js/workflows/Build%20Site/badge.svg)
KevinK.dev is my personal page, now on Gatsby. I've chosen Gatsby as a framework as it offers me the speed of client-side-rendered pages with the compatibility and stability of a traditional server-side-rendered page. This is also the repo I try new stuff on, so feel free to look around and pick up some useful. KevinK.dev is my personal page, now on Gatsby. I've chosen Gatsby as a framework as it offers me the speed of client-side-rendered pages with the compatibility and stability of a traditional server-side-rendered page. This is also the repo I try new stuff on, so feel free to look around and pick up some useful.
You may also want to take a look at [Unkn0wnCat/cfw-language-redirector](https://github.com/Unkn0wnCat/cfw-language-redirector) for the Cloudflare Worker used to redirect landing pages to their localized versions. You may also want to take a look at [Unkn0wnCat/cfw-language-redirector](https://github.com/Unkn0wnCat/cfw-language-redirector) for the Cloudflare Worker used to redirect landing pages to their localized versions.

View file

@ -1,18 +1,18 @@
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
module.exports = { module.exports = {
siteName: "KevinK.dev", siteName: "KevinK.dev",
siteAuthor: "@Unkn0wnKevin", siteAuthor: "@Unkn0wnKevin",
siteURL: "https://kevink.dev", siteURL: "https://kevink.dev",
payPalMail: "kevin@1in9.net", payPalMail: "kevin@1in9.net",
siteKeywords: siteKeywords:
"Kevin Kandlbinder, Kevin, Kandlbinder, Web, Web Developer, Developer, JavaScript, PHP, Java, Photos, Fotos", "Kevin Kandlbinder, Kevin, Kandlbinder, Web, Web Developer, Developer, JavaScript, PHP, Java, Photos, Fotos",
iconPath: "src/images/fullbglogo@10x.png", iconPath: "src/images/fullbglogo@10x.png",
languages: ["en", "de"], languages: ["en", "de"],
contactEmail: "kevin@kevink.dev", contactEmail: "kevin@kevink.dev",
contactPhone: "+4941068068004", contactPhone: "+4941068068004",
mapsLink: "https://goo.gl/maps/KVq9z1PVaVP2", mapsLink: "https://goo.gl/maps/KVq9z1PVaVP2",
contactTwitter: "Unkn0wnKevin", contactTwitter: "Unkn0wnKevin",
contactGitHub: "Unkn0wnCat", contactGitHub: "Unkn0wnCat",
contactMastodon: "@kevin@1in1.net", contactMastodon: "@kevin@1in1.net",
contactMastodonHref: "https://mastodon.1in1.net/@kevin", contactMastodonHref: "https://mastodon.1in1.net/@kevin",
}; };

View file

@ -1,6 +1,6 @@
{ {
"profession": "Full-Stack-Developer", "profession": "Full-Stack-Developer",
"name": "Feuerhamster", "name": "Feuerhamster",
"url": "https://hamsterlabs.de", "url": "https://hamsterlabs.de",
"imageURL": "https://cdn.kevink.dev/assets/friends/feuerhamster.png" "imageURL": "https://cdn.kevink.dev/assets/friends/feuerhamster.png"
} }

View file

@ -1,6 +1,6 @@
{ {
"profession": "Photographer", "profession": "Photographer",
"name": "Jannik Kiel", "name": "Jannik Kiel",
"url": "https://unsplash.com/@jannikkiel", "url": "https://unsplash.com/@jannikkiel",
"imageURL": "https://source.unsplash.com/user/jannikkiel/300x300" "imageURL": "https://source.unsplash.com/user/jannikkiel/300x300"
} }

View file

@ -1,6 +1,6 @@
{ {
"profession": "Filmmaker", "profession": "Filmmaker",
"name": "Max Christian Rüster", "name": "Max Christian Rüster",
"url": "https://maxchristian.de/", "url": "https://maxchristian.de/",
"imageURL": "https://cdn.kevink.dev/assets/friends/max_ruester.jpg" "imageURL": "https://cdn.kevink.dev/assets/friends/max_ruester.jpg"
} }

View file

@ -1,6 +1,6 @@
{ {
"profession": "System Administrator", "profession": "System Administrator",
"name": "Timo Strüker", "name": "Timo Strüker",
"url": "https://strueker.dev", "url": "https://strueker.dev",
"imageURL": "https://cdn.kevink.dev/assets/friends/timo.jpg" "imageURL": "https://cdn.kevink.dev/assets/friends/timo.jpg"
} }

View file

@ -1,3 +1,3 @@
# Über KevinK.dev # Über KevinK.dev
Schon so lange ich im Internet unterwegs bin war ich fasziniert von der Idee eine eigene Website zu haben. Deshalb habe ich mich an diese Seite gesetzt um mich selbst und meine Projekte zu repräsentieren. Wenn du interessiert an dem Code hinter der Seite bist, schau doch gerne auf GitHub vorbei! Schon so lange ich im Internet unterwegs bin war ich fasziniert von der Idee eine eigene Website zu haben. Deshalb habe ich mich an diese Seite gesetzt um mich selbst und meine Projekte zu repräsentieren. Wenn du interessiert an dem Code hinter der Seite bist, schau doch gerne auf GitHub vorbei!

View file

@ -1,3 +1,3 @@
# About KevinK.dev # About KevinK.dev
For as long as I've been poking around the internet I've always been facinated by the idea to have my own website. This is why I've created this site to showcase myself and my projects. If you are interested in the code behind the scenes feel free to look at it on GitHub! For as long as I've been poking around the internet I've always been facinated by the idea to have my own website. This is why I've created this site to showcase myself and my projects. If you are interested in the code behind the scenes feel free to look at it on GitHub!

View file

@ -1,3 +1,3 @@
# Über KREIG.de # Über KREIG.de
Videospiele sind ein wesentlicher Teil unserer heutigen Gesellschaft. Ob Kompetitiv oder einfach nur zum Spaß: Fast jeder hat irgendeine Erfahrnug mit Videospielen. Ich bin da keine Ausnahme und für meine Gaming-Gruppe habe ich diese Seite erstellt, bei der ich modernes Design mit dem Gefühl von klassischen Gaming-Websites vereint habe. Videospiele sind ein wesentlicher Teil unserer heutigen Gesellschaft. Ob Kompetitiv oder einfach nur zum Spaß: Fast jeder hat irgendeine Erfahrnug mit Videospielen. Ich bin da keine Ausnahme und für meine Gaming-Gruppe habe ich diese Seite erstellt, bei der ich modernes Design mit dem Gefühl von klassischen Gaming-Websites vereint habe.

View file

@ -1,3 +1,3 @@
# About KREIG.de # About KREIG.de
Video games are a big part of today's society. Competitive or just for fun: Almost everyone has some contact with video games. I am no different to that and for my gaming clan I've created this site, which combines a modern design with the feeling of classical gaming sites on the early web. Video games are a big part of today's society. Competitive or just for fun: Almost everyone has some contact with video games. I am no different to that and for my gaming clan I've created this site, which combines a modern design with the feeling of classical gaming sites on the early web.

View file

@ -1,12 +1,12 @@
{ {
"urlname": "foobar", "urlname": "foobar",
"lang": "ignoreme", "lang": "ignoreme",
"name": "foobar", "name": "foobar",
"shortDescription": "foobar", "shortDescription": "foobar",
"links": { "links": {
"website": "https://foo.bar", "website": "https://foo.bar",
"github": "https://foo.bar" "github": "https://foo.bar"
}, },
"image": "../images/test.jpg", "image": "../images/test.jpg",
"featured": 0 "featured": 0
} }

View file

@ -1,11 +1,11 @@
{ {
"urlname": "else", "urlname": "else",
"lang": "de", "lang": "de",
"name": "Schülerzeitung \"ELSE\"", "name": "Schülerzeitung \"ELSE\"",
"shortDescription": "Eine News-Seite für die Schülerzeitung meiner Schule.", "shortDescription": "Eine News-Seite für die Schülerzeitung meiner Schule.",
"links": { "links": {
"website": "https://schuelerzeitung-elsensee.de" "website": "https://schuelerzeitung-elsensee.de"
}, },
"image": "../images/ELSE.jpg", "image": "../images/ELSE.jpg",
"featured": 2 "featured": 2
} }

View file

@ -1,11 +1,11 @@
{ {
"urlname": "else", "urlname": "else",
"lang": "en", "lang": "en",
"name": "Student Newspaper \"ELSE\"", "name": "Student Newspaper \"ELSE\"",
"shortDescription": "A news-site for the my schools school paper.", "shortDescription": "A news-site for the my schools school paper.",
"links": { "links": {
"website": "https://schuelerzeitung-elsensee.de" "website": "https://schuelerzeitung-elsensee.de"
}, },
"image": "../images/ELSE.jpg", "image": "../images/ELSE.jpg",
"featured": 2 "featured": 2
} }

View file

@ -1,12 +1,12 @@
{ {
"urlname": "kevink-dev", "urlname": "kevink-dev",
"lang": "de", "lang": "de",
"name": "KevinK.dev", "name": "KevinK.dev",
"shortDescription": "Diese Seite und der Code dahinter.", "shortDescription": "Diese Seite und der Code dahinter.",
"links": { "links": {
"website": "https://kevink.dev", "website": "https://kevink.dev",
"github": "https://github.com/Unkn0wnCat/KevinK.dev.js" "github": "https://github.com/Unkn0wnCat/KevinK.dev.js"
}, },
"image": "../images/KevinK.dev.jpg", "image": "../images/KevinK.dev.jpg",
"featured": 0 "featured": 0
} }

View file

@ -1,12 +1,12 @@
{ {
"urlname": "kevink-dev", "urlname": "kevink-dev",
"lang": "en", "lang": "en",
"name": "KevinK.dev", "name": "KevinK.dev",
"shortDescription": "This site and the code behind the scenes.", "shortDescription": "This site and the code behind the scenes.",
"links": { "links": {
"website": "https://kevink.dev", "website": "https://kevink.dev",
"github": "https://github.com/Unkn0wnCat/KevinK.dev.js" "github": "https://github.com/Unkn0wnCat/KevinK.dev.js"
}, },
"image": "../images/KevinK.dev.jpg", "image": "../images/KevinK.dev.jpg",
"featured": 0 "featured": 0
} }

View file

@ -1,11 +1,11 @@
{ {
"urlname": "kreig", "urlname": "kreig",
"lang": "de", "lang": "de",
"name": "KREIG.de", "name": "KREIG.de",
"shortDescription": "Eine einfache aber schöne Gaming-Seite.", "shortDescription": "Eine einfache aber schöne Gaming-Seite.",
"links": { "links": {
"website": "https://kreig.de" "website": "https://kreig.de"
}, },
"image": "../images/KREIG.de.jpg", "image": "../images/KREIG.de.jpg",
"featured": 1 "featured": 1
} }

View file

@ -1,11 +1,11 @@
{ {
"urlname": "kreig", "urlname": "kreig",
"lang": "en", "lang": "en",
"name": "KREIG.de", "name": "KREIG.de",
"shortDescription": "A simple but nice gaming website.", "shortDescription": "A simple but nice gaming website.",
"links": { "links": {
"website": "https://kreig.de" "website": "https://kreig.de"
}, },
"image": "../images/KREIG.de.jpg", "image": "../images/KREIG.de.jpg",
"featured": 1 "featured": 1
} }

View file

@ -1,6 +1,6 @@
{ {
"platformName": "Blog", "platformName": "Blog",
"platformHandle": "@kevin@blog.1in9.net", "platformHandle": "@kevin@blog.1in9.net",
"url": "https://blog.1in9.net/~/Kevin", "url": "https://blog.1in9.net/~/Kevin",
"image": "https://source.unsplash.com/xG8IQMqMITM/300x300" "image": "https://source.unsplash.com/xG8IQMqMITM/300x300"
} }

View file

@ -1,6 +1,6 @@
{ {
"platformName": "GitHub", "platformName": "GitHub",
"platformHandle": "@Unkn0wnCat", "platformHandle": "@Unkn0wnCat",
"url": "https://github.com/Unkn0wnCat", "url": "https://github.com/Unkn0wnCat",
"image": "https://source.unsplash.com/842ofHC6MaI/300x300" "image": "https://source.unsplash.com/842ofHC6MaI/300x300"
} }

View file

@ -1,6 +1,6 @@
{ {
"platformName": "Mastodon", "platformName": "Mastodon",
"platformHandle": "@kevin@1in1.net", "platformHandle": "@kevin@1in1.net",
"url": "https://mastodon.1in1.net/@kevin", "url": "https://mastodon.1in1.net/@kevin",
"image": "https://source.unsplash.com/8bghKxNU1j0/300x300" "image": "https://source.unsplash.com/8bghKxNU1j0/300x300"
} }

View file

@ -1,6 +1,6 @@
{ {
"platformName": "Matrix", "platformName": "Matrix",
"platformHandle": "@kevin:1in1.net", "platformHandle": "@kevin:1in1.net",
"url": "https://matrix.to/#/@kevin:1in1.net", "url": "https://matrix.to/#/@kevin:1in1.net",
"image": "https://source.unsplash.com/Zq6HerrBPEs/300x300" "image": "https://source.unsplash.com/Zq6HerrBPEs/300x300"
} }

View file

@ -1,6 +1,6 @@
{ {
"platformName": "Unkn0wnCat.net", "platformName": "Unkn0wnCat.net",
"platformHandle": "Gaming", "platformHandle": "Gaming",
"url": "https://unkn0wncat.net", "url": "https://unkn0wncat.net",
"image": "https://source.unsplash.com/nCU4yq5xDEQ/300x300" "image": "https://source.unsplash.com/nCU4yq5xDEQ/300x300"
} }

View file

@ -1,6 +1,6 @@
{ {
"platformName": "Twitter", "platformName": "Twitter",
"platformHandle": "@Unkn0wnKevin", "platformHandle": "@Unkn0wnKevin",
"url": "https://twitter.com/@Unkn0wnKevin", "url": "https://twitter.com/@Unkn0wnKevin",
"image": "https://source.unsplash.com/RnW1taVZqm8/300x300" "image": "https://source.unsplash.com/RnW1taVZqm8/300x300"
} }

View file

@ -1,6 +1,6 @@
{ {
"platformName": "Unsplash", "platformName": "Unsplash",
"platformHandle": "@Unkn0wnCat", "platformHandle": "@Unkn0wnCat",
"url": "https://unsplash.com/@unkn0wncat", "url": "https://unsplash.com/@unkn0wncat",
"image": "https://source.unsplash.com/user/unkn0wncat/300x300" "image": "https://source.unsplash.com/user/unkn0wncat/300x300"
} }

View file

@ -1,3 +1,3 @@
# Hallo 👋 # Hallo 👋
Ich bin Kevin Kandlbinder, ein Entwickler und Hobby-Fotograf aus Norddeutschland. Ich habe schon früh in meinem Leben gelernt mit Computern umzugehen, da mein Vater mir seinen alten Windows 2000-Tower überließ, als er sich einen neuen holte. Kontakt zur Entwicklung von Webseiten hatte ich einige Jahre darauf zum ersten Mal, als ich mir ein Buch zu HTML, CSS und PHP gekauft habe. Seitdem ist Web Development für mich gleichermaßen ein Hobby und ein Job. Ich bin Kevin Kandlbinder, ein Entwickler und Hobby-Fotograf aus Norddeutschland. Ich habe schon früh in meinem Leben gelernt mit Computern umzugehen, da mein Vater mir seinen alten Windows 2000-Tower überließ, als er sich einen neuen holte. Kontakt zur Entwicklung von Webseiten hatte ich einige Jahre darauf zum ersten Mal, als ich mir ein Buch zu HTML, CSS und PHP gekauft habe. Seitdem ist Web Development für mich gleichermaßen ein Hobby und ein Job.

View file

@ -1,3 +1,3 @@
# Hello 👋 # Hello 👋
I am Kevin Kandlbinder, a developer and hobby photographer from northern germany. I've learned operating computers very early in my life with my father giving me his old Windows 2000 tower. Some years later I've had my first contact with web development a few years later when I bought a book about HTML, PHP, JavaScript and CSS from a sale at my local library. From this point onwards web development has been a job and a hobby equally. I am Kevin Kandlbinder, a developer and hobby photographer from northern germany. I've learned operating computers very early in my life with my father giving me his old Windows 2000 tower. Some years later I've had my first contact with web development a few years later when I bought a book about HTML, PHP, JavaScript and CSS from a sale at my local library. From this point onwards web development has been a job and a hobby equally.

View file

@ -1,107 +1,113 @@
/* eslint-disable no-undef */ /* eslint-disable no-undef */
const extConfig = require("./config"); const extConfig = require("./config");
module.exports = { module.exports = {
siteMetadata: { siteMetadata: {
title: extConfig.siteName, title: extConfig.siteName,
author: extConfig.siteAuthor, author: extConfig.siteAuthor,
siteUrl: extConfig.siteURL, siteUrl: extConfig.siteURL,
keywords: extConfig.siteKeywords, keywords: extConfig.siteKeywords,
payPalMail: extConfig.payPalMail, payPalMail: extConfig.payPalMail,
contactEmail: extConfig.contactEmail, contactEmail: extConfig.contactEmail,
contactPhone: extConfig.contactPhone, contactPhone: extConfig.contactPhone,
mapsLink: extConfig.mapsLink, mapsLink: extConfig.mapsLink,
contactTwitter: extConfig.contactTwitter, contactTwitter: extConfig.contactTwitter,
contactGitHub: extConfig.contactGitHub, contactGitHub: extConfig.contactGitHub,
contactMastodon: extConfig.contactMastodon, contactMastodon: extConfig.contactMastodon,
contactMastodonHref: extConfig.contactMastodonHref, contactMastodonHref: extConfig.contactMastodonHref,
}, },
assetPrefix: "/assets", assetPrefix: "/assets",
plugins: [ plugins: [
`gatsby-plugin-eslint`, `gatsby-plugin-eslint`,
{ {
resolve: "gatsby-plugin-asset-path", resolve: "gatsby-plugin-asset-path",
}, },
`gatsby-plugin-sharp`, `gatsby-plugin-sharp`,
`gatsby-transformer-sharp`, `gatsby-transformer-sharp`,
`gatsby-transformer-json`, `gatsby-transformer-json`,
{ {
resolve: `gatsby-source-filesystem`, resolve: `gatsby-source-filesystem`,
options: { options: {
path: `${__dirname}/content/textblocks`, path: `${__dirname}/content/textblocks`,
name: `textblocks`, name: `textblocks`,
}, },
}, },
{ {
resolve: `gatsby-source-filesystem`, resolve: `gatsby-source-filesystem`,
options: { options: {
path: `${__dirname}/content/projectTextblocks`, path: `${__dirname}/content/projectTextblocks`,
name: `projectTextblocks`, name: `projectTextblocks`,
}, },
}, },
"gatsby-plugin-mdx", "gatsby-plugin-mdx",
{ {
resolve: `gatsby-source-filesystem`, resolve: `gatsby-source-filesystem`,
options: { options: {
path: `./content/`, path: `./content/`,
}, },
}, },
{ {
resolve: `gatsby-source-filesystem`, resolve: `gatsby-source-filesystem`,
options: { options: {
path: `${__dirname}/locales`, path: `${__dirname}/locales`,
name: `locale`, name: `locale`,
}, },
}, },
`gatsby-plugin-sass`, `gatsby-plugin-sass`,
{ {
resolve: `gatsby-plugin-manifest`, resolve: `gatsby-plugin-manifest`,
options: { options: {
name: extConfig.siteName, name: extConfig.siteName,
short_name: extConfig.siteName, short_name: extConfig.siteName,
start_url: `/`, start_url: `/`,
background_color: `#000710`, background_color: `#000710`,
theme_color: `#000710`, theme_color: `#000710`,
display: `minimal-ui`, display: `minimal-ui`,
icon: extConfig.iconPath, // This path is relative to the root of the site. icon: extConfig.iconPath, // This path is relative to the root of the site.
cache_busting_mode: "none", cache_busting_mode: "none",
}, },
}, },
`gatsby-plugin-robots-txt`, `gatsby-plugin-robots-txt`,
{ {
resolve: `gatsby-plugin-offline`, resolve: `gatsby-plugin-offline`,
options: { options: {
precachePages: ["/", "/en", "/en/projects", "/de", "/de/projects"], precachePages: [
workboxConfig: { "/",
globPatterns: ["**/*"], "/en",
}, "/en/projects",
}, "/de",
}, "/de/projects",
`gatsby-plugin-sitemap`, ],
`gatsby-plugin-react-helmet`, workboxConfig: {
{ globPatterns: ["**/*"],
resolve: `gatsby-plugin-react-i18next`, },
options: { },
localeJsonSourceName: `locale`, },
languages: extConfig.languages, `gatsby-plugin-sitemap`,
defaultLanguage: `en`, `gatsby-plugin-react-helmet`,
generateDefaultLanguagePage: true, {
siteUrl: extConfig.siteURL, resolve: `gatsby-plugin-react-i18next`,
i18nextOptions: { options: {
interpolation: { localeJsonSourceName: `locale`,
escapeValue: false, // not needed for react as it escapes by default languages: extConfig.languages,
}, defaultLanguage: `en`,
keySeparator: false, generateDefaultLanguagePage: true,
nsSeparator: false, siteUrl: extConfig.siteURL,
}, i18nextOptions: {
pages: [ interpolation: {
{ escapeValue: false, // not needed for react as it escapes by default
matchPath: "/:lang/projects/:urlname", },
getLanguageFromPath: true, keySeparator: false,
excludeLanguages: extConfig.languages, nsSeparator: false,
}, },
], pages: [
}, {
}, matchPath: "/:lang/projects/:urlname",
], getLanguageFromPath: true,
}; excludeLanguages: extConfig.languages,
},
],
},
},
],
};

View file

@ -1,174 +1,179 @@
/* eslint-disable no-undef */ /* eslint-disable no-undef */
const path = require(`path`); const path = require(`path`);
const fs = require("fs"); const fs = require("fs");
exports.createPages = async ({ actions, graphql, reporter }) => { exports.createPages = async ({ actions, graphql, reporter }) => {
const { createPage } = actions; const { createPage } = actions;
const projectTemplate = path.resolve(`src/templates/project.js`); const projectTemplate = path.resolve(`src/templates/project.js`);
const result = await graphql(` const result = await graphql(`
query AllPagesQuery { query AllPagesQuery {
allProjectsJson { allProjectsJson {
nodes { nodes {
lang lang
urlname urlname
} }
} }
} }
`); `);
if (result.errors) { if (result.errors) {
reporter.panicOnBuild(`Error while running GraphQL query.`); reporter.panicOnBuild(`Error while running GraphQL query.`);
return; return;
} }
result.data.allProjectsJson.nodes.forEach((node) => { result.data.allProjectsJson.nodes.forEach((node) => {
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
console.log("Creating Page: ", `/${node.lang}/projects/${node.urlname}`); console.log(
"Creating Page: ",
if (node.lang !== "ignoreme") `/${node.lang}/projects/${node.urlname}`
createPage({ );
path: `/${node.lang}/projects/${node.urlname}`,
component: projectTemplate, if (node.lang !== "ignoreme")
context: { createPage({
lang: node.lang, path: `/${node.lang}/projects/${node.urlname}`,
urlname: node.urlname, component: projectTemplate,
}, context: {
}); lang: node.lang,
}); urlname: node.urlname,
}; },
});
const config = require("./config.js"); });
};
exports.onPostBuild = async ({ graphql, reporter }) => {
console.log("Building static api..."); const config = require("./config.js");
const apiPrefix = "./public/api"; exports.onPostBuild = async ({ graphql, reporter }) => {
console.log("Building static api...");
if (!fs.existsSync(apiPrefix)) fs.mkdirSync(apiPrefix);
const apiPrefix = "./public/api";
fs.writeFileSync(
`${apiPrefix}.json`, if (!fs.existsSync(apiPrefix)) fs.mkdirSync(apiPrefix);
JSON.stringify({
success: true, fs.writeFileSync(
endpoints: { `${apiPrefix}.json`,
projects: [ JSON.stringify({
{ success: true,
name: "Projects Overview", endpoints: {
description: "Returns overview of all available projects", projects: [
path: "/api/projects.json", {
}, name: "Projects Overview",
{ description:
name: "Projects Overview for Language", "Returns overview of all available projects",
description: path: "/api/projects.json",
"Returns overview of all available projects in a specified language", },
path: "/api/projects/:lang.json", {
}, name: "Projects Overview for Language",
{ description:
name: "Get specific Project", "Returns overview of all available projects in a specified language",
description: "Returns specific project in specified language", path: "/api/projects/:lang.json",
path: "/api/projects/:lang/:slug.json", },
}, {
], name: "Get specific Project",
}, description:
}) "Returns specific project in specified language",
); path: "/api/projects/:lang/:slug.json",
},
const projectsPrefix = apiPrefix + "/projects"; ],
},
if (!fs.existsSync(projectsPrefix)) fs.mkdirSync(projectsPrefix); })
);
await graphql(`
query { const projectsPrefix = apiPrefix + "/projects";
allProjectsJson {
nodes { if (!fs.existsSync(projectsPrefix)) fs.mkdirSync(projectsPrefix);
urlname
shortDescription await graphql(`
name query {
links { allProjectsJson {
github nodes {
website urlname
} shortDescription
lang name
image { links {
publicURL github
} website
featured }
} lang
} image {
} publicURL
`).then((res) => { }
if (res.errors) { featured
reporter.panicOnBuild(`Error while running GraphQL query.`); }
return; }
} }
`).then((res) => {
let projects = res.data.allProjectsJson.nodes.filter((project) => { if (res.errors) {
return project.lang !== "ignoreme"; reporter.panicOnBuild(`Error while running GraphQL query.`);
}); return;
}
fs.writeFileSync(
`${projectsPrefix}.json`, let projects = res.data.allProjectsJson.nodes.filter((project) => {
JSON.stringify({ return project.lang !== "ignoreme";
success: true, });
projects: projects.map((project) => {
return { fs.writeFileSync(
slug: project.urlname, `${projectsPrefix}.json`,
lang: project.lang, JSON.stringify({
api: `/api/projects/${project.lang}/${project.urlname}.json`, success: true,
}; projects: projects.map((project) => {
}), return {
}) slug: project.urlname,
); lang: project.lang,
api: `/api/projects/${project.lang}/${project.urlname}.json`,
config.languages.forEach((lang) => { };
if (!fs.existsSync(`${projectsPrefix}/${lang}`)) }),
fs.mkdirSync(`${projectsPrefix}/${lang}`); })
);
fs.writeFileSync(
`${projectsPrefix}/${lang}.json`, config.languages.forEach((lang) => {
JSON.stringify({ if (!fs.existsSync(`${projectsPrefix}/${lang}`))
success: true, fs.mkdirSync(`${projectsPrefix}/${lang}`);
projects: projects
.filter((project) => { fs.writeFileSync(
return project.lang == lang; `${projectsPrefix}/${lang}.json`,
}) JSON.stringify({
.map((project) => { success: true,
return { projects: projects
slug: project.urlname, .filter((project) => {
lang: project.lang, return project.lang == lang;
api: `/api/projects/${project.lang}/${project.urlname}.json`, })
}; .map((project) => {
}), return {
}) slug: project.urlname,
); lang: project.lang,
}); api: `/api/projects/${project.lang}/${project.urlname}.json`,
};
projects.forEach((project) => { }),
fs.writeFileSync( })
`${projectsPrefix}/${project.lang}/${project.urlname}.json`, );
JSON.stringify({ });
success: true,
project: { projects.forEach((project) => {
slug: project.urlname, fs.writeFileSync(
lang: project.lang, `${projectsPrefix}/${project.lang}/${project.urlname}.json`,
name: project.name, JSON.stringify({
shortDescription: project.shortDescription, success: true,
longDescription: project.longDescription, project: {
links: slug: project.urlname,
project.links !== null lang: project.lang,
? { name: project.name,
github: project.links.github, shortDescription: project.shortDescription,
website: project.links.website, longDescription: project.longDescription,
} links:
: null, project.links !== null
image: project.image.publicURL, ? {
featured: project.featured, github: project.links.github,
frontend: `/${project.lang}/projects/${project.urlname}`, website: project.links.website,
}, }
}) : null,
); image: project.image.publicURL,
}); featured: project.featured,
}); frontend: `/${project.lang}/projects/${project.urlname}`,
}; },
})
);
});
});
};

View file

@ -1,35 +1,35 @@
{ {
"siteDescription": "Hallo, ich bin Kevin Kandlbinder, ein Entwickler und Hobby-Fotograf aus Norddeutschland.", "siteDescription": "Hallo, ich bin Kevin Kandlbinder, ein Entwickler und Hobby-Fotograf aus Norddeutschland.",
"imprint": "Impressum", "imprint": "Impressum",
"datasec": "Datenschutz", "datasec": "Datenschutz",
"disclaimer": "Disclaimer", "disclaimer": "Disclaimer",
"projects": "Projekte", "projects": "Projekte",
"project": "Projekt", "project": "Projekt",
"social": "Soziales", "social": "Soziales",
"homeHello": "Hallo, ich bin", "homeHello": "Hallo, ich bin",
"homeMe": "Ich bin", "homeMe": "Ich bin",
"homeWebDeveloper": "Web Developer", "homeWebDeveloper": "Web Developer",
"homeMyLocation": "Quickborn, Schleswig-Holstein, Deutschland", "homeMyLocation": "Quickborn, Schleswig-Holstein, Deutschland",
"donationCatchphrase": "Gefällt dir was du siehst? Spende doch etwas.", "donationCatchphrase": "Gefällt dir was du siehst? Spende doch etwas.",
"homeImageCredit": "Portrait aufgenommen von Jannik Kiel", "homeImageCredit": "Portrait aufgenommen von Jannik Kiel",
"de": "Deutsch", "de": "Deutsch",
"en": "Englisch", "en": "Englisch",
"projectAboutHeader": "Über {{projectName}}", "projectAboutHeader": "Über {{projectName}}",
"projectViewGitHub": "Auf GitHub anschauen", "projectViewGitHub": "Auf GitHub anschauen",
"projectViewWebsite": "Projekt-Website anschauen", "projectViewWebsite": "Projekt-Website anschauen",
"projectsDescription": "Das ist woran ich grade arbeite oder woran ich gearbeitet habe.", "projectsDescription": "Das ist woran ich grade arbeite oder woran ich gearbeitet habe.",
"projectView": "Anschauen", "projectView": "Anschauen",
"socialDescriptionWithLink": "Finde mich auf anderen Plattformen oder <1>besuche meine Freunde</1>!", "socialDescriptionWithLink": "Finde mich auf anderen Plattformen oder <1>besuche meine Freunde</1>!",
"socialDescription": "Finde mich auf anderen Plattformen!", "socialDescription": "Finde mich auf anderen Plattformen!",
"friends": "Freunde", "friends": "Freunde",
"friendsDescription": "In dieser Liste stehen Freunde von mir und meiner Seite. Schau doch bei ihnen mal rein, wenn du mehr interessante Projekte sehen willst.", "friendsDescription": "In dieser Liste stehen Freunde von mir und meiner Seite. Schau doch bei ihnen mal rein, wenn du mehr interessante Projekte sehen willst.",
"donateThanksText": "Ich finde es schön, dass du meine Arbeit schön findest und das zeigst! Sende mir gerne eine E-Mail an <1>{{contactEmail}}</1> wenn du mit mir über irgendwas reden möchtest!", "donateThanksText": "Ich finde es schön, dass du meine Arbeit schön findest und das zeigst! Sende mir gerne eine E-Mail an <1>{{contactEmail}}</1> wenn du mit mir über irgendwas reden möchtest!",
"donateThanks": "Danke für die Spende!", "donateThanks": "Danke für die Spende!",
"donateDescription": "Hey! Es sieht so aus als würdest du über eine Spende nachdenken. Das ist nett! Wenn du ein bestimmtes Projekt unterstützen willst, schreibe deine Wünsche gerne in den Spendenkommentar.", "donateDescription": "Hey! Es sieht so aus als würdest du über eine Spende nachdenken. Das ist nett! Wenn du ein bestimmtes Projekt unterstützen willst, schreibe deine Wünsche gerne in den Spendenkommentar.",
"donate": "Spenden", "donate": "Spenden",
"featuredProjects": "Vorgestellte Projekte", "featuredProjects": "Vorgestellte Projekte",
"seeMore": "Mehr erkunden", "seeMore": "Mehr erkunden",
"donateGitHub": "Du kannst mich mit dem folgenden Button ganz einfach über GitHub Sponsors unterstützen!", "donateGitHub": "Du kannst mich mit dem folgenden Button ganz einfach über GitHub Sponsors unterstützen!",
"donatePayPal": "Wenn du mich lieber über PayPal unterstützen willst ist hier der Button für dich:", "donatePayPal": "Wenn du mich lieber über PayPal unterstützen willst ist hier der Button für dich:",
"sponsorGitHub": "Über GitHub unterstützen" "sponsorGitHub": "Über GitHub unterstützen"
} }

View file

@ -1,35 +1,35 @@
{ {
"siteDescription": "Hello, I am Kevin Kandlbinder, a developer and hobby photographer from northern Germany.", "siteDescription": "Hello, I am Kevin Kandlbinder, a developer and hobby photographer from northern Germany.",
"imprint": "Imprint", "imprint": "Imprint",
"datasec": "Data Protection", "datasec": "Data Protection",
"disclaimer": "Disclaimer", "disclaimer": "Disclaimer",
"projects": "Projects", "projects": "Projects",
"project": "Project", "project": "Project",
"social": "Social", "social": "Social",
"homeHello": "Hello, I am", "homeHello": "Hello, I am",
"homeMe": "I am", "homeMe": "I am",
"homeWebDeveloper": "a web developer", "homeWebDeveloper": "a web developer",
"homeMyLocation": "Quickborn, Schleswig-Holstein, Germany", "homeMyLocation": "Quickborn, Schleswig-Holstein, Germany",
"donationCatchphrase": "Like what you're seeing? Consider donating.", "donationCatchphrase": "Like what you're seeing? Consider donating.",
"homeImageCredit": "Portrait taken by Jannik Kiel", "homeImageCredit": "Portrait taken by Jannik Kiel",
"de": "German", "de": "German",
"en": "English", "en": "English",
"projectAboutHeader": "About {{projectName}}", "projectAboutHeader": "About {{projectName}}",
"projectViewGitHub": "View on GitHub", "projectViewGitHub": "View on GitHub",
"projectViewWebsite": "View Project-Website", "projectViewWebsite": "View Project-Website",
"projectsDescription": "This is what I am working on or have worked on.", "projectsDescription": "This is what I am working on or have worked on.",
"projectView": "View", "projectView": "View",
"socialDescriptionWithLink": "Find me on other platforms or <1>visit my friends</1>!", "socialDescriptionWithLink": "Find me on other platforms or <1>visit my friends</1>!",
"socialDescription": "Find me on other platforms!", "socialDescription": "Find me on other platforms!",
"friends": "Friends", "friends": "Friends",
"friendsDescription": "In this list you can find friends of mine and this site. Feel free to check them out for more interesting projects.", "friendsDescription": "In this list you can find friends of mine and this site. Feel free to check them out for more interesting projects.",
"donate": "Donate", "donate": "Donate",
"donateDescription": "Hey! It looks like you're thinking about donating to me. That's nice of you! If you want your donation to go towards a specific project, feel free to write your wishes into the donation comment.", "donateDescription": "Hey! It looks like you're thinking about donating to me. That's nice of you! If you want your donation to go towards a specific project, feel free to write your wishes into the donation comment.",
"donateThanks": "Thanks for donating!", "donateThanks": "Thanks for donating!",
"donateThanksText": "I really appreciate you appreciating my work and showing it! Feel free to mail me at <1>{{contactEmail}}</1> if you have anything you want to talk about!", "donateThanksText": "I really appreciate you appreciating my work and showing it! Feel free to mail me at <1>{{contactEmail}}</1> if you have anything you want to talk about!",
"featuredProjects": "Featured Projects", "featuredProjects": "Featured Projects",
"seeMore": "See more", "seeMore": "See more",
"donateGitHub": "You can very easily support me via GitHub Sponsors using the following button!", "donateGitHub": "You can very easily support me via GitHub Sponsors using the following button!",
"donatePayPal": "If you'd rather support me via PayPal the following button is for you:", "donatePayPal": "If you'd rather support me via PayPal the following button is for you:",
"sponsorGitHub": "Sponsor using GitHub" "sponsorGitHub": "Sponsor using GitHub"
} }

54248
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,68 +1,67 @@
{ {
"name": "kevink.dev", "name": "kevink.dev",
"version": "1.1.0", "version": "1.1.0",
"private": true, "private": true,
"description": "KevinK.dev", "description": "KevinK.dev",
"author": "Kevin Kandlbinder", "author": "Kevin Kandlbinder",
"keywords": [ "keywords": [
"gatsby" "gatsby"
], ],
"scripts": { "scripts": {
"develop": "gatsby develop", "develop": "gatsby develop",
"start": "gatsby develop", "start": "gatsby develop",
"build": "gatsby build --prefix-paths", "build": "gatsby build --prefix-paths",
"build:fab": "npm run build && npm run fab:build", "prettier": "npx prettier --write .",
"fab:build": "fab build", "serve": "gatsby serve",
"fab:serve": "fab serve fab.zip", "clean": "gatsby clean"
"serve": "gatsby serve", },
"clean": "gatsby clean" "license": "Apache-2.0",
}, "dependencies": {
"license": "Apache-2.0", "@babel/cli": "7.14.8",
"dependencies": { "@babel/plugin-transform-typescript": "7.14.6",
"@babel/cli": "7.14.8", "@mdx-js/mdx": "1.6.22",
"@babel/plugin-transform-typescript": "7.14.6", "@mdx-js/react": "1.6.22",
"@mdx-js/mdx": "1.6.22", "animejs": "3.2.1",
"@mdx-js/react": "1.6.22", "babel-plugin-i18next-extract": "0.8.3",
"animejs": "3.2.1", "gatsby": "3.10.1",
"babel-plugin-i18next-extract": "0.8.3", "gatsby-cli": "3.10.0",
"gatsby": "3.10.1", "gatsby-plugin-asset-path": "3.0.4",
"gatsby-cli": "3.10.0", "gatsby-plugin-manifest": "3.10.0",
"gatsby-plugin-asset-path": "3.0.4", "gatsby-plugin-mdx": "2.10.0",
"gatsby-plugin-manifest": "3.10.0", "gatsby-plugin-offline": "4.10.0",
"gatsby-plugin-mdx": "2.10.0", "gatsby-plugin-react-helmet": "4.10.0",
"gatsby-plugin-offline": "4.10.0", "gatsby-plugin-react-i18next": "1.1.1",
"gatsby-plugin-react-helmet": "4.10.0", "gatsby-plugin-robots-txt": "1.6.8",
"gatsby-plugin-react-i18next": "1.1.1", "gatsby-plugin-sass": "4.10.0",
"gatsby-plugin-robots-txt": "1.6.8", "gatsby-plugin-sharp": "3.10.2",
"gatsby-plugin-sass": "4.10.0", "gatsby-plugin-sitemap": "4.6.0",
"gatsby-plugin-sharp": "3.10.2", "gatsby-source-filesystem": "3.10.0",
"gatsby-plugin-sitemap": "4.6.0", "gatsby-transformer-json": "3.10.0",
"gatsby-source-filesystem": "3.10.0", "gatsby-transformer-sharp": "3.10.0",
"gatsby-transformer-json": "3.10.0", "i18next": "20.3.5",
"gatsby-transformer-sharp": "3.10.0", "locale": "0.1.0",
"i18next": "20.3.5", "node-sass": "4.14.1",
"locale": "0.1.0", "prop-types": "15.7.2",
"node-sass": "4.14.1", "react": "17.0.2",
"prop-types": "15.7.2", "react-dom": "17.0.2",
"react": "17.0.2", "react-github-btn": "1.2.0",
"react-dom": "17.0.2", "react-helmet": "6.1.0",
"react-github-btn": "1.2.0", "react-i18next": "11.11.3",
"react-helmet": "6.1.0", "tsparticles": "1.32.0"
"react-i18next": "11.11.3", },
"tsparticles": "1.32.0" "devDependencies": {
}, "@fab/actions": "1.0.0-rc.3-beta.1",
"devDependencies": { "@fab/cli": "1.0.0-rc.3-beta.1",
"@fab/actions": "1.0.0-rc.3-beta.1", "@fab/input-static": "1.0.0-rc.3-beta.1",
"@fab/cli": "1.0.0-rc.3-beta.1", "@fab/plugin-render-html": "1.0.0-rc.3-beta.1",
"@fab/input-static": "1.0.0-rc.3-beta.1", "@fab/plugin-rewire-assets": "1.0.0-rc.3-beta.1",
"@fab/plugin-render-html": "1.0.0-rc.3-beta.1", "@fab/server": "1.0.0-rc.3-beta.1",
"@fab/plugin-rewire-assets": "1.0.0-rc.3-beta.1", "babel-eslint": "10.1.0",
"@fab/server": "1.0.0-rc.3-beta.1", "eslint": "7.31.0",
"babel-eslint": "10.1.0", "eslint-loader": "4.0.2",
"eslint": "7.31.0", "eslint-plugin-import": "2.23.4",
"eslint-loader": "4.0.2", "eslint-plugin-react": "7.24.0",
"eslint-plugin-import": "2.23.4", "gatsby-plugin-eslint": "2.0.8",
"eslint-plugin-react": "7.24.0", "prettier": "2.3.2"
"gatsby-plugin-eslint": "2.0.8" }
} }
}

View file

@ -1,6 +1,6 @@
{ {
"extends": ["config:base"], "extends": ["config:base"],
"assignees": ["Unkn0wnCat"], "assignees": ["Unkn0wnCat"],
"automerge": true, "automerge": true,
"baseBranches": ["main"] "baseBranches": ["main"]
} }

View file

@ -1,80 +1,80 @@
@import "./variables"; @import "./variables";
@mixin flexList { @mixin flexList {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: center;
} }
@mixin cardGeneric { @mixin cardGeneric {
border-radius: 5px; border-radius: 5px;
overflow: hidden; overflow: hidden;
box-shadow: -1px 11px 33px -10px rgba(127, 127, 127, 0.3); box-shadow: -1px 11px 33px -10px rgba(127, 127, 127, 0.3);
transition: transform 0.25s, box-shadow 0.25s; transition: transform 0.25s, box-shadow 0.25s;
color: $textColor; color: $textColor;
text-decoration: none; text-decoration: none;
margin: 20px; margin: 20px;
background: $background; background: $background;
&:hover, &:hover,
&:active, &:active,
&:focus { &:focus {
transform: scale(1.05); transform: scale(1.05);
box-shadow: -1px 11px 33px -10px rgba(127, 127, 127, 0.2), box-shadow: -1px 11px 33px -10px rgba(127, 127, 127, 0.2),
-1px 11px 33px -10px rgba($accentColor, 0.75); -1px 11px 33px -10px rgba($accentColor, 0.75);
} }
} }
@mixin buttonBasic { @mixin buttonBasic {
display: block; display: block;
padding: 10px; padding: 10px;
text-align: center; text-align: center;
background: $accentColor; background: $accentColor;
color: white; color: white;
text-decoration: none; text-decoration: none;
box-shadow: 0 0 33px -10px rgba($accentColor, 0.5); box-shadow: 0 0 33px -10px rgba($accentColor, 0.5);
transition: box-shadow 0.25s; transition: box-shadow 0.25s;
&:hover, &:hover,
&:active, &:active,
&:hover { &:hover {
box-shadow: 0 0 33px -10px rgba($accentColor, 0.9); box-shadow: 0 0 33px -10px rgba($accentColor, 0.9);
} }
} }
@mixin button { @mixin button {
@include buttonBasic; @include buttonBasic;
border-radius: 5px; border-radius: 5px;
} }
@mixin homeBanner { @mixin homeBanner {
background: lighten($background, 1); background: lighten($background, 1);
cursor: pointer; cursor: pointer;
display: block; display: block;
text-decoration: none; text-decoration: none;
color: inherit; color: inherit;
img { img {
height: 50px; height: 50px;
} }
> div { > div {
display: flex; display: flex;
height: 100%; height: 100%;
padding: 20px !important; padding: 20px !important;
line-height: 50px; line-height: 50px;
font-size: 1.7em; font-size: 1.7em;
color: white; color: white;
> span { > span {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
} }
> i { > i {
display: inline-flex; display: inline-flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
} }
} }
} }

View file

@ -1,7 +1,7 @@
$layoutWidth: 1200px; $layoutWidth: 1200px;
$accentColor: #e5502b; $accentColor: #e5502b;
$background: #070707; $background: #070707;
$textColor: white; $textColor: white;
$layoutPadding: 20px; $layoutPadding: 20px;
$mainFont: "Anonymous Pro", monospace; $mainFont: "Anonymous Pro", monospace;

View file

@ -1,31 +1,31 @@
import React from "react"; import React from "react";
import { Link, Trans, useI18next } from "gatsby-plugin-react-i18next"; import { Link, Trans, useI18next } from "gatsby-plugin-react-i18next";
import * as styles from "./languageSwitcher.module.scss"; import * as styles from "./languageSwitcher.module.scss";
export default function LanguageSwitcher() { export default function LanguageSwitcher() {
const { languages, originalPath } = useI18next(); const { languages, originalPath } = useI18next();
return ( return (
<div className={styles.languageModal} id="languageChooser"> <div className={styles.languageModal} id="languageChooser">
<div className={styles.languageModalInner}> <div className={styles.languageModalInner}>
<h2> <h2>
Languages ( Languages (
<a href="#top" className={styles.modalCloseLink}> <a href="#top" className={styles.modalCloseLink}>
&times; &times;
</a> </a>
) )
</h2> </h2>
<ul> <ul>
{languages.map((lng) => ( {languages.map((lng) => (
<li key={lng}> <li key={lng}>
<Link to={originalPath} language={lng}> <Link to={originalPath} language={lng}>
<Trans>{lng}</Trans> <Trans>{lng}</Trans>
</Link> </Link>
</li> </li>
))} ))}
</ul> </ul>
</div> </div>
</div> </div>
); );
} }

View file

@ -1,41 +1,41 @@
@import "../mixins"; @import "../mixins";
@import "../variables"; @import "../variables";
.languageModal { .languageModal {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background: rgba(0, 0, 0, 0.7); background: rgba(0, 0, 0, 0.7);
z-index: 1000; z-index: 1000;
opacity: 0; opacity: 0;
pointer-events: none; pointer-events: none;
transition: opacity 0.25s; transition: opacity 0.25s;
&:target { &:target {
opacity: 1; opacity: 1;
pointer-events: auto; pointer-events: auto;
} }
.languageModalInner { .languageModalInner {
position: fixed; position: fixed;
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
color: white; color: white;
background: black; background: black;
font-family: $mainFont; font-family: $mainFont;
padding: 20px; padding: 20px;
border-radius: 5px; border-radius: 5px;
a { a {
color: white; color: white;
text-decoration-style: dotted; text-decoration-style: dotted;
} }
} }
.modalCloseLink { .modalCloseLink {
text-decoration: none; text-decoration: none;
} }
} }

View file

@ -1,91 +1,92 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { Trans, Link } from "gatsby-plugin-react-i18next"; import { Trans, Link } from "gatsby-plugin-react-i18next";
import { graphql, StaticQuery } from "gatsby"; import { graphql, StaticQuery } from "gatsby";
import * as styles from "./navigation.module.scss"; import * as styles from "./navigation.module.scss";
const Navigation = ({ isHome }) => { const Navigation = ({ isHome }) => {
let [atTop, setAtTop] = useState(false); let [atTop, setAtTop] = useState(false);
const updateTransparency = () => { const updateTransparency = () => {
if (typeof window === "undefined") return; if (typeof window === "undefined") return;
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
if (window.scrollY < 15) { if (window.scrollY < 15) {
if (!atTop) setAtTop(true); if (!atTop) setAtTop(true);
} else { } else {
if (atTop) setAtTop(false); if (atTop) setAtTop(false);
} }
}; };
useEffect(() => { useEffect(() => {
if (typeof window === "undefined") return; if (typeof window === "undefined") return;
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
window.addEventListener("scroll", updateTransparency); window.addEventListener("scroll", updateTransparency);
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
window.addEventListener("navigate", updateTransparency); window.addEventListener("navigate", updateTransparency);
updateTransparency(); updateTransparency();
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
let int = window.setInterval(updateTransparency, 10000); let int = window.setInterval(updateTransparency, 10000);
return () => { return () => {
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
window.removeEventListener("scroll", updateTransparency); window.removeEventListener("scroll", updateTransparency);
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
window.removeEventListener("navigate", updateTransparency); window.removeEventListener("navigate", updateTransparency);
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
window.clearInterval(int); window.clearInterval(int);
}; };
}); });
return ( return (
<div <div
className={ className={
styles.topBar + styles.topBar +
(isHome ? " " + styles.homeBar : "") + (isHome ? " " + styles.homeBar : "") +
(atTop ? " " + styles.homeBarTransparent : "") (atTop ? " " + styles.homeBarTransparent : "")
} }>
> <nav className={styles.topBarInner}>
<nav className={styles.topBarInner}> <StaticQuery
<StaticQuery query={graphql`
query={graphql` query {
query { site {
site { siteMetadata {
siteMetadata { title
title }
} }
} }
} `}
`} render={(data) => (
render={(data) => ( <Link to="/" activeClassName={styles.active}>
<Link to="/" activeClassName={styles.active}> {data.site.siteMetadata.title}
{data.site.siteMetadata.title} </Link>
</Link> )}
)} />
/> <div className="flexSpacer"></div>
<div className="flexSpacer"></div> <Link
<Link id="navBtnProjects"
id="navBtnProjects" to="/projects"
to="/projects" activeClassName={styles.active}>
activeClassName={styles.active} <Trans>projects</Trans>
> </Link>
<Trans>projects</Trans> <Link
</Link> id="navBtnSocial"
<Link id="navBtnSocial" to="/social" activeClassName={styles.active}> to="/social"
<Trans>social</Trans> activeClassName={styles.active}>
</Link> <Trans>social</Trans>
</nav> </Link>
</div> </nav>
); </div>
}; );
};
Navigation.propTypes = {
isHome: PropTypes.bool.isRequired, Navigation.propTypes = {
}; isHome: PropTypes.bool.isRequired,
};
export default Navigation;
export default Navigation;

View file

@ -1,59 +1,59 @@
@import "../variables"; @import "../variables";
@import "../mixins"; @import "../mixins";
.topBar { .topBar {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
display: flex; display: flex;
width: 100%; width: 100%;
background: rgba($background, 0.95); background: rgba($background, 0.95);
backdrop-filter: blur(5px); backdrop-filter: blur(5px);
z-index: 999; z-index: 999;
transition: background 0.25s; transition: background 0.25s;
@supports (backdrop-filter: blur(5px)) { @supports (backdrop-filter: blur(5px)) {
background: rgba($background, 0.9); background: rgba($background, 0.9);
} }
.topBarInner { .topBarInner {
display: flex; display: flex;
width: 100%; width: 100%;
max-width: $layoutWidth; max-width: $layoutWidth;
margin: auto; margin: auto;
> :first-child { > :first-child {
padding-left: $layoutPadding; padding-left: $layoutPadding;
} }
> :last-child { > :last-child {
padding-right: $layoutPadding; padding-right: $layoutPadding;
} }
a { a {
display: block; display: block;
padding: 10px $layoutPadding; padding: 10px $layoutPadding;
color: white; color: white;
text-decoration: none; text-decoration: none;
border-top: 2px solid transparent; border-top: 2px solid transparent;
&:hover { &:hover {
border-color: rgba(255, 255, 255, 0.25); border-color: rgba(255, 255, 255, 0.25);
} }
&.active { &.active {
border-color: white; border-color: white;
} }
} }
} }
} }
.homeBar.homeBarTransparent { .homeBar.homeBarTransparent {
background: transparent; background: transparent;
backdrop-filter: blur(0); backdrop-filter: blur(0);
} }
.flexSpacer { .flexSpacer {
flex-grow: 1; flex-grow: 1;
text-align: center; text-align: center;
} }

View file

@ -1,93 +1,93 @@
import React from "react"; import React from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { Helmet } from "gatsby-plugin-react-i18next"; import { Helmet } from "gatsby-plugin-react-i18next";
import { useStaticQuery, graphql } from "gatsby"; import { useStaticQuery, graphql } from "gatsby";
import { useTranslation } from "gatsby-plugin-react-i18next"; import { useTranslation } from "gatsby-plugin-react-i18next";
function SEO({ description, meta, title }) { function SEO({ description, meta, title }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { site } = useStaticQuery( const { site } = useStaticQuery(
graphql` graphql`
query { query {
site { site {
siteMetadata { siteMetadata {
title title
author author
keywords keywords
} }
} }
} }
` `
); );
const metaDescription = description || t("siteDescription"); const metaDescription = description || t("siteDescription");
return ( return (
<Helmet <Helmet
title={title} title={title}
titleTemplate={`%s | ${site.siteMetadata.title}`} titleTemplate={`%s | ${site.siteMetadata.title}`}
meta={[ meta={[
{ {
name: `description`, name: `description`,
content: metaDescription, content: metaDescription,
}, },
{ {
property: `og:title`, property: `og:title`,
content: title, content: title,
}, },
{ {
property: `og:description`, property: `og:description`,
content: metaDescription, content: metaDescription,
}, },
{ {
property: `og:type`, property: `og:type`,
content: `website`, content: `website`,
}, },
{ {
name: `twitter:card`, name: `twitter:card`,
content: `summary`, content: `summary`,
}, },
{ {
name: `twitter:creator`, name: `twitter:creator`,
content: site.siteMetadata.author, content: site.siteMetadata.author,
}, },
{ {
name: `twitter:title`, name: `twitter:title`,
content: title, content: title,
}, },
{ {
name: `twitter:description`, name: `twitter:description`,
content: metaDescription, content: metaDescription,
}, },
{ {
name: "keywords", name: "keywords",
content: site.siteMetadata.keywords, content: site.siteMetadata.keywords,
}, },
].concat(meta)} ].concat(meta)}>
> <script
<script src="https://kit.fontawesome.com/1377f925e0.js"
src="https://kit.fontawesome.com/1377f925e0.js" crossOrigin="anonymous"></script>
crossOrigin="anonymous" <link rel="preconnect" href="https://fonts.gstatic.com" />
></script> <link
<link rel="preconnect" href="https://fonts.gstatic.com" /> href="https://fonts.googleapis.com/css2?family=Anonymous+Pro:wght@400;700&family=Roboto&display=swap"
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Anonymous+Pro:wght@400;700&family=Roboto&display=swap" />
rel="stylesheet" <meta
/> name="battery-savings"
<meta name="battery-savings" content="allow-reduced-framerate"></meta> content="allow-reduced-framerate"></meta>
</Helmet> </Helmet>
); );
} }
SEO.defaultProps = { SEO.defaultProps = {
meta: [], meta: [],
description: ``, description: ``,
}; };
SEO.propTypes = { SEO.propTypes = {
description: PropTypes.string, description: PropTypes.string,
meta: PropTypes.arrayOf(PropTypes.object), meta: PropTypes.arrayOf(PropTypes.object),
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired,
}; };
export default SEO; export default SEO;

View file

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

View file

@ -1,73 +1,73 @@
@import "../variables"; @import "../variables";
* { * {
box-sizing: border-box; box-sizing: border-box;
} }
body, body,
html, html,
#___gatsby, #___gatsby,
#gatsby-focus-wrapper { #gatsby-focus-wrapper {
margin: 0; margin: 0;
padding: 0; padding: 0;
width: 100%; width: 100%;
min-height: 100vh; min-height: 100vh;
font-family: $mainFont; font-family: $mainFont;
} }
#gatsby-focus-wrapper { #gatsby-focus-wrapper {
background: $background; background: $background;
color: $textColor; color: $textColor;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
footer { footer {
background: darken($background, 1); background: darken($background, 1);
width: 100%; width: 100%;
color: white; color: white;
padding: 5px; padding: 5px;
text-align: center; text-align: center;
a { a {
color: white; color: white;
text-decoration: underline dotted currentColor; text-decoration: underline dotted currentColor;
} }
} }
#content { #content {
flex-grow: 1; flex-grow: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.flexSpacer { .flexSpacer {
flex-grow: 1; flex-grow: 1;
text-align: center; text-align: center;
} }
section > div:not(.profile), section > div:not(.profile),
section > article, section > article,
.section > div:not(.profile), .section > div:not(.profile),
.section > article { .section > article {
max-width: $layoutWidth; max-width: $layoutWidth;
width: 100%; width: 100%;
padding: 39px 20px; padding: 39px 20px;
margin: 0 auto; margin: 0 auto;
} }
article { article {
p { p {
text-align: justify; text-align: justify;
} }
a { a {
color: $accentColor; color: $accentColor;
text-decoration: underline dotted currentColor; text-decoration: underline dotted currentColor;
text-decoration-skip: none; text-decoration-skip: none;
} }
} }
h1 { h1 {
font-size: 2em; font-size: 2em;
} }

View file

@ -1,21 +1,21 @@
import * as React from "react"; import * as React from "react";
import { Link } from "gatsby-plugin-react-i18next"; import { Link } from "gatsby-plugin-react-i18next";
import Layout from "../layouts/default"; import Layout from "../layouts/default";
const NotFoundPage = () => { const NotFoundPage = () => {
return ( return (
<Layout title="Not found"> <Layout title="Not found">
<section> <section>
<article> <article>
<h1>Page not found</h1> <h1>Page not found</h1>
<p> <p>
Whoops... That page doesn&apos;t exist, so you may as well{" "} Whoops... That page doesn&apos;t exist, so you may as
<Link to="/">go home</Link>. well <Link to="/">go home</Link>.
</p> </p>
</article> </article>
</section> </section>
</Layout> </Layout>
); );
}; };
export default NotFoundPage; export default NotFoundPage;

View file

@ -1,135 +1,142 @@
import React, { useState } from "react"; import React, { useState } from "react";
import Layout from "../layouts/default"; import Layout from "../layouts/default";
import { graphql } from "gatsby"; import { graphql } from "gatsby";
import { Trans, useI18next, I18nextContext } from "gatsby-plugin-react-i18next"; import { Trans, useI18next, I18nextContext } from "gatsby-plugin-react-i18next";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import GitHubButton from "react-github-btn"; import GitHubButton from "react-github-btn";
import * as styles from "./donate.module.scss"; import * as styles from "./donate.module.scss";
export const query = graphql` export const query = graphql`
query($language: String!) { query ($language: String!) {
site { site {
siteMetadata { siteMetadata {
title title
siteUrl siteUrl
payPalMail payPalMail
contactGitHub contactGitHub
} }
} }
file(relativePath: { eq: "images/pplogo.png" }) { file(relativePath: { eq: "images/pplogo.png" }) {
childImageSharp { childImageSharp {
resize(width: 240, height: 240, fit: CONTAIN) { resize(width: 240, height: 240, fit: CONTAIN) {
src src
} }
} }
} }
locales: allLocale(filter: { language: { eq: $language } }) { locales: allLocale(filter: { language: { eq: $language } }) {
edges { edges {
node { node {
ns ns
data data
language language
} }
} }
} }
} }
`; `;
const DonatePage = (props) => { const DonatePage = (props) => {
const [amount, setAmount] = useState(5); const [amount, setAmount] = useState(5);
const { t } = useI18next(); const { t } = useI18next();
const { path } = React.useContext(I18nextContext); const { path } = React.useContext(I18nextContext);
const { site, file } = props.data; const { site, file } = props.data;
return ( return (
<Layout title={t("donate")} description={t("donationCatchphrase")}> <Layout title={t("donate")} description={t("donationCatchphrase")}>
<section> <section>
<article> <article>
<h1> <h1>
<Trans>donate</Trans> <Trans>donate</Trans>
</h1> </h1>
<p> <p>
<Trans>donateDescription</Trans> <Trans>donateDescription</Trans>
</p> </p>
<p> <p>
<Trans>donateGitHub</Trans> <Trans>donateGitHub</Trans>
</p> </p>
<p style={{ display: "block", textAlign: "center" }}> <p style={{ display: "block", textAlign: "center" }}>
<GitHubButton <GitHubButton
href={ href={
"https://github.com/sponsors/" + site.siteMetadata.contactGitHub "https://github.com/sponsors/" +
} site.siteMetadata.contactGitHub
data-color-scheme="no-preference: light; light: dark; dark: dark;" }
data-icon="octicon-heart" data-color-scheme="no-preference: light; light: dark; dark: dark;"
data-size="large" data-icon="octicon-heart"
aria-label="Sponsor @Unkn0wnCat on GitHub" data-size="large"
> aria-label="Sponsor @Unkn0wnCat on GitHub">
<Trans>sponsorGitHub</Trans> <Trans>sponsorGitHub</Trans>
</GitHubButton> </GitHubButton>
</p> </p>
<p> <p>
<Trans>donatePayPal</Trans> <Trans>donatePayPal</Trans>
</p> </p>
<div className={styles.priceAmount}> <div className={styles.priceAmount}>
<label htmlFor="priceInput" className={styles.sronly}> <label htmlFor="priceInput" className={styles.sronly}>
Amount Amount
</label> </label>
<input <input
type="number" type="number"
min="1" min="1"
placeholder="10.00" placeholder="10.00"
step="1" step="1"
value={amount} value={amount}
onChange={(ev) => { onChange={(ev) => {
setAmount(ev.target.value); setAmount(ev.target.value);
}} }}
name="priceInput" name="priceInput"
id="priceInput" id="priceInput"
/> />
<div></div> <div></div>
</div> </div>
<a <a
className={styles.donateButton} className={styles.donateButton}
rel="noopener" rel="noopener"
id="payPalBtn" id="payPalBtn"
href={ href={
"https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=" + "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=" +
encodeURIComponent(site.siteMetadata.payPalMail) + encodeURIComponent(site.siteMetadata.payPalMail) +
"&item_name=" + "&item_name=" +
encodeURIComponent(site.siteMetadata.title) + encodeURIComponent(site.siteMetadata.title) +
"&currency_code=EUR&image_url=" + "&currency_code=EUR&image_url=" +
encodeURIComponent( encodeURIComponent(
site.siteMetadata.siteUrl + file.childImageSharp.resize.src site.siteMetadata.siteUrl +
) + file.childImageSharp.resize.src
"&return=" + ) +
encodeURIComponent( "&return=" +
site.siteMetadata.siteUrl + "/" + path + "thank-you/" encodeURIComponent(
) + site.siteMetadata.siteUrl +
"&rm=0&cancel_return=" + "/" +
encodeURIComponent(site.siteMetadata.siteUrl + "/" + path) + path +
"&amount=" + "thank-you/"
amount ) +
} "&rm=0&cancel_return=" +
> encodeURIComponent(
<span>Donate using PayPal</span> site.siteMetadata.siteUrl + "/" + path
<i className="fas fa-fw fa-chevron-right" aria-hidden="true"></i> ) +
</a> "&amount=" +
</article> amount
</section> }>
</Layout> <span>Donate using PayPal</span>
); <i
}; className="fas fa-fw fa-chevron-right"
aria-hidden="true"></i>
DonatePage.propTypes = { </a>
data: PropTypes.object.isRequired, </article>
}; </section>
</Layout>
export default DonatePage; );
};
DonatePage.propTypes = {
data: PropTypes.object.isRequired,
};
export default DonatePage;

View file

@ -1,40 +1,40 @@
@import "../variables"; @import "../variables";
@import "../mixins"; @import "../mixins";
.priceAmount { .priceAmount {
display: flex; display: flex;
width: 150px; width: 150px;
margin: 20px auto; margin: 20px auto;
border: thin solid rgba(0, 0, 0, 0.25); border: thin solid rgba(0, 0, 0, 0.25);
border-radius: 5px; border-radius: 5px;
overflow: hidden; overflow: hidden;
line-height: 40px; line-height: 40px;
input { input {
flex-grow: 1; flex-grow: 1;
border: none; border: none;
padding-left: 10px; padding-left: 10px;
width: 1px; width: 1px;
border-right: thin solid rgba(0, 0, 0, 0.25); border-right: thin solid rgba(0, 0, 0, 0.25);
} }
div { div {
width: 20px; width: 20px;
text-align: center; text-align: center;
} }
} }
.donateButton { .donateButton {
@include button; @include button;
} }
.sronly { .sronly {
border: 0; border: 0;
clip: rect(0, 0, 0, 0); clip: rect(0, 0, 0, 0);
height: 1px; height: 1px;
margin: -1px; margin: -1px;
overflow: hidden; overflow: hidden;
padding: 0; padding: 0;
position: absolute; position: absolute;
width: 1px; width: 1px;
} }

View file

@ -1,55 +1,59 @@
import React from "react"; import React from "react";
import Layout from "../../layouts/default"; import Layout from "../../layouts/default";
import { Trans, useI18next } from "gatsby-plugin-react-i18next"; import { Trans, useI18next } from "gatsby-plugin-react-i18next";
import { graphql } from "gatsby"; import { graphql } from "gatsby";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
export const query = graphql` export const query = graphql`
query GetThankYouPage($language: String!) { query GetThankYouPage($language: String!) {
site { site {
siteMetadata { siteMetadata {
contactEmail contactEmail
} }
} }
locales: allLocale(filter: { language: { eq: $language } }) { locales: allLocale(filter: { language: { eq: $language } }) {
edges { edges {
node { node {
ns ns
data data
language language
} }
} }
} }
} }
`; `;
const ThankYouPage = (props) => { const ThankYouPage = (props) => {
const { site } = props.data; const { site } = props.data;
let contactEmail = site.siteMetadata.contactEmail; let contactEmail = site.siteMetadata.contactEmail;
const { t } = useI18next(); const { t } = useI18next();
return ( return (
<Layout title={t("donate")}> <Layout title={t("donate")}>
<section> <section>
<article> <article>
<h1> <h1>
<Trans>donateThanks</Trans> <Trans>donateThanks</Trans>
</h1> </h1>
<p> <p>
<Trans contactEmail={contactEmail} i18nKey="donateThanksText"> <Trans
donateThanksText contactEmail={contactEmail}
<a href={"mailto:" + contactEmail}>{{ contactEmail }}</a> i18nKey="donateThanksText">
</Trans> donateThanksText
</p> <a href={"mailto:" + contactEmail}>
</article> {{ contactEmail }}
</section> </a>
</Layout> </Trans>
); </p>
}; </article>
</section>
ThankYouPage.propTypes = { </Layout>
data: PropTypes.object.isRequired, );
}; };
export default ThankYouPage; ThankYouPage.propTypes = {
data: PropTypes.object.isRequired,
};
export default ThankYouPage;

View file

@ -1,97 +1,140 @@
import React from "react"; import React from "react";
import Layout from "../layouts/default"; import Layout from "../layouts/default";
import { Trans, useI18next } from "gatsby-plugin-react-i18next"; import { Trans, useI18next } from "gatsby-plugin-react-i18next";
import { graphql } from "gatsby"; import { graphql } from "gatsby";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import * as styles from "./friends.module.scss"; import * as styles from "./friends.module.scss";
export const query = graphql` export const query = graphql`
query AllFriendsQuery($language: String!) { query AllFriendsQuery($language: String!) {
allFriendsJson { allFriendsJson {
nodes { nodes {
name name
profession profession
url url
imageURL imageURL
} }
} }
locales: allLocale(filter: { language: { eq: $language } }) { locales: allLocale(filter: { language: { eq: $language } }) {
edges { edges {
node { node {
ns ns
data data
language language
} }
} }
} }
} }
`; `;
const FriendsPage = ({ data }) => { const FriendsPage = ({ data }) => {
const { t } = useI18next(); const { t } = useI18next();
/*function shuffle(a) { /*function shuffle(a) {
for (let i = a.length - 1; i > 0; i--) { for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1)); const j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]]; [a[i], a[j]] = [a[j], a[i]];
} }
return a; return a;
}*/ }*/
return ( return (
<Layout title={t("friends")} description={t("friendsDescription")}> <Layout title={t("friends")} description={t("friendsDescription")}>
<section> <section>
<article> <article>
<h1> <h1>
<Trans>social</Trans> <Trans>social</Trans>
</h1> </h1>
<p> <p>
<Trans>friendsDescription</Trans> <Trans>friendsDescription</Trans>
</p> </p>
<div className={styles.friendsList}> <div className={styles.friendsList}>
{/*shuffle(*/data.allFriendsJson.nodes/*)*/.map((friend) => { {
return ( /*shuffle(*/ data.allFriendsJson.nodes /*)*/
<div .map((friend) => {
className={styles.friendProfile} return (
key={friend.url + "#" + friend.name} <div
> className={styles.friendProfile}
<div key={
className={styles.friendImage} friend.url + "#" + friend.name
style={{ backgroundImage: "url(" + friend.imageURL + ")" }} }>
key={friend.url + "#" + friend.name + "#image"} <div
> className={styles.friendImage}
<span className={styles.friendName} key={friend.url + "#" + friend.name + "#name"}>{friend.name}</span> style={{
<span className={styles.friendTitle} key={friend.url + "#" + friend.name + "#profession"}> backgroundImage:
{friend.profession} "url(" +
</span> friend.imageURL +
</div> ")",
}}
<div className={styles.contactLinks} key={friend.url + "#" + friend.name + "#links"}> key={
<a friend.url +
className={styles.contactLink} "#" +
href={friend.url} friend.name +
target="_blank" "#image"
rel="noreferrer" }>
> <span
<i className="fas fa-globe-europe" aria-hidden="true"></i>{" "} className={
{friend.url} styles.friendName
</a> }
</div> key={
</div> friend.url +
); "#" +
})} friend.name +
</div> "#name"
</article> }>
</section> {friend.name}
</Layout> </span>
); <span
}; className={
styles.friendTitle
FriendsPage.propTypes = { }
data: PropTypes.object.isRequired, key={
}; friend.url +
"#" +
export default FriendsPage; friend.name +
"#profession"
}>
{friend.profession}
</span>
</div>
<div
className={styles.contactLinks}
key={
friend.url +
"#" +
friend.name +
"#links"
}>
<a
className={
styles.contactLink
}
href={friend.url}
target="_blank"
rel="noreferrer">
<i
className="fas fa-globe-europe"
aria-hidden="true"></i>{" "}
{friend.url}
</a>
</div>
</div>
);
})
}
</div>
</article>
</section>
</Layout>
);
};
FriendsPage.propTypes = {
data: PropTypes.object.isRequired,
};
export default FriendsPage;

View file

@ -1,62 +1,62 @@
@import "../variables"; @import "../variables";
@import "../mixins"; @import "../mixins";
.friendsList { .friendsList {
@include flexList; @include flexList;
.friendProfile { .friendProfile {
@include cardGeneric; @include cardGeneric;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 300px; width: 300px;
flex-shrink: 0; flex-shrink: 0;
.friendImage { .friendImage {
width: 100%; width: 100%;
height: 300px; height: 300px;
background-position: center; background-position: center;
background-size: cover; background-size: cover;
display: flex; display: flex;
padding: 10px; padding: 10px;
flex-direction: column-reverse; flex-direction: column-reverse;
text-shadow: 0 0 10px black, 0 0 10px black, 0 0 20px black; text-shadow: 0 0 10px black, 0 0 10px black, 0 0 20px black;
.friendName { .friendName {
font-size: 2em; font-size: 2em;
margin-top: -5px; margin-top: -5px;
} }
.friendTitle { .friendTitle {
margin-top: auto; margin-top: auto;
} }
} }
.friendBio { .friendBio {
padding: 15px; padding: 15px;
flex-grow: 1; flex-grow: 1;
text-align: justify; text-align: justify;
display: block; display: block;
padding-bottom: 0; padding-bottom: 0;
} }
.contactLinks { .contactLinks {
padding: 15px; padding: 15px;
margin: 0; margin: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.contactLink { .contactLink {
transition: text-decoration 0.5s; transition: text-decoration 0.5s;
text-decoration: underline dotted rgba(0, 0, 0, 0); text-decoration: underline dotted rgba(0, 0, 0, 0);
padding: 6px 0 6px 25px; padding: 6px 0 6px 25px;
color: $textColor; color: $textColor;
> i { > i {
color: $accentColor; color: $accentColor;
margin-left: -25px; margin-left: -25px;
margin-right: 5px; margin-right: 5px;
} }
} }
} }
} }
} }

View file

@ -1,255 +1,264 @@
import * as React from "react"; import * as React from "react";
import Layout from "../layouts/default"; import Layout from "../layouts/default";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import * as styles from "./index.module.scss"; import * as styles from "./index.module.scss";
import * as projectStyles from "./projects.module.scss"; import * as projectStyles from "./projects.module.scss";
import { Trans, Link } from "gatsby-plugin-react-i18next"; import { Trans, Link } from "gatsby-plugin-react-i18next";
import { graphql } from "gatsby"; import { graphql } from "gatsby";
import { MDXRenderer } from "gatsby-plugin-mdx"; import { MDXRenderer } from "gatsby-plugin-mdx";
import anime from "animejs"; import anime from "animejs";
import { tsParticles } from "tsparticles"; import { tsParticles } from "tsparticles";
import * as particleConfig from "./index.particles.json";
import * as particleConfig from "./index.particles.json";
export const query = graphql`
export const query = graphql` query GetMetaAndProjects($language: String) {
query GetMetaAndProjects($language: String) { site {
site { siteMetadata {
siteMetadata { contactEmail
contactEmail contactPhone
contactPhone mapsLink
mapsLink contactTwitter
contactTwitter contactGitHub
contactGitHub contactMastodon
contactMastodon contactMastodonHref
contactMastodonHref }
} }
} allProjectsJson(
allProjectsJson( filter: { lang: { eq: $language }, featured: { gte: 0 } }
filter: { lang: { eq: $language }, featured: { gte: 0 } } sort: { fields: featured, order: ASC }
sort: { fields: featured, order: ASC } ) {
) { nodes {
nodes { lang
lang urlname
urlname name
name image {
image { childImageSharp {
childImageSharp { resize(width: 400, quality: 90) {
resize(width: 400, quality: 90) { src
src }
} }
} }
} shortDescription
shortDescription featured
featured }
} }
} locales: allLocale(filter: { language: { eq: $language } }) {
locales: allLocale(filter: { language: { eq: $language } }) { edges {
edges { node {
node { ns
ns data
data language
language }
} }
} }
} file(
file( sourceInstanceName: { eq: "textblocks" }
sourceInstanceName: {eq: "textblocks"}, relativeDirectory: {eq: "home/about"}, name: {eq: $language} relativeDirectory: { eq: "home/about" }
) { name: { eq: $language }
id ) {
childMdx { id
body childMdx {
} body
name }
} name
} }
`; }
`;
const IndexPage = (props) => {
React.useEffect(() => { const IndexPage = (props) => {
if (typeof window === "undefined") return; React.useEffect(() => {
if (typeof window === "undefined") return;
anime({
targets: [ anime({
"." + styles.profileCard + " > span", targets: [
"." + styles.profileCard + " a", "." + styles.profileCard + " > span",
], "." + styles.profileCard + " a",
opacity: [0, 1], ],
translateX: [100, 0], opacity: [0, 1],
duration: 250, translateX: [100, 0],
delay: anime.stagger(20), duration: 250,
easing: "easeInOutCirc", delay: anime.stagger(20),
}); easing: "easeInOutCirc",
anime({ });
targets: ["." + styles.profileImageDummy], anime({
translateX: [0, -3], targets: ["." + styles.profileImageDummy],
translateY: [0, 3], translateX: [0, -3],
duration: 250, translateY: [0, 3],
easing: "easeInOutCirc", duration: 250,
}); easing: "easeInOutCirc",
anime({ });
targets: ["." + styles.profileImage], anime({
translateX: [0, 4], targets: ["." + styles.profileImage],
translateY: [0, -4], translateX: [0, 4],
duration: 250, translateY: [0, -4],
easing: "easeInOutCirc", duration: 250,
}); easing: "easeInOutCirc",
});
tsParticles.load("particle-container", particleConfig);
}, []); tsParticles.load("particle-container", particleConfig);
}, []);
let meta = props.data.site.siteMetadata;
let file = props.data.file; let meta = props.data.site.siteMetadata;
let file = props.data.file;
return (
<Layout title="Kevin Kandlbinder" transparentTopbar={true}> return (
<section className={styles.heroSection}> <Layout title="Kevin Kandlbinder" transparentTopbar={true}>
<div className={styles.heroSectionBg} id="particle-container"></div> <section className={styles.heroSection}>
<div className={styles.heroSectionBgOver}></div> <div
<div className={styles.profile + " profile"}> className={styles.heroSectionBg}
<div id="particle-container"></div>
data-bg="url(https://cdn.kevink.dev/images/kevin/kevin-kandlbinder-03.jpg)" <div className={styles.heroSectionBgOver}></div>
style={{ <div className={styles.profile + " profile"}>
backgroundImage: <div
"url(https://cdn.kevink.dev/images/kevin/kevin-kandlbinder-03.jpg)", data-bg="url(https://cdn.kevink.dev/images/kevin/kevin-kandlbinder-03.jpg)"
}} style={{
className={styles.profileImage + " lazy"} backgroundImage:
></div> "url(https://cdn.kevink.dev/images/kevin/kevin-kandlbinder-03.jpg)",
<div className={styles.profileImageDummy}></div> }}
<div className={styles.profileCard}> className={styles.profileImage + " lazy"}></div>
<span className={styles.hello}> <div className={styles.profileImageDummy}></div>
<Trans>homeHello</Trans> <div className={styles.profileCard}>
</span> <span className={styles.hello}>
<span className={styles.name}>Kevin Kandlbinder</span> <Trans>homeHello</Trans>
<span className={styles.description}> </span>
<Trans>homeMe</Trans>{" "} <span className={styles.name}>Kevin Kandlbinder</span>
<span id="descriptionType"> <span className={styles.description}>
<Trans>homeWebDeveloper</Trans> <Trans>homeMe</Trans>{" "}
</span> <span id="descriptionType">
. <Trans>homeWebDeveloper</Trans>
</span> </span>
.
<div className={styles.contactLinks}> </span>
<a
className={styles.contactLink} <div className={styles.contactLinks}>
href={"tel:" + meta.contactPhone} <a
rel="me" className={styles.contactLink}
> href={"tel:" + meta.contactPhone}
<i className="fas fa-fw fa-phone"></i> rel="me">
{meta.contactPhone} <i className="fas fa-fw fa-phone"></i>
</a> {meta.contactPhone}
<a </a>
className={styles.contactLink} <a
href={"mailto:" + meta.contactEmail} className={styles.contactLink}
rel="me" href={"mailto:" + meta.contactEmail}
> rel="me">
<i className="far fa-fw fa-envelope"></i> <i className="far fa-fw fa-envelope"></i>
{meta.contactEmail} {meta.contactEmail}
</a> </a>
<a <a
className={styles.contactLink} className={styles.contactLink}
href={meta.mapsLink} href={meta.mapsLink}
rel="noreferrer " rel="noreferrer "
target="_blank" target="_blank">
> <i className="fas fa-fw fa-map-marker-alt"></i>
<i className="fas fa-fw fa-map-marker-alt"></i> <Trans>homeMyLocation</Trans>
<Trans>homeMyLocation</Trans> </a>
</a> <a
<a className={styles.contactLink}
className={styles.contactLink} href={meta.contactMastodonHref}
href={meta.contactMastodonHref} rel="noreferrer me"
rel="noreferrer me" target="_blank">
target="_blank" <i className="fab fa-fw fa-mastodon"></i>
> {meta.contactMastodon}
<i className="fab fa-fw fa-mastodon"></i> </a>
{meta.contactMastodon} <a
</a> className={styles.contactLink}
<a href={
className={styles.contactLink} "https://github.com/" + meta.contactGitHub
href={"https://github.com/" + meta.contactGitHub} }
rel="noreferrer me" rel="noreferrer me"
target="_blank" target="_blank">
> <i className="fab fa-fw fa-github"></i>
<i className="fab fa-fw fa-github"></i> {meta.contactGitHub}
{meta.contactGitHub} </a>
</a> </div>
</div> </div>
</div> </div>
</div> </section>
</section> <section className="aboutSection">
<section className="aboutSection"> <article>
<article> <MDXRenderer>{file.childMdx.body}</MDXRenderer>
<MDXRenderer>{file.childMdx.body}</MDXRenderer> </article>
</article> </section>
</section> <a
<a className={styles.creditSection}
className={styles.creditSection} href="https://unsplash.com/@jannikkiel"
href="https://unsplash.com/@jannikkiel" target="_blank"
target="_blank" rel="noreferrer">
rel="noreferrer" <div>
> <span>
<div> <i className="fas fa-fw fa-camera"></i>{" "}
<span> <Trans>homeImageCredit</Trans>
<i className="fas fa-fw fa-camera"></i>{" "} </span>
<Trans>homeImageCredit</Trans> <i className="fas fa-fw fa-chevron-right"></i>
</span> </div>
<i className="fas fa-fw fa-chevron-right"></i> </a>
</div> <section className="featuredSection">
</a> <article>
<section className="featuredSection"> <h1>
<article> <Trans>featuredProjects</Trans>
<h1> </h1>
<Trans>featuredProjects</Trans> <div className={projectStyles.projectList}>
</h1> {props.data.allProjectsJson.nodes.map((project) => {
<div className={projectStyles.projectList}> return (
{props.data.allProjectsJson.nodes.map((project) => { <Link
return ( className={projectStyles.projectCard}
<Link key={project.lang + "/" + project.urlname}
className={projectStyles.projectCard} to={"/projects/" + project.urlname}>
key={project.lang + "/" + project.urlname} <div
to={"/projects/" + project.urlname} className={
> projectStyles.projectCardImage
<div }
className={projectStyles.projectCardImage} style={{
style={{ backgroundImage:
backgroundImage: "url(" +
"url(" + project.image.childImageSharp.resize.src + ")", project.image.childImageSharp
}} .resize.src +
> ")",
<div className={projectStyles.projectCardMeta}> }}>
<span className={projectStyles.projectCardTitle}> <div
{project.name} className={
</span> projectStyles.projectCardMeta
<span>{project.shortDescription}</span> }>
</div> <span
</div> className={
</Link> projectStyles.projectCardTitle
); }>
})} {project.name}
</div> </span>
<Link to="/projects" className={styles.seeMoreButton}> <span>
<Trans>seeMore</Trans>{" "} {project.shortDescription}
<i className="fas fa-fw fa-chevron-right"></i> </span>
</Link> </div>
</article> </div>
</section> </Link>
<Link className={styles.donationSection} to="/donate"> );
<div> })}
<span> </div>
<Trans>donationCatchphrase</Trans> <Link to="/projects" className={styles.seeMoreButton}>
</span> <Trans>seeMore</Trans>{" "}
<i className="fas fa-fw fa-chevron-right"></i> <i className="fas fa-fw fa-chevron-right"></i>
</div> </Link>
</Link> </article>
</Layout> </section>
); <Link className={styles.donationSection} to="/donate">
}; <div>
<span>
IndexPage.propTypes = { <Trans>donationCatchphrase</Trans>
data: PropTypes.object.isRequired, </span>
}; <i className="fas fa-fw fa-chevron-right"></i>
</div>
export default IndexPage; </Link>
</Layout>
);
};
IndexPage.propTypes = {
data: PropTypes.object.isRequired,
};
export default IndexPage;

View file

@ -1,170 +1,184 @@
@import "../variables"; @import "../variables";
@import "../mixins"; @import "../mixins";
.heroSection { .heroSection {
width: 100%; width: 100%;
height: 600px; height: 600px;
overflow: hidden; overflow: hidden;
.heroSectionBg, .heroSectionBgOver { .heroSectionBg,
position: absolute; .heroSectionBgOver {
width: 100%; position: absolute;
max-width: unset; width: 100%;
height: 600px; max-width: unset;
padding: 0; height: 600px;
padding: 0;
@media (pointer: coarse), (pointer: none) {
height: 700px; @media (pointer: coarse), (pointer: none) {
} height: 700px;
} }
}
.heroSectionBg {
/*background: radial-gradient(ellipse at top left, #1f0ba659, transparent), .heroSectionBg {
radial-gradient(ellipse at bottom right, #4a086829, transparent);*/ /*background: radial-gradient(ellipse at top left, #1f0ba659, transparent),
radial-gradient(ellipse at bottom right, #4a086829, transparent);*/
background: linear-gradient(45deg, #000850 0%, #000320 100%), radial-gradient(100% 225% at 100% 0%, #FF6928 0%, #000000 100%), linear-gradient(225deg, #FF7A00 0%, #000000 100%), linear-gradient(135deg, #CDFFEB 10%, #CDFFEB 35%, #009F9D 35%, #009F9D 60%, #07456F 60%, #07456F 67%, #0F0A3C 67%, #0F0A3C 100%);
background-blend-mode: screen, overlay, hard-light, normal; background: linear-gradient(45deg, #000850 0%, #000320 100%),
} radial-gradient(100% 225% at 100% 0%, #ff6928 0%, #000000 100%),
linear-gradient(225deg, #ff7a00 0%, #000000 100%),
.heroSectionBgOver { linear-gradient(
background: linear-gradient(to bottom, transparent 80%, $background); 135deg,
} #cdffeb 10%,
#cdffeb 35%,
@media (pointer: coarse), (pointer: none) { #009f9d 35%,
height: 700px; #009f9d 60%,
} #07456f 60%,
#07456f 67%,
.profile { #0f0a3c 67%,
position: relative; #0f0a3c 100%
left: 50%; );
width: calc(90% - 40px); background-blend-mode: screen, overlay, hard-light, normal;
max-width: 600px; }
max-height: 400px;
transform: translate(-50%, 0%); .heroSectionBgOver {
top: 100px; background: linear-gradient(to bottom, transparent 80%, $background);
}
.hello {
font-weight: 100; @media (pointer: coarse), (pointer: none) {
opacity: 0.75; height: 700px;
display: block; }
margin-bottom: -5px;
} .profile {
position: relative;
.name { left: 50%;
font-weight: 100; width: calc(90% - 40px);
font-size: 2em; max-width: 600px;
display: block; max-height: 400px;
} transform: translate(-50%, 0%);
top: 100px;
.description {
font-weight: 100; .hello {
display: block; font-weight: 100;
} opacity: 0.75;
display: block;
.contactLinks { margin-bottom: -5px;
margin-top: 20px; }
display: flex;
flex-direction: column; .name {
} font-weight: 100;
font-size: 2em;
.contactLink { display: block;
transition: text-decoration 0.5s; }
text-decoration: underline dotted rgba(0, 0, 0, 0);
padding: 6px 0 6px 25px; .description {
color: $textColor; font-weight: 100;
display: block;
@media (pointer: coarse), (pointer: none) { }
padding-top: 15px;
padding-bottom: 15px; .contactLinks {
} margin-top: 20px;
} display: flex;
flex-direction: column;
.contactLink:hover, }
.contactLink:active {
text-decoration: underline dotted rgba(0, 0, 0, 0.5); .contactLink {
} transition: text-decoration 0.5s;
text-decoration: underline dotted rgba(0, 0, 0, 0);
.contactLink > i { padding: 6px 0 6px 25px;
color: $accentColor; color: $textColor;
margin-left: -25px;
margin-right: 5px; @media (pointer: coarse), (pointer: none) {
} padding-top: 15px;
padding-bottom: 15px;
.profileCard { }
width: calc(100% - 40px); }
height: calc(100% - 20px);
transform: translate(40px, 20px); .contactLink:hover,
border-radius: 5px; .contactLink:active {
padding: 20px 20px 20px 230px; text-decoration: underline dotted rgba(0, 0, 0, 0.5);
color: $textColor; }
}
.contactLink > i {
.profileImage, color: $accentColor;
.profileImageDummy { margin-left: -25px;
display: inline-block; margin-right: 5px;
width: 250px; }
height: 350px;
border-radius: 5px; .profileCard {
position: absolute; width: calc(100% - 40px);
z-index: 100; height: calc(100% - 20px);
background-color: #1c1c1c; transform: translate(40px, 20px);
background-size: cover; border-radius: 5px;
background-position: center; padding: 20px 20px 20px 230px;
transition: transform 0.25s; color: $textColor;
} }
.profileImage { .profileImage,
z-index: 20; .profileImageDummy {
box-shadow: -1px 11px 33px -10px #e5502b4b; display: inline-block;
clip-path: polygon(6% 8%, 88% 5%, 95% 91%, 7% 96%); width: 250px;
} height: 350px;
border-radius: 5px;
.profileImageDummy { position: absolute;
z-index: 10; z-index: 100;
background: $accentColor; background-color: #1c1c1c;
opacity: 0.2; background-size: cover;
clip-path: polygon(14% 4%, 95% 1%, 88% 96%, 2% 89%); background-position: center;
} transition: transform 0.25s;
}
@media (max-width: 590px) {
.profileImage, .profileImage {
.profileImageDummy { z-index: 20;
display: none; box-shadow: -1px 11px 33px -10px #e5502b4b;
} clip-path: polygon(6% 8%, 88% 5%, 95% 91%, 7% 96%);
}
.profileCard {
padding: 20px 20px 20px 20px; .profileImageDummy {
transform: translate(20px, 20px); z-index: 10;
} background: $accentColor;
} opacity: 0.2;
} clip-path: polygon(14% 4%, 95% 1%, 88% 96%, 2% 89%);
} }
.amazonAlexaSection, @media (max-width: 590px) {
.donationSection, .profileImage,
.hireMeSection { .profileImageDummy {
@include homeBanner; display: none;
} }
.creditSection { .profileCard {
@include homeBanner; padding: 20px 20px 20px 20px;
transform: translate(20px, 20px);
> div { }
padding: 15px !important; }
line-height: 15px; }
font-size: 1.2em; }
color: white;
.amazonAlexaSection,
> span > i { .donationSection,
line-height: 15px !important; .hireMeSection {
} @include homeBanner;
} }
}
.creditSection {
.seeMoreButton { @include homeBanner;
@include button;
width: fit-content; > div {
margin: 0 auto; padding: 15px !important;
margin-top: 40px; line-height: 15px;
padding: 10px 20px; font-size: 1.2em;
} color: white;
> span > i {
line-height: 15px !important;
}
}
}
.seeMoreButton {
@include button;
width: fit-content;
margin: 0 auto;
margin-top: 40px;
padding: 10px 20px;
}

View file

@ -1,107 +1,107 @@
{ {
"particles": { "particles": {
"number": { "number": {
"value": 33, "value": 33,
"density": { "density": {
"enable": true, "enable": true,
"value_area": 800 "value_area": 800
} }
}, },
"color": { "color": {
"value": "#1b1e34" "value": "#1b1e34"
}, },
"shape": { "shape": {
"type": "circle", "type": "circle",
"stroke": { "stroke": {
"width": 0, "width": 0,
"color": "#000" "color": "#000"
}, },
"polygon": { "polygon": {
"nb_sides": 3 "nb_sides": 3
} }
}, },
"opacity": { "opacity": {
"value": 0.4, "value": 0.4,
"random": true, "random": true,
"anim": { "anim": {
"enable": false, "enable": false,
"speed": 1, "speed": 1,
"opacity_min": 0.1, "opacity_min": 0.1,
"sync": false "sync": false
} }
}, },
"size": { "size": {
"value": 27.620603391810075, "value": 27.620603391810075,
"random": true, "random": true,
"anim": { "anim": {
"enable": false, "enable": false,
"speed": 10, "speed": 10,
"size_min": 40, "size_min": 40,
"sync": false "sync": false
} }
}, },
"line_linked": { "line_linked": {
"enable": false, "enable": false,
"distance": 200, "distance": 200,
"color": "#ffffff", "color": "#ffffff",
"opacity": 0.14994041841268327, "opacity": 0.14994041841268327,
"width": 2 "width": 2
}, },
"move": { "move": {
"enable": true, "enable": true,
"speed": 0.2, "speed": 0.2,
"direction": "top", "direction": "top",
"random": true, "random": true,
"straight": false, "straight": false,
"out_mode": "out", "out_mode": "out",
"bounce": false, "bounce": false,
"attract": { "attract": {
"enable": false, "enable": false,
"rotateX": 600, "rotateX": 600,
"rotateY": 1200 "rotateY": 1200
} }
} }
}, },
"interactivity": { "interactivity": {
"detect_on": "window", "detect_on": "window",
"events": { "events": {
"onhover": { "onhover": {
"enable": false, "enable": false,
"mode": "repulse" "mode": "repulse"
}, },
"onclick": { "onclick": {
"enable": false, "enable": false,
"mode": "push" "mode": "push"
}, },
"resize": true "resize": true
}, },
"modes": { "modes": {
"grab": { "grab": {
"distance": 400, "distance": 400,
"line_linked": { "line_linked": {
"opacity": 1 "opacity": 1
} }
}, },
"bubble": { "bubble": {
"distance": 400, "distance": 400,
"size": 40, "size": 40,
"duration": 2, "duration": 2,
"opacity": 8, "opacity": 8,
"speed": 3 "speed": 3
}, },
"repulse": { "repulse": {
"distance": 200, "distance": 200,
"duration": 0.4 "duration": 0.4
}, },
"push": { "push": {
"particles_nb": 4 "particles_nb": 4
}, },
"remove": { "remove": {
"particles_nb": 2 "particles_nb": 2
} }
} }
}, },
"detectRetina": true, "detectRetina": true,
"pauseOnBlur": true, "pauseOnBlur": true,
"pauseOnOutsideViewport": true "pauseOnOutsideViewport": true
} }

View file

@ -1,56 +1,59 @@
import React from "react"; import React from "react";
import Layout from "../../layouts/default"; import Layout from "../../layouts/default";
import { Trans, useI18next } from "gatsby-plugin-react-i18next"; import { Trans, useI18next } from "gatsby-plugin-react-i18next";
import { graphql } from "gatsby"; import { graphql } from "gatsby";
export const query = graphql` export const query = graphql`
query($language: String!) { query ($language: String!) {
locales: allLocale(filter: { language: { eq: $language } }) { locales: allLocale(filter: { language: { eq: $language } }) {
edges { edges {
node { node {
ns ns
data data
language language
} }
} }
} }
} }
`; `;
export default function ImprintPage() { export default function ImprintPage() {
const { t } = useI18next(); const { t } = useI18next();
return ( return (
<Layout title={t("imprint")}> <Layout title={t("imprint")}>
<section> <section>
<article> <article>
<h1> <h1>
<Trans>imprint</Trans> <Trans>imprint</Trans>
</h1> </h1>
<p>Angaben gemäß § 5 TMG</p> <p>Angaben gemäß § 5 TMG</p>
<p> <p>
Kevin Kandlbinder Kevin Kandlbinder
<br /> <br />
Eichenweg 48 Eichenweg 48
<br /> <br />
25451 Quickborn <br /> 25451 Quickborn <br />
</p> </p>
<p> <p>
{" "} {" "}
<strong>Vertreten durch: </strong> <strong>Vertreten durch: </strong>
<br /> <br />
Kevin Kandlbinder Kevin Kandlbinder
<br /> <br />
</p> </p>
<p> <p>
<strong>Kontakt:</strong> <br /> <strong>Kontakt:</strong> <br />
Telefon: +49 4106 8068004 Telefon: +49 4106 8068004
<br /> <br />
E-Mail: <a href="mailto:contact@kevink.dev">contact@kevink.dev</a> E-Mail:{" "}
<br /> <a href="mailto:contact@kevink.dev">
</p> contact@kevink.dev
</article> </a>
</section> <br />
</Layout> </p>
); </article>
} </section>
</Layout>
);
}

File diff suppressed because it is too large Load diff

View file

@ -1,94 +1,101 @@
import React from "react"; import React from "react";
import Layout from "../../layouts/default"; import Layout from "../../layouts/default";
import { Trans, useI18next } from "gatsby-plugin-react-i18next"; import { Trans, useI18next } from "gatsby-plugin-react-i18next";
import { graphql } from "gatsby"; import { graphql } from "gatsby";
export const query = graphql` export const query = graphql`
query($language: String!) { query ($language: String!) {
locales: allLocale(filter: { language: { eq: $language } }) { locales: allLocale(filter: { language: { eq: $language } }) {
edges { edges {
node { node {
ns ns
data data
language language
} }
} }
} }
} }
`; `;
export default function DisclaimerPage() { export default function DisclaimerPage() {
const { t } = useI18next(); const { t } = useI18next();
return ( return (
<Layout title={t("disclaimer")}> <Layout title={t("disclaimer")}>
<section> <section>
<article> <article>
<h1> <h1>
<Trans>disclaimer</Trans> <Trans>disclaimer</Trans>
</h1> </h1>
<h2>Haftung für Inhalte</h2> <h2>Haftung für Inhalte</h2>
<p> <p>
Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für
auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach eigene Inhalte auf diesen Seiten nach den allgemeinen
§§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir
verpflichtet, übermittelte oder gespeicherte fremde Informationen zu als Diensteanbieter jedoch nicht verpflichtet,
überwachen oder nach Umständen zu forschen, die auf eine übermittelte oder gespeicherte fremde Informationen zu
rechtswidrige Tätigkeit hinweisen. überwachen oder nach Umständen zu forschen, die auf eine
</p> rechtswidrige Tätigkeit hinweisen.
</p>
<p>
Verpflichtungen zur Entfernung oder Sperrung der Nutzung von <p>
Informationen nach den allgemeinen Gesetzen bleiben hiervon Verpflichtungen zur Entfernung oder Sperrung der Nutzung
unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem von Informationen nach den allgemeinen Gesetzen bleiben
Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei hiervon unberührt. Eine diesbezügliche Haftung ist
Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese jedoch erst ab dem Zeitpunkt der Kenntnis einer
Inhalte umgehend entfernen. konkreten Rechtsverletzung möglich. Bei Bekanntwerden
</p> von entsprechenden Rechtsverletzungen werden wir diese
Inhalte umgehend entfernen.
<h2>Haftung für Links</h2> </p>
<p> <h2>Haftung für Links</h2>
Unser Angebot enthält Links zu externen Websites Dritter, auf deren
Inhalte wir keinen Einfluss haben. Deshalb können wir für diese <p>
fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der Unser Angebot enthält Links zu externen Websites
verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber Dritter, auf deren Inhalte wir keinen Einfluss haben.
der Seiten verantwortlich. Die verlinkten Seiten wurden zum Deshalb können wir für diese fremden Inhalte auch keine
Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Gewähr übernehmen. Für die Inhalte der verlinkten Seiten
Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht ist stets der jeweilige Anbieter oder Betreiber der
erkennbar. Seiten verantwortlich. Die verlinkten Seiten wurden zum
</p> Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße
überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der
<p> Verlinkung nicht erkennbar.
Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist </p>
jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht
zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir <p>
derartige Links umgehend entfernen. Eine permanente inhaltliche Kontrolle der verlinkten
</p> Seiten ist jedoch ohne konkrete Anhaltspunkte einer
Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von
<h2>Urheberrecht</h2> Rechtsverletzungen werden wir derartige Links umgehend
entfernen.
<p> </p>
Die durch die Seitenbetreiber erstellten Inhalte und Werke auf
diesen Seiten unterliegen dem deutschen Urheberrecht. Die <h2>Urheberrecht</h2>
Vervielfältigung, Bearbeitung, Verbreitung und jede Art der
Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der <p>
schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Die durch die Seitenbetreiber erstellten Inhalte und
Downloads und Kopien dieser Seite sind nur für den privaten, nicht Werke auf diesen Seiten unterliegen dem deutschen
kommerziellen Gebrauch gestattet. Urheberrecht. Die Vervielfältigung, Bearbeitung,
</p> Verbreitung und jede Art der Verwertung außerhalb der
Grenzen des Urheberrechtes bedürfen der schriftlichen
<p> Zustimmung des jeweiligen Autors bzw. Erstellers.
Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt Downloads und Kopien dieser Seite sind nur für den
wurden, werden die Urheberrechte Dritter beachtet. Insbesondere privaten, nicht kommerziellen Gebrauch gestattet.
werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie </p>
trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten
wir um einen entsprechenden Hinweis. Bei Bekanntwerden von <p>
Rechtsverletzungen werden wir derartige Inhalte umgehend entfernen. Soweit die Inhalte auf dieser Seite nicht vom Betreiber
</p> erstellt wurden, werden die Urheberrechte Dritter
</article> beachtet. Insbesondere werden Inhalte Dritter als solche
</section> gekennzeichnet. Sollten Sie trotzdem auf eine
</Layout> Urheberrechtsverletzung aufmerksam werden, bitten wir um
); einen entsprechenden Hinweis. Bei Bekanntwerden von
} Rechtsverletzungen werden wir derartige Inhalte umgehend
entfernen.
</p>
</article>
</section>
</Layout>
);
}

View file

@ -1,88 +1,94 @@
import React from "react"; import React from "react";
import Layout from "../layouts/default"; import Layout from "../layouts/default";
import { Trans, Link, useI18next } from "gatsby-plugin-react-i18next"; import { Trans, Link, useI18next } from "gatsby-plugin-react-i18next";
import { graphql } from "gatsby"; import { graphql } from "gatsby";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import * as styles from "./projects.module.scss"; import * as styles from "./projects.module.scss";
export const query = graphql` export const query = graphql`
query GetProjects($language: String) { query GetProjects($language: String) {
allProjectsJson(filter: { lang: { eq: $language } }) { allProjectsJson(filter: { lang: { eq: $language } }) {
nodes { nodes {
lang lang
urlname urlname
name name
image { image {
childImageSharp { childImageSharp {
resize(width: 400, quality: 90) { resize(width: 400, quality: 90) {
src src
} }
} }
} }
shortDescription shortDescription
} }
} }
locales: allLocale(filter: { language: { eq: $language } }) { locales: allLocale(filter: { language: { eq: $language } }) {
edges { edges {
node { node {
ns ns
data data
language language
} }
} }
} }
} }
`; `;
const ProjectsPage = ({ data }) => { const ProjectsPage = ({ data }) => {
const { t } = useI18next(); const { t } = useI18next();
return ( return (
<Layout title={t("projects")} description={t("projectsDescription")}> <Layout title={t("projects")} description={t("projectsDescription")}>
<section> <section>
<article> <article>
<h1> <h1>
<Trans>projects</Trans> <Trans>projects</Trans>
</h1> </h1>
<p> <p>
<Trans>projectsDescription</Trans> <Trans>projectsDescription</Trans>
</p> </p>
<div className={styles.projectList}> <div className={styles.projectList}>
{data.allProjectsJson.nodes.map((project) => { {data.allProjectsJson.nodes.map((project) => {
return ( return (
<Link <Link
className={styles.projectCard} className={styles.projectCard}
key={project.lang + project.urlname} key={project.lang + project.urlname}
to={"/projects/" + project.urlname} to={"/projects/" + project.urlname}>
> <div
<div className={styles.projectCardImage}
className={styles.projectCardImage} style={{
style={{ backgroundImage:
backgroundImage: "url(" +
"url(" + project.image.childImageSharp.resize.src + ")", project.image.childImageSharp
}} .resize.src +
> ")",
<div className={styles.projectCardMeta}> }}>
<span className={styles.projectCardTitle}> <div className={styles.projectCardMeta}>
{project.name} <span
</span> className={
<span>{project.shortDescription}</span> styles.projectCardTitle
</div> }>
</div> {project.name}
</Link> </span>
); <span>
})} {project.shortDescription}
</div> </span>
</article> </div>
</section> </div>
</Layout> </Link>
); );
}; })}
</div>
ProjectsPage.propTypes = { </article>
data: PropTypes.object, </section>
}; </Layout>
);
export default ProjectsPage; };
ProjectsPage.propTypes = {
data: PropTypes.object,
};
export default ProjectsPage;

View file

@ -1,89 +1,89 @@
@import "../variables"; @import "../variables";
@import "../mixins"; @import "../mixins";
.projectList { .projectList {
@include flexList; @include flexList;
margin: 15px 0; margin: 15px 0;
} }
.projectCard { .projectCard {
@include cardGeneric; @include cardGeneric;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-grow: 1; flex-grow: 1;
width: 250px; width: 250px;
flex-shrink: 0; flex-shrink: 0;
.projectCardActivityIndicator { .projectCardActivityIndicator {
position: absolute; position: absolute;
margin: 12px; margin: 12px;
padding: 2px 5px; padding: 2px 5px;
border-radius: 3px; border-radius: 3px;
&.activityIndicatorGreen { &.activityIndicatorGreen {
background: #26de81; background: #26de81;
} }
&.activityIndicatorYellow { &.activityIndicatorYellow {
background: #f7b731; background: #f7b731;
} }
&.activityIndicatorRed { &.activityIndicatorRed {
background: #fc5c65; background: #fc5c65;
} }
&.activityIndicatorBlue { &.activityIndicatorBlue {
background: #45aaf2; background: #45aaf2;
} }
} }
.projectCardImage { .projectCardImage {
width: 100%; width: 100%;
height: 250px; height: 250px;
background-position: center; background-position: center;
background-size: cover; background-size: cover;
text-shadow: 0 0 10px black, 0 0 10px black, 0 0 20px black; text-shadow: 0 0 10px black, 0 0 10px black, 0 0 20px black;
} }
.projectCardMeta { .projectCardMeta {
padding: 10px; padding: 10px;
flex-grow: 1; flex-grow: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 10px; padding: 10px;
height: 100%; height: 100%;
background: linear-gradient(to bottom, transparent, black); background: linear-gradient(to bottom, transparent, black);
} }
.projectCardTitle { .projectCardTitle {
display: block; display: block;
font-size: 1.5em; font-size: 1.5em;
margin-top: auto; margin-top: auto;
} }
.projectCardCTA { .projectCardCTA {
display: block; display: block;
} }
.projectCardCTA a { .projectCardCTA a {
@include buttonBasic; @include buttonBasic;
} }
.projectCardCTAContainer { .projectCardCTAContainer {
display: flex; display: flex;
} }
@media (max-width: 900px) { @media (max-width: 900px) {
.projectCardCTAContainer { .projectCardCTAContainer {
flex-direction: column; flex-direction: column;
} }
.projectCardCTA:nth-child(2) { .projectCardCTA:nth-child(2) {
border-left: none; border-left: none;
} }
} }
.projectCardCTAContainer > * { .projectCardCTAContainer > * {
flex-grow: 1; flex-grow: 1;
} }
} }

View file

@ -1,82 +1,83 @@
import React from "react"; import React from "react";
import Layout from "../layouts/default"; import Layout from "../layouts/default";
import { Trans, Link, useI18next } from "gatsby-plugin-react-i18next"; import { Trans, Link, useI18next } from "gatsby-plugin-react-i18next";
import { graphql } from "gatsby"; import { graphql } from "gatsby";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import * as styles from "./social.module.scss"; import * as styles from "./social.module.scss";
export const query = graphql` export const query = graphql`
query AllSocialsQuery($language: String!) { query AllSocialsQuery($language: String!) {
allSocialsJson { allSocialsJson {
nodes { nodes {
image image
platformHandle platformHandle
platformName platformName
url url
} }
} }
locales: allLocale(filter: { language: { eq: $language } }) { locales: allLocale(filter: { language: { eq: $language } }) {
edges { edges {
node { node {
ns ns
data data
language language
} }
} }
} }
} }
`; `;
const SocialPage = ({ data }) => { const SocialPage = ({ data }) => {
const { t } = useI18next(); const { t } = useI18next();
return ( return (
<Layout title={t("social")} description={t("socialDescription")}> <Layout title={t("social")} description={t("socialDescription")}>
<section> <section>
<article> <article>
<h1> <h1>
<Trans>social</Trans> <Trans>social</Trans>
</h1> </h1>
<p> <p>
<Trans i18nKey="socialDescriptionWithLink"> <Trans i18nKey="socialDescriptionWithLink">
socialDescriptionWith<Link to="/friends">Link</Link> socialDescriptionWith<Link to="/friends">Link</Link>
</Trans> </Trans>
</p> </p>
<div className={styles.socialList}> <div className={styles.socialList}>
{data.allSocialsJson.nodes.map((social) => { {data.allSocialsJson.nodes.map((social) => {
return ( return (
<a <a
className={styles.socialCard} className={styles.socialCard}
href={social.url} href={social.url}
target="_blank" target="_blank"
rel="noreferrer me" rel="noreferrer me"
key={social.url} key={social.url}>
> <div
<div className={styles.socialImage}
className={styles.socialImage} style={{
style={{ backgroundImage: "url(" + social.image + ")" }} backgroundImage:
> "url(" + social.image + ")",
<span className={styles.socialName}> }}>
{social.platformName} <span className={styles.socialName}>
</span> {social.platformName}
<span className={styles.socialUsername}> </span>
{social.platformHandle} <span className={styles.socialUsername}>
</span> {social.platformHandle}
</div> </span>
</a> </div>
); </a>
})} );
</div> })}
</article> </div>
</section> </article>
</Layout> </section>
); </Layout>
}; );
};
SocialPage.propTypes = {
data: PropTypes.object.isRequired, SocialPage.propTypes = {
}; data: PropTypes.object.isRequired,
};
export default SocialPage;
export default SocialPage;

View file

@ -1,32 +1,32 @@
@import "../variables"; @import "../variables";
@import "../mixins"; @import "../mixins";
.socialList { .socialList {
@include flexList; @include flexList;
.socialCard { .socialCard {
@include cardGeneric; @include cardGeneric;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.socialImage { .socialImage {
width: 300px; width: 300px;
height: 300px; height: 300px;
background-position: center; background-position: center;
background-size: cover; background-size: cover;
display: flex; display: flex;
padding: 10px; padding: 10px;
flex-direction: column-reverse; flex-direction: column-reverse;
text-shadow: 0 0 10px black, 0 0 10px black, 0 0 20px black; text-shadow: 0 0 10px black, 0 0 10px black, 0 0 20px black;
.socialName { .socialName {
font-size: 2em; font-size: 2em;
margin-top: -5px; margin-top: -5px;
} }
.socialUsername { .socialUsername {
margin-top: auto; margin-top: auto;
} }
} }
} }
} }

View file

@ -1,122 +1,128 @@
import React from "react"; import React from "react";
import { graphql } from "gatsby"; import { graphql } from "gatsby";
import { Trans, useTranslation } from "gatsby-plugin-react-i18next"; import { Trans, useTranslation } from "gatsby-plugin-react-i18next";
import Layout from "../layouts/default"; import Layout from "../layouts/default";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import * as styles from "./project.module.scss"; import * as styles from "./project.module.scss";
import { MDXRenderer } from "gatsby-plugin-mdx"; import { MDXRenderer } from "gatsby-plugin-mdx";
export const query = graphql` export const query = graphql`
query GetProject($urlname: String!, $lang: String!, $language: String!) { query GetProject($urlname: String!, $lang: String!, $language: String!) {
allProjectsJson( allProjectsJson(
filter: { urlname: { eq: $urlname }, lang: { eq: $lang } } filter: { urlname: { eq: $urlname }, lang: { eq: $lang } }
) { ) {
nodes { nodes {
lang lang
urlname urlname
name name
links { links {
github github
website website
} }
image { image {
publicURL publicURL
} }
shortDescription shortDescription
} }
} }
locales: allLocale(filter: { language: { eq: $language } }) { locales: allLocale(filter: { language: { eq: $language } }) {
edges { edges {
node { node {
ns ns
data data
language language
} }
} }
} }
file( file(
sourceInstanceName: {eq: "projectTextblocks"}, relativeDirectory: {eq: $urlname}, name: {eq: $language} sourceInstanceName: { eq: "projectTextblocks" }
) { relativeDirectory: { eq: $urlname }
id name: { eq: $language }
childMdx { ) {
body id
} childMdx {
name body
} }
} name
`; }
}
const ProjectTemplate = ({ data }) => { `;
const { t } = useTranslation();
let project = data.allProjectsJson.nodes[0]; const ProjectTemplate = ({ data }) => {
let projectName = project.name; const { t } = useTranslation();
let file = data.file; let project = data.allProjectsJson.nodes[0];
let projectName = project.name;
return ( let file = data.file;
<Layout
description={project.shortDescription} return (
title={t("project") + ": " + projectName} <Layout
transparentTopbar={true} description={project.shortDescription}
> title={t("project") + ": " + projectName}
<section className={styles.projectHeader}> transparentTopbar={true}>
<div style={{ paddingTop: 0 }}> <section className={styles.projectHeader}>
<div <div style={{ paddingTop: 0 }}>
className={styles.headerBackground} <div
style={{ backgroundImage: "url(" + project.image.publicURL + ")" }} className={styles.headerBackground}
></div> style={{
<header> backgroundImage:
<div className={styles.headerInner}> "url(" + project.image.publicURL + ")",
<h1> }}></div>
<Trans>project</Trans>: {projectName} <header>
</h1> <div className={styles.headerInner}>
<span>{project.shortDescription}</span> <h1>
</div> <Trans>project</Trans>: {projectName}
</header> </h1>
<div className={styles.headerPlaceholder}></div> <span>{project.shortDescription}</span>
</div> </div>
</section> </header>
{file != null && file.childMdx != null ? ( <div className={styles.headerPlaceholder}></div>
<section className={styles.projectAbout}> </div>
<article> </section>
<MDXRenderer>{file.childMdx.body}</MDXRenderer> {file != null && file.childMdx != null ? (
</article> <section className={styles.projectAbout}>
</section> <article>
) : null} <MDXRenderer>{file.childMdx.body}</MDXRenderer>
{project.links !== null ? ( </article>
<section className={styles.projectLinks}> </section>
<div> ) : null}
<h1>Links</h1> {project.links !== null ? (
<div className={styles.linkList}> <section className={styles.projectLinks}>
{project.links.github !== null ? ( <div>
<a href={project.links.github} target="_blank" rel="noreferrer"> <h1>Links</h1>
<i className="fab fa-github" aria-hidden="true"></i>{" "} <div className={styles.linkList}>
<Trans>projectViewGitHub</Trans> {project.links.github !== null ? (
</a> <a
) : null} href={project.links.github}
{project.links.website !== null ? ( target="_blank"
<a rel="noreferrer">
href={project.links.website} <i
target="_blank" className="fab fa-github"
rel="noreferrer" aria-hidden="true"></i>{" "}
> <Trans>projectViewGitHub</Trans>
<i </a>
className="fas fa-external-link-alt" ) : null}
aria-hidden="true" {project.links.website !== null ? (
></i>{" "} <a
<Trans>projectViewWebsite</Trans> href={project.links.website}
</a> target="_blank"
) : null} rel="noreferrer">
</div> <i
</div> className="fas fa-external-link-alt"
</section> aria-hidden="true"></i>{" "}
) : null} <Trans>projectViewWebsite</Trans>
</Layout> </a>
); ) : null}
}; </div>
</div>
ProjectTemplate.propTypes = { </section>
data: PropTypes.object.isRequired, ) : null}
}; </Layout>
);
export default ProjectTemplate; };
ProjectTemplate.propTypes = {
data: PropTypes.object.isRequired,
};
export default ProjectTemplate;

View file

@ -1,99 +1,99 @@
@import "../variables"; @import "../variables";
.projectHeader { .projectHeader {
> div { > div {
padding-bottom: 0 !important; padding-bottom: 0 !important;
} }
.headerBackground { .headerBackground {
position: absolute; position: absolute;
left: 0; left: 0;
width: 100%; width: 100%;
height: 400px; height: 400px;
background-position: center; background-position: center;
background-size: cover; background-size: cover;
} }
header { header {
position: absolute; position: absolute;
left: 0; left: 0;
width: 100%; width: 100%;
height: 400px; height: 400px;
background: linear-gradient( background: linear-gradient(
to bottom, to bottom,
rgba($background, 0.95), rgba($background, 0.95),
rgba($background, 0.25) 20%, rgba($background, 0.25) 20%,
rgba($background, 0.35) 80%, rgba($background, 0.35) 80%,
rgba($background, 1) 100% rgba($background, 1) 100%
); );
.headerInner { .headerInner {
max-width: $layoutWidth; max-width: $layoutWidth;
width: 100%; width: 100%;
height: 100%; height: 100%;
margin: 0 auto; margin: 0 auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
text-shadow: 0 0 10px black, 0 0 20px black; text-shadow: 0 0 10px black, 0 0 20px black;
padding: 10px 20px; padding: 10px 20px;
* { * {
margin: 0; margin: 0;
color: white; color: white;
font-size: 1.25em; font-size: 1.25em;
} }
h1 { h1 {
font-size: 2.2em; font-size: 2.2em;
margin-top: auto; margin-top: auto;
} }
} }
} }
.headerPlaceholder { .headerPlaceholder {
width: 100%; width: 100%;
height: 400px; height: 400px;
} }
} }
.projectAbout, .projectAbout,
.projectLinks { .projectLinks {
&:nth-of-type(2) { &:nth-of-type(2) {
> div, > div,
> article { > article {
padding-top: 20px; padding-top: 20px;
} }
} }
} }
.projectAbout { .projectAbout {
background: #060606; background: #060606;
color: white; color: white;
} }
.projectLinks { .projectLinks {
.linkList { .linkList {
display: flex; display: flex;
justify-content: center; justify-content: center;
flex-wrap: wrap; flex-wrap: wrap;
} }
a { a {
display: inline-block; display: inline-block;
border: thin solid rgb(200, 200, 200); border: thin solid rgb(200, 200, 200);
border-radius: 5px; border-radius: 5px;
padding: 10px 15px; padding: 10px 15px;
margin: 5px; margin: 5px;
color: $textColor; color: $textColor;
text-decoration-skip: none; text-decoration-skip: none;
text-decoration: underline dotted currentColor; text-decoration: underline dotted currentColor;
i.fab, i.fab,
i.fas, i.fas,
i.fa, i.fa,
i.far, i.far,
i.fal { i.fal {
display: inline; display: inline;
} }
} }
} }