From 6c542750f4f68ed88726b196dc5871b6a5060806 Mon Sep 17 00:00:00 2001 From: bimlas Date: Mon, 26 Mar 2018 16:48:07 +0200 Subject: [PATCH] Narrow list of tags to related ones When a tag is selected, the tag list narrows to show only the related ones: all tags associated to the currently visible notes. Clicking on the plus sign near another tag narrows the list again to the tags of notes associated with the firstly AND secondly selected tag. To show every tags again, press the tag icon on the top-left corner of Boostnote. Before: ![screencast](https://i.imgur.com/PwAdhLe.gif) After: ![screencast](https://i.imgur.com/s3JCaFq.gif) NOTE: Tags are joined with `&` character (`#` not works) in `location.pathname` thus it will make the tags with this character unavailable. Any suggestion to pass multiple values via pathname? --- browser/components/TagListItem.js | 19 ++++++---- browser/components/TagListItem.styl | 37 ++++++++++++++------ browser/main/NoteList/index.js | 3 +- browser/main/SideNav/index.js | 54 +++++++++++++++++++++++++---- browser/main/index.js | 3 ++ 5 files changed, 90 insertions(+), 26 deletions(-) diff --git a/browser/components/TagListItem.js b/browser/components/TagListItem.js index 4346ac21..cbac00ce 100644 --- a/browser/components/TagListItem.js +++ b/browser/components/TagListItem.js @@ -12,13 +12,18 @@ import CSSModules from 'browser/lib/CSSModules' * @param {bool} isActive */ -const TagListItem = ({name, handleClickTagListItem, isActive, count}) => ( - +const TagListItem = ({name, handleClickTagListItem, handleClickNarrowToTag, isActive, count}) => ( +
+ + +
) TagListItem.propTypes = { diff --git a/browser/components/TagListItem.styl b/browser/components/TagListItem.styl index 513d112a..4c5c7379 100644 --- a/browser/components/TagListItem.styl +++ b/browser/components/TagListItem.styl @@ -1,10 +1,10 @@ -.tagList-item +.tagList-itemContainer display flex - width 100% + +.tagList-item, .tagList-itemNarrow height 26px background-color transparent color $ui-inactive-text-color - padding 0 margin-bottom 5px text-align left border none @@ -20,12 +20,18 @@ color $ui-button-default-color background-color $ui-button-default--active-backgroundColor -.tagList-item-active - background-color $ui-button-default--active-backgroundColor +.tagList-item display flex + flex 1 width 100% - height 26px padding 0 + +.tagList-itemNarrow + padding 0 4px + +.tagList-item-active, .tagList-itemNarrow-active + background-color $ui-button-default--active-backgroundColor + height 26px margin-bottom 5px text-align left border none @@ -36,10 +42,19 @@ background-color alpha($ui-button-default--active-backgroundColor, 60%) transition 0.2s +.tagList-item-active + display flex + flex 1 + width 100% + padding 0 + +.tagList-itemNarrow-active + padding 0 4px + .tagList-item-name display block flex 1 - padding 0 15px + padding 0 8px 0 4px height 26px line-height 26px border-width 0 0 0 2px @@ -55,7 +70,7 @@ font-size 13px body[data-theme="white"] - .tagList-item + .tagList-item, .tagList-itemNarrow color $ui-inactive-text-color &:hover color $ui-text-color @@ -64,7 +79,7 @@ body[data-theme="white"] color $ui-text-color background-color $ui-button--active-backgroundColor - .tagList-item-active + .tagList-item-active, .tagList-itemNarrow-active background-color $ui-button--active-backgroundColor color $ui-text-color &:hover @@ -73,7 +88,7 @@ body[data-theme="white"] color $ui-text-color body[data-theme="dark"] - .tagList-item + .tagList-item, .tagList-itemNarrow color $ui-dark-inactive-text-color &:hover color $ui-dark-text-color @@ -82,7 +97,7 @@ body[data-theme="dark"] color $ui-dark-text-color background-color $ui-dark-button--active-backgroundColor - .tagList-item-active + .tagList-item-active, .tagList-itemNarrow-active background-color $ui-dark-button--active-backgroundColor color $ui-dark-text-color &:active diff --git a/browser/main/NoteList/index.js b/browser/main/NoteList/index.js index dedad209..867457ca 100644 --- a/browser/main/NoteList/index.js +++ b/browser/main/NoteList/index.js @@ -343,10 +343,11 @@ class NoteList extends React.Component { } if (location.pathname.match(/\/tags/)) { + const listOfTags = params.tagname.split('&') return data.noteMap.map(note => { return note }).filter(note => { - return note.tags.includes(params.tagname) + return listOfTags.every((tag) => note.tags.includes(tag)) }) } diff --git a/browser/main/SideNav/index.js b/browser/main/SideNav/index.js index f8a65013..a9f9f0da 100644 --- a/browser/main/SideNav/index.js +++ b/browser/main/SideNav/index.js @@ -91,7 +91,7 @@ class SideNav extends React.Component { let component // TagsMode is not selected - if (!location.pathname.match('/tags') && !location.pathname.match('/alltags')) { + if (!location.pathname.match('/tags') && !location.pathname.match('/alltags') && !location.pathname.match('/narrowToTag')) { component = (
({name, size: tag.size})), - ['name'] - ) + const relatedTags = this.getRelatedTags(this.getActiveTags(location.pathname), data.noteMap) + let tagList = _.sortBy(data.tagNoteMap.map((tag, name) => { + return { name, size: tag.size } + }), ['name']).filter(tag => { + return (relatedTags.size === 0) ? true : relatedTags.has(tag.name) + }) if (config.sortTagsBy === 'COUNTER') { tagList = _.sortBy(tagList, item => (0 - item.size)) } @@ -158,6 +160,7 @@ class SideNav extends React.Component { { + return {key: note.key, tags: note.tags} + }).filter((note) => { + return activeTags.every((tag) => note.tags.includes(tag)) + }) + let relatedTags = new Set() + relatedNotes.forEach(note => { + note.tags.map(tag => { + relatedTags.add(tag) + }) + }) + return relatedTags + } + getTagActive (path, tag) { + const pathTag = this.getActiveTags(path) + return pathTag.includes(tag) + } + + getActiveTags (path) { const pathSegments = path.split('/') - const pathTag = pathSegments[pathSegments.length - 1] - return pathTag === tag + const tags = pathSegments[pathSegments.length - 1] + if (tags === 'alltags') { + return [] + } + return tags.split('&') } handleClickTagListItem (name) { @@ -192,6 +218,20 @@ class SideNav extends React.Component { }) } + handleClickNarrowToTag (name) { + const { router } = this.context + const { location } = this.props + let listOfTags = this.getActiveTags(location.pathname) + if (listOfTags.includes(name)) { + listOfTags = listOfTags.filter(function (currentTag) { + return name !== currentTag + }) + } else { + listOfTags.push(name) + } + router.push(`/tags/${listOfTags.join('&')}`) + } + emptyTrash (entries) { const { dispatch } = this.props const deletionPromises = entries.map((note) => { diff --git a/browser/main/index.js b/browser/main/index.js index 6e8bdcc5..02bf7125 100644 --- a/browser/main/index.js +++ b/browser/main/index.js @@ -112,6 +112,9 @@ ReactDOM.render(( + + +