diff --git a/__tests__/src/components/ThumbnailNavigation.test.js b/__tests__/src/components/ThumbnailNavigation.test.js index b418a310ec80fd480ab0e16cfa31566d2bcf7b68..30b60008edcb676d7ca479fcc21e48bdb4d52c94 100644 --- a/__tests__/src/components/ThumbnailNavigation.test.js +++ b/__tests__/src/components/ThumbnailNavigation.test.js @@ -64,8 +64,7 @@ describe('ThumbnailNavigation', () => { expect(setCanvas).toHaveBeenCalledWith('foobar', 0); }); it('sets up calculated width based off of height of area and dimensions of canvas', () => { - expect(renderedGrid.find('.mirador-thumbnail-nav-container').first().prop('style').width).toEqual(108); - expect(renderedGrid.find('.mirador-thumbnail-nav-canvas').first().prop('style').width).toEqual(100); + expect(renderedGrid.find('.mirador-thumbnail-nav-container').first().prop('style').width).toEqual(95); }); it('renders canvas thumbnails', () => { expect(renderedGrid.find('CanvasThumbnail').length).toBe(3); @@ -109,7 +108,7 @@ describe('ThumbnailNavigation', () => { }); it('style', () => { expect(wrapper.instance().style()).toMatchObject({ height: '150px', width: '100%' }); - expect(rightWrapper.instance().style()).toMatchObject({ height: '100%', width: '100px' }); + expect(rightWrapper.instance().style()).toMatchObject({ height: '100%', width: '131px' }); }); it('rightWidth', () => { expect(wrapper.instance().rightWidth()).toEqual(100); @@ -126,12 +125,12 @@ describe('ThumbnailNavigation', () => { expect(wrapper.instance().rightWidth()).toEqual(200); }); it('calculateScaledWidth', () => { - expect(wrapper.instance().calculateScaledWidth({ index: 0 })).toEqual(108); - expect(rightWrapper.instance().calculateScaledWidth({ index: 0 })).toEqual(100); + expect(wrapper.instance().calculateScaledWidth({ index: 0 })).toEqual(95); + expect(rightWrapper.instance().calculateScaledWidth({ index: 0 })).toEqual(116); }); it('calculateScaledHeight', () => { - expect(wrapper.instance().calculateScaledHeight({ index: 0 })).toEqual(150); - expect(rightWrapper.instance().calculateScaledHeight({ index: 0 })).toEqual(150); + expect(wrapper.instance().calculateScaledHeight({ index: 0 })).toEqual(135); + expect(rightWrapper.instance().calculateScaledHeight({ index: 0 })).toEqual(166); }); it('columnCount', () => { diff --git a/src/components/ThumbnailNavigation.js b/src/components/ThumbnailNavigation.js index 2626aaadbb367d23dfe07edb4e5afab6c22dae20..7950ec197ffa8097afd2af8164b179881f520dce 100644 --- a/src/components/ThumbnailNavigation.js +++ b/src/components/ThumbnailNavigation.js @@ -5,8 +5,10 @@ import Grid from 'react-virtualized/dist/commonjs/Grid'; import GridListTile from '@material-ui/core/GridListTile'; import GridListTileBar from '@material-ui/core/GridListTileBar'; import Typography from '@material-ui/core/Typography'; +import classNames from 'classnames'; import { CanvasThumbnail } from './CanvasThumbnail'; import ManifestoCanvas from '../lib/ManifestoCanvas'; +import CanvasWorld from '../lib/CanvasWorld'; import ns from '../config/css-ns'; import 'react-virtualized/styles.css'; @@ -18,6 +20,8 @@ export class ThumbnailNavigation extends Component { constructor(props) { super(props); + this.scrollbarSize = 15; + this.spacing = 16; // 2 * (2px margin + 2px border + 2px padding + 2px padding) this.cellRenderer = this.cellRenderer.bind(this); this.calculateScaledHeight = this.calculateScaledHeight.bind(this); this.calculateScaledWidth = this.calculateScaledWidth.bind(this); @@ -58,7 +62,6 @@ export class ThumbnailNavigation extends Component { classes, window, setCanvas, config, canvasGroupings, position, } = this.props; const currentIndex = (position === 'far-right') ? rowIndex : columnIndex; - const currentGroupings = canvasGroupings.groupings()[currentIndex]; return ( <div @@ -68,29 +71,40 @@ export class ThumbnailNavigation extends Component { > <div style={{ - width: style.width - 8, + display: 'flex', + flexWrap: 'nowrap', }} - className={ns(['thumbnail-nav-canvas', `thumbnail-nav-canvas-${currentIndex}`, this.currentCanvasClass(currentGroupings.map(canvas => canvas.index))])} + className={classNames( + ns(['thumbnail-nav-canvas', `thumbnail-nav-canvas-${currentIndex}`, this.currentCanvasClass(currentGroupings.map(canvas => canvas.index))]), + classes.canvas, + { + [classes.currentCanvas]: currentGroupings + .map(canvas => canvas.index).includes(window.canvasIndex), + }, + )} > {currentGroupings.map((canvas, i) => { - const { height } = config.thumbnailNavigation; const manifestoCanvas = new ManifestoCanvas(canvas); - + const thumbWidth = Math.floor( + (style.height - this.spacing) * manifestoCanvas.aspectRatio, + ); + const maxHeight = (position === 'far-right') ? null : style.height - this.spacing; + const maxWidth = (position === 'far-right') ? thumbWidth : null; return ( <GridListTile component="div" key={canvas.index} onClick={() => setCanvas(window.id, currentGroupings[0].index)} style={{ - position: 'absolute', left: (style.width - 8) * i / 2, top: 2, + height: '100%', + width: 'auto', }} > <CanvasThumbnail - imageUrl={manifestoCanvas.thumbnail(null, height)} + imageUrl={manifestoCanvas.thumbnail(null, config.thumbnailNavigation.height)} isValid={manifestoCanvas.hasValidDimensions} - maxHeight={config.thumbnailNavigation.height} - maxWidth={style.width} - aspectRatio={manifestoCanvas.aspectRatio} + maxHeight={maxHeight} + maxWidth={maxWidth} /> <GridListTileBar classes={{ root: classes.root }} @@ -117,12 +131,18 @@ export class ThumbnailNavigation extends Component { const { config, canvasGroupings, position } = this.props; switch (position) { case 'far-right': - return this.rightWidth(); + return this.rightWidth() + this.spacing; // Default case bottom - default: - return canvasGroupings.getCanvases(options.index) - .map(canvas => new ManifestoCanvas(canvas)) - .reduce((acc, currentCanvas) => { return acc + (currentCanvas.hasValidDimensions ? Math.floor(config.thumbnailNavigation.height * currentCanvas.aspectRatio) : config.thumbnailNavigation.width); }, 8); // eslint-disable-line arrow-body-style, max-len + default: { + const canvases = canvasGroupings.getCanvases(options.index); + const world = new CanvasWorld(canvases); + const bounds = world.worldBounds(); + const calc = Math.floor( + (config.thumbnailNavigation.height - this.scrollbarSize - this.spacing) + * bounds[2] / bounds[3], + ); + return calc + this.spacing; + } } } @@ -134,15 +154,18 @@ export class ThumbnailNavigation extends Component { calculateScaledHeight(options) { const { config, canvasGroupings, position } = this.props; switch (position) { - case 'far-right': - return Math.max( - ...canvasGroupings.getCanvases(options.index) - .map(canvas => new ManifestoCanvas(canvas)) - .map(canvas => (canvas.hasValidDimensions ? Math.floor(config.thumbnailNavigation.width / canvas.aspectRatio) : config.thumbnailNavigation.height)), // eslint-disable-line arrow-body-style, max-len + case 'far-right': { + const canvases = canvasGroupings.getCanvases(options.index); + const world = new CanvasWorld(canvases); + const bounds = world.worldBounds(); + const calc = Math.floor( + config.thumbnailNavigation.width * canvases.length * bounds[3] / bounds[2], ); + return calc + this.spacing; + } // Default case bottom default: - return config.thumbnailNavigation.height; + return config.thumbnailNavigation.height - this.scrollbarSize; } } @@ -167,7 +190,7 @@ export class ThumbnailNavigation extends Component { case 'far-right': return { height: '100%', - width: `${this.rightWidth()}px`, + width: `${this.rightWidth() + this.scrollbarSize + this.spacing}px`, display: 'flex', minHeight: 0, }; @@ -185,7 +208,7 @@ export class ThumbnailNavigation extends Component { const { window, config } = this.props; switch (window.view) { case 'book': - return config.thumbnailNavigation.width * 2; + return (config.thumbnailNavigation.width * 2); default: return config.thumbnailNavigation.width; } diff --git a/src/config/settings.js b/src/config/settings.js index 9272519a711d72242a6c16c41b56fc7fa5a9fa33..e076ca82263400634b33b158b2e30ca93156364d 100644 --- a/src/config/settings.js +++ b/src/config/settings.js @@ -132,8 +132,8 @@ export default { windows: [], thumbnailNavigation: { defaultPosition: 'far-bottom', - height: 150, - width: 100, + height: 150, // height of entire ThumbnailNavigation area when position is "far-bottom" + width: 100, // width of a single thumb in ThumbnailNavigation area when position is "far-right" }, workspace: { type: 'mosaic', diff --git a/src/containers/ThumbnailNavigation.js b/src/containers/ThumbnailNavigation.js index caf749915c08ff23d9fa48cf251eca71e911b8e2..e3bddc280c3ac8ef2d59b72f36565f5b8161a85a 100644 --- a/src/containers/ThumbnailNavigation.js +++ b/src/containers/ThumbnailNavigation.js @@ -36,14 +36,26 @@ const mapDispatchToProps = { /** * Styles for withStyles HOC */ -const styles = { +const styles = theme => ({ + currentCanvas: { + }, + canvas: { + border: '2px solid transparent', + color: theme.palette.common.white, + cursor: 'pointer', + padding: '2px', + margin: '2px', + '&$currentCanvas': { + border: `2px solid ${theme.palette.secondary.main}`, + }, + }, root: { 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%)', }, title: { color: '#ffffff', }, -}; +}); const enhance = compose( withStyles(styles), diff --git a/src/styles/index.scss b/src/styles/index.scss index c27b0e559b37eebdbf0f8d07a23ab736f9028075..0ac95a47fa4829bb97590e5bab97de8eeee6ce9c 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -183,17 +183,8 @@ } &-thumb-navigation { - - .mirador-thumbnail-nav-canvas { - border: 1px solid $black; - color: $white; - cursor: pointer; - height: 100%; - - &.mirador-current-canvas { - border: 3px solid $blue; - } - } + margin: 2px; + padding: 2px; } &-label-value-metadata {