2022-08-30 09:41:47 +00:00
|
|
|
import clsx from 'clsx'
|
2021-12-19 09:08:12 +00:00
|
|
|
import { Fragment } from 'react'
|
2021-12-31 19:17:32 +00:00
|
|
|
import { SiteLink } from './site-link'
|
2021-12-19 09:08:12 +00:00
|
|
|
|
2022-10-04 01:28:21 +00:00
|
|
|
// Return a JSX span, linkifying @username, and https://...
|
2022-08-30 09:41:47 +00:00
|
|
|
export function Linkify(props: {
|
|
|
|
text: string
|
|
|
|
className?: string
|
|
|
|
gray?: boolean
|
|
|
|
}) {
|
|
|
|
const { text, className, gray } = props
|
2022-05-17 12:13:12 +00:00
|
|
|
// Replace "m1234" with "ϻ1234"
|
2022-05-20 02:28:38 +00:00
|
|
|
// const mRegex = /(\W|^)m(\d+)/g
|
|
|
|
// text = text.replace(mRegex, (_, pre, num) => `${pre}ϻ${num}`)
|
2022-05-17 12:13:12 +00:00
|
|
|
|
|
|
|
// Find instances of @username, #hashtag, and https://...
|
2022-02-16 18:32:44 +00:00
|
|
|
const regex =
|
2022-10-04 01:28:21 +00:00
|
|
|
/(?:^|\s)(?:@[a-z0-9_]+|https?:\/\/[-A-Za-z0-9+&@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&@#/%=~_|])/gi
|
2021-12-19 09:08:12 +00:00
|
|
|
const matches = text.match(regex) || []
|
|
|
|
const links = matches.map((match) => {
|
|
|
|
// Matches are in the form: " @username" or "https://example.com"
|
2022-05-12 01:42:33 +00:00
|
|
|
const whitespace = match.match(/^\s/)
|
|
|
|
const symbol = match.trim().substring(0, 1)
|
|
|
|
const tag = match.trim().substring(1)
|
2021-12-19 09:08:12 +00:00
|
|
|
const href =
|
|
|
|
{
|
|
|
|
'@': `/${tag}`,
|
2022-05-12 01:42:33 +00:00
|
|
|
}[symbol] ?? match.trim()
|
2021-12-19 09:08:12 +00:00
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
2022-05-12 01:42:33 +00:00
|
|
|
{whitespace}
|
2022-01-04 22:09:03 +00:00
|
|
|
<SiteLink
|
|
|
|
className={gray ? 'text-gray-500' : 'text-indigo-700'}
|
|
|
|
href={href}
|
|
|
|
>
|
2021-12-31 19:17:32 +00:00
|
|
|
{symbol}
|
|
|
|
{tag}
|
|
|
|
</SiteLink>
|
2021-12-19 09:08:12 +00:00
|
|
|
</>
|
|
|
|
)
|
|
|
|
})
|
|
|
|
return (
|
2022-08-30 09:41:47 +00:00
|
|
|
<span className={clsx(className, 'break-anywhere')}>
|
2021-12-19 09:08:12 +00:00
|
|
|
{text.split(regex).map((part, i) => (
|
|
|
|
<Fragment key={i}>
|
|
|
|
{part}
|
|
|
|
{links[i]}
|
|
|
|
</Fragment>
|
|
|
|
))}
|
|
|
|
</span>
|
|
|
|
)
|
|
|
|
}
|