Plugin

ShowConnections

Show connected accounts in user popouts

Friends Appearance
index.tsx
Download

Source

src/plugins/showConnections/index.tsx
1import "./styles.css";
2
3import { isPluginEnabled } from "@api/PluginManager";
4import { definePluginSettings } from "@api/Settings";
5import ErrorBoundary from "@components/ErrorBoundary";
6import { Flex } from "@components/Flex";
7import { CopyIcon, LinkIcon } from "@components/Icons";
8import OpenInAppPlugin from "@plugins/openInApp";
9import { Devs } from "@utils/constants";
10import { copyWithToast } from "@utils/discord";
11import definePlugin, { OptionType } from "@utils/types";
12import { ConnectedAccount, User } from "@vencord/discord-types";
13import { findByCodeLazy, findByPropsLazy } from "@webpack";
14import { Tooltip, UserProfileStore } from "@webpack/common";
15
16import { VerifiedIcon } from "./VerifiedIcon";
17
18const useLegacyPlatformType: (platform: string) => string = findByCodeLazy(".TWITTER_LEGACY:");
19const platforms: { get(type: string): ConnectionPlatform; } = findByPropsLazy("isSupported", "getByUrl");
20const getProfileThemeProps = findByCodeLazy(".getPreviewThemeColors", "primaryColor:");
21
22const enum Spacing {
23 COMPACT,
24 COZY,
25 ROOMY
26}
27const getSpacingPx = (spacing: Spacing | undefined) => (spacing ?? Spacing.COMPACT) * 2 + 4;
28
29const settings = definePluginSettings({
30 iconSize: {
31 type: OptionType.NUMBER,
32 description: "Icon size (px)",
33 default: 32
34 },
35 iconSpacing: {
36 type: OptionType.SELECT,
37 description: "Icon margin",
38 default: Spacing.COZY,
39 options: [
40 { label: "Compact", value: Spacing.COMPACT },
41 { label: "Cozy", value: Spacing.COZY }, class="ts-cmt">// US Spelling :/
42 { label: "Roomy", value: Spacing.ROOMY }
43 ]
44 }
45});
46
47interface ConnectionPlatform {
48 getPlatformUserUrl(connection: ConnectedAccount): string;
49 icon: { lightSVG: string, darkSVG: string; };
50}
51
52const profilePopoutComponent = ErrorBoundary.wrap(
53 (props: { user: User; displayProfile?: any; }) => (
54 <ConnectionsComponent
55 {...props}
56 id={props.user.id}
57 theme={getProfileThemeProps(props).theme}
58 />
59 ),
60 { noop: true }
61);
62
63function ConnectionsComponent({ id, theme }: { id: string, theme: string; }) {
64 const profile = UserProfileStore.getUserProfile(id);
65 if (!profile)
66 return null;
67
68 const connections = profile.connectedAccounts;
69 if (!connections?.length)
70 return null;
71
72 return (
73 <Flex gap={getSpacingPx(settings.store.iconSpacing)} flexWrap="wrap">
74 {connections.map(connection => <CompactConnectionComponent connection={connection} theme={theme} key={connection.id} />)}
75 </Flex>
76 );
77}
78
79function CompactConnectionComponent({ connection, theme }: { connection: ConnectedAccount, theme: string; }) {
80 const platform = platforms.get(useLegacyPlatformType(connection.type));
81 const url = platform.getPlatformUserUrl?.(connection);
82
83 const img = (
84 <img
85 aria-label={connection.name}
86 src={theme === "light" ? platform.icon.lightSVG : platform.icon.darkSVG}
87 style={{
88 width: settings.store.iconSize,
89 height: settings.store.iconSize
90 }}
91 />
92 );
93
94 const TooltipIcon = url ? LinkIcon : CopyIcon;
95
96 return (
97 <Tooltip
98 text={
99 <span className="vc-sc-tooltip">
100 <span className="vc-sc-connection-name">{connection.name}</span>
101 {connection.verified && <VerifiedIcon />}
102 <TooltipIcon height={16} width={16} className="vc-sc-tooltip-icon" />
103 </span>
104 }
105 key={connection.id}
106 >
107 {tooltipProps =>
108 url
109 ? <a
110 {...tooltipProps}
111 className="vc-user-connection"
112 href={url}
113 target="_blank"
114 rel="noreferrer"
115 onClick={e => {
116 if (isPluginEnabled(OpenInAppPlugin.name)) {
117 // handleLink will .preventDefault() if applicable
118 OpenInAppPlugin.handleLink(e.currentTarget, e);
119 }
120 }}
121 >
122 {img}
123 </a>
124 : <button
125 {...tooltipProps}
126 className="vc-user-connection"
127 onClick={() => copyWithToast(connection.name)}
128 >
129 {img}
130 </button>
131
132 }
133 </Tooltip>
134 );
135}
136
137export default definePlugin({
138 name: "ShowConnections",
139 description: "Show connected accounts in user popouts",
140 tags: ["Friends", "Appearance"],
141 authors: [Devs.TheKodeToad],
142 settings,
143
144 patches: [
145 {
146 // Same find as ReviewDB
147 find: &#039;"UserProfilePopout");&#039;,
148 replacement: {
149 match: /userId:\i\.id,guild:\i\}\)(?=])/,
150 replace: "$&,$self.profilePopoutComponent(arguments[0])"
151 }
152 }
153 ],
154
155 profilePopoutComponent,
156});
157