mirror of
https://github.com/stashapp/stash.git
synced 2026-02-28 18:22:59 +01:00
Fix misclicks resulting in navigating to new page during selection (#6599)
* Disable studio overlay link if selecting * Prevent scene preview scrubber click navigating during selection * Prevent gallery preview scrubber click navigating during selection
This commit is contained in:
parent
86abe7b24c
commit
410dd27d93
7 changed files with 60 additions and 7 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import { Button, ButtonGroup, OverlayTrigger, Tooltip } from "react-bootstrap";
|
||||
import React, { useState } from "react";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
import { GridCard } from "../Shared/GridCard/GridCard";
|
||||
import { HoverPopover } from "../Shared/HoverPopover";
|
||||
|
|
@ -21,11 +21,13 @@ import { PatchComponent } from "src/patch";
|
|||
interface IGalleryPreviewProps {
|
||||
gallery: GQL.SlimGalleryDataFragment;
|
||||
onScrubberClick?: (index: number) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export const GalleryPreview: React.FC<IGalleryPreviewProps> = ({
|
||||
gallery,
|
||||
onScrubberClick,
|
||||
disabled,
|
||||
}) => {
|
||||
const [imgSrc, setImgSrc] = useState<string | undefined>(
|
||||
gallery.paths.cover ?? undefined
|
||||
|
|
@ -48,6 +50,7 @@ export const GalleryPreview: React.FC<IGalleryPreviewProps> = ({
|
|||
imageCount={gallery.image_count}
|
||||
onClick={onScrubberClick}
|
||||
onPathChanged={setImgSrc}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -195,7 +198,16 @@ const GalleryCardDetails = PatchComponent(
|
|||
const GalleryCardOverlays = PatchComponent(
|
||||
"GalleryCard.Overlays",
|
||||
(props: IGalleryCardProps) => {
|
||||
return <StudioOverlay studio={props.gallery.studio} />;
|
||||
const ret = useMemo(() => {
|
||||
return (
|
||||
<StudioOverlay
|
||||
studio={props.gallery.studio}
|
||||
disabled={props.selecting}
|
||||
/>
|
||||
);
|
||||
}, [props.gallery.studio, props.selecting]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -211,6 +223,7 @@ const GalleryCardImage = PatchComponent(
|
|||
onScrubberClick={(i) => {
|
||||
history.push(`/galleries/${props.gallery.id}/images/${i}`);
|
||||
}}
|
||||
disabled={props.selecting}
|
||||
/>
|
||||
<RatingBanner rating={props.gallery.rating100} />
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export const GalleryPreviewScrubber: React.FC<{
|
|||
imageCount: number;
|
||||
onClick?: (imageIndex: number) => void;
|
||||
onPathChanged: React.Dispatch<React.SetStateAction<string | undefined>>;
|
||||
disabled?: boolean;
|
||||
}> = ({
|
||||
className,
|
||||
previewPath,
|
||||
|
|
@ -17,6 +18,7 @@ export const GalleryPreviewScrubber: React.FC<{
|
|||
imageCount,
|
||||
onClick,
|
||||
onPathChanged,
|
||||
disabled,
|
||||
}) => {
|
||||
const [activeIndex, setActiveIndex] = useState<number>();
|
||||
const debounceSetActiveIndex = useThrottle(setActiveIndex, 50);
|
||||
|
|
@ -48,6 +50,7 @@ export const GalleryPreviewScrubber: React.FC<{
|
|||
activeIndex={activeIndex}
|
||||
setActiveIndex={(i) => debounceSetActiveIndex(i)}
|
||||
onClick={onScrubberClick}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -148,7 +148,13 @@ const ImageCardDetails = PatchComponent(
|
|||
const ImageCardOverlays = PatchComponent(
|
||||
"ImageCard.Overlays",
|
||||
(props: IImageCardProps) => {
|
||||
return <StudioOverlay studio={props.image.studio} />;
|
||||
const ret = useMemo(() => {
|
||||
return (
|
||||
<StudioOverlay studio={props.image.studio} disabled={props.selecting} />
|
||||
);
|
||||
}, [props.image.studio, props.selecting]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { HoverScrubber } from "../Shared/HoverScrubber";
|
|||
interface IScenePreviewProps {
|
||||
vttPath: string | undefined;
|
||||
onClick?: (timestamp: number) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
function scaleToFit(dimensions: { w: number; h: number }, bounds: DOMRect) {
|
||||
|
|
@ -32,6 +33,7 @@ const defaultSprites = 81; // 9x9 grid by default
|
|||
export const PreviewScrubber: React.FC<IScenePreviewProps> = ({
|
||||
vttPath,
|
||||
onClick,
|
||||
disabled,
|
||||
}) => {
|
||||
const imageParentRef = useRef<HTMLDivElement>(null);
|
||||
const [style, setStyle] = useState({});
|
||||
|
|
@ -113,6 +115,7 @@ export const PreviewScrubber: React.FC<IScenePreviewProps> = ({
|
|||
activeIndex={activeIndex}
|
||||
setActiveIndex={(i) => debounceSetActiveIndex(i)}
|
||||
onClick={onScrubberClick}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ interface IScenePreviewProps {
|
|||
soundActive: boolean;
|
||||
vttPath?: string;
|
||||
onScrubberClick?: (timestamp: number) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export const ScenePreview: React.FC<IScenePreviewProps> = ({
|
||||
|
|
@ -47,6 +48,7 @@ export const ScenePreview: React.FC<IScenePreviewProps> = ({
|
|||
soundActive,
|
||||
vttPath,
|
||||
onScrubberClick,
|
||||
disabled,
|
||||
}) => {
|
||||
const videoEl = useRef<HTMLVideoElement>(null);
|
||||
|
||||
|
|
@ -86,7 +88,11 @@ export const ScenePreview: React.FC<IScenePreviewProps> = ({
|
|||
ref={videoEl}
|
||||
src={video}
|
||||
/>
|
||||
<PreviewScrubber vttPath={vttPath} onClick={onScrubberClick} />
|
||||
<PreviewScrubber
|
||||
vttPath={vttPath}
|
||||
onClick={onScrubberClick}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -336,7 +342,13 @@ const SceneCardDetails = PatchComponent(
|
|||
const SceneCardOverlays = PatchComponent(
|
||||
"SceneCard.Overlays",
|
||||
(props: ISceneCardProps) => {
|
||||
return <StudioOverlay studio={props.scene.studio} />;
|
||||
const ret = useMemo(() => {
|
||||
return (
|
||||
<StudioOverlay studio={props.scene.studio} disabled={props.selecting} />
|
||||
);
|
||||
}, [props.scene.studio, props.selecting]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -390,6 +402,7 @@ const SceneCardImage = PatchComponent(
|
|||
}
|
||||
|
||||
function onScrubberClick(timestamp: number) {
|
||||
if (props.selecting) return;
|
||||
const link = props.queue
|
||||
? props.queue.makeLink(props.scene.id, {
|
||||
sceneIndex: props.index,
|
||||
|
|
@ -416,6 +429,7 @@ const SceneCardImage = PatchComponent(
|
|||
soundActive={configuration?.interface?.soundOnPreview ?? false}
|
||||
vttPath={props.scene.paths.vtt ?? undefined}
|
||||
onScrubberClick={onScrubberClick}
|
||||
disabled={props.selecting}
|
||||
/>
|
||||
<RatingBanner rating={props.scene.rating100} />
|
||||
{maybeRenderSceneSpecsOverlay()}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ interface IStudio {
|
|||
|
||||
export const StudioOverlay: React.FC<{
|
||||
studio: IStudio | null | undefined;
|
||||
}> = ({ studio }) => {
|
||||
disabled?: boolean;
|
||||
}> = ({ studio, disabled }) => {
|
||||
const { configuration } = useConfigurationContext();
|
||||
|
||||
const configValue = configuration?.interface.showStudioAsText;
|
||||
|
|
@ -29,12 +30,18 @@ export const StudioOverlay: React.FC<{
|
|||
return false;
|
||||
}, [configValue, studio?.image_path]);
|
||||
|
||||
function onClick(e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) {
|
||||
if (disabled) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
if (!studio) return <></>;
|
||||
|
||||
return (
|
||||
// this class name is incorrect
|
||||
<div className="studio-overlay">
|
||||
<Link to={`/studios/${studio.id}`}>
|
||||
<Link to={`/studios/${studio.id}`} onClick={onClick}>
|
||||
{showStudioAsText ? (
|
||||
studio.name
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ interface IHoverScrubber {
|
|||
activeIndex: number | undefined;
|
||||
setActiveIndex: (index: number | undefined) => void;
|
||||
onClick?: (index: number) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export const HoverScrubber: React.FC<IHoverScrubber> = ({
|
||||
|
|
@ -16,6 +17,7 @@ export const HoverScrubber: React.FC<IHoverScrubber> = ({
|
|||
activeIndex,
|
||||
setActiveIndex,
|
||||
onClick,
|
||||
disabled,
|
||||
}) => {
|
||||
function getActiveIndex(
|
||||
e:
|
||||
|
|
@ -69,6 +71,11 @@ export const HoverScrubber: React.FC<IHoverScrubber> = ({
|
|||
| React.TouchEvent<HTMLDivElement>
|
||||
) {
|
||||
if (!onClick) return;
|
||||
if (disabled) {
|
||||
// allow propagation up so that selection still works
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
const relatedTarget = e.currentTarget;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue