diff --git a/frontend/components/CenteredContent/CenteredContent.js b/frontend/components/CenteredContent/CenteredContent.js index 6f135e1e..cfc4fe08 100644 --- a/frontend/components/CenteredContent/CenteredContent.js +++ b/frontend/components/CenteredContent/CenteredContent.js @@ -8,7 +8,7 @@ type Props = { const Container = styled.div` width: 100%; - margin: 40px 20px; + margin: 60px 20px; `; const Content = styled.div` diff --git a/frontend/components/Collaborators/Collaborators.js b/frontend/components/Collaborators/Collaborators.js new file mode 100644 index 00000000..487921fd --- /dev/null +++ b/frontend/components/Collaborators/Collaborators.js @@ -0,0 +1,56 @@ +// @flow +import React from 'react'; +import moment from 'moment'; +import styled from 'styled-components'; +import { color } from 'styles/constants'; +import Flex from 'components/Flex'; +import Tooltip from 'components/Tooltip'; +import Document from 'models/Document'; + +const Collaborators = function({ document }: { document: Document }) { + const { + createdAt, + updatedAt, + createdBy, + updatedBy, + collaborators, + } = document; + let tooltip; + + if (createdAt === updatedAt) { + tooltip = `${createdBy.name} published ${moment(createdAt).fromNow()}`; + } else { + tooltip = `${updatedBy.name} modified ${moment(updatedAt).fromNow()}`; + } + + return ( + + + {collaborators.map(user => ( + + ))} + + + ); +}; + +const Avatars = styled(Flex)` + flex-direction: row-reverse; + margin-right: 10px; + height: 26px; +`; + +const Avatar = styled.img` + width: 26px; + height: 26px; + flex-shrink: 0; + border-radius: 50%; + border: 2px solid ${color.white}; + margin-right: -13px; + + &:first-child { + margin-right: 0; + } +`; + +export default Collaborators; diff --git a/frontend/components/Collaborators/index.js b/frontend/components/Collaborators/index.js new file mode 100644 index 00000000..68cac4de --- /dev/null +++ b/frontend/components/Collaborators/index.js @@ -0,0 +1,3 @@ +// @flow +import Collaborators from './Collaborators'; +export default Collaborators; diff --git a/frontend/components/DocumentPreview/DocumentPreview.js b/frontend/components/DocumentPreview/DocumentPreview.js index 6703e896..91d8bff1 100644 --- a/frontend/components/DocumentPreview/DocumentPreview.js +++ b/frontend/components/DocumentPreview/DocumentPreview.js @@ -5,7 +5,7 @@ import { Link } from 'react-router-dom'; import Document from 'models/Document'; import styled from 'styled-components'; import { color } from 'styles/constants'; -import PublishingInfo from 'components/PublishingInfo'; +import PublishingInfo from './components/PublishingInfo'; import StarIcon from 'components/Icon/StarIcon'; type Props = { diff --git a/frontend/components/PublishingInfo/PublishingInfo.js b/frontend/components/DocumentPreview/components/PublishingInfo.js similarity index 70% rename from frontend/components/PublishingInfo/PublishingInfo.js rename to frontend/components/DocumentPreview/components/PublishingInfo.js index 90b00c6d..878bfdda 100644 --- a/frontend/components/PublishingInfo/PublishingInfo.js +++ b/frontend/components/DocumentPreview/components/PublishingInfo.js @@ -5,7 +5,6 @@ import styled from 'styled-components'; import { color } from 'styles/constants'; import Collection from 'models/Collection'; import Document from 'models/Document'; -import type { User } from 'types'; import Flex from 'components/Flex'; const Container = styled(Flex)` @@ -13,24 +12,6 @@ const Container = styled(Flex)` font-size: 13px; `; -const Avatars = styled(Flex)` - flex-direction: row-reverse; - margin-right: 10px; -`; - -const Avatar = styled.img` - width: 26px; - height: 26px; - flex-shrink: 0; - border-radius: 50%; - border: 2px solid ${color.white}; - margin-right: -13px; - - &:first-child { - margin-right: 0; - } -`; - const Modified = styled.span` color: ${props => (props.highlight ? color.slateDark : color.slate)}; font-weight: ${props => (props.highlight ? '600' : '400')}; @@ -38,14 +19,13 @@ const Modified = styled.span` class PublishingInfo extends Component { props: { - collaborators?: Array, collection?: Collection, document: Document, views?: number, }; render() { - const { collaborators, collection, document } = this.props; + const { collection, document } = this.props; const { modifiedSinceViewed, createdAt, @@ -56,12 +36,6 @@ class PublishingInfo extends Component { return ( - {collaborators && - - {collaborators.map(user => ( - - ))} - } {createdAt === updatedAt ? {createdBy.name} diff --git a/frontend/components/Editor/Editor.js b/frontend/components/Editor/Editor.js index 25803128..f496faf2 100644 --- a/frontend/components/Editor/Editor.js +++ b/frontend/components/Editor/Editor.js @@ -27,7 +27,6 @@ type Props = { onImageUploadStop: Function, emoji: string, readOnly: boolean, - heading?: ?React.Element<*>, }; type KeyData = { @@ -187,12 +186,7 @@ type KeyData = { auto > - - {this.props.heading} - +
(this.editor = ref)} @@ -224,11 +218,10 @@ const MaxWidth = styled(Flex)` height: 100%; `; -const HeaderContainer = styled(Flex).attrs({ - align: 'flex-end', -})` - height: 100px; +const Header = styled(Flex)` + height: 60px; flex-shrink: 0; + align-items: flex-end; ${({ readOnly }) => !readOnly && 'cursor: text;'} `; diff --git a/frontend/components/PublishingInfo/index.js b/frontend/components/PublishingInfo/index.js deleted file mode 100644 index fb57b45f..00000000 --- a/frontend/components/PublishingInfo/index.js +++ /dev/null @@ -1,3 +0,0 @@ -// @flow -import PublishingInfo from './PublishingInfo'; -export default PublishingInfo; diff --git a/frontend/components/Tooltip/index.js b/frontend/components/Tooltip/index.js new file mode 100644 index 00000000..7416605c --- /dev/null +++ b/frontend/components/Tooltip/index.js @@ -0,0 +1,11 @@ +// @flow +import { TooltipTrigger } from 'pui-react-tooltip'; +import { injectGlobal } from 'styled-components'; + +injectGlobal([ + ` + .tooltip:hover .tooltip-container:not(.tooltip-container-hidden){visibility:visible;opacity:1}.tooltip-container{visibility:hidden;-webkit-transition:opacity ease-out 0.2s;transition:opacity ease-out 0.2s;z-index:10;position:absolute;bottom:100%;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);margin:0 0 8px 0;text-align:left}.tooltip-container.tooltip-container-visible{visibility:visible}.tooltip-container.tooltip-hoverable:after{content:"";position:absolute;width:calc(100% + 16px);height:calc(100% + 16px);top:50%;left:50%;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%)}.tooltip-container .tooltip-content{white-space:nowrap;padding:4px 8px;font-size:12px;line-height:16px;font-weight:400;letter-spacing:0;text-transform:none;background-color:#243641;color:#fff;border-radius:2px;border:1px solid #243641;box-shadow:0px 2px 2px 0px rgba(36, 54, 65, .1),0px 0px 2px 0px rgba(36, 54, 65, .1)}.tooltip-container .tooltip-content:before{content:"";z-index:1;position:absolute;bottom:-4px;left:50%;-webkit-transform:translateX(-50%) rotateZ(45deg);transform:translateX(-50%) rotateZ(45deg);background-color:#243641;border-bottom:1px solid #243641;border-right:1px solid #243641;width:8px;height:8px}.tooltip-container .tooltip-content:after{content:"";box-sizing:content-box;z-index:-1;position:absolute;bottom:-4px;left:50%;-webkit-transform:translateX(-50%) rotateZ(45deg);transform:translateX(-50%) rotateZ(45deg);background-color:#243641;box-shadow:0px 2px 2px 0px rgba(36, 54, 65, .1),0px 0px 2px 0px rgba(36, 54, 65, .1);width:8px;height:8px}.tooltip{position:relative;display:inline-block}.tooltip.tooltip-light .tooltip-content{background-color:#fff;color:#243641;border:1px solid #DFE5E8}.tooltip.tooltip-light .tooltip-content:before{background-color:#fff;border-bottom:1px solid #DFE5E8;border-right:1px solid #DFE5E8}.tooltip.tooltip-light .tooltip-content:after{background-color:#fff}.tooltip.tooltip-bottom .tooltip-container{top:100%;bottom:auto;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);margin:8px 0 0 0}.tooltip.tooltip-bottom .tooltip-container .tooltip-content:before{bottom:auto;top:-4px;border-top:1px solid #243641;border-right:none;border-bottom:none;border-left:1px solid #243641}.tooltip.tooltip-bottom .tooltip-container .tooltip-content:after{bottom:auto;top:-4px}.tooltip.tooltip-bottom.tooltip-light .tooltip-content:before{border-top:1px solid #DFE5E8;border-left:1px solid #DFE5E8}.tooltip.tooltip-right .tooltip-container{top:50%;bottom:auto;left:100%;-webkit-transform:translatey(-50%);transform:translatey(-50%);margin:0 0 0 8px}.tooltip.tooltip-right .tooltip-container .tooltip-content:before{bottom:auto;left:-4px;top:50%;-webkit-transform:translatey(-50%) rotateZ(45deg);transform:translatey(-50%) rotateZ(45deg);border-top:none;border-right:none;border-bottom:1px solid #243641;border-left:1px solid #243641}.tooltip.tooltip-right .tooltip-container .tooltip-content:after{bottom:auto;left:-4px;top:50%;-webkit-transform:translatey(-50%) rotateZ(45deg);transform:translatey(-50%) rotateZ(45deg)}.tooltip.tooltip-right.tooltip-light .tooltip-content:before{border-bottom:1px solid #DFE5E8;border-left:1px solid #DFE5E8}.tooltip.tooltip-left .tooltip-container{top:50%;bottom:auto;right:100%;left:auto;-webkit-transform:translatey(-50%);transform:translatey(-50%);margin:0 8px 0 0}.tooltip.tooltip-left .tooltip-container .tooltip-content:before{bottom:auto;right:-4px;left:auto;top:50%;-webkit-transform:translatey(-50%) rotateZ(45deg);transform:translatey(-50%) rotateZ(45deg);border-top:1px solid #243641;border-right:1px solid #243641;border-bottom:none;border-left:none}.tooltip.tooltip-left .tooltip-container .tooltip-content:after{bottom:auto;right:-4px;left:auto;top:50%;-webkit-transform:translatey(-50%) rotateZ(45deg);transform:translatey(-50%) rotateZ(45deg)}.tooltip.tooltip-left.tooltip-light .tooltip-content:before{border-top:1px solid #DFE5E8;border-right:1px solid #DFE5E8}.tooltip-sm.tooltip-container{width:120px}.tooltip-sm.tooltip-container .tooltip-content{white-space:normal}.tooltip-md.tooltip-container{width:240px}.tooltip-md.tooltip-container .tooltip-content{white-space:normal}.tooltip-lg.tooltip-container{width:360px}.tooltip-lg.tooltip-container .tooltip-content{white-space:normal}.tether-element{z-index:99}.overlay-trigger{color:#1B78B3;-webkit-transition:all 300ms ease-out;transition:all 300ms ease-out;-webkit-transition-property:background-color, color, opacity;transition-property:background-color, color, opacity}.overlay-trigger:hover,.overlay-trigger:focus{color:#1f8ace;cursor:pointer;outline:none;text-decoration:none}.overlay-trigger:active,.overlay-trigger.active{color:#176698} +`, +]); + +export default TooltipTrigger; diff --git a/frontend/scenes/Document/Document.js b/frontend/scenes/Document/Document.js index 125949a7..531d289f 100644 --- a/frontend/scenes/Document/Document.js +++ b/frontend/scenes/Document/Document.js @@ -6,7 +6,6 @@ import { observer, inject } from 'mobx-react'; import { withRouter, Prompt } from 'react-router'; import Flex from 'components/Flex'; import { layout } from 'styles/constants'; -import invariant from 'invariant'; import Document from 'models/Document'; import UiStore from 'stores/UiStore'; @@ -18,7 +17,7 @@ import Editor from 'components/Editor'; import DropToImport from 'components/DropToImport'; import { HeaderAction } from 'components/Layout'; import LoadingIndicator from 'components/LoadingIndicator'; -import PublishingInfo from 'components/PublishingInfo'; +import Collaborators from 'components/Collaborators'; import CenteredContent from 'components/CenteredContent'; import PageTitle from 'components/PageTitle'; @@ -154,20 +153,6 @@ type Props = { this.setState({ isDragging: false }); }; - renderHeading(isEditing: boolean) { - invariant(this.document, 'document not available'); - if (this.props.newDocument) return; - - return ( - - - - ); - } - render() { const isNew = this.props.newDocument; const isEditing = !!this.props.match.params.edit || isNew; @@ -211,11 +196,14 @@ type Props = { onChange={this.onChange} onSave={this.onSave} onCancel={this.onCancel} - heading={this.renderHeading(!!isEditing)} readOnly={!isEditing} /> + {document && + !isNew && + !isEditing && + } {isEditing ? (visible ? '1' : '0')}; - transition: all 100ms ease-in-out; -`; - const Container = styled(Flex)` position: relative; width: 100%; diff --git a/package.json b/package.json index 12755300..64b20ba4 100644 --- a/package.json +++ b/package.json @@ -138,6 +138,7 @@ "pg": "^6.1.5", "pg-hstore": "2.3.2", "polished": "1.2.1", + "pui-react-tooltip": "^8.3.3", "query-string": "^4.3.4", "randomstring": "1.1.5", "raw-loader": "^0.5.1", diff --git a/yarn.lock b/yarn.lock index b04a33ea..104fa6ff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -946,7 +946,7 @@ babel-register@^6.26.0: mkdirp "^0.5.1" source-map-support "^0.4.15" -babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: +babel-runtime@^6.1.18, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: @@ -1506,7 +1506,7 @@ clap@^1.0.9: dependencies: chalk "^1.1.3" -classnames@2.2.3, classnames@^2.1.5: +classnames@2.2.3, classnames@^2.1.5, classnames@^2.2.0: version "2.2.3" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.3.tgz#551b774b6762a0c0a997187f7ba4f1d603961ac5" @@ -7207,7 +7207,7 @@ promise@7.x, promise@^7.0.3, promise@^7.1.1: dependencies: asap "~2.0.3" -prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8: +prop-types@>=15.5.6, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8: version "15.5.10" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154" dependencies: @@ -7242,6 +7242,19 @@ public-encrypt@^4.0.0: parse-asn1 "^5.0.0" randombytes "^2.0.1" +pui-css-tooltips@=8.3.3: + version "8.3.3" + resolved "https://registry.yarnpkg.com/pui-css-tooltips/-/pui-css-tooltips-8.3.3.tgz#3e4dd13e4883991dcdb27b065377b3e866edfd7e" + +pui-react-tooltip@^8.3.3: + version "8.3.3" + resolved "https://registry.yarnpkg.com/pui-react-tooltip/-/pui-react-tooltip-8.3.3.tgz#bb7e67c38a06e88501f245e6c2891e6252a7f546" + dependencies: + babel-runtime "^6.1.18" + classnames "^2.2.0" + prop-types ">=15.5.6" + pui-css-tooltips "=8.3.3" + "pullstream@>= 0.4.1 < 1": version "0.4.1" resolved "https://registry.yarnpkg.com/pullstream/-/pullstream-0.4.1.tgz#d6fb3bf5aed697e831150eb1002c25a3f8ae1314"