Move star out of editor into documentpreview (#174)

* Move star out of editor into documentpreview

* 💚
This commit is contained in:
Tom Moor
2017-08-02 20:45:09 -07:00
committed by GitHub
parent 09b0f9f860
commit ca35cee841
7 changed files with 61 additions and 70 deletions

View File

@ -1,10 +1,12 @@
// @flow // @flow
import React, { Component } from 'react'; import React, { Component } from 'react';
import { observer } from 'mobx-react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import Document from 'models/Document'; import Document from 'models/Document';
import styled from 'styled-components'; import styled from 'styled-components';
import { color } from 'styles/constants'; import { color } from 'styles/constants';
import PublishingInfo from 'components/PublishingInfo'; import PublishingInfo from 'components/PublishingInfo';
import StarIcon from 'components/Icon/StarIcon';
type Props = { type Props = {
document: Document, document: Document,
@ -13,10 +15,27 @@ type Props = {
innerRef?: Function, innerRef?: Function,
}; };
const StyledStar = styled(StarIcon)`
top: 2px;
position: relative;
margin-left: 4px;
opacity: ${props => (props.solid ? 1 : 0.25)};
transition: opacity 100ms ease-in-out;
&:hover {
opacity: 1;
}
svg {
width: 1em;
height: 1em;
}
`;
const DocumentLink = styled(Link)` const DocumentLink = styled(Link)`
display: block; display: block;
margin: 0 -16px; margin: 0 -16px;
padding: 16px; padding: 10px 16px;
border-radius: 8px; border-radius: 8px;
border: 2px solid transparent; border: 2px solid transparent;
max-height: 50vh; max-height: 50vh;
@ -37,18 +56,36 @@ const DocumentLink = styled(Link)`
h3 { h3 {
margin-top: 0; margin-top: 0;
margin-bottom: .25em;
} }
`; `;
class DocumentPreview extends Component { @observer class DocumentPreview extends Component {
props: Props; props: Props;
star = (ev: SyntheticEvent) => {
ev.preventDefault();
ev.stopPropagation();
this.props.document.star();
};
unstar = (ev: SyntheticEvent) => {
ev.preventDefault();
ev.stopPropagation();
this.props.document.unstar();
};
render() { render() {
const { document, showCollection, innerRef, ...rest } = this.props; const { document, showCollection, innerRef, ...rest } = this.props;
return ( return (
<DocumentLink to={document.url} innerRef={innerRef} {...rest}> <DocumentLink to={document.url} innerRef={innerRef} {...rest}>
<h3>{document.title}</h3> <h3>
{document.title}
{document.starred
? <a onClick={this.unstar}><StyledStar solid /></a>
: <a onClick={this.star}><StyledStar /></a>}
</h3>
<PublishingInfo <PublishingInfo
document={document} document={document}
collection={showCollection ? document.collection : undefined} collection={showCollection ? document.collection : undefined}

View File

@ -1,6 +1,5 @@
// @flow // @flow
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { Editor, Plain } from 'slate'; import { Editor, Plain } from 'slate';
import keydown from 'react-keydown'; import keydown from 'react-keydown';
@ -24,11 +23,8 @@ type Props = {
onChange: Function, onChange: Function,
onSave: Function, onSave: Function,
onCancel: Function, onCancel: Function,
onStar: Function,
onUnstar: Function,
onImageUploadStart: Function, onImageUploadStart: Function,
onImageUploadStop: Function, onImageUploadStop: Function,
starred: boolean,
emoji: string, emoji: string,
readOnly: boolean, readOnly: boolean,
heading?: ?React.Element<*>, heading?: ?React.Element<*>,
@ -52,10 +48,7 @@ type KeyData = {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
this.schema = createSchema({ this.schema = createSchema();
onStar: props.onStar,
onUnstar: props.onUnstar,
});
this.plugins = createPlugins({ this.plugins = createPlugins({
onImageUploadStart: props.onImageUploadStart, onImageUploadStart: props.onImageUploadStart,
onImageUploadStop: props.onImageUploadStop, onImageUploadStop: props.onImageUploadStop,
@ -84,10 +77,6 @@ type KeyData = {
} }
} }
getChildContext() {
return { starred: this.props.starred };
}
onChange = (state: State) => { onChange = (state: State) => {
this.setState({ state }); this.setState({ state });
}; };
@ -207,7 +196,6 @@ type KeyData = {
</HeaderContainer> </HeaderContainer>
<Toolbar state={this.state.state} onChange={this.onChange} /> <Toolbar state={this.state.state} onChange={this.onChange} />
<Editor <Editor
key={this.props.starred}
ref={ref => (this.editor = ref)} ref={ref => (this.editor = ref)}
placeholder="Start with a title…" placeholder="Start with a title…"
bodyPlaceholder="Insert witty platitude here" bodyPlaceholder="Insert witty platitude here"
@ -232,10 +220,6 @@ type KeyData = {
}; };
} }
MarkdownEditor.childContextTypes = {
starred: PropTypes.bool,
};
const MaxWidth = styled(Flex)` const MaxWidth = styled(Flex)`
max-width: 50em; max-width: 50em;
height: 100%; height: 100%;

View File

@ -1,11 +1,9 @@
// @flow // @flow
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { Document } from 'slate'; import { Document } from 'slate';
import styled from 'styled-components';
import _ from 'lodash'; import _ from 'lodash';
import slug from 'slug'; import slug from 'slug';
import StarIcon from 'components/Icon/StarIcon';
import type { Node, Editor } from '../types'; import type { Node, Editor } from '../types';
import styles from '../Editor.scss'; import styles from '../Editor.scss';
@ -14,46 +12,22 @@ type Props = {
placeholder?: boolean, placeholder?: boolean,
parent: Node, parent: Node,
node: Node, node: Node,
onStar?: Function,
onUnstar?: Function,
editor: Editor, editor: Editor,
readOnly: boolean, readOnly: boolean,
component?: string, component?: string,
}; };
type Context = {
starred?: boolean,
};
const Wrapper = styled.div` const Wrapper = styled.div`
display: inline;
margin-left: ${props => (props.hasEmoji ? '-1.2em' : 0)} margin-left: ${props => (props.hasEmoji ? '-1.2em' : 0)}
`; `;
const StyledStar = styled(StarIcon)` function Heading(props: Props) {
top: 3px;
position: relative;
margin-left: 4px;
opacity: ${props => (props.solid ? 1 : 0.25)};
transition: opacity 100ms ease-in-out;
&:hover {
opacity: 1;
}
svg {
width: 28px;
height: 28px;
}
`;
function Heading(props: Props, { starred }: Context) {
const { const {
parent, parent,
placeholder, placeholder,
node, node,
editor, editor,
onStar,
onUnstar,
readOnly, readOnly,
children, children,
component = 'h1', component = 'h1',
@ -62,8 +36,7 @@ function Heading(props: Props, { starred }: Context) {
const firstHeading = parentIsDocument && parent.nodes.first() === node; const firstHeading = parentIsDocument && parent.nodes.first() === node;
const showPlaceholder = placeholder && firstHeading && !node.text; const showPlaceholder = placeholder && firstHeading && !node.text;
const slugish = _.escape(`${component}-${slug(node.text)}`); const slugish = _.escape(`${component}-${slug(node.text)}`);
const showStar = readOnly && !!onStar; const showHash = readOnly && !!slugish;
const showHash = readOnly && !!slugish && !showStar;
const Component = component; const Component = component;
const emoji = editor.props.emoji || ''; const emoji = editor.props.emoji || '';
const title = node.text.trim(); const title = node.text.trim();
@ -79,14 +52,8 @@ function Heading(props: Props, { starred }: Context) {
</span>} </span>}
{showHash && {showHash &&
<a name={slugish} className={styles.anchor} href={`#${slugish}`}>#</a>} <a name={slugish} className={styles.anchor} href={`#${slugish}`}>#</a>}
{showStar && starred && <a onClick={onUnstar}><StyledStar solid /></a>}
{showStar && !starred && <a onClick={onStar}><StyledStar /></a>}
</Component> </Component>
); );
} }
Heading.contextTypes = {
starred: PropTypes.bool,
};
export default Heading; export default Heading;

