From 1f98013004ec3ce5b60c613e3e2308a012387474 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sun, 3 Sep 2017 14:55:44 -0700 Subject: [PATCH 01/11] Text only save feedback based on jori/actions --- frontend/scenes/Document/Document.js | 19 +++++++--- .../components/Breadcrumbs/Breadcrumbs.js | 35 ------------------- .../Document/components/Breadcrumbs/index.js | 3 -- .../components/SaveAction/SaveAction.js | 28 ++++----------- .../Document}/components/SaveAction/index.js | 0 5 files changed, 21 insertions(+), 64 deletions(-) delete mode 100644 frontend/scenes/Document/components/Breadcrumbs/Breadcrumbs.js delete mode 100644 frontend/scenes/Document/components/Breadcrumbs/index.js rename frontend/{components/Layout => scenes/Document}/components/SaveAction/SaveAction.js (57%) rename frontend/{components/Layout => scenes/Document}/components/SaveAction/index.js (100%) diff --git a/frontend/scenes/Document/Document.js b/frontend/scenes/Document/Document.js index 28994dc3..125949a7 100644 --- a/frontend/scenes/Document/Document.js +++ b/frontend/scenes/Document/Document.js @@ -12,10 +12,11 @@ import Document from 'models/Document'; import UiStore from 'stores/UiStore'; import DocumentsStore from 'stores/DocumentsStore'; import Menu from './components/Menu'; +import SaveAction from './components/SaveAction'; import LoadingPlaceholder from 'components/LoadingPlaceholder'; import Editor from 'components/Editor'; import DropToImport from 'components/DropToImport'; -import { HeaderAction, SaveAction } from 'components/Layout'; +import { HeaderAction } from 'components/Layout'; import LoadingIndicator from 'components/LoadingIndicator'; import PublishingInfo from 'components/PublishingInfo'; import CenteredContent from 'components/CenteredContent'; @@ -44,6 +45,7 @@ type Props = { state = { isDragging: false, isLoading: false, + isSaving: false, newDocument: undefined, showAsSaved: false, }; @@ -108,7 +110,7 @@ type Props = { let document = this.document; if (!document) return; - this.setState({ isLoading: true }); + this.setState({ isLoading: true, isSaving: true }); document = await document.save(); this.setState({ isLoading: false }); @@ -120,7 +122,7 @@ type Props = { }; showAsSaved() { - this.setState({ showAsSaved: true }); + this.setState({ showAsSaved: true, isSaving: false }); this.savedTimeout = setTimeout( () => this.setState({ showAsSaved: false }), 2000 @@ -217,13 +219,20 @@ type Props = { {isEditing ? : Edit} + {isEditing && + + Cancel + } {!isEditing && } diff --git a/frontend/scenes/Document/components/Breadcrumbs/Breadcrumbs.js b/frontend/scenes/Document/components/Breadcrumbs/Breadcrumbs.js deleted file mode 100644 index 14e59899..00000000 --- a/frontend/scenes/Document/components/Breadcrumbs/Breadcrumbs.js +++ /dev/null @@ -1,35 +0,0 @@ -// @flow -import React from 'react'; -import { Link } from 'react-router-dom'; -import type { Document, NavigationNode } from 'types'; - -type Props = { - document: Document, - pathToDocument: Array, -}; - -const Breadcrumbs = ({ document, pathToDocument }: Props) => { - if (document && document.collection) { - const titleSections = pathToDocument - ? pathToDocument.map(node => ( - {node.title} - )) - : []; - titleSections.unshift( - - {document.collection.name} - - ); - - return ( - -  /  - {titleSections.reduce((prev, curr) => [prev, ' / ', curr])} - {` / ${document.title}`} - - ); - } - return null; -}; - -export default Breadcrumbs; diff --git a/frontend/scenes/Document/components/Breadcrumbs/index.js b/frontend/scenes/Document/components/Breadcrumbs/index.js deleted file mode 100644 index 8fe21291..00000000 --- a/frontend/scenes/Document/components/Breadcrumbs/index.js +++ /dev/null @@ -1,3 +0,0 @@ -// @flow -import Breadcrumbs from './Breadcrumbs'; -export default Breadcrumbs; diff --git a/frontend/components/Layout/components/SaveAction/SaveAction.js b/frontend/scenes/Document/components/SaveAction/SaveAction.js similarity index 57% rename from frontend/components/Layout/components/SaveAction/SaveAction.js rename to frontend/scenes/Document/components/SaveAction/SaveAction.js index f33cfec4..48ec1d00 100644 --- a/frontend/components/Layout/components/SaveAction/SaveAction.js +++ b/frontend/scenes/Document/components/SaveAction/SaveAction.js @@ -1,28 +1,26 @@ // @flow import React from 'react'; import styled from 'styled-components'; -import CheckIcon from 'components/Icon/CheckIcon'; -import { fadeAndScaleIn } from 'styles/animations'; type Props = { onClick: Function, - showCheckmark: boolean, disabled?: boolean, isNew?: boolean, + isSaving?: boolean, }; class SaveAction extends React.Component { props: Props; - onClick = (event: MouseEvent) => { + onClick = (ev: MouseEvent) => { if (this.props.disabled) return; - event.preventDefault(); + ev.preventDefault(); this.props.onClick(); }; render() { - const { showCheckmark, disabled, isNew } = this.props; + const { isSaving, isNew, disabled } = this.props; return ( - {showCheckmark && } - {isNew ? 'Publish' : 'Save'} + {isNew + ? isSaving ? 'Publishing…' : 'Publish' + : isSaving ? 'Saving…' : 'Save'} ); } @@ -45,17 +44,4 @@ const Link = styled.a` cursor: ${props => (props.disabled ? 'default' : 'pointer')}; `; -const SavedIcon = styled(CheckIcon)` - animation: ${fadeAndScaleIn} 250ms ease; - display: inline-block; - margin-right: 4px; - width: 18px; - height: 18px; - - svg { - width: 18px; - height: 18px; - } -`; - export default SaveAction; diff --git a/frontend/components/Layout/components/SaveAction/index.js b/frontend/scenes/Document/components/SaveAction/index.js similarity index 100% rename from frontend/components/Layout/components/SaveAction/index.js rename to frontend/scenes/Document/components/SaveAction/index.js From 136280adf359141cfbaff19d8e3023629c931f20 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sun, 3 Sep 2017 15:08:29 -0700 Subject: [PATCH 02/11] :green_heart: --- frontend/components/Layout/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/components/Layout/index.js b/frontend/components/Layout/index.js index 7956f3e9..38c7a426 100644 --- a/frontend/components/Layout/index.js +++ b/frontend/components/Layout/index.js @@ -2,8 +2,7 @@ import Layout from './Layout'; import Title from './components/Title'; import HeaderAction from './components/HeaderAction'; -import SaveAction from './components/SaveAction'; export default Layout; -export { Title, HeaderAction, SaveAction }; +export { Title, HeaderAction }; From bdb7c46874477a177854e8baecd71c3d92348917 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sun, 3 Sep 2017 15:45:25 -0700 Subject: [PATCH 03/11] Remove UserStore --- frontend/components/Layout/Layout.js | 7 +++--- frontend/index.js | 9 ++++---- frontend/stores/AuthStore.js | 12 ----------- frontend/stores/UserStore.js | 32 ---------------------------- 4 files changed, 7 insertions(+), 53 deletions(-) delete mode 100644 frontend/stores/UserStore.js diff --git a/frontend/components/Layout/Layout.js b/frontend/components/Layout/Layout.js index 9679eb83..284383a2 100644 --- a/frontend/components/Layout/Layout.js +++ b/frontend/components/Layout/Layout.js @@ -27,7 +27,6 @@ import SidebarCollection from './components/SidebarCollection'; import SidebarCollectionList from './components/SidebarCollectionList'; import SidebarLink from './components/SidebarLink'; -import UserStore from 'stores/UserStore'; import AuthStore from 'stores/AuthStore'; import UiStore from 'stores/UiStore'; import CollectionsStore from 'stores/CollectionsStore'; @@ -40,7 +39,6 @@ type Props = { children?: ?React.Element, actions?: ?React.Element, title?: ?React.Element, - user: UserStore, auth: AuthStore, ui: UiStore, search: ?boolean, @@ -108,7 +106,8 @@ type Props = { }; render() { - const { user, auth, documents, collections, history, ui } = this.props; + const { auth, documents, collections, history, ui } = this.props; + const { user } = auth; return ( @@ -134,7 +133,7 @@ type Props = { Atlas - }> + }> Settings diff --git a/frontend/index.js b/frontend/index.js index d47f3774..b783b4e7 100644 --- a/frontend/index.js +++ b/frontend/index.js @@ -51,23 +51,22 @@ type AuthProps = { }; const Auth = ({ children }: AuthProps) => { - if (stores.auth.authenticated && stores.auth.team) { + if (stores.auth.authenticated && stores.auth.team && stores.auth.user) { // Only initialize stores once. Kept in global scope // because otherwise they will get overriden on route // change if (!authenticatedStores) { // Stores for authenticated user - const user = stores.auth.getUserStore(); - const cache = new CacheStore(user.user.id); + const { user, team } = stores.auth; + const cache = new CacheStore(user.id); authenticatedStores = { - user, documents: new DocumentsStore({ ui: stores.ui, cache, }), collections: new CollectionsStore({ ui: stores.ui, - teamId: user.team.id, + teamId: team.id, cache, }), }; diff --git a/frontend/stores/AuthStore.js b/frontend/stores/AuthStore.js index dcc879c4..f5b77ecb 100644 --- a/frontend/stores/AuthStore.js +++ b/frontend/stores/AuthStore.js @@ -2,7 +2,6 @@ import { observable, action, computed, autorunAsync } from 'mobx'; import invariant from 'invariant'; import { client } from 'utils/ApiClient'; -import UserStore from 'stores/UserStore'; import type { User, Team } from 'types'; const AUTH_STORE = 'AUTH_STORE'; @@ -72,17 +71,6 @@ class AuthStore { }; }; - getUserStore(): UserStore { - invariant( - this.user && this.team, - 'Tried to create a user store without data' - ); - return new UserStore({ - user: this.user, - team: this.team, - }); - } - constructor() { // Rehydrate const data = JSON.parse(localStorage.getItem(AUTH_STORE) || '{}'); diff --git a/frontend/stores/UserStore.js b/frontend/stores/UserStore.js deleted file mode 100644 index 7d368c93..00000000 --- a/frontend/stores/UserStore.js +++ /dev/null @@ -1,32 +0,0 @@ -// @flow -import { observable, computed } from 'mobx'; -import type { User, Team } from 'types'; - -type Options = { - user: User, - team: Team, -}; - -class UserStore { - @observable user: User; - @observable team: Team; - - @observable isLoading: boolean = false; - - /* Computed */ - - @computed get asJson(): string { - return JSON.stringify({ - user: this.user, - team: this.team, - }); - } - - constructor(options: Options) { - // Rehydrate - this.user = options.user; - this.team = options.team; - } -} - -export default UserStore; From 432b7afede344baf33ccecaf13d96450927d2ed1 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sun, 3 Sep 2017 17:08:56 -0700 Subject: [PATCH 04/11] Refactor Slack signin codE --- frontend/components/Layout/Layout.js | 6 ++- server/api/auth.js | 59 +++++----------------------- server/slack.js | 34 ++++++++++++++++ 3 files changed, 48 insertions(+), 51 deletions(-) create mode 100644 server/slack.js diff --git a/frontend/components/Layout/Layout.js b/frontend/components/Layout/Layout.js index 284383a2..b42b7426 100644 --- a/frontend/components/Layout/Layout.js +++ b/frontend/components/Layout/Layout.js @@ -107,7 +107,7 @@ type Props = { render() { const { auth, documents, collections, history, ui } = this.props; - const { user } = auth; + const { user, team } = auth; return ( @@ -128,10 +128,12 @@ type Props = { {auth.authenticated && user && + team &&
- Atlas + {team.name} + {user.username} }> diff --git a/server/api/auth.js b/server/api/auth.js index 811055cf..35ae88c1 100644 --- a/server/api/auth.js +++ b/server/api/auth.js @@ -1,11 +1,9 @@ // @flow import Router from 'koa-router'; -import apiError, { httpErrors } from '../errors'; -import fetch from 'isomorphic-fetch'; -import querystring from 'querystring'; - +import apiError from '../errors'; import { presentUser, presentTeam } from '../presenters'; import { User, Team } from '../models'; +import * as Slack from '../slack'; const router = new Router(); @@ -88,24 +86,7 @@ router.post('auth.slack', async ctx => { const { code } = ctx.body; ctx.assertPresent(code, 'code is required'); - const body = { - client_id: process.env.SLACK_KEY, - client_secret: process.env.SLACK_SECRET, - redirect_uri: `${process.env.URL || ''}/auth/slack`, - code, - }; - - let data; - try { - const response = await fetch( - `https://slack.com/api/oauth.access?${querystring.stringify(body)}` - ); - data = await response.json(); - } catch (e) { - throw httpErrors.BadRequest(); - } - - if (!data.ok) throw httpErrors.BadRequest(data.error); + const data = await Slack.oauthAccess(code); // Temp to block const allowedSlackDomains = (process.env.ALLOWED_SLACK_DOMAINS || '') @@ -118,22 +99,20 @@ router.post('auth.slack', async ctx => { ); } - // User let user = await User.findOne({ where: { slackId: data.user.id } }); - - // Team let team = await Team.findOne({ where: { slackId: data.team.id } }); const teamExisted = !!team; - if (!team) { + + if (team) { + team.name = data.team.name; + team.slackData = data.team; + await team.save(); + } else { team = await Team.create({ name: data.team.name, slackId: data.team.id, slackData: data.team, }); - } else { - team.name = data.team.name; - team.slackData = data.team; - team = await team.save(); } if (user) { @@ -143,7 +122,6 @@ router.post('auth.slack', async ctx => { } else { user = await User.create({ slackId: data.user.id, - username: data.user.name, name: data.user.name, email: data.user.email, teamId: team.id, @@ -169,24 +147,7 @@ router.post('auth.slackCommands', async ctx => { const { code } = ctx.body; ctx.assertPresent(code, 'code is required'); - const body = { - client_id: process.env.SLACK_KEY, - client_secret: process.env.SLACK_SECRET, - redirect_uri: `${process.env.URL || ''}/auth/slack/commands`, - code, - }; - - let data; - try { - const response = await fetch( - `https://slack.com/api/oauth.access?${querystring.stringify(body)}` - ); - data = await response.json(); - } catch (e) { - throw httpErrors.BadRequest(); - } - - if (!data.ok) throw httpErrors.BadRequest(data.error); + await Slack.oauthAccess(code, `${process.env.URL || ''}/auth/slack/commands`); }); export default router; diff --git a/server/slack.js b/server/slack.js new file mode 100644 index 00000000..62bb75eb --- /dev/null +++ b/server/slack.js @@ -0,0 +1,34 @@ +// @flow +import fetch from 'isomorphic-fetch'; +import querystring from 'querystring'; +import { httpErrors } from './errors'; + +const SLACK_API_URL = 'https://slack.com/api'; + +export async function request(endpoint: string, body: Object) { + let data; + try { + const response = await fetch( + `${SLACK_API_URL}/${endpoint}?${querystring.stringify(body)}` + ); + data = await response.json(); + } catch (e) { + throw httpErrors.BadRequest(); + } + console.log('DATA', data); + if (!data.ok) throw httpErrors.BadRequest(data.error); + + return data; +} + +export async function oauthAccess( + code: string, + redirect_uri: string = `${process.env.URL || ''}/auth/slack` +) { + return request('oauth.access', { + client_id: process.env.SLACK_KEY, + client_secret: process.env.SLACK_SECRET, + redirect_uri: `${process.env.URL || ''}/auth/slack`, + code, + }); +} From e34ffe0cf41258e355c2a7692b63a221a7e0401e Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sun, 3 Sep 2017 17:26:57 -0700 Subject: [PATCH 05/11] Move collaborators to top right (#201) * Hopefully the last time we rejig this before launch * Improved spacing * Move to injectGlobal, alignment fixes --- .../CenteredContent/CenteredContent.js | 2 +- .../components/Collaborators/Collaborators.js | 56 +++++++++++++++++++ frontend/components/Collaborators/index.js | 3 + .../DocumentPreview/DocumentPreview.js | 2 +- .../components}/PublishingInfo.js | 28 +--------- frontend/components/Editor/Editor.js | 15 ++--- frontend/components/PublishingInfo/index.js | 3 - frontend/components/Tooltip/index.js | 11 ++++ frontend/scenes/Document/Document.js | 27 ++------- package.json | 1 + yarn.lock | 19 ++++++- 11 files changed, 99 insertions(+), 68 deletions(-) create mode 100644 frontend/components/Collaborators/Collaborators.js create mode 100644 frontend/components/Collaborators/index.js rename frontend/components/{PublishingInfo => DocumentPreview/components}/PublishingInfo.js (70%) delete mode 100644 frontend/components/PublishingInfo/index.js create mode 100644 frontend/components/Tooltip/index.js 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" From 1b52cb6c19d6acc57c64f990303fabd5d8d56339 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sun, 3 Sep 2017 17:27:12 -0700 Subject: [PATCH 06/11] Refactor --- frontend/components/Layout/Layout.js | 37 ++++------------ .../Layout/components/HeaderBlock.js | 42 +++++++++++++++++++ 2 files changed, 51 insertions(+), 28 deletions(-) create mode 100644 frontend/components/Layout/components/HeaderBlock.js diff --git a/frontend/components/Layout/Layout.js b/frontend/components/Layout/Layout.js index b42b7426..87ff7dd9 100644 --- a/frontend/components/Layout/Layout.js +++ b/frontend/components/Layout/Layout.js @@ -10,11 +10,11 @@ import keydown from 'react-keydown'; import Flex from 'components/Flex'; import { color, layout } from 'styles/constants'; import { documentEditUrl, homeUrl, searchUrl } from 'utils/routeHelpers'; - import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu'; + +import Avatar from 'components/Avatar'; import { LoadingIndicatorBar } from 'components/LoadingIndicator'; import Scrollable from 'components/Scrollable'; -import Avatar from 'components/Avatar'; import Modal from 'components/Modal'; import AddIcon from 'components/Icon/AddIcon'; import MoreIcon from 'components/Icon/MoreIcon'; @@ -26,6 +26,7 @@ import Settings from 'scenes/Settings'; import SidebarCollection from './components/SidebarCollection'; import SidebarCollectionList from './components/SidebarCollectionList'; import SidebarLink from './components/SidebarLink'; +import HeaderBlock from './components/HeaderBlock'; import AuthStore from 'stores/AuthStore'; import UiStore from 'stores/UiStore'; @@ -130,11 +131,7 @@ type Props = { user && team && -
- - {team.name} - {user.username} - + }> Settings @@ -149,8 +146,7 @@ type Props = { Logout -
- + @@ -251,19 +247,6 @@ const Container = styled(Flex)` height: 100%; `; -const LogoLink = styled(Link)` - margin-top: 15px; - font-family: 'Atlas Grotesk'; - font-weight: bold; - color: ${color.text}; - text-decoration: none; - font-size: 16px; -`; - -const MenuLink = styled(Link)` - color: ${color.text}; -`; - const Content = styled(Flex)` overflow: scroll; position: absolute; @@ -274,6 +257,10 @@ const Content = styled(Flex)` transition: left 200ms ease-in-out; `; +const MenuLink = styled(Link)` + color: ${color.text}; +`; + const Sidebar = styled(Flex)` width: ${layout.sidebarWidth}; margin-left: ${props => (props.editMode ? `-${layout.sidebarWidth}` : 0)}; @@ -282,12 +269,6 @@ const Sidebar = styled(Flex)` transition: margin-left 200ms ease-in-out; `; -const Header = styled(Flex)` - flex-shrink: 0; - padding: ${layout.padding}; - padding-bottom: 10px; -`; - const LinkSection = styled(Flex)` flex-direction: column; padding: 10px 0; diff --git a/frontend/components/Layout/components/HeaderBlock.js b/frontend/components/Layout/components/HeaderBlock.js new file mode 100644 index 00000000..87aab583 --- /dev/null +++ b/frontend/components/Layout/components/HeaderBlock.js @@ -0,0 +1,42 @@ +// @flow +import React from 'react'; +import styled from 'styled-components'; +import { Link } from 'react-router-dom'; +import { color, layout } from 'styles/constants'; +import type { User, Team } from 'types'; +import Flex from 'components/Flex'; + +type Props = { + user: User, + team: Team, + children?: React$Element, +}; + +function HeaderBlock({ user, team, children }: Props) { + return ( +
+ + {team.name} +

{user.username}

+
+ {children} +
+ ); +} + +const LogoLink = styled(Link)` + margin-top: 15px; + font-family: 'Atlas Grotesk'; + font-weight: bold; + color: ${color.text}; + text-decoration: none; + font-size: 16px; +`; + +const Header = styled(Flex)` + flex-shrink: 0; + padding: ${layout.padding}; + padding-bottom: 10px; +`; + +export default HeaderBlock; From c2c7f48d85ad40746ec1bac2a04d9a90bc1933a0 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sun, 3 Sep 2017 23:03:49 -0700 Subject: [PATCH 07/11] Neaten --- .../components/DropdownMenu/DropdownMenu.js | 5 +- frontend/components/Layout/Layout.js | 49 ++++++++++--------- .../Layout/components/HeaderBlock.js | 29 +++++++++-- 3 files changed, 52 insertions(+), 31 deletions(-) diff --git a/frontend/components/DropdownMenu/DropdownMenu.js b/frontend/components/DropdownMenu/DropdownMenu.js index 36c56004..69874c0a 100644 --- a/frontend/components/DropdownMenu/DropdownMenu.js +++ b/frontend/components/DropdownMenu/DropdownMenu.js @@ -22,6 +22,7 @@ const DropdownMenuItem = ({ onClick, children }: MenuItemProps) => { type DropdownMenuProps = { label: React.Element, children?: React.Element, + style?: Object, }; @observer class DropdownMenu extends React.Component { @@ -42,7 +43,7 @@ type DropdownMenuProps = { {this.menuOpen && - + {this.props.children} } @@ -65,9 +66,7 @@ const Label = styled(Flex).attrs({ })` cursor: pointer; z-index: 1000; - min-height: 43px; - margin: 0 5px; `; const MenuContainer = styled.div` diff --git a/frontend/components/Layout/Layout.js b/frontend/components/Layout/Layout.js index 87ff7dd9..a3d2d509 100644 --- a/frontend/components/Layout/Layout.js +++ b/frontend/components/Layout/Layout.js @@ -131,29 +131,33 @@ type Props = { user && team && - - }> - - Settings - - - Keyboard shortcuts - - - API - - - Logout - - - + + + + } + > + + Settings + + + Keyboard shortcuts + + + API + + + Logout + + + - - Search - Home + Search Starred @@ -225,7 +229,7 @@ type Props = { const CollectionAction = styled.a` position: absolute; - top: 8px; + top: -2px; right: ${layout.hpadding}; svg { @@ -264,14 +268,13 @@ const MenuLink = styled(Link)` const Sidebar = styled(Flex)` width: ${layout.sidebarWidth}; margin-left: ${props => (props.editMode ? `-${layout.sidebarWidth}` : 0)}; - background: rgba(250, 251, 252, 0.71); - border-right: 1px solid #eceff3; + background: ${color.smoke}; transition: margin-left 200ms ease-in-out; `; const LinkSection = styled(Flex)` flex-direction: column; - padding: 10px 0; + margin: 24px 0; position: relative; `; diff --git a/frontend/components/Layout/components/HeaderBlock.js b/frontend/components/Layout/components/HeaderBlock.js index 87aab583..cacecf10 100644 --- a/frontend/components/Layout/components/HeaderBlock.js +++ b/frontend/components/Layout/components/HeaderBlock.js @@ -14,18 +14,21 @@ type Props = { function HeaderBlock({ user, team, children }: Props) { return ( -
- +
+ {team.name} -

{user.username}

+ {user.name}
{children}
); } +const Name = styled.div` + font-size: 13px; +`; + const LogoLink = styled(Link)` - margin-top: 15px; font-family: 'Atlas Grotesk'; font-weight: bold; color: ${color.text}; @@ -36,7 +39,23 @@ const LogoLink = styled(Link)` const Header = styled(Flex)` flex-shrink: 0; padding: ${layout.padding}; - padding-bottom: 10px; + position: relative; + cursor: pointer; + width: 100%; + + &:hover { + background: rgba(0,0,0,.05); + } + + &::after { + content: ""; + left: ${layout.hpadding}; + right: ${layout.hpadding}; + background: rgba(0,0,0,.075); + height: 1px; + position: absolute; + bottom: 0; + } `; export default HeaderBlock; From f4735246ade626281a38923c9237819b92b7a491 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Mon, 4 Sep 2017 08:32:31 -0700 Subject: [PATCH 08/11] Readability --- frontend/components/Editor/Editor.scss | 2 +- frontend/components/Layout/components/HeaderBlock.js | 10 +++++----- .../Layout/components/SidebarLink/SidebarLink.js | 1 + frontend/styles/base.scss | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/frontend/components/Editor/Editor.scss b/frontend/components/Editor/Editor.scss index a7694603..ecc91bb2 100644 --- a/frontend/components/Editor/Editor.scss +++ b/frontend/components/Editor/Editor.scss @@ -1,7 +1,7 @@ .editor { font-weight: 400; font-size: 1em; - line-height: 1.5em; + line-height: 1.7em; width: 100%; color: #1b2631; diff --git a/frontend/components/Layout/components/HeaderBlock.js b/frontend/components/Layout/components/HeaderBlock.js index cacecf10..8bf4fd57 100644 --- a/frontend/components/Layout/components/HeaderBlock.js +++ b/frontend/components/Layout/components/HeaderBlock.js @@ -1,7 +1,6 @@ // @flow import React from 'react'; import styled from 'styled-components'; -import { Link } from 'react-router-dom'; import { color, layout } from 'styles/constants'; import type { User, Team } from 'types'; import Flex from 'components/Flex'; @@ -16,19 +15,19 @@ function HeaderBlock({ user, team, children }: Props) { return (
- {team.name} - {user.name} + {team.name} + {user.name} {children}
); } -const Name = styled.div` +const UserName = styled.div` font-size: 13px; `; -const LogoLink = styled(Link)` +const TeamName = styled.div` font-family: 'Atlas Grotesk'; font-weight: bold; color: ${color.text}; @@ -43,6 +42,7 @@ const Header = styled(Flex)` cursor: pointer; width: 100%; + &:active, &:hover { background: rgba(0,0,0,.05); } diff --git a/frontend/components/Layout/components/SidebarLink/SidebarLink.js b/frontend/components/Layout/components/SidebarLink/SidebarLink.js index 7df81e86..d09f85c3 100644 --- a/frontend/components/Layout/components/SidebarLink/SidebarLink.js +++ b/frontend/components/Layout/components/SidebarLink/SidebarLink.js @@ -17,6 +17,7 @@ const StyledNavLink = styled(NavLink)` display: block; padding: 5px ${layout.hpadding}; color: ${color.slateDark}; + font-size: 15px; &:hover { color: ${darken(0.1, color.slateDark)}; diff --git a/frontend/styles/base.scss b/frontend/styles/base.scss index 3fcc4acd..66deb194 100644 --- a/frontend/styles/base.scss +++ b/frontend/styles/base.scss @@ -21,7 +21,7 @@ html, body, .viewport { body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; - font-size: 15px; + font-size: 16px; line-height: 1.5; margin: 0; color: #617180; From 24686aac44dbd11d9a0bcc0bc87c24855cd4a101 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Mon, 4 Sep 2017 08:56:07 -0700 Subject: [PATCH 09/11] Fixes: Scroll to top behavior when changing pages Fixes: Different max-width on docs and other content --- .../CenteredContent/CenteredContent.js | 2 +- frontend/components/Editor/Editor.scss | 2 +- frontend/components/Layout/Layout.js | 16 +++++++--------- frontend/styles/base.scss | 5 ----- 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/frontend/components/CenteredContent/CenteredContent.js b/frontend/components/CenteredContent/CenteredContent.js index cfc4fe08..b9f15975 100644 --- a/frontend/components/CenteredContent/CenteredContent.js +++ b/frontend/components/CenteredContent/CenteredContent.js @@ -12,7 +12,7 @@ const Container = styled.div` `; const Content = styled.div` - max-width: 740px; + max-width: 50em; margin: 0 auto; `; diff --git a/frontend/components/Editor/Editor.scss b/frontend/components/Editor/Editor.scss index ecc91bb2..7508c602 100644 --- a/frontend/components/Editor/Editor.scss +++ b/frontend/components/Editor/Editor.scss @@ -3,7 +3,7 @@ font-size: 1em; line-height: 1.7em; width: 100%; - color: #1b2631; + color: #1b2830; h1, h2, diff --git a/frontend/components/Layout/Layout.js b/frontend/components/Layout/Layout.js index a3d2d509..c0a6121e 100644 --- a/frontend/components/Layout/Layout.js +++ b/frontend/components/Layout/Layout.js @@ -252,13 +252,8 @@ const Container = styled(Flex)` `; const Content = styled(Flex)` - overflow: scroll; - position: absolute; - top: 0; - bottom: 0; - right: 0; - left: ${props => (props.editMode ? 0 : layout.sidebarWidth)}; - transition: left 200ms ease-in-out; + margin-left: ${props => (props.editMode ? 0 : layout.sidebarWidth)}; + transition: margin-left 200ms ease-in-out; `; const MenuLink = styled(Link)` @@ -266,10 +261,13 @@ const MenuLink = styled(Link)` `; const Sidebar = styled(Flex)` + position: fixed; + top: 0; + bottom: 0; + left: ${props => (props.editMode ? `-${layout.sidebarWidth}` : 0)}; width: ${layout.sidebarWidth}; - margin-left: ${props => (props.editMode ? `-${layout.sidebarWidth}` : 0)}; background: ${color.smoke}; - transition: margin-left 200ms ease-in-out; + transition: left 200ms ease-in-out; `; const LinkSection = styled(Flex)` diff --git a/frontend/styles/base.scss b/frontend/styles/base.scss index 66deb194..cd822c1d 100644 --- a/frontend/styles/base.scss +++ b/frontend/styles/base.scss @@ -27,11 +27,6 @@ body { color: #617180; background-color: #fff; display: flex; - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; From dc3ebf0c27babd6a8c0dc59ce809541cd5b86904 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Mon, 4 Sep 2017 12:26:00 -0700 Subject: [PATCH 10/11] Quick fixes from last PR --- frontend/components/Layout/components/HeaderBlock.js | 2 +- frontend/styles/base.scss | 1 + server/static/dev.html | 4 ++-- server/static/index.html | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/frontend/components/Layout/components/HeaderBlock.js b/frontend/components/Layout/components/HeaderBlock.js index 8bf4fd57..1038738e 100644 --- a/frontend/components/Layout/components/HeaderBlock.js +++ b/frontend/components/Layout/components/HeaderBlock.js @@ -14,7 +14,7 @@ type Props = { function HeaderBlock({ user, team, children }: Props) { return (
- + {team.name} {user.name} diff --git a/frontend/styles/base.scss b/frontend/styles/base.scss index cd822c1d..1e745df7 100644 --- a/frontend/styles/base.scss +++ b/frontend/styles/base.scss @@ -16,6 +16,7 @@ html, body, .viewport { width: 100%; + min-height: 100vh; margin: 0; } diff --git a/server/static/dev.html b/server/static/dev.html index 1933c80b..8eea6eee 100644 --- a/server/static/dev.html +++ b/server/static/dev.html @@ -20,7 +20,7 @@ #root { flex: 1; - height: 100%; + min-height: 100vh; } @@ -30,4 +30,4 @@ - \ No newline at end of file + diff --git a/server/static/index.html b/server/static/index.html index 90df71b6..e79463d5 100644 --- a/server/static/index.html +++ b/server/static/index.html @@ -18,7 +18,7 @@ #root { flex: 1; - height: 100%; + min-height: 100vh; } @@ -28,4 +28,4 @@ - \ No newline at end of file + From 7e82fd944e705ecf635a5cfc00ba13475ec215c3 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Mon, 4 Sep 2017 13:27:29 -0700 Subject: [PATCH 11/11] allow-null-username --- .../20170904202454-allow-null-username.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 server/migrations/20170904202454-allow-null-username.js diff --git a/server/migrations/20170904202454-allow-null-username.js b/server/migrations/20170904202454-allow-null-username.js new file mode 100644 index 00000000..399dc4e8 --- /dev/null +++ b/server/migrations/20170904202454-allow-null-username.js @@ -0,0 +1,15 @@ +module.exports = { + up: async function(queryInterface, Sequelize) { + await queryInterface.changeColumn('users', 'username', { + type: Sequelize.STRING, + allowNull: true, + }); + }, + + down: async function(queryInterface, Sequelize) { + await queryInterface.changeColumn('users', 'username', { + type: Sequelize.STRING, + allowNull: false, + }); + }, +};