atom.close() }>
+ render: ->
+ closeType = if @props.pageData.addingAccount then "close" else "quit"
+
-
+ _renderButtons: ->
+ buttons = []
+ # if @state.step > 0
+ # buttons.push
Back
+ btnText = if @state.step is 2 then "Get Started" else "Continue"
+ buttons.push
+ return buttons
+
+ _renderSteps: -> [
+ @_renderStep0()
+ @_renderStep1()
+ @_renderStep2()
+ ]
+
+ _stepClass: (n) ->
+ obj =
+ "step-wrap": true
+ "active": @state.step is n
+ obj["step-#{n}-wrap"] = true
+ className = classnames(obj)
+ return className
+
+ _renderStep0: ->
+
+
N1 is a new email app that is fast,
friendly, and easy to use.
+
+
+
+
It is the foundation for a highly extensible email experience
+ {@_renderNavBubble(0)}
+
+
+ _renderStep1: ->
+
+
Under the hood, N1 is built for developers.
+
+
+
+
+
You can extend it using packages and build your own components.
+ {@_renderNavBubble(1)}
+
+
+ _gears: ->
+ gears = []
+ for i in [0..3]
+ gears.push
+ return gears
+
+ _renderStep2: ->
+
+
N1 is secured and enhanced by the Nylas Sync Engine
+
+ {@_renderNavBubble(2)}
+
+
+ _open: (link) ->
+ shell.openExternal(link)
+ return
+
+ _renderNavBubble: (step=0) ->
+ bubbles = [0..2].map (n) =>
+ active = if n is step then "active" else ""
+
@setState step: n }>
+
+
+ {bubbles}
+
_onBack: =>
@setState(step: @state.step - 1)
diff --git a/internal_packages/onboarding/stylesheets/onboarding.less b/internal_packages/onboarding/stylesheets/onboarding.less
index 7e7648796..b6906563e 100644
--- a/internal_packages/onboarding/stylesheets/onboarding.less
+++ b/internal_packages/onboarding/stylesheets/onboarding.less
@@ -109,10 +109,6 @@
padding: 0 15px;
width: 330px
}
- &.account-choose {
- width: 330px;
- padding-bottom:10px;
- }
&.opaque {
background-color: @gray-lighter;
}
@@ -139,8 +135,9 @@
.quit {
position: absolute;
- top:5px;
- left:5px;
+ z-index: 100;
+ top: 1px;
+ left: 6px;
}
.back,
@@ -167,30 +164,6 @@
opacity: 0.01;
}
- .welcome-image-container {
- height:391px;
- display:block;
- }
- .welcome-image {
- position:absolute;
- }
- .welcome-image-enter {
- opacity: 0;
- transition: opacity .3s linear;
- }
-
- .welcome-image-enter.welcome-image-enter-active {
- opacity: 1;
- }
- .welcome-image-leave {
- opacity: 1;
- transition: opacity .3s linear;
- }
-
- .welcome-image-leave.welcome-image-leave-active {
- opacity: 0;
- }
-
.check {
width: @checkSize;
height: @checkSize;
@@ -242,25 +215,6 @@
}
}
- .provider {
- text-align: left;
- border-top: 1px solid rgba(0,0,0,0.05);
- cursor: default;
-
- img.icon {
- }
- .icon-container {
- width: 50px;
- height: 50px;
- display: inline-block;
- box-sizing: content-box;
- padding: 5px 15px;
- }
- }
- .provider:hover{
- background: rgba(255,255,255,0.7);
- }
-
.errormsg {
color: #A33;
margin-bottom:5px;
@@ -338,6 +292,44 @@
}
}
+.page.account-choose {
+ width: 388px;
+ height: 602px;
+ img.logo.content-mask {
+ background-color: rgba(255,255,255,0.4);
+ }
+
+ .caption {
+ font-size: 17px;
+ color: rgba(0,0,0,0.56);
+ }
+
+ .provider-name {
+ font-size: 20px;
+ font-weight: 300;
+ color: rgba(0,0,0,0.7);
+ }
+
+ .provider {
+ text-align: left;
+ border-top: 1px solid rgba(0,0,0,0.05);
+ cursor: default;
+
+ img.icon {
+ }
+ .icon-container {
+ width: 50px;
+ height: 50px;
+ display: inline-block;
+ box-sizing: content-box;
+ padding: 10px 25px;
+ }
+ }
+ .provider:hover{
+ background: rgba(255,255,255,0.7);
+ }
+}
+
.initial-package {
display:block;
margin:auto;
@@ -361,3 +353,266 @@
max-width:500px;
}
}
+
+.welcome-page {
+ width: 675px;
+ height: 480px;
+ display: flex;
+ flex-direction: column;
+
+ @-webkit-keyframes slideIn {
+ from {
+ transform: translate3d(20,0,0);
+ opacity: 0;
+ }
+ to {
+ transform: translate3d(0,0,0);
+ opacity: 1;
+ }
+ }
+
+ a {
+ color: rgba(255,255,255,0.7);
+ border-bottom: 1px solid rgba(255,255,255,0.7);
+ &:hover {
+ cursor: default;
+ color: white;
+ border-bottom: 1px solid white;
+ }
+ }
+
+ .steps-container {
+ position: relative;
+ flex: 1;
+ }
+
+ .step-wrap {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ transition: all 0.3s;
+ z-index: 1;
+
+ opacity: 0;
+ &.active {
+ opacity: 1;
+ z-index: 3;
+ }
+ }
+
+ .footer {
+ text-align: center;
+ background: #ececec;
+ border-top: 1px solid #d4d4d4;
+
+ .btn-continue {
+ font-size: 18px;
+ font-weight: 300;
+ margin: 20px 0;
+ padding: 12px 0;
+ width: 296px;
+ }
+ .btn-back {
+ color: rgba(0,0,0,0.4);
+ &:hover {
+ color: rgba(0,0,0,0.7);
+ cursor: default;
+ }
+ position: absolute;
+ left: 20px;
+ bottom: 30px;
+ }
+ }
+
+ p.hero-text {
+ font-weight: 200;
+ -webkit-font-smoothing: subpixel-antialiased;
+ }
+ p.sub-text {
+ font-size: 17px;
+ font-weight: 300;
+ }
+
+ .nylas-wash-light-bg {
+ background-image: linear-gradient(to bottom, rgba(236,236,236,0) 0%, rgba(236,236,236,1) 88%), linear-gradient(to right, rgba(213,224,0,0.47) 0%,rgba(88,182,63,0.47) 50%,rgba(12,162,163,0.47) 100%);
+ color: white;
+ }
+
+ .nylas-wash-bg {
+ background: rgba(101, 191, 191, 0.44);
+ background-image: linear-gradient(to right, rgba(213,224,0,0.35) 0%,rgba(88,182,63,0.35) 50%,rgba(12,162,163,0.35) 100%);
+ color: white;
+ }
+
+ .nylas-static-wash-bg {
+ background-image: linear-gradient(to right, rgba(162,210,128,1) 0%,rgba(113,193,154,1) 50%,rgba(89,187,187,1) 100%);
+ color: white;
+ }
+
+ .nylas-dark-bg {
+ background: rgba(58, 68, 74, 1);
+ color: rgba(255,255,255,0.7);
+ .sub-text {
+ color: rgba(255,255,255,0.5);
+ }
+ }
+
+ .nylas-blue-wash-bg {
+ background-image: linear-gradient(to right, rgba(79,186,151,1) 0%,rgba(113,193,154,1) 50%,rgba(34,172,187,1) 100%);
+ color: white;
+ }
+
+ .step-0-wrap {
+ .nylas-static-wash-bg;
+
+ .hero-text {
+ font-size: 36px;
+ line-height: 41px;
+ }
+
+ img.logo.content-mask {
+ background-color: rgba(255,255,255,0.4);
+ }
+ img.icons.content-mask {
+ background-color: rgba(255,255,255,0.7);
+ }
+ }
+
+ .step-1-wrap {
+ .nylas-dark-bg;
+
+ .hero-text {
+ font-size: 29px;
+ }
+ .gear-outer-container {
+ background: #69767f;
+ border: 1px solid #161f25;
+ width: 210px;
+ height: 210px;
+ margin: 20px auto;
+ border-radius: 105px;
+ }
+ .gear-container {
+ position: relative;
+ background: #182025;
+ border: 4px solid #161f25;
+ width: 204px;
+ height: 204px;
+ margin: 3px auto;
+ border-radius: 102px;
+ overflow: hidden;
+ // http://stackoverflow.com/questions/5736503/how-to-make-css3-rounded-corners-hide-overflow-in-chrome-opera
+ -webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC);
+ }
+
+ &.active {
+ @keyframes rotate {
+ from { transform: rotate(0deg); }
+ to { transform: rotate(720deg); }
+ }
+ @keyframes rotate-2 {
+ from { transform: rotate(7deg); }
+ to { transform: rotate(727deg); }
+ }
+
+ .gear-large {
+ animation: rotate 20s ease-in-out;
+ animation-iteration-count: infinite;
+ }
+ .gear-large-0{
+ animation-name: rotate-2;
+ animation-direction: reverse;
+ }
+ }
+
+ .gear-large {
+ position: absolute;
+ }
+
+ .gear-large-0 {
+ left: 50%;
+ top: 50%;
+ margin-left: -150px;
+ margin-top: -150px;
+ transform: rotate(7deg);
+ }
+ .gear-large-1 {
+ left: -147px;
+ top: -147px;
+ }
+ .gear-large-2 {
+ right: -147px;
+ top: -147px;
+ }
+ .gear-large-3 {
+ left: 50%;
+ margin-left: -148px;
+ bottom: -226px;
+ }
+
+ .gear-small {
+ position: absolute;
+ top: 470px;
+ left: 390px;
+ }
+ .wrench {
+ position: absolute;
+ right: 310px;
+ top: 370px;
+ }
+ }
+
+ .step-2-wrap {
+ .nylas-blue-wash-bg;
+ .cell-wrap {
+ width: 514px;
+ margin: 30px auto 0 auto;
+ }
+
+ .cell {
+ width: 242px;
+ background: rgba(247, 251, 251, 0.25);
+ border-radius: 10px;
+ box-shadow: 0px 1px 1px rgba(0,0,0,0.09), inset 0px 0px 1px rgba(255,255,255,0.15);
+ padding: 30px 0;
+
+ p {
+ margin-top: 1em;
+ color: rgba(255,255,255,0.7);
+ font-size: 17px;
+ line-height: 24px;
+ }
+ a {
+ margin-top: 1em;
+ }
+ }
+
+ .hero-text {
+ font-size: 27px;
+ }
+ }
+
+ .nav-bubbles {
+ position: absolute;
+ bottom: 14px;
+ left: 50%;
+ margin-left: -24px;
+ display: flex;
+ width: 48px;
+ }
+ .nav-bubble {
+ margin: 4px;
+ width: 8px;
+ height: 8px;
+ border-radius: 4px;
+ background-color: rgba(255,255,255,0.2);
+ &:hover {
+ background-color: rgba(255,255,255,0.4);
+ }
+ &.active {
+ background-color: rgba(255,255,255,0.7);
+ }
+ }
+}
diff --git a/src/atom.coffee b/src/atom.coffee
index 6ac872048..90e0972a4 100644
--- a/src/atom.coffee
+++ b/src/atom.coffee
@@ -401,6 +401,9 @@ class Atom extends Model
close: ->
@getCurrentWindow().close()
+ quit: ->
+ remote.require('app').quit()
+
# Essential: Get the size of current window.
#
# Returns an {Object} in the format `{width: 1000, height: 700}`
@@ -631,7 +634,10 @@ class Atom extends Model
CommandInstaller.installApmCommand resourcePath, false, (error) ->
console.warn error.message if error?
@commands.add 'atom-workspace',
- 'atom-workspace:add-account': @addAccount
+ 'atom-workspace:add-account': @onAddAccount
+
+ onAddAccount: =>
+ require('remote').getGlobal('application').windowManager.newOnboardingWindow(addingAccount: true)
# Call this method when establishing a secondary application window
# displaying a specific set of packages.
@@ -766,17 +772,6 @@ class Atom extends Model
executeJavaScriptInDevTools: (code) ->
ipc.send('call-window-method', 'executeJavaScriptInDevTools', code)
- addAccount: =>
- @newWindow
- title: 'Add an Account'
- width: 340
- height: 550
- toolbar: false
- resizable: false
- windowType: 'onboarding'
- windowProps:
- page: 'add-account'
-
###
Section: Private
###
diff --git a/src/browser/application.coffee b/src/browser/application.coffee
index b1244fa0f..28ae16ba8 100644
--- a/src/browser/application.coffee
+++ b/src/browser/application.coffee
@@ -159,7 +159,7 @@ class Application
@windowManager.showMainWindow(loadingMessage)
@windowManager.ensureWorkWindow()
else
- @windowManager.newOnboardingWindow({welcome: true})
+ @windowManager.newOnboardingWindow()
# The onboarding window automatically shows when it's ready
_resetConfigAndRelaunch: =>
@@ -169,7 +169,7 @@ class Application
@config.set('nylas', null)
@config.set('edgehill', null)
@setDatabasePhase('setup')
- @windowManager.newOnboardingWindow({welcome: true})
+ @windowManager.newOnboardingWindow()
_deleteDatabase: (callback) ->
@deleteFileWithRetry path.join(configDirPath,'edgehill.db'), callback
diff --git a/src/browser/window-manager.coffee b/src/browser/window-manager.coffee
index 097b6e585..a437e3022 100644
--- a/src/browser/window-manager.coffee
+++ b/src/browser/window-manager.coffee
@@ -132,23 +132,20 @@ class WindowManager
# Returns a new onboarding window
#
- newOnboardingWindow: ({welcome} = {}) ->
- options =
+ newOnboardingWindow: ({addingAccount}={}) ->
+ page = if addingAccount then "account-choose" else "welcome"
+ title = if addingAccount then "Add an Account" else "Welcome to N1"
+ win = @newWindow
+ title: title
toolbar: false
resizable: false
- hidden: true
- title: 'Add an Account'
+ hidden: true # The `PageRouter` will center and show on load
windowType: 'onboarding'
windowProps:
- page: 'account-choose'
+ page: page
+ pageData: {addingAccount}
uniqueId: 'onboarding'
- if welcome
- options.title = "Welcome to N1"
- options.windowProps.page = "welcome"
-
- @newWindow(options)
-
# Makes a new window appear of a certain `windowType`.
#
# In almost all cases, instead of booting up a new window from scratch,
diff --git a/src/components/retina-img.cjsx b/src/components/retina-img.cjsx
index fb1cc4e75..a5d53005c 100644
--- a/src/components/retina-img.cjsx
+++ b/src/components/retina-img.cjsx
@@ -108,7 +108,7 @@ class RetinaImg extends React.Component
style = @props.style ? {}
style.WebkitUserDrag = 'none'
- style.zoom = if pathIsRetina then 0.5 else 1
+ style.zoom ?= if pathIsRetina then 0.5 else 1
style.width = style.width / style.zoom if style.width
style.height = style.height / style.zoom if style.height