Merge pull request #161 from life-itself/twitter-embed
[site/markdown/links]: Twitter embeds
This commit is contained in:
commit
6cce1c7620
|
|
@ -1,15 +1,21 @@
|
||||||
import LiteYouTubeEmbed from "react-lite-youtube-embed";
|
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) => {
|
export const Paragraph = (props) => {
|
||||||
if (
|
if (
|
||||||
typeof props.children == "object" &&
|
typeof props.children == "object" &&
|
||||||
props.children.props &&
|
props.children.props &&
|
||||||
props.children.props.href &&
|
props.children.props.href
|
||||||
YOUTUBE_REGEX.test(props.children.props.href)
|
|
||||||
) {
|
) {
|
||||||
const youtubeId = props.children.props.href.split(/^|=|\//).pop();
|
if (YOUTUBE_REGEX.test(props.children.props.href)) {
|
||||||
return <LiteYouTubeEmbed id={youtubeId} />;
|
const youtubeId = props.children.props.href.split(/^|=|\//).pop();
|
||||||
|
return <LiteYouTubeEmbed id={youtubeId} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TWITTER_REGEX.test(props.children.props.href)) {
|
||||||
|
return <TwitterEmbed url={props.children.props.href} {...props} />;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return <p {...props} />;
|
return <p {...props} />;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
import { useEffect, useState, useRef } from "react";
|
||||||
|
|
||||||
|
const twitterWidgetJs = "https://platform.twitter.com/widgets.js";
|
||||||
|
const message = "Loading tweet...";
|
||||||
|
|
||||||
|
export default function TwitterEmbed({ url, ...props }) {
|
||||||
|
let ref = useRef(null);
|
||||||
|
const [state, setState] = useState({
|
||||||
|
isLoading: true,
|
||||||
|
message: message,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tweetId = url.split("status/").pop();
|
||||||
|
|
||||||
|
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(() => {
|
||||||
|
let componentMounted = true;
|
||||||
|
|
||||||
|
const script = document.createElement("script");
|
||||||
|
script.src = twitterWidgetJs;
|
||||||
|
script.async = true;
|
||||||
|
script.onload = () => renderTweet();
|
||||||
|
|
||||||
|
if (componentMounted) {
|
||||||
|
if (!window.twttr) {
|
||||||
|
document.head.appendChild(script);
|
||||||
|
} else {
|
||||||
|
renderTweet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
setState({ isLoading: true, message: message });
|
||||||
|
componentMounted = false;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{state.isLoading && state.message && (
|
||||||
|
<div className="relative my-4 w-full sm:max-w-xl bg-neutral-900 drop-shadow-md rounded-lg">
|
||||||
|
<div className="absolute flex flex-col flex-wrap break-all items-center justify-center bg-slate-700/60 w-full h-full px-4 py-2 rounded-lg top-0 left-0 z-10">
|
||||||
|
<svg
|
||||||
|
role="img"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
className="w-6 absolute right-4 top-4"
|
||||||
|
>
|
||||||
|
<title>Twitter</title>
|
||||||
|
<path
|
||||||
|
fill="#1DA1F2"
|
||||||
|
d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<div className="text-gray-300 font-bold my-2 italic">
|
||||||
|
{state.message}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`p-3 space-y-4 ${
|
||||||
|
state.isLoading && state.message === message && "animate-pulse"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="flex items-center">
|
||||||
|
<div className="mr-2 h-10 w-10 rounded-full bg-slate-700" />
|
||||||
|
<div className="w-1/3 h-4 bg-slate-700"></div>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="w-2/3 h-3 bg-slate-700"></div>
|
||||||
|
<div className="w-2/3 h-3 bg-slate-700"></div>
|
||||||
|
</div>
|
||||||
|
<div className="flex space-x-4">
|
||||||
|
<div className="w-1/4 h-3 bg-slate-700"></div>
|
||||||
|
<div className="w-1/4 h-3 bg-slate-700"></div>
|
||||||
|
<div className="w-1/4 h-3 bg-slate-700"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="twitter-tweet" ref={ref} />
|
||||||
|
{!state.message && <p {...props} />}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -2,11 +2,24 @@
|
||||||
title: Test frontmatter in markdown
|
title: Test frontmatter in markdown
|
||||||
created: 2022-04-26
|
created: 2022-04-26
|
||||||
date: 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 <description> field.'
|
||||||
youtube: https://youtube.com/
|
youtube: https://youtube.com/
|
||||||
featured: false
|
featured: false
|
||||||
---
|
---
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
## Test twitter embeds in markdown
|
||||||
|
|
||||||
|
*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/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
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
## Test (Obsidian) wiki link syntax
|
## Test (Obsidian) wiki link syntax
|
||||||
|
|
||||||
|
|
@ -30,7 +43,6 @@ featured: false
|
||||||
*`[[#Our Approach]]`*
|
*`[[#Our Approach]]`*
|
||||||
[[#Our Approach]]
|
[[#Our Approach]]
|
||||||
|
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
## Test video embed links in markdown
|
## Test video embed links in markdown
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
export const YOUTUBE_REGEX =
|
export const YOUTUBE_REGEX = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
|
||||||
/^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
|
|
||||||
|
export const TWITTER_REGEX = /^https?:\/\/twitter\.com\/(?:#!\/)?(\w+)\/status(es)?\/(\d+)/;
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 451 KiB After Width: | Height: | Size: 131 B |
Binary file not shown.
|
Before Width: | Height: | Size: 482 KiB After Width: | Height: | Size: 131 B |
Binary file not shown.
|
Before Width: | Height: | Size: 360 KiB After Width: | Height: | Size: 131 B |
|
|
@ -8,6 +8,10 @@
|
||||||
h1, h2, h3, h4, h5 {
|
h1, h2, h3, h4, h5 {
|
||||||
@apply font-sans;
|
@apply font-sans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.twitter-tweet iframe {
|
||||||
|
@apply !border !border-2 !border-neutral-900 !rounded-2xl !bg-neutral-900 shadow;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OTHERS */
|
/* OTHERS */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue