Skip to content

Commit 6c67b96

Browse files
committed
search
1 parent b6d3447 commit 6c67b96

3 files changed

Lines changed: 148 additions & 22 deletions

File tree

browser/main/Main.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ class Main extends React.Component {
102102
'dispatch',
103103
'storages',
104104
'config',
105+
'notes',
105106
'params',
106107
'location'
107108
])}

browser/main/TopBar/TopBar.styl

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,46 @@ $control-height = 34px
3636
outline none
3737
border none
3838

39+
.control-search-optionList
40+
position fixed
41+
z-index 200
42+
width 275px
43+
height 175px
44+
overflow-y auto
45+
background-color $modal-background
46+
border-radius 2px
47+
box-shadow 2px 2px 10px gray
48+
49+
.control-search-optionList-item
50+
height 50px
51+
border-bottom $ui-border
52+
transition background-color 0.15s
53+
padding 5px
54+
cursor pointer
55+
overflow ellipsis
56+
&:hover
57+
background-color alpha($ui-active-color, 10%)
58+
.control-search-optionList-item-folder
59+
border-left 4px solid transparent
60+
padding 2px 5px
61+
color $ui-text-color
62+
overflow ellipsis
63+
font-size 12px
64+
height 16px
65+
margin-bottom 4px
66+
.control-search-optionList-item-folder-surfix
67+
font-size 10px
68+
margin-left 5px
69+
color $ui-inactive-text-color
70+
.control-search-optionList-item-type
71+
font-size 12px
72+
color $ui-inactive-text-color
73+
padding-right 3px
74+
.control-search-optionList-empty
75+
height 150px
76+
color $ui-inactive-text-color
77+
line-height 150px
78+
text-align center
3979
.control-newPostButton
4080
display block
4181
absolute top right bottom
@@ -51,7 +91,6 @@ $control-height = 34px
5191
&:hover .left-control-newPostButton-tooltip
5292
display block
5393

54-
5594
.control-newPostButton-tooltip
5695
position fixed
5796
line-height 1.4

browser/main/TopBar/index.js

Lines changed: 107 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Commander from 'browser/main/lib/Commander'
77
import dataApi from 'browser/main/lib/dataApi'
88
import modal from 'browser/main/lib/modal'
99
import NewNoteModal from 'browser/main/modals/NewNoteModal'
10+
import { hashHistory } from 'react-router'
1011

1112
const OSX = window.process.platform === 'darwin'
1213

@@ -15,25 +16,12 @@ class TopBar extends React.Component {
1516
super(props)
1617

1718
this.state = {
18-
search: ''
19+
search: '',
20+
searchOptions: [],
21+
searchPopupOpen: false
1922
}
2023
}
2124

22-
isInputFocused () {
23-
return document.activeElement === this.refs.searchInput
24-
}
25-
26-
escape () {
27-
}
28-
29-
focusInput () {
30-
this.searchInput.focus()
31-
}
32-
33-
blurInput () {
34-
this.searchInput.blur()
35-
}
36-
3725
handleNewPostButtonClick (e) {
3826
let { storages, params, dispatch, location } = this.props
3927
let storage = _.find(storages, {key: params.storageKey})
@@ -51,11 +39,98 @@ class TopBar extends React.Component {
5139
})
5240
}
5341

54-
handleTutorialButtonClick (e) {
42+
handleSearchChange (e) {
43+
this.setState({
44+
search: this.refs.searchInput.value
45+
})
46+
}
47+
48+
getOptions () {
49+
let { notes } = this.props
50+
let { search } = this.state
51+
if (search.trim().length === 0) return []
52+
let searchBlocks = search.split(' ')
53+
searchBlocks.forEach((block) => {
54+
if (block.match(/^#.+/)) {
55+
let tag = block.match(/#(.+)/)[1]
56+
notes = notes.filter((note) => note.tags.some((_tag) => _tag === tag))
57+
}
58+
notes = notes.filter((note) => {
59+
if (note.type === 'SNIPPET_NOTE') {
60+
return note.description.match(block)
61+
} else if (note.type === 'MARKDOWN_NOTE') {
62+
return note.content.match(block)
63+
}
64+
return false
65+
})
66+
})
67+
68+
return notes
69+
}
70+
71+
handleOptionClick (uniqueKey) {
72+
return (e) => {
73+
this.setState({
74+
searchPopupOpen: false
75+
}, () => {
76+
let { location } = this.props
77+
hashHistory.push({
78+
pathname: location.pathname,
79+
query: {
80+
key: uniqueKey
81+
}
82+
})
83+
})
84+
}
85+
}
86+
87+
handleSearchFocus (e) {
88+
this.setState({
89+
searchPopupOpen: true
90+
})
91+
}
92+
handleSearchBlur (e) {
93+
e.stopPropagation()
94+
95+
let el = e.relatedTarget
96+
let isStillFocused = false
97+
while (el != null) {
98+
if (el === this.refs.search) {
99+
isStillFocused = true
100+
break
101+
}
102+
el = el.parentNode
103+
}
104+
if (!isStillFocused) {
105+
this.setState({
106+
searchPopupOpen: false
107+
})
108+
}
55109
}
56110

57111
render () {
58-
let { config, style } = this.props
112+
let { config, style, storages } = this.props
113+
let searchOptionList = this.getOptions()
114+
.map((note) => {
115+
let storage = _.find(storages, {key: note.storage})
116+
let folder = _.find(storage.folders, {key: note.folder})
117+
return <div styleName='control-search-optionList-item'
118+
key={note.uniqueKey}
119+
onClick={(e) => this.handleOptionClick(note.uniqueKey)(e)}
120+
>
121+
<div styleName='control-search-optionList-item-folder'
122+
style={{borderColor: folder.color}}>
123+
{folder.name}
124+
<span styleName='control-search-optionList-item-folder-surfix'>in {storage.name}</span>
125+
</div>
126+
{note.type === 'SNIPPET_NOTE'
127+
? <i styleName='control-search-optionList-item-type' className='fa fa-code'/>
128+
: <i styleName='control-search-optionList-item-type' className='fa fa-file-text-o'/>
129+
}&nbsp;
130+
{note.title}
131+
</div>
132+
})
133+
59134
return (
60135
<div className='TopBar'
61136
styleName={config.isSideNavFolded ? 'root--expanded' : 'root'}
@@ -64,16 +139,27 @@ class TopBar extends React.Component {
64139
<div styleName='control'>
65140
<div styleName='control-search'>
66141
<i styleName='control-search-icon' className='fa fa-search fa-fw'/>
67-
<div styleName='control-search-input'>
142+
<div styleName='control-search-input'
143+
onFocus={(e) => this.handleSearchFocus(e)}
144+
onBlur={(e) => this.handleSearchBlur(e)}
145+
tabIndex='-1'
146+
ref='search'
147+
>
68148
<input
69149
ref='searchInput'
70-
onFocus={(e) => this.handleSearchChange(e)}
71-
onBlur={(e) => this.handleSearchChange(e)}
72150
value={this.state.search}
73151
onChange={(e) => this.handleSearchChange(e)}
74152
placeholder='Search'
75153
type='text'
76154
/>
155+
{this.state.searchPopupOpen &&
156+
<div styleName='control-search-optionList'>
157+
{searchOptionList.length > 0
158+
? searchOptionList
159+
: <div styleName='control-search-optionList-empty'>Empty List</div>
160+
}
161+
</div>
162+
}
77163
</div>
78164
{this.state.search > 0 &&
79165
<button styleName='left-search-clearButton'

0 commit comments

Comments
 (0)