mirror of
https://github.com/Unkn0wnCat/KevinK.dev.js.git
synced 2025-05-10 07:26:57 +02:00
Configure & Run prettier
This commit is contained in:
parent
79ab0bb9af
commit
420f8930fd
66 changed files with 31825 additions and 31500 deletions
|
@ -28,11 +28,9 @@
|
|||
"EditorConfig.EditorConfig"
|
||||
],
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
"forwardPorts": [
|
||||
8000
|
||||
],
|
||||
"forwardPorts": [8000],
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": "npm install",
|
||||
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||
"remoteUser": "node"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
||||
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.
|
||||
|
|
23
.eslintrc
23
.eslintrc
|
@ -1,15 +1,12 @@
|
|||
{
|
||||
"parser": "babel-eslint",
|
||||
"rules": {
|
||||
"strict": 0
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:react/recommended"
|
||||
],
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "detect"
|
||||
"parser": "babel-eslint",
|
||||
"rules": {
|
||||
"strict": 0
|
||||
},
|
||||
"extends": ["eslint:recommended", "plugin:react/recommended"],
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "detect"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
42
.github/workflows/build.yaml
vendored
42
.github/workflows/build.yaml
vendored
|
@ -1,30 +1,30 @@
|
|||
name: Build Site
|
||||
|
||||
on:
|
||||
push:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
update:
|
||||
name: Build Site
|
||||
runs-on: ubuntu-latest
|
||||
update:
|
||||
name: Build Site
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout Repo
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
name: Checkout Repo
|
||||
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '12.x'
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: "12.x"
|
||||
|
||||
- run: npm install
|
||||
name: Install Dependencies
|
||||
- run: npm install
|
||||
name: Install Dependencies
|
||||
|
||||
- run: npm run build
|
||||
name: Build Site
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
name: Upload Artifacts
|
||||
with:
|
||||
name: site
|
||||
path: public
|
||||
- run: npm run build
|
||||
name: Build Site
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
name: Upload Artifacts
|
||||
with:
|
||||
name: site
|
||||
path: public
|
||||
|
|
4
.prettierignore
Normal file
4
.prettierignore
Normal file
|
@ -0,0 +1,4 @@
|
|||
/.cache
|
||||
/.vscode
|
||||
/node_modules
|
||||
/public
|
8
.prettierrc.json
Normal file
8
.prettierrc.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 4,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"jsxBracketSameLine": true,
|
||||
"endOfLine": "lf"
|
||||
}
|
14
README.md
14
README.md
|
@ -1,7 +1,7 @@
|
|||
# KevinK.dev.js
|
||||
|
||||

