mirror of
https://github.com/stashapp/stash.git
synced 2025-12-16 20:07:05 +03:00
Make directors and photographers clickable in detail view (#4621)
* Make directors and photographers clickable * Make director clickable on movie details page --------- Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import { PerformerCard } from "src/components/Performers/PerformerCard";
|
||||
import { RatingSystem } from "src/components/Shared/Rating/RatingSystem";
|
||||
import { sortPerformers } from "src/core/performers";
|
||||
import { galleryTitle } from "src/core/galleries";
|
||||
import { PhotographerLink } from "src/components/Shared/Link";
|
||||
|
||||
interface IGalleryDetailProps {
|
||||
gallery: GQL.GalleryDataFragment;
|
||||
@@ -118,7 +119,11 @@ export const GalleryDetailPanel: React.FC<IGalleryDetailProps> = ({
|
||||
)}
|
||||
{gallery.photographer && (
|
||||
<h6>
|
||||
<FormattedMessage id="photographer" />: {gallery.photographer}{" "}
|
||||
<FormattedMessage id="photographer" />:{" "}
|
||||
<PhotographerLink
|
||||
photographer={gallery.photographer}
|
||||
linkType="gallery"
|
||||
/>
|
||||
</h6>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -9,6 +9,7 @@ import { RatingSystem } from "src/components/Shared/Rating/RatingSystem";
|
||||
import { sortPerformers } from "src/core/performers";
|
||||
import { FormattedDate, FormattedMessage, useIntl } from "react-intl";
|
||||
import { objectTitle } from "src/core/files";
|
||||
import { PhotographerLink } from "src/components/Shared/Link";
|
||||
interface IImageDetailProps {
|
||||
image: GQL.ImageDataFragment;
|
||||
}
|
||||
@@ -154,7 +155,11 @@ export const ImageDetailPanel: React.FC<IImageDetailProps> = (props) => {
|
||||
)}
|
||||
{props.image.photographer && (
|
||||
<h6>
|
||||
<FormattedMessage id="photographer" />: {props.image.photographer}{" "}
|
||||
<FormattedMessage id="photographer" />:{" "}
|
||||
<PhotographerLink
|
||||
photographer={props.image.photographer}
|
||||
linkType="image"
|
||||
/>
|
||||
</h6>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,7 @@ import * as GQL from "src/core/generated-graphql";
|
||||
import TextUtils from "src/utils/text";
|
||||
import { DetailItem } from "src/components/Shared/DetailItem";
|
||||
import { Link } from "react-router-dom";
|
||||
import { DirectorLink } from "src/components/Shared/Link";
|
||||
|
||||
interface IMovieDetailsPanel {
|
||||
movie: GQL.MovieDataFragment;
|
||||
@@ -45,7 +46,17 @@ export const MovieDetailsPanel: React.FC<IMovieDetailsPanel> = ({
|
||||
fullWidth={fullWidth}
|
||||
/>
|
||||
|
||||
<DetailItem id="director" value={movie.director} fullWidth={fullWidth} />
|
||||
<DetailItem
|
||||
id="director"
|
||||
value={
|
||||
movie.director ? (
|
||||
<DirectorLink director={movie.director} linkType="movie" />
|
||||
) : (
|
||||
""
|
||||
)
|
||||
}
|
||||
fullWidth={fullWidth}
|
||||
/>
|
||||
<DetailItem id="synopsis" value={movie.synopsis} fullWidth={fullWidth} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -9,6 +9,7 @@ import { PerformerCard } from "src/components/Performers/PerformerCard";
|
||||
import { sortPerformers } from "src/core/performers";
|
||||
import { RatingSystem } from "src/components/Shared/Rating/RatingSystem";
|
||||
import { objectTitle } from "src/core/files";
|
||||
import { DirectorLink } from "src/components/Shared/Link";
|
||||
|
||||
interface ISceneDetailProps {
|
||||
scene: GQL.SceneDataFragment;
|
||||
@@ -128,7 +129,8 @@ export const SceneDetailPanel: React.FC<ISceneDetailProps> = (props) => {
|
||||
)}
|
||||
{props.scene.director && (
|
||||
<h6>
|
||||
<FormattedMessage id="director" />: {props.scene.director}{" "}
|
||||
<FormattedMessage id="director" />:{" "}
|
||||
<DirectorLink director={props.scene.director} linkType="scene" />
|
||||
</h6>
|
||||
)}
|
||||
</div>
|
||||
|
||||
37
ui/v2.5/src/components/Shared/Link.tsx
Normal file
37
ui/v2.5/src/components/Shared/Link.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { useMemo } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import NavUtils from "src/utils/navigation";
|
||||
|
||||
// common link components
|
||||
|
||||
export const DirectorLink: React.FC<{
|
||||
director: string;
|
||||
linkType: "scene" | "movie";
|
||||
}> = ({ director: director, linkType = "scene" }) => {
|
||||
const link = useMemo(() => {
|
||||
switch (linkType) {
|
||||
case "scene":
|
||||
return NavUtils.makeDirectorScenesUrl(director);
|
||||
case "movie":
|
||||
return NavUtils.makeDirectorMoviesUrl(director);
|
||||
}
|
||||
}, [director, linkType]);
|
||||
|
||||
return <Link to={link}>{director}</Link>;
|
||||
};
|
||||
|
||||
export const PhotographerLink: React.FC<{
|
||||
photographer: string;
|
||||
linkType: "gallery" | "image";
|
||||
}> = ({ photographer, linkType = "image" }) => {
|
||||
const link = useMemo(() => {
|
||||
switch (linkType) {
|
||||
case "gallery":
|
||||
return NavUtils.makePhotographerGalleriesUrl(photographer);
|
||||
case "image":
|
||||
return NavUtils.makePhotographerImagesUrl(photographer);
|
||||
}
|
||||
}, [photographer, linkType]);
|
||||
|
||||
return <Link to={link}>{photographer}</Link>;
|
||||
};
|
||||
@@ -15,7 +15,10 @@ import { ListFilterModel } from "src/models/list-filter/filter";
|
||||
import { MoviesCriterion } from "src/models/list-filter/criteria/movies";
|
||||
import {
|
||||
Criterion,
|
||||
CriterionOption,
|
||||
CriterionValue,
|
||||
StringCriterion,
|
||||
createStringCriterionOption,
|
||||
} from "src/models/list-filter/criteria/criterion";
|
||||
import { GalleriesCriterion } from "src/models/list-filter/criteria/galleries";
|
||||
import { PhashCriterion } from "src/models/list-filter/criteria/phash";
|
||||
@@ -355,6 +358,55 @@ const makeGalleryImagesUrl = (
|
||||
return `/images?${filter.makeQueryParameters()}`;
|
||||
};
|
||||
|
||||
function stringEqualsCriterion(option: CriterionOption, value: string) {
|
||||
const criterion = new StringCriterion(option);
|
||||
criterion.modifier = GQL.CriterionModifier.Equals;
|
||||
criterion.value = value;
|
||||
return criterion;
|
||||
}
|
||||
|
||||
const makeDirectorScenesUrl = (director: string) => {
|
||||
if (director.length == 0) return "#";
|
||||
const filter = new ListFilterModel(GQL.FilterMode.Scenes, undefined);
|
||||
filter.criteria.push(
|
||||
stringEqualsCriterion(createStringCriterionOption("director"), director)
|
||||
);
|
||||
return `/scenes?${filter.makeQueryParameters()}`;
|
||||
};
|
||||
|
||||
const makeDirectorMoviesUrl = (director: string) => {
|
||||
if (director.length == 0) return "#";
|
||||
const filter = new ListFilterModel(GQL.FilterMode.Movies, undefined);
|
||||
filter.criteria.push(
|
||||
stringEqualsCriterion(createStringCriterionOption("director"), director)
|
||||
);
|
||||
return `/movies?${filter.makeQueryParameters()}`;
|
||||
};
|
||||
|
||||
const makePhotographerGalleriesUrl = (photographer: string) => {
|
||||
if (photographer.length == 0) return "#";
|
||||
const filter = new ListFilterModel(GQL.FilterMode.Galleries, undefined);
|
||||
filter.criteria.push(
|
||||
stringEqualsCriterion(
|
||||
createStringCriterionOption("photographer"),
|
||||
photographer
|
||||
)
|
||||
);
|
||||
return `/galleries?${filter.makeQueryParameters()}`;
|
||||
};
|
||||
|
||||
const makePhotographerImagesUrl = (photographer: string) => {
|
||||
if (photographer.length == 0) return "#";
|
||||
const filter = new ListFilterModel(GQL.FilterMode.Images, undefined);
|
||||
filter.criteria.push(
|
||||
stringEqualsCriterion(
|
||||
createStringCriterionOption("photographer"),
|
||||
photographer
|
||||
)
|
||||
);
|
||||
return `/images?${filter.makeQueryParameters()}`;
|
||||
};
|
||||
|
||||
export function handleUnsavedChanges(
|
||||
intl: IntlShape,
|
||||
basepath: string,
|
||||
@@ -394,6 +446,10 @@ const NavUtils = {
|
||||
makeMovieScenesUrl,
|
||||
makeChildStudiosUrl,
|
||||
makeGalleryImagesUrl,
|
||||
makeDirectorScenesUrl,
|
||||
makePhotographerGalleriesUrl,
|
||||
makePhotographerImagesUrl,
|
||||
makeDirectorMoviesUrl,
|
||||
};
|
||||
|
||||
export default NavUtils;
|
||||
|
||||
Reference in New Issue
Block a user