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:
@ -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;
|
||||||
|
@ -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)
|
||||||
|
);
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
>
|
>
|
||||||
|
@ -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>
|
||||||
|
@ -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
3
app/utils/keyboard.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
export const meta = window.navigator.platform === 'MacIntel' ? '⌘' : 'Ctrl';
|
@ -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;
|
||||||
`;
|
`;
|
||||||
|
Reference in New Issue
Block a user