Add 'n' shortcut for new doc

Fixed cmd+enter shortcut to publish doc
Fixed keyboard shortcut display on non-mac
Fixed heading alignment
Fixed documents smaller than page should not scroll
This commit is contained in:
Tom Moor
2019-03-09 20:00:45 -08:00
parent f75783c2f1
commit fc7c485ba9
10 changed files with 53 additions and 20 deletions

View File

@ -2,9 +2,8 @@
import styled from 'styled-components'; import styled from 'styled-components';
const ClickablePadding = styled.div` const ClickablePadding = styled.div`
min-height: 50vh;
cursor: ${({ onClick }) => (onClick ? 'text' : 'default')}; cursor: ${({ onClick }) => (onClick ? 'text' : 'default')};
${({ grow }) => grow && `flex-grow: 1;`}; ${({ grow }) => grow && `flex-grow: 100;`};
`; `;
export default ClickablePadding; export default ClickablePadding;

View File

@ -1,8 +1,11 @@
// @flow // @flow
import * as React from 'react'; import * as React from 'react';
import { observer, inject } from 'mobx-react'; import { observer, inject } from 'mobx-react';
import { withRouter } from 'react-router-dom';
import keydown from 'react-keydown';
import Flex from 'shared/components/Flex'; import Flex from 'shared/components/Flex';
import { PlusIcon } from 'outline-icons'; import { PlusIcon } from 'outline-icons';
import { newDocumentUrl } from 'utils/routeHelpers';
import Header from './Header'; import Header from './Header';
import SidebarLink from './SidebarLink'; import SidebarLink from './SidebarLink';
@ -14,6 +17,7 @@ import UiStore from 'stores/UiStore';
import DocumentsStore from 'stores/DocumentsStore'; import DocumentsStore from 'stores/DocumentsStore';
type Props = { type Props = {
history: Object,
collections: CollectionsStore, collections: CollectionsStore,
documents: DocumentsStore, documents: DocumentsStore,
onCreateCollection: () => void, onCreateCollection: () => void,
@ -28,8 +32,17 @@ class Collections extends React.Component<Props> {
this.props.collections.fetchPage({ limit: 100 }); this.props.collections.fetchPage({ limit: 100 });
} }
@keydown('n')
goToNewDocument() {
const activeCollection = this.props.collections.active;
if (!activeCollection) return;
this.props.history.push(newDocumentUrl(activeCollection));
}
render() { render() {
const { collections, ui, documents } = this.props; const { collections, ui, documents } = this.props;
const content = ( const content = (
<Flex column> <Flex column>
<Header>Collections</Header> <Header>Collections</Header>
@ -57,4 +70,6 @@ class Collections extends React.Component<Props> {
} }
} }
export default inject('collections', 'ui', 'documents')(Collections); export default inject('collections', 'ui', 'documents')(
withRouter(Collections)
);

View File

@ -86,7 +86,7 @@ export default class Document extends BaseModel {
@computed @computed
get isEmpty(): boolean { get isEmpty(): boolean {
// Check if the document title has been modified and user generated content exists // Check if the document title has been modified and user generated content exists
return this.text.replace(new RegExp(`^#$`), '').trim().length === 0; return this.text.replace(/^#/, '').trim().length === 0;
} }
@computed @computed

View File

@ -194,6 +194,10 @@ class DocumentScene extends React.Component<Props> {
handleCloseMoveModal = () => (this.moveModalOpen = false); handleCloseMoveModal = () => (this.moveModalOpen = false);
handleOpenMoveModal = () => (this.moveModalOpen = true); handleOpenMoveModal = () => (this.moveModalOpen = true);
onSaveAndExit = () => {
this.onSave({ done: true, publish: true });
};
onSave = async ( onSave = async (
options: { done?: boolean, publish?: boolean, autosave?: boolean } = {} options: { done?: boolean, publish?: boolean, autosave?: boolean } = {}
) => { ) => {
@ -367,7 +371,7 @@ class DocumentScene extends React.Component<Props> {
onImageUploadStop={this.onImageUploadStop} onImageUploadStop={this.onImageUploadStop}
onSearchLink={this.onSearchLink} onSearchLink={this.onSearchLink}
onChange={this.onChange} onChange={this.onChange}
onSave={this.onSave} onSave={this.onSaveAndExit}
onCancel={this.onDiscard} onCancel={this.onDiscard}
readOnly={!this.isEditing} readOnly={!this.isEditing}
toc={!revision} toc={!revision}
@ -387,7 +391,6 @@ const MaxWidth = styled(Flex)`
padding: 0 16px; padding: 0 16px;
max-width: 100vw; max-width: 100vw;
width: 100%; width: 100%;
height: 100%;
${breakpoint('tablet')` ${breakpoint('tablet')`
padding: 0 24px; padding: 0 24px;

View File

@ -48,6 +48,8 @@ class DocumentEditor extends React.Component<Props> {
} }
const StyledEditor = styled(Editor)` const StyledEditor = styled(Editor)`
justify-content: start;
p { p {
${Placeholder} { ${Placeholder} {
visibility: hidden; visibility: hidden;

View File

@ -10,6 +10,7 @@ import { NewDocumentIcon } from 'outline-icons';
import Document from 'models/Document'; import Document from 'models/Document';
import AuthStore from 'stores/AuthStore'; import AuthStore from 'stores/AuthStore';
import { documentEditUrl } from 'utils/routeHelpers'; import { documentEditUrl } from 'utils/routeHelpers';
import { meta } from 'utils/keyboard';
import Flex from 'shared/components/Flex'; import Flex from 'shared/components/Flex';
import Breadcrumb from './Breadcrumb'; import Breadcrumb from './Breadcrumb';
@ -107,6 +108,7 @@ class Header extends React.Component<Props> {
justify="space-between" justify="space-between"
readOnly={!isEditing} readOnly={!isEditing}
isCompact={this.isScrolled} isCompact={this.isScrolled}
shrink={false}
> >
<Modal <Modal
isOpen={this.showShareModal} isOpen={this.showShareModal}
@ -149,7 +151,7 @@ class Header extends React.Component<Props> {
<Action> <Action>
<Button <Button
onClick={this.handleSave} onClick={this.handleSave}
title="Save changes (Cmd+Enter)" title={`Save changes ${isDraft ? '' : `${meta}+Enter`}`}
disabled={savingIsDisabled} disabled={savingIsDisabled}
isSaving={isSaving} isSaving={isSaving}
neutral={isDraft} neutral={isDraft}
@ -164,7 +166,7 @@ class Header extends React.Component<Props> {
<Action> <Action>
<Button <Button
onClick={this.handlePublish} onClick={this.handlePublish}
title="Publish document (Cmd+Enter)" title={`Publish document (${meta}+Enter)`}
disabled={savingIsDisabled} disabled={savingIsDisabled}
small small
> >

View File

@ -4,6 +4,7 @@ import styled from 'styled-components';
import Key from 'components/Key'; import Key from 'components/Key';
import Flex from 'shared/components/Flex'; import Flex from 'shared/components/Flex';
import HelpText from 'components/HelpText'; import HelpText from 'components/HelpText';
import { meta } from 'utils/keyboard';
function KeyboardShortcuts() { function KeyboardShortcuts() {
return ( return (
@ -17,6 +18,11 @@ function KeyboardShortcuts() {
<h2>Navigation</h2> <h2>Navigation</h2>
<List> <List>
<Keys>
<Key>n</Key>
</Keys>
<Label>New document in current collection</Label>
<Keys> <Keys>
<Key>e</Key> <Key>e</Key>
</Keys> </Keys>
@ -46,44 +52,44 @@ function KeyboardShortcuts() {
<h2>Editor</h2> <h2>Editor</h2>
<List> <List>
<Keys> <Keys>
<Key></Key> + <Key>Enter</Key> <Key>{meta}</Key> + <Key>Enter</Key>
</Keys> </Keys>
<Label>Save and exit document edit mode</Label> <Label>Save and exit document edit mode</Label>
<Keys> <Keys>
<Key></Key> + <Key>S</Key> <Key>{meta}</Key> + <Key>S</Key>
</Keys> </Keys>
<Label>Save document and continue editing</Label> <Label>Save document and continue editing</Label>
<Keys> <Keys>
<Key></Key> + <Key>Esc</Key> <Key>{meta}</Key> + <Key>Esc</Key>
</Keys> </Keys>
<Label>Cancel editing</Label> <Label>Cancel editing</Label>
<Keys> <Keys>
<Key></Key> + <Key>b</Key> <Key>{meta}</Key> + <Key>b</Key>
</Keys> </Keys>
<Label>Bold</Label> <Label>Bold</Label>
<Keys> <Keys>
<Key></Key> + <Key>i</Key> <Key>{meta}</Key> + <Key>i</Key>
</Keys> </Keys>
<Label>Italic</Label> <Label>Italic</Label>
<Keys> <Keys>
<Key></Key> + <Key>u</Key> <Key>{meta}</Key> + <Key>u</Key>
</Keys> </Keys>
<Label>Underline</Label> <Label>Underline</Label>
<Keys> <Keys>
<Key></Key> + <Key>d</Key> <Key>{meta}</Key> + <Key>d</Key>
</Keys> </Keys>
<Label>Strikethrough</Label> <Label>Strikethrough</Label>
<Keys> <Keys>
<Key></Key> + <Key>k</Key> <Key>{meta}</Key> + <Key>k</Key>
</Keys> </Keys>
<Label>Link</Label> <Label>Link</Label>
<Keys> <Keys>
<Key></Key> + <Key>z</Key> <Key>{meta}</Key> + <Key>z</Key>
</Keys> </Keys>
<Label>Undo</Label> <Label>Undo</Label>
<Keys> <Keys>
<Key></Key> + <Key>Shift</Key> + <Key>z</Key> <Key>{meta}</Key> + <Key>Shift</Key> + <Key>z</Key>
</Keys> </Keys>
<Label>Redo</Label> <Label>Redo</Label>
</List> </List>

View File

@ -13,6 +13,7 @@ import ArrowKeyNavigation from 'boundless-arrow-key-navigation';
import { DEFAULT_PAGINATION_LIMIT } from 'stores/BaseStore'; import { DEFAULT_PAGINATION_LIMIT } from 'stores/BaseStore';
import DocumentsStore from 'stores/DocumentsStore'; import DocumentsStore from 'stores/DocumentsStore';
import { searchUrl } from 'utils/routeHelpers'; import { searchUrl } from 'utils/routeHelpers';
import { meta } from 'utils/keyboard';
import Flex from 'shared/components/Flex'; import Flex from 'shared/components/Flex';
import Empty from 'components/Empty'; import Empty from 'components/Empty';
@ -193,8 +194,8 @@ class Search extends React.Component<Props> {
{showShortcutTip && ( {showShortcutTip && (
<Fade> <Fade>
<HelpText small> <HelpText small>
Use the <strong>CMD+K</strong> shortcut to search from anywhere Use the <strong>{meta}+K</strong> shortcut to search from
in Outline anywhere in Outline
</HelpText> </HelpText>
</Fade> </Fade>
)} )}

3
app/utils/keyboard.js Normal file
View File

@ -0,0 +1,3 @@
// @flow
export const meta = window.navigator.platform === 'MacIntel' ? '⌘' : 'Ctrl';

View File

@ -18,6 +18,7 @@ type AlignValues =
type Props = { type Props = {
column?: ?boolean, column?: ?boolean,
shrink?: ?boolean,
align?: AlignValues, align?: AlignValues,
justify?: JustifyValues, justify?: JustifyValues,
auto?: ?boolean, auto?: ?boolean,
@ -36,6 +37,7 @@ const Container = styled.div`
flex-direction: ${({ column }) => (column ? 'column' : 'row')}; flex-direction: ${({ column }) => (column ? 'column' : 'row')};
align-items: ${({ align }) => align}; align-items: ${({ align }) => align};
justify-content: ${({ justify }) => justify}; justify-content: ${({ justify }) => justify};
flex-shrink: ${({ shrink }) => (shrink ? 1 : 0)};
min-height: 0; min-height: 0;
min-width: 0; min-width: 0;
`; `;