diff --git a/build/Gruntfile.coffee b/build/Gruntfile.coffee index 8c7dd6b45..ed1c27130 100644 --- a/build/Gruntfile.coffee +++ b/build/Gruntfile.coffee @@ -248,6 +248,8 @@ module.exports = (grunt) -> src: [ 'static/**/*.less' ] + options: + imports: ['variables/*.less'] 'download-atom-shell': version: packageJson.atomShellVersion @@ -262,7 +264,7 @@ module.exports = (grunt) -> authors: 'InboxApp Inc.' loadingGif: path.resolve(__dirname, '..', 'resources', 'win', 'loading.gif') iconUrl: 'https://raw.githubusercontent.com/atom/atom/master/resources/win/atom.ico' - setupIcon: path.resolve(__dirname, '..', 'resources', 'win', 'atom.ico') + setupIcon: path.resolve(__dirname, '..', 'resources', 'win', 'edgehill.ico') shell: 'kill-atom': @@ -281,10 +283,10 @@ module.exports = (grunt) -> ciTasks.push('dump-symbols') if process.platform isnt 'win32' ciTasks.push('set-version', 'lint') ciTasks.push('mkdeb') if process.platform is 'linux' - ciTasks.push('create-windows-installer') if process.platform is 'win32' ciTasks.push('test') if process.platform is 'darwin' ciTasks.push('codesign') ciTasks.push('mkdmg') if process.platform is 'darwin' + ciTasks.push('create-windows-installer') if process.platform is 'win32' ciTasks.push('publish-edgehill-build') if process.platform is 'darwin' # ciTasks.push('publish-build') grunt.registerTask('ci', ciTasks) diff --git a/build/tasks/build-task.coffee b/build/tasks/build-task.coffee index 31bf3f033..415804343 100644 --- a/build/tasks/build-task.coffee +++ b/build/tasks/build-task.coffee @@ -21,6 +21,11 @@ module.exports = (grunt) -> cp(path.join(shellAppDir, 'Contents', 'MacOS', 'Atom'), path.join(shellAppDir, 'Contents', 'MacOS', 'Edgehill')) rm path.join(shellAppDir, 'Contents', 'MacOS', 'Atom') + else if process.platform is 'win32' + cp 'atom-shell', shellAppDir, filter: /default_app/ + # We can rename atom.exe to edgehill.exe, but all of the node libraries with + # native code are hard-linked to a file called atom.exe. For now, let's just + # leave it as atom.exe. https://github.com/atom/atom-shell/issues/713 else cp 'atom-shell', shellAppDir, filter: /default_app/ cp path.join(shellAppDir, 'atom'), path.join(shellAppDir, 'edgehill') diff --git a/build/tasks/codesign-task.coffee b/build/tasks/codesign-task.coffee index d935c5344..e7f854a9c 100644 --- a/build/tasks/codesign-task.coffee +++ b/build/tasks/codesign-task.coffee @@ -41,16 +41,19 @@ module.exports = (grunt) -> args = ['--deep', '--force', '--verbose', '--sign', 'Developer ID Application: InboxApp, Inc.', grunt.config.get('atom.shellAppDir')] spawn {cmd, args}, (error) -> callback(error) when 'win32' - spawn {cmd: 'taskkill', args: ['/F', '/IM', 'edgehill.exe']}, -> + # TODO: Don't do anything now, because we need a certificate pfx file + # issued from a certificate authority, and we don't have one. + return callback() + spawn {cmd: 'taskkill', args: ['/F', '/IM', 'atom.exe']}, -> cmd = process.env.JANKY_SIGNTOOL ? 'signtool' - args = [path.join(grunt.config.get('atom.shellAppDir'), 'edgehill.exe')] + args = ['sign', path.join(grunt.config.get('atom.shellAppDir'), 'atom.exe')] spawn {cmd, args}, (error) -> return callback(error) if error? setupExePath = path.resolve(grunt.config.get('atom.buildDir'), 'installer', 'AtomSetup.exe') if fs.isFileSync(setupExePath) - args = [setupExePath] + args = ['sign', setupExePath] spawn {cmd, args}, (error) -> callback(error) else callback() diff --git a/internal_packages/account-sidebar/lib/account-sidebar-store.coffee b/internal_packages/account-sidebar/lib/account-sidebar-store.coffee index 0234e85b6..cdd88d868 100644 --- a/internal_packages/account-sidebar/lib/account-sidebar-store.coffee +++ b/internal_packages/account-sidebar/lib/account-sidebar-store.coffee @@ -55,8 +55,8 @@ AccountSidebarStore = Reflux.createStore namespace = NamespaceStore.current() return unless namespace - @_sections.forEach (section) => - section.tags.forEach (tag) => + @_sections.forEach (section) -> + section.tags.forEach (tag) -> # Some tags don't have unread counts return if tag.id in ['archive', 'drafts', 'sent', 'trash'] diff --git a/internal_packages/calendar-bar/lib/main.cjsx b/internal_packages/calendar-bar/lib/main.cjsx index 85456f8cc..8fc09b9e0 100644 --- a/internal_packages/calendar-bar/lib/main.cjsx +++ b/internal_packages/calendar-bar/lib/main.cjsx @@ -2,21 +2,10 @@ React = require "react" CalendarBar = require "./calendar-bar" module.exports = - item: null # The DOM item the main React component renders into activate: (@state) -> - unless @item? - @item = document.createElement("div") - @item.setAttribute("id", "calendar-bar") - @item.setAttribute("class", "calendar-bar") - - React.render( , @item) - - atom.workspace.addRow(@item) - + # Package turned off for now + deactivate: -> - React.unmountComponentAtNode(@item) - @item.remove() - @item = null serialize: -> @state diff --git a/internal_packages/composer/lib/composer-view.cjsx b/internal_packages/composer/lib/composer-view.cjsx index 3283b2f21..23f0fcf73 100644 --- a/internal_packages/composer/lib/composer-view.cjsx +++ b/internal_packages/composer/lib/composer-view.cjsx @@ -42,7 +42,6 @@ ComposerView = React.createClass @_checkForKnownFrames() componentDidMount: -> - @undoManager = new UndoManager @keymap_unsubscriber = atom.commands.add '.composer-outer-wrap', { 'composer:show-and-focus-bcc': @_showAndFocusBcc 'composer:show-and-focus-cc': @_showAndFocusCc @@ -82,6 +81,8 @@ ComposerView = React.createClass @_prepareForDraft() _prepareForDraft: -> + # UndoManager must be ready before we call _onDraftChanged for the first time + @undoManager = new UndoManager @_proxy = DraftStore.sessionForLocalId(@props.localId) if @_proxy.draft() @_onDraftChanged() diff --git a/internal_packages/inbox-activity-bar/lib/activity-bar.cjsx b/internal_packages/inbox-activity-bar/lib/activity-bar.cjsx index 0f9818680..e39f206e5 100644 --- a/internal_packages/inbox-activity-bar/lib/activity-bar.cjsx +++ b/internal_packages/inbox-activity-bar/lib/activity-bar.cjsx @@ -35,8 +35,8 @@ ActivityBar = React.createClass render: -> + minHeight={ActivityBarClosedHeight} + handle={ResizableRegion.Handle.Top}>
{@_caret()}
@@ -140,10 +140,6 @@ ActivityBar = React.createClass @setState(section: section) @_onShow() - _onTrayResized: (height) -> - height = ActivityBarClosedHeight if height < 80 - @setState(height: height) - _onFeedback: -> user = NamespaceStore.current().name diff --git a/internal_packages/message-templates/lib/main.cjsx b/internal_packages/message-templates/lib/main.cjsx index 0679ba276..7f52e19f1 100644 --- a/internal_packages/message-templates/lib/main.cjsx +++ b/internal_packages/message-templates/lib/main.cjsx @@ -7,11 +7,10 @@ module.exports = activate: (@state={}) -> # Register our menu item in the composer footer - ComponentRegistry.register - name: 'TemplatePicker' - role: 'Composer:Footer' - view: TemplatePicker - + # ComponentRegistry.register + # name: 'TemplatePicker' + # role: 'Composer:Footer' + # view: TemplatePicker deactivate: -> diff --git a/internal_packages/notifications/lib/main.cjsx b/internal_packages/notifications/lib/main.cjsx index f03f1d6b3..e6dee488a 100644 --- a/internal_packages/notifications/lib/main.cjsx +++ b/internal_packages/notifications/lib/main.cjsx @@ -1,32 +1,24 @@ React = require "react" Notifications = require "./notifications" NotificationsStickyBar = require "./notifications-sticky-bar" +{ComponentRegistry} = require("inbox-exports") module.exports = item: null # The DOM item the main React component renders into activate: (@state={}) -> - unless @item? - @item = document.createElement("div") - @item.setAttribute("id", "notifications-wrap") - @item.setAttribute("class", "notifications-wrap") - atom.workspace.addColumnItem(@item, "thread-list-column") - React.render( , @item) + ComponentRegistry.register + view: Notifications + name: 'Notifications' + role: 'ThreadList:Center' - unless @stickyItem? - @stickyItem = document.createElement("div") - @stickyItem.setAttribute("id", "notifications-sticky-bar") - @stickyItem.setAttribute("class", "notifications-sticky-bar") - atom.workspace.addRow(@stickyItem) - React.render( , @stickyItem) + ComponentRegistry.register + view: NotificationsStickyBar + name: 'NotificationsStickyBar' + role: 'ThreadList:Top' deactivate: -> - React.unmountComponentAtNode(@item) - @item.remove() - @item = null - - React.unmountComponentAtNode(@stickyItem) - @stickyItem.remove() - @stickyItem = null + ComponentRegistry.unregister('NotificationsStickyBar') + ComponentRegistry.unregister('Notifications') serialize: -> @state diff --git a/internal_packages/notifications/lib/notifications-sticky-bar.cjsx b/internal_packages/notifications/lib/notifications-sticky-bar.cjsx index e114b23e5..b89fe2709 100644 --- a/internal_packages/notifications/lib/notifications-sticky-bar.cjsx +++ b/internal_packages/notifications/lib/notifications-sticky-bar.cjsx @@ -41,7 +41,7 @@ NotificationStickyBar = React.createClass @ render: -> -
+
{@_notificationComponents()}
diff --git a/internal_packages/notifications/lib/notifications.cjsx b/internal_packages/notifications/lib/notifications.cjsx index a6415893b..c5a297a2f 100644 --- a/internal_packages/notifications/lib/notifications.cjsx +++ b/internal_packages/notifications/lib/notifications.cjsx @@ -14,12 +14,17 @@ Notifications = React.createClass @unsubscribeStore() if @unsubscribeStore render: -> -
{ - for notification in @state.notifications -
- {notification.message} -
- }
+
+
+ {@_notificationComponents()} +
+
+ + _notificationComponents: -> + @state.notifications.map (notification) -> +
+ {notification.message} +
_onStoreChange: -> @setState diff --git a/internal_packages/notifications/stylesheets/notifications.less b/internal_packages/notifications/stylesheets/notifications.less index 719d5d212..e15ee82b9 100644 --- a/internal_packages/notifications/stylesheets/notifications.less +++ b/internal_packages/notifications/stylesheets/notifications.less @@ -2,35 +2,13 @@ @import "ui-mixins"; // Notification Colors -.notifications-wrap, .notifications-sticky-bar { +.notifications-momentary, +.notifications-sticky { .notification-info { background: @background-color-info; } .notification-error { background: @background-color-error; } .notification-success { background: @background-color-success; } -} -// Notifications Above Threads -.notifications-wrap { - position: absolute; - width: 100%; - order: 1; - z-index: 400; - - .notifications { - text-align: center; - font-size: @font-size-small; - height: 19px; - overflow: auto; - } - - .notification-item { - color: @text-color-inverse; - padding: 0px 15px 2px 1px; - } -} - -// Notifications Across Top Bar -.notifications-sticky-bar { - order: -1; + order: -1; .notifications-sticky-item { height: 25px; @@ -65,3 +43,22 @@ } } } + +// Notifications Above Threads +.notifications-momentary { + position: absolute; + order: 1; + z-index: 400; + width:100%; + + .inner { + text-align: center; + font-size: @font-size-small; + overflow: auto; + + .notification-item { + color: @text-color-inverse; + padding: 3px 15px 2px 1px; + } + } +} diff --git a/internal_packages/onboarding/lib/container-view.cjsx b/internal_packages/onboarding/lib/container-view.cjsx index 6239a5262..0d4c16c9e 100644 --- a/internal_packages/onboarding/lib/container-view.cjsx +++ b/internal_packages/onboarding/lib/container-view.cjsx @@ -4,6 +4,7 @@ OnboardingActions = require './onboarding-actions' OnboardingStore = require './onboarding-store' querystring = require 'querystring' {EdgehillAPI} = require 'inbox-exports' +{RetinaImg} = require 'ui-components' module.exports = ContainerView = React.createClass @@ -30,21 +31,22 @@ ContainerView = React.createClass webview = this.refs['connect-iframe'] if webview node = webview.getDOMNode() - node.addEventListener 'did-finish-load', (e) -> - if node.getUrl().indexOf('/connect/complete') != -1 - query = node.getUrl().split('?')[1] - token = querystring.decode(query) - OnboardingActions.finishedConnect(token) + if node.hasListeners is undefined + node.addEventListener 'did-start-loading', (e) -> + if node.hasMobileUserAgent is undefined + node.setUserAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 7_1 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D167 Safari/9537.53") + node.hasMobileUserAgent = true + node.reload() + node.addEventListener 'did-finish-load', (e) -> + if node.getUrl().indexOf('/connect/complete') != -1 + query = node.getUrl().split('?')[1] + token = querystring.decode(query) + OnboardingActions.finishedConnect(token) render: -> -
- - {@_pageComponent()} - -
- - -
+ + {@_pageComponent()} + _pageComponent: -> if @state.error @@ -54,71 +56,53 @@ ContainerView = React.createClass if @state.page is 'welcome'
-

