Skip to content
Snippets Groups Projects
Unverified Commit f544fddb authored by Jack Reed's avatar Jack Reed Committed by GitHub
Browse files

Merge pull request #1761 from ProjectMirador/1583-about-this-item-sidebar-panel

Add WindowSideBarPanel and WindowSideBarInfoPanel components to …
parents 5c5f36d2 41f9bf10
No related merge requests found
Showing
with 372 additions and 25 deletions
...@@ -58,4 +58,17 @@ describe('window actions', () => { ...@@ -58,4 +58,17 @@ describe('window actions', () => {
expect(actions.setWindowThumbnailPosition(id, 'right')).toEqual(expectedAction); expect(actions.setWindowThumbnailPosition(id, 'right')).toEqual(expectedAction);
}); });
}); });
describe('toggleWindowSideBarPanel', () => {
it('returns the appropriate action type', () => {
const windowId = 'abc123';
const panelType = 'panelType';
const expectedAction = {
type: ActionTypes.TOGGLE_WINDOW_SIDE_BAR_PANEL,
windowId,
panelType,
};
expect(actions.toggleWindowSideBarPanel(windowId, 'panelType')).toEqual(expectedAction);
});
});
}); });
...@@ -9,7 +9,7 @@ describe('WindowSideBar', () => { ...@@ -9,7 +9,7 @@ describe('WindowSideBar', () => {
}); });
it('renders without an error', () => { it('renders without an error', () => {
expect(wrapper.find('WithStyles(Drawer)').length).toBe(1); expect(wrapper.find('WithStyles(Drawer)').length).toBe(2);
expect(wrapper.find('WithStyles(List)').length).toBe(1); expect(wrapper.find('WithStyles(List)').length).toBe(1);
}); });
}); });
...@@ -11,4 +11,16 @@ describe('WindowSideBarButtons', () => { ...@@ -11,4 +11,16 @@ describe('WindowSideBarButtons', () => {
it('renders without an error', () => { it('renders without an error', () => {
expect(wrapper.find('Fragment').length).toBe(1); expect(wrapper.find('Fragment').length).toBe(1);
}); });
it('triggers the toggleWindowSideBarPanel prop on click', () => {
const toggleWindowSideBarPanel = jest.fn();
wrapper = shallow(
<WindowSideBarButtons toggleWindowSideBarPanel={toggleWindowSideBarPanel} />,
);
const iconButton = wrapper.find('WithStyles(IconButton)[aria-label="Open information companion window"]');
expect(iconButton.simulate('click'));
expect(toggleWindowSideBarPanel).toHaveBeenCalledTimes(1);
expect(toggleWindowSideBarPanel).toHaveBeenCalledWith('info');
});
}); });
import React from 'react';
import { shallow } from 'enzyme';
import createStore from '../../../src/state/createStore';
import * as actions from '../../../src/state/actions';
import WindowSideBarInfoPanel from '../../../src/components/WindowSideBarInfoPanel';
import fixture from '../../fixtures/version-2/001.json';
describe('WindowSideBarInfoPanel', () => {
let wrapper;
let manifest;
const store = createStore();
beforeEach(() => {
store.dispatch(actions.receiveManifest('foo', fixture));
manifest = store.getState().manifests.foo;
wrapper = shallow(<WindowSideBarInfoPanel manifest={manifest} />);
});
it('renders without an error', () => {
expect(wrapper.find('h2').text()).toBe('About this item');
expect(wrapper.find('h3').text()).toBe('Bodleian Library Human Freaks 2 (33)');
expect(wrapper.find('.mirador-window-sidebar-info-panel div').text()).toBe('[Handbill of Mr. Becket, [1787] ]');
});
});
import React from 'react';
import { shallow } from 'enzyme';
import createStore from '../../../src/state/createStore';
import * as actions from '../../../src/state/actions';
import WindowSideBarPanel from '../../../src/components/WindowSideBarPanel';
import fixture from '../../fixtures/version-2/001.json';
describe('WindowSideBarPanel', () => {
let wrapper;
let manifest;
const store = createStore();
beforeEach(() => {
store.dispatch(actions.receiveManifest('foo', fixture));
manifest = store.getState().manifests.foo;
});
describe('when the sideBarPanel is set to "info"', () => {
beforeEach(() => {
wrapper = shallow(<WindowSideBarPanel sideBarPanel="info" manifest={manifest} />);
});
it('renders the WindowSideBarInfoPanel', () => {
expect(wrapper.find('WindowSideBarInfoPanel').length).toBe(1);
});
});
describe('when the sideBarPanel is set to "closed" (or any other unknown value)', () => {
beforeEach(() => {
wrapper = shallow(<WindowSideBarPanel sideBarPanel="closed" manifest={manifest} />);
});
it('does not render any panel component', () => {
expect(wrapper.find('WindowSideBarInfoPanel').length).toBe(0);
});
});
});
...@@ -65,6 +65,44 @@ describe('windows reducer', () => { ...@@ -65,6 +65,44 @@ describe('windows reducer', () => {
expect(reducer(before, action)).toEqual(after); expect(reducer(before, action)).toEqual(after);
}); });
describe('TOGGLE_WINDOW_SIDE_BAR_PANEL', () => {
it('sets the sideBarPanel value to the given value when it was changed', () => {
const action = {
type: ActionTypes.TOGGLE_WINDOW_SIDE_BAR_PANEL,
windowId: 'abc123',
panelType: 'info',
};
const before = {
abc123: { sideBarPanel: 'closed' },
abc321: { sideBarPanel: 'closed' },
};
const after = {
abc123: { sideBarPanel: 'info' },
abc321: { sideBarPanel: 'closed' },
};
expect(reducer(before, action)).toEqual(after);
});
it('sets the sideBarPanel value to "closed" when trying to open a panel that already is open', () => {
const action = {
type: ActionTypes.TOGGLE_WINDOW_SIDE_BAR_PANEL,
windowId: 'abc123',
panelType: 'info',
};
const before = {
abc123: { sideBarPanel: 'info' },
abc321: { sideBarPanel: 'closed' },
};
const after = {
abc123: { sideBarPanel: 'closed' },
abc321: { sideBarPanel: 'closed' },
};
expect(reducer(before, action)).toEqual(after);
});
});
it('should handle NEXT_CANVAS', () => { it('should handle NEXT_CANVAS', () => {
expect(reducer({ expect(reducer({
abc123: { abc123: {
......
...@@ -39,6 +39,7 @@ class WindowMiddleContent extends Component { ...@@ -39,6 +39,7 @@ class WindowMiddleContent extends Component {
windowId={window.id} windowId={window.id}
manifest={manifest} manifest={manifest}
sideBarOpen={window.sideBarOpen} sideBarOpen={window.sideBarOpen}
sideBarPanel={window.sideBarPanel}
/> />
<CompanionWindow <CompanionWindow
windowId={window.id} windowId={window.id}
......
...@@ -5,6 +5,8 @@ import Drawer from '@material-ui/core/Drawer'; ...@@ -5,6 +5,8 @@ import Drawer from '@material-ui/core/Drawer';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import List from '@material-ui/core/List'; import List from '@material-ui/core/List';
import WindowSideBarButtons from '../containers/WindowSideBarButtons'; import WindowSideBarButtons from '../containers/WindowSideBarButtons';
import WindowSideBarPanel from './WindowSideBarPanel';
import ns from '../config/css-ns';
/** /**
* WindowSideBar * WindowSideBar
...@@ -16,10 +18,11 @@ class WindowSideBar extends Component { ...@@ -16,10 +18,11 @@ class WindowSideBar extends Component {
*/ */
render() { render() {
const { const {
windowId, classes, sideBarOpen, classes, manifest, windowId, sideBarOpen, sideBarPanel,
} = this.props; } = this.props;
return ( return (
<>
<Drawer <Drawer
variant="temporary" variant="temporary"
className={classNames(classes.drawer)} className={classNames(classes.drawer)}
...@@ -34,24 +37,48 @@ class WindowSideBar extends Component { ...@@ -34,24 +37,48 @@ class WindowSideBar extends Component {
style: { position: 'absolute' }, style: { position: 'absolute' },
}} }}
> >
<div className={classes.toolbar} />
<List> <List>
<WindowSideBarButtons windowId={windowId} /> <WindowSideBarButtons windowId={windowId} sideBarPanel={sideBarPanel} />
</List> </List>
</Drawer> </Drawer>
<Drawer
variant="temporary"
className={classNames(classes.drawer, ns('window-sidebar-panel-drawer'))}
classes={{ paper: classNames(classes.drawer) }}
open={sideBarOpen && sideBarPanel !== 'closed'}
anchor="left"
PaperProps={{ style: { position: 'relative', width: '200px' } }}
ModalProps={{
container: document.getElementById(windowId),
disablePortal: true,
hideBackdrop: true,
style: { position: 'absolute', width: '200px' },
}}
>
<WindowSideBarPanel
manifest={manifest}
windowId={windowId}
sideBarPanel={sideBarPanel}
/>
</Drawer>
</>
); );
} }
} }
WindowSideBar.propTypes = { WindowSideBar.propTypes = {
windowId: PropTypes.string.isRequired,
classes: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types, classes: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types,
manifest: PropTypes.object, // eslint-disable-line react/forbid-prop-types
windowId: PropTypes.string.isRequired,
sideBarOpen: PropTypes.bool, sideBarOpen: PropTypes.bool,
sideBarPanel: PropTypes.string,
}; };
WindowSideBar.defaultProps = { WindowSideBar.defaultProps = {
manifest: {},
sideBarOpen: false, sideBarOpen: false,
sideBarPanel: 'closed',
}; };
/** /**
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types';
import IconButton from '@material-ui/core/IconButton';
import InfoIcon from '@material-ui/icons/Info';
/** /**
* *
*/ */
class WindowSideBarButtons extends Component { class WindowSideBarButtons extends Component {
/**
* sideBarPanelCurrentlySelected - return if the given sideBarPanel is currently selected
* @return Boolean
*/
sideBarPanelCurrentlySelected(panelType) {
const { sideBarPanel } = this.props;
return sideBarPanel === panelType;
}
/** /**
* render * render
* *
* @return {type} description * @return {type} description
*/ */
render() { render() {
return (<></>); const { toggleWindowSideBarPanel } = this.props;
return (
<>
<IconButton
aria-label="Open information companion window"
color="inherit"
onClick={() => (toggleWindowSideBarPanel('info'))}
>
<InfoIcon
color={this.sideBarPanelCurrentlySelected('info') ? 'action' : 'inherit'}
/>
</IconButton>
</>
);
} }
} }
WindowSideBarButtons.propTypes = {
toggleWindowSideBarPanel: PropTypes.func,
sideBarPanel: PropTypes.string,
};
WindowSideBarButtons.defaultProps = {
toggleWindowSideBarPanel: () => {},
sideBarPanel: 'closed',
};
export default WindowSideBarButtons; export default WindowSideBarButtons;
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ns from '../config/css-ns';
/**
* WindowSideBarInfoPanel
*/
export default class WindowSideBarInfoPanel extends Component {
/**
* manifestLabel - get the label from the manifesto manifestation
* @return String
*/
manifestLabel() {
const { manifest } = this.props;
if (manifest.manifestation) {
return manifest.manifestation.getLabel().map(label => label.value)[0];
}
return '';
}
/**
* manifestDescription - get the description from the manifesto manifestation
* @return String
*/
manifestDescription() {
const { manifest } = this.props;
if (manifest.manifestation) {
return manifest.manifestation.getDescription().map(label => label.value);
}
return '';
}
/**
* render
* @return
*/
render() {
return (
<div className={ns('window-sidebar-info-panel')}>
<h2>About this item</h2>
<h3>{this.manifestLabel()}</h3>
<div>{this.manifestDescription()}</div>
</div>
);
}
}
WindowSideBarInfoPanel.propTypes = {
manifest: PropTypes.object, // eslint-disable-line react/forbid-prop-types
};
WindowSideBarInfoPanel.defaultProps = {
manifest: {},
};
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import WindowSideBarInfoPanel from './WindowSideBarInfoPanel';
/**
* WindowSideBarPanel - the panel that pops out from the sidebar
* when various icons are clicked such as Info, Search, etc.
*/
class WindowSideBarPanel extends Component {
/**
* activePanelComponent
* @return React Component
*/
activePanelComponent() {
const { manifest, sideBarPanel } = this.props;
switch (sideBarPanel) {
case 'info':
return <WindowSideBarInfoPanel manifest={manifest} />;
default:
return null;
}
}
/**
* render
* @return
*/
render() {
return (
<div>
{this.activePanelComponent()}
</div>
);
}
}
WindowSideBarPanel.propTypes = {
manifest: PropTypes.object, // eslint-disable-line react/forbid-prop-types
sideBarPanel: PropTypes.string,
};
WindowSideBarPanel.defaultProps = {
manifest: {},
sideBarPanel: 'closed', // Closed will fall out to the default null case for the actiuve panel
};
export default WindowSideBarPanel;
import { compose } from 'redux';
import { connect } from 'react-redux';
import * as actions from '../state/actions';
import miradorWithPlugins from '../lib/miradorWithPlugins'; import miradorWithPlugins from '../lib/miradorWithPlugins';
import WindowSideBarButtons from '../components/WindowSideBarButtons'; import WindowSideBarButtons from '../components/WindowSideBarButtons';
export default miradorWithPlugins(WindowSideBarButtons);
/**
* mapDispatchToProps - used to hook up connect to action creators
* @memberof WindowSideButtons
* @private
*/
const mapDispatchToProps = (dispatch, props) => ({
toggleWindowSideBarPanel: panelType => dispatch(
actions.toggleWindowSideBarPanel(props.windowId, panelType),
),
});
const enhance = compose(
connect(null, mapDispatchToProps),
miradorWithPlugins,
// further HOC go here
);
export default enhance(WindowSideBarButtons);
import miradorWithPlugins from '../lib/miradorWithPlugins';
import WindowSideBarPanel from '../components/WindowSideBarPanel';
export default miradorWithPlugins(WindowSideBarPanel);
...@@ -14,6 +14,7 @@ const ActionTypes = { ...@@ -14,6 +14,7 @@ const ActionTypes = {
SET_CONFIG: 'SET_CONFIG', SET_CONFIG: 'SET_CONFIG',
SET_WINDOW_THUMBNAIL_POSITION: 'SET_WINDOW_THUMBNAIL_POSITION', SET_WINDOW_THUMBNAIL_POSITION: 'SET_WINDOW_THUMBNAIL_POSITION',
TOGGLE_WINDOW_SIDE_BAR: 'TOGGLE_WINDOW_SIDE_BAR', TOGGLE_WINDOW_SIDE_BAR: 'TOGGLE_WINDOW_SIDE_BAR',
TOGGLE_WINDOW_SIDE_BAR_PANEL: 'TOGGLE_WINDOW_SIDE_BAR_PANEL',
UPDATE_CONFIG: 'UPDATE_CONFIG', UPDATE_CONFIG: 'UPDATE_CONFIG',
REMOVE_MANIFEST: 'REMOVE_MANIFEST', REMOVE_MANIFEST: 'REMOVE_MANIFEST',
REQUEST_INFO_RESPONSE: 'REQUEST_INFO_RESPONSE', REQUEST_INFO_RESPONSE: 'REQUEST_INFO_RESPONSE',
......
...@@ -52,9 +52,21 @@ export function toggleWindowSideBar(windowId) { ...@@ -52,9 +52,21 @@ export function toggleWindowSideBar(windowId) {
} }
/** /**
* toggleWindowSideBar - action creator * toggleWindowSideBarPanel - action creator
*
* @param {String} windowId
* @param {String} panelType
* @memberof ActionCreators
*/
export function toggleWindowSideBarPanel(windowId, panelType) {
return { type: ActionTypes.TOGGLE_WINDOW_SIDE_BAR_PANEL, windowId, panelType };
}
/**
* setWindowThumbnailPosition - action creator
* *
* @param {String} windowId * @param {String} windowId
* @param {String} position
* @memberof ActionCreators * @memberof ActionCreators
*/ */
export function setWindowThumbnailPosition(windowId, position) { export function setWindowThumbnailPosition(windowId, position) {
......
...@@ -22,6 +22,7 @@ const windowsReducer = (state = {}, action) => { ...@@ -22,6 +22,7 @@ const windowsReducer = (state = {}, action) => {
sideBarOpen: !state[action.windowId].sideBarOpen, sideBarOpen: !state[action.windowId].sideBarOpen,
}, },
}; };
case ActionTypes.SET_WINDOW_THUMBNAIL_POSITION: case ActionTypes.SET_WINDOW_THUMBNAIL_POSITION:
return { return {
...state, ...state,
...@@ -30,6 +31,18 @@ const windowsReducer = (state = {}, action) => { ...@@ -30,6 +31,18 @@ const windowsReducer = (state = {}, action) => {
thumbnailNavigationPosition: action.position, thumbnailNavigationPosition: action.position,
}, },
}; };
case ActionTypes.TOGGLE_WINDOW_SIDE_BAR_PANEL:
return {
...state,
[action.windowId]: {
...state[action.windowId],
sideBarPanel: (
state[action.windowId].sideBarPanel === action.panelType
? 'closed'
: action.panelType
),
},
};
case ActionTypes.NEXT_CANVAS: case ActionTypes.NEXT_CANVAS:
return setCanvasIndex(state, action.windowId, currentIndex => currentIndex + 1); return setCanvasIndex(state, action.windowId, currentIndex => currentIndex + 1);
case ActionTypes.PREVIOUS_CANVAS: case ActionTypes.PREVIOUS_CANVAS:
......
...@@ -36,6 +36,10 @@ body { ...@@ -36,6 +36,10 @@ body {
position: relative; position: relative;
} }
&-window-sidebar-panel-drawer {
margin-left: $window-sidebar-width;
}
&-window-companion-side { &-window-companion-side {
background: lighten($gray, 40%); background: lighten($gray, 40%);
min-width: 75px; min-width: 75px;
......
...@@ -4,3 +4,4 @@ $gray: #808080; ...@@ -4,3 +4,4 @@ $gray: #808080;
$white: #fff; $white: #fff;
$window-top-bar-gradient-top: rgba(0, 0, 0, .65); $window-top-bar-gradient-top: rgba(0, 0, 0, .65);
$window-top-bar-gradient-bottom: rgba(0, 0, 0, 0); $window-top-bar-gradient-bottom: rgba(0, 0, 0, 0);
$window-sidebar-width: 55px;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment