@samitouri / QOSami-HFS / commits / 195b7bac

file show: arrow up for full-height mode

Massimo Melina committed Jul 26, 2023 at 16:54 UTC 195b7bac2bc850de4f1be67c9cbbf43e35245e93
4 files changed +36 -20
frontend/src/components.ts
+2 -1
@@ -19,8 +19,9 @@ export function Spinner(props: any) {
19 return hIcon('spinner', { className:'spinner', ...props })
20 }
21
22 -export function Flex({ gap='.8em', center=false, vert=false, children=null, props={}, ...rest }) {
22 +export function Flex({ gap='.8em', center=false, vert=false, children=null, className=undefined, props={}, ...rest }) {
23 return h('div', {
24 + className,
25 style: {
26 display: 'flex',
27 gap,
frontend/src/index.scss
+10
@@ -556,11 +556,21 @@ button label {
556 height: 100%;
557 width: 100%;
558 }
559 + .showing-container { max-height: 100%; }
560 .showing {
561 max-width: calc(100% - var(--nav-size)*2); // avoid overlapping of controls and nav buttons
562 max-height: 100%;
563 }
564 img.showing { max-width: 100% } // we are ok with overlapping for simple images
565 + .main {
566 + flex: 1; position: relative; max-height: 100%;
567 + overflow: hidden; // without this <video> can make me go beyond the screen limit
568 + }
569 + .fullY {
570 + .main { overflow-y: auto; }
571 + .showing { max-height: initial }
572 + .showing-container { overflow: auto; }
573 + }
574 --nav-size: min(25vh, 15vw);
575 .nav {
576 position: absolute;
frontend/src/show.ts
+22 -17
@@ -1,5 +1,5 @@
1 import { DirEntry, ext2type, state } from './state'
2 -import { createElement as h, Fragment, useRef, useState } from 'react'
2 +import { createElement as h, Fragment, useEffect, useRef, useState } from 'react'
3 import { hfsEvent, hIcon, newDialog, restartAnimation, WIKI_URL } from './misc'
4 import { useEventListener, useWindowSize } from 'usehooks-ts'
5 import { EntryDetails, useMidnight } from './BrowseFiles'
@@ -15,6 +15,7 @@ export function fileShow(entry: DirEntry) {
15 const [cur, setCur] = useState(entry)
16 const moving = useRef(0)
17 const lastGood = useRef(entry)
18 + const [fullY, setFullY] = useState(false)
19 useEventListener('keydown', ({ key }) => {
20 if (key === 'ArrowLeft')
21 return go(-1)
@@ -22,6 +23,8 @@ export function fileShow(entry: DirEntry) {
23 return go(+1)
24 if (key === 'ArrowDown')
25 return location.href = cur.uri + '?dl'
26 + if (key === 'ArrowUp')
27 + return setFullY(x => !x)
28 if (key === ' ') {
29 const sel = state.selected
30 if (sel[cur.uri])
@@ -34,9 +37,11 @@ export function fileShow(entry: DirEntry) {
37 })
38 const [loading, setLoading] = useState(false)
39 const [failed, setFailed] = useState<false | string>(false)
40 + const containerRef = useRef<HTMLDivElement>()
41 + useEffect(() => { containerRef.current?.scrollTo(0,0) }, [cur])
42 const {t} = useI18N()
43 return h(Fragment, {},
39 - h(FlexV, { gap: 0, alignItems: 'stretch' },
44 + h(FlexV, { gap: 0, alignItems: 'stretch', className: fullY ? 'fullY' : undefined, },
45 h('div', { className: 'bar' },
46 h('div', { className: 'filename' }, cur.n),
47 h(EntryDetails, { entry: cur, midnight: useMidnight() }),
@@ -46,26 +51,26 @@ export function fileShow(entry: DirEntry) {
51 iconBtn('close', close),
52 )
53 ),
49 - h(FlexV, { flex: 1, center: true, position: 'relative', maxHeight: '100%',
50 - overflow: 'hidden' // without this <video> can make me go beyond the screen limit
51 - },
54 + h(FlexV, { center: true, className: 'main' },
55 loading && h(Spinner, { style: { position: 'absolute', fontSize: '20vh', opacity: .5 } }),
56 failed === cur.n ? h(FlexV, { alignItems: 'center', textAlign: 'center' },
57 hIcon('error', { style: { fontSize: '20vh' } }),
58 h('div', {}, cur.name),
59 t`Loading failed`
57 - ) : h(getShowType(cur) || Fragment, {
58 - src: cur.uri,
59 - className: 'showing',
60 - onLoad: () => {
61 - lastGood.current = cur
62 - setLoading(false)
63 - },
64 - onError: () => {
65 - go()
66 - setFailed(cur.n)
67 - }
68 - }),
60 + ) : h('div', { className: 'showing-container', ref: containerRef },
61 + h(getShowType(cur) || Fragment, {
62 + src: cur.uri,
63 + className: 'showing',
64 + onLoad: () => {
65 + lastGood.current = cur
66 + setLoading(false)
67 + },
68 + onError: () => {
69 + go()
70 + setFailed(cur.n)
71 + }
72 + })
73 + ),
74 hIcon('❮', { className: 'nav', style: { left: 0 }, onClick: () => go(-1) }),
75 hIcon('❯', { className: 'nav', style: { right: 0 }, onClick: () => go(+1) }),
76 ),
frontend/src/upload.ts
+2 -2
@@ -1,6 +1,6 @@
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 { createElement as h, Fragment, useMemo, useState } from 'react'
3 +import { createElement as h, DragEvent, Fragment, useMemo, useState } from 'react'
4 import { Checkbox, Flex, FlexV, iconBtn } from './components'
5 import {
6 closeDialog,
@@ -102,7 +102,7 @@ export function showUpload() {
102 const size = formatBytes(files.reduce((a, f) => a + f.size, 0))
103
104 return h(FlexV, { gap: 0, props: acceptDropFiles(x => setFiles([ ...files, ...x ])) },
105 - h(FlexV, { props: { className: 'upload-toolbar' } },
105 + h(FlexV, { className: 'upload-toolbar' },
106 !can_upload ? t('no_upload_here', "No upload permission for the current folder")
107 : h(FlexV, { margin: '0 0 1em' },
108 h(Flex, { justifyContent: 'center', flexWrap: 'wrap', alignItems: 'center' },