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

new feature: filter tags and folder list

This commit is contained in:
HarlanLuo
2019-01-07 20:18:21 +08:00
committed by amedora
parent 1be208d96b
commit 8dc5214c9e
9 changed files with 240 additions and 35 deletions

View File

@@ -1,5 +1,5 @@
.menu
margin-bottom 30px
margin-bottom 20px
.menu-button
navButtonColor()

View File

@@ -1,7 +1,5 @@
.storageList
absolute left right
bottom 37px
top 180px
margin-bottom 37px
overflow-y auto
.storageList-folded

View File

@@ -1,8 +1,5 @@
.top-menu-preference
navButtonColor()
position absolute
top 22px
right 10px
width 2em
background-color transparent
&:hover

View File

@@ -0,0 +1,22 @@
import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './SearchButton.styl'
import i18n from 'browser/lib/i18n'
const SearchButton = ({ onClick, isActive }) => (
<button styleName='top-menu-search' onClick={(e) => onClick(e)}>
<img
styleName='icon-search'
src={isActive ? '../resources/icon/icon-search-active.svg' : '../resources/icon/icon-search.svg'}
/>
<span styleName='tooltip'>{i18n.__('Search')}</span>
</button>
)
SearchButton.propTypes = {
onClick: PropTypes.func.isRequired,
isActive: PropTypes.bool
}
export default CSSModules(SearchButton, styles)

View File

@@ -0,0 +1,55 @@
.top-menu-search
navButtonColor()
position relative
margin-right 6px
top 3px
width 2em
background-color transparent
&:hover
color $ui-button-default--active-backgroundColor
background-color transparent
.tooltip
opacity 1
&:active, &:active:hover
color $ui-button-default--active-backgroundColor
.icon-search
width 16px
body[data-theme="white"]
.top-menu-search
navWhiteButtonColor()
background-color transparent
&:hover
color #0B99F1
background-color transparent
&:active, &:active:hover
color #0B99F1
background-color transparent
body[data-theme="dark"]
.top-menu-search
navDarkButtonColor()
background-color transparent
&:active
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
background-color transparent
&:hover
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
background-color transparent
.tooltip
tooltip()
position absolute
pointer-events none
top 26px
left -20px
z-index 200
padding 5px
line-height normal
border-radius 2px
opacity 0
transition 0.1s
white-space nowrap

View File

@@ -18,7 +18,37 @@
display flex
text-align center
.extra-buttons
position absolute
display flex
align-items center
justify-content flex-end
right 10px
top 24px
.search
position relative
flex 1
display flex
max-height 0
overflow hidden
transition max-height .4s
margin -5px 10px 0
.search-input
flex 1
height 2em
vertical-align middle
font-size 14px
border solid 1px $border-color
border-radius 2px
padding 2px 6px
outline none
.search-clear
width 10px
position absolute
right 8px
top 9px
cursor pointer
.top-menu-label
margin-left 5px
@@ -98,6 +128,17 @@
.top-menu-preference
position absolute
left 7px
.search
height 28px
.search-input
display none
.search-clear
display none
.search-folded
width 16px
padding-left 4px
margin-bottom 8px
cursor pointer
body[data-theme="white"]
.root, .root--folded

View File

@@ -13,6 +13,7 @@ import StorageList from 'browser/components/StorageList'
import NavToggleButton from 'browser/components/NavToggleButton'
import EventEmitter from 'browser/main/lib/eventEmitter'
import PreferenceButton from './PreferenceButton'
import SearchButton from './SearchButton'
import ListButton from './ListButton'
import TagButton from './TagButton'
import {SortableContainer} from 'react-sortable-hoc'
@@ -36,21 +37,26 @@ class SideNav extends React.Component {
show: false,
color: null,
tagName: null,
targetRect: null
targetRect: null,
showSearch: false,
searchText: ''
}
}
this.dismissColorPicker = this.dismissColorPicker.bind(this)
this.handleColorPickerConfirm = this.handleColorPickerConfirm.bind(this)
this.handleColorPickerReset = this.handleColorPickerReset.bind(this)
this.handleSearchButtonClick = this.handleSearchButtonClick.bind(this)
this.handleSearchInputChange = this.handleSearchInputChange.bind(this)
this.handleSearchInputClear = this.handleSearchInputClear.bind(this)
}
componentDidMount () {
EventEmitter.on('side:preferences', this.handleMenuButtonClick)
EventEmitter.on('side:preferences', this.handlePreferenceButtonClick)
}
componentWillUnmount () {
EventEmitter.off('side:preferences', this.handleMenuButtonClick)
EventEmitter.off('side:preferences', this.handlePreferenceButtonClick)
}
deleteTag (tag) {
@@ -99,10 +105,30 @@ class SideNav extends React.Component {
}
}
handleMenuButtonClick (e) {
handlePreferenceButtonClick (e) {
openModal(PreferencesModal)
}
handleSearchButtonClick (e) {
const { showSearch } = this.state
this.setState({
showSearch: !showSearch,
searchText: ''
})
}
handleSearchInputClear (e) {
this.setState({
searchText: ''
})
}
handleSearchInputChange (e) {
this.setState({
searchText: e.target.value
})
}
handleHomeButtonClick (e) {
const { router } = this.context
router.push('/home')
@@ -181,12 +207,19 @@ class SideNav extends React.Component {
handleToggleButtonClick (e) {
const { dispatch, config } = this.props
const { showSearch, searchText } = this.state
ConfigManager.set({isSideNavFolded: !config.isSideNavFolded})
dispatch({
type: 'SET_IS_SIDENAV_FOLDED',
isFolded: !config.isSideNavFolded
})
if (showSearch && searchText.length === 0) {
this.setState({
showSearch: false
})
}
}
handleTrashedButtonClick (e) {
@@ -215,8 +248,9 @@ class SideNav extends React.Component {
}
}
SideNavComponent (isFolded, storageList) {
const { location, data, config } = this.props
SideNavComponent (isFolded) {
const { location, data, config, dispatch } = this.props
const { showSearch, searchText } = this.state
const isHomeActive = !!location.pathname.match(/^\/home$/)
const isStarredActive = !!location.pathname.match(/^\/starred$/)
@@ -226,6 +260,28 @@ class SideNav extends React.Component {
// TagsMode is not selected
if (!location.pathname.match('/tags') && !location.pathname.match('/alltags')) {
let storageMap = data.storageMap
if (showSearch && searchText.length > 0) {
storageMap = storageMap.map((storage) => {
const folders = storage.folders.filter(folder => folder.name.toLowerCase().indexOf(searchText.toLowerCase()) !== -1)
return Object.assign({}, storage, { folders })
})
}
const storageList = storageMap.map((storage, key) => {
const SortableStorageItem = SortableContainer(StorageItem)
return <SortableStorageItem
key={storage.key}
storage={storage}
data={data}
location={location}
isFolded={isFolded}
dispatch={dispatch}
onSortEnd={this.onSortEnd.bind(this)(storage)}
useDragHandle
/>
})
component = (
<div>
<SideNavFilter
@@ -279,7 +335,7 @@ class SideNav extends React.Component {
tagListComponent () {
const { data, location, config } = this.props
const { colorPicker } = this.state
const { colorPicker, showSearch, searchText } = this.state
const activeTags = this.getActiveTags(location.pathname)
const relatedTags = this.getRelatedTags(activeTags, data.noteMap)
let tagList = _.sortBy(data.tagNoteMap.map(
@@ -287,6 +343,9 @@ class SideNav extends React.Component {
).filter(
tag => tag.size > 0
), ['name'])
if (showSearch && searchText.length > 0) {
tagList = tagList.filter(tag => tag.name.toLowerCase().indexOf(searchText.toLowerCase()) !== -1)
}
if (config.ui.enableLiveNoteCounts && activeTags.length !== 0) {
const notesTags = data.noteMap.map(note => note.tags)
tagList = tagList.map(tag => {
@@ -406,24 +465,8 @@ class SideNav extends React.Component {
}
render () {
const { data, location, config, dispatch } = this.props
const { colorPicker: colorPickerState } = this.state
const isFolded = config.isSideNavFolded
const storageList = data.storageMap.map((storage, key) => {
const SortableStorageItem = SortableContainer(StorageItem)
return <SortableStorageItem
key={storage.key}
storage={storage}
data={data}
location={location}
isFolded={isFolded}
dispatch={dispatch}
onSortEnd={this.onSortEnd.bind(this)(storage)}
useDragHandle
/>
})
const { location, config } = this.props
const { showSearch, searchText, colorPicker: colorPickerState } = this.state
let colorPicker
if (colorPickerState.show) {
@@ -438,9 +481,25 @@ class SideNav extends React.Component {
)
}
const isFolded = config.isSideNavFolded
const style = {}
if (!isFolded) style.width = this.props.width
const isTagActive = location.pathname.match(/tag/)
const navSearch = (
<div styleName='search' style={{maxHeight: showSearch ? '3em' : '0'}}>
<input
styleName='search-input'
type='text'
ref={dom => { this.searchInput = dom }}
onChange={this.handleSearchInputChange}
value={searchText}
/>
<img styleName='search-clear' src='../resources/icon/icon-x.svg' onClick={this.handleSearchInputClear} />
{isFolded && <img styleName='search-folded' src='../resources/icon/icon-search-active.svg' onClick={this.handleSearchButtonClick} />}
</div>
)
return (
<div className='SideNav'
styleName={isFolded ? 'root--folded' : 'root'}
@@ -452,11 +511,16 @@ class SideNav extends React.Component {
<ListButton onClick={this.handleSwitchFoldersButtonClick.bind(this)} isTagActive={isTagActive} />
<TagButton onClick={this.handleSwitchTagsButtonClick.bind(this)} isTagActive={isTagActive} />
</div>
<div>
<PreferenceButton onClick={this.handleMenuButtonClick} />
<div styleName='extra-buttons'>
<SearchButton
onClick={this.handleSearchButtonClick}
isActive={showSearch}
/>
<PreferenceButton onClick={this.handlePreferenceButtonClick} />
</div>
</div>
{this.SideNavComponent(isFolded, storageList)}
{navSearch}
{this.SideNavComponent(isFolded)}
{colorPicker}
</div>
)

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1546833265368" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="1101" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200">
<defs>
<style type="text/css"></style>
</defs>
<path
d="M384 768c-213.333333 0-384-170.666667-384-384s170.666667-384 384-384 384 170.666667 384 384S597.333333 768 384 768zM384 85.333333C217.6 85.333333 85.333333 217.6 85.333333 384s132.266667 298.666667 298.666667 298.666667 298.666667-132.266667 298.666667-298.666667S550.4 85.333333 384 85.333333z"
p-id="1102" fill="#1EC38B"></path>
<path
d="M981.333333 1024c-12.8 0-21.333333-4.266667-29.866667-12.8l-341.333333-341.333333c-17.066667-17.066667-17.066667-42.666667 0-59.733333s42.666667-17.066667 59.733333 0l341.333333 341.333333c17.066667 17.066667 17.066667 42.666667 0 59.733333C1002.666667 1019.733333 994.133333 1024 981.333333 1024z"
p-id="1103" fill="#1EC38B"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg t="1546833265368" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="1101" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200">
<defs>
<style type="text/css"></style>
</defs>
<path
d="M384 768c-213.333333 0-384-170.666667-384-384s170.666667-384 384-384 384 170.666667 384 384S597.333333 768 384 768zM384 85.333333C217.6 85.333333 85.333333 217.6 85.333333 384s132.266667 298.666667 298.666667 298.666667 298.666667-132.266667 298.666667-298.666667S550.4 85.333333 384 85.333333z"
p-id="1102" fill="#8A8C8D"></path>
<path
d="M981.333333 1024c-12.8 0-21.333333-4.266667-29.866667-12.8l-341.333333-341.333333c-17.066667-17.066667-17.066667-42.666667 0-59.733333s42.666667-17.066667 59.733333 0l341.333333 341.333333c17.066667 17.066667 17.066667 42.666667 0 59.733333C1002.666667 1019.733333 994.133333 1024 981.333333 1024z"
p-id="1103" fill="#8A8C8D"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB