search button
Massimo Melina committed
Dec 21, 2021 at 09:48 UTC
bf0533a6993d04829900602e62fdf2436c77b61b
6 files changed
+58
-15
frontend/src/BrowseFiles.ts
+7
-2
@@ -30,12 +30,17 @@ function useFetchList() {
30
const [preloading, setPreloading] = useState(true)
31
const [path, setPath] = useState('')
32
useEffect(()=>{
33
+ const loc = window.location
34
+ if (!desiredPath.endsWith('/')) // useful only in dev, while accessing the frontend directly without passing by the main server
35
+ loc.href = loc.href+'/'
36
setPreloading(true)
37
setPath(desiredPath)
38
}, [desiredPath])
39
const API = 'file_list'
37
- const preload = useApi(path && API, { path, limit: PRELOAD_SIZE })
38
- const rest = useApi(!preloading && API, { path, offset: PRELOAD_SIZE })
40
+ const snap = useSnapState()
41
+ const search = snap.remoteSearch
42
+ const preload = useApi(path && API, { path, search, limit: PRELOAD_SIZE })
43
+ const rest = useApi(!preloading && API, { path, search, offset: PRELOAD_SIZE })
44
const list = useMemo(() => !preload ? null
45
: !rest ? (preload.list||preload) // the || is for an Error instance
46
: [...preload.list, ...rest.list],
frontend/src/Head.ts
+32
-6
@@ -18,33 +18,59 @@ export function Head() {
18
}
19
20
function MenuPanel() {
21
- const [showFilter, setShowFilter] = useState(false)
22
- const [filter, setFilter] = useState('')
21
+ const [showFilter, setShowFilter] = useState(state.listFilter > '')
22
+ const [showSearch, setShowSearch] = useState(state.remoteSearch > '')
23
+ const [filter, setFilter] = useState(state.listFilter)
24
+ const [search, setSearch] = useState(state.remoteSearch)
25
;[state.listFilter] = useDebounce(filter, 300)
26
+ ;[state.remoteSearch] = useDebounce(search, 1000)
27
+ if (!showFilter)
28
+ state.listFilter = ''
29
+ if (!showSearch)
30
+ state.remoteSearch = ''
31
return h('div', { id:'menu-panel' },
32
h('div', { id:'menu-bar' },
33
h(LoginButton),
34
h(MenuButton, {
35
icon: 'filter',
36
label: 'Filter',
37
+ toggled: showFilter,
38
onClick() {
39
setShowFilter(!showFilter)
40
}
41
+ }),
42
+ h(MenuButton, {
43
+ icon: 'search',
44
+ label: 'Search',
45
+ toggled: showSearch,
46
+ onClick() {
47
+ setShowSearch(!showSearch)
48
+ }
49
})
50
),
51
showFilter && h('input',{
36
- id:'filter',
52
+ id: 'filter',
53
+ placeholder: 'Filter',
54
value: filter,
55
autoFocus: true,
56
onChange(ev) {
57
setFilter(ev.target.value)
58
}
42
- })
59
+ }),
60
+ showSearch && h('input',{
61
+ id: 'search',
62
+ placeholder: 'Search',
63
+ value: search,
64
+ autoFocus: true,
65
+ onChange(ev) {
66
+ setSearch(ev.target.value)
67
+ }
68
+ }),
69
)
70
}
71
46
-function MenuButton({ icon, label, onClick }:{ icon:string, label:string, onClick?:()=>void }) {
47
- return h('button', { title:label, onClick },
72
+function MenuButton({ icon, label, toggled, onClick }:{ icon:string, label:string, toggled?:boolean, onClick?:()=>void }) {
73
+ return h('button', { title:label, onClick, className:toggled ? 'toggled' : '' },
74
hIcon(icon),
75
h('label',{}, label))
76
}
frontend/src/index.scss
+13
-3
@@ -32,6 +32,9 @@ button {
32
vertical-align: middle;
33
cursor: pointer;
34
}
35
+button.toggled {
36
+ background-color: #79b;
37
+}
38
39
.error-msg {
40
background-color: #faa;
@@ -69,11 +72,10 @@ header {
72
position: sticky;
73
top: 0;
74
}
72
-#filter {
73
- width: calc(100% - 0.5em);
75
+header input {
76
+ width: 100%;
77
margin: 0.2em auto;
78
box-sizing: border-box;
76
- display: block;
79
}
80
81
ul.dir {
@@ -111,9 +113,17 @@ ul.dir {
113
}
114
115
#menu-panel {
116
+ margin: .1em;
117
margin-bottom: .2em;
118
+ & button {
119
+ margin: 0.1em;
120
+ }
121
& button label {
122
cursor: inherit;
123
margin-left: 0.8em;
124
}
125
}
126
+
127
+@media (max-width: 50em) {
128
+ #menu-bar button:nth-child(1n+2) label { display: none } /* icons only */
129
+}
frontend/src/state.ts
+1
@@ -3,6 +3,7 @@ import { proxy, useSnapshot } from 'valtio'
3
export const state = proxy({
4
username: '',
5
listFilter: '',
6
+ remoteSearch: '',
7
filteredEntries: -1,
8
})
9
todo.md
renamed
+3
-4
@@ -1,7 +1,6 @@
1
# To do
2
-- search
3
- try to use server-sent events for the reply
4
- https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events
2
+- search: try to use server-sent events for the reply
3
+ https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events
4
- file_list: option to decide what fields to get. If m && !c but we have no m, then copy from c.
5
- api: gzip for >5kb
6
- frontend: dialogs
@@ -13,7 +12,7 @@
12
- don't depend on cdn
13
- webdav?
14
- streamable zip archives
16
- - no compression
15
+ - no compression
16
- resumable?
17
- vfs: ability to remove/hide/rename files deep in a source
18
- let user change password
vfs.yaml
+2
@@ -10,3 +10,5 @@ children:
10
- name: for-rejetto
11
perm:
12
rejetto: r
13
+ children:
14
+ - source: tests/alfa.txt