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:
Tom Moor
2017-09-03 17:26:57 -07:00
committed by GitHub
parent 7f88c56c2f
commit e34ffe0cf4
11 changed files with 99 additions and 68 deletions

View File

@@ -8,7 +8,7 @@ type Props = {
const Container = styled.div`
width: 100%;
margin: 40px 20px;
margin: 60px 20px;
`;
const Content = styled.div`

View 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;

View File

@@ -0,0 +1,3 @@
// @flow
import Collaborators from './Collaborators';
export default Collaborators;

View File

@@ -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 = {

View File

@@ -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}

View File

@@ -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;'}
`;

View File

@@ -1,3 +0,0 @@
// @flow
import PublishingInfo from './PublishingInfo';
export default PublishingInfo;

View 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;

View File

@@ -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%;