diff --git a/ui/src/artist/ArtistExternalLink.js b/ui/src/artist/ArtistExternalLink.js new file mode 100644 index 000000000..3d0d315cf --- /dev/null +++ b/ui/src/artist/ArtistExternalLink.js @@ -0,0 +1,50 @@ +import React from 'react' +import { useTranslate } from 'react-admin' +import { IconButton, Tooltip, Link, useMediaQuery } from '@material-ui/core' + +import { ImLastfm2 } from 'react-icons/im' +import MusicBrainz from '../icons/MusicBrainz' +import { intersperse } from '../utils' + +const ArtistExternalLinks = ({ artistInfo, record }) => { + const translate = useTranslate() + let links = [] + let linkButtons = [] + const lastFMlink = artistInfo?.biography?.match( + /]*?\s+)?href=(["'])(.*?)\1/ + ) + + if (lastFMlink) { + links.push(lastFMlink[2]) + } + if (artistInfo && artistInfo.musicBrainzId) { + links.push(`https://musicbrainz.org/artist/${artistInfo.musicBrainzId}`) + } + + const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('sm')) + + const addLink = (url, title, icon) => { + const translatedTitle = translate(title) + const link = ( + + + + {icon} + + + + ) + const id = linkButtons.length + linkButtons.push({link}) + } + + isDesktop && addLink(links[0], 'message.openIn.lastfm', ) + + isDesktop && + artistInfo?.musicBrainzId && + addLink(links[1], 'message.openIn.musicbrainz', ) + + return isDesktop &&
{intersperse(linkButtons, ' ')}
+} + +export default ArtistExternalLinks diff --git a/ui/src/artist/ArtistShow.js b/ui/src/artist/ArtistShow.js index 19c19161b..35c01089a 100644 --- a/ui/src/artist/ArtistShow.js +++ b/ui/src/artist/ArtistShow.js @@ -1,11 +1,6 @@ -import React, { useState, useEffect, useCallback } from 'react' -import { Typography, Collapse, Link } from '@material-ui/core' -import { makeStyles } from '@material-ui/core/styles' -import Card from '@material-ui/core/Card' -import CardContent from '@material-ui/core/CardContent' -import CardMedia from '@material-ui/core/CardMedia' +import React, { useState, createElement, useEffect } from 'react' +import { useMediaQuery } from '@material-ui/core' import { - useTranslate, useShowController, ShowContextProvider, useRecordContext, @@ -14,152 +9,22 @@ import { } from 'react-admin' import subsonic from '../subsonic' import AlbumGridView from '../album/AlbumGridView' +import MobileArtistDetails from './MobileArtistDetails' +import DesktopArtistDetails from './DesktopArtistDetails' -const useStyles = makeStyles( - (theme) => ({ - root: { - display: 'flex', - padding: '1em', - '& .MuiTypography-h5': { - wordBreak: 'break-word', - }, - [theme.breakpoints.down('xs')]: { - padding: 'unset', - background: ({ img }) => `url(${img})`, - }, - }, - bgContainer: { - display: 'flex', - width: '100%', - [theme.breakpoints.down('xs')]: { - height: '15rem', - width: '100vw', - padding: 'unset', - backdropFilter: 'blur(1px)', - backgroundPosition: '50% 30%', - background: `linear-gradient(to bottom, rgba(52 52 52 / 72%), rgba(21 21 21))`, - }, - }, - albumList: { - margin: '20px', - display: 'grid', - }, - details: { - display: 'flex', - flex: '1', - flexDirection: 'column', - }, - bioBlock: { - display: 'inline-block', - marginTop: '1em', - float: 'left', - wordBreak: 'break-word', - cursor: 'pointer', - }, - link: { - margin: '1px', - }, - mdetails: { - display: 'none', - [theme.breakpoints.down('xs')]: { - display: 'flex', - alignItems: 'center', - width: '7rem', - marginLeft: '0.5rem', - flex: '1', - }, - }, - mbio: { - display: 'none', - [theme.breakpoints.down('xs')]: { - display: 'flex', - marginLeft: '3%', - marginRight: '3%', - zIndex: '1', - '& p': { - whiteSpace: ({ expanded }) => (expanded ? 'unset' : 'nowrap'), - overflow: 'hidden', - width: '95vw', - textOverflow: 'ellipsis', - }, - }, - }, - content: { - flex: '1 0 auto', - }, - cover: { - width: 151, - boxShadow: '0px 0px 6px 0px #565656', - borderRadius: '5px', - [theme.breakpoints.up('sm')]: { - borderRadius: '7em', - }, - }, - martImage: { - marginLeft: '1em', - maxHeight: '10rem', - backgroundColor: 'inherit', - display: 'none', - [theme.breakpoints.down('xs')]: { - marginTop: '4rem', - maxHeight: '7rem', - width: '7rem', - display: 'flex', - }, - }, - artImage: { - maxHeight: '9.5rem', - backgroundColor: 'inherit', - display: 'flex', - [theme.breakpoints.down('xs')]: { - marginTop: '4rem', - maxHeight: '7rem', - width: '7rem', - }, - }, - artDetail: { - flex: '1', - padding: '3%', - display: 'flex', - minHeight: '10rem', - '& .MuiPaper-elevation1': { - boxShadow: 'none', - padding: '4px', - }, - [theme.breakpoints.down('xs')]: { - display: 'none', - }, - }, - artistSummary: { - marginBottom: '1em', - }, - }), - { name: 'NDArtistPage' } -) - -const ArtistDetails = () => { +const ArtistDetails = (props) => { + const record = useRecordContext(props) + const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('sm')) const [artistInfo, setArtistInfo] = useState() - const [expanded, setExpanded] = useState(false) - const record = useRecordContext() - const artistId = record?.id - const title = record.name - let completeBioLink = '' - const link = artistInfo?.biography?.match( - /]*?\s+)?href=(["'])(.*?)\1/ - ) - if (link) { - completeBioLink = link[2] - } - const biography = artistInfo?.biography?.replace(new RegExp('<.*>', 'g'), '') - const translate = useTranslate() - - const img = artistInfo?.largeImageUrl - const classes = useStyles({ img, expanded }) + const biography = + artistInfo?.biography?.replace(new RegExp('<.*>', 'g'), '') || + record.biography + const img = artistInfo?.largeImageUrl || record.largeImageUrl useEffect(() => { subsonic - .getArtistInfo(artistId) + .getArtistInfo(record.id) .then((resp) => resp.json['subsonic-response']) .then((data) => { if (data.status === 'ok') { @@ -169,106 +34,21 @@ const ArtistDetails = () => { .catch((e) => { console.error('error on artist page', e) }) - }, [artistId, record]) - - const handleExpandClick = useCallback(() => { - setExpanded(!expanded) - }, [expanded, setExpanded]) + }, [record]) + const component = isDesktop ? DesktopArtistDetails : MobileArtistDetails return ( <> -
-
- - {artistInfo && ( - - )} - -
- - {title} - -
- - - {artistInfo && ( - - )} - -
- - - {title} - - - - - {completeBioLink !== '' && ( - - {translate('message.lastfmLink')} - - )} - - - -
-
-
-
-
- - - {biography} - - {translate('message.lastfmLink')} - - - -
+ {createElement(component, { + img, + artistInfo, + record, + biography, + })} ) } -const ArtistAlbums = ({ ...props }) => { - const { ids } = props - const classes = useStyles() - const translate = useTranslate() - - return ( -
-
- {ids.length + - ' ' + - translate('resources.album.name', { smart_count: ids.length })} -
- -
- ) -} - const AlbumShowLayout = (props) => { const showContext = useShowContext(props) const record = useRecordContext() @@ -287,7 +67,7 @@ const AlbumShowLayout = (props) => { perPage={0} pagination={null} > - + )} diff --git a/ui/src/artist/DesktopArtistDetails.js b/ui/src/artist/DesktopArtistDetails.js new file mode 100644 index 000000000..b6291c9e0 --- /dev/null +++ b/ui/src/artist/DesktopArtistDetails.js @@ -0,0 +1,134 @@ +import React, { useState } from 'react' +import { Typography, Collapse } from '@material-ui/core' +import { makeStyles } from '@material-ui/core' +import Card from '@material-ui/core/Card' +import CardContent from '@material-ui/core/CardContent' +import CardMedia from '@material-ui/core/CardMedia' +import ArtistExternalLinks from './ArtistExternalLink' +import config from '../config' +import { LoveButton, RatingField } from '../common' + +const useStyles = makeStyles( + (theme) => ({ + root: { + display: 'flex', + padding: '1em', + }, + details: { + display: 'flex', + flex: '1', + flexDirection: 'column', + }, + biography: { + display: 'inline-block', + marginTop: '1em', + float: 'left', + wordBreak: 'break-word', + cursor: 'pointer', + }, + content: { + flex: '1 0 auto', + }, + cover: { + width: 151, + borderRadius: '6em', + }, + artistImage: { + maxHeight: '9.5rem', + backgroundColor: 'inherit', + display: 'flex', + boxShadow: 'none', + }, + artistDetail: { + flex: '1', + padding: '3%', + display: 'flex', + minHeight: '10rem', + }, + button: { + marginLeft: '0.9em', + }, + loveButton: { + top: theme.spacing(-0.2), + left: theme.spacing(0.5), + }, + rating: { + marginTop: '5px', + }, + artistName: { + wordBreak: 'break-word', + }, + }), + { name: 'NDDesktopArtistDetails' } +) + +const DesktopArtistDetails = ({ img, artistInfo, record, biography }) => { + const [expanded, setExpanded] = useState(false) + const classes = useStyles({ img, expanded }) + const title = record.name + + return ( +
+ + + {artistInfo && ( + + )} + +
+ + + {title} + {config.enableFavourites && ( + + )} + + {config.enableStarRating && ( +
+ +
+ )} + + setExpanded(!expanded)} + > + + + +
+ + + +
+
+
+ ) +} + +export default DesktopArtistDetails diff --git a/ui/src/artist/MobileArtistDetails.js b/ui/src/artist/MobileArtistDetails.js new file mode 100644 index 000000000..5826cf2da --- /dev/null +++ b/ui/src/artist/MobileArtistDetails.js @@ -0,0 +1,134 @@ +import React, { useState } from 'react' +import { Typography, Collapse } from '@material-ui/core' +import { makeStyles } from '@material-ui/core/styles' +import Card from '@material-ui/core/Card' +import CardMedia from '@material-ui/core/CardMedia' +import config from '../config' +import { LoveButton, RatingField } from '../common' + +const useStyles = makeStyles( + (theme) => ({ + root: { + display: 'flex', + background: ({ img }) => `url(${img})`, + }, + bgContainer: { + display: 'flex', + height: '15rem', + width: '100vw', + padding: 'unset', + backdropFilter: 'blur(1px)', + backgroundPosition: '50% 30%', + background: `linear-gradient(to bottom, rgba(52 52 52 / 72%), rgba(21 21 21))`, + }, + link: { + margin: '1px', + }, + details: { + display: 'flex', + alignItems: 'flex-start', + flexDirection: 'column', + justifyContent: 'center', + marginLeft: '0.5rem', + }, + biography: { + display: 'flex', + marginLeft: '3%', + marginRight: '3%', + marginTop: '-2em', + zIndex: '1', + '& p': { + whiteSpace: ({ expanded }) => (expanded ? 'unset' : 'nowrap'), + overflow: 'hidden', + width: '95vw', + textOverflow: 'ellipsis', + }, + }, + cover: { + width: 151, + boxShadow: '0px 0px 6px 0px #565656', + borderRadius: '5px', + }, + artistImage: { + marginLeft: '1em', + maxHeight: '7rem', + backgroundColor: 'inherit', + marginTop: '4rem', + width: '7rem', + minWidth: '7rem', + display: 'flex', + borderRadius: '5em', + }, + loveButton: { + top: theme.spacing(-0.2), + left: theme.spacing(0.5), + }, + rating: { + marginTop: '5px', + }, + artistName: { + wordBreak: 'break-word', + }, + }), + { name: 'NDMobileArtistDetails' } +) + +const MobileArtistDetails = ({ img, artistInfo, biography, record }) => { + const [expanded, setExpanded] = useState(false) + const classes = useStyles({ img, expanded }) + const title = record.name + + return ( + <> +
+
+ + {artistInfo && ( + + )} + +
+ + {title} + {config.enableFavourites && ( + + )} + + {config.enableStarRating && ( + + )} +
+
+
+
+ + setExpanded(!expanded)}> + + + +
+ + ) +} + +export default MobileArtistDetails diff --git a/ui/src/themes/dark.js b/ui/src/themes/dark.js index c293cd18a..69cdec053 100644 --- a/ui/src/themes/dark.js +++ b/ui/src/themes/dark.js @@ -32,14 +32,11 @@ export default { boxShadow: '3px 3px 5px #000000a3', }, }, - NDArtistPage: { + NDMobileArtistDetails: { bgContainer: { background: 'linear-gradient(to bottom, rgba(52 52 52 / 72%), rgb(48 48 48))!important', }, - more: { - boxShadow: '-10px 0px 18px 5px #303030!important', - }, }, }, player: { diff --git a/ui/src/themes/green.js b/ui/src/themes/green.js index c414833d8..e7709ad29 100644 --- a/ui/src/themes/green.js +++ b/ui/src/themes/green.js @@ -27,14 +27,11 @@ export default { color: '#eee', }, }, - NDArtistPage: { + NDMobileArtistDetails: { bgContainer: { background: 'linear-gradient(to bottom, rgba(52 52 52 / 72%), rgb(48 48 48))!important', }, - more: { - boxShadow: '-10px 0px 18px 5px #303030!important', - }, }, }, player: { diff --git a/ui/src/themes/ligera.js b/ui/src/themes/ligera.js index 6afc5bb5d..c339d8836 100644 --- a/ui/src/themes/ligera.js +++ b/ui/src/themes/ligera.js @@ -359,14 +359,11 @@ export default { marginTop: '-50px', }, }, - NDArtistPage: { + NDMobileArtistDetails: { bgContainer: { background: 'linear-gradient(to bottom, rgb(255 255 255 / 51%), rgb(240 242 245))!important', }, - more: { - boxShadow: '-10px 0px 18px 5px #f0f2f5!important', - }, }, RaLayout: { content: { diff --git a/ui/src/themes/light.js b/ui/src/themes/light.js index c29d51171..ee1737fd6 100644 --- a/ui/src/themes/light.js +++ b/ui/src/themes/light.js @@ -46,14 +46,11 @@ export default { color: '#0085ff', }, }, - NDArtistPage: { + NDMobileArtistDetails: { bgContainer: { background: 'linear-gradient(to bottom, rgb(255 255 255 / 51%), rgb(250 250 250))!important', }, - more: { - boxShadow: '-10px 0px 18px 5px #fafafa!important', - }, }, }, player: {