ux: frontend: clicking select made the button move out of the mouse pointer
Massimo Melina committed
Feb 17, 2023 at 11:41 UTC
36f6b8c4704758c7384d80d396c2c55e253f6840
2 files changed
+37
-20
frontend/src/index.scss
+17
-1
@@ -117,6 +117,22 @@ header {
117
z-index: 1; /* necessary to not be covered by checkboxes */
118
}
119
120
+.before-sliding {
121
+ width: 0 !important;
122
+ flex: 0 !important;
123
+ margin: 0 !important;
124
+ height: 0 !important;
125
+ padding: 0 !important;
126
+ overflow: hidden !important;
127
+ transition: all .5s;
128
+}
129
+.show-sliding {
130
+ transition: all .5s;
131
+ overflow: clip;
132
+ flex: 1;
133
+ white-space: nowrap;
134
+}
135
+
136
.ani-working { animation:1s blink infinite }
137
138
@keyframes blink {
@@ -237,7 +253,7 @@ ul.dir {
253
justify-content: space-evenly;
254
flex-wrap: wrap;
255
&>* {
240
- flex: auto;
256
+ flex: 1;
257
margin: 0.1em;
258
}
259
& button { /* no need for horizontal padding as we are using flex to grow */
frontend/src/menu.ts
+20
-19
@@ -1,7 +1,7 @@
1
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3
import { state, useSnapState } from './state'
4
-import { createElement as h, Fragment, useEffect, useMemo, useState } from 'react'
4
+import { ComponentPropsWithoutRef, createElement as h, Fragment, useEffect, useMemo, useState } from 'react'
5
import { alertDialog, confirmDialog, ConfirmOptions, promptDialog } from './dialog'
6
import { err2msg, hError, hIcon, onlyTruthy, prefix, useStateMounted } from './misc'
7
import { loginDialog } from './login'
@@ -42,26 +42,26 @@ export function MenuPanel() {
42
return h('div', { id: 'menu-panel' },
43
h('div', { id: 'menu-bar' },
44
h(LoginButton),
45
- showFilter && can_delete ? h(MenuButton, {
46
- icon: 'trash',
47
- label: "Delete",
48
- onClick: () => deleteFiles(Object.keys(selected), pathname)
49
- })
50
- : (can_upload || qs.length > 0) && h(MenuButton, {
51
- icon: 'upload',
52
- label: "Upload",
53
- className: uploading && 'ani-working',
54
- onClick: showUpload,
55
- }),
45
h(MenuButton, {
46
icon: 'check',
47
label: "Select",
59
- tooltip: `Selection applies to "Download zip", but you can also filter the list`,
48
+ tooltip: `Selection applies to "Zip" and "Delete" (when available), but you can also filter the list`,
49
toggled: showFilter,
50
onClick() {
51
state.showFilter = !showFilter
52
}
53
}),
54
+ h(MenuButton, showFilter && can_delete ? {
55
+ icon: 'trash',
56
+ label: "Delete",
57
+ className: 'show-sliding',
58
+ onClick: () => deleteFiles(Object.keys(selected), pathname)
59
+ } : (can_upload || qs.length > 0) ? {
60
+ icon: 'upload',
61
+ label: "Upload",
62
+ className: 'show-sliding ' + (uploading ? 'ani-working' : ''),
63
+ onClick: showUpload,
64
+ } : { icon: '', label: '', className: 'before-sliding' }),
65
h(MenuButton, getSearchProps()),
66
h(MenuButton, {
67
icon: 'settings',
@@ -70,7 +70,7 @@ export function MenuPanel() {
70
}),
71
h(MenuLink, {
72
icon: 'archive',
73
- label: "Download zip",
73
+ label: "Zip",
74
tooltip: list ? "Download selected elements as a single zip file"
75
: "Download whole list (unfiltered) as a single zip file. If you select some elements, only those will be downloaded.",
76
href: '?'+String(new URLSearchParams(_.pickBy({
@@ -85,7 +85,7 @@ export function MenuPanel() {
85
onClick() {
86
state.showFilter = true
87
closeDialog(false)
88
- return alertDialog("Use checkboxes to select the files, then you can use Download-zip again")
88
+ return alertDialog("Use checkboxes to select the files, then you can use Zip again")
89
},
90
}, "Select some files"),
91
}
@@ -122,17 +122,17 @@ export function MenuPanel() {
122
}
123
}
124
125
-interface MenuButtonProps {
125
+interface MenuButtonProps extends ComponentPropsWithoutRef<"button"> {
126
icon: string,
127
label: string,
128
tooltip?: string,
129
toggled?: boolean,
130
className?: string,
131
- onClick?: () => void
131
+ onClick?: () => unknown
132
onClickAnimation?: boolean
133
}
134
135
-export function MenuButton({ icon, label, tooltip, toggled, onClick, onClickAnimation, className = '' }: MenuButtonProps) {
135
+export function MenuButton({ icon, label, tooltip, toggled, onClick, onClickAnimation, ...rest }: MenuButtonProps) {
136
const [working, setWorking] = useState(false)
137
return h('button', {
138
title: tooltip || label,
@@ -142,7 +142,8 @@ export function MenuButton({ icon, label, tooltip, toggled, onClick, onClickAnim
142
setWorking(true)
143
Promise.resolve(onClick()).finally(() => setWorking(false))
144
},
145
- className: [className, toggled && 'toggled', working && 'ani-working'].filter(Boolean).join(' ')
145
+ className: [rest.className, toggled && 'toggled', working && 'ani-working'].filter(Boolean).join(' '),
146
+ ...rest,
147
}, hIcon(icon), h('label', {}, label) )
148
}
149