diff --git a/__tests__/integration/mirador/toc.html b/__tests__/integration/mirador/toc.html
new file mode 100644
index 0000000000..875765b48b
--- /dev/null
+++ b/__tests__/integration/mirador/toc.html
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+ Mirador - Table of contents
+
+
+
+
+
+
+
+
diff --git a/__tests__/src/selectors/manifests.test.js b/__tests__/src/selectors/manifests.test.js
index 3e4b4d9415..776d23df55 100644
--- a/__tests__/src/selectors/manifests.test.js
+++ b/__tests__/src/selectors/manifests.test.js
@@ -25,6 +25,7 @@ import {
getManifestRenderings,
getManifestUrl,
getManifestViewingHint,
+ getManifestTreeStructure,
getMetadataLocales,
getRequiredStatement,
getRights,
diff --git a/src/components/SidebarIndexTableOfContents.js b/src/components/SidebarIndexTableOfContents.js
new file mode 100644
index 0000000000..7eba105f4e
--- /dev/null
+++ b/src/components/SidebarIndexTableOfContents.js
@@ -0,0 +1,66 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import TreeView from '@material-ui/lab/TreeView';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import ChevronRightIcon from '@material-ui/icons/ChevronRight';
+import TreeItem from '@material-ui/lab/TreeItem';
+
+/** */
+export class SidebarIndexTableOfContents extends Component {
+ /** */
+ selectTreeItem(node) {
+ const { setCanvas, windowId } = this.props;
+ // Do not select if there are child nodes
+ if (node.nodes.length > 0) {
+ return;
+ }
+ const canvas = node.data.getCanvasIds()[0];
+ setCanvas(windowId, canvas);
+ }
+
+ /** */
+ buildTreeItems(nodes) {
+ return (
+ nodes.map(node => (
+ this.selectTreeItem(node)}
+ >
+ {node.nodes.length > 0 ? this.buildTreeItems(node.nodes) : null}
+
+ ))
+ );
+ }
+
+ /** */
+ render() {
+ const {
+ classes, treeStructure,
+ } = this.props;
+
+ if (!treeStructure) {
+ return <>>;
+ }
+
+ return (
+ <>
+ }
+ defaultExpandIcon={}
+ >
+ {this.buildTreeItems(treeStructure.nodes)}
+
+ >
+ );
+ }
+}
+
+SidebarIndexTableOfContents.propTypes = {
+ classes: PropTypes.objectOf(PropTypes.string).isRequired,
+ setCanvas: PropTypes.func.isRequired,
+ treeStructure: PropTypes.objectOf().isRequired,
+ windowId: PropTypes.string.isRequired,
+};
diff --git a/src/components/WindowSideBarCanvasPanel.js b/src/components/WindowSideBarCanvasPanel.js
index a3416e7b14..9371c93991 100644
--- a/src/components/WindowSideBarCanvasPanel.js
+++ b/src/components/WindowSideBarCanvasPanel.js
@@ -7,6 +7,7 @@ import RootRef from '@material-ui/core/RootRef';
import Select from '@material-ui/core/Select';
import CompanionWindow from '../containers/CompanionWindow';
import SidebarIndexList from '../containers/SidebarIndexList';
+import SidebarIndexTableOfContents from '../containers/SidebarIndexTableOfContents';
/**
* a panel showing the canvases for a given manifest
@@ -46,6 +47,24 @@ export class WindowSideBarCanvasPanel extends Component {
} = this.props;
const { variantSelectionOpened } = this.state;
+ let listComponent;
+ if (variant === 'tableOfContents') {
+ listComponent = (
+
+ );
+ } else {
+ listComponent = (
+
+ );
+ }
return (
+
)}
>
-
+ {listComponent}
);
@@ -97,10 +117,10 @@ WindowSideBarCanvasPanel.propTypes = {
t: PropTypes.func.isRequired,
toggleDraggingEnabled: PropTypes.func.isRequired,
updateVariant: PropTypes.func.isRequired,
- variant: PropTypes.oneOf(['compact', 'thumbnail']),
+ variant: PropTypes.oneOf(['compact', 'thumbnail', 'tableOfContents']),
windowId: PropTypes.string.isRequired,
};
WindowSideBarCanvasPanel.defaultProps = {
- variant: 'thumbnail',
+ variant: 'tableOfContents',
};
diff --git a/src/containers/SidebarIndexTableOfContents.js b/src/containers/SidebarIndexTableOfContents.js
new file mode 100644
index 0000000000..dc65dd848e
--- /dev/null
+++ b/src/containers/SidebarIndexTableOfContents.js
@@ -0,0 +1,49 @@
+import { compose } from 'redux';
+import { connect } from 'react-redux';
+import { withTranslation } from 'react-i18next';
+import { withStyles } from '@material-ui/core/styles';
+import { withPlugins } from '../extend/withPlugins';
+import { SidebarIndexTableOfContents } from '../components/SidebarIndexTableOfContents';
+import {
+ getManifestoInstance,
+ getManifestTreeStructure,
+ getVisibleCanvases,
+} from '../state/selectors';
+import * as actions from '../state/actions';
+
+
+/**
+ * mapStateToProps - to hook up connect
+ */
+const mapStateToProps = (state, { id, windowId }) => ({
+ canvases: getVisibleCanvases(state, { windowId }),
+ manifesto: getManifestoInstance(state, { windowId }),
+ treeStructure: getManifestTreeStructure(state, { windowId }),
+});
+
+/**
+ * mapStateToProps - used to hook up connect to state
+ * @memberof SidebarIndexTableOfContents
+ * @private
+ */
+const mapDispatchToProps = (dispatch, { id, windowId }) => ({
+ setCanvas: (...args) => dispatch(actions.setCanvas(...args)),
+});
+
+/**
+ * Styles for withStyles HOC
+ */
+const styles = theme => ({
+ root: {
+ flexGrow: 1,
+ },
+});
+
+const enhance = compose(
+ withStyles(styles),
+ withTranslation(),
+ connect(mapStateToProps, mapDispatchToProps),
+ withPlugins('SidebarIndexTableOfContents'),
+);
+
+export default enhance(SidebarIndexTableOfContents);
diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json
index 46e1bf03b7..b45c8315fe 100644
--- a/src/locales/en/translation.json
+++ b/src/locales/en/translation.json
@@ -109,6 +109,7 @@
"single": "Single",
"startHere": "Start Here",
"suggestSearch": "Search this document for \"{{ query }}\"",
+ "tableOfContentsList": "Table of contents",
"theme": "Theme",
"thumbnailList": "Thumbnail list",
"thumbnailNavigation": "Thumbnails",
diff --git a/src/state/selectors/manifests.js b/src/state/selectors/manifests.js
index e6fe70f08d..2889174595 100644
--- a/src/state/selectors/manifests.js
+++ b/src/state/selectors/manifests.js
@@ -432,3 +432,12 @@ export const getManifestAutocompleteService = createSelector(
return autocompleteService && autocompleteService;
},
);
+
+/** */
+export const getManifestTreeStructure = createSelector(
+ [getManifestoInstance],
+ (manifest) => {
+ if (!manifest) return null;
+ return manifest.getDefaultTree();
+ },
+);