diff --git a/src/plugins/serverProfile/GuildProfileModal.tsx b/src/plugins/serverProfile/GuildProfileModal.tsx new file mode 100644 index 00000000..8620980f --- /dev/null +++ b/src/plugins/serverProfile/GuildProfileModal.tsx @@ -0,0 +1,117 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2023 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import "./styles.css"; + +import { classNameFactory } from "@api/Styles"; +import { ModalRoot, ModalSize, openModal } from "@utils/modal"; +import { useAwaiter } from "@utils/react"; +import { Forms, Parser, SnowflakeUtils, TabBar, UserUtils, useState } from "@webpack/common"; +import { Guild } from "discord-types/general"; + +const cl = classNameFactory("vc-gp-"); + +export function openGuildProfileModal(guild: Guild) { + openModal(props => + + + + ); +} + +const Tabs = { + ServerInfo: { + label: "Server Info", + component: ServerInfoTab + }, + Friends: { + label: "Friends", + component: FriendsTab + }, + BlockedUsers: { + label: "Blocked Users", + component: BlockedUsersTab + } +} as const; + +type TabKeys = keyof typeof Tabs; + +interface GuildProps { + guild: Guild; +} + +function GuildProfileModal({ guild }: GuildProps) { + const [currentTab, setCurrentTab] = useState("ServerInfo"); + + const Tab = Tabs[currentTab].component; + + return ( +
+ + {Object.entries(Tabs).map(([id, { label }]) => + + {label} + + )} + + +
+ +
+
+ ); +} + + +const dateFormat = new Intl.DateTimeFormat(void 0, { timeStyle: "short", dateStyle: "medium" }); +function renderTimestampFromId(id: string) { + return dateFormat.format(SnowflakeUtils.extractTimestamp(id)); +} + +function ServerInfoTab({ guild }: GuildProps) { + useAwaiter(() => UserUtils.fetchUser(guild.ownerId), { + deps: [guild.ownerId], + fallbackValue: null + }); + + const Fields = { + "Server Owner": Parser.parse(`<@${guild.ownerId}>`), + "Created At": renderTimestampFromId(guild.id), + "Joined At": dateFormat.format(guild.joinedAt), + "Vanity Link": guild.vanityURLCode ? Parser.parse(`https://discord.gg/${guild.vanityURLCode}`) : "-", + "Preferred Locale": guild.preferredLocale || "-", + "Verification Level": ["Low", "Medium", "High", "Highest"][guild.verificationLevel] || "?" + }; + + return ( +
+ {Object.entries(Fields).map(([name, node]) => +
+ {name} + {typeof node === "string" ? {node} : node} +
+ )} +
+ ); +} + +function FriendsTab({ guild }: GuildProps) { + return null; +} + +function BlockedUsersTab({ guild }: GuildProps) { + return null; +} diff --git a/src/plugins/serverProfile/index.tsx b/src/plugins/serverProfile/index.tsx new file mode 100644 index 00000000..1845b700 --- /dev/null +++ b/src/plugins/serverProfile/index.tsx @@ -0,0 +1,38 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2023 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu"; +import { Devs } from "@utils/constants"; +import definePlugin from "@utils/types"; +import { Menu } from "@webpack/common"; +import { Guild } from "discord-types/general"; + +import { openGuildProfileModal } from "./GuildProfileModal"; + +const Patch: NavContextMenuPatchCallback = (children, { guild }: { guild: Guild; }) => () => { + children.splice(-1, 0, ( + openGuildProfileModal(guild)} + /> + )); +}; + +export default definePlugin({ + name: "ServerProfile", + description: "Allows you to view info about a server by right clicking it in the server list", + authors: [Devs.Ven], + tags: ["guild", "info"], + + start() { + addContextMenuPatch("guild-context", Patch); + }, + + stop() { + removeContextMenuPatch("guild-context", Patch); + } +}); diff --git a/src/plugins/serverProfile/styles.css b/src/plugins/serverProfile/styles.css new file mode 100644 index 00000000..546f1330 --- /dev/null +++ b/src/plugins/serverProfile/styles.css @@ -0,0 +1,38 @@ +.vc-gp-root { + height: 100%; +} + +.vc-gp-tab-bar { + border-bottom: 2px solid var(--background-modifier-accent); + margin: 20px 12px 0; + display: flex; + gap: 40px; + align-items: stretch; + flex-direction: row; +} + +.vc-gp-tab { + border-bottom: 2px solid transparent; + color: var(--interactive-normal); + cursor: pointer; + height: 39px; + line-height: 14px; +} + +.vc-gp-tab-content { + margin: 1em; +} + +.vc-gp-tab:where(.vc-gp-selected, :hover, :focus) { + border-bottom-color: var(--interactive-active); +} + +.vc-gp-server-info { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 1em; +} + +.vc-gp-server-info-pair { + color: var(--text-normal); +}