Skip to content

Commit e4d8438

Browse files
committed
save ALL
1 parent f9539ab commit e4d8438

5 files changed

Lines changed: 125 additions & 34 deletions

File tree

browser/main/HomePage/ArticleTopBar.js

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,35 @@
11
import React, { PropTypes } from 'react'
22
import ReactDOM from 'react-dom'
33
import ExternalLink from 'browser/components/ExternalLink'
4-
import { setSearchFilter, clearSearch, toggleOnlyUnsavedFilter, toggleTutorial } from '../actions'
4+
import { setSearchFilter, clearSearch, toggleOnlyUnsavedFilter, toggleTutorial, saveAllArticles, switchArticle } from '../actions'
5+
import store from '../store'
6+
7+
const electron = require('electron')
8+
const remote = electron.remote
9+
const Menu = remote.Menu
10+
const MenuItem = remote.MenuItem
11+
12+
var menu = new Menu()
13+
var lastIndex = -1
14+
menu.append(new MenuItem({
15+
label: 'Show only unsaved',
16+
click: function () {
17+
store.dispatch(setSearchFilter('--unsaved'))
18+
}
19+
}))
20+
menu.append(new MenuItem({
21+
label: 'Go to an unsaved article',
22+
click: function () {
23+
lastIndex++
24+
let state = store.getState()
25+
let modified = state.articles.modified
26+
if (modified.length === 0) return
27+
if (modified.length <= lastIndex) {
28+
lastIndex = 0
29+
}
30+
store.dispatch(switchArticle(modified[lastIndex].key))
31+
}
32+
}))
533

634
const BRAND_COLOR = '#18AF90'
735

@@ -111,19 +139,28 @@ export default class ArticleTopBar extends React.Component {
111139
dispatch(toggleOnlyUnsavedFilter())
112140
}
113141

142+
handleSaveAllButtonClick (e) {
143+
let { dispatch } = this.props
144+
145+
dispatch(saveAllArticles())
146+
}
147+
148+
handleSaveMenuButtonClick (e) {
149+
menu.popup(590, 45)
150+
}
151+
114152
handleTutorialButtonClick (e) {
115153
let { dispatch } = this.props
116-
console.log(e.target.value)
117154

118155
dispatch(toggleTutorial())
119156
}
120157

