From 3b1e0350d6d77a38562742938b02e48e8e8e142a Mon Sep 17 00:00:00 2001
From: khalilcodes
Date: Wed, 18 May 2022 18:54:57 +0300
Subject: [PATCH 01/10] [site][xs]: create file to store regex constants
---
site/lib/constants.js | 3 +++
1 file changed, 3 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..2cceaed
--- /dev/null
+++ b/site/lib/constants.js
@@ -0,0 +1,3 @@
+export const YOUTUBE_REGEX = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
+
+export const TWITTER_REGEX = /^https?:\/\/twitter\.com\/(?:#!\/)?(\w+)\/status(es)?\/(\d+)/;
\ No newline at end of file
From 0be1d0b72fdc092cc9edae64796f865aeaf05dbf Mon Sep 17 00:00:00 2001
From: khalilcodes
Date: Wed, 18 May 2022 18:59:05 +0300
Subject: [PATCH 02/10] [site/mdx][xs]: refactor code for youtube regex
---
site/components/MDX.js | 112 +++++++++++++++++++++++++----------------
1 file changed, 70 insertions(+), 42 deletions(-)
diff --git a/site/components/MDX.js b/site/components/MDX.js
index fe906ff..c704c05 100644
--- a/site/components/MDX.js
+++ b/site/components/MDX.js
@@ -1,37 +1,49 @@
-import Head from 'next/head'
-import ReactPlayer from 'react-player/lazy'
-import { Paragraph } from './Link'
-import { NextSeo } from 'next-seo'
-import siteConfig from "../config/siteConfig"
+import Head from "next/head";
+import ReactPlayer from "react-player/lazy";
+import { Paragraph } from "./Link";
+import { NextSeo } from "next-seo";
+import siteConfig from "../config/siteConfig";
+import { YOUTUBE_REGEX } from "../lib/constants";
const components = {
Head,
- p: Paragraph
-}
+ p: Paragraph,
+};
export default function MdxPage({ children, editUrl }) {
- const { Component, frontmatter: {
- title, description, date, authors, youtube, podcast, image, _raw
- }} = children
+ const {
+ Component,
+ frontmatter: {
+ title,
+ description,
+ date,
+ authors,
+ youtube,
+ podcast,
+ image,
+ _raw,
+ },
+ } = children;
- let youtubeThumnbnail
- let podcastEmbed
+ let youtubeThumnbnail;
+ let podcastEmbed;
- if (youtube && !image) {
+ if (youtube && YOUTUBE_REGEX.test(youtube) && !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";
+ const youtubeId = youtube.split(/^|=|\//).pop();
+ youtubeThumnbnail = youtube.replace(
+ YOUTUBE_REGEX,
+ `https://img.youtube.com/vi/${youtubeId}/maxresdefault.jpg`
+ );
}
if (podcast && podcast.includes("life-itself")) {
- const podcastUrl = podcast
- podcastEmbed = ([
+ const podcastUrl = podcast;
+ podcastEmbed = [
podcastUrl.slice(0, "https://anchor.fm/life-itself".length),
"/embed",
- podcastUrl.slice("https://anchor.fm/life-itself".length)
- ].join(""))
+ podcastUrl.slice("https://anchor.fm/life-itself".length),
+ ].join("");
}
const titleFromUrl = _raw.flattenedPath
@@ -44,7 +56,9 @@ export default function MdxPage({ children, editUrl }) {
const SeoTitle = title ?? titleFromUrl;
const imageUrl = image
? siteConfig.url + image
- : youtubeThumnbnail ? youtubeThumnbnail : null
+ : youtubeThumnbnail
+ ? youtubeThumnbnail
+ : null;
return (
<>
@@ -56,15 +70,15 @@ export default function MdxPage({ children, editUrl }) {
title: SeoTitle,
description: description,
images: imageUrl
- ? ([
+ ? [
{
url: imageUrl,
width: 1200,
height: 627,
alt: title,
- type: "image/png"
+ type: "image/png",
},
- ])
+ ]
: siteConfig.nextSeo.openGraph.images,
}}
/>
@@ -82,10 +96,8 @@ export default function MdxPage({ children, editUrl }) {
on {date}
)}
- {description && (
- {description}
- )}
- {youtube && (
+ {description && {description}
}
+ {youtube && YOUTUBE_REGEX.test(youtube) && (
-
-
- {editUrl && (
- )}
+
+
+ {editUrl && (
+
+ )}
>
From 48cbd1f0d9c55100f049ea22cb4448c3944c910e Mon Sep 17 00:00:00 2001
From: khalilcodes
Date: Wed, 18 May 2022 19:01:23 +0300
Subject: [PATCH 03/10] [site/components][md]: create twitter embed component
---
site/components/TwitterEmbed.js | 86 +++++++++++++++++++++++++++++++++
1 file changed, 86 insertions(+)
create mode 100644 site/components/TwitterEmbed.js
diff --git a/site/components/TwitterEmbed.js b/site/components/TwitterEmbed.js
new file mode 100644
index 0000000..4fd1956
--- /dev/null
+++ b/site/components/TwitterEmbed.js
@@ -0,0 +1,86 @@
+import { useEffect, useState, useRef } from "react";
+
+const twitterWidgetJs = "https://platform.twitter.com/widgets.js";
+
+export default function TwitterEmbed({ url }) {
+ let ref = useRef(null)
+ const [isLoading, setLoading] = useState(true)
+
+ const tweetId = url.split("status/").pop()
+
+ var callbacks = [];
+
+ const loadScript = (src, cb) => {
+ if (callbacks.length === 0) {
+ callbacks.push(cb);
+ var s = document.createElement("script");
+ s.setAttribute("src", src);
+ s.setAttribute("async", "true");
+ s.onload = () => callbacks.forEach((cb) => cb());
+ document.head.appendChild(s);
+ } else {
+ callbacks.push(cb);
+ }
+ }
+
+ useEffect(() => {
+ if (!ref.current) return;
+
+ const renderTweet = () => {
+ window.twttr.widgets.createTweet(tweetId, ref.current, {
+ theme: "dark"
+ }).then(() => {
+ setLoading(false)
+ })
+ }
+
+ if (!window.twttr) {
+ loadScript(twitterWidgetJs, renderTweet)
+ } else {
+ renderTweet()
+ }
+
+ return () => {
+ setLoading(true);
+ };
+ },[]);
+
+ return (
+ <>
+ {isLoading &&
+
+
+ Twitter
+
+
+ Loading tweet...
+
+
+
}
+
+ >
+ );
+}
From 20baae0c6805efde8620564995130e6571b8e636 Mon Sep 17 00:00:00 2001
From: khalilcodes
Date: Wed, 18 May 2022 19:03:19 +0300
Subject: [PATCH 04/10] [site/mdx][s]: add twitter embed component to parse
twitter links in markdown
---
site/components/Link.js | 45 ++++++++++++++++++++---------------------
1 file changed, 22 insertions(+), 23 deletions(-)
diff --git a/site/components/Link.js b/site/components/Link.js
index b1d97df..0cb260e 100644
--- a/site/components/Link.js
+++ b/site/components/Link.js
@@ -1,31 +1,30 @@
-import Link from "next/link";
import ReactPlayer from "react-player";
-
-const videoLinks = [
- "youtube.com",
- "dailymotion.com",
- "vimeo.com",
- "soundcloud.com",
- "facebook.com/watch",
- "twitch.com",
-];
+import TwitterEmbed from "./TwitterEmbed";
+import { YOUTUBE_REGEX, TWITTER_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 (
-
-
-
- );
+ props.children.props.href
+ ) {
+ if (YOUTUBE_REGEX.test(props.children.props.href)) {
+ return (
+
+
+
+ );
+ }
+
+ if (TWITTER_REGEX.test(props.children.props.href)) {
+ return ;
+ }
+ }
+
return
;
};
From 161e08a9c25bf93675f0a2e50de11561c18c32bd Mon Sep 17 00:00:00 2001
From: khalilcodes
Date: Wed, 18 May 2022 19:06:26 +0300
Subject: [PATCH 05/10] [site/styles][xs]: add styles for twitter embeds
---
site/styles/global.css | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/site/styles/global.css b/site/styles/global.css
index 0387224..5c5400b 100644
--- a/site/styles/global.css
+++ b/site/styles/global.css
@@ -8,6 +8,10 @@
h1, h2, h3, h4, h5 {
@apply font-sans;
}
+
+ .twitter-tweet iframe {
+ @apply !border !border-2 !border-neutral-900 !rounded-2xl !bg-neutral-900 shadow;
+ }
}
/* OTHERS */
From 2fe9d5487e60257cf22d9cb84f663cf4a40ee711 Mon Sep 17 00:00:00 2001
From: khalilcodes
Date: Wed, 18 May 2022 19:08:05 +0300
Subject: [PATCH 06/10] [site/mdx][xs]: add twitter embed link in test page
---
site/content/test.md | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/site/content/test.md b/site/content/test.md
index adcf563..d3852b6 100644
--- a/site/content/test.md
+++ b/site/content/test.md
@@ -2,11 +2,20 @@
title: Test frontmatter in markdown
created: 2022-04-26
date: 2022-04-26
-description: 'In this test episode with somebody about their work to make community finance transparent and sustainable with Open Collective, their commitment ot steward ownership and the value of an exit to community.'
+description: 'This description is from the frontmatter field.'
youtube: https://youtube.com/
featured: false
---
+***
+
+## Test twitter embeds in markdown
+
+*eg. if this twitter link https://twitter.com/ecb/status/1518591205365460992 is on a separate line, then it will be rendered as seen below*
+
+https://twitter.com/ecb/status/1518591205365460992
+
+***
## Test (Obsidian) wiki link syntax
@@ -30,7 +39,6 @@ featured: false
*`[[#Our Approach]]`*
[[#Our Approach]]
-
***
## Test video embed links in markdown
From 22fbbe3ad52f9ebe74d25dbb7c3785ac1acea478 Mon Sep 17 00:00:00 2001
From: khalilcodes
Date: Wed, 18 May 2022 20:12:38 +0300
Subject: [PATCH 07/10] [site/twitter-embeds]: add checks for deleted/not-found
tweets
---
site/components/TwitterEmbed.js | 79 +++++++++++++++++++--------------
1 file changed, 45 insertions(+), 34 deletions(-)
diff --git a/site/components/TwitterEmbed.js b/site/components/TwitterEmbed.js
index 4fd1956..d5b0f59 100644
--- a/site/components/TwitterEmbed.js
+++ b/site/components/TwitterEmbed.js
@@ -1,10 +1,14 @@
import { useEffect, useState, useRef } from "react";
const twitterWidgetJs = "https://platform.twitter.com/widgets.js";
+const message = "Loading tweet..."
export default function TwitterEmbed({ url }) {
let ref = useRef(null)
- const [isLoading, setLoading] = useState(true)
+ const [state, setState] = useState({
+ isLoading: true,
+ message: message
+ })
const tweetId = url.split("status/").pop()
@@ -29,8 +33,9 @@ export default function TwitterEmbed({ url }) {
const renderTweet = () => {
window.twttr.widgets.createTweet(tweetId, ref.current, {
theme: "dark"
- }).then(() => {
- setLoading(false)
+ }).then((el) => {
+ if (el) return setState(prev => ({ ...prev, isLoading: false }))
+ return setState(prev => ({ ...prev, message: "Sorry, this tweet could not be found." }))
})
}
@@ -41,45 +46,51 @@ export default function TwitterEmbed({ url }) {
}
return () => {
- setLoading(true);
+ setState(prev => ({ ...prev, isLoading: true }));
};
},[]);
return (
<>
- {isLoading &&
-
-
+
+
+ Twitter
+
+
+
{state.message}
+
+
-
Twitter
-
-
- Loading tweet...
-
-
- }
+ )}
>
);
From 007742af236a5e21b18fac5e5535cb2961a368bf Mon Sep 17 00:00:00 2001
From: khalilcodes
Date: Mon, 13 Jun 2022 00:44:35 +0300
Subject: [PATCH 08/10] [site/components][md]: refactor twitter embed component
and modify styles for mobile
---
site/components/TwitterEmbed.js | 83 +++++++++++++++++----------------
1 file changed, 42 insertions(+), 41 deletions(-)
diff --git a/site/components/TwitterEmbed.js b/site/components/TwitterEmbed.js
index d5b0f59..6f35ffd 100644
--- a/site/components/TwitterEmbed.js
+++ b/site/components/TwitterEmbed.js
@@ -1,65 +1,64 @@
import { useEffect, useState, useRef } from "react";
const twitterWidgetJs = "https://platform.twitter.com/widgets.js";
-const message = "Loading tweet..."
+const message = "Loading tweet...";
-export default function TwitterEmbed({ url }) {
- let ref = useRef(null)
+export default function TwitterEmbed({ url, ...props }) {
+ let ref = useRef(null);
const [state, setState] = useState({
isLoading: true,
- message: message
- })
-
- const tweetId = url.split("status/").pop()
+ message: message,
+ });
- var callbacks = [];
+ const tweetId = url.split("status/").pop();
- const loadScript = (src, cb) => {
- if (callbacks.length === 0) {
- callbacks.push(cb);
- var s = document.createElement("script");
- s.setAttribute("src", src);
- s.setAttribute("async", "true");
- s.onload = () => callbacks.forEach((cb) => cb());
- document.head.appendChild(s);
- } else {
- callbacks.push(cb);
- }
- }
+ const renderTweet = () => {
+ window.twttr.widgets
+ .createTweet(tweetId, ref.current, {
+ theme: "dark",
+ })
+ .then((el) => {
+ if (el) return setState((prev) => ({ ...prev, isLoading: false }));
+ return setState((prev) => ({
+ ...prev,
+ message: null
+ }));
+ });
+ return window.twttr.widgets.load(ref.current);
+ };
useEffect(() => {
- if (!ref.current) return;
+ let componentMounted = true;
- const renderTweet = () => {
- window.twttr.widgets.createTweet(tweetId, ref.current, {
- theme: "dark"
- }).then((el) => {
- if (el) return setState(prev => ({ ...prev, isLoading: false }))
- return setState(prev => ({ ...prev, message: "Sorry, this tweet could not be found." }))
- })
- }
+ const script = document.createElement("script");
+ script.src = twitterWidgetJs;
+ script.async = true;
+ script.onload = () => renderTweet();
- if (!window.twttr) {
- loadScript(twitterWidgetJs, renderTweet)
- } else {
- renderTweet()
+ if (componentMounted) {
+ if (!window.twttr) {
+ document.head.appendChild(script);
+ } else {
+ renderTweet();
+ }
}
return () => {
- setState(prev => ({ ...prev, isLoading: true }));
+ setState({ isLoading: true, message: message });
+ componentMounted = false;
};
- },[]);
+ }, []);
return (
<>
- {state.isLoading && (
-
-
+ {state.isLoading && state.message && (
+
+
Twitter
-
{state.message}
+
+ {state.message}
+
-
@@ -92,6 +92,7 @@ export default function TwitterEmbed({ url }) {
)}
+ {!state.message &&
}
>
);
}
From 77e41e922bcc6fa33e8c0c5156f541c9e6bc2c70 Mon Sep 17 00:00:00 2001
From: khalilcodes
Date: Mon, 13 Jun 2022 00:45:46 +0300
Subject: [PATCH 09/10] [site/mdx][s]: add logic for twitter embeds
---
site/components/Paragraph.js | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/site/components/Paragraph.js b/site/components/Paragraph.js
index 3940a5d..c3e985d 100644
--- a/site/components/Paragraph.js
+++ b/site/components/Paragraph.js
@@ -1,15 +1,21 @@
import LiteYouTubeEmbed from "react-lite-youtube-embed";
-import { YOUTUBE_REGEX } from "../lib/constants";
+import TwitterEmbed from "./TwitterEmbed";
+import { YOUTUBE_REGEX, TWITTER_REGEX } from "../lib/constants";
export const Paragraph = (props) => {
if (
typeof props.children == "object" &&
props.children.props &&
- props.children.props.href &&
- YOUTUBE_REGEX.test(props.children.props.href)
+ props.children.props.href
) {
- const youtubeId = props.children.props.href.split(/^|=|\//).pop();
- return ;
+ if (YOUTUBE_REGEX.test(props.children.props.href)) {
+ const youtubeId = props.children.props.href.split(/^|=|\//).pop();
+ return ;
+ }
+
+ if (TWITTER_REGEX.test(props.children.props.href)) {
+ return ;
+ }
}
return
;
};
From c5e97ec0a2509823179ba0675895c988c9bc2402 Mon Sep 17 00:00:00 2001
From: khalilcodes
Date: Mon, 13 Jun 2022 00:47:18 +0300
Subject: [PATCH 10/10] [site/content][s]: update twitter links in test page
---
site/content/test.md | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/site/content/test.md b/site/content/test.md
index d3852b6..2ceb017 100644
--- a/site/content/test.md
+++ b/site/content/test.md
@@ -11,9 +11,13 @@ featured: false
## Test twitter embeds in markdown
-*eg. if this twitter link https://twitter.com/ecb/status/1518591205365460992 is on a separate line, then it will be rendered as seen below*
+*eg. if this twitter link https://twitter.com/rufuspollock/status/1524012242777395201 is on a separate line, then it will be rendered as seen below*
-https://twitter.com/ecb/status/1518591205365460992
+https://twitter.com/rufuspollock/status/1524012242777395201
+
+*tweets that have been deleted or are private would show the link instead as seen below*
+
+https://twitter.com/polka_ether_up/status/1524052691692908544
***