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 { useRatingKeybinds } from "src/hooks/keybinds";
|
||||||
import { useLoadStickyHeader } from "src/hooks/detailsPanel";
|
import { useLoadStickyHeader } from "src/hooks/detailsPanel";
|
||||||
import { useScrollToTopOnMount } from "src/hooks/scrollToTop";
|
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 { BackgroundImage } from "src/components/Shared/DetailsPage/BackgroundImage";
|
||||||
import { DetailTitle } from "src/components/Shared/DetailsPage/DetailTitle";
|
import { DetailTitle } from "src/components/Shared/DetailsPage/DetailTitle";
|
||||||
import { ExpandCollapseButton } from "src/components/Shared/CollapseButton";
|
import { ExpandCollapseButton } from "src/components/Shared/CollapseButton";
|
||||||
@@ -374,7 +374,7 @@ const GroupPage: React.FC<IProps> = ({ group, tabKey }) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<span className="name-icons">
|
<span className="name-icons">
|
||||||
<ExternalLinksButton urls={group.urls} />
|
<ExternalLinkButtons urls={group.urls ?? undefined} />
|
||||||
</span>
|
</span>
|
||||||
</DetailTitle>
|
</DetailTitle>
|
||||||
|
|
||||||
|
|||||||
@@ -6,73 +6,76 @@ import { IconDefinition, faLink } from "@fortawesome/free-solid-svg-icons";
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { faInstagram, faTwitter } from "@fortawesome/free-brands-svg-icons";
|
import { faInstagram, faTwitter } from "@fortawesome/free-brands-svg-icons";
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
|
import { PatchComponent } from "src/patch";
|
||||||
|
|
||||||
export const ExternalLinksButton: React.FC<{
|
export const ExternalLinksButton: React.FC<{
|
||||||
icon?: IconDefinition;
|
icon?: IconDefinition;
|
||||||
urls: string[];
|
urls: string[];
|
||||||
className?: string;
|
className?: string;
|
||||||
}> = ({ urls, icon = faLink, className = "" }) => {
|
}> = PatchComponent(
|
||||||
if (!urls.length) {
|
"ExternalLinksButton",
|
||||||
return null;
|
({ 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 [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const twitter = urls.filter((u) =>
|
const Menu = () =>
|
||||||
u.match(/https?:\/\/(?:www\.)?(?:twitter|x).com\//)
|
ReactDOM.createPortal(
|
||||||
);
|
<Dropdown.Menu>
|
||||||
const instagram = urls.filter((u) =>
|
{urls.map((url) => (
|
||||||
u.match(/https?:\/\/(?:www\.)?instagram.com\//)
|
<Dropdown.Item
|
||||||
);
|
key={url}
|
||||||
const others = urls.filter(
|
as={ExternalLink}
|
||||||
(u) => !twitter.includes(u) && !instagram.includes(u)
|
href={TextUtils.sanitiseURL(url)}
|
||||||
);
|
title={url}
|
||||||
|
>
|
||||||
|
{url}
|
||||||
|
</Dropdown.Item>
|
||||||
|
))}
|
||||||
|
</Dropdown.Menu>,
|
||||||
|
document.body
|
||||||
|
);
|
||||||
|
|
||||||
return [
|
return (
|
||||||
{ icon: faLink, className: "", urls: others },
|
<Dropdown className="external-links-button">
|
||||||
{ icon: faTwitter, className: "twitter", urls: twitter },
|
<Dropdown.Toggle as={Button} className={`minimal link ${className}`}>
|
||||||
{ icon: faInstagram, className: "instagram", urls: instagram },
|
<Icon icon={icon} />
|
||||||
];
|
</Dropdown.Toggle>
|
||||||
}, [urls]);
|
<Menu />
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
export const ExternalLinkButtons: React.FC<{ urls: string[] | undefined }> =
|
||||||
<>
|
PatchComponent("ExternalLinkButtons", ({ urls }) => {
|
||||||
{urlSpecs.map((spec, i) => (
|
const urlSpecs = useMemo(() => {
|
||||||
<ExternalLinksButton key={i} {...spec} />
|
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`
|
- `Intl`
|
||||||
- `FontAwesomeRegular`
|
- `FontAwesomeRegular`
|
||||||
- `FontAwesomeSolid`
|
- `FontAwesomeSolid`
|
||||||
|
- `FontAwesomeBrands`
|
||||||
- `Mousetrap`
|
- `Mousetrap`
|
||||||
- `MousetrapPause`
|
- `MousetrapPause`
|
||||||
- `ReactSelect`
|
- `ReactSelect`
|
||||||
@@ -147,6 +148,8 @@ Returns `void`.
|
|||||||
- `ConstantSetting`
|
- `ConstantSetting`
|
||||||
- `CountrySelect`
|
- `CountrySelect`
|
||||||
- `DateInput`
|
- `DateInput`
|
||||||
|
- `ExternalLinkButtons`
|
||||||
|
- `ExternalLinksButton`
|
||||||
- `FolderSelect`
|
- `FolderSelect`
|
||||||
- `FrontPage`
|
- `FrontPage`
|
||||||
- `GalleryIDSelect`
|
- `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 Bootstrap: typeof import("react-bootstrap");
|
||||||
const FontAwesomeRegular: typeof import("@fortawesome/free-regular-svg-icons");
|
const FontAwesomeRegular: typeof import("@fortawesome/free-regular-svg-icons");
|
||||||
const FontAwesomeSolid: typeof import("@fortawesome/free-solid-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 Intl: typeof import("react-intl");
|
||||||
const Mousetrap: typeof import("mousetrap");
|
const Mousetrap: typeof import("mousetrap");
|
||||||
const ReactSelect: typeof import("react-select");
|
const ReactSelect: typeof import("react-select");
|
||||||
@@ -697,6 +698,8 @@ declare namespace PluginApi {
|
|||||||
PerformerImagesPanel: React.FC<any>;
|
PerformerImagesPanel: React.FC<any>;
|
||||||
TabTitleCounter: React.FC<any>;
|
TabTitleCounter: React.FC<any>;
|
||||||
PerformerCard: React.FC<any>;
|
PerformerCard: React.FC<any>;
|
||||||
|
ExternalLinkButtons: React.FC<any>;
|
||||||
|
ExternalLinksButton: React.FC<any>;
|
||||||
"PerformerCard.Popovers": React.FC<any>;
|
"PerformerCard.Popovers": React.FC<any>;
|
||||||
"PerformerCard.Details": React.FC<any>;
|
"PerformerCard.Details": React.FC<any>;
|
||||||
"PerformerCard.Overlays": 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 Intl from "react-intl";
|
||||||
import * as FontAwesomeSolid from "@fortawesome/free-solid-svg-icons";
|
import * as FontAwesomeSolid from "@fortawesome/free-solid-svg-icons";
|
||||||
import * as FontAwesomeRegular from "@fortawesome/free-regular-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 * as ReactSelect from "react-select";
|
||||||
import { useSpriteInfo } from "./hooks/sprite";
|
import { useSpriteInfo } from "./hooks/sprite";
|
||||||
import { useToast } from "./hooks/Toast";
|
import { useToast } from "./hooks/Toast";
|
||||||
@@ -72,6 +73,7 @@ export const PluginApi = {
|
|||||||
Intl,
|
Intl,
|
||||||
FontAwesomeRegular,
|
FontAwesomeRegular,
|
||||||
FontAwesomeSolid,
|
FontAwesomeSolid,
|
||||||
|
FontAwesomeBrands,
|
||||||
Mousetrap,
|
Mousetrap,
|
||||||
MousetrapPause,
|
MousetrapPause,
|
||||||
ReactSelect,
|
ReactSelect,
|
||||||
|
|||||||
Reference in New Issue
Block a user