diff --git a/__tests__/src/components/OpenSeadragonViewer.test.js b/__tests__/src/components/OpenSeadragonViewer.test.js index 8113ca8e9bfbda73b9526d85e757ff14710bd62f..de9d67affb259637b40c27ae79ad0759fe08b588 100644 --- a/__tests__/src/components/OpenSeadragonViewer.test.js +++ b/__tests__/src/components/OpenSeadragonViewer.test.js @@ -4,7 +4,6 @@ import OpenSeadragon from 'openseadragon'; import { OpenSeadragonViewer } from '../../../src/components/OpenSeadragonViewer'; import OpenSeadragonCanvasOverlay from '../../../src/lib/OpenSeadragonCanvasOverlay'; import Annotation from '../../../src/lib/Annotation'; -import ZoomControls from '../../../src/containers/ZoomControls'; jest.mock('openseadragon'); jest.mock('../../../src/lib/OpenSeadragonCanvasOverlay'); @@ -26,6 +25,7 @@ describe('OpenSeadragonViewer', () => { config={{}} updateViewport={updateViewport} t={k => k} + classes={{ controls: 'controls' }} > <div className="foo" /> </OpenSeadragonViewer>, @@ -37,8 +37,8 @@ describe('OpenSeadragonViewer', () => { it('renders child components', () => { expect(wrapper.find('.foo').length).toBe(1); }); - it('renders ZoomControls', () => { - expect(wrapper.find(ZoomControls).length).toBe(1); + it('renders viewer controls', () => { + expect(wrapper.find('.controls').length).toBe(1); }); describe('tileSourcesMatch', () => { it('when they do not match', () => { diff --git a/__tests__/src/components/WindowViewer.test.js b/__tests__/src/components/WindowViewer.test.js index ab419d68a6bbcbdc15faf2477f290b12901f8abf..f3b21fc8939a39e238cce283f33beac1157fce03 100644 --- a/__tests__/src/components/WindowViewer.test.js +++ b/__tests__/src/components/WindowViewer.test.js @@ -1,9 +1,11 @@ import React from 'react'; import { shallow } from 'enzyme'; import manifesto from 'manifesto.js'; +import Typography from '@material-ui/core/Typography'; import { WindowViewer } from '../../../src/components/WindowViewer'; import OSDViewer from '../../../src/containers/OpenSeadragonViewer'; import ViewerNavigation from '../../../src/containers/ViewerNavigation'; +import ZoomControls from '../../../src/containers/ZoomControls'; import fixture from '../../fixtures/version-2/019.json'; import emptyCanvasFixture from '../../fixtures/version-2/emptyCanvas.json'; import otherContentFixture from '../../fixtures/version-2/299843.json'; @@ -22,6 +24,7 @@ let mockWindow = { function createWrapper(props) { return shallow( <WindowViewer + canvasLabel="label" infoResponses={{}} fetchInfoResponse={() => {}} fetchAnnotation={() => {}} @@ -41,7 +44,11 @@ describe('WindowViewer', () => { expect(wrapper.matchesElement( <> <OSDViewer> - <ViewerNavigation /> + <div> + <ZoomControls /> + <ViewerNavigation /> + <Typography>label</Typography> + </div> </OSDViewer> </>, )).toBe(true); diff --git a/__tests__/src/components/ZoomControls.test.js b/__tests__/src/components/ZoomControls.test.js index f76ce271def4ebff8b63e391ea890699f617882a..31f5fb083c92096bc7892b4aea878f6eab232edd 100644 --- a/__tests__/src/components/ZoomControls.test.js +++ b/__tests__/src/components/ZoomControls.test.js @@ -12,7 +12,7 @@ describe('ZoomControls', () => { updateViewport = jest.fn(); wrapper = shallow( <ZoomControls - classes={{}} + classes={{ zoom_controls: 'zoom_controls' }} windowId="xyz" viewer={viewer} showZoomControls={showZoomControls} @@ -23,7 +23,7 @@ describe('ZoomControls', () => { describe('with showZoomControls=false', () => { it('renders nothing unless asked', () => { - expect(wrapper.find('WithStyles(List)').length).toBe(0); + expect(wrapper.find('div.zoom_controls').length).toBe(0); }); }); @@ -33,7 +33,7 @@ describe('ZoomControls', () => { updateViewport = jest.fn(); wrapper = shallow( <ZoomControls - classes={{}} + classes={{ zoom_controls: 'zoom_controls' }} windowId="xyz" viewer={viewer} showZoomControls @@ -43,7 +43,7 @@ describe('ZoomControls', () => { }); it('renders a couple buttons', () => { - expect(wrapper.find('WithStyles(List)').length).toBe(1); + expect(wrapper.find('div.zoom_controls').length).toBe(1); }); it('has a zoom-in button', () => { diff --git a/src/components/OpenSeadragonViewer.js b/src/components/OpenSeadragonViewer.js index 50708b5ac3df3f776f1e861e68fa4e0498b30ca0..62b592661514883efc90c71a8d058edc21d6f98a 100644 --- a/src/components/OpenSeadragonViewer.js +++ b/src/components/OpenSeadragonViewer.js @@ -1,8 +1,8 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; +import Paper from '@material-ui/core/Paper'; import OpenSeadragon from 'openseadragon'; import ns from '../config/css-ns'; -import ZoomControls from '../containers/ZoomControls'; import OpenSeadragonCanvasOverlay from '../lib/OpenSeadragonCanvasOverlay'; /** @@ -259,7 +259,7 @@ export class OpenSeadragonViewer extends Component { */ render() { const { - windowId, children, label, t, + windowId, children, classes, label, t, } = this.props; return ( @@ -270,8 +270,9 @@ export class OpenSeadragonViewer extends Component { ref={this.ref} aria-label={t('item', { label })} > - <ZoomControls windowId={windowId} /> - { children } + <Paper square className={classes.controls} elevation={0}> + { children } + </Paper> </section> </> ); @@ -284,6 +285,7 @@ OpenSeadragonViewer.defaultProps = { tileSources: [], viewer: null, label: null, + classes: {}, }; OpenSeadragonViewer.propTypes = { @@ -295,4 +297,5 @@ OpenSeadragonViewer.propTypes = { windowId: PropTypes.string.isRequired, label: PropTypes.string, t: PropTypes.func.isRequired, + classes: PropTypes.object, // eslint-disable-line react/forbid-prop-types }; diff --git a/src/components/WindowViewer.js b/src/components/WindowViewer.js index 78b5354560789a897ae934acd703cdb380deb9db..5fa7b8176a4576d8dabd903e5b5ead7d1f3cc8ea 100644 --- a/src/components/WindowViewer.js +++ b/src/components/WindowViewer.js @@ -1,9 +1,12 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; +import Typography from '@material-ui/core/Typography'; import OSDViewer from '../containers/OpenSeadragonViewer'; +import ZoomControls from '../containers/ZoomControls'; import ViewerNavigation from '../containers/ViewerNavigation'; import ManifestoCanvas from '../lib/ManifestoCanvas'; import CanvasGroupings from '../lib/CanvasGroupings'; +import ns from '../config/css-ns'; /** * Represents a WindowViewer in the mirador workspace. Responsible for mounting @@ -121,7 +124,7 @@ export class WindowViewer extends Component { * Renders things */ render() { - const { window } = this.props; + const { canvasLabel, window } = this.props; return ( <> <OSDViewer @@ -129,7 +132,15 @@ export class WindowViewer extends Component { currentCanvases={this.currentCanvases()} windowId={window.id} > - <ViewerNavigation window={window} canvases={this.canvases} /> + <div className={ns('canvas-nav')}> + <ZoomControls windowId={window.id} /> + <ViewerNavigation window={window} canvases={this.canvases} /> + { + canvasLabel && ( + <Typography variant="caption" className={ns('canvas-label')}>{canvasLabel}</Typography> + ) + } + </div> </OSDViewer> </> ); @@ -142,4 +153,9 @@ WindowViewer.propTypes = { fetchInfoResponse: PropTypes.func.isRequired, manifest: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types window: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + canvasLabel: PropTypes.string, +}; + +WindowViewer.defaultProps = { + canvasLabel: undefined, }; diff --git a/src/components/ZoomControls.js b/src/components/ZoomControls.js index bd29e210cf87c5592c8e7c3409ab20c1021b98c0..718a9ec9fd9cd2a7eed4e084dee4908b7cee7848 100644 --- a/src/components/ZoomControls.js +++ b/src/components/ZoomControls.js @@ -1,7 +1,5 @@ import React, { Component } from 'react'; import IconButton from '@material-ui/core/IconButton'; -import List from '@material-ui/core/List'; -import ListItem from '@material-ui/core/ListItem'; import AddCircleIcon from '@material-ui/icons/AddCircleOutlineSharp'; import RemoveCircleIcon from '@material-ui/icons/RemoveCircleOutlineSharp'; import PropTypes from 'prop-types'; @@ -73,23 +71,17 @@ export class ZoomControls extends Component { ); } return ( - <List className={classes.zoom_controls}> - <ListItem> - <IconButton aria-label={t('zoomIn')} onClick={this.handleZoomInClick}> - <AddCircleIcon /> - </IconButton> - </ListItem> - <ListItem> - <IconButton aria-label={t('zoomOut')} onClick={this.handleZoomOutClick}> - <RemoveCircleIcon /> - </IconButton> - </ListItem> - <ListItem> - <IconButton aria-label={t('zoomReset')} onClick={this.handleZoomResetClick}> - <RestoreZoomIcon /> - </IconButton> - </ListItem> - </List> + <div className={classes.zoom_controls}> + <IconButton aria-label={t('zoomIn')} onClick={this.handleZoomInClick}> + <AddCircleIcon /> + </IconButton> + <IconButton aria-label={t('zoomOut')} onClick={this.handleZoomOutClick}> + <RemoveCircleIcon /> + </IconButton> + <IconButton aria-label={t('zoomReset')} onClick={this.handleZoomResetClick}> + <RestoreZoomIcon /> + </IconButton> + </div> ); } } diff --git a/src/config/settings.js b/src/config/settings.js index ed89c75786110fe207e62b4102363e87899f361d..6f49d0842a7d06f1aa3557af07d98febf7065c1e 100644 --- a/src/config/settings.js +++ b/src/config/settings.js @@ -40,7 +40,7 @@ export default { }, caption: { fontSize: "0.772rem", - letterSpacing: "0.33em", + letterSpacing: "0.033em", lineHeight: "1.6rem", }, body1Next: { diff --git a/src/containers/OpenSeadragonViewer.js b/src/containers/OpenSeadragonViewer.js index 7099f30dc6460276366607398747635cf8499a66..4e12d11f0ade0b2430f2f84083aa57b43a8914a0 100644 --- a/src/containers/OpenSeadragonViewer.js +++ b/src/containers/OpenSeadragonViewer.js @@ -1,6 +1,8 @@ import { compose } from 'redux'; import { connect } from 'react-redux'; import { withTranslation } from 'react-i18next'; +import { withStyles } from '@material-ui/core'; +import { fade } from '@material-ui/core/styles/colorManipulator'; import miradorWithPlugins from '../lib/miradorWithPlugins'; import { OpenSeadragonViewer } from '../components/OpenSeadragonViewer'; import * as actions from '../state/actions'; @@ -38,7 +40,23 @@ const mapDispatchToProps = { updateViewport: actions.updateViewport, }; +/** + * + * @param theme + * @returns {{windowSideBarHeading: *}} + */ +const styles = theme => ({ + controls: { + width: '100%', + position: 'absolute', + bottom: 0, + zIndex: 50, + backgroundColor: fade(theme.palette.background.paper, 0.5), + }, +}); + const enhance = compose( + withStyles(styles), withTranslation(), connect(mapStateToProps, mapDispatchToProps), miradorWithPlugins, diff --git a/src/containers/WindowViewer.js b/src/containers/WindowViewer.js index 85cf2a36df5a8f8d2f5894b8fbcde973f58433b3..5c8b47026bcd2843fa948740a7d168c76e662a0a 100644 --- a/src/containers/WindowViewer.js +++ b/src/containers/WindowViewer.js @@ -2,6 +2,10 @@ import { compose } from 'redux'; import { connect } from 'react-redux'; import * as actions from '../state/actions'; import miradorWithPlugins from '../lib/miradorWithPlugins'; +import { + getCanvasLabel, + getSelectedCanvas, +} from '../state/selectors'; import { WindowViewer } from '../components/WindowViewer'; /** @@ -9,8 +13,12 @@ import { WindowViewer } from '../components/WindowViewer'; * @memberof WindowViewer * @private */ -const mapStateToProps = state => ( +const mapStateToProps = (state, { window }) => ( { + canvasLabel: getCanvasLabel( + getSelectedCanvas(state, window.id), + state.windows[window.id].canvasIndex, + ), infoResponses: state.infoResponses, } ); diff --git a/src/containers/ZoomControls.js b/src/containers/ZoomControls.js index 2f468c4354379592b700fe2a77d50963ff69668f..d333253896b3341dc60d5dd9275aec966d4f3411 100644 --- a/src/containers/ZoomControls.js +++ b/src/containers/ZoomControls.js @@ -32,10 +32,8 @@ const mapDispatchToProps = { updateViewport: actions.updateViewport }; */ const styles = theme => ({ zoom_controls: { - position: 'absolute', - right: 0, - zIndex: 33, - top: 0, + display: 'flex', + flexDirection: 'row', }, ListItem: { paddingTop: 0, diff --git a/src/styles/index.scss b/src/styles/index.scss index 0022f7500612ed8428ebc76b7a240419f41ce0b1..8ff74cc5528efa470072c704a48bf781aa9cf16e 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -99,13 +99,25 @@ position: relative; } - &-osd-navigation { - bottom: 10px; - left: 0; + div + &-osd-navigation:before { + content: '|'; + color: $gray; position: absolute; - right: 0; + font-size: 24px; + top: 12px; + } + + &-canvas-nav { + display: flex; + justify-content: center; + flex-wrap: wrap; text-align: center; - z-index: 33; + } + + &-canvas-label { + width: 100%; + text-overflow: ellipsis; + padding-bottom: 3px; } &-thumb-navigation {