diff --git a/browser/components/NoteItem.js b/browser/components/NoteItem.js index 9f49fb28..ce209471 100644 --- a/browser/components/NoteItem.js +++ b/browser/components/NoteItem.js @@ -72,6 +72,9 @@ const NoteItem = ({ isActive, note, dateDisplay, handleNoteClick, handleNoteCont {note.isStarred ? : '' } + {note.isPinned + ? : '' + } {note.type === 'MARKDOWN_NOTE' ? : '' @@ -101,6 +104,7 @@ NoteItem.propTypes = { isTrashed: PropTypes.bool.isRequired }), handleNoteClick: PropTypes.func.isRequired, + handleNoteContextMenu: PropTypes.func.isRequired, handleDragStart: PropTypes.func.isRequired, handleDragEnd: PropTypes.func.isRequired } diff --git a/browser/main/NoteList/index.js b/browser/main/NoteList/index.js index 6f3860eb..8fad912c 100644 --- a/browser/main/NoteList/index.js +++ b/browser/main/NoteList/index.js @@ -14,6 +14,7 @@ import { hashHistory } from 'react-router' import markdown from 'browser/lib/markdown' import { findNoteTitle } from 'browser/lib/findNoteTitle' import stripgtags from 'striptags' +import store from 'browser/main/store' const { remote } = require('electron') const { Menu, MenuItem, dialog } = remote @@ -283,6 +284,21 @@ class NoteList extends React.Component { return folderNoteKeyList.map((uniqueKey) => data.noteMap.get(uniqueKey)) } + sortByPinn (unorderedNotes) { + const { data, params } = this.props + let storageKey = params.storageKey + let folderKey = params.folderKey + let storage = data.storageMap.get(storageKey) + if (storage == null) return [] + + let folder = _.find(storage.folders, {key: folderKey}) + const pinnedNotes = unorderedNotes.filter((el) => { + return folder.pinnedNotes && folder.pinnedNotes.includes(el.key) + }) + + return pinnedNotes.concat(unorderedNotes) + } + handleNoteClick (e, uniqueKey) { let { router } = this.context let { location } = this.props @@ -413,6 +429,56 @@ class NoteList extends React.Component { }) } + handleNoteContextMenu (e, uniqueKey) { + let menu = new Menu() + menu.append(new MenuItem({ + label: 'Pin to Top', + click: (e) => this.handlePinToTop(e, uniqueKey) + })) + menu.popup() + } + + handlePinToTop (e, uniqueKey) { + const { data, location } = this.props + let splitted = location.pathname.split('/') + const storageKey = splitted[2] + const folderKey = splitted[4] + + const currentStorage = data.storageMap.get(storageKey) + const currentFolder = _.find(currentStorage.folders, {key: folderKey}) + + dataApi + .updateFolder(storageKey, folderKey, { + color: currentFolder.color, + name: currentFolder.name, + pinnedNote: uniqueKey.split('-').pop() + }) + .then((data) => { + store.dispatch({ + type: 'UPDATE_FOLDER', + storage: data.storage + }) + this.setState({ + status: 'IDLE' + }) + }) + + let targetIndex = _.findIndex(this.notes, (note) => { + return note != null && note.storage + '-' + note.key === location.query.key + }) + let note = this.notes[targetIndex] + + dataApi + .updateNote(note.storage, note.key, note) + .then((note) => { + note.isPinned = true + store.dispatch({ + type: 'UPDATE_NOTE', + note: note + }) + }) + } + render () { let { location, notes, config, dispatch } = this.props let sortFunc = config.sortBy === 'CREATED_AT' @@ -420,8 +486,8 @@ class NoteList extends React.Component { : config.sortBy === 'ALPHABETICAL' ? sortByAlphabetical : sortByUpdatedAt - this.notes = notes = this.getNotes() - .sort(sortFunc) + const sortedNotes = this.getNotes().sort(sortFunc) + this.notes = notes = this.sortByPinn(sortedNotes) .filter((note) => { // this is for the trash box if (note.isTrashed !== true || location.pathname === '/trashed') return true @@ -450,6 +516,7 @@ class NoteList extends React.Component { key={key} handleNoteContextMenu={this.handleNoteContextMenu.bind(this)} handleNoteClick={this.handleNoteClick.bind(this)} + handleNoteContextMenu={this.handleNoteContextMenu.bind(this)} handleDragStart={this.handleDragStart.bind(this)} /> ) @@ -526,4 +593,4 @@ NoteList.propTypes = { }) } -export default CSSModules(NoteList, styles) + diff --git a/browser/main/lib/dataApi/createFolder.js b/browser/main/lib/dataApi/createFolder.js index 9357e17c..69c27d38 100644 --- a/browser/main/lib/dataApi/createFolder.js +++ b/browser/main/lib/dataApi/createFolder.js @@ -44,7 +44,8 @@ function createFolder (storageKey, input) { let newFolder = { key, color: input.color, - name: input.name + name: input.name, + pinnedNotes: [] } storage.folders.push(newFolder) diff --git a/browser/main/lib/dataApi/updateFolder.js b/browser/main/lib/dataApi/updateFolder.js index e128a2d3..414e32b6 100644 --- a/browser/main/lib/dataApi/updateFolder.js +++ b/browser/main/lib/dataApi/updateFolder.js @@ -44,6 +44,12 @@ function updateFolder (storageKey, folderKey, input) { if (targetFolder == null) throw new Error('Target folder doesn\'t exist.') targetFolder.name = input.name targetFolder.color = input.color + // For compativility + if (targetFolder.pinnedNotes) { + targetFolder.pinnedNotes.push(input.pinnedNote) + } else { + targetFolder.pinnedNotes = [input.pinnedNote] + } CSON.writeFileSync(path.join(storage.path, 'boostnote.json'), _.pick(storage, ['folders', 'version'])) diff --git a/browser/main/lib/dataApi/updateNote.js b/browser/main/lib/dataApi/updateNote.js index 4bf5ca29..e6bc7b55 100644 --- a/browser/main/lib/dataApi/updateNote.js +++ b/browser/main/lib/dataApi/updateNote.js @@ -104,6 +104,7 @@ function updateNote (storageKey, noteKey, input) { noteData.isStarred = false noteData.isTrashed = false noteData.tags = [] + noteData.isPinned = false } if (noteData.type === 'SNIPPET_NOTE') {