Files
stash/ui/v2.5/src/components/Wall/WallItem.tsx
Infinite 3fa3f61d93 Styling
2020-03-01 21:04:35 +01:00

158 lines
4.8 KiB
TypeScript

import _ from "lodash";
import React, { useRef, useState, useEffect } from "react";
import { Link } from "react-router-dom";
import * as GQL from "src/core/generated-graphql";
import { StashService } from "src/core/StashService";
import { VideoHoverHook } from "src/hooks";
import { TextUtils, NavUtils } from "src/utils";
interface IWallItemProps {
scene?: GQL.SlimSceneDataFragment;
sceneMarker?: GQL.SceneMarkerDataFragment;
origin?: string;
onOverlay: (show: boolean) => void;
clickHandler?: (
item: GQL.SlimSceneDataFragment | GQL.SceneMarkerDataFragment
) => void;
}
export const WallItem: React.FC<IWallItemProps> = (
props: IWallItemProps
) => {
const [videoPath, setVideoPath] = useState<string>();
const [previewPath, setPreviewPath] = useState<string>("");
const [screenshotPath, setScreenshotPath] = useState<string>("");
const [title, setTitle] = useState<string>("");
const [tags, setTags] = useState<JSX.Element[]>([]);
const config = StashService.useConfiguration();
const videoHoverHook = VideoHoverHook.useVideoHover({
resetOnMouseLeave: true
});
const showTextContainer = config.data?.configuration.interface.wallShowTitle ?? true;
function onMouseEnter() {
VideoHoverHook.onMouseEnter(videoHoverHook);
if (!videoPath || videoPath === "") {
if (props.sceneMarker) {
setVideoPath(props.sceneMarker.stream || "");
} else if (props.scene) {
setVideoPath(props.scene.paths.preview || "");
}
}
props.onOverlay(true);
}
const debouncedOnMouseEnter = useRef(_.debounce(onMouseEnter, 500));
function onMouseLeave() {
VideoHoverHook.onMouseLeave(videoHoverHook);
setVideoPath("");
debouncedOnMouseEnter.current.cancel();
props.onOverlay(false);
}
function onClick() {
if (props.clickHandler === undefined) {
return;
}
if (props.scene !== undefined) {
props.clickHandler(props.scene);
} else if (props.sceneMarker !== undefined) {
props.clickHandler(props.sceneMarker);
}
}
let linkSrc: string = "#";
if (props.clickHandler) {
if (props.scene) {
linkSrc = `/scenes/${props.scene.id}`;
} else if (props.sceneMarker) {
linkSrc = NavUtils.makeSceneMarkerUrl(props.sceneMarker);
}
}
function onTransitionEnd(event: React.TransitionEvent<HTMLDivElement>) {
const target = event.currentTarget;
if (target.classList.contains("double-scale") && target.parentElement) {
target.parentElement.style.zIndex = "10";
} else if (target.parentElement) {
target.parentElement.style.zIndex = "";
}
}
useEffect(() => {
if (props.sceneMarker) {
setPreviewPath(props.sceneMarker.preview);
setTitle(
`${props.sceneMarker!.title} - ${TextUtils.secondsToTimestamp(
props.sceneMarker.seconds
)}`
);
const thisTags = props.sceneMarker.tags.map(tag => (
<span key={tag.id}>{tag.name}</span>
));
thisTags.unshift(
<span key={props.sceneMarker.primary_tag.id}>
{props.sceneMarker.primary_tag.name}
</span>
);
setTags(thisTags);
} else if (props.scene) {
setPreviewPath(props.scene.paths.webp || "");
setScreenshotPath(props.scene.paths.screenshot || "");
setTitle(props.scene.title || "");
// tags = props.scene.tags.map((tag) => (<span key={tag.id}>{tag.name}</span>));
}
}, [props.sceneMarker, props.scene]);
function previewNotFound() {
if (previewPath !== screenshotPath) {
setPreviewPath(screenshotPath);
}
}
const className = ["scene-wall-item-container"];
if (videoHoverHook.isHovering.current) {
className.push("double-scale");
}
const style: React.CSSProperties = {};
if (props.origin) {
style.transformOrigin = props.origin;
}
return (
<div className="wall-item">
<div
className={className.join(" ")}
style={style}
onTransitionEnd={onTransitionEnd}
onMouseEnter={() => debouncedOnMouseEnter.current()}
onMouseMove={() => debouncedOnMouseEnter.current()}
onMouseLeave={onMouseLeave}
>
<Link onClick={() => onClick()} to={linkSrc}>
<video
src={videoPath}
poster={screenshotPath}
style={videoHoverHook.isHovering.current ? {} : { display: "none" }}
autoPlay
loop
ref={videoHoverHook.videoEl}
/>
<img
alt={title}
src={previewPath || screenshotPath}
onError={() => previewNotFound()}
/>
{showTextContainer ? (
<div className="scene-wall-item-text-container">
<div style={{ lineHeight: 1 }}>{title}</div>
{tags}
</div>
) : (
""
)}
</Link>
</div>
</div>
);
};