Files
Compass/web/components/widgets/linkify.tsx
Martin Braquet ba9b3cfb06 Add pretty formatting (#29)
* Test

* Add pretty formatting

* Fix Tests

* Fix Tests

* Fix Tests

* Fix

* Add pretty formatting fix

* Fix

* Test

* Fix tests

* Clean typeckech

* Add prettier check

* Fix api tsconfig

* Fix api tsconfig

* Fix tsconfig

* Fix

* Fix

* Prettier
2026-02-20 17:32:27 +01:00

65 lines
1.8 KiB
TypeScript

import clsx from 'clsx'
import Link from 'next/link'
import {Fragment} from 'react'
import {linkClass} from './site-link'
// Return a JSX span, linkifying @username, and https://...
export function Linkify(props: {text: string; className?: string}) {
const {text, className} = props
// Handle undefined/null text
if (!text) {
return <span className={clsx(className, 'break-anywhere')}></span>
}
// Replace "m1234" with "ϻ1234"
// const mRegex = /(\W|^)m(\d+)/g
// text = text.replace(mRegex, (_, pre, num) => `${pre}ϻ${num}`)
// Find instances of @username, #hashtag, and https://...
const regex =
/(?:^|\s)(?:@[a-z0-9_]+|https?:\/\/[-A-Za-z0-9+&@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&@#/%=~_|])/gi
const matches = text.match(regex) || []
const links = matches.map((match) => {
// Matches are in the form: " @username" or "https://example.com"
const whitespace = match.match(/^\s/)
const symbol = match.trim().substring(0, 1)
const tag = match.trim().substring(1)
const href =
{
'@': `/${tag}`,
}[symbol] ?? match.trim()
return (
<>
{whitespace}
<Link
target={getLinkTarget(href)}
className={clsx(linkClass, 'text-primary-700')}
href={href}
>
{symbol}
{tag}
</Link>
</>
)
})
return (
<span className={clsx(className, 'break-anywhere')}>
{text.split(regex).map((part, i) => (
<Fragment key={i}>
{part}
{links[i]}
</Fragment>
))}
</span>
)
}
export const getLinkTarget = (href: string, newTab?: boolean) => {
// TODO: make this more robust against domain changes?
if (href.startsWith('http') && !href.startsWith(`https://compassmeet`)) return '_blank'
return newTab ? '_blank' : '_self'
}