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