mirror of
https://github.com/stashapp/stash.git
synced 2025-12-16 20:07:05 +03:00
Add external links display option for performer thumbnails (#6153)
* Add external links display option for performer thumbnails - Introduced a new setting to show links on performer thumbnails. - Updated PerformerCard to conditionally render social media links (Twitter, Instagram) and other external links. - Enhanced ExternalLinksButton to open single links directly if specified. - Updated configuration and localization files to support the new feature.
This commit is contained in:
@@ -17,12 +17,15 @@ import {
|
||||
} from "src/models/list-filter/criteria/criterion";
|
||||
import { PopoverCountButton } from "../Shared/PopoverCountButton";
|
||||
import GenderIcon from "./GenderIcon";
|
||||
import { faTag } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faLink, faTag } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faInstagram, faTwitter } from "@fortawesome/free-brands-svg-icons";
|
||||
import { RatingBanner } from "../Shared/RatingBanner";
|
||||
import { usePerformerUpdate } from "src/core/StashService";
|
||||
import { ILabeledId } from "src/models/list-filter/types";
|
||||
import { FavoriteIcon } from "../Shared/FavoriteIcon";
|
||||
import { PatchComponent } from "src/patch";
|
||||
import { ExternalLinksButton } from "../Shared/ExternalLinksButton";
|
||||
import { ConfigurationContext } from "src/hooks/Config";
|
||||
|
||||
export interface IPerformerCardExtraCriteria {
|
||||
scenes?: ModifierCriterion<CriterionValue>[];
|
||||
@@ -176,6 +179,8 @@ const PerformerCardPopovers: React.FC<IPerformerCardProps> = PatchComponent(
|
||||
const PerformerCardOverlays: React.FC<IPerformerCardProps> = PatchComponent(
|
||||
"PerformerCard.Overlays",
|
||||
({ performer }) => {
|
||||
const { configuration } = React.useContext(ConfigurationContext);
|
||||
const uiConfig = configuration?.ui;
|
||||
const [updatePerformer] = usePerformerUpdate();
|
||||
|
||||
function onToggleFavorite(v: boolean) {
|
||||
@@ -215,6 +220,63 @@ const PerformerCardOverlays: React.FC<IPerformerCardProps> = PatchComponent(
|
||||
}
|
||||
}
|
||||
|
||||
function maybeRenderLinks() {
|
||||
if (!uiConfig?.showLinksOnPerformerCard) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (performer.urls && performer.urls.length > 0) {
|
||||
const twitter = performer.urls.filter((u) =>
|
||||
u.match(/https?:\/\/(?:www\.)?(?:twitter|x).com\//)
|
||||
);
|
||||
const instagram = performer.urls.filter((u) =>
|
||||
u.match(/https?:\/\/(?:www\.)?instagram.com\//)
|
||||
);
|
||||
const others = performer.urls.filter(
|
||||
(u) => !twitter.includes(u) && !instagram.includes(u)
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="performer-card__links"
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: "0",
|
||||
bottom: "0",
|
||||
display: "flex",
|
||||
gap: "0.5rem",
|
||||
flexDirection: "column-reverse",
|
||||
}}
|
||||
>
|
||||
{twitter.length > 0 && (
|
||||
<ExternalLinksButton
|
||||
className="performer-card__link twitter"
|
||||
urls={twitter}
|
||||
icon={faTwitter}
|
||||
openIfSingle={true}
|
||||
></ExternalLinksButton>
|
||||
)}
|
||||
{instagram.length > 0 && (
|
||||
<ExternalLinksButton
|
||||
className="performer-card__link instagram"
|
||||
urls={instagram}
|
||||
icon={faInstagram}
|
||||
openIfSingle={true}
|
||||
></ExternalLinksButton>
|
||||
)}
|
||||
{others.length > 0 && (
|
||||
<ExternalLinksButton
|
||||
className="performer-card__link"
|
||||
icon={faLink}
|
||||
urls={others}
|
||||
openIfSingle={true}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<FavoriteIcon
|
||||
@@ -224,6 +286,7 @@ const PerformerCardOverlays: React.FC<IPerformerCardProps> = PatchComponent(
|
||||
className="hide-not-favorite"
|
||||
/>
|
||||
{maybeRenderRatingBanner()}
|
||||
{maybeRenderLinks()}
|
||||
{maybeRenderFlag()}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -107,6 +107,10 @@
|
||||
|
||||
.thumbnail-section {
|
||||
position: relative;
|
||||
|
||||
.instagram {
|
||||
color: pink;
|
||||
}
|
||||
}
|
||||
|
||||
&-image {
|
||||
|
||||
@@ -470,6 +470,7 @@ export const SettingsInterfacePanel: React.FC = PatchComponent(
|
||||
onChange={(v) => saveUI({ showChildTagContent: v })}
|
||||
/>
|
||||
</SettingSection>
|
||||
|
||||
<SettingSection headingID="config.ui.studio_panel.heading">
|
||||
<BooleanSetting
|
||||
id="show-child-studio-content"
|
||||
@@ -480,6 +481,15 @@ export const SettingsInterfacePanel: React.FC = PatchComponent(
|
||||
/>
|
||||
</SettingSection>
|
||||
|
||||
<SettingSection headingID="config.ui.performer_list.heading">
|
||||
<BooleanSetting
|
||||
id="show-links-on-grid-card"
|
||||
headingID="config.ui.performer_list.options.show_links_on_grid_card.heading"
|
||||
checked={ui.showLinksOnPerformerCard ?? undefined}
|
||||
onChange={(v) => saveUI({ showLinksOnPerformerCard: v })}
|
||||
/>
|
||||
</SettingSection>
|
||||
|
||||
<SettingSection headingID="config.ui.image_wall.heading">
|
||||
<NumberSetting
|
||||
headingID="config.ui.image_wall.margin"
|
||||
|
||||
@@ -12,9 +12,10 @@ export const ExternalLinksButton: React.FC<{
|
||||
icon?: IconDefinition;
|
||||
urls: string[];
|
||||
className?: string;
|
||||
openIfSingle?: boolean;
|
||||
}> = PatchComponent(
|
||||
"ExternalLinksButton",
|
||||
({ urls, icon = faLink, className = "" }) => {
|
||||
({ urls, icon = faLink, className = "", openIfSingle = false }) => {
|
||||
if (!urls.length) {
|
||||
return null;
|
||||
}
|
||||
@@ -36,14 +37,27 @@ export const ExternalLinksButton: React.FC<{
|
||||
document.body
|
||||
);
|
||||
|
||||
return (
|
||||
<Dropdown className="external-links-button">
|
||||
<Dropdown.Toggle as={Button} className={`minimal link ${className}`}>
|
||||
if (openIfSingle && urls.length === 1) {
|
||||
return (
|
||||
<ExternalLink
|
||||
className={`external-links-button-link minimal btn link ${className}`}
|
||||
href={TextUtils.sanitiseURL(urls[0])}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Icon icon={icon} />
|
||||
</Dropdown.Toggle>
|
||||
<Menu />
|
||||
</Dropdown>
|
||||
);
|
||||
</ExternalLink>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Dropdown className="external-links-button">
|
||||
<Dropdown.Toggle as={Button} className={`minimal link ${className}`}>
|
||||
<Icon icon={icon} />
|
||||
</Dropdown.Toggle>
|
||||
<Menu />
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ export interface IUIConfig {
|
||||
|
||||
showChildTagContent?: boolean;
|
||||
showChildStudioContent?: boolean;
|
||||
showLinksOnPerformerCard?: boolean;
|
||||
showTagCardOnHover?: boolean;
|
||||
|
||||
abbreviateCounters?: boolean;
|
||||
|
||||
@@ -801,6 +801,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"performer_list": {
|
||||
"heading": "Performer list",
|
||||
"options": {
|
||||
"show_links_on_grid_card": {
|
||||
"heading": "Display links on performer grid cards"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tag_panel": {
|
||||
"heading": "Tag view",
|
||||
"options": {
|
||||
|
||||
Reference in New Issue
Block a user