Configure & Run prettier

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

View file

@ -28,9 +28,7 @@
"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.

View file

@ -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"
}
}
}
}

View file

@ -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
- run: npm run build
name: Build Site
- uses: actions/upload-artifact@v2
name: Upload Artifacts
with:
name: site
path: public
- uses: actions/upload-artifact@v2
name: Upload Artifacts
with:
name: site
path: public

4
.prettierignore Normal file
View file

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

8
.prettierrc.json Normal file
View file

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

View file

@ -1,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",
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",
};

View file

@ -2,106 +2,112 @@
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,
siteMetadata: {
title: extConfig.siteName,
author: extConfig.siteAuthor,
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,
},
],
},
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,
},
],
},
},
],
};

View file

@ -3,172 +3,177 @@ const path = require(`path`);
const fs = require("fs");
exports.createPages = async ({ actions, graphql, reporter }) => {
const { createPage } = actions;
const { createPage } = actions;
const projectTemplate = path.resolve(`src/templates/project.js`);
const projectTemplate = path.resolve(`src/templates/project.js`);
const result = await graphql(`
query AllPagesQuery {
allProjectsJson {
nodes {
lang
urlname
const result = await graphql(`
query AllPagesQuery {
allProjectsJson {
nodes {
lang
urlname
}
}
}
}
`);
if (result.errors) {
reporter.panicOnBuild(`Error while running GraphQL query.`);
return;
}
`);
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}`
);
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,
},
});
});
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...");
console.log("Building static api...");
const apiPrefix = "./public/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";
});
if (!fs.existsSync(apiPrefix)) fs.mkdirSync(apiPrefix);
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`,
};
}),
})
`${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",
},
],
},
})
);
config.languages.forEach((lang) => {
if (!fs.existsSync(`${projectsPrefix}/${lang}`))
fs.mkdirSync(`${projectsPrefix}/${lang}`);
const projectsPrefix = apiPrefix + "/projects";
fs.writeFileSync(
`${projectsPrefix}/${lang}.json`,
JSON.stringify({
success: true,
projects: projects
.filter((project) => {
return project.lang == lang;
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`,
};
}),
})
.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}`,
},
})
);
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}`,
},
})
);
});
});
});
};

View file

@ -11,9 +11,7 @@
"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",
"prettier": "npx prettier --write .",
"serve": "gatsby serve",
"clean": "gatsby clean"
},
@ -63,6 +61,7 @@
"eslint-loader": "4.0.2",
"eslint-plugin-import": "2.23.4",
"eslint-plugin-react": "7.24.0",
"gatsby-plugin-eslint": "2.0.8"
"gatsby-plugin-eslint": "2.0.8",
"prettier": "2.3.2"
}
}

View file

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

View file

@ -6,86 +6,87 @@ import { graphql, StaticQuery } from "gatsby";
import * as styles from "./navigation.module.scss";
const Navigation = ({ isHome }) => {
let [atTop, setAtTop] = useState(false);
let [atTop, setAtTop] = useState(false);
const updateTransparency = () => {
if (typeof window === "undefined") return;
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);
// eslint-disable-next-line no-undef
if (window.scrollY < 15) {
if (!atTop) setAtTop(true);
} else {
if (atTop) setAtTop(false);
}
};
});
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>
);
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,
isHome: PropTypes.bool.isRequired,
};
export default Navigation;

View file

@ -5,89 +5,89 @@ 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 { t } = useTranslation();
const { site } = useStaticQuery(
graphql`
query {
site {
siteMetadata {
title
author
keywords
}
}
}
`
);
const metaDescription = description || t("siteDescription");
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>
);
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: ``,
meta: [],
description: ``,
};
SEO.propTypes = {
description: PropTypes.string,
meta: PropTypes.arrayOf(PropTypes.object),
title: PropTypes.string.isRequired,
description: PropTypes.string,
meta: PropTypes.arrayOf(PropTypes.object),
title: PropTypes.string.isRequired,
};
export default SEO;

View file

@ -8,55 +8,55 @@ 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>
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 />
</>
);
}
<LanguageSwitcher />
</>
);
}
}
Layout.defaultProps = {
module: `none`,
meta: [],
description: ``,
transparentTopbar: false,
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,
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;

View file

@ -3,19 +3,19 @@ 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&apos;t exist, so you may as well{" "}
<Link to="/">go home</Link>.
</p>
</article>
</section>
</Layout>
);
return (
<Layout title="Not found">
<section>
<article>
<h1>Page not found</h1>
<p>
Whoops... That page doesn&apos;t exist, so you may as
well <Link to="/">go home</Link>.
</p>
</article>
</section>
</Layout>
);
};
export default NotFoundPage;

View file

