feat: Separate title from body (#1216)
* first pass at updating all Time components each second * fix a couple date variable typos * use class style state management instead of hooks * wip: Separate title from body * address feedback * test: Remove unused test * feat: You in publishing info language fix: Removal of secondary headings * After much deliberation… a migration is needed for this to be reliable * fix: Export to work with new title structure * fix: Untitled * fix: Consistent spacing of first editor node * fix: Emoji in title handling * fix: Time component not updating for new props * chore: Add createdAt case * fix: Conflict after merging new TOC * PR feedback * lint * fix: Heading level adjustment Co-authored-by: Taylor Lapeyre <taylorlapeyre@gmail.com>
This commit is contained in:
@@ -1,19 +1,32 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { inject, observer } from 'mobx-react';
|
||||
import Editor from 'components/Editor';
|
||||
import PublishingInfo from 'components/PublishingInfo';
|
||||
import ClickablePadding from 'components/ClickablePadding';
|
||||
import Flex from 'shared/components/Flex';
|
||||
import parseTitle from 'shared/utils/parseTitle';
|
||||
import ViewsStore from 'stores/ViewsStore';
|
||||
import Document from 'models/Document';
|
||||
import plugins from './plugins';
|
||||
|
||||
type Props = {|
|
||||
defaultValue?: string,
|
||||
onChangeTitle: (event: SyntheticInputEvent<>) => void,
|
||||
title: string,
|
||||
defaultValue: string,
|
||||
document: Document,
|
||||
views: ViewsStore,
|
||||
isDraft: boolean,
|
||||
readOnly?: boolean,
|
||||
|};
|
||||
|
||||
@observer
|
||||
class DocumentEditor extends React.Component<Props> {
|
||||
editor: ?Editor;
|
||||
|
||||
componentDidMount() {
|
||||
if (!this.props.defaultValue) {
|
||||
if (this.props.title) {
|
||||
setImmediate(this.focusAtStart);
|
||||
}
|
||||
}
|
||||
@@ -30,22 +43,82 @@ class DocumentEditor extends React.Component<Props> {
|
||||
}
|
||||
};
|
||||
|
||||
handleTitleKeyDown = (event: SyntheticKeyboardEvent<>) => {
|
||||
if (event.key === 'Enter' || event.key === 'Tab') {
|
||||
event.preventDefault();
|
||||
this.focusAtStart();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { readOnly } = this.props;
|
||||
const {
|
||||
views,
|
||||
document,
|
||||
title,
|
||||
onChangeTitle,
|
||||
isDraft,
|
||||
readOnly,
|
||||
} = this.props;
|
||||
const totalViews = views.countForDocument(document.id);
|
||||
const { emoji } = parseTitle(title);
|
||||
const startsWithEmojiAndSpace = !!(
|
||||
emoji && title.match(new RegExp(`^${emoji}\\s`))
|
||||
);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Flex column>
|
||||
<Title
|
||||
type="text"
|
||||
onChange={onChangeTitle}
|
||||
onKeyDown={this.handleTitleKeyDown}
|
||||
placeholder="Start with a title…"
|
||||
value={!title && readOnly ? 'Untitled' : title}
|
||||
offsetLeft={startsWithEmojiAndSpace}
|
||||
readOnly={readOnly}
|
||||
autoFocus={!title}
|
||||
/>
|
||||
<Meta document={document}>
|
||||
{totalViews && !isDraft ? (
|
||||
<React.Fragment>
|
||||
· Viewed{' '}
|
||||
{totalViews === 1 ? 'once' : `${totalViews} times`}
|
||||
</React.Fragment>
|
||||
) : null}
|
||||
</Meta>
|
||||
<Editor
|
||||
ref={ref => (this.editor = ref)}
|
||||
autoFocus={!this.props.defaultValue}
|
||||
autoFocus={title && !this.props.defaultValue}
|
||||
placeholder="…the rest is up to you"
|
||||
plugins={plugins}
|
||||
grow
|
||||
{...this.props}
|
||||
/>
|
||||
{!readOnly && <ClickablePadding onClick={this.focusAtEnd} grow />}
|
||||
</React.Fragment>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DocumentEditor;
|
||||
const Meta = styled(PublishingInfo)`
|
||||
margin: -12px 0 2em 0;
|
||||
font-size: 14px;
|
||||
`;
|
||||
|
||||
const Title = styled('input')`
|
||||
line-height: 1.25;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
margin-left: ${props => (props.offsetLeft ? '-1.2em' : 0)};
|
||||
color: ${props => props.theme.text};
|
||||
font-size: 2.25em;
|
||||
font-weight: 500;
|
||||
outline: none;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
|
||||
&::placeholder {
|
||||
color: ${props => props.theme.placeholder};
|
||||
}
|
||||
`;
|
||||
|
||||
export default inject('views')(DocumentEditor);
|
||||
|
||||
Reference in New Issue
Block a user