From a9b303d0292b34e173d696210e31f938083dc80a Mon Sep 17 00:00:00 2001 From: khalilcodes Date: Wed, 1 Jun 2022 17:57:57 +0300 Subject: [PATCH 01/12] [site/config]: add keywords field and move date logic to contentlayer --- site/contentlayer.config.ts | 18 ++++++++++++++---- site/pages/[...slug].js | 12 ++---------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/site/contentlayer.config.ts b/site/contentlayer.config.ts index 15e0d31..43cf1e0 100644 --- a/site/contentlayer.config.ts +++ b/site/contentlayer.config.ts @@ -5,6 +5,9 @@ import rehypeSlug from 'rehype-slug' import rehypeAutolinkHeadings from 'rehype-autolink-headings' import wikiLinkPlugin from "remark-wiki-link-plus" +const isValidDate = dateObject => new Date(dateObject) + .toString() !== 'Invalid Date'; + const ObsidianAliases = defineNestedType(() => ({ name: 'Obsidian', filePathPattern: '**/*.md*', @@ -22,6 +25,7 @@ const OtherPage = defineDocumentType(() => ({ date: { type: "date", description: "This will be the publication date" }, image: { type: "string" }, description: { type: 'string' }, + keywords: { type: "string" }, youtube: { type: "string" }, podcast: { type: "string" }, featured: { type: "boolean", default: false }, @@ -31,13 +35,19 @@ const OtherPage = defineDocumentType(() => ({ computedFields: { date: { type: "date", - resolve: (doc) => new Date(doc.date).toLocaleDateString('en-US', { - weekday: "long", year: "numeric", month: "long", day: "numeric" - }) + resolve: (doc) => { + const formattedDate = new Date(doc.date).toLocaleDateString('en-US', { + weekday: "long", year: "numeric", month: "long", day: "numeric" + }) + return isValidDate(formattedDate) ? formattedDate : null + } }, created: { type: "date", - resolve: (doc) => new Date(doc.created).toLocaleDateString('en-US') + resolve: (doc) => { + const formattedDate = new Date(doc.created).toLocaleDateString('en-US') + return isValidDate(formattedDate) ? formattedDate : null + } }, } })); diff --git a/site/pages/[...slug].js b/site/pages/[...slug].js index 4ec7602..4c51bd9 100644 --- a/site/pages/[...slug].js +++ b/site/pages/[...slug].js @@ -1,7 +1,6 @@ import MdxPage from '../components/MDX'; import { allOtherPages } from 'contentlayer/generated'; import { useMDXComponent } from 'next-contentlayer/hooks'; -import siteConfig from "../config/siteConfig" export default function Page({ body, ...rest }) { @@ -9,19 +8,12 @@ export default function Page({ body, ...rest }) { const children = { Component, frontmatter: { - ...rest, - date: rest.date === "Invalid Date" ? null : rest.date, - created: rest.created === "Invalid Date" ? null : rest.created + ...rest }, }; - - // enable editing content only for claims, concepts, and guide for now - const editUrl = ['claims', 'concepts', 'guide'].includes(rest._raw.sourceFileDir) - ? siteConfig.repoRoot + siteConfig.repoEditPath + rest._raw.sourceFilePath - : null return ( - + ); } From ed858069588cce83b50d7900d5b16f7a233c0dc4 Mon Sep 17 00:00:00 2001 From: khalilcodes Date: Wed, 1 Jun 2022 17:58:48 +0300 Subject: [PATCH 02/12] [site/lib]: create file to store regex constants --- site/lib/constants.js | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 site/lib/constants.js diff --git a/site/lib/constants.js b/site/lib/constants.js new file mode 100644 index 0000000..2ebe063 --- /dev/null +++ b/site/lib/constants.js @@ -0,0 +1,2 @@ +export const YOUTUBE_REGEX = + /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/; From d04ee80ea64b4bec5be373d6fdf7d1c0d6741b1d Mon Sep 17 00:00:00 2001 From: khalilcodes Date: Wed, 1 Jun 2022 18:29:38 +0300 Subject: [PATCH 03/12] [site/components]: replace youtube embed with lite-youtube component --- site/components/Paragraph.js | 29 +++++++---------------------- site/pages/_app.js | 1 + 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/site/components/Paragraph.js b/site/components/Paragraph.js index b1096bf..3940a5d 100644 --- a/site/components/Paragraph.js +++ b/site/components/Paragraph.js @@ -1,30 +1,15 @@ -import ReactPlayer from "react-player"; - -const videoLinks = [ - "youtube.com", - "dailymotion.com", - "vimeo.com", - "soundcloud.com", - "facebook.com/watch", - "twitch.com", -]; +import LiteYouTubeEmbed from "react-lite-youtube-embed"; +import { YOUTUBE_REGEX } from "../lib/constants"; export const Paragraph = (props) => { if ( typeof props.children == "object" && props.children.props && props.children.props.href && - videoLinks.some((str) => props.children.props.href.includes(str)) - ) - return ( -
- -
- ); + YOUTUBE_REGEX.test(props.children.props.href) + ) { + const youtubeId = props.children.props.href.split(/^|=|\//).pop(); + return ; + } return

; }; diff --git a/site/pages/_app.js b/site/pages/_app.js index b4da4b1..21c40fd 100644 --- a/site/pages/_app.js +++ b/site/pages/_app.js @@ -5,6 +5,7 @@ import { DefaultSeo } from 'next-seo' import { ThemeProvider } from 'next-themes' import '../styles/global.css' +import "react-lite-youtube-embed/dist/LiteYouTubeEmbed.css"; import siteConfig from '../config/siteConfig.js' import Layout from '../components/Layout' import * as gtag from '../lib/gtag' From fa80441cbffbfcfe014663e6e18ad4397601a25e Mon Sep 17 00:00:00 2001 From: khalilcodes Date: Wed, 1 Jun 2022 18:30:05 +0300 Subject: [PATCH 04/12] [site/components]: remove unused import --- site/components/Anchor.js | 1 - 1 file changed, 1 deletion(-) diff --git a/site/components/Anchor.js b/site/components/Anchor.js index 6ef0b78..f239f93 100644 --- a/site/components/Anchor.js +++ b/site/components/Anchor.js @@ -1,5 +1,4 @@ import { Tooltip } from './Tooltip'; -import siteConfig from '../config/siteConfig.js' /** * Component for adding previews on hovering over anchor tags with relative paths From 1d527ca32932815ffc1226dcf1f0bbfe5b9f0756 Mon Sep 17 00:00:00 2001 From: khalilcodes Date: Wed, 1 Jun 2022 18:44:01 +0300 Subject: [PATCH 05/12] [site/mdx/seo]: add seo keyword, youtube embed and dynamic imports * add keywords and article tags for seo * replace youtube embed with lite-youtube component for faster page loads * use youtube regex to add proper id check to render youtube component * add dynamic imports for faster builds and improving page speed performance * remove podcast embed iframe and replace with link due to slower page loads --- site/components/MDX.js | 88 ++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 47 deletions(-) diff --git a/site/components/MDX.js b/site/components/MDX.js index e93c671..43b3af2 100644 --- a/site/components/MDX.js +++ b/site/components/MDX.js @@ -1,9 +1,15 @@ import Head from 'next/head' -import ReactPlayer from 'react-player/lazy' +import dynamic from 'next/dynamic' import { NextSeo } from 'next-seo' import siteConfig from "../config/siteConfig" -import { Paragraph } from './Paragraph' -import { Anchor } from './Anchor' +import LiteYouTubeEmbed from "react-lite-youtube-embed" +import { YOUTUBE_REGEX } from "../lib/constants" + +const Anchor = dynamic(() => import('./Anchor').then(module => module.Anchor), { + ssr: false +}) + +const Paragraph = dynamic(() => import("./Paragraph").then(mod => mod.Paragraph)) const components = { Head, @@ -11,30 +17,25 @@ const components = { a: Anchor } -export default function MdxPage({ children, editUrl }) { +export default function MdxPage({ children }) { const { Component, frontmatter: { - title, description, date, authors, youtube, podcast, image, _raw + title, description, date, keywords, youtube, podcast, image, _raw }} = children let youtubeThumnbnail - let podcastEmbed - if (youtube && !image) { + const youtubeId = + youtube && YOUTUBE_REGEX.test(youtube) && youtube.split(/^|=|\//).pop(); + + if (youtubeId && !image) { // get the youtube thumbnail image from https://img.youtube.com/vi//maxresdefault.jpg - const regex = - /\www.youtube.com\/\embed\/|youtube.com\/\embed\/|youtu.be\/|\www.youtube.com\/\watch\?v=|\youtube.com\/\watch\?v=/; - youtubeThumnbnail = - youtube.replace(regex, "img.youtube.com/vi/") + "/maxresdefault.jpg"; + youtubeThumnbnail = youtube.replace( + YOUTUBE_REGEX, + `https://img.youtube.com/vi/${youtubeId}/maxresdefault.jpg` + ); } - if (podcast && podcast.includes("life-itself")) { - const podcastUrl = podcast - podcastEmbed = ([ - podcastUrl.slice(0, "https://anchor.fm/life-itself".length), - "/embed", - podcastUrl.slice("https://anchor.fm/life-itself".length) - ].join("")) - } + const PodcastIcon = siteConfig.social.find((s) => s.name === "Podcast").icon; const titleFromUrl = _raw.flattenedPath .split("/") @@ -47,6 +48,11 @@ export default function MdxPage({ children, editUrl }) { const imageUrl = image ? siteConfig.url + image : youtubeThumnbnail ? youtubeThumnbnail : null + + // enable editing content only for claims, concepts, and guide for now + const editUrl = ['claims', 'concepts', 'guide'].includes(_raw.sourceFileDir) + ? siteConfig.repoRoot + siteConfig.repoEditPath + _raw.sourceFilePath + : null return ( <> @@ -57,6 +63,11 @@ export default function MdxPage({ children, editUrl }) { openGraph={{ title: SeoTitle, description: description, + url: `${siteConfig.url}/${_raw.flattenedPath}`, + type: "article", + article: { + tags: keywords ? keywords.split(",") : [] + }, images: imageUrl ? ([ { @@ -69,16 +80,14 @@ export default function MdxPage({ children, editUrl }) { ]) : siteConfig.nextSeo.openGraph.images, }} + additionalMetaTags={[ + { name: "keywords", content: keywords ? keywords : "" } + ]} />

{title &&

{title}

} - {authors && ( -
-

{authors}

-
- )} {date && (

on {date} @@ -87,36 +96,21 @@ export default function MdxPage({ children, editUrl }) { {description && (

{description}

)} - {youtube && ( -
- -
+ {youtubeId && ( + )} {podcast && (
- {podcastEmbed && ( -
-