feat: Improved table of contents (#1223)

* feat: New table of contents

* fix: Hide TOC in edit mode

* feat: Highlight follows scroll position

* scroll tracking

* UI

* fix: Unrelated css fix with long doc titles

* Improve responsiveness

* feat: Add keyboard shortcut access to TOC

* fix: Headings should reflect content correctly when viewing old document revision

* flow

* fix: Persist TOC choice between sessions
This commit is contained in:
Tom Moor
2020-04-05 12:22:26 -07:00
committed by GitHub
parent 0deecfac44
commit d0606a72c3
17 changed files with 370 additions and 55 deletions

View File

@@ -6,7 +6,7 @@ import { observer, inject } from 'mobx-react';
import { Redirect } from 'react-router-dom';
import styled from 'styled-components';
import breakpoint from 'styled-components-breakpoint';
import { EditIcon, PlusIcon } from 'outline-icons';
import { TableOfContentsIcon, EditIcon, PlusIcon } from 'outline-icons';
import { transparentize, darken } from 'polished';
import Document from 'models/Document';
import AuthStore from 'stores/AuthStore';
@@ -14,7 +14,7 @@ import { documentEditUrl } from 'utils/routeHelpers';
import { meta } from 'utils/keyboard';
import Flex from 'shared/components/Flex';
import Breadcrumb from 'shared/components/Breadcrumb';
import Breadcrumb, { Slash } from 'shared/components/Breadcrumb';
import DocumentMenu from 'menus/DocumentMenu';
import NewChildDocumentMenu from 'menus/NewChildDocumentMenu';
import DocumentShare from 'scenes/DocumentShare';
@@ -26,8 +26,11 @@ import Badge from 'components/Badge';
import Collaborators from 'components/Collaborators';
import { Action, Separator } from 'components/Actions';
import PoliciesStore from 'stores/PoliciesStore';
import UiStore from 'stores/UiStore';
type Props = {
auth: AuthStore,
ui: UiStore,
policies: PoliciesStore,
document: Document,
isDraft: boolean,
@@ -43,7 +46,6 @@ type Props = {
publish?: boolean,
autosave?: boolean,
}) => void,
auth: AuthStore,
};
@observer
@@ -80,7 +82,9 @@ class Header extends React.Component<Props> {
handleShareLink = async (ev: SyntheticEvent<>) => {
const { document } = this.props;
if (!document.shareUrl) await document.share();
if (!document.shareUrl) {
await document.share();
}
this.showShareModal = true;
};
@@ -108,6 +112,7 @@ class Header extends React.Component<Props> {
isSaving,
savingIsDisabled,
publishingIsDisabled,
ui,
auth,
} = this.props;
@@ -134,7 +139,33 @@ class Header extends React.Component<Props> {
onSubmit={this.handleCloseShareModal}
/>
</Modal>
<Breadcrumb document={document} />
<BreadcrumbAndContents align="center" justify="flex-start">
<Breadcrumb document={document} />
{!isEditing && (
<React.Fragment>
<Slash />
<Tooltip
tooltip={ui.tocVisible ? 'Hide contents' : 'Show contents'}
shortcut={`ctrl+${meta}+h`}
delay={250}
placement="bottom"
>
<Button
onClick={
ui.tocVisible
? ui.hideTableOfContents
: ui.showTableOfContents
}
icon={<TableOfContentsIcon />}
iconColor="currentColor"
borderOnHover
neutral
small
/>
</Tooltip>
</React.Fragment>
)}
</BreadcrumbAndContents>
{this.isScrolled && (
<Title onClick={this.handleClickTitle}>
<Fade>
@@ -273,6 +304,14 @@ const Status = styled.div`
color: ${props => props.theme.slate};
`;
const BreadcrumbAndContents = styled(Flex)`
display: none;
${breakpoint('tablet')`
display: flex;
`};
`;
const Wrapper = styled(Flex)`
width: 100%;
align-self: flex-end;
@@ -289,7 +328,7 @@ const Actions = styled(Flex)`
right: 0;
left: 0;
z-index: 1;
background: ${props => transparentize(0.1, props.theme.background)};
background: ${props => transparentize(0.2, props.theme.background)};
box-shadow: 0 1px 0
${props =>
props.isCompact
@@ -298,7 +337,7 @@ const Actions = styled(Flex)`
padding: 12px;
transition: all 100ms ease-out;
transform: translate3d(0, 0, 0);
-webkit-backdrop-filter: blur(20px);
backdrop-filter: blur(20px);
@media print {
display: none;
@@ -327,4 +366,4 @@ const Title = styled.div`
`};
`;
export default inject('auth', 'policies')(Header);
export default inject('auth', 'ui', 'policies')(Header);