@samitouri / QOSami-HFS / commits / 8778b8c4

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,