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:
WithoutPants 2025-09-25 15:26:01 +10:00 committed by GitHub
parent acddf97771
commit 724d438721
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 146 additions and 69 deletions

View file

@ -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!}

View file

@ -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}
/>

View file

@ -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}

View file

@ -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}