mirror of
https://github.com/Unkn0wnCat/KevinK.dev.js.git
synced 2025-05-25 14:56:33 +02:00
Add full blogging functionality
This commit is contained in:
parent
bb7486635c
commit
c8e8351b43
14 changed files with 557 additions and 178 deletions
|
@ -105,11 +105,11 @@ const Navigation = ({ isHome }) => {
|
|||
<Trans>social</Trans>
|
||||
</Link>
|
||||
<Link
|
||||
id="navBtnScambox"
|
||||
to="/scambox"
|
||||
id="navBtnBlog"
|
||||
to="/blog"
|
||||
activeClassName={styles.active}
|
||||
>
|
||||
<Trans>scambox</Trans>
|
||||
<Trans>blog.title</Trans>
|
||||
</Link>
|
||||
<div className={styles.hamburger}>
|
||||
<Hamburger
|
||||
|
|
|
@ -48,11 +48,11 @@ const OffScreenNav = ({ active, close }) => {
|
|||
<Trans>social</Trans>
|
||||
</Link>
|
||||
<Link
|
||||
id="osnavBtnScambox"
|
||||
to="/scambox"
|
||||
id="osnavBtnBlog"
|
||||
to="/blog"
|
||||
activeClassName={styles.active}
|
||||
>
|
||||
<Trans>scambox</Trans>
|
||||
<Trans>blog.title</Trans>
|
||||
</Link>
|
||||
</div>
|
||||
</div>,
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
/* eslint-disable react/prop-types */
|
||||
import { graphql } from "gatsby";
|
||||
import { Link } from "gatsby-plugin-react-i18next";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import Layout from "../layouts/default";
|
||||
|
||||
import * as styles from "./scambox.module.scss";
|
||||
|
||||
const ScamBox = ({ data }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Layout title={t("scambox")} description={t("scamboxDescription")}>
|
||||
<section>
|
||||
<article>
|
||||
<h1>{t("scambox")}</h1>
|
||||
|
||||
<p>{t("scamboxDescription")}</p>
|
||||
|
||||
<div className={styles.list}>
|
||||
{data.scambox.nodes.map((post) => {
|
||||
return (
|
||||
<Link
|
||||
to={`/scambox/${post.childMdx.frontmatter.url}`}
|
||||
key={post.childMdx.slug}
|
||||
className={styles.post}
|
||||
>
|
||||
<span className={styles.title}>
|
||||
{post.childMdx.frontmatter.title}
|
||||
</span>
|
||||
<span className={styles.meta}>
|
||||
{t("scamboxPosted", {
|
||||
date: post.childMdx.frontmatter
|
||||
.published,
|
||||
})}
|
||||
</span>
|
||||
|
||||
<span className={styles.excerpt}>
|
||||
{post.childMdx.excerpt}{" "}
|
||||
<span>{t("scamboxReadFull")}</span>
|
||||
</span>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<span className={styles.moreSoon}>{t("moreSoon")}</span>
|
||||
</article>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export const query = graphql`
|
||||
query ($language: String!) {
|
||||
scambox: allFile(
|
||||
filter: { sourceInstanceName: { eq: "scamboxContent" } }
|
||||
sort: { fields: childMdx___frontmatter___published, order: DESC }
|
||||
) {
|
||||
nodes {
|
||||
childMdx {
|
||||
frontmatter {
|
||||
platform
|
||||
tags
|
||||
title
|
||||
url
|
||||
published(formatString: "DD.MM.YYYY")
|
||||
}
|
||||
excerpt
|
||||
}
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default ScamBox;
|
|
@ -1,45 +0,0 @@
|
|||
@import "../variables";
|
||||
@import "../mixins";
|
||||
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: $layoutPadding;
|
||||
|
||||
.post {
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: inherit;
|
||||
padding: $layoutPadding;
|
||||
|
||||
border-bottom: thin dotted grey;
|
||||
|
||||
.title {
|
||||
color: $accentColor;
|
||||
font-size: 1.5em;
|
||||
text-decoration: underline dotted currentColor;
|
||||
}
|
||||
|
||||
.meta {
|
||||
margin-bottom: 10px;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.excerpt {
|
||||
margin-left: 10px;
|
||||
|
||||
> span {
|
||||
color: $accentColor;
|
||||
text-decoration: underline dotted currentColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.moreSoon {
|
||||
display: block;
|
||||
padding: $layoutPadding;
|
||||
text-align: center;
|
||||
opacity: .5;
|
||||
}
|
187
src/templates/blogListing.js
Normal file
187
src/templates/blogListing.js
Normal file
|
@ -0,0 +1,187 @@
|
|||
/* eslint-disable react/prop-types */
|
||||
import { graphql, Link as Link2 } from "gatsby";
|
||||
import { StaticImage } from "gatsby-plugin-image";
|
||||
import { Link } from "gatsby-plugin-react-i18next";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import Layout from "../layouts/default";
|
||||
|
||||
import * as styles from "./blogListing.module.scss";
|
||||
|
||||
const BlogListing = ({ data, pageContext }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const title = t(`blog.section.${pageContext.section ?? "blog"}.name`);
|
||||
const description = t(
|
||||
`blog.section.${pageContext.section ?? "blog"}.description`
|
||||
);
|
||||
|
||||
const hasSection = typeof pageContext.section !== "undefined";
|
||||
|
||||
return (
|
||||
<Layout title={title} description={description}>
|
||||
<section>
|
||||
<article>
|
||||
{hasSection && (
|
||||
<Link to={"/blog"} className={styles.sectionBacklink}>
|
||||
{t("blog.title")} /
|
||||
</Link>
|
||||
)}
|
||||
<h1>{title}</h1>
|
||||
|
||||
<p>{description}</p>
|
||||
|
||||
{!hasSection && (
|
||||
<>
|
||||
<h2>Sections</h2>
|
||||
|
||||
<div className={styles.sectionList}>
|
||||
<Link
|
||||
className={styles.sectionCard}
|
||||
to={"/blog/scambox"}
|
||||
>
|
||||
<div className={styles.sectionImage}>
|
||||
<div className={styles.sectionBg}>
|
||||
<StaticImage src="https://source.unsplash.com/gf8e6XvG_3E/300x150"></StaticImage>
|
||||
</div>
|
||||
<span className={styles.sectionName}>
|
||||
Scambox
|
||||
</span>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<h2>Posts</h2>
|
||||
|
||||
<div className={styles.list}>
|
||||
{data.posts.nodes.map((post) => {
|
||||
return (
|
||||
<Link2
|
||||
to={`/${
|
||||
post.childMdx.frontmatter.language
|
||||
}/blog/${
|
||||
post.childMdx.frontmatter.section
|
||||
? post.childMdx.frontmatter
|
||||
.section + "/"
|
||||
: ""
|
||||
}${
|
||||
post.childMdx.frontmatter.urlPublished
|
||||
}/${post.childMdx.frontmatter.url}`}
|
||||
key={post.childMdx.slug}
|
||||
className={styles.post}
|
||||
>
|
||||
<span className={styles.title}>
|
||||
{post.childMdx.frontmatter.title}
|
||||
</span>
|
||||
<span className={styles.meta}>
|
||||
{t("blog.meta", {
|
||||
date: post.childMdx.frontmatter
|
||||
.published,
|
||||
author: post.childMdx.frontmatter
|
||||
.author.name,
|
||||
})}
|
||||
|
||||
{post.childMdx.frontmatter.section &&
|
||||
!hasSection && (
|
||||
<>
|
||||
{" | "}
|
||||
<Link
|
||||
to={`/blog/${post.childMdx.frontmatter.section}`}
|
||||
>
|
||||
{t(
|
||||
`blog.section.${post.childMdx.frontmatter.section}.name`
|
||||
)}
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
|
||||
{" | "}
|
||||
{t(
|
||||
`language.${post.childMdx.frontmatter.language}.name`
|
||||
)}
|
||||
</span>
|
||||
|
||||
<span className={styles.excerpt}>
|
||||
{post.childMdx.excerpt}{" "}
|
||||
<span>{t("blog.readFull")}</span>
|
||||
</span>
|
||||
</Link2>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className={styles.pageSwitcher}>
|
||||
{pageContext.pageNumber > 0 ? (
|
||||
<Link to={pageContext.previousPagePath}>
|
||||
{t("blog.previous")}
|
||||
</Link>
|
||||
) : (
|
||||
<span></span>
|
||||
)}
|
||||
<span>
|
||||
{t("blog.page", {
|
||||
page: pageContext.humanPageNumber,
|
||||
maxPage: pageContext.numberOfPages,
|
||||
})}
|
||||
</span>
|
||||
{pageContext.humanPageNumber <
|
||||
pageContext.numberOfPages ? (
|
||||
<Link to={pageContext.nextPagePath}>
|
||||
{t("blog.next")}
|
||||
</Link>
|
||||
) : (
|
||||
<span></span>
|
||||
)}
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export const query = graphql`
|
||||
query ($language: String!, $skip: Int!, $limit: Int!, $section: String) {
|
||||
posts: allFile(
|
||||
filter: {
|
||||
sourceInstanceName: { eq: "blogContent" }
|
||||
childMdx: { frontmatter: { section: { eq: $section } } }
|
||||
}
|
||||
sort: { fields: childMdx___frontmatter___published, order: DESC }
|
||||
limit: $limit
|
||||
skip: $skip
|
||||
) {
|
||||
nodes {
|
||||
childMdx {
|
||||
frontmatter {
|
||||
platform
|
||||
tags
|
||||
title
|
||||
url
|
||||
published(formatString: "DD.MM.YYYY")
|
||||
urlPublished: published(formatString: "YYYY/MM")
|
||||
section
|
||||
language
|
||||
author {
|
||||
name
|
||||
}
|
||||
}
|
||||
excerpt
|
||||
}
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
edges {
|
||||
node {
|
||||
ns
|
||||
data
|
||||
language
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default BlogListing;
|
109
src/templates/blogListing.module.scss
Normal file
109
src/templates/blogListing.module.scss
Normal file
|
@ -0,0 +1,109 @@
|
|||
@import "../variables";
|
||||
@import "../mixins";
|
||||
|
||||
.sectionBacklink {
|
||||
display: block;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: -2rem;
|
||||
font-size: .8em;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.sectionList {
|
||||
@include flexList;
|
||||
|
||||
.sectionCard {
|
||||
@include cardGeneric;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
|
||||
.sectionImage {
|
||||
width: 300px;
|
||||
height: 150px;
|
||||
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;
|
||||
color: white;
|
||||
position: relative;
|
||||
|
||||
.sectionBg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.sectionName {
|
||||
font-size: 2em;
|
||||
margin-top: -5px;
|
||||
z-index: 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.pageSwitcher {
|
||||
display: flex;
|
||||
margin-top: $layoutPadding;
|
||||
|
||||
>* {
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
:nth-child(2) {
|
||||
text-align: center;
|
||||
}
|
||||
:nth-child(3) {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: $layoutPadding;
|
||||
|
||||
.post {
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: inherit;
|
||||
padding: $layoutPadding;
|
||||
|
||||
border-bottom: thin dotted grey;
|
||||
|
||||
.title {
|
||||
color: $accentColor;
|
||||
font-size: 1.5em;
|
||||
text-decoration: underline dotted currentColor;
|
||||
}
|
||||
|
||||
.meta {
|
||||
margin-bottom: 10px;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.excerpt {
|
||||
margin-left: 10px;
|
||||
|
||||
> span {
|
||||
color: $accentColor;
|
||||
text-decoration: underline dotted currentColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.moreSoon {
|
||||
display: block;
|
||||
padding: $layoutPadding;
|
||||
text-align: center;
|
||||
opacity: .5;
|
||||
}
|
|
@ -8,14 +8,15 @@ import Utterances from "utterances-react";
|
|||
|
||||
import Layout from "../layouts/default";
|
||||
|
||||
import * as styles from "./scamboxPost.module.scss";
|
||||
import * as styles from "./blogPost.module.scss";
|
||||
import { Link } from "gatsby-plugin-react-i18next";
|
||||
|
||||
const ScamBoxPost = ({ data }) => {
|
||||
const { t, i18n } = useTranslation();
|
||||
const BlogPost = ({ data }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Layout
|
||||
title={`${data.mdx.frontmatter.title} | ${t("scambox")}`}
|
||||
title={`${data.mdx.frontmatter.title}`}
|
||||
description={data.mdx.excerpt}
|
||||
seoAdditional={
|
||||
<script type="application/ld+json">
|
||||
|
@ -28,13 +29,12 @@ const ScamBoxPost = ({ data }) => {
|
|||
"https://example.com/photos/4x3/photo.jpg",
|
||||
"https://example.com/photos/16x9/photo.jpg"
|
||||
],*/
|
||||
datePublished: data.mdx.publishedIso,
|
||||
dateModified: data.mdx.publishedIso,
|
||||
datePublished: data.mdx.frontmatter.publishedIso,
|
||||
dateModified: data.mdx.frontmatter.publishedIso,
|
||||
author: [
|
||||
{
|
||||
"@type": "Person",
|
||||
name: "Kevin Kandlbinder",
|
||||
url: "https://kevink.dev",
|
||||
name: data.mdx.frontmatter.author.name,
|
||||
},
|
||||
],
|
||||
})}
|
||||
|
@ -47,11 +47,15 @@ const ScamBoxPost = ({ data }) => {
|
|||
},
|
||||
{
|
||||
name: "article:published_time",
|
||||
content: data.mdx.publishedIso,
|
||||
content: data.mdx.frontmatter.publishedIso,
|
||||
},
|
||||
{
|
||||
name: "article:section",
|
||||
content: "Scambox",
|
||||
content: t(
|
||||
`blog.section.${
|
||||
data.mdx.frontmatter.section ?? "blog"
|
||||
}.name`
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "keywords",
|
||||
|
@ -63,17 +67,24 @@ const ScamBoxPost = ({ data }) => {
|
|||
<article>
|
||||
<h1>{data.mdx.frontmatter.title}</h1>
|
||||
<span className={styles.meta}>
|
||||
{t("scamboxPosted", {
|
||||
{t("blog.meta", {
|
||||
date: data.mdx.frontmatter.published,
|
||||
author: data.mdx.frontmatter.author.name,
|
||||
})}
|
||||
</span>
|
||||
|
||||
{i18n.language !== "en" && (
|
||||
<div className={styles.noticeBox}>
|
||||
<b>{t("scamboxNotice")}</b>
|
||||
<p>{t("scamboxLanguage")}</p>
|
||||
</div>
|
||||
)}
|
||||
{data.mdx.frontmatter.section && (
|
||||
<>
|
||||
{" | "}
|
||||
<Link
|
||||
to={`/blog/${data.mdx.frontmatter.section}`}
|
||||
>
|
||||
{t(
|
||||
`blog.section.${data.mdx.frontmatter.section}.name`
|
||||
)}
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
|
||||
<MDXProvider components={{ Chat }}>
|
||||
<MDXRenderer>{data.mdx.body}</MDXRenderer>
|
||||
|
@ -81,7 +92,7 @@ const ScamBoxPost = ({ data }) => {
|
|||
|
||||
<Utterances
|
||||
repo="Unkn0wnCat/KevinK.dev.js"
|
||||
issueTerm={`Scambox-Comments: ${data.mdx.frontmatter.title}`}
|
||||
issueTerm={`Blog-Comments: ${data.mdx.frontmatter.title}`}
|
||||
theme="preferred-color-scheme"
|
||||
label="comments"
|
||||
style={{
|
||||
|
@ -114,6 +125,10 @@ export const query = graphql`
|
|||
title
|
||||
published(formatString: "DD.MM.YYYY")
|
||||
publishedIso: published(formatString: "")
|
||||
author {
|
||||
name
|
||||
}
|
||||
section
|
||||
}
|
||||
}
|
||||
locales: allLocale(filter: { language: { eq: $language } }) {
|
||||
|
@ -128,4 +143,4 @@ export const query = graphql`
|
|||
}
|
||||
`;
|
||||
|
||||
export default ScamBoxPost;
|
||||
export default BlogPost;
|
Loading…
Add table
Add a link
Reference in a new issue