mirror of
https://github.com/Unkn0wnCat/KevinK.dev.js.git
synced 2025-04-28 09:46:52 +02:00
Add more structured metadata
This commit is contained in:
parent
df9e2b2bb8
commit
412ee72112
10 changed files with 148 additions and 5 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -1,3 +1,4 @@
|
|||
{
|
||||
"i18n-ally.localesPaths": "locales"
|
||||
"i18n-ally.localesPaths": "locales",
|
||||
"i18n-ally.keystyle": "nested"
|
||||
}
|
|
@ -10,9 +10,18 @@ module.exports = {
|
|||
languages: ["en", "de"],
|
||||
contactEmail: "kevin@kevink.dev",
|
||||
contactPhone: "+4941068068004",
|
||||
address: "25451 Quickborn, Schleswig-Holstein, Germany",
|
||||
mapsLink: "https://goo.gl/maps/KVq9z1PVaVP2",
|
||||
contactTwitter: "Unkn0wnKevin",
|
||||
contactGitHub: "Unkn0wnCat",
|
||||
contactMastodon: "@kevin@1in1.net",
|
||||
contactMastodonHref: "https://mastodon.1in1.net/@kevin",
|
||||
givenName: "Kevin",
|
||||
familyName: "Kandlbinder",
|
||||
birthDate: "2001-03-11",
|
||||
gender: "Male",
|
||||
height: "168 cm",
|
||||
nationality: "Germany",
|
||||
personImage: "./content/images/kevin-kandlbinder-04.jpg",
|
||||
sameAs: ["https://mastodon.1in1.net/@kevin", "https://github.com/Unkn0wnCat", "https://unkn0wncat.net/", "https://twitter.com/@Unkn0wnKevin", "https://unsplash.com/@unkn0wncat"]
|
||||
};
|
||||
|
|
|
@ -11,10 +11,19 @@ module.exports = {
|
|||
contactEmail: extConfig.contactEmail,
|
||||
contactPhone: extConfig.contactPhone,
|
||||
mapsLink: extConfig.mapsLink,
|
||||
address: extConfig.address,
|
||||
contactTwitter: extConfig.contactTwitter,
|
||||
contactGitHub: extConfig.contactGitHub,
|
||||
contactMastodon: extConfig.contactMastodon,
|
||||
contactMastodonHref: extConfig.contactMastodonHref,
|
||||
givenName: extConfig.givenName,
|
||||
familyName: extConfig.familyName,
|
||||
birthDate: extConfig.birthDate,
|
||||
gender: extConfig.gender,
|
||||
height: extConfig.height,
|
||||
nationality: extConfig.nationality,
|
||||
personImage: extConfig.personImage,
|
||||
sameAs: extConfig.sameAs
|
||||
},
|
||||
plugins: [
|
||||
`gatsby-plugin-eslint`,
|
||||
|
|
|
@ -2,9 +2,11 @@ import React from "react";
|
|||
import PropTypes from "prop-types";
|
||||
import { Helmet } from "gatsby-plugin-react-i18next";
|
||||
import { useStaticQuery, graphql } from "gatsby";
|
||||
import { useLocation } from "@reach/router"
|
||||
import { useTranslation } from "gatsby-plugin-react-i18next";
|
||||
import useSiteMetadata from "../helpers/useSiteMetadata";
|
||||
|
||||
function SEO({ description, meta, title }) {
|
||||
function SEO({ description, meta, title, speakable, image, children }) {
|
||||
const { t } = useTranslation();
|
||||
const { site } = useStaticQuery(
|
||||
graphql`
|
||||
|
@ -22,6 +24,10 @@ function SEO({ description, meta, title }) {
|
|||
|
||||
const metaDescription = description || t("siteDescription");
|
||||
|
||||
const siteMeta = useSiteMetadata();
|
||||
const location = useLocation();
|
||||
|
||||
|
||||
return (
|
||||
<Helmet
|
||||
title={title}
|
||||
|
@ -79,6 +85,45 @@ function SEO({ description, meta, title }) {
|
|||
data-domain="kevink.dev"
|
||||
src="https://analytics.kevink.dev/js/plausible.js"
|
||||
></script>
|
||||
|
||||
{
|
||||
image && [
|
||||
<meta name="twitter:image" content={meta.siteUrl + image} key="twimg"/>,
|
||||
<meta name="og:image" content={meta.siteUrl + image} key="ogimg"/>,
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
<script type="application/ld+json">
|
||||
{JSON.stringify({
|
||||
"@context": "https://schema.org/",
|
||||
"@type": "WebPage",
|
||||
"name": title,
|
||||
"url": siteMeta.siteUrl+location.pathname,
|
||||
"speakable": speakable,
|
||||
"image": meta.siteUrl + image,
|
||||
"about": {
|
||||
"@type": "Person",
|
||||
"name": siteMeta.givenName + " " + siteMeta.familyName,
|
||||
"givenName": siteMeta.givenName,
|
||||
"familyName": siteMeta.familyName,
|
||||
"birthDate": siteMeta.birthDate,
|
||||
"address": siteMeta.address,
|
||||
"email": siteMeta.contactEmail,
|
||||
"telephone": siteMeta.contactPhone,
|
||||
"gender": siteMeta.gender,
|
||||
"height": siteMeta.height,
|
||||
"nationality": {
|
||||
"@type": "Country",
|
||||
"name": siteMeta.nationality
|
||||
},
|
||||
"image": siteMeta.siteUrl + "/owner.jpg",
|
||||
"sameAs": siteMeta.sameAs
|
||||
}
|
||||
})}
|
||||
</script>
|
||||
|
||||
{children}
|
||||
</Helmet>
|
||||
);
|
||||
}
|
||||
|
@ -92,6 +137,9 @@ SEO.propTypes = {
|
|||
description: PropTypes.string,
|
||||
meta: PropTypes.arrayOf(PropTypes.object),
|
||||
title: PropTypes.string.isRequired,
|
||||
speakable: PropTypes.any,
|
||||
image: PropTypes.string,
|
||||
children: PropTypes.any
|
||||
};
|
||||
|
||||
export default SEO;
|
||||
|
|
37
src/helpers/useSiteMetadata.js
Normal file
37
src/helpers/useSiteMetadata.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
import { useStaticQuery, graphql } from 'gatsby';
|
||||
|
||||
const useSiteMetadata = () => {
|
||||
const { site } = useStaticQuery(
|
||||
graphql`
|
||||
query {
|
||||
site {
|
||||
siteMetadata {
|
||||
title
|
||||
keywords
|
||||
author
|
||||
siteUrl
|
||||
payPalMail
|
||||
contactEmail
|
||||
contactPhone
|
||||
mapsLink
|
||||
contactTwitter
|
||||
contactGitHub
|
||||
contactMastodon
|
||||
contactMastodonHref
|
||||
givenName
|
||||
familyName
|
||||
birthDate
|
||||
address
|
||||
gender
|
||||
height
|
||||
nationality
|
||||
sameAs
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
);
|
||||
return site.siteMetadata;
|
||||
};
|
||||
|
||||
export default useSiteMetadata;
|
|
@ -16,7 +16,9 @@ class Layout extends React.Component {
|
|||
lang={this.props.lang}
|
||||
meta={this.props.meta}
|
||||
title={this.props.title}
|
||||
/>
|
||||
image={this.props.image}
|
||||
speakable={this.props.speakable}
|
||||
>{this.props.seoAdditional ?? null}</SEO>
|
||||
<Navigation isHome={this.props.transparentTopbar} />
|
||||
<div id="content" role="main">
|
||||
{this.props.children}
|
||||
|
@ -57,6 +59,9 @@ Layout.propTypes = {
|
|||
title: PropTypes.string.isRequired,
|
||||
transparentTopbar: PropTypes.bool,
|
||||
children: PropTypes.any.isRequired,
|
||||
seoAdditional: PropTypes.any,
|
||||
image: PropTypes.string,
|
||||
speakable: PropTypes.any
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
|
|
|
@ -112,7 +112,16 @@ const IndexPage = (props) => {
|
|||
let file = props.data.file;
|
||||
|
||||
return (
|
||||
<Layout title="Kevin Kandlbinder" transparentTopbar={true} description={t("siteDescription")}>
|
||||
<Layout title="Kevin Kandlbinder" transparentTopbar={true} description={t("siteDescription")}
|
||||
image={meta.siteUrl + "/owner.jpg"}
|
||||
speakable={{
|
||||
"@type": "SpeakableSpecification",
|
||||
"xPath": [
|
||||
"/html/head/title",
|
||||
"/html/head/meta[@name='description']/@content",
|
||||
"article"
|
||||
]
|
||||
}}>
|
||||
<section className={styles.heroSection}>
|
||||
<div
|
||||
className={styles.heroSectionBg}
|
||||
|
|
|
@ -6,6 +6,7 @@ import PropTypes from "prop-types";
|
|||
|
||||
import * as styles from "./projects.module.scss";
|
||||
import { GatsbyImage } from "gatsby-plugin-image";
|
||||
import useSiteMetadata from "../helpers/useSiteMetadata";
|
||||
|
||||
export const query = graphql`
|
||||
query GetProjects($language: String) {
|
||||
|
@ -21,6 +22,7 @@ export const query = graphql`
|
|||
childImageSharp {
|
||||
gatsbyImageData(placeholder: BLURRED, layout: FULL_WIDTH)
|
||||
}
|
||||
publicURL
|
||||
}
|
||||
shortDescription
|
||||
}
|
||||
|
@ -39,8 +41,29 @@ export const query = graphql`
|
|||
|
||||
const ProjectsPage = ({ data }) => {
|
||||
const { t } = useI18next();
|
||||
const meta = useSiteMetadata();
|
||||
return (
|
||||
<Layout title={t("projects")} description={t("projectsDescription")}>
|
||||
<Layout title={t("projects")} description={t("projectsDescription")} seoAdditional={
|
||||
|
||||
<script type="application/ld+json">
|
||||
{JSON.stringify(
|
||||
{
|
||||
"@context":"https://schema.org",
|
||||
"@type":"ItemList",
|
||||
"itemListElement":data.allProjectsJson.nodes.map((project, i) => {
|
||||
return {
|
||||
"@type":"ListItem",
|
||||
"position":i,
|
||||
"url": meta.siteUrl+"/projects/"+project.urlname,
|
||||
"image": project.image.publicURL,
|
||||
"name": project.name,
|
||||
"description": project.shortDescription
|
||||
}
|
||||
})
|
||||
}
|
||||
)}
|
||||
</script>
|
||||
}>
|
||||
<section>
|
||||
<article>
|
||||
<h1>
|
||||
|
|
|
@ -26,6 +26,7 @@ export const query = graphql`
|
|||
childImageSharp {
|
||||
gatsbyImageData(placeholder: BLURRED, layout: FULL_WIDTH)
|
||||
}
|
||||
publicURL
|
||||
}
|
||||
shortDescription
|
||||
}
|
||||
|
@ -64,6 +65,7 @@ const ProjectTemplate = ({ data }) => {
|
|||
description={project.shortDescription}
|
||||
title={t("project") + ": " + projectName}
|
||||
transparentTopbar={true}
|
||||
image={project.image.publicURL}
|
||||
>
|
||||
<section className={styles.projectHeader}>
|
||||
<div style={{ paddingTop: 0 }}>
|
||||
|
|
BIN
static/owner.jpg
Normal file
BIN
static/owner.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 73 KiB |
Loading…
Add table
Reference in a new issue