Internal links are not target=_blank by default (#1037)
* feat: internal links are not target=_blank by default * feat: use <Link> --------- Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
This commit is contained in:
parent
4633e8eb5e
commit
5be6df0266
|
@ -19,7 +19,7 @@ import { rehypeInlineCodeProperty } from '@/lib/md'
|
||||||
import { Button } from 'react-bootstrap'
|
import { Button } from 'react-bootstrap'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { UNKNOWN_LINK_REL } from '@/lib/constants'
|
import { SSR, UNKNOWN_LINK_REL } from '@/lib/constants'
|
||||||
import isEqual from 'lodash/isEqual'
|
import isEqual from 'lodash/isEqual'
|
||||||
|
|
||||||
export function SearchText ({ text }) {
|
export function SearchText ({ text }) {
|
||||||
|
@ -178,6 +178,8 @@ export default memo(function Text ({ rel, imgproxyUrls, children, tab, itemId, o
|
||||||
// If [text](url) was parsed as <a> and text is not empty and not a link itself,
|
// If [text](url) was parsed as <a> and text is not empty and not a link itself,
|
||||||
// we don't render it as an image since it was probably a conscious choice to include text.
|
// we don't render it as an image since it was probably a conscious choice to include text.
|
||||||
const text = children[0]
|
const text = children[0]
|
||||||
|
const url = !href.startsWith('/') && new URL(href)
|
||||||
|
const internalURL = SSR ? 'https://stacker.news' : window.location.origin
|
||||||
if (!!text && !/^https?:\/\//.test(text)) {
|
if (!!text && !/^https?:\/\//.test(text)) {
|
||||||
if (props['data-footnote-ref'] || typeof props['data-footnote-backref'] !== 'undefined') {
|
if (props['data-footnote-ref'] || typeof props['data-footnote-backref'] !== 'undefined') {
|
||||||
return (
|
return (
|
||||||
|
@ -189,6 +191,16 @@ export default memo(function Text ({ rel, imgproxyUrls, children, tab, itemId, o
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (href.startsWith('/') || url.origin === internalURL) {
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
id={props.id}
|
||||||
|
href={href}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
<a id={props.id} target='_blank' rel={rel ?? UNKNOWN_LINK_REL} href={href}>{text}</a>
|
<a id={props.id} target='_blank' rel={rel ?? UNKNOWN_LINK_REL} href={href}>{text}</a>
|
||||||
|
@ -198,7 +210,7 @@ export default memo(function Text ({ rel, imgproxyUrls, children, tab, itemId, o
|
||||||
try {
|
try {
|
||||||
const linkText = parseInternalLinks(href)
|
const linkText = parseInternalLinks(href)
|
||||||
if (linkText) {
|
if (linkText) {
|
||||||
return <a target='_blank' href={href} rel='noreferrer'>{linkText}</a>
|
return <Link href={href}>{linkText}</Link>
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// ignore errors like invalid URLs
|
// ignore errors like invalid URLs
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { SSR } from './constants'
|
||||||
|
|
||||||
export function ensureProtocol (value) {
|
export function ensureProtocol (value) {
|
||||||
if (!value) return value
|
if (!value) return value
|
||||||
value = value.trim()
|
value = value.trim()
|
||||||
|
@ -28,11 +30,12 @@ export function removeTracking (value) {
|
||||||
*/
|
*/
|
||||||
export function parseInternalLinks (href) {
|
export function parseInternalLinks (href) {
|
||||||
const url = new URL(href)
|
const url = new URL(href)
|
||||||
|
const internalURL = SSR ? 'https://stacker.news' : window.location.origin
|
||||||
const { pathname, searchParams } = url
|
const { pathname, searchParams } = url
|
||||||
// ignore empty parts which exist due to pathname starting with '/'
|
// ignore empty parts which exist due to pathname starting with '/'
|
||||||
const emptyPart = part => !!part
|
const emptyPart = part => !!part
|
||||||
const parts = pathname.split('/').filter(emptyPart)
|
const parts = pathname.split('/').filter(emptyPart)
|
||||||
if (parts[0] === 'items' && /^[0-9]+$/.test(parts[1])) {
|
if (parts[0] === 'items' && /^[0-9]+$/.test(parts[1]) && url.origin === internalURL) {
|
||||||
const itemId = parts[1]
|
const itemId = parts[1]
|
||||||
// check for valid item page due to referral links like /items/123456/r/ekzyis
|
// check for valid item page due to referral links like /items/123456/r/ekzyis
|
||||||
const itemPages = ['edit', 'ots', 'related']
|
const itemPages = ['edit', 'ots', 'related']
|
||||||
|
|
Loading…
Reference in New Issue