From 4f2a87a61042713a746749184478c9c1d88d0dc5 Mon Sep 17 00:00:00 2001 From: Elvyra <88881326+EepyElvyra@users.noreply.github.com> Date: Fri, 3 Jan 2025 14:27:29 +0100 Subject: [PATCH] add lists to plugin modals (super shitty) also fixes some bugs lol --- src/components/PluginSettings/PluginModal.tsx | 6 +- .../components/SettingListComponent.tsx | 97 ++++++++++++++++--- src/plugins/_api/settingLists.tsx | 27 ++++-- src/plugins/messageLogger/index.tsx | 4 +- src/plugins/textReplace/index.tsx | 7 +- src/utils/types.ts | 3 + 6 files changed, 113 insertions(+), 31 deletions(-) diff --git a/src/components/PluginSettings/PluginModal.tsx b/src/components/PluginSettings/PluginModal.tsx index 2825022b7..b8d01276a 100644 --- a/src/components/PluginSettings/PluginModal.tsx +++ b/src/components/PluginSettings/PluginModal.tsx @@ -40,11 +40,11 @@ import { ISettingElementProps, SettingBooleanComponent, SettingCustomComponent, + SettingListComponent, SettingNumericComponent, SettingSelectComponent, SettingSliderComponent, SettingTextComponent, - SettingListComponent, } from "./components"; import { openContributorModal } from "./ContributorModal"; import { GithubButton, WebsiteButton } from "./LinkIconButton"; @@ -83,10 +83,10 @@ const Components: Record. */ +import ErrorBoundary from "@components/ErrorBoundary"; +import { Flex } from "@components/Flex"; import { Margins } from "@utils/margins"; import { wordsFromCamel, wordsToTitle } from "@utils/text"; -import { PluginOptionSelect } from "@utils/types"; -import { Forms, useState, useEffect, ChannelStore, UserStore, GuildStore } from "@webpack/common"; +import { OptionType, PluginOptionList } from "@utils/types"; +import { findComponentByCodeLazy } from "@webpack"; +import { Button,ChannelStore, Forms, GuildStore, React, useState } from "@webpack/common"; import { ISettingElementProps } from "."; +import { Channel } from "discord-types/general"; -export function SettingListComponent({ option, pluginSettings, definedSettings, onChange, onError, id }: ISettingElementProps) { +const UserMentionComponent = findComponentByCodeLazy(".USER_MENTION)"); + +const CloseIcon = () => { + return ; +}; + +interface UserMentionComponentProps { + id: string; + channelId: string; + guildId: string; +} + +export function SettingListComponent({ + option, + pluginSettings, + definedSettings, + onChange, + onError, + id +}: ISettingElementProps) { const [error, setError] = useState(null); const [items, setItems] = useState([]); @@ -34,31 +59,75 @@ export function SettingListComponent({ option, pluginSettings, definedSettings, setItems([...items, newItem]); setNewItem(""); } + pluginSettings[id] = items; }; + if (items.length === 0 && pluginSettings[id].length !== 0) { + setItems(pluginSettings[id]); + } + const removeItem = (index: number) => { setItems(items.filter((_, i) => i !== index)); + pluginSettings[id] = items; }; - useEffect(() => { - onError(error !== null); - }, [error]); - function handleChange(newValue) { - const isValid = option.isValid?.call(definedSettings, newValue) ?? true; - if (typeof isValid === "string") setError(isValid); - else if (!isValid) setError("Invalid input provided."); - else { - setError(null); - onChange(newValue); - } + onChange(newValue); } + function wrapChannel(id: string) { + const channel = ChannelStore.getChannel(id) as Channel; + if (!channel) { + return "Unknown Channel"; + } + return (GuildStore.getGuild(channel.guild_id)?.name ?? "Unknown Guild") + " - " + channel.name; + } + + // FIXME make channels and guilds nicer! return ( {wordsToTitle(wordsFromCamel(id))} {option.description} + + {items.map((item, index) => ( + + + {option.type === OptionType.USERS ? ( + + ) : option.type === OptionType.CHANNELS ? ( + {wrapChannel(item)} + ) : option.type === OptionType.GUILDS ? ( + + {GuildStore.getGuild(item)?.name || "Unknown Guild"} + + // TODO add logo to guild and channel? + ) : ( + {item} + )} + + + + ))} + + + {error && {error}} diff --git a/src/plugins/_api/settingLists.tsx b/src/plugins/_api/settingLists.tsx index 0af3558c9..fbf616adc 100644 --- a/src/plugins/_api/settingLists.tsx +++ b/src/plugins/_api/settingLists.tsx @@ -8,7 +8,7 @@ import { NavContextMenuPatchCallback } from "@api/ContextMenu"; import { Devs } from "@utils/constants"; import { getIntlMessage } from "@utils/discord"; import definePlugin, { OptionType } from "@utils/types"; -import { Menu, useState } from "@webpack/common"; +import { Menu, React } from "@webpack/common"; function createContextMenu(name: "Guild" | "User" | "Channel", value: any) { return ( @@ -26,16 +26,24 @@ function renderRegisteredPlugins(name: "Guild" | "User" | "Channel", value: any) const type = name === "Guild" ? OptionType.GUILDS : name === "User" ? OptionType.USERS : OptionType.CHANNELS; const plugins = registeredPlugins[type]; - const [checkedItems, setCheckedItems] = useState>({}); + + const [checkedItems, setCheckedItems] = React.useState>( + Object.fromEntries( + Object.keys(plugins).flatMap(plugin => + plugins[plugin].map(setting => [`${plugin}-${setting}-${value.id}`, Vencord.Plugins.plugins[plugin].settings?.store[setting].includes(value.id)]) + ) + ) + ); const handleCheckboxClick = (plugin: string, setting: string) => { - const key = `${plugin}-${setting}`; + const key = `${plugin}-${setting}-${value.id}`; setCheckedItems(prevState => ({ ...prevState, [key]: !prevState[key] })); - // @ts-ignore (can't be undefined because settings have to exist for this to be called in the first place) + // @ts-ignore settings must be defined otherwise we wouldn't be here const s = Vencord.Plugins.plugins[plugin].settings.store[setting]; + // @ts-ignore Vencord.Plugins.plugins[plugin].settings.store[setting] = s.includes(value.id) ? s.filter(id => id !== value.id) : [...s, value.id]; @@ -49,10 +57,9 @@ function renderRegisteredPlugins(name: "Guild" | "User" | "Channel", value: any) {plugins[plugin].map(setting => ( handleCheckboxClick(plugin, setting)} - checked={checkedItems[`${plugin}-${setting}`]} + checked={checkedItems[`${plugin}-${setting}-${value.id}`]} /> ))} @@ -93,7 +100,7 @@ const registeredPlugins: Record = O extends PluginSettingStri O extends PluginSettingSelectDef ? O["options"][number]["value"] : O extends PluginSettingSliderDef ? number : O extends PluginSettingComponentDef ? any : + O extends PluginSettingListDef ? any[] : never; type PluginSettingDefaultType = O extends PluginSettingSelectDef ? ( O["options"] extends { default?: boolean; }[] ? O["options"][number]["value"] : undefined @@ -361,6 +363,7 @@ export type PluginOptionBoolean = PluginSettingBooleanDef & PluginSettingCommon export type PluginOptionSelect = PluginSettingSelectDef & PluginSettingCommon & IsDisabled & IsValid; export type PluginOptionSlider = PluginSettingSliderDef & PluginSettingCommon & IsDisabled & IsValid; export type PluginOptionComponent = PluginSettingComponentDef & PluginSettingCommon; +export type PluginOptionList = PluginSettingListDef & PluginSettingCommon; export type PluginNative any>> = { [key in keyof PluginExports]: