feat: Keyboard shortcut reference inside editor
This commit is contained in:
@ -21,6 +21,8 @@ import Sidebar from 'components/Sidebar';
|
||||
import SettingsSidebar from 'components/Sidebar/Settings';
|
||||
import Modals from 'components/Modals';
|
||||
import DocumentHistory from 'components/DocumentHistory';
|
||||
import Modal from 'components/Modal';
|
||||
import KeyboardShortcuts from 'scenes/KeyboardShortcuts';
|
||||
import ErrorSuspended from 'scenes/ErrorSuspended';
|
||||
import AuthStore from 'stores/AuthStore';
|
||||
import UiStore from 'stores/UiStore';
|
||||
@ -41,6 +43,7 @@ type Props = {
|
||||
class Layout extends React.Component<Props> {
|
||||
scrollable: ?HTMLDivElement;
|
||||
@observable redirectTo: ?string;
|
||||
@observable keyboardShortcutsOpen: boolean = false;
|
||||
|
||||
componentWillMount() {
|
||||
this.updateBackground();
|
||||
@ -54,6 +57,15 @@ class Layout extends React.Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
@keydown('shift+/')
|
||||
handleOpenKeyboardShortcuts() {
|
||||
this.keyboardShortcutsOpen = true;
|
||||
}
|
||||
|
||||
handleCloseKeyboardShortcuts = () => {
|
||||
this.keyboardShortcutsOpen = false;
|
||||
};
|
||||
|
||||
updateBackground() {
|
||||
// ensure the wider page color always matches the theme
|
||||
window.document.body.style.background = this.props.theme.background;
|
||||
@ -71,11 +83,6 @@ class Layout extends React.Component<Props> {
|
||||
this.redirectTo = homeUrl();
|
||||
}
|
||||
|
||||
@keydown('shift+/')
|
||||
openKeyboardShortcuts() {
|
||||
this.props.ui.setActiveModal('keyboard-shortcuts');
|
||||
}
|
||||
|
||||
render() {
|
||||
const { auth, ui } = this.props;
|
||||
const { user, team } = auth;
|
||||
@ -118,6 +125,13 @@ class Layout extends React.Component<Props> {
|
||||
</Switch>
|
||||
</Container>
|
||||
<Modals ui={ui} />
|
||||
<Modal
|
||||
isOpen={this.keyboardShortcutsOpen}
|
||||
onRequestClose={this.handleCloseKeyboardShortcuts}
|
||||
title="Keyboard shortcuts"
|
||||
>
|
||||
<KeyboardShortcuts />
|
||||
</Modal>
|
||||
<GlobalStyles />
|
||||
</Container>
|
||||
);
|
||||
|
@ -9,7 +9,6 @@ import CollectionDelete from 'scenes/CollectionDelete';
|
||||
import CollectionExport from 'scenes/CollectionExport';
|
||||
import DocumentDelete from 'scenes/DocumentDelete';
|
||||
import DocumentShare from 'scenes/DocumentShare';
|
||||
import KeyboardShortcuts from 'scenes/KeyboardShortcuts';
|
||||
|
||||
type Props = {
|
||||
ui: UiStore,
|
||||
@ -55,9 +54,6 @@ class Modals extends React.Component<Props> {
|
||||
<Modal name="document-delete" title="Delete document">
|
||||
<DocumentDelete onSubmit={this.handleClose} />
|
||||
</Modal>
|
||||
<Modal name="keyboard-shortcuts" title="Keyboard shortcuts">
|
||||
<KeyboardShortcuts />
|
||||
</Modal>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ type Props = {
|
||||
children: React.Node,
|
||||
delay?: number,
|
||||
className?: string,
|
||||
block?: boolean,
|
||||
};
|
||||
|
||||
class Tooltip extends React.Component<Props> {
|
||||
@ -17,7 +18,15 @@ class Tooltip extends React.Component<Props> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { tooltip, delay = 50, children, className, ...rest } = this.props;
|
||||
const {
|
||||
tooltip,
|
||||
delay = 50,
|
||||
children,
|
||||
block,
|
||||
className,
|
||||
...rest
|
||||
} = this.props;
|
||||
const Component = block ? 'div' : 'span';
|
||||
|
||||
return (
|
||||
<StyledTippy
|
||||
@ -30,7 +39,7 @@ class Tooltip extends React.Component<Props> {
|
||||
inertia
|
||||
{...rest}
|
||||
>
|
||||
<span className={className}>{children}</span>
|
||||
<Component className={className}>{children}</Component>
|
||||
</StyledTippy>
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { observable } from 'mobx';
|
||||
import { inject, observer } from 'mobx-react';
|
||||
import { MoonIcon } from 'outline-icons';
|
||||
import styled, { withTheme } from 'styled-components';
|
||||
@ -8,6 +9,8 @@ import UiStore from 'stores/UiStore';
|
||||
import AuthStore from 'stores/AuthStore';
|
||||
import Flex from 'shared/components/Flex';
|
||||
import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu';
|
||||
import Modal from 'components/Modal';
|
||||
import KeyboardShortcuts from 'scenes/KeyboardShortcuts';
|
||||
import {
|
||||
developers,
|
||||
changelog,
|
||||
@ -26,19 +29,33 @@ type Props = {
|
||||
|
||||
@observer
|
||||
class AccountMenu extends React.Component<Props> {
|
||||
handleOpenKeyboardShortcuts = () => {
|
||||
this.props.ui.setActiveModal('keyboard-shortcuts');
|
||||
};
|
||||
@observable keyboardShortcutsOpen: boolean = false;
|
||||
|
||||
handleLogout = () => {
|
||||
this.props.auth.logout();
|
||||
};
|
||||
|
||||
handleOpenKeyboardShortcuts = () => {
|
||||
this.keyboardShortcutsOpen = true;
|
||||
};
|
||||
|
||||
handleCloseKeyboardShortcuts = () => {
|
||||
this.keyboardShortcutsOpen = false;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { ui, theme } = this.props;
|
||||
const isLightTheme = ui.theme === 'light';
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Modal
|
||||
isOpen={this.keyboardShortcutsOpen}
|
||||
onRequestClose={this.handleCloseKeyboardShortcuts}
|
||||
title="Keyboard shortcuts"
|
||||
>
|
||||
<KeyboardShortcuts />
|
||||
</Modal>
|
||||
<DropdownMenu
|
||||
style={{ marginRight: 10, marginTop: -10 }}
|
||||
label={this.props.label}
|
||||
@ -75,8 +92,11 @@ class AccountMenu extends React.Component<Props> {
|
||||
</NightMode>
|
||||
</DropdownMenuItem>
|
||||
<hr />
|
||||
<DropdownMenuItem onClick={this.handleLogout}>Log out</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={this.handleLogout}>
|
||||
Log out
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenu>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import { emojiToUrl } from 'utils/emoji';
|
||||
import Header from './components/Header';
|
||||
import DocumentMove from './components/DocumentMove';
|
||||
import Branding from './components/Branding';
|
||||
import KeyboardShortcuts from './components/KeyboardShortcuts';
|
||||
import Backlinks from './components/Backlinks';
|
||||
import ErrorBoundary from 'components/ErrorBoundary';
|
||||
import LoadingPlaceholder from 'components/LoadingPlaceholder';
|
||||
@ -426,7 +427,7 @@ class DocumentScene extends React.Component<Props> {
|
||||
</MaxWidth>
|
||||
</Container>
|
||||
</Container>
|
||||
{isShare && <Branding />}
|
||||
{isShare ? <Branding /> : <KeyboardShortcuts />}
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
|
72
app/scenes/Document/components/KeyboardShortcuts.js
Normal file
72
app/scenes/Document/components/KeyboardShortcuts.js
Normal file
@ -0,0 +1,72 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import breakpoint from 'styled-components-breakpoint';
|
||||
import { observable } from 'mobx';
|
||||
import { observer } from 'mobx-react';
|
||||
import { KeyboardIcon } from 'outline-icons';
|
||||
import Modal from 'components/Modal';
|
||||
import Tooltip from 'components/Tooltip';
|
||||
import KeyboardShortcuts from 'scenes/KeyboardShortcuts';
|
||||
|
||||
type Props = {};
|
||||
|
||||
@observer
|
||||
class KeyboardShortcutsButton extends React.Component<Props> {
|
||||
@observable keyboardShortcutsOpen: boolean = false;
|
||||
|
||||
handleOpenKeyboardShortcuts = () => {
|
||||
this.keyboardShortcutsOpen = true;
|
||||
};
|
||||
|
||||
handleCloseKeyboardShortcuts = () => {
|
||||
this.keyboardShortcutsOpen = false;
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Modal
|
||||
isOpen={this.keyboardShortcutsOpen}
|
||||
onRequestClose={this.handleCloseKeyboardShortcuts}
|
||||
title="Keyboard shortcuts"
|
||||
>
|
||||
<KeyboardShortcuts />
|
||||
</Modal>
|
||||
<Button onClick={this.handleOpenKeyboardShortcuts}>
|
||||
<Tooltip tooltip="Keyboard shortcuts" placement="left" block>
|
||||
<KeyboardIcon />
|
||||
</Tooltip>
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const Button = styled.button`
|
||||
display: none;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
margin: 24px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
opacity: 0.8;
|
||||
background: none;
|
||||
line-height: 0;
|
||||
border: 0;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
${breakpoint('tablet')`
|
||||
display: block;
|
||||
`};
|
||||
|
||||
@media print {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
export default KeyboardShortcutsButton;
|
@ -10,10 +10,8 @@ function KeyboardShortcuts() {
|
||||
return (
|
||||
<Flex column>
|
||||
<HelpText>
|
||||
Outline is designed to be super fast and easy to use. All of your usual
|
||||
keyboard shortcuts work here, and there
|
||||
{"'"}
|
||||
s Markdown too.
|
||||
Outline is designed to be fast and easy to use. All of your usual
|
||||
keyboard shortcuts work here, and there’s Markdown too.
|
||||
</HelpText>
|
||||
|
||||
<h2>Navigation</h2>
|
||||
|
Reference in New Issue
Block a user