mirror of
https://github.com/stashapp/stash.git
synced 2026-04-25 08:24:03 +02:00
Plugin API - recommendation row components (#6492)
* Patched RecommendationRow component * Patched @ant-design/react-slick library to ReactSlick * Patched GalleryRecommendationRow component * Patched GroupRecommendationRow component * Patched ImageRecommendationRow component * Patched PerformerRecommendationRow component * Patched SceneRecommendationRow component * Patched SceneMarkerRecommendationRow component * Patched StudioRecommendationRow component * Patched TagRecommendationRow component
This commit is contained in:
parent
6049b21d22
commit
b4969add27
11 changed files with 352 additions and 297 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import React, { PropsWithChildren } from "react";
|
||||
import { PatchComponent } from "src/patch";
|
||||
|
||||
interface IProps {
|
||||
className?: string;
|
||||
|
|
@ -6,19 +7,18 @@ interface IProps {
|
|||
link: JSX.Element;
|
||||
}
|
||||
|
||||
export const RecommendationRow: React.FC<PropsWithChildren<IProps>> = ({
|
||||
className,
|
||||
header,
|
||||
link,
|
||||
children,
|
||||
}) => (
|
||||
<div className={`recommendation-row ${className}`}>
|
||||
<div className="recommendation-row-head">
|
||||
<div>
|
||||
<h2>{header}</h2>
|
||||
export const RecommendationRow: React.FC<PropsWithChildren<IProps>> =
|
||||
PatchComponent(
|
||||
"RecommendationRow",
|
||||
({ className, header, link, children }) => (
|
||||
<div className={`recommendation-row ${className}`}>
|
||||
<div className="recommendation-row-head">
|
||||
<div>
|
||||
<h2>{header}</h2>
|
||||
</div>
|
||||
{link}
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
{link}
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { ListFilterModel } from "src/models/list-filter/filter";
|
|||
import { getSlickSliderSettings } from "src/core/recommendations";
|
||||
import { RecommendationRow } from "../FrontPage/RecommendationRow";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { PatchComponent } from "src/patch";
|
||||
|
||||
interface IProps {
|
||||
isTouch: boolean;
|
||||
|
|
@ -14,41 +15,44 @@ interface IProps {
|
|||
header: string;
|
||||
}
|
||||
|
||||
export const GalleryRecommendationRow: React.FC<IProps> = (props) => {
|
||||
const result = useFindGalleries(props.filter);
|
||||
const cardCount = result.data?.findGalleries.count;
|
||||
export const GalleryRecommendationRow: React.FC<IProps> = PatchComponent(
|
||||
"GalleryRecommendationRow",
|
||||
(props) => {
|
||||
const result = useFindGalleries(props.filter);
|
||||
const cardCount = result.data?.findGalleries.count;
|
||||
|
||||
if (!result.loading && !cardCount) {
|
||||
return null;
|
||||
}
|
||||
if (!result.loading && !cardCount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<RecommendationRow
|
||||
className="gallery-recommendations"
|
||||
header={props.header}
|
||||
link={
|
||||
<Link to={`/galleries?${props.filter.makeQueryParameters()}`}>
|
||||
<FormattedMessage id="view_all" />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
<Slider
|
||||
{...getSlickSliderSettings(
|
||||
cardCount ? cardCount : props.filter.itemsPerPage,
|
||||
props.isTouch
|
||||
)}
|
||||
return (
|
||||
<RecommendationRow
|
||||
className="gallery-recommendations"
|
||||
header={props.header}
|
||||
link={
|
||||
<Link to={`/galleries?${props.filter.makeQueryParameters()}`}>
|
||||
<FormattedMessage id="view_all" />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div
|
||||
key={`_${i}`}
|
||||
className="gallery-skeleton skeleton-card"
|
||||
></div>
|
||||
))
|
||||
: result.data?.findGalleries.galleries.map((g) => (
|
||||
<GalleryCard key={g.id} gallery={g} zoomIndex={1} />
|
||||
))}
|
||||
</Slider>
|
||||
</RecommendationRow>
|
||||
);
|
||||
};
|
||||
<Slider
|
||||
{...getSlickSliderSettings(
|
||||
cardCount ? cardCount : props.filter.itemsPerPage,
|
||||
props.isTouch
|
||||
)}
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div
|
||||
key={`_${i}`}
|
||||
className="gallery-skeleton skeleton-card"
|
||||
></div>
|
||||
))
|
||||
: result.data?.findGalleries.galleries.map((g) => (
|
||||
<GalleryCard key={g.id} gallery={g} zoomIndex={1} />
|
||||
))}
|
||||
</Slider>
|
||||
</RecommendationRow>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { ListFilterModel } from "src/models/list-filter/filter";
|
|||
import { getSlickSliderSettings } from "src/core/recommendations";
|
||||
import { RecommendationRow } from "../FrontPage/RecommendationRow";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { PatchComponent } from "src/patch";
|
||||
|
||||
interface IProps {
|
||||
isTouch: boolean;
|
||||
|
|
@ -14,38 +15,44 @@ interface IProps {
|
|||
header: string;
|
||||
}
|
||||
|
||||
export const GroupRecommendationRow: React.FC<IProps> = (props: IProps) => {
|
||||
const result = useFindGroups(props.filter);
|
||||
const cardCount = result.data?.findGroups.count;
|
||||
export const GroupRecommendationRow: React.FC<IProps> = PatchComponent(
|
||||
"GroupRecommendationRow",
|
||||
(props: IProps) => {
|
||||
const result = useFindGroups(props.filter);
|
||||
const cardCount = result.data?.findGroups.count;
|
||||
|
||||
if (!result.loading && !cardCount) {
|
||||
return null;
|
||||
}
|
||||
if (!result.loading && !cardCount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<RecommendationRow
|
||||
className="group-recommendations"
|
||||
header={props.header}
|
||||
link={
|
||||
<Link to={`/groups?${props.filter.makeQueryParameters()}`}>
|
||||
<FormattedMessage id="view_all" />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
<Slider
|
||||
{...getSlickSliderSettings(
|
||||
cardCount ? cardCount : props.filter.itemsPerPage,
|
||||
props.isTouch
|
||||
)}
|
||||
return (
|
||||
<RecommendationRow
|
||||
className="group-recommendations"
|
||||
header={props.header}
|
||||
link={
|
||||
<Link to={`/groups?${props.filter.makeQueryParameters()}`}>
|
||||
<FormattedMessage id="view_all" />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div key={`_${i}`} className="group-skeleton skeleton-card"></div>
|
||||
))
|
||||
: result.data?.findGroups.groups.map((g) => (
|
||||
<GroupCard key={g.id} group={g} />
|
||||
))}
|
||||
</Slider>
|
||||
</RecommendationRow>
|
||||
);
|
||||
};
|
||||
<Slider
|
||||
{...getSlickSliderSettings(
|
||||
cardCount ? cardCount : props.filter.itemsPerPage,
|
||||
props.isTouch
|
||||
)}
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div
|
||||
key={`_${i}`}
|
||||
className="group-skeleton skeleton-card"
|
||||
></div>
|
||||
))
|
||||
: result.data?.findGroups.groups.map((g) => (
|
||||
<GroupCard key={g.id} group={g} />
|
||||
))}
|
||||
</Slider>
|
||||
</RecommendationRow>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { getSlickSliderSettings } from "src/core/recommendations";
|
|||
import { RecommendationRow } from "../FrontPage/RecommendationRow";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { ImageCard } from "./ImageCard";
|
||||
import { PatchComponent } from "src/patch";
|
||||
|
||||
interface IProps {
|
||||
isTouch: boolean;
|
||||
|
|
@ -14,38 +15,44 @@ interface IProps {
|
|||
header: string;
|
||||
}
|
||||
|
||||
export const ImageRecommendationRow: React.FC<IProps> = (props: IProps) => {
|
||||
const result = useFindImages(props.filter);
|
||||
const cardCount = result.data?.findImages.count;
|
||||
export const ImageRecommendationRow: React.FC<IProps> = PatchComponent(
|
||||
"ImageRecommendationRow",
|
||||
(props: IProps) => {
|
||||
const result = useFindImages(props.filter);
|
||||
const cardCount = result.data?.findImages.count;
|
||||
|
||||
if (!result.loading && !cardCount) {
|
||||
return null;
|
||||
}
|
||||
if (!result.loading && !cardCount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<RecommendationRow
|
||||
className="images-recommendations"
|
||||
header={props.header}
|
||||
link={
|
||||
<Link to={`/images?${props.filter.makeQueryParameters()}`}>
|
||||
<FormattedMessage id="view_all" />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
<Slider
|
||||
{...getSlickSliderSettings(
|
||||
cardCount ? cardCount : props.filter.itemsPerPage,
|
||||
props.isTouch
|
||||
)}
|
||||
return (
|
||||
<RecommendationRow
|
||||
className="images-recommendations"
|
||||
header={props.header}
|
||||
link={
|
||||
<Link to={`/images?${props.filter.makeQueryParameters()}`}>
|
||||
<FormattedMessage id="view_all" />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div key={`_${i}`} className="image-skeleton skeleton-card"></div>
|
||||
))
|
||||
: result.data?.findImages.images.map((i) => (
|
||||
<ImageCard key={i.id} image={i} zoomIndex={1} />
|
||||
))}
|
||||
</Slider>
|
||||
</RecommendationRow>
|
||||
);
|
||||
};
|
||||
<Slider
|
||||
{...getSlickSliderSettings(
|
||||
cardCount ? cardCount : props.filter.itemsPerPage,
|
||||
props.isTouch
|
||||
)}
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div
|
||||
key={`_${i}`}
|
||||
className="image-skeleton skeleton-card"
|
||||
></div>
|
||||
))
|
||||
: result.data?.findImages.images.map((i) => (
|
||||
<ImageCard key={i.id} image={i} zoomIndex={1} />
|
||||
))}
|
||||
</Slider>
|
||||
</RecommendationRow>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { ListFilterModel } from "src/models/list-filter/filter";
|
|||
import { getSlickSliderSettings } from "src/core/recommendations";
|
||||
import { RecommendationRow } from "../FrontPage/RecommendationRow";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { PatchComponent } from "src/patch";
|
||||
|
||||
interface IProps {
|
||||
isTouch: boolean;
|
||||
|
|
@ -14,41 +15,44 @@ interface IProps {
|
|||
header: string;
|
||||
}
|
||||
|
||||
export const PerformerRecommendationRow: React.FC<IProps> = (props) => {
|
||||
const result = useFindPerformers(props.filter);
|
||||
const cardCount = result.data?.findPerformers.count;
|
||||
export const PerformerRecommendationRow: React.FC<IProps> = PatchComponent(
|
||||
"PerformerRecommendationRow",
|
||||
(props) => {
|
||||
const result = useFindPerformers(props.filter);
|
||||
const cardCount = result.data?.findPerformers.count;
|
||||
|
||||
if (!result.loading && !cardCount) {
|
||||
return null;
|
||||
}
|
||||
if (!result.loading && !cardCount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<RecommendationRow
|
||||
className="performer-recommendations"
|
||||
header={props.header}
|
||||
link={
|
||||
<Link to={`/performers?${props.filter.makeQueryParameters()}`}>
|
||||
<FormattedMessage id="view_all" />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
<Slider
|
||||
{...getSlickSliderSettings(
|
||||
cardCount ? cardCount : props.filter.itemsPerPage,
|
||||
props.isTouch
|
||||
)}
|
||||
return (
|
||||
<RecommendationRow
|
||||
className="performer-recommendations"
|
||||
header={props.header}
|
||||
link={
|
||||
<Link to={`/performers?${props.filter.makeQueryParameters()}`}>
|
||||
<FormattedMessage id="view_all" />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div
|
||||
key={`_${i}`}
|
||||
className="performer-skeleton skeleton-card"
|
||||
></div>
|
||||
))
|
||||
: result.data?.findPerformers.performers.map((p) => (
|
||||
<PerformerCard key={p.id} performer={p} />
|
||||
))}
|
||||
</Slider>
|
||||
</RecommendationRow>
|
||||
);
|
||||
};
|
||||
<Slider
|
||||
{...getSlickSliderSettings(
|
||||
cardCount ? cardCount : props.filter.itemsPerPage,
|
||||
props.isTouch
|
||||
)}
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div
|
||||
key={`_${i}`}
|
||||
className="performer-skeleton skeleton-card"
|
||||
></div>
|
||||
))
|
||||
: result.data?.findPerformers.performers.map((p) => (
|
||||
<PerformerCard key={p.id} performer={p} />
|
||||
))}
|
||||
</Slider>
|
||||
</RecommendationRow>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { getSlickSliderSettings } from "src/core/recommendations";
|
|||
import { RecommendationRow } from "../FrontPage/RecommendationRow";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { SceneMarkerCard } from "./SceneMarkerCard";
|
||||
import { PatchComponent } from "src/patch";
|
||||
|
||||
interface IProps {
|
||||
isTouch: boolean;
|
||||
|
|
@ -14,46 +15,51 @@ interface IProps {
|
|||
header: string;
|
||||
}
|
||||
|
||||
export const SceneMarkerRecommendationRow: React.FC<IProps> = (props) => {
|
||||
const result = useFindSceneMarkers(props.filter);
|
||||
const cardCount = result.data?.findSceneMarkers.count;
|
||||
export const SceneMarkerRecommendationRow: React.FC<IProps> = PatchComponent(
|
||||
"SceneMarkerRecommendationRow",
|
||||
(props) => {
|
||||
const result = useFindSceneMarkers(props.filter);
|
||||
const cardCount = result.data?.findSceneMarkers.count;
|
||||
|
||||
if (!result.loading && !cardCount) {
|
||||
return null;
|
||||
}
|
||||
if (!result.loading && !cardCount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<RecommendationRow
|
||||
className="scene-marker-recommendations"
|
||||
header={props.header}
|
||||
link={
|
||||
<Link to={`/scenes/markers?${props.filter.makeQueryParameters()}`}>
|
||||
<FormattedMessage id="view_all" />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
<Slider
|
||||
{...getSlickSliderSettings(
|
||||
cardCount ? cardCount : props.filter.itemsPerPage,
|
||||
props.isTouch
|
||||
)}
|
||||
return (
|
||||
<RecommendationRow
|
||||
className="scene-marker-recommendations"
|
||||
header={props.header}
|
||||
link={
|
||||
<Link to={`/scenes/markers?${props.filter.makeQueryParameters()}`}>
|
||||
<FormattedMessage id="view_all" />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div
|
||||
key={`_${i}`}
|
||||
className="scene-marker-skeleton skeleton-card"
|
||||
></div>
|
||||
))
|
||||
: result.data?.findSceneMarkers.scene_markers.map((marker, index) => (
|
||||
<SceneMarkerCard
|
||||
key={marker.id}
|
||||
marker={marker}
|
||||
index={index}
|
||||
zoomIndex={1}
|
||||
/>
|
||||
))}
|
||||
</Slider>
|
||||
</RecommendationRow>
|
||||
);
|
||||
};
|
||||
<Slider
|
||||
{...getSlickSliderSettings(
|
||||
cardCount ? cardCount : props.filter.itemsPerPage,
|
||||
props.isTouch
|
||||
)}
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div
|
||||
key={`_${i}`}
|
||||
className="scene-marker-skeleton skeleton-card"
|
||||
></div>
|
||||
))
|
||||
: result.data?.findSceneMarkers.scene_markers.map(
|
||||
(marker, index) => (
|
||||
<SceneMarkerCard
|
||||
key={marker.id}
|
||||
marker={marker}
|
||||
index={index}
|
||||
zoomIndex={1}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</Slider>
|
||||
</RecommendationRow>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { ListFilterModel } from "src/models/list-filter/filter";
|
|||
import { getSlickSliderSettings } from "src/core/recommendations";
|
||||
import { RecommendationRow } from "../FrontPage/RecommendationRow";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { PatchComponent } from "src/patch";
|
||||
|
||||
interface IProps {
|
||||
isTouch: boolean;
|
||||
|
|
@ -15,48 +16,54 @@ interface IProps {
|
|||
header: string;
|
||||
}
|
||||
|
||||
export const SceneRecommendationRow: React.FC<IProps> = (props) => {
|
||||
const result = useFindScenes(props.filter);
|
||||
const cardCount = result.data?.findScenes.count;
|
||||
export const SceneRecommendationRow: React.FC<IProps> = PatchComponent(
|
||||
"SceneRecommendationRow",
|
||||
(props) => {
|
||||
const result = useFindScenes(props.filter);
|
||||
const cardCount = result.data?.findScenes.count;
|
||||
|
||||
const queue = useMemo(() => {
|
||||
return SceneQueue.fromListFilterModel(props.filter);
|
||||
}, [props.filter]);
|
||||
const queue = useMemo(() => {
|
||||
return SceneQueue.fromListFilterModel(props.filter);
|
||||
}, [props.filter]);
|
||||
|
||||
if (!result.loading && !cardCount) {
|
||||
return null;
|
||||
}
|
||||
if (!result.loading && !cardCount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<RecommendationRow
|
||||
className="scene-recommendations"
|
||||
header={props.header}
|
||||
link={
|
||||
<Link to={`/scenes?${props.filter.makeQueryParameters()}`}>
|
||||
<FormattedMessage id="view_all" />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
<Slider
|
||||
{...getSlickSliderSettings(
|
||||
cardCount ? cardCount : props.filter.itemsPerPage,
|
||||
props.isTouch
|
||||
)}
|
||||
return (
|
||||
<RecommendationRow
|
||||
className="scene-recommendations"
|
||||
header={props.header}
|
||||
link={
|
||||
<Link to={`/scenes?${props.filter.makeQueryParameters()}`}>
|
||||
<FormattedMessage id="view_all" />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div key={`_${i}`} className="scene-skeleton skeleton-card"></div>
|
||||
))
|
||||
: result.data?.findScenes.scenes.map((scene, index) => (
|
||||
<SceneCard
|
||||
key={scene.id}
|
||||
scene={scene}
|
||||
queue={queue}
|
||||
index={index}
|
||||
zoomIndex={1}
|
||||
/>
|
||||
))}
|
||||
</Slider>
|
||||
</RecommendationRow>
|
||||
);
|
||||
};
|
||||
<Slider
|
||||
{...getSlickSliderSettings(
|
||||
cardCount ? cardCount : props.filter.itemsPerPage,
|
||||
props.isTouch
|
||||
)}
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div
|
||||
key={`_${i}`}
|
||||
className="scene-skeleton skeleton-card"
|
||||
></div>
|
||||
))
|
||||
: result.data?.findScenes.scenes.map((scene, index) => (
|
||||
<SceneCard
|
||||
key={scene.id}
|
||||
scene={scene}
|
||||
queue={queue}
|
||||
index={index}
|
||||
zoomIndex={1}
|
||||
/>
|
||||
))}
|
||||
</Slider>
|
||||
</RecommendationRow>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { ListFilterModel } from "src/models/list-filter/filter";
|
|||
import { getSlickSliderSettings } from "src/core/recommendations";
|
||||
import { RecommendationRow } from "../FrontPage/RecommendationRow";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { PatchComponent } from "src/patch";
|
||||
|
||||
interface IProps {
|
||||
isTouch: boolean;
|
||||
|
|
@ -14,41 +15,44 @@ interface IProps {
|
|||
header: string;
|
||||
}
|
||||
|
||||
export const StudioRecommendationRow: React.FC<IProps> = (props) => {
|
||||
const result = useFindStudios(props.filter);
|
||||
const cardCount = result.data?.findStudios.count;
|
||||
export const StudioRecommendationRow: React.FC<IProps> = PatchComponent(
|
||||
"StudioRecommendationRow",
|
||||
(props) => {
|
||||
const result = useFindStudios(props.filter);
|
||||
const cardCount = result.data?.findStudios.count;
|
||||
|
||||
if (!result.loading && !cardCount) {
|
||||
return null;
|
||||
}
|
||||
if (!result.loading && !cardCount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<RecommendationRow
|
||||
className="studio-recommendations"
|
||||
header={props.header}
|
||||
link={
|
||||
<Link to={`/studios?${props.filter.makeQueryParameters()}`}>
|
||||
<FormattedMessage id="view_all" />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
<Slider
|
||||
{...getSlickSliderSettings(
|
||||
cardCount ? cardCount : props.filter.itemsPerPage,
|
||||
props.isTouch
|
||||
)}
|
||||
return (
|
||||
<RecommendationRow
|
||||
className="studio-recommendations"
|
||||
header={props.header}
|
||||
link={
|
||||
<Link to={`/studios?${props.filter.makeQueryParameters()}`}>
|
||||
<FormattedMessage id="view_all" />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div
|
||||
key={`_${i}`}
|
||||
className="studio-skeleton skeleton-card"
|
||||
></div>
|
||||
))
|
||||
: result.data?.findStudios.studios.map((s) => (
|
||||
<StudioCard key={s.id} studio={s} hideParent={true} />
|
||||
))}
|
||||
</Slider>
|
||||
</RecommendationRow>
|
||||
);
|
||||
};
|
||||
<Slider
|
||||
{...getSlickSliderSettings(
|
||||
cardCount ? cardCount : props.filter.itemsPerPage,
|
||||
props.isTouch
|
||||
)}
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div
|
||||
key={`_${i}`}
|
||||
className="studio-skeleton skeleton-card"
|
||||
></div>
|
||||
))
|
||||
: result.data?.findStudios.studios.map((s) => (
|
||||
<StudioCard key={s.id} studio={s} hideParent={true} />
|
||||
))}
|
||||
</Slider>
|
||||
</RecommendationRow>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { ListFilterModel } from "src/models/list-filter/filter";
|
|||
import { getSlickSliderSettings } from "src/core/recommendations";
|
||||
import { RecommendationRow } from "../FrontPage/RecommendationRow";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { PatchComponent } from "src/patch";
|
||||
|
||||
interface IProps {
|
||||
isTouch: boolean;
|
||||
|
|
@ -14,38 +15,41 @@ interface IProps {
|
|||
header: string;
|
||||
}
|
||||
|
||||
export const TagRecommendationRow: React.FC<IProps> = (props) => {
|
||||
const result = useFindTags(props.filter);
|
||||
const cardCount = result.data?.findTags.count;
|
||||
export const TagRecommendationRow: React.FC<IProps> = PatchComponent(
|
||||
"TagRecommendationRow",
|
||||
(props) => {
|
||||
const result = useFindTags(props.filter);
|
||||
const cardCount = result.data?.findTags.count;
|
||||
|
||||
if (!result.loading && !cardCount) {
|
||||
return null;
|
||||
}
|
||||
if (!result.loading && !cardCount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<RecommendationRow
|
||||
className="tag-recommendations"
|
||||
header={props.header}
|
||||
link={
|
||||
<Link to={`/tags?${props.filter.makeQueryParameters()}`}>
|
||||
<FormattedMessage id="view_all" />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
<Slider
|
||||
{...getSlickSliderSettings(
|
||||
cardCount ? cardCount : props.filter.itemsPerPage,
|
||||
props.isTouch
|
||||
)}
|
||||
return (
|
||||
<RecommendationRow
|
||||
className="tag-recommendations"
|
||||
header={props.header}
|
||||
link={
|
||||
<Link to={`/tags?${props.filter.makeQueryParameters()}`}>
|
||||
<FormattedMessage id="view_all" />
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div key={`_${i}`} className="tag-skeleton skeleton-card"></div>
|
||||
))
|
||||
: result.data?.findTags.tags.map((p) => (
|
||||
<TagCard key={p.id} tag={p} zoomIndex={0} />
|
||||
))}
|
||||
</Slider>
|
||||
</RecommendationRow>
|
||||
);
|
||||
};
|
||||
<Slider
|
||||
{...getSlickSliderSettings(
|
||||
cardCount ? cardCount : props.filter.itemsPerPage,
|
||||
props.isTouch
|
||||
)}
|
||||
>
|
||||
{result.loading
|
||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||
<div key={`_${i}`} className="tag-skeleton skeleton-card"></div>
|
||||
))
|
||||
: result.data?.findTags.tags.map((p) => (
|
||||
<TagCard key={p.id} tag={p} zoomIndex={0} />
|
||||
))}
|
||||
</Slider>
|
||||
</RecommendationRow>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
10
ui/v2.5/src/pluginApi.d.ts
vendored
10
ui/v2.5/src/pluginApi.d.ts
vendored
|
|
@ -619,6 +619,7 @@ declare namespace PluginApi {
|
|||
const Mousetrap: typeof import("mousetrap");
|
||||
const ReactFontAwesome: typeof import("@fortawesome/react-fontawesome");
|
||||
const ReactSelect: typeof import("react-select");
|
||||
const ReactSlick: typeof import("@ant-design/react-slick");
|
||||
|
||||
// @ts-expect-error
|
||||
import { MousetrapStatic } from "mousetrap";
|
||||
|
|
@ -677,12 +678,14 @@ declare namespace PluginApi {
|
|||
GalleryIDSelect: React.FC<any>;
|
||||
GalleryImagesPanel: React.FC<any>;
|
||||
GalleryList: React.FC<any>;
|
||||
GalleryRecommendationRow: React.FC<any>;
|
||||
GallerySelect: React.FC<any>;
|
||||
GridCard: React.FC<any>;
|
||||
GroupCard: React.FC<any>;
|
||||
GroupCardGrid: React.FC<any>;
|
||||
GroupIDSelect: React.FC<any>;
|
||||
GroupList: React.FC<any>;
|
||||
GroupRecommendationRow: React.FC<any>;
|
||||
GroupSelect: React.FC<any>;
|
||||
GroupSubGroupsPanel: React.FC<any>;
|
||||
HeaderImage: React.FC<any>;
|
||||
|
|
@ -692,6 +695,7 @@ declare namespace PluginApi {
|
|||
ImageCardGrid: React.FC<any>;
|
||||
ImageInput: React.FC<any>;
|
||||
ImageList: React.FC<any>;
|
||||
ImageRecommendationRow: React.FC<any>;
|
||||
LightboxLink: React.FC<any>;
|
||||
LoadingIndicator: React.FC<any>;
|
||||
"MainNavBar.MenuItems": React.FC<any>;
|
||||
|
|
@ -715,12 +719,14 @@ declare namespace PluginApi {
|
|||
PerformerImagesPanel: React.FC<any>;
|
||||
PerformerList: React.FC<any>;
|
||||
PerformerPage: React.FC<any>;
|
||||
PerformerRecommendationRow: React.FC<any>;
|
||||
PerformerScenesPanel: React.FC<any>;
|
||||
PerformerSelect: React.FC<any>;
|
||||
PluginSettings: React.FC<any>;
|
||||
RatingNumber: React.FC<any>;
|
||||
RatingStars: React.FC<any>;
|
||||
RatingSystem: React.FC<any>;
|
||||
RecommendationRow: React.FC<any>;
|
||||
SceneFileInfoPanel: React.FC<any>;
|
||||
SceneIDSelect: React.FC<any>;
|
||||
ScenePage: React.FC<any>;
|
||||
|
|
@ -741,6 +747,8 @@ declare namespace PluginApi {
|
|||
"SceneMarkerCard.Popovers": React.FC<any>;
|
||||
SceneMarkerCardGrid: React.FC<any>;
|
||||
SceneMarkerList: React.FC<any>;
|
||||
SceneMarkerRecommendationRow: React.FC<any>;
|
||||
SceneRecommendationRow: React.FC<any>;
|
||||
SelectSetting: React.FC<any>;
|
||||
Setting: React.FC<any>;
|
||||
SettingGroup: React.FC<any>;
|
||||
|
|
@ -752,6 +760,7 @@ declare namespace PluginApi {
|
|||
StudioDetailsPanel: React.FC<any>;
|
||||
StudioIDSelect: React.FC<any>;
|
||||
StudioList: React.FC<any>;
|
||||
StudioRecommendationRow: React.FC<any>;
|
||||
StudioSelect: React.FC<any>;
|
||||
SweatDrops: React.FC<any>;
|
||||
TabTitleCounter: React.FC<any>;
|
||||
|
|
@ -764,6 +773,7 @@ declare namespace PluginApi {
|
|||
TagCardGrid: React.FC<any>;
|
||||
TagLink: React.FC<any>;
|
||||
TagList: React.FC<any>;
|
||||
TagRecommendationRow: React.FC<any>;
|
||||
TagSelect: React.FC<any>;
|
||||
TruncatedText: React.FC<any>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import * as FontAwesomeRegular from "@fortawesome/free-regular-svg-icons";
|
|||
import * as FontAwesomeBrands from "@fortawesome/free-brands-svg-icons";
|
||||
import * as ReactFontAwesome from "@fortawesome/react-fontawesome";
|
||||
import * as ReactSelect from "react-select";
|
||||
import * as ReactSlick from "@ant-design/react-slick";
|
||||
import { useSpriteInfo } from "./hooks/sprite";
|
||||
import { useToast } from "./hooks/Toast";
|
||||
import Event from "./hooks/event";
|
||||
|
|
@ -81,6 +82,7 @@ export const PluginApi = {
|
|||
MousetrapPause,
|
||||
ReactFontAwesome,
|
||||
ReactSelect,
|
||||
ReactSlick,
|
||||
},
|
||||
register: {
|
||||
// register a route to be added to the main router
|
||||
|
|
|
|||
Loading…
Reference in a new issue