From 0ea7227f3a2dff7201595bc031a086c855e29b1f Mon Sep 17 00:00:00 2001 From: Ben Gotow Date: Thu, 24 Aug 2017 01:58:36 -0400 Subject: [PATCH] =?UTF-8?q?Clean=20up=20modals,=20add=20nice=20animation?= =?UTF-8?q?=20when=20modals=20appear=20=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/tabs/preferences-identity.jsx | 4 +- app/src/components/billing-modal.jsx | 3 ++ .../decorators/has-tutorial-tip.jsx | 2 +- app/src/components/feature-used-up-modal.jsx | 36 +++++++++--------- app/src/components/modal.jsx | 29 +++++++-------- app/src/flux/stores/feature-usage-store.jsx | 16 +++++--- app/src/flux/stores/modal-store.jsx | 2 +- app/src/flux/stores/popover-store.jsx | 2 +- app/static/components/modal.less | 37 ++++++++++++++----- 9 files changed, 79 insertions(+), 52 deletions(-) diff --git a/app/internal_packages/preferences/lib/tabs/preferences-identity.jsx b/app/internal_packages/preferences/lib/tabs/preferences-identity.jsx index 89824f021..edab9fd2e 100644 --- a/app/internal_packages/preferences/lib/tabs/preferences-identity.jsx +++ b/app/internal_packages/preferences/lib/tabs/preferences-identity.jsx @@ -32,8 +32,8 @@ class PreferencesIdentity extends React.Component { component: ( ), - height: 575, - width: 412, + width: BillingModal.IntrinsicWidth, + height: BillingModal.IntrinsicHeight, }) } diff --git a/app/src/components/billing-modal.jsx b/app/src/components/billing-modal.jsx index 0f0d74f3f..c7321eb64 100644 --- a/app/src/components/billing-modal.jsx +++ b/app/src/components/billing-modal.jsx @@ -4,6 +4,9 @@ import Actions from '../flux/actions' import IdentityStore from '../flux/stores/identity-store' export default class BillingModal extends React.Component { + static IntrinsicWidth = 412; + static IntrinsicHeight = 535; + static propTypes = { upgradeUrl: React.PropTypes.string, source: React.PropTypes.string, diff --git a/app/src/components/decorators/has-tutorial-tip.jsx b/app/src/components/decorators/has-tutorial-tip.jsx index d1e138c2a..2f231b194 100644 --- a/app/src/components/decorators/has-tutorial-tip.jsx +++ b/app/src/components/decorators/has-tutorial-tip.jsx @@ -10,7 +10,7 @@ const TipsBackgroundEl = document.createElement('tutorial-tip-background'); const TipsContainerEl = document.createElement('div'); TipsContainerEl.classList.add('tooltips-container'); -document.body.appendChild(TipsContainerEl); +document.body.insertBefore(TipsContainerEl, document.body.children[0]); class TipsStoreCls extends NylasStore { diff --git a/app/src/components/feature-used-up-modal.jsx b/app/src/components/feature-used-up-modal.jsx index 043203cc2..9fe414946 100644 --- a/app/src/components/feature-used-up-modal.jsx +++ b/app/src/components/feature-used-up-modal.jsx @@ -28,23 +28,23 @@ export default class FeatureUsedUpModal extends React.Component { componentWillUnmount() { this._mounted = false; } + + onGoToFeatures = () => { + shell.openExternal("https://getmerani.com/pro"); + }; + + onUpgrade = (e) => { + e.stopPropagation(); + Actions.openModal({ + component: ( + + ), + width: BillingModal.IntrinsicWidth, + height: BillingModal.IntrinsicHeight, + }); + } render() { - const gotoFeatures = () => { - shell.openExternal("https://getmerani.com/pro"); - }; - - const upgrade = (e) => { - e.stopPropagation(); - Actions.openModal({ - component: ( - - ), - height: 575, - width: 412, - }) - } - return (
@@ -68,10 +68,12 @@ export default class FeatureUsedUpModal extends React.Component {
  • Unlimited Reminders
  • Unlimited Mail Merge
  • -

    … plus dozens of other features

    +

    … plus dozens of other features

    - +
    ) diff --git a/app/src/components/modal.jsx b/app/src/components/modal.jsx index 7cb60ca94..38fe2786e 100644 --- a/app/src/components/modal.jsx +++ b/app/src/components/modal.jsx @@ -19,11 +19,21 @@ class Modal extends React.Component { this.state = { offset: 0, dimensions: {}, + animateClass: false, }; } componentDidMount() { this._focusImportantElement(); + this._mounted = true; + window.requestAnimationFrame(() => { + if (!this._mounted) { return; } + this.setState({animateClass: true}); + }); + } + + componentWillUnmount() { + this._mounted = false; } _focusImportantElement = () => { @@ -55,17 +65,7 @@ class Modal extends React.Component { boxShadow: "0 10px 20px rgba(0,0,0,0.19), inset 0 0 1px rgba(0,0,0,0.5)", borderRadius: "5px", }; - const containerStyle = { - display: "flex", - alignItems: "center", - justifyContent: "center", - height: "100%", - width: "100%", - zIndex: 1000, - position: "absolute", - backgroundColor: "rgba(255,255,255,0.58)", - }; - return {containerStyle, modalStyle}; + return {modalStyle}; }; _onKeyDown = (event) => { @@ -76,17 +76,16 @@ class Modal extends React.Component { render() { const {children, height, width} = this.props; - const {containerStyle, modalStyle} = this._computeModalStyles(height, width); + const {modalStyle} = this._computeModalStyles(height, width); return (
    Actions.closeModal()} >
    event.stopPropagation()} > diff --git a/app/src/flux/stores/feature-usage-store.jsx b/app/src/flux/stores/feature-usage-store.jsx index 7dc36a841..ea2179755 100644 --- a/app/src/flux/stores/feature-usage-store.jsx +++ b/app/src/flux/stores/feature-usage-store.jsx @@ -67,12 +67,7 @@ class FeatureUsageStore extends NylasStore { this._usub(); } - async asyncUseFeature(feature, {lexicon = {}} = {}) { - if (this._isUsable(feature)) { - this._markFeatureUsed(feature); - return Promise.resolve(); - } - + displayUpgradeModal(feature, {lexicon}) { const {headerText, rechargeText} = this._modalText(feature, lexicon); Actions.openModal({ @@ -88,6 +83,15 @@ class FeatureUsageStore extends NylasStore { /> ), }); + } + + async asyncUseFeature(feature, {lexicon = {}} = {}) { + if (this._isUsable(feature)) { + this._markFeatureUsed(feature); + return true; + } + + this.displayUpgradeModal(feature, {lexicon}); return new Promise((resolve, reject) => { this._waitForModalClose.push({resolve, reject, feature}) diff --git a/app/src/flux/stores/modal-store.jsx b/app/src/flux/stores/modal-store.jsx index cb380d1cc..6182cc5a1 100644 --- a/app/src/flux/stores/modal-store.jsx +++ b/app/src/flux/stores/modal-store.jsx @@ -9,7 +9,7 @@ const CONTAINER_ID = "nylas-modal-container"; function createContainer(id) { const element = document.createElement(id); - document.body.appendChild(element); + document.body.insertBefore(element, document.body.children[0]); return element; } diff --git a/app/src/flux/stores/popover-store.jsx b/app/src/flux/stores/popover-store.jsx index 6508120a1..4933ea07f 100644 --- a/app/src/flux/stores/popover-store.jsx +++ b/app/src/flux/stores/popover-store.jsx @@ -9,7 +9,7 @@ const CONTAINER_ID = "nylas-popover-container"; function createContainer(id) { const element = document.createElement(id); - document.body.appendChild(element); + document.body.insertBefore(element, document.body.children[0]); return element; } diff --git a/app/static/components/modal.less b/app/static/components/modal.less index 20c88fd08..582582228 100644 --- a/app/static/components/modal.less +++ b/app/static/components/modal.less @@ -1,21 +1,40 @@ @import "ui-variables"; -.nylas-modal-container { +.modal-container { + perspective: 1000px; + display: flex; + align-items: center; + justify-content: center; + height:100%; + width: 100%; + z-index: 1000; position: absolute; - z-index: 40; - - .modal-close { - margin: 6px; - } + background-color: rgba(255,255,255,0.0); + transition: background-color 100ms ease-out; .modal { position: absolute; - background-color: @background-primary; - border-radius: @border-radius-base; - box-shadow: 0 10px 20px rgba(0, 0, 0, 0.20), 0 0 1px rgba(0, 0, 0, 0.7); + transform-origin: top; + z-index: 40; + opacity: 0; + transform: translateY(10px) rotateX(-7deg); + transition: transform 360ms ease-out, opacity 240ms ease-out; + + .modal-close { + margin: 6px; + } + } + + &.animate { + background-color: rgba(255,255,255,0.58); + .modal { + opacity: 1; + transform: translateY(0) rotateX(0); + } } } + @media (-webkit-min-device-pixel-ratio: 2) { .modal-close { margin: 12px;