1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 09:46:22 +00:00
This commit is contained in:
Rokt33r
2015-12-28 16:11:42 +09:00
parent f9539ab50a
commit e4d8438801
5 changed files with 125 additions and 34 deletions

View File

@@ -1,7 +1,35 @@
import React, { PropTypes } from 'react'
import ReactDOM from 'react-dom'
import ExternalLink from 'browser/components/ExternalLink'
import { setSearchFilter, clearSearch, toggleOnlyUnsavedFilter, toggleTutorial } from '../actions'
import { setSearchFilter, clearSearch, toggleOnlyUnsavedFilter, toggleTutorial, saveAllArticles, switchArticle } from '../actions'
import store from '../store'
const electron = require('electron')
const remote = electron.remote
const Menu = remote.Menu
const MenuItem = remote.MenuItem
var menu = new Menu()
var lastIndex = -1
menu.append(new MenuItem({
label: 'Show only unsaved',
click: function () {
store.dispatch(setSearchFilter('--unsaved'))
}
}))
menu.append(new MenuItem({
label: 'Go to an unsaved article',
click: function () {
lastIndex++
let state = store.getState()
let modified = state.articles.modified
if (modified.length === 0) return
if (modified.length <= lastIndex) {
lastIndex = 0
}
store.dispatch(switchArticle(modified[lastIndex].key))
}
}))
const BRAND_COLOR = '#18AF90'
@@ -111,19 +139,28 @@ export default class ArticleTopBar extends React.Component {
dispatch(toggleOnlyUnsavedFilter())
}
handleSaveAllButtonClick (e) {
let { dispatch } = this.props
dispatch(saveAllArticles())
}
handleSaveMenuButtonClick (e) {
menu.popup(590, 45)
}
handleTutorialButtonClick (e) {
let { dispatch } = this.props
console.log(e.target.value)
dispatch(toggleTutorial())
}
render () {
let { status } = this.props
let { status, modified } = this.props
return (
<div className='ArticleTopBar'>
<div className='left'>
<div className='search'>
<div className='ArticleTopBar-left'>
<div className='ArticleTopBar-left-search'>
<i className='fa fa-search fa-fw' />
<input
ref='searchInput'
@@ -142,16 +179,25 @@ export default class ArticleTopBar extends React.Component {
<div className={'tooltip' + (this.state.isTooltipHidden ? ' hide' : '')}>
<ul>
<li>- Search by tag : #{'{string}'}</li>
<li>- Search by folder : /{'{folder_name}'}</li>
<li><small>exact match : //{'{folder_name}'}</small></li>
<li>- Search by folder : /{'{folder_name}'}<br/><small>exact match : //{'{folder_name}'}</small></li>
<li>- Only unsaved : --unsaved</li>
</ul>
</div>
</div>
{status.isTutorialOpen ? searchTutorialElement : null}
<label className='only-unsaved'><input value={status.onlyUnsaved} onChange={e => this.handleOnlyUnsavedChange(e)} type='checkbox'/> only unsaved</label>
<div className={'ArticleTopBar-left-unsaved'}>
<button onClick={e => this.handleSaveAllButtonClick(e)} className='ArticleTopBar-left-unsaved-save-button' disabled={modified.length === 0}>
<i className='fa fa-save'/>
<span className={'ArticleTopBar-left-unsaved-save-button-count' + (modified.length === 0 ? ' hide' : '')} children={modified.length}/>
<span className='ArticleTopBar-left-unsaved-save-button-tooltip' children={`Save all ${modified.length} articles (⌘ + Shift + s)`}></span>
</button>
<button onClick={e => this.handleSaveMenuButtonClick(e)} className='ArticleTopBar-left-unsaved-menu-button'><i className='fa fa-angle-down'/></button>
</div>
</div>
<div className='right'>
<div className='ArticleTopBar-right'>
<button onClick={e => this.handleTutorialButtonClick(e)}>?<span className='tooltip'>How to use</span>
</button>
<a ref='links' className='linksBtn' href>
@@ -198,5 +244,6 @@ ArticleTopBar.propTypes = {
dispatch: PropTypes.func,
status: PropTypes.shape({
search: PropTypes.string
})
}),
modified: PropTypes.array
}

View File

@@ -84,6 +84,7 @@ class HomePage extends React.Component {
ref='top'
dispatch={dispatch}
status={status}
modified={modified}
/>
<ArticleList
ref='list'
@@ -112,7 +113,7 @@ class HomePage extends React.Component {
// Ignore invalid key
function ignoreInvalidKey (key) {
return key.length > 0 && !key.match(/^\/\/$/) && !key.match(/^\/$/) && !key.match(/^#$/)
return key.length > 0 && !key.match(/^\/\/$/) && !key.match(/^\/$/) && !key.match(/^#$/) && !key.match(/^--/)
}
// Build filter object by key
@@ -144,10 +145,6 @@ function remap (state) {
let articles = _articles != null ? _articles.data : []
let modified = _articles != null ? _articles.modified : []
if (state.status.onlyUnsaved) {
articles = modified.map(modifiedArticle => _.findWhere(articles, {key: modifiedArticle.key}))
}
articles.sort((a, b) => {
return new Date(b.updatedAt) - new Date(a.updatedAt)
})
@@ -158,6 +155,7 @@ function remap (state) {
return sum.concat(article.tags)
}, []))
if (status.search.split(' ').some(key => key === '--unsaved')) articles = articles.filter(article => _.findWhere(modified, {key: article.key}))
// Filter articles
let filters = status.search.split(' ')
.map(key => key.trim())

View File

@@ -5,6 +5,7 @@ export const CLEAR_NEW_ARTICLE = 'CLEAR_NEW_ARTICLE'
export const ARTICLE_UPDATE = 'ARTICLE_UPDATE'
export const ARTICLE_DESTROY = 'ARTICLE_DESTROY'
export const ARTICLE_SAVE = 'ARTICLE_SAVE'
export const ARTICLE_SAVE_ALL = 'ARTICLE_SAVE_ALL'
export const ARTICLE_CACHE = 'ARTICLE_CACHE'
export const FOLDER_CREATE = 'FOLDER_CREATE'
export const FOLDER_UPDATE = 'FOLDER_UPDATE'
@@ -16,7 +17,6 @@ export const SWITCH_ARTICLE = 'SWITCH_ARTICLE'
export const SET_SEARCH_FILTER = 'SET_SEARCH_FILTER'
export const SET_TAG_FILTER = 'SET_TAG_FILTER'
export const CLEAR_SEARCH = 'CLEAR_SEARCH'
export const TOGGLE_ONLY_UNSAVED_FILTER = 'TOGGLE_ONLY_UNSAVED_FILTER'
export const TOGGLE_TUTORIAL = 'TOGGLE_TUTORIAL'
@@ -51,6 +51,12 @@ export function saveArticle (key, article, forceSwitch) {
}
}
export function saveAllArticles () {
return {
type: ARTICLE_SAVE_ALL
}
}
export function updateArticle (article) {
return {
type: ARTICLE_UPDATE,
@@ -132,12 +138,6 @@ export function clearSearch () {
}
}
export function toggleOnlyUnsavedFilter () {
return {
type: TOGGLE_ONLY_UNSAVED_FILTER
}
}
export function toggleTutorial () {
return {
type: TOGGLE_TUTORIAL
@@ -146,20 +146,23 @@ export function toggleTutorial () {
export default {
updateUser,
clearNewArticle,
updateArticle,
destroyArticle,
cacheArticle,
saveArticle,
saveAllArticles,
createFolder,
updateFolder,
destroyFolder,
replaceFolder,
switchFolder,
switchArticle,
setSearchFilter,
setTagFilter,
clearSearch,
toggleOnlyUnsavedFilter,
toggleTutorial
}

View File

@@ -7,7 +7,6 @@ import {
SET_SEARCH_FILTER,
SET_TAG_FILTER,
CLEAR_SEARCH,
TOGGLE_ONLY_UNSAVED_FILTER,
TOGGLE_TUTORIAL,
// user
@@ -18,6 +17,7 @@ import {
ARTICLE_DESTROY,
ARTICLE_CACHE,
ARTICLE_SAVE,
ARTICLE_SAVE_ALL,
// Folder action type
FOLDER_CREATE,
@@ -31,8 +31,7 @@ import activityRecord from 'browser/lib/activityRecord'
const initialStatus = {
search: '',
isTutorialOpen: false,
onlyUnsaved: false
isTutorialOpen: false
}
let data = dataStore.getData()
@@ -195,6 +194,18 @@ function articles (state = initialArticles, action) {
dataStore.setArticles(state.data)
return state
}
case ARTICLE_SAVE_ALL:
if (state.modified.length > 0) {
state.modified.forEach(modifiedArticle => {
let targetIndex = _.findIndex(state.data, _article => modifiedArticle.key === _article.key)
Object.assign(state.data[targetIndex], modifiedArticle, {key: modifiedArticle.key, updatedAt: new Date()})
})
}
state.modified = []
dataStore.setArticles(state.data)
return state
case ARTICLE_UPDATE:
{
let article = action.data.article
@@ -265,10 +276,6 @@ function status (state = initialStatus, action) {
case CLEAR_SEARCH:
state.search = ''
return state
case TOGGLE_ONLY_UNSAVED_FILTER:
state.onlyUnsaved = !state.onlyUnsaved
return state
default:
return state

View File

@@ -36,14 +36,14 @@ infoBtnActiveBgColor = #3A3A3A
fixed top left bottom right
z-index 20
background-color transparentify(black, 80%)
&>.left
&>.ArticleTopBar-left
float left
&>.tutorial
fixed top
left 200px
z-index 36
font-style italic
&>.search
&>.ArticleTopBar-left-search
position relative
float left
height 33px
@@ -63,11 +63,15 @@ infoBtnActiveBgColor = #3A3A3A
&.hide
opacity 0
ul
li
line-height 18px
li:last-child
line-height 10px
margin-bottom 3px
small
font-size 10px
position relative
top -2px
margin-left 15px
input
absolute top left
@@ -122,13 +126,45 @@ infoBtnActiveBgColor = #3A3A3A
transition 0.1s
&:hover
color refreshBtnActiveColor
.only-unsaved
.ArticleTopBar-left-unsaved
line-height 33px
float left
height 33px
margin-top 13.5px
margin-left 10px
&>.right
button
background transparent
font-size 20px
border none
outline none
color inactiveTextColor
&:hover
color inherit
&.ArticleTopBar-left-unsaved-save-button
position relative
.ArticleTopBar-left-unsaved-save-button-count
position absolute
font-size 10px
background-color brandColor
color white
height 14px
width 14px
line-height 14px
border-radius 7px
top 16px
right -3px
transition 0.15s
&.hide
transform scale(0)
.ArticleTopBar-left-unsaved-save-button-tooltip
tooltip()
margin-top 30px
margin-left -100px
&:hover
.ArticleTopBar-left-unsaved-save-button-tooltip
opacity 1
&>.ArticleTopBar-right
float right
&>button
display block