Skip to content

Commit

Permalink
Merge pull request #3824 from ProjectMirador/mui5-iiif-thumbnail
Browse files Browse the repository at this point in the history
Push IIIFThumbnail styling into slots + variants
  • Loading branch information
jcoyne authored Nov 29, 2023
2 parents 7a59d5c + 92db8c3 commit ef80ab0
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 72 deletions.
2 changes: 1 addition & 1 deletion src/components/CanvasLayers.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export class CanvasLayers extends Component {
maxHeight={height}
maxWidth={width}
resource={resource}
imageStyle
border
/>
<Typography
sx={{
Expand Down
103 changes: 32 additions & 71 deletions src/components/IIIFThumbnail.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,26 @@ import {
} from 'react';
import PropTypes from 'prop-types';
import { styled } from '@mui/material/styles';
import Typography from '@mui/material/Typography';
import { useInView } from 'react-intersection-observer';
import getThumbnail from '../lib/ThumbnailFactory';

const StyledRoot = styled('div')({
});
const Root = styled('div', { name: 'IIIFThumbnail', slot: 'root' })({});

const StyledLabel = styled('div')({
});
const Label = styled('span', { name: 'IIIFThumbnail', slot: 'label' })(({ theme }) => ({
...theme.typography.caption,
}));

const Image = styled('img', { name: 'IIIFThumbnail', slot: 'image' })(() => ({
height: 'auto',
width: 'auto',
}));

/**
* A lazy-loaded image that uses IntersectionObserver to determine when to
* try to load the image (or even calculate that the image url/height/width are)
*/
const LazyLoadedImage = ({
placeholder, style = {}, thumbnail, resource, maxHeight, maxWidth, thumbnailsConfig, ...props
border, placeholder, style = {}, thumbnail, resource, maxHeight, maxWidth, thumbnailsConfig, ...props
}) => {
const { ref, inView } = useInView();
const [loaded, setLoaded] = useState(false);
Expand All @@ -44,9 +48,14 @@ const LazyLoadedImage = ({
}, [resource, thumbnail, maxWidth, maxHeight, thumbnailsConfig]);

const imageStyles = useMemo(() => {
const styleProps = { height: 'auto', width: 'auto' };
const styleProps = {
height: undefined,
maxHeight: undefined,
maxWidth: undefined,
width: undefined,
};

if (!image) return { ...style, height: maxHeight || 'auto', width: maxWidth || 'auto' };
if (!image) return { ...style, height: maxHeight, width: maxWidth };

const { height: thumbHeight, width: thumbWidth } = image;
if (thumbHeight && thumbWidth) {
Expand Down Expand Up @@ -93,7 +102,8 @@ const LazyLoadedImage = ({
const { url: src = placeholder } = (loaded && (thumbnail || image)) || {};

return (
<img
<Image
ownerState={{ border }}
ref={ref}
alt=""
role="presentation"
Expand All @@ -104,11 +114,8 @@ const LazyLoadedImage = ({
);
};

const StyledLazyLoadedImage = styled(LazyLoadedImage)(() => ({

}));

LazyLoadedImage.propTypes = {
border: PropTypes.bool,
maxHeight: PropTypes.number.isRequired,
maxWidth: PropTypes.number.isRequired,
placeholder: PropTypes.string.isRequired,
Expand All @@ -123,6 +130,7 @@ LazyLoadedImage.propTypes = {
};

LazyLoadedImage.defaultProps = {
border: false,
style: {},
thumbnail: null,
thumbnailsConfig: {},
Expand Down Expand Up @@ -152,93 +160,46 @@ export class IIIFThumbnail extends Component {
*/
render() {
const {
border,
children,
imagePlaceholder,
labelled,
imageStyle,
maxHeight,
maxWidth,
resource,
style,
thumbnail,
thumbnailsConfig,
variant,
} = this.props;

return (
<StyledRoot
sx={{
...(variant === 'inside' && {
display: 'inline-block',
height: 'inherit',
position: 'relative',
}),
}}
>
<StyledLazyLoadedImage
<Root ownerState={this.props}>
<LazyLoadedImage
placeholder={imagePlaceholder}
thumbnail={thumbnail}
resource={resource}
maxHeight={maxHeight}
maxWidth={maxWidth}
thumbnailsConfig={thumbnailsConfig}
style={style}
sx={{
...(imageStyle && {
borderBottom: '1px solid',
borderBottomColor: 'divider',
}),
}}
border={border}
/>

{ labelled && (
<StyledLabel
sx={{
overflow: 'hidden',
textOverflow: 'ellipsis',
...(variant === 'inside' && {
background: 'linear-gradient(to top, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.3) 70%, rgba(0,0,0,0) 100%)',
bottom: '5px',
boxSizing: 'border-box',
left: '0px',
padding: '4px',
position: 'absolute',
width: '100%',
}),
}}
>
<Typography
variant="caption"
sx={{
lineHeight: '1.5em',
wordBreak: 'break-word',
...(variant === 'inside' && {
color: '#ffffff',
WebkitLineClamp: 1,
whiteSpace: 'nowrap',
}),
...(variant === 'outside' && {
display: '-webkit-box',
maxHeight: '3em',
MozBoxOrient: 'vertical',
WebkitLineClamp: 2,
}),
}}
>
{this.label()}
</Typography>
</StyledLabel>
<Label ownerState={this.props}>
{this.label()}
</Label>
)}
{children}
</StyledRoot>
</Root>
);
}
}

IIIFThumbnail.propTypes = {
border: PropTypes.bool,
children: PropTypes.node,
imagePlaceholder: PropTypes.string,
imageStyle: PropTypes.bool,
label: PropTypes.string,
labelled: PropTypes.bool,
maxHeight: PropTypes.number,
Expand All @@ -251,14 +212,14 @@ IIIFThumbnail.propTypes = {
width: PropTypes.number,
}),
thumbnailsConfig: PropTypes.object, // eslint-disable-line react/forbid-prop-types
variant: PropTypes.oneOf(['inside', 'outside']),
variant: PropTypes.oneOf(['inside', 'outside']), // eslint-disable-line react/no-unused-prop-types
};

IIIFThumbnail.defaultProps = {
border: false,
children: null,
// Transparent "gray"
imagePlaceholder: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mMMDQmtBwADgwF/Op8FmAAAAABJRU5ErkJggg==',
imageStyle: false,
label: undefined,
labelled: false,
maxHeight: null,
Expand Down
42 changes: 42 additions & 0 deletions src/config/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,48 @@ export default {
},
},
},
IIIFThumbnail: {
styleOverrides: {
root: ({ ownerState }) => ({
...(ownerState?.variant === 'inside' && {
display: 'inline-block',
height: 'inherit',
position: 'relative',
}),
}),
label: ({ ownerState }) => ({
overflow: 'hidden',
textOverflow: 'ellipsis',
lineHeight: '1.5em',
wordBreak: 'break-word',
...(ownerState?.variant === 'inside' && {
color: '#ffffff',
WebkitLineClamp: 1,
whiteSpace: 'nowrap',
}),
...(ownerState?.variant === 'outside' && {
display: '-webkit-box',
maxHeight: '3em',
MozBoxOrient: 'vertical',
WebkitLineClamp: 2,
}),
...(ownerState?.variant === 'inside' && {
background: 'linear-gradient(to top, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.3) 70%, rgba(0,0,0,0) 100%)',
bottom: '5px',
boxSizing: 'border-box',
left: '0px',
padding: '4px',
position: 'absolute',
width: '100%',
}),
}),
image: ({ ownerState }) => ({
...(ownerState?.border && {
border: '1px solid rgba(0, 0, 0, 0.125)',
}),
})
}
},
MuiAccordion: {
variants: [
{
Expand Down

0 comments on commit ef80ab0

Please sign in to comment.