@ -8,128 +8,135 @@ 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
query ($language: String!) {
site {
siteMetadata {
title
siteUrl
payPalMail
contactGitHub
}
}
}
}
locales: allLocale(filter: { language: { eq: $language } }) {
edges {
node {
ns
data
language
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 [amount, setAmount] = useState(5);
const { t } = useI18next();
const { path } = React.useContext(I18nextContext);
const { site, file } = props.data;
const { site, file } = props.data;
return (
<Layout title={t("donate")} description={t("donationCatchphrase")}>
<section>
<article>
<h1>
<Trans>donate</Trans>
</h1>
return (
<Layout title={t("donate")} description={t("donationCatchphrase")}>
<section>
<article>
<h1>
<Trans>donate</Trans>
</h1>
<p>
<Trans>donateDescription</Trans>
</p>
<p>
<Trans>donateDescription</Trans>
</p>
<p>
<Trans>donateGitHub</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 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>
<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>
<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) +
"&currency_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>
);
<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) +
"&currency_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,
data: PropTypes.object.isRequired,
};
export default DonatePage;

View file

@ -5,51 +5,55 @@ 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
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;
const { site } = props.data;
let contactEmail = site.siteMetadata.contactEmail;
const { t } = useI18next();
return (
<Layout title={t("donate")}>
<section>
<article>
<h1>
<Trans>donateThanks</Trans>
</h1>
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>
);
<p>
<Trans
contactEmail={contactEmail}
i18nKey="donateThanksText">
donateThanksText
<a href={"mailto:" + contactEmail}>
{{ contactEmail }}
</a>
</Trans>
</p>
</article>
</section>
</Layout>
);
};
ThankYouPage.propTypes = {
data: PropTypes.object.isRequired,
data: PropTypes.object.isRequired,
};
export default ThankYouPage;

View file

@ -7,31 +7,31 @@ 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
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();
const { t } = useI18next();
/*function shuffle(a) {
/*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]];
@ -39,59 +39,102 @@ const FriendsPage = ({ data }) => {
return a;
}*/
return (
<Layout title={t("friends")} description={t("friendsDescription")}>
<section>
<article>
<h1>
<Trans>social</Trans>
</h1>
return (
<Layout title={t("friends")} description={t("friendsDescription")}>
<section>
<article>
<h1>
<Trans>social</Trans>
</h1>
<p>
<Trans>friendsDescription</Trans>
</p>
<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.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>
);
<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,
data: PropTypes.object.isRequired,
};
export default FriendsPage;

View file

@ -12,244 +12,253 @@ 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
query GetMetaAndProjects($language: String) {
site {
siteMetadata {
contactEmail
contactPhone
mapsLink
contactTwitter
contactGitHub
contactMastodon
contactMastodonHref
}
}
}
shortDescription
featured
}
}
locales: allLocale(filter: { language: { eq: $language } }) {
edges {
node {
ns
data
language
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
}
}
}
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;
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",
});
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);
}, []);
tsParticles.load("particle-container", particleConfig);
}, []);
let meta = props.data.site.siteMetadata;
let file = props.data.file;
let meta = props.data.site.siteMetadata;
let file = props.data.file;
return (
<Layout title="Kevin Kandlbinder" transparentTopbar={true}>
<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>
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 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>
</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>
);
</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,
data: PropTypes.object.isRequired,
};
export default IndexPage;

View file

@ -6,7 +6,8 @@
height: 600px;
overflow: hidden;
.heroSectionBg, .heroSectionBgOver {
.heroSectionBg,
.heroSectionBgOver {
position: absolute;
width: 100%;
max-width: unset;
@ -22,7 +23,20 @@
/*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: 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;
}

View file

@ -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,
"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": {
"opacity": 1
"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
}
}
},
"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
},
"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
}

View file

@ -4,53 +4,56 @@ 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
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>
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>
);
<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

View file

@ -4,91 +4,98 @@ 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
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>
const { t } = useI18next();
return (
<Layout title={t("disclaimer")}>
<section>
<article>
<h1>
<Trans>disclaimer</Trans>
</h1>
<h2>Haftung für Inhalte</h2>
<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>
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>
<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>
<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>
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>
<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>
<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>
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>
);
<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>
);
}

View file

@ -7,82 +7,88 @@ 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
query GetProjects($language: String) {
allProjectsJson(filter: { lang: { eq: $language } }) {
nodes {
lang
urlname
name
image {
childImageSharp {
resize(width: 400, quality: 90) {
src
}
}
}
shortDescription
}
}
}
shortDescription
}
}
locales: allLocale(filter: { language: { eq: $language } }) {
edges {
node {
ns
data
language
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>
const { t } = useI18next();
return (
<Layout title={t("projects")} description={t("projectsDescription")}>
<section>
<article>
<h1>
<Trans>projects</Trans>
</h1>
<p>
<Trans>projectsDescription</Trans>
</p>
<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 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>
</div>
</Link>
);
})}
</div>
</article>
</section>
</Layout>
);
</article>
</section>
</Layout>
);
};
ProjectsPage.propTypes = {
data: PropTypes.object,
data: PropTypes.object,
};
export default ProjectsPage;

View file

@ -7,76 +7,77 @@ 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
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>
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>
<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>
);
<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,
data: PropTypes.object.isRequired,
};
export default SocialPage;

View file

@ -8,115 +8,121 @@ 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
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
}
}
image {
publicURL
locales: allLocale(filter: { language: { eq: $language } }) {
edges {
node {
ns
data
language
}
}
}
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
}
}
}
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;
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>
);
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,
data: PropTypes.object.isRequired,
};
export default ProjectTemplate;