From 82fe032cfbd79ba84c91ee1d584b4e9fff767f62 Mon Sep 17 00:00:00 2001 From: Austin Chen Date: Wed, 10 Aug 2022 16:26:25 -0700 Subject: [PATCH] Embed a tweet by URL --- common/package.json | 3 +- common/tsconfig.json | 5 +- common/util/parse.ts | 2 + common/util/tiptap-tweet.ts | 37 +++++++++++++ common/util/tweet-embed.tsx | 13 +++++ web/components/editor.tsx | 24 +++++++++ web/components/editor/tweetModal.tsx | 77 ++++++++++++++++++++++++++++ web/package.json | 1 + web/tsconfig.json | 8 ++- yarn.lock | 12 +++++ 10 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 common/util/tiptap-tweet.ts create mode 100644 common/util/tweet-embed.tsx create mode 100644 web/components/editor/tweetModal.tsx diff --git a/common/package.json b/common/package.json index c324379f..47866e98 100644 --- a/common/package.json +++ b/common/package.json @@ -12,7 +12,8 @@ "@tiptap/extension-link": "2.0.0-beta.43", "@tiptap/extension-mention": "2.0.0-beta.102", "@tiptap/starter-kit": "2.0.0-beta.190", - "lodash": "4.17.21" + "lodash": "4.17.21", + "react-twitter-embed": "4.0.4" }, "devDependencies": { "@types/lodash": "4.14.178" diff --git a/common/tsconfig.json b/common/tsconfig.json index 62a5c745..43ca937e 100644 --- a/common/tsconfig.json +++ b/common/tsconfig.json @@ -8,7 +8,8 @@ "outDir": "lib", "sourceMap": true, "strict": true, - "target": "es2017" + "target": "es2017", + "jsx": "preserve" }, - "include": ["**/*.ts"] + "include": ["**/*.ts", "util/tiptap-tweet.tsx"] } diff --git a/common/util/parse.ts b/common/util/parse.ts index f07e4097..dcc2c357 100644 --- a/common/util/parse.ts +++ b/common/util/parse.ts @@ -22,6 +22,7 @@ import { Image } from '@tiptap/extension-image' import { Link } from '@tiptap/extension-link' import { Mention } from '@tiptap/extension-mention' import Iframe from './tiptap-iframe' +import TiptapTweet from './tiptap-tweet' import { uniq } from 'lodash' export function parseTags(text: string) { @@ -94,6 +95,7 @@ export const exhibitExts = [ Link, Mention, Iframe, + TiptapTweet, ] export function richTextToString(text?: JSONContent) { diff --git a/common/util/tiptap-tweet.ts b/common/util/tiptap-tweet.ts new file mode 100644 index 00000000..6e44fa49 --- /dev/null +++ b/common/util/tiptap-tweet.ts @@ -0,0 +1,37 @@ +import { Node, mergeAttributes } from '@tiptap/core' +import { ReactNodeViewRenderer } from '@tiptap/react' +import WrappedTwitterTweetEmbed from './tweet-embed' + +export interface TweetOptions { + tweetId: string +} + +export default Node.create({ + name: 'tiptapTweet', + group: 'block', + atom: true, + + addAttributes() { + return { + tweetId: { + default: null, + }, + } + }, + + parseHTML() { + return [ + { + tag: 'tiptap-tweet', + }, + ] + }, + + renderHTML({ HTMLAttributes }) { + return ['tiptap-tweet', mergeAttributes(HTMLAttributes)] + }, + + addNodeView() { + return ReactNodeViewRenderer(WrappedTwitterTweetEmbed) + }, +}) diff --git a/common/util/tweet-embed.tsx b/common/util/tweet-embed.tsx new file mode 100644 index 00000000..5dc7d628 --- /dev/null +++ b/common/util/tweet-embed.tsx @@ -0,0 +1,13 @@ +import { NodeViewWrapper } from '@tiptap/react' +import { TwitterTweetEmbed } from 'react-twitter-embed' + +export default function WrappedTwitterTweetEmbed(props: any): JSX.Element { + console.log('wtwe props', props.node.attrs) + return ( + + + + ) +} diff --git a/web/components/editor.tsx b/web/components/editor.tsx index d52913b3..1da14703 100644 --- a/web/components/editor.tsx +++ b/web/components/editor.tsx @@ -21,12 +21,14 @@ import { useUsers } from 'web/hooks/use-users' import { mentionSuggestion } from './editor/mention-suggestion' import { DisplayMention } from './editor/mention' import Iframe from 'common/util/tiptap-iframe' +import TiptapTweet from 'common/util/tiptap-tweet' import { CodeIcon, PhotographIcon } from '@heroicons/react/solid' import { Modal } from './layout/modal' import { Col } from './layout/col' import { Button } from './button' import { Row } from './layout/row' import { Spacer } from './layout/spacer' +import { TweetModal } from './editor/tweetModal' const DisplayImage = Image.configure({ HTMLAttributes: { @@ -82,6 +84,7 @@ export function useTextEditor(props: { suggestion: mentionSuggestion(users), }), Iframe, + TiptapTweet, ], content: defaultValue, }, @@ -139,6 +142,7 @@ export function TextEditor(props: { }) { const { editor, upload, children } = props const [iframeOpen, setIframeOpen] = useState(false) + const [tweetOpen, setTweetOpen] = useState(false) return ( <> @@ -172,6 +176,26 @@ export function TextEditor(props: { Embed an iframe +
+ +
{/* Spacer that also focuses editor on click */}
void +}) { + const { editor, open, setOpen } = props + const [input, setInput] = useState('') + const tweetId = getTweetId(input) + const tweetCode = `` + console.log('tweetCode', tweetCode) + + return ( + + + + setInput(e.target.value)} + /> + + {/* Preview the embed if it's valid */} + {tweetId ? : } + + + + + + + + ) +} diff --git a/web/package.json b/web/package.json index 4fba3359..a008026b 100644 --- a/web/package.json +++ b/web/package.json @@ -53,6 +53,7 @@ "react-hot-toast": "2.2.0", "react-instantsearch-hooks-web": "6.24.1", "react-query": "3.39.0", + "react-twitter-embed": "4.0.4", "string-similarity": "^4.0.4", "tippy.js": "6.3.7" }, diff --git a/web/tsconfig.json b/web/tsconfig.json index 2f31aa8c..75221b93 100644 --- a/web/tsconfig.json +++ b/web/tsconfig.json @@ -19,6 +19,12 @@ "watchOptions": { "excludeDirectories": [".next"] }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "../common/**/*.ts"], + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + "../common/**/*.ts", + "../common/util/tiptap-tweet.tsx" + ], "exclude": ["node_modules"] } diff --git a/yarn.lock b/yarn.lock index bbf8d3ee..e83ffc0a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9964,6 +9964,13 @@ react-textarea-autosize@^8.3.2: use-composed-ref "^1.3.0" use-latest "^1.2.1" +react-twitter-embed@4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/react-twitter-embed/-/react-twitter-embed-4.0.4.tgz#4a6b8354acc266876ff1110b9f648518ea20db6d" + integrity sha512-2JIL7qF+U62zRzpsh6SZDXNI3hRNVYf5vOZ1WRcMvwKouw+xC00PuFaD0aEp2wlyGaZ+f4x2VvX+uDadFQ3HVA== + dependencies: + scriptjs "^2.5.9" + react-with-forwarded-ref@^0.3.3: version "0.3.4" resolved "https://registry.yarnpkg.com/react-with-forwarded-ref/-/react-with-forwarded-ref-0.3.4.tgz#b1e884ea081ec3c5dd578f37889159797454c0a5" @@ -10464,6 +10471,11 @@ schema-utils@^4.0.0: ajv-formats "^2.1.1" ajv-keywords "^5.0.0" +scriptjs@^2.5.9: + version "2.5.9" + resolved "https://registry.yarnpkg.com/scriptjs/-/scriptjs-2.5.9.tgz#343915cd2ec2ed9bfdde2b9875cd28f59394b35f" + integrity sha512-qGVDoreyYiP1pkQnbnFAUIS5AjenNwwQBdl7zeos9etl+hYKWahjRTfzAZZYBv5xNHx7vNKCmaLDQZ6Fr2AEXg== + search-insights@^2.1.0: version "2.2.1" resolved "https://registry.yarnpkg.com/search-insights/-/search-insights-2.2.1.tgz#9c93344fbae5fbf2f88c1a81b46b4b5d888c11f7"