Merge pull request #161 from life-itself/twitter-embed

[site/markdown/links]: Twitter embeds
This commit is contained in:
Khalil Ali 2022-06-13 01:15:17 +03:00 committed by GitHub
commit 6cce1c7620
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 130 additions and 9 deletions

View File

@ -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 <LiteYouTubeEmbed id={youtubeId} />;
if (YOUTUBE_REGEX.test(props.children.props.href)) {
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} />;
};

View File

@ -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} />}
</>
);
}

View File

@ -2,11 +2,24 @@
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 <description> field.'
youtube: https://youtube.com/
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
@ -30,7 +43,6 @@ featured: false
*`[[#Our Approach]]`*
[[#Our Approach]]
***
## Test video embed links in markdown

View File

@ -1,2 +1,3 @@
export const YOUTUBE_REGEX =
/^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
export const YOUTUBE_REGEX = /^.*((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

View File

@ -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 */