Upgrade prettier

This commit is contained in:
Tom Moor
2017-11-10 14:14:30 -08:00
parent c737b613e4
commit ab13f51d5d
79 changed files with 780 additions and 533 deletions

View File

@ -10,7 +10,8 @@ type Props = {
type?: 'info' | 'success' | 'warning' | 'danger' | 'offline',
};
@observer class Alert extends React.Component {
@observer
class Alert extends React.Component {
props: Props;
defaultProps = {
type: 'info',

View File

@ -29,35 +29,35 @@ const RealButton = styled.button`
svg {
position: relative;
top: .05em;
top: 0.05em;
}
${props => props.light && `
${props =>
props.light &&
`
color: ${color.text};
background: ${lighten(0.08, color.slateLight)};
&:hover {
background: ${color.slateLight};
}
`}
${props => props.neutral && `
`} ${props =>
props.neutral &&
`
background: ${color.slate};
&:hover {
background: ${darken(0.05, color.slate)};
}
`}
${props => props.danger && `
`} ${props =>
props.danger &&
`
background: ${color.danger};
&:hover {
background: ${darken(0.05, color.danger)};
}
`}
&:disabled {
`} &:disabled {
background: ${color.slateLight};
cursor: default;
}
@ -68,7 +68,7 @@ const Label = styled.span`
white-space: nowrap;
text-overflow: ellipsis;
${props => props.hasIcon && 'padding-left: 2px;'}
${props => props.hasIcon && 'padding-left: 2px;'};
`;
const Inner = styled.span`
@ -78,7 +78,9 @@ const Inner = styled.span`
justify-content: center;
align-items: center;
${props => props.hasIcon && (props.small ? 'padding-left: 6px;' : 'padding-left: 10px;')}
${props =>
props.hasIcon &&
(props.small ? 'padding-left: 6px;' : 'padding-left: 10px;')};
`;
export type Props = {

View File

@ -19,9 +19,7 @@ const Content = styled.div`
const CenteredContent = ({ children, ...rest }: Props) => {
return (
<Container {...rest}>
<Content>
{children}
</Content>
<Content>{children}</Content>
</Container>
);
};

View File

@ -25,7 +25,8 @@ type Props = {
value?: string,
};
@observer class ColorPicker extends React.Component {
@observer
class ColorPicker extends React.Component {
props: Props;
@observable selectedColor: string = colors[0];
@ -52,26 +53,30 @@ type Props = {
);
};
@computed get customColor(): string {
@computed
get customColor(): string {
return this.customColorValue &&
validateColorHex(`#${this.customColorValue}`)
? `#${this.customColorValue}`
: colors[0];
}
@action setColor = (color: string) => {
@action
setColor = (color: string) => {
this.selectedColor = color;
this.customColorSelected = false;
this.fireCallback();
};
@action focusOnCustomColor = (event: SyntheticEvent) => {
@action
focusOnCustomColor = (event: SyntheticEvent) => {
this.selectedColor = '';
this.customColorSelected = true;
this.fireCallback();
};
@action setCustomColor = (event: SyntheticEvent) => {
@action
setCustomColor = (event: SyntheticEvent) => {
let target = event.target;
if (target instanceof HTMLInputElement) {
const color = target.value;
@ -137,9 +142,7 @@ const SwatchOutset = styled(Flex)`
border: 2px solid ${({ active, color }) => (active ? color : 'transparent')};
border-radius: 2px;
background: ${({ color }) => color};
${({ onClick }) => onClick && `cursor: pointer;`}
&:last-child {
${({ onClick }) => onClick && `cursor: pointer;`} &:last-child {
margin-right: 0;
}
`;

View File

@ -4,7 +4,11 @@ import styled from 'styled-components';
import Flex from 'shared/components/Flex';
const Divider = () => {
return <Flex auto justify="center"><Content /></Flex>;
return (
<Flex auto justify="center">
<Content />
</Flex>
);
};
const Content = styled.span`

View File

@ -49,7 +49,7 @@ const DocumentLink = styled(Link)`
outline: none;
${StyledStar} {
opacity: .5;
opacity: 0.5;
&:hover {
opacity: 1;
@ -63,11 +63,12 @@ const DocumentLink = styled(Link)`
h3 {
margin-top: 0;
margin-bottom: .25em;
margin-bottom: 0.25em;
}
`;
@observer class DocumentPreview extends Component {
@observer
class DocumentPreview extends Component {
props: Props;
star = (ev: SyntheticEvent) => {
@ -89,13 +90,15 @@ const DocumentLink = styled(Link)`
<DocumentLink to={document.url} innerRef={innerRef} {...rest}>
<h3>
{document.title}
{document.starred
? <a onClick={this.unstar}>
<StyledStar solid />
</a>
: <a onClick={this.star}>
<StyledStar />
</a>}
{document.starred ? (
<a onClick={this.unstar}>
<StyledStar solid />
</a>
) : (
<a onClick={this.star}>
<StyledStar />
</a>
)}
</h3>
<PublishingInfo
document={document}

View File

@ -36,24 +36,24 @@ class PublishingInfo extends Component {
return (
<Container align="center">
{createdAt === updatedAt
? <span>
{createdBy.name}
{createdAt === updatedAt ? (
<span>
{createdBy.name} published {moment(createdAt).fromNow()}
</span>
) : (
<span>
{updatedBy.name}
<Modified highlight={modifiedSinceViewed}>
{' '}
published
{' '}
{moment(createdAt).fromNow()}
</span>
: <span>
{updatedBy.name}
<Modified highlight={modifiedSinceViewed}>
{' '}
modified
{' '}
{moment(updatedAt).fromNow()}
</Modified>
</span>}
{collection && <span>&nbsp;in <strong>{collection.name}</strong></span>}
modified {moment(updatedAt).fromNow()}
</Modified>
</span>
)}
{collection && (
<span>
&nbsp;in <strong>{collection.name}</strong>
</span>
)}
</Container>
);
}

View File

@ -14,7 +14,8 @@ class DocumentViewersStore {
@observable viewers: Array<View>;
@observable isFetching: boolean;
@action fetchViewers = async () => {
@action
fetchViewers = async () => {
this.isFetching = true;
try {

View File

@ -25,7 +25,8 @@ type Props = {
count: number,
};
@observer class DocumentViews extends Component {
@observer
class DocumentViews extends Component {
anchor: HTMLElement;
store: DocumentViewersStore;
props: Props;
@ -55,19 +56,16 @@ type Props = {
return (
<Container align="center">
<a ref={this.setRef} onClick={this.openPopover}>
Viewed
{' '}
{this.props.count}
{' '}
{this.props.count === 1 ? 'time' : 'times'}
Viewed {this.props.count} {this.props.count === 1 ? 'time' : 'times'}
</a>
{this.state.opened &&
{this.state.opened && (
<Popover anchor={this.anchor} onClose={this.closePopover}>
<DocumentViewers
onMount={this.store.fetchViewers}
viewers={this.store.viewers}
/>
</Popover>}
</Popover>
)}
</Container>
);
}

View File

@ -40,8 +40,7 @@ class DocumentViewers extends Component {
{map(this.props.viewers, view => (
<li key={view.user.id}>
<Flex align="center">
<Avatar src={view.user.avatarUrl} />
{' '}
<Avatar src={view.user.avatarUrl} />{' '}
<UserName>{view.user.name}</UserName>
</Flex>
</li>

View File

@ -17,7 +17,8 @@ type Props = {
style?: Object,
};
@observer class DropdownMenu extends Component {
@observer
class DropdownMenu extends Component {
props: Props;
@observable top: number;
@observable left: number;
@ -93,7 +94,8 @@ const Menu = styled.div`
border-radius: 2px;
min-width: 160px;
overflow: hidden;
box-shadow: 0 0 0 1px rgba(0,0,0,.05), 0 4px 8px rgba(0,0,0,.08), 0 2px 4px rgba(0,0,0,.08);
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05), 0 4px 8px rgba(0, 0, 0, 0.08),
0 2px 4px rgba(0, 0, 0, 0.08);
`;
export default DropdownMenu;

View File

@ -11,11 +11,7 @@ const DropdownMenuItem = ({
onClick?: SyntheticEvent => void,
children?: React.Element<any>,
}) => {
return (
<MenuItem onClick={onClick}>
{children}
</MenuItem>
);
return <MenuItem onClick={onClick}>{children}</MenuItem>;
};
const MenuItem = styled(Flex)`

View File

@ -34,7 +34,8 @@ type KeyData = {
key: string,
};
@observer class MarkdownEditor extends Component {
@observer
class MarkdownEditor extends Component {
props: Props;
editor: EditorType;
schema: Object;
@ -193,14 +194,16 @@ type KeyData = {
<MaxWidth column auto>
<Header onClick={this.focusAtStart} readOnly={readOnly} />
<Contents state={this.editorState} />
{!readOnly &&
<Toolbar state={this.editorState} onChange={this.onChange} />}
{!readOnly &&
{!readOnly && (
<Toolbar state={this.editorState} onChange={this.onChange} />
)}
{!readOnly && (
<BlockInsert
state={this.editorState}
onChange={this.onChange}
onInsertImage={this.insertImageFile}
/>}
/>
)}
<StyledEditor
innerRef={ref => (this.editor = ref)}
placeholder="Start with a title…"
@ -234,7 +237,7 @@ const Header = styled(Flex)`
height: 60px;
flex-shrink: 0;
align-items: flex-end;
${({ readOnly }) => !readOnly && 'cursor: text;'}
${({ readOnly }) => !readOnly && 'cursor: text;'};
`;
const StyledEditor = styled(Editor)`
@ -326,7 +329,8 @@ const StyledEditor = styled(Editor)`
padding: 5px 20px 5px 0;
}
b, strong {
b,
strong {
font-weight: 600;
}
`;

View File

@ -126,20 +126,23 @@ const Trigger = styled.div`
z-index: 1;
opacity: 0;
background-color: ${color.white};
transition: opacity 150ms cubic-bezier(0.175, 0.885, 0.32, 1.275), transform 150ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
transition: opacity 150ms cubic-bezier(0.175, 0.885, 0.32, 1.275),
transform 150ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
line-height: 0;
margin-left: -10px;
box-shadow: inset 0 0 0 2px ${color.slate};
border-radius: 100%;
transform: scale(.9);
transform: scale(0.9);
cursor: pointer;
&:hover {
background-color: ${color.smokeDark};
}
${({ active }) => active && `
${({ active }) =>
active &&
`
transform: scale(1);
opacity: .9;
`}
`};
`;

View File

@ -16,7 +16,7 @@ const Container = styled.div`
padding-top: 50px;
cursor: ${({ onClick }) => (onClick ? 'text' : 'default')};
${({ grow }) => grow && `flex-grow: 1;`}
${({ grow }) => grow && `flex-grow: 1;`};
`;
export default ClickablePadding;

View File

@ -12,16 +12,14 @@ export default function Code({ children, node, readOnly, attributes }: Props) {
<Container {...attributes}>
{readOnly && <CopyButton text={node.text} />}
<Pre className={`language-${language}`}>
<code className={`language-${language}`}>
{children}
</code>
<code className={`language-${language}`}>{children}</code>
</Pre>
</Container>
);
}
const Pre = styled.pre`
padding: .5em 1em;
padding: 0.5em 1em;
background: ${color.smokeLight};
border-radius: 4px;
border: 1px solid ${color.smokeDark};

View File

@ -12,7 +12,8 @@ type Props = {
state: State,
};
@observer class Contents extends Component {
@observer
class Contents extends Component {
props: Props;
@observable activeHeading: ?string;

View File

@ -6,7 +6,8 @@ import { color } from 'shared/styles/constants';
import styled from 'styled-components';
import CopyToClipboard from 'components/CopyToClipboard';
@observer class CopyButton extends Component {
@observer
class CopyButton extends Component {
@observable copied: boolean = false;
copiedTimeout: ?number;

View File

@ -41,26 +41,29 @@ function Heading(props: Props) {
return (
<Component {...attributes} id={slugish}>
<Wrapper hasEmoji={startsWithEmojiAndSpace}>
{children}
</Wrapper>
{showPlaceholder &&
<Wrapper hasEmoji={startsWithEmojiAndSpace}>{children}</Wrapper>
{showPlaceholder && (
<Placeholder contentEditable={false}>
{editor.props.placeholder}
</Placeholder>}
{showHash && <Anchor name={slugish} href={`#${slugish}`}>#</Anchor>}
</Placeholder>
)}
{showHash && (
<Anchor name={slugish} href={`#${slugish}`}>
#
</Anchor>
)}
</Component>
);
}
const Wrapper = styled.div`
display: inline;
margin-left: ${(props: Props) => (props.hasEmoji ? '-1.2em' : 0)}
margin-left: ${(props: Props) => (props.hasEmoji ? '-1.2em' : 0)};
`;
const Anchor = styled.a`
visibility: hidden;
padding-left: .25em;
padding-left: 0.25em;
color: #dedede;
&:hover {

View File

@ -11,10 +11,11 @@ function HorizontalRule(props: Props) {
}
const StyledHr = styled.hr`
padding-top: .75em;
padding-top: 0.75em;
margin: 0;
border: 0;
border-bottom: 1px solid ${props => (props.active ? color.slate : color.slateLight)};
border-bottom: 1px solid
${props => (props.active ? color.slate : color.slateLight)};
`;
export default HorizontalRule;

View File

@ -35,26 +35,28 @@ class Image extends Component {
return (
<CenteredImage>
{!readOnly
? <StyledImg
{...attributes}
src={src}
alt={caption}
active={active}
loading={loading}
/>
: <ImageZoom
image={{
src,
alt: caption,
style: {
maxWidth: '100%',
},
...attributes,
}}
shouldRespectMaxDimension
/>}
{showCaption &&
{!readOnly ? (
<StyledImg
{...attributes}
src={src}
alt={caption}
active={active}
loading={loading}
/>
) : (
<ImageZoom
image={{
src,
alt: caption,
style: {
maxWidth: '100%',
},
...attributes,
}}
shouldRespectMaxDimension
/>
)}
{showCaption && (
<Caption
type="text"
placeholder="Write a caption"
@ -64,7 +66,8 @@ class Image extends Component {
contentEditable={false}
disabled={readOnly}
tabIndex={-1}
/>}
/>
)}
</CenteredImage>
);
}

View File

@ -3,7 +3,7 @@ import styled from 'styled-components';
import { color } from 'shared/styles/constants';
const InlineCode = styled.code`
padding: .25em;
padding: 0.25em;
background: ${color.smoke};
border-radius: 4px;
border: 1px solid ${color.smokeDark};

View File

@ -31,8 +31,16 @@ export default function Link({ attributes, node, children, readOnly }: Props) {
const path = getPathFromUrl(href);
if (isOutlineUrl(href) && readOnly) {
return <InternalLink {...attributes} to={path}>{children}</InternalLink>;
return (
<InternalLink {...attributes} to={path}>
{children}
</InternalLink>
);
} else {
return <a {...attributes} href={href} target="_blank">{children}</a>;
return (
<a {...attributes} href={href} target="_blank">
{children}
</a>
);
}
}

View File

@ -25,10 +25,11 @@ export default function Link({
return (
<p {...attributes}>
{children}
{showPlaceholder &&
{showPlaceholder && (
<Placeholder contentEditable={false}>
{editor.props.bodyPlaceholder}
</Placeholder>}
</Placeholder>
)}
</p>
);
}

View File

@ -7,5 +7,5 @@ export default styled.span`
visibility: hidden;
pointer-events: none;
user-select: none;
color: #B1BECC;
color: #b1becc;
`;

View File

@ -170,7 +170,7 @@ const Bar = styled(Flex)`
&:before,
&:after {
content: "";
content: '';
position: absolute;
left: -100%;
width: 100%;

View File

@ -99,7 +99,9 @@ export default class Toolbar extends Component {
const left =
rect.left + window.scrollX - this.menu.offsetWidth / 2 + rect.width / 2;
data.top = `${Math.round(rect.top + window.scrollY - this.menu.offsetHeight)}px`;
data.top = `${Math.round(
rect.top + window.scrollY - this.menu.offsetHeight
)}px`;
data.left = `${Math.round(Math.max(padding, left))}px`;
this.setState(data);
}
@ -120,17 +122,15 @@ export default class Toolbar extends Component {
return (
<Portal>
<Menu active={this.state.active} innerRef={this.setRef} style={style}>
{link &&
<LinkToolbar
{...this.props}
link={link}
onBlur={this.handleBlur}
/>}
{!link &&
{link && (
<LinkToolbar {...this.props} link={link} onBlur={this.handleBlur} />
)}
{!link && (
<FormattingToolbar
onCreateLink={this.handleFocus}
{...this.props}
/>}
/>
)}
</Menu>
</Portal>
);
@ -144,16 +144,19 @@ const Menu = styled.div`
top: -10000px;
left: -10000px;
opacity: 0;
background-color: #2F3336;
background-color: #2f3336;
border-radius: 4px;
transform: scale(.95);
transition: opacity 150ms cubic-bezier(0.175, 0.885, 0.32, 1.275), transform 150ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
transform: scale(0.95);
transition: opacity 150ms cubic-bezier(0.175, 0.885, 0.32, 1.275),
transform 150ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
line-height: 0;
height: 40px;
min-width: 260px;
${({ active }) => active && `
${({ active }) =>
active &&
`
transform: translateY(-6px) scale(1);
opacity: 1;
`}
`};
`;

View File

@ -14,7 +14,9 @@ type Props = {
function DocumentResult({ document, ...rest }: Props) {
return (
<ListItem {...rest} href="">
<i><NextIcon light /></i>
<i>
<NextIcon light />
</i>
{document.title}
</ListItem>
);

View File

@ -42,7 +42,10 @@ class FormattingToolbar extends Component {
ev.preventDefault();
let { state } = this.props;
state = state.transform().toggleMark(type).apply();
state = state
.transform()
.toggleMark(type)
.apply();
this.props.onChange(state);
};
@ -50,7 +53,10 @@ class FormattingToolbar extends Component {
ev.preventDefault();
let { state } = this.props;
state = state.transform().setBlock(type).apply();
state = state
.transform()
.setBlock(type)
.apply();
this.props.onChange(state);
};
@ -59,7 +65,10 @@ class FormattingToolbar extends Component {
ev.stopPropagation();
let { state } = this.props;
const data = { href: '' };
state = state.transform().wrapInline({ type: 'link', data }).apply();
state = state
.transform()
.wrapInline({ type: 'link', data })
.apply();
this.props.onChange(state);
this.props.onCreateLink();
};
@ -109,8 +118,8 @@ class FormattingToolbar extends Component {
const Separator = styled.div`
height: 100%;
width: 1px;
background: #FFF;
opacity: .2;
background: #fff;
opacity: 0.2;
display: inline-block;
margin-left: 10px;
`;

View File

@ -39,7 +39,8 @@ class LinkToolbar extends Component {
this.isEditing = !!this.props.link.data.get('href');
}
@action search = async () => {
@action
search = async () => {
this.isFetching = true;
if (this.searchTerm) {
@ -144,15 +145,16 @@ class LinkToolbar extends Component {
onChange={this.onChange}
autoFocus
/>
{this.isEditing &&
{this.isEditing && (
<ToolbarButton onMouseDown={this.openLink}>
<OpenIcon light />
</ToolbarButton>}
</ToolbarButton>
)}
<ToolbarButton onMouseDown={this.removeLink}>
{this.isEditing ? <TrashIcon light /> : <CloseIcon light />}
</ToolbarButton>
</LinkEditor>
{hasResults &&
{hasResults && (
<SearchResults>
<ArrowKeyNavigation
mode={ArrowKeyNavigation.mode.VERTICAL}
@ -165,7 +167,8 @@ class LinkToolbar extends Component {
return (
<DocumentResult
innerRef={ref =>
index === 0 && this.setFirstDocumentRef(ref)}
index === 0 && this.setFirstDocumentRef(ref)
}
document={document}
key={document.id}
onClick={ev => this.selectDocument(ev, document)}
@ -173,14 +176,15 @@ class LinkToolbar extends Component {
);
})}
</ArrowKeyNavigation>
</SearchResults>}
</SearchResults>
)}
</span>
);
}
}
const SearchResults = styled.div`
background: #2F3336;
background: #2f3336;
position: absolute;
top: 100%;
width: 100%;
@ -199,7 +203,7 @@ const LinkEditor = styled(Flex)`
const Input = styled.input`
font-size: 15px;
background: rgba(255,255,255,.1);
background: rgba(255, 255, 255, 0.1);
border-radius: 2px;
padding: 4px 8px;
border: 0;

View File

@ -12,7 +12,7 @@ export default styled.button`
background: none;
transition: opacity 100ms ease-in-out;
padding: 0;
opacity: .7;
opacity: 0.7;
&:first-child {
margin-left: 0;
@ -22,5 +22,5 @@ export default styled.button`
opacity: 1;
}
${({ active }) => active && 'opacity: 1;'}
${({ active }) => active && 'opacity: 1;'};
`;

View File

@ -37,7 +37,10 @@ export default function KeyboardShortcuts() {
const firstNode = state.document.nodes.first();
if (firstNode === state.startBlock) return;
state = state.transform().toggleMark(type).apply();
state = state
.transform()
.toggleMark(type)
.apply();
return state;
},
};

View File

@ -64,7 +64,10 @@ export default function MarkdownShortcuts() {
}
}
state = transform.extendToStartOf(startBlock).delete().apply();
state = transform
.extendToStartOf(startBlock)
.delete()
.apply();
return state;
}
@ -113,7 +116,10 @@ export default function MarkdownShortcuts() {
lastCodeTagIndex - shortcut.length
);
transform.addMark(mark);
state = transform.collapseToEnd().removeMark(mark).apply();
state = transform
.collapseToEnd()
.removeMark(mark)
.apply();
return state;
}
}
@ -212,7 +218,11 @@ export default function MarkdownShortcuts() {
onTab(ev: SyntheticEvent, state: Object) {
if (state.startBlock.type === 'heading1') {
ev.preventDefault();
return state.transform().splitBlock().setBlock('paragraph').apply();
return state
.transform()
.splitBlock()
.setBlock('paragraph')
.apply();
}
},
@ -253,7 +263,11 @@ export default function MarkdownShortcuts() {
}
ev.preventDefault();
return state.transform().splitBlock().setBlock('paragraph').apply();
return state
.transform()
.splitBlock()
.setBlock('paragraph')
.apply();
},
/**

View File

@ -9,12 +9,14 @@ export default function CheckboxIcon({
}: Props & { checked: boolean }) {
return (
<Icon {...rest}>
{checked
? <path d="M8,5 L16,5 L16,5 C17.6568542,5 19,6.34314575 19,8 L19,16 C19,17.6568542 17.6568542,19 16,19 L8,19 L8,19 C6.34314575,19 5,17.6568542 5,16 L5,8 L5,8 C5,6.34314575 6.34314575,5 8,5 L8,5 Z M10.958729,12.8883948 L9.26824635,10.8598156 C8.91468227,10.4355387 8.28411757,10.3782146 7.85984067,10.7317787 C7.43556378,11.0853428 7.37823971,11.7159075 7.73180379,12.1401844 L10.2318038,15.1401844 C10.6450125,15.6360348 11.4127535,15.616362 11.8000251,15.1 L16.3000251,9.1 C16.6313959,8.6581722 16.5418529,8.03137085 16.1000251,7.7 C15.6581973,7.36862915 15.0313959,7.4581722 14.7000251,7.9 L10.958729,12.8883948 Z" />
: <path
d="M8,5 L16,5 L16,5 C17.6568542,5 19,6.34314575 19,8 L19,16 C19,17.6568542 17.6568542,19 16,19 L8,19 L8,19 C6.34314575,19 5,17.6568542 5,16 L5,8 L5,8 C5,6.34314575 6.34314575,5 8,5 L8,5 Z M8,7 C7.44771525,7 7,7.44771525 7,8 L7,16 C7,16.5522847 7.44771525,17 8,17 L16,17 C16.5522847,17 17,16.5522847 17,16 L17,8 C17,7.44771525 16.5522847,7 16,7 L8,7 Z"
id="path-1"
/>}
{checked ? (
<path d="M8,5 L16,5 L16,5 C17.6568542,5 19,6.34314575 19,8 L19,16 C19,17.6568542 17.6568542,19 16,19 L8,19 L8,19 C6.34314575,19 5,17.6568542 5,16 L5,8 L5,8 C5,6.34314575 6.34314575,5 8,5 L8,5 Z M10.958729,12.8883948 L9.26824635,10.8598156 C8.91468227,10.4355387 8.28411757,10.3782146 7.85984067,10.7317787 C7.43556378,11.0853428 7.37823971,11.7159075 7.73180379,12.1401844 L10.2318038,15.1401844 C10.6450125,15.6360348 11.4127535,15.616362 11.8000251,15.1 L16.3000251,9.1 C16.6313959,8.6581722 16.5418529,8.03137085 16.1000251,7.7 C15.6581973,7.36862915 15.0313959,7.4581722 14.7000251,7.9 L10.958729,12.8883948 Z" />
) : (
<path
d="M8,5 L16,5 L16,5 C17.6568542,5 19,6.34314575 19,8 L19,16 C19,17.6568542 17.6568542,19 16,19 L8,19 L8,19 C6.34314575,19 5,17.6568542 5,16 L5,8 L5,8 C5,6.34314575 6.34314575,5 8,5 L8,5 Z M8,7 C7.44771525,7 7,7.44771525 7,8 L7,16 C7,16.5522847 7.44771525,17 8,17 L16,17 C16.5522847,17 17,16.5522847 17,16 L17,8 C17,7.44771525 16.5522847,7 16,7 L8,7 Z"
id="path-1"
/>
)}
</Icon>
);
}

View File

@ -9,9 +9,11 @@ export default function CollectionIcon({
}: Props & { expanded: boolean }) {
return (
<Icon {...rest}>
{expanded
? <path d="M16.701875,4.16415178 L17,4.14285714 C18.1045695,4.06395932 19,5.02334914 19,6.28571429 L19,17.7142857 C19,18.9766509 18.1045695,19.9360407 17,19.8571429 L16.701875,19.8358482 C16.8928984,19.371917 17,18.8348314 17,18.25 L17,5.75 C17,5.16516859 16.8928984,4.62808299 16.701875,4.16415178 Z M14,3.36363636 C15.1045695,3.16280555 16,4.15126779 16,5.57142857 L16,18.4285714 C16,19.8487322 15.1045695,20.8371945 14,20.6363636 L7,19.3636364 C5.8954305,19.1628055 5,18.1045695 5,17 L5,7 C5,5.8954305 5.8954305,4.83719445 7,4.63636364 L14,3.36363636 Z M7.5,6.67532468 C7.22385763,6.71118732 7,6.97574633 7,7.26623377 L7,16.7337662 C7,17.0242537 7.22385763,17.2888127 7.5,17.3246753 L8.5,17.4545455 C8.77614237,17.4904081 9,17.272365 9,16.9675325 L9,7.03246753 C9,6.72763504 8.77614237,6.5095919 8.5,6.54545455 L7.5,6.67532468 Z" />
: <path d="M7,4 L17,4 C18.1045695,4 19,4.8954305 19,6 L19,18 C19,19.1045695 18.1045695,20 17,20 L7,20 C5.8954305,20 5,19.1045695 5,18 L5,6 L5,6 C5,4.8954305 5.8954305,4 7,4 L7,4 Z M7.5,6 C7.22385763,6 7,6.22385763 7,6.5 L7,17.5 C7,17.7761424 7.22385763,18 7.5,18 L8.5,18 C8.77614237,18 9,17.7761424 9,17.5 L9,6.5 C9,6.22385763 8.77614237,6 8.5,6 L7.5,6 Z" />}
{expanded ? (
<path d="M16.701875,4.16415178 L17,4.14285714 C18.1045695,4.06395932 19,5.02334914 19,6.28571429 L19,17.7142857 C19,18.9766509 18.1045695,19.9360407 17,19.8571429 L16.701875,19.8358482 C16.8928984,19.371917 17,18.8348314 17,18.25 L17,5.75 C17,5.16516859 16.8928984,4.62808299 16.701875,4.16415178 Z M14,3.36363636 C15.1045695,3.16280555 16,4.15126779 16,5.57142857 L16,18.4285714 C16,19.8487322 15.1045695,20.8371945 14,20.6363636 L7,19.3636364 C5.8954305,19.1628055 5,18.1045695 5,17 L5,7 C5,5.8954305 5.8954305,4.83719445 7,4.63636364 L14,3.36363636 Z M7.5,6.67532468 C7.22385763,6.71118732 7,6.97574633 7,7.26623377 L7,16.7337662 C7,17.0242537 7.22385763,17.2888127 7.5,17.3246753 L8.5,17.4545455 C8.77614237,17.4904081 9,17.272365 9,16.9675325 L9,7.03246753 C9,6.72763504 8.77614237,6.5095919 8.5,6.54545455 L7.5,6.67532468 Z" />
) : (
<path d="M7,4 L17,4 C18.1045695,4 19,4.8954305 19,6 L19,18 C19,19.1045695 18.1045695,20 17,20 L7,20 C5.8954305,20 5,19.1045695 5,18 L5,6 L5,6 C5,4.8954305 5.8954305,4 7,4 L7,4 Z M7.5,6 C7.22385763,6 7,6.22385763 7,6.5 L7,17.5 C7,17.7761424 7.22385763,18 7.5,18 L8.5,18 C8.77614237,18 9,17.7761424 9,17.5 L9,6.5 C9,6.22385763 8.77614237,6 8.5,6 L7.5,6 Z" />
)}
</Icon>
);
}

View File

@ -28,9 +28,7 @@ const RealInput = styled.input`
}
`;
const Wrapper = styled.div`
`;
const Wrapper = styled.div``;
export const Outline = styled(Flex)`
display: flex;
@ -44,7 +42,7 @@ export const Outline = styled(Flex)`
font-weight: normal;
&:focus {
border-color: ${color.slate}
border-color: ${color.slate};
}
`;

View File

@ -5,7 +5,8 @@ import { color } from 'shared/styles/constants';
const Key = styled.kbd`
display: inline-block;
padding: 4px 6px;
font: 11px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
font: 11px 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier,
monospace;
line-height: 10px;
color: ${color.text};
vertical-align: middle;

View File

@ -22,7 +22,7 @@ export const Label = styled(Flex)`
font-size: 13px;
font-weight: 500;
text-transform: uppercase;
color: #9FA6AB;
color: #9fa6ab;
letter-spacing: 0.04em;
`;

View File

@ -43,7 +43,8 @@ type Props = {
notifications?: React.Element<any>,
};
@observer class Layout extends React.Component {
@observer
class Layout extends React.Component {
props: Props;
scrollable: ?HTMLDivElement;
@ -117,41 +118,42 @@ type Props = {
<Flex auto>
{auth.authenticated &&
user &&
team &&
<Sidebar column editMode={ui.editMode}>
<AccountMenu
label={
<HeaderBlock user={user} team={team}>
<Avatar src={user.avatarUrl} />
</HeaderBlock>
}
/>
team && (
<Sidebar column editMode={ui.editMode}>
<AccountMenu
label={
<HeaderBlock user={user} team={team}>
<Avatar src={user.avatarUrl} />
</HeaderBlock>
}
/>
<Flex auto column>
<Scrollable innerRef={this.setScrollableRef}>
<LinkSection>
<SidebarLink to="/dashboard" icon={<HomeIcon />}>
Home
</SidebarLink>
<SidebarLink to="/search" icon={<SearchIcon />}>
Search
</SidebarLink>
<SidebarLink to="/starred" icon={<StarredIcon />}>
Starred
</SidebarLink>
</LinkSection>
<LinkSection>
<SidebarCollections
history={this.props.history}
location={this.props.location}
activeDocument={documents.active}
onCreateCollection={this.handleCreateCollection}
activeDocumentRef={this.scrollToActiveDocument}
/>
</LinkSection>
</Scrollable>
</Flex>
</Sidebar>}
<Flex auto column>
<Scrollable innerRef={this.setScrollableRef}>
<LinkSection>
<SidebarLink to="/dashboard" icon={<HomeIcon />}>
Home
</SidebarLink>
<SidebarLink to="/search" icon={<SearchIcon />}>
Search
</SidebarLink>
<SidebarLink to="/starred" icon={<StarredIcon />}>
Starred
</SidebarLink>
</LinkSection>
<LinkSection>
<SidebarCollections
history={this.props.history}
location={this.props.location}
activeDocument={documents.active}
onCreateCollection={this.handleCreateCollection}
activeDocumentRef={this.scrollToActiveDocument}
/>
</LinkSection>
</Scrollable>
</Flex>
</Sidebar>
)}
<Content auto justify="center" editMode={ui.editMode}>
{this.props.children}

View File

@ -43,14 +43,14 @@ const Header = styled(Flex)`
&:active,
&:hover {
background: rgba(0,0,0,.05);
background: rgba(0, 0, 0, 0.05);
}
&::after {
content: "";
content: '';
left: 24px;
right: 24px;
background: rgba(0,0,0,.075);
background: rgba(0, 0, 0, 0.075);
height: 1px;
position: absolute;
bottom: 0;

View File

@ -10,7 +10,8 @@ import DocumentDelete from 'scenes/DocumentDelete';
import KeyboardShortcuts from 'scenes/KeyboardShortcuts';
import Settings from 'scenes/Settings';
@observer class Modals extends Component {
@observer
class Modals extends Component {
props: {
ui: UiStore,
};

View File

@ -31,7 +31,8 @@ type Props = {
ui: UiStore,
};
@observer class SidebarCollections extends Component {
@observer
class SidebarCollections extends Component {
props: Props;
render() {
@ -61,13 +62,14 @@ type Props = {
/>
))}
{collections.isLoaded &&
{collections.isLoaded && (
<SidebarLink
onClick={this.props.onCreateCollection}
icon={<PlusIcon />}
>
New collection
</SidebarLink>}
</SidebarLink>
)}
</Flex>
);
}
@ -82,7 +84,8 @@ type CollectionLinkProps = {
prefetchDocument: (id: string) => Promise<void>,
};
@observer class CollectionLink extends Component {
@observer
class CollectionLink extends Component {
props: CollectionLinkProps;
dropzoneRef;
@ -133,7 +136,7 @@ type CollectionLinkProps = {
</CollectionAction>
</Flex>
{expanded &&
{expanded && (
<Children column>
{collection.documents.map(document => (
<DocumentLink
@ -146,7 +149,8 @@ type CollectionLinkProps = {
depth={0}
/>
))}
</Children>}
</Children>
)}
</SidebarLink>
</StyledDropToImport>
);
@ -172,11 +176,13 @@ const DocumentLink = observer(
}: DocumentLinkProps) => {
const isActiveDocument =
activeDocument && activeDocument.id === document.id;
const showChildren = !!(activeDocument &&
const showChildren = !!(
activeDocument &&
(activeDocument.pathToDocument
.map(entry => entry.id)
.includes(document.id) ||
isActiveDocument));
isActiveDocument)
);
const handleMouseEnter = (event: SyntheticEvent) => {
event.stopPropagation();
@ -200,20 +206,22 @@ const DocumentLink = observer(
to={document.url}
expand={showChildren}
expandedContent={
document.children.length
? <Children column>
{document.children.map(childDocument => (
<DocumentLink
key={childDocument.id}
history={history}
document={childDocument}
activeDocument={activeDocument}
prefetchDocument={prefetchDocument}
depth={depth + 1}
/>
))}
</Children>
: undefined
document.children.length ? (
<Children column>
{document.children.map(childDocument => (
<DocumentLink
key={childDocument.id}
history={history}
document={childDocument}
activeDocument={activeDocument}
prefetchDocument={prefetchDocument}
depth={depth + 1}
/>
))}
</Children>
) : (
undefined
)
}
>
{document.title}
@ -228,10 +236,14 @@ const CollectionAction = styled.a`
position: absolute;
right: 0;
color: ${color.slate};
svg { opacity: .75; }
svg {
opacity: 0.75;
}
&:hover {
svg { opacity: 1; }
svg {
opacity: 1;
}
}
`;

View File

@ -17,7 +17,7 @@ const StyledGoTo = styled(CollapsedIcon)`
margin-bottom: -4px;
margin-left: 1px;
margin-right: -3px;
${({ expanded }) => !expanded && 'transform: rotate(-90deg);'}
${({ expanded }) => !expanded && 'transform: rotate(-90deg);'};
`;
const IconWrapper = styled.span`
@ -55,7 +55,8 @@ type Props = {
iconColor?: string,
};
@observer class SidebarLink extends Component {
@observer
class SidebarLink extends Component {
props: Props;
@observable expanded: boolean = false;
@ -67,13 +68,15 @@ type Props = {
if (nextProps.expand) this.handleExpand();
}
@action handleClick = (event: SyntheticEvent) => {
@action
handleClick = (event: SyntheticEvent) => {
event.preventDefault();
event.stopPropagation();
this.expanded = !this.expanded;
};
@action handleExpand = () => {
@action
handleExpand = () => {
this.expanded = true;
};
@ -91,8 +94,9 @@ type Props = {
exact
>
{icon && <IconWrapper>{icon}</IconWrapper>}
{expandedContent &&
<StyledGoTo expanded={this.expanded} onClick={this.handleClick} />}
{expandedContent && (
<StyledGoTo expanded={this.expanded} onClick={this.handleClick} />
)}
<Content onClick={this.handleExpand}>{children}</Content>
</Component>
{this.expanded && expandedContent}

View File

@ -2,7 +2,8 @@
import React from 'react';
import { inject, observer } from 'mobx-react';
@observer class LoadingIndicator extends React.Component {
@observer
class LoadingIndicator extends React.Component {
componentDidMount() {
this.props.ui.enableProgressBar();
}

View File

@ -20,7 +20,7 @@ const Container = styled.div`
top: 0;
z-index: 9999;
background-color: #03A9F4;
background-color: #03a9f4;
width: 100%;
animation: ${loadingFrame} 4s ease-in-out infinite;
animation-delay: 250ms;
@ -30,7 +30,7 @@ const Container = styled.div`
const Loader = styled.div`
width: 100%;
height: 2px;
background-color: #03A9F4;
background-color: #03a9f4;
`;
export default LoadingIndicatorBar;

View File

@ -43,7 +43,9 @@ const Modal = ({
>
<Content column>
{title && <h1>{title}</h1>}
<Close onClick={onRequestClose}><CloseIcon size={32} /></Close>
<Close onClick={onRequestClose}>
<CloseIcon size={32} />
</Close>
{children}
</Content>
</StyledModal>
@ -79,7 +81,7 @@ const Close = styled.a`
position: fixed;
top: 3rem;
right: 3rem;
opacity: .5;
opacity: 0.5;
color: ${color.text};
&:hover {

View File

@ -7,7 +7,9 @@ type Props = {
};
const PageTitle = ({ title }: Props) => (
<Helmet><title>{`${title} - Outline`}</title></Helmet>
<Helmet>
<title>{`${title} - Outline`}</title>
</Helmet>
);
export default PageTitle;

View File

@ -30,18 +30,19 @@ const StyledPopover = styled(BoundlessPopover)`
position: absolute;
polygon:first-child {
fill: rgba(0,0,0,.075);
fill: rgba(0, 0, 0, 0.075);
}
polygon {
fill: #FFF;
fill: #fff;
}
}
`;
const Dialog = styled.div`
outline: none;
background: #FFF;
box-shadow: 0 0 0 1px rgba(0,0,0,.05), 0 8px 16px rgba(0,0,0,.1), 0 2px 4px rgba(0,0,0,.1);
background: #fff;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05), 0 8px 16px rgba(0, 0, 0, 0.1),
0 2px 4px rgba(0, 0, 0, 0.1);
border-radius: 4px;
line-height: 1.5;
padding: 16px;

View File

@ -10,7 +10,8 @@ type Props = {
redirectUri: string,
};
@observer class SlackAuthLink extends React.Component {
@observer
class SlackAuthLink extends React.Component {
props: Props;
static defaultProps = {

View File

@ -5,7 +5,8 @@ import styled from 'styled-components';
import { layout } from 'shared/styles/constants';
import Toast from './components/Toast';
@observer class Toasts extends Component {
@observer
class Toasts extends Component {
handleClose = index => {
this.props.errors.remove(index);
};

View File

@ -82,9 +82,7 @@ const Auth = ({ children }: AuthProps) => {
return (
<Flex auto>
<Provider {...authenticatedStores}>
{children}
</Provider>
<Provider {...authenticatedStores}>{children}</Provider>
</Flex>
);
} else {

View File

@ -6,7 +6,8 @@ import UiStore from 'stores/UiStore';
import AuthStore from 'stores/AuthStore';
import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu';
@observer class AccountMenu extends Component {
@observer
class AccountMenu extends Component {
props: {
label?: React$Element<any>,
history: Object,
@ -42,9 +43,7 @@ import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu';
<Link to="/developers">
<DropdownMenuItem>API documentation</DropdownMenuItem>
</Link>
<DropdownMenuItem onClick={this.handleLogout}>
Logout
</DropdownMenuItem>
<DropdownMenuItem onClick={this.handleLogout}>Logout</DropdownMenuItem>
</DropdownMenu>
);
}

View File

@ -8,7 +8,8 @@ import MoreIcon from 'components/Icon/MoreIcon';
import Flex from 'shared/components/Flex';
import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu';
@observer class CollectionMenu extends Component {
@observer
class CollectionMenu extends Component {
props: {
label?: React$Element<*>,
onOpen?: () => void,
@ -44,7 +45,7 @@ import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu';
onOpen={onOpen}
onClose={onClose}
>
{collection &&
{collection && (
<Flex column>
<DropdownMenuItem onClick={this.onNewDocument}>
New document
@ -53,9 +54,11 @@ import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu';
Import document
</DropdownMenuItem>
<DropdownMenuItem onClick={this.onEdit}>Edit</DropdownMenuItem>
</Flex>}
{allowDelete &&
<DropdownMenuItem onClick={this.onDelete}>Delete</DropdownMenuItem>}
</Flex>
)}
{allowDelete && (
<DropdownMenuItem onClick={this.onDelete}>Delete</DropdownMenuItem>
)}
</DropdownMenu>
);
}

View File

@ -8,7 +8,8 @@ import MoreIcon from 'components/Icon/MoreIcon';
import { documentMoveUrl } from 'utils/routeHelpers';
import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu';
@observer class DocumentMenu extends Component {
@observer
class DocumentMenu extends Component {
props: {
ui: UiStore,
label?: React$Element<any>,
@ -50,11 +51,13 @@ import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu';
return (
<DropdownMenu label={label || <MoreIcon />}>
{document.starred
? <DropdownMenuItem onClick={this.handleUnstar}>
Unstar
</DropdownMenuItem>
: <DropdownMenuItem onClick={this.handleStar}>Star</DropdownMenuItem>}
{document.starred ? (
<DropdownMenuItem onClick={this.handleUnstar}>
Unstar
</DropdownMenuItem>
) : (
<DropdownMenuItem onClick={this.handleStar}>Star</DropdownMenuItem>
)}
<DropdownMenuItem
onClick={this.handleNewChild}
title="Create a new child document for the current document"
@ -65,10 +68,11 @@ import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu';
Download
</DropdownMenuItem>
<DropdownMenuItem onClick={this.handleMove}>Move</DropdownMenuItem>
{allowDelete &&
{allowDelete && (
<DropdownMenuItem onClick={this.handleDelete}>
Delete
</DropdownMenuItem>}
</DropdownMenuItem>
)}
</DropdownMenu>
);
}

View File

@ -27,19 +27,22 @@ class Collection extends BaseModel {
/* Computed */
@computed get entryUrl(): string {
@computed
get entryUrl(): string {
return this.type === 'atlas' && this.documents.length > 0
? this.documents[0].url
: this.url;
}
@computed get allowDelete(): boolean {
@computed
get allowDelete(): boolean {
return true;
}
/* Actions */
@action fetch = async () => {
@action
fetch = async () => {
try {
const res = await client.post('/collections.info', { id: this.id });
invariant(res && res.data, 'API response should be available');
@ -54,7 +57,8 @@ class Collection extends BaseModel {
return this;
};
@action save = async () => {
@action
save = async () => {
if (this.isSaving) return this;
this.isSaving = true;
@ -89,7 +93,8 @@ class Collection extends BaseModel {
return true;
};
@action delete = async () => {
@action
delete = async () => {
try {
await client.post('/collections.delete', { id: this.id });
this.emit('collections.delete', {
@ -102,7 +107,8 @@ class Collection extends BaseModel {
return false;
};
@action updateData(data: Object = {}) {
@action
updateData(data: Object = {}) {
this.data = data;
extendObservable(this, data);
}

View File

@ -43,11 +43,13 @@ class Document extends BaseModel {
/* Computed */
@computed get modifiedSinceViewed(): boolean {
@computed
get modifiedSinceViewed(): boolean {
return !!this.lastViewedAt && this.lastViewedAt < this.updatedAt;
}
@computed get pathToDocument(): Array<{ id: string, title: string }> {
@computed
get pathToDocument(): Array<{ id: string, title: string }> {
let path;
const traveler = (nodes, previousPath) => {
nodes.forEach(childNode => {
@ -76,16 +78,19 @@ class Document extends BaseModel {
return [];
}
@computed get isEmpty(): boolean {
@computed
get isEmpty(): boolean {
// Check if the document title has been modified and user generated content exists
return this.text.replace(new RegExp(`^#$`), '').trim().length === 0;
}
@computed get allowSave(): boolean {
@computed
get allowSave(): boolean {
return !this.isEmpty && !this.isSaving;
}
@computed get allowDelete(): boolean {
@computed
get allowDelete(): boolean {
const collection = this.collection;
return (
collection &&
@ -95,7 +100,8 @@ class Document extends BaseModel {
);
}
@computed get parentDocumentId(): ?string {
@computed
get parentDocumentId(): ?string {
return this.pathToDocument.length > 1
? this.pathToDocument[this.pathToDocument.length - 2].id
: null;
@ -103,7 +109,8 @@ class Document extends BaseModel {
/* Actions */
@action star = async () => {
@action
star = async () => {
this.starred = true;
try {
await client.post('/documents.star', { id: this.id });
@ -113,7 +120,8 @@ class Document extends BaseModel {
}
};
@action unstar = async () => {
@action
unstar = async () => {
this.starred = false;
try {
await client.post('/documents.unstar', { id: this.id });
@ -123,7 +131,8 @@ class Document extends BaseModel {
}
};
@action view = async () => {
@action
view = async () => {
this.views++;
try {
await client.post('/views.create', { id: this.id });
@ -132,7 +141,8 @@ class Document extends BaseModel {
}
};
@action fetch = async () => {
@action
fetch = async () => {
try {
const res = await client.post('/documents.info', { id: this.id });
invariant(res && res.data, 'Document API response should be available');
@ -145,7 +155,8 @@ class Document extends BaseModel {
}
};
@action save = async () => {
@action
save = async () => {
if (this.isSaving) return this;
this.isSaving = true;
@ -196,7 +207,8 @@ class Document extends BaseModel {
return this;
};
@action move = async (parentDocumentId: ?string) => {
@action
move = async (parentDocumentId: ?string) => {
try {
const res = await client.post('/documents.move', {
id: this.id,
@ -214,7 +226,8 @@ class Document extends BaseModel {
return;
};
@action delete = async () => {
@action
delete = async () => {
try {
await client.post('/documents.delete', { id: this.id });
this.emit('documents.delete', {
@ -232,7 +245,9 @@ class Document extends BaseModel {
const a = window.document.createElement('a');
a.textContent = 'download';
a.download = `${this.title}.md`;
a.href = `data:text/markdown;charset=UTF-8,${encodeURIComponent(this.text)}`;
a.href = `data:text/markdown;charset=UTF-8,${encodeURIComponent(
this.text
)}`;
a.click();
}

View File

@ -20,7 +20,8 @@ type Props = {
match: Object,
};
@observer class CollectionScene extends Component {
@observer
class CollectionScene extends Component {
props: Props;
@observable collection: ?Collection;
@observable isFetching = true;
@ -56,11 +57,8 @@ type Props = {
<NewDocumentContainer auto column justify="center">
<h1>Create a document</h1>
<HelpText>
Publish your first document to start building the
{' '}
<strong>{this.collection.name}</strong>
{' '}
collection.
Publish your first document to start building the{' '}
<strong>{this.collection.name}</strong> collection.
</HelpText>
<Action>
<Link to={newDocumentUrl(this.collection)}>
@ -76,9 +74,11 @@ type Props = {
return (
<CenteredContent>
{this.isFetching
? <LoadingListPlaceholder />
: this.renderEmptyCollection()}
{this.isFetching ? (
<LoadingListPlaceholder />
) : (
this.renderEmptyCollection()
)}
</CenteredContent>
);
}

View File

@ -17,7 +17,8 @@ type Props = {
onSubmit: () => void,
};
@observer class CollectionDelete extends Component {
@observer
class CollectionDelete extends Component {
props: Props;
@observable isDeleting: boolean;
@ -42,12 +43,9 @@ type Props = {
<Flex column>
<form onSubmit={this.handleSubmit}>
<HelpText>
Are you sure? Deleting the
{' '}
<strong>{collection.name}</strong>
{' '}
collection is permanant and will also delete all of the documents within
it, so be careful with that.
Are you sure? Deleting the <strong>{collection.name}</strong>{' '}
collection is permanant and will also delete all of the documents
within it, so be careful with that.
</HelpText>
<Button type="submit" danger>
{this.isDeleting ? 'Deleting…' : 'Delete'}

View File

@ -16,7 +16,8 @@ type Props = {
onSubmit: () => void,
};
@observer class CollectionEdit extends Component {
@observer
class CollectionEdit extends Component {
props: Props;
@observable name: string;
@observable color: string = '';

View File

@ -17,7 +17,8 @@ type Props = {
onSubmit: () => void,
};
@observer class CollectionNew extends Component {
@observer
class CollectionNew extends Component {
props: Props;
@observable collection: Collection;
@observable name: string = '';
@ -56,8 +57,9 @@ type Props = {
return (
<form onSubmit={this.handleSubmit}>
<HelpText>
Collections are for grouping your Outline. They work best when organized
around a topic or internal team Product or Engineering for example.
Collections are for grouping your Outline. They work best when
organized around a topic or internal team Product or Engineering for
example.
</HelpText>
<Input
type="text"

View File

@ -15,7 +15,7 @@ const Subheading = styled.h3`
font-size: 11px;
font-weight: 500;
text-transform: uppercase;
color: #9FA6AB;
color: #9fa6ab;
letter-spacing: 0.04em;
border-bottom: 1px solid #ddd;
padding-bottom: 10px;
@ -26,7 +26,8 @@ type Props = {
documents: DocumentsStore,
};
@observer class Dashboard extends Component {
@observer
class Dashboard extends Component {
props: Props;
@observable isLoaded: boolean = false;
@ -53,20 +54,24 @@ type Props = {
<CenteredContent>
<PageTitle title="Home" />
<h1>Home</h1>
{showContent
? <Flex column>
{recentlyViewedLoaded &&
<Flex column>
<Subheading>Recently viewed</Subheading>
<DocumentList documents={documents.recentlyViewed} />
</Flex>}
{recentlyEditedLoaded &&
<Flex column>
<Subheading>Recently edited</Subheading>
<DocumentList documents={documents.recentlyEdited} />
</Flex>}
</Flex>
: <ListPlaceholder count={5} />}
{showContent ? (
<Flex column>
{recentlyViewedLoaded && (
<Flex column>
<Subheading>Recently viewed</Subheading>
<DocumentList documents={documents.recentlyViewed} />
</Flex>
)}
{recentlyEditedLoaded && (
<Flex column>
<Subheading>Recently edited</Subheading>
<DocumentList documents={documents.recentlyEdited} />
</Flex>
)}
</Flex>
) : (
<ListPlaceholder count={5} />
)}
</CenteredContent>
);
}

View File

@ -51,7 +51,8 @@ type Props = {
ui: UiStore,
};
@observer class DocumentScene extends Component {
@observer
class DocumentScene extends Component {
props: Props;
savedTimeout: number;
@ -219,66 +220,74 @@ type Props = {
{isMoving && document && <DocumentMove document={document} />}
{titleText && <PageTitle title={titleText} />}
{this.isLoading && <LoadingIndicator />}
{isFetching &&
{isFetching && (
<CenteredContent>
<LoadingState />
</CenteredContent>}
</CenteredContent>
)}
{!isFetching &&
document &&
<Flex justify="center" auto>
<Prompt
when={document.hasPendingChanges}
message={DISCARD_CHANGES}
/>
<Editor
key={document.id}
text={document.text}
emoji={document.emoji}
onImageUploadStart={this.onImageUploadStart}
onImageUploadStop={this.onImageUploadStop}
onChange={this.onChange}
onSave={this.onSave}
onCancel={this.onDiscard}
readOnly={!this.isEditing}
/>
<Meta align="center" justify="flex-end" readOnly={!this.isEditing}>
<Flex align="center">
{!isNew &&
!this.isEditing &&
<Collaborators document={document} />}
<HeaderAction>
{this.isEditing
? <SaveAction
document && (
<Flex justify="center" auto>
<Prompt
when={document.hasPendingChanges}
message={DISCARD_CHANGES}
/>
<Editor
key={document.id}
text={document.text}
emoji={document.emoji}
onImageUploadStart={this.onImageUploadStart}
onImageUploadStop={this.onImageUploadStop}
onChange={this.onChange}
onSave={this.onSave}
onCancel={this.onDiscard}
readOnly={!this.isEditing}
/>
<Meta
align="center"
justify="flex-end"
readOnly={!this.isEditing}
>
<Flex align="center">
{!isNew &&
!this.isEditing && <Collaborators document={document} />}
<HeaderAction>
{this.isEditing ? (
<SaveAction
isSaving={this.isSaving}
onClick={this.onSave.bind(this, true)}
disabled={
!(this.document && this.document.allowSave) ||
this.isSaving
this.isSaving
}
isNew={!!isNew}
/>
: <a onClick={this.onClickEdit}>
Edit
</a>}
</HeaderAction>
{this.isEditing &&
) : (
<a onClick={this.onClickEdit}>Edit</a>
)}
</HeaderAction>
{this.isEditing && (
<HeaderAction>
<a onClick={this.onDiscard}>Discard</a>
</HeaderAction>
)}
{!this.isEditing && (
<HeaderAction>
<DocumentMenu document={document} />
</HeaderAction>
)}
{!this.isEditing && <Separator />}
<HeaderAction>
<a onClick={this.onDiscard}>Discard</a>
</HeaderAction>}
{!this.isEditing &&
<HeaderAction>
<DocumentMenu document={document} />
</HeaderAction>}
{!this.isEditing && <Separator />}
<HeaderAction>
{!this.isEditing &&
<a onClick={this.onClickNew}>
<NewDocumentIcon />
</a>}
</HeaderAction>
</Flex>
</Meta>
</Flex>}
{!this.isEditing && (
<a onClick={this.onClickNew}>
<NewDocumentIcon />
</a>
)}
</HeaderAction>
</Flex>
</Meta>
</Flex>
)}
</Container>
);
}

View File

@ -28,14 +28,16 @@ type Props = {
collections: CollectionsStore,
};
@observer class DocumentMove extends Component {
@observer
class DocumentMove extends Component {
props: Props;
firstDocument: HTMLElement;
@observable searchTerm: ?string;
@observable isSaving: boolean;
@computed get searchIndex() {
@computed
get searchIndex() {
const { document, collections } = this.props;
const paths = collections.pathsToDocuments;
const index = new Search('id');
@ -54,7 +56,8 @@ type Props = {
return index;
}
@computed get results(): DocumentPath[] {
@computed
get results(): DocumentPath[] {
const { document, collections } = this.props;
let results = [];
@ -134,43 +137,46 @@ type Props = {
return (
<Modal isOpen onRequestClose={this.handleClose} title="Move document">
{document &&
collections.isLoaded &&
<Flex column>
<Section>
<Labeled label="Current location">
{this.renderPathToCurrentDocument()}
</Labeled>
</Section>
collections.isLoaded && (
<Flex column>
<Section>
<Labeled label="Current location">
{this.renderPathToCurrentDocument()}
</Labeled>
</Section>
<Section column>
<Labeled label="Choose a new location">
<Input
type="text"
placeholder="Filter by document name…"
onKeyDown={this.handleKeyDown}
onChange={this.handleFilter}
required
autoFocus
/>
</Labeled>
<Flex column>
<StyledArrowKeyNavigation
mode={ArrowKeyNavigation.mode.VERTICAL}
defaultActiveChildIndex={0}
>
{this.results.map((result, index) => (
<PathToDocument
key={result.id}
result={result}
document={document}
ref={ref => index === 0 && this.setFirstDocumentRef(ref)}
onSuccess={this.handleClose}
/>
))}
</StyledArrowKeyNavigation>
</Flex>
</Section>
</Flex>}
<Section column>
<Labeled label="Choose a new location">
<Input
type="text"
placeholder="Filter by document name…"
onKeyDown={this.handleKeyDown}
onChange={this.handleFilter}
required
autoFocus
/>
</Labeled>
<Flex column>
<StyledArrowKeyNavigation
mode={ArrowKeyNavigation.mode.VERTICAL}
defaultActiveChildIndex={0}
>
{this.results.map((result, index) => (
<PathToDocument
key={result.id}
result={result}
document={document}
ref={ref =>
index === 0 && this.setFirstDocumentRef(ref)
}
onSuccess={this.handleClose}
/>
))}
</StyledArrowKeyNavigation>
</Flex>
</Section>
</Flex>
)}
</Modal>
);
}

View File

@ -19,8 +19,7 @@ const ResultWrapper = styled.div`
cursor: default;
`;
const StyledGoToIcon = styled(GoToIcon)`
`;
const StyledGoToIcon = styled(GoToIcon)``;
const ResultWrapperLink = ResultWrapper.withComponent('a').extend`
height: 32px;
@ -50,7 +49,8 @@ type Props = {
ref?: Function,
};
@observer class PathToDocument extends React.Component {
@observer
class PathToDocument extends React.Component {
props: Props;
handleClick = async (ev: SyntheticEvent) => {
@ -83,12 +83,12 @@ type Props = {
{result.path
.map(doc => <span key={doc.id}>{doc.title}</span>)
.reduce((prev, curr) => [prev, <StyledGoToIcon />, curr])}
{document &&
{document && (
<Flex>
{' '}
<StyledGoToIcon />
{' '}{document.title}
</Flex>}
<StyledGoToIcon /> {document.title}
</Flex>
)}
</Component>
);
}

View File

@ -16,7 +16,8 @@ type Props = {
onSubmit: () => void,
};
@observer class DocumentDelete extends Component {
@observer
class DocumentDelete extends Component {
props: Props;
@observable isDeleting: boolean;
@ -41,10 +42,7 @@ type Props = {
<Flex column>
<form onSubmit={this.handleSubmit}>
<HelpText>
Are you sure? Deleting the
{' '}
<strong>{document.title}</strong>
{' '}
Are you sure? Deleting the <strong>{document.title}</strong>{' '}
document is permanant and will also delete all of its history.
</HelpText>
<Button type="submit" danger>

View File

@ -14,7 +14,9 @@ class Error404 extends React.Component {
<p>We're unable to find the page you're accessing.</p>
<p>Maybe you want to try <Link to="/search">search</Link> instead?</p>
<p>
Maybe you want to try <Link to="/search">search</Link> instead?
</p>
</CenteredContent>
);
}

View File

@ -9,75 +9,123 @@ 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
Outline is designed to be super fast and easy to use. All of your usual
keyboard shortcuts work here, and there
{"'"}
s Markdown too.
</HelpText>
<h2>Navigation</h2>
<List>
<Keys><Key>e</Key></Keys>
<Keys>
<Key>e</Key>
</Keys>
<Label>Edit current document</Label>
<Keys><Key>m</Key></Keys>
<Keys>
<Key>m</Key>
</Keys>
<Label>Move current document</Label>
<Keys><Key>/</Key> or <Key>t</Key></Keys>
<Keys>
<Key>/</Key> or <Key>t</Key>
</Keys>
<Label>Jump to search</Label>
<Keys><Key>d</Key></Keys>
<Keys>
<Key>d</Key>
</Keys>
<Label>Jump to dashboard</Label>
<Keys><Key></Key> + <Key>/</Key></Keys>
<Keys>
<Key></Key> + <Key>/</Key>
</Keys>
<Label>Open this guide</Label>
</List>
<h2>Editor</h2>
<List>
<Keys><Key></Key> + <Key>Enter</Key></Keys>
<Keys>
<Key></Key> + <Key>Enter</Key>
</Keys>
<Label>Save and exit document edit mode</Label>
<Keys><Key></Key> + <Key>S</Key></Keys>
<Keys>
<Key></Key> + <Key>S</Key>
</Keys>
<Label>Save document and continue editing</Label>
<Keys><Key></Key> + <Key>Esc</Key></Keys>
<Keys>
<Key></Key> + <Key>Esc</Key>
</Keys>
<Label>Cancel editing</Label>
<Keys><Key></Key> + <Key>b</Key></Keys>
<Keys>
<Key></Key> + <Key>b</Key>
</Keys>
<Label>Bold</Label>
<Keys><Key></Key> + <Key>i</Key></Keys>
<Keys>
<Key></Key> + <Key>i</Key>
</Keys>
<Label>Italic</Label>
<Keys><Key></Key> + <Key>u</Key></Keys>
<Keys>
<Key></Key> + <Key>u</Key>
</Keys>
<Label>Underline</Label>
<Keys><Key></Key> + <Key>d</Key></Keys>
<Keys>
<Key></Key> + <Key>d</Key>
</Keys>
<Label>Strikethrough</Label>
<Keys><Key></Key> + <Key>k</Key></Keys>
<Keys>
<Key></Key> + <Key>k</Key>
</Keys>
<Label>Link</Label>
<Keys><Key></Key> + <Key>z</Key></Keys>
<Keys>
<Key></Key> + <Key>z</Key>
</Keys>
<Label>Undo</Label>
<Keys><Key></Key> + <Key>Shift</Key> + <Key>z</Key></Keys>
<Keys>
<Key></Key> + <Key>Shift</Key> + <Key>z</Key>
</Keys>
<Label>Redo</Label>
</List>
<h2>Markdown</h2>
<List>
<Keys><Key>#</Key> <Key>Space</Key></Keys>
<Keys>
<Key>#</Key> <Key>Space</Key>
</Keys>
<Label>Large header</Label>
<Keys><Key>##</Key> <Key>Space</Key></Keys>
<Keys>
<Key>##</Key> <Key>Space</Key>
</Keys>
<Label>Medium header</Label>
<Keys><Key>###</Key> <Key>Space</Key></Keys>
<Keys>
<Key>###</Key> <Key>Space</Key>
</Keys>
<Label>Small header</Label>
<Keys><Key>1.</Key> <Key>Space</Key></Keys>
<Keys>
<Key>1.</Key> <Key>Space</Key>
</Keys>
<Label>Numbered list</Label>
<Keys><Key>-</Key> <Key>Space</Key></Keys>
<Keys>
<Key>-</Key> <Key>Space</Key>
</Keys>
<Label>Bulleted list</Label>
<Keys><Key>[ ]</Key> <Key>Space</Key></Keys>
<Keys>
<Key>[ ]</Key> <Key>Space</Key>
</Keys>
<Label>Todo list</Label>
<Keys><Key>&gt;</Key> <Key>Space</Key></Keys>
<Keys>
<Key>&gt;</Key> <Key>Space</Key>
</Keys>
<Label>Blockquote</Label>
<Keys><Key>---</Key></Keys>
<Keys>
<Key>---</Key>
</Keys>
<Label>Horizontal divider</Label>
<Keys><Key>{'```'}</Key></Keys>
<Keys>
<Key>{'```'}</Key>
</Keys>
<Label>Code block</Label>
<Keys>_italic_</Keys>
@ -97,21 +145,21 @@ const List = styled.dl`
width: 100%;
overflow: hidden;
padding: 0;
margin: 0
margin: 0;
`;
const Keys = styled.dt`
float: left;
width: 25%;
padding: 0 0 4px;
margin: 0
margin: 0;
`;
const Label = styled.dd`
float: left;
width: 75%;
padding: 0 0 4px;
margin: 0
margin: 0;
`;
export default KeyboardShortcuts;

View File

@ -54,7 +54,8 @@ const StyledArrowKeyNavigation = styled(ArrowKeyNavigation)`
flex: 1;
`;
@observer class Search extends React.Component {
@observer
class Search extends React.Component {
firstDocument: HTMLElement;
props: Props;
@ -99,7 +100,8 @@ const StyledArrowKeyNavigation = styled(ArrowKeyNavigation)`
this.search(this.props.match.params.query);
}, 250);
@action search = async (query: string) => {
@action
search = async (query: string) => {
this.searchTerm = query;
this.isFetching = true;
@ -141,11 +143,12 @@ const StyledArrowKeyNavigation = styled(ArrowKeyNavigation)`
<Container auto>
<PageTitle title={this.title} />
{this.isFetching && <LoadingIndicator />}
{notFound &&
{notFound && (
<div>
<h1>Not Found</h1>
<p>Were unable to find the page youre accessing.</p>
</div>}
</div>
)}
<ResultsWrapper pinToTop={hasResults} column auto>
<SearchField
searchTerm={this.searchTerm}
@ -165,7 +168,8 @@ const StyledArrowKeyNavigation = styled(ArrowKeyNavigation)`
return (
<DocumentPreview
innerRef={ref =>
index === 0 && this.setFirstDocumentRef(ref)}
index === 0 && this.setFirstDocumentRef(ref)
}
key={documentId}
document={document}
highlight={this.searchTerm}

View File

@ -53,10 +53,18 @@ const StyledInput = styled.input`
outline: none;
border: 0;
::-webkit-input-placeholder { color: ${color.slateLight}; }
:-moz-placeholder { color: ${color.slateLight}; }
::-moz-placeholder { color: ${color.slateLight}; }
:-ms-input-placeholder { color: ${color.slateLight}; }
::-webkit-input-placeholder {
color: ${color.slateLight};
}
:-moz-placeholder {
color: ${color.slateLight};
}
::-moz-placeholder {
color: ${color.slateLight};
}
:-ms-input-placeholder {
color: ${color.slateLight};
}
`;
const StyledIcon = styled(SearchIcon)`

View File

@ -14,7 +14,8 @@ import HelpText from 'components/HelpText';
import { Label } from 'components/Labeled';
import SlackAuthLink from 'components/SlackAuthLink';
@observer class Settings extends React.Component {
@observer
class Settings extends React.Component {
store: SettingsStore;
constructor() {
@ -27,12 +28,12 @@ import SlackAuthLink from 'components/SlackAuthLink';
return (
<Flex column>
{showSlackSettings &&
{showSlackSettings && (
<Section>
<SectionLabel>Slack</SectionLabel>
<HelpText>
Connect Outline to your Slack to instantly search for your documents
using <Code>/outline</Code> command.
Connect Outline to your Slack to instantly search for your
documents using <Code>/outline</Code> command.
</HelpText>
<SlackAuthLink
@ -47,16 +48,17 @@ import SlackAuthLink from 'components/SlackAuthLink';
srcSet="https://platform.slack-edge.com/img/add_to_slack.png 1x, https://platform.slack-edge.com/img/add_to_slack@2x.png 2x"
/>
</SlackAuthLink>
</Section>}
</Section>
)}
<Section>
<SectionLabel>API Access</SectionLabel>
<HelpText>
Create API tokens to hack on your Outline.
Learn more in <Link to="/developers">API documentation</Link>.
Create API tokens to hack on your Outline. Learn more in{' '}
<Link to="/developers">API documentation</Link>.
</HelpText>
{this.store.apiKeys &&
{this.store.apiKeys && (
<Table>
<tbody>
{this.store.apiKeys &&
@ -70,7 +72,8 @@ import SlackAuthLink from 'components/SlackAuthLink';
/>
))}
</tbody>
</Table>}
</Table>
)}
<InlineForm
placeholder="Token name"
buttonLabel="Create token"
@ -162,13 +165,13 @@ const Table = styled.table`
const SectionLabel = styled(Label)`
padding-bottom: 12px;
margin-bottom: 20px;
border-bottom: 1px solid #EAEBEA;
border-bottom: 1px solid #eaebea;
`;
const Code = styled.code`
padding: 4px 6px;
margin: 0 2px;
background: #EAEBEA;
background: #eaebea;
border-radius: 4px;
`;

View File

@ -10,7 +10,8 @@ class SearchStore {
@observable isFetching: boolean = false;
@action fetchApiKeys = async () => {
@action
fetchApiKeys = async () => {
this.isFetching = true;
try {
@ -27,7 +28,8 @@ class SearchStore {
this.isFetching = false;
};
@action createApiKey = async () => {
@action
createApiKey = async () => {
this.isFetching = true;
try {
@ -46,7 +48,8 @@ class SearchStore {
this.isFetching = false;
};
@action deleteApiKey = async (id: string) => {
@action
deleteApiKey = async (id: string) => {
this.isFetching = true;
try {
@ -62,7 +65,8 @@ class SearchStore {
this.isFetching = false;
};
@action setKeyName = (value: SyntheticInputEvent) => {
@action
setKeyName = (value: SyntheticInputEvent) => {
this.keyName = value.target.value;
};

View File

@ -12,7 +12,8 @@ type Props = {
onDelete: Function,
};
@observer class ApiKeyRow extends React.Component {
@observer
class ApiKeyRow extends React.Component {
props: Props;
@observable disabled: boolean;
@ -28,7 +29,9 @@ type Props = {
return (
<tr>
<td>{name}</td>
<td><code>{secret}</code></td>
<td>
<code>{secret}</code>
</td>
<td>
<Action role="button" onClick={this.onClick} disabled={disabled}>
Action

View File

@ -15,7 +15,8 @@ type Props = {
location: Location,
};
@observer class SlackAuth extends React.Component {
@observer
class SlackAuth extends React.Component {
props: Props;
@observable redirectTo: string;

View File

@ -8,7 +8,8 @@ import PageTitle from 'components/PageTitle';
import DocumentList from 'components/DocumentList';
import DocumentsStore from 'stores/DocumentsStore';
@observer class Starred extends Component {
@observer
class Starred extends Component {
props: {
documents: DocumentsStore,
};

View File

@ -16,11 +16,13 @@ class AuthStore {
/* Computed */
@computed get authenticated(): boolean {
@computed
get authenticated(): boolean {
return !!this.token;
}
@computed get asJson(): string {
@computed
get asJson(): string {
return JSON.stringify({
user: this.user,
team: this.team,
@ -31,19 +33,24 @@ class AuthStore {
/* Actions */
@action logout = () => {
@action
logout = () => {
this.user = null;
this.token = null;
Cookie.remove('loggedIn', { path: '/' });
};
@action getOauthState = () => {
const state = Math.random().toString(36).substring(7);
@action
getOauthState = () => {
const state = Math.random()
.toString(36)
.substring(7);
this.oauthState = state;
return this.oauthState;
};
@action authWithSlack = async (code: string, state: string) => {
@action
authWithSlack = async (code: string, state: string) => {
if (state !== this.oauthState) {
return {
success: false,

View File

@ -43,20 +43,23 @@ class CollectionsStore {
cache: CacheStore;
ui: UiStore;
@computed get active(): ?Collection {
@computed
get active(): ?Collection {
return this.ui.activeCollectionId
? this.getById(this.ui.activeCollectionId)
: undefined;
}
@computed get orderedData(): Collection[] {
@computed
get orderedData(): Collection[] {
return _.sortBy(this.data, 'name');
}
/**
* List of paths to each of the documents, where paths are composed of id and title/name pairs
*/
@computed get pathsToDocuments(): Array<DocumentPath> {
@computed
get pathsToDocuments(): Array<DocumentPath> {
let results = [];
const travelDocuments = (documentList, path) =>
documentList.forEach(document => {
@ -95,7 +98,8 @@ class CollectionsStore {
/* Actions */
@action fetchAll = async (): Promise<*> => {
@action
fetchAll = async (): Promise<*> => {
try {
const res = await this.client.post('/collections.list', {
id: this.teamId,
@ -111,7 +115,8 @@ class CollectionsStore {
}
};
@action fetchById = async (id: string): Promise<?Collection> => {
@action
fetchById = async (id: string): Promise<?Collection> => {
let collection = this.getById(id);
if (!collection) {
try {
@ -133,11 +138,13 @@ class CollectionsStore {
return collection;
};
@action add = (collection: Collection): void => {
@action
add = (collection: Collection): void => {
this.data.push(collection);
};
@action remove = (id: string): void => {
@action
remove = (id: string): void => {
this.data.splice(this.data.indexOf(id), 1);
};

View File

@ -37,7 +37,8 @@ class DocumentsStore extends BaseStore {
/* Computed */
@computed get recentlyViewed(): Array<Document> {
@computed
get recentlyViewed(): Array<Document> {
return _.take(
_.filter(this.data.values(), ({ id }) =>
this.recentlyViewedIds.includes(id)
@ -46,15 +47,18 @@ class DocumentsStore extends BaseStore {
);
}
@computed get recentlyEdited(): Array<Document> {
@computed
get recentlyEdited(): Array<Document> {
return _.take(_.orderBy(this.data.values(), 'updatedAt', 'desc'), 5);
}
@computed get starred(): Array<Document> {
@computed
get starred(): Array<Document> {
return _.filter(this.data.values(), 'starred');
}
@computed get active(): ?Document {
@computed
get active(): ?Document {
return this.ui.activeDocumentId
? this.getById(this.ui.activeDocumentId)
: undefined;
@ -62,10 +66,8 @@ class DocumentsStore extends BaseStore {
/* Actions */
@action fetchAll = async (
request: string = 'list',
options: ?Object
): Promise<*> => {
@action
fetchAll = async (request: string = 'list', options: ?Object): Promise<*> => {
this.isFetching = true;
try {
@ -86,11 +88,13 @@ class DocumentsStore extends BaseStore {
}
};
@action fetchRecentlyModified = async (options: ?Object): Promise<*> => {
@action
fetchRecentlyModified = async (options: ?Object): Promise<*> => {
return await this.fetchAll('list', options);
};
@action fetchRecentlyViewed = async (options: ?Object): Promise<*> => {
@action
fetchRecentlyViewed = async (options: ?Object): Promise<*> => {
const data = await this.fetchAll('viewed', options);
runInAction('DocumentsStore#fetchRecentlyViewed', () => {
@ -99,11 +103,13 @@ class DocumentsStore extends BaseStore {
return data;
};
@action fetchStarred = async (): Promise<*> => {
@action
fetchStarred = async (): Promise<*> => {
await this.fetchAll('starred');
};
@action search = async (query: string): Promise<*> => {
@action
search = async (query: string): Promise<*> => {
const res = await client.get('/documents.search', { query });
invariant(res && res.data, 'res or res.data missing');
const { data } = res;
@ -111,11 +117,13 @@ class DocumentsStore extends BaseStore {
return data.map(documentData => documentData.id);
};
@action prefetchDocument = async (id: string) => {
@action
prefetchDocument = async (id: string) => {
if (!this.getById(id)) this.fetch(id, true);
};
@action fetch = async (id: string, prefetch?: boolean): Promise<*> => {
@action
fetch = async (id: string, prefetch?: boolean): Promise<*> => {
if (!prefetch) this.isFetching = true;
try {
@ -137,11 +145,13 @@ class DocumentsStore extends BaseStore {
}
};
@action add = (document: Document): void => {
@action
add = (document: Document): void => {
this.data.set(document.id, document);
};
@action remove = (id: string): void => {
@action
remove = (id: string): void => {
this.data.delete(id);
};

View File

@ -6,11 +6,13 @@ class ErrorsStore {
/* Actions */
@action add = (message: string): void => {
@action
add = (message: string): void => {
this.data.push(message);
};
@action remove = (index: number): void => {
@action
remove = (index: number): void => {
this.data.splice(index, 1);
};
}

View File

@ -11,39 +11,47 @@ class UiStore {
@observable editMode: boolean = false;
/* Actions */
@action setActiveModal = (name: string, props: ?Object): void => {
@action
setActiveModal = (name: string, props: ?Object): void => {
this.activeModalName = name;
this.activeModalProps = props;
};
@action clearActiveModal = (): void => {
@action
clearActiveModal = (): void => {
this.activeModalName = undefined;
this.activeModalProps = undefined;
};
@action setActiveDocument = (document: Document): void => {
@action
setActiveDocument = (document: Document): void => {
this.activeDocumentId = document.id;
this.activeCollectionId = document.collection.id;
};
@action clearActiveDocument = (): void => {
@action
clearActiveDocument = (): void => {
this.activeDocumentId = undefined;
this.activeCollectionId = undefined;
};
@action enableEditMode() {
@action
enableEditMode() {
this.editMode = true;
}
@action disableEditMode() {
@action
disableEditMode() {
this.editMode = false;
}
@action enableProgressBar() {
@action
enableProgressBar() {
this.progressBarVisible = true;
}
@action disableProgressBar() {
@action
disableProgressBar() {
this.progressBarVisible = false;
}
}