mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 08:26:00 +01:00
Wall item height fix (#6101)
* Fix scene wall item height with fewer items * Fix for marker wall * Fix for image wall * Provide some allowance for items to go over height
This commit is contained in:
parent
acddf97771
commit
724d438721
4 changed files with 146 additions and 69 deletions
|
|
@ -20,7 +20,7 @@ import { ImageWallItem } from "./ImageWallItem";
|
|||
import { EditImagesDialog } from "./EditImagesDialog";
|
||||
import { DeleteImagesDialog } from "./DeleteImagesDialog";
|
||||
import "flexbin/flexbin.css";
|
||||
import Gallery from "react-photo-gallery";
|
||||
import Gallery, { RenderImageProps } from "react-photo-gallery";
|
||||
import { ExportDialog } from "../Shared/ExportDialog";
|
||||
import { objectTitle } from "src/core/files";
|
||||
import { ConfigurationContext } from "src/hooks/Config";
|
||||
|
|
@ -54,6 +54,8 @@ const ImageWall: React.FC<IImageWallProps> = ({
|
|||
const { configuration } = useContext(ConfigurationContext);
|
||||
const uiConfig = configuration?.ui;
|
||||
|
||||
const containerRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
let photos: {
|
||||
src: string;
|
||||
srcSet?: string | string[] | undefined;
|
||||
|
|
@ -94,22 +96,45 @@ const ImageWall: React.FC<IImageWallProps> = ({
|
|||
return Math.round(columnCount);
|
||||
}
|
||||
|
||||
function targetRowHeight(containerWidth: number) {
|
||||
let zoomHeight = 280;
|
||||
breakpointZoomHeights.forEach((e) => {
|
||||
if (containerWidth >= e.minWidth) {
|
||||
zoomHeight = e.heights[zoomIndex];
|
||||
}
|
||||
});
|
||||
return zoomHeight;
|
||||
}
|
||||
const targetRowHeight = useCallback(
|
||||
(containerWidth: number) => {
|
||||
let zoomHeight = 280;
|
||||
breakpointZoomHeights.forEach((e) => {
|
||||
if (containerWidth >= e.minWidth) {
|
||||
zoomHeight = e.heights[zoomIndex];
|
||||
}
|
||||
});
|
||||
return zoomHeight;
|
||||
},
|
||||
[zoomIndex]
|
||||
);
|
||||
|
||||
// set the max height as a factor of the targetRowHeight
|
||||
// this allows some images to be taller than the target row height
|
||||
// but prevents images from becoming too tall when there is a small number of items
|
||||
const maxHeightFactor = 1.3;
|
||||
|
||||
const renderImage = useCallback(
|
||||
(props: RenderImageProps) => {
|
||||
return (
|
||||
<ImageWallItem
|
||||
{...props}
|
||||
maxHeight={
|
||||
targetRowHeight(containerRef.current?.offsetWidth ?? 0) *
|
||||
maxHeightFactor
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[targetRowHeight]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="gallery">
|
||||
<div className="gallery" ref={containerRef}>
|
||||
{photos.length ? (
|
||||
<Gallery
|
||||
photos={photos}
|
||||
renderImage={ImageWallItem}
|
||||
renderImage={renderImage}
|
||||
onClick={showLightboxOnClick}
|
||||
margin={uiConfig?.imageWallOptions?.margin!}
|
||||
direction={uiConfig?.imageWallOptions?.direction!}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,17 @@
|
|||
import React from "react";
|
||||
import type {
|
||||
RenderImageProps,
|
||||
renderImageClickHandler,
|
||||
PhotoProps,
|
||||
} from "react-photo-gallery";
|
||||
import type { RenderImageProps } from "react-photo-gallery";
|
||||
|
||||
interface IImageWallProps {
|
||||
margin?: string;
|
||||
index: number;
|
||||
photo: PhotoProps;
|
||||
onClick: renderImageClickHandler | null;
|
||||
direction: "row" | "column";
|
||||
top?: number;
|
||||
left?: number;
|
||||
interface IExtraProps {
|
||||
maxHeight: number;
|
||||
}
|
||||
|
||||
export const ImageWallItem: React.FC<RenderImageProps> = (
|
||||
props: IImageWallProps
|
||||
export const ImageWallItem: React.FC<RenderImageProps & IExtraProps> = (
|
||||
props: RenderImageProps & IExtraProps
|
||||
) => {
|
||||
const height = Math.min(props.maxHeight, props.photo.height);
|
||||
const zoomFactor = height / props.photo.height;
|
||||
const width = props.photo.width * zoomFactor;
|
||||
|
||||
type style = Record<string, string | number | undefined>;
|
||||
var imgStyle: style = {
|
||||
margin: props.margin,
|
||||
|
|
@ -49,8 +43,8 @@ export const ImageWallItem: React.FC<RenderImageProps> = (
|
|||
key={props.photo.key}
|
||||
style={imgStyle}
|
||||
src={props.photo.src}
|
||||
width={props.photo.width}
|
||||
height={props.photo.height}
|
||||
width={width}
|
||||
height={height}
|
||||
alt={props.photo.alt}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -39,15 +39,23 @@ interface IMarkerPhoto {
|
|||
onError?: (photo: PhotoProps<IMarkerPhoto>) => void;
|
||||
}
|
||||
|
||||
export const MarkerWallItem: React.FC<RenderImageProps<IMarkerPhoto>> = (
|
||||
props: RenderImageProps<IMarkerPhoto>
|
||||
) => {
|
||||
interface IExtraProps {
|
||||
maxHeight: number;
|
||||
}
|
||||
|
||||
export const MarkerWallItem: React.FC<
|
||||
RenderImageProps<IMarkerPhoto> & IExtraProps
|
||||
> = (props: RenderImageProps<IMarkerPhoto> & IExtraProps) => {
|
||||
const { configuration } = useContext(ConfigurationContext);
|
||||
const playSound = configuration?.interface.soundOnPreview ?? false;
|
||||
const showTitle = configuration?.interface.wallShowTitle ?? false;
|
||||
|
||||
const [active, setActive] = useState(false);
|
||||
|
||||
const height = Math.min(props.maxHeight, props.photo.height);
|
||||
const zoomFactor = height / props.photo.height;
|
||||
const width = props.photo.width * zoomFactor;
|
||||
|
||||
type style = Record<string, string | number | undefined>;
|
||||
var divStyle: style = {
|
||||
margin: props.margin,
|
||||
|
|
@ -79,8 +87,8 @@ export const MarkerWallItem: React.FC<RenderImageProps<IMarkerPhoto>> = (
|
|||
role="button"
|
||||
style={{
|
||||
...divStyle,
|
||||
width: props.photo.width,
|
||||
height: props.photo.height,
|
||||
width,
|
||||
height,
|
||||
}}
|
||||
>
|
||||
<ImagePreview
|
||||
|
|
@ -90,8 +98,8 @@ export const MarkerWallItem: React.FC<RenderImageProps<IMarkerPhoto>> = (
|
|||
autoPlay={video}
|
||||
key={props.photo.key}
|
||||
src={props.photo.src}
|
||||
width={props.photo.width}
|
||||
height={props.photo.height}
|
||||
width={width}
|
||||
height={height}
|
||||
alt={props.photo.alt}
|
||||
onMouseEnter={() => setActive(true)}
|
||||
onMouseLeave={() => setActive(false)}
|
||||
|
|
@ -163,6 +171,8 @@ const breakpointZoomHeights = [
|
|||
const MarkerWall: React.FC<IMarkerWallProps> = ({ markers, zoomIndex }) => {
|
||||
const history = useHistory();
|
||||
|
||||
const containerRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
const margin = 3;
|
||||
const direction = "row";
|
||||
|
||||
|
|
@ -208,22 +218,41 @@ const MarkerWall: React.FC<IMarkerWallProps> = ({ markers, zoomIndex }) => {
|
|||
return Math.round(columnCount);
|
||||
}
|
||||
|
||||
function targetRowHeight(containerWidth: number) {
|
||||
let zoomHeight = 280;
|
||||
breakpointZoomHeights.forEach((e) => {
|
||||
if (containerWidth >= e.minWidth) {
|
||||
zoomHeight = e.heights[zoomIndex];
|
||||
}
|
||||
});
|
||||
return zoomHeight;
|
||||
}
|
||||
const targetRowHeight = useCallback(
|
||||
(containerWidth: number) => {
|
||||
let zoomHeight = 280;
|
||||
breakpointZoomHeights.forEach((e) => {
|
||||
if (containerWidth >= e.minWidth) {
|
||||
zoomHeight = e.heights[zoomIndex];
|
||||
}
|
||||
});
|
||||
return zoomHeight;
|
||||
},
|
||||
[zoomIndex]
|
||||
);
|
||||
|
||||
const renderImage = useCallback((props: RenderImageProps<IMarkerPhoto>) => {
|
||||
return <MarkerWallItem {...props} />;
|
||||
}, []);
|
||||
// set the max height as a factor of the targetRowHeight
|
||||
// this allows some images to be taller than the target row height
|
||||
// but prevents images from becoming too tall when there is a small number of items
|
||||
const maxHeightFactor = 1.3;
|
||||
|
||||
const renderImage = useCallback(
|
||||
(props: RenderImageProps<IMarkerPhoto>) => {
|
||||
return (
|
||||
<MarkerWallItem
|
||||
{...props}
|
||||
maxHeight={
|
||||
targetRowHeight(containerRef.current?.offsetWidth ?? 0) *
|
||||
maxHeightFactor
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[targetRowHeight]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="marker-wall">
|
||||
<div className="marker-wall" ref={containerRef}>
|
||||
{photos.length ? (
|
||||
<MarkerGallery
|
||||
photos={photos}
|
||||
|
|
|
|||
|
|
@ -26,15 +26,23 @@ interface IScenePhoto {
|
|||
onError?: (photo: PhotoProps<IScenePhoto>) => void;
|
||||
}
|
||||
|
||||
export const SceneWallItem: React.FC<RenderImageProps<IScenePhoto>> = (
|
||||
props: RenderImageProps<IScenePhoto>
|
||||
) => {
|
||||
interface IExtraProps {
|
||||
maxHeight: number;
|
||||
}
|
||||
|
||||
export const SceneWallItem: React.FC<
|
||||
RenderImageProps<IScenePhoto> & IExtraProps
|
||||
> = (props: RenderImageProps<IScenePhoto> & IExtraProps) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const { configuration } = useContext(ConfigurationContext);
|
||||
const playSound = configuration?.interface.soundOnPreview ?? false;
|
||||
const showTitle = configuration?.interface.wallShowTitle ?? false;
|
||||
|
||||
const height = Math.min(props.maxHeight, props.photo.height);
|
||||
const zoomFactor = height / props.photo.height;
|
||||
const width = props.photo.width * zoomFactor;
|
||||
|
||||
const [active, setActive] = useState(false);
|
||||
|
||||
type style = Record<string, string | number | undefined>;
|
||||
|
|
@ -72,8 +80,8 @@ export const SceneWallItem: React.FC<RenderImageProps<IScenePhoto>> = (
|
|||
role="button"
|
||||
style={{
|
||||
...divStyle,
|
||||
width: props.photo.width,
|
||||
height: props.photo.height,
|
||||
width,
|
||||
height,
|
||||
}}
|
||||
>
|
||||
<ImagePreview
|
||||
|
|
@ -83,8 +91,8 @@ export const SceneWallItem: React.FC<RenderImageProps<IScenePhoto>> = (
|
|||
autoPlay={video}
|
||||
key={props.photo.key}
|
||||
src={props.photo.src}
|
||||
width={props.photo.width}
|
||||
height={props.photo.height}
|
||||
width={width}
|
||||
height={height}
|
||||
alt={props.photo.alt}
|
||||
onMouseEnter={() => setActive(true)}
|
||||
onMouseLeave={() => setActive(false)}
|
||||
|
|
@ -146,6 +154,8 @@ const SceneWall: React.FC<ISceneWallProps> = ({
|
|||
}) => {
|
||||
const history = useHistory();
|
||||
|
||||
const containerRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
const margin = 3;
|
||||
const direction = "row";
|
||||
|
||||
|
|
@ -196,22 +206,41 @@ const SceneWall: React.FC<ISceneWallProps> = ({
|
|||
return Math.round(columnCount);
|
||||
}
|
||||
|
||||
function targetRowHeight(containerWidth: number) {
|
||||
let zoomHeight = 280;
|
||||
breakpointZoomHeights.forEach((e) => {
|
||||
if (containerWidth >= e.minWidth) {
|
||||
zoomHeight = e.heights[zoomIndex];
|
||||
}
|
||||
});
|
||||
return zoomHeight;
|
||||
}
|
||||
const targetRowHeight = useCallback(
|
||||
(containerWidth: number) => {
|
||||
let zoomHeight = 280;
|
||||
breakpointZoomHeights.forEach((e) => {
|
||||
if (containerWidth >= e.minWidth) {
|
||||
zoomHeight = e.heights[zoomIndex];
|
||||
}
|
||||
});
|
||||
return zoomHeight;
|
||||
},
|
||||
[zoomIndex]
|
||||
);
|
||||
|
||||
const renderImage = useCallback((props: RenderImageProps<IScenePhoto>) => {
|
||||
return <SceneWallItem {...props} />;
|
||||
}, []);
|
||||
// set the max height as a factor of the targetRowHeight
|
||||
// this allows some images to be taller than the target row height
|
||||
// but prevents images from becoming too tall when there is a small number of items
|
||||
const maxHeightFactor = 1.3;
|
||||
|
||||
const renderImage = useCallback(
|
||||
(props: RenderImageProps<IScenePhoto>) => {
|
||||
return (
|
||||
<SceneWallItem
|
||||
{...props}
|
||||
maxHeight={
|
||||
targetRowHeight(containerRef.current?.offsetWidth ?? 0) *
|
||||
maxHeightFactor
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[targetRowHeight]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="scene-wall">
|
||||
<div className={`scene-wall`} ref={containerRef}>
|
||||
{photos.length ? (
|
||||
<SceneGallery
|
||||
photos={photos}
|
||||
|
|
|
|||
Loading…
Reference in a new issue