Browse Source

feat: allow writing pages in markdown

master
Garrit Franke 3 years ago
parent
commit
1448128bd3
Signed by: garrit
GPG Key ID: 65586C4DDA55EA2C
  1. 263
      components/BlogList.js
  2. 558
      components/Meta.js
  3. 149
      components/Page.js
  4. 15
      content/todo.md
  5. 12036
      package-lock.json
  6. 6
      package.json
  7. 51
      pages/[page].js
  8. 244
      pages/posts/[post].js

263
components/BlogList.js

@ -2,140 +2,147 @@ import Link from "next/link";
import ReactMarkdown from "react-markdown";
function reformatDate(fullDate) {
const date = new Date(fullDate);
return date.toDateString().slice(4);
const date = new Date(fullDate);
return date.toDateString().slice(4);
}
function truncateSummary(content) {
return content.slice(0, 200).trimEnd() + "...";
return content.slice(0, 200).trimEnd() + "...";
}
const BlogList = ({ posts }) => {
return (
<>
<ul className="list">
{posts.length > 1 &&
posts
// Filter drafts
.filter((post) => !post.slug.startsWith("_"))
// Ternary operator is used to fix chromium sorting
// See: https://stackoverflow.com/a/36507611
.sort((a, b) => (a.frontmatter.date < b.frontmatter.date ? 1 : -1))
.map((post) => (
<Link key={post.slug} href={{ pathname: `/posts/${post.slug}` }}>
<a>
<li>
<div className="blog__info">
<h2>{post.frontmatter.title}</h2>
<h3> {reformatDate(post.frontmatter.date)}</h3>
<p>
<ReactMarkdown
source={truncateSummary(post.markdownBody)}
/>
</p>
</div>
</li>
</a>
</Link>
))}
</ul>
<style jsx>
{`
margin-bottom: 0;
a:hover {
opacity: 1;
}
a:hover li div.hero_image img {
opacity: 0.8;
transition: opacity 0.3s ease;
}
a:hover li .blog__info h2,
a:hover li .blog__info h3,
a:hover li .blog__info p {
transform: translateX(10px);
transition: transform 0.5s ease-out;
}
@media (prefers-reduced-motion) {
a:hover li .blog__info h2,
a:hover li .blog__info h3,
a:hover li .blog__info p {
transform: translateX(0px);
}
}
.hero_image {
width: 100%;
height: 33vh;
overflow: hidden;
background-color: #000;
}
.hero_image img {
object-fit: cover;
object-position: 50% 50%;
opacity: 1;
transition: opacity 0.3s ease;
min-height: 100%;
}
.blog__info {
display: flex;
flex-direction: column;
justify-content: center;
padding: 1.5rem 1.25rem;
transform: translateX(0px);
transition: transform 0.3s ease-in;
}
.blog__info h2,
.blog__info h3,
.blog__info p {
transform: translateX(0px);
transition: transform 0.5s ease-out;
}
li {
opacity: inherit;
display: flex;
flex-direction: column;
min-height: 38vh;
margin-bottom: 0;
}
h2 {
margin-bottom: 0.5rem;
}
h3 {
margin-bottom: 1rem;
}
p {
max-width: 900px;
}
@media (min-width: 768px) {
li {
min-height: 250px;
height: 33.333vh;
flex-direction: row;
}
.hero_image {
height: 100%;
}
.hero_image img {
min-width: 100%;
height: 100%;
width: auto;
min-height: 0;
}
.blog__info {
min-width: 70%;
}
}
@media (min-width: 1280px) {
.blog__info {
padding: 3rem;
}
h3 {
margin-bottom: 1.2rem;
}
}
`}
</style>
</>
);
return (
<>
<ul className="list">
{posts.length > 1 &&
posts
// Filter drafts
.filter((post) => !post.slug.startsWith("_"))
// Ternary operator is used to fix chromium sorting
// See: https://stackoverflow.com/a/36507611
.sort((a, b) =>
a.frontmatter.date < b.frontmatter.date ? 1 : -1
)
.map((post) => (
<a href={`/posts/${post.slug}`}>
<li>
<div className="blog__info">
<h2>{post.frontmatter.title}</h2>
<h3>
{" "}
{reformatDate(
post.frontmatter.date
)}
</h3>
<p>
<ReactMarkdown
source={truncateSummary(
post.markdownBody
)}
/>
</p>
</div>
</li>
</a>
))}
</ul>
<style jsx>
{`
margin-bottom: 0;
a:hover {
opacity: 1;
}
a:hover li div.hero_image img {
opacity: 0.8;
transition: opacity 0.3s ease;
}
a:hover li .blog__info h2,
a:hover li .blog__info h3,
a:hover li .blog__info p {
transform: translateX(10px);
transition: transform 0.5s ease-out;
}
@media (prefers-reduced-motion) {
a:hover li .blog__info h2,
a:hover li .blog__info h3,
a:hover li .blog__info p {
transform: translateX(0px);
}
}
.hero_image {
width: 100%;
height: 33vh;
overflow: hidden;
background-color: #000;
}
.hero_image img {
object-fit: cover;
object-position: 50% 50%;
opacity: 1;
transition: opacity 0.3s ease;
min-height: 100%;
}
.blog__info {
display: flex;
flex-direction: column;
justify-content: center;
padding: 1.5rem 1.25rem;
transform: translateX(0px);
transition: transform 0.3s ease-in;
}
.blog__info h2,
.blog__info h3,
.blog__info p {
transform: translateX(0px);
transition: transform 0.5s ease-out;
}
li {
opacity: inherit;
display: flex;
flex-direction: column;
min-height: 38vh;
margin-bottom: 0;
}
h2 {
margin-bottom: 0.5rem;
}
h3 {
margin-bottom: 1rem;
}
p {
max-width: 900px;
}
@media (min-width: 768px) {
li {
min-height: 250px;
height: 33.333vh;
flex-direction: row;
}
.hero_image {
height: 100%;
}
.hero_image img {
min-width: 100%;
height: 100%;
width: auto;
min-height: 0;
}
.blog__info {
min-width: 70%;
}
}
@media (min-width: 1280px) {
.blog__info {
padding: 3rem;
}
h3 {
margin-bottom: 1.2rem;
}
}
`}
</style>
</>
);
};
export default BlogList;