121158
render () {
122-
let { status } = this.props
159+
let { status, modified } = this.props
123160
return (
124161
<div className='ArticleTopBar'>
125-
<div className='left'>
126-
<div className='search'>
162+
<div className='ArticleTopBar-left'>
163+
<div className='ArticleTopBar-left-search'>
127164
<i className='fa fa-search fa-fw' />
128165
<input
129166
ref='searchInput'
@@ -142,16 +179,25 @@ export default class ArticleTopBar extends React.Component {
142179
<div className={'tooltip' + (this.state.isTooltipHidden ? ' hide' : '')}>
143180
<ul>
144181
<li>- Search by tag : #{'{string}'}</li>
145-
<li>- Search by folder : /{'{folder_name}'}</li>
146-
<li><small>exact match : //{'{folder_name}'}</small></li>
182+
<li>- Search by folder : /{'{folder_name}'}<br/><small>exact match : //{'{folder_name}'}</small></li>
183+
<li>- Only unsaved : --unsaved</li>
147184
</ul>
148185
</div>
149186
</div>
150187

151188
{status.isTutorialOpen ? searchTutorialElement : null}
152-
<label className='only-unsaved'><input value={status.onlyUnsaved} onChange={e => this.handleOnlyUnsavedChange(e)} type='checkbox'/> only unsaved</label>
189+
190+
<div className={'ArticleTopBar-left-unsaved'}>
191+
<button onClick={e => this.handleSaveAllButtonClick(e)} className='ArticleTopBar-left-unsaved-save-button' disabled={modified.length === 0}>
192+
<i className='fa fa-save'/>
193+
<span className={'ArticleTopBar-left-unsaved-save-button-count' + (modified.length === 0 ? ' hide' : '')} children={modified.length}/>
194+
<span className='ArticleTopBar-left-unsaved-save-button-tooltip' children={`Save all ${modified.length} articles (⌘ + Shift + s)`}></span>
195+
</button>
196+
<button onClick={e => this.handleSaveMenuButtonClick(e)} className='ArticleTopBar-left-unsaved-menu-button'><i className='fa fa-angle-down'/></button>
197+
</div>
153198
</div>
154-
<div className='right'>
199+
200+
<div className='ArticleTopBar-right'>
155201
<button onClick={e => this.handleTutorialButtonClick(e)}>?<span className='tooltip'>How to use</span>
156202
</button>
157203
<a ref='links' className='linksBtn' href>
@@ -198,5 +244,6 @@ ArticleTopBar.propTypes = {
198244
dispatch: PropTypes.func,
199245
status: PropTypes.shape({
200246
search: PropTypes.string
201-
})
247+
}),
248+
modified: PropTypes.array
202249
}

browser/main/HomePage/index.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class HomePage extends React.Component {
8484
ref='top'
8585
dispatch={dispatch}
8686
status={status}
87+
modified={modified}
8788
/>
8889
<ArticleList
8990
ref='list'
@@ -112,7 +113,7 @@ class HomePage extends React.Component {
112113

113114
// Ignore invalid key
114115
function ignoreInvalidKey (key) {
115-
return key.length > 0 && !key.match(/^\/\/$/) && !key.match(/^\/$/) && !key.match(/^#$/)
116+
return key.length > 0 && !key.match(/^\/\/$/) && !key.match(/^\/$/) && !key.match(/^#$/) && !key.match(/^--/)
116117
}
117118

118119
// Build filter object by key
@@ -144,10 +145,6 @@ function remap (state) {
144145
let articles = _articles != null ? _articles.data : []
145146
let modified = _articles != null ? _articles.modified : []
146147

147-
if (state.status.onlyUnsaved) {
148-
articles = modified.map(modifiedArticle => _.findWhere(articles, {key: modifiedArticle.key}))
149-
}
150-
151148
articles.sort((a, b) => {
152149
return new Date(b.updatedAt) - new Date(a.updatedAt)
153150
})
@@ -158,6 +155,7 @@ function remap (state) {
158155
return sum.concat(article.tags)
159156
}, []))
160157

158+
if (status.search.split(' ').some(key => key === '--unsaved')) articles = articles.filter(article => _.findWhere(modified, {key: article.key}))
161159
// Filter articles
162160
let filters = status.search.split(' ')
163161
.map(key => key.trim())

browser/main/actions.js

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export const CLEAR_NEW_ARTICLE = 'CLEAR_NEW_ARTICLE'
55
export const ARTICLE_UPDATE = 'ARTICLE_UPDATE'
66
export const ARTICLE_DESTROY = 'ARTICLE_DESTROY'
77
export const ARTICLE_SAVE = 'ARTICLE_SAVE'
8+
export const ARTICLE_SAVE_ALL = 'ARTICLE_SAVE_ALL'
89
export const ARTICLE_CACHE = 'ARTICLE_CACHE'
910
export const FOLDER_CREATE = 'FOLDER_CREATE'
1011
export const FOLDER_UPDATE = 'FOLDER_UPDATE'
@@ -16,7 +17,6 @@ export const SWITCH_ARTICLE = 'SWITCH_ARTICLE'
1617
export const SET_SEARCH_FILTER = 'SET_SEARCH_FILTER'
1718
export const SET_TAG_FILTER = 'SET_TAG_FILTER'
1819
export const CLEAR_SEARCH = 'CLEAR_SEARCH'
19-
export const TOGGLE_ONLY_UNSAVED_FILTER = 'TOGGLE_ONLY_UNSAVED_FILTER'
2020

2121
export const TOGGLE_TUTORIAL = 'TOGGLE_TUTORIAL'
2222

@@ -51,6 +51,12 @@ export function saveArticle (key, article, forceSwitch) {
5151
}
5252
}
5353

54+
export function saveAllArticles () {
55+
return {
56+
type: ARTICLE_SAVE_ALL
57+
}
58+
}
59+
5460
export function updateArticle (article) {
5561
return {
5662
type: ARTICLE_UPDATE,
@@ -132,12 +138,6 @@ export function clearSearch () {
132138
}
133139
}
134140

135-
export function toggleOnlyUnsavedFilter () {
136-
return {
137-
type: TOGGLE_ONLY_UNSAVED_FILTER
138-
}
139-
}
140-
141141
export function toggleTutorial () {
142142
return {
143143
type: TOGGLE_TUTORIAL
@@ -146,20 +146,23 @@ export function toggleTutorial () {
146146

147147
export default {
148148
updateUser,
149+
149150
clearNewArticle,
150151
updateArticle,
151152
destroyArticle,
152153
cacheArticle,
153154
saveArticle,
155+
saveAllArticles,
156+
154157
createFolder,
155158
updateFolder,
156159
destroyFolder,
157160
replaceFolder,
161+
158162
switchFolder,
159163
switchArticle,
160164
setSearchFilter,
161165
setTagFilter,
162166
clearSearch,
163-
toggleOnlyUnsavedFilter,
164167
toggleTutorial
165168
}

browser/main/reducer.js

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
SET_SEARCH_FILTER,
88
SET_TAG_FILTER,
99
CLEAR_SEARCH,
10-
TOGGLE_ONLY_UNSAVED_FILTER,
1110
TOGGLE_TUTORIAL,
1211

1312
// user
@@ -18,6 +17,7 @@ import {
1817
ARTICLE_DESTROY,
1918
ARTICLE_CACHE,
2019
ARTICLE_SAVE,
20+
ARTICLE_SAVE_ALL,
2121

2222
// Folder action type
2323
FOLDER_CREATE,
@@ -31,8 +31,7 @@ import activityRecord from 'browser/lib/activityRecord'
3131

3232
const initialStatus = {
3333
search: '',
34-
isTutorialOpen: false,
35-
onlyUnsaved: false
34+
isTutorialOpen: false
3635
}
3736

3837
let data = dataStore.getData()
@@ -195,6 +194,18 @@ function articles (state = initialArticles, action) {
195194
dataStore.setArticles(state.data)
196195
return state
197196
}
197+
case ARTICLE_SAVE_ALL:
198+
if (state.modified.length > 0) {
199+
state.modified.forEach(modifiedArticle => {
200+
let targetIndex = _.findIndex(state.data, _article => modifiedArticle.key === _article.key)
201+
Object.assign(state.data[targetIndex], modifiedArticle, {key: modifiedArticle.key, updatedAt: new Date()})
202+
})
203+
}
204+
205+
state.modified = []
206+
dataStore.setArticles(state.data)
207+
208+
return state
198209
case ARTICLE_UPDATE:
199210
{
200211
let article = action.data.article
@@ -265,10 +276,6 @@ function status (state = initialStatus, action) {
265276
case CLEAR_SEARCH:
266277
state.search = ''
267278

268-
return state
269-
case TOGGLE_ONLY_UNSAVED_FILTER:
270-
state.onlyUnsaved = !state.onlyUnsaved
271-
272279
return state
273280
default:
274281
return state

browser/styles/main/HomeContainer/components/ArticleTopBar.styl

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ infoBtnActiveBgColor = #3A3A3A
3636
fixed top left bottom right
3737
z-index 20
3838
background-color transparentify(black, 80%)
39-
&>.left
39+
&>.ArticleTopBar-left
4040
float left
4141
&>.tutorial
4242
fixed top
4343
left 200px
4444
z-index 36
4545
font-style italic
46-
&>.search
46+
&>.ArticleTopBar-left-search
4747
position relative
4848
float left
4949
height 33px
@@ -63,11 +63,15 @@ infoBtnActiveBgColor = #3A3A3A
6363
&.hide
6464
opacity 0
6565
ul
66+
li
67+
line-height 18px
6668
li:last-child
6769
line-height 10px
6870
margin-bottom 3px
6971
small
7072
font-size 10px
73+
position relative
74+
top -2px
7175
margin-left 15px
7276
input
7377
absolute top left
@@ -122,13 +126,45 @@ infoBtnActiveBgColor = #3A3A3A
122126
transition 0.1s
123127
&:hover
124128
color refreshBtnActiveColor
125-
.only-unsaved
129+
.ArticleTopBar-left-unsaved
126130
line-height 33px
127131
float left
128132
height 33px
129133
margin-top 13.5px
130134
margin-left 10px
131-
&>.right
135+
button
136+
background transparent
137+
font-size 20px
138+
border none
139+
outline none
140+
color inactiveTextColor
141+
&:hover
142+
color inherit
143+
&.ArticleTopBar-left-unsaved-save-button
144+
position relative
145+
.ArticleTopBar-left-unsaved-save-button-count
146+
position absolute
147+
font-size 10px
148+
background-color brandColor
149+
color white
150+
height 14px
151+
width 14px
152+
line-height 14px
153+
border-radius 7px
154+
top 16px
155+
right -3px
156+
transition 0.15s
157+
&.hide
158+
transform scale(0)
159+
.ArticleTopBar-left-unsaved-save-button-tooltip
160+
tooltip()
161+
margin-top 30px
162+
margin-left -100px
163+
&:hover
164+
.ArticleTopBar-left-unsaved-save-button-tooltip
165+
opacity 1
166+
167+
&>.ArticleTopBar-right
132168
float right
133169
&>button
134170
display block

0 commit comments

Comments
 (0)