Welcome to Edgehill

-
- - -
-
Environment
- -
+
+
-
- else if @state.page is 'sign-in' -
+ +

Welcome to Nilas

+ + +
- {alert} -
- -
-
- -
- -
-
- else if @state.page == 'create-account' -
-
- {alert} -
- -
-
- -
-
- -
-
- -
-
- -
- +
Enter your email address:
+ + + {@_environmentComponent()}
+
+ else if @state.page == 'add-account'
-

Connect an Account

-

Link accounts from other services to supercharge your email.

-
- - +
+
+ +

Connect an Account

+ + + +
+
Link accounts from other services to supercharge your email.
+ + +
else if @state.page == 'add-account-auth' - React.createElement('webview',{ - "ref": "connect-iframe", - "key": this.state.page, - "src": this._connectWebViewURL() - }); +
+ { + React.createElement('webview',{ + "ref": "connect-iframe", + "key": this.state.page, + "src": this._connectWebViewURL() + }); + } +
+ +
+
else if @state.page == 'add-account-success' # http://codepen.io/stevenfabre/pen/NPWeVb @@ -129,7 +113,16 @@ ContainerView = React.createClass
- + + _environmentComponent: -> + return [] unless atom.inDevMode() +
+ +
_connectWebViewURL: -> EdgehillAPI.urlForConnecting(@state.connectType, @state.email) @@ -146,11 +139,14 @@ ContainerView = React.createClass atom.close() _fireQuit: -> - require('remote').require('app').quit() + require('ipc').send('command', 'application:quit') _fireSetEnvironment: (event) -> OnboardingActions.setEnvironment(event.target.value) + _fireStart: (e) -> + OnboardingActions.startConnect('inbox') + _fireAuthAccount: (service) -> OnboardingActions.startConnect(service) @@ -160,10 +156,3 @@ ContainerView = React.createClass _fireMoveToPrevPage: -> OnboardingActions.moveToPreviousPage() - _fireSignIn: (e) -> - e.preventDefault() - OnboardingActions.signIn(@state) - - _fireCreateAccount: (e) -> - e.preventDefault() - OnboardingActions.createAccount(@state) diff --git a/internal_packages/onboarding/lib/onboarding-actions.coffee b/internal_packages/onboarding/lib/onboarding-actions.coffee index e88b3b461..51e35b01a 100644 --- a/internal_packages/onboarding/lib/onboarding-actions.coffee +++ b/internal_packages/onboarding/lib/onboarding-actions.coffee @@ -2,8 +2,6 @@ Reflux = require 'reflux' actions = [ "setEnvironment", - "createAccount", - "signIn", "authErrorOccurred", "startConnect", "finishedConnect", diff --git a/internal_packages/onboarding/lib/onboarding-store.coffee b/internal_packages/onboarding/lib/onboarding-store.coffee index 7c2e0e813..36dd1ec21 100644 --- a/internal_packages/onboarding/lib/onboarding-store.coffee +++ b/internal_packages/onboarding/lib/onboarding-store.coffee @@ -3,23 +3,24 @@ Actions = require './onboarding-actions' {EdgehillAPI} = require 'inbox-exports' ipc = require 'ipc' +if atom.state.mode isnt "onboarding" and atom.state.mode isnt "spec" then return + module.exports = OnboardingStore = Reflux.createStore init: -> @_error = '' @_page = atom.getLoadSettings().page || 'welcome' + @_pageStack = [@_page] defaultEnv = if atom.inDevMode() then 'staging' else 'production' - atom.config.set('inbox.env', defaultEnv) unless atom.config.get('inbox.env') + atom.config.set('env', defaultEnv) unless atom.config.get('env') @listenTo Actions.setEnvironment, @_onSetEnvironment @listenTo Actions.moveToPreviousPage, @_onMoveToPreviousPage @listenTo Actions.moveToPage, @_onMoveToPage @listenTo Actions.startConnect, @_onStartConnect @listenTo Actions.finishedConnect, @_onFinishedConnect - @listenTo Actions.createAccount, @_onCreateAccount - @listenTo Actions.signIn, @_onSignIn page: -> @_page @@ -28,7 +29,7 @@ OnboardingStore = Reflux.createStore @_error environment: -> - atom.config.get('inbox.env') + atom.config.get('env') connectType: -> @_connectType @@ -44,37 +45,6 @@ OnboardingStore = Reflux.createStore @_page = page @trigger() - _onSignIn: (fields) -> - @_error = null - @trigger() - - EdgehillAPI.signIn(fields) - .then (user) => - if atom.config.get('inbox.token') - @_onMoveToPage('add-account-success') - setTimeout -> - # Important: This delay is actually necessary, because - # atom.config changes are not persisted instantly. - ipc.send('onboarding-complete') - atom.close() - , 2500 - else - @_onStartConnect('inbox') - .catch (err) => - @_error = err - @trigger() - - _onCreateAccount: (fields) -> - @_error = null - @trigger() - - EdgehillAPI.createAccount(fields) - .then => - @_onStartConnect('inbox') - .catch (err) => - @_error = err - @trigger() - _onStartConnect: (service) -> @_connectType = service @_onMoveToPage('add-account-auth') @@ -90,5 +60,5 @@ OnboardingStore = Reflux.createStore _onSetEnvironment: (env) -> throw new Error("Environment #{env} is not allowed") unless env in ['development', 'staging', 'production'] - atom.config.set('inbox.env', env) + atom.config.set('env', env) @trigger() diff --git a/internal_packages/onboarding/stylesheets/onboarding.less b/internal_packages/onboarding/stylesheets/onboarding.less index 25f21359e..306257f44 100644 --- a/internal_packages/onboarding/stylesheets/onboarding.less +++ b/internal_packages/onboarding/stylesheets/onboarding.less @@ -22,101 +22,92 @@ .onboarding-container { width:100%; height:100%; + background-color: #f0f0f0; -webkit-animation: fadein 0.8s; + -webkit-user-select:none; + text-align: center; - h2 { - padding:0; - margin:0; - } - h2, p { - text-align: center; - } iframe, webview { + position: absolute; width:100%; height:100%; - position: absolute; + left:0; + top:0; border:0; } + h2 { + margin-top: 27px; + margin-bottom: 60px; + } + + .prompt { + color:#5D5D5D; + font-size:1.07em; + font-weight:300; + margin-top:20px; + margin-bottom:14px; + } + + form { + padding-right:25px; + padding-left:25px; + } + + input { + display:block; + padding:10px; + width:100%; + margin-bottom:20px; + background-color: #F5F5F5; + } + .environment-selector { position: absolute; - bottom: 10px; - width:100%; - border-top:1px solid @border-color-divider; - text-align: center; - - h5 { - text-align: center; - position: relative; - top: -18px; - background-color: white; - display: inline-block; - padding-left: 10px; - padding-right: 10px; - margin-bottom: 0; - height: 10px; - } + opacity:0.1; + top: 224px; + width:292px; select { - position: relative; - top: -14px; width:100%; } } - .thin-container { - margin:auto; - padding-top:40px; - width:250px; - position: relative; - height:100%; - } .page { position:absolute; top:0; width:100%; height:100%; - padding:40px; padding-top:15%; } - .add-account .back, - .welcome .back { - display:none; - } - .quit, .dismiss { - display:none; - } - - .add-account .dismiss, - .welcome .quit { - display:inherit; - } - - .back, .dismiss, .quit { + .quit { position: absolute; - top:10px; - left:10px; + top:5px; + left:5px; + } + + .back, + .dismiss { + position: absolute; + top:25px; + left:25px; } .page-enter { opacity: 0.01; - transform: translateY(20px); transition: all .3s ease-out; } .page-enter.page-enter-active { opacity: 1; - transform: translateY(0); } .page-leave { opacity: 1; - transform: translateY(0); transition: all .3s ease-in; } .page-leave.page-leave-active { opacity: 0.01; - transform: translateY(20px); } .check { diff --git a/internal_packages/search-bar/lib/search-bar.cjsx b/internal_packages/search-bar/lib/search-bar.cjsx index 03b7c7758..fa41d2da7 100644 --- a/internal_packages/search-bar/lib/search-bar.cjsx +++ b/internal_packages/search-bar/lib/search-bar.cjsx @@ -25,6 +25,7 @@ SearchBar = React.createClass render: -> inputValue = @_queryToString(@state.query) inputClass = React.addons.classSet + 'input-bordered': true 'empty': inputValue.length is 0 headerComponents = [ @@ -93,6 +94,8 @@ SearchBar = React.createClass _onValueChange: (event) -> Actions.searchQueryChanged(@_stringToQuery(event.target.value)) + if (event.target.value is '') + @_onClearSearch() _onSelectSuggestion: (item) -> Actions.searchQueryCommitted(item.value) diff --git a/internal_packages/search-bar/stylesheets/search-bar.less b/internal_packages/search-bar/stylesheets/search-bar.less index 5d10ba8b4..42e449bf8 100644 --- a/internal_packages/search-bar/stylesheets/search-bar.less +++ b/internal_packages/search-bar/stylesheets/search-bar.less @@ -65,7 +65,10 @@ position: relative; &.showing-suggestions { - .suggestions{ display: inherit; } + .suggestions { display: inherit; } + } + &.showing-query { + .clear { display: inherit; } } } @@ -79,11 +82,10 @@ &.clear { position: absolute; - top: 0; + top: floor(40px - 26px)/2; + color: @input-accessory-color; + right: @padding-base-horizontal; display: none; - padding: 17px 19px; - line-height: 20px - right: 0; } } } diff --git a/internal_packages/sidebar-fullcontact/lib/main.cjsx b/internal_packages/sidebar-fullcontact/lib/main.cjsx index 49f853ae1..10543ed41 100644 --- a/internal_packages/sidebar-fullcontact/lib/main.cjsx +++ b/internal_packages/sidebar-fullcontact/lib/main.cjsx @@ -1,29 +1,17 @@ _ = require 'underscore-plus' React = require "react" SidebarFullContact = require "./sidebar-fullcontact.cjsx" - {ComponentRegistry} = require("inbox-exports") module.exports = item: null activate: (@state={}) -> - unless @item? - @item = document.createElement("div") - @item.setAttribute("id", "sidebar-fullcontact") - @item.setAttribute("class", "sidebar-fullcontact") - - atom.workspace.addColumnItem(@item, "message-and-composer") - - ComponentRegistry.register - name: 'SidebarFullContact' - view: SidebarFullContact - - React.render(, @item) + ComponentRegistry.register + name: 'SidebarFullContact' + view: SidebarFullContact deactivate: -> - React.unmountComponentAtNode(@item) - @item.remove() - @item = null + ComponentRegistry.unregister('SidebarFullContact') serialize: -> @state diff --git a/keymaps/base.cson b/keymaps/base.cson index 665862d28..1116bccbd 100644 --- a/keymaps/base.cson +++ b/keymaps/base.cson @@ -1,42 +1,24 @@ # Email-specific core key-mappings -# All platforms are put here to consolidate custom actions and to prevent -# duplication in 3 files. # -# TODO let the user pick whether they want to use Gmail, Mac Mail, or -# Outlook keymappings +# There are additional mappings in .cson files that bind +# menu items. In the future, we should break these into files like: +# darwin-gmail.cson, darwin-macmail.cson, win32-gmail.cson... + 'body': - 'c' : 'application:new-message' # Gmail - 'cmd-n' : 'application:new-message' # Mac mail - 'ctrl-n': 'application:new-message' # Outlook - - 'k' : 'application:previous-message' # Gmail - 'up': 'application:previous-message' # Mac mail - - 'j' : 'application:next-message' # Gmail - 'down': 'application:next-message' # Mac mail - + 'c' : 'application:new-message' # Gmail + 'k' : 'application:previous-message' # Gmail + 'up' : 'application:previous-message' # Mac mail + 'j' : 'application:next-message' # Gmail + 'down' : 'application:next-message' # Mac mail ']' : 'application:archive-and-previous' # Gmail - '[' : 'application:archive-thread' # Gmail 'e' : 'application:archive-thread' # Gmail 'delete' : 'application:archive-thread' # Mac mail 'backspace': 'application:archive-thread' # Outlook 'r' : 'application:reply' # Gmail - 'cmd-r' : 'application:reply' # Mac mail - 'ctrl-r': 'application:reply' # Outlook - 'a' : 'application:reply-all' # Gmail - 'cmd-R' : 'application:reply-all' # Mac mail - 'ctrl-R': 'application:reply-all' # Outlook - 'f' : 'application:forward' # Gmail - 'cmd-F' : 'application:forward' # Mac mail - 'ctrl-F': 'application:forward' # Outlook - - 'cmd-alt-f': 'application:focus-search' # Mac mail - - 'cmd-D': 'application:send-message' # Mac mail # Default cross-platform core behaviors 'left': 'core:move-left' @@ -53,7 +35,8 @@ 'shift-delete': 'core:cut' # Inputs are native by default. -'body input, body textarea, body *[contenteditable]': +# Also make sure not to catch anything intended for a webview +'body input, body textarea, body *[contenteditable], body webview': 'up': 'native!' 'left': 'native!' 'down': 'native!' @@ -79,8 +62,6 @@ 'cmd-enter': 'native!' 'ctrl-enter': 'native!' 'shift-enter': 'native!' - 'tab': 'core:focus-next' - 'shift-tab': 'core:focus-previous' 'backspace': 'native!' 'shift-backspace': 'native!' 'delete': 'native!' @@ -207,6 +188,16 @@ '?': 'native!' '/': 'native!' +'body input, body textarea, body *[contenteditable]': + 'tab': 'core:focus-next' + 'shift-tab': 'core:focus-previous' + +'body webview': + 'tab': 'native!' + 'shift-tab': 'native!' + + + # For menus 'body .menu, body .menu, body .menu input': 'up': 'menu:move-up' diff --git a/keymaps/darwin.cson b/keymaps/darwin.cson index 151626c0e..e331d8f50 100644 --- a/keymaps/darwin.cson +++ b/keymaps/darwin.cson @@ -1,8 +1,16 @@ # Note: For a menu item to have a keyboard equiavalent, it needs # to be listed in this file. -# Mac application keys 'body': + # Mac email-specific menu items + 'cmd-n' : 'application:new-message' # Mac mail + 'cmd-r' : 'application:reply' # Mac mail + 'cmd-R' : 'application:reply-all' # Mac mail + 'cmd-F' : 'application:forward' # Mac mail + 'cmd-alt-f': 'application:focus-search' # Mac mail + 'cmd-D': 'application:send-message' # Mac mail + + # Mac application keys 'cmd-q': 'application:quit' 'cmd-h': 'application:hide' 'cmd-1': 'application:show-main-window' @@ -11,7 +19,7 @@ 'alt-cmd-ctrl-m': 'application:zoom' 'cmd-alt-ctrl-s': 'application:run-all-specs' -# Mac core keys + # Mac core keys 'cmd-z': 'core:undo' 'cmd-Z': 'core:redo' 'cmd-y': 'core:redo' @@ -20,7 +28,7 @@ 'cmd-a': 'core:select-all' 'cmd-v': 'core:paste' -# Mac window keys + # Mac window keys 'cmd-w': 'window:close' 'cmd-=': 'window:increase-font-size' 'cmd-+': 'window:increase-font-size' diff --git a/keymaps/linux.cson b/keymaps/linux.cson index a27d6af27..9b233c040 100644 --- a/keymaps/linux.cson +++ b/keymaps/linux.cson @@ -1,12 +1,18 @@ # Note: For a menu item to have a keyboard equiavalent, it needs # to be listed in this file. -# Linux application keys +# Linux email-specific menu items 'body': + 'ctrl-n': 'application:new-message' # Outlook + 'ctrl-r': 'application:reply' # Outlook + 'ctrl-R': 'application:reply-all' # Outlook + 'ctrl-F': 'application:forward' # Outlook + + # Linux application keys 'ctrl-q': 'application:quit' 'ctrl-alt-s': 'application:run-all-specs' -# Linux core keys + # Linux core keys 'ctrl-z': 'core:undo' 'ctrl-Z': 'core:redo' 'ctrl-y': 'core:redo' @@ -17,7 +23,7 @@ 'ctrl-insert': 'core:copy' 'shift-insert': 'core:paste' -# Linux window keys + # Linux window keys 'ctrl-w': 'core:close' 'ctrl-=': 'window:increase-font-size' 'ctrl-+': 'window:increase-font-size' diff --git a/keymaps/win32.cson b/keymaps/win32.cson index 9e661999e..a286ca691 100644 --- a/keymaps/win32.cson +++ b/keymaps/win32.cson @@ -1,8 +1,14 @@ # Note: For a menu item to have a keyboard equiavalent, it needs # to be listed in this file. -# Windows application keys 'body': + # Windows email-specific menu items + 'ctrl-n': 'application:new-message' # Outlook + 'ctrl-r': 'application:reply' # Outlook + 'ctrl-R': 'application:reply-all' # Outlook + 'ctrl-F': 'application:forward' # Outlook + + # Windows application keys 'ctrl-q': 'application:quit' 'ctrl-alt-s': 'application:run-all-specs' diff --git a/package.json b/package.json index 2a80e8e5c..efde07a79 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,6 @@ }, "private": true, "scripts": { - "preinstall": "node -e 'process.exit(0)'", - "postinstall": "(cd internal_packages/composer; npm install)" + "preinstall": "node -e 'process.exit(0)'" } } diff --git a/resources/win/edgehill.ico b/resources/win/edgehill.ico index f0bfbd3ef..3c8a332ae 100644 Binary files a/resources/win/edgehill.ico and b/resources/win/edgehill.ico differ diff --git a/resources/win/loading.gif b/resources/win/loading.gif index 11fd6cb12..ddaa01005 100644 Binary files a/resources/win/loading.gif and b/resources/win/loading.gif differ diff --git a/resources/win/loading.png b/resources/win/loading.png new file mode 100644 index 000000000..649fa71d5 Binary files /dev/null and b/resources/win/loading.png differ diff --git a/script/bootstrap b/script/bootstrap index f33129b9f..72ebbc69d 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -124,7 +124,7 @@ function bootstrap() { options: semverOptions }, { - command: 'build/node_modules/.bin/grunt download-atom-shell --gruntfile build/Gruntfile.coffee', + command: 'grunt download-atom-shell --gruntfile ./build/Gruntfile.coffee', message: m7 } ]; diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 084b6c1fb..0735dc4a0 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -14,7 +14,6 @@ KeymapManager = require '../src/keymap-extensions' {$} = require '../src/space-pen-extensions' Config = require '../src/config' -Workspace = require '../src/workspace-edgehill' ServiceHub = require 'service-hub' pathwatcher = require 'pathwatcher' clipboard = require 'clipboard' @@ -97,12 +96,10 @@ beforeEach -> $.fx.off = true documentTitle = null - atom.workspace = new Workspace() atom.packages.serviceHub = new ServiceHub atom.keymaps.keyBindings = _.clone(keyBindingsToRestore) atom.commands.restoreSnapshot(commandsToRestore) atom.styles.restoreSnapshot(styleElementsToRestore) - atom.workspaceViewParentSelector = '#jasmine-content' window.resetTimeouts() @@ -164,10 +161,6 @@ afterEach -> atom.menu.template = [] atom.contextMenu.clear() - atom.workspace?.destroy() - atom.workspace = null - delete atom.state.workspace - atom.themes.removeStylesheet('global-editor-styles') delete atom.state.packageStates diff --git a/src/atom.coffee b/src/atom.coffee index 70c78b038..033f668b2 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -210,6 +210,14 @@ class Atom extends Model @keymaps = new KeymapManager({configDirPath, resourcePath}) @keymaps.subscribeToFileReadFailure() + @keymaps.onDidMatchBinding (event) -> + # If the user fired a command with the application: prefix bound to the body, re-fire it + # up into the browser process. This prevents us from needing this crap, which has to be + # updated every time a new application: command is added: + # https://github.com/atom/atom/blob/master/src/workspace-element.coffee#L119 + if event.binding.command.indexOf('application:') is 0 and event.binding.selector is "body" + ipc.send('command', event.binding.command) + @tooltips = new TooltipManager @notifications = new NotificationManager @commands = new CommandRegistry @@ -357,6 +365,9 @@ class Atom extends Model isReleasedVersion: -> not /\w{7}/.test(@getVersion()) # Check if the release is a 7-character SHA prefix + isLoggedIn: -> + atom.config.get('inbox.token') + # Public: Get the directory path to Atom's configuration area. # # Returns the absolute path to `~/.atom`. @@ -509,6 +520,7 @@ class Atom extends Model width > 0 and height > 0 and x + width > 0 and y + height > 0 storeDefaultWindowDimensions: -> + return unless @mode is 'editor' dimensions = @getWindowDimensions() if @isValidDimensions(dimensions) localStorage.setItem("defaultWindowDimensions", JSON.stringify(dimensions)) @@ -564,17 +576,17 @@ class Atom extends Model @requireUserInitScript() unless safeMode @menu.update() + @commands.add 'atom-workspace', + 'atom-workspace:add-account': => + @displayOnboardingWindow('add-account') + 'atom-workspace:logout': => + @logout() if @isLoggedIn() + ipc.on 'onboarding-complete', => maximize = dimensions?.maximized and process.platform isnt 'darwin' @displayWindow({maximize}) - @commands.add 'atom-workspace', - 'atom-workspace:logout': => @logout() - - @commands.add 'atom-workspace', - 'atom-workspace:add-account': => @displayOnboardingWindow('add-account') - - if atom.config.get('inbox.token') + if @isLoggedIn() maximize = dimensions?.maximized and process.platform isnt 'darwin' @displayWindow({maximize}) else @@ -583,24 +595,22 @@ class Atom extends Model # Call this method when establishing a secondary application window # displaying a specific set of packages. startSecondaryWindow: (packages = []) -> - {resourcePath, safeMode} = @getLoadSettings() + {resourcePath, safeMode, width, height} = @getLoadSettings() @loadConfig() @inbox.APIToken = atom.config.get('inbox.token') @keymaps.loadBundledKeymaps() @themes.loadBaseStylesheets() - - Workspace = require './workspace-edgehill' - Actions = require './flux/actions' - - @workspace = new Workspace + @keymaps.loadUserKeymap() for pack in packages @packages.loadPackage(pack) @packages.activate() @keymaps.loadUserKeymap() + @setWindowDimensions({width, height}) if width and height + @menu.update() @subscribe @config.onDidChange 'core.autoHideMenuBar', ({newValue}) => @setAutoHideMenuBar(newValue) @@ -621,20 +631,20 @@ class Atom extends Model title: 'Welcome to Edgehill' frame: false page: page + width: 340 + height: 475 + resizable: false windowName: 'onboarding' windowPackages: ['onboarding'] ipc.send('show-secondary-window', options) unloadEditorWindow: -> - @state.edgehillWorkspace = @workspace.serialize() @packages.deactivatePackages() @state.packageStates = @packages.packageStates @saveSync() @windowState = null removeEditorWindow: -> - @workspace?.destroy() - @workspace = null @windowEventHandler?.unsubscribe() ### @@ -715,19 +725,16 @@ class Atom extends Model ### deserializeWorkspaceView: -> - # Put state back into store startTime = Date.now() - Workspace = require './workspace-edgehill' - #@workspace = Workspace.deserialize(@state.edgehillWorkspace) ? new Workspace - @workspace = new Workspace + # Put state back into sheet-container? Restore app state here @deserializeTimings.workspace = Date.now() - startTime - SheetContainer = require './sheet-container' - @item = document.createElement("div") + @item = document.createElement("atom-workspace") @item.setAttribute("id", "sheet-container") @item.setAttribute("class", "sheet-container") React = require "react" + SheetContainer = require './sheet-container' React.render(React.createElement(SheetContainer), @item) document.querySelector(@workspaceViewParentSelector).appendChild(@item) diff --git a/src/browser/atom-window.coffee b/src/browser/atom-window.coffee index a16fd5b73..98469b689 100644 --- a/src/browser/atom-window.coffee +++ b/src/browser/atom-window.coffee @@ -18,7 +18,7 @@ class AtomWindow isSpec: null constructor: (settings={}) -> - {@resourcePath, pathToOpen, initialLine, initialColumn, @neverClose, @isSpec, @exitWhenDone, @safeMode, @devMode, frame, title} = settings + {@resourcePath, pathToOpen, initialLine, initialColumn, @neverClose, @isSpec, @exitWhenDone, @safeMode, @devMode, frame, title, resizable} = settings # Normalize to make sure drive letter case is consistent on Windows @resourcePath = path.normalize(@resourcePath) if @resourcePath @@ -27,10 +27,12 @@ class AtomWindow show: false title: title ? 'Edgehill' frame: frame ? true + resizable: resizable ? true icon: @constructor.iconPath 'web-preferences': 'direct-write': true 'subpixel-font-scaling': false + # Don't set icon on Windows so the exe's ico will be used as window and # taskbar's icon. See https://github.com/atom/atom/issues/4811 for more. if process.platform is 'linux' diff --git a/src/components/flexbox.cjsx b/src/components/flexbox.cjsx index f0d1c32be..af1b55202 100644 --- a/src/components/flexbox.cjsx +++ b/src/components/flexbox.cjsx @@ -13,6 +13,7 @@ Flexbox = React.createClass render: -> style = _.extend (@props.style || {}), 'flexDirection': @props.direction, + 'position':'relative' 'display': 'flex' 'height':'100%' diff --git a/src/flux/edgehill-api.coffee b/src/flux/edgehill-api.coffee index 7e2847bf8..810da17ec 100644 --- a/src/flux/edgehill-api.coffee +++ b/src/flux/edgehill-api.coffee @@ -8,12 +8,12 @@ async = require 'async' class EdgehillAPI constructor: -> - atom.config.onDidChange('inbox.env', @_onConfigChanged) + atom.config.onDidChange('env', @_onConfigChanged) @_onConfigChanged() @ _onConfigChanged: => - env = atom.config.get('inbox.env') + env = atom.config.get('env') if env is 'development' @APIRoot = "https://edgehill-dev.nilas.com" else if env is 'staging' @@ -44,49 +44,17 @@ class EdgehillAPI else options.success(body) if options.success - createAccount: ({first_name, last_name, username, password}, callback) -> - new Promise (resolve, reject) => - @request - path: '/users' - method: 'POST' - body: - first_name: first_name - last_name: last_name - username: username - password: password - success: => - @setCredentials - username: username - password: password - resolve() - error: (err) -> - reject(err.message) - - signIn: ({username, password}) -> - @setCredentials - username: username - password: password - new Promise (resolve, reject) => - @request - path: '/users/me' - method: 'GET' - success: (userJson) => - @addTokens(userJson.tokens) - resolve(userJson) - error: (err) => - @setCredentials(null) - reject(err.message) - urlForConnecting: (provider, email_address = '') -> auth = @getCredentials() - root = @APIRoot.replace('://', "://#{auth.username}:#{auth.password}@") + root = @APIRoot + root = root.replace('://', "://#{auth.username}:#{auth.password}@") if auth "#{root}/connect/#{provider}?login_hint=#{email_address}" getCredentials: -> - atom.config.get('inbox.account') + atom.config.get('edgehill.credentials') setCredentials: (credentials) -> - atom.config.set('inbox.account', credentials) + atom.config.set('edgehill.credentials', credentials) addTokens: (tokens) -> for token in tokens @@ -94,7 +62,10 @@ class EdgehillAPI atom.config.set('inbox.token', token.access_token) if token.provider is 'salesforce' atom.config.set('salesforce.token', token.access_token) - + + if token.user_identifier? + @setCredentials({username: token.user_identifier, password: ''}) + tokenForProvider: (provider) -> atom.config.get("#{provider}.token") diff --git a/src/flux/inbox-api.coffee b/src/flux/inbox-api.coffee index 6ac965a0e..84a67a1df 100644 --- a/src/flux/inbox-api.coffee +++ b/src/flux/inbox-api.coffee @@ -12,7 +12,7 @@ class InboxAPI constructor: -> @_streamingConnections = [] - atom.config.onDidChange('inbox.env', @_onConfigChanged) + atom.config.onDidChange('env', @_onConfigChanged) atom.config.onDidChange('inbox.token', @_onConfigChanged) @_onConfigChanged() @@ -24,7 +24,7 @@ class InboxAPI prev = {@APIToken, @AppID, @APIRoot} @APIToken = atom.config.get('inbox.token') - env = atom.config.get('inbox.env') + env = atom.config.get('env') if env in ['production'] @AppID = 'c96gge1jo29pl2rebcb7utsbp' @APIRoot = 'https://api.nilas.com' @@ -83,7 +83,7 @@ class InboxAPI ## TODO use OfflineStatusStore Actions.longPollOffline() - connection.onDeltas (deltas) => + connection.onDeltas (deltas) -> # TODO DO NOT FORGET TO UNCOMMENT ME # @_handleDeltas(deltas) diff --git a/src/flux/inbox-long-connection.coffee b/src/flux/inbox-long-connection.coffee index 8a3d3ad36..b5eed414f 100644 --- a/src/flux/inbox-long-connection.coffee +++ b/src/flux/inbox-long-connection.coffee @@ -86,11 +86,10 @@ class InboxLongConnection @_buffer = bufferJSONs[bufferJSONs.length - 1] start: -> + return if not @_inbox.APIToken? return if @_state is InboxLongConnection.State.Ended return if @_req - throw (new Error 'Cannot start polling without auth token.') unless @_inbox.APIToken - console.log("Long Polling Connection: Starting....") @withCursor (cursor) => return if @state is InboxLongConnection.State.Ended diff --git a/src/flux/models/utils.coffee b/src/flux/models/utils.coffee index 09945dcc6..e879c378c 100644 --- a/src/flux/models/utils.coffee +++ b/src/flux/models/utils.coffee @@ -81,10 +81,15 @@ Utils = [name, ext] = fullname.split('.') if Utils.images is undefined + start = Date.now() + {resourcePath} = atom.getLoadSettings() + imagesPath = path.join(resourcePath, 'static', 'images') + files = fs.listTreeSync(imagesPath) + Utils.images = {} files = fs.listTreeSync('./static/images') - for file in files - Utils.images[path.basename(file)] = file.substr(7) + Utils.images[path.basename(file)] = file for file in files + # console.log("Loaded image map in #{Date.now()-start}msec") if window.devicePixelRatio > 1 return Utils.images["#{name}@2x.#{ext}"] ? Utils.images[fullname] ? Utils.images["#{name}@1x.#{ext}"] diff --git a/src/theme-manager.coffee b/src/theme-manager.coffee index f9c8f6f4a..4389ab7b3 100644 --- a/src/theme-manager.coffee +++ b/src/theme-manager.coffee @@ -370,13 +370,15 @@ class ThemeManager isInitialLoadComplete: -> @initialLoadComplete addActiveThemeClasses: -> - workspaceElement = atom.views.getView(atom.workspace) + workspaceElement = document.getElementsByTagName('atom-workspace')[0] + return unless workspaceElement for pack in @getActiveThemes() workspaceElement.classList.add("theme-#{pack.name}") return removeActiveThemeClasses: -> - workspaceElement = atom.views.getView(atom.workspace) + workspaceElement = document.getElementsByTagName('atom-workspace')[0] + return unless workspaceElement for pack in @getActiveThemes() workspaceElement.classList.remove("theme-#{pack.name}") return diff --git a/src/workspace-edgehill.coffee b/src/workspace-edgehill.coffee deleted file mode 100644 index 905066b48..000000000 --- a/src/workspace-edgehill.coffee +++ /dev/null @@ -1,61 +0,0 @@ -_ = require 'underscore-plus' -{Model} = require 'theorist' -Q = require 'q' -Serializable = require 'serializable' -{Emitter, Disposable, CompositeDisposable} = require 'event-kit' -WorkspaceElement = require './workspace-element-edgehill' - -# Essential: Represents the state of the user interface for the entire window. -# An instance of this class is available via the `atom.workspace` global. -# -# Interact with this object to open files, be notified of current and future -# editors, and manipulate panes. To add panels, you'll need to use the -# {WorkspaceView} class for now until we establish APIs at the model layer. -# -# * `editor` {TextEditor} the new editor -# -module.exports = -class Workspace extends Model - atom.deserializers.add(this) - Serializable.includeInto(this) - - @properties - fullScreen: false - - constructor: (params) -> - super - @emitter = new Emitter - - atom.views.addViewProvider - modelConstructor: Workspace - viewConstructor: WorkspaceElement - - # Called by the Serializable mixin during deserialization - deserializeParams: (params) -> - for packageName in params.packagesWithActiveGrammars ? [] - atom.packages.getLoadedPackage(packageName)?.loadGrammarsSync() - params - - # Called by the Serializable mixin during serialization. - serializeParams: -> - fullScreen: atom.isFullScreen() - - # Updates the application's title and proxy icon based on whichever file is - # open. - updateWindowTitle: -> - ## TODO we might want to put the unread count here in the future. - document.title = "Edgehill" - atom.setRepresentedFilename("Edgehill") - - confirmClose: -> - true - - # A no-op in Edgehill Workspace - open: -> - - # Appending Children to the Workspace - # ---- - - addColumnItem: (item, columnId="") -> - - addRow: (item) -> diff --git a/src/workspace-element-edgehill.coffee b/src/workspace-element-edgehill.coffee deleted file mode 100644 index 82cd4bac4..000000000 --- a/src/workspace-element-edgehill.coffee +++ /dev/null @@ -1,73 +0,0 @@ -ipc = require 'ipc' -path = require 'path' -{Disposable, CompositeDisposable} = require 'event-kit' -Grim = require 'grim' -scrollbarStyle = require 'scrollbar-style' -{callAttachHooks} = require 'space-pen' - -module.exports = -class WorkspaceElement extends HTMLElement - - createdCallback: -> - @subscriptions = new CompositeDisposable - @initializeContent() - @observeScrollbarStyle() - - attachedCallback: -> - callAttachHooks(this) - @focus() - - detachedCallback: -> - @subscriptions.dispose() - @model.destroy() - - initializeContent: -> - @classList.add 'workspace' - @setAttribute 'tabindex', -1 - - @horizontalAxis = document.createElement('atom-workspace-axis') - @horizontalAxis.classList.add('horizontal') - - @horizontalContainer = document.createElement('div') - @horizontalContainer.classList.add('atom-workspace-axis-container') - @horizontalContainer.appendChild(@horizontalAxis) - - @verticalAxis = document.createElement('atom-workspace-axis') - @verticalAxis.classList.add('vertical') - @verticalAxis.appendChild(@horizontalContainer) - - @appendChild(@verticalAxis) - - observeScrollbarStyle: -> - @subscriptions.add scrollbarStyle.onValue (style) => - switch style - when 'legacy' - @classList.remove('scrollbars-visible-when-scrolling') - @classList.add("scrollbars-visible-always") - when 'overlay' - @classList.remove('scrollbars-visible-always') - @classList.add("scrollbars-visible-when-scrolling") - - getModel: -> - @model - - setModel: (@model) -> - -atom.commands.add 'atom-workspace', - 'application:show-main-window': -> ipc.send('command', 'application:show-main-window') - 'application:new-message': -> ipc.send('command', 'application:new-message') - 'application:about': -> ipc.send('command', 'application:about') - 'application:run-all-specs': -> ipc.send('command', 'application:run-all-specs') - 'application:run-benchmarks': -> ipc.send('command', 'application:run-benchmarks') - 'application:show-settings': -> ipc.send('command', 'application:show-settings') - 'application:quit': -> ipc.send('command', 'application:quit') - 'application:hide': -> ipc.send('command', 'application:hide') - 'application:hide-other-applications': -> ipc.send('command', 'application:hide-other-applications') - 'application:install-update': -> ipc.send('command', 'application:install-update') - 'application:unhide-all-applications': -> ipc.send('command', 'application:unhide-all-applications') - 'application:minimize': -> ipc.send('command', 'application:minimize') - 'application:zoom': -> ipc.send('command', 'application:zoom') - 'application:bring-all-windows-to-front': -> ipc.send('command', 'application:bring-all-windows-to-front') - 'window:run-package-specs': -> ipc.send('run-package-specs', path.join(atom.project.getPath(), 'spec')) - -module.exports = WorkspaceElement = document.registerElement 'atom-workspace', prototype: WorkspaceElement.prototype diff --git a/static/buttons.less b/static/buttons.less index a4301d1c0..e5113e327 100644 --- a/static/buttons.less +++ b/static/buttons.less @@ -1,3 +1,6 @@ +@import "ui-variables"; +@import "ui-mixins"; + // .btn-background (@color, @hover-color, @selected-color, @border-color, @text-color, @text-color-hover) { // @border-shadow: inset 0 0 0 1px @border-color; // @active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); @@ -50,22 +53,18 @@ // // .btn { - border: 0; padding: 0.33em 1em; border-radius: @border-radius-base; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.21); height: auto; line-height: 1; - box-shadow: 0 1px 4px rgba(0, 0, 0, 0.21); - &:hover { - cursor: pointer; - box-shadow: 0 1px 6px rgba(0, 0, 0, 0.25); - } &:active { cursor: pointer; - box-shadow: 0 0 1px rgba(0, 0, 0, 0.21); + background-color: darken(@btn-default-bg-color, 9%); + box-shadow: 0 -1px 1px rgba(0, 0, 0, 0.21); } &:focus { outline: none @@ -80,9 +79,11 @@ } &.btn-large { font-size: @font-size-large; + padding: 0.5em 1.3em; } &.btn-larger { font-size: @font-size-larger; + padding: 0.66em 1.6em; } color: @btn-default-text-color; @@ -101,35 +102,42 @@ } } -// .btn-icon { -// background: transparent; -// border: 0; -// color: @text-color-subtle; -// margin-right: 10px; -// outline: none !important; -// font-size: 20px; -// -// &:last-child { -// margin-right: 0; -// } -// -// &.inverse { -// color: @text-color-inverse; -// -// &:hover { -// color: white; -// } -// -// &:active { -// color: @text-color-inverse; -// } -// } -// -// &:hover { -// cursor: pointer; -// color: @text-color-link; -// } -// &:active { -// color: darken(@text-color-link, 5%); -// } -// } +.btn-gradient { + background: -webkit-gradient(linear, left top, left bottom, from(@btn-default-bg-color), to(darken(@btn-default-bg-color, 4.5%))); +} +.btn-gradient:active { + background: -webkit-gradient(linear, left top, left bottom, from(darken(@btn-default-bg-color, 9%)), to(darken(@btn-default-bg-color, 13.5%))); +} + +.btn-icon { + background: transparent; + border: 0; + color: @text-color-subtle; + margin-right: 10px; + outline: none !important; + font-size: 20px; + + &:last-child { + margin-right: 0; + } + + &.inverse { + color: @text-color-inverse; + + &:hover { + color: white; + } + + &:active { + color: @text-color-inverse; + } + } + + &:hover { + cursor: pointer; + color: @text-color-link; + } + &:active { + color: @text-color-link-active; + } +} diff --git a/static/components/tokenizing-text-field.less b/static/components/tokenizing-text-field.less index 9a8bd9b2b..fab9df3d0 100644 --- a/static/components/tokenizing-text-field.less +++ b/static/components/tokenizing-text-field.less @@ -72,6 +72,9 @@ min-width: 5em; background-color:transparent; } + input:focus { + box-shadow: none; + } } } diff --git a/static/images/onboarding/onboarding-back@2x.png b/static/images/onboarding/onboarding-back@2x.png new file mode 100644 index 000000000..0e504bb9e Binary files /dev/null and b/static/images/onboarding/onboarding-back@2x.png differ diff --git a/static/images/onboarding/onboarding-close@2x.png b/static/images/onboarding/onboarding-close@2x.png new file mode 100644 index 000000000..119c2cd1a Binary files /dev/null and b/static/images/onboarding/onboarding-close@2x.png differ diff --git a/static/images/onboarding/onboarding-divider@2x.png b/static/images/onboarding/onboarding-divider@2x.png new file mode 100644 index 000000000..3acf36e43 Binary files /dev/null and b/static/images/onboarding/onboarding-divider@2x.png differ diff --git a/static/images/onboarding/onboarding-logo@2x.png b/static/images/onboarding/onboarding-logo@2x.png new file mode 100644 index 000000000..5eca2fffb Binary files /dev/null and b/static/images/onboarding/onboarding-logo@2x.png differ diff --git a/static/inputs.less b/static/inputs.less index 41260aff5..2b6847271 100644 --- a/static/inputs.less +++ b/static/inputs.less @@ -1,10 +1,23 @@ -input[type="text"] { +@import "ui-variables"; +@import "ui-mixins"; + +input[type="text"], +input[type="email"] { width: 100%; padding-left: @padding-xs-horizontal; padding-right: @padding-xs-horizontal; font-size: @font-size-base; line-height: @line-height-computed; - border-radius: @border-radius-base; - border: 1px solid @input-border; font-weight:400; + + &.input-bordered { + border-radius: @border-radius-base; + border: 1px solid @input-border; + } } +input[type="text"]:focus, +input[type="email"]:focus, { + &.input-bordered { + box-shadow: 0 0 3px @accent-primary; + } +} \ No newline at end of file diff --git a/static/mixins/common-ui-elements.less b/static/mixins/common-ui-elements.less index b92247071..97f95dfec 100644 --- a/static/mixins/common-ui-elements.less +++ b/static/mixins/common-ui-elements.less @@ -1,3 +1,5 @@ +@import "ui-variables"; + // A Mixin holding common UI elements. // A box to hold counts of things (like number of items in a tag, or diff --git a/static/normalize.less b/static/normalize.less index c5e8b95bc..869336bbb 100644 --- a/static/normalize.less +++ b/static/normalize.less @@ -94,12 +94,6 @@ audio:not([controls]) { height: 0; } -// * Address `[hidden]` styling not present in IE 8/9/10. -// * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. -[hidden], -template { - display: none; -} // Links ========================================================================== // * Remove the gray background color from active links in IE 10. diff --git a/static/type.less b/static/type.less index 6001cd2e8..c3c0df58d 100644 --- a/static/type.less +++ b/static/type.less @@ -1,3 +1,6 @@ +@import "ui-variables"; +@import "ui-mixins"; + // // Typography // -------------------------------------------------- diff --git a/static/utilities.less b/static/utilities.less index 8ae28184f..49fff3f96 100644 --- a/static/utilities.less +++ b/static/utilities.less @@ -1,3 +1,6 @@ +@import "ui-variables"; +@import "ui-mixins"; + :focus { outline: none; } diff --git a/static/variables/ui-variables.less b/static/variables/ui-variables.less index 3d19cee1b..4635d34a4 100644 --- a/static/variables/ui-variables.less +++ b/static/variables/ui-variables.less @@ -1,4 +1,4 @@ -// Color abstraction heirarcy: +// Color abstraction hierarchy: // 1. Hex code (#428bca) // 2. Common color name (@blue) // 3. Generic color descriptor (@accent-primary, @background-primary) @@ -6,7 +6,7 @@ // 4. Generic usage descriptor (@input-background, @button-background) // 5. Application-specific usage (@unread-label-background) -// Typography abstraction heirarcy +// Typography abstraction hierarchy // 1. Font-face (FaktPro) // 2. Common name (@bold, @italic) // 3. Generic font descriptor mixins (.bold, .italic, .h1, .h2) @@ -386,6 +386,10 @@ ///// +// ------------- +// EVERYTHING BELOW THIS NEEDS TO BE DEPRECATED OR MOVED ABOVE THIS +// old stuff +// ------------- // Private // diff --git a/static/workspace.less b/static/workspace.less index 9aaae5472..122c95f29 100644 --- a/static/workspace.less +++ b/static/workspace.less @@ -1,3 +1,6 @@ +@import "ui-variables"; +@import "ui-mixins"; + html, body { width: 100%; @@ -100,7 +103,7 @@ atom-workspace { padding-right:3px; } &.flexbox-handle-bottom { - bottom: 0px; + bottom: 0; padding-right:2px; } }