Move collaborators to top right (#201)
* Hopefully the last time we rejig this before launch * Improved spacing * Move to injectGlobal, alignment fixes
This commit is contained in:
@@ -8,7 +8,7 @@ type Props = {
|
||||
|
||||
const Container = styled.div`
|
||||
width: 100%;
|
||||
margin: 40px 20px;
|
||||
margin: 60px 20px;
|
||||
`;
|
||||
|
||||
const Content = styled.div`
|
||||
|
||||
56
frontend/components/Collaborators/Collaborators.js
Normal file
56
frontend/components/Collaborators/Collaborators.js
Normal file
@@ -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 (
|
||||
<Avatars>
|
||||
<Tooltip tooltip={tooltip} placement="bottom">
|
||||
{collaborators.map(user => (
|
||||
<Avatar key={user.id} src={user.avatarUrl} />
|
||||
))}
|
||||
</Tooltip>
|
||||
</Avatars>
|
||||
);
|
||||
};
|
||||
|
||||
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;
|
||||
3
frontend/components/Collaborators/index.js
Normal file
3
frontend/components/Collaborators/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
// @flow
|
||||
import Collaborators from './Collaborators';
|
||||
export default Collaborators;
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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<User>,
|
||||
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 (
|
||||
<Container align="center">
|
||||
{collaborators &&
|
||||
<Avatars>
|
||||
{collaborators.map(user => (
|
||||
<Avatar key={user.id} src={user.avatarUrl} title={user.name} />
|
||||
))}
|
||||
</Avatars>}
|
||||
{createdAt === updatedAt
|
||||
? <span>
|
||||
{createdBy.name}
|
||||
@@ -27,7 +27,6 @@ type Props = {
|
||||
onImageUploadStop: Function,
|
||||
emoji: string,
|
||||
readOnly: boolean,
|
||||
heading?: ?React.Element<*>,
|
||||
};
|
||||
|
||||
type KeyData = {
|
||||
@@ -187,12 +186,7 @@ type KeyData = {
|
||||
auto
|
||||
>
|
||||
<MaxWidth column auto>
|
||||
<HeaderContainer
|
||||
onClick={this.focusAtStart}
|
||||
readOnly={this.props.readOnly}
|
||||
>
|
||||
{this.props.heading}
|
||||
</HeaderContainer>
|
||||
<Header onClick={this.focusAtStart} readOnly={this.props.readOnly} />
|
||||
<Toolbar state={this.state.state} onChange={this.onChange} />
|
||||
<Editor
|
||||
ref={ref => (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;'}
|
||||
`;
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
// @flow
|
||||
import PublishingInfo from './PublishingInfo';
|
||||
export default PublishingInfo;
|
||||
11
frontend/components/Tooltip/index.js
Normal file
11
frontend/components/Tooltip/index.js
Normal file
@@ -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;
|
||||
@@ -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 (
|
||||
<InfoWrapper visible={!isEditing}>
|
||||
<PublishingInfo
|
||||
collaborators={this.document.collaborators}
|
||||
document={this.document}
|
||||
/>
|
||||
</InfoWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
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}
|
||||
/>
|
||||
<Meta align="center" justify="flex-end" readOnly={!isEditing}>
|
||||
<Flex align="center">
|
||||
{document &&
|
||||
!isNew &&
|
||||
!isEditing &&
|
||||
<Collaborators document={document} />}
|
||||
<HeaderAction>
|
||||
{isEditing
|
||||
? <SaveAction
|
||||
@@ -263,11 +251,6 @@ const Meta = styled(Flex)`
|
||||
padding: ${layout.padding};
|
||||
`;
|
||||
|
||||
const InfoWrapper = styled(Flex)`
|
||||
opacity: ${({ visible }) => (visible ? '1' : '0')};
|
||||
transition: all 100ms ease-in-out;
|
||||
`;
|
||||
|
||||
const Container = styled(Flex)`
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
Reference in New Issue
Block a user