MemberCount: Also add to server tooltip; refactor code
This commit is contained in:
parent
7de54a294f
commit
da50c7a19b
4 changed files with 189 additions and 80 deletions
66
src/plugins/memberCount/MemberCount.tsx
Normal file
66
src/plugins/memberCount/MemberCount.tsx
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { getCurrentChannel } from "@utils/discord";
|
||||
import { SelectedChannelStore, Tooltip, useEffect, useStateFromStores } from "@webpack/common";
|
||||
|
||||
import { ChannelMemberStore, cl, GuildMemberCountStore, numberFormat } from ".";
|
||||
import { OnlineMemberCountStore } from "./OnlineMemberCountStore";
|
||||
|
||||
export function MemberCount({ isTooltip, tooltipGuildId }: { isTooltip?: true; tooltipGuildId?: string; }) {
|
||||
const currentChannel = useStateFromStores([SelectedChannelStore], () => getCurrentChannel());
|
||||
|
||||
const guildId = isTooltip ? tooltipGuildId! : currentChannel.guild_id;
|
||||
|
||||
const totalCount = useStateFromStores(
|
||||
[GuildMemberCountStore],
|
||||
() => GuildMemberCountStore.getMemberCount(guildId)
|
||||
);
|
||||
|
||||
let onlineCount = useStateFromStores(
|
||||
[OnlineMemberCountStore],
|
||||
() => OnlineMemberCountStore.getCount(guildId)
|
||||
);
|
||||
|
||||
const { groups } = useStateFromStores(
|
||||
[ChannelMemberStore],
|
||||
() => ChannelMemberStore.getProps(guildId, currentChannel.id)
|
||||
);
|
||||
|
||||
if (!isTooltip && (groups.length >= 1 || groups[0].id !== "unknown")) {
|
||||
onlineCount = groups.reduce((total, curr) => total + (curr.id === "offline" ? 0 : curr.count), 0);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
OnlineMemberCountStore.ensureCount(guildId);
|
||||
}, [guildId]);
|
||||
|
||||
if (totalCount == null)
|
||||
return null;
|
||||
|
||||
const formattedOnlineCount = onlineCount != null ? numberFormat(onlineCount) : "?";
|
||||
|
||||
return (
|
||||
<div className={cl("widget", { tooltip: isTooltip, "member-list": !isTooltip })}>
|
||||
<Tooltip text={`${formattedOnlineCount} online in this channel`} position="bottom">
|
||||
{props => (
|
||||
<div {...props}>
|
||||
<span className={cl("online-dot")} />
|
||||
<span className={cl("online")}>{formattedOnlineCount}</span>
|
||||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
<Tooltip text={`${numberFormat(totalCount)} total server members`} position="bottom">
|
||||
{props => (
|
||||
<div {...props}>
|
||||
<span className={cl("total-dot")} />
|
||||
<span className={cl("total")}>{numberFormat(totalCount)}</span>
|
||||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
}
|
52
src/plugins/memberCount/OnlineMemberCountStore.ts
Normal file
52
src/plugins/memberCount/OnlineMemberCountStore.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { proxyLazy } from "@utils/lazy";
|
||||
import { sleep } from "@utils/misc";
|
||||
import { Queue } from "@utils/Queue";
|
||||
import { Flux, FluxDispatcher, GuildChannelStore, PrivateChannelsStore } from "@webpack/common";
|
||||
|
||||
export const OnlineMemberCountStore = proxyLazy(() => {
|
||||
const preloadQueue = new Queue();
|
||||
|
||||
const onlineMemberMap = new Map<string, number>();
|
||||
|
||||
class OnlineMemberCountStore extends Flux.Store {
|
||||
getCount(guildId: string) {
|
||||
return onlineMemberMap.get(guildId);
|
||||
}
|
||||
|
||||
async _ensureCount(guildId: string) {
|
||||
if (onlineMemberMap.has(guildId)) return;
|
||||
|
||||
await PrivateChannelsStore.preload(guildId, GuildChannelStore.getDefaultChannel(guildId).id);
|
||||
}
|
||||
|
||||
ensureCount(guildId: string) {
|
||||
if (onlineMemberMap.has(guildId)) return;
|
||||
|
||||
preloadQueue.push(() =>
|
||||
this._ensureCount(guildId)
|
||||
.then(
|
||||
() => sleep(200),
|
||||
() => sleep(200)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return new OnlineMemberCountStore(FluxDispatcher, {
|
||||
GUILD_MEMBER_LIST_UPDATE({ guildId, groups }: { guildId: string, groups: { count: number; id: string; }[]; }) {
|
||||
onlineMemberMap.set(
|
||||
guildId,
|
||||
groups.reduce((total, curr) => total + (curr.id === "offline" ? 0 : curr.count), 0)
|
||||
);
|
||||
},
|
||||
ONLINE_GUILD_MEMBER_COUNT_UPDATE({ guildId, count }) {
|
||||
onlineMemberMap.set(guildId, count);
|
||||
}
|
||||
});
|
||||
});
|
|
@ -16,101 +16,48 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import "./style.css";
|
||||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getCurrentChannel } from "@utils/discord";
|
||||
import definePlugin from "@utils/types";
|
||||
import { findStoreLazy } from "@webpack";
|
||||
import { SelectedChannelStore, Tooltip, useStateFromStores } from "@webpack/common";
|
||||
import { FluxStore } from "@webpack/types";
|
||||
|
||||
const GuildMemberCountStore = findStoreLazy("GuildMemberCountStore") as FluxStore & { getMemberCount(guildId: string): number | null; };
|
||||
const ChannelMemberStore = findStoreLazy("ChannelMemberStore") as FluxStore & {
|
||||
import { MemberCount } from "./MemberCount";
|
||||
|
||||
export const GuildMemberCountStore = findStoreLazy("GuildMemberCountStore") as FluxStore & { getMemberCount(guildId: string): number | null; };
|
||||
export const ChannelMemberStore = findStoreLazy("ChannelMemberStore") as FluxStore & {
|
||||
getProps(guildId: string, channelId: string): { groups: { count: number; id: string; }[]; };
|
||||
};
|
||||
|
||||
const sharedIntlNumberFormat = new Intl.NumberFormat();
|
||||
const numberFormat = (value: number) => sharedIntlNumberFormat.format(value);
|
||||
|
||||
function MemberCount() {
|
||||
const { id: channelId, guild_id: guildId } = useStateFromStores([SelectedChannelStore], () => getCurrentChannel());
|
||||
const { groups } = useStateFromStores(
|
||||
[ChannelMemberStore],
|
||||
() => ChannelMemberStore.getProps(guildId, channelId)
|
||||
);
|
||||
const total = useStateFromStores(
|
||||
[GuildMemberCountStore],
|
||||
() => GuildMemberCountStore.getMemberCount(guildId)
|
||||
);
|
||||
|
||||
if (total == null)
|
||||
return null;
|
||||
|
||||
const online =
|
||||
(groups.length === 1 && groups[0].id === "unknown")
|
||||
? 0
|
||||
: groups.reduce((count, curr) => count + (curr.id === "offline" ? 0 : curr.count), 0);
|
||||
|
||||
return (
|
||||
<Flex id="vc-membercount" style={{
|
||||
marginTop: "1em",
|
||||
paddingInline: "1em",
|
||||
justifyContent: "center",
|
||||
alignContent: "center",
|
||||
gap: 0
|
||||
}}>
|
||||
<Tooltip text={`${numberFormat(online)} online in this channel`} position="bottom">
|
||||
{props => (
|
||||
<div {...props}>
|
||||
<span
|
||||
style={{
|
||||
backgroundColor: "var(--green-360)",
|
||||
width: "12px",
|
||||
height: "12px",
|
||||
borderRadius: "50%",
|
||||
display: "inline-block",
|
||||
marginRight: "0.5em"
|
||||
}}
|
||||
/>
|
||||
<span style={{ color: "var(--green-360)" }}>{numberFormat(online)}</span>
|
||||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
<Tooltip text={`${numberFormat(total)} total server members`} position="bottom">
|
||||
{props => (
|
||||
<div {...props}>
|
||||
<span
|
||||
style={{
|
||||
width: "6px",
|
||||
height: "6px",
|
||||
borderRadius: "50%",
|
||||
border: "3px solid var(--primary-400)",
|
||||
display: "inline-block",
|
||||
marginRight: "0.5em",
|
||||
marginLeft: "1em"
|
||||
}}
|
||||
/>
|
||||
<span style={{ color: "var(--primary-400)" }}>{numberFormat(total)}</span>
|
||||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
export const numberFormat = (value: number) => sharedIntlNumberFormat.format(value);
|
||||
export const cl = classNameFactory("vc-membercount-");
|
||||
|
||||
export default definePlugin({
|
||||
name: "MemberCount",
|
||||
description: "Shows the amount of online & total members in the server member list",
|
||||
description: "Shows the amount of online & total members in the server member list and tooltip",
|
||||
authors: [Devs.Ven, Devs.Commandtechno],
|
||||
|
||||
patches: [{
|
||||
patches: [
|
||||
{
|
||||
find: "{isSidebarVisible:",
|
||||
replacement: {
|
||||
match: /(?<=let\{className:(\i),.+?children):\[(\i\.useMemo[^}]+"aria-multiselectable")/,
|
||||
replace: ":[$1?.startsWith('members')?$self.render():null,$2"
|
||||
}
|
||||
}],
|
||||
},
|
||||
{
|
||||
find: ".invitesDisabledTooltip",
|
||||
replacement: {
|
||||
match: /(?<=\.VIEW_AS_ROLES_MENTIONS_WARNING.{0,100})]/,
|
||||
replace: ",$self.renderTooltip(arguments[0].guild)]"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
render: ErrorBoundary.wrap(MemberCount, { noop: true })
|
||||
render: ErrorBoundary.wrap(MemberCount, { noop: true }),
|
||||
renderTooltip: ErrorBoundary.wrap(guild => <MemberCount isTooltip tooltipGuildId={guild.id} />, { noop: true })
|
||||
});
|
||||
|
|
44
src/plugins/memberCount/style.css
Normal file
44
src/plugins/memberCount/style.css
Normal file
|
@ -0,0 +1,44 @@
|
|||
.vc-membercount-widget {
|
||||
display: flex;
|
||||
align-content: center;
|
||||
|
||||
--color-online: var(--green-360);
|
||||
--color-total: var(--primary-400);
|
||||
}
|
||||
|
||||
.vc-membercount-tooltip {
|
||||
margin-top: 0.25em;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.vc-membercount-member-list {
|
||||
justify-content: center;
|
||||
margin-top: 1em;
|
||||
padding-inline: 1em;
|
||||
}
|
||||
|
||||
.vc-membercount-online {
|
||||
color: var(--color-online);
|
||||
}
|
||||
|
||||
.vc-membercount-total {
|
||||
color: var(--color-total);
|
||||
}
|
||||
|
||||
.vc-membercount-online-dot {
|
||||
background-color: var(--color-online);
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.vc-membercount-total-dot {
|
||||
display: inline-block;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid var(--color-total);
|
||||
margin: 0 0.5em 0 1em;
|
||||
}
|
Loading…
Reference in a new issue