frontend: "select all" button
Massimo Melina committed
Mar 18, 2022 at 20:17 UTC
f60c7880a13c01cf716228ed3efda27c4e8ee731
5 files changed
+38
-22
frontend/src/BrowseFiles.ts
+1
-5
@@ -2,7 +2,7 @@
2
3
import { Link, useLocation } from 'react-router-dom'
4
import { createElement as h, Fragment, memo, useEffect, useMemo, useState } from 'react'
5
-import { formatBytes, hError, hfsEvent, hIcon } from './misc'
5
+import { formatBytes, hError, hfsEvent, hIcon, isMobile } from './misc'
6
import { Checkbox, Html, Spinner } from './components'
7
import { Head } from './Head'
8
import { state, useSnapState } from './state'
@@ -85,10 +85,6 @@ function useMidnight() {
85
}
86
}
87
88
-function isMobile() {
89
- return window.innerWidth < 800
90
-}
91
-
88
const Entry = memo(function(entry: DirEntry & { midnight: Date }) {
89
let { n: relativePath, isFolder } = entry
90
const base = usePath()
frontend/src/icons.ts
+1
@@ -22,6 +22,7 @@ const SYS_ICONS = {
22
download: ':📥',
23
invert: 'retweet:🙃',
24
admin: 'crown:👑',
25
+ check: ':✔️',
26
}
27
28
document.fonts.ready.then(async ()=> {
frontend/src/index.scss
+10
-4
@@ -155,6 +155,7 @@ header input {
155
#filter-bar {
156
display: flex;
157
gap: .3em;
158
+ margin: 0.5em 0;
159
& input { flex: 1 }
160
& button {
161
padding: 0 0.5em;
@@ -206,6 +207,11 @@ ul.dir {
207
margin: 0.1em;
208
}
209
}
210
+#menu-bar {
211
+ display: flex;
212
+ justify-content: space-evenly;
213
+ flex-wrap: wrap;
214
+}
215
#searched {
216
margin: .2em;
217
}
@@ -264,14 +270,14 @@ button label {
270
border: 1px solid var(--faint-contrast)
271
}
272
267
-@media (max-width: 40em) {
273
+@media (max-width: 42em) {
274
body, button, select { font-size: 14pt; }
275
#menu-bar {
270
- display: flex;
271
- justify-content: space-between;
272
- align-content: stretch;
276
& button label { display: none } /* icons only */
277
}
278
+ #filter-bar {
279
+ margin: 0.2em 0;
280
+ }
281
#filter-bar label { display:none }
282
#filter-bar button { /* make it same size of top bar */
283
width: 17.6vw;
frontend/src/menu.ts
+22
-13
@@ -4,7 +4,7 @@ import { state, useSnapState } from './state'
4
import { createElement as h, useEffect, useState } from 'react'
5
import { useDebounce } from 'use-debounce'
6
import { confirmDialog, promptDialog } from './dialog'
7
-import { hIcon, prefix } from './misc'
7
+import { hIcon, isMobile, prefix } from './misc'
8
import { login } from './login'
9
import { showOptions } from './options'
10
import showUserPanel from './UserPanel'
@@ -34,7 +34,7 @@ export function MenuPanel() {
34
h(LoginButton),
35
h(MenuButton, {
36
icon: 'filter',
37
- label: 'Filter',
37
+ label: "Filter list",
38
toggled: showFilter,
39
onClick() {
40
state.showFilter = !showFilter
@@ -62,7 +62,7 @@ export function MenuPanel() {
62
showFilter && h('div', { id: 'filter-bar' },
63
h('input', {
64
id: 'filter',
65
- placeholder: 'Filter list',
65
+ placeholder: "Type here to filter the list below",
66
autoComplete: 'off',
67
value: filter,
68
autoFocus: true,
@@ -70,21 +70,30 @@ export function MenuPanel() {
70
setFilter(ev.target.value)
71
}
72
}),
73
+ !isMobile() && h(MenuButton, {
74
+ icon: 'check',
75
+ label: "Select all",
76
+ onClick() { workSel(() => true) }
77
+ }),
78
h(MenuButton, {
79
icon: 'invert',
80
label: 'Invert selection',
76
- onClick() {
77
- const sel = state.selected
78
- for (const { n } of state.filteredList || state.list)
79
- if (sel[n])
80
- delete sel[n]
81
- else
82
- sel[n] = true
83
- }
84
- })
81
+ onClick() { workSel(x => !x) }
82
+ }),
83
)
84
)
85
86
+ function workSel(cb: (b:boolean) => boolean) {
87
+ const sel = state.selected
88
+ for (const { n } of state.filteredList || state.list) {
89
+ const was = sel[n]
90
+ if (was !== cb(was))
91
+ if (was)
92
+ delete sel[n]
93
+ else
94
+ sel[n] = true
95
+ }
96
+ }
97
98
function getSearchProps() {
99
return stopSearch && started1secAgo ? {
@@ -103,7 +112,7 @@ export function MenuPanel() {
112
}
113
} : {
114
icon: 'search',
106
- label: 'Search',
115
+ label: "Search deep",
116
async onClick() {
117
state.remoteSearch = await promptDialog('Search for...') || ''
118
}
frontend/src/misc.ts
+4
@@ -16,6 +16,10 @@ export function hError(err: Error | string | null) {
16
return err && h('div', { className:'error-msg' }, typeof err === 'string' ? err : err.message)
17
}
18
19
+export function isMobile() {
20
+ return window.innerWidth < 800
21
+}
22
+
23
let isWorking = false // we want the 'working' thing to be singleton
24
export function working() {
25
if (isWorking)