mirror of
https://github.com/Vendicated/Vencord.git
synced 2025-01-10 18:06:22 +00:00
feat(memberListActivities): better tooltips
This commit is contained in:
parent
0753b51104
commit
e87ced9f9d
2 changed files with 109 additions and 27 deletions
|
@ -24,7 +24,8 @@ import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByPropsLazy, findComponentByCodeLazy, findStoreLazy } from "@webpack";
|
import { findByPropsLazy, findComponentByCodeLazy, findStoreLazy } from "@webpack";
|
||||||
import { Tooltip } from "@webpack/common";
|
import { Tooltip, useMemo } from "@webpack/common";
|
||||||
|
import { User } from "discord-types/general";
|
||||||
import type { ImgHTMLAttributes } from "react";
|
import type { ImgHTMLAttributes } from "react";
|
||||||
|
|
||||||
import { SpotifyIcon } from "./components/SpotifyIcon";
|
import { SpotifyIcon } from "./components/SpotifyIcon";
|
||||||
|
@ -104,6 +105,7 @@ interface ApplicationIcon {
|
||||||
alt: string;
|
alt: string;
|
||||||
};
|
};
|
||||||
activity: Activity;
|
activity: Activity;
|
||||||
|
application?: Application;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ActivityListIcon {
|
interface ActivityListIcon {
|
||||||
|
@ -124,7 +126,47 @@ const DefaultActivityIcon = findComponentByCodeLazy("M6,7 L2,7 L2,6 L6,6 L6,7 Z
|
||||||
|
|
||||||
const fetchedApplications = new Map<string, Application | null>();
|
const fetchedApplications = new Map<string, Application | null>();
|
||||||
|
|
||||||
const xboxUrl = "https://discord.com/assets/9a15d086141be29d9fcd.png";
|
const xboxUrl = "https://discord.com/assets/9a15d086141be29d9fcd.png"; // TODO: replace with "renderXboxImage"?
|
||||||
|
|
||||||
|
function getActivityImage(activity: Activity): string | undefined {
|
||||||
|
if (activity.type === 2 && activity.name === "Spotify") {
|
||||||
|
// get either from large or small image
|
||||||
|
const image = activity.assets?.large_image ?? activity.assets?.small_image;
|
||||||
|
// image needs to replace 'spotify:
|
||||||
|
if (image?.startsWith("spotify:")) {
|
||||||
|
// spotify cover art is always https://i.scdn.co/image/ID
|
||||||
|
return image.replace("spotify:", "https://i.scdn.co/image/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: we could support other assets here, like showing the small/large image counterpart in comparison to that was shown in the activity list
|
||||||
|
}
|
||||||
|
|
||||||
|
const ActivityTooltip = ({ activity }: Readonly<{ activity: Activity }>) => {
|
||||||
|
const image = useMemo(() => {
|
||||||
|
const activityImage = getActivityImage(activity);
|
||||||
|
if (activityImage) {
|
||||||
|
return activityImage;
|
||||||
|
}
|
||||||
|
const icon = getApplicationIcons([activity])[0];
|
||||||
|
return icon?.image.src;
|
||||||
|
}, [activity]);
|
||||||
|
|
||||||
|
const hasDetails = activity.details ?? activity.state;
|
||||||
|
return (
|
||||||
|
<ErrorBoundary>
|
||||||
|
<div className={cl("activity")}>
|
||||||
|
{image && <img className={cl("activity-image")} src={image} alt="Activity logo" />}
|
||||||
|
<div className={cl("activity-title")}>{activity.name}</div>
|
||||||
|
{hasDetails && <div className={cl("activity-divider")} />}
|
||||||
|
<div className={cl("activity-details")}>
|
||||||
|
<div>{activity.details}</div>
|
||||||
|
<div>{activity.state}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ErrorBoundary>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
function getApplicationIcons(activities: Activity[]) {
|
function getApplicationIcons(activities: Activity[]) {
|
||||||
const applicationIcons: ApplicationIcon[] = [];
|
const applicationIcons: ApplicationIcon[] = [];
|
||||||
|
@ -183,12 +225,14 @@ function getApplicationIcons(activities: Activity[]) {
|
||||||
const src = `https://cdn.discordapp.com/app-icons/${application.id}/${application.icon}.png`;
|
const src = `https://cdn.discordapp.com/app-icons/${application.id}/${application.icon}.png`;
|
||||||
applicationIcons.push({
|
applicationIcons.push({
|
||||||
image: { src, alt: application.name },
|
image: { src, alt: application.name },
|
||||||
activity
|
activity,
|
||||||
|
application
|
||||||
});
|
});
|
||||||
} else if (platform === "xbox") {
|
} else if (platform === "xbox") {
|
||||||
applicationIcons.push({
|
applicationIcons.push({
|
||||||
image: { src: xboxUrl, alt: "Xbox" },
|
image: { src: xboxUrl, alt: "Xbox" },
|
||||||
activity
|
activity,
|
||||||
|
application
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,17 +257,23 @@ export default definePlugin({
|
||||||
|
|
||||||
settings,
|
settings,
|
||||||
|
|
||||||
patchActivityList: (activities: Activity[]): JSX.Element | null => {
|
patchActivityList: ({ activities, user }: { activities: Activity[], user: User }): JSX.Element | null => {
|
||||||
const icons: ActivityListIcon[] = [];
|
const icons: ActivityListIcon[] = [];
|
||||||
|
|
||||||
const spotifyActivity = activities.find(({ name }) => name === "Spotify");
|
const spotifyActivity = activities.find(({ name }) => name === "Spotify");
|
||||||
if (spotifyActivity) {
|
if (spotifyActivity) {
|
||||||
icons.push({ iconElement: <SpotifyIcon />, tooltip: spotifyActivity.details ?? spotifyActivity.name });
|
icons.push({
|
||||||
|
iconElement: <SpotifyIcon />,
|
||||||
|
tooltip: <ActivityTooltip activity={spotifyActivity} />
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const twitchActivity = activities.find(({ name }) => name === "Twitch");
|
const twitchActivity = activities.find(({ name }) => name === "Twitch");
|
||||||
if (twitchActivity) {
|
if (twitchActivity) {
|
||||||
icons.push({ iconElement: <TwitchIcon />, tooltip: twitchActivity.details ?? twitchActivity.name });
|
icons.push({
|
||||||
|
iconElement: <TwitchIcon />,
|
||||||
|
tooltip: <ActivityTooltip activity={twitchActivity} />
|
||||||
|
});
|
||||||
}
|
}
|
||||||
const applicationIcons = getApplicationIcons(activities);
|
const applicationIcons = getApplicationIcons(activities);
|
||||||
if (applicationIcons.length) {
|
if (applicationIcons.length) {
|
||||||
|
@ -236,7 +286,7 @@ export default definePlugin({
|
||||||
for (const appIcon of uniqueIcons) {
|
for (const appIcon of uniqueIcons) {
|
||||||
icons.push({
|
icons.push({
|
||||||
iconElement: <img {...appIcon.image} />,
|
iconElement: <img {...appIcon.image} />,
|
||||||
tooltip: appIcon.activity.details ?? appIcon.activity.name
|
tooltip: <ActivityTooltip activity={appIcon.activity} />
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,24 +294,22 @@ export default definePlugin({
|
||||||
if (icons.length) {
|
if (icons.length) {
|
||||||
return <ErrorBoundary noop>
|
return <ErrorBoundary noop>
|
||||||
<div className={cl("row")}>
|
<div className={cl("row")}>
|
||||||
{icons.map(({ iconElement, tooltip }, i) => {
|
{icons.map(({ iconElement, tooltip }, i) => (
|
||||||
return (
|
<div key={i} className={cl("icon")} style={{
|
||||||
<div key={i} className={cl("icon")} style={{
|
width: `${settings.store.iconSize}px`,
|
||||||
width: `${settings.store.iconSize}px`,
|
height: `${settings.store.iconSize}px`
|
||||||
height: `${settings.store.iconSize}px`
|
}}>
|
||||||
}}>
|
{tooltip ? <Tooltip text={tooltip}>
|
||||||
{tooltip ? <Tooltip text={tooltip}>
|
{({ onMouseEnter, onMouseLeave }) => (
|
||||||
{({ onMouseEnter, onMouseLeave }) => (
|
<div
|
||||||
<div
|
onMouseEnter={onMouseEnter}
|
||||||
onMouseEnter={onMouseEnter}
|
onMouseLeave={onMouseLeave}>
|
||||||
onMouseLeave={onMouseLeave}>
|
{iconElement}
|
||||||
{iconElement}
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
</Tooltip> : iconElement}
|
||||||
</Tooltip> : iconElement}
|
</div>
|
||||||
</div>
|
))}
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
</ErrorBoundary>;
|
</ErrorBoundary>;
|
||||||
} else {
|
} else {
|
||||||
|
@ -282,7 +330,7 @@ export default definePlugin({
|
||||||
find: "default.getHangStatusActivity():null!",
|
find: "default.getHangStatusActivity():null!",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /null!=(\i)&&\i.some\(\i=>\(0,\i.default\)\(\i,\i\)\)\?/,
|
match: /null!=(\i)&&\i.some\(\i=>\(0,\i.default\)\(\i,\i\)\)\?/,
|
||||||
replace: "$self.patchActivityList($1),false?"
|
replace: "$self.patchActivityList(e),false?"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -18,3 +18,37 @@
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vc-mla-activity {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-mla-activity-title {
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-mla-activity-image {
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-mla-activity-divider {
|
||||||
|
width: 100%;
|
||||||
|
border-top: 1px dotted rgba(255, 255, 255, 0.2);
|
||||||
|
margin-top: 3px;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-mla-activity-details {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
/* discord gray */
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue