UNPKG

mirador

Version:

An open-source, web-based 'multi-up' viewer that supports zoom-pan-rotate functionality, ability to display/compare simple images, and images with annotations.

245 lines (223 loc) 7.84 kB
import { useContext, useState } from 'react'; import PropTypes from 'prop-types'; import { Button, Chip, Dialog, DialogActions, DialogTitle, Link, MenuList, MenuItem, Typography, } from '@mui/material'; import ArrowBackIcon from '@mui/icons-material/ArrowBackSharp'; import Skeleton from '@mui/material/Skeleton'; import { styled } from '@mui/material/styles'; import { useTranslation } from 'react-i18next'; import asArray from '../lib/asArray'; import LabelValueMetadata from '../containers/LabelValueMetadata'; import CollapsibleSection from '../containers/CollapsibleSection'; import ScrollIndicatedDialogContent from '../containers/ScrollIndicatedDialogContent'; import ManifestInfo from '../containers/ManifestInfo'; import WorkspaceContext from '../contexts/WorkspaceContext'; import { IIIFResourceLabel } from './IIIFResourceLabel'; const StyledScrollIndicatedDialogContent = styled(ScrollIndicatedDialogContent)(() => ({ padding: (theme) => theme.spacing(1), })); const StyledCollectionMetadata = styled('div')(() => ({ '& .MuiPaper-root': { background: 'transparent', }, padding: (theme) => theme.spacing(2), })); const StyledCollectionFilter = styled('div')(() => ({ padding: (theme) => theme.spacing(2), paddingTop: 0, })); /** */ const Placeholder = ({ onClose, container }) => ( <Dialog variant="contained" onClose={onClose} open container={container} > <DialogTitle id="select-collection"> <Skeleton variant="text" /> </DialogTitle> <ScrollIndicatedDialogContent> <Skeleton variant="text" /> <Skeleton variant="text" /> </ScrollIndicatedDialogContent> </Dialog> ); Placeholder.propTypes = { container: PropTypes.instanceOf(Element).isRequired, onClose: PropTypes.func.isRequired, }; /** * a dialog providing the possibility to select the collection */ export function CollectionDialog({ addWindow, collection = null, dialogCollectionPath = [], error = null, hideCollectionDialog, isMultipart = false, manifest, manifestId, ready = false, setWorkspaceAddVisibility, showCollectionDialog, updateWindow, windowId = null, }) { const container = useContext(WorkspaceContext); const { t } = useTranslation(); const [filter, setFilter] = useState(null); /** */ const hideDialog = () => { hideCollectionDialog(windowId); }; /** */ const selectCollection = (c) => { showCollectionDialog(c.id, [...dialogCollectionPath, manifestId], windowId); }; /** */ const goToPreviousCollection = () => { showCollectionDialog( dialogCollectionPath[dialogCollectionPath.length - 1], dialogCollectionPath.slice(0, -1), windowId, ); }; /** */ const selectManifest = (m) => { if (windowId) { updateWindow(windowId, { canvasId: null, collectionPath: [...dialogCollectionPath, manifestId], manifestId: m.id, }); } else { addWindow({ collectionPath: [...dialogCollectionPath, manifestId], manifestId: m.id }); } hideDialog(); setWorkspaceAddVisibility(false); }; /** */ const dialogContainer = (container?.current || document.body).querySelector(`#${windowId}`); if (error) return null; if (!dialogContainer) { return null; } if (!ready) return <Placeholder container={dialogContainer} onClose={hideDialog} />; const rights = manifest && (asArray(manifest.getProperty('rights') || manifest.getProperty('license'))); const requiredStatement = manifest && asArray(manifest.getRequiredStatement()).filter(l => l && l.getValue()).map(labelValuePair => ({ label: null, values: labelValuePair.getValues(), })); const collections = manifest.getCollections(); const currentFilter = filter || (collections.length > 0 ? 'collections' : 'manifests'); return ( <Dialog variant="contained" onClose={hideDialog} container={dialogContainer} open > <DialogTitle id="select-collection"> <Typography component="div" variant="overline"> { t(isMultipart ? 'multipartCollection' : 'collection') } </Typography> <Typography component="div" variant="h3"> <IIIFResourceLabel resource={manifest} /> </Typography> </DialogTitle> <StyledScrollIndicatedDialogContent> { collection && ( <Button startIcon={<ArrowBackIcon />} onClick={() => goToPreviousCollection()} > <IIIFResourceLabel resource={collection} /> </Button> )} <StyledCollectionMetadata> <ManifestInfo manifestId={manifest.id} /> <CollapsibleSection id="select-collection-rights" label={t('attributionTitle')} > { requiredStatement && ( <LabelValueMetadata labelValuePairs={requiredStatement} defaultLabel={t('attribution')} /> )} { rights && rights.length > 0 && ( <> <Typography variant="subtitle2" component="dt">{t('rights')}</Typography> { rights.map(v => ( <Typography variant="body1" component="dd" key={v}> <Link target="_blank" rel="noopener noreferrer" href={v}> {v} </Link> </Typography> )) } </> ) } </CollapsibleSection> </StyledCollectionMetadata> <StyledCollectionFilter> {manifest.getTotalCollections() > 0 && ( <Chip clickable color={currentFilter === 'collections' ? 'primary' : 'default'} onClick={() => setFilter('collections')} label={t('totalCollections', { count: manifest.getTotalCollections() })} /> )} {manifest.getTotalManifests() > 0 && ( <Chip clickable color={currentFilter === 'manifests' ? 'primary' : 'default'} onClick={() => setFilter('manifests')} label={t('totalManifests', { count: manifest.getTotalManifests() })} /> )} </StyledCollectionFilter> { currentFilter === 'collections' && ( <MenuList> { collections.map(c => ( <MenuItem key={c.id} onClick={() => { selectCollection(c); }} variant="multiline" > <IIIFResourceLabel resource={c} /> </MenuItem> )) } </MenuList> )} { currentFilter === 'manifests' && ( <MenuList> { manifest.getManifests().map(m => ( <MenuItem key={m.id} onClick={() => { selectManifest(m); }} variant="multiline" > <IIIFResourceLabel resource={m} /> </MenuItem> )) } </MenuList> )} </StyledScrollIndicatedDialogContent> <DialogActions> <Button onClick={hideDialog}> {t('close')} </Button> </DialogActions> </Dialog> ); } CollectionDialog.propTypes = { addWindow: PropTypes.func.isRequired, collection: PropTypes.object, // eslint-disable-line react/forbid-prop-types dialogCollectionPath: PropTypes.arrayOf(PropTypes.string), error: PropTypes.string, hideCollectionDialog: PropTypes.func.isRequired, isMultipart: PropTypes.bool, manifest: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types manifestId: PropTypes.string.isRequired, ready: PropTypes.bool, setWorkspaceAddVisibility: PropTypes.func.isRequired, showCollectionDialog: PropTypes.func.isRequired, updateWindow: PropTypes.func.isRequired, windowId: PropTypes.string, };