diff --git a/interface/app/$libraryId/Explorer/FilePath/Original.tsx b/interface/app/$libraryId/Explorer/FilePath/Original.tsx index 7720a22d7..6bd3e2a95 100644 --- a/interface/app/$libraryId/Explorer/FilePath/Original.tsx +++ b/interface/app/$libraryId/Explorer/FilePath/Original.tsx @@ -184,11 +184,17 @@ interface VideoProps extends VideoHTMLAttributes { } const Video = ({ paused, blackBars, blackBarsSize, className, ...props }: VideoProps) => { - const ref = useRef(null); - const size = useSize(ref); - const { style: blackBarsStyle } = useBlackBars(size, blackBarsSize); const { t } = useLocale(); + const ref = useRef(null); + + const size = useSize(ref); + + const { style: blackBarsStyle } = useBlackBars(ref, size, { + size: blackBarsSize, + disabled: !blackBars + }); + useEffect(() => { if (!ref.current) return; paused ? ref.current.pause() : ref.current.play(); @@ -214,7 +220,7 @@ const Video = ({ paused, blackBars, blackBarsSize, className, ...props }: VideoP }} playsInline draggable={false} - style={{ ...(blackBars ? blackBarsStyle : {}) }} + style={{ ...blackBarsStyle }} className={clsx(blackBars && size.width === 0 && 'invisible', className)} {...props} key={props.src} diff --git a/interface/app/$libraryId/Explorer/FilePath/Thumb.tsx b/interface/app/$libraryId/Explorer/FilePath/Thumb.tsx index 0f43d9464..337471cd5 100644 --- a/interface/app/$libraryId/Explorer/FilePath/Thumb.tsx +++ b/interface/app/$libraryId/Explorer/FilePath/Thumb.tsx @@ -240,10 +240,7 @@ interface ThumbnailProps extends Omit { } const Thumbnail = forwardRef( - ( - { crossOrigin, blackBars, blackBarsSize, extension, cover, className, style, ...props }, - _ref - ) => { + ({ blackBars, blackBarsSize, extension, cover, className, style, ...props }, _ref) => { const ref = useRef(null); useImperativeHandle( _ref, @@ -252,27 +249,28 @@ const Thumbnail = forwardRef( const size = useSize(ref); - const { style: blackBarsStyle } = useBlackBars(size, blackBarsSize); + const { style: blackBarsStyle } = useBlackBars(ref, size, { + size: blackBarsSize, + disabled: !blackBars + }); return ( <> - {(cover || (size && size.width > 80)) && extension && ( + + {(cover || size.width > 80) && extension && (
) { - const explorerSettings = useExplorerContext({ suspense: false })?.useSettingsSnapshot(); - - const initialized = useRef(false); - const [size, setSize] = useState({ width: 0, height: 0 }); - useEffect(() => { - initialized.current = false; - }, [explorerSettings?.gridItemSize, explorerSettings?.listViewIconSize]); - - useCallbackToWatchResize( - ({ width, height }) => { - if (initialized.current || (!width && !height)) return; - setSize({ width, height }); - initialized.current = true; - }, - [], - ref - ); + useCallbackToWatchResize(({ width, height }) => setSize({ width, height }), [], ref); return size; } -export function useBlackBars(videoSize: { width: number; height: number }, blackBarsSize?: number) { +export function useBlackBars( + node: RefObject, + size: ReturnType, + options: { size?: number; disabled?: boolean } = {} +) { + const previousNodeSize = useRef(); + const previousParentSize = useRef(); + const previousBarSize = useRef<{ x?: number; y?: number }>(); + return useMemo(() => { - const { width, height } = videoSize; + if (options.disabled) return {}; - const orientation = height > width ? 'vertical' : 'horizontal'; + const orientation = size.height > size.width ? 'vertical' : 'horizontal'; - const barSize = - blackBarsSize || - Math.floor(Math.ceil(orientation === 'vertical' ? height : width) / 10); + const getBarSize = () => { + return Math.floor( + Math.ceil(orientation === 'vertical' ? size.height : size.width) / 10 + ); + }; - const xBarSize = orientation === 'vertical' ? barSize : 0; - const yBarSize = orientation === 'horizontal' ? barSize : 0; + let barSize = options.size; + + if (barSize === undefined) { + let parentSize = { width: 0, height: 0 }; + + const parent = node.current?.parentElement; + + if (parent) { + const style = getComputedStyle(parent); + + const paddingX = parseFloat(style.paddingLeft) + parseFloat(style.paddingRight); + const paddingY = parseFloat(style.paddingTop) + parseFloat(style.paddingBottom); + + parentSize = { + width: parent.clientWidth - paddingX, + height: parent.clientHeight - paddingY + }; + } + + if ( + parentSize.width !== previousParentSize.current?.width || + parentSize.height !== previousParentSize.current?.height + ) { + barSize = getBarSize(); + } else if (previousNodeSize.current && previousBarSize.current) { + const previousNodeWidth = + previousNodeSize.current.width + (previousBarSize.current.x ?? 0) * 2; + + const previousNodeHeight = + previousNodeSize.current.height + (previousBarSize.current.y ?? 0) * 2; + + const nodeWidth = + previousNodeSize.current.width - + Math.max(0, previousNodeWidth - parentSize.width); + + const nodeHeight = + previousNodeSize.current.height - + Math.max(0, previousNodeHeight - parentSize.height); + + if ( + (orientation === 'vertical' && nodeWidth === size.width) || + (orientation === 'horizontal' && nodeHeight === size.height) + ) { + barSize = previousBarSize.current.x ?? previousBarSize.current.y; + } else { + barSize = getBarSize(); + } + } else { + barSize = getBarSize(); + } + + previousParentSize.current = parentSize; + } + + const xBarSize = orientation === 'vertical' ? barSize : undefined; + const yBarSize = orientation === 'horizontal' ? barSize : undefined; + + previousNodeSize.current = { width: size.width, height: size.height }; + previousBarSize.current = { x: xBarSize, y: yBarSize }; return { size: { @@ -54,5 +103,5 @@ export function useBlackBars(videoSize: { width: number; height: number }, black borderRadius: 4 } satisfies CSSProperties }; - }, [videoSize, blackBarsSize]); + }, [options.disabled, options.size, size.height, size.width, node]); }