diff --git a/ui/src/album/AlbumDetails.js b/ui/src/album/AlbumDetails.js
index 0827c1a0d..166d2af64 100644
--- a/ui/src/album/AlbumDetails.js
+++ b/ui/src/album/AlbumDetails.js
@@ -1,15 +1,170 @@
-import React from 'react'
-import { Card, CardContent, CardMedia, Typography } from '@material-ui/core'
+import React, { useMemo } from 'react'
+import {
+ Card,
+ CardContent,
+ CardMedia,
+ Typography,
+ Collapse,
+ makeStyles,
+ IconButton,
+ Fab,
+ useMediaQuery,
+} from '@material-ui/core'
+import classnames from 'classnames'
import { useTranslate } from 'react-admin'
import Lightbox from 'react-image-lightbox'
import 'react-image-lightbox/style.css'
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore'
import subsonic from '../subsonic'
-import { DurationField, StarButton, SizeField } from '../common'
-import { ArtistLinkField, formatRange } from '../common'
+import {
+ DurationField,
+ StarButton,
+ SizeField,
+ ArtistLinkField,
+ formatRange,
+ MultiLineTextField,
+} from '../common'
-const AlbumDetails = ({ classes, record }) => {
+const useStyles = makeStyles((theme) => ({
+ container: {
+ [theme.breakpoints.down('xs')]: {
+ padding: '0.7em',
+ minWidth: '24em',
+ },
+ [theme.breakpoints.up('sm')]: {
+ padding: '1em',
+ minWidth: '32em',
+ },
+ },
+ starButton: {
+ bottom: theme.spacing(-1.5),
+ right: theme.spacing(-1.5),
+ },
+ albumCover: {
+ display: 'inline-flex',
+ justifyContent: 'flex-end',
+ alignItems: 'flex-end',
+ cursor: 'pointer',
+
+ [theme.breakpoints.down('xs')]: {
+ height: '8em',
+ width: '8em',
+ },
+ [theme.breakpoints.up('sm')]: {
+ height: '10em',
+ width: '10em',
+ },
+ [theme.breakpoints.up('lg')]: {
+ height: '15em',
+ width: '15em',
+ },
+ },
+
+ albumDetails: {
+ display: 'inline-block',
+ verticalAlign: 'top',
+ [theme.breakpoints.down('xs')]: {
+ width: '14em',
+ },
+ [theme.breakpoints.up('sm')]: {
+ width: '26em',
+ },
+ [theme.breakpoints.up('lg')]: {
+ width: '43em',
+ },
+ },
+ albumTitle: {
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ },
+ comment: {
+ whiteSpace: 'nowrap',
+ marginTop: '1em',
+ display: 'inline-block',
+ [theme.breakpoints.down('xs')]: {
+ width: '10em',
+ },
+ [theme.breakpoints.up('sm')]: {
+ width: '10em',
+ },
+ [theme.breakpoints.up('lg')]: {
+ width: '10em',
+ },
+ },
+ commentFirstLine: {
+ float: 'left',
+ marginRight: '5px',
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ },
+ expand: {
+ marginTop: '-5px',
+ transform: 'rotate(0deg)',
+ marginLeft: 'auto',
+ transition: theme.transitions.create('transform', {
+ duration: theme.transitions.duration.shortest,
+ }),
+ },
+ expandOpen: {
+ transform: 'rotate(180deg)',
+ },
+}))
+
+const AlbumComment = ({ classes, record, commentNumLines }) => {
+ const [expanded, setExpanded] = React.useState(false)
+
+ const handleExpandClick = React.useCallback(() => {
+ commentNumLines > 1 && setExpanded(!expanded)
+ }, [expanded, setExpanded, commentNumLines])
+
+ return (
+
+
+
+
+ {commentNumLines > 1 && (
+
+
+
+ )}
+
+
+
+
+ )
+}
+
+const AlbumDetails = ({ record }) => {
+ const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('lg'))
+ const classes = useStyles()
const [isLightboxOpen, setLightboxOpen] = React.useState(false)
const translate = useTranslate()
+
+ const commentNumLines = useMemo(
+ () => record.comment && record.comment.split('\n').length,
+ [record]
+ )
+
const genreYear = (record) => {
let genreDateLine = []
if (record.genre) {
@@ -38,14 +193,23 @@ const AlbumDetails = ({ classes, record }) => {
() => setLightboxOpen(false),
[]
)
-
return (
+ >
+
+
{record.name}
@@ -60,8 +224,23 @@ const AlbumDetails = ({ classes, record }) => {
{' · '} {' · '}
-
+ {isDesktop && record['comment'] && (
+
+ )}
+ {!isDesktop && record['comment'] && (
+
+ )}
{isLightboxOpen && (
{
- const classes = useStyles()
const { data: record, loading, error } = useGetOne('album', props.id)
if (loading) {
@@ -21,7 +19,7 @@ const AlbumShow = (props) => {
return (
<>
-
+
({
- container: {
- [theme.breakpoints.down('xs')]: {
- padding: '0.7em',
- minWidth: '24em',
- },
- [theme.breakpoints.up('sm')]: {
- padding: '1em',
- minWidth: '32em',
- },
- },
- albumCover: {
- display: 'inline-flex',
- justifyContent: 'center',
- alignItems: 'center',
- cursor: 'pointer',
-
- [theme.breakpoints.down('xs')]: {
- height: '8em',
- width: '8em',
- },
- [theme.breakpoints.up('sm')]: {
- height: '10em',
- width: '10em',
- },
- [theme.breakpoints.up('lg')]: {
- height: '15em',
- width: '15em',
- },
- '&:hover $playButton': {
- opacity: 1,
- },
- },
- albumDetails: {
- display: 'inline-block',
- verticalAlign: 'top',
- [theme.breakpoints.down('xs')]: {
- width: '14em',
- },
- [theme.breakpoints.up('sm')]: {
- width: '26em',
- },
- [theme.breakpoints.up('lg')]: {
- width: '43em',
- },
- },
- albumTitle: {
- whiteSpace: 'nowrap',
- overflow: 'hidden',
- textOverflow: 'ellipsis',
- },
-}))
diff --git a/ui/src/common/MultiLineTextField.js b/ui/src/common/MultiLineTextField.js
index 2f267925f..bc36326a3 100644
--- a/ui/src/common/MultiLineTextField.js
+++ b/ui/src/common/MultiLineTextField.js
@@ -4,10 +4,22 @@ import Typography from '@material-ui/core/Typography'
import sanitizeFieldRestProps from './sanitizeFieldRestProps'
import md5 from 'md5-hex'
-const MultiLineTextField = memo(
- ({ className, emptyText, source, record = {}, stripTags, ...rest }) => {
+export const MultiLineTextField = memo(
+ ({
+ className,
+ emptyText,
+ source,
+ record,
+ firstLine,
+ maxLines,
+ addLabel,
+ ...rest
+ }) => {
const value = get(record, source)
- const lines = value ? value.split('\n') : []
+ let lines = value ? value.split('\n') : []
+ if (maxLines || firstLine) {
+ lines = lines.slice(firstLine, maxLines)
+ }
return (
{lines.length === 0 && emptyText
? emptyText
- : lines.map((line, idx) => (
-
- ))}
+ : lines.map((line, idx) =>
+ line === '' ? (
+
+ ) : (
+
+ )
+ )}
)
}
)
MultiLineTextField.defaultProps = {
+ record: {},
addLabel: true,
+ firstLine: 0,
}
-
-export default MultiLineTextField
diff --git a/ui/src/common/SongDetails.js b/ui/src/common/SongDetails.js
index 714c7e0b7..b26ceed22 100644
--- a/ui/src/common/SongDetails.js
+++ b/ui/src/common/SongDetails.js
@@ -8,7 +8,7 @@ import TableRow from '@material-ui/core/TableRow'
import { BooleanField, DateField, TextField, useTranslate } from 'react-admin'
import inflection from 'inflection'
import { BitrateField, SizeField } from './index'
-import MultiLineTextField from './MultiLineTextField'
+import { MultiLineTextField } from './MultiLineTextField'
export const SongDetails = (props) => {
const translate = useTranslate()
diff --git a/ui/src/common/StarButton.js b/ui/src/common/StarButton.js
index 9958747fa..133f35d15 100644
--- a/ui/src/common/StarButton.js
+++ b/ui/src/common/StarButton.js
@@ -15,7 +15,16 @@ const useStyles = makeStyles({
},
})
-export const StarButton = ({ resource, record, color, visible, size }) => {
+export const StarButton = ({
+ resource,
+ record,
+ color,
+ visible,
+ size,
+ component: Button,
+ addLabel,
+ ...rest
+}) => {
const [loading, setLoading] = useState(false)
const classes = useStyles({ color, visible, starred: record.starred })
const notify = useNotify()
@@ -56,18 +65,19 @@ export const StarButton = ({ resource, record, color, visible, size }) => {
}
return (
-
{record.starred ? (
) : (
)}
-
+
)
}
@@ -77,6 +87,7 @@ StarButton.propTypes = {
visible: PropTypes.bool,
color: PropTypes.string,
size: PropTypes.string,
+ component: PropTypes.object,
}
StarButton.defaultProps = {
@@ -85,4 +96,5 @@ StarButton.defaultProps = {
visible: true,
size: 'small',
color: 'inherit',
+ component: IconButton,
}
diff --git a/ui/src/common/index.js b/ui/src/common/index.js
index 856f5d64c..2cae83232 100644
--- a/ui/src/common/index.js
+++ b/ui/src/common/index.js
@@ -6,6 +6,7 @@ export * from './ContextMenus'
export * from './DocLink'
export * from './DurationField'
export * from './List'
+export * from './MultiLineTextField'
export * from './Pagination'
export * from './PlayButton'
export * from './QuickFilter'