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:
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
21
browser/main/Detail/RestoreButton.js
Normal file
21
browser/main/Detail/RestoreButton.js
Normal 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)
|
||||||
22
browser/main/Detail/RestoreButton.styl
Normal file
22
browser/main/Detail/RestoreButton.styl
Normal 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()
|
||||||
@@ -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)} />
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 () {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user