Skip to content

Commit 0557232

Browse files
committed
feat: add menu to telemetry page and keyboard shortcut for representative filter input (fixes #94)
1 parent 673dda6 commit 0557232

File tree

7 files changed

+105
-42
lines changed

7 files changed

+105
-42
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@
156156
"eslint-plugin-react": "7.33.0",
157157
"file-loader": "^6.2.0",
158158
"highlight.js": "^11.8.0",
159+
"hotkeys-js": "^3.13.7",
159160
"html-inline-script-webpack-plugin": "^2.0.3",
160161
"html-loader": "^2.1.2",
161162
"html-webpack-plugin": "^5.5.3",
Lines changed: 61 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,83 @@
1-
import React from 'react'
1+
import React, { useState, useEffect, useRef } from 'react'
22
import PropTypes from 'prop-types'
33
import ClearIcon from '@mui/icons-material/Clear'
4+
import KeyboardCommandKeyIcon from '@mui/icons-material/KeyboardCommandKey'
5+
import hotkeys from 'hotkeys-js'
46

57
import { debounce } from '@core/utils'
68

79
import './representatives-search.styl'
810

9-
export default class RepresentativesSearch extends React.Component {
10-
constructor(props) {
11-
super(props)
11+
const RepresentativesSearch = ({
12+
value: initialValue,
13+
search,
14+
align = 'center'
15+
}) => {
16+
const [value, setValue] = useState(initialValue || '')
17+
const inputRef = useRef(null)
1218

13-
this.state = {
14-
value: this.props.value || ''
19+
const debouncedSearch = debounce((value) => {
20+
search(value)
21+
}, 300)
22+
23+
useEffect(() => {
24+
const handleHotkeys = (event, handler) => {
25+
event.preventDefault()
26+
inputRef.current.focus()
1527
}
1628

17-
this.search = debounce((value) => {
18-
this.props.search(value)
19-
}, 300)
20-
}
29+
hotkeys('command+k,ctrl+k', handleHotkeys)
2130

22-
handleClick = () => {
23-
const value = ''
24-
this.setState({ value })
25-
this.props.search(value)
31+
return () => {
32+
hotkeys.unbind('command+k,ctrl+k')
33+
}
34+
}, [])
35+
36+
const handleClick = () => {
37+
setValue('')
38+
search('')
2639
}
2740

28-
handleChange = (event) => {
41+
const handleChange = (event) => {
2942
const { value } = event.target
30-
this.setState({ value })
31-
this.search(value)
43+
setValue(value)
44+
debouncedSearch(value)
3245
}
3346

34-
render = () => {
35-
return (
36-
<div className='representatives__search'>
37-
<input
38-
className='search__input'
39-
type='text'
40-
placeholder='Filter by account, alias, ip'
41-
value={this.state.value}
42-
onChange={this.handleChange}
43-
/>
44-
{this.state.value && (
45-
<div className='search__input-clear' onClick={this.handleClick}>
46-
<ClearIcon />
47-
</div>
48-
)}
49-
</div>
50-
)
47+
const classNames = ['representatives__search']
48+
49+
if (align === 'left') {
50+
classNames.push('left')
51+
} else {
52+
classNames.push('center')
5153
}
54+
55+
return (
56+
<div className={classNames.join(' ')}>
57+
<input
58+
ref={inputRef}
59+
className='search__input'
60+
type='text'
61+
placeholder='Filter by account, alias, ip'
62+
value={value}
63+
onChange={handleChange}
64+
/>
65+
<div className='search__shortcut-icon'>
66+
<KeyboardCommandKeyIcon fontSize='small' />K
67+
</div>
68+
{value && (
69+
<div className='search__input-clear' onClick={handleClick}>
70+
<ClearIcon />
71+
</div>
72+
)}
73+
</div>
74+
)
5275
}
5376

5477
RepresentativesSearch.propTypes = {
5578
value: PropTypes.string,
56-
search: PropTypes.func
79+
search: PropTypes.func,
80+
align: PropTypes.oneOf(['left', 'center'])
5781
}
82+
83+
export default RepresentativesSearch

src/views/components/representatives-search/representatives-search.styl

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,31 @@
33
width 380px
44
min-width 160px
55
max-width 400px
6-
margin 8px
7-
margin-right 8px
8-
border-radius 99em
6+
border-radius 6px
97
overflow hidden
108
position relative
119
display flex
1210
align-items center
1311
background white
12+
13+
&.center
14+
margin 8px auto
15+
16+
&.left
17+
margin 8px
18+
19+
.search__shortcut-icon
20+
display flex
21+
align-items center
22+
justify-content center
23+
padding 4px
24+
cursor pointer
25+
margin-right 4px
26+
27+
border 1px solid #e0e0e0
28+
border-radius 6px
29+
30+
.MuiSvgIcon-root
31+
width 14px
32+
height 14px
33+

src/views/pages/representatives/representatives.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,10 @@ export default class RepresentativesPage extends React.Component {
8585
<RepresentativesCountryByWeight />
8686
</div>
8787
<div className='representatives__body'>
88-
<RepresentativesSearch />
89-
<RepresentativesFilters />
88+
<div className='representatives__body-header'>
89+
<RepresentativesSearch align='left' />
90+
<RepresentativesFilters />
91+
</div>
9092
<Representatives />
9193
<div className='representatives__metrics'>
9294
<Tabs

src/views/pages/representatives/representatives.styl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
margin 0 auto
1111
max-width 1300px
1212

13+
.representatives__body-header
14+
flex 1
15+
display flex
16+
1317
.representatives__metrics
1418
width 100%
1519
max-width 1100px

src/views/pages/telemetry/telemetry.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,13 @@ export default function TelemetryPage() {
5252
]}
5353
/>
5454
<div className='representatives__body'>
55-
<RepresentativesSearch />
55+
<div className='representatives__body-header'>
56+
<RepresentativesSearch />
57+
</div>
5658
<Representatives table_height={table_height} />
5759
</div>
5860
<div className='representatives__footer'>
59-
<Menu hide_speed_dial={true} />
61+
<Menu />
6062
</div>
6163
</>
6264
)

yarn.lock

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9841,6 +9841,13 @@ __metadata:
98419841
languageName: node
98429842
linkType: hard
98439843

9844+
"hotkeys-js@npm:^3.13.7":
9845+
version: 3.13.7
9846+
resolution: "hotkeys-js@npm:3.13.7"
9847+
checksum: 8c1da52704c1c2a97810d0d2c9d0917b87a7edd250aae79cd4b185b9374b2ddc7ba24eeec8491018ba51726b72faecf89042fede2b3a05d0599f334355bb968c
9848+
languageName: node
9849+
linkType: hard
9850+
98449851
"hpack.js@npm:^2.1.6":
98459852
version: 2.1.6
98469853
resolution: "hpack.js@npm:2.1.6"
@@ -15711,6 +15718,7 @@ __metadata:
1571115718
front-matter: ^4.0.2
1571215719
fs-extra: ^11.1.1
1571315720
highlight.js: ^11.8.0
15721+
hotkeys-js: ^3.13.7
1571415722
html-inline-script-webpack-plugin: ^2.0.3
1571515723
html-loader: ^2.1.2
1571615724
html-webpack-plugin: ^5.5.3

0 commit comments

Comments
 (0)