file-show: cover

Massimo Melina committed Feb 3, 2024 at 19:49 UTC 24e68b5bb5f6e29fd3646c77385e6c6264d02e1e
2 files changed +16 -2
frontend/src/index.scss
+12 -1
@@ -648,11 +648,22 @@ button .icon + .label {
648 flex-direction: column-reverse !important; // bar at the bottom, easier on the thumb
649 }
650 }
651 - .showing-container { width: 100%; height: 100%; display: flex; justify-content: center; align-items: center;}
651 + .showing-container { width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; position: relative; }
652 .showing {
653 max-width: calc(100% - min(4vw, var(--nav-size)) * 2); // avoid overlapping of controls and nav buttons
654 max-height: 100%;
655 }
656 + .cover {
657 + position: absolute;
658 + width: 100%; height: 100%;
659 + background-repeat: no-repeat;
660 + background-size: contain;
661 + background-position: center;
662 + z-index: -1; // otherwise firefox
663 + opacity: .3;
664 + transition: opacity 1s;
665 + &.none { opacity: 0; }
666 + }
667 audio.showing { min-width: 60%; }
668 audio.showing, // even on mobile, we need the whole thing to control it decently, and nav-s don't seem to be a problem
669 img.showing { max-width: 100% } // we are ok with overlapping for simple images
frontend/src/show.ts
+4 -1
@@ -26,6 +26,7 @@ export function fileShow(entry: DirEntry) {
26 const [mode, setMode] = useState(ZoomMode.contain)
27 const [shuffle, setShuffle] = useState<undefined|DirList>()
28 const [repeat, setRepeat] = useState(false)
29 + const [cover, setCover] = useState('')
30 useEffect(() => {
31 if (shuffle)
32 goTo(shuffle[0])
@@ -73,7 +74,7 @@ export function fileShow(entry: DirEntry) {
74
75 const { auto_play_seconds } = useSnapState()
76 const [autoPlaying, setAutoPlaying] = useState(false)
76 - const showElement = containerRef.current?.querySelector('*')
77 + const showElement = containerRef.current?.querySelector('.showing')
78 useEffect(() => {
79 if (!autoPlaying || !showElement) return
80 if (showElement instanceof HTMLMediaElement) {
@@ -139,6 +140,7 @@ export function fileShow(entry: DirEntry) {
140 h('div', {}, cur.name),
141 t`Loading failed`
142 ) : h('div', { className: 'showing-container', ref: containerRef },
143 + h('div', { className: 'cover ' + (cover ? '' : 'none'), style: { backgroundImage: `url(${cover})` } }),
144 h(getShowType(cur) || Fragment, {
145 src: cur.uri,
146 className: 'showing',
@@ -151,6 +153,7 @@ export function fileShow(entry: DirEntry) {
153 const folder = cur.n.slice(0, -cur.name)
154 const covers = state.list.filter(x => folder === x.n.slice(0, -x.name) // same folder
155 && x.name.match(/(?:folder|cover|albumart.*)\.jpe?g$/i))
156 + setCover(_.maxBy(covers, 's')?.n || '')
157 navigator.mediaSession.metadata = new MediaMetadata({
158 title: cur.name,
159 album: decodeURIComponent(basename(dirname(cur.uri))),