Skip to content
Snippets Groups Projects
Commit 1d24ebb0 authored by Chris Beer's avatar Chris Beer
Browse files

Add toggle between compact + thumbnail canvas navigation

parent c22472c6
No related branches found
No related tags found
No related merge requests found
...@@ -72,4 +72,9 @@ describe('CompanionWindow', () => { ...@@ -72,4 +72,9 @@ describe('CompanionWindow', () => {
expect(updateCompanionWindow).toHaveBeenCalledTimes(1); expect(updateCompanionWindow).toHaveBeenCalledTimes(1);
expect(updateCompanionWindow).toHaveBeenCalledWith('x', 'abc123', { position: 'right' }); expect(updateCompanionWindow).toHaveBeenCalledWith('x', 'abc123', { position: 'right' });
}); });
it('renders title controls', () => {
companionWindow = createWrapper({ position: 'bottom', titleControls: <div className="xyz" /> });
expect(companionWindow.find('div.xyz').length).toBe(1);
});
}); });
...@@ -5,40 +5,70 @@ import ListItem from '@material-ui/core/ListItem'; ...@@ -5,40 +5,70 @@ import ListItem from '@material-ui/core/ListItem';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import manifesto from 'manifesto.js'; import manifesto from 'manifesto.js';
import { WindowSideBarCanvasPanel } from '../../../src/components/WindowSideBarCanvasPanel'; import { WindowSideBarCanvasPanel } from '../../../src/components/WindowSideBarCanvasPanel';
import { CanvasThumbnail } from '../../../src/components/CanvasThumbnail';
import manifestJson from '../../fixtures/version-2/019.json'; import manifestJson from '../../fixtures/version-2/019.json';
import { getIdAndLabelOfCanvases } from '../../../src/state/selectors'; import { getIdAndLabelOfCanvases } from '../../../src/state/selectors';
describe('WindowSideBarCanvasPanel', () => { /**
let wrapper; * Helper function to create a shallow wrapper around WindowSideBarCanvasPanel
let setCanvas; */
let canvases; function createWrapper(props) {
const canvases = manifesto.create(manifestJson).getSequences()[0].getCanvases();
beforeEach(() => {
setCanvas = jest.fn();
canvases = manifesto.create(manifestJson).getSequences()[0].getCanvases();
wrapper = shallow( return shallow(
<WindowSideBarCanvasPanel <WindowSideBarCanvasPanel
id="asdf" id="asdf"
canvases={canvases} canvases={canvases}
classes={{}} classes={{}}
t={key => key} t={key => key}
windowId="xyz" windowId="xyz"
setCanvas={setCanvas} setCanvas={() => {}}
config={{ canvasNavigation: { height: 100 } }} config={{ canvasNavigation: { height: 100 } }}
{...props}
/>, />,
); );
}
describe('WindowSideBarCanvasPanel', () => {
let setCanvas;
beforeEach(() => {
setCanvas = jest.fn();
}); });
it('renders all needed elements', () => { it('renders all needed elements for the thumbnail view', () => {
const wrapper = createWrapper();
expect(wrapper.props().title).toBe('canvasIndex'); expect(wrapper.props().title).toBe('canvasIndex');
expect(wrapper.find(List).length).toBe(1); expect(wrapper.find(List).length).toBe(1);
expect(wrapper.find(ListItem).length).toBe(3); expect(wrapper.find(ListItem).length).toBe(3);
expect(wrapper.find(ListItem).first().props().component).toEqual('li'); expect(wrapper.find(ListItem).first().props().component).toEqual('li');
expect(wrapper.find(List).find(Typography).length).toBe(3); expect(wrapper.find(List).find(Typography).length).toBe(3);
expect(wrapper.find(CanvasThumbnail).length).toBe(3);
}); });
describe('handleVariantChange', () => {
it('toggles state', () => {
const wrapper = createWrapper();
wrapper.instance().handleVariantChange({ target: { value: 'compact' } });
expect(wrapper.state().variant).toBe('compact');
});
});
it('renders all needed elements for the compact view', () => {
const wrapper = createWrapper();
wrapper.setState({ variant: 'compact' });
expect(wrapper.props().title).toBe('canvasIndex');
expect(wrapper.find(List).length).toBe(1);
expect(wrapper.find(ListItem).length).toBe(3);
expect(wrapper.find(ListItem).first().props().component).toEqual('li');
expect(wrapper.find(List).find(Typography).length).toBe(3);
expect(wrapper.find(CanvasThumbnail).length).toBe(0);
});
it('should set the correct labels', () => { it('should set the correct labels', () => {
const wrapper = createWrapper();
const canvases = manifesto.create(manifestJson).getSequences()[0].getCanvases();
const idsAndLabels = getIdAndLabelOfCanvases(canvases); const idsAndLabels = getIdAndLabelOfCanvases(canvases);
expect(wrapper expect(wrapper
.find(List) .find(List)
...@@ -56,6 +86,7 @@ describe('WindowSideBarCanvasPanel', () => { ...@@ -56,6 +86,7 @@ describe('WindowSideBarCanvasPanel', () => {
}); });
it('should call the onClick handler of a list item', () => { it('should call the onClick handler of a list item', () => {
const wrapper = createWrapper({ setCanvas });
wrapper.find(ListItem).at(1).simulate('click'); wrapper.find(ListItem).at(1).simulate('click');
expect(setCanvas).toHaveBeenCalledTimes(1); expect(setCanvas).toHaveBeenCalledTimes(1);
}); });
......
...@@ -21,7 +21,7 @@ export class CompanionWindow extends Component { ...@@ -21,7 +21,7 @@ export class CompanionWindow extends Component {
render() { render() {
const { const {
classes, paperClassName, id, onCloseClick, updateCompanionWindow, isDisplayed, classes, paperClassName, id, onCloseClick, updateCompanionWindow, isDisplayed,
position, t, windowId, title, children, position, t, windowId, title, children, titleControls,
} = this.props; } = this.props;
return ( return (
...@@ -35,10 +35,13 @@ export class CompanionWindow extends Component { ...@@ -35,10 +35,13 @@ export class CompanionWindow extends Component {
component="aside" component="aside"
aria-label={title} aria-label={title}
> >
<Toolbar variant="dense" className={[position === 'left' ? classes.leftPadding : undefined, ns('companion-window-header')].join(' ')} disableGutters> <Toolbar className={[classes.toolbar, position === 'left' ? classes.leftPadding : undefined, ns('companion-window-header')].join(' ')} disableGutters>
<Typography variant="h3" className={classes.windowSideBarTitle}> <Typography variant="h3" className={classes.windowSideBarTitle}>
{title} {title}
</Typography> </Typography>
<div className={ns('companion-window-title-controls')}>
{titleControls}
</div>
{ {
position === 'left' position === 'left'
? updateCompanionWindow ? updateCompanionWindow
...@@ -94,6 +97,7 @@ CompanionWindow.propTypes = { ...@@ -94,6 +97,7 @@ CompanionWindow.propTypes = {
isDisplayed: PropTypes.bool, isDisplayed: PropTypes.bool,
t: PropTypes.func, t: PropTypes.func,
title: PropTypes.string, title: PropTypes.string,
titleControls: PropTypes.node,
windowId: PropTypes.string.isRequired, windowId: PropTypes.string.isRequired,
children: PropTypes.node, children: PropTypes.node,
}; };
...@@ -107,4 +111,5 @@ CompanionWindow.defaultProps = { ...@@ -107,4 +111,5 @@ CompanionWindow.defaultProps = {
title: null, title: null,
t: key => key, t: key => key,
children: undefined, children: undefined,
titleControls: null,
}; };
...@@ -4,6 +4,10 @@ import classNames from 'classnames'; ...@@ -4,6 +4,10 @@ import classNames from 'classnames';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import List from '@material-ui/core/List'; import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem'; import ListItem from '@material-ui/core/ListItem';
import FilledInput from '@material-ui/core/FilledInput';
import MenuItem from '@material-ui/core/MenuItem';
import FormControl from '@material-ui/core/FormControl';
import Select from '@material-ui/core/Select';
import { CanvasThumbnail } from './CanvasThumbnail'; import { CanvasThumbnail } from './CanvasThumbnail';
import ManifestoCanvas from '../lib/ManifestoCanvas'; import ManifestoCanvas from '../lib/ManifestoCanvas';
import CompanionWindow from '../containers/CompanionWindow'; import CompanionWindow from '../containers/CompanionWindow';
...@@ -13,37 +17,51 @@ import { getIdAndLabelOfCanvases } from '../state/selectors'; ...@@ -13,37 +17,51 @@ import { getIdAndLabelOfCanvases } from '../state/selectors';
* a panel showing the canvases for a given manifest * a panel showing the canvases for a given manifest
*/ */
export class WindowSideBarCanvasPanel extends Component { export class WindowSideBarCanvasPanel extends Component {
/** /** */
* render constructor(props) {
*/ super(props);
render() {
this.state = { variant: 'thumbnail' };
this.handleVariantChange = this.handleVariantChange.bind(this);
}
/** */
handleVariantChange(event) {
this.setState({ variant: event.target.value });
}
/** */
renderCompact(canvas, otherCanvas) {
const { const {
canvases, classes, config, setCanvas, t, windowId, id, classes,
} = this.props; } = this.props;
const canvasesIdAndLabel = getIdAndLabelOfCanvases(canvases);
return ( return (
<CompanionWindow title={t('canvasIndex')} id={id} windowId={windowId}> <>
<List> <Typography
{ className={classNames(classes.label)}
canvasesIdAndLabel.map((canvas, canvasIndex) => { variant="body2"
>
{canvas.label}
</Typography>
</>
);
}
/** */
renderThumbnail(canvas, otherCanvas) {
const {
classes, config,
} = this.props;
const { width, height } = config.canvasNavigation; const { width, height } = config.canvasNavigation;
const manifestoCanvas = new ManifestoCanvas(canvases[canvasIndex]); const manifestoCanvas = new ManifestoCanvas(otherCanvas);
const isValid = manifestoCanvas.hasValidDimensions;
const onClick = () => { setCanvas(windowId, canvasIndex); }; // eslint-disable-line require-jsdoc, max-len
return ( return (
<ListItem <>
key={canvas.id}
alignItems="flex-start"
onClick={onClick}
button
component="li"
>
<div style={{ minWidth: 50 }}> <div style={{ minWidth: 50 }}>
<CanvasThumbnail <CanvasThumbnail
className={classNames(classes.clickable)} className={classNames(classes.clickable)}
isValid={isValid} isValid={manifestoCanvas.hasValidDimensions}
imageUrl={manifestoCanvas.thumbnail(width, height)} imageUrl={manifestoCanvas.thumbnail(width, height)}
maxHeight={config.canvasNavigation.height} maxHeight={config.canvasNavigation.height}
maxWidth={config.canvasNavigation.width} maxWidth={config.canvasNavigation.width}
...@@ -56,6 +74,58 @@ export class WindowSideBarCanvasPanel extends Component { ...@@ -56,6 +74,58 @@ export class WindowSideBarCanvasPanel extends Component {
> >
{canvas.label} {canvas.label}
</Typography> </Typography>
</>
);
}
/**
* render
*/
render() {
const {
canvases, setCanvas, t, windowId, id,
} = this.props;
const { variant } = this.state;
const canvasesIdAndLabel = getIdAndLabelOfCanvases(canvases);
return (
<CompanionWindow
title={t('canvasIndex')}
id={id}
windowId={windowId}
titleControls={(
<FormControl variant="filled">
<Select
value={variant}
onChange={this.handleVariantChange}
name="variant"
autoWidth
variant="filled"
input={<FilledInput name="variant" />}
>
<MenuItem value="compact">Compact List</MenuItem>
<MenuItem value="thumbnail">Thumbnail List</MenuItem>
</Select>
</FormControl>
)}
>
<List>
{
canvasesIdAndLabel.map((canvas, canvasIndex) => {
const onClick = () => { setCanvas(windowId, canvasIndex); }; // eslint-disable-line require-jsdoc, max-len
return (
<ListItem
key={canvas.id}
alignItems="flex-start"
onClick={onClick}
button
component="li"
>
{variant === 'compact' && this.renderCompact(canvas, canvases[canvasIndex])}
{variant === 'thumbnail' && this.renderThumbnail(canvas, canvases[canvasIndex])}
</ListItem> </ListItem>
); );
}) })
......
...@@ -59,6 +59,9 @@ const styles = theme => ({ ...@@ -59,6 +59,9 @@ const styles = theme => ({
positionButton: { positionButton: {
order: -100, order: -100,
}, },
toolbar: {
minHeight: 'max-content',
},
leftPadding: { leftPadding: {
...theme.mixins.gutters(), ...theme.mixins.gutters(),
paddingRight: 0, paddingRight: 0,
......
...@@ -20,6 +20,21 @@ ...@@ -20,6 +20,21 @@
} }
} }
&-companion-window-header {
flex-wrap: wrap;
}
&-companion-window-title-controls {
order: 1000;
flex-grow: 1;
}
&-companion-window-bottom {
.mirador-companion-window-title-controls {
order: unset;
}
}
&-companion-window-header { &-companion-window-header {
background: $surface-dark; background: $surface-dark;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment