diff --git a/internal_packages/account-sidebar/lib/account-switcher.cjsx b/internal_packages/account-sidebar/lib/account-switcher.cjsx index 930026c62..b8efedde1 100644 --- a/internal_packages/account-sidebar/lib/account-switcher.cjsx +++ b/internal_packages/account-sidebar/lib/account-switcher.cjsx @@ -115,9 +115,8 @@ class AccountSwitcher extends React.Component @setState(showing: false) _onAddAccount: => - ipc = require('ipc') - ipc.send('command', 'application:add-account') - @setState(showing: false) + require('remote').getGlobal('application').windowManager.newOnboardingWindow(addingAccount: true) + @setState showing: false _getStateFromStores: => accounts: AccountStore.items() diff --git a/internal_packages/onboarding/assets/cloud@2x.png b/internal_packages/onboarding/assets/cloud@2x.png new file mode 100644 index 000000000..4d3dd95d4 Binary files /dev/null and b/internal_packages/onboarding/assets/cloud@2x.png differ diff --git a/internal_packages/onboarding/assets/gear-large@2x.png b/internal_packages/onboarding/assets/gear-large@2x.png new file mode 100644 index 000000000..1f4189847 Binary files /dev/null and b/internal_packages/onboarding/assets/gear-large@2x.png differ diff --git a/internal_packages/onboarding/assets/gear-small@2x.png b/internal_packages/onboarding/assets/gear-small@2x.png new file mode 100644 index 000000000..25189457a Binary files /dev/null and b/internal_packages/onboarding/assets/gear-small@2x.png differ diff --git a/internal_packages/onboarding/assets/lock@2x.png b/internal_packages/onboarding/assets/lock@2x.png new file mode 100644 index 000000000..9d58c3913 Binary files /dev/null and b/internal_packages/onboarding/assets/lock@2x.png differ diff --git a/internal_packages/onboarding/assets/nylas-pictograph@2x.png b/internal_packages/onboarding/assets/nylas-pictograph@2x.png new file mode 100644 index 000000000..7eb185eb5 Binary files /dev/null and b/internal_packages/onboarding/assets/nylas-pictograph@2x.png differ diff --git a/internal_packages/onboarding/assets/shapes-left@2x.png b/internal_packages/onboarding/assets/shapes-left@2x.png new file mode 100644 index 000000000..2b9701631 Binary files /dev/null and b/internal_packages/onboarding/assets/shapes-left@2x.png differ diff --git a/internal_packages/onboarding/assets/shapes-right@2x.png b/internal_packages/onboarding/assets/shapes-right@2x.png new file mode 100644 index 000000000..a7cc1deac Binary files /dev/null and b/internal_packages/onboarding/assets/shapes-right@2x.png differ diff --git a/internal_packages/onboarding/assets/wrench@2x.png b/internal_packages/onboarding/assets/wrench@2x.png new file mode 100644 index 000000000..6d4ae7ab9 Binary files /dev/null and b/internal_packages/onboarding/assets/wrench@2x.png differ diff --git a/internal_packages/onboarding/lib/account-choose-page.cjsx b/internal_packages/onboarding/lib/account-choose-page.cjsx index a2592223c..14817e3a2 100644 --- a/internal_packages/onboarding/lib/account-choose-page.cjsx +++ b/internal_packages/onboarding/lib/account-choose-page.cjsx @@ -25,16 +25,15 @@ class AccountChoosePage extends React.Component @_usub?() render: => + closeType = if @props.pageData.addingAccount then "close" else "quit"
-
atom.close() }> +
atom[closeType]() }>
-
- -
+ -
Select your email provider
+
Select your email provider
{@_renderProviders()} @@ -47,7 +46,7 @@ class AccountChoosePage extends React.Component
- {provider.displayName} + {provider.displayName}
_renderError: -> diff --git a/internal_packages/onboarding/lib/account-settings-page.cjsx b/internal_packages/onboarding/lib/account-settings-page.cjsx index 434682a4a..aa6a5ecce 100644 --- a/internal_packages/onboarding/lib/account-settings-page.cjsx +++ b/internal_packages/onboarding/lib/account-settings-page.cjsx @@ -158,15 +158,15 @@ class AccountSettingsPage extends React.Component _renderButton: => pages = @state.provider.pages || [] - if pages.length > @state.pageNumber + 1 - + if pages.length > @state.pageNumber+1 + else if @state.provider.name isnt 'gmail' if @state.tryingToAuthenticate else - + _onNextButton: (event) => @setState(pageNumber: @state.pageNumber + 1) diff --git a/internal_packages/onboarding/lib/account-types.coffee b/internal_packages/onboarding/lib/account-types.coffee index 49669bf01..c2bf5405b 100644 --- a/internal_packages/onboarding/lib/account-types.coffee +++ b/internal_packages/onboarding/lib/account-types.coffee @@ -2,6 +2,13 @@ Providers = [ { + name: 'gmail' + displayName: 'Gmail' + icon: 'ic-settings-account-gmail.png' + header_icon: 'setup-icon-provider-gmail.png' + color: '#e99999' + settings: [] + }, { name: 'exchange' displayName: 'Microsoft Exchange / Live' icon: 'ic-settings-account-eas.png' @@ -34,38 +41,6 @@ Providers = [ } ] }, { -# name: 'outlook' -# displayName: 'Outlook / Hotmail' -# icon: 'ic-settings-account-eas.png' -# header_icon: 'setup-icon-provider-hotmail.png' -# color: '#308acd' -# fields: [ -# { -# name: 'name' -# type: 'text' -# placeholder: 'Ashton Letterman' -# label: 'Name' -# }, { -# name: 'email' -# type: 'text' -# placeholder: 'you@hotmail.com' -# label: 'Email' -# } -# ] -# settings: [ -# { -# name: 'username' -# type: 'text' -# placeholder: 'MYCORP\\bob (if known)' -# label: 'Username (optional)' -# },{ -# name: 'password' -# type: 'password' -# placeholder: 'Password' -# label: 'Password' -# } -# ] -# }, { name: 'icloud' displayName: 'iCloud' icon: 'ic-settings-account-icloud.png' @@ -90,13 +65,6 @@ Providers = [ placeholder: 'Password' label: 'Password' }] - }, { - name: 'gmail' - displayName: 'Gmail' - icon: 'ic-settings-account-gmail.png' - header_icon: 'setup-icon-provider-gmail.png' - color: '#e99999' - settings: [] }, { name: 'yahoo' displayName: 'Yahoo' @@ -246,4 +214,4 @@ Providers = [ } ] -module.exports = Providers \ No newline at end of file +module.exports = Providers diff --git a/internal_packages/onboarding/lib/initial-packages-page.cjsx b/internal_packages/onboarding/lib/initial-packages-page.cjsx index 87eabd5fb..1bb9eeb59 100644 --- a/internal_packages/onboarding/lib/initial-packages-page.cjsx +++ b/internal_packages/onboarding/lib/initial-packages-page.cjsx @@ -61,7 +61,11 @@ class InitialPackagesPage extends React.Component @displayName: "InitialPackagesPage" render: => + closeType = if @props.pageData.addingAccount then "close" else "quit"
+
atom[closeType]() }> + +
diff --git a/internal_packages/onboarding/lib/initial-preferences-page.cjsx b/internal_packages/onboarding/lib/initial-preferences-page.cjsx index 9d7f6b325..518dfbbd7 100644 --- a/internal_packages/onboarding/lib/initial-preferences-page.cjsx +++ b/internal_packages/onboarding/lib/initial-preferences-page.cjsx @@ -80,7 +80,11 @@ class InitialPreferencesPage extends React.Component @displayName: "InitialPreferencesPage" render: => + closeType = if @props.pageData.addingAccount then "close" else "quit"
+
atom[closeType]() }> + +

Welcome to N1

Let's set things up to your liking.

diff --git a/internal_packages/onboarding/lib/page-router.cjsx b/internal_packages/onboarding/lib/page-router.cjsx index 0840f9e87..9e3943813 100644 --- a/internal_packages/onboarding/lib/page-router.cjsx +++ b/internal_packages/onboarding/lib/page-router.cjsx @@ -64,11 +64,11 @@ class PageRouter extends React.Component gradient = @state.pageData?.provider?.color if gradient background = "linear-gradient(to top, #f6f7f8, #{gradient})" + height = 200 else - background = "linear-gradient(to top, #f6f7f8 0%, rgba(255,255,255,0) 100%), - linear-gradient(to right, #e1e58f 0%, #a8d29e 50%, #8bc9c9 100%)" - -
+ background = "linear-gradient(to top, #f6f7f8 0%, rgba(255,255,255,0) 100%), linear-gradient(to right, #e1e58f 0%, #a8d29e 50%, #8bc9c9 100%)" + height = 330 +
_renderCurrentPage: => Component = { @@ -86,9 +86,9 @@ class PageRouter extends React.Component _renderDragRegion: -> styles = top:0 - left:40 + left: 26 right:0 - height: 20 + height: 27 zIndex:100 position: 'absolute' "WebkitAppRegion": "drag" diff --git a/internal_packages/onboarding/lib/welcome-page.cjsx b/internal_packages/onboarding/lib/welcome-page.cjsx index 32b091ccb..e5e2c4fc0 100644 --- a/internal_packages/onboarding/lib/welcome-page.cjsx +++ b/internal_packages/onboarding/lib/welcome-page.cjsx @@ -1,4 +1,6 @@ React = require 'react' +shell = require 'shell' +classnames = require 'classnames' {RetinaImg, TimeoutTransitionGroup} = require 'nylas-component-kit' OnboardingActions = require './onboarding-actions' @@ -8,44 +10,107 @@ class WelcomePage extends React.Component constructor: (@props) -> @state = step: 0 + lastStep: 0 - render: => - buttons = [] - if @state.step > 0 - buttons.push - buttons.push - -
-
atom.close() }> + render: -> + closeType = if @props.pageData.addingAccount then "close" else "quit" +
+
atom[closeType]() }>
- - - {@_renderStep()} - - -
- {buttons} -
+
{@_renderSteps()}
+
{@_renderButtons()}
- _renderStep: => - if @state.step is 0 -
- - -
- else if @state.step is 1 -
- -
- else if @state.step is 2 -
- + _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.

+
+ {@_gears()} +
+ + + +

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

+
+
+ +

Secured using
bank-grade encryption

+ @_open("https://nylas.com/security/")}>more info +
+
+ +

Synced by Nylas to be
faster and more extensible

+ @_open("https://github.com/nylas/sync-engine")}>more info +
+ {@_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