558
components/Meta.js

@ -1,278 +1,306 @@
import Head from "next/head";
export default function Meta(props) {
return (
<>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charSet="utf-8" />
<title>{props.siteTitle}</title>
<meta
name="Description"
content="Random thoughts, tips and rants about software"
></meta>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
return (
<>
<Head>
<meta
name="viewport"
content="width=device-width, initial-scale=1"
/>
<meta charSet="utf-8" />
<title>{props.siteTitle}</title>
<meta
name="Description"
content="Random thoughts, tips and rants about software"
></meta>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<script async defer data-domain="blog.garrit.xyz" src="https://analytics.slashdev.space/js/plausible.js"></script>
<script
async
defer
data-domain="blog.garrit.xyz"
src="https://analytics.slashdev.space/js/plausible.js"
></script>
</Head>
<style jsx global>
{`
@import url("https://fonts.googleapis.com/css?family=Work+Sans&display=swap");
* {
box-sizing: inherit;
}
html {
box-sizing: border-box;
overflow-y: scroll;
}
body {
margin: 0;
font-family: "Work Sans", "Helvetica Neue", Helvetica,
sans-serif;
overflow-x: hidden;
color: #000;
font-size: 16px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
text-decoration: none;
color: inherit;
transition: opacity 0.2s ease;
}
a:hover {
transition: opacity 0.2s ease;
opacity: 0.5;
text-decoration-color: inherit;
}
ul {
margin: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
list-style-position: outside;
list-style-image: none;
}
ol {
margin: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
list-style-position: outside;
list-style-image: none;
}
ul,
ol,
p {
margin-bottom: 1.45rem;
}
img {
max-width: 100%;
}
img,
figure,
table,
fieldset {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
pre {
margin-left: 0;
margin-right: 0;
margin-top: 0;
margin-bottom: 1.45rem;
font-size: 0.85rem;
line-height: 1.42;
background: hsla(0, 0%, 0%, 0.04);
border-radius: 3px;
overflow: auto;
word-wrap: normal;
padding: 1.45rem;
}
table {
font-size: 1rem;
line-height: 1.45rem;
border-collapse: collapse;
width: 100%;
}
blockquote {
margin-left: 1.45rem;
margin-right: 1.45rem;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
strong {
font-weight: bold;
}
li {
margin-bottom: calc(1.45rem / 2);
}
ol li {
padding-left: 0;
}
ul li {
padding-left: 0;
}
li > ol {
margin-left: 1.45rem;
margin-bottom: calc(1.45rem / 2);
margin-top: calc(1.45rem / 2);
}
li > ul {
margin-left: 1.45rem;
margin-bottom: calc(1.45rem / 2);
margin-top: calc(1.45rem / 2);
}
blockquote *:last-child {
margin-bottom: 0;
}
li *:last-child {
margin-bottom: 0;
}
p *:last-child {
margin-bottom: 0;
}
li > p {
margin-bottom: calc(1.45rem / 2);
}
code {
line-height: 1.45rem;
}
p code {
background: hsla(0, 0%, 0%, 0.1);
padding: 0 0.4rem;
}
@media (prefers-reduced-motion) {
* {
transition: none !important;
}
}
</Head>
<style jsx global>
{`
@import url("https://fonts.googleapis.com/css?family=Work+Sans&display=swap");
* {
box-sizing: inherit;
}
html {
box-sizing: border-box;
overflow-y: scroll;
}
body {
margin: 0;
font-family: "Work Sans", "Helvetica Neue", Helvetica, sans-serif;
overflow-x: hidden;
color: #000;
font-size: 16px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
text-decoration: none;
color: inherit;
transition: opacity 0.2s ease;
}
a:hover {
transition: opacity 0.2s ease;
opacity: 0.5;
text-decoration-color: inherit;
}
ul {
list-style: none;
margin: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
list-style-position: outside;
list-style-image: none;
}
ol {
margin: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
list-style-position: outside;
list-style-image: none;
}
ul,
ol,
p {
margin-bottom: 1.45rem;
}
img {
max-width: 100%;
}
img,
figure,
table,
fieldset {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
pre {
margin-left: 0;
margin-right: 0;
margin-top: 0;
margin-bottom: 1.45rem;
font-size: 0.85rem;
line-height: 1.42;
background: hsla(0, 0%, 0%, 0.04);
border-radius: 3px;
overflow: auto;
word-wrap: normal;
padding: 1.45rem;
}
table {
font-size: 1rem;
line-height: 1.45rem;
border-collapse: collapse;
width: 100%;
}
blockquote {
margin-left: 1.45rem;
margin-right: 1.45rem;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
strong {
font-weight: bold;
}
li {
margin-bottom: calc(1.45rem / 2);
}
ol li {
padding-left: 0;
}
ul li {
padding-left: 0;
}
li > ol {
margin-left: 1.45rem;
margin-bottom: calc(1.45rem / 2);
margin-top: calc(1.45rem / 2);
}
li > ul {
margin-left: 1.45rem;
margin-bottom: calc(1.45rem / 2);
margin-top: calc(1.45rem / 2);
}
blockquote *:last-child {
margin-bottom: 0;
}
li *:last-child {
margin-bottom: 0;
}
p *:last-child {
margin-bottom: 0;
}
li > p {
margin-bottom: calc(1.45rem / 2);
}
code {
line-height: 1.45rem;
}
p code {
background: hsla(0, 0%, 0%, 0.1);
padding: 0 0.4rem;
}
@media (prefers-reduced-motion) {
* {
transition: none !important;
}
}
{
/* //TYPOGRAPHY------------------------------------- */
}
h1,
h2,
h3,
h4,
h5,
h6,
p {
font-family: "Work Sans", "Helvetica Neue", Helvetica,
sans-serif;
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
color: inherit;
text-rendering: optimizeLegibility;
}
h1,
h2 {
font-weight: 500;
}
h1 {
font-size: 2rem;
letter-spacing: -1px;
line-height: 1.1875;
}
h2 {
font-size: 1.7rem;
letter-spacing: -0.75px;
line-height: 1.2;
}
h3 {
font-size: 1.2rem;
letter-spacing: -0.5px;
line-height: 1.1875;
color: #a0a0a0;
font-weight: normal;
}
p {
font-size: 1.2rem;
letter-spacing: -0.5px;
line-height: 1.5;
color: #464646;
}
@media (min-width: 1280px) {
h1 {
font-size: 2rem;
letter-spacing: -1px;
line-height: 1.1875;
}
h2 {
font-size: 1.5rem;
letter-spacing: -0.75px;
line-height: 1.1667;
}
h3 {
font-size: 1rem;
letter-spacing: -0.5px;
line-height: 1.1875;
color: #a0a0a0;
font-weight: normal;
}
p {
line-height: 1.4375;
}
}
{
/* //TYPOGRAPHY------------------------------------- */
}
h1,
h2,
h3,
h4,
h5,
h6,
p {
font-family: "Work Sans", "Helvetica Neue", Helvetica, sans-serif;
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
color: inherit;
text-rendering: optimizeLegibility;
}
h1,
h2 {
font-weight: 500;
}
h1 {
font-size: 2rem;
letter-spacing: -1px;
line-height: 1.1875;
}
h2 {
font-size: 1.7rem;
letter-spacing: -0.75px;
line-height: 1.2;
}
h3 {
font-size: 1.2rem;
letter-spacing: -0.5px;
line-height: 1.1875;
color: #a0a0a0;
font-weight: normal;
}
p {
font-size: 1.2rem;
letter-spacing: -0.5px;
line-height: 1.5;
color: #464646;
}
@media (min-width: 1280px) {
h1 {
font-size: 2rem;
letter-spacing: -1px;
line-height: 1.1875;
}
h2 {
font-size: 1.5rem;
letter-spacing: -0.75px;
line-height: 1.1667;
}
h3 {
font-size: 1rem;
letter-spacing: -0.5px;
line-height: 1.1875;
color: #a0a0a0;
font-weight: normal;
}
p {
line-height: 1.4375;
}
}
// FIXME: I could not get this to work inside the post component,
// but here it apparently works. Maybe an overriding selector?
.page__body a,
.page__footer a {
text-decoration: underline;
}
// FIXME: I could not get this to work inside the post component,
// but here it apparently works. Maybe an overriding selector?
.blog__body a,
.blog__footer a {
text-decoration: underline;
}
@media (prefers-color-scheme: dark) {
:root {
background-color: #161618;
color: #dbd7db;
}
@media (prefers-color-scheme: dark) {
:root {
background-color: #161618;
color: #dbd7db;
}
html {
scrollbar-color: #dbd7db #161618 !important;
}
html {
scrollbar-color: #dbd7db #161618 !important;
}
h1,
h2,
h3,
h4,
p,
pre,
a,
ul,
li,
blog__body > * {
color: #dbd7db;
}
h1,
h2,
h3,
h4,
p,
pre,
a,
ul,
li,
blog__body > * {
color: #dbd7db;
}
.button__link {
background-color: #67676c;
}
.button__link {
background-color: #67676c;
}
a {
color: #dbd7db;
}
a {
color: #dbd7db;
}
}
`}
</style>
</>
);
article a[href^="http"]::after,
article a[href^="https://"]::after {
filter: invert(100%);
}
}
article a[href^="http"]::after,
article a[href^="https://"]::after
{
content: "";
width: 11px;
height: 11px;
margin-left: 4px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z'/%3E%3Cpath fill-rule='evenodd' d='M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z'/%3E%3C/svg%3E");
background-position: center;
background-repeat: no-repeat;
background-size: contain;
display: inline-block;
}
`}
</style>
</>
);
}

149
components/Page.js

@ -0,0 +1,149 @@
import Layout from "./Layout";
export default function Page(props) {
const { title, date } = props;
return (
<Layout siteTitle={title}>
<article className="blog">
<div className="page__info">
<h1>{title}</h1>
{ date && <h3>{ date }</h3> }
</div>
<div className="page__body">
{ props.children }
</div>
<div className="page__footer">
</div>
</article>
<style jsx>
{`
.page h1 {
margin-bottom: 0.7rem;
}
.page__hero {
min-height: 300px;
height: 60vh;
width: 100%;
margin: 0;
overflow: hidden;
}
.page__hero img {
margin-bottom: 0;
object-fit: cover;
min-height: 100%;
min-width: 100%;
object-position: center;
}
.page__info {
padding: 1.5rem 1.25rem;
width: 100%;
max-width: 768px;
margin: 0 auto;
}
.page__info h1 {
margin-bottom: 0.66rem;
}
.page__info h3 {
margin-bottom: 0;
}
.page__body {
width: 100%;
padding: 0 1.25rem;
margin: 0 auto;
display: flex;
flex-direction: column;
justify-content: center;
}
.page__body a {
text-decoration: underline;
padding-bottom: 1.5rem;
}
.page__body:last-child {
margin-bottom: 0;
}
.page__body h1 h2 h3 h4 h5 h6 p {
font-weight: normal;
}
.page__body ul {
list-style-type: circle;
}
.page__body ul ol {
margin-left: 1.25rem;
margin-bottom: 1.25rem;
padding-left: 1.45rem;
}
.page__footer {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.5rem 1.25rem;
width: 100%;
max-width: 800px;
margin: 0 auto;
}
.page__footer h2 {
margin-bottom: 0;
}
.page__footer a {
display: flex;
justify-content: space-between;
align-items: center;
}
.page__footer a svg {
width: 20px;
}
@media (max-width: 768px) {
.page__footer {
display: none;
}
}
@media (min-width: 768px) {
.page {
display: flex;
flex-direction: column;
}
.page__body {
max-width: 800px;
padding: 0 2rem;
}
.page__body span {
width: 100%;
margin: 1.5rem auto;
}
.page__body ul ol {
margin-left: 1.5rem;
margin-bottom: 1.5rem;
}
.page__hero {
min-height: 600px;
height: 75vh;
}
.page__info {
text-align: center;
padding: 2rem 0;
}
.page__info h1 {
max-width: 500px;
margin: 0 auto 0.66rem auto;
}
.page__footer {
padding: 2.25rem;
}
}
@media (min-width: 1440px) {
.page__hero {
height: 70vh;
}
.page__info {
padding: 3rem 0;
}
.page__footer {
padding: 2rem 2rem 3rem 2rem;
}
}
`}
</style>
</Layout>
);
}

15
content/todo.md

@ -0,0 +1,15 @@
---
title: "A comprehensive list of projects that I want to build but probably never will"
---
- A fork of [birdsite.live](https://github.com/NicolasConstant/BirdsiteLive)
for instagram
- Battle Royale App for habit tracking
- Federated sports tracker ([somewhat in the making already](https://github.com/SamR1/FitTrackee/issues/16))
- C compiler for [uxn](https://wiki.xxiivv.com/site/uxn.html) (or
[antimony](https://github.com/antimony-lang/antimony) backend?)
- Turn this blog into my main website
- Mirror this blog to [Gemini](https://gemini.circumlunar.space/)
- [~~"todo" Page on website (this list)~~](/todo)

12036
package-lock.json generated

File diff suppressed because it is too large Load Diff

6
package.json

@ -11,10 +11,10 @@
"glob": "^7.1.6",
"gray-matter": "^4.0.2",
"markdown": "^0.5.0",
"next": "9.5.3",
"next": "11.1.0",
"raw-loader": "^4.0.2",
"react": "16.13.1",
"react-dom": "16.13.1",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-markdown": "^4.3.1",
"rfc822-date": "0.0.3"
}

51
pages/[page].js

@ -0,0 +1,51 @@
import matter from "gray-matter";
import ReactMarkdown from "react-markdown";
import glob from "glob";
import Page from "../components/Page";
export default function PageTemplate(props) {
/*
** Odd fix to get build to run
** It seems like on first go the props
** are undefined could be a Next bug?
*/
if (!props.frontmatter) return <></>;
return (
<Page title={props.frontmatter.title}>
<ReactMarkdown source={props.markdownBody} />
</Page>
);
}
export async function getStaticProps({ ...ctx }) {
const { page } = ctx.params;
const content = await import(`../content/${page}.md`);
const data = matter(content.default);
return {
props: {
siteTitle: "~/garrit",
frontmatter: data.data,
markdownBody: data.content,
},
};
}
export async function getStaticPaths() {
//get all .md files in the posts dir
const pages = glob.sync("content/*.md");
//remove path and extension to leave filename only
const pageSlugs = pages.map((file) =>
file.split("/")[1].replace(/ /g, "-").slice(0, -3).trim()
);
// create paths with `slug` param
const paths = pageSlugs.map((slug) => `/${slug}`);
return {
paths,
fallback: false,
};
}

244
pages/posts/[post].js

@ -1,208 +1,74 @@
import matter from "gray-matter";
import ReactMarkdown from "react-markdown";
import Layout from "../../components/Layout";
import Page from "../../components/Page";
import glob from "glob";
export default function BlogTemplate(props) {
function reformatDate(fullDate) {
const date = new Date(fullDate);
return date.toDateString().slice(4);
}
function reformatDate(fullDate) {
const date = new Date(fullDate);
return date.toDateString().slice(4);
}
/*
** Odd fix to get build to run
** It seems like on first go the props
** are undefined could be a Next bug?
*/
/*
** Odd fix to get build to run
** It seems like on first go the props
** are undefined could be a Next bug?
*/
if (!props.frontmatter) return <></>;
if (!props.frontmatter) return <></>;
return (
<Layout siteTitle={props.frontmatter.title}>
<article className="blog">
<div className="blog__info">
<h1>{props.frontmatter.title}</h1>
<h3>{reformatDate(props.frontmatter.date)}</h3>
</div>
<div className="blog__body">
<ReactMarkdown source={props.markdownBody} />
<p>
If you enjoyed this post, consider{" "}
<a href="https://donate.slashdev.space">buying me a coffee</a>! Got
comments? Send me a{" "}
<a href="mailto:garrit@slashdev.space">
Mail
</a>
, or shoot me a message on{" "}
<a href="https://matrix.to/#/@garrit:matrix.slashdev.space">
Matrix
</a>
.
</p>
</div>
<div className="blog__footer">
<h2>Written By: Garrit Franke</h2>
</div>
</article>
<style jsx>
{`
.blog h1 {
margin-bottom: 0.7rem;
}
.blog__hero {
min-height: 300px;
height: 60vh;
width: 100%;
margin: 0;
overflow: hidden;
}
.blog__hero img {
margin-bottom: 0;
object-fit: cover;
min-height: 100%;
min-width: 100%;
object-position: center;
}
.blog__info {
padding: 1.5rem 1.25rem;
width: 100%;
max-width: 768px;
margin: 0 auto;
}
.blog__info h1 {
margin-bottom: 0.66rem;
}
.blog__info h3 {
margin-bottom: 0;
}
.blog__body {
width: 100%;
padding: 0 1.25rem;
margin: 0 auto;
display: flex;
flex-direction: column;
justify-content: center;
}
.blog__body a {
padding-bottom: 1.5rem;
}
.blog__body:last-child {
margin-bottom: 0;
}
.blog__body h1 h2 h3 h4 h5 h6 p {
font-weight: normal;
}
.blog__body ul {
list-style: initial;
}
.blog__body ul ol {
margin-left: 1.25rem;
margin-bottom: 1.25rem;
padding-left: 1.45rem;
}
.blog__footer {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.5rem 1.25rem;
width: 100%;
max-width: 800px;
margin: 0 auto;
}
.blog__footer h2 {
margin-bottom: 0;
}
.blog__footer a {
display: flex;
justify-content: space-between;
align-items: center;
}
.blog__footer a svg {
width: 20px;
}
@media (max-width: 768px) {
.blog__footer {
display: none;
}
}
@media (min-width: 768px) {
.blog {
display: flex;
flex-direction: column;
}
.blog__body {
max-width: 800px;
padding: 0 2rem;
}
.blog__body span {
width: 100%;
margin: 1.5rem auto;
}
.blog__body ul ol {
margin-left: 1.5rem;
margin-bottom: 1.5rem;
}
.blog__hero {
min-height: 600px;
height: 75vh;
}
.blog__info {
text-align: center;
padding: 2rem 0;
}
.blog__info h1 {
max-width: 500px;
margin: 0 auto 0.66rem auto;
}
.blog__footer {
padding: 2.25rem;
}
}
@media (min-width: 1440px) {
.blog__hero {
height: 70vh;
}
.blog__info {
padding: 3rem 0;
}
.blog__footer {
padding: 2rem 2rem 3rem 2rem;
}
}
`}
</style>
</Layout>
);
return (
<Page title={props.frontmatter.title}>
<ReactMarkdown
source={props.markdownBody}
date={props.frontmatter.date}
/>
<p>
If you enjoyed this post, consider{" "}
<a href="https://donate.slashdev.space">buying me a coffee</a>!
Got comments? Send me a{" "}
<a href="mailto:garrit@slashdev.space">Mail</a>, or shoot me a
message on{" "}
<a href="https://matrix.to/#/@garrit:matrix.slashdev.space">
Matrix
</a>
.
</p>
<div className="blog__footer">
<h2>Written By: Garrit Franke</h2>
</div>
</Page>
);
}
export async function getStaticProps({ ...ctx }) {
const { post } = ctx.params;
const content = await import(`../../content/posts/${post}.md`);
const data = matter(content.default);
const { post } = ctx.params;
const content = await import(`../../content/posts/${post}.md`);
const data = matter(content.default);
return {
props: {
siteTitle: "~/garrit",
frontmatter: data.data,
markdownBody: data.content,
},
};
return {
props: {
siteTitle: "~/garrit",
frontmatter: data.data,
markdownBody: data.content,
},
};
}
export async function getStaticPaths() {
//get all .md files in the posts dir
const blogs = glob.sync("content/posts/**/*.md");
//get all .md files in the posts dir
const blogs = glob.sync("content/posts/**/*.md");
//remove path and extension to leave filename only
const blogSlugs = blogs.map((file) =>
file.split("/")[2].replace(/ /g, "-").slice(0, -3).trim()
);
//remove path and extension to leave filename only
const blogSlugs = blogs.map((file) =>
file.split("/")[2].replace(/ /g, "-").slice(0, -3).trim()
);
// create paths with `slug` param
const paths = blogSlugs.map((slug) => `/posts/${slug}`);
// create paths with `slug` param
const paths = blogSlugs.map((slug) => `/posts/${slug}`);
return {
paths,
fallback: false,
};
return {
paths,
fallback: false,
};
}

Loading…
Cancel
Save