|
||||
|
||||
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.
|
||||
# KevinK.dev.js
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
|
36
config.js
36
config.js
|
@ -1,18 +1,18 @@
|
|||
// eslint-disable-next-line no-undef
|
||||
module.exports = {
|
||||
siteName: "KevinK.dev",
|
||||
siteAuthor: "@Unkn0wnKevin",
|
||||
siteURL: "https://kevink.dev",
|
||||
payPalMail: "kevin@1in9.net",
|
||||
siteKeywords:
|
||||
"Kevin Kandlbinder, Kevin, Kandlbinder, Web, Web Developer, Developer, JavaScript, PHP, Java, Photos, Fotos",
|
||||
iconPath: "src/images/fullbglogo@10x.png",
|
||||
languages: ["en", "de"],
|
||||
contactEmail: "kevin@kevink.dev",
|
||||
contactPhone: "+4941068068004",
|
||||
mapsLink: "https://goo.gl/maps/KVq9z1PVaVP2",
|
||||
contactTwitter: "Unkn0wnKevin",
|
||||
contactGitHub: "Unkn0wnCat",
|
||||
contactMastodon: "@kevin@1in1.net",
|
||||
contactMastodonHref: "https://mastodon.1in1.net/@kevin",
|
||||
};
|
||||
// eslint-disable-next-line no-undef
|
||||
module.exports = {
|
||||
siteName: "KevinK.dev",
|
||||
siteAuthor: "@Unkn0wnKevin",
|
||||
siteURL: "https://kevink.dev",
|
||||
payPalMail: "kevin@1in9.net",
|
||||
siteKeywords:
|
||||
"Kevin Kandlbinder, Kevin, Kandlbinder, Web, Web Developer, Developer, JavaScript, PHP, Java, Photos, Fotos",
|
||||
iconPath: "src/images/fullbglogo@10x.png",
|
||||
languages: ["en", "de"],
|
||||
contactEmail: "kevin@kevink.dev",
|
||||
contactPhone: "+4941068068004",
|
||||
mapsLink: "https://goo.gl/maps/KVq9z1PVaVP2",
|
||||
contactTwitter: "Unkn0wnKevin",
|
||||
contactGitHub: "Unkn0wnCat",
|
||||
contactMastodon: "@kevin@1in1.net",
|
||||
contactMastodonHref: "https://mastodon.1in1.net/@kevin",
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"profession": "Full-Stack-Developer",
|
||||
"name": "Feuerhamster",
|
||||
"url": "https://hamsterlabs.de",
|
||||
"imageURL": "https://cdn.kevink.dev/assets/friends/feuerhamster.png"
|
||||
}
|
||||
{
|
||||
"profession": "Full-Stack-Developer",
|
||||
"name": "Feuerhamster",
|
||||
"url": "https://hamsterlabs.de",
|
||||
"imageURL": "https://cdn.kevink.dev/assets/friends/feuerhamster.png"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"profession": "Photographer",
|
||||
"name": "Jannik Kiel",
|
||||
"url": "https://unsplash.com/@jannikkiel",
|
||||
"imageURL": "https://source.unsplash.com/user/jannikkiel/300x300"
|
||||
}
|
||||
{
|
||||
"profession": "Photographer",
|
||||
"name": "Jannik Kiel",
|
||||
"url": "https://unsplash.com/@jannikkiel",
|
||||
"imageURL": "https://source.unsplash.com/user/jannikkiel/300x300"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"profession": "Filmmaker",
|
||||
"name": "Max Christian Rüster",
|
||||
"url": "https://maxchristian.de/",
|
||||
"imageURL": "https://cdn.kevink.dev/assets/friends/max_ruester.jpg"
|
||||
}
|
||||
{
|
||||
"profession": "Filmmaker",
|
||||
"name": "Max Christian Rüster",
|
||||
"url": "https://maxchristian.de/",
|
||||
"imageURL": "https://cdn.kevink.dev/assets/friends/max_ruester.jpg"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"profession": "System Administrator",
|
||||
"name": "Timo Strüker",
|
||||
"url": "https://strueker.dev",
|
||||
"imageURL": "https://cdn.kevink.dev/assets/friends/timo.jpg"
|
||||
}
|
||||
{
|
||||
"profession": "System Administrator",
|
||||
"name": "Timo Strüker",
|
||||
"url": "https://strueker.dev",
|
||||
"imageURL": "https://cdn.kevink.dev/assets/friends/timo.jpg"
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# Ü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!
|
||||
# Ü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!
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# 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!
|
||||
# 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!
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# Ü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.
|
||||
# Ü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.
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# 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.
|
||||
# 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.
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"urlname": "foobar",
|
||||
"lang": "ignoreme",
|
||||
"name": "foobar",
|
||||
"shortDescription": "foobar",
|
||||
"links": {
|
||||
"website": "https://foo.bar",
|
||||
"github": "https://foo.bar"
|
||||
},
|
||||
"image": "../images/test.jpg",
|
||||
"featured": 0
|
||||
}
|
||||
{
|
||||
"urlname": "foobar",
|
||||
"lang": "ignoreme",
|
||||
"name": "foobar",
|
||||
"shortDescription": "foobar",
|
||||
"links": {
|
||||
"website": "https://foo.bar",
|
||||
"github": "https://foo.bar"
|
||||
},
|
||||
"image": "../images/test.jpg",
|
||||
"featured": 0
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"urlname": "else",
|
||||
"lang": "de",
|
||||
"name": "Schülerzeitung \"ELSE\"",
|
||||
"shortDescription": "Eine News-Seite für die Schülerzeitung meiner Schule.",
|
||||
"links": {
|
||||
"website": "https://schuelerzeitung-elsensee.de"
|
||||
},
|
||||
"image": "../images/ELSE.jpg",
|
||||
"featured": 2
|
||||
}
|
||||
{
|
||||
"urlname": "else",
|
||||
"lang": "de",
|
||||
"name": "Schülerzeitung \"ELSE\"",
|
||||
"shortDescription": "Eine News-Seite für die Schülerzeitung meiner Schule.",
|
||||
"links": {
|
||||
"website": "https://schuelerzeitung-elsensee.de"
|
||||
},
|
||||
"image": "../images/ELSE.jpg",
|
||||
"featured": 2
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"urlname": "else",
|
||||
"lang": "en",
|
||||
"name": "Student Newspaper \"ELSE\"",
|
||||
"shortDescription": "A news-site for the my schools school paper.",
|
||||
"links": {
|
||||
"website": "https://schuelerzeitung-elsensee.de"
|
||||
},
|
||||
"image": "../images/ELSE.jpg",
|
||||
"featured": 2
|
||||
}
|
||||
{
|
||||
"urlname": "else",
|
||||
"lang": "en",
|
||||
"name": "Student Newspaper \"ELSE\"",
|
||||
"shortDescription": "A news-site for the my schools school paper.",
|
||||
"links": {
|
||||
"website": "https://schuelerzeitung-elsensee.de"
|
||||
},
|
||||
"image": "../images/ELSE.jpg",
|
||||
"featured": 2
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"urlname": "kevink-dev",
|
||||
"lang": "de",
|
||||
"name": "KevinK.dev",
|
||||
"shortDescription": "Diese Seite und der Code dahinter.",
|
||||
"links": {
|
||||
"website": "https://kevink.dev",
|
||||
"github": "https://github.com/Unkn0wnCat/KevinK.dev.js"
|
||||
},
|
||||
"image": "../images/KevinK.dev.jpg",
|
||||
"featured": 0
|
||||
}
|
||||
{
|
||||
"urlname": "kevink-dev",
|
||||
"lang": "de",
|
||||
"name": "KevinK.dev",
|
||||
"shortDescription": "Diese Seite und der Code dahinter.",
|
||||
"links": {
|
||||
"website": "https://kevink.dev",
|
||||
"github": "https://github.com/Unkn0wnCat/KevinK.dev.js"
|
||||
},
|
||||
"image": "../images/KevinK.dev.jpg",
|
||||
"featured": 0
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"urlname": "kevink-dev",
|
||||
"lang": "en",
|
||||
"name": "KevinK.dev",
|
||||
"shortDescription": "This site and the code behind the scenes.",
|
||||
"links": {
|
||||
"website": "https://kevink.dev",
|
||||
"github": "https://github.com/Unkn0wnCat/KevinK.dev.js"
|
||||
},
|
||||
"image": "../images/KevinK.dev.jpg",
|
||||
"featured": 0
|
||||
}
|
||||
{
|
||||
"urlname": "kevink-dev",
|
||||
"lang": "en",
|
||||
"name": "KevinK.dev",
|
||||
"shortDescription": "This site and the code behind the scenes.",
|
||||
"links": {
|
||||
"website": "https://kevink.dev",
|
||||
"github": "https://github.com/Unkn0wnCat/KevinK.dev.js"
|
||||
},
|
||||
"image": "../images/KevinK.dev.jpg",
|
||||
"featured": 0
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"urlname": "kreig",
|
||||
"lang": "de",
|
||||
"name": "KREIG.de",
|
||||
"shortDescription": "Eine einfache aber schöne Gaming-Seite.",
|
||||
"links": {
|
||||
"website": "https://kreig.de"
|
||||
},
|
||||
"image": "../images/KREIG.de.jpg",
|
||||
"featured": 1
|
||||
}
|
||||
{
|
||||
"urlname": "kreig",
|
||||
"lang": "de",
|
||||
"name": "KREIG.de",
|
||||
"shortDescription": "Eine einfache aber schöne Gaming-Seite.",
|
||||
"links": {
|
||||
"website": "https://kreig.de"
|
||||
},
|
||||
"image": "../images/KREIG.de.jpg",
|
||||
"featured": 1
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"urlname": "kreig",
|
||||
"lang": "en",
|
||||
"name": "KREIG.de",
|
||||
"shortDescription": "A simple but nice gaming website.",
|
||||
"links": {
|
||||
"website": "https://kreig.de"
|
||||
},
|
||||
"image": "../images/KREIG.de.jpg",
|
||||
"featured": 1
|
||||
}
|
||||
{
|
||||
"urlname": "kreig",
|
||||
"lang": "en",
|
||||
"name": "KREIG.de",
|
||||
"shortDescription": "A simple but nice gaming website.",
|
||||
"links": {
|
||||
"website": "https://kreig.de"
|
||||
},
|
||||
"image": "../images/KREIG.de.jpg",
|
||||
"featured": 1
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"platformName": "Blog",
|
||||
"platformHandle": "@kevin@blog.1in9.net",
|
||||
"url": "https://blog.1in9.net/~/Kevin",
|
||||
"image": "https://source.unsplash.com/xG8IQMqMITM/300x300"
|
||||
}
|
||||
{
|
||||
"platformName": "Blog",
|
||||
"platformHandle": "@kevin@blog.1in9.net",
|
||||
"url": "https://blog.1in9.net/~/Kevin",
|
||||
"image": "https://source.unsplash.com/xG8IQMqMITM/300x300"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"platformName": "GitHub",
|
||||
"platformHandle": "@Unkn0wnCat",
|
||||
"url": "https://github.com/Unkn0wnCat",
|
||||
"image": "https://source.unsplash.com/842ofHC6MaI/300x300"
|
||||
}
|
||||
{
|
||||
"platformName": "GitHub",
|
||||
"platformHandle": "@Unkn0wnCat",
|
||||
"url": "https://github.com/Unkn0wnCat",
|
||||
"image": "https://source.unsplash.com/842ofHC6MaI/300x300"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"platformName": "Mastodon",
|
||||
"platformHandle": "@kevin@1in1.net",
|
||||
"url": "https://mastodon.1in1.net/@kevin",
|
||||
"image": "https://source.unsplash.com/8bghKxNU1j0/300x300"
|
||||
}
|
||||
{
|
||||
"platformName": "Mastodon",
|
||||
"platformHandle": "@kevin@1in1.net",
|
||||
"url": "https://mastodon.1in1.net/@kevin",
|
||||
"image": "https://source.unsplash.com/8bghKxNU1j0/300x300"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"platformName": "Matrix",
|
||||
"platformHandle": "@kevin:1in1.net",
|
||||
"url": "https://matrix.to/#/@kevin:1in1.net",
|
||||
"image": "https://source.unsplash.com/Zq6HerrBPEs/300x300"
|
||||
}
|
||||
{
|
||||
"platformName": "Matrix",
|
||||
"platformHandle": "@kevin:1in1.net",
|
||||
"url": "https://matrix.to/#/@kevin:1in1.net",
|
||||
"image": "https://source.unsplash.com/Zq6HerrBPEs/300x300"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"platformName": "Unkn0wnCat.net",
|
||||
"platformHandle": "Gaming",
|
||||
"url": "https://unkn0wncat.net",
|
||||
"image": "https://source.unsplash.com/nCU4yq5xDEQ/300x300"
|
||||
}
|
||||
{
|
||||
"platformName": "Unkn0wnCat.net",
|
||||
"platformHandle": "Gaming",
|
||||
"url": "https://unkn0wncat.net",
|
||||
"image": "https://source.unsplash.com/nCU4yq5xDEQ/300x300"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"platformName": "Twitter",
|
||||
"platformHandle": "@Unkn0wnKevin",
|
||||
"url": "https://twitter.com/@Unkn0wnKevin",
|
||||
"image": "https://source.unsplash.com/RnW1taVZqm8/300x300"
|
||||
}
|
||||
{
|
||||
"platformName": "Twitter",
|
||||
"platformHandle": "@Unkn0wnKevin",
|
||||
"url": "https://twitter.com/@Unkn0wnKevin",
|
||||
"image": "https://source.unsplash.com/RnW1taVZqm8/300x300"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"platformName": "Unsplash",
|
||||
"platformHandle": "@Unkn0wnCat",
|
||||
"url": "https://unsplash.com/@unkn0wncat",
|
||||
"image": "https://source.unsplash.com/user/unkn0wncat/300x300"
|
||||
}
|
||||
{
|
||||
"platformName": "Unsplash",
|
||||
"platformHandle": "@Unkn0wnCat",
|
||||
"url": "https://unsplash.com/@unkn0wncat",
|
||||
"image": "https://source.unsplash.com/user/unkn0wncat/300x300"
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# 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.
|
||||
# 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.
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# 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.
|
||||
# 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.
|
||||
|
|
220
gatsby-config.js
220
gatsby-config.js
|
@ -1,107 +1,113 @@
|
|||
/* eslint-disable no-undef */
|
||||
const extConfig = require("./config");
|
||||
|
||||
module.exports = {
|
||||
siteMetadata: {
|
||||
title: extConfig.siteName,
|
||||
author: extConfig.siteAuthor,
|
||||
siteUrl: extConfig.siteURL,
|
||||
keywords: extConfig.siteKeywords,
|
||||
payPalMail: extConfig.payPalMail,
|
||||
contactEmail: extConfig.contactEmail,
|
||||
contactPhone: extConfig.contactPhone,
|
||||
mapsLink: extConfig.mapsLink,
|
||||
contactTwitter: extConfig.contactTwitter,
|
||||
contactGitHub: extConfig.contactGitHub,
|
||||
contactMastodon: extConfig.contactMastodon,
|
||||
contactMastodonHref: extConfig.contactMastodonHref,
|
||||
},
|
||||
assetPrefix: "/assets",
|
||||
plugins: [
|
||||
`gatsby-plugin-eslint`,
|
||||
{
|
||||
resolve: "gatsby-plugin-asset-path",
|
||||
},
|
||||
`gatsby-plugin-sharp`,
|
||||
`gatsby-transformer-sharp`,
|
||||
`gatsby-transformer-json`,
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
path: `${__dirname}/content/textblocks`,
|
||||
name: `textblocks`,
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
path: `${__dirname}/content/projectTextblocks`,
|
||||
name: `projectTextblocks`,
|
||||
},
|
||||
},
|
||||
"gatsby-plugin-mdx",
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
path: `./content/`,
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
path: `${__dirname}/locales`,
|
||||
name: `locale`,
|
||||
},
|
||||
},
|
||||
`gatsby-plugin-sass`,
|
||||
{
|
||||
resolve: `gatsby-plugin-manifest`,
|
||||
options: {
|
||||
name: extConfig.siteName,
|
||||
short_name: extConfig.siteName,
|
||||
start_url: `/`,
|
||||
background_color: `#000710`,
|
||||
theme_color: `#000710`,
|
||||
display: `minimal-ui`,
|
||||
icon: extConfig.iconPath, // This path is relative to the root of the site.
|
||||
cache_busting_mode: "none",
|
||||
},
|
||||
},
|
||||
`gatsby-plugin-robots-txt`,
|
||||
{
|
||||
resolve: `gatsby-plugin-offline`,
|
||||
options: {
|
||||
precachePages: ["/", "/en", "/en/projects", "/de", "/de/projects"],
|
||||
workboxConfig: {
|
||||
globPatterns: ["**/*"],
|
||||
},
|
||||
},
|
||||
},
|
||||
`gatsby-plugin-sitemap`,
|
||||
`gatsby-plugin-react-helmet`,
|
||||
{
|
||||
resolve: `gatsby-plugin-react-i18next`,
|
||||
options: {
|
||||
localeJsonSourceName: `locale`,
|
||||
languages: extConfig.languages,
|
||||
defaultLanguage: `en`,
|
||||
generateDefaultLanguagePage: true,
|
||||
siteUrl: extConfig.siteURL,
|
||||
i18nextOptions: {
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
},
|
||||
keySeparator: false,
|
||||
nsSeparator: false,
|
||||
},
|
||||
pages: [
|
||||
{
|
||||
matchPath: "/:lang/projects/:urlname",
|
||||
getLanguageFromPath: true,
|
||||
excludeLanguages: extConfig.languages,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
/* eslint-disable no-undef */
|
||||
const extConfig = require("./config");
|
||||
|
||||
module.exports = {
|
||||
siteMetadata: {
|
||||
title: extConfig.siteName,
|
||||
author: extConfig.siteAuthor,
|
||||
siteUrl: extConfig.siteURL,
|
||||
keywords: extConfig.siteKeywords,
|
||||
payPalMail: extConfig.payPalMail,
|
||||
contactEmail: extConfig.contactEmail,
|
||||
contactPhone: extConfig.contactPhone,
|
||||
mapsLink: extConfig.mapsLink,
|
||||
contactTwitter: extConfig.contactTwitter,
|
||||
contactGitHub: extConfig.contactGitHub,
|
||||
contactMastodon: extConfig.contactMastodon,
|
||||
contactMastodonHref: extConfig.contactMastodonHref,
|
||||
},
|
||||
assetPrefix: "/assets",
|
||||
plugins: [
|
||||
`gatsby-plugin-eslint`,
|
||||
{
|
||||
resolve: "gatsby-plugin-asset-path",
|
||||
},
|
||||
`gatsby-plugin-sharp`,
|
||||
`gatsby-transformer-sharp`,
|
||||
`gatsby-transformer-json`,
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
path: `${__dirname}/content/textblocks`,
|
||||
name: `textblocks`,
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
path: `${__dirname}/content/projectTextblocks`,
|
||||
name: `projectTextblocks`,
|
||||
},
|
||||
},
|
||||
"gatsby-plugin-mdx",
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
path: `./content/`,
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
path: `${__dirname}/locales`,
|
||||
name: `locale`,
|
||||
},
|
||||
},
|
||||
`gatsby-plugin-sass`,
|
||||
{
|
||||
resolve: `gatsby-plugin-manifest`,
|
||||
options: {
|
||||
name: extConfig.siteName,
|
||||
short_name: extConfig.siteName,
|
||||
start_url: `/`,
|
||||
background_color: `#000710`,
|
||||
theme_color: `#000710`,
|
||||
display: `minimal-ui`,
|
||||
icon: extConfig.iconPath, // This path is relative to the root of the site.
|
||||
cache_busting_mode: "none",
|
||||
},
|
||||
},
|
||||
`gatsby-plugin-robots-txt`,
|
||||
{
|
||||
resolve: `gatsby-plugin-offline`,
|
||||
options: {
|
||||
precachePages: [
|
||||
"/",
|
||||
"/en",
|
||||
"/en/projects",
|
||||
"/de",
|
||||
"/de/projects",
|
||||
],
|
||||
workboxConfig: {
|
||||
globPatterns: ["**/*"],
|
||||
},
|
||||
},
|
||||
},
|
||||
`gatsby-plugin-sitemap`,
|
||||
`gatsby-plugin-react-helmet`,
|
||||
{
|
||||
resolve: `gatsby-plugin-react-i18next`,
|
||||
options: {
|
||||
localeJsonSourceName: `locale`,
|
||||
languages: extConfig.languages,
|
||||
defaultLanguage: `en`,
|
||||
generateDefaultLanguagePage: true,
|
||||
siteUrl: extConfig.siteURL,
|
||||
i18nextOptions: {
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
},
|
||||
keySeparator: false,
|
||||
nsSeparator: false,
|
||||
},
|
||||
pages: [
|
||||
{
|
||||
matchPath: "/:lang/projects/:urlname",
|
||||
getLanguageFromPath: true,
|
||||
excludeLanguages: extConfig.languages,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
353
gatsby-node.js
353
gatsby-node.js
|
@ -1,174 +1,179 @@
|
|||
/* eslint-disable no-undef */
|
||||
const path = require(`path`);
|
||||
const fs = require("fs");
|
||||
|
||||
exports.createPages = async ({ actions, graphql, reporter }) => {
|
||||
const { createPage } = actions;
|
||||
|
||||
const projectTemplate = path.resolve(`src/templates/project.js`);
|
||||
|
||||
const result = await graphql(`
|
||||
query AllPagesQuery {
|
||||
allProjectsJson {
|
||||
nodes {
|
||||
lang
|
||||
urlname
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
if (result.errors) {
|
||||
reporter.panicOnBuild(`Error while running GraphQL query.`);
|
||||
return;
|
||||
}
|
||||
|
||||
result.data.allProjectsJson.nodes.forEach((node) => {
|
||||
// eslint-disable-next-line no-undef
|
||||
console.log("Creating Page: ", `/${node.lang}/projects/${node.urlname}`);
|
||||
|
||||
if (node.lang !== "ignoreme")
|
||||
createPage({
|
||||
path: `/${node.lang}/projects/${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 apiPrefix = "./public/api";
|
||||
|
||||
if (!fs.existsSync(apiPrefix)) fs.mkdirSync(apiPrefix);
|
||||
|
||||
fs.writeFileSync(
|
||||
`${apiPrefix}.json`,
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
endpoints: {
|
||||
projects: [
|
||||
{
|
||||
name: "Projects Overview",
|
||||
description: "Returns overview of all available projects",
|
||||
path: "/api/projects.json",
|
||||
},
|
||||
{
|
||||
name: "Projects Overview for Language",
|
||||
description:
|
||||
"Returns overview of all available projects in a specified language",
|
||||
path: "/api/projects/:lang.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 {
|
||||
allProjectsJson {
|
||||
nodes {
|
||||
urlname
|
||||
shortDescription
|
||||
name
|
||||
links {
|
||||
github
|
||||
website
|
||||
}
|
||||
lang
|
||||
image {
|
||||
publicURL
|
||||
}
|
||||
featured
|
||||
}
|
||||
}
|
||||
}
|
||||
`).then((res) => {
|
||||
if (res.errors) {
|
||||
reporter.panicOnBuild(`Error while running GraphQL query.`);
|
||||
return;
|
||||
}
|
||||
|
||||
let projects = res.data.allProjectsJson.nodes.filter((project) => {
|
||||
return project.lang !== "ignoreme";
|
||||
});
|
||||
|
||||
fs.writeFileSync(
|
||||
`${projectsPrefix}.json`,
|
||||
JSON.stringify({
|
||||
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`,
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
projects: projects
|
||||
.filter((project) => {
|
||||
return project.lang == lang;
|
||||
})
|
||||
.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: {
|
||||
slug: project.urlname,
|
||||
lang: project.lang,
|
||||
name: project.name,
|
||||
shortDescription: project.shortDescription,
|
||||
longDescription: project.longDescription,
|
||||
links:
|
||||
project.links !== null
|
||||
? {
|
||||
github: project.links.github,
|
||||
website: project.links.website,
|
||||
}
|
||||
: null,
|
||||
image: project.image.publicURL,
|
||||
featured: project.featured,
|
||||
frontend: `/${project.lang}/projects/${project.urlname}`,
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
/* eslint-disable no-undef */
|
||||
const path = require(`path`);
|
||||
const fs = require("fs");
|
||||
|
||||
exports.createPages = async ({ actions, graphql, reporter }) => {
|
||||
const { createPage } = actions;
|
||||
|
||||
const projectTemplate = path.resolve(`src/templates/project.js`);
|
||||
|
||||
const result = await graphql(`
|
||||
query AllPagesQuery {
|
||||
allProjectsJson {
|
||||
nodes {
|
||||
lang
|
||||
urlname
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
if (result.errors) {
|
||||
reporter.panicOnBuild(`Error while running GraphQL query.`);
|
||||
return;
|
||||
}
|
||||
|
||||
result.data.allProjectsJson.nodes.forEach((node) => {
|
||||
// eslint-disable-next-line no-undef
|
||||
console.log(
|
||||
"Creating Page: ",
|
||||
`/${node.lang}/projects/${node.urlname}`
|
||||
);
|
||||
|
||||
if (node.lang !== "ignoreme")
|
||||
createPage({
|
||||
path: `/${node.lang}/projects/${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 apiPrefix = "./public/api";
|
||||
|
||||
if (!fs.existsSync(apiPrefix)) fs.mkdirSync(apiPrefix);
|
||||
|
||||
fs.writeFileSync(
|
||||
`${apiPrefix}.json`,
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
endpoints: {
|
||||
projects: [
|
||||
{
|
||||
name: "Projects Overview",
|
||||
description:
|
||||
"Returns overview of all available projects",
|
||||
path: "/api/projects.json",
|
||||
},
|
||||
{
|
||||
name: "Projects Overview for Language",
|
||||
description:
|
||||
"Returns overview of all available projects in a specified language",
|
||||
path: "/api/projects/:lang.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 {
|
||||
allProjectsJson {
|
||||
nodes {
|
||||
urlname
|
||||
shortDescription
|
||||
name
|
||||
links {
|
||||
github
|
||||
website
|
||||
}
|
||||
lang
|
||||
image {
|
||||
publicURL
|
||||
}
|
||||
featured
|
||||
}
|
||||
}
|
||||
}
|
||||
`).then((res) => {
|
||||
if (res.errors) {
|
||||
reporter.panicOnBuild(`Error while running GraphQL query.`);
|
||||
return;
|
||||
}
|
||||
|
||||
let projects = res.data.allProjectsJson.nodes.filter((project) => {
|
||||
return project.lang !== "ignoreme";
|
||||
});
|
||||
|
||||
fs.writeFileSync(
|
||||
`${projectsPrefix}.json`,
|
||||
JSON.stringify({
|
||||
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`,
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
projects: projects
|
||||
.filter((project) => {
|
||||
return project.lang == lang;
|
||||
})
|
||||
.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: {
|
||||
slug: project.urlname,
|
||||
lang: project.lang,
|
||||
name: project.name,
|
||||
shortDescription: project.shortDescription,
|
||||
longDescription: project.longDescription,
|
||||
links:
|
||||
project.links !== null
|
||||
? {
|
||||
github: project.links.github,
|
||||
website: project.links.website,
|
||||
}
|
||||
: null,
|
||||
image: project.image.publicURL,
|
||||
featured: project.featured,
|
||||
frontend: `/${project.lang}/projects/${project.urlname}`,
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,35 +1,35 @@
|
|||
{
|
||||
"siteDescription": "Hallo, ich bin Kevin Kandlbinder, ein Entwickler und Hobby-Fotograf aus Norddeutschland.",
|
||||
"imprint": "Impressum",
|
||||
"datasec": "Datenschutz",
|
||||
"disclaimer": "Disclaimer",
|
||||
"projects": "Projekte",
|
||||
"project": "Projekt",
|
||||
"social": "Soziales",
|
||||
"homeHello": "Hallo, ich bin",
|
||||
"homeMe": "Ich bin",
|
||||
"homeWebDeveloper": "Web Developer",
|
||||
"homeMyLocation": "Quickborn, Schleswig-Holstein, Deutschland",
|
||||
"donationCatchphrase": "Gefällt dir was du siehst? Spende doch etwas.",
|
||||
"homeImageCredit": "Portrait aufgenommen von Jannik Kiel",
|
||||
"de": "Deutsch",
|
||||
"en": "Englisch",
|
||||
"projectAboutHeader": "Über {{projectName}}",
|
||||
"projectViewGitHub": "Auf GitHub anschauen",
|
||||
"projectViewWebsite": "Projekt-Website anschauen",
|
||||
"projectsDescription": "Das ist woran ich grade arbeite oder woran ich gearbeitet habe.",
|
||||
"projectView": "Anschauen",
|
||||
"socialDescriptionWithLink": "Finde mich auf anderen Plattformen oder <1>besuche meine Freunde</1>!",
|
||||
"socialDescription": "Finde mich auf anderen Plattformen!",
|
||||
"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.",
|
||||
"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!",
|
||||
"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",
|
||||
"featuredProjects": "Vorgestellte Projekte",
|
||||
"seeMore": "Mehr erkunden",
|
||||
"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:",
|
||||
"sponsorGitHub": "Über GitHub unterstützen"
|
||||
}
|
||||
{
|
||||
"siteDescription": "Hallo, ich bin Kevin Kandlbinder, ein Entwickler und Hobby-Fotograf aus Norddeutschland.",
|
||||
"imprint": "Impressum",
|
||||
"datasec": "Datenschutz",
|
||||
"disclaimer": "Disclaimer",
|
||||
"projects": "Projekte",
|
||||
"project": "Projekt",
|
||||
"social": "Soziales",
|
||||
"homeHello": "Hallo, ich bin",
|
||||
"homeMe": "Ich bin",
|
||||
"homeWebDeveloper": "Web Developer",
|
||||
"homeMyLocation": "Quickborn, Schleswig-Holstein, Deutschland",
|
||||
"donationCatchphrase": "Gefällt dir was du siehst? Spende doch etwas.",
|
||||
"homeImageCredit": "Portrait aufgenommen von Jannik Kiel",
|
||||
"de": "Deutsch",
|
||||
"en": "Englisch",
|
||||
"projectAboutHeader": "Über {{projectName}}",
|
||||
"projectViewGitHub": "Auf GitHub anschauen",
|
||||
"projectViewWebsite": "Projekt-Website anschauen",
|
||||
"projectsDescription": "Das ist woran ich grade arbeite oder woran ich gearbeitet habe.",
|
||||
"projectView": "Anschauen",
|
||||
"socialDescriptionWithLink": "Finde mich auf anderen Plattformen oder <1>besuche meine Freunde</1>!",
|
||||
"socialDescription": "Finde mich auf anderen Plattformen!",
|
||||
"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.",
|
||||
"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!",
|
||||
"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",
|
||||
"featuredProjects": "Vorgestellte Projekte",
|
||||
"seeMore": "Mehr erkunden",
|
||||
"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:",
|
||||
"sponsorGitHub": "Über GitHub unterstützen"
|
||||
}
|
||||
|
|
|
@ -1,35 +1,35 @@
|
|||
{
|
||||
"siteDescription": "Hello, I am Kevin Kandlbinder, a developer and hobby photographer from northern Germany.",
|
||||
"imprint": "Imprint",
|
||||
"datasec": "Data Protection",
|
||||
"disclaimer": "Disclaimer",
|
||||
"projects": "Projects",
|
||||
"project": "Project",
|
||||
"social": "Social",
|
||||
"homeHello": "Hello, I am",
|
||||
"homeMe": "I am",
|
||||
"homeWebDeveloper": "a web developer",
|
||||
"homeMyLocation": "Quickborn, Schleswig-Holstein, Germany",
|
||||
"donationCatchphrase": "Like what you're seeing? Consider donating.",
|
||||
"homeImageCredit": "Portrait taken by Jannik Kiel",
|
||||
"de": "German",
|
||||
"en": "English",
|
||||
"projectAboutHeader": "About {{projectName}}",
|
||||
"projectViewGitHub": "View on GitHub",
|
||||
"projectViewWebsite": "View Project-Website",
|
||||
"projectsDescription": "This is what I am working on or have worked on.",
|
||||
"projectView": "View",
|
||||
"socialDescriptionWithLink": "Find me on other platforms or <1>visit my friends</1>!",
|
||||
"socialDescription": "Find me on other platforms!",
|
||||
"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.",
|
||||
"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.",
|
||||
"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!",
|
||||
"featuredProjects": "Featured Projects",
|
||||
"seeMore": "See more",
|
||||
"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:",
|
||||
"sponsorGitHub": "Sponsor using GitHub"
|
||||
}
|
||||
{
|
||||
"siteDescription": "Hello, I am Kevin Kandlbinder, a developer and hobby photographer from northern Germany.",
|
||||
"imprint": "Imprint",
|
||||
"datasec": "Data Protection",
|
||||
"disclaimer": "Disclaimer",
|
||||
"projects": "Projects",
|
||||
"project": "Project",
|
||||
"social": "Social",
|
||||
"homeHello": "Hello, I am",
|
||||
"homeMe": "I am",
|
||||
"homeWebDeveloper": "a web developer",
|
||||
"homeMyLocation": "Quickborn, Schleswig-Holstein, Germany",
|
||||
"donationCatchphrase": "Like what you're seeing? Consider donating.",
|
||||
"homeImageCredit": "Portrait taken by Jannik Kiel",
|
||||
"de": "German",
|
||||
"en": "English",
|
||||
"projectAboutHeader": "About {{projectName}}",
|
||||
"projectViewGitHub": "View on GitHub",
|
||||
"projectViewWebsite": "View Project-Website",
|
||||
"projectsDescription": "This is what I am working on or have worked on.",
|
||||
"projectView": "View",
|
||||
"socialDescriptionWithLink": "Find me on other platforms or <1>visit my friends</1>!",
|
||||
"socialDescription": "Find me on other platforms!",
|
||||
"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.",
|
||||
"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.",
|
||||
"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!",
|
||||
"featuredProjects": "Featured Projects",
|
||||
"seeMore": "See more",
|
||||
"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:",
|
||||
"sponsorGitHub": "Sponsor using GitHub"
|
||||
}
|
||||
|
|
54248
package-lock.json
generated
54248
package-lock.json
generated
File diff suppressed because it is too large
Load diff
135
package.json
135
package.json
|
@ -1,68 +1,67 @@
|
|||
{
|
||||
"name": "kevink.dev",
|
||||
"version": "1.1.0",
|
||||
"private": true,
|
||||
"description": "KevinK.dev",
|
||||
"author": "Kevin Kandlbinder",
|
||||
"keywords": [
|
||||
"gatsby"
|
||||
],
|
||||
"scripts": {
|
||||
"develop": "gatsby develop",
|
||||
"start": "gatsby develop",
|
||||
"build": "gatsby build --prefix-paths",
|
||||
"build:fab": "npm run build && npm run fab:build",
|
||||
"fab:build": "fab build",
|
||||
"fab:serve": "fab serve fab.zip",
|
||||
"serve": "gatsby serve",
|
||||
"clean": "gatsby clean"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/cli": "7.14.8",
|
||||
"@babel/plugin-transform-typescript": "7.14.6",
|
||||
"@mdx-js/mdx": "1.6.22",
|
||||
"@mdx-js/react": "1.6.22",
|
||||
"animejs": "3.2.1",
|
||||
"babel-plugin-i18next-extract": "0.8.3",
|
||||
"gatsby": "3.10.1",
|
||||
"gatsby-cli": "3.10.0",
|
||||
"gatsby-plugin-asset-path": "3.0.4",
|
||||
"gatsby-plugin-manifest": "3.10.0",
|
||||
"gatsby-plugin-mdx": "2.10.0",
|
||||
"gatsby-plugin-offline": "4.10.0",
|
||||
"gatsby-plugin-react-helmet": "4.10.0",
|
||||
"gatsby-plugin-react-i18next": "1.1.1",
|
||||
"gatsby-plugin-robots-txt": "1.6.8",
|
||||
"gatsby-plugin-sass": "4.10.0",
|
||||
"gatsby-plugin-sharp": "3.10.2",
|
||||
"gatsby-plugin-sitemap": "4.6.0",
|
||||
"gatsby-source-filesystem": "3.10.0",
|
||||
"gatsby-transformer-json": "3.10.0",
|
||||
"gatsby-transformer-sharp": "3.10.0",
|
||||
"i18next": "20.3.5",
|
||||
"locale": "0.1.0",
|
||||
"node-sass": "4.14.1",
|
||||
"prop-types": "15.7.2",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-github-btn": "1.2.0",
|
||||
"react-helmet": "6.1.0",
|
||||
"react-i18next": "11.11.3",
|
||||
"tsparticles": "1.32.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fab/actions": "1.0.0-rc.3-beta.1",
|
||||
"@fab/cli": "1.0.0-rc.3-beta.1",
|
||||
"@fab/input-static": "1.0.0-rc.3-beta.1",
|
||||
"@fab/plugin-render-html": "1.0.0-rc.3-beta.1",
|
||||
"@fab/plugin-rewire-assets": "1.0.0-rc.3-beta.1",
|
||||
"@fab/server": "1.0.0-rc.3-beta.1",
|
||||
"babel-eslint": "10.1.0",
|
||||
"eslint": "7.31.0",
|
||||
"eslint-loader": "4.0.2",
|
||||
"eslint-plugin-import": "2.23.4",
|
||||
"eslint-plugin-react": "7.24.0",
|
||||
"gatsby-plugin-eslint": "2.0.8"
|
||||
}
|
||||
}
|
||||
{
|
||||
"name": "kevink.dev",
|
||||
"version": "1.1.0",
|
||||
"private": true,
|
||||
"description": "KevinK.dev",
|
||||
"author": "Kevin Kandlbinder",
|
||||
"keywords": [
|
||||
"gatsby"
|
||||
],
|
||||
"scripts": {
|
||||
"develop": "gatsby develop",
|
||||
"start": "gatsby develop",
|
||||
"build": "gatsby build --prefix-paths",
|
||||
"prettier": "npx prettier --write .",
|
||||
"serve": "gatsby serve",
|
||||
"clean": "gatsby clean"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/cli": "7.14.8",
|
||||
"@babel/plugin-transform-typescript": "7.14.6",
|
||||
"@mdx-js/mdx": "1.6.22",
|
||||
"@mdx-js/react": "1.6.22",
|
||||
"animejs": "3.2.1",
|
||||
"babel-plugin-i18next-extract": "0.8.3",
|
||||
"gatsby": "3.10.1",
|
||||
"gatsby-cli": "3.10.0",
|
||||
"gatsby-plugin-asset-path": "3.0.4",
|
||||
"gatsby-plugin-manifest": "3.10.0",
|
||||
"gatsby-plugin-mdx": "2.10.0",
|
||||
"gatsby-plugin-offline": "4.10.0",
|
||||
"gatsby-plugin-react-helmet": "4.10.0",
|
||||
"gatsby-plugin-react-i18next": "1.1.1",
|
||||
"gatsby-plugin-robots-txt": "1.6.8",
|
||||
"gatsby-plugin-sass": "4.10.0",
|
||||
"gatsby-plugin-sharp": "3.10.2",
|
||||
"gatsby-plugin-sitemap": "4.6.0",
|
||||
"gatsby-source-filesystem": "3.10.0",
|
||||
"gatsby-transformer-json": "3.10.0",
|
||||
"gatsby-transformer-sharp": "3.10.0",
|
||||
"i18next": "20.3.5",
|
||||
"locale": "0.1.0",
|
||||
"node-sass": "4.14.1",
|
||||
"prop-types": "15.7.2",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-github-btn": "1.2.0",
|
||||
"react-helmet": "6.1.0",
|
||||
"react-i18next": "11.11.3",
|
||||
"tsparticles": "1.32.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fab/actions": "1.0.0-rc.3-beta.1",
|
||||
"@fab/cli": "1.0.0-rc.3-beta.1",
|
||||
"@fab/input-static": "1.0.0-rc.3-beta.1",
|
||||
"@fab/plugin-render-html": "1.0.0-rc.3-beta.1",
|
||||
"@fab/plugin-rewire-assets": "1.0.0-rc.3-beta.1",
|
||||
"@fab/server": "1.0.0-rc.3-beta.1",
|
||||
"babel-eslint": "10.1.0",
|
||||
"eslint": "7.31.0",
|
||||
"eslint-loader": "4.0.2",
|
||||
"eslint-plugin-import": "2.23.4",
|
||||
"eslint-plugin-react": "7.24.0",
|
||||
"gatsby-plugin-eslint": "2.0.8",
|
||||
"prettier": "2.3.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"extends": ["config:base"],
|
||||
"assignees": ["Unkn0wnCat"],
|
||||
"automerge": true,
|
||||
"baseBranches": ["main"]
|
||||
}
|
||||
{
|
||||
"extends": ["config:base"],
|
||||
"assignees": ["Unkn0wnCat"],
|
||||
"automerge": true,
|
||||
"baseBranches": ["main"]
|
||||
}
|
||||
|
|
160
src/_mixins.scss
160
src/_mixins.scss
|
@ -1,80 +1,80 @@
|
|||
@import "./variables";
|
||||
|
||||
@mixin flexList {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@mixin cardGeneric {
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
box-shadow: -1px 11px 33px -10px rgba(127, 127, 127, 0.3);
|
||||
transition: transform 0.25s, box-shadow 0.25s;
|
||||
color: $textColor;
|
||||
text-decoration: none;
|
||||
margin: 20px;
|
||||
background: $background;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
transform: scale(1.05);
|
||||
box-shadow: -1px 11px 33px -10px rgba(127, 127, 127, 0.2),
|
||||
-1px 11px 33px -10px rgba($accentColor, 0.75);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin buttonBasic {
|
||||
display: block;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
background: $accentColor;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
box-shadow: 0 0 33px -10px rgba($accentColor, 0.5);
|
||||
transition: box-shadow 0.25s;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:hover {
|
||||
box-shadow: 0 0 33px -10px rgba($accentColor, 0.9);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin button {
|
||||
@include buttonBasic;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
@mixin homeBanner {
|
||||
background: lighten($background, 1);
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
|
||||
img {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding: 20px !important;
|
||||
line-height: 50px;
|
||||
font-size: 1.7em;
|
||||
color: white;
|
||||
|
||||
> span {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
> i {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
@import "./variables";
|
||||
|
||||
@mixin flexList {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@mixin cardGeneric {
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
box-shadow: -1px 11px 33px -10px rgba(127, 127, 127, 0.3);
|
||||
transition: transform 0.25s, box-shadow 0.25s;
|
||||
color: $textColor;
|
||||
text-decoration: none;
|
||||
margin: 20px;
|
||||
background: $background;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
transform: scale(1.05);
|
||||
box-shadow: -1px 11px 33px -10px rgba(127, 127, 127, 0.2),
|
||||
-1px 11px 33px -10px rgba($accentColor, 0.75);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin buttonBasic {
|
||||
display: block;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
background: $accentColor;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
box-shadow: 0 0 33px -10px rgba($accentColor, 0.5);
|
||||
transition: box-shadow 0.25s;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:hover {
|
||||
box-shadow: 0 0 33px -10px rgba($accentColor, 0.9);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin button {
|
||||
@include buttonBasic;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
@mixin homeBanner {
|
||||
background: lighten($background, 1);
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
|
||||
img {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding: 20px !important;
|
||||
line-height: 50px;
|
||||
font-size: 1.7em;
|
||||
color: white;
|
||||
|
||||
> span {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
> i {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
$layoutWidth: 1200px;
|
||||
$accentColor: #e5502b;
|
||||
$background: #070707;
|
||||
$textColor: white;
|
||||
$layoutPadding: 20px;
|
||||
|
||||
$mainFont: "Anonymous Pro", monospace;
|
||||
$layoutWidth: 1200px;
|
||||
$accentColor: #e5502b;
|
||||
$background: #070707;
|
||||
$textColor: white;
|
||||
$layoutPadding: 20px;
|
||||
|
||||
$mainFont: "Anonymous Pro", monospace;
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
import React from "react";
|
||||
import { Link, Trans, useI18next } from "gatsby-plugin-react-i18next";
|
||||
|
||||
import * as styles from "./languageSwitcher.module.scss";
|
||||
|
||||
export default function LanguageSwitcher() {
|
||||
const { languages, originalPath } = useI18next();
|
||||
|
||||
return (
|
||||
<div className={styles.languageModal} id="languageChooser">
|
||||
<div className={styles.languageModalInner}>
|
||||
<h2>
|
||||
Languages (
|
||||
<a href="#top" className={styles.modalCloseLink}>
|
||||
×
|
||||
</a>
|
||||
)
|
||||
</h2>
|
||||
<ul>
|
||||
{languages.map((lng) => (
|
||||
<li key={lng}>
|
||||
<Link to={originalPath} language={lng}>
|
||||
<Trans>{lng}</Trans>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
import React from "react";
|
||||
import { Link, Trans, useI18next } from "gatsby-plugin-react-i18next";
|
||||
|
||||
import * as styles from "./languageSwitcher.module.scss";
|
||||
|
||||
export default function LanguageSwitcher() {
|
||||
const { languages, originalPath } = useI18next();
|
||||
|
||||
return (
|
||||
<div className={styles.languageModal} id="languageChooser">
|
||||
<div className={styles.languageModalInner}>
|
||||
<h2>
|
||||
Languages (
|
||||
<a href="#top" className={styles.modalCloseLink}>
|
||||
×
|
||||
</a>
|
||||
)
|
||||
</h2>
|
||||
<ul>
|
||||
{languages.map((lng) => (
|
||||
<li key={lng}>
|
||||
<Link to={originalPath} language={lng}>
|
||||
<Trans>{lng}</Trans>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,41 +1,41 @@
|
|||
@import "../mixins";
|
||||
@import "../variables";
|
||||
|
||||
.languageModal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
z-index: 1000;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.25s;
|
||||
|
||||
&:target {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.languageModalInner {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: white;
|
||||
background: black;
|
||||
font-family: $mainFont;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
|
||||
a {
|
||||
color: white;
|
||||
text-decoration-style: dotted;
|
||||
}
|
||||
}
|
||||
|
||||
.modalCloseLink {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
@import "../mixins";
|
||||
@import "../variables";
|
||||
|
||||
.languageModal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
z-index: 1000;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.25s;
|
||||
|
||||
&:target {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.languageModalInner {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: white;
|
||||
background: black;
|
||||
font-family: $mainFont;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
|
||||
a {
|
||||
color: white;
|
||||
text-decoration-style: dotted;
|
||||
}
|
||||
}
|
||||
|
||||
.modalCloseLink {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,91 +1,92 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Trans, Link } from "gatsby-plugin-react-i18next";
|
||||
import { graphql, StaticQuery } from "gatsby";
|
||||
|
||||
import * as styles from "./navigation.module.scss";
|
||||
|
||||
const Navigation = ({ isHome }) => {
|
||||
let [atTop, setAtTop] = useState(false);
|
||||
|
||||
const updateTransparency = () => {
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
if (window.scrollY < 15) {
|
||||
if (!atTop) setAtTop(true);
|
||||
} else {
|
||||
if (atTop) setAtTop(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
window.addEventListener("scroll", updateTransparency);
|
||||
// eslint-disable-next-line no-undef
|
||||
window.addEventListener("navigate", updateTransparency);
|
||||
|
||||
updateTransparency();
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
let int = window.setInterval(updateTransparency, 10000);
|
||||
|
||||
return () => {
|
||||
// eslint-disable-next-line no-undef
|
||||
window.removeEventListener("scroll", updateTransparency);
|
||||
// eslint-disable-next-line no-undef
|
||||
window.removeEventListener("navigate", updateTransparency);
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
window.clearInterval(int);
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
styles.topBar +
|
||||
(isHome ? " " + styles.homeBar : "") +
|
||||
(atTop ? " " + styles.homeBarTransparent : "")
|
||||
}
|
||||
>
|
||||
<nav className={styles.topBarInner}>
|
||||
<StaticQuery
|
||||
query={graphql`
|
||||
query {
|
||||
site {
|
||||
siteMetadata {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
`}
|
||||
render={(data) => (
|
||||
<Link to="/" activeClassName={styles.active}>
|
||||
{data.site.siteMetadata.title}
|
||||
</Link>
|
||||
)}
|
||||
/>
|
||||
<div className="flexSpacer"></div>
|
||||
<Link
|
||||
id="navBtnProjects"
|
||||
to="/projects"
|
||||
activeClassName={styles.active}
|
||||
>
|
||||
<Trans>projects</Trans>
|
||||
</Link>
|
||||
<Link id="navBtnSocial" to="/social" activeClassName={styles.active}>
|
||||
<Trans>social</Trans>
|
||||
</Link>
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Navigation.propTypes = {
|
||||
isHome: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default Navigation;
|
||||
import React, { useEffect, useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Trans, Link } from "gatsby-plugin-react-i18next";
|
||||
import { graphql, StaticQuery } from "gatsby";
|
||||
|
||||
import * as styles from "./navigation.module.scss";
|
||||
|
||||
const Navigation = ({ isHome }) => {
|
||||
let [atTop, setAtTop] = useState(false);
|
||||
|
||||
const updateTransparency = () => {
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
if (window.scrollY < 15) {
|
||||
if (!atTop) setAtTop(true);
|
||||
} else {
|
||||
if (atTop) setAtTop(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
window.addEventListener("scroll", updateTransparency);
|
||||
// eslint-disable-next-line no-undef
|
||||
window.addEventListener("navigate", updateTransparency);
|
||||
|
||||
updateTransparency();
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
let int = window.setInterval(updateTransparency, 10000);
|
||||
|
||||
return () => {
|
||||
// eslint-disable-next-line no-undef
|
||||
window.removeEventListener("scroll", updateTransparency);
|
||||
// eslint-disable-next-line no-undef
|
||||
window.removeEventListener("navigate", updateTransparency);
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
window.clearInterval(int);
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
styles.topBar +
|
||||
(isHome ? " " + styles.homeBar : "") +
|
||||
(atTop ? " " + styles.homeBarTransparent : "")
|
||||
}>
|
||||
<nav className={styles.topBarInner}>
|
||||
<StaticQuery
|
||||
query={graphql`
|
||||
query {
|
||||
site {
|
||||
siteMetadata {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
`}
|
||||
render={(data) => (
|
||||
<Link to="/" activeClassName={styles.active}>
|
||||
{data.site.siteMetadata.title}
|
||||
</Link>
|
||||
)}
|
||||
/>
|
||||
<div className="flexSpacer"></div>
|
||||
<Link
|
||||
id="navBtnProjects"
|
||||
to="/projects"
|
||||
activeClassName={styles.active}>
|
||||
<Trans>projects</Trans>
|
||||
</Link>
|
||||
<Link
|
||||
id="navBtnSocial"
|
||||
to="/social"
|
||||
activeClassName={styles.active}>
|
||||
<Trans>social</Trans>
|
||||
</Link>
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Navigation.propTypes = {
|
||||
isHome: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default Navigation;
|
||||
|
|
|
@ -1,59 +1,59 @@
|
|||
@import "../variables";
|
||||
@import "../mixins";
|
||||
|
||||
.topBar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
background: rgba($background, 0.95);
|
||||
backdrop-filter: blur(5px);
|
||||
z-index: 999;
|
||||
transition: background 0.25s;
|
||||
|
||||
@supports (backdrop-filter: blur(5px)) {
|
||||
background: rgba($background, 0.9);
|
||||
}
|
||||
|
||||
.topBarInner {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
max-width: $layoutWidth;
|
||||
margin: auto;
|
||||
|
||||
> :first-child {
|
||||
padding-left: $layoutPadding;
|
||||
}
|
||||
|
||||
> :last-child {
|
||||
padding-right: $layoutPadding;
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
padding: 10px $layoutPadding;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-top: 2px solid transparent;
|
||||
|
||||
&:hover {
|
||||
border-color: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.homeBar.homeBarTransparent {
|
||||
background: transparent;
|
||||
backdrop-filter: blur(0);
|
||||
}
|
||||
|
||||
.flexSpacer {
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
}
|
||||
@import "../variables";
|
||||
@import "../mixins";
|
||||
|
||||
.topBar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
background: rgba($background, 0.95);
|
||||
backdrop-filter: blur(5px);
|
||||
z-index: 999;
|
||||
transition: background 0.25s;
|
||||
|
||||
@supports (backdrop-filter: blur(5px)) {
|
||||
background: rgba($background, 0.9);
|
||||
}
|
||||
|
||||
.topBarInner {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
max-width: $layoutWidth;
|
||||
margin: auto;
|
||||
|
||||
> :first-child {
|
||||
padding-left: $layoutPadding;
|
||||
}
|
||||
|
||||
> :last-child {
|
||||
padding-right: $layoutPadding;
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
padding: 10px $layoutPadding;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-top: 2px solid transparent;
|
||||
|
||||
&:hover {
|
||||
border-color: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.homeBar.homeBarTransparent {
|
||||
background: transparent;
|
||||
backdrop-filter: blur(0);
|
||||
}
|
||||
|
||||
.flexSpacer {
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
|
@ -1,93 +1,93 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Helmet } from "gatsby-plugin-react-i18next";
|
||||
import { useStaticQuery, graphql } from "gatsby";
|
||||
import { useTranslation } from "gatsby-plugin-react-i18next";
|
||||
|
||||
function SEO({ description, meta, title }) {
|
||||
const { t } = useTranslation();
|
||||
const { site } = useStaticQuery(
|
||||
graphql`
|
||||
query {
|
||||
site {
|
||||
siteMetadata {
|
||||
title
|
||||
author
|
||||
keywords
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
const metaDescription = description || t("siteDescription");
|
||||
|
||||
return (
|
||||
<Helmet
|
||||
title={title}
|
||||
titleTemplate={`%s | ${site.siteMetadata.title}`}
|
||||
meta={[
|
||||
{
|
||||
name: `description`,
|
||||
content: metaDescription,
|
||||
},
|
||||
{
|
||||
property: `og:title`,
|
||||
content: title,
|
||||
},
|
||||
{
|
||||
property: `og:description`,
|
||||
content: metaDescription,
|
||||
},
|
||||
{
|
||||
property: `og:type`,
|
||||
content: `website`,
|
||||
},
|
||||
{
|
||||
name: `twitter:card`,
|
||||
content: `summary`,
|
||||
},
|
||||
{
|
||||
name: `twitter:creator`,
|
||||
content: site.siteMetadata.author,
|
||||
},
|
||||
{
|
||||
name: `twitter:title`,
|
||||
content: title,
|
||||
},
|
||||
{
|
||||
name: `twitter:description`,
|
||||
content: metaDescription,
|
||||
},
|
||||
{
|
||||
name: "keywords",
|
||||
content: site.siteMetadata.keywords,
|
||||
},
|
||||
].concat(meta)}
|
||||
>
|
||||
<script
|
||||
src="https://kit.fontawesome.com/1377f925e0.js"
|
||||
crossOrigin="anonymous"
|
||||
></script>
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Anonymous+Pro:wght@400;700&family=Roboto&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<meta name="battery-savings" content="allow-reduced-framerate"></meta>
|
||||
</Helmet>
|
||||
);
|
||||
}
|
||||
|
||||
SEO.defaultProps = {
|
||||
meta: [],
|
||||
description: ``,
|
||||
};
|
||||
|
||||
SEO.propTypes = {
|
||||
description: PropTypes.string,
|
||||
meta: PropTypes.arrayOf(PropTypes.object),
|
||||
title: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default SEO;
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Helmet } from "gatsby-plugin-react-i18next";
|
||||
import { useStaticQuery, graphql } from "gatsby";
|
||||
import { useTranslation } from "gatsby-plugin-react-i18next";
|
||||
|
||||
function SEO({ description, meta, title }) {
|
||||
const { t } = useTranslation();
|
||||
const { site } = useStaticQuery(
|
||||
graphql`
|
||||
query {
|
||||
site {
|
||||
siteMetadata {
|
||||
title
|
||||
author
|
||||
keywords
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
const metaDescription = description || t("siteDescription");
|
||||
|
||||
return (
|
||||
<Helmet
|
||||
title={title}
|
||||
titleTemplate={`%s | ${site.siteMetadata.title}`}
|
||||
meta={[
|
||||
{
|
||||
name: `description`,
|
||||
content: metaDescription,
|
||||
},
|
||||
{
|
||||
property: `og:title`,
|
||||
content: title,
|
||||
},
|
||||
{
|
||||
property: `og:description`,
|
||||
content: metaDescription,
|
||||
},
|
||||
{
|
||||
property: `og:type`,
|
||||
content: `website`,
|
||||
},
|
||||
{
|
||||
name: `twitter:card`,
|
||||
content: `summary`,
|
||||
},
|
||||
{
|
||||
name: `twitter:creator`,
|
||||
content: site.siteMetadata.author,
|
||||
},
|
||||
{
|
||||
name: `twitter:title`,
|
||||
content: title,
|
||||
},
|
||||
{
|
||||
name: `twitter:description`,
|
||||
content: metaDescription,
|
||||
},
|
||||
{
|
||||
name: "keywords",
|
||||
content: site.siteMetadata.keywords,
|
||||
},
|
||||
].concat(meta)}>
|
||||
<script
|
||||
src="https://kit.fontawesome.com/1377f925e0.js"
|
||||
crossOrigin="anonymous"></script>
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Anonymous+Pro:wght@400;700&family=Roboto&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<meta
|
||||
name="battery-savings"
|
||||
content="allow-reduced-framerate"></meta>
|
||||
</Helmet>
|
||||
);
|
||||
}
|
||||
|
||||
SEO.defaultProps = {
|
||||
meta: [],
|
||||
description: ``,
|
||||
};
|
||||
|
||||
SEO.propTypes = {
|
||||
description: PropTypes.string,
|
||||
meta: PropTypes.arrayOf(PropTypes.object),
|
||||
title: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default SEO;
|
||||
|
|
|
@ -1,62 +1,62 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Navigation from "../components/navigation";
|
||||
import SEO from "../components/seo";
|
||||
|
||||
import "./default.scss";
|
||||
import { Link, Trans } from "gatsby-plugin-react-i18next";
|
||||
import LanguageSwitcher from "../components/languageSwitcher";
|
||||
|
||||
class Layout extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<SEO
|
||||
description={this.props.description}
|
||||
lang={this.props.lang}
|
||||
meta={this.props.meta}
|
||||
title={this.props.title}
|
||||
/>
|
||||
<Navigation isHome={this.props.transparentTopbar} />
|
||||
<div id="content" role="main">
|
||||
{this.props.children}
|
||||
</div>
|
||||
<footer role="contentinfo">
|
||||
CC-BY 4.0 Kevin Kandlbinder,{" "}
|
||||
<Link to="/legal/about" className="spf-link">
|
||||
<Trans i18nKey="imprint">Imprint</Trans>
|
||||
</Link>{" "}
|
||||
|{" "}
|
||||
<Link to="/legal/datasec" className="spf-link">
|
||||
<Trans i18nKey="datasec">Data Protection</Trans>
|
||||
</Link>{" "}
|
||||
|{" "}
|
||||
<Link to="/legal/disclaimer" className="spf-link">
|
||||
<Trans i18nKey="disclaimer">Disclaimer</Trans>
|
||||
</Link>{" "}
|
||||
| <a href="#languageChooser">Language</a>
|
||||
</footer>
|
||||
|
||||
<LanguageSwitcher />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Layout.defaultProps = {
|
||||
module: `none`,
|
||||
meta: [],
|
||||
description: ``,
|
||||
transparentTopbar: false,
|
||||
};
|
||||
|
||||
Layout.propTypes = {
|
||||
description: PropTypes.string,
|
||||
lang: PropTypes.string,
|
||||
meta: PropTypes.arrayOf(PropTypes.object),
|
||||
title: PropTypes.string.isRequired,
|
||||
transparentTopbar: PropTypes.bool,
|
||||
children: PropTypes.any.isRequired,
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Navigation from "../components/navigation";
|
||||
import SEO from "../components/seo";
|
||||
|
||||
import "./default.scss";
|
||||
import { Link, Trans } from "gatsby-plugin-react-i18next";
|
||||
import LanguageSwitcher from "../components/languageSwitcher";
|
||||
|
||||
class Layout extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<SEO
|
||||
description={this.props.description}
|
||||
lang={this.props.lang}
|
||||
meta={this.props.meta}
|
||||
title={this.props.title}
|
||||
/>
|
||||
<Navigation isHome={this.props.transparentTopbar} />
|
||||
<div id="content" role="main">
|
||||
{this.props.children}
|
||||
</div>
|
||||
<footer role="contentinfo">
|
||||
CC-BY 4.0 Kevin Kandlbinder,{" "}
|
||||
<Link to="/legal/about" className="spf-link">
|
||||
<Trans i18nKey="imprint">Imprint</Trans>
|
||||
</Link>{" "}
|
||||
|{" "}
|
||||
<Link to="/legal/datasec" className="spf-link">
|
||||
<Trans i18nKey="datasec">Data Protection</Trans>
|
||||
</Link>{" "}
|
||||
|{" "}
|
||||
<Link to="/legal/disclaimer" className="spf-link">
|
||||
<Trans i18nKey="disclaimer">Disclaimer</Trans>
|
||||
</Link>{" "}
|
||||
| <a href="#languageChooser">Language</a>
|
||||
</footer>
|
||||
|
||||
<LanguageSwitcher />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Layout.defaultProps = {
|
||||
module: `none`,
|
||||
meta: [],
|
||||
description: ``,
|
||||
transparentTopbar: false,
|
||||
};
|
||||
|
||||
Layout.propTypes = {
|
||||
description: PropTypes.string,
|
||||
lang: PropTypes.string,
|
||||
meta: PropTypes.arrayOf(PropTypes.object),
|
||||
title: PropTypes.string.isRequired,
|
||||
transparentTopbar: PropTypes.bool,
|
||||
children: PropTypes.any.isRequired,
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
|
|
|
@ -1,73 +1,73 @@
|
|||
@import "../variables";
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body,
|
||||
html,
|
||||
#___gatsby,
|
||||
#gatsby-focus-wrapper {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
font-family: $mainFont;
|
||||
}
|
||||
|
||||
#gatsby-focus-wrapper {
|
||||
background: $background;
|
||||
color: $textColor;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
footer {
|
||||
background: darken($background, 1);
|
||||
width: 100%;
|
||||
color: white;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
|
||||
a {
|
||||
color: white;
|
||||
text-decoration: underline dotted currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
#content {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.flexSpacer {
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
section > div:not(.profile),
|
||||
section > article,
|
||||
.section > div:not(.profile),
|
||||
.section > article {
|
||||
max-width: $layoutWidth;
|
||||
width: 100%;
|
||||
padding: 39px 20px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
article {
|
||||
p {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $accentColor;
|
||||
text-decoration: underline dotted currentColor;
|
||||
text-decoration-skip: none;
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
@import "../variables";
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body,
|
||||
html,
|
||||
#___gatsby,
|
||||
#gatsby-focus-wrapper {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
font-family: $mainFont;
|
||||
}
|
||||
|
||||
#gatsby-focus-wrapper {
|
||||
background: $background;
|
||||
color: $textColor;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
footer {
|
||||
background: darken($background, 1);
|
||||
width: 100%;
|
||||
color: white;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
|
||||
a {
|
||||
color: white;
|
||||
text-decoration: underline dotted currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
#content {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.flexSpacer {
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
section > div:not(.profile),
|
||||
section > article,
|
||||
.section > div:not(.profile),
|
||||
.section > article {
|
||||
max-width: $layoutWidth;
|
||||
width: 100%;
|
||||
padding: 39px 20px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
article {
|
||||
p {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $accentColor;
|
||||
text-decoration: underline dotted currentColor;
|
||||
text-decoration-skip: none;
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import * as React from "react";
|
||||
import { Link } from "gatsby-plugin-react-i18next";
|
||||
import Layout from "../layouts/default";
|
||||
|
||||
const NotFoundPage = () => {
|
||||
return (
|
||||
<Layout title="Not found">
|
||||
<section>
|
||||
<article>
|
||||
<h1>Page not found</h1>
|
||||
<p>
|
||||
Whoops... That page doesn't exist, so you may as well{" "}
|
||||
<Link to="/">go home</Link>.
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotFoundPage;
|
||||
import * as React from "react";
|
||||
import { Link } from "gatsby-plugin-react-i18next";
|
||||
import Layout from "../layouts/default";
|
||||
|
||||
const NotFoundPage = () => {
|
||||
return (
|
||||
<Layout title="Not found">
|
||||
<section>
|
||||
<article>
|
||||
<h1>Page not found</h1>
|
||||
<p>
|
||||
Whoops... That page doesn't exist, so you may as
|
||||
well <Link to="/">go home</Link>.
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotFoundPage;
|
||||
|
|
|
@ -1,135 +1,142 @@
|
|||
import React, { useState } from "react";
|
||||
import Layout from "../layouts/default";
|
||||
import { graphql } from "gatsby";
|
||||
import { Trans, useI18next, I18nextContext } from "gatsby-plugin-react-i18next";
|
||||
import PropTypes from "prop-types";
|
||||
import GitHubButton from "react-github-btn";
|
||||
|
||||
import * as styles from "./donate.module.scss";
|
||||
|
||||
export const query = graphql`
|
||||
query($language: String!) {
|
||||
site {
|
||||
siteMetadata {
|
||||
title
|
||||
siteUrl
|
||||
payPalMail
|
||||
contactGitHub
|
||||
}
|
||||
}
|
||||
file(relativePath: { eq: "images/pplogo.png" }) {
|
||||
childImageSharp {
|
||||
resize(width: 240, height: 240, fit: CONTAIN) {
|
||||
src
|
||||
}
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const DonatePage = (props) => {
|
||||
const [amount, setAmount] = useState(5);
|
||||
const { t } = useI18next();
|
||||
const { path } = React.useContext(I18nextContext);
|
||||
|
||||
const { site, file } = props.data;
|
||||
|
||||
return (
|
||||
<Layout title={t("donate")} description={t("donationCatchphrase")}>
|
||||
<section>
|
||||
<article>
|
||||
<h1>
|
||||
<Trans>donate</Trans>
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
<Trans>donateDescription</Trans>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<Trans>donateGitHub</Trans>
|
||||
</p>
|
||||
|
||||
<p style={{ display: "block", textAlign: "center" }}>
|
||||
<GitHubButton
|
||||
href={
|
||||
"https://github.com/sponsors/" + site.siteMetadata.contactGitHub
|
||||
}
|
||||
data-color-scheme="no-preference: light; light: dark; dark: dark;"
|
||||
data-icon="octicon-heart"
|
||||
data-size="large"
|
||||
aria-label="Sponsor @Unkn0wnCat on GitHub"
|
||||
>
|
||||
<Trans>sponsorGitHub</Trans>
|
||||
</GitHubButton>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<Trans>donatePayPal</Trans>
|
||||
</p>
|
||||
|
||||
<div className={styles.priceAmount}>
|
||||
<label htmlFor="priceInput" className={styles.sronly}>
|
||||
Amount
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
placeholder="10.00"
|
||||
step="1"
|
||||
value={amount}
|
||||
onChange={(ev) => {
|
||||
setAmount(ev.target.value);
|
||||
}}
|
||||
name="priceInput"
|
||||
id="priceInput"
|
||||
/>
|
||||
<div>€</div>
|
||||
</div>
|
||||
|
||||
<a
|
||||
className={styles.donateButton}
|
||||
rel="noopener"
|
||||
id="payPalBtn"
|
||||
href={
|
||||
"https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=" +
|
||||
encodeURIComponent(site.siteMetadata.payPalMail) +
|
||||
"&item_name=" +
|
||||
encodeURIComponent(site.siteMetadata.title) +
|
||||
"¤cy_code=EUR&image_url=" +
|
||||
encodeURIComponent(
|
||||
site.siteMetadata.siteUrl + file.childImageSharp.resize.src
|
||||
) +
|
||||
"&return=" +
|
||||
encodeURIComponent(
|
||||
site.siteMetadata.siteUrl + "/" + path + "thank-you/"
|
||||
) +
|
||||
"&rm=0&cancel_return=" +
|
||||
encodeURIComponent(site.siteMetadata.siteUrl + "/" + path) +
|
||||
"&amount=" +
|
||||
amount
|
||||
}
|
||||
>
|
||||
<span>Donate using PayPal</span>
|
||||
<i className="fas fa-fw fa-chevron-right" aria-hidden="true"></i>
|
||||
</a>
|
||||
</article>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
DonatePage.propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default DonatePage;
|
||||
import React, { useState } from "react";
|
||||
import Layout from "../layouts/default";
|
||||
import { graphql } from "gatsby";
|
||||
import { Trans, useI18next, I18nextContext } from "gatsby-plugin-react-i18next";
|
||||
import PropTypes from "prop-types";
|
||||
import GitHubButton from "react-github-btn";
|
||||
|
||||
import * as styles from "./donate.module.scss";
|
||||
|
||||
export const query = graphql`
|
||||
query ($language: String!) {
|
||||
site {
|
||||
siteMetadata {
|
||||
title
|
||||
siteUrl
|
||||
payPalMail
|
||||
contactGitHub
|
||||
}
|
||||
}
|
||||
file(relativePath: { eq: "images/pplogo.png" }) {
|
||||
childImageSharp {
|
||||
resize(width: 240, height: 240, fit: CONTAIN) {
|
||||
src
|
||||
}
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const DonatePage = (props) => {
|
||||
const [amount, setAmount] = useState(5);
|
||||
const { t } = useI18next();
|
||||
const { path } = React.useContext(I18nextContext);
|
||||
|
||||
const { site, file } = props.data;
|
||||
|
||||
return (
|
||||
<Layout title={t("donate")} description={t("donationCatchphrase")}>
|
||||
<section>
|
||||
<article>
|
||||
<h1>
|
||||
<Trans>donate</Trans>
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
<Trans>donateDescription</Trans>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<Trans>donateGitHub</Trans>
|
||||
</p>
|
||||
|
||||
<p style={{ display: "block", textAlign: "center" }}>
|
||||
<GitHubButton
|
||||
href={
|
||||
"https://github.com/sponsors/" +
|
||||
site.siteMetadata.contactGitHub
|
||||
}
|
||||
data-color-scheme="no-preference: light; light: dark; dark: dark;"
|
||||
data-icon="octicon-heart"
|
||||
data-size="large"
|
||||
aria-label="Sponsor @Unkn0wnCat on GitHub">
|
||||
<Trans>sponsorGitHub</Trans>
|
||||
</GitHubButton>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<Trans>donatePayPal</Trans>
|
||||
</p>
|
||||
|
||||
<div className={styles.priceAmount}>
|
||||
<label htmlFor="priceInput" className={styles.sronly}>
|
||||
Amount
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
placeholder="10.00"
|
||||
step="1"
|
||||
value={amount}
|
||||
onChange={(ev) => {
|
||||
setAmount(ev.target.value);
|
||||
}}
|
||||
name="priceInput"
|
||||
id="priceInput"
|
||||
/>
|
||||
<div>€</div>
|
||||
</div>
|
||||
|
||||
<a
|
||||
className={styles.donateButton}
|
||||
rel="noopener"
|
||||
id="payPalBtn"
|
||||
href={
|
||||
"https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=" +
|
||||
encodeURIComponent(site.siteMetadata.payPalMail) +
|
||||
"&item_name=" +
|
||||
encodeURIComponent(site.siteMetadata.title) +
|
||||
"¤cy_code=EUR&image_url=" +
|
||||
encodeURIComponent(
|
||||
site.siteMetadata.siteUrl +
|
||||
file.childImageSharp.resize.src
|
||||
) +
|
||||
"&return=" +
|
||||
encodeURIComponent(
|
||||
site.siteMetadata.siteUrl +
|
||||
"/" +
|
||||
path +
|
||||
"thank-you/"
|
||||
) +
|
||||
"&rm=0&cancel_return=" +
|
||||
encodeURIComponent(
|
||||
site.siteMetadata.siteUrl + "/" + path
|
||||
) +
|
||||
"&amount=" +
|
||||
amount
|
||||
}>
|
||||
<span>Donate using PayPal</span>
|
||||
<i
|
||||
className="fas fa-fw fa-chevron-right"
|
||||
aria-hidden="true"></i>
|
||||
</a>
|
||||
</article>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
DonatePage.propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default DonatePage;
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
@import "../variables";
|
||||
@import "../mixins";
|
||||
|
||||
.priceAmount {
|
||||
display: flex;
|
||||
width: 150px;
|
||||
margin: 20px auto;
|
||||
border: thin solid rgba(0, 0, 0, 0.25);
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
line-height: 40px;
|
||||
|
||||
input {
|
||||
flex-grow: 1;
|
||||
border: none;
|
||||
padding-left: 10px;
|
||||
width: 1px;
|
||||
border-right: thin solid rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
div {
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.donateButton {
|
||||
@include button;
|
||||
}
|
||||
|
||||
.sronly {
|
||||
border: 0;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
}
|
||||
@import "../variables";
|
||||
@import "../mixins";
|
||||
|
||||
.priceAmount {
|
||||
display: flex;
|
||||
width: 150px;
|
||||
margin: 20px auto;
|
||||
border: thin solid rgba(0, 0, 0, 0.25);
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
line-height: 40px;
|
||||
|
||||
input {
|
||||
flex-grow: 1;
|
||||
border: none;
|
||||
padding-left: 10px;
|
||||
width: 1px;
|
||||
border-right: thin solid rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
div {
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.donateButton {
|
||||
@include button;
|
||||
}
|
||||
|
||||
.sronly {
|
||||
border: 0;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
}
|
||||
|
|
|
@ -1,55 +1,59 @@
|
|||
import React from "react";
|
||||
import Layout from "../../layouts/default";
|
||||
import { Trans, useI18next } from "gatsby-plugin-react-i18next";
|
||||
import { graphql } from "gatsby";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
export const query = graphql`
|
||||
query GetThankYouPage($language: String!) {
|
||||
site {
|
||||
siteMetadata {
|
||||
contactEmail
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const ThankYouPage = (props) => {
|
||||
const { site } = props.data;
|
||||
|
||||
let contactEmail = site.siteMetadata.contactEmail;
|
||||
const { t } = useI18next();
|
||||
return (
|
||||
<Layout title={t("donate")}>
|
||||
<section>
|
||||
<article>
|
||||
<h1>
|
||||
<Trans>donateThanks</Trans>
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
<Trans contactEmail={contactEmail} i18nKey="donateThanksText">
|
||||
donateThanksText
|
||||
<a href={"mailto:" + contactEmail}>{{ contactEmail }}</a>
|
||||
</Trans>
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
ThankYouPage.propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default ThankYouPage;
|
||||
import React from "react";
|
||||
import Layout from "../../layouts/default";
|
||||
import { Trans, useI18next } from "gatsby-plugin-react-i18next";
|
||||
import { graphql } from "gatsby";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
export const query = graphql`
|
||||
query GetThankYouPage($language: String!) {
|
||||
site {
|
||||
siteMetadata {
|
||||
contactEmail
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const ThankYouPage = (props) => {
|
||||
const { site } = props.data;
|
||||
|
||||
let contactEmail = site.siteMetadata.contactEmail;
|
||||
const { t } = useI18next();
|
||||
return (
|
||||
<Layout title={t("donate")}>
|
||||
<section>
|
||||
<article>
|
||||
<h1>
|
||||
<Trans>donateThanks</Trans>
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
<Trans
|
||||
contactEmail={contactEmail}
|
||||
i18nKey="donateThanksText">
|
||||
donateThanksText
|
||||
<a href={"mailto:" + contactEmail}>
|
||||
{{ contactEmail }}
|
||||
</a>
|
||||
</Trans>
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
ThankYouPage.propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default ThankYouPage;
|
||||
|
|
|
@ -1,97 +1,140 @@
|
|||
import React from "react";
|
||||
import Layout from "../layouts/default";
|
||||
import { Trans, useI18next } from "gatsby-plugin-react-i18next";
|
||||
import { graphql } from "gatsby";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import * as styles from "./friends.module.scss";
|
||||
|
||||
export const query = graphql`
|
||||
query AllFriendsQuery($language: String!) {
|
||||
allFriendsJson {
|
||||
nodes {
|
||||
name
|
||||
profession
|
||||
url
|
||||
imageURL
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const FriendsPage = ({ data }) => {
|
||||
const { t } = useI18next();
|
||||
|
||||
/*function shuffle(a) {
|
||||
for (let i = a.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[a[i], a[j]] = [a[j], a[i]];
|
||||
}
|
||||
return a;
|
||||
}*/
|
||||
|
||||
return (
|
||||
<Layout title={t("friends")} description={t("friendsDescription")}>
|
||||
<section>
|
||||
<article>
|
||||
<h1>
|
||||
<Trans>social</Trans>
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
<Trans>friendsDescription</Trans>
|
||||
</p>
|
||||
|
||||
<div className={styles.friendsList}>
|
||||
{/*shuffle(*/data.allFriendsJson.nodes/*)*/.map((friend) => {
|
||||
return (
|
||||
<div
|
||||
className={styles.friendProfile}
|
||||
key={friend.url + "#" + friend.name}
|
||||
>
|
||||
<div
|
||||
className={styles.friendImage}
|
||||
style={{ backgroundImage: "url(" + friend.imageURL + ")" }}
|
||||
key={friend.url + "#" + friend.name + "#image"}
|
||||
>
|
||||
<span className={styles.friendName} key={friend.url + "#" + friend.name + "#name"}>{friend.name}</span>
|
||||
<span className={styles.friendTitle} key={friend.url + "#" + 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;
|
||||
import React from "react";
|
||||
import Layout from "../layouts/default";
|
||||
import { Trans, useI18next } from "gatsby-plugin-react-i18next";
|
||||
import { graphql } from "gatsby";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import * as styles from "./friends.module.scss";
|
||||
|
||||
export const query = graphql`
|
||||
query AllFriendsQuery($language: String!) {
|
||||
allFriendsJson {
|
||||
nodes {
|
||||
name
|
||||
profession
|
||||
url
|
||||
imageURL
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const FriendsPage = ({ data }) => {
|
||||
const { t } = useI18next();
|
||||
|
||||
/*function shuffle(a) {
|
||||
for (let i = a.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[a[i], a[j]] = [a[j], a[i]];
|
||||
}
|
||||
return a;
|
||||
}*/
|
||||
|
||||
return (
|
||||
<Layout title={t("friends")} description={t("friendsDescription")}>
|
||||
<section>
|
||||
<article>
|
||||
<h1>
|
||||
<Trans>social</Trans>
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
<Trans>friendsDescription</Trans>
|
||||
</p>
|
||||
|
||||
<div className={styles.friendsList}>
|
||||
{
|
||||
/*shuffle(*/ data.allFriendsJson.nodes /*)*/
|
||||
.map((friend) => {
|
||||
return (
|
||||
<div
|
||||
className={styles.friendProfile}
|
||||
key={
|
||||
friend.url + "#" + friend.name
|
||||
}>
|
||||
<div
|
||||
className={styles.friendImage}
|
||||
style={{
|
||||
backgroundImage:
|
||||
"url(" +
|
||||
friend.imageURL +
|
||||
")",
|
||||
}}
|
||||
key={
|
||||
friend.url +
|
||||
"#" +
|
||||
friend.name +
|
||||
"#image"
|
||||
}>
|
||||
<span
|
||||
className={
|
||||
styles.friendName
|
||||
}
|
||||
key={
|
||||
friend.url +
|
||||
"#" +
|
||||
friend.name +
|
||||
"#name"
|
||||
}>
|
||||
{friend.name}
|
||||
</span>
|
||||
<span
|
||||
className={
|
||||
styles.friendTitle
|
||||
}
|
||||
key={
|
||||
friend.url +
|
||||
"#" +
|
||||
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;
|
||||
|
|
|
@ -1,62 +1,62 @@
|
|||
@import "../variables";
|
||||
@import "../mixins";
|
||||
|
||||
.friendsList {
|
||||
@include flexList;
|
||||
|
||||
.friendProfile {
|
||||
@include cardGeneric;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 300px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.friendImage {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
flex-direction: column-reverse;
|
||||
text-shadow: 0 0 10px black, 0 0 10px black, 0 0 20px black;
|
||||
|
||||
.friendName {
|
||||
font-size: 2em;
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
.friendTitle {
|
||||
margin-top: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.friendBio {
|
||||
padding: 15px;
|
||||
flex-grow: 1;
|
||||
text-align: justify;
|
||||
display: block;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.contactLinks {
|
||||
padding: 15px;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.contactLink {
|
||||
transition: text-decoration 0.5s;
|
||||
text-decoration: underline dotted rgba(0, 0, 0, 0);
|
||||
padding: 6px 0 6px 25px;
|
||||
color: $textColor;
|
||||
|
||||
> i {
|
||||
color: $accentColor;
|
||||
margin-left: -25px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@import "../variables";
|
||||
@import "../mixins";
|
||||
|
||||
.friendsList {
|
||||
@include flexList;
|
||||
|
||||
.friendProfile {
|
||||
@include cardGeneric;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 300px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.friendImage {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
flex-direction: column-reverse;
|
||||
text-shadow: 0 0 10px black, 0 0 10px black, 0 0 20px black;
|
||||
|
||||
.friendName {
|
||||
font-size: 2em;
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
.friendTitle {
|
||||
margin-top: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.friendBio {
|
||||
padding: 15px;
|
||||
flex-grow: 1;
|
||||
text-align: justify;
|
||||
display: block;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.contactLinks {
|
||||
padding: 15px;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.contactLink {
|
||||
transition: text-decoration 0.5s;
|
||||
text-decoration: underline dotted rgba(0, 0, 0, 0);
|
||||
padding: 6px 0 6px 25px;
|
||||
color: $textColor;
|
||||
|
||||
> i {
|
||||
color: $accentColor;
|
||||
margin-left: -25px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,255 +1,264 @@
|
|||
import * as React from "react";
|
||||
import Layout from "../layouts/default";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import * as styles from "./index.module.scss";
|
||||
import * as projectStyles from "./projects.module.scss";
|
||||
|
||||
import { Trans, Link } from "gatsby-plugin-react-i18next";
|
||||
import { graphql } from "gatsby";
|
||||
import { MDXRenderer } from "gatsby-plugin-mdx";
|
||||
|
||||
import anime from "animejs";
|
||||
import { tsParticles } from "tsparticles";
|
||||
|
||||
|
||||
import * as particleConfig from "./index.particles.json";
|
||||
|
||||
export const query = graphql`
|
||||
query GetMetaAndProjects($language: String) {
|
||||
site {
|
||||
siteMetadata {
|
||||
contactEmail
|
||||
contactPhone
|
||||
mapsLink
|
||||
contactTwitter
|
||||
contactGitHub
|
||||
contactMastodon
|
||||
contactMastodonHref
|
||||
}
|
||||
}
|
||||
allProjectsJson(
|
||||
filter: { lang: { eq: $language }, featured: { gte: 0 } }
|
||||
sort: { fields: featured, order: ASC }
|
||||
) {
|
||||
nodes {
|
||||
lang
|
||||
urlname
|
||||
name
|
||||
image {
|
||||
childImageSharp {
|
||||
resize(width: 400, quality: 90) {
|
||||
src
|
||||
}
|
||||
}
|
||||
}
|
||||
shortDescription
|
||||
featured
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
file(
|
||||
sourceInstanceName: {eq: "textblocks"}, relativeDirectory: {eq: "home/about"}, name: {eq: $language}
|
||||
) {
|
||||
id
|
||||
childMdx {
|
||||
body
|
||||
}
|
||||
name
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const IndexPage = (props) => {
|
||||
React.useEffect(() => {
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
anime({
|
||||
targets: [
|
||||
"." + styles.profileCard + " > span",
|
||||
"." + styles.profileCard + " a",
|
||||
],
|
||||
opacity: [0, 1],
|
||||
translateX: [100, 0],
|
||||
duration: 250,
|
||||
delay: anime.stagger(20),
|
||||
easing: "easeInOutCirc",
|
||||
});
|
||||
anime({
|
||||
targets: ["." + styles.profileImageDummy],
|
||||
translateX: [0, -3],
|
||||
translateY: [0, 3],
|
||||
duration: 250,
|
||||
easing: "easeInOutCirc",
|
||||
});
|
||||
anime({
|
||||
targets: ["." + styles.profileImage],
|
||||
translateX: [0, 4],
|
||||
translateY: [0, -4],
|
||||
duration: 250,
|
||||
easing: "easeInOutCirc",
|
||||
});
|
||||
|
||||
tsParticles.load("particle-container", particleConfig);
|
||||
}, []);
|
||||
|
||||
let meta = props.data.site.siteMetadata;
|
||||
let file = props.data.file;
|
||||
|
||||
return (
|
||||
<Layout title="Kevin Kandlbinder" transparentTopbar={true}>
|
||||
<section className={styles.heroSection}>
|
||||
<div className={styles.heroSectionBg} id="particle-container"></div>
|
||||
<div className={styles.heroSectionBgOver}></div>
|
||||
<div className={styles.profile + " profile"}>
|
||||
<div
|
||||
data-bg="url(https://cdn.kevink.dev/images/kevin/kevin-kandlbinder-03.jpg)"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"url(https://cdn.kevink.dev/images/kevin/kevin-kandlbinder-03.jpg)",
|
||||
}}
|
||||
className={styles.profileImage + " lazy"}
|
||||
></div>
|
||||
<div className={styles.profileImageDummy}></div>
|
||||
<div className={styles.profileCard}>
|
||||
<span className={styles.hello}>
|
||||
<Trans>homeHello</Trans>
|
||||
</span>
|
||||
<span className={styles.name}>Kevin Kandlbinder</span>
|
||||
<span className={styles.description}>
|
||||
<Trans>homeMe</Trans>{" "}
|
||||
<span id="descriptionType">
|
||||
<Trans>homeWebDeveloper</Trans>
|
||||
</span>
|
||||
.
|
||||
</span>
|
||||
|
||||
<div className={styles.contactLinks}>
|
||||
<a
|
||||
className={styles.contactLink}
|
||||
href={"tel:" + meta.contactPhone}
|
||||
rel="me"
|
||||
>
|
||||
<i className="fas fa-fw fa-phone"></i>
|
||||
{meta.contactPhone}
|
||||
</a>
|
||||
<a
|
||||
className={styles.contactLink}
|
||||
href={"mailto:" + meta.contactEmail}
|
||||
rel="me"
|
||||
>
|
||||
<i className="far fa-fw fa-envelope"></i>
|
||||
{meta.contactEmail}
|
||||
</a>
|
||||
<a
|
||||
className={styles.contactLink}
|
||||
href={meta.mapsLink}
|
||||
rel="noreferrer "
|
||||
target="_blank"
|
||||
>
|
||||
<i className="fas fa-fw fa-map-marker-alt"></i>
|
||||
<Trans>homeMyLocation</Trans>
|
||||
</a>
|
||||
<a
|
||||
className={styles.contactLink}
|
||||
href={meta.contactMastodonHref}
|
||||
rel="noreferrer me"
|
||||
target="_blank"
|
||||
>
|
||||
<i className="fab fa-fw fa-mastodon"></i>
|
||||
{meta.contactMastodon}
|
||||
</a>
|
||||
<a
|
||||
className={styles.contactLink}
|
||||
href={"https://github.com/" + meta.contactGitHub}
|
||||
rel="noreferrer me"
|
||||
target="_blank"
|
||||
>
|
||||
<i className="fab fa-fw fa-github"></i>
|
||||
{meta.contactGitHub}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="aboutSection">
|
||||
<article>
|
||||
<MDXRenderer>{file.childMdx.body}</MDXRenderer>
|
||||
</article>
|
||||
</section>
|
||||
<a
|
||||
className={styles.creditSection}
|
||||
href="https://unsplash.com/@jannikkiel"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<div>
|
||||
<span>
|
||||
<i className="fas fa-fw fa-camera"></i>{" "}
|
||||
<Trans>homeImageCredit</Trans>
|
||||
</span>
|
||||
<i className="fas fa-fw fa-chevron-right"></i>
|
||||
</div>
|
||||
</a>
|
||||
<section className="featuredSection">
|
||||
<article>
|
||||
<h1>
|
||||
<Trans>featuredProjects</Trans>
|
||||
</h1>
|
||||
<div className={projectStyles.projectList}>
|
||||
{props.data.allProjectsJson.nodes.map((project) => {
|
||||
return (
|
||||
<Link
|
||||
className={projectStyles.projectCard}
|
||||
key={project.lang + "/" + project.urlname}
|
||||
to={"/projects/" + project.urlname}
|
||||
>
|
||||
<div
|
||||
className={projectStyles.projectCardImage}
|
||||
style={{
|
||||
backgroundImage:
|
||||
"url(" + project.image.childImageSharp.resize.src + ")",
|
||||
}}
|
||||
>
|
||||
<div className={projectStyles.projectCardMeta}>
|
||||
<span className={projectStyles.projectCardTitle}>
|
||||
{project.name}
|
||||
</span>
|
||||
<span>{project.shortDescription}</span>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<Link to="/projects" className={styles.seeMoreButton}>
|
||||
<Trans>seeMore</Trans>{" "}
|
||||
<i className="fas fa-fw fa-chevron-right"></i>
|
||||
</Link>
|
||||
</article>
|
||||
</section>
|
||||
<Link className={styles.donationSection} to="/donate">
|
||||
<div>
|
||||
<span>
|
||||
<Trans>donationCatchphrase</Trans>
|
||||
</span>
|
||||
<i className="fas fa-fw fa-chevron-right"></i>
|
||||
</div>
|
||||
</Link>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
IndexPage.propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default IndexPage;
|
||||
import * as React from "react";
|
||||
import Layout from "../layouts/default";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import * as styles from "./index.module.scss";
|
||||
import * as projectStyles from "./projects.module.scss";
|
||||
|
||||
import { Trans, Link } from "gatsby-plugin-react-i18next";
|
||||
import { graphql } from "gatsby";
|
||||
import { MDXRenderer } from "gatsby-plugin-mdx";
|
||||
|
||||
import anime from "animejs";
|
||||
import { tsParticles } from "tsparticles";
|
||||
|
||||
import * as particleConfig from "./index.particles.json";
|
||||
|
||||
export const query = graphql`
|
||||
query GetMetaAndProjects($language: String) {
|
||||
site {
|
||||
siteMetadata {
|
||||
contactEmail
|
||||
contactPhone
|
||||
mapsLink
|
||||
contactTwitter
|
||||
contactGitHub
|
||||
contactMastodon
|
||||
contactMastodonHref
|
||||
}
|
||||
}
|
||||
allProjectsJson(
|
||||
filter: { lang: { eq: $language }, featured: { gte: 0 } }
|
||||
sort: { fields: featured, order: ASC }
|
||||
) {
|
||||
nodes {
|
||||
lang
|
||||
urlname
|
||||
name
|
||||
image {
|
||||
childImageSharp {
|
||||
resize(width: 400, quality: 90) {
|
||||
src
|
||||
}
|
||||
}
|
||||
}
|
||||
shortDescription
|
||||
featured
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
file(
|
||||
sourceInstanceName: { eq: "textblocks" }
|
||||
relativeDirectory: { eq: "home/about" }
|
||||
name: { eq: $language }
|
||||
) {
|
||||
id
|
||||
childMdx {
|
||||
body
|
||||
}
|
||||
name
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const IndexPage = (props) => {
|
||||
React.useEffect(() => {
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
anime({
|
||||
targets: [
|
||||
"." + styles.profileCard + " > span",
|
||||
"." + styles.profileCard + " a",
|
||||
],
|
||||
opacity: [0, 1],
|
||||
translateX: [100, 0],
|
||||
duration: 250,
|
||||
delay: anime.stagger(20),
|
||||
easing: "easeInOutCirc",
|
||||
});
|
||||
anime({
|
||||
targets: ["." + styles.profileImageDummy],
|
||||
translateX: [0, -3],
|
||||
translateY: [0, 3],
|
||||
duration: 250,
|
||||
easing: "easeInOutCirc",
|
||||
});
|
||||
anime({
|
||||
targets: ["." + styles.profileImage],
|
||||
translateX: [0, 4],
|
||||
translateY: [0, -4],
|
||||
duration: 250,
|
||||
easing: "easeInOutCirc",
|
||||
});
|
||||
|
||||
tsParticles.load("particle-container", particleConfig);
|
||||
}, []);
|
||||
|
||||
let meta = props.data.site.siteMetadata;
|
||||
let file = props.data.file;
|
||||
|
||||
return (
|
||||
<Layout title="Kevin Kandlbinder" transparentTopbar={true}>
|
||||
<section className={styles.heroSection}>
|
||||
<div
|
||||
className={styles.heroSectionBg}
|
||||
id="particle-container"></div>
|
||||
<div className={styles.heroSectionBgOver}></div>
|
||||
<div className={styles.profile + " profile"}>
|
||||
<div
|
||||
data-bg="url(https://cdn.kevink.dev/images/kevin/kevin-kandlbinder-03.jpg)"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"url(https://cdn.kevink.dev/images/kevin/kevin-kandlbinder-03.jpg)",
|
||||
}}
|
||||
className={styles.profileImage + " lazy"}></div>
|
||||
<div className={styles.profileImageDummy}></div>
|
||||
<div className={styles.profileCard}>
|
||||
<span className={styles.hello}>
|
||||
<Trans>homeHello</Trans>
|
||||
</span>
|
||||
<span className={styles.name}>Kevin Kandlbinder</span>
|
||||
<span className={styles.description}>
|
||||
<Trans>homeMe</Trans>{" "}
|
||||
<span id="descriptionType">
|
||||
<Trans>homeWebDeveloper</Trans>
|
||||
</span>
|
||||
.
|
||||
</span>
|
||||
|
||||
<div className={styles.contactLinks}>
|
||||
<a
|
||||
className={styles.contactLink}
|
||||
href={"tel:" + meta.contactPhone}
|
||||
rel="me">
|
||||
<i className="fas fa-fw fa-phone"></i>
|
||||
{meta.contactPhone}
|
||||
</a>
|
||||
<a
|
||||
className={styles.contactLink}
|
||||
href={"mailto:" + meta.contactEmail}
|
||||
rel="me">
|
||||
<i className="far fa-fw fa-envelope"></i>
|
||||
{meta.contactEmail}
|
||||
</a>
|
||||
<a
|
||||
className={styles.contactLink}
|
||||
href={meta.mapsLink}
|
||||
rel="noreferrer "
|
||||
target="_blank">
|
||||
<i className="fas fa-fw fa-map-marker-alt"></i>
|
||||
<Trans>homeMyLocation</Trans>
|
||||
</a>
|
||||
<a
|
||||
className={styles.contactLink}
|
||||
href={meta.contactMastodonHref}
|
||||
rel="noreferrer me"
|
||||
target="_blank">
|
||||
<i className="fab fa-fw fa-mastodon"></i>
|
||||
{meta.contactMastodon}
|
||||
</a>
|
||||
<a
|
||||
className={styles.contactLink}
|
||||
href={
|
||||
"https://github.com/" + meta.contactGitHub
|
||||
}
|
||||
rel="noreferrer me"
|
||||
target="_blank">
|
||||
<i className="fab fa-fw fa-github"></i>
|
||||
{meta.contactGitHub}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="aboutSection">
|
||||
<article>
|
||||
<MDXRenderer>{file.childMdx.body}</MDXRenderer>
|
||||
</article>
|
||||
</section>
|
||||
<a
|
||||
className={styles.creditSection}
|
||||
href="https://unsplash.com/@jannikkiel"
|
||||
target="_blank"
|
||||
rel="noreferrer">
|
||||
<div>
|
||||
<span>
|
||||
<i className="fas fa-fw fa-camera"></i>{" "}
|
||||
<Trans>homeImageCredit</Trans>
|
||||
</span>
|
||||
<i className="fas fa-fw fa-chevron-right"></i>
|
||||
</div>
|
||||
</a>
|
||||
<section className="featuredSection">
|
||||
<article>
|
||||
<h1>
|
||||
<Trans>featuredProjects</Trans>
|
||||
</h1>
|
||||
<div className={projectStyles.projectList}>
|
||||
{props.data.allProjectsJson.nodes.map((project) => {
|
||||
return (
|
||||
<Link
|
||||
className={projectStyles.projectCard}
|
||||
key={project.lang + "/" + project.urlname}
|
||||
to={"/projects/" + project.urlname}>
|
||||
<div
|
||||
className={
|
||||
projectStyles.projectCardImage
|
||||
}
|
||||
style={{
|
||||
backgroundImage:
|
||||
"url(" +
|
||||
project.image.childImageSharp
|
||||
.resize.src +
|
||||
")",
|
||||
}}>
|
||||
<div
|
||||
className={
|
||||
projectStyles.projectCardMeta
|
||||
}>
|
||||
<span
|
||||
className={
|
||||
projectStyles.projectCardTitle
|
||||
}>
|
||||
{project.name}
|
||||
</span>
|
||||
<span>
|
||||
{project.shortDescription}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<Link to="/projects" className={styles.seeMoreButton}>
|
||||
<Trans>seeMore</Trans>{" "}
|
||||
<i className="fas fa-fw fa-chevron-right"></i>
|
||||
</Link>
|
||||
</article>
|
||||
</section>
|
||||
<Link className={styles.donationSection} to="/donate">
|
||||
<div>
|
||||
<span>
|
||||
<Trans>donationCatchphrase</Trans>
|
||||
</span>
|
||||
<i className="fas fa-fw fa-chevron-right"></i>
|
||||
</div>
|
||||
</Link>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
IndexPage.propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default IndexPage;
|
||||
|
|
|
@ -1,170 +1,184 @@
|
|||
@import "../variables";
|
||||
@import "../mixins";
|
||||
|
||||
.heroSection {
|
||||
width: 100%;
|
||||
height: 600px;
|
||||
overflow: hidden;
|
||||
|
||||
.heroSectionBg, .heroSectionBgOver {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
max-width: unset;
|
||||
height: 600px;
|
||||
padding: 0;
|
||||
|
||||
@media (pointer: coarse), (pointer: none) {
|
||||
height: 700px;
|
||||
}
|
||||
}
|
||||
|
||||
.heroSectionBg {
|
||||
/*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;
|
||||
}
|
||||
|
||||
.heroSectionBgOver {
|
||||
background: linear-gradient(to bottom, transparent 80%, $background);
|
||||
}
|
||||
|
||||
@media (pointer: coarse), (pointer: none) {
|
||||
height: 700px;
|
||||
}
|
||||
|
||||
.profile {
|
||||
position: relative;
|
||||
left: 50%;
|
||||
width: calc(90% - 40px);
|
||||
max-width: 600px;
|
||||
max-height: 400px;
|
||||
transform: translate(-50%, 0%);
|
||||
top: 100px;
|
||||
|
||||
.hello {
|
||||
font-weight: 100;
|
||||
opacity: 0.75;
|
||||
display: block;
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-weight: 100;
|
||||
font-size: 2em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-weight: 100;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.contactLinks {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.contactLink {
|
||||
transition: text-decoration 0.5s;
|
||||
text-decoration: underline dotted rgba(0, 0, 0, 0);
|
||||
padding: 6px 0 6px 25px;
|
||||
color: $textColor;
|
||||
|
||||
@media (pointer: coarse), (pointer: none) {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.contactLink:hover,
|
||||
.contactLink:active {
|
||||
text-decoration: underline dotted rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.contactLink > i {
|
||||
color: $accentColor;
|
||||
margin-left: -25px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.profileCard {
|
||||
width: calc(100% - 40px);
|
||||
height: calc(100% - 20px);
|
||||
transform: translate(40px, 20px);
|
||||
border-radius: 5px;
|
||||
padding: 20px 20px 20px 230px;
|
||||
color: $textColor;
|
||||
}
|
||||
|
||||
.profileImage,
|
||||
.profileImageDummy {
|
||||
display: inline-block;
|
||||
width: 250px;
|
||||
height: 350px;
|
||||
border-radius: 5px;
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
background-color: #1c1c1c;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
transition: transform 0.25s;
|
||||
}
|
||||
|
||||
.profileImage {
|
||||
z-index: 20;
|
||||
box-shadow: -1px 11px 33px -10px #e5502b4b;
|
||||
clip-path: polygon(6% 8%, 88% 5%, 95% 91%, 7% 96%);
|
||||
}
|
||||
|
||||
.profileImageDummy {
|
||||
z-index: 10;
|
||||
background: $accentColor;
|
||||
opacity: 0.2;
|
||||
clip-path: polygon(14% 4%, 95% 1%, 88% 96%, 2% 89%);
|
||||
}
|
||||
|
||||
@media (max-width: 590px) {
|
||||
.profileImage,
|
||||
.profileImageDummy {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.profileCard {
|
||||
padding: 20px 20px 20px 20px;
|
||||
transform: translate(20px, 20px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.amazonAlexaSection,
|
||||
.donationSection,
|
||||
.hireMeSection {
|
||||
@include homeBanner;
|
||||
}
|
||||
|
||||
.creditSection {
|
||||
@include homeBanner;
|
||||
|
||||
> div {
|
||||
padding: 15px !important;
|
||||
line-height: 15px;
|
||||
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;
|
||||
}
|
||||
@import "../variables";
|
||||
@import "../mixins";
|
||||
|
||||
.heroSection {
|
||||
width: 100%;
|
||||
height: 600px;
|
||||
overflow: hidden;
|
||||
|
||||
.heroSectionBg,
|
||||
.heroSectionBgOver {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
max-width: unset;
|
||||
height: 600px;
|
||||
padding: 0;
|
||||
|
||||
@media (pointer: coarse), (pointer: none) {
|
||||
height: 700px;
|
||||
}
|
||||
}
|
||||
|
||||
.heroSectionBg {
|
||||
/*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;
|
||||
}
|
||||
|
||||
.heroSectionBgOver {
|
||||
background: linear-gradient(to bottom, transparent 80%, $background);
|
||||
}
|
||||
|
||||
@media (pointer: coarse), (pointer: none) {
|
||||
height: 700px;
|
||||
}
|
||||
|
||||
.profile {
|
||||
position: relative;
|
||||
left: 50%;
|
||||
width: calc(90% - 40px);
|
||||
max-width: 600px;
|
||||
max-height: 400px;
|
||||
transform: translate(-50%, 0%);
|
||||
top: 100px;
|
||||
|
||||
.hello {
|
||||
font-weight: 100;
|
||||
opacity: 0.75;
|
||||
display: block;
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-weight: 100;
|
||||
font-size: 2em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-weight: 100;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.contactLinks {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.contactLink {
|
||||
transition: text-decoration 0.5s;
|
||||
text-decoration: underline dotted rgba(0, 0, 0, 0);
|
||||
padding: 6px 0 6px 25px;
|
||||
color: $textColor;
|
||||
|
||||
@media (pointer: coarse), (pointer: none) {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.contactLink:hover,
|
||||
.contactLink:active {
|
||||
text-decoration: underline dotted rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.contactLink > i {
|
||||
color: $accentColor;
|
||||
margin-left: -25px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.profileCard {
|
||||
width: calc(100% - 40px);
|
||||
height: calc(100% - 20px);
|
||||
transform: translate(40px, 20px);
|
||||
border-radius: 5px;
|
||||
padding: 20px 20px 20px 230px;
|
||||
color: $textColor;
|
||||
}
|
||||
|
||||
.profileImage,
|
||||
.profileImageDummy {
|
||||
display: inline-block;
|
||||
width: 250px;
|
||||
height: 350px;
|
||||
border-radius: 5px;
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
background-color: #1c1c1c;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
transition: transform 0.25s;
|
||||
}
|
||||
|
||||
.profileImage {
|
||||
z-index: 20;
|
||||
box-shadow: -1px 11px 33px -10px #e5502b4b;
|
||||
clip-path: polygon(6% 8%, 88% 5%, 95% 91%, 7% 96%);
|
||||
}
|
||||
|
||||
.profileImageDummy {
|
||||
z-index: 10;
|
||||
background: $accentColor;
|
||||
opacity: 0.2;
|
||||
clip-path: polygon(14% 4%, 95% 1%, 88% 96%, 2% 89%);
|
||||
}
|
||||
|
||||
@media (max-width: 590px) {
|
||||
.profileImage,
|
||||
.profileImageDummy {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.profileCard {
|
||||
padding: 20px 20px 20px 20px;
|
||||
transform: translate(20px, 20px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.amazonAlexaSection,
|
||||
.donationSection,
|
||||
.hireMeSection {
|
||||
@include homeBanner;
|
||||
}
|
||||
|
||||
.creditSection {
|
||||
@include homeBanner;
|
||||
|
||||
> div {
|
||||
padding: 15px !important;
|
||||
line-height: 15px;
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,107 +1,107 @@
|
|||
{
|
||||
"particles": {
|
||||
"number": {
|
||||
"value": 33,
|
||||
"density": {
|
||||
"enable": true,
|
||||
"value_area": 800
|
||||
}
|
||||
},
|
||||
"color": {
|
||||
"value": "#1b1e34"
|
||||
},
|
||||
"shape": {
|
||||
"type": "circle",
|
||||
"stroke": {
|
||||
"width": 0,
|
||||
"color": "#000"
|
||||
},
|
||||
"polygon": {
|
||||
"nb_sides": 3
|
||||
}
|
||||
},
|
||||
"opacity": {
|
||||
"value": 0.4,
|
||||
"random": true,
|
||||
"anim": {
|
||||
"enable": false,
|
||||
"speed": 1,
|
||||
"opacity_min": 0.1,
|
||||
"sync": false
|
||||
}
|
||||
},
|
||||
"size": {
|
||||
"value": 27.620603391810075,
|
||||
"random": true,
|
||||
"anim": {
|
||||
"enable": false,
|
||||
"speed": 10,
|
||||
"size_min": 40,
|
||||
"sync": false
|
||||
}
|
||||
},
|
||||
"line_linked": {
|
||||
"enable": false,
|
||||
"distance": 200,
|
||||
"color": "#ffffff",
|
||||
"opacity": 0.14994041841268327,
|
||||
"width": 2
|
||||
},
|
||||
"move": {
|
||||
"enable": true,
|
||||
"speed": 0.2,
|
||||
"direction": "top",
|
||||
"random": true,
|
||||
"straight": false,
|
||||
"out_mode": "out",
|
||||
"bounce": false,
|
||||
"attract": {
|
||||
"enable": false,
|
||||
"rotateX": 600,
|
||||
"rotateY": 1200
|
||||
}
|
||||
}
|
||||
},
|
||||
"interactivity": {
|
||||
"detect_on": "window",
|
||||
"events": {
|
||||
"onhover": {
|
||||
"enable": false,
|
||||
"mode": "repulse"
|
||||
},
|
||||
"onclick": {
|
||||
"enable": false,
|
||||
"mode": "push"
|
||||
},
|
||||
"resize": true
|
||||
},
|
||||
"modes": {
|
||||
"grab": {
|
||||
"distance": 400,
|
||||
"line_linked": {
|
||||
"opacity": 1
|
||||
}
|
||||
},
|
||||
"bubble": {
|
||||
"distance": 400,
|
||||
"size": 40,
|
||||
"duration": 2,
|
||||
"opacity": 8,
|
||||
"speed": 3
|
||||
},
|
||||
"repulse": {
|
||||
"distance": 200,
|
||||
"duration": 0.4
|
||||
},
|
||||
"push": {
|
||||
"particles_nb": 4
|
||||
},
|
||||
"remove": {
|
||||
"particles_nb": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"detectRetina": true,
|
||||
"pauseOnBlur": true,
|
||||
"pauseOnOutsideViewport": true
|
||||
}
|
||||
{
|
||||
"particles": {
|
||||
"number": {
|
||||
"value": 33,
|
||||
"density": {
|
||||
"enable": true,
|
||||
"value_area": 800
|
||||
}
|
||||
},
|
||||
"color": {
|
||||
"value": "#1b1e34"
|
||||
},
|
||||
"shape": {
|
||||
"type": "circle",
|
||||
"stroke": {
|
||||
"width": 0,
|
||||
"color": "#000"
|
||||
},
|
||||
"polygon": {
|
||||
"nb_sides": 3
|
||||
}
|
||||
},
|
||||
"opacity": {
|
||||
"value": 0.4,
|
||||
"random": true,
|
||||
"anim": {
|
||||
"enable": false,
|
||||
"speed": 1,
|
||||
"opacity_min": 0.1,
|
||||
"sync": false
|
||||
}
|
||||
},
|
||||
"size": {
|
||||
"value": 27.620603391810075,
|
||||
"random": true,
|
||||
"anim": {
|
||||
"enable": false,
|
||||
"speed": 10,
|
||||
"size_min": 40,
|
||||
"sync": false
|
||||
}
|
||||
},
|
||||
"line_linked": {
|
||||
"enable": false,
|
||||
"distance": 200,
|
||||
"color": "#ffffff",
|
||||
"opacity": 0.14994041841268327,
|
||||
"width": 2
|
||||
},
|
||||
"move": {
|
||||
"enable": true,
|
||||
"speed": 0.2,
|
||||
"direction": "top",
|
||||
"random": true,
|
||||
"straight": false,
|
||||
"out_mode": "out",
|
||||
"bounce": false,
|
||||
"attract": {
|
||||
"enable": false,
|
||||
"rotateX": 600,
|
||||
"rotateY": 1200
|
||||
}
|
||||
}
|
||||
},
|
||||
"interactivity": {
|
||||
"detect_on": "window",
|
||||
"events": {
|
||||
"onhover": {
|
||||
"enable": false,
|
||||
"mode": "repulse"
|
||||
},
|
||||
"onclick": {
|
||||
"enable": false,
|
||||
"mode": "push"
|
||||
},
|
||||
"resize": true
|
||||
},
|
||||
"modes": {
|
||||
"grab": {
|
||||
"distance": 400,
|
||||
"line_linked": {
|
||||
"opacity": 1
|
||||
}
|
||||
},
|
||||
"bubble": {
|
||||
"distance": 400,
|
||||
"size": 40,
|
||||
"duration": 2,
|
||||
"opacity": 8,
|
||||
"speed": 3
|
||||
},
|
||||
"repulse": {
|
||||
"distance": 200,
|
||||
"duration": 0.4
|
||||
},
|
||||
"push": {
|
||||
"particles_nb": 4
|
||||
},
|
||||
"remove": {
|
||||
"particles_nb": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"detectRetina": true,
|
||||
"pauseOnBlur": true,
|
||||
"pauseOnOutsideViewport": true
|
||||
}
|
||||
|
|
|
@ -1,56 +1,59 @@
|
|||
import React from "react";
|
||||
import Layout from "../../layouts/default";
|
||||
import { Trans, useI18next } from "gatsby-plugin-react-i18next";
|
||||
import { graphql } from "gatsby";
|
||||
|
||||
export const query = graphql`
|
||||
query($language: String!) {
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default function ImprintPage() {
|
||||
const { t } = useI18next();
|
||||
return (
|
||||
<Layout title={t("imprint")}>
|
||||
<section>
|
||||
<article>
|
||||
<h1>
|
||||
<Trans>imprint</Trans>
|
||||
</h1>
|
||||
|
||||
<p>Angaben gemäß § 5 TMG</p>
|
||||
<p>
|
||||
Kevin Kandlbinder
|
||||
<br />
|
||||
Eichenweg 48
|
||||
<br />
|
||||
25451 Quickborn <br />
|
||||
</p>
|
||||
<p>
|
||||
{" "}
|
||||
<strong>Vertreten durch: </strong>
|
||||
<br />
|
||||
Kevin Kandlbinder
|
||||
<br />
|
||||
</p>
|
||||
<p>
|
||||
<strong>Kontakt:</strong> <br />
|
||||
Telefon: +49 4106 8068004
|
||||
<br />
|
||||
E-Mail: <a href="mailto:contact@kevink.dev">contact@kevink.dev</a>
|
||||
<br />
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
import React from "react";
|
||||
import Layout from "../../layouts/default";
|
||||
import { Trans, useI18next } from "gatsby-plugin-react-i18next";
|
||||
import { graphql } from "gatsby";
|
||||
|
||||
export const query = graphql`
|
||||
query ($language: String!) {
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default function ImprintPage() {
|
||||
const { t } = useI18next();
|
||||
return (
|
||||
<Layout title={t("imprint")}>
|
||||
<section>
|
||||
<article>
|
||||
<h1>
|
||||
<Trans>imprint</Trans>
|
||||
</h1>
|
||||
|
||||
<p>Angaben gemäß § 5 TMG</p>
|
||||
<p>
|
||||
Kevin Kandlbinder
|
||||
<br />
|
||||
Eichenweg 48
|
||||
<br />
|
||||
25451 Quickborn <br />
|
||||
</p>
|
||||
<p>
|
||||
{" "}
|
||||
<strong>Vertreten durch: </strong>
|
||||
<br />
|
||||
Kevin Kandlbinder
|
||||
<br />
|
||||
</p>
|
||||
<p>
|
||||
<strong>Kontakt:</strong> <br />
|
||||
Telefon: +49 4106 8068004
|
||||
<br />
|
||||
E-Mail:{" "}
|
||||
<a href="mailto:contact@kevink.dev">
|
||||
contact@kevink.dev
|
||||
</a>
|
||||
<br />
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,94 +1,101 @@
|
|||
import React from "react";
|
||||
import Layout from "../../layouts/default";
|
||||
import { Trans, useI18next } from "gatsby-plugin-react-i18next";
|
||||
import { graphql } from "gatsby";
|
||||
|
||||
export const query = graphql`
|
||||
query($language: String!) {
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default function DisclaimerPage() {
|
||||
const { t } = useI18next();
|
||||
return (
|
||||
<Layout title={t("disclaimer")}>
|
||||
<section>
|
||||
<article>
|
||||
<h1>
|
||||
<Trans>disclaimer</Trans>
|
||||
</h1>
|
||||
|
||||
<h2>Haftung für Inhalte</h2>
|
||||
|
||||
<p>
|
||||
Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte
|
||||
auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach
|
||||
§§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht
|
||||
verpflichtet, übermittelte oder gespeicherte fremde Informationen zu
|
||||
überwachen oder nach Umständen zu forschen, die auf eine
|
||||
rechtswidrige Tätigkeit hinweisen.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Verpflichtungen zur Entfernung oder Sperrung der Nutzung von
|
||||
Informationen nach den allgemeinen Gesetzen bleiben hiervon
|
||||
unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem
|
||||
Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei
|
||||
Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese
|
||||
Inhalte umgehend entfernen.
|
||||
</p>
|
||||
|
||||
<h2>Haftung für Links</h2>
|
||||
|
||||
<p>
|
||||
Unser Angebot enthält Links zu externen Websites Dritter, auf deren
|
||||
Inhalte wir keinen Einfluss haben. Deshalb können wir für diese
|
||||
fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der
|
||||
verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber
|
||||
der Seiten verantwortlich. Die verlinkten Seiten wurden zum
|
||||
Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft.
|
||||
Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht
|
||||
erkennbar.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist
|
||||
jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht
|
||||
zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir
|
||||
derartige Links umgehend entfernen.
|
||||
</p>
|
||||
|
||||
<h2>Urheberrecht</h2>
|
||||
|
||||
<p>
|
||||
Die durch die Seitenbetreiber erstellten Inhalte und Werke auf
|
||||
diesen Seiten unterliegen dem deutschen Urheberrecht. Die
|
||||
Vervielfältigung, Bearbeitung, Verbreitung und jede Art der
|
||||
Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der
|
||||
schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers.
|
||||
Downloads und Kopien dieser Seite sind nur für den privaten, nicht
|
||||
kommerziellen Gebrauch gestattet.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt
|
||||
wurden, werden die Urheberrechte Dritter beachtet. Insbesondere
|
||||
werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie
|
||||
trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten
|
||||
wir um einen entsprechenden Hinweis. Bei Bekanntwerden von
|
||||
Rechtsverletzungen werden wir derartige Inhalte umgehend entfernen.
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
import React from "react";
|
||||
import Layout from "../../layouts/default";
|
||||
import { Trans, useI18next } from "gatsby-plugin-react-i18next";
|
||||
import { graphql } from "gatsby";
|
||||
|
||||
export const query = graphql`
|
||||
query ($language: String!) {
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default function DisclaimerPage() {
|
||||
const { t } = useI18next();
|
||||
return (
|
||||
<Layout title={t("disclaimer")}>
|
||||
<section>
|
||||
<article>
|
||||
<h1>
|
||||
<Trans>disclaimer</Trans>
|
||||
</h1>
|
||||
|
||||
<h2>Haftung für Inhalte</h2>
|
||||
|
||||
<p>
|
||||
Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für
|
||||
eigene Inhalte auf diesen Seiten nach den allgemeinen
|
||||
Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir
|
||||
als Diensteanbieter jedoch nicht verpflichtet,
|
||||
übermittelte oder gespeicherte fremde Informationen zu
|
||||
überwachen oder nach Umständen zu forschen, die auf eine
|
||||
rechtswidrige Tätigkeit hinweisen.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Verpflichtungen zur Entfernung oder Sperrung der Nutzung
|
||||
von Informationen nach den allgemeinen Gesetzen bleiben
|
||||
hiervon unberührt. Eine diesbezügliche Haftung ist
|
||||
jedoch erst ab dem Zeitpunkt der Kenntnis einer
|
||||
konkreten Rechtsverletzung möglich. Bei Bekanntwerden
|
||||
von entsprechenden Rechtsverletzungen werden wir diese
|
||||
Inhalte umgehend entfernen.
|
||||
</p>
|
||||
|
||||
<h2>Haftung für Links</h2>
|
||||
|
||||
<p>
|
||||
Unser Angebot enthält Links zu externen Websites
|
||||
Dritter, auf deren Inhalte wir keinen Einfluss haben.
|
||||
Deshalb können wir für diese fremden Inhalte auch keine
|
||||
Gewähr übernehmen. Für die Inhalte der verlinkten Seiten
|
||||
ist stets der jeweilige Anbieter oder Betreiber der
|
||||
Seiten verantwortlich. Die verlinkten Seiten wurden zum
|
||||
Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße
|
||||
überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der
|
||||
Verlinkung nicht erkennbar.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Eine permanente inhaltliche Kontrolle der verlinkten
|
||||
Seiten ist jedoch ohne konkrete Anhaltspunkte einer
|
||||
Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von
|
||||
Rechtsverletzungen werden wir derartige Links umgehend
|
||||
entfernen.
|
||||
</p>
|
||||
|
||||
<h2>Urheberrecht</h2>
|
||||
|
||||
<p>
|
||||
Die durch die Seitenbetreiber erstellten Inhalte und
|
||||
Werke auf diesen Seiten unterliegen dem deutschen
|
||||
Urheberrecht. Die Vervielfältigung, Bearbeitung,
|
||||
Verbreitung und jede Art der Verwertung außerhalb der
|
||||
Grenzen des Urheberrechtes bedürfen der schriftlichen
|
||||
Zustimmung des jeweiligen Autors bzw. Erstellers.
|
||||
Downloads und Kopien dieser Seite sind nur für den
|
||||
privaten, nicht kommerziellen Gebrauch gestattet.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Soweit die Inhalte auf dieser Seite nicht vom Betreiber
|
||||
erstellt wurden, werden die Urheberrechte Dritter
|
||||
beachtet. Insbesondere werden Inhalte Dritter als solche
|
||||
gekennzeichnet. Sollten Sie trotzdem auf eine
|
||||
Urheberrechtsverletzung aufmerksam werden, bitten wir um
|
||||
einen entsprechenden Hinweis. Bei Bekanntwerden von
|
||||
Rechtsverletzungen werden wir derartige Inhalte umgehend
|
||||
entfernen.
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,88 +1,94 @@
|
|||
import React from "react";
|
||||
import Layout from "../layouts/default";
|
||||
import { Trans, Link, useI18next } from "gatsby-plugin-react-i18next";
|
||||
import { graphql } from "gatsby";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import * as styles from "./projects.module.scss";
|
||||
|
||||
export const query = graphql`
|
||||
query GetProjects($language: String) {
|
||||
allProjectsJson(filter: { lang: { eq: $language } }) {
|
||||
nodes {
|
||||
lang
|
||||
urlname
|
||||
name
|
||||
image {
|
||||
childImageSharp {
|
||||
resize(width: 400, quality: 90) {
|
||||
src
|
||||
}
|
||||
}
|
||||
}
|
||||
shortDescription
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const ProjectsPage = ({ data }) => {
|
||||
const { t } = useI18next();
|
||||
return (
|
||||
<Layout title={t("projects")} description={t("projectsDescription")}>
|
||||
<section>
|
||||
<article>
|
||||
<h1>
|
||||
<Trans>projects</Trans>
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
<Trans>projectsDescription</Trans>
|
||||
</p>
|
||||
|
||||
<div className={styles.projectList}>
|
||||
{data.allProjectsJson.nodes.map((project) => {
|
||||
return (
|
||||
<Link
|
||||
className={styles.projectCard}
|
||||
key={project.lang + project.urlname}
|
||||
to={"/projects/" + project.urlname}
|
||||
>
|
||||
<div
|
||||
className={styles.projectCardImage}
|
||||
style={{
|
||||
backgroundImage:
|
||||
"url(" + project.image.childImageSharp.resize.src + ")",
|
||||
}}
|
||||
>
|
||||
<div className={styles.projectCardMeta}>
|
||||
<span className={styles.projectCardTitle}>
|
||||
{project.name}
|
||||
</span>
|
||||
<span>{project.shortDescription}</span>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
ProjectsPage.propTypes = {
|
||||
data: PropTypes.object,
|
||||
};
|
||||
|
||||
export default ProjectsPage;
|
||||
import React from "react";
|
||||
import Layout from "../layouts/default";
|
||||
import { Trans, Link, useI18next } from "gatsby-plugin-react-i18next";
|
||||
import { graphql } from "gatsby";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import * as styles from "./projects.module.scss";
|
||||
|
||||
export const query = graphql`
|
||||
query GetProjects($language: String) {
|
||||
allProjectsJson(filter: { lang: { eq: $language } }) {
|
||||
nodes {
|
||||
lang
|
||||
urlname
|
||||
name
|
||||
image {
|
||||
childImageSharp {
|
||||
resize(width: 400, quality: 90) {
|
||||
src
|
||||
}
|
||||
}
|
||||
}
|
||||
shortDescription
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const ProjectsPage = ({ data }) => {
|
||||
const { t } = useI18next();
|
||||
return (
|
||||
<Layout title={t("projects")} description={t("projectsDescription")}>
|
||||
<section>
|
||||
<article>
|
||||
<h1>
|
||||
<Trans>projects</Trans>
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
<Trans>projectsDescription</Trans>
|
||||
</p>
|
||||
|
||||
<div className={styles.projectList}>
|
||||
{data.allProjectsJson.nodes.map((project) => {
|
||||
return (
|
||||
<Link
|
||||
className={styles.projectCard}
|
||||
key={project.lang + project.urlname}
|
||||
to={"/projects/" + project.urlname}>
|
||||
<div
|
||||
className={styles.projectCardImage}
|
||||
style={{
|
||||
backgroundImage:
|
||||
"url(" +
|
||||
project.image.childImageSharp
|
||||
.resize.src +
|
||||
")",
|
||||
}}>
|
||||
<div className={styles.projectCardMeta}>
|
||||
<span
|
||||
className={
|
||||
styles.projectCardTitle
|
||||
}>
|
||||
{project.name}
|
||||
</span>
|
||||
<span>
|
||||
{project.shortDescription}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
ProjectsPage.propTypes = {
|
||||
data: PropTypes.object,
|
||||
};
|
||||
|
||||
export default ProjectsPage;
|
||||
|
|
|
@ -1,89 +1,89 @@
|
|||
@import "../variables";
|
||||
@import "../mixins";
|
||||
|
||||
.projectList {
|
||||
@include flexList;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.projectCard {
|
||||
@include cardGeneric;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
width: 250px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.projectCardActivityIndicator {
|
||||
position: absolute;
|
||||
margin: 12px;
|
||||
padding: 2px 5px;
|
||||
border-radius: 3px;
|
||||
|
||||
&.activityIndicatorGreen {
|
||||
background: #26de81;
|
||||
}
|
||||
|
||||
&.activityIndicatorYellow {
|
||||
background: #f7b731;
|
||||
}
|
||||
|
||||
&.activityIndicatorRed {
|
||||
background: #fc5c65;
|
||||
}
|
||||
|
||||
&.activityIndicatorBlue {
|
||||
background: #45aaf2;
|
||||
}
|
||||
}
|
||||
|
||||
.projectCardImage {
|
||||
width: 100%;
|
||||
height: 250px;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
text-shadow: 0 0 10px black, 0 0 10px black, 0 0 20px black;
|
||||
}
|
||||
|
||||
.projectCardMeta {
|
||||
padding: 10px;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
height: 100%;
|
||||
background: linear-gradient(to bottom, transparent, black);
|
||||
}
|
||||
|
||||
.projectCardTitle {
|
||||
display: block;
|
||||
font-size: 1.5em;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.projectCardCTA {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.projectCardCTA a {
|
||||
@include buttonBasic;
|
||||
}
|
||||
|
||||
.projectCardCTAContainer {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.projectCardCTAContainer {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.projectCardCTA:nth-child(2) {
|
||||
border-left: none;
|
||||
}
|
||||
}
|
||||
|
||||
.projectCardCTAContainer > * {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
@import "../variables";
|
||||
@import "../mixins";
|
||||
|
||||
.projectList {
|
||||
@include flexList;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.projectCard {
|
||||
@include cardGeneric;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
width: 250px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.projectCardActivityIndicator {
|
||||
position: absolute;
|
||||
margin: 12px;
|
||||
padding: 2px 5px;
|
||||
border-radius: 3px;
|
||||
|
||||
&.activityIndicatorGreen {
|
||||
background: #26de81;
|
||||
}
|
||||
|
||||
&.activityIndicatorYellow {
|
||||
background: #f7b731;
|
||||
}
|
||||
|
||||
&.activityIndicatorRed {
|
||||
background: #fc5c65;
|
||||
}
|
||||
|
||||
&.activityIndicatorBlue {
|
||||
background: #45aaf2;
|
||||
}
|
||||
}
|
||||
|
||||
.projectCardImage {
|
||||
width: 100%;
|
||||
height: 250px;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
text-shadow: 0 0 10px black, 0 0 10px black, 0 0 20px black;
|
||||
}
|
||||
|
||||
.projectCardMeta {
|
||||
padding: 10px;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
height: 100%;
|
||||
background: linear-gradient(to bottom, transparent, black);
|
||||
}
|
||||
|
||||
.projectCardTitle {
|
||||
display: block;
|
||||
font-size: 1.5em;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.projectCardCTA {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.projectCardCTA a {
|
||||
@include buttonBasic;
|
||||
}
|
||||
|
||||
.projectCardCTAContainer {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.projectCardCTAContainer {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.projectCardCTA:nth-child(2) {
|
||||
border-left: none;
|
||||
}
|
||||
}
|
||||
|
||||
.projectCardCTAContainer > * {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,82 +1,83 @@
|
|||
import React from "react";
|
||||
import Layout from "../layouts/default";
|
||||
import { Trans, Link, useI18next } from "gatsby-plugin-react-i18next";
|
||||
import { graphql } from "gatsby";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import * as styles from "./social.module.scss";
|
||||
|
||||
export const query = graphql`
|
||||
query AllSocialsQuery($language: String!) {
|
||||
allSocialsJson {
|
||||
nodes {
|
||||
image
|
||||
platformHandle
|
||||
platformName
|
||||
url
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const SocialPage = ({ data }) => {
|
||||
const { t } = useI18next();
|
||||
return (
|
||||
<Layout title={t("social")} description={t("socialDescription")}>
|
||||
<section>
|
||||
<article>
|
||||
<h1>
|
||||
<Trans>social</Trans>
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
<Trans i18nKey="socialDescriptionWithLink">
|
||||
socialDescriptionWith<Link to="/friends">Link</Link>
|
||||
</Trans>
|
||||
</p>
|
||||
|
||||
<div className={styles.socialList}>
|
||||
{data.allSocialsJson.nodes.map((social) => {
|
||||
return (
|
||||
<a
|
||||
className={styles.socialCard}
|
||||
href={social.url}
|
||||
target="_blank"
|
||||
rel="noreferrer me"
|
||||
key={social.url}
|
||||
>
|
||||
<div
|
||||
className={styles.socialImage}
|
||||
style={{ backgroundImage: "url(" + social.image + ")" }}
|
||||
>
|
||||
<span className={styles.socialName}>
|
||||
{social.platformName}
|
||||
</span>
|
||||
<span className={styles.socialUsername}>
|
||||
{social.platformHandle}
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
SocialPage.propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default SocialPage;
|
||||
import React from "react";
|
||||
import Layout from "../layouts/default";
|
||||
import { Trans, Link, useI18next } from "gatsby-plugin-react-i18next";
|
||||
import { graphql } from "gatsby";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import * as styles from "./social.module.scss";
|
||||
|
||||
export const query = graphql`
|
||||
query AllSocialsQuery($language: String!) {
|
||||
allSocialsJson {
|
||||
nodes {
|
||||
image
|
||||
platformHandle
|
||||
platformName
|
||||
url
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const SocialPage = ({ data }) => {
|
||||
const { t } = useI18next();
|
||||
return (
|
||||
<Layout title={t("social")} description={t("socialDescription")}>
|
||||
<section>
|
||||
<article>
|
||||
<h1>
|
||||
<Trans>social</Trans>
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
<Trans i18nKey="socialDescriptionWithLink">
|
||||
socialDescriptionWith<Link to="/friends">Link</Link>
|
||||
</Trans>
|
||||
</p>
|
||||
|
||||
<div className={styles.socialList}>
|
||||
{data.allSocialsJson.nodes.map((social) => {
|
||||
return (
|
||||
<a
|
||||
className={styles.socialCard}
|
||||
href={social.url}
|
||||
target="_blank"
|
||||
rel="noreferrer me"
|
||||
key={social.url}>
|
||||
<div
|
||||
className={styles.socialImage}
|
||||
style={{
|
||||
backgroundImage:
|
||||
"url(" + social.image + ")",
|
||||
}}>
|
||||
<span className={styles.socialName}>
|
||||
{social.platformName}
|
||||
</span>
|
||||
<span className={styles.socialUsername}>
|
||||
{social.platformHandle}
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
SocialPage.propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default SocialPage;
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
@import "../variables";
|
||||
@import "../mixins";
|
||||
|
||||
.socialList {
|
||||
@include flexList;
|
||||
|
||||
.socialCard {
|
||||
@include cardGeneric;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.socialImage {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
flex-direction: column-reverse;
|
||||
text-shadow: 0 0 10px black, 0 0 10px black, 0 0 20px black;
|
||||
|
||||
.socialName {
|
||||
font-size: 2em;
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
.socialUsername {
|
||||
margin-top: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@import "../variables";
|
||||
@import "../mixins";
|
||||
|
||||
.socialList {
|
||||
@include flexList;
|
||||
|
||||
.socialCard {
|
||||
@include cardGeneric;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.socialImage {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
flex-direction: column-reverse;
|
||||
text-shadow: 0 0 10px black, 0 0 10px black, 0 0 20px black;
|
||||
|
||||
.socialName {
|
||||
font-size: 2em;
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
.socialUsername {
|
||||
margin-top: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,122 +1,128 @@
|
|||
import React from "react";
|
||||
import { graphql } from "gatsby";
|
||||
import { Trans, useTranslation } from "gatsby-plugin-react-i18next";
|
||||
import Layout from "../layouts/default";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import * as styles from "./project.module.scss";
|
||||
import { MDXRenderer } from "gatsby-plugin-mdx";
|
||||
|
||||
export const query = graphql`
|
||||
query GetProject($urlname: String!, $lang: String!, $language: String!) {
|
||||
allProjectsJson(
|
||||
filter: { urlname: { eq: $urlname }, lang: { eq: $lang } }
|
||||
) {
|
||||
nodes {
|
||||
lang
|
||||
urlname
|
||||
name
|
||||
links {
|
||||
github
|
||||
website
|
||||
}
|
||||
image {
|
||||
publicURL
|
||||
}
|
||||
shortDescription
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
file(
|
||||
sourceInstanceName: {eq: "projectTextblocks"}, relativeDirectory: {eq: $urlname}, name: {eq: $language}
|
||||
) {
|
||||
id
|
||||
childMdx {
|
||||
body
|
||||
}
|
||||
name
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const ProjectTemplate = ({ data }) => {
|
||||
const { t } = useTranslation();
|
||||
let project = data.allProjectsJson.nodes[0];
|
||||
let projectName = project.name;
|
||||
let file = data.file;
|
||||
|
||||
return (
|
||||
<Layout
|
||||
description={project.shortDescription}
|
||||
title={t("project") + ": " + projectName}
|
||||
transparentTopbar={true}
|
||||
>
|
||||
<section className={styles.projectHeader}>
|
||||
<div style={{ paddingTop: 0 }}>
|
||||
<div
|
||||
className={styles.headerBackground}
|
||||
style={{ backgroundImage: "url(" + project.image.publicURL + ")" }}
|
||||
></div>
|
||||
<header>
|
||||
<div className={styles.headerInner}>
|
||||
<h1>
|
||||
<Trans>project</Trans>: {projectName}
|
||||
</h1>
|
||||
<span>{project.shortDescription}</span>
|
||||
</div>
|
||||
</header>
|
||||
<div className={styles.headerPlaceholder}></div>
|
||||
</div>
|
||||
</section>
|
||||
{file != null && file.childMdx != null ? (
|
||||
<section className={styles.projectAbout}>
|
||||
<article>
|
||||
<MDXRenderer>{file.childMdx.body}</MDXRenderer>
|
||||
</article>
|
||||
</section>
|
||||
) : null}
|
||||
{project.links !== null ? (
|
||||
<section className={styles.projectLinks}>
|
||||
<div>
|
||||
<h1>Links</h1>
|
||||
<div className={styles.linkList}>
|
||||
{project.links.github !== null ? (
|
||||
<a href={project.links.github} target="_blank" rel="noreferrer">
|
||||
<i className="fab fa-github" aria-hidden="true"></i>{" "}
|
||||
<Trans>projectViewGitHub</Trans>
|
||||
</a>
|
||||
) : null}
|
||||
{project.links.website !== null ? (
|
||||
<a
|
||||
href={project.links.website}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<i
|
||||
className="fas fa-external-link-alt"
|
||||
aria-hidden="true"
|
||||
></i>{" "}
|
||||
<Trans>projectViewWebsite</Trans>
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
) : null}
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
ProjectTemplate.propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default ProjectTemplate;
|
||||
import React from "react";
|
||||
import { graphql } from "gatsby";
|
||||
import { Trans, useTranslation } from "gatsby-plugin-react-i18next";
|
||||
import Layout from "../layouts/default";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import * as styles from "./project.module.scss";
|
||||
import { MDXRenderer } from "gatsby-plugin-mdx";
|
||||
|
||||
export const query = graphql`
|
||||
query GetProject($urlname: String!, $lang: String!, $language: String!) {
|
||||
allProjectsJson(
|
||||
filter: { urlname: { eq: $urlname }, lang: { eq: $lang } }
|
||||
) {
|
||||
nodes {
|
||||
lang
|
||||
urlname
|
||||
name
|
||||
links {
|
||||
github
|
||||
website
|
||||
}
|
||||
image {
|
||||
publicURL
|
||||
}
|
||||
shortDescription
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
file(
|
||||
sourceInstanceName: { eq: "projectTextblocks" }
|
||||
relativeDirectory: { eq: $urlname }
|
||||
name: { eq: $language }
|
||||
) {
|
||||
id
|
||||
childMdx {
|
||||
body
|
||||
}
|
||||
name
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const ProjectTemplate = ({ data }) => {
|
||||
const { t } = useTranslation();
|
||||
let project = data.allProjectsJson.nodes[0];
|
||||
let projectName = project.name;
|
||||
let file = data.file;
|
||||
|
||||
return (
|
||||
<Layout
|
||||
description={project.shortDescription}
|
||||
title={t("project") + ": " + projectName}
|
||||
transparentTopbar={true}>
|
||||
<section className={styles.projectHeader}>
|
||||
<div style={{ paddingTop: 0 }}>
|
||||
<div
|
||||
className={styles.headerBackground}
|
||||
style={{
|
||||
backgroundImage:
|
||||
"url(" + project.image.publicURL + ")",
|
||||
}}></div>
|
||||
<header>
|
||||
<div className={styles.headerInner}>
|
||||
<h1>
|
||||
<Trans>project</Trans>: {projectName}
|
||||
</h1>
|
||||
<span>{project.shortDescription}</span>
|
||||
</div>
|
||||
</header>
|
||||
<div className={styles.headerPlaceholder}></div>
|
||||
</div>
|
||||
</section>
|
||||
{file != null && file.childMdx != null ? (
|
||||
<section className={styles.projectAbout}>
|
||||
<article>
|
||||
<MDXRenderer>{file.childMdx.body}</MDXRenderer>
|
||||
</article>
|
||||
</section>
|
||||
) : null}
|
||||
{project.links !== null ? (
|
||||
<section className={styles.projectLinks}>
|
||||
<div>
|
||||
<h1>Links</h1>
|
||||
<div className={styles.linkList}>
|
||||
{project.links.github !== null ? (
|
||||
<a
|
||||
href={project.links.github}
|
||||
target="_blank"
|
||||
rel="noreferrer">
|
||||
<i
|
||||
className="fab fa-github"
|
||||
aria-hidden="true"></i>{" "}
|
||||
<Trans>projectViewGitHub</Trans>
|
||||
</a>
|
||||
) : null}
|
||||
{project.links.website !== null ? (
|
||||
<a
|
||||
href={project.links.website}
|
||||
target="_blank"
|
||||
rel="noreferrer">
|
||||
<i
|
||||
className="fas fa-external-link-alt"
|
||||
aria-hidden="true"></i>{" "}
|
||||
<Trans>projectViewWebsite</Trans>
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
) : null}
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
ProjectTemplate.propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default ProjectTemplate;
|
||||
|
|
|
@ -1,99 +1,99 @@
|
|||
@import "../variables";
|
||||
|
||||
.projectHeader {
|
||||
> div {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.headerBackground {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
header {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba($background, 0.95),
|
||||
rgba($background, 0.25) 20%,
|
||||
rgba($background, 0.35) 80%,
|
||||
rgba($background, 1) 100%
|
||||
);
|
||||
|
||||
.headerInner {
|
||||
max-width: $layoutWidth;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-shadow: 0 0 10px black, 0 0 20px black;
|
||||
padding: 10px 20px;
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
color: white;
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.2em;
|
||||
margin-top: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.headerPlaceholder {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
.projectAbout,
|
||||
.projectLinks {
|
||||
&:nth-of-type(2) {
|
||||
> div,
|
||||
> article {
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.projectAbout {
|
||||
background: #060606;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.projectLinks {
|
||||
.linkList {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
a {
|
||||
display: inline-block;
|
||||
border: thin solid rgb(200, 200, 200);
|
||||
border-radius: 5px;
|
||||
padding: 10px 15px;
|
||||
margin: 5px;
|
||||
color: $textColor;
|
||||
text-decoration-skip: none;
|
||||
text-decoration: underline dotted currentColor;
|
||||
|
||||
i.fab,
|
||||
i.fas,
|
||||
i.fa,
|
||||
i.far,
|
||||
i.fal {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
@import "../variables";
|
||||
|
||||
.projectHeader {
|
||||
> div {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.headerBackground {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
header {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba($background, 0.95),
|
||||
rgba($background, 0.25) 20%,
|
||||
rgba($background, 0.35) 80%,
|
||||
rgba($background, 1) 100%
|
||||
);
|
||||
|
||||
.headerInner {
|
||||
max-width: $layoutWidth;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-shadow: 0 0 10px black, 0 0 20px black;
|
||||
padding: 10px 20px;
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
color: white;
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.2em;
|
||||
margin-top: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.headerPlaceholder {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
.projectAbout,
|
||||
.projectLinks {
|
||||
&:nth-of-type(2) {
|
||||
> div,
|
||||
> article {
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.projectAbout {
|
||||
background: #060606;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.projectLinks {
|
||||
.linkList {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
a {
|
||||
display: inline-block;
|
||||
border: thin solid rgb(200, 200, 200);
|
||||
border-radius: 5px;
|
||||
padding: 10px 15px;
|
||||
margin: 5px;
|
||||
color: $textColor;
|
||||
text-decoration-skip: none;
|
||||
text-decoration: underline dotted currentColor;
|
||||
|
||||
i.fab,
|
||||
i.fas,
|
||||
i.fa,
|
||||
i.far,
|
||||
i.fal {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue