From 8dc5214c9e10f5e683385b64d54292cad8c027c0 Mon Sep 17 00:00:00 2001 From: HarlanLuo Date: Mon, 7 Jan 2019 20:18:21 +0800 Subject: [PATCH] new feature: filter tags and folder list --- browser/components/SideNavFilter.styl | 2 +- browser/components/StorageList.styl | 4 +- browser/main/SideNav/PreferenceButton.styl | 3 - browser/main/SideNav/SearchButton.js | 22 ++++ browser/main/SideNav/SearchButton.styl | 55 ++++++++++ browser/main/SideNav/SideNav.styl | 41 +++++++ browser/main/SideNav/index.js | 120 ++++++++++++++++----- resources/icon/icon-search-active.svg | 14 +++ resources/icon/icon-search.svg | 14 +++ 9 files changed, 240 insertions(+), 35 deletions(-) create mode 100644 browser/main/SideNav/SearchButton.js create mode 100644 browser/main/SideNav/SearchButton.styl create mode 100644 resources/icon/icon-search-active.svg create mode 100644 resources/icon/icon-search.svg diff --git a/browser/components/SideNavFilter.styl b/browser/components/SideNavFilter.styl index 1da8c7e4..d5435a16 100644 --- a/browser/components/SideNavFilter.styl +++ b/browser/components/SideNavFilter.styl @@ -1,5 +1,5 @@ .menu - margin-bottom 30px + margin-bottom 20px .menu-button navButtonColor() diff --git a/browser/components/StorageList.styl b/browser/components/StorageList.styl index 474f896b..61fe195c 100644 --- a/browser/components/StorageList.styl +++ b/browser/components/StorageList.styl @@ -1,7 +1,5 @@ .storageList - absolute left right - bottom 37px - top 180px + margin-bottom 37px overflow-y auto .storageList-folded diff --git a/browser/main/SideNav/PreferenceButton.styl b/browser/main/SideNav/PreferenceButton.styl index 54513cb6..12cb9267 100644 --- a/browser/main/SideNav/PreferenceButton.styl +++ b/browser/main/SideNav/PreferenceButton.styl @@ -1,8 +1,5 @@ .top-menu-preference navButtonColor() - position absolute - top 22px - right 10px width 2em background-color transparent &:hover diff --git a/browser/main/SideNav/SearchButton.js b/browser/main/SideNav/SearchButton.js new file mode 100644 index 00000000..e9643128 --- /dev/null +++ b/browser/main/SideNav/SearchButton.js @@ -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 }) => ( + +) + +SearchButton.propTypes = { + onClick: PropTypes.func.isRequired, + isActive: PropTypes.bool +} + +export default CSSModules(SearchButton, styles) diff --git a/browser/main/SideNav/SearchButton.styl b/browser/main/SideNav/SearchButton.styl new file mode 100644 index 00000000..76d4b806 --- /dev/null +++ b/browser/main/SideNav/SearchButton.styl @@ -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 diff --git a/browser/main/SideNav/SideNav.styl b/browser/main/SideNav/SideNav.styl index 9fa6d4fa..f6b4582b 100644 --- a/browser/main/SideNav/SideNav.styl +++ b/browser/main/SideNav/SideNav.styl @@ -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 diff --git a/browser/main/SideNav/index.js b/browser/main/SideNav/index.js index 640bedbf..de70861a 100644 --- a/browser/main/SideNav/index.js +++ b/browser/main/SideNav/index.js @@ -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 + }) + component = (
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 - }) + 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 = ( +
+ { this.searchInput = dom }} + onChange={this.handleSearchInputChange} + value={searchText} + /> + + {isFolded && } +
+ ) + return (
-
- +
+ +
- {this.SideNavComponent(isFolded, storageList)} + {navSearch} + {this.SideNavComponent(isFolded)} {colorPicker}
) diff --git a/resources/icon/icon-search-active.svg b/resources/icon/icon-search-active.svg new file mode 100644 index 00000000..f8cace73 --- /dev/null +++ b/resources/icon/icon-search-active.svg @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/resources/icon/icon-search.svg b/resources/icon/icon-search.svg new file mode 100644 index 00000000..d2181a34 --- /dev/null +++ b/resources/icon/icon-search.svg @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file