file-show: full screen (in menu)

Massimo Melina committed Jul 29, 2023 at 15:39 UTC 7c0bb2d9207e9b8246ae0ade7e58516d533ba10b
5 files changed +35 -22
frontend/src/components.ts
+15 -18
@@ -2,25 +2,25 @@
2
3 import { getHFS, hfsEvent, hIcon } from './misc'
4 import {
5 - ButtonHTMLAttributes,
6 - ChangeEvent,
7 - createElement as h,
8 - FC,
9 - Fragment,
10 - HTMLAttributes,
11 - InputHTMLAttributes,
12 - isValidElement, MouseEventHandler,
13 - ReactNode,
14 - SelectHTMLAttributes,
15 - useMemo
5 + ButtonHTMLAttributes, ChangeEvent, createElement as h, CSSProperties, FC, forwardRef, Fragment,
6 + HTMLAttributes, InputHTMLAttributes, isValidElement, MouseEventHandler, ReactNode, SelectHTMLAttributes, useMemo
7 } from 'react'
8
9 export function Spinner(props: any) {
10 return hIcon('spinner', { className:'spinner', ...props })
11 }
12
22 -export function Flex({ gap='.8em', center=false, vert=false, children=null, className='', props={}, ...rest }) {
23 - return h('div', {
13 +interface FlexProps extends CSSProperties {
14 + gap?: CSSProperties['gap'],
15 + center?: boolean,
16 + vert?: boolean,
17 + children?: ReactNode,
18 + className?: string,
19 + props?: HTMLAttributes<HTMLDivElement>
20 +}
21 +export const Flex = forwardRef(({ gap='.8em', center=false, vert=false, children=null, className='', props={}, ...rest }: FlexProps, ref) =>
22 + h('div', {
23 + ref,
24 className,
25 style: {
26 display: 'flex',
@@ -30,12 +30,9 @@ export function Flex({ gap='.8em', center=false, vert=false, children=null, clas
30 ...rest,
31 },
32 ...props
33 - }, children)
34 -}
33 + }, children) )
34
36 -export function FlexV(props:any) {
37 - return h(Flex, { vert:true, ...props })
38 -}
35 +export const FlexV = forwardRef((props: FlexProps, ref) => h(Flex, { ref, vert: true, ...props }))
36
37 interface CheckboxProps extends Omit<Partial<InputHTMLAttributes<any>>, 'onChange'> {
38 children?: ReactNode,
frontend/src/index.scss
+1 -1
@@ -557,7 +557,7 @@ button label {
557 height: 100%;
558 width: 100%;
559 }
560 - .showing-container { max-height: 100%; }
560 + .showing-container { width: 100%; height: 100%; display: flex; justify-content: center; align-items: center;}
561 .showing {
562 max-width: calc(100% - var(--nav-size)*2); // avoid overlapping of controls and nav buttons
563 max-height: 100%;
frontend/src/show.ts
+15 -1
@@ -7,6 +7,7 @@ import { Flex, FlexV, iconBtn, Spinner } from './components'
7 import { openFileMenu } from './fileMenu'
8 import { useI18N } from './i18n'
9 import md from '@hfs/admin/src/md'
10 +import { alertDialog } from './dialog'
11
12 enum ZoomMode {
13 fullWidth,
@@ -36,6 +37,8 @@ export function fileShow(entry: DirEntry) {
37 return location.href = cur.uri + '?dl'
38 if (key === 'z')
39 return switchZoomMode()
40 + if (key === 'f')
41 + return toggleFullScreen()
42 if (key === ' ') {
43 const sel = state.selected
44 if (sel[cur.uri])
@@ -53,6 +56,7 @@ export function fileShow(entry: DirEntry) {
56 const [loading, setLoading] = useState(false)
57 const [failed, setFailed] = useState<false | string>(false)
58 const containerRef = useRef<HTMLDivElement>()
59 + const mainRef = useRef<HTMLDivElement>()
60 useEffect(() => { scrollY(-1E9) }, [cur])
61 const {t} = useI18N()
62 return h(Fragment, {},
@@ -74,11 +78,12 @@ export function fileShow(entry: DirEntry) {
78 iconBtn('menu', ev => openFileMenu(cur, ev, [
79 'open','delete',
80 { icon: 'zoom', label: md(t`Switch _z_oom mode`), onClick: switchZoomMode },
81 + { icon: 'fullscreen', label: md(t`_F_ull screen`), onClick: toggleFullScreen },
82 ])),
83 iconBtn('close', close),
84 )
85 ),
81 - h(FlexV, { center: true, className: 'main' },
86 + h(FlexV, { center: true, className: 'main', ref: mainRef },
87 loading && h(Spinner, { style: { position: 'absolute', fontSize: '20vh', opacity: .5 } }),
88 failed === cur.n ? h(FlexV, { alignItems: 'center', textAlign: 'center' },
89 hIcon('error', { style: { fontSize: '20vh' } }),
@@ -122,6 +127,15 @@ export function fileShow(entry: DirEntry) {
127 setCur(e)
128 }
129
130 + function toggleFullScreen() {
131 + if (!document.fullscreenEnabled)
132 + return alertDialog(t`Full-screen not supported`, 'error')
133 + if (document.fullscreenElement)
134 + document.exitFullscreen()
135 + else
136 + mainRef.current?.requestFullscreen()
137 + }
138 +
139 function switchZoomMode() {
140 setMode(x => x ? x - 1 : ZoomMode.contain)
141 }
src/langs/hfs-lang-en.json
+2 -1
@@ -121,6 +121,7 @@
121 "Operation successful": "Operation successful",
122 "Uploader": "Uploader",
123 "Download counter": "Download counter",
124 - "Switch _z_oom mode": "Switch _z_oom mode"
124 + "Switch _z_oom mode": "Switch _z_oom mode",
125 + "_F_ull screen": "_F_ull screen"
126 }
127 }
src/langs/hfs-lang-it.json
+2 -1
@@ -115,6 +115,7 @@
115 "Operation successful": "Operazione riuscita",
116 "Uploader": "Upload da",
117 "Download counter": "Download conteggiati",
118 - "Switch _z_oom mode": "Cambia _z_oom"
118 + "Switch _z_oom mode": "Cambia _z_oom",
119 + "_F_ull screen": "Pieno schermo (_F_)"
120 }
121 }