fix: file picker dialog didn't fit smaller screens
Massimo Melina committed
Jun 15, 2022 at 20:59 UTC
5bc8e1ade0b12a5474cc6a6a269b9f30ebb7c24b
5 files changed
+50
-49
admin/src/FileField.ts
+24
-22
@@ -2,12 +2,13 @@ import { FieldProps, StringField } from '@hfs/mui-grid-form'
2
import { createElement as h } from 'react'
3
import { InputAdornment } from '@mui/material'
4
import { Eject } from '@mui/icons-material'
5
-import { IconBtn } from './misc'
5
+import { IconBtn, useBreakpoint } from './misc'
6
import { newDialog } from '@hfs/shared'
7
import FilePicker from './FilePicker'
8
import { apiCall } from './api'
9
10
export default function FileField({ value, onChange, files=true, folders=false, fileMask, defaultPath, title, ...props }: FieldProps<string>) {
11
+ const large = useBreakpoint('md')
12
return h(StringField, {
13
...props,
14
value,
@@ -21,28 +22,29 @@ export default function FileField({ value, onChange, files=true, folders=false,
22
onClick() {
23
const close = newDialog({
24
title: title ?? (files ? "Pick a file" : "Pick a folder"),
24
- dialogProps: { sx:{ minWidth:'min(90vw, 40em)', minHeight: 'calc(100vh - 9em)' } },
25
- Content,
25
+ dialogProps: {
26
+ fullScreen: !large,
27
+ sx: { minWidth: 'min(90vw, 40em)', minHeight: 'calc(100vh - 9em)' }
28
+ },
29
+ Content() {
30
+ return h(FilePicker, {
31
+ multiple: false,
32
+ folders,
33
+ files,
34
+ fileMask,
35
+ from: value || defaultPath,
36
+ async onSelect(sel) {
37
+ let one = sel?.[0]
38
+ if (!one) return
39
+ const cwd = (await apiCall('get_cwd'))?.path
40
+ if (one.startsWith(cwd))
41
+ one = one.slice(cwd.length+1)
42
+ onChange(one, { was: value, event: 'picker' })
43
+ close()
44
+ }
45
+ })
46
+ },
47
})
27
-
28
- function Content() {
29
- return h(FilePicker, {
30
- multiple: false,
31
- folders,
32
- files,
33
- fileMask,
34
- from: value || defaultPath,
35
- async onSelect(sel) {
36
- let one = sel?.[0]
37
- if (!one) return
38
- const cwd = (await apiCall('get_cwd'))?.path
39
- if (one.startsWith(cwd))
40
- one = one.slice(cwd.length+1)
41
- onChange(one, { was: value, event: 'picker' })
42
- close()
43
- }
44
- })
45
- }
48
},
49
}))
50
}
admin/src/FilePicker.ts
+2
-3
@@ -90,7 +90,7 @@ export default function FilePicker({ onSelect, multiple=true, files=true, folder
90
const it: DirEntry = filteredList[index]
91
const isFolder = it.k === 'd'
92
return h(MenuItem, {
93
- style,
93
+ style: { ...style, padding: 0 },
94
key: it.n,
95
onClick() {
96
if (isFolder)
@@ -136,8 +136,7 @@ export default function FilePicker({ onSelect, multiple=true, files=true, folder
136
onChange(ev) {
137
setFilterBounced(ev.target.value)
138
},
139
- sx: { minWidth: '20em' },
140
- fullWidth: true,
139
+ sx: { flex: 1 },
140
}),
141
),
142
)
admin/src/addFiles.ts
+19
-22
@@ -11,29 +11,26 @@ import { onlyTruthy } from './misc'
11
12
export default function addFiles() {
13
const close = newDialog({
14
- title: 'Add files or folders',
15
- dialogProps: { sx:{ minWidth:'min(90vw, 40em)', minHeight: 'calc(100vh - 9em)' } },
16
- Content,
14
+ title: "Add files or folders",
15
+ dialogProps: { sx:{ minWidth: 'min(90vw, 40em)', minHeight: 'calc(100vh - 9em)' } },
16
+ Content() {
17
+ const under = getUnder()
18
+ return h(Fragment, {},
19
+ h(Box, { sx:{ typography: 'body1', px: 1, py: 2 } }, "Selected elements will be added to " + (under || '(home)')),
20
+ h(FilePicker, {
21
+ async onSelect(sel) {
22
+ let failed = await Promise.all(sel.map(source =>
23
+ apiCall('add_vfs', { under, source }).then(() => '', () => source) ))
24
+ failed = onlyTruthy(failed)
25
+ if (failed.length)
26
+ await alertDialog("Some elements have been rejected: "+failed.join(', '), 'error')
27
+ reloadVfs()
28
+ close()
29
+ }
30
+ })
31
+ )
32
+ }
33
})
18
-
19
- function Content() {
20
- const under = getUnder()
21
- return h(Fragment, {},
22
- h(Box, { sx:{ typography: 'body1', px: 1, py: 2 } }, "Selected elements will be added to " + (under || '(home)')),
23
- h(FilePicker, {
24
- async onSelect(sel) {
25
- let failed = await Promise.all(sel.map(source =>
26
- apiCall('add_vfs', { under, source }).then(() => '', () => source) ))
27
- failed = onlyTruthy(failed)
28
- if (failed.length)
29
- await alertDialog("Some elements have been rejected: "+failed.join(', '), 'error')
30
- reloadVfs()
31
- close()
32
- }
33
- })
34
- )
35
- }
36
-
34
}
35
36
export async function addVirtual() {
admin/src/dialog.ts
+2
@@ -21,6 +21,7 @@ import {
21
import { Check, Close, Error as ErrorIcon, Forward, Info, Warning } from '@mui/icons-material'
22
import { newDialog, closeDialog, dialogsDefaults, DialogOptions } from '@hfs/shared'
23
import { Form, FormProps } from '@hfs/mui-grid-form'
24
+import { useBreakpoint } from './misc'
25
export * from '@hfs/shared/lib/dialogs'
26
27
dialogsDefaults.Container = function Container(d:DialogOptions) {
@@ -34,6 +35,7 @@ dialogsDefaults.Container = function Container(d:DialogOptions) {
35
return h(MuiDialog, {
36
open: true,
37
maxWidth: 'lg',
38
+ fullScreen: !useBreakpoint('sm'),
39
...rest,
40
...root,
41
onClose: ()=> closeDialog(),
admin/src/misc.ts
+3
-2
@@ -123,8 +123,9 @@ export function xlate(input: any, table: Record<string, any>) {
123
return table[input] ?? input
124
}
125
126
-export function useBreakpoint(name: Breakpoint) {
127
- return useMediaQuery((theme: any) => theme.breakpoints.up(name), { noSsr:true }) // without noSsr, first execution always returns false
126
+// return true if same size or larger
127
+export function useBreakpoint(breakpoint: Breakpoint) {
128
+ return useMediaQuery((theme: any) => theme.breakpoints.up(breakpoint), { noSsr:true }) // without noSsr, first execution always returns false
129
}
130
131
export function err2msg(code: string) {