Skip to content

Commit

Permalink
Make react-tweet more customizable (#86)
Browse files Browse the repository at this point in the history
* Update dependencies for react-tweet

* Expose getEntities and getEntityText

* Strict props in tweet-link

* Expose useMp4Video

* Removed unrequired use of useMemo

* Export the useTweet hook

* Moved components to twitter theme

* moved useMounted to hooks

* Updated imports in twitter theme

* Export twitter theme components

* Component updates

* Export hooks and utils

* Improve loading state for SWR tweet

* Fixed import

* Added custom-tweet-dub

* Replaced video hook with util

* Updated TweetProps type

* Removed unused imports

* Removed unused code

* Make dub tweet a server component

* Updated lock

* Updated readme

* Updated getEntities utility

* Added a more powerful util

* Use the getTweetData util in SWR

* Updated custom tweet

* Renamed TweetData with EnrichedTweet

* Added nextra docs theme

* Added initial docs to the nextra site

* Added docs to the API types

* Added API reference docs

* Added Twitter theme docs

* Added docs for the Next.js usage

* Added docs for CRA usage

* Added docs for Vite usage

* Updated docs site

* Updated pnpm-lock.yaml

* Removed unnecessary pnpm-lock.yaml

* Updated SEO

* Added custom theme docs

* Updated twitter theme docs

* Updated framework docs and readme

* Updated main readme and added contributing docs

* documentation updates and fixes

* Added demo link

* Added fetchOptions support

* Added changeset

* Updated intro
  • Loading branch information
lfades authored Jun 30, 2023
1 parent d3cf679 commit 7a92646
Show file tree
Hide file tree
Showing 116 changed files with 6,999 additions and 3,684 deletions.
5 changes: 5 additions & 0 deletions .changeset/brave-pumpkins-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'react-tweet': major
---

Theme support
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ node_modules
# Next.js
.next
out
next-env.d.ts

# Production
build
Expand Down
2 changes: 1 addition & 1 deletion apps/create-react-app/.env
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
BROWSER = none
PORT = 3001
PORT = 3002
34 changes: 2 additions & 32 deletions apps/create-react-app/readme.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,3 @@
# react-tweet for create-react-app
# react-tweet for Create React App

## Installation

Follow the [installation docs in the main README](/readme.md#installation).

## Usage

In any component, import [`Tweet`](/readme.md#tweet) from `react-tweet` and use it like so:

```tsx
import { Tweet } from 'react-tweet'

export default function App() {
return <Tweet id="1628832338187636740" />
}
```

To see the code in action go to: [/apps/create-react-app/src/app.js](/apps/create-react-app/src/app.js).

You can learn more about `react-tweet` in the [API Reference](/readme.md#api-reference).

## Running the test app

Clone this repository and run the following commands:

```bash
pnpm install && pnpm dev --filter=create-react-app...
```

The app will be up and running at http://localhost:3001.

`react-tweet` is imported from the root directory, so you can make changes to the package and see the changes reflected in the app immediately.
Follow the instructions in the [official docs](https://react-tweet.vercel.app/create-react-app) to learn more about `react-tweet` for Create React App.
4 changes: 4 additions & 0 deletions apps/custom-tweet-dub/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"typescript.tsdk": "../../node_modules/.pnpm/[email protected]/node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
11 changes: 11 additions & 0 deletions apps/custom-tweet-dub/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { FC, ReactNode } from 'react'
import '../base.css'

const RootLayout: FC<{ children: ReactNode }> = ({ children }) => (
<html>
<head></head>
<body>{children}</body>
</html>
)

export default RootLayout
27 changes: 27 additions & 0 deletions apps/custom-tweet-dub/app/light/[tweet]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { getTweet } from 'react-tweet/api'
import { Tweet } from '@/components/tweet'

type Props = {
params: { tweet: string }
}

export const revalidate = 1800

export async function generateMetadata({ params }: Props) {
const tweet = await getTweet(params.tweet).catch(() => undefined)

if (!tweet) return { title: 'Next Tweet' }

const username = ` - @${tweet.user.screen_name}`
const maxLength = 68 - username.length
const text =
tweet.text.length > maxLength
? `${tweet.text.slice(0, maxLength)}…`
: tweet.text

return { title: `${text}${username}` }
}

const Page = ({ params }: Props) => <Tweet id={params.tweet} />

export default Page
17 changes: 17 additions & 0 deletions apps/custom-tweet-dub/app/light/layout.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.root {
font-family: var(--tweet-font-family);
color: var(--tweet-font-color);
background: var(--tweet-bg-color);
height: 100vh;
overflow: auto;
padding: 2rem 1rem;
}
.main {
display: flex;
justify-content: center;
}
.footer {
font-size: 0.875rem;
text-align: center;
margin-top: -0.5rem;
}
14 changes: 14 additions & 0 deletions apps/custom-tweet-dub/app/light/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { ReactNode } from 'react'
import s from './layout.module.css'

const Layout = ({ children }: { children: ReactNode }) => (
<div data-theme="light">
<div className={s.root}>
<main className={s.main}>
<div className="max-w-[550px] min-w-[250px]">{children}</div>
</main>
</div>
</div>
)

export default Layout
5 changes: 5 additions & 0 deletions apps/custom-tweet-dub/app/light/mdx/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Post from './post.mdx'

export default function Page() {
return <Post />
}
3 changes: 3 additions & 0 deletions apps/custom-tweet-dub/app/light/mdx/post.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Tweet } from '@/components/tweet'

<Tweet id={'1629307668568633344'} />
29 changes: 29 additions & 0 deletions apps/custom-tweet-dub/base.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

*,
*::before,
*::after {
box-sizing: inherit;
}
html {
height: 100%;
box-sizing: border-box;
}
body {
position: relative;
min-height: 100%;
margin: 0;
line-height: 1.65;
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
font-weight: 400;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
scroll-behavior: smooth;
}
html,
body {
background: #fff;
}
25 changes: 25 additions & 0 deletions apps/custom-tweet-dub/components/tweet/blur-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use client'

import Image, { ImageProps } from 'next/image'
import { useEffect, useState } from 'react'

export default function BlurImage(props: ImageProps) {
const [loading, setLoading] = useState(true)
const [src, setSrc] = useState(props.src)
useEffect(() => setSrc(props.src), [props.src]) // update the `src` value when the `prop.src` value changes

return (
<Image
{...props}
src={src}
alt={props.alt}
className={`${props.className} ${loading ? 'blur-[2px]' : 'blur-0'}`}
onLoadingComplete={async () => {
setLoading(false)
}}
onError={() => {
setSrc(`https://avatar.vercel.sh/${props.alt}`) // if the image fails to load, use the default avatar
}}
/>
)
}
91 changes: 91 additions & 0 deletions apps/custom-tweet-dub/components/tweet/dub-tweet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { type EnrichedTweet } from 'react-tweet'
import { nFormatter } from './utils'
import { Heart, Message } from './icons'
import { Tilt } from './tilt'
import { TweetHeader } from './tweet-header'
import { TweetText } from './tweet-text'
import { TweetMedia } from './tweet-media'

export const DubTweet = ({
tweet,
noTilt,
}: {
tweet: EnrichedTweet
noTilt?: boolean
}) => {
const TweetBody = (
<div className="break-inside-avoid rounded-lg border border-gray-300 bg-white/20 bg-clip-padding p-6 pb-4 backdrop-blur-lg backdrop-filter">
{/* User info, verified badge, twitter logo, text, etc. */}
<div>
<TweetHeader tweet={tweet} />
{tweet.in_reply_to_status_id_str && tweet.in_reply_to_screen_name && (
<div className="mt-5 text-base text-gray-500">
Replying to{' '}
<a
className="text-[#1da1f2] no-underline"
href={tweet.in_reply_to_url}
target="_blank"
>
@{tweet.in_reply_to_screen_name}
</a>
</div>
)}
<TweetText tweet={tweet} />
</div>
{/* Images, Preview images, videos, polls, etc. */}
<div className="-mb-2 mt-3">
{tweet.mediaDetails?.length ? (
<div
className={
tweet.mediaDetails.length === 1
? ''
: 'inline-grid grid-cols-2 gap-x-2 gap-y-2'
}
>
{tweet.mediaDetails?.map((media) => (
<a key={media.media_url_https} href={tweet.url} target="_blank">
<TweetMedia tweet={tweet} media={media} />
</a>
))}
</div>
) : null}
</div>
<div className="flex justify-center space-x-8 text-sm text-gray-500 mt-5">
<a
className="group flex items-center space-x-3 hover:text-red-600"
href={tweet.like_url}
target="_blank"
rel="noreferrer"
>
<Heart className="h-4 w-4 group-hover:fill-red-600" />
<p>{nFormatter(tweet.favorite_count)}</p>
</a>
<a
className="group flex items-center space-x-3 hover:text-blue-600"
href={tweet.reply_url}
target="_blank"
rel="noreferrer"
>
<Message className="h-4 w-4 group-hover:fill-blue-600" />
<p>{nFormatter(tweet.conversation_count)}</p>
</a>
</div>
</div>
)

return noTilt ? (
TweetBody
) : (
<Tilt
glareEnable={true}
glareMaxOpacity={0.3}
glareColor="#ffffff"
glarePosition="all"
glareBorderRadius="8px"
tiltMaxAngleX={10}
tiltMaxAngleY={10}
>
{TweetBody}
</Tilt>
)
}
16 changes: 16 additions & 0 deletions apps/custom-tweet-dub/components/tweet/icons/heart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const Heart = ({ className }: { className: string }) => (
<svg
fill="none"
shapeRendering="geometricPrecision"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
viewBox="0 0 24 24"
width="14"
height="14"
className={className}
>
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" />
</svg>
)
4 changes: 4 additions & 0 deletions apps/custom-tweet-dub/components/tweet/icons/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './heart'
export * from './message'
export * from './repeat'
export * from './twitter'
16 changes: 16 additions & 0 deletions apps/custom-tweet-dub/components/tweet/icons/message.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const Message = ({ className }: { className: string }) => (
<svg
fill="none"
shapeRendering="geometricPrecision"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
viewBox="0 0 24 24"
width="14"
height="14"
className={className}
>
<path d="M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z" />{' '}
</svg>
)
19 changes: 19 additions & 0 deletions apps/custom-tweet-dub/components/tweet/icons/repeat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export const Repeat = ({ className }: { className: string }) => (
<svg
fill="none"
shapeRendering="geometricPrecision"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
viewBox="0 0 24 24"
width="14"
height="14"
className={className}
>
<path d="M17 1l4 4-4 4" />
<path d="M3 11V9a4 4 0 014-4h14" />
<path d="M7 23l-4-4 4-4" />
<path d="M21 13v2a4 4 0 01-4 4H3" />{' '}
</svg>
)
12 changes: 12 additions & 0 deletions apps/custom-tweet-dub/components/tweet/icons/twitter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const Twitter = ({ className }: { className?: string }) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 248 204"
className={className}
>
<path
fill="currentColor"
d="M221.95 51.29c.15 2.17.15 4.34.15 6.53 0 66.73-50.8 143.69-143.69 143.69v-.04c-27.44.04-54.31-7.82-77.41-22.64 3.99.48 8 .72 12.02.73 22.74.02 44.83-7.61 62.72-21.66-21.61-.41-40.56-14.5-47.18-35.07 7.57 1.46 15.37 1.16 22.8-.87-23.56-4.76-40.51-25.46-40.51-49.5v-.64c7.02 3.91 14.88 6.08 22.92 6.32C11.58 63.31 4.74 33.79 18.14 10.71c25.64 31.55 63.47 50.73 104.08 52.76-4.07-17.54 1.49-35.92 14.61-48.25 20.34-19.12 52.33-18.14 71.45 2.19 11.31-2.23 22.15-6.38 32.07-12.26-3.77 11.69-11.66 21.62-22.2 27.93 10.01-1.18 19.79-3.86 29-7.95-6.78 10.16-15.32 19.01-25.2 26.16z"
/>
</svg>
)
1 change: 1 addition & 0 deletions apps/custom-tweet-dub/components/tweet/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './tweet'
12 changes: 12 additions & 0 deletions apps/custom-tweet-dub/components/tweet/tilt.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* client component wrapper around react-parallax-tilt because it uses class components
* that can't be used in React Server Components.
*/

'use client'

import TiltComponent, { type ReactParallaxTiltProps } from 'react-parallax-tilt'

export const Tilt = ({ children, ...props }: ReactParallaxTiltProps) => (
<TiltComponent {...props}>{children}</TiltComponent>
)
Loading

3 comments on commit 7a92646

@vercel
Copy link

@vercel vercel bot commented on 7a92646 Jun 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

react-tweet-site – ./apps/site

react-tweet-site-git-main-vercel-labs.vercel.app
react-tweet-next-app-4bp8.vercel.app
react-tweet-site-vercel-labs.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 7a92646 Jun 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

react-tweet-custom-tweet-dub – ./apps/custom-tweet-dub

react-tweet-dub.vercel.app
react-tweet-custom-tweet-dub-git-main-vercel-labs.vercel.app
react-tweet-custom-tweet-dub-vercel-labs.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 7a92646 Jul 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.