mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 12:24:38 +03:00
Patchable ExternalLinkButtons component (#5727)
* Patchable ExternalLinkButtons component * added fontAwesomeBrands * use ExternalLinkButtons on groups page
This commit is contained in:
@@ -28,7 +28,7 @@ import { DetailImage } from "src/components/Shared/DetailImage";
|
||||
import { useRatingKeybinds } from "src/hooks/keybinds";
|
||||
import { useLoadStickyHeader } from "src/hooks/detailsPanel";
|
||||
import { useScrollToTopOnMount } from "src/hooks/scrollToTop";
|
||||
import { ExternalLinksButton } from "src/components/Shared/ExternalLinksButton";
|
||||
import { ExternalLinkButtons } from "src/components/Shared/ExternalLinksButton";
|
||||
import { BackgroundImage } from "src/components/Shared/DetailsPage/BackgroundImage";
|
||||
import { DetailTitle } from "src/components/Shared/DetailsPage/DetailTitle";
|
||||
import { ExpandCollapseButton } from "src/components/Shared/CollapseButton";
|
||||
@@ -374,7 +374,7 @@ const GroupPage: React.FC<IProps> = ({ group, tabKey }) => {
|
||||
/>
|
||||
)}
|
||||
<span className="name-icons">
|
||||
<ExternalLinksButton urls={group.urls} />
|
||||
<ExternalLinkButtons urls={group.urls ?? undefined} />
|
||||
</span>
|
||||
</DetailTitle>
|
||||
|
||||
|
||||
@@ -6,73 +6,76 @@ import { IconDefinition, faLink } from "@fortawesome/free-solid-svg-icons";
|
||||
import { useMemo } from "react";
|
||||
import { faInstagram, faTwitter } from "@fortawesome/free-brands-svg-icons";
|
||||
import ReactDOM from "react-dom";
|
||||
import { PatchComponent } from "src/patch";
|
||||
|
||||
export const ExternalLinksButton: React.FC<{
|
||||
icon?: IconDefinition;
|
||||
urls: string[];
|
||||
className?: string;
|
||||
}> = ({ urls, icon = faLink, className = "" }) => {
|
||||
if (!urls.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const Menu = () =>
|
||||
ReactDOM.createPortal(
|
||||
<Dropdown.Menu>
|
||||
{urls.map((url) => (
|
||||
<Dropdown.Item
|
||||
key={url}
|
||||
as={ExternalLink}
|
||||
href={TextUtils.sanitiseURL(url)}
|
||||
title={url}
|
||||
>
|
||||
{url}
|
||||
</Dropdown.Item>
|
||||
))}
|
||||
</Dropdown.Menu>,
|
||||
document.body
|
||||
);
|
||||
|
||||
return (
|
||||
<Dropdown className="external-links-button">
|
||||
<Dropdown.Toggle as={Button} className={`minimal link ${className}`}>
|
||||
<Icon icon={icon} />
|
||||
</Dropdown.Toggle>
|
||||
<Menu />
|
||||
</Dropdown>
|
||||
);
|
||||
};
|
||||
|
||||
export const ExternalLinkButtons: React.FC<{ urls: string[] | undefined }> = ({
|
||||
urls,
|
||||
}) => {
|
||||
const urlSpecs = useMemo(() => {
|
||||
if (!urls?.length) {
|
||||
return [];
|
||||
}> = PatchComponent(
|
||||
"ExternalLinksButton",
|
||||
({ urls, icon = faLink, className = "" }) => {
|
||||
if (!urls.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const twitter = urls.filter((u) =>
|
||||
u.match(/https?:\/\/(?:www\.)?(?:twitter|x).com\//)
|
||||
);
|
||||
const instagram = urls.filter((u) =>
|
||||
u.match(/https?:\/\/(?:www\.)?instagram.com\//)
|
||||
);
|
||||
const others = urls.filter(
|
||||
(u) => !twitter.includes(u) && !instagram.includes(u)
|
||||
);
|
||||
const Menu = () =>
|
||||
ReactDOM.createPortal(
|
||||
<Dropdown.Menu>
|
||||
{urls.map((url) => (
|
||||
<Dropdown.Item
|
||||
key={url}
|
||||
as={ExternalLink}
|
||||
href={TextUtils.sanitiseURL(url)}
|
||||
title={url}
|
||||
>
|
||||
{url}
|
||||
</Dropdown.Item>
|
||||
))}
|
||||
</Dropdown.Menu>,
|
||||
document.body
|
||||
);
|
||||
|
||||
return [
|
||||
{ icon: faLink, className: "", urls: others },
|
||||
{ icon: faTwitter, className: "twitter", urls: twitter },
|
||||
{ icon: faInstagram, className: "instagram", urls: instagram },
|
||||
];
|
||||
}, [urls]);
|
||||
return (
|
||||
<Dropdown className="external-links-button">
|
||||
<Dropdown.Toggle as={Button} className={`minimal link ${className}`}>
|
||||
<Icon icon={icon} />
|
||||
</Dropdown.Toggle>
|
||||
<Menu />
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{urlSpecs.map((spec, i) => (
|
||||
<ExternalLinksButton key={i} {...spec} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
export const ExternalLinkButtons: React.FC<{ urls: string[] | undefined }> =
|
||||
PatchComponent("ExternalLinkButtons", ({ urls }) => {
|
||||
const urlSpecs = useMemo(() => {
|
||||
if (!urls?.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const twitter = urls.filter((u) =>
|
||||
u.match(/https?:\/\/(?:www\.)?(?:twitter|x).com\//)
|
||||
);
|
||||
const instagram = urls.filter((u) =>
|
||||
u.match(/https?:\/\/(?:www\.)?instagram.com\//)
|
||||
);
|
||||
const others = urls.filter(
|
||||
(u) => !twitter.includes(u) && !instagram.includes(u)
|
||||
);
|
||||
|
||||
return [
|
||||
{ icon: faLink, className: "", urls: others },
|
||||
{ icon: faTwitter, className: "twitter", urls: twitter },
|
||||
{ icon: faInstagram, className: "instagram", urls: instagram },
|
||||
];
|
||||
}, [urls]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{urlSpecs.map((spec, i) => (
|
||||
<ExternalLinksButton key={i} {...spec} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -29,6 +29,7 @@ This namespace contains the generated graphql client interface. This is a low-le
|
||||
- `Intl`
|
||||
- `FontAwesomeRegular`
|
||||
- `FontAwesomeSolid`
|
||||
- `FontAwesomeBrands`
|
||||
- `Mousetrap`
|
||||
- `MousetrapPause`
|
||||
- `ReactSelect`
|
||||
@@ -147,6 +148,8 @@ Returns `void`.
|
||||
- `ConstantSetting`
|
||||
- `CountrySelect`
|
||||
- `DateInput`
|
||||
- `ExternalLinkButtons`
|
||||
- `ExternalLinksButton`
|
||||
- `FolderSelect`
|
||||
- `FrontPage`
|
||||
- `GalleryIDSelect`
|
||||
|
||||
3
ui/v2.5/src/pluginApi.d.ts
vendored
3
ui/v2.5/src/pluginApi.d.ts
vendored
@@ -614,6 +614,7 @@ declare namespace PluginApi {
|
||||
const Bootstrap: typeof import("react-bootstrap");
|
||||
const FontAwesomeRegular: typeof import("@fortawesome/free-regular-svg-icons");
|
||||
const FontAwesomeSolid: typeof import("@fortawesome/free-solid-svg-icons");
|
||||
const FontAwesomeBrands: typeof import("@fortawesome/free-brands-svg-icons");
|
||||
const Intl: typeof import("react-intl");
|
||||
const Mousetrap: typeof import("mousetrap");
|
||||
const ReactSelect: typeof import("react-select");
|
||||
@@ -697,6 +698,8 @@ declare namespace PluginApi {
|
||||
PerformerImagesPanel: React.FC<any>;
|
||||
TabTitleCounter: React.FC<any>;
|
||||
PerformerCard: React.FC<any>;
|
||||
ExternalLinkButtons: React.FC<any>;
|
||||
ExternalLinksButton: React.FC<any>;
|
||||
"PerformerCard.Popovers": React.FC<any>;
|
||||
"PerformerCard.Details": React.FC<any>;
|
||||
"PerformerCard.Overlays": React.FC<any>;
|
||||
|
||||
@@ -11,6 +11,7 @@ import * as Bootstrap from "react-bootstrap";
|
||||
import * as Intl from "react-intl";
|
||||
import * as FontAwesomeSolid from "@fortawesome/free-solid-svg-icons";
|
||||
import * as FontAwesomeRegular from "@fortawesome/free-regular-svg-icons";
|
||||
import * as FontAwesomeBrands from "@fortawesome/free-brands-svg-icons";
|
||||
import * as ReactSelect from "react-select";
|
||||
import { useSpriteInfo } from "./hooks/sprite";
|
||||
import { useToast } from "./hooks/Toast";
|
||||
@@ -72,6 +73,7 @@ export const PluginApi = {
|
||||
Intl,
|
||||
FontAwesomeRegular,
|
||||
FontAwesomeSolid,
|
||||
FontAwesomeBrands,
|
||||
Mousetrap,
|
||||
MousetrapPause,
|
||||
ReactSelect,
|
||||
|
||||
Reference in New Issue
Block a user