Boo: Add Plugin
This commit is contained in:
parent
b8261aba5e
commit
81a4ea94c9
5 changed files with 167 additions and 0 deletions
60
src/equicordplugins/boo/Boo.tsx
Normal file
60
src/equicordplugins/boo/Boo.tsx
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Channel, Message } from "@vencord/discord-types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { MessageStore, useEffect, UserStore, useState, useStateFromStores } from "@webpack/common";
|
||||
|
||||
import { cl } from ".";
|
||||
import { IconGhost } from "./IconGhost";
|
||||
|
||||
const countedChannels = new Set<string>();
|
||||
export let booCount = 0;
|
||||
|
||||
const ChannelWrapperStyles = findByPropsLazy("muted", "wrapper");
|
||||
|
||||
export function Boo({ channel }: { channel: Channel; }) {
|
||||
const { id } = channel;
|
||||
|
||||
const currentUserId = useStateFromStores([UserStore], () => UserStore.getCurrentUser()?.id);
|
||||
const lastMessage: Message = useStateFromStores([MessageStore], () =>
|
||||
MessageStore.getMessages(id)?.last()
|
||||
);
|
||||
|
||||
const [state, setState] = useState({
|
||||
isCurrentUser: null as boolean | null,
|
||||
containsQuestionMark: false,
|
||||
isDataProcessed: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!lastMessage || !currentUserId) return;
|
||||
|
||||
const lastIsCurrentUser = lastMessage.author.id === currentUserId;
|
||||
const containsQuestionMark = !lastIsCurrentUser && lastMessage.content.includes("?");
|
||||
|
||||
setState({
|
||||
isCurrentUser: lastIsCurrentUser,
|
||||
containsQuestionMark,
|
||||
isDataProcessed: true,
|
||||
});
|
||||
}, [lastMessage, currentUserId]);
|
||||
|
||||
if (!state.isDataProcessed || !currentUserId || !lastMessage || state.isCurrentUser) return null;
|
||||
|
||||
if (!countedChannels.has(id)) {
|
||||
countedChannels.add(id);
|
||||
booCount++;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cl("icon", ChannelWrapperStyles.wrapper)}>
|
||||
{state.containsQuestionMark
|
||||
? <IconGhost fill="#ff8000" />
|
||||
: <IconGhost fill="currentColor" />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
19
src/equicordplugins/boo/IconGhost.tsx
Normal file
19
src/equicordplugins/boo/IconGhost.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export function IconGhost({ fill }) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1.5em"
|
||||
height="1.5em"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path fill={fill} d="M12 4a7 7 0 0 0-7 7v8.62a.4.4 0 0 0 .594.35l.943-.523a4 4 0 0 1 3.927.023l.544.311a2 2 0 0 0 1.984 0l.544-.31a4 4 0 0 1 3.927-.024l.943.523a.4.4 0 0 0 .594-.35V11a7 7 0 0 0-7-7m-9 7a9 9 0 0 1 18 0v8.62c0 1.83-1.966 2.987-3.565 2.099l-.943-.524a2 2 0 0 0-1.964.012l-.543.31a4 4 0 0 1-3.97 0l-.543-.31a2 2 0 0 0-1.964-.012l-.942.524C4.966 22.607 3 21.45 3 19.62zm7.5-.5a1.5 1.5 0 1 1-3 0a1.5 1.5 0 0 1 3 0M15 12a1.5 1.5 0 1 0 0-3a1.5 1.5 0 0 0 0 3" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
68
src/equicordplugins/boo/index.tsx
Normal file
68
src/equicordplugins/boo/index.tsx
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import "./styles.css";
|
||||
|
||||
import { addServerListElement, removeServerListElement, ServerListRenderPosition } from "@api/ServerList";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs, EquicordDevs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import { Channel } from "@vencord/discord-types";
|
||||
import { Tooltip } from "@webpack/common";
|
||||
|
||||
import { Boo, booCount } from "./Boo";
|
||||
import { IconGhost } from "./IconGhost";
|
||||
|
||||
export const cl = classNameFactory("vc-boo-");
|
||||
|
||||
export default definePlugin({
|
||||
name: "Boo",
|
||||
description: "A cute ghost will appear if you don't answer their DMs",
|
||||
authors: [EquicordDevs.vei, Devs.sadan],
|
||||
patches: [
|
||||
{
|
||||
find: "interactiveSelected]",
|
||||
replacement: {
|
||||
match: /interactiveSelected.{0,50}children:\[/,
|
||||
replace: "$&$self.renderBoo(arguments[0]),"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
renderBoo(props: { channel: Channel; }) {
|
||||
return (
|
||||
<ErrorBoundary noop>
|
||||
<Boo {...props} />
|
||||
</ErrorBoundary>
|
||||
);
|
||||
},
|
||||
|
||||
renderIndicator() {
|
||||
return <ErrorBoundary noop>
|
||||
<div id={cl("container")}>
|
||||
<Tooltip text={`${booCount} Ghosted Users`} position="right">
|
||||
{({ onMouseEnter, onMouseLeave }) => (
|
||||
<div
|
||||
id={cl("container")}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}>
|
||||
{booCount} <IconGhost fill="currentColor" />
|
||||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
</div>
|
||||
</ErrorBoundary>;
|
||||
},
|
||||
|
||||
start() {
|
||||
addServerListElement(ServerListRenderPosition.Above, this.renderIndicator);
|
||||
},
|
||||
|
||||
stop() {
|
||||
removeServerListElement(ServerListRenderPosition.Above, this.renderIndicator);
|
||||
}
|
||||
});
|
||||
16
src/equicordplugins/boo/styles.css
Normal file
16
src/equicordplugins/boo/styles.css
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
.vc-boo-icon {
|
||||
height: 42px;
|
||||
}
|
||||
|
||||
#vc-boo-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--background-primary);
|
||||
height: 30px;
|
||||
width: 48px;
|
||||
margin-left: 8px;
|
||||
color: var(--text-default);
|
||||
fill: var(--text-default);
|
||||
}
|
||||
|
|
@ -1178,6 +1178,10 @@ export const EquicordDevs = Object.freeze({
|
|||
name: "mja00",
|
||||
id: 108698087769260032n
|
||||
},
|
||||
vei: {
|
||||
name: "Vei",
|
||||
id: 239414094799699968n
|
||||
},
|
||||
} satisfies Record<string, Dev>);
|
||||
|
||||
// iife so #__PURE__ works correctly
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue