Skip to content

Commit

Permalink
feat: improve tweet embedding using react-tweet
Browse files Browse the repository at this point in the history
  • Loading branch information
transitive-bullshit committed Nov 10, 2024
1 parent 172bd84 commit e2017fd
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 87 deletions.
17 changes: 14 additions & 3 deletions components/NotionPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ import { type PageBlock } from 'notion-types'
import { formatDate, getBlockTitle, getPageProperty } from 'notion-utils'
import * as React from 'react'
import BodyClassName from 'react-body-classname'
import { type NotionComponents, NotionRenderer } from 'react-notion-x'
import TweetEmbed from 'react-tweet-embed'
import {
type NotionComponents,
NotionRenderer,
useNotionContext
} from 'react-notion-x'
import { EmbeddedTweet, TweetNotFound, TweetSkeleton } from 'react-tweet'
import { useSearchParam } from 'react-use'

import type * as types from '@/lib/types'
Expand Down Expand Up @@ -97,7 +101,14 @@ const Modal = dynamic(
)

function Tweet({ id }: { id: string }) {
return <TweetEmbed tweetId={id} />
const { recordMap } = useNotionContext()
const tweet = (recordMap as types.ExtendedTweetRecordMap)?.tweets?.[id]

return (
<React.Suspense fallback={<TweetSkeleton />}>
{tweet ? <EmbeddedTweet tweet={tweet} /> : <TweetNotFound />}
</React.Suspense>
)
}

const propertyLastEditedTimeValue = (
Expand Down
62 changes: 62 additions & 0 deletions lib/get-tweets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { type ExtendedRecordMap } from 'notion-types'
import { getPageTweetIds } from 'notion-utils'
import pMap from 'p-map'
import pMemoize from 'p-memoize'
import { getTweet as getTweetData } from 'react-tweet/api'

import type { ExtendedTweetRecordMap } from './types'
import { db } from './db'

export async function getTweetsMap(
recordMap: ExtendedRecordMap
): Promise<void> {
const tweetIds = getPageTweetIds(recordMap)

const tweetsMap = Object.fromEntries(
await pMap(
tweetIds,
async (tweetId: string) => {
return [tweetId, await getTweet(tweetId)]
},
{
concurrency: 8
}
)
)

;(recordMap as ExtendedTweetRecordMap).tweets = tweetsMap
}

async function getTweetImpl(tweetId: string): Promise<any> {
if (!tweetId) return null

const cacheKey = `tweet:${tweetId}`

try {
try {
const cachedTweet = await db.get(cacheKey)
if (cachedTweet) {
return cachedTweet
}
} catch (err) {
// ignore redis errors
console.warn(`redis error get "${cacheKey}"`, err.message)
}

const tweetData = await getTweetData(tweetId)

try {
await db.set(cacheKey, tweetData)
} catch (err) {
// ignore redis errors
console.warn(`redis error set "${cacheKey}"`, err.message)
}

return tweetData
} catch (err: any) {
console.warn('failed to get tweet', tweetId, err.message)
return null
}
}

export const getTweet = pMemoize(getTweetImpl)
3 changes: 3 additions & 0 deletions lib/notion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
navigationLinks,
navigationStyle
} from './config'
import { getTweetsMap } from './get-tweets'
import { notion } from './notion-api'
import { getPreviewImageMap } from './preview-images'

Expand Down Expand Up @@ -64,6 +65,8 @@ export async function getPage(pageId: string): Promise<ExtendedRecordMap> {
;(recordMap as any).preview_images = previewImageMap
}

await getTweetsMap(recordMap)

return recordMap
}

Expand Down
4 changes: 4 additions & 0 deletions lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ export interface PageProps {
error?: PageError
}

export interface ExtendedTweetRecordMap extends ExtendedRecordMap {
tweets: Record<string, any>
}

export interface Params extends ParsedUrlQuery {
pageId: string
}
Expand Down
46 changes: 10 additions & 36 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,12 @@ export default withBundleAnalyzer({
staticPageGenerationTimeout: 300,
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'www.notion.so',
pathname: '**'
},
{
protocol: 'https',
hostname: 'notion.so',
pathname: '**'
},
{
protocol: 'https',
hostname: 'images.unsplash.com',
pathname: '**'
},
{
protocol: 'https',
hostname: 'pbs.twimg.com',
pathname: '**'
},
{
protocol: 'https',
hostname: 'abs.twimg.com',
pathname: '**'
},
{
protocol: 'https',
hostname: 's3.us-west-2.amazonaws.com',
pathname: '**'
},
{
protocol: 'https',
hostname: 'transitivebullsh.it',
pathname: '**'
}
{ protocol: 'https', hostname: 'www.notion.so' },
{ protocol: 'https', hostname: 'notion.so' },
{ protocol: 'https', hostname: 'images.unsplash.com' },
{ protocol: 'https', hostname: 'abs.twimg.com' },
{ protocol: 'https', hostname: 'pbs.twimg.com' },
{ protocol: 'https', hostname: 's3.us-west-2.amazonaws.com' }
],
formats: ['image/avif', 'image/webp'],
dangerouslyAllowSVG: true,
Expand All @@ -62,5 +33,8 @@ export default withBundleAnalyzer({
'node_modules/react-dom'
)
return config
}
},

// See https://react-tweet.vercel.app/next#troubleshooting
transpilePackages: ['react-tweet']
})
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,18 @@
"ky": "^1.7.2",
"lqip-modern": "^2.2.1",
"next": "^15.0.3",
"notion-client": "^7.1.1",
"notion-types": "^7.1.1",
"notion-utils": "^7.1.1",
"notion-client": "^7.1.3",
"notion-types": "^7.1.3",
"notion-utils": "^7.1.3",
"p-map": "^7.0.2",
"p-memoize": "^7.1.1",
"posthog-js": "^1.181.0",
"prismjs": "^1.29.0",
"react": "^18.2.0",
"react-body-classname": "^1.3.1",
"react-dom": "^18.2.0",
"react-notion-x": "^7.2.1",
"react-tweet-embed": "^2.0.0",
"react-notion-x": "^7.2.3",
"react-tweet": "^3.2.1",
"react-use": "^17.4.2",
"rss": "^1.2.2"
},
Expand Down
Loading

0 comments on commit e2017fd

Please sign in to comment.