diff --git a/__tests__/src/components/ViewerInfo.test.js b/__tests__/src/components/ViewerInfo.test.js new file mode 100644 index 0000000000000000000000000000000000000000..357d0392db8f679aa9c9124a690328b07c6cedaf --- /dev/null +++ b/__tests__/src/components/ViewerInfo.test.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { Typography } from '@material-ui/core'; +import { ViewerInfo } from '../../../src/components/ViewerInfo'; + +/** create wrapper */ +function createWrapper(props) { + return shallow( + <ViewerInfo + canvasCount={8} + canvasIndex={2} + canvasLabel="testLabel" + t={k => k} + {...props} + />, + ); +} + +describe('ViewerNavigation', () => { + let wrapper; + + it('renders the component', () => { + wrapper = createWrapper(); + expect(wrapper.find(Typography).length).toBe(1); + expect(wrapper.find(Typography).at(0) + .matchesElement(<Typography>3 of 8 • testLabel</Typography>)).toBe(true); + }); +}); diff --git a/__tests__/src/components/WindowCanvasNavigationControls.test.js b/__tests__/src/components/WindowCanvasNavigationControls.test.js index 64394bd2e840e8e8692104d69ef077fddfb332dd..8f2953f0cbea64f0e1452d25ecfbc769a433cef1 100644 --- a/__tests__/src/components/WindowCanvasNavigationControls.test.js +++ b/__tests__/src/components/WindowCanvasNavigationControls.test.js @@ -1,7 +1,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import Typography from '@material-ui/core/Typography'; import { WindowCanvasNavigationControls } from '../../../src/components/WindowCanvasNavigationControls'; +import ViewerInfo from '../../../src/containers/ViewerInfo'; import ViewerNavigation from '../../../src/containers/ViewerNavigation'; import ZoomControls from '../../../src/containers/ZoomControls'; @@ -26,7 +26,7 @@ describe('WindowCanvasNavigationControls', () => { <div> <ZoomControls /> <ViewerNavigation /> - <Typography>label</Typography> + <ViewerInfo /> </div>, )).toBe(true); }); diff --git a/locales/de/translation.json b/locales/de/translation.json index 8b052391c1235884d281cb1da797c0ab57cb66b9..e2307126dbb038c6ea3fe672299eb2fb73a48a9b 100644 --- a/locales/de/translation.json +++ b/locales/de/translation.json @@ -39,6 +39,7 @@ "mosaic": "Mosaik", "nextCanvas": "Nächstes Objekt", "numItems": "{{number}} Elemente", + "of": "von", "off": "Keine", "openAnnotationCompanionWindow": "Annotationsfenster öffnen", "openCanvasNavigationCompanionWindow": "Hilfsfenster für die Leinwandnavigation schließen", diff --git a/locales/en/translation.json b/locales/en/translation.json index b5abc9e32a8727044a903968f7d0913146f11279..a2ecf454f34703065b7ac7929526a6c53a32ee38 100644 --- a/locales/en/translation.json +++ b/locales/en/translation.json @@ -45,6 +45,7 @@ "moveCompanionWindowToRight": "Move to right", "nextCanvas": "Next item", "numItems": "{{number}} items", + "of": "of", "off": "Off", "openAnnotationCompanionWindow": "Open annotation companion window", "openCanvasNavigationCompanionWindow": "Open canvas navigation companion window", @@ -69,7 +70,6 @@ "tryAgain": "Try again", "untitled": "[Untitled]", "view": "View", - "window": "Window: {{label}}", "windowMenu": "Window menu", "workspace": "Workspace", "workspaceFullScreen": "Full Screen", diff --git a/src/components/ViewerInfo.js b/src/components/ViewerInfo.js new file mode 100644 index 0000000000000000000000000000000000000000..94c1b361f57312dd049e91d40268b16dd892e5d8 --- /dev/null +++ b/src/components/ViewerInfo.js @@ -0,0 +1,40 @@ +import React, { Component } from 'react'; +import Typography from '@material-ui/core/Typography'; +import PropTypes from 'prop-types'; +import ns from '../config/css-ns'; + +/** + * + */ +export class ViewerInfo extends Component { + /** */ + render() { + const { + canvasCount, + canvasIndex, + canvasLabel, + t, + } = this.props; + + return ( + <div className={ns('osd-info')}> + <Typography variant="caption" className={ns('canvas-label')}> + {`${canvasIndex + 1} ${t('of')} ${canvasCount}`} + {canvasLabel && ` ${String.fromCharCode(8226)} ${canvasLabel}`} + </Typography> + </div> + ); + } +} + +ViewerInfo.defaultProps = { + canvasLabel: undefined, + t: () => {}, +}; + +ViewerInfo.propTypes = { + canvasCount: PropTypes.number.isRequired, + canvasIndex: PropTypes.number.isRequired, + canvasLabel: PropTypes.string, + t: PropTypes.func, +}; diff --git a/src/components/WindowCanvasNavigationControls.js b/src/components/WindowCanvasNavigationControls.js index 6044dd780dd798f0f7062f6e0a66d9b6d092f776..991ca758d5f7f2e183a59ec629adb559efe81abe 100644 --- a/src/components/WindowCanvasNavigationControls.js +++ b/src/components/WindowCanvasNavigationControls.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import Typography from '@material-ui/core/Typography'; import ZoomControls from '../containers/ZoomControls'; +import ViewerInfo from '../containers/ViewerInfo'; import ViewerNavigation from '../containers/ViewerNavigation'; import ns from '../config/css-ns'; @@ -12,7 +12,7 @@ export class WindowCanvasNavigationControls extends Component { /** */ render() { const { - canvases, canvasLabel, visible, window, + canvases, visible, window, } = this.props; if (!visible) return (<></>); @@ -21,11 +21,7 @@ export class WindowCanvasNavigationControls extends Component { <div className={ns('canvas-nav')}> <ZoomControls windowId={window.id} /> <ViewerNavigation window={window} canvases={canvases} /> - { - canvasLabel && ( - <Typography variant="caption" className={ns('canvas-label')}>{canvasLabel}</Typography> - ) - } + <ViewerInfo windowId={window.id} /> </div> ); } @@ -35,11 +31,9 @@ export class WindowCanvasNavigationControls extends Component { WindowCanvasNavigationControls.propTypes = { canvases: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types window: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types - canvasLabel: PropTypes.string, visible: PropTypes.bool, }; WindowCanvasNavigationControls.defaultProps = { - canvasLabel: undefined, visible: true, }; diff --git a/src/components/index.js b/src/components/index.js index 790be5479f269e0f746c6dde479f65a1802509a5..f9a96ce3a5274885ef34cba969637b6563bdb1b7 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -10,6 +10,7 @@ export * from './NestedMenu'; export * from './OpenSeadragonViewer'; export * from './SanitizedHtml'; export * from './ThumbnailNavigation'; +export * from './ViewerInfo'; export * from './ViewerNavigation'; export * from './Window'; export * from './WindowList'; diff --git a/src/containers/ViewerInfo.js b/src/containers/ViewerInfo.js new file mode 100644 index 0000000000000000000000000000000000000000..9793fa8f369fce28d11a5b3e936581660c34b77a --- /dev/null +++ b/src/containers/ViewerInfo.js @@ -0,0 +1,31 @@ +import { compose } from 'redux'; +import { connect } from 'react-redux'; +import { withTranslation } from 'react-i18next'; +import { ViewerInfo } from '../components/ViewerInfo'; +import { getCanvasLabel, getWindowManifest, getManifestCanvases } from '../state/selectors'; + +/** + * mapStateToProps - to hook up connect + * @memberof Window + * @private + */ +const mapStateToProps = (state, props) => { + const { windowId } = props; + const manifest = getWindowManifest(state, windowId); + const canvases = getManifestCanvases(manifest); + const { canvasIndex } = state.windows[windowId]; + + return { + canvasCount: canvases.length, + canvasIndex, + canvasLabel: getCanvasLabel(canvases[canvasIndex], canvasIndex), + }; +}; + +const enhance = compose( + withTranslation(), + connect(mapStateToProps, null), + // further HOC go here +); + +export default enhance(ViewerInfo); diff --git a/src/styles/index.scss b/src/styles/index.scss index 67df89db700f1e0829e52f365d3a954f52126bb5..894cc142ca9dfb5f0431574523ce41152bbfb81c 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -111,10 +111,19 @@ top: 12px; } + &-osd-navigation { + order: 1; + } + + &-osd-info { + order: 2 + } + &-canvas-nav { display: flex; - justify-content: center; flex-wrap: wrap; + flex-direction: column; + justify-content: center; text-align: center; }