better code: moved Btn to proper file
Massimo Melina committed
Jan 24, 2024 at 22:28 UTC
8778b8c4176e91c6815fec57abd69d36cef90313
5 files changed
+37
-39
frontend/src/UserPanel.ts
+1
-2
@@ -6,10 +6,9 @@ import { alertDialog, closeDialog, newDialog, promptDialog } from './dialog'
6
import { createVerifierAndSalt, SRPParameters, SRPRoutines } from 'tssrp6a'
7
import { apiCall } from '@hfs/shared/api'
8
import { logout } from './login'
9
-import { Btn } from './menu'
9
+import { Btn, CustomCode } from './components'
10
import { hIcon, HTTP_NOT_ACCEPTABLE, working } from './misc'
11
import { t } from './i18n'
12
-import { CustomCode } from './components'
12
13
export default function showUserPanel() {
14
newDialog({
frontend/src/clip.ts
+1
-1
@@ -1,6 +1,6 @@
1
import { createElement as h, Fragment } from 'react'
2
import { DirList, state, useSnapState } from './state'
3
-import { Btn } from './menu'
3
+import { Btn } from './components'
4
import { t, useI18N } from './i18n'
5
import { alertDialog } from './dialog'
6
import { useNavigate } from 'react-router-dom'
frontend/src/components.ts
+30
-5
@@ -1,10 +1,9 @@
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 { getHFS, hfsEvent, hIcon } from './misc'
4
-import {
5
- ButtonHTMLAttributes, ChangeEvent, createElement as h, CSSProperties, FC, forwardRef, Fragment,
6
- HTMLAttributes, InputHTMLAttributes, isValidElement, MouseEventHandler, ReactNode, SelectHTMLAttributes, useMemo
7
-} from 'react'
3
+import { getHFS, hfsEvent, hIcon, prefix } from './misc'
4
+import { ButtonHTMLAttributes, ChangeEvent, createElement as h, CSSProperties, FC, forwardRef, Fragment,
5
+ HTMLAttributes, InputHTMLAttributes, isValidElement, MouseEventHandler, ReactNode, SelectHTMLAttributes,
6
+ useMemo, useState, ComponentPropsWithoutRef } from 'react'
7
8
export function Spinner(props: any) {
9
return hIcon('spinner', { className:'spinner', ...props })
@@ -99,3 +98,29 @@ export function iconBtn(icon: string, onClick: MouseEventHandler, { small=true,
98
icon.length > 1 ? hIcon(icon) : icon
99
)
100
}
101
+
102
+export interface BtnProps extends ComponentPropsWithoutRef<"button"> {
103
+ icon?: string,
104
+ label: string,
105
+ tooltip?: string,
106
+ toggled?: boolean,
107
+ className?: string,
108
+ onClick?: () => unknown
109
+ onClickAnimation?: boolean
110
+}
111
+
112
+export function Btn({ icon, label, tooltip, toggled, onClick, onClickAnimation, ...rest }: BtnProps) {
113
+ const [working, setWorking] = useState(false)
114
+ return h('button', {
115
+ title: label + prefix(' - ', tooltip),
116
+ 'aria-label': label,
117
+ onClick() {
118
+ if (!onClick) return
119
+ if (onClickAnimation !== false)
120
+ setWorking(true)
121
+ Promise.resolve(onClick()).finally(() => setWorking(false))
122
+ },
123
+ ...rest,
124
+ className: [rest.className, toggled && 'toggled', working && 'ani-working'].filter(Boolean).join(' '),
125
+ }, icon && hIcon(icon), h('span', { className: 'label' }, label) ) // don't use <label> as VoiceOver will get redundant
126
+}
frontend/src/menu.ts
+4
-29
@@ -1,9 +1,9 @@
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 { ComponentPropsWithoutRef, createElement as h, Fragment, useEffect, useMemo, useState } from 'react'
4
+import { createElement as h, Fragment, useEffect, useMemo, useState } from 'react'
5
import { alertDialog, confirmDialog, ConfirmOptions, promptDialog } from './dialog'
6
-import { defaultPerms, err2msg, ErrorMsg, hIcon, onlyTruthy, prefix, useStateMounted, VfsPerms, working } from './misc'
6
+import { defaultPerms, err2msg, ErrorMsg, onlyTruthy, prefix, useStateMounted, VfsPerms, working } from './misc'
7
import { loginDialog } from './login'
8
import { showOptions } from './options'
9
import showUserPanel from './UserPanel'
@@ -15,6 +15,7 @@ import { apiCall } from '@hfs/shared/api'
15
import { reloadList } from './useFetchList'
16
import { t, useI18N } from './i18n'
17
import { cut } from './clip'
18
+import { Btn, BtnProps } from './components'
19
20
export function MenuPanel() {
21
const { showFilter, remoteSearch, stopSearch, stoppedSearch, selected, props } = useSnapState()
@@ -146,33 +147,7 @@ export function MenuPanel() {
147
}
148
}
149
149
-interface MenuButtonProps extends ComponentPropsWithoutRef<"button"> {
150
- icon?: string,
151
- label: string,
152
- tooltip?: string,
153
- toggled?: boolean,
154
- className?: string,
155
- onClick?: () => unknown
156
- onClickAnimation?: boolean
157
-}
158
-
159
-export function Btn({ icon, label, tooltip, toggled, onClick, onClickAnimation, ...rest }: MenuButtonProps) {
160
- const [working, setWorking] = useState(false)
161
- return h('button', {
162
- title: label + prefix(' - ', tooltip),
163
- 'aria-label': label,
164
- onClick() {
165
- if (!onClick) return
166
- if (onClickAnimation !== false)
167
- setWorking(true)
168
- Promise.resolve(onClick()).finally(() => setWorking(false))
169
- },
170
- ...rest,
171
- className: [rest.className, toggled && 'toggled', working && 'ani-working'].filter(Boolean).join(' '),
172
- }, icon && hIcon(icon), h('span', { className: 'label' }, label) ) // don't use <label> as VoiceOver will get redundant
173
-}
174
-
175
-export function MenuLink({ href, target, confirm, confirmOptions, ...rest }: MenuButtonProps & { href: string, target?: string, confirm?: string, confirmOptions?: ConfirmOptions }) {
150
+export function MenuLink({ href, target, confirm, confirmOptions, ...rest }: BtnProps & { href: string, target?: string, confirm?: string, confirmOptions?: ConfirmOptions }) {
151
return h('a', {
152
tabIndex: -1,
153
href,
frontend/src/show.ts
+1
-2
@@ -3,12 +3,11 @@ import { createElement as h, Fragment, useEffect, useRef, useState } from 'react
3
import { domOn, hfsEvent, hIcon, newDialog, restartAnimation } from './misc'
4
import { useEventListener, useWindowSize } from 'usehooks-ts'
5
import { EntryDetails, useMidnight } from './BrowseFiles'
6
-import { Flex, FlexV, iconBtn, Spinner } from './components'
6
+import { Btn, Flex, FlexV, iconBtn, Spinner } from './components'
7
import { openFileMenu } from './fileMenu'
8
import { t, useI18N } from './i18n'
9
import { alertDialog } from './dialog'
10
import _ from 'lodash'
11
-import { Btn } from './menu'
11
12
enum ZoomMode {
13
fullWidth,