mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-11-12 12:40:08 +08:00
351a602b86
- Creates OutlineView generic component and uses that instead of custom code - Refactors AccountSidebarStore: - Split the generation of the state tree into smaller functions - Adds different types of account sidebar items and sections, which contain logic and props necessary to be rendered as OutlineViewItems, and removes that logic from the store - Removes WorkspaceStore.SidebarItem and removes the ability to register new sidebar items. If people want to add something to the sidebar they can just register a Component via the component registry and use the OutlineView component - Removes the DraftListSidebarItem, which was basically duplicated code for an item but with a different data source. This is now handled generically by the account sidebar by rendering OutlineViewItems with different props and handlers - Clean ups here and there: - TODO - Add AccountSwitcher - Revisit calculation and generation of the state tree. Should the parent store contain and update the entire state all the time. Should separate items inside the tree have their own data sources? - This would avoid having the AccountSidebarStore listen to a bunch of different other stores, and the specific logic wold be contained inside each item type.
134 lines
4 KiB
CoffeeScript
134 lines
4 KiB
CoffeeScript
React = require 'react'
|
|
AccountSidebarStore = require './account-sidebar-store'
|
|
{Actions, AccountStore} = require("nylas-exports")
|
|
{RetinaImg} = require 'nylas-component-kit'
|
|
crypto = require 'crypto'
|
|
classNames = require 'classnames'
|
|
|
|
class AccountSwitcher extends React.Component
|
|
@displayName: 'AccountSwitcher'
|
|
|
|
@containerRequired: false
|
|
@containerStyles:
|
|
minWidth: 165
|
|
maxWidth: 210
|
|
|
|
constructor: (@props) ->
|
|
@state = @_getStateFromStores()
|
|
@state.showing = false
|
|
|
|
componentDidMount: =>
|
|
@unsubscribers = []
|
|
@unsubscribers.push AccountStore.listen @_onStoreChange
|
|
|
|
componentWillUnmount: =>
|
|
unsubscribe() for unsubscribe in @unsubscribers
|
|
|
|
render: =>
|
|
return false unless @state.account
|
|
|
|
classnames = ""
|
|
classnames += "open" if @state.showing
|
|
|
|
<div id="account-switcher"
|
|
tabIndex={-1}
|
|
onBlur={@_onBlur}
|
|
ref="button"
|
|
className={classnames}>
|
|
{@_renderPrimaryItem()}
|
|
{@_renderDropdown()}
|
|
</div>
|
|
|
|
_renderPrimaryItem: =>
|
|
label = @state.account.label.trim()
|
|
<div className="item primary-item" onClick={@_toggleDropdown}>
|
|
{@_renderGravatarForAccount(@state.account)}
|
|
<div style={float: 'right', marginTop: -2}>
|
|
<RetinaImg className="toggle"
|
|
name="account-switcher-dropdown.png"
|
|
mode={RetinaImg.Mode.ContentDark} />
|
|
</div>
|
|
<div className="name" style={lineHeight: "110%"}>
|
|
{label}
|
|
</div>
|
|
<div style={clear: "both"}></div>
|
|
</div>
|
|
|
|
_renderAccount: (account) =>
|
|
email = account.emailAddress.trim().toLowerCase()
|
|
label = account.label.trim()
|
|
classes = classNames
|
|
"active": account is @state.account
|
|
"item": true
|
|
"secondary-item": true
|
|
|
|
<div className={classes} onClick={ => @_onSwitchAccount(account)} key={email}>
|
|
{@_renderGravatarForAccount(account)}
|
|
<div className="name" style={lineHeight: "110%"}>{label}</div>
|
|
<div style={clear: "both"}></div>
|
|
</div>
|
|
|
|
_renderNewAccountOption: =>
|
|
<div className="item secondary-item new-account-option"
|
|
onClick={@_onManageAccounts}
|
|
tabIndex={999}>
|
|
<div style={float: 'left'}>
|
|
<RetinaImg name="icon-accounts-addnew.png"
|
|
fallback="ic-settings-account-imap.png"
|
|
mode={RetinaImg.Mode.ContentPreserve}
|
|
style={width: 28, height: 28, marginTop: -10} />
|
|
</div>
|
|
<div className="name" style={lineHeight: "110%", textTransform: 'none'}>
|
|
Manage accounts…
|
|
</div>
|
|
<div style={clear: "both"}></div>
|
|
</div>
|
|
|
|
_renderDropdown: =>
|
|
<div className="dropdown">
|
|
<div className="inner">
|
|
{@state.accounts.map(@_renderAccount)}
|
|
{@_renderNewAccountOption()}
|
|
</div>
|
|
</div>
|
|
|
|
_renderGravatarForAccount: (account) =>
|
|
email = account.emailAddress.trim().toLowerCase()
|
|
hash = crypto.createHash('md5').update(email, 'utf8').digest('hex')
|
|
url = "url(http://www.gravatar.com/avatar/#{hash}?d=blank&s=56)"
|
|
|
|
<div style={float: 'left', position: "relative"}>
|
|
<div className="gravatar" style={backgroundImage:url}></div>
|
|
<RetinaImg name={"ic-settings-account-#{account.provider}@2x.png"}
|
|
style={width: 28, height: 28, marginTop: -10}
|
|
fallback="ic-settings-account-imap.png"
|
|
mode={RetinaImg.Mode.ContentPreserve} />
|
|
</div>
|
|
|
|
_toggleDropdown: =>
|
|
@setState showing: !@state.showing
|
|
|
|
_onStoreChange: =>
|
|
@setState @_getStateFromStores()
|
|
|
|
_onBlur: (e) =>
|
|
target = e.nativeEvent.relatedTarget
|
|
if target? and React.findDOMNode(@refs.button).contains(target)
|
|
return
|
|
@setState(showing: false)
|
|
|
|
_onSwitchAccount: (account) =>
|
|
Actions.focusDefaultMailboxPerspectiveForAccount(account.id)
|
|
@setState(showing: false)
|
|
|
|
_onManageAccounts: =>
|
|
Actions.switchPreferencesTab('Accounts')
|
|
Actions.openPreferences()
|
|
|
|
@setState(showing: false)
|
|
|
|
_getStateFromStores: =>
|
|
accounts: AccountStore.accounts()
|
|
account: AccountSidebarStore.currentAccount()
|
|
|
|
module.exports = AccountSwitcher
|