mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-16 04:00:38 +03:00
Simple approach, may be extended/enhanced in the future.
This commit is contained in:
parent
fa5dc5af10
commit
c530ccf138
@ -33,6 +33,7 @@ import {
|
||||
import config from '../config'
|
||||
import { intersperse } from '../utils'
|
||||
import AlbumExternalLinks from './AlbumExternalLinks'
|
||||
import AnchorMe from '../common/AnchorMe'
|
||||
|
||||
const useStyles = makeStyles(
|
||||
(theme) => ({
|
||||
@ -116,7 +117,7 @@ const AlbumComment = ({ record }) => {
|
||||
const formatted = useMemo(() => {
|
||||
return lines.map((line, idx) => (
|
||||
<span key={record.id + '-comment-' + idx}>
|
||||
<span dangerouslySetInnerHTML={{ __html: line }} />
|
||||
<AnchorMe text={line} />
|
||||
<br />
|
||||
</span>
|
||||
))
|
||||
|
73
ui/src/common/AnchorMe.js
Normal file
73
ui/src/common/AnchorMe.js
Normal file
@ -0,0 +1,73 @@
|
||||
import React, { useCallback, useMemo } from 'react'
|
||||
import { Link } from '@material-ui/core'
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const useStyles = makeStyles(
|
||||
(theme) => ({
|
||||
link: {
|
||||
textDecoration: 'none',
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
}),
|
||||
{ name: 'RaLink' }
|
||||
)
|
||||
|
||||
const AnchorMe = ({ text, ...rest }) => {
|
||||
const classes = useStyles()
|
||||
const linkify = useCallback((text) => {
|
||||
const urlRegex =
|
||||
/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#/%?=~_|!:,.;]*[-A-Z0-9+&@#/%=~_|])/gi
|
||||
return [...text.matchAll(urlRegex)]
|
||||
}, [])
|
||||
|
||||
const parse = useCallback(() => {
|
||||
const matches = linkify(text)
|
||||
if (matches.length === 0) return text
|
||||
|
||||
const elements = []
|
||||
let lastIndex = 0
|
||||
matches.forEach((match, index) => {
|
||||
// Push text located before matched string
|
||||
if (match.index > lastIndex) {
|
||||
elements.push(text.substring(lastIndex, match.index))
|
||||
}
|
||||
|
||||
const href = match[0]
|
||||
// Push Link component
|
||||
elements.push(
|
||||
<Link
|
||||
{...rest}
|
||||
target="_blank"
|
||||
className={classes.link}
|
||||
rel="noopener noreferrer"
|
||||
key={index}
|
||||
href={href}
|
||||
>
|
||||
{href}
|
||||
</Link>
|
||||
)
|
||||
|
||||
lastIndex = match.index + href.length
|
||||
})
|
||||
|
||||
// Push remaining text
|
||||
if (text.length > lastIndex) {
|
||||
elements.push(
|
||||
<span dangerouslySetInnerHTML={{ __html: text.substring(lastIndex) }} />
|
||||
)
|
||||
}
|
||||
|
||||
return elements.length === 1 ? elements[0] : elements
|
||||
}, [linkify, text, rest, classes.link])
|
||||
|
||||
const parsedText = useMemo(() => parse(), [parse])
|
||||
|
||||
return <>{parsedText}</>
|
||||
}
|
||||
|
||||
AnchorMe.propTypes = {
|
||||
text: PropTypes.string,
|
||||
}
|
||||
|
||||
export default React.memo(AnchorMe)
|
Loading…
x
Reference in New Issue
Block a user