View File

@ -9,12 +9,7 @@ import Paragraph from './components/Paragraph';
import type { Props, Node, Transform } from './types'; import type { Props, Node, Transform } from './types';
import styles from './Editor.scss'; import styles from './Editor.scss';
type Options = { const createSchema = () => {
onStar: Function,
onUnstar: Function,
};
const createSchema = ({ onStar, onUnstar }: Options) => {
return { return {
marks: { marks: {
bold: (props: Props) => <strong>{props.children}</strong>, bold: (props: Props) => <strong>{props.children}</strong>,
@ -44,9 +39,7 @@ const createSchema = ({ onStar, onUnstar }: Options) => {
image: Image, image: Image,
link: Link, link: Link,
'list-item': ListItem, 'list-item': ListItem,
heading1: (props: Props) => ( heading1: (props: Props) => <Heading placeholder {...props} />,
<Heading placeholder onStar={onStar} onUnstar={onUnstar} {...props} />
),
heading2: (props: Props) => <Heading component="h2" {...props} />, heading2: (props: Props) => <Heading component="h2" {...props} />,
heading3: (props: Props) => <Heading component="h3" {...props} />, heading3: (props: Props) => <Heading component="h3" {...props} />,
heading4: (props: Props) => <Heading component="h4" {...props} />, heading4: (props: Props) => <Heading component="h4" {...props} />,

View File

@ -26,6 +26,7 @@ const SidebarCollectionList = observer(({ history, collections }: Props) => {
<Header>Collections</Header> <Header>Collections</Header>
{collections.data.map(collection => ( {collections.data.map(collection => (
<DropToImport <DropToImport
key={collection.id}
history={history} history={history}
collectionId={collection.id} collectionId={collection.id}
activeStyle={activeStyle} activeStyle={activeStyle}

View File

@ -209,9 +209,6 @@ type Props = {
onChange={this.onChange} onChange={this.onChange}
onSave={this.onSave} onSave={this.onSave}
onCancel={this.onCancel} onCancel={this.onCancel}
onStar={document.star}
onUnstar={document.unstar}
starred={document.starred}
heading={this.renderHeading(!!isEditing)} heading={this.renderHeading(!!isEditing)}
readOnly={!isEditing} readOnly={!isEditing}
/> />

View File

@ -40,7 +40,19 @@ router.post('documents.viewed', auth(), pagination(), async ctx => {
const views = await View.findAll({ const views = await View.findAll({
where: { userId: user.id }, where: { userId: user.id },
order: [[sort, direction]], order: [[sort, direction]],
include: [{ model: Document, required: true }], include: [
{
model: Document,
include: [
{
model: Star,
as: 'starred',
where: { userId: user.id },
required: false,
},
],
},
],
offset: ctx.state.pagination.offset, offset: ctx.state.pagination.offset,
limit: ctx.state.pagination.limit, limit: ctx.state.pagination.limit,
}); });