Clean up modals, add nice animation when modals appear

This commit is contained in:
Ben Gotow 2017-08-24 01:58:36 -04:00
parent 5eca04bec1
commit 0ea7227f3a
9 changed files with 79 additions and 52 deletions

View file

@ -32,8 +32,8 @@ class PreferencesIdentity extends React.Component {
component: (
<BillingModal source="preferences" />
),
height: 575,
width: 412,
width: BillingModal.IntrinsicWidth,
height: BillingModal.IntrinsicHeight,
})
}

View file

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

View file

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

View file

@ -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: (
<BillingModal source="feature-limit" upgradeUrl={this.state.upgradeUrl} />
),
width: BillingModal.IntrinsicWidth,
height: BillingModal.IntrinsicHeight,
});
}
render() {
const gotoFeatures = () => {
shell.openExternal("https://getmerani.com/pro");
};
const upgrade = (e) => {
e.stopPropagation();
Actions.openModal({
component: (
<BillingModal source="feature-limit" upgradeUrl={this.state.upgradeUrl} />
),
height: 575,
width: 412,
})
}
return (
<div className={`feature-usage-modal ${this.props.modalClass}`}>
<div className="feature-header">
@ -68,10 +68,12 @@ export default class FeatureUsedUpModal extends React.Component {
<li>Unlimited Reminders</li>
<li>Unlimited Mail Merge</li>
</ul>
<p>&hellip; plus <a onClick={gotoFeatures}>dozens of other features</a></p>
<p>&hellip; plus <a onClick={this.onGoToFeatures}>dozens of other features</a></p>
</div>
<button className="btn btn-cta btn-emphasis" onClick={upgrade}>Upgrade</button>
<button className="btn btn-cta btn-emphasis" onClick={this.onUpgrade}>
Upgrade
</button>
</div>
</div>
)

View file

@ -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 (
<div
style={containerStyle}
className="modal-container"
className={`modal-container ${this.state.animateClass && 'animate'}`}
onKeyDown={this._onKeyDown}
onClick={() => Actions.closeModal()}
>
<div
className="modal nylas-modal-container"
className="modal"
style={modalStyle}
onClick={(event) => event.stopPropagation()}
>

View file

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

View file

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

View file

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

View file

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