1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 17:56:25 +00:00

Merge branch 'master' into all-notes-storage-labels

This commit is contained in:
Christopher Tran
2018-02-24 06:40:25 -08:00
committed by GitHub
11 changed files with 165 additions and 52 deletions

View File

@@ -17,7 +17,7 @@ import styles from './SideNavFilter.styl'
const SideNavFilter = ({ const SideNavFilter = ({
isFolded, isHomeActive, handleAllNotesButtonClick, isFolded, isHomeActive, handleAllNotesButtonClick,
isStarredActive, handleStarredButtonClick, isTrashedActive, handleTrashedButtonClick, counterDelNote, isStarredActive, handleStarredButtonClick, isTrashedActive, handleTrashedButtonClick, counterDelNote,
counterTotalNote, counterStarredNote counterTotalNote, counterStarredNote, handleFilterButtonContextMenu
}) => ( }) => (
<div styleName={isFolded ? 'menu--folded' : 'menu'}> <div styleName={isFolded ? 'menu--folded' : 'menu'}>
@@ -59,7 +59,7 @@ const SideNavFilter = ({
} }
/> />
</div> </div>
<span styleName='menu-button-label'>Trash</span> <span onContextMenu={handleFilterButtonContextMenu} styleName='menu-button-label'>Trash</span>
<span styleName='counters'>{counterDelNote}</span> <span styleName='counters'>{counterDelNote}</span>
</button> </button>

View File

@@ -12,10 +12,11 @@ import CSSModules from 'browser/lib/CSSModules'
* @param {bool} isActive * @param {bool} isActive
*/ */
const TagListItem = ({name, handleClickTagListItem, isActive}) => ( const TagListItem = ({name, handleClickTagListItem, isActive, count}) => (
<button styleName={isActive ? 'tagList-item-active' : 'tagList-item'} onClick={() => handleClickTagListItem(name)}> <button styleName={isActive ? 'tagList-item-active' : 'tagList-item'} onClick={() => handleClickTagListItem(name)}>
<span styleName='tagList-item-name'> <span styleName='tagList-item-name'>
{`# ${name}`} {`# ${name}`}
<span styleName='tagList-item-count'> {count}</span>
</span> </span>
</button> </button>
) )

View File

@@ -48,6 +48,9 @@
overflow hidden overflow hidden
text-overflow ellipsis text-overflow ellipsis
.tagList-item-count
padding 0 3px
body[data-theme="white"] body[data-theme="white"]
.tagList-item .tagList-item
color $ui-inactive-text-color color $ui-inactive-text-color
@@ -63,6 +66,8 @@ body[data-theme="white"]
color $ui-text-color color $ui-text-color
&:hover &:hover
background-color alpha($ui-button--active-backgroundColor, 60%) background-color alpha($ui-button--active-backgroundColor, 60%)
.tagList-item-count
color $ui-text-color
body[data-theme="dark"] body[data-theme="dark"]
.tagList-item .tagList-item
@@ -82,3 +87,5 @@ body[data-theme="dark"]
&:hover &:hover
color $ui-dark-text-color color $ui-dark-text-color
background-color alpha($ui-dark-button--active-backgroundColor, 50%) background-color alpha($ui-dark-button--active-backgroundColor, 50%)
.tagList-item-count
color $ui-dark-button--active-color

View File

@@ -19,6 +19,7 @@ import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
import ConfigManager from 'browser/main/lib/ConfigManager' import ConfigManager from 'browser/main/lib/ConfigManager'
import TrashButton from './TrashButton' import TrashButton from './TrashButton'
import FullscreenButton from './FullscreenButton' import FullscreenButton from './FullscreenButton'
import RestoreButton from './RestoreButton'
import PermanentDeleteButton from './PermanentDeleteButton' import PermanentDeleteButton from './PermanentDeleteButton'
import InfoButton from './InfoButton' import InfoButton from './InfoButton'
import ToggleModeButton from './ToggleModeButton' import ToggleModeButton from './ToggleModeButton'
@@ -321,10 +322,7 @@ class MarkdownNoteDetail extends React.Component {
const trashTopBar = <div styleName='info'> const trashTopBar = <div styleName='info'>
<div styleName='info-left'> <div styleName='info-left'>
<i styleName='undo-button' <RestoreButton onClick={(e) => this.handleUndoButtonClick(e)} />
className='fa fa-undo fa-fw'
onClick={(e) => this.handleUndoButtonClick(e)}
/>
</div> </div>
<div styleName='info-right'> <div styleName='info-right'>
<PermanentDeleteButton onClick={(e) => this.handleTrashButtonClick(e)} /> <PermanentDeleteButton onClick={(e) => this.handleTrashButtonClick(e)} />
@@ -359,12 +357,10 @@ class MarkdownNoteDetail extends React.Component {
value={this.state.note.tags} value={this.state.note.tags}
onChange={this.handleUpdateTag.bind(this)} onChange={this.handleUpdateTag.bind(this)}
/> />
<ToggleModeButton onClick={(e) => this.handleSwitchMode(e)} editorType={editorType} />
<TodoListPercentage percentageOfTodo={getTodoPercentageOfCompleted(note.content)} /> <TodoListPercentage percentageOfTodo={getTodoPercentageOfCompleted(note.content)} />
</div> </div>
<div styleName='info-right'> <div styleName='info-right'>
<ToggleModeButton onClick={(e) => this.handleSwitchMode(e)} editorType={editorType} />
<StarButton <StarButton
onClick={(e) => this.handleStarButtonClick(e)} onClick={(e) => this.handleStarButtonClick(e)}
isActive={note.isStarred} isActive={note.isStarred}

View File

@@ -7,6 +7,7 @@
background-color $ui-noteDetail-backgroundColor background-color $ui-noteDetail-backgroundColor
box-shadow none box-shadow none
padding 20px 40px padding 20px 40px
overflow hidden
.lock-button .lock-button
padding-bottom 3px padding-bottom 3px

View File

@@ -0,0 +1,21 @@
import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './RestoreButton.styl'
const RestoreButton = ({
onClick
}) => (
<button styleName='control-restoreButton'
onClick={onClick}
>
<i className='fa fa-undo fa-fw' styleName='iconRestore' />
<span styleName='tooltip'>Restore</span>
</button>
)
RestoreButton.propTypes = {
onClick: PropTypes.func.isRequired
}
export default CSSModules(RestoreButton, styles)

View File

@@ -0,0 +1,22 @@
.control-restoreButton
top 115px
topBarButtonRight()
&:hover .tooltip
opacity 1
.tooltip
tooltip()
position absolute
pointer-events none
top 50px
left 25px
z-index 200
padding 5px
line-height normal
border-radius 2px
opacity 0
transition 0.1s
body[data-theme="dark"]
.control-restoreButton
topBarButtonDark()

View File

@@ -20,6 +20,7 @@ import _ from 'lodash'
import { findNoteTitle } from 'browser/lib/findNoteTitle' import { findNoteTitle } from 'browser/lib/findNoteTitle'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig' import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
import TrashButton from './TrashButton' import TrashButton from './TrashButton'
import RestoreButton from './RestoreButton'
import PermanentDeleteButton from './PermanentDeleteButton' import PermanentDeleteButton from './PermanentDeleteButton'
import InfoButton from './InfoButton' import InfoButton from './InfoButton'
import InfoPanel from './InfoPanel' import InfoPanel from './InfoPanel'
@@ -589,10 +590,7 @@ class SnippetNoteDetail extends React.Component {
const trashTopBar = <div styleName='info'> const trashTopBar = <div styleName='info'>
<div styleName='info-left'> <div styleName='info-left'>
<i styleName='undo-button' <RestoreButton onClick={(e) => this.handleUndoButtonClick(e)} />
className='fa fa-undo fa-fw'
onClick={(e) => this.handleUndoButtonClick(e)}
/>
</div> </div>
<div styleName='info-right'> <div styleName='info-right'>
<PermanentDeleteButton onClick={(e) => this.handleTrashButtonClick(e)} /> <PermanentDeleteButton onClick={(e) => this.handleTrashButtonClick(e)} />

View File

@@ -5,8 +5,8 @@
width 52px width 52px
display flex display flex
align-items center align-items center
position absolute position: relative
right 165px top 2px
.active .active
background-color #1EC38B background-color #1EC38B
width 33px width 33px

View File

@@ -69,6 +69,7 @@ class NoteList extends React.Component {
this.getNoteStorage = this.getNoteStorage.bind(this) this.getNoteStorage = this.getNoteStorage.bind(this)
this.getNoteFolder = this.getNoteFolder.bind(this) this.getNoteFolder = this.getNoteFolder.bind(this)
this.getViewType = this.getViewType.bind(this) this.getViewType = this.getViewType.bind(this)
this.restoreNote = this.restoreNote.bind(this)
// TODO: not Selected noteKeys but SelectedNote(for reusing) // TODO: not Selected noteKeys but SelectedNote(for reusing)
this.state = { this.state = {
@@ -456,6 +457,7 @@ class NoteList extends React.Component {
const pinLabel = note.isPinned ? 'Remove pin' : 'Pin to Top' const pinLabel = note.isPinned ? 'Remove pin' : 'Pin to Top'
const deleteLabel = 'Delete Note' const deleteLabel = 'Delete Note'
const cloneNote = 'Clone Note' const cloneNote = 'Clone Note'
const restoreNote = 'Restore Note'
const menu = new Menu() const menu = new Menu()
if (!location.pathname.match(/\/starred|\/trash/)) { if (!location.pathname.match(/\/starred|\/trash/)) {
@@ -464,6 +466,14 @@ class NoteList extends React.Component {
click: this.pinToTop click: this.pinToTop
})) }))
} }
if (location.pathname.match(/\/trash/)) {
menu.append(new MenuItem({
label: restoreNote,
click: this.restoreNote
}))
}
menu.append(new MenuItem({ menu.append(new MenuItem({
label: deleteLabel, label: deleteLabel,
click: this.deleteNote click: this.deleteNote
@@ -475,15 +485,20 @@ class NoteList extends React.Component {
menu.popup() menu.popup()
} }
pinToTop () { updateSelectedNotes (updateFunc, cleanSelection = true) {
const { selectedNoteKeys } = this.state const { selectedNoteKeys } = this.state
const { dispatch } = this.props const { dispatch } = this.props
const notes = this.notes.map((note) => Object.assign({}, note)) const notes = this.notes.map((note) => Object.assign({}, note))
const selectedNotes = findNotesByKeys(notes, selectedNoteKeys) const selectedNotes = findNotesByKeys(notes, selectedNoteKeys)
if (!_.isFunction(updateFunc)) {
console.warn('Update function is not defined. No update will happen')
updateFunc = (note) => { return note }
}
Promise.all( Promise.all(
selectedNotes.map((note) => { selectedNotes.map((note) => {
note.isPinned = !note.isPinned note = updateFunc(note)
return dataApi return dataApi
.updateNote(note.storage, note.key, note) .updateNote(note.storage, note.key, note)
}) })
@@ -496,7 +511,24 @@ class NoteList extends React.Component {
}) })
}) })
}) })
this.setState({ selectedNoteKeys: [] })
if (cleanSelection) {
this.selectNextNote()
}
}
pinToTop () {
this.updateSelectedNotes((note) => {
note.isPinned = !note.isPinned
return note
})
}
restoreNote () {
this.updateSelectedNotes((note) => {
note.isTrashed = false
return note
})
} }
deleteNote () { deleteNote () {

View File

@@ -1,6 +1,9 @@
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import React from 'react' import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
const { remote } = require('electron')
const { Menu } = remote
import dataApi from 'browser/main/lib/dataApi'
import styles from './SideNav.styl' import styles from './SideNav.styl'
import { openModal } from 'browser/main/lib/modal' import { openModal } from 'browser/main/lib/modal'
import PreferencesModal from '../modals/PreferencesModal' import PreferencesModal from '../modals/PreferencesModal'
@@ -89,6 +92,7 @@ class SideNav extends React.Component {
counterTotalNote={data.noteMap._map.size - data.trashedSet._set.size} counterTotalNote={data.noteMap._map.size - data.trashedSet._set.size}
counterStarredNote={data.starredSet._set.size} counterStarredNote={data.starredSet._set.size}
counterDelNote={data.trashedSet._set.size} counterDelNote={data.trashedSet._set.size}
handleFilterButtonContextMenu={this.handleFilterButtonContextMenu.bind(this)}
/> />
<StorageList storageList={storageList} /> <StorageList storageList={storageList} />
@@ -113,18 +117,21 @@ class SideNav extends React.Component {
tagListComponent () { tagListComponent () {
const { data, location } = this.props const { data, location } = this.props
const tagList = data.tagNoteMap.map((tag, key) => { const tagList = data.tagNoteMap.map((tag, name) => {
return key return { name, size: tag.size }
}) })
return ( return (
tagList.map(tag => ( tagList.map(tag => {
return (
<TagListItem <TagListItem
name={tag} name={tag.name}
handleClickTagListItem={this.handleClickTagListItem.bind(this)} handleClickTagListItem={this.handleClickTagListItem.bind(this)}
isActive={this.getTagActive(location.pathname, tag)} isActive={this.getTagActive(location.pathname, tag)}
key={tag} key={tag.name}
count={tag.size}
/> />
)) )
})
) )
} }
@@ -139,6 +146,34 @@ class SideNav extends React.Component {
router.push(`/tags/${name}`) router.push(`/tags/${name}`)
} }
emptyTrash (entries) {
const { dispatch } = this.props
const deletionPromises = entries.map((storageAndNoteKey) => {
const storageKey = storageAndNoteKey.split('-')[0]
const noteKey = storageAndNoteKey.split('-')[1]
return dataApi.deleteNote(storageKey, noteKey)
})
Promise.all(deletionPromises)
.then((arrayOfStorageAndNoteKeys) => {
arrayOfStorageAndNoteKeys.forEach(({ storageKey, noteKey }) => {
dispatch({ type: 'DELETE_NOTE', storageKey, noteKey })
})
})
.catch((err) => {
console.error('Cannot Delete note: ' + err)
})
console.log('Trash emptied')
}
handleFilterButtonContextMenu (event) {
const { data } = this.props
const entries = data.trashedSet.toJS()
const menu = Menu.buildFromTemplate([
{ label: 'Empty Trash', click: () => this.emptyTrash(entries) }
])
menu.popup()
}
render () { render () {
const { data, location, config, dispatch } = this.props const { data, location, config, dispatch } = this.props