IRememberYou: Remove Broken Editor
This commit is contained in:
parent
5404305e0a
commit
3bab98c7db
4 changed files with 307 additions and 355 deletions
172
src/equicordplugins/iRememberYou/components/data.tsx
Normal file
172
src/equicordplugins/iRememberYou/components/data.tsx
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { DataStore } from "@api/index";
|
||||
import { Guild, User } from "@vencord/discord-types";
|
||||
import { ChannelStore, GuildMemberStore, GuildStore, MessageStore, UserStore, } from "@webpack/common";
|
||||
|
||||
export interface IUserExtra {
|
||||
isOwner?: boolean;
|
||||
updatedAt?: number;
|
||||
}
|
||||
|
||||
export interface IStorageUser {
|
||||
id: string;
|
||||
username: string,
|
||||
tag: string,
|
||||
iconURL?: string;
|
||||
extra?: IUserExtra;
|
||||
}
|
||||
|
||||
export interface GroupData {
|
||||
id: string;
|
||||
users: { [key: string]: IStorageUser; };
|
||||
name: string;
|
||||
}
|
||||
|
||||
export class Data {
|
||||
declare usersCollection: Record<string, GroupData>;
|
||||
declare _storageAutoSaveProtocol_interval;
|
||||
declare _onMessagePreSend_preSend;
|
||||
|
||||
withStart() {
|
||||
return this;
|
||||
}
|
||||
|
||||
onMessagePreSend(channelId, message, extra) {
|
||||
const target: Set<{ user: User; source?: Guild, extra: IUserExtra; }> = new Set();
|
||||
const now = Date.now();
|
||||
const { replyOptions } = extra;
|
||||
|
||||
const guild = (() => {
|
||||
const channel = ChannelStore.getChannel(channelId);
|
||||
return GuildStore.getGuild(channel.guild_id) || undefined;
|
||||
})();
|
||||
|
||||
if (replyOptions.messageReference) {
|
||||
const { channel_id, message_id } = replyOptions.messageReference;
|
||||
const message = MessageStore.getMessage(channel_id, message_id);
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
const { author } = message;
|
||||
|
||||
target.add({ user: author, source: guild, extra: { updatedAt: now } });
|
||||
}
|
||||
|
||||
if (message.content) {
|
||||
const { content } = message;
|
||||
const ids = [...content.matchAll(/<@!?(?<id>\d{17,23})>/g)].map(
|
||||
({ groups }) => groups.id
|
||||
);
|
||||
|
||||
const users = ids
|
||||
.map(id => UserStore.getUser(id))
|
||||
.filter(Boolean);
|
||||
for (const user of users) {
|
||||
target.add({ user, source: guild, extra: { updatedAt: now } });
|
||||
}
|
||||
}
|
||||
|
||||
this.processUsersToCollection([...target]);
|
||||
}
|
||||
|
||||
async processUsersToCollection(
|
||||
array: { user: User; source?: Guild; extra?: IUserExtra; }[]
|
||||
) {
|
||||
const target = this.usersCollection;
|
||||
for (const { user, source, extra } of array) {
|
||||
if (user.bot) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const groupKey = source?.id ?? "dm";
|
||||
const group = (target[groupKey] ||= {
|
||||
name: source?.name || "dm",
|
||||
id: source?.id || user.id,
|
||||
users: {}
|
||||
});
|
||||
const usersField = group.users;
|
||||
const previouExtra = usersField[user.id]?.extra ?? {};
|
||||
const { id, username } = user;
|
||||
|
||||
usersField[id] = {
|
||||
id,
|
||||
username,
|
||||
tag: user.discriminator === "0" ? user.username : user.tag,
|
||||
extra: { ...previouExtra, ...extra },
|
||||
iconURL: user.getAvatarURL(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async updateStorage() {
|
||||
await DataStore.set("irememberyou.data", this.usersCollection);
|
||||
}
|
||||
|
||||
async initializeUsersCollection() {
|
||||
const data = await DataStore.get("irememberyou.data");
|
||||
this.usersCollection = data ?? {};
|
||||
}
|
||||
|
||||
writeMembersFromUserGuildsToCollection() {
|
||||
const target: Set<{ user: User; source?: Guild, extra: IUserExtra; }> =
|
||||
new Set();
|
||||
|
||||
const now = Date.now();
|
||||
const LIMIT = 1_000;
|
||||
|
||||
const clientId = UserStore.getCurrentUser().id;
|
||||
if (!clientId) {
|
||||
return;
|
||||
}
|
||||
for (const guild of Object.values(GuildStore.getGuilds())) {
|
||||
const { ownerId } = guild;
|
||||
if (ownerId !== clientId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const members = GuildMemberStore.getMembers(guild.id);
|
||||
if (members.length > LIMIT) {
|
||||
members.length = LIMIT;
|
||||
}
|
||||
for (const member of members) {
|
||||
const user = UserStore.getUser(member.userId);
|
||||
target.add({ user, source: guild, extra: { updatedAt: now } });
|
||||
}
|
||||
|
||||
this.processUsersToCollection([...target]);
|
||||
}
|
||||
}
|
||||
|
||||
writeGuildsOwnersToCollection() {
|
||||
const target: Set<{ user: User; source?: Guild; extra: IUserExtra; }> =
|
||||
new Set();
|
||||
const now = Date.now();
|
||||
|
||||
for (const guild of Object.values(GuildStore.getGuilds())) {
|
||||
const { ownerId } = guild;
|
||||
const owner = UserStore.getUser(ownerId);
|
||||
if (!owner) {
|
||||
continue;
|
||||
}
|
||||
target.add({
|
||||
user: owner,
|
||||
source: guild,
|
||||
extra: { isOwner: true, updatedAt: now },
|
||||
});
|
||||
}
|
||||
|
||||
this.processUsersToCollection([...target]);
|
||||
}
|
||||
|
||||
storageAutoSaveProtocol() {
|
||||
this._storageAutoSaveProtocol_interval = setInterval(
|
||||
this.updateStorage.bind(this),
|
||||
60_000 * 3
|
||||
);
|
||||
}
|
||||
}
|
||||
119
src/equicordplugins/iRememberYou/components/ui.tsx
Normal file
119
src/equicordplugins/iRememberYou/components/ui.tsx
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { BaseText } from "@components/BaseText";
|
||||
import { Paragraph } from "@components/Paragraph";
|
||||
import { openUserProfile } from "@utils/discord";
|
||||
import { Avatar, Clickable, Flex, React, TextInput, Tooltip, } from "@webpack/common";
|
||||
|
||||
import { Data, IStorageUser } from "./data";
|
||||
|
||||
const cl = classNameFactory("vc-i-remember-you-");
|
||||
|
||||
function tooltipText(user: IStorageUser) {
|
||||
const { updatedAt } = user.extra || {};
|
||||
const updatedAtContent = updatedAt ? new Intl.DateTimeFormat().format(updatedAt) : null;
|
||||
return `${user.username ?? user.tag}, updated at ${updatedAtContent}`;
|
||||
}
|
||||
|
||||
function SectionDescription() {
|
||||
return (
|
||||
<BaseText>
|
||||
{"Provides a list of users you have mentioned or replied to, or those who own the servers you belong to (owner*), or are members of your guild"}
|
||||
</BaseText>
|
||||
);
|
||||
}
|
||||
|
||||
function UsersCollectionRows({ usersCollection }: { usersCollection: Data["usersCollection"]; }) {
|
||||
if (Object.keys(usersCollection).length === 0) return (
|
||||
<BaseText>
|
||||
It's empty right now
|
||||
</BaseText>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{Object.entries(usersCollection)
|
||||
.map(([_key, { users, name }]) => ({ name, users: Object.values(users) }))
|
||||
.sort((a, b) => b.users.length - a.users.length)
|
||||
.map(({ name, users }) => (
|
||||
<aside key={name}>
|
||||
<div className={cl("header-container")}>
|
||||
<BaseText>{name.toUpperCase()}</BaseText>
|
||||
<div className={cl("header-btns")}>
|
||||
<Flex>
|
||||
{users.map(u => <UserRow key={u.id} user={u} />)}
|
||||
</Flex>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function UserRow({ user, allowOwner = true }: { user: IStorageUser, allowOwner?: boolean; }) {
|
||||
return (
|
||||
<Flex key={user.id} className={cl("user-row")}>
|
||||
<span className={cl("user")}>
|
||||
<Flex>
|
||||
<Clickable onClick={() => openUserProfile(user.id)}>
|
||||
<span className={cl("user-avatar")}>
|
||||
<Avatar src={user.iconURL} size="SIZE_24" />
|
||||
</span>
|
||||
</Clickable>
|
||||
<Tooltip text={tooltipText(user)}>
|
||||
{props =>
|
||||
<Paragraph {...props} className={cl("user-username")}>
|
||||
{user.tag} {allowOwner && user.extra?.isOwner && "(owner)"}
|
||||
</Paragraph>
|
||||
}
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
</span>
|
||||
|
||||
<span className={cl("user-id")}>
|
||||
<Paragraph>
|
||||
{user.id}
|
||||
</Paragraph>
|
||||
</span>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
function SearchElement({ usersCollection }: { usersCollection: Data["usersCollection"]; }) {
|
||||
const [current, setCurrent] = React.useState("");
|
||||
const list = Object.values(usersCollection).flatMap(col => Object.values(col.users)) as IStorageUser[];
|
||||
|
||||
return (
|
||||
<section className={cl("search")}>
|
||||
<TextInput placeholder="Filter by tag, username" name="Filter" onChange={setCurrent} />
|
||||
{current && (
|
||||
<Flex className={cl("search-user")}>
|
||||
{list.filter(user => user.tag.includes(current) || user.username.includes(current))
|
||||
.map(user => <UserRow key={user.id} user={user} allowOwner={false} />)}
|
||||
</Flex>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export function DataUI({ plugin, usersCollection }: { plugin: any; usersCollection: Data["usersCollection"]; }) {
|
||||
return (
|
||||
<main className={cl("header")}>
|
||||
<BaseText size="lg" weight="bold" tag="h1">
|
||||
IRememberYou
|
||||
</BaseText>
|
||||
|
||||
<SectionDescription />
|
||||
<SearchElement usersCollection={usersCollection} />
|
||||
<Flex className={cl("rows")}>
|
||||
<UsersCollectionRows usersCollection={usersCollection} />
|
||||
</Flex>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
|
@ -6,362 +6,13 @@
|
|||
|
||||
import "./styles.css";
|
||||
|
||||
import { DataStore } from "@api/index";
|
||||
import { addMessagePreSendListener, removeMessagePreSendListener } from "@api/MessageEvents";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { BaseText } from "@components/BaseText";
|
||||
import { Paragraph } from "@components/Paragraph";
|
||||
import { EquicordDevs } from "@utils/constants";
|
||||
import { openUserProfile } from "@utils/discord";
|
||||
import * as Modal from "@utils/modal";
|
||||
import definePlugin from "@utils/types";
|
||||
import { Guild, User } from "@vencord/discord-types";
|
||||
import { Avatar, Button, ChannelStore, Clickable, Flex, GuildMemberStore, GuildStore, MessageStore, React, TextArea, TextInput, Tooltip, UserStore, } from "@webpack/common";
|
||||
import { React, } from "@webpack/common";
|
||||
|
||||
interface IUserExtra {
|
||||
isOwner?: boolean;
|
||||
updatedAt?: number;
|
||||
}
|
||||
|
||||
interface IStorageUser {
|
||||
id: string;
|
||||
username: string,
|
||||
tag: string,
|
||||
iconURL?: string;
|
||||
extra?: IUserExtra;
|
||||
}
|
||||
|
||||
interface GroupData {
|
||||
id: string;
|
||||
users: { [key: string]: IStorageUser; };
|
||||
name: string;
|
||||
}
|
||||
|
||||
const cl = classNameFactory("vc-i-remember-you-");
|
||||
|
||||
class Data {
|
||||
declare usersCollection: Record<string, GroupData>;
|
||||
declare _storageAutoSaveProtocol_interval;
|
||||
declare _onMessagePreSend_preSend;
|
||||
|
||||
withStart() {
|
||||
return this;
|
||||
}
|
||||
|
||||
onMessagePreSend(channelId, message, extra) {
|
||||
const target: Set<{ user: User; source?: Guild, extra: IUserExtra; }> = new Set();
|
||||
const now = Date.now();
|
||||
const { replyOptions } = extra;
|
||||
|
||||
const guild = (() => {
|
||||
const channel = ChannelStore.getChannel(channelId);
|
||||
return GuildStore.getGuild(channel.guild_id) || undefined;
|
||||
})();
|
||||
|
||||
if (replyOptions.messageReference) {
|
||||
const { channel_id, message_id } = replyOptions.messageReference;
|
||||
const message = MessageStore.getMessage(channel_id, message_id);
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
const { author } = message;
|
||||
|
||||
target.add({ user: author, source: guild, extra: { updatedAt: now } });
|
||||
}
|
||||
|
||||
if (message.content) {
|
||||
const { content } = message;
|
||||
const ids = [...content.matchAll(/<@!?(?<id>\d{17,23})>/g)].map(
|
||||
({ groups }) => groups.id
|
||||
);
|
||||
|
||||
const users = ids
|
||||
.map(id => UserStore.getUser(id))
|
||||
.filter(Boolean);
|
||||
for (const user of users) {
|
||||
target.add({ user, source: guild, extra: { updatedAt: now } });
|
||||
}
|
||||
}
|
||||
|
||||
this.processUsersToCollection([...target]);
|
||||
}
|
||||
|
||||
async processUsersToCollection(
|
||||
array: { user: User; source?: Guild; extra?: IUserExtra; }[]
|
||||
) {
|
||||
const target = this.usersCollection;
|
||||
for (const { user, source, extra } of array) {
|
||||
if (user.bot) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const groupKey = source?.id ?? "dm";
|
||||
const group = (target[groupKey] ||= {
|
||||
name: source?.name || "dm",
|
||||
id: source?.id || user.id,
|
||||
users: {}
|
||||
});
|
||||
const usersField = group.users;
|
||||
const previouExtra = usersField[user.id]?.extra ?? {};
|
||||
const { id, username } = user;
|
||||
|
||||
usersField[id] = {
|
||||
id,
|
||||
username,
|
||||
tag: user.discriminator === "0" ? user.username : user.tag,
|
||||
extra: { ...previouExtra, ...extra },
|
||||
iconURL: user.getAvatarURL(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async updateStorage() {
|
||||
await DataStore.set("irememberyou.data", this.usersCollection);
|
||||
}
|
||||
|
||||
async initializeUsersCollection() {
|
||||
const data = await DataStore.get("irememberyou.data");
|
||||
this.usersCollection = data ?? {};
|
||||
}
|
||||
|
||||
writeMembersFromUserGuildsToCollection() {
|
||||
const target: Set<{ user: User; source?: Guild, extra: IUserExtra; }> =
|
||||
new Set();
|
||||
|
||||
const now = Date.now();
|
||||
const LIMIT = 1_000;
|
||||
|
||||
const clientId = UserStore.getCurrentUser().id;
|
||||
if (!clientId) {
|
||||
return;
|
||||
}
|
||||
for (const guild of Object.values(GuildStore.getGuilds())) {
|
||||
const { ownerId } = guild;
|
||||
if (ownerId !== clientId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const members = GuildMemberStore.getMembers(guild.id);
|
||||
if (members.length > LIMIT) {
|
||||
members.length = LIMIT;
|
||||
}
|
||||
for (const member of members) {
|
||||
const user = UserStore.getUser(member.userId);
|
||||
target.add({ user, source: guild, extra: { updatedAt: now } });
|
||||
}
|
||||
|
||||
this.processUsersToCollection([...target]);
|
||||
}
|
||||
}
|
||||
|
||||
writeGuildsOwnersToCollection() {
|
||||
const target: Set<{ user: User; source?: Guild; extra: IUserExtra; }> =
|
||||
new Set();
|
||||
const now = Date.now();
|
||||
|
||||
for (const guild of Object.values(GuildStore.getGuilds())) {
|
||||
const { ownerId } = guild;
|
||||
const owner = UserStore.getUser(ownerId);
|
||||
if (!owner) {
|
||||
continue;
|
||||
}
|
||||
target.add({
|
||||
user: owner,
|
||||
source: guild,
|
||||
extra: { isOwner: true, updatedAt: now },
|
||||
});
|
||||
}
|
||||
|
||||
this.processUsersToCollection([...target]);
|
||||
}
|
||||
|
||||
storageAutoSaveProtocol() {
|
||||
this._storageAutoSaveProtocol_interval = setInterval(
|
||||
this.updateStorage.bind(this),
|
||||
60_000 * 3
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DataUI {
|
||||
declare plugin;
|
||||
|
||||
constructor(plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
start() {
|
||||
return this;
|
||||
}
|
||||
|
||||
renderSectionDescription() {
|
||||
return <BaseText>{"Provides a list of users you have mentioned or replied to, or those who own the servers you belong to (owner*), or are members of your guild"}</BaseText>;
|
||||
}
|
||||
|
||||
renderUsersCollectionAsRows(usersCollection: Data["usersCollection"]) {
|
||||
if (Object.keys(usersCollection).length === 0) {
|
||||
return <BaseText>It's empty right now</BaseText>;
|
||||
}
|
||||
const elements = Object.entries(usersCollection)
|
||||
.map(([_key, { users, name }]) => ({ name, users: Object.values(users) }))
|
||||
.sort((a, b) => b.users.length - a.users.length)
|
||||
.map(({ name, users }) =>
|
||||
this.renderUsersCollectionRows(name, users)
|
||||
);
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
renderUsersCollectionRows(key: string, users: IStorageUser[]) {
|
||||
const usersElements = users.map(user => this.renderUserRow(user));
|
||||
|
||||
|
||||
return <aside key={key} >
|
||||
<div className={cl("header-container")}>
|
||||
<BaseText>{key.toUpperCase()}</BaseText>
|
||||
<div className={cl("header-btns")}>
|
||||
<Flex>
|
||||
{usersElements}
|
||||
</Flex>
|
||||
</div>
|
||||
</div>
|
||||
</aside>;
|
||||
}
|
||||
|
||||
renderUserAvatar(user: IStorageUser) {
|
||||
return <Clickable onClick={() => openUserProfile(user.id)}>
|
||||
<span className={cl("user-avatar")}>
|
||||
<Avatar src={user.iconURL} size="SIZE_24" />
|
||||
</span>
|
||||
</Clickable>;
|
||||
}
|
||||
|
||||
userTooltipText(user: IStorageUser) {
|
||||
const { updatedAt } = user.extra || {};
|
||||
const updatedAtContent = updatedAt ? new Intl.DateTimeFormat().format(updatedAt) : null;
|
||||
return `${user.username ?? user.tag}, updated at ${updatedAtContent}`;
|
||||
}
|
||||
|
||||
renderUserRow(user: IStorageUser, allowExtra: { owner?: boolean; } = {}) {
|
||||
allowExtra = Object.assign({ owner: true }, allowExtra);
|
||||
|
||||
return (
|
||||
<Flex key={user.id} className={cl("user-row")}>
|
||||
<span className={cl("user")}>
|
||||
<Flex>
|
||||
{this.renderUserAvatar(user)}
|
||||
<Tooltip text={this.userTooltipText(user)}>
|
||||
{props =>
|
||||
<Paragraph {...props} className={cl("user-username")}>
|
||||
{user.tag} {allowExtra.owner && user.extra?.isOwner && "(owner)"}
|
||||
</Paragraph>
|
||||
}
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
</span>
|
||||
|
||||
<span className={cl("user-id")}>
|
||||
<Paragraph>
|
||||
{user.id}
|
||||
</Paragraph>
|
||||
</span>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
renderButtonsFooter(usersCollection: Data["usersCollection"]) {
|
||||
return (
|
||||
<footer className={cl("buttons")}>
|
||||
<Flex>
|
||||
|
||||
<Clickable onClick={() => Modal.openModal(props => <Modal.ModalRoot size={Modal.ModalSize.LARGE} fullscreenOnMobile={true} {...props}>
|
||||
<Modal.ModalHeader separator={false}>
|
||||
<BaseText
|
||||
size="lg"
|
||||
weight="semibold"
|
||||
color="header-primary"
|
||||
tag="h1"
|
||||
className={cl("buttons-editor")}
|
||||
>
|
||||
Editor
|
||||
</BaseText>
|
||||
<Modal.ModalCloseButton onClick={props.onClose} />
|
||||
</Modal.ModalHeader>
|
||||
<Modal.ModalContent>
|
||||
<Flex className={cl("buttons-save")}>
|
||||
<Button label="Validate and save" >Validate and save</Button>
|
||||
<Button label="Cancel" color={Button.Colors.TRANSPARENT}>Cancel</Button>
|
||||
</Flex>
|
||||
<TextArea value={JSON.stringify(usersCollection, null, "\t")} onChange={() => { }} rows={20} />
|
||||
</Modal.ModalContent>
|
||||
</Modal.ModalRoot>)}>
|
||||
<BaseText className={cl("buttons-editor-open")}>Open editor</BaseText>
|
||||
</Clickable>
|
||||
|
||||
<Clickable onClick={
|
||||
async () => {
|
||||
const confirmed = confirm("Sure?");
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { plugin } = this;
|
||||
const data = plugin.dataManager as Data;
|
||||
data.usersCollection = {};
|
||||
await data.updateStorage();
|
||||
}
|
||||
}>
|
||||
<BaseText className={cl("buttons-reset")}>
|
||||
Reset storage
|
||||
</BaseText>
|
||||
</Clickable>
|
||||
</Flex>
|
||||
</footer >
|
||||
);
|
||||
}
|
||||
|
||||
renderSearchElement(usersCollection: Data["usersCollection"]) {
|
||||
const [current, setState] = React.useState<string>();
|
||||
const map: Map<string, IStorageUser> = Object.values(usersCollection)
|
||||
.reduce((acc, { users }) => (acc.push(...Object.values(users)), acc), [] as IStorageUser[])
|
||||
.reduce((acc, current) => acc.set(current.id, current), new Map());
|
||||
|
||||
const list = [...map.values()];
|
||||
|
||||
return (
|
||||
<section className={cl("search")}>
|
||||
<TextInput placeholder="Filter by tag, username" name="Filter" onChange={value => setState(value)} />
|
||||
{current &&
|
||||
<Flex className={cl("search-user")}>
|
||||
{list.filter(user => user.tag.includes(current) || user.username.includes(current))
|
||||
.map(user => this.renderUserRow(
|
||||
user,
|
||||
{ owner: false }
|
||||
))
|
||||
}
|
||||
</Flex>
|
||||
}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
toElement(usersCollection: Data["usersCollection"]) {
|
||||
return (
|
||||
<main className={cl("header")}>
|
||||
<BaseText size="lg" weight="bold" tag="h1">
|
||||
{"IRememberYou"}
|
||||
</BaseText>
|
||||
|
||||
{this.renderSectionDescription()}
|
||||
{this.renderSearchElement(usersCollection)}
|
||||
<Flex className={cl("rows")}>
|
||||
{this.renderUsersCollectionAsRows(usersCollection)}
|
||||
</Flex>
|
||||
{this.renderButtonsFooter(usersCollection)}
|
||||
</main>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
import { Data } from "./components/data";
|
||||
import { DataUI } from "./components/ui";
|
||||
|
||||
export default definePlugin({
|
||||
name: "IRememberYou",
|
||||
|
|
@ -373,7 +24,6 @@ export default definePlugin({
|
|||
|
||||
async start() {
|
||||
const data = (this.dataManager = await new Data().withStart());
|
||||
const ui = (this.uiManager = await new DataUI(this).start());
|
||||
|
||||
await data.initializeUsersCollection();
|
||||
data.writeGuildsOwnersToCollection();
|
||||
|
|
@ -392,7 +42,7 @@ export default definePlugin({
|
|||
customSettingsSections.push(_ => ({
|
||||
section: "iremeberyou.display-data",
|
||||
label: "IRememberYou",
|
||||
element: () => ui.toElement(data.usersCollection),
|
||||
element: () => <DataUI plugin={this} usersCollection={data.usersCollection} />
|
||||
}));
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,18 @@
|
|||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.vc-i-remember-you-buttons-save,
|
||||
.vc-i-remember-you-buttons-cancel {
|
||||
margin-left: 490px;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.vc-i-remember-you-buttons-cancel {
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.vc-i-remember-you-buttons-reset {
|
||||
cursor: pointer;
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue