chore: Upgrade Prettier 1.8 -> 2.0 (#1436)

This commit is contained in:
Tom Moor
2020-08-08 18:53:11 -07:00
committed by GitHub
parent 68dcb4de5f
commit e312b264a6
218 changed files with 1156 additions and 1169 deletions

View File

@ -12,7 +12,7 @@ export const Action = styled(Flex)`
flex-shrink: 0; flex-shrink: 0;
a { a {
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
height: 24px; height: 24px;
} }
@ -26,7 +26,7 @@ export const Separator = styled.div`
margin-left: 12px; margin-left: 12px;
width: 1px; width: 1px;
height: 28px; height: 28px;
background: ${props => props.theme.divider}; background: ${(props) => props.theme.divider};
`; `;
const Actions = styled(Flex)` const Actions = styled(Flex)`
@ -35,8 +35,8 @@ const Actions = styled(Flex)`
right: 0; right: 0;
left: 0; left: 0;
border-radius: 3px; border-radius: 3px;
background: ${props => props.theme.background}; background: ${(props) => props.theme.background};
transition: ${props => props.theme.backgroundTransition}; transition: ${(props) => props.theme.backgroundTransition};
padding: 12px; padding: 12px;
-webkit-backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);

View File

@ -14,7 +14,7 @@ export default class Analytics extends React.Component<Props> {
// standard Google Analytics script // standard Google Analytics script
window.ga = window.ga =
window.ga || window.ga ||
function() { function () {
// $FlowIssue // $FlowIssue
(ga.q = ga.q || []).push(arguments); (ga.q = ga.q || []).push(arguments);
}; };

View File

@ -48,8 +48,8 @@ const IconWrapper = styled.div`
position: absolute; position: absolute;
bottom: -2px; bottom: -2px;
right: -2px; right: -2px;
background: ${props => props.theme.primary}; background: ${(props) => props.theme.primary};
border: 2px solid ${props => props.theme.background}; border: 2px solid ${(props) => props.theme.background};
border-radius: 100%; border-radius: 100%;
width: 20px; width: 20px;
height: 20px; height: 20px;
@ -57,10 +57,10 @@ const IconWrapper = styled.div`
const CircleImg = styled.img` const CircleImg = styled.img`
display: block; display: block;
width: ${props => props.size}px; width: ${(props) => props.size}px;
height: ${props => props.size}px; height: ${(props) => props.size}px;
border-radius: 50%; border-radius: 50%;
border: 2px solid ${props => props.theme.background}; border: 2px solid ${(props) => props.theme.background};
flex-shrink: 0; flex-shrink: 0;
`; `;

View File

@ -47,7 +47,9 @@ class AvatarWithPresence extends React.Component<Props> {
<strong>{user.name}</strong> {isCurrentUser && "(You)"} <strong>{user.name}</strong> {isCurrentUser && "(You)"}
<br /> <br />
{isPresent {isPresent
? isEditing ? "currently editing" : "currently viewing" ? isEditing
? "currently editing"
: "currently viewing"
: `viewed ${distanceInWordsToNow(new Date(lastViewedAt))} ago`} : `viewed ${distanceInWordsToNow(new Date(lastViewedAt))} ago`}
</Centered> </Centered>
} }
@ -77,7 +79,7 @@ const Centered = styled.div`
`; `;
const AvatarWrapper = styled.div` const AvatarWrapper = styled.div`
opacity: ${props => (props.isPresent ? 1 : 0.5)}; opacity: ${(props) => (props.isPresent ? 1 : 0.5)};
transition: opacity 250ms ease-in-out; transition: opacity 250ms ease-in-out;
`; `;

View File

@ -11,7 +11,8 @@ type Props = {
function Branding({ href = env.URL }: Props) { function Branding({ href = env.URL }: Props) {
return ( return (
<Link href={href}> <Link href={href}>
<OutlineLogo size={16} />&nbsp;Outline <OutlineLogo size={16} />
&nbsp;Outline
</Link> </Link>
); );
} }
@ -25,17 +26,17 @@ const Link = styled.a`
font-size: 14px; font-size: 14px;
text-decoration: none; text-decoration: none;
border-top-right-radius: 2px; border-top-right-radius: 2px;
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
display: flex; display: flex;
align-items: center; align-items: center;
padding: 16px; padding: 16px;
svg { svg {
fill: ${props => props.theme.text}; fill: ${(props) => props.theme.text};
} }
&:hover { &:hover {
background: ${props => props.theme.sidebarBackground}; background: ${(props) => props.theme.sidebarBackground};
} }
`; `;

View File

@ -40,7 +40,7 @@ const Breadcrumb = observer(({ document, collections, onlyText }: Props) => {
</React.Fragment> </React.Fragment>
)} )}
{collection.name} {collection.name}
{path.map(n => ( {path.map((n) => (
<React.Fragment key={n.id}> <React.Fragment key={n.id}>
<SmallSlash /> <SmallSlash />
{n.title} {n.title}
@ -61,7 +61,8 @@ const Breadcrumb = observer(({ document, collections, onlyText }: Props) => {
{isTemplate && ( {isTemplate && (
<React.Fragment> <React.Fragment>
<CollectionName to="/templates"> <CollectionName to="/templates">
<ShapesIcon color="currentColor" />&nbsp; <ShapesIcon color="currentColor" />
&nbsp;
<span>Templates</span> <span>Templates</span>
</CollectionName> </CollectionName>
<Slash /> <Slash />
@ -70,14 +71,16 @@ const Breadcrumb = observer(({ document, collections, onlyText }: Props) => {
{isDraft && ( {isDraft && (
<React.Fragment> <React.Fragment>
<CollectionName to="/drafts"> <CollectionName to="/drafts">
<EditIcon color="currentColor" />&nbsp; <EditIcon color="currentColor" />
&nbsp;
<span>Drafts</span> <span>Drafts</span>
</CollectionName> </CollectionName>
<Slash /> <Slash />
</React.Fragment> </React.Fragment>
)} )}
<CollectionName to={collectionUrl(collection.id)}> <CollectionName to={collectionUrl(collection.id)}>
<CollectionIcon collection={collection} expanded />&nbsp; <CollectionIcon collection={collection} expanded />
&nbsp;
<span>{collection.name}</span> <span>{collection.name}</span>
</CollectionName> </CollectionName>
{isNestedDocument && ( {isNestedDocument && (
@ -119,7 +122,7 @@ const SmallSlash = styled(GoToIcon)`
export const Slash = styled(GoToIcon)` export const Slash = styled(GoToIcon)`
flex-shrink: 0; flex-shrink: 0;
fill: ${props => props.theme.divider}; fill: ${(props) => props.theme.divider};
`; `;
const Overflow = styled(MoreIcon)` const Overflow = styled(MoreIcon)`
@ -134,7 +137,7 @@ const Overflow = styled(MoreIcon)`
`; `;
const Crumb = styled(Link)` const Crumb = styled(Link)`
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
font-size: 15px; font-size: 15px;
height: 24px; height: 24px;
text-overflow: ellipsis; text-overflow: ellipsis;
@ -149,7 +152,7 @@ const Crumb = styled(Link)`
const CollectionName = styled(Link)` const CollectionName = styled(Link)`
display: flex; display: flex;
flex-shrink: 0; flex-shrink: 0;
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
font-size: 15px; font-size: 15px;
font-weight: 500; font-weight: 500;
white-space: nowrap; white-space: nowrap;

View File

@ -14,7 +14,7 @@ export default class BreadcrumbMenu extends React.Component<Props> {
return ( return (
<DropdownMenu label={this.props.label} position="center"> <DropdownMenu label={this.props.label} position="center">
{path.map(item => ( {path.map((item) => (
<DropdownMenuItem as={Link} to={item.url} key={item.id}> <DropdownMenuItem as={Link} to={item.url} key={item.id}>
{item.title} {item.title}
</DropdownMenuItem> </DropdownMenuItem>

View File

@ -5,13 +5,13 @@ import { darken, lighten } from "polished";
import { ExpandedIcon } from "outline-icons"; import { ExpandedIcon } from "outline-icons";
const RealButton = styled.button` const RealButton = styled.button`
display: ${props => (props.fullwidth ? "block" : "inline-block")}; display: ${(props) => (props.fullwidth ? "block" : "inline-block")};
width: ${props => (props.fullwidth ? "100%" : "auto")}; width: ${(props) => (props.fullwidth ? "100%" : "auto")};
margin: 0; margin: 0;
padding: 0; padding: 0;
border: 0; border: 0;
background: ${props => props.theme.buttonBackground}; background: ${(props) => props.theme.buttonBackground};
color: ${props => props.theme.buttonText}; color: ${(props) => props.theme.buttonText};
box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 2px; box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 2px;
border-radius: 4px; border-radius: 4px;
font-size: 14px; font-size: 14px;
@ -24,7 +24,7 @@ const RealButton = styled.button`
user-select: none; user-select: none;
svg { svg {
fill: ${props => props.iconColor || props.theme.buttonText}; fill: ${(props) => props.iconColor || props.theme.buttonText};
} }
&::-moz-focus-inner { &::-moz-focus-inner {
@ -33,12 +33,12 @@ const RealButton = styled.button`
} }
&:hover { &:hover {
background: ${props => darken(0.05, props.theme.buttonBackground)}; background: ${(props) => darken(0.05, props.theme.buttonBackground)};
} }
&:focus { &:focus {
transition-duration: 0.05s; transition-duration: 0.05s;
box-shadow: ${props => lighten(0.4, props.theme.buttonBackground)} 0px 0px box-shadow: ${(props) => lighten(0.4, props.theme.buttonBackground)} 0px 0px
0px 3px; 0px 3px;
outline: none; outline: none;
} }
@ -46,10 +46,10 @@ const RealButton = styled.button`
&:disabled { &:disabled {
cursor: default; cursor: default;
pointer-events: none; pointer-events: none;
color: ${props => props.theme.white50}; color: ${(props) => props.theme.white50};
} }
${props => ${(props) =>
props.neutral && props.neutral &&
` `
background: ${props.theme.buttonNeutralBackground}; background: ${props.theme.buttonNeutralBackground};
@ -80,9 +80,9 @@ const RealButton = styled.button`
&:disabled { &:disabled {
color: ${props.theme.textTertiary}; color: ${props.theme.textTertiary};
} }
`} ${props => `} ${(props) =>
props.danger && props.danger &&
` `
background: ${props.theme.danger}; background: ${props.theme.danger};
color: ${props.theme.white}; color: ${props.theme.white};
@ -103,20 +103,20 @@ const Label = styled.span`
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
${props => props.hasIcon && "padding-left: 4px;"}; ${(props) => props.hasIcon && "padding-left: 4px;"};
`; `;
export const Inner = styled.span` export const Inner = styled.span`
display: flex; display: flex;
padding: 0 8px; padding: 0 8px;
padding-right: ${props => (props.disclosure ? 2 : 8)}px; padding-right: ${(props) => (props.disclosure ? 2 : 8)}px;
line-height: ${props => (props.hasIcon ? 24 : 32)}px; line-height: ${(props) => (props.hasIcon ? 24 : 32)}px;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
min-height: 30px; min-height: 30px;
${props => props.hasIcon && props.hasText && "padding-left: 4px;"}; ${(props) => props.hasIcon && props.hasText && "padding-left: 4px;"};
${props => props.hasIcon && !props.hasText && "padding: 0 4px;"}; ${(props) => props.hasIcon && !props.hasText && "padding: 0 4px;"};
`; `;
export type Props = { export type Props = {

View File

@ -15,13 +15,13 @@ export type Props = {
const LabelText = styled.span` const LabelText = styled.span`
font-weight: 500; font-weight: 500;
margin-left: ${props => (props.small ? "6px" : "10px")}; margin-left: ${(props) => (props.small ? "6px" : "10px")};
${props => (props.small ? `color: ${props.theme.textSecondary}` : "")}; ${(props) => (props.small ? `color: ${props.theme.textSecondary}` : "")};
`; `;
const Wrapper = styled.div` const Wrapper = styled.div`
padding-bottom: 8px; padding-bottom: 8px;
${props => (props.small ? "font-size: 14px" : "")}; ${(props) => (props.small ? "font-size: 14px" : "")};
`; `;
const Label = styled.label` const Label = styled.label`

View File

@ -32,27 +32,27 @@ class Collaborators extends React.Component<Props> {
const documentViews = views.inDocument(document.id); const documentViews = views.inDocument(document.id);
const presentIds = documentPresence.map(p => p.userId); const presentIds = documentPresence.map((p) => p.userId);
const editingIds = documentPresence const editingIds = documentPresence
.filter(p => p.isEditing) .filter((p) => p.isEditing)
.map(p => p.userId); .map((p) => p.userId);
// ensure currently present via websocket are always ordered first // ensure currently present via websocket are always ordered first
const mostRecentViewers = sortBy( const mostRecentViewers = sortBy(
documentViews.slice(0, MAX_AVATAR_DISPLAY), documentViews.slice(0, MAX_AVATAR_DISPLAY),
view => { (view) => {
return presentIds.includes(view.user.id); return presentIds.includes(view.user.id);
} }
); );
const viewersKeyedByUserId = keyBy(mostRecentViewers, v => v.user.id); const viewersKeyedByUserId = keyBy(mostRecentViewers, (v) => v.user.id);
const overflow = documentViews.length - mostRecentViewers.length; const overflow = documentViews.length - mostRecentViewers.length;
return ( return (
<Facepile <Facepile
users={mostRecentViewers.map(v => v.user)} users={mostRecentViewers.map((v) => v.user)}
overflow={overflow} overflow={overflow}
renderAvatar={user => { renderAvatar={(user) => {
const isPresent = presentIds.includes(user.id); const isPresent = presentIds.includes(user.id);
const isEditing = editingIds.includes(user.id); const isEditing = editingIds.includes(user.id);
const { lastViewedAt } = viewersKeyedByUserId[user.id]; const { lastViewedAt } = viewersKeyedByUserId[user.id];

View File

@ -133,16 +133,16 @@ const Wrapper = styled(Flex)`
top: 0; top: 0;
right: 0; right: 0;
z-index: 1; z-index: 1;
min-width: ${props => props.theme.sidebarWidth}; min-width: ${(props) => props.theme.sidebarWidth};
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
overscroll-behavior: none; overscroll-behavior: none;
`; `;
const Sidebar = styled(Flex)` const Sidebar = styled(Flex)`
background: ${props => props.theme.background}; background: ${(props) => props.theme.background};
min-width: ${props => props.theme.sidebarWidth}; min-width: ${(props) => props.theme.sidebarWidth};
border-left: 1px solid ${props => props.theme.divider}; border-left: 1px solid ${(props) => props.theme.divider};
z-index: 1; z-index: 1;
`; `;

View File

@ -66,7 +66,7 @@ const StyledRevisionMenu = styled(RevisionMenu)`
`; `;
const StyledNavLink = styled(NavLink)` const StyledNavLink = styled(NavLink)`
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
display: block; display: block;
padding: 8px 16px; padding: 8px 16px;
font-size: 15px; font-size: 15px;

View File

@ -17,7 +17,7 @@ export default function DocumentList({ limit, documents, ...rest }: Props) {
mode={ArrowKeyNavigation.mode.VERTICAL} mode={ArrowKeyNavigation.mode.VERTICAL}
defaultActiveChildIndex={0} defaultActiveChildIndex={0}
> >
{items.map(document => ( {items.map((document) => (
<DocumentPreview key={document.id} document={document} {...rest} /> <DocumentPreview key={document.id} document={document} {...rest} />
))} ))}
</ArrowKeyNavigation> </ArrowKeyNavigation>

View File

@ -48,7 +48,7 @@ class DocumentPreview extends React.Component<Props> {
return tag.replace(/<b\b[^>]*>(.*?)<\/b>/gi, "$1"); return tag.replace(/<b\b[^>]*>(.*?)<\/b>/gi, "$1");
}; };
handleNewFromTemplate = event => { handleNewFromTemplate = (event) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
@ -97,18 +97,14 @@ class DocumentPreview extends React.Component<Props> {
)} )}
</Actions> </Actions>
)} )}
{document.isDraft && {document.isDraft && showDraft && (
showDraft && ( <Tooltip tooltip="Only visible to you" delay={500} placement="top">
<Tooltip <Badge>Draft</Badge>
tooltip="Only visible to you" </Tooltip>
delay={500} )}
placement="top" {document.isTemplate && showTemplate && (
> <Badge primary>Template</Badge>
<Badge>Draft</Badge> )}
</Tooltip>
)}
{document.isTemplate &&
showTemplate && <Badge primary>Template</Badge>}
<SecondaryActions> <SecondaryActions>
{document.isTemplate && {document.isTemplate &&
!document.isArchived && !document.isArchived &&
@ -120,7 +116,8 @@ class DocumentPreview extends React.Component<Props> {
> >
New doc New doc
</Button> </Button>
)}&nbsp; )}
&nbsp;
<DocumentMenu document={document} showPin={showPin} /> <DocumentMenu document={document} showPin={showPin} />
</SecondaryActions> </SecondaryActions>
</Heading> </Heading>
@ -146,7 +143,7 @@ const StyledStar = withTheme(styled(({ solid, theme, ...props }) => (
<StarredIcon color={theme.text} {...props} /> <StarredIcon color={theme.text} {...props} />
))` ))`
flex-shrink: 0; flex-shrink: 0;
opacity: ${props => (props.solid ? "1 !important" : 0)}; opacity: ${(props) => (props.solid ? "1 !important" : 0)};
transition: all 100ms ease-in-out; transition: all 100ms ease-in-out;
&:hover { &:hover {
@ -182,7 +179,7 @@ const DocumentLink = styled(Link)`
&:hover, &:hover,
&:active, &:active,
&:focus { &:focus {
background: ${props => props.theme.listItemHoverBackground}; background: ${(props) => props.theme.listItemHoverBackground};
outline: none; outline: none;
${SecondaryActions} { ${SecondaryActions} {
@ -207,7 +204,7 @@ const Heading = styled.h3`
margin-bottom: 0.25em; margin-bottom: 0.25em;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
`; `;
@ -225,7 +222,7 @@ const Title = styled(Highlight)`
const ResultContext = styled(Highlight)` const ResultContext = styled(Highlight)`
display: block; display: block;
color: ${props => props.theme.textTertiary}; color: ${(props) => props.theme.textTertiary};
font-size: 14px; font-size: 14px;
margin-top: -0.25em; margin-top: -0.25em;
margin-bottom: 0.25em; margin-bottom: 0.25em;

View File

@ -30,12 +30,12 @@ type Props = {
export const GlobalStyles = createGlobalStyle` export const GlobalStyles = createGlobalStyle`
.activeDropZone { .activeDropZone {
border-radius: 4px; border-radius: 4px;
background: ${props => props.theme.slateDark}; background: ${(props) => props.theme.slateDark};
svg { fill: ${props => props.theme.white}; } svg { fill: ${(props) => props.theme.white}; }
} }
.activeDropZone a { .activeDropZone a {
color: ${props => props.theme.white} !important; color: ${(props) => props.theme.white} !important;
} }
`; `;

View File

@ -204,7 +204,7 @@ class DropdownMenu extends React.Component<Props> {
onClick={ onClick={
typeof children === "function" typeof children === "function"
? undefined ? undefined
: ev => { : (ev) => {
ev.stopPropagation(); ev.stopPropagation();
closePortal(); closePortal();
} }
@ -245,24 +245,24 @@ const Position = styled.div`
${({ bottom }) => (bottom !== undefined ? `bottom: ${bottom}px` : "")}; ${({ bottom }) => (bottom !== undefined ? `bottom: ${bottom}px` : "")};
max-height: 75%; max-height: 75%;
z-index: 1000; z-index: 1000;
transform: ${props => transform: ${(props) =>
props.position === "center" ? "translateX(-50%)" : "initial"}; props.position === "center" ? "translateX(-50%)" : "initial"};
pointer-events: none; pointer-events: none;
`; `;
const Menu = styled.div` const Menu = styled.div`
animation: ${fadeAndScaleIn} 200ms ease; animation: ${fadeAndScaleIn} 200ms ease;
transform-origin: ${props => (props.left !== undefined ? "25%" : "75%")} 0; transform-origin: ${(props) => (props.left !== undefined ? "25%" : "75%")} 0;
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
background: ${props => rgba(props.theme.menuBackground, 0.8)}; background: ${(props) => rgba(props.theme.menuBackground, 0.8)};
border: ${props => border: ${(props) =>
props.theme.menuBorder ? `1px solid ${props.theme.menuBorder}` : "none"}; props.theme.menuBorder ? `1px solid ${props.theme.menuBorder}` : "none"};
border-radius: 2px; border-radius: 2px;
padding: 0.5em 0; padding: 0.5em 0;
min-width: 180px; min-width: 180px;
overflow: hidden; overflow: hidden;
overflow-y: auto; overflow-y: auto;
box-shadow: ${props => props.theme.menuShadow}; box-shadow: ${(props) => props.theme.menuShadow};
pointer-events: all; pointer-events: all;
hr { hr {
@ -278,7 +278,7 @@ export const Header = styled.h3`
font-size: 11px; font-size: 11px;
font-weight: 600; font-weight: 600;
text-transform: uppercase; text-transform: uppercase;
color: ${props => props.theme.sidebarText}; color: ${(props) => props.theme.sidebarText};
letter-spacing: 0.04em; letter-spacing: 0.04em;
margin: 1em 12px 0.5em; margin: 1em 12px 0.5em;
`; `;

View File

@ -29,7 +29,8 @@ const DropdownMenuItem = ({
<React.Fragment> <React.Fragment>
<CheckmarkIcon <CheckmarkIcon
color={selected === false ? "transparent" : undefined} color={selected === false ? "transparent" : undefined}
/>&nbsp; />
&nbsp;
</React.Fragment> </React.Fragment>
)} )}
{children} {children}
@ -44,7 +45,7 @@ const MenuItem = styled.a`
width: 100%; width: 100%;
min-height: 32px; min-height: 32px;
color: ${props => color: ${(props) =>
props.disabled ? props.theme.textTertiary : props.theme.textSecondary}; props.disabled ? props.theme.textTertiary : props.theme.textSecondary};
justify-content: left; justify-content: left;
align-items: center; align-items: center;
@ -57,10 +58,10 @@ const MenuItem = styled.a`
} }
svg { svg {
opacity: ${props => (props.disabled ? ".5" : 1)}; opacity: ${(props) => (props.disabled ? ".5" : 1)};
} }
${props => ${(props) =>
props.disabled props.disabled
? "pointer-events: none;" ? "pointer-events: none;"
: ` : `

View File

@ -81,11 +81,11 @@ class Editor extends React.Component<Props> {
} }
const StyledEditor = styled(RichMarkdownEditor)` const StyledEditor = styled(RichMarkdownEditor)`
flex-grow: ${props => (props.grow ? 1 : 0)}; flex-grow: ${(props) => (props.grow ? 1 : 0)};
justify-content: start; justify-content: start;
> div { > div {
transition: ${props => props.theme.backgroundTransition}; transition: ${(props) => props.theme.backgroundTransition};
} }
.notice-block.tip, .notice-block.tip,
@ -95,13 +95,13 @@ const StyledEditor = styled(RichMarkdownEditor)`
p { p {
a { a {
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
border-bottom: 1px solid ${props => lighten(0.5, props.theme.text)}; border-bottom: 1px solid ${(props) => lighten(0.5, props.theme.text)};
text-decoration: none !important; text-decoration: none !important;
font-weight: 500; font-weight: 500;
&:hover { &:hover {
border-bottom: 1px solid ${props => props.theme.text}; border-bottom: 1px solid ${(props) => props.theme.text};
text-decoration: none; text-decoration: none;
} }
} }

View File

@ -2,7 +2,7 @@
import styled from "styled-components"; import styled from "styled-components";
const Empty = styled.p` const Empty = styled.p`
color: ${props => props.theme.textTertiary}; color: ${(props) => props.theme.textTertiary};
`; `;
export default Empty; export default Empty;

View File

@ -48,9 +48,9 @@ class ErrorBoundary extends React.Component<Props> {
<PageTitle title="Something Unexpected Happened" /> <PageTitle title="Something Unexpected Happened" />
<h1>Something Unexpected Happened</h1> <h1>Something Unexpected Happened</h1>
<HelpText> <HelpText>
Sorry, an unrecoverable error occurred{isReported && Sorry, an unrecoverable error occurred
" our engineers have been notified"}. Please try reloading the {isReported && " our engineers have been notified"}. Please try
page, it may have been a temporary glitch. reloading the page, it may have been a temporary glitch.
</HelpText> </HelpText>
{this.showDetails && <Pre>{this.error.toString()}</Pre>} {this.showDetails && <Pre>{this.error.toString()}</Pre>}
<p> <p>
@ -73,7 +73,7 @@ class ErrorBoundary extends React.Component<Props> {
} }
const Pre = styled.pre` const Pre = styled.pre`
background: ${props => props.theme.smoke}; background: ${(props) => props.theme.smoke};
padding: 16px; padding: 16px;
border-radius: 4px; border-radius: 4px;
font-size: 12px; font-size: 12px;

View File

@ -31,7 +31,7 @@ class Facepile extends React.Component<Props> {
<span>+{overflow}</span> <span>+{overflow}</span>
</More> </More>
)} )}
{users.map(user => ( {users.map((user) => (
<AvatarWrapper key={user.id}>{renderAvatar(user)}</AvatarWrapper> <AvatarWrapper key={user.id}>{renderAvatar(user)}</AvatarWrapper>
))} ))}
</Avatars> </Avatars>
@ -56,12 +56,12 @@ const More = styled.div`
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
min-width: ${props => props.size}px; min-width: ${(props) => props.size}px;
height: ${props => props.size}px; height: ${(props) => props.size}px;
border-radius: 100%; border-radius: 100%;
background: ${props => props.theme.slate}; background: ${(props) => props.theme.slate};
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
border: 2px solid ${props => props.theme.background}; border: 2px solid ${(props) => props.theme.background};
text-align: center; text-align: center;
font-size: 11px; font-size: 11px;
font-weight: 600; font-weight: 600;

View File

@ -3,7 +3,7 @@ import styled from "styled-components";
import { fadeIn } from "shared/styles/animations"; import { fadeIn } from "shared/styles/animations";
const Fade = styled.span` const Fade = styled.span`
animation: ${fadeIn} ${props => props.timing || "250ms"} ease-in-out; animation: ${fadeIn} ${(props) => props.timing || "250ms"} ease-in-out;
`; `;
export default Fade; export default Fade;

View File

@ -41,7 +41,7 @@ class GroupListItem extends React.Component<Props> {
const membershipsInGroup = groupMemberships.inGroup(group.id); const membershipsInGroup = groupMemberships.inGroup(group.id);
const users = membershipsInGroup const users = membershipsInGroup
.slice(0, MAX_AVATAR_DISPLAY) .slice(0, MAX_AVATAR_DISPLAY)
.map(gm => gm.user); .map((gm) => gm.user);
const overflow = memberCount - users.length; const overflow = memberCount - users.length;

View File

@ -3,8 +3,8 @@ import styled from "styled-components";
const HelpText = styled.p` const HelpText = styled.p`
margin-top: 0; margin-top: 0;
color: ${props => props.theme.textSecondary}; color: ${(props) => props.theme.textSecondary};
font-size: ${props => (props.small ? "13px" : "inherit")}; font-size: ${(props) => (props.small ? "13px" : "inherit")};
`; `;
export default HelpText; export default HelpText;

View File

@ -38,7 +38,7 @@ function Highlight({
} }
const Mark = styled.mark` const Mark = styled.mark`
background: ${props => props.theme.yellow}; background: ${(props) => props.theme.yellow};
border-radius: 2px; border-radius: 2px;
padding: 0 4px; padding: 0 4px;
`; `;

View File

@ -57,42 +57,39 @@ function HoverPreview({ node, documents, onClose, event }: Props) {
} }
}; };
React.useEffect( React.useEffect(() => {
() => { if (slug) {
if (slug) { documents.prefetchDocument(slug, {
documents.prefetchDocument(slug, { prefetch: true,
prefetch: true, });
}); }
}
startOpenTimer(); startOpenTimer();
if (cardRef.current) {
cardRef.current.addEventListener("mouseenter", stopCloseTimer);
cardRef.current.addEventListener("mouseleave", startCloseTimer);
}
node.addEventListener("mouseout", startCloseTimer);
node.addEventListener("mouseover", stopCloseTimer);
node.addEventListener("mouseover", startOpenTimer);
return () => {
node.removeEventListener("mouseout", startCloseTimer);
node.removeEventListener("mouseover", stopCloseTimer);
node.removeEventListener("mouseover", startOpenTimer);
if (cardRef.current) { if (cardRef.current) {
cardRef.current.addEventListener("mouseenter", stopCloseTimer); cardRef.current.removeEventListener("mouseenter", stopCloseTimer);
cardRef.current.addEventListener("mouseleave", startCloseTimer); cardRef.current.removeEventListener("mouseleave", startCloseTimer);
} }
node.addEventListener("mouseout", startCloseTimer); if (timerClose.current) {
node.addEventListener("mouseover", stopCloseTimer); clearTimeout(timerClose.current);
node.addEventListener("mouseover", startOpenTimer); }
};
return () => { }, [node]);
node.removeEventListener("mouseout", startCloseTimer);
node.removeEventListener("mouseover", stopCloseTimer);
node.removeEventListener("mouseover", startOpenTimer);
if (cardRef.current) {
cardRef.current.removeEventListener("mouseenter", stopCloseTimer);
cardRef.current.removeEventListener("mouseleave", startCloseTimer);
}
if (timerClose.current) {
clearTimeout(timerClose.current);
}
};
},
[node]
);
const anchorBounds = node.getBoundingClientRect(); const anchorBounds = node.getBoundingClientRect();
const cardBounds = cardRef.current const cardBounds = cardRef.current
@ -112,7 +109,7 @@ function HoverPreview({ node, documents, onClose, event }: Props) {
> >
<div ref={cardRef}> <div ref={cardRef}>
<HoverPreviewDocument url={node.href}> <HoverPreviewDocument url={node.href}>
{content => {(content) =>
isVisible ? ( isVisible ? (
<Animate> <Animate>
<Card> <Card>
@ -156,8 +153,8 @@ const CardContent = styled.div`
// &:after — gradient mask for overflow text // &:after — gradient mask for overflow text
const Card = styled.div` const Card = styled.div`
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
background: ${props => props.theme.background}; background: ${(props) => props.theme.background};
border: ${props => border: ${(props) =>
props.theme.menuBorder ? `1px solid ${props.theme.menuBorder}` : "none"}; props.theme.menuBorder ? `1px solid ${props.theme.menuBorder}` : "none"};
border-radius: 4px; border-radius: 4px;
box-shadow: 0 30px 90px -20px rgba(0, 0, 0, 0.3), box-shadow: 0 30px 90px -20px rgba(0, 0, 0, 0.3),
@ -179,15 +176,15 @@ const Card = styled.div`
pointer-events: none; pointer-events: none;
background: linear-gradient( background: linear-gradient(
90deg, 90deg,
${props => transparentize(1, props.theme.background)} 0%, ${(props) => transparentize(1, props.theme.background)} 0%,
${props => transparentize(1, props.theme.background)} 75%, ${(props) => transparentize(1, props.theme.background)} 75%,
${props => props.theme.background} 90% ${(props) => props.theme.background} 90%
); );
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
height: 1.7em; height: 1.7em;
border-bottom: 16px solid ${props => props.theme.background}; border-bottom: 16px solid ${(props) => props.theme.background};
border-bottom-left-radius: 4px; border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px; border-bottom-right-radius: 4px;
} }
@ -205,7 +202,7 @@ const Position = styled.div`
const Pointer = styled.div` const Pointer = styled.div`
top: -22px; top: -22px;
left: ${props => props.offset}px; left: ${(props) => props.offset}px;
width: 22px; width: 22px;
height: 22px; height: 22px;
position: absolute; position: absolute;
@ -222,14 +219,14 @@ const Pointer = styled.div`
&:before { &:before {
border: 8px solid transparent; border: 8px solid transparent;
border-bottom-color: ${props => border-bottom-color: ${(props) =>
props.theme.menuBorder || "rgba(0, 0, 0, 0.1)"}; props.theme.menuBorder || "rgba(0, 0, 0, 0.1)"};
right: -1px; right: -1px;
} }
&:after { &:after {
border: 7px solid transparent; border: 7px solid transparent;
border-bottom-color: ${props => props.theme.background}; border-bottom-color: ${(props) => props.theme.background};
} }
`; `;

View File

@ -11,7 +11,7 @@ import DocumentMeta from "components/DocumentMeta";
type Props = { type Props = {
url: string, url: string,
documents: DocumentsStore, documents: DocumentsStore,
children: React.Node => React.Node, children: (React.Node) => React.Node,
}; };
function HoverPreviewDocument({ url, documents, children }: Props) { function HoverPreviewDocument({ url, documents, children }: Props) {
@ -45,7 +45,7 @@ const Content = styled(Link)`
const Heading = styled.h2` const Heading = styled.h2`
margin: 0 0 0.75em; margin: 0 0 0.75em;
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
`; `;
export default inject("documents")(observer(HoverPreviewDocument)); export default inject("documents")(observer(HoverPreviewDocument));

View File

@ -166,7 +166,7 @@ class IconPicker extends React.Component<Props> {
const Component = icons[this.props.icon || "collection"].component; const Component = icons[this.props.icon || "collection"].component;
return ( return (
<Wrapper ref={ref => (this.node = ref)}> <Wrapper ref={(ref) => (this.node = ref)}>
<label> <label>
<LabelText>Icon</LabelText> <LabelText>Icon</LabelText>
</label> </label>
@ -179,7 +179,7 @@ class IconPicker extends React.Component<Props> {
} }
> >
<Icons onClick={preventEventBubble}> <Icons onClick={preventEventBubble}>
{Object.keys(icons).map(name => { {Object.keys(icons).map((name) => {
const Component = icons[name].component; const Component = icons[name].component;
return ( return (
<IconButton <IconButton
@ -195,7 +195,7 @@ class IconPicker extends React.Component<Props> {
<Flex onClick={preventEventBubble}> <Flex onClick={preventEventBubble}>
<ColorPicker <ColorPicker
color={this.props.color} color={this.props.color}
onChange={color => onChange={(color) =>
this.props.onChange(color.hex, this.props.icon) this.props.onChange(color.hex, this.props.icon)
} }
colors={colors} colors={colors}
@ -214,7 +214,7 @@ const Icons = styled.div`
`; `;
const LabelButton = styled(NudeButton)` const LabelButton = styled(NudeButton)`
border: 1px solid ${props => props.theme.inputBorder}; border: 1px solid ${(props) => props.theme.inputBorder};
width: 32px; width: 32px;
height: 32px; height: 32px;
`; `;

View File

@ -9,29 +9,29 @@ import Flex from "components/Flex";
const RealTextarea = styled.textarea` const RealTextarea = styled.textarea`
border: 0; border: 0;
flex: 1; flex: 1;
padding: 8px 12px 8px ${props => (props.hasIcon ? "8px" : "12px")}; padding: 8px 12px 8px ${(props) => (props.hasIcon ? "8px" : "12px")};
outline: none; outline: none;
background: none; background: none;
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
&:disabled, &:disabled,
&::placeholder { &::placeholder {
color: ${props => props.theme.placeholder}; color: ${(props) => props.theme.placeholder};
} }
`; `;
const RealInput = styled.input` const RealInput = styled.input`
border: 0; border: 0;
flex: 1; flex: 1;
padding: 8px 12px 8px ${props => (props.hasIcon ? "8px" : "12px")}; padding: 8px 12px 8px ${(props) => (props.hasIcon ? "8px" : "12px")};
outline: none; outline: none;
background: none; background: none;
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
height: 30px; height: 30px;
&:disabled, &:disabled,
&::placeholder { &::placeholder {
color: ${props => props.theme.placeholder}; color: ${(props) => props.theme.placeholder};
} }
&::-webkit-search-cancel-button { &::-webkit-search-cancel-button {
@ -40,8 +40,8 @@ const RealInput = styled.input`
`; `;
const Wrapper = styled.div` const Wrapper = styled.div`
flex: ${props => (props.flex ? "1" : "0")}; flex: ${(props) => (props.flex ? "1" : "0")};
max-width: ${props => (props.short ? "350px" : "100%")}; max-width: ${(props) => (props.short ? "350px" : "100%")};
min-height: ${({ minHeight }) => (minHeight ? `${minHeight}px` : "0")}; min-height: ${({ minHeight }) => (minHeight ? `${minHeight}px` : "0")};
max-height: ${({ maxHeight }) => (maxHeight ? `${maxHeight}px` : "initial")}; max-height: ${({ maxHeight }) => (maxHeight ? `${maxHeight}px` : "initial")};
`; `;
@ -56,16 +56,17 @@ const IconWrapper = styled.span`
export const Outline = styled(Flex)` export const Outline = styled(Flex)`
display: flex; display: flex;
flex: 1; flex: 1;
margin: ${props => (props.margin !== undefined ? props.margin : "0 0 16px")}; margin: ${(props) =>
props.margin !== undefined ? props.margin : "0 0 16px"};
color: inherit; color: inherit;
border-width: 1px; border-width: 1px;
border-style: solid; border-style: solid;
border-color: ${props => border-color: ${(props) =>
props.hasError props.hasError
? "red" ? "red"
: props.focused : props.focused
? props.theme.inputBorderFocused ? props.theme.inputBorderFocused
: props.theme.inputBorder}; : props.theme.inputBorder};
border-radius: 4px; border-radius: 4px;
font-weight: normal; font-weight: normal;
align-items: center; align-items: center;
@ -147,7 +148,7 @@ class Input extends React.Component<Props> {
<Outline focused={this.focused} margin={margin}> <Outline focused={this.focused} margin={margin}>
{icon && <IconWrapper>{icon}</IconWrapper>} {icon && <IconWrapper>{icon}</IconWrapper>}
<InputComponent <InputComponent
ref={ref => (this.input = ref)} ref={(ref) => (this.input = ref)}
onBlur={this.handleBlur} onBlur={this.handleBlur}
onFocus={this.handleFocus} onFocus={this.handleFocus}
type={type === "textarea" ? undefined : type} type={type === "textarea" ? undefined : type}

View File

@ -30,7 +30,7 @@ class InputSearch extends React.Component<Props> {
} }
} }
handleSearchInput = ev => { handleSearchInput = (ev) => {
ev.preventDefault(); ev.preventDefault();
this.props.history.push( this.props.history.push(
searchUrl(ev.target.value, this.props.collectionId) searchUrl(ev.target.value, this.props.collectionId)
@ -50,7 +50,7 @@ class InputSearch extends React.Component<Props> {
return ( return (
<InputMaxWidth <InputMaxWidth
ref={ref => (this.input = ref)} ref={(ref) => (this.input = ref)}
type="search" type="search"
placeholder={placeholder} placeholder={placeholder}
onInput={this.handleSearchInput} onInput={this.handleSearchInput}

View File

@ -12,11 +12,11 @@ const Select = styled.select`
padding: 8px 12px; padding: 8px 12px;
outline: none; outline: none;
background: none; background: none;
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
&:disabled, &:disabled,
&::placeholder { &::placeholder {
color: ${props => props.theme.placeholder}; color: ${(props) => props.theme.placeholder};
} }
`; `;
@ -57,7 +57,7 @@ class InputSelect extends React.Component<Props> {
))} ))}
<Outline focused={this.focused} className={className}> <Outline focused={this.focused} className={className}>
<Select onBlur={this.handleBlur} onFocus={this.handleFocus} {...rest}> <Select onBlur={this.handleBlur} onFocus={this.handleFocus} {...rest}>
{options.map(option => ( {options.map((option) => (
<option value={option.value} key={option.value}> <option value={option.value} key={option.value}>
{option.label} {option.label}
</option> </option>

View File

@ -7,13 +7,13 @@ const Key = styled.kbd`
font: 11px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, font: 11px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier,
monospace; monospace;
line-height: 10px; line-height: 10px;
color: ${props => props.theme.almostBlack}; color: ${(props) => props.theme.almostBlack};
vertical-align: middle; vertical-align: middle;
background-color: ${props => props.theme.smokeLight}; background-color: ${(props) => props.theme.smokeLight};
border: solid 1px ${props => props.theme.slateLight}; border: solid 1px ${(props) => props.theme.slateLight};
border-bottom-color: ${props => props.theme.slate}; border-bottom-color: ${(props) => props.theme.slate};
border-radius: 3px; border-radius: 3px;
box-shadow: inset 0 -1px 0 ${props => props.theme.slate}; box-shadow: inset 0 -1px 0 ${(props) => props.theme.slate};
`; `;
export default Key; export default Key;

View File

@ -21,7 +21,7 @@ export const Label = styled(Flex)`
font-size: 13px; font-size: 13px;
font-weight: 500; font-weight: 500;
text-transform: uppercase; text-transform: uppercase;
color: ${props => props.theme.textTertiary}; color: ${(props) => props.theme.textTertiary};
letter-spacing: 0.04em; letter-spacing: 0.04em;
`; `;

View File

@ -142,8 +142,8 @@ class Layout extends React.Component<Props> {
} }
const Container = styled(Flex)` const Container = styled(Flex)`
background: ${props => props.theme.background}; background: ${(props) => props.theme.background};
transition: ${props => props.theme.backgroundTransition}; transition: ${(props) => props.theme.backgroundTransition};
position: relative; position: relative;
width: 100%; width: 100%;
min-height: 100%; min-height: 100%;
@ -158,7 +158,7 @@ const Content = styled(Flex)`
} }
${breakpoint("tablet")` ${breakpoint("tablet")`
margin-left: ${props => (props.editMode ? 0 : props.theme.sidebarWidth)}; margin-left: ${(props) => (props.editMode ? 0 : props.theme.sidebarWidth)};
`}; `};
`; `;

View File

@ -27,9 +27,9 @@ const ListItem = ({ image, title, subtitle, actions }: Props) => {
const Wrapper = styled.li` const Wrapper = styled.li`
display: flex; display: flex;
padding: ${props => (props.compact ? "8px" : "12px")} 0; padding: ${(props) => (props.compact ? "8px" : "12px")} 0;
margin: 0; margin: 0;
border-bottom: 1px solid ${props => props.theme.divider}; border-bottom: 1px solid ${(props) => props.theme.divider};
&:last-child { &:last-child {
border-bottom: 0; border-bottom: 0;
@ -59,7 +59,7 @@ const Content = styled(Flex)`
const Subtitle = styled.p` const Subtitle = styled.p`
margin: 0; margin: 0;
font-size: 14px; font-size: 14px;
color: ${props => props.theme.slate}; color: ${(props) => props.theme.slate};
`; `;
const Actions = styled.div` const Actions = styled.div`

View File

@ -13,7 +13,7 @@ type Props = {
const Placeholder = ({ count }: Props) => { const Placeholder = ({ count }: Props) => {
return ( return (
<Fade> <Fade>
{times(count || 2, index => ( {times(count || 2, (index) => (
<Item key={index} column auto> <Item key={index} column auto>
<Mask /> <Mask />
</Item> </Item>

View File

@ -13,7 +13,7 @@ type Props = {
const ListPlaceHolder = ({ count }: Props) => { const ListPlaceHolder = ({ count }: Props) => {
return ( return (
<Fade> <Fade>
{times(count || 2, index => ( {times(count || 2, (index) => (
<Item key={index} column auto> <Item key={index} column auto>
<Mask header /> <Mask header />
<Mask /> <Mask />

View File

@ -27,10 +27,11 @@ class Mask extends React.Component<Props> {
} }
const Redacted = styled(Flex)` const Redacted = styled(Flex)`
width: ${props => (props.header ? props.width / 2 : props.width)}%; width: ${(props) => (props.header ? props.width / 2 : props.width)}%;
height: ${props => (props.height ? props.height : props.header ? 24 : 18)}px; height: ${(props) =>
props.height ? props.height : props.header ? 24 : 18}px;
margin-bottom: 6px; margin-bottom: 6px;
background-color: ${props => props.theme.divider}; background-color: ${(props) => props.theme.divider};
animation: ${pulsate} 1.3s infinite; animation: ${pulsate} 1.3s infinite;
&:last-child { &:last-child {

View File

@ -21,7 +21,7 @@ type Props = {
const GlobalStyles = createGlobalStyle` const GlobalStyles = createGlobalStyle`
.ReactModal__Overlay { .ReactModal__Overlay {
background-color: ${props => background-color: ${(props) =>
transparentize(0.25, props.theme.background)} !important; transparentize(0.25, props.theme.background)} !important;
z-index: 100; z-index: 100;
} }
@ -30,7 +30,7 @@ const GlobalStyles = createGlobalStyle`
.ReactModalPortal + .ReactModalPortal { .ReactModalPortal + .ReactModalPortal {
.ReactModal__Overlay { .ReactModal__Overlay {
margin-left: 12px; margin-left: 12px;
box-shadow: 0 -2px 10px ${props => props.theme.shadow}; box-shadow: 0 -2px 10px ${(props) => props.theme.shadow};
border-radius: 8px 0 0 8px; border-radius: 8px 0 0 8px;
overflow: hidden; overflow: hidden;
} }
@ -72,7 +72,7 @@ const Modal = ({
isOpen={isOpen} isOpen={isOpen}
{...rest} {...rest}
> >
<Content onClick={ev => ev.stopPropagation()} column> <Content onClick={(ev) => ev.stopPropagation()} column>
{title && <h1>{title}</h1>} {title && <h1>{title}</h1>}
{children} {children}
@ -109,8 +109,8 @@ const StyledModal = styled(ReactModal)`
align-items: flex-start; align-items: flex-start;
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
background: ${props => props.theme.background}; background: ${(props) => props.theme.background};
transition: ${props => props.theme.backgroundTransition}; transition: ${(props) => props.theme.backgroundTransition};
padding: 8vh 2rem 2rem; padding: 8vh 2rem 2rem;
outline: none; outline: none;
@ -133,7 +133,7 @@ const Close = styled(NudeButton)`
right: 0; right: 0;
margin: 12px; margin: 12px;
opacity: 0.75; opacity: 0.75;
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
width: auto; width: auto;
height: auto; height: auto;
@ -153,7 +153,7 @@ const Back = styled(NudeButton)`
top: 2rem; top: 2rem;
left: 2rem; left: 2rem;
opacity: 0.75; opacity: 0.75;
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
width: auto; width: auto;
height: auto; height: auto;

View File

@ -2,8 +2,8 @@
import styled from "styled-components"; import styled from "styled-components";
const Notice = styled.p` const Notice = styled.p`
background: ${props => props.theme.sidebarBackground}; background: ${(props) => props.theme.sidebarBackground};
color: ${props => props.theme.sidebarText}; color: ${(props) => props.theme.sidebarText};
padding: 10px 12px; padding: 10px 12px;
border-radius: 4px; border-radius: 4px;
position: relative; position: relative;

View File

@ -14,7 +14,7 @@ const Button = styled.button`
&:focus { &:focus {
transition-duration: 0.05s; transition-duration: 0.05s;
box-shadow: ${props => lighten(0.4, props.theme.buttonBackground)} 0px 0px box-shadow: ${(props) => lighten(0.4, props.theme.buttonBackground)} 0px 0px
0px 3px; 0px 3px;
outline: none; outline: none;
} }

View File

@ -25,7 +25,7 @@ class PaginatedDocumentList extends React.Component<Props> {
heading={heading} heading={heading}
fetch={fetch} fetch={fetch}
options={options} options={options}
renderItem={item => ( renderItem={(item) => (
<DocumentPreview key={item.id} document={item} {...rest} /> <DocumentPreview key={item.id} document={item} {...rest} />
)} )}
/> />

View File

@ -14,7 +14,7 @@ type Props = {
heading?: React.Node, heading?: React.Node,
empty?: React.Node, empty?: React.Node,
items: any[], items: any[],
renderItem: any => React.Node, renderItem: (any) => React.Node,
}; };
@observer @observer

View File

@ -44,7 +44,7 @@ class PathToDocument extends React.Component<Props> {
<Component ref={ref} onClick={this.handleClick} href="" selectable> <Component ref={ref} onClick={this.handleClick} href="" selectable>
{collection && <CollectionIcon collection={collection} />} {collection && <CollectionIcon collection={collection} />}
{result.path {result.path
.map(doc => <Title key={doc.id}>{doc.title}</Title>) .map((doc) => <Title key={doc.id}>{doc.title}</Title>)
.reduce((prev, curr) => [prev, <StyledGoToIcon />, curr])} .reduce((prev, curr) => [prev, <StyledGoToIcon />, curr])}
{document && ( {document && (
<Flex> <Flex>
@ -73,7 +73,7 @@ const ResultWrapper = styled.div`
margin-left: -4px; margin-left: -4px;
user-select: none; user-select: none;
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
cursor: default; cursor: default;
`; `;
@ -85,7 +85,7 @@ const ResultWrapperLink = styled(ResultWrapper.withComponent("a"))`
&:hover, &:hover,
&:active, &:active,
&:focus { &:focus {
background: ${props => props.theme.listItemHoverBackground}; background: ${(props) => props.theme.listItemHoverBackground};
outline: none; outline: none;
} }
`; `;

View File

@ -10,16 +10,16 @@ import CollectionsStore from "stores/CollectionsStore";
import AuthStore from "stores/AuthStore"; import AuthStore from "stores/AuthStore";
const Container = styled(Flex)` const Container = styled(Flex)`
color: ${props => props.theme.textTertiary}; color: ${(props) => props.theme.textTertiary};
font-size: 13px; font-size: 13px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
`; `;
const Modified = styled.span` const Modified = styled.span`
color: ${props => color: ${(props) =>
props.highlight ? props.theme.text : props.theme.textTertiary}; props.highlight ? props.theme.text : props.theme.textTertiary};
font-weight: ${props => (props.highlight ? "600" : "400")}; font-weight: ${(props) => (props.highlight ? "600" : "400")};
`; `;
type Props = { type Props = {
@ -104,15 +104,14 @@ function PublishingInfo({
<Container align="center" {...rest}> <Container align="center" {...rest}>
{updatedByMe ? "You" : updatedBy.name}&nbsp; {updatedByMe ? "You" : updatedBy.name}&nbsp;
{content} {content}
{showCollection && {showCollection && collection && (
collection && ( <span>
<span> &nbsp;in&nbsp;
&nbsp;in&nbsp; <strong>
<strong> <Breadcrumb document={document} onlyText />
<Breadcrumb document={document} onlyText /> </strong>
</strong> </span>
</span> )}
)}
{children} {children}
</Container> </Container>
); );

View File

@ -31,7 +31,7 @@ const Wrapper = styled.div`
overflow-x: hidden; overflow-x: hidden;
overscroll-behavior: none; overscroll-behavior: none;
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
box-shadow: ${props => box-shadow: ${(props) =>
props.shadow ? "0 1px inset rgba(0,0,0,.1)" : "none"}; props.shadow ? "0 1px inset rgba(0,0,0,.1)" : "none"};
transition: all 250ms ease-in-out; transition: all 250ms ease-in-out;
`; `;

View File

@ -119,7 +119,8 @@ class MainSidebar extends React.Component<Props> {
icon={<EditIcon color="currentColor" />} icon={<EditIcon color="currentColor" />}
label={ label={
<Drafts align="center"> <Drafts align="center">
Drafts{draftDocumentsCount > 0 && ( Drafts
{draftDocumentsCount > 0 && (
<Bubble count={draftDocumentsCount} /> <Bubble count={draftDocumentsCount} />
)} )}
</Drafts> </Drafts>

View File

@ -146,13 +146,12 @@ class SettingsSidebar extends React.Component<Props> {
/> />
</Section> </Section>
)} )}
{can.update && {can.update && env.DEPLOYMENT !== "hosted" && (
env.DEPLOYMENT !== "hosted" && ( <Section>
<Section> <Header>Installation</Header>
<Header>Installation</Header> <Version />
<Version /> </Section>
</Section> )}
)}
</Scrollable> </Scrollable>
</Flex> </Flex>
</Sidebar> </Sidebar>

View File

@ -67,9 +67,10 @@ const Container = styled(Flex)`
top: 0; top: 0;
bottom: 0; bottom: 0;
width: 100%; width: 100%;
background: ${props => props.theme.sidebarBackground}; background: ${(props) => props.theme.sidebarBackground};
transition: left 100ms ease-out, ${props => props.theme.backgroundTransition}; transition: left 100ms ease-out,
margin-left: ${props => (props.mobileSidebarVisible ? 0 : "-100%")}; ${(props) => props.theme.backgroundTransition};
margin-left: ${(props) => (props.mobileSidebarVisible ? 0 : "-100%")};
z-index: 1000; z-index: 1000;
@media print { @media print {
@ -80,7 +81,7 @@ const Container = styled(Flex)`
&:before, &:before,
&:after { &:after {
content: ""; content: "";
background: ${props => props.theme.sidebarBackground}; background: ${(props) => props.theme.sidebarBackground};
position: absolute; position: absolute;
top: -50vh; top: -50vh;
left: 0; left: 0;
@ -94,8 +95,8 @@ const Container = styled(Flex)`
} }
${breakpoint("tablet")` ${breakpoint("tablet")`
left: ${props => (props.editMode ? `-${props.theme.sidebarWidth}` : 0)}; left: ${(props) => (props.editMode ? `-${props.theme.sidebarWidth}` : 0)};
width: ${props => props.theme.sidebarWidth}; width: ${(props) => props.theme.sidebarWidth};
margin: 0; margin: 0;
z-index: 3; z-index: 3;
`}; `};
@ -106,8 +107,8 @@ const Toggle = styled.a`
align-items: center; align-items: center;
position: fixed; position: fixed;
top: 0; top: 0;
left: ${props => (props.mobileSidebarVisible ? "auto" : 0)}; left: ${(props) => (props.mobileSidebarVisible ? "auto" : 0)};
right: ${props => (props.mobileSidebarVisible ? 0 : "auto")}; right: ${(props) => (props.mobileSidebarVisible ? 0 : "auto")};
z-index: 1; z-index: 1;
margin: 12px; margin: 12px;

View File

@ -14,8 +14,8 @@ const Bubble = ({ count }: Props) => {
const Count = styled.div` const Count = styled.div`
animation: ${bounceIn} 600ms; animation: ${bounceIn} 600ms;
transform-origin: center center; transform-origin: center center;
color: ${props => props.theme.white}; color: ${(props) => props.theme.white};
background: ${props => props.theme.slateDark}; background: ${(props) => props.theme.slateDark};
display: inline-block; display: inline-block;
font-feature-settings: "tnum"; font-feature-settings: "tnum";
font-weight: 600; font-weight: 600;

View File

@ -61,7 +61,7 @@ class CollectionLink extends React.Component<Props> {
} }
> >
<Flex column> <Flex column>
{collection.documents.map(node => ( {collection.documents.map((node) => (
<DocumentLink <DocumentLink
key={node.id} key={node.id}
node={node} node={node}

View File

@ -57,7 +57,7 @@ class Collections extends React.Component<Props> {
const content = ( const content = (
<React.Fragment> <React.Fragment>
{collections.orderedData.map(collection => ( {collections.orderedData.map((collection) => (
<CollectionLink <CollectionLink
key={collection.id} key={collection.id}
documents={documents} documents={documents}
@ -94,6 +94,9 @@ class Collections extends React.Component<Props> {
} }
} }
export default inject("collections", "ui", "documents", "policies")( export default inject(
withRouter(Collections) "collections",
); "ui",
"documents",
"policies"
)(withRouter(Collections));

View File

@ -76,7 +76,7 @@ class DocumentLink extends React.Component<Props> {
collection && collection &&
(collection (collection
.pathToDocument(activeDocument) .pathToDocument(activeDocument)
.map(entry => entry.id) .map((entry) => entry.id)
.includes(node.id) || .includes(node.id) ||
this.isActiveDocument()) this.isActiveDocument())
); );
@ -110,14 +110,12 @@ class DocumentLink extends React.Component<Props> {
onClose={() => (this.menuOpen = false)} onClose={() => (this.menuOpen = false)}
/> />
</Fade> </Fade>
) : ( ) : undefined
undefined
)
} }
> >
{this.hasChildDocuments() && ( {this.hasChildDocuments() && (
<DocumentChildren column> <DocumentChildren column>
{node.children.map(childNode => ( {node.children.map((childNode) => (
<DocumentLink <DocumentLink
key={childNode.id} key={childNode.id}
collection={collection} collection={collection}

View File

@ -6,7 +6,7 @@ const Header = styled(Flex)`
font-size: 11px; font-size: 11px;
font-weight: 600; font-weight: 600;
text-transform: uppercase; text-transform: uppercase;
color: ${props => props.theme.sidebarText}; color: ${(props) => props.theme.sidebarText};
letter-spacing: 0.04em; letter-spacing: 0.04em;
margin: 4px 16px; margin: 4px 16px;
`; `;

View File

@ -46,7 +46,7 @@ const Subheading = styled.div`
font-size: 11px; font-size: 11px;
text-transform: uppercase; text-transform: uppercase;
font-weight: 500; font-weight: 500;
color: ${props => props.theme.sidebarText}; color: ${(props) => props.theme.sidebarText};
`; `;
const TeamName = styled.div` const TeamName = styled.div`
@ -54,7 +54,7 @@ const TeamName = styled.div`
padding-left: 10px; padding-left: 10px;
padding-right: 24px; padding-right: 24px;
font-weight: 600; font-weight: 600;
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
text-decoration: none; text-decoration: none;
font-size: 16px; font-size: 16px;
`; `;

View File

@ -108,11 +108,11 @@ const IconWrapper = styled.span`
`; `;
const Action = styled.span` const Action = styled.span`
display: ${props => (props.menuOpen ? "inline" : "none")}; display: ${(props) => (props.menuOpen ? "inline" : "none")};
position: absolute; position: absolute;
top: 4px; top: 4px;
right: 4px; right: 4px;
color: ${props => props.theme.textTertiary}; color: ${(props) => props.theme.textTertiary};
svg { svg {
opacity: 0.75; opacity: 0.75;
@ -132,17 +132,17 @@ const StyledNavLink = styled(NavLink)`
text-overflow: ellipsis; text-overflow: ellipsis;
padding: 4px 16px; padding: 4px 16px;
border-radius: 4px; border-radius: 4px;
color: ${props => props.theme.sidebarText}; color: ${(props) => props.theme.sidebarText};
font-size: 15px; font-size: 15px;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
} }
&:focus { &:focus {
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
background: ${props => props.theme.black05}; background: ${(props) => props.theme.black05};
outline: none; outline: none;
} }

View File

@ -71,13 +71,13 @@ class SocketProvider extends React.Component<Props> {
this.socket.authenticated = true; this.socket.authenticated = true;
}); });
this.socket.on("unauthorized", err => { this.socket.on("unauthorized", (err) => {
this.socket.authenticated = false; this.socket.authenticated = false;
ui.showToast(err.message); ui.showToast(err.message);
throw err; throw err;
}); });
this.socket.on("entities", async event => { this.socket.on("entities", async (event) => {
if (event.documentIds) { if (event.documentIds) {
for (const documentDescriptor of event.documentIds) { for (const documentDescriptor of event.documentIds) {
const documentId = documentDescriptor.id; const documentId = documentDescriptor.id;
@ -182,23 +182,23 @@ class SocketProvider extends React.Component<Props> {
} }
}); });
this.socket.on("documents.star", event => { this.socket.on("documents.star", (event) => {
documents.starredIds.set(event.documentId, true); documents.starredIds.set(event.documentId, true);
}); });
this.socket.on("documents.unstar", event => { this.socket.on("documents.unstar", (event) => {
documents.starredIds.set(event.documentId, false); documents.starredIds.set(event.documentId, false);
}); });
// received when a user is given access to a collection // received when a user is given access to a collection
// if the user is us then we go ahead and load the collection from API. // if the user is us then we go ahead and load the collection from API.
this.socket.on("collections.add_user", event => { this.socket.on("collections.add_user", (event) => {
if (auth.user && event.userId === auth.user.id) { if (auth.user && event.userId === auth.user.id) {
collections.fetch(event.collectionId, { force: true }); collections.fetch(event.collectionId, { force: true });
} }
// Document policies might need updating as the permission changes // Document policies might need updating as the permission changes
documents.inCollection(event.collectionId).forEach(document => { documents.inCollection(event.collectionId).forEach((document) => {
policies.remove(document.id); policies.remove(document.id);
}); });
}); });
@ -206,7 +206,7 @@ class SocketProvider extends React.Component<Props> {
// received when a user is removed from having access to a collection // received when a user is removed from having access to a collection
// to keep state in sync we must update our UI if the user is us, // to keep state in sync we must update our UI if the user is us,
// or otherwise just remove any membership state we have for that user. // or otherwise just remove any membership state we have for that user.
this.socket.on("collections.remove_user", event => { this.socket.on("collections.remove_user", (event) => {
if (auth.user && event.userId === auth.user.id) { if (auth.user && event.userId === auth.user.id) {
collections.remove(event.collectionId); collections.remove(event.collectionId);
memberships.removeCollectionMemberships(event.collectionId); memberships.removeCollectionMemberships(event.collectionId);
@ -218,32 +218,32 @@ class SocketProvider extends React.Component<Props> {
// received a message from the API server that we should request // received a message from the API server that we should request
// to join a specific room. Forward that to the ws server. // to join a specific room. Forward that to the ws server.
this.socket.on("join", event => { this.socket.on("join", (event) => {
this.socket.emit("join", event); this.socket.emit("join", event);
}); });
// received a message from the API server that we should request // received a message from the API server that we should request
// to leave a specific room. Forward that to the ws server. // to leave a specific room. Forward that to the ws server.
this.socket.on("leave", event => { this.socket.on("leave", (event) => {
this.socket.emit("leave", event); this.socket.emit("leave", event);
}); });
// received whenever we join a document room, the payload includes // received whenever we join a document room, the payload includes
// userIds that are present/viewing and those that are editing. // userIds that are present/viewing and those that are editing.
this.socket.on("document.presence", event => { this.socket.on("document.presence", (event) => {
presence.init(event.documentId, event.userIds, event.editingIds); presence.init(event.documentId, event.userIds, event.editingIds);
}); });
// received whenever a new user joins a document room, aka they // received whenever a new user joins a document room, aka they
// navigate to / start viewing a document // navigate to / start viewing a document
this.socket.on("user.join", event => { this.socket.on("user.join", (event) => {
presence.touch(event.documentId, event.userId, event.isEditing); presence.touch(event.documentId, event.userId, event.isEditing);
views.touch(event.documentId, event.userId); views.touch(event.documentId, event.userId);
}); });
// received whenever a new user leaves a document room, aka they // received whenever a new user leaves a document room, aka they
// navigate away / stop viewing a document // navigate away / stop viewing a document
this.socket.on("user.leave", event => { this.socket.on("user.leave", (event) => {
presence.leave(event.documentId, event.userId); presence.leave(event.documentId, event.userId);
views.touch(event.documentId, event.userId); views.touch(event.documentId, event.userId);
}); });
@ -251,7 +251,7 @@ class SocketProvider extends React.Component<Props> {
// received when another client in a document room wants to change // received when another client in a document room wants to change
// or update it's presence. Currently the only property is whether // or update it's presence. Currently the only property is whether
// the client is in editing state or not. // the client is in editing state or not.
this.socket.on("user.presence", event => { this.socket.on("user.presence", (event) => {
presence.touch(event.documentId, event.userId, event.isEditing); presence.touch(event.documentId, event.userId, event.isEditing);
}); });
} }

View File

@ -7,7 +7,7 @@ type Props = {
}; };
const H3 = styled.h3` const H3 = styled.h3`
border-bottom: 1px solid ${props => props.theme.divider}; border-bottom: 1px solid ${(props) => props.theme.divider};
margin-top: 22px; margin-top: 22px;
margin-bottom: 12px; margin-bottom: 12px;
line-height: 1; line-height: 1;
@ -21,8 +21,8 @@ const Underline = styled("span")`
font-weight: 500; font-weight: 500;
font-size: 14px; font-size: 14px;
line-height: 1.5; line-height: 1.5;
color: ${props => props.theme.textSecondary}; color: ${(props) => props.theme.textSecondary};
border-bottom: 3px solid ${props => props.theme.textSecondary}; border-bottom: 3px solid ${(props) => props.theme.textSecondary};
padding-bottom: 5px; padding-bottom: 5px;
`; `;

View File

@ -38,8 +38,8 @@ const Label = styled.label`
const Wrapper = styled.label` const Wrapper = styled.label`
position: relative; position: relative;
display: inline-block; display: inline-block;
width: ${props => props.width}px; width: ${(props) => props.width}px;
height: ${props => props.height}px; height: ${(props) => props.height}px;
margin-bottom: 4px; margin-bottom: 4px;
margin-right: 8px; margin-right: 8px;
`; `;
@ -51,16 +51,16 @@ const Slider = styled.span`
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
background-color: ${props => props.theme.slate}; background-color: ${(props) => props.theme.slate};
-webkit-transition: 0.4s; -webkit-transition: 0.4s;
transition: 0.4s; transition: 0.4s;
border-radius: ${props => props.height}px; border-radius: ${(props) => props.height}px;
&:before { &:before {
position: absolute; position: absolute;
content: ""; content: "";
height: ${props => props.height - 8}px; height: ${(props) => props.height - 8}px;
width: ${props => props.height - 8}px; width: ${(props) => props.height - 8}px;
left: 4px; left: 4px;
bottom: 4px; bottom: 4px;
background-color: white; background-color: white;
@ -77,15 +77,15 @@ const HiddenInput = styled.input`
visibility: hidden; visibility: hidden;
&:checked + ${Slider} { &:checked + ${Slider} {
background-color: ${props => props.theme.primary}; background-color: ${(props) => props.theme.primary};
} }
&:focus + ${Slider} { &:focus + ${Slider} {
box-shadow: 0 0 1px ${props => props.theme.primary}; box-shadow: 0 0 1px ${(props) => props.theme.primary};
} }
&:checked + ${Slider}:before { &:checked + ${Slider}:before {
transform: translateX(${props => props.width - props.height}px); transform: translateX(${(props) => props.width - props.height}px);
} }
`; `;

View File

@ -15,20 +15,20 @@ const StyledNavLink = styled(NavLink)`
display: inline-block; display: inline-block;
font-weight: 500; font-weight: 500;
font-size: 14px; font-size: 14px;
color: ${props => props.theme.textTertiary}; color: ${(props) => props.theme.textTertiary};
margin-right: 24px; margin-right: 24px;
padding-bottom: 8px; padding-bottom: 8px;
&:hover { &:hover {
color: ${props => props.theme.textSecondary}; color: ${(props) => props.theme.textSecondary};
border-bottom: 3px solid ${props => props.theme.divider}; border-bottom: 3px solid ${(props) => props.theme.divider};
padding-bottom: 5px; padding-bottom: 5px;
} }
&:focus { &:focus {
outline: none; outline: none;
border-bottom: 3px solid border-bottom: 3px solid
${props => lighten(0.4, props.theme.buttonBackground)}; ${(props) => lighten(0.4, props.theme.buttonBackground)};
padding-bottom: 5px; padding-bottom: 5px;
} }
`; `;

View File

@ -3,13 +3,13 @@ import styled from "styled-components";
const Tabs = styled.nav` const Tabs = styled.nav`
position: relative; position: relative;
border-bottom: 1px solid ${props => props.theme.divider}; border-bottom: 1px solid ${(props) => props.theme.divider};
margin-top: 22px; margin-top: 22px;
margin-bottom: 12px; margin-bottom: 12px;
`; `;
export const Separator = styled.span` export const Separator = styled.span`
border-left: 1px solid ${props => props.theme.divider}; border-left: 1px solid ${(props) => props.theme.divider};
position: relative; position: relative;
top: 2px; top: 2px;
margin-right: 24px; margin-right: 24px;

View File

@ -5,8 +5,8 @@ const TeamLogo = styled.img`
width: auto; width: auto;
height: 38px; height: 38px;
border-radius: 4px; border-radius: 4px;
background: ${props => props.theme.background}; background: ${(props) => props.theme.background};
border: 1px solid ${props => props.theme.divider}; border: 1px solid ${(props) => props.theme.divider};
`; `;
export default TeamLogo; export default TeamLogo;

View File

@ -9,14 +9,14 @@ let callbacks = [];
// This is a shared timer that fires every minute, used for // This is a shared timer that fires every minute, used for
// updating all Time components across the page all at once. // updating all Time components across the page all at once.
setInterval(() => { setInterval(() => {
callbacks.forEach(cb => cb()); callbacks.forEach((cb) => cb());
}, 1000 * 60); }, 1000 * 60);
function eachMinute(fn) { function eachMinute(fn) {
callbacks.push(fn); callbacks.push(fn);
return () => { return () => {
callbacks = callbacks.filter(cb => cb !== fn); callbacks = callbacks.filter((cb) => cb !== fn);
}; };
} }

View File

@ -15,7 +15,7 @@ class Toasts extends React.Component<Props> {
return ( return (
<List> <List>
{ui.orderedToasts.map(toast => ( {ui.orderedToasts.map((toast) => (
<Toast <Toast
key={toast.id} key={toast.id}
toast={toast} toast={toast}
@ -29,8 +29,8 @@ class Toasts extends React.Component<Props> {
const List = styled.ol` const List = styled.ol`
position: fixed; position: fixed;
left: ${props => props.theme.hpadding}; left: ${(props) => props.theme.hpadding};
bottom: ${props => props.theme.vpadding}; bottom: ${(props) => props.theme.vpadding};
list-style: none; list-style: none;
margin: 0; margin: 0;
padding: 0; padding: 0;

View File

@ -61,13 +61,13 @@ const Action = styled.span`
height: 100%; height: 100%;
text-transform: uppercase; text-transform: uppercase;
font-size: 12px; font-size: 12px;
color: ${props => props.theme.toastText}; color: ${(props) => props.theme.toastText};
background: ${props => darken(0.05, props.theme.toastBackground)}; background: ${(props) => darken(0.05, props.theme.toastBackground)};
border-top-right-radius: 5px; border-top-right-radius: 5px;
border-bottom-right-radius: 5px; border-bottom-right-radius: 5px;
&:hover { &:hover {
background: ${props => darken(0.1, props.theme.toastBackground)}; background: ${(props) => darken(0.1, props.theme.toastBackground)};
} }
`; `;
@ -76,14 +76,14 @@ const Container = styled.div`
align-items: center; align-items: center;
animation: ${fadeAndScaleIn} 100ms ease; animation: ${fadeAndScaleIn} 100ms ease;
margin: 8px 0; margin: 8px 0;
color: ${props => props.theme.toastText}; color: ${(props) => props.theme.toastText};
background: ${props => props.theme.toastBackground}; background: ${(props) => props.theme.toastBackground};
font-size: 15px; font-size: 15px;
border-radius: 5px; border-radius: 5px;
cursor: default; cursor: default;
&:hover { &:hover {
background: ${props => darken(0.05, props.theme.toastBackground)}; background: ${(props) => darken(0.05, props.theme.toastBackground)};
} }
`; `;

View File

@ -54,19 +54,19 @@ const Shortcut = styled.kbd`
font: 10px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, font: 10px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier,
monospace; monospace;
line-height: 10px; line-height: 10px;
color: ${props => props.theme.tooltipBackground}; color: ${(props) => props.theme.tooltipBackground};
vertical-align: middle; vertical-align: middle;
background-color: ${props => props.theme.tooltipText}; background-color: ${(props) => props.theme.tooltipText};
border-radius: 3px; border-radius: 3px;
`; `;
const StyledTippy = styled(Tippy)` const StyledTippy = styled(Tippy)`
font-size: 13px; font-size: 13px;
background-color: ${props => props.theme.tooltipBackground}; background-color: ${(props) => props.theme.tooltipBackground};
color: ${props => props.theme.tooltipText}; color: ${(props) => props.theme.tooltipText};
svg { svg {
fill: ${props => props.theme.tooltipBackground}; fill: ${(props) => props.theme.tooltipBackground};
} }
`; `;

View File

@ -19,9 +19,7 @@ export default class Figma extends React.Component<Props> {
render() { render() {
return ( return (
<Frame <Frame
src={`https://www.figma.com/embed?embed_host=outline&url=${ src={`https://www.figma.com/embed?embed_host=outline&url=${this.props.attrs.href}`}
this.props.attrs.href
}`}
title="Figma Embed" title="Figma Embed"
border border
/> />

View File

@ -48,14 +48,10 @@ class Gist extends React.Component<Props> {
} }
const gistLink = `https://gist.github.com/${id}.js`; const gistLink = `https://gist.github.com/${id}.js`;
const gistScript = `<script type="text/javascript" src="${ const gistScript = `<script type="text/javascript" src="${gistLink}"></script>`;
gistLink
}"></script>`;
const styles = const styles =
"<style>*{ font-size:12px; } body { margin: 0; } .gist .blob-wrapper.data { max-height:150px; overflow:auto; }</style>"; "<style>*{ font-size:12px; } body { margin: 0; } .gist .blob-wrapper.data { max-height:150px; overflow:auto; }</style>";
const iframeHtml = `<html><head><base target="_parent">${ const iframeHtml = `<html><head><base target="_parent">${styles}</head><body>${gistScript}</body></html>`;
styles
}</head><body>${gistScript}</body></html>`;
doc.open(); doc.open();
doc.writeln(iframeHtml); doc.writeln(iframeHtml);
@ -67,7 +63,7 @@ class Gist extends React.Component<Props> {
return ( return (
<iframe <iframe
ref={ref => { ref={(ref) => {
this.iframeNode = ref; this.iframeNode = ref;
}} }}
type="text/html" type="text/html"

View File

@ -65,17 +65,17 @@ class Frame extends React.Component<Props> {
const Rounded = styled.div` const Rounded = styled.div`
border-radius: 3px; border-radius: 3px;
overflow: hidden; overflow: hidden;
width: ${props => props.width}; width: ${(props) => props.width};
height: ${props => props.height}; height: ${(props) => props.height};
`; `;
// This wrapper allows us to pass non-standard HTML attributes through to the DOM element // This wrapper allows us to pass non-standard HTML attributes through to the DOM element
// https://www.styled-components.com/docs/basics#passed-props // https://www.styled-components.com/docs/basics#passed-props
const Iframe = props => <iframe {...props} />; const Iframe = (props) => <iframe {...props} />;
const StyledIframe = styled(Iframe)` const StyledIframe = styled(Iframe)`
border: 1px solid; border: 1px solid;
border-color: ${props => props.theme.embedBorder}; border-color: ${(props) => props.theme.embedBorder};
border-radius: 3px; border-radius: 3px;
`; `;

View File

@ -97,9 +97,9 @@ class CollectionMenu extends React.Component<Props> {
<VisuallyHidden> <VisuallyHidden>
<input <input
type="file" type="file"
ref={ref => (this.file = ref)} ref={(ref) => (this.file = ref)}
onChange={this.onFilePicked} onChange={this.onFilePicked}
onClick={ev => ev.stopPropagation()} onClick={(ev) => ev.stopPropagation()}
accept="text/markdown, text/plain" accept="text/markdown, text/plain"
/> />
</VisuallyHidden> </VisuallyHidden>
@ -153,6 +153,8 @@ class CollectionMenu extends React.Component<Props> {
} }
} }
export default inject("ui", "documents", "policies")( export default inject(
withRouter(CollectionMenu) "ui",
); "documents",
"policies"
)(withRouter(CollectionMenu));

View File

@ -219,12 +219,11 @@ class DocumentMenu extends React.Component<Props> {
New nested document New nested document
</DropdownMenuItem> </DropdownMenuItem>
)} )}
{can.update && {can.update && !document.isTemplate && (
!document.isTemplate && ( <DropdownMenuItem onClick={this.handleOpenTemplateModal}>
<DropdownMenuItem onClick={this.handleOpenTemplateModal}> Create template
Create template </DropdownMenuItem>
</DropdownMenuItem> )}
)}
{can.update && ( {can.update && (
<DropdownMenuItem onClick={this.handleEdit}>Edit</DropdownMenuItem> <DropdownMenuItem onClick={this.handleEdit}>Edit</DropdownMenuItem>
)} )}

View File

@ -63,7 +63,7 @@ class NewDocumentMenu extends React.Component<Props> {
{...rest} {...rest}
> >
<Header>Choose a collection</Header> <Header>Choose a collection</Header>
{collections.orderedData.map(collection => { {collections.orderedData.map((collection) => {
const can = policies.abilities(collection.id); const can = policies.abilities(collection.id);
return ( return (
@ -72,7 +72,8 @@ class NewDocumentMenu extends React.Component<Props> {
onClick={() => this.handleNewDocument(collection.id)} onClick={() => this.handleNewDocument(collection.id)}
disabled={!can.update} disabled={!can.update}
> >
<CollectionIcon collection={collection} />&nbsp;{collection.name} <CollectionIcon collection={collection} />
&nbsp;{collection.name}
</DropdownMenuItem> </DropdownMenuItem>
); );
})} })}

View File

@ -53,7 +53,7 @@ class NewTemplateMenu extends React.Component<Props> {
{...rest} {...rest}
> >
<Header>Choose a collection</Header> <Header>Choose a collection</Header>
{collections.orderedData.map(collection => { {collections.orderedData.map((collection) => {
const can = policies.abilities(collection.id); const can = policies.abilities(collection.id);
return ( return (
@ -62,7 +62,8 @@ class NewTemplateMenu extends React.Component<Props> {
onClick={() => this.handleNewDocument(collection.id)} onClick={() => this.handleNewDocument(collection.id)}
disabled={!can.update} disabled={!can.update}
> >
<CollectionIcon collection={collection} />&nbsp;{collection.name} <CollectionIcon collection={collection} />
&nbsp;{collection.name}
</DropdownMenuItem> </DropdownMenuItem>
); );
})} })}

View File

@ -33,7 +33,7 @@ class TemplatesMenu extends React.Component<Props> {
} }
{...rest} {...rest}
> >
{templates.map(template => ( {templates.map((template) => (
<DropdownMenuItem <DropdownMenuItem
key={template.id} key={template.id}
onClick={() => document.updateFromTemplate(template)} onClick={() => document.updateFromTemplate(template)}

View File

@ -18,9 +18,7 @@ class UserMenu extends React.Component<Props> {
const { user, users } = this.props; const { user, users } = this.props;
if ( if (
!window.confirm( !window.confirm(
`Are you want to make ${ `Are you want to make ${user.name} an admin? Admins can modify team and billing information.`
user.name
} an admin? Admins can modify team and billing information.`
) )
) { ) {
return; return;
@ -72,12 +70,11 @@ class UserMenu extends React.Component<Props> {
Make {user.name} a member Make {user.name} a member
</DropdownMenuItem> </DropdownMenuItem>
)} )}
{!user.isAdmin && {!user.isAdmin && !user.isSuspended && (
!user.isSuspended && ( <DropdownMenuItem onClick={this.handlePromote}>
<DropdownMenuItem onClick={this.handlePromote}> Make {user.name} an admin
Make {user.name} an admin </DropdownMenuItem>
</DropdownMenuItem> )}
)}
{!user.lastActiveAt && ( {!user.lastActiveAt && (
<DropdownMenuItem onClick={this.handleRevoke}> <DropdownMenuItem onClick={this.handleRevoke}>
Revoke invite Revoke invite

View File

@ -11,7 +11,7 @@ export default class BaseModel {
this.store = store; this.store = store;
} }
save = async params => { save = async (params) => {
this.isSaving = true; this.isSaving = true;
try { try {

View File

@ -37,7 +37,7 @@ export default class Collection extends BaseModel {
get documentIds(): string[] { get documentIds(): string[] {
const results = []; const results = [];
const travelDocuments = (documentList, path) => const travelDocuments = (documentList, path) =>
documentList.forEach(document => { documentList.forEach((document) => {
results.push(document.id); results.push(document.id);
travelDocuments(document.children); travelDocuments(document.children);
}); });
@ -49,7 +49,7 @@ export default class Collection extends BaseModel {
@action @action
updateDocument(document: Document) { updateDocument(document: Document) {
const travelDocuments = (documentList, path) => const travelDocuments = (documentList, path) =>
documentList.forEach(d => { documentList.forEach((d) => {
if (d.id === document.id) { if (d.id === document.id) {
d.title = document.title; d.title = document.title;
d.url = document.url; d.url = document.url;
@ -63,8 +63,8 @@ export default class Collection extends BaseModel {
getDocumentChildren(documentId: string): NavigationNode[] { getDocumentChildren(documentId: string): NavigationNode[] {
let result = []; let result = [];
const traveler = nodes => { const traveler = (nodes) => {
nodes.forEach(childNode => { nodes.forEach((childNode) => {
if (childNode.id === documentId) { if (childNode.id === documentId) {
result = childNode.children; result = childNode.children;
return; return;
@ -83,7 +83,7 @@ export default class Collection extends BaseModel {
pathToDocument(document: Document) { pathToDocument(document: Document) {
let path; let path;
const traveler = (nodes, previousPath) => { const traveler = (nodes, previousPath) => {
nodes.forEach(childNode => { nodes.forEach((childNode) => {
const newPath = [...previousPath, childNode]; const newPath = [...previousPath, childNode];
if (childNode.id === document.id) { if (childNode.id === document.id) {
path = newPath; path = newPath;

View File

@ -133,7 +133,7 @@ export default class Document extends BaseModel {
}; };
@action @action
updateFromJson = data => { updateFromJson = (data) => {
set(this, data); set(this, data);
}; };
@ -253,11 +253,7 @@ export default class Document extends BaseModel {
}; };
getSummary = (paragraphs: number = 4) => { getSummary = (paragraphs: number = 4) => {
const result = this.text const result = this.text.trim().split("\n").slice(0, paragraphs).join("\n");
.trim()
.split("\n")
.slice(0, paragraphs)
.join("\n");
return result; return result;
}; };

View File

@ -171,14 +171,17 @@ class CollectionScene extends React.Component<Props> {
<Centered column> <Centered column>
<HelpText> <HelpText>
<strong>{collection.name}</strong> doesnt contain any <strong>{collection.name}</strong> doesnt contain any
documents yet.<br />Get started by creating a new one! documents yet.
<br />
Get started by creating a new one!
</HelpText> </HelpText>
<Wrapper> <Wrapper>
<Link to={newDocumentUrl(collection.id)}> <Link to={newDocumentUrl(collection.id)}>
<Button icon={<NewDocumentIcon color={theme.buttonText} />}> <Button icon={<NewDocumentIcon color={theme.buttonText} />}>
Create a document Create a document
</Button> </Button>
</Link>&nbsp;&nbsp; </Link>
&nbsp;&nbsp;
{collection.private && ( {collection.private && (
<Button onClick={this.onPermissions} neutral> <Button onClick={this.onPermissions} neutral>
Manage members Manage members
@ -329,6 +332,9 @@ const Wrapper = styled(Flex)`
margin: 10px 0; margin: 10px 0;
`; `;
export default inject("collections", "policies", "documents", "ui")( export default inject(
withTheme(CollectionScene) "collections",
); "policies",
"documents",
"ui"
)(withTheme(CollectionScene));

View File

@ -56,7 +56,7 @@ class CollectionEdit extends React.Component<Props> {
} }
}; };
handleDescriptionChange = getValue => { handleDescriptionChange = (getValue) => {
this.description = getValue(); this.description = getValue();
}; };

View File

@ -52,7 +52,7 @@ class AddGroupsToCollection extends React.Component<Props> {
}); });
}, 250); }, 250);
handleAddGroup = group => { handleAddGroup = (group) => {
try { try {
this.props.collectionGroupMemberships.create({ this.props.collectionGroupMemberships.create({
collectionId: this.props.collection.id, collectionId: this.props.collection.id,
@ -77,7 +77,8 @@ class AddGroupsToCollection extends React.Component<Props> {
Cant find the group youre looking for?{" "} Cant find the group youre looking for?{" "}
<a role="button" onClick={this.handleNewGroupModalOpen}> <a role="button" onClick={this.handleNewGroupModalOpen}>
Create a group Create a group
</a>. </a>
.
</HelpText> </HelpText>
<Input <Input
@ -99,7 +100,7 @@ class AddGroupsToCollection extends React.Component<Props> {
} }
items={groups.notInCollection(collection.id, this.query)} items={groups.notInCollection(collection.id, this.query)}
fetch={this.query ? undefined : groups.fetchPage} fetch={this.query ? undefined : groups.fetchPage}
renderItem={item => ( renderItem={(item) => (
<GroupListItem <GroupListItem
key={item.id} key={item.id}
group={item} group={item}
@ -130,6 +131,9 @@ const ButtonWrap = styled.div`
margin-left: 6px; margin-left: 6px;
`; `;
export default inject("auth", "groups", "collectionGroupMemberships", "ui")( export default inject(
AddGroupsToCollection "auth",
); "groups",
"collectionGroupMemberships",
"ui"
)(AddGroupsToCollection);

View File

@ -50,7 +50,7 @@ class AddPeopleToCollection extends React.Component<Props> {
}); });
}, 250); }, 250);
handleAddUser = user => { handleAddUser = (user) => {
try { try {
this.props.memberships.create({ this.props.memberships.create({
collectionId: this.props.collection.id, collectionId: this.props.collection.id,
@ -74,7 +74,8 @@ class AddPeopleToCollection extends React.Component<Props> {
Need to add someone whos not yet on the team yet?{" "} Need to add someone whos not yet on the team yet?{" "}
<a role="button" onClick={this.handleInviteModalOpen}> <a role="button" onClick={this.handleInviteModalOpen}>
Invite people to {team.name} Invite people to {team.name}
</a>. </a>
.
</HelpText> </HelpText>
<Input <Input
@ -97,7 +98,7 @@ class AddPeopleToCollection extends React.Component<Props> {
} }
items={users.notInCollection(collection.id, this.query)} items={users.notInCollection(collection.id, this.query)}
fetch={this.query ? undefined : users.fetchPage} fetch={this.query ? undefined : users.fetchPage}
renderItem={item => ( renderItem={(item) => (
<MemberListItem <MemberListItem
key={item.id} key={item.id}
user={item} user={item}
@ -118,6 +119,9 @@ class AddPeopleToCollection extends React.Component<Props> {
} }
} }
export default inject("auth", "users", "memberships", "ui")( export default inject(
AddPeopleToCollection "auth",
); "users",
"memberships",
"ui"
)(AddPeopleToCollection);

View File

@ -55,7 +55,7 @@ class CollectionMembers extends React.Component<Props> {
this.addMemberModalOpen = false; this.addMemberModalOpen = false;
}; };
handleRemoveUser = user => { handleRemoveUser = (user) => {
try { try {
this.props.memberships.delete({ this.props.memberships.delete({
collectionId: this.props.collection.id, collectionId: this.props.collection.id,
@ -80,7 +80,7 @@ class CollectionMembers extends React.Component<Props> {
} }
}; };
handleRemoveGroup = group => { handleRemoveGroup = (group) => {
try { try {
this.props.collectionGroupMemberships.delete({ this.props.collectionGroupMemberships.delete({
collectionId: this.props.collection.id, collectionId: this.props.collection.id,
@ -118,7 +118,7 @@ class CollectionMembers extends React.Component<Props> {
if (!user) return null; if (!user) return null;
const key = memberships.orderedData const key = memberships.orderedData
.map(m => m.permission) .map((m) => m.permission)
.concat(collection.private) .concat(collection.private)
.join("-"); .join("-");
@ -133,7 +133,8 @@ class CollectionMembers extends React.Component<Props> {
team by{" "} team by{" "}
<a role="button" onClick={this.props.onEdit}> <a role="button" onClick={this.props.onEdit}>
changing its visibility changing its visibility
</a>. </a>
.
</HelpText> </HelpText>
<span> <span>
<Button <Button
@ -153,7 +154,8 @@ class CollectionMembers extends React.Component<Props> {
collection,{" "} collection,{" "}
<a role="button" onClick={this.props.onEdit}> <a role="button" onClick={this.props.onEdit}>
make it private make it private
</a>. </a>
.
</HelpText> </HelpText>
)} )}
@ -166,7 +168,7 @@ class CollectionMembers extends React.Component<Props> {
fetch={collectionGroupMemberships.fetchPage} fetch={collectionGroupMemberships.fetchPage}
options={collection.private ? { id: collection.id } : undefined} options={collection.private ? { id: collection.id } : undefined}
empty={<Empty>This collection has no groups.</Empty>} empty={<Empty>This collection has no groups.</Empty>}
renderItem={group => ( renderItem={(group) => (
<CollectionGroupMemberListItem <CollectionGroupMemberListItem
key={group.id} key={group.id}
group={group} group={group}
@ -174,7 +176,7 @@ class CollectionMembers extends React.Component<Props> {
`${group.id}-${collection.id}` `${group.id}-${collection.id}`
)} )}
onRemove={() => this.handleRemoveGroup(group)} onRemove={() => this.handleRemoveGroup(group)}
onUpdate={permission => onUpdate={(permission) =>
this.handleUpdateGroup(group, permission) this.handleUpdateGroup(group, permission)
} }
/> />
@ -219,14 +221,14 @@ class CollectionMembers extends React.Component<Props> {
} }
fetch={collection.private ? memberships.fetchPage : users.fetchPage} fetch={collection.private ? memberships.fetchPage : users.fetchPage}
options={collection.private ? { id: collection.id } : undefined} options={collection.private ? { id: collection.id } : undefined}
renderItem={item => ( renderItem={(item) => (
<MemberListItem <MemberListItem
key={item.id} key={item.id}
user={item} user={item}
membership={memberships.get(`${item.id}-${collection.id}`)} membership={memberships.get(`${item.id}-${collection.id}`)}
canEdit={collection.private && item.id !== user.id} canEdit={collection.private && item.id !== user.id}
onRemove={() => this.handleRemoveUser(item)} onRemove={() => this.handleRemoveUser(item)}
onUpdate={permission => this.handleUpdateUser(item, permission)} onUpdate={(permission) => this.handleUpdateUser(item, permission)}
/> />
)} )}
/> />

View File

@ -39,7 +39,7 @@ const MemberListItem = ({
? collectionGroupMembership.permission ? collectionGroupMembership.permission
: undefined : undefined
} }
onChange={ev => onUpdate(ev.target.value)} onChange={(ev) => onUpdate(ev.target.value)}
labelHidden labelHidden
/> />
<ButtonWrap> <ButtonWrap>

View File

@ -52,29 +52,26 @@ const MemberListItem = ({
image={<Avatar src={user.avatarUrl} size={40} />} image={<Avatar src={user.avatarUrl} size={40} />}
actions={ actions={
<Flex align="center"> <Flex align="center">
{canEdit && {canEdit && onUpdate && (
onUpdate && ( <Select
<Select label="Permissions"
label="Permissions" options={PERMISSIONS}
options={PERMISSIONS} value={membership ? membership.permission : undefined}
value={membership ? membership.permission : undefined} onChange={(ev) => onUpdate(ev.target.value)}
onChange={ev => onUpdate(ev.target.value)} labelHidden
labelHidden />
/> )}
)}
&nbsp;&nbsp; &nbsp;&nbsp;
{canEdit && {canEdit && onRemove && (
onRemove && ( <DropdownMenu>
<DropdownMenu> <DropdownMenuItem onClick={onRemove}>Remove</DropdownMenuItem>
<DropdownMenuItem onClick={onRemove}>Remove</DropdownMenuItem> </DropdownMenu>
</DropdownMenu> )}
)} {canEdit && onAdd && (
{canEdit && <Button onClick={onAdd} neutral>
onAdd && ( Add
<Button onClick={onAdd} neutral> </Button>
Add )}
</Button>
)}
</Flex> </Flex>
} }
/> />

View File

@ -37,9 +37,7 @@ const UserListItem = ({ user, onAdd, canEdit }: Props) => {
<Button type="button" onClick={onAdd} icon={<PlusIcon />} neutral> <Button type="button" onClick={onAdd} icon={<PlusIcon />} neutral>
Add Add
</Button> </Button>
) : ( ) : undefined
undefined
)
} }
/> />
); );

View File

@ -85,7 +85,7 @@ class CollectionNew extends React.Component<Props> {
this.hasOpenedIconPicker = true; this.hasOpenedIconPicker = true;
}; };
handleDescriptionChange = getValue => { handleDescriptionChange = (getValue) => {
this.description = getValue(); this.description = getValue();
}; };

View File

@ -4,7 +4,7 @@ import Flex from "components/Flex";
const Container = styled(Flex)` const Container = styled(Flex)`
position: relative; position: relative;
margin-top: ${props => (props.isShare ? "50px" : "0")}; margin-top: ${(props) => (props.isShare ? "50px" : "0")};
`; `;
export default Container; export default Container;

View File

@ -16,26 +16,23 @@ export default function Contents({ headings }: Props) {
const [activeSlug, setActiveSlug] = React.useState(); const [activeSlug, setActiveSlug] = React.useState();
const position = useWindowScrollPosition({ throttle: 100 }); const position = useWindowScrollPosition({ throttle: 100 });
React.useEffect( React.useEffect(() => {
() => { for (let key = 0; key < headings.length; key++) {
for (let key = 0; key < headings.length; key++) { const heading = headings[key];
const heading = headings[key]; const element = window.document.getElementById(
const element = window.document.getElementById( decodeURIComponent(heading.id)
decodeURIComponent(heading.id) );
);
if (element) { if (element) {
const bounding = element.getBoundingClientRect(); const bounding = element.getBoundingClientRect();
if (bounding.top > HEADING_OFFSET) { if (bounding.top > HEADING_OFFSET) {
const last = headings[Math.max(0, key - 1)]; const last = headings[Math.max(0, key - 1)];
setActiveSlug(last.id); setActiveSlug(last.id);
return; return;
}
} }
} }
}, }
[position, headings] }, [position, headings]);
);
// calculate the minimum heading level and adjust all the headings to make // calculate the minimum heading level and adjust all the headings to make
// that the top-most. This prevents the contents from being weirdly indented // that the top-most. This prevents the contents from being weirdly indented
@ -52,7 +49,7 @@ export default function Contents({ headings }: Props) {
<Heading>Contents</Heading> <Heading>Contents</Heading>
{headings.length ? ( {headings.length ? (
<List> <List>
{headings.map(heading => ( {headings.map((heading) => (
<ListItem <ListItem
key={heading.id} key={heading.id}
level={heading.level - headingAdjustment} level={heading.level - headingAdjustment}
@ -75,7 +72,7 @@ const Wrapper = styled("div")`
position: sticky; position: sticky;
top: 80px; top: 80px;
box-shadow: 1px 0 0 ${props => darken(0.05, props.theme.sidebarBackground)}; box-shadow: 1px 0 0 ${(props) => darken(0.05, props.theme.sidebarBackground)};
margin-top: 40px; margin-top: 40px;
margin-right: 2em; margin-right: 2em;
min-height: 40px; min-height: 40px;
@ -93,7 +90,7 @@ const Heading = styled("h3")`
font-size: 11px; font-size: 11px;
font-weight: 600; font-weight: 600;
text-transform: uppercase; text-transform: uppercase;
color: ${props => props.theme.sidebarText}; color: ${(props) => props.theme.sidebarText};
letter-spacing: 0.04em; letter-spacing: 0.04em;
`; `;
@ -106,20 +103,20 @@ const Empty = styled(HelpText)`
`; `;
const ListItem = styled("li")` const ListItem = styled("li")`
margin-left: ${props => (props.level - 1) * 10}px; margin-left: ${(props) => (props.level - 1) * 10}px;
margin-bottom: 8px; margin-bottom: 8px;
padding-right: 2em; padding-right: 2em;
line-height: 1.3; line-height: 1.3;
border-right: 3px solid border-right: 3px solid
${props => (props.active ? props.theme.textSecondary : "transparent")}; ${(props) => (props.active ? props.theme.textSecondary : "transparent")};
`; `;
const Link = styled("a")` const Link = styled("a")`
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
font-size: 14px; font-size: 14px;
&:hover { &:hover {
color: ${props => props.theme.primary}; color: ${(props) => props.theme.primary};
} }
`; `;

View File

@ -77,7 +77,7 @@ class DataLoader extends React.Component<Props> {
const results = await this.props.documents.search(term); const results = await this.props.documents.search(term);
return results return results
.filter(result => result.document.title) .filter((result) => result.document.title)
.map((result, index) => ({ .map((result, index) => ({
title: result.document.title, title: result.document.title,
url: result.document.url, url: result.document.url,
@ -130,7 +130,7 @@ class DataLoader extends React.Component<Props> {
return this.goToDocumentCanonical(); return this.goToDocumentCanonical();
} }
this.props.shares.fetch(document.id).catch(err => { this.props.shares.fetch(document.id).catch((err) => {
if (!(err instanceof NotFoundError)) { if (!(err instanceof NotFoundError)) {
throw err; throw err;
} }
@ -195,7 +195,12 @@ class DataLoader extends React.Component<Props> {
} }
export default withRouter( export default withRouter(
inject("ui", "auth", "documents", "revisions", "policies", "shares")( inject(
DataLoader "ui",
) "auth",
"documents",
"revisions",
"policies",
"shares"
)(DataLoader)
); );

View File

@ -298,7 +298,7 @@ class DocumentScene extends React.Component<Props> {
this.isUploading = false; this.isUploading = false;
}; };
onChange = getEditorText => { onChange = (getEditorText) => {
this.getEditorText = getEditorText; this.getEditorText = getEditorText;
// document change while read only is presumed to be a checkbox edit, // document change while read only is presumed to be a checkbox edit,
@ -312,7 +312,7 @@ class DocumentScene extends React.Component<Props> {
} }
}; };
onChangeTitle = event => { onChangeTitle = (event) => {
this.title = event.target.value; this.title = event.target.value;
this.updateIsDirtyDebounced(); this.updateIsDirtyDebounced();
this.autosave(); this.autosave();
@ -409,22 +409,20 @@ class DocumentScene extends React.Component<Props> {
column column
auto auto
> >
{document.isTemplate && {document.isTemplate && !readOnly && (
!readOnly && ( <Notice muted>
<Notice muted> Youre editing a template. Highlight some text and use the{" "}
Youre editing a template. Highlight some text and use the{" "} <PlaceholderIcon color="currentColor" /> control to add
<PlaceholderIcon color="currentColor" /> control to add placeholders that can be filled out when creating new
placeholders that can be filled out when creating new documents from this template.
documents from this template. </Notice>
</Notice> )}
)} {document.archivedAt && !document.deletedAt && (
{document.archivedAt && <Notice muted>
!document.deletedAt && ( Archived by {document.updatedBy.name}{" "}
<Notice muted> <Time dateTime={document.archivedAt} /> ago
Archived by {document.updatedBy.name}{" "} </Notice>
<Time dateTime={document.archivedAt} /> ago )}
</Notice>
)}
{document.deletedAt && ( {document.deletedAt && (
<Notice muted> <Notice muted>
Deleted by {document.updatedBy.name}{" "} Deleted by {document.updatedBy.name}{" "}
@ -440,15 +438,14 @@ class DocumentScene extends React.Component<Props> {
</Notice> </Notice>
)} )}
<Flex auto={!readOnly}> <Flex auto={!readOnly}>
{ui.tocVisible && {ui.tocVisible && readOnly && (
readOnly && ( <Contents
<Contents headings={this.editor ? this.editor.getHeadings() : []}
headings={this.editor ? this.editor.getHeadings() : []} />
/> )}
)}
<Editor <Editor
id={document.id} id={document.id}
ref={ref => { ref={(ref) => {
if (ref) { if (ref) {
this.editor = ref; this.editor = ref;
} }
@ -476,16 +473,14 @@ class DocumentScene extends React.Component<Props> {
ui={this.props.ui} ui={this.props.ui}
/> />
</Flex> </Flex>
{readOnly && {readOnly && !isShare && !revision && (
!isShare && <React.Fragment>
!revision && ( <MarkAsViewed document={document} />
<React.Fragment> <ReferencesWrapper isOnlyTitle={document.isOnlyTitle}>
<MarkAsViewed document={document} /> <References document={document} />
<ReferencesWrapper isOnlyTitle={document.isOnlyTitle}> </ReferencesWrapper>
<References document={document} /> </React.Fragment>
</ReferencesWrapper> )}
</React.Fragment>
)}
</MaxWidth> </MaxWidth>
</Container> </Container>
</Background> </Background>
@ -501,12 +496,12 @@ const PlaceholderIcon = styled(InputIcon)`
`; `;
const Background = styled(Container)` const Background = styled(Container)`
background: ${props => props.theme.background}; background: ${(props) => props.theme.background};
transition: ${props => props.theme.backgroundTransition}; transition: ${(props) => props.theme.backgroundTransition};
`; `;
const ReferencesWrapper = styled("div")` const ReferencesWrapper = styled("div")`
margin-top: ${props => (props.isOnlyTitle ? -45 : 16)}px; margin-top: ${(props) => (props.isOnlyTitle ? -45 : 16)}px;
@media print { @media print {
display: none; display: none;
@ -514,7 +509,7 @@ const ReferencesWrapper = styled("div")`
`; `;
const MaxWidth = styled(Flex)` const MaxWidth = styled(Flex)`
${props => ${(props) =>
props.archived && `* { color: ${props.theme.textSecondary} !important; } `}; props.archived && `* { color: ${props.theme.textSecondary} !important; } `};
padding: 0 16px; padding: 0 16px;
max-width: 100vw; max-width: 100vw;
@ -523,7 +518,7 @@ const MaxWidth = styled(Flex)`
${breakpoint("tablet")` ${breakpoint("tablet")`
padding: 0 24px; padding: 0 24px;
margin: 4px auto 12px; margin: 4px auto 12px;
max-width: calc(48px + ${props => (props.tocVisible ? "64em" : "46em")}); max-width: calc(48px + ${(props) => (props.tocVisible ? "64em" : "46em")});
`}; `};
${breakpoint("desktopLarge")` ${breakpoint("desktopLarge")`

View File

@ -44,7 +44,7 @@ class DocumentMove extends React.Component<Props> {
// Build index // Build index
const indexeableDocuments = []; const indexeableDocuments = [];
paths.forEach(path => indexeableDocuments.push(path)); paths.forEach((path) => indexeableDocuments.push(path));
index.addDocuments(indexeableDocuments); index.addDocuments(indexeableDocuments);
return index; return index;
@ -65,20 +65,20 @@ class DocumentMove extends React.Component<Props> {
// Exclude root from search results if document is already at the root // Exclude root from search results if document is already at the root
if (!document.parentDocumentId) { if (!document.parentDocumentId) {
results = results.filter(result => result.id !== document.collectionId); results = results.filter((result) => result.id !== document.collectionId);
} }
// Exclude document if on the path to result, or the same result // Exclude document if on the path to result, or the same result
results = results.filter( results = results.filter(
result => (result) =>
!result.path.map(doc => doc.id).includes(document.id) && !result.path.map((doc) => doc.id).includes(document.id) &&
last(result.path.map(doc => doc.id)) !== document.parentDocumentId last(result.path.map((doc) => doc.id)) !== document.parentDocumentId
); );
return results; return results;
} }
handleKeyDown = ev => { handleKeyDown = (ev) => {
// Down // Down
if (ev.which === 40) { if (ev.which === 40) {
ev.preventDefault(); ev.preventDefault();
@ -98,7 +98,7 @@ class DocumentMove extends React.Component<Props> {
this.searchTerm = ev.target.value; this.searchTerm = ev.target.value;
}; };
setFirstDocumentRef = ref => { setFirstDocumentRef = (ref) => {
this.firstDocument = ref; this.firstDocument = ref;
}; };
@ -121,50 +121,47 @@ class DocumentMove extends React.Component<Props> {
return ( return (
<Modal isOpen onRequestClose={onRequestClose} title="Move document"> <Modal isOpen onRequestClose={onRequestClose} title="Move document">
{document && {document && collections.isLoaded && (
collections.isLoaded && ( <Flex column>
<Flex column> <Section>
<Section> <Labeled label="Current location">
<Labeled label="Current location"> {this.renderPathToCurrentDocument()}
{this.renderPathToCurrentDocument()} </Labeled>
</Labeled> </Section>
</Section>
<Section column> <Section column>
<Labeled label="Choose a new location"> <Labeled label="Choose a new location">
<Input <Input
type="search" type="search"
placeholder="Search collections & documents…" placeholder="Search collections & documents…"
onKeyDown={this.handleKeyDown} onKeyDown={this.handleKeyDown}
onChange={this.handleFilter} onChange={this.handleFilter}
required required
autoFocus autoFocus
/> />
</Labeled> </Labeled>
<Flex column> <Flex column>
<StyledArrowKeyNavigation <StyledArrowKeyNavigation
mode={ArrowKeyNavigation.mode.VERTICAL} mode={ArrowKeyNavigation.mode.VERTICAL}
defaultActiveChildIndex={0} defaultActiveChildIndex={0}
> >
{this.results {this.results.slice(0, MAX_RESULTS).map((result, index) => (
.slice(0, MAX_RESULTS) <PathToDocument
.map((result, index) => ( key={result.id}
<PathToDocument result={result}
key={result.id} document={document}
result={result} collection={collections.get(result.collectionId)}
document={document} ref={(ref) =>
collection={collections.get(result.collectionId)} index === 0 && this.setFirstDocumentRef(ref)
ref={ref => }
index === 0 && this.setFirstDocumentRef(ref) onSuccess={this.handleSuccess}
} />
onSuccess={this.handleSuccess} ))}
/> </StyledArrowKeyNavigation>
))} </Flex>
</StyledArrowKeyNavigation> </Section>
</Flex> </Flex>
</Section> )}
</Flex>
)}
</Modal> </Modal>
); );
} }

View File

@ -89,7 +89,7 @@ class DocumentEditor extends React.Component<Props> {
/> />
<DocumentMeta isDraft={isDraft} document={document} /> <DocumentMeta isDraft={isDraft} document={document} />
<Editor <Editor
ref={ref => (this.editor = ref)} ref={(ref) => (this.editor = ref)}
autoFocus={title && !this.props.defaultValue} autoFocus={title && !this.props.defaultValue}
placeholder="…the rest is up to you" placeholder="…the rest is up to you"
onHoverLink={this.handleLinkActive} onHoverLink={this.handleLinkActive}
@ -98,15 +98,13 @@ class DocumentEditor extends React.Component<Props> {
{...this.props} {...this.props}
/> />
{!readOnly && <ClickablePadding onClick={this.focusAtEnd} grow />} {!readOnly && <ClickablePadding onClick={this.focusAtEnd} grow />}
{this.activeLinkEvent && {this.activeLinkEvent && !isShare && readOnly && (
!isShare && <HoverPreview
readOnly && ( node={this.activeLinkEvent.target}
<HoverPreview event={this.activeLinkEvent}
node={this.activeLinkEvent.target} onClose={this.handleLinkInactive}
event={this.activeLinkEvent} />
onClose={this.handleLinkInactive} )}
/>
)}
</Flex> </Flex>
); );
} }
@ -117,10 +115,10 @@ const Title = styled(Textarea)`
line-height: 1.25; line-height: 1.25;
margin-top: 1em; margin-top: 1em;
margin-bottom: 0.5em; margin-bottom: 0.5em;
text: ${props => props.theme.text}; text: ${(props) => props.theme.text};
background: ${props => props.theme.background}; background: ${(props) => props.theme.background};
transition: ${props => props.theme.backgroundTransition}; transition: ${(props) => props.theme.backgroundTransition};
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
font-size: 2.25em; font-size: 2.25em;
font-weight: 500; font-weight: 500;
outline: none; outline: none;
@ -129,7 +127,7 @@ const Title = styled(Textarea)`
resize: none; resize: none;
&::placeholder { &::placeholder {
color: ${props => props.theme.placeholder}; color: ${(props) => props.theme.placeholder};
} }
`; `;

View File

@ -194,12 +194,11 @@ class Header extends React.Component<Props> {
</Title> </Title>
)} )}
<Wrapper align="center" justify="flex-end"> <Wrapper align="center" justify="flex-end">
{isSaving && {isSaving && !isPublishing && (
!isPublishing && ( <Action>
<Action> <Status>Saving</Status>
<Status>Saving</Status> </Action>
</Action> )}
)}
&nbsp; &nbsp;
<Fade> <Fade>
<Collaborators <Collaborators
@ -207,40 +206,38 @@ class Header extends React.Component<Props> {
currentUserId={auth.user ? auth.user.id : undefined} currentUserId={auth.user ? auth.user.id : undefined}
/> />
</Fade> </Fade>
{isEditing && {isEditing && !isTemplate && isNew && (
!isTemplate && <Action>
isNew && ( <TemplatesMenu document={document} />
<Action> </Action>
<TemplatesMenu document={document} /> )}
</Action> {!isEditing && canShareDocuments && (
)} <Action>
{!isEditing && <Tooltip
canShareDocuments && ( tooltip={
<Action> isPubliclyShared ? (
<Tooltip <React.Fragment>
tooltip={ Anyone with the link <br />
isPubliclyShared ? ( can view this document
<React.Fragment> </React.Fragment>
Anyone with the link <br />can view this document ) : (
</React.Fragment> ""
) : ( )
"" }
) delay={500}
} placement="bottom"
delay={500} >
placement="bottom" <Button
icon={isPubliclyShared ? <GlobeIcon /> : undefined}
onClick={this.handleShareLink}
neutral
small
> >
<Button Share
icon={isPubliclyShared ? <GlobeIcon /> : undefined} </Button>
onClick={this.handleShareLink} </Tooltip>
neutral </Action>
small )}
>
Share
</Button>
</Tooltip>
</Action>
)}
{isEditing && ( {isEditing && (
<React.Fragment> <React.Fragment>
<Action> <Action>
@ -282,62 +279,56 @@ class Header extends React.Component<Props> {
</Tooltip> </Tooltip>
</Action> </Action>
)} )}
{canEdit && {canEdit && can.createChildDocument && (
can.createChildDocument && ( <Action>
<Action> <NewChildDocumentMenu
<NewChildDocumentMenu document={document}
document={document} label={
label={ <Tooltip
<Tooltip tooltip="New document"
tooltip="New document" shortcut="n"
shortcut="n" delay={500}
delay={500} placement="bottom"
placement="bottom" >
> <Button icon={<PlusIcon />} neutral>
<Button icon={<PlusIcon />} neutral> New doc
New doc </Button>
</Button> </Tooltip>
</Tooltip> }
} />
/> </Action>
</Action> )}
)} {canEdit && isTemplate && !isDraft && !isRevision && (
{canEdit && <Action>
isTemplate && <Button
!isDraft && icon={<PlusIcon />}
!isRevision && ( onClick={this.handleNewFromTemplate}
<Action> primary
small
>
New from template
</Button>
</Action>
)}
{can.update && isDraft && !isRevision && (
<Action>
<Tooltip
tooltip="Publish"
shortcut={`${meta}+shift+p`}
delay={500}
placement="bottom"
>
<Button <Button
icon={<PlusIcon />} onClick={this.handlePublish}
onClick={this.handleNewFromTemplate} title="Publish document"
primary disabled={publishingIsDisabled}
small small
> >
New from template {isPublishing ? "Publishing…" : "Publish"}
</Button> </Button>
</Action> </Tooltip>
)} </Action>
{can.update && )}
isDraft &&
!isRevision && (
<Action>
<Tooltip
tooltip="Publish"
shortcut={`${meta}+shift+p`}
delay={500}
placement="bottom"
>
<Button
onClick={this.handlePublish}
title="Publish document"
disabled={publishingIsDisabled}
small
>
{isPublishing ? "Publishing…" : "Publish"}
</Button>
</Tooltip>
</Action>
)}
{!isEditing && ( {!isEditing && (
<React.Fragment> <React.Fragment>
<Separator /> <Separator />
@ -358,7 +349,7 @@ class Header extends React.Component<Props> {
} }
const Status = styled.div` const Status = styled.div`
color: ${props => props.theme.slate}; color: ${(props) => props.theme.slate};
`; `;
const BreadcrumbAndContents = styled(Flex)` const BreadcrumbAndContents = styled(Flex)`
@ -386,9 +377,9 @@ const Actions = styled(Flex)`
right: 0; right: 0;
left: 0; left: 0;
z-index: 2; z-index: 2;
background: ${props => transparentize(0.2, props.theme.background)}; background: ${(props) => transparentize(0.2, props.theme.background)};
box-shadow: 0 1px 0 box-shadow: 0 1px 0
${props => ${(props) =>
props.isCompact props.isCompact
? darken(0.05, props.theme.sidebarBackground) ? darken(0.05, props.theme.sidebarBackground)
: "transparent"}; : "transparent"};
@ -402,7 +393,7 @@ const Actions = styled(Flex)`
} }
${breakpoint("tablet")` ${breakpoint("tablet")`
padding: ${props => (props.isCompact ? "12px" : `24px 24px 0`)}; padding: ${(props) => (props.isCompact ? "12px" : `24px 24px 0`)};
`}; `};
`; `;

View File

@ -26,7 +26,7 @@ const DocumentLink = styled(Link)`
&:hover, &:hover,
&:active, &:active,
&:focus { &:focus {
background: ${props => props.theme.listItemHoverBackground}; background: ${(props) => props.theme.listItemHoverBackground};
outline: none; outline: none;
} }
`; `;
@ -39,7 +39,7 @@ const Title = styled.h3`
margin-top: 0; margin-top: 0;
margin-bottom: 0.25em; margin-bottom: 0.25em;
white-space: nowrap; white-space: nowrap;
color: ${props => props.theme.text}; color: ${(props) => props.theme.text};
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
`; `;

View File

@ -52,7 +52,7 @@ class References extends React.Component<Props> {
)} )}
</Tabs> </Tabs>
{isBacklinksTab {isBacklinksTab
? backlinks.map(backlinkedDocument => ( ? backlinks.map((backlinkedDocument) => (
<ReferenceListItem <ReferenceListItem
anchor={document.urlId} anchor={document.urlId}
key={backlinkedDocument.id} key={backlinkedDocument.id}
@ -62,7 +62,7 @@ class References extends React.Component<Props> {
} }
/> />
)) ))
: children.map(node => { : children.map((node) => {
// If we have the document in the store already then use it to get the extra // If we have the document in the store already then use it to get the extra
// contextual info, otherwise the collection node will do (only has title and id) // contextual info, otherwise the collection node will do (only has title and id)
const document = documents.get(node.id); const document = documents.get(node.id);

View File

@ -51,17 +51,15 @@ class DocumentDelete extends React.Component<Props> {
<HelpText> <HelpText>
Are you sure about that? Deleting the{" "} Are you sure about that? Deleting the{" "}
<strong>{document.titleWithDefault}</strong> {document.noun} will <strong>{document.titleWithDefault}</strong> {document.noun} will
delete all of its history{document.isTemplate delete all of its history
? "" {document.isTemplate ? "" : ", and any nested documents"}.
: ", and any nested documents"}.
</HelpText> </HelpText>
{!document.isDraft && {!document.isDraft && !document.isArchived && (
!document.isArchived && ( <HelpText>
<HelpText> If youd like the option of referencing or restoring this{" "}
If youd like the option of referencing or restoring this{" "} {document.noun} in the future, consider archiving it instead.
{document.noun} in the future, consider archiving it instead. </HelpText>
</HelpText> )}
)}
<Button type="submit" danger> <Button type="submit" danger>
{this.isDeleting ? "Deleting…" : "Im sure  Delete"} {this.isDeleting ? "Deleting…" : "Im sure  Delete"}
</Button> </Button>

View File

@ -35,7 +35,7 @@ class DocumentShare extends React.Component<Props> {
clearTimeout(this.timeout); clearTimeout(this.timeout);
} }
handlePublishedChange = async event => { handlePublishedChange = async (event) => {
const { document, shares } = this.props; const { document, shares } = this.props;
const share = shares.getByDocumentId(document.id); const share = shares.getByDocumentId(document.id);
invariant(share, "Share must exist"); invariant(share, "Share must exist");
@ -76,7 +76,8 @@ class DocumentShare extends React.Component<Props> {
: "It is only viewable by those that already have access to the collection."}{" "} : "It is only viewable by those that already have access to the collection."}{" "}
<Link to="/settings/shares" onClick={onSubmit}> <Link to="/settings/shares" onClick={onSubmit}>
Manage all share links Manage all share links
</Link>. </Link>
.
</HelpText> </HelpText>
{canPublish && ( {canPublish && (
<React.Fragment> <React.Fragment>
@ -112,7 +113,9 @@ class DocumentShare extends React.Component<Props> {
<Button type="submit" disabled={this.isCopied || !share} primary> <Button type="submit" disabled={this.isCopied || !share} primary>
{this.isCopied ? "Copied!" : "Copy Link"} {this.isCopied ? "Copied!" : "Copy Link"}
</Button> </Button>
</CopyToClipboard>&nbsp;&nbsp;&nbsp;<a href={share.url} target="_blank"> </CopyToClipboard>
&nbsp;&nbsp;&nbsp;
<a href={share.url} target="_blank">
Preview Preview
</a> </a>
</div> </div>

View File

@ -10,9 +10,8 @@ const Error404 = () => {
<PageTitle title="Not Found" /> <PageTitle title="Not Found" />
<h1>Not found</h1> <h1>Not found</h1>
<Empty> <Empty>
We were unable to find the page youre looking for. Go to the&nbsp;<a href="/"> We were unable to find the page youre looking for. Go to the&nbsp;
homepage <a href="/">homepage</a>?
</a>?
</Empty> </Empty>
</CenteredContent> </CenteredContent>
); );

View File

@ -50,7 +50,7 @@ class AddPeopleToGroup extends React.Component<Props> {
}); });
}, 250); }, 250);
handleAddUser = async user => { handleAddUser = async (user) => {
try { try {
await this.props.groupMemberships.create({ await this.props.groupMemberships.create({
groupId: this.props.group.id, groupId: this.props.group.id,
@ -74,7 +74,8 @@ class AddPeopleToGroup extends React.Component<Props> {
someone whos not yet on the team yet?{" "} someone whos not yet on the team yet?{" "}
<a role="button" onClick={this.handleInviteModalOpen}> <a role="button" onClick={this.handleInviteModalOpen}>
Invite them to {team.name} Invite them to {team.name}
</a>. </a>
.
</HelpText> </HelpText>
<Input <Input
@ -97,7 +98,7 @@ class AddPeopleToGroup extends React.Component<Props> {
} }
items={users.notInGroup(group.id, this.query)} items={users.notInGroup(group.id, this.query)}
fetch={this.query ? undefined : users.fetchPage} fetch={this.query ? undefined : users.fetchPage}
renderItem={item => ( renderItem={(item) => (
<GroupMemberListItem <GroupMemberListItem
key={item.id} key={item.id}
user={item} user={item}
@ -118,6 +119,9 @@ class AddPeopleToGroup extends React.Component<Props> {
} }
} }
export default inject("auth", "users", "groupMemberships", "ui")( export default inject(
AddPeopleToGroup "auth",
); "users",
"groupMemberships",
"ui"
)(AddPeopleToGroup);

Some files were not shown because too many files have changed in this diff Show More