diff --git a/exports/ui-components.coffee b/exports/ui-components.coffee index f99d80fbd..fdca0c489 100644 --- a/exports/ui-components.coffee +++ b/exports/ui-components.coffee @@ -8,6 +8,8 @@ module.exports = Flexbox: require '../src/components/flexbox' RetinaImg: require '../src/components/retina-img' ListTabular: require '../src/components/list-tabular' - ModelList: require '../src/components/model-list' + MultiselectList: require '../src/components/multiselect-list' + MultiselectActionBar: require '../src/components/multiselect-action-bar' ResizableRegion: require '../src/components/resizable-region' TokenizingTextField: require '../src/components/tokenizing-text-field' + EventedIFrame: require '../src/components/evented-iframe' \ No newline at end of file diff --git a/internal_packages/account-sidebar/lib/account-sidebar-divider-item.cjsx b/internal_packages/account-sidebar/lib/account-sidebar-divider-item.cjsx index baad406a9..be4cedb2e 100644 --- a/internal_packages/account-sidebar/lib/account-sidebar-divider-item.cjsx +++ b/internal_packages/account-sidebar/lib/account-sidebar-divider-item.cjsx @@ -4,5 +4,7 @@ React = require 'react' module.exports = AccountSidebarDividerItem = React.createClass + displayName: 'AccountSidebarDividerItem' + render: ->
{@props.label}
diff --git a/internal_packages/account-sidebar/lib/account-sidebar-sheet-item.cjsx b/internal_packages/account-sidebar/lib/account-sidebar-sheet-item.cjsx new file mode 100644 index 000000000..6d4216f8a --- /dev/null +++ b/internal_packages/account-sidebar/lib/account-sidebar-sheet-item.cjsx @@ -0,0 +1,21 @@ +React = require 'react' +{Actions, Utils, WorkspaceStore} = require 'inbox-exports' +{RetinaImg} = require 'ui-components' + +module.exports = +AccountSidebarSheetItem = React.createClass + displayName: 'AccountSidebarSheetItem' + + render: -> + classSet = React.addons.classSet + 'item': true + 'selected': @props.select + +
+ + {@props.item.name} +
+ + _onClick: (event) -> + event.preventDefault() + Actions.selectRootSheet(@props.item) diff --git a/internal_packages/account-sidebar/lib/account-sidebar-store.coffee b/internal_packages/account-sidebar/lib/account-sidebar-store.coffee index e335fac23..b1dcf74db 100644 --- a/internal_packages/account-sidebar/lib/account-sidebar-store.coffee +++ b/internal_packages/account-sidebar/lib/account-sidebar-store.coffee @@ -2,6 +2,7 @@ Reflux = require 'reflux' _ = require 'underscore-plus' {DatabaseStore, NamespaceStore, + WorkspaceStore, Actions, Tag, Message, @@ -14,17 +15,17 @@ AccountSidebarStore = Reflux.createStore @_registerListeners() @_populate() - # Keep a cache of unread counts since requesting the number from the - # server is a fairly expensive operation. - @_unreadCountCache = {} - @localDraftsTag = new Tag({id: "drafts", name: "Local Drafts"}) - - ########### PUBLIC ##################################################### sections: -> @_sections + selected: -> + if WorkspaceStore.rootSheet() is WorkspaceStore.Sheet.Threads + FocusedTagStore.tag() + else + WorkspaceStore.rootSheet() + ########### PRIVATE #################################################### _setStoreDefaults: -> @@ -33,6 +34,8 @@ AccountSidebarStore = Reflux.createStore _registerListeners: -> @listenTo DatabaseStore, @_onDataChanged @listenTo NamespaceStore, @_onNamespaceChanged + @listenTo WorkspaceStore, @_onWorkspaceChanged + @listenTo FocusedTagStore, @_onFocusChange _populate: -> namespace = NamespaceStore.current() @@ -44,7 +47,9 @@ AccountSidebarStore = Reflux.createStore # We ignore the server drafts so we can use our own localDrafts tags = _.reject tags, (tag) -> tag.id is "drafts" - tags.push(@localDraftsTag) + + # We ignore the trash tag because you can't trash anything + tags = _.reject tags, (tag) -> tag.id is "trash" mainTagIDs = ['inbox', 'drafts', 'sent', 'archive'] mainTags = _.filter tags, (tag) -> _.contains(mainTagIDs, tag.id) @@ -57,10 +62,14 @@ AccountSidebarStore = Reflux.createStore # Sort user tags by name userTags = _.sortBy(userTags, 'name') + # Find root views, add the Views section + rootSheets = _.filter WorkspaceStore.Sheet, (sheet) -> sheet.root and sheet.name + lastSections = @_sections @_sections = [ - { label: 'Mailboxes', tags: mainTags }, - { label: 'Tags', tags: userTags }, + { label: 'Mailboxes', items: mainTags, type: 'tag' }, + { label: 'Views', items: rootSheets, type: 'sheet' }, + { label: 'Tags', items: userTags, type: 'tag' }, ] @trigger(@) @@ -83,7 +92,6 @@ AccountSidebarStore = Reflux.createStore @localDraftsTag.unreadCount = count @trigger(@) - _refetchFromAPI: -> namespace = NamespaceStore.current() return unless namespace @@ -96,6 +104,12 @@ AccountSidebarStore = Reflux.createStore @_populateInboxCount() @_populate() + _onWorkspaceChanged: -> + @_populate() + + _onFocusChange: -> + @trigger(@) + _onDataChanged: (change) -> @populateInboxCountDebounced ?= _.debounce -> @_populateInboxCount() diff --git a/internal_packages/account-sidebar/lib/account-sidebar-tag-item.cjsx b/internal_packages/account-sidebar/lib/account-sidebar-tag-item.cjsx index e8b58b483..8aa28f79b 100644 --- a/internal_packages/account-sidebar/lib/account-sidebar-tag-item.cjsx +++ b/internal_packages/account-sidebar/lib/account-sidebar-tag-item.cjsx @@ -1,32 +1,32 @@ React = require 'react' -{Actions, Utils} = require 'inbox-exports' +{Actions, Utils, WorkspaceStore} = require 'inbox-exports' {RetinaImg} = require 'ui-components' module.exports = AccountSidebarTagItem = React.createClass + displayName: 'AccountSidebarTagItem' + + shouldComponentUpdate: (nextProps) -> + @props?.item.id isnt nextProps.item.id or + @props?.item.unreadCount isnt nextProps.item.unreadCount or + @props?.select isnt nextProps.select + render: -> unread = [] - if @props.tag.unreadCount > 0 - unread =
{@props.tag.unreadCount}
- - name = if @props.tag.name is "drafts" then "Local Drafts" else @props.tag.name + if @props.item.unreadCount > 0 + unread =
{@props.item.unreadCount}
classSet = React.addons.classSet 'item': true - 'item-tag': true 'selected': @props.select -
- - {name} +
+ + {@props.item.name} {unread}
_onClick: (event) -> event.preventDefault() - - if @props.tag.id is 'drafts' - Actions.selectView('drafts') - else - Actions.selectView('threads') - Actions.focusTag(@props.tag) + Actions.selectRootSheet(WorkspaceStore.Sheet.Threads) + Actions.focusTag(@props.item) diff --git a/internal_packages/account-sidebar/lib/account-sidebar.cjsx b/internal_packages/account-sidebar/lib/account-sidebar.cjsx index fa455fd38..2405e1dc2 100644 --- a/internal_packages/account-sidebar/lib/account-sidebar.cjsx +++ b/internal_packages/account-sidebar/lib/account-sidebar.cjsx @@ -1,7 +1,8 @@ React = require 'react' -{Actions, FocusedTagStore} = require("inbox-exports") +{Actions} = require("inbox-exports") SidebarDividerItem = require("./account-sidebar-divider-item") SidebarTagItem = require("./account-sidebar-tag-item") +SidebarSheetItem = require("./account-sidebar-sheet-item") SidebarStore = require ("./account-sidebar-store") module.exports = @@ -13,14 +14,12 @@ AccountSidebar = React.createClass componentDidMount: -> @unsubscribe = SidebarStore.listen @_onStoreChange - @unsubscribe_focus = FocusedTagStore.listen @_onStoreChange # It's important that every React class explicitly stops listening to # atom events before it unmounts. Thank you event-kit # This can be fixed via a Reflux mixin componentWillUnmount: -> @unsubscribe() if @unsubscribe - @unsubscribe_focus() if @unsubscribe_focus render: ->
@@ -37,18 +36,25 @@ AccountSidebar = React.createClass _itemComponents: (section) -> - return section.tags?.map (tag) => - + if section.type is 'tag' + itemClass = SidebarTagItem + else if section.type is 'sheet' + itemClass = SidebarSheetItem + else + throw new Error("Unsure how to render item type #{section.type}") + + section.items?.map (item) => + _onStoreChange: -> @setState @_getStateFromStores() _getStateFromStores: -> sections: SidebarStore.sections() - selected: FocusedTagStore.tagId() + selected: SidebarStore.selected() AccountSidebar.minWidth = 165 diff --git a/internal_packages/account-sidebar/stylesheets/account-sidebar.less b/internal_packages/account-sidebar/stylesheets/account-sidebar.less index b3dc915de..b818d507f 100644 --- a/internal_packages/account-sidebar/stylesheets/account-sidebar.less +++ b/internal_packages/account-sidebar/stylesheets/account-sidebar.less @@ -26,15 +26,7 @@ font-weight: 400; padding: 0 @spacing-standard; line-height: @line-height-large * 1.1; - } - .item-divider { - color:#586870; - padding-top: 1em; - padding-bottom: 0.25em; - } - - .item-tag { .unread { font-weight: @font-weight-medium; color: @source-list-active-bg; @@ -56,10 +48,16 @@ background: @source-list-active-color; } } - + &:hover { background: darken(@source-list-bg, 5%); cursor: default; } } + + .item-divider { + color:#586870; + padding-top: 1em; + padding-bottom: 0.25em; + } } diff --git a/internal_packages/file-list/.gitignore b/internal_packages/file-list/.gitignore new file mode 100755 index 000000000..3c3629e64 --- /dev/null +++ b/internal_packages/file-list/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/internal_packages/file-list/lib/file-frame-store.coffee b/internal_packages/file-list/lib/file-frame-store.coffee new file mode 100644 index 000000000..622127cba --- /dev/null +++ b/internal_packages/file-list/lib/file-frame-store.coffee @@ -0,0 +1,55 @@ +Reflux = require 'reflux' +_ = require 'underscore-plus' +fs = require 'fs' + +{WorkspaceStore, + FocusedContentStore, + FileDownloadStore, + Actions} = require 'inbox-exports' + +module.exports = +FileFrameStore = Reflux.createStore + init: -> + @_resetInstanceVars() + @_afterViewUpdate = [] + + @listenTo FocusedContentStore, @_onFocusedContentChange + @listenTo FileDownloadStore, @_onFileDownloadChange + + file: -> + @_file + + ready: -> + @_ready + + download: -> + @_download + + _resetInstanceVars: -> + @_file = null + @_download = null + @_ready = false + + _update: -> + + _onFileDownloadChange: -> + @_download = FileDownloadStore.downloadForFileId(@_file.id) if @_file + if @_file and @_ready is false and not @_download + @_ready = true + @trigger() + + _onFocusedContentChange: (change) -> + return unless change.impactsCollection('file') + + @_file = FocusedContentStore.focused('file') + if @_file + filepath = FileDownloadStore.pathForFile(@_file) + fs.exists filepath, (exists) => + Actions.fetchFile(@_file) if not exists + @_download = FileDownloadStore.downloadForFileId(@_file.id) + @_ready = not @_download + @trigger() + else + @_ready = false + @_download = null + @trigger() \ No newline at end of file diff --git a/internal_packages/file-list/lib/file-frame.cjsx b/internal_packages/file-list/lib/file-frame.cjsx new file mode 100644 index 000000000..f6835bd0d --- /dev/null +++ b/internal_packages/file-list/lib/file-frame.cjsx @@ -0,0 +1,37 @@ +React = require 'react' +_ = require "underscore-plus" +{Utils, FileDownloadStore, Actions} = require 'inbox-exports' +{Spinner, EventedIFrame} = require 'ui-components' +FileFrameStore = require './file-frame-store' + +module.exports = +FileFrame = React.createClass + displayName: 'FileFrame' + + render: -> + src = if @state.ready then @state.filepath else '' + if @state.file +
+ + +
+ else +
+ + getInitialState: -> + @getStateFromStores() + + componentDidMount: -> + @_unsubscribers = [] + @_unsubscribers.push FileFrameStore.listen @_onChange + + componentWillUnmount: -> + unsubscribe() for unsubscribe in @_unsubscribers + + getStateFromStores: -> + file: FileFrameStore.file() + filepath: FileDownloadStore.pathForFile(FileFrameStore.file()) + ready: FileFrameStore.ready() + + _onChange: -> + @setState(@getStateFromStores()) diff --git a/internal_packages/file-list/lib/file-list-store.coffee b/internal_packages/file-list/lib/file-list-store.coffee new file mode 100644 index 000000000..8e10b59df --- /dev/null +++ b/internal_packages/file-list/lib/file-list-store.coffee @@ -0,0 +1,20 @@ +Reflux = require 'reflux' +_ = require 'underscore-plus' +{File, + DatabaseStore, + DatabaseView} = require 'inbox-exports' + +module.exports = +FileListStore = Reflux.createStore + init: -> + @listenTo DatabaseStore, @_onDataChanged + + @_view = new DatabaseView(File, matchers: [File.attributes.filename.not('')]) + @listenTo @_view, => @trigger({}) + + view: -> + @_view + + _onDataChanged: (change) -> + return unless change.objectClass is File.name + @_view.invalidate({shallow: true, changed: change.objects}) diff --git a/internal_packages/file-list/lib/file-list.cjsx b/internal_packages/file-list/lib/file-list.cjsx new file mode 100644 index 000000000..b0a418251 --- /dev/null +++ b/internal_packages/file-list/lib/file-list.cjsx @@ -0,0 +1,48 @@ +_ = require 'underscore-plus' +React = require 'react' +{ListTabular, MultiselectList} = require 'ui-components' +{Actions, + DatabaseStore, + ComponentRegistry} = require 'inbox-exports' +FileListStore = require './file-list-store' + +module.exports = +FileList = React.createClass + displayName: 'FileList' + + componentWillMount: -> + prettySize = (size) -> + units = ['GB', 'MB', 'KB', 'bytes'] + while size > 1024 + size /= 1024 + units.pop() + size = "#{(Math.ceil(size * 10) / 10)}" + pretty = units.pop() + "#{size} #{pretty}" + + c1 = new ListTabular.Column + name: "Name" + flex: 1 + resolver: (file) -> +
{file.filename}
+ + c2 = new ListTabular.Column + name: "Size" + width: '100px' + resolver: (file) -> +
{prettySize(file.size)}
+ + @columns = [c1, c2] + + render: -> + } + className="file-list" + collection="file" /> + + _onDoubleClick: (item) -> + diff --git a/internal_packages/file-list/lib/file-selection-bar.cjsx b/internal_packages/file-list/lib/file-selection-bar.cjsx new file mode 100644 index 000000000..89b51fa37 --- /dev/null +++ b/internal_packages/file-list/lib/file-selection-bar.cjsx @@ -0,0 +1,12 @@ +React = require "react/addons" +FileListStore = require './file-list-store' +{MultiselectActionBar} = require 'ui-components' + +module.exports = +FileSelectionBar = React.createClass + displayName: 'FileSelectionBar' + + render: -> + diff --git a/internal_packages/file-list/lib/main.cjsx b/internal_packages/file-list/lib/main.cjsx new file mode 100644 index 000000000..a11ab5e72 --- /dev/null +++ b/internal_packages/file-list/lib/main.cjsx @@ -0,0 +1,34 @@ +FileFrame = require "./file-frame" +FileList = require './file-list' +FileSelectionBar = require './file-selection-bar' +{ComponentRegistry, + WorkspaceStore} = require 'inbox-exports' + +module.exports = + + activate: (@state={}) -> + WorkspaceStore.defineSheet 'Files', {root: true, supportedModes: ['list'], name: 'Files'}, + list: ['RootSidebar', 'FileList'] + + WorkspaceStore.defineSheet 'File', {supportedModes: ['list']}, + list: ['File'] + + ComponentRegistry.register + view: FileList + name: 'FileList' + location: WorkspaceStore.Location.FileList + + ComponentRegistry.register + view: FileSelectionBar + name: 'FileSelectionBar' + location: WorkspaceStore.Location.FileList.Toolbar + + ComponentRegistry.register + name: 'FileFrame' + view: FileFrame + location: WorkspaceStore.Location.File + + deactivate: -> + ComponentRegistry.unregister 'FileSelectionBar' + ComponentRegistry.unregister 'FileList' + ComponentRegistry.unregister 'FileFrame' diff --git a/internal_packages/file-list/package.json b/internal_packages/file-list/package.json new file mode 100755 index 000000000..70061034b --- /dev/null +++ b/internal_packages/file-list/package.json @@ -0,0 +1,13 @@ +{ + "name": "file-list", + "version": "0.1.0", + "main": "./lib/main", + "description": "View files", + "license": "Proprietary", + "private": true, + "engines": { + "atom": "*" + }, + "dependencies": { + } +} diff --git a/internal_packages/file-list/stylesheets/file-list.less b/internal_packages/file-list/stylesheets/file-list.less new file mode 100644 index 000000000..27e2bf69f --- /dev/null +++ b/internal_packages/file-list/stylesheets/file-list.less @@ -0,0 +1,15 @@ +@import "ui-variables"; +@import "ui-mixins"; + +@message-max-width: 800px; + +.file-frame-container { + width:100%; + height:100%; + + iframe { + width:100%; + height:100%; + border:0; + } +} \ No newline at end of file diff --git a/internal_packages/message-list/LICENSE.md b/internal_packages/message-list/LICENSE.md deleted file mode 100755 index 4d231b456..000000000 --- a/internal_packages/message-list/LICENSE.md +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2014 GitHub Inc. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/internal_packages/message-list/README.md b/internal_packages/message-list/README.md deleted file mode 100755 index 33e34f297..000000000 --- a/internal_packages/message-list/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Tree View package [![Build Status](https://travis-ci.org/atom/tree-view.svg?branch=master)](https://travis-ci.org/atom/tree-view) - -Explore and open files in the current project. - -Press `cmd-\` to open/close the Tree view and `ctrl-0` to focus it. - -When the Tree view has focus you can press `a`, `m`, or `delete` to add, move -or delete files and folders. - -![](https://f.cloud.github.com/assets/671378/2241932/6d9cface-9ceb-11e3-9026-31d5011d889d.png) diff --git a/internal_packages/message-list/lib/email-frame.cjsx b/internal_packages/message-list/lib/email-frame.cjsx index 32ffd9c3e..ae208d236 100644 --- a/internal_packages/message-list/lib/email-frame.cjsx +++ b/internal_packages/message-list/lib/email-frame.cjsx @@ -1,5 +1,6 @@ React = require 'react' _ = require "underscore-plus" +{EventedIFrame} = require 'ui-components' {Utils} = require 'inbox-exports' EmailFixingStyles = """ @@ -109,7 +110,7 @@ EmailFrame = React.createClass displayName: 'EmailFrame' render: -> -