mirror of
https://github.com/stashapp/stash.git
synced 2025-12-16 20:07:05 +03:00
Gallery card patched component (#5880)
* Gallery card patched component * Define in pluginApi.d.ts
This commit is contained in:
@@ -16,6 +16,7 @@ import { StudioOverlay } from "../Shared/GridCard/StudioOverlay";
|
||||
import { GalleryPreviewScrubber } from "./GalleryPreviewScrubber";
|
||||
import cx from "classnames";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { PatchComponent } from "src/patch";
|
||||
|
||||
interface IGalleryPreviewProps {
|
||||
gallery: GQL.SlimGalleryDataFragment;
|
||||
@@ -53,7 +54,7 @@ export const GalleryPreview: React.FC<IGalleryPreviewProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
interface IProps {
|
||||
interface IGalleryCardProps {
|
||||
gallery: GQL.SlimGalleryDataFragment;
|
||||
cardWidth?: number;
|
||||
selecting?: boolean;
|
||||
@@ -62,148 +63,179 @@ interface IProps {
|
||||
onSelectedChanged?: (selected: boolean, shiftKey: boolean) => void;
|
||||
}
|
||||
|
||||
export const GalleryCard: React.FC<IProps> = (props) => {
|
||||
const history = useHistory();
|
||||
const GalleryCardPopovers = PatchComponent(
|
||||
"GalleryCard.Popovers",
|
||||
(props: IGalleryCardProps) => {
|
||||
function maybeRenderScenePopoverButton() {
|
||||
if (props.gallery.scenes.length === 0) return;
|
||||
|
||||
function maybeRenderScenePopoverButton() {
|
||||
if (props.gallery.scenes.length === 0) return;
|
||||
const popoverContent = props.gallery.scenes.map((scene) => (
|
||||
<SceneLink key={scene.id} scene={scene} />
|
||||
));
|
||||
|
||||
const popoverContent = props.gallery.scenes.map((scene) => (
|
||||
<SceneLink key={scene.id} scene={scene} />
|
||||
));
|
||||
|
||||
return (
|
||||
<HoverPopover
|
||||
className="scene-count"
|
||||
placement="bottom"
|
||||
content={popoverContent}
|
||||
>
|
||||
<Button className="minimal">
|
||||
<Icon icon={faPlayCircle} />
|
||||
<span>{props.gallery.scenes.length}</span>
|
||||
</Button>
|
||||
</HoverPopover>
|
||||
);
|
||||
}
|
||||
|
||||
function maybeRenderTagPopoverButton() {
|
||||
if (props.gallery.tags.length <= 0) return;
|
||||
|
||||
const popoverContent = props.gallery.tags.map((tag) => (
|
||||
<TagLink key={tag.id} tag={tag} linkType="gallery" />
|
||||
));
|
||||
|
||||
return (
|
||||
<HoverPopover
|
||||
className="tag-count"
|
||||
placement="bottom"
|
||||
content={popoverContent}
|
||||
>
|
||||
<Button className="minimal">
|
||||
<Icon icon={faTag} />
|
||||
<span>{props.gallery.tags.length}</span>
|
||||
</Button>
|
||||
</HoverPopover>
|
||||
);
|
||||
}
|
||||
|
||||
function maybeRenderPerformerPopoverButton() {
|
||||
if (props.gallery.performers.length <= 0) return;
|
||||
|
||||
return (
|
||||
<PerformerPopoverButton
|
||||
performers={props.gallery.performers}
|
||||
linkType="gallery"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function maybeRenderImagesPopoverButton() {
|
||||
if (!props.gallery.image_count) return;
|
||||
|
||||
return (
|
||||
<PopoverCountButton
|
||||
className="image-count"
|
||||
type="image"
|
||||
count={props.gallery.image_count}
|
||||
url={NavUtils.makeGalleryImagesUrl(props.gallery)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function maybeRenderOrganized() {
|
||||
if (props.gallery.organized) {
|
||||
return (
|
||||
<OverlayTrigger
|
||||
overlay={<Tooltip id="organised-tooltip">{"Organized"}</Tooltip>}
|
||||
<HoverPopover
|
||||
className="scene-count"
|
||||
placement="bottom"
|
||||
content={popoverContent}
|
||||
>
|
||||
<div className="organized">
|
||||
<Button className="minimal">
|
||||
<Icon icon={faBox} />
|
||||
</Button>
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
<Button className="minimal">
|
||||
<Icon icon={faPlayCircle} />
|
||||
<span>{props.gallery.scenes.length}</span>
|
||||
</Button>
|
||||
</HoverPopover>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function maybeRenderPopoverButtonGroup() {
|
||||
if (
|
||||
props.gallery.scenes.length > 0 ||
|
||||
props.gallery.performers.length > 0 ||
|
||||
props.gallery.tags.length > 0 ||
|
||||
props.gallery.organized ||
|
||||
props.gallery.image_count > 0
|
||||
) {
|
||||
function maybeRenderTagPopoverButton() {
|
||||
if (props.gallery.tags.length <= 0) return;
|
||||
|
||||
const popoverContent = props.gallery.tags.map((tag) => (
|
||||
<TagLink key={tag.id} tag={tag} linkType="gallery" />
|
||||
));
|
||||
|
||||
return (
|
||||
<>
|
||||
<hr />
|
||||
<ButtonGroup className="card-popovers">
|
||||
{maybeRenderImagesPopoverButton()}
|
||||
{maybeRenderTagPopoverButton()}
|
||||
{maybeRenderPerformerPopoverButton()}
|
||||
{maybeRenderScenePopoverButton()}
|
||||
{maybeRenderOrganized()}
|
||||
</ButtonGroup>
|
||||
</>
|
||||
<HoverPopover
|
||||
className="tag-count"
|
||||
placement="bottom"
|
||||
content={popoverContent}
|
||||
>
|
||||
<Button className="minimal">
|
||||
<Icon icon={faTag} />
|
||||
<span>{props.gallery.tags.length}</span>
|
||||
</Button>
|
||||
</HoverPopover>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<GridCard
|
||||
className={`gallery-card zoom-${props.zoomIndex}`}
|
||||
url={`/galleries/${props.gallery.id}`}
|
||||
width={props.cardWidth}
|
||||
title={galleryTitle(props.gallery)}
|
||||
linkClassName="gallery-card-header"
|
||||
image={
|
||||
<>
|
||||
<GalleryPreview
|
||||
gallery={props.gallery}
|
||||
onScrubberClick={(i) => {
|
||||
history.push(`/galleries/${props.gallery.id}/images/${i}`);
|
||||
}}
|
||||
/>
|
||||
<RatingBanner rating={props.gallery.rating100} />
|
||||
</>
|
||||
function maybeRenderPerformerPopoverButton() {
|
||||
if (props.gallery.performers.length <= 0) return;
|
||||
|
||||
return (
|
||||
<PerformerPopoverButton
|
||||
performers={props.gallery.performers}
|
||||
linkType="gallery"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function maybeRenderImagesPopoverButton() {
|
||||
if (!props.gallery.image_count) return;
|
||||
|
||||
return (
|
||||
<PopoverCountButton
|
||||
className="image-count"
|
||||
type="image"
|
||||
count={props.gallery.image_count}
|
||||
url={NavUtils.makeGalleryImagesUrl(props.gallery)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function maybeRenderOrganized() {
|
||||
if (props.gallery.organized) {
|
||||
return (
|
||||
<OverlayTrigger
|
||||
overlay={<Tooltip id="organised-tooltip">{"Organized"}</Tooltip>}
|
||||
placement="bottom"
|
||||
>
|
||||
<div className="organized">
|
||||
<Button className="minimal">
|
||||
<Icon icon={faBox} />
|
||||
</Button>
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
);
|
||||
}
|
||||
overlays={<StudioOverlay studio={props.gallery.studio} />}
|
||||
details={
|
||||
<div className="gallery-card__details">
|
||||
<span className="gallery-card__date">{props.gallery.date}</span>
|
||||
<TruncatedText
|
||||
className="gallery-card__description"
|
||||
text={props.gallery.details}
|
||||
lineCount={3}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
function maybeRenderPopoverButtonGroup() {
|
||||
if (
|
||||
props.gallery.scenes.length > 0 ||
|
||||
props.gallery.performers.length > 0 ||
|
||||
props.gallery.tags.length > 0 ||
|
||||
props.gallery.organized ||
|
||||
props.gallery.image_count > 0
|
||||
) {
|
||||
return (
|
||||
<>
|
||||
<hr />
|
||||
<ButtonGroup className="card-popovers">
|
||||
{maybeRenderImagesPopoverButton()}
|
||||
{maybeRenderTagPopoverButton()}
|
||||
{maybeRenderPerformerPopoverButton()}
|
||||
{maybeRenderScenePopoverButton()}
|
||||
{maybeRenderOrganized()}
|
||||
</ButtonGroup>
|
||||
</>
|
||||
);
|
||||
}
|
||||
popovers={maybeRenderPopoverButtonGroup()}
|
||||
selected={props.selected}
|
||||
selecting={props.selecting}
|
||||
onSelectedChanged={props.onSelectedChanged}
|
||||
/>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
return <>{maybeRenderPopoverButtonGroup()}</>;
|
||||
}
|
||||
);
|
||||
|
||||
const GalleryCardDetails = PatchComponent(
|
||||
"GalleryCard.Details",
|
||||
(props: IGalleryCardProps) => {
|
||||
return (
|
||||
<div className="gallery-card__details">
|
||||
<span className="gallery-card__date">{props.gallery.date}</span>
|
||||
<TruncatedText
|
||||
className="gallery-card__description"
|
||||
text={props.gallery.details}
|
||||
lineCount={3}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const GalleryCardOverlays = PatchComponent(
|
||||
"GalleryCard.Overlays",
|
||||
(props: IGalleryCardProps) => {
|
||||
return <StudioOverlay studio={props.gallery.studio} />;
|
||||
}
|
||||
);
|
||||
|
||||
const GalleryCardImage = PatchComponent(
|
||||
"GalleryCard.Image",
|
||||
(props: IGalleryCardProps) => {
|
||||
const history = useHistory();
|
||||
|
||||
return (
|
||||
<>
|
||||
<GalleryPreview
|
||||
gallery={props.gallery}
|
||||
onScrubberClick={(i) => {
|
||||
history.push(`/galleries/${props.gallery.id}/images/${i}`);
|
||||
}}
|
||||
/>
|
||||
<RatingBanner rating={props.gallery.rating100} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export const GalleryCard = PatchComponent(
|
||||
"GalleryCard",
|
||||
(props: IGalleryCardProps) => {
|
||||
return (
|
||||
<GridCard
|
||||
className={`gallery-card zoom-${props.zoomIndex}`}
|
||||
url={`/galleries/${props.gallery.id}`}
|
||||
width={props.cardWidth}
|
||||
title={galleryTitle(props.gallery)}
|
||||
linkClassName="gallery-card-header"
|
||||
image={<GalleryCardImage {...props} />}
|
||||
overlays={<GalleryCardOverlays {...props} />}
|
||||
details={<GalleryCardDetails {...props} />}
|
||||
popovers={<GalleryCardPopovers {...props} />}
|
||||
selected={props.selected}
|
||||
selecting={props.selecting}
|
||||
onSelectedChanged={props.onSelectedChanged}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -154,6 +154,11 @@ Returns `void`.
|
||||
- `ExternalLinksButton`
|
||||
- `FolderSelect`
|
||||
- `FrontPage`
|
||||
- `GalleryCard`
|
||||
- `GalleryCard.Details`
|
||||
- `GalleryCard.Image`
|
||||
- `GalleryCard.Overlays`
|
||||
- `GalleryCard.Popovers`
|
||||
- `GalleryIDSelect`
|
||||
- `GallerySelect`
|
||||
- `GallerySelect.sort`
|
||||
|
||||
5
ui/v2.5/src/pluginApi.d.ts
vendored
5
ui/v2.5/src/pluginApi.d.ts
vendored
@@ -715,6 +715,11 @@ declare namespace PluginApi {
|
||||
"ScenePage.TabContent": React.FC<any>;
|
||||
ScenePlayer: React.FC<any>;
|
||||
FrontPage: React.FC<any>;
|
||||
GalleryCard: React.FC<any>;
|
||||
"GalleryCard.Details": React.FC<any>;
|
||||
"GalleryCard.Image": React.FC<any>;
|
||||
"GalleryCard.Overlays": React.FC<any>;
|
||||
"GalleryCard.Popovers": React.FC<any>;
|
||||
};
|
||||
type PatchableComponentNames = keyof typeof components | string;
|
||||
namespace utils {
|
||||
|
||||
Reference in New Issue
Block a user