feat(fs.dev): Added OG intro for description
This commit is contained in:
parent
d71a8246ac
commit
b59c5036ed
8 changed files with 51 additions and 150 deletions
|
@ -1,45 +1,11 @@
|
||||||
/*
|
|
||||||
* This page will be used to generate all markdown content
|
|
||||||
* which, on freesewing.dev, is pretty much the entire website
|
|
||||||
* apart from the home page.
|
|
||||||
*
|
|
||||||
* It uses a dynamic route and data fetching to do that.
|
|
||||||
* More info is available at the bottom of this page, or check
|
|
||||||
* https://nextjs.org/docs/basic-features/data-fetching
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Page wrapper - a MUST for all pages
|
|
||||||
*/
|
|
||||||
import Page from 'shared/components/wrappers/page.js'
|
import Page from 'shared/components/wrappers/page.js'
|
||||||
|
|
||||||
/*
|
|
||||||
* useApp hook - also a MUST for all pages
|
|
||||||
*/
|
|
||||||
import useApp from 'site/hooks/useApp.js'
|
import useApp from 'site/hooks/useApp.js'
|
||||||
|
|
||||||
/*
|
|
||||||
* mdxMeta is generated in the prebuild step and contains
|
|
||||||
* meta-data about markdown content (titles, slugs, intro)
|
|
||||||
*/
|
|
||||||
import mdxMeta from 'site/prebuild/mdx.en.js'
|
import mdxMeta from 'site/prebuild/mdx.en.js'
|
||||||
|
|
||||||
/*
|
|
||||||
* This loads MDX (markdown) from disk
|
|
||||||
*/
|
|
||||||
import mdxLoader from 'shared/mdx/loader'
|
import mdxLoader from 'shared/mdx/loader'
|
||||||
|
|
||||||
/*
|
|
||||||
* This wraps MDX making sure to include all components
|
|
||||||
* like Tip, Note, Example, and so on
|
|
||||||
*/
|
|
||||||
import MdxWrapper from 'shared/components/wrappers/mdx'
|
import MdxWrapper from 'shared/components/wrappers/mdx'
|
||||||
|
import Head from 'next/head'
|
||||||
import Popout from 'shared/components/popout.js'
|
import Popout from 'shared/components/popout.js'
|
||||||
|
|
||||||
/*
|
|
||||||
* The NextJS page object
|
|
||||||
*/
|
|
||||||
const MdxPage = props => {
|
const MdxPage = props => {
|
||||||
|
|
||||||
// This hook is used for shared code and global state
|
// This hook is used for shared code and global state
|
||||||
|
@ -56,6 +22,15 @@ const MdxPage = props => {
|
||||||
*/
|
*/
|
||||||
return (
|
return (
|
||||||
<Page app={app} {...props.page}>
|
<Page app={app} {...props.page}>
|
||||||
|
<Head>
|
||||||
|
<meta property="og:title" content={props.page.title} key="title" />
|
||||||
|
<meta property="og:type" content="article" key='type' />
|
||||||
|
<meta property="og:description" content={props.intro} key='type' />
|
||||||
|
<meta property="og:article:author" content='Joost De Cock' key='author' />
|
||||||
|
<meta property="og:url" content={`https://canary.freesewing.dev/${props.page.slug}`} key='url' />
|
||||||
|
<meta property="og:locale" content="en_US" key='locale' />
|
||||||
|
<meta property="og:site_name" content="freesewing.dev" key='site' />
|
||||||
|
</Head>
|
||||||
<MdxWrapper mdx={props.mdx} app={app}/>
|
<MdxWrapper mdx={props.mdx} app={app}/>
|
||||||
<Popout tip className='max-w-prose'>
|
<Popout tip className='max-w-prose'>
|
||||||
<h6>Found a mistake?</h6>
|
<h6>Found a mistake?</h6>
|
||||||
|
@ -87,11 +62,12 @@ export default MdxPage
|
||||||
*/
|
*/
|
||||||
export async function getStaticProps({ params }) {
|
export async function getStaticProps({ params }) {
|
||||||
|
|
||||||
const mdx = await mdxLoader('en', 'dev', params.mdxslug.join('/'))
|
const { mdx, intro } = await mdxLoader('en', 'dev', params.mdxslug.join('/'))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
mdx,
|
mdx,
|
||||||
|
intro: intro.join(' '),
|
||||||
page: {
|
page: {
|
||||||
slug: params.mdxslug.join('/'),
|
slug: params.mdxslug.join('/'),
|
||||||
path: '/' + params.mdxslug.join('/'),
|
path: '/' + params.mdxslug.join('/'),
|
||||||
|
|
|
@ -49,17 +49,21 @@ const Author = ({ author }) => (
|
||||||
|
|
||||||
const PostPage = ({ post, author }) => {
|
const PostPage = ({ post, author }) => {
|
||||||
const app = useApp()
|
const app = useApp()
|
||||||
|
console.log(post)
|
||||||
return (
|
return (
|
||||||
<Page app={app} title={post.title}>
|
<Page app={app} title={post.title}>
|
||||||
<Head>
|
<Head>
|
||||||
<meta property="og:title" content={post.title} key="title" />
|
<meta property="og:title" content={post.title} key="title" />
|
||||||
<meta property="og:type" content="article" />
|
<meta property="og:type" content="article" key='type' />
|
||||||
<meta property="og:article:author" content={author.displayname} />
|
<meta property="og:description" content={post.intro || post.title} key='description' />
|
||||||
<meta property="og:url" content={`https://canary.freesewing.dev/blog/${post.slug}`} />
|
<meta property="og:article:author" content={author.displayname} key='author' />
|
||||||
<meta property="og:image" content={`${strapi}${post.image.formats.large.url}`} />
|
<meta property="og:url" content={`https://canary.freesewing.dev/blog/${post.slug}`} key='url' />
|
||||||
<meta property="og:local" content="en_US" />
|
<meta property="og:image" content={`${strapi}${post.image.formats.large.url}`} key='image' />
|
||||||
<meta property="og:site_name" content="freesewing.dev" />
|
<meta property="og:image:type" content={post.image.mime} key='image' />
|
||||||
|
<meta property="og:image:width" content={post.image.width} key='image' />
|
||||||
|
<meta property="og:image:height" content={post.image.height} key='image' />
|
||||||
|
<meta property="og:locale" content="en_US" key='locale' />
|
||||||
|
<meta property="og:site_name" content="freesewing.dev" key='site' />
|
||||||
</Head>
|
</Head>
|
||||||
<article className="mb-12">
|
<article className="mb-12">
|
||||||
<div className="flex flex-row justify-between text-sm mb-1 mt-2">
|
<div className="flex flex-row justify-between text-sm mb-1 mt-2">
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
{
|
|
||||||
"dev": true,
|
|
||||||
"localizations": [],
|
|
||||||
"_id": "60f0616ddb32b45d5c4d6dac",
|
|
||||||
"body": "I wanted to do a quick write-up of the main layout blocks of our websites. So let's have a look:\n\n## Screen sizes and break points: 1024px wide or not?\n\nOur websites should work on a variety of devices:\n\n\nFor this, we practice so-called **responsive design**. A design that adapts to the screen size. \nOr rather, the screen width because thanks to scrolling, we always have plenty of height.\n\nIn practice, we use so-called **break points**. A list of one or more screen widths at which we apply a different layout for our website.\nTo keep things simple, we utilize a single breakpoint: **1024px**. \n\n - large screen: 1024 pixels or more wide\n - small screen: less than 1024 pixels wide\n\n## Page structure: Three elements, one dimension\n\nThe structure of each page on the website is a vertical column with three elements:\n\n - The header which holds the so-called `navbar`, short for *navigation bar*\n - The main part of the page, which in this case shows this blog post\n - The footer\n\nIt looks like this:\n\n\n\nThat's on large screens. We'll have a closer look at small screens later.\n\n## Footer\n\nThe footer is the simplest element. It's always there, and it sits at the bottom of the page.\n\nThe footer spans the entire width of the screen, but the content within is constrained by a maximum width. That width is **1536px** (indicated by the red dashed lines in the image above).\nThis is to avoid that people on a 4K monitor get neck cramps like they're attending some tennis match, just to read what's on the screen.\n\n## Navbar\n\nThe navbar is similar to the footer in the sense that it spans the full width, yet the content within is constrained to maximum 1536 pixels.\n\nOn large screens, the navbar sits at the top of the page and does not have a background color to make it stand out.\nThat's because it's rather intuitive to have the navigation at the top of the page.\n\nOn mobile, the navbar collapses gets fixed at the bottom of the screen, and gets a background color to draw attention to the fact that this is where the navigation controls are:\n\n\n\nThe reason we place the navigation at the bottom of the screen is that it's easier to reach when using a mobile phone with one hand.\n\nRather than try to cram everything in the (now very small) navbar. We simply use a button that makes the whole screen the navigation menu on small screens.\n\n## Main layout\n\nThe *main* part of a page can be pretty much anything we want. But on most pages, it looks like this:\n\n\n\nHere's too we are constraining the content to the same maximum width.\nApart from that, we have the main content of the page, and the `aside` which typically holds navigation.\n\nThis aside is not available on mobile, and instead can be reached by bringing up the menu.\n\n\n## Summary\n\nAll our websites look the same\n\n - The page is a vertical column made of 3 parts: header -> main -> footer\n - The main part can be any layout, but the most common has content + aside\n - On mobile, the navbar sits fixed at the bottom, and aside moves off-canvas\n\n",
|
|
||||||
"caption": " Photo by Kelly Lacy via Pexels",
|
|
||||||
"slug": "layout-blocks-overview",
|
|
||||||
"date": "2021-07-15",
|
|
||||||
"title": "A quick tour of the main layout blocks",
|
|
||||||
"linktitle": "Main layout blocks",
|
|
||||||
"published_at": "2021-07-15T16:25:20.922Z",
|
|
||||||
"createdAt": "2021-07-15T16:25:17.007Z",
|
|
||||||
"updatedAt": "2021-07-23T15:04:30.866Z",
|
|
||||||
"__v": 0,
|
|
||||||
"author": "joostdecock",
|
|
||||||
"image": {
|
|
||||||
"_id": "60f05ac3db32b45d5c4d6da7",
|
|
||||||
"name": "pexels-kelly-lacy-2402233.jpg",
|
|
||||||
"alternativeText": "",
|
|
||||||
"caption": "",
|
|
||||||
"hash": "pexels_kelly_lacy_2402233_45b5683839",
|
|
||||||
"ext": ".jpg",
|
|
||||||
"mime": "image/jpeg",
|
|
||||||
"size": 630.2,
|
|
||||||
"width": 1920,
|
|
||||||
"height": 1078,
|
|
||||||
"url": "/uploads/pexels_kelly_lacy_2402233_45b5683839.jpg",
|
|
||||||
"formats": {
|
|
||||||
"thumbnail": {
|
|
||||||
"name": "thumbnail_pexels-kelly-lacy-2402233.jpg",
|
|
||||||
"hash": "thumbnail_pexels_kelly_lacy_2402233_45b5683839",
|
|
||||||
"ext": ".jpg",
|
|
||||||
"mime": "image/jpeg",
|
|
||||||
"width": 245,
|
|
||||||
"height": 138,
|
|
||||||
"size": 16.81,
|
|
||||||
"path": null,
|
|
||||||
"url": "/uploads/thumbnail_pexels_kelly_lacy_2402233_45b5683839.jpg"
|
|
||||||
},
|
|
||||||
"large": {
|
|
||||||
"name": "large_pexels-kelly-lacy-2402233.jpg",
|
|
||||||
"hash": "large_pexels_kelly_lacy_2402233_45b5683839",
|
|
||||||
"ext": ".jpg",
|
|
||||||
"mime": "image/jpeg",
|
|
||||||
"width": 1000,
|
|
||||||
"height": 561,
|
|
||||||
"size": 207.61,
|
|
||||||
"path": null,
|
|
||||||
"url": "/uploads/large_pexels_kelly_lacy_2402233_45b5683839.jpg"
|
|
||||||
},
|
|
||||||
"medium": {
|
|
||||||
"name": "medium_pexels-kelly-lacy-2402233.jpg",
|
|
||||||
"hash": "medium_pexels_kelly_lacy_2402233_45b5683839",
|
|
||||||
"ext": ".jpg",
|
|
||||||
"mime": "image/jpeg",
|
|
||||||
"width": 750,
|
|
||||||
"height": 421,
|
|
||||||
"size": 122.96,
|
|
||||||
"path": null,
|
|
||||||
"url": "/uploads/medium_pexels_kelly_lacy_2402233_45b5683839.jpg"
|
|
||||||
},
|
|
||||||
"small": {
|
|
||||||
"name": "small_pexels-kelly-lacy-2402233.jpg",
|
|
||||||
"hash": "small_pexels_kelly_lacy_2402233_45b5683839",
|
|
||||||
"ext": ".jpg",
|
|
||||||
"mime": "image/jpeg",
|
|
||||||
"width": 500,
|
|
||||||
"height": 281,
|
|
||||||
"size": 61.63,
|
|
||||||
"path": null,
|
|
||||||
"url": "/uploads/small_pexels_kelly_lacy_2402233_45b5683839.jpg"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"provider": "local",
|
|
||||||
"related": [
|
|
||||||
"60f0616ddb32b45d5c4d6dac"
|
|
||||||
],
|
|
||||||
"createdAt": "2021-07-15T15:56:51.570Z",
|
|
||||||
"updatedAt": "2021-07-15T16:25:17.017Z",
|
|
||||||
"__v": 0,
|
|
||||||
"id": "60f05ac3db32b45d5c4d6da7"
|
|
||||||
},
|
|
||||||
"site": "60ead51670e8d35a6d089fa0",
|
|
||||||
"locale": "en",
|
|
||||||
"id": "60f0616ddb32b45d5c4d6dac",
|
|
||||||
"intro": "I wanted to do a quick write-up of the main layout blocks of our websites. So let's have a look:"
|
|
||||||
}
|
|
|
@ -108,13 +108,15 @@ const DefaultLayout = ({ app, title=false, children=[]}) => {
|
||||||
<PrimaryNavigation app={app} active={slug}/>
|
<PrimaryNavigation app={app} active={slug}/>
|
||||||
</aside>
|
</aside>
|
||||||
<section className='max-w-61.8% lg:pt-8 p-4 w-full'>
|
<section className='max-w-61.8% lg:pt-8 p-4 w-full'>
|
||||||
{title && (
|
<div className="max-w-5xl">
|
||||||
<>
|
{title && (
|
||||||
<Breadcrumbs app={app} slug={slug} title={title} />
|
<>
|
||||||
<PageTitle app={app} slug={slug} title={title} />
|
<Breadcrumbs app={app} slug={slug} title={title} />
|
||||||
</>
|
<PageTitle app={app} slug={slug} title={title} />
|
||||||
)}
|
</>
|
||||||
{children}
|
)}
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<Footer app={app} />
|
<Footer app={app} />
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { compile } from '@mdx-js/mdx'
|
||||||
import remarkFrontmatter from 'remark-frontmatter'
|
import remarkFrontmatter from 'remark-frontmatter'
|
||||||
import remarkGfm from 'remark-gfm'
|
import remarkGfm from 'remark-gfm'
|
||||||
import remarkCopyLinkedFiles from 'remark-copy-linked-files'
|
import remarkCopyLinkedFiles from 'remark-copy-linked-files'
|
||||||
|
import { remarkIntroPlugin } from './remark-intro-plugin.mjs'
|
||||||
// Rehype plugins we want to use
|
// Rehype plugins we want to use
|
||||||
import rehypeHighlight from 'rehype-highlight'
|
import rehypeHighlight from 'rehype-highlight'
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@ const mdxLoader = async (language, site, slug) => {
|
||||||
path.resolve(`../../markdown/${site}/${slug}/${language}.md`),
|
path.resolve(`../../markdown/${site}/${slug}/${language}.md`),
|
||||||
'utf-8'
|
'utf-8'
|
||||||
)
|
)
|
||||||
|
const intro = []
|
||||||
const mdx = String(
|
const mdx = String(
|
||||||
await compile(md, {
|
await compile(md, {
|
||||||
outputFormat: 'function-body',
|
outputFormat: 'function-body',
|
||||||
|
@ -42,6 +44,10 @@ const mdxLoader = async (language, site, slug) => {
|
||||||
sourceDir: path.resolve(`../../markdown/${site}/${slug}`),
|
sourceDir: path.resolve(`../../markdown/${site}/${slug}`),
|
||||||
staticPath: '/mdx/',
|
staticPath: '/mdx/',
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
remarkIntroPlugin,
|
||||||
|
{ intro }
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
rehypePlugins: [
|
rehypePlugins: [
|
||||||
|
@ -50,7 +56,7 @@ const mdxLoader = async (language, site, slug) => {
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
return mdx
|
return {mdx, intro}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default mdxLoader
|
export default mdxLoader
|
||||||
|
|
|
@ -25,7 +25,9 @@ const asText = [
|
||||||
]
|
]
|
||||||
|
|
||||||
// The actual plugin starts here
|
// The actual plugin starts here
|
||||||
export const remarkIntroPlugin = () => {
|
export const remarkIntroPlugin = (opts={}) => {
|
||||||
|
|
||||||
|
const { intro=[] } = opts
|
||||||
|
|
||||||
// Check to see whether the node has frontmatter
|
// Check to see whether the node has frontmatter
|
||||||
const hasFrontmatter = node => (node.children[0].type === 'yaml')
|
const hasFrontmatter = node => (node.children[0].type === 'yaml')
|
||||||
|
@ -52,14 +54,15 @@ export const remarkIntroPlugin = () => {
|
||||||
|
|
||||||
// Tree visitor
|
// Tree visitor
|
||||||
const visitor = (node) => {
|
const visitor = (node) => {
|
||||||
const intro = extractFirstParagraph(node)
|
const nodeIntro = extractFirstParagraph(node)
|
||||||
|
// Forgive me for this hack
|
||||||
|
intro.push(nodeIntro)
|
||||||
if (hasFrontmatter(node)) {
|
if (hasFrontmatter(node)) {
|
||||||
node.children[0].value += `\nintro: "${intro}"\n`
|
node.children[0].value += `\nintro: "${nodeIntro}"\n`
|
||||||
//console.log(node.children[0])
|
|
||||||
} else {
|
} else {
|
||||||
node.children.unshift({
|
node.children.unshift({
|
||||||
type: 'yaml',
|
type: 'yaml',
|
||||||
value: `intro: "${intro}"`
|
value: `intro: "${nodeIntro}"`
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,7 +11,6 @@ import remarkMdx from 'remark-mdx'
|
||||||
import vfileReporter from 'vfile-reporter'
|
import vfileReporter from 'vfile-reporter'
|
||||||
import { readSync } from 'to-vfile'
|
import { readSync } from 'to-vfile'
|
||||||
import yaml from 'js-yaml'
|
import yaml from 'js-yaml'
|
||||||
import { remarkIntroPlugin } from './remark-intro-plugin.mjs'
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -54,7 +53,7 @@ const fileToSlug = (file, site, lang) => (file.slice(-6) === `/${lang}.md`)
|
||||||
: false
|
: false
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper method to get the title and intro text from an MDX file
|
* Helper method to get the title and meta data from an MDX file
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
*
|
*
|
||||||
|
@ -64,8 +63,7 @@ const mdxMetaInfo = async file => {
|
||||||
let result
|
let result
|
||||||
try {
|
try {
|
||||||
result = await unified()
|
result = await unified()
|
||||||
// .use(remarkMdx)
|
//.use(remarkMdx)
|
||||||
// .use(remarkIntroPlugin)
|
|
||||||
.use(remarkParser)
|
.use(remarkParser)
|
||||||
.use(remarkCompiler)
|
.use(remarkCompiler)
|
||||||
.use(remarkFrontmatter)
|
.use(remarkFrontmatter)
|
||||||
|
@ -109,7 +107,6 @@ export const prebuildMdx = async(site) => {
|
||||||
if (meta?.data?.title && meta?.data?.title) {
|
if (meta?.data?.title && meta?.data?.title) {
|
||||||
pages[lang][slug] = {
|
pages[lang][slug] = {
|
||||||
title: meta.data.title,
|
title: meta.data.title,
|
||||||
intro: meta.data.intro,
|
|
||||||
order: meta.data.order
|
order: meta.data.order
|
||||||
? meta.data.order+meta.data.title
|
? meta.data.order+meta.data.title
|
||||||
: meta.data.title,
|
: meta.data.title,
|
||||||
|
@ -119,7 +116,7 @@ export const prebuildMdx = async(site) => {
|
||||||
: meta.data.title
|
: meta.data.title
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log('Failed to extract title & intro from:', slug)
|
console.log('Failed to extract meta info from:', slug)
|
||||||
console.log(meta.messages, null ,2)
|
console.log(meta.messages, null ,2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import remarkCompiler from 'remark-stringify'
|
||||||
import remarkFrontmatter from 'remark-frontmatter'
|
import remarkFrontmatter from 'remark-frontmatter'
|
||||||
import remarkFrontmatterExtractor from 'remark-extract-frontmatter'
|
import remarkFrontmatterExtractor from 'remark-extract-frontmatter'
|
||||||
import yaml from 'yaml'
|
import yaml from 'yaml'
|
||||||
import { remarkIntroPlugin } from './remark-intro-plugin.mjs'
|
import { remarkIntroPlugin } from '../mdx/remark-intro-plugin.mjs'
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue