+
No permissions to display!
)}
{selectedItem && (
-
-
+
+
{permissions.map((permission, index) => {
- const user = UserStore.getUser(permission.id ?? "");
- const role = roles[permission.id ?? ""];
+ const user: User | undefined = UserStore.getUser(permission.id ?? "");
+ const role: Role | undefined = roles[permission.id ?? ""];
+ const roleIconSrc = role != null ? getRoleIconSrc(role) : undefined;
return (
-
+
);
})}
-
-
+
+
+
{Object.entries(PermissionsBits).map(([permissionName, bit]) => (
-
-
+
+
{(() => {
const { permissions, overwriteAllow, overwriteDeny } = selectedItem;
@@ -192,11 +199,11 @@ function RolesAndUsersPermissionsComponent({ permissions, guild, modalProps, hea
))}
-
+
)}
-
+
);
}
@@ -208,7 +215,7 @@ function RoleContextMenu({ guild, roleId, onClose }: { guild: Guild; roleId: str
aria-label="Role Options"
>
{
Clipboard.copy(roleId);
@@ -217,14 +224,13 @@ function RoleContextMenu({ guild, roleId, onClose }: { guild: Guild; roleId: str
{(settings.store as any).unsafeViewAsRole && (
{
const role = GuildStore.getRole(guild.id, roleId);
if (!role) return;
onClose();
-
FluxDispatcher.dispatch({
type: "IMPERSONATE_UPDATE",
guildId: guild.id,
@@ -235,15 +241,14 @@ function RoleContextMenu({ guild, roleId, onClose }: { guild: Guild; roleId: str
}
}
});
- }
- }
+ }}
/>
)}
);
}
-function UserContextMenu({ userId, onClose }: { userId: string; onClose: () => void; }) {
+function UserContextMenu({ userId }: { userId: string; }) {
return (
v
aria-label="User Options"
>
{
Clipboard.copy(userId);
@@ -263,4 +268,13 @@ function UserContextMenu({ userId, onClose }: { userId: string; onClose: () => v
const RolesAndUsersPermissions = ErrorBoundary.wrap(RolesAndUsersPermissionsComponent);
-export default openRolesAndUsersPermissionsModal;
+export default function openRolesAndUsersPermissionsModal(permissions: Array, guild: Guild, header: string) {
+ return openModal(modalProps => (
+
+ ));
+}
diff --git a/src/plugins/permissionsViewer/components/UserPermissions.tsx b/src/plugins/permissionsViewer/components/UserPermissions.tsx
index dc2aa6fa4..7c0858f10 100644
--- a/src/plugins/permissionsViewer/components/UserPermissions.tsx
+++ b/src/plugins/permissionsViewer/components/UserPermissions.tsx
@@ -29,6 +29,7 @@ import openRolesAndUsersPermissionsModal, { PermissionType, type RoleOrUserPermi
interface UserPermission {
permission: string;
+ roleName: string;
roleColor: string;
rolePosition: number;
}
@@ -45,8 +46,48 @@ const { RoleRootClasses, RoleClasses, RoleBorderClasses } = proxyLazyWebpack(()
return { RoleRootClasses, RoleClasses, RoleBorderClasses };
});
+interface FakeRoleProps extends React.HTMLAttributes {
+ text: string;
+ color: string;
+}
+
+function FakeRole({ text, color, ...props }: FakeRoleProps) {
+ return (
+
+ );
+}
+
+interface GrantedByTooltipProps {
+ roleName: string;
+ roleColor: string;
+}
+
+function GrantedByTooltip({ roleName, roleColor }: GrantedByTooltipProps) {
+ return (
+ <>
+ Granted By
+
+ >
+ );
+}
+
function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { guild: Guild; guildMember: GuildMember; forceOpen?: boolean; }) {
- const stns = settings.use(["permissionsSortOrder"]);
+ const { permissionsSortOrder } = settings.use(["permissionsSortOrder"]);
const [rolePermissions, userPermissions] = useMemo(() => {
const userPermissions: UserPermissions = [];
@@ -67,6 +108,7 @@ function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { g
const OWNER = i18n.Messages.GUILD_OWNER || "Server Owner";
userPermissions.push({
permission: OWNER,
+ roleName: "Owner",
roleColor: "var(--primary-300)",
rolePosition: Infinity
});
@@ -75,10 +117,11 @@ function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { g
sortUserRoles(userRoles);
for (const [permission, bit] of Object.entries(PermissionsBits)) {
- for (const { permissions, colorString, position } of userRoles) {
+ for (const { permissions, colorString, position, name } of userRoles) {
if ((permissions & bit) === bit) {
userPermissions.push({
permission: getPermissionString(permission),
+ roleName: name,
roleColor: colorString || "var(--primary-300)",
rolePosition: position
});
@@ -91,7 +134,7 @@ function UserPermissionsComponent({ guild, guildMember, forceOpen = false }: { g
userPermissions.sort((a, b) => b.rolePosition - a.rolePosition);
return [rolePermissions, userPermissions];
- }, [stns.permissionsSortOrder]);
+ }, [permissionsSortOrder]);
return (
settings.store.defaultPermissionsDropdownState = !state}
defaultState={settings.store.defaultPermissionsDropdownState}
buttons={[
- (
+
{tooltipProps => (
-
+
)}
- )
+
]}>
{userPermissions.length > 0 && (
- {userPermissions.map(({ permission, roleColor }) => (
-
-
-
-
-
-
- {permission}
-
-
-
+ {userPermissions.map(({ permission, roleColor, roleName }) => (
+
}
+ tooltipClassName={cl("granted-by-container")}
+ tooltipContentClassName={cl("granted-by-content")}
+ >
+ {tooltipProps => (
+
+ )}
+
))}
)}
diff --git a/src/plugins/permissionsViewer/index.tsx b/src/plugins/permissionsViewer/index.tsx
index 7c3967a37..44dfd5f54 100644
--- a/src/plugins/permissionsViewer/index.tsx
+++ b/src/plugins/permissionsViewer/index.tsx
@@ -26,7 +26,7 @@ import { Devs } from "@utils/constants";
import { classes } from "@utils/misc";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy } from "@webpack";
-import { Button, ChannelStore, Dialog, GuildMemberStore, GuildStore, Menu, PermissionsBits, Popout, TooltipContainer, UserStore } from "@webpack/common";
+import { Button, ChannelStore, Dialog, GuildMemberStore, GuildStore, match, Menu, PermissionsBits, Popout, TooltipContainer, UserStore } from "@webpack/common";
import type { Guild, GuildMember } from "discord-types/general";
import openRolesAndUsersPermissionsModal, { PermissionType, RoleOrUserPermission } from "./components/RolesAndUsersPermissions";
@@ -54,12 +54,12 @@ export const settings = definePluginSettings({
options: [
{ label: "Highest Role", value: PermissionsSortOrder.HighestRole, default: true },
{ label: "Lowest Role", value: PermissionsSortOrder.LowestRole }
- ],
+ ]
},
defaultPermissionsDropdownState: {
description: "Whether the permissions dropdown on user popouts should be open by default",
type: OptionType.BOOLEAN,
- default: false,
+ default: false
}
});
@@ -73,14 +73,11 @@ function MenuItem(guildId: string, id?: string, type?: MenuItemParentType) {
action={() => {
const guild = GuildStore.getGuild(guildId);
- let permissions: RoleOrUserPermission[];
- let header: string;
-
- switch (type) {
- case MenuItemParentType.User: {
+ const { permissions, header }: { permissions: RoleOrUserPermission[], header: string; } = match(type)
+ .with(MenuItemParentType.User, () => {
const member = GuildMemberStore.getMember(guildId, id!);
- permissions = getSortedRoles(guild, member)
+ const permissions: RoleOrUserPermission[] = getSortedRoles(guild, member)
.map(role => ({
type: PermissionType.Role,
...role
@@ -93,37 +90,37 @@ function MenuItem(guildId: string, id?: string, type?: MenuItemParentType) {
});
}
- header = member.nick ?? UserStore.getUser(member.userId).username;
-
- break;
- }
-
- case MenuItemParentType.Channel: {
+ return {
+ permissions,
+ header: member.nick ?? UserStore.getUser(member.userId).username
+ };
+ })
+ .with(MenuItemParentType.Channel, () => {
const channel = ChannelStore.getChannel(id!);
- permissions = sortPermissionOverwrites(Object.values(channel.permissionOverwrites).map(({ id, allow, deny, type }) => ({
+ const permissions = sortPermissionOverwrites(Object.values(channel.permissionOverwrites).map(({ id, allow, deny, type }) => ({
type: type as PermissionType,
id,
overwriteAllow: allow,
overwriteDeny: deny
})), guildId);
- header = channel.name;
-
- break;
- }
-
- default: {
- permissions = Object.values(GuildStore.getRoles(guild.id)).map(role => ({
+ return {
+ permissions,
+ header: channel.name
+ };
+ })
+ .otherwise(() => {
+ const permissions = Object.values(GuildStore.getRoles(guild.id)).map(role => ({
type: PermissionType.Role,
...role
}));
- header = guild.name;
-
- break;
- }
- }
+ return {
+ permissions,
+ header: guild.name
+ };
+ });
openRolesAndUsersPermissionsModal(permissions, guild, header);
}}
@@ -133,32 +130,34 @@ function MenuItem(guildId: string, id?: string, type?: MenuItemParentType) {
function makeContextMenuPatch(childId: string | string[], type?: MenuItemParentType): NavContextMenuPatchCallback {
return (children, props) => {
- if (!props) return;
- if ((type === MenuItemParentType.User && !props.user) || (type === MenuItemParentType.Guild && !props.guild) || (type === MenuItemParentType.Channel && (!props.channel || !props.guild)))
+ if (
+ !props ||
+ (type === MenuItemParentType.User && !props.user) ||
+ (type === MenuItemParentType.Guild && !props.guild) ||
+ (type === MenuItemParentType.Channel && (!props.channel || !props.guild))
+ ) {
return;
+ }
const group = findGroupChildrenByChildId(childId, children);
- const item = (() => {
- switch (type) {
- case MenuItemParentType.User:
- return MenuItem(props.guildId, props.user.id, type);
- case MenuItemParentType.Channel:
- return MenuItem(props.guild.id, props.channel.id, type);
- case MenuItemParentType.Guild:
- return MenuItem(props.guild.id);
- default:
- return null;
- }
- })();
+ const item = match(type)
+ .with(MenuItemParentType.User, () => MenuItem(props.guildId, props.user.id, type))
+ .with(MenuItemParentType.Channel, () => MenuItem(props.guild.id, props.channel.id, type))
+ .with(MenuItemParentType.Guild, () => MenuItem(props.guild.id))
+ .otherwise(() => null);
+
if (item == null) return;
- if (group)
- group.push(item);
- else if (childId === "roles" && props.guildId)
- // "roles" may not be present due to the member not having any roles. In that case, add it above "Copy ID"
+ if (group) {
+ return group.push(item);
+ }
+
+ // "roles" may not be present due to the member not having any roles. In that case, add it above "Copy ID"
+ if (childId === "roles" && props.guildId) {
children.splice(-1, 0, {item});
+ }
};
}
diff --git a/src/plugins/permissionsViewer/styles.css b/src/plugins/permissionsViewer/styles.css
index 0ef961e5a..0123f86e2 100644
--- a/src/plugins/permissionsViewer/styles.css
+++ b/src/plugins/permissionsViewer/styles.css
@@ -1,20 +1,6 @@
/* User Permissions Component */
-.vc-permviewer-userperms-title-container {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-top: 10px;
- margin-bottom: 6px;
-}
-
-.vc-permviewer-userperms-btns-container {
- display: flex;
- align-items: center;
-}
-
-.vc-permviewer-userperms-sortorder-btn {
- all: unset;
+.vc-permviewer-user-sortorder-btn {
cursor: pointer;
display: flex;
align-items: center;
@@ -23,27 +9,17 @@
height: 24px;
}
-.vc-permviewer-userperms-permdetails-btn {
- all: unset;
- cursor: pointer;
- display: flex;
- align-items: center;
-}
-
-.vc-permviewer-userperms-toggleperms-btn {
- all: unset;
- cursor: pointer;
- display: flex;
- align-items: center;
-}
-
/* RolesAndUsersPermissions Component */
-.vc-permviewer-perms-title {
+.vc-permviewer-modal-content {
+ padding: 16px 4px 16px 16px;
+}
+
+.vc-permviewer-modal-title {
flex-grow: 1;
}
-.vc-permviewer-perms-no-perms {
+.vc-permviewer-modal-no-perms {
width: 100%;
height: 100%;
display: flex;
@@ -52,101 +28,103 @@
text-align: center;
}
-.vc-permviewer-perms-container {
- display: grid;
- grid-template-columns: 1fr 2fr;
- grid-template-areas: "list permissions";
- padding: 16px 0;
+.vc-permviewer-modal-container {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ gap: 8px;
}
-.vc-permviewer-perms-list {
- grid-area: list;
+.vc-permviewer-modal-list {
display: flex;
flex-direction: column;
gap: 2px;
- border-right: 2px solid var(--background-modifier-active);
+ padding-right: 8px;
+ width: 200px;
}
-.vc-permviewer-perms-list-item-btn {
- all: unset;
+.vc-permviewer-modal-list-item-btn {
cursor: pointer;
}
-.vc-permviewer-perms-list-item {
+.vc-permviewer-modal-list-item {
display: flex;
align-items: center;
- padding: 8px 5px;
- cursor: pointer;
- width: 230px;
+ gap: 8px;
+ padding: 8px;
border-radius: 5px;
}
-.vc-permviewer-perms-list-item:hover {
+.vc-permviewer-modal-list-item:hover {
background-color: var(--background-modifier-hover);
}
-.vc-permviewer-perms-list-item-active {
+.vc-permviewer-modal-list-item-active {
background-color: var(--background-modifier-selected);
}
-.vc-permviewer-perms-list-item > div {
+.vc-permviewer-modal-list-item > div {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
-.vc-permviewer-perms-role-circle {
+.vc-permviewer-modal-role-circle {
border-radius: 50%;
width: 12px;
height: 12px;
- margin-left: 3px;
- margin-right: 11px;
flex-shrink: 0;
}
-.vc-permviewer-perms-user-img {
+.vc-permviewer-modal-role-image {
+ width: 20px;
+ height: 20px;
+ object-fit: contain;
+}
+
+.vc-permviewer-modal-user-img {
border-radius: 50%;
width: 20px;
height: 20px;
- margin-right: 6px;
}
-.vc-permviewer-perms-perms {
- grid-area: permissions;
+.vc-permviewer-modal-divider {
+ width: 2px;
+ background-color: var(--background-modifier-active);
+}
+
+.vc-permviewer-modal-perms {
display: flex;
flex-direction: column;
- margin-left: 5px;
+ padding-right: 8px;
}
-.vc-permviewer-perms-perms-item {
- position: relative;
+.vc-permviewer-modal-perms-item {
display: flex;
align-items: center;
- padding: 10px;
+ gap: 5px;
+ padding: 10px 2px 10px 10px;
border-bottom: 2px solid var(--background-modifier-active);
}
-.vc-permviewer-perms-perms-item:last-child {
+.vc-permviewer-modal-perms-item:last-child {
border: 0;
}
-.vc-permviewer-perms-perms-item-icon {
+.vc-permviewer-modal-perms-item-icon {
border: 1px solid var(--background-modifier-selected);
width: 24px;
height: 24px;
- margin-right: 5px;
}
-.vc-permviewer-perms-perms-item .vc-info-icon {
+.vc-permviewer-modal-perms-item .vc-info-icon {
color: var(--interactive-muted);
+ margin-left: auto;
cursor: pointer;
- position: absolute;
- right: 0;
- scale: 0.9;
transition: color ease-in 0.1s;
}
-.vc-permviewer-perms-perms-item .vc-info-icon:hover {
+.vc-permviewer-modal-perms-item .vc-info-icon:hover {
color: var(--interactive-active);
}
@@ -167,3 +145,14 @@
background: rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-6));
border-color: var(--profile-body-border-color)
}
+
+.vc-permviewer-granted-by-container {
+ max-width: 300px;
+ width: auto;
+}
+
+.vc-permviewer-granted-by-content {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+}
diff --git a/src/webpack/common/types/components.d.ts b/src/webpack/common/types/components.d.ts
index 5dcc95194..0588d5e4c 100644
--- a/src/webpack/common/types/components.d.ts
+++ b/src/webpack/common/types/components.d.ts
@@ -459,7 +459,7 @@ export type ScrollerThin = ComponentType
Date: Mon, 2 Sep 2024 06:50:52 +0300
Subject: [PATCH 16/32] MutualGroupDMs: Add Mutual Groups to DM Sidebar (#2817)
---
src/plugins/mutualGroupDMs/index.tsx | 75 ++++++++++++++++++++--------
1 file changed, 53 insertions(+), 22 deletions(-)
diff --git a/src/plugins/mutualGroupDMs/index.tsx b/src/plugins/mutualGroupDMs/index.tsx
index a1e73cabf..ec52b4061 100644
--- a/src/plugins/mutualGroupDMs/index.tsx
+++ b/src/plugins/mutualGroupDMs/index.tsx
@@ -20,7 +20,7 @@ import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import { isNonNullish } from "@utils/guards";
import definePlugin from "@utils/types";
-import { findByPropsLazy } from "@webpack";
+import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
import { Avatar, ChannelStore, Clickable, IconUtils, RelationshipStore, ScrollerThin, useMemo, UserStore } from "@webpack/common";
import { Channel, User } from "discord-types/general";
@@ -28,6 +28,7 @@ const SelectedChannelActionCreators = findByPropsLazy("selectPrivateChannel");
const UserUtils = findByPropsLazy("getGlobalName");
const ProfileListClasses = findByPropsLazy("emptyIconFriends", "emptyIconGuilds");
+const ExpandableList = findComponentByCodeLazy(".mutualFriendItem]");
const GuildLabelClasses = findByPropsLazy("guildNick", "guildAvatarWithoutIcon");
function getGroupDMName(channel: Channel) {
@@ -50,6 +51,29 @@ function getMutualGDMCountText(user: User) {
return `${count === 0 ? "No" : count} Mutual Group${count !== 1 ? "s" : ""}`;
}
+function renderClickableGDMs(mutualDms: Channel[], onClose: () => void) {
+ return mutualDms.map(c => (
+ {
+ onClose();
+ SelectedChannelActionCreators.selectPrivateChannel(c.id);
+ }}
+ >
+
+
+
+
{getGroupDMName(c)}
+
{c.recipients.length + 1} Members
+
+
+ ));
+}
+
const IS_PATCHED = Symbol("MutualGroupDMs.Patched");
export default definePlugin({
@@ -70,6 +94,13 @@ export default definePlugin({
replace: "$1==='MUTUAL_GDMS'?$self.renderMutualGDMs(arguments[0]):$&"
}
]
+ },
+ {
+ find: 'section:"MUTUAL_FRIENDS"',
+ replacement: {
+ match: /\.openUserProfileModal.+?\)}\)}\)(?<=(\(0,\i\.jsxs?\)\(\i\.\i,{className:(\i)\.divider}\)).+?)/,
+ replace: "$&,$self.renderDMPageList({user: arguments[0].user, Divider: $1, listStyle: $2.list})"
+ }
}
],
@@ -84,28 +115,9 @@ export default definePlugin({
},
renderMutualGDMs: ErrorBoundary.wrap(({ user, onClose }: { user: User, onClose: () => void; }) => {
- const mutualDms = useMemo(() => getMutualGroupDms(user.id), [user.id]);
+ const mutualGDms = useMemo(() => getMutualGroupDms(user.id), [user.id]);
- const entries = mutualDms.map(c => (
- {
- onClose();
- SelectedChannelActionCreators.selectPrivateChannel(c.id);
- }}
- >
-
-
-
-
{getGroupDMName(c)}
-
{c.recipients.length + 1} Members
-
-
- ));
+ const entries = renderClickableGDMs(mutualGDms, onClose);
return (
);
+ }),
+
+ renderDMPageList: ErrorBoundary.wrap(({ user, Divider, listStyle }: { user: User, Divider: JSX.Element, listStyle: string; }) => {
+ const mutualGDms = getMutualGroupDms(user.id);
+ if (mutualGDms.length === 0) return null;
+
+ const header = getMutualGDMCountText(user);
+
+ return (
+ <>
+ {Divider}
+ { })}
+ />
+ >
+ );
})
});
From 27e81b20db23f09ca7334cc74bc5aee841cd6705 Mon Sep 17 00:00:00 2001
From: Maddie <52103563+maddie480@users.noreply.github.com>
Date: Mon, 2 Sep 2024 06:51:29 +0200
Subject: [PATCH 17/32] Allow online themes to be applied only in dark or light
mode (#2701)
---
src/components/VencordSettings/ThemesTab.tsx | 19 ++++++++++++++-----
src/plugins/clientTheme/index.tsx | 3 +--
src/utils/quickCss.ts | 15 ++++++++++++++-
src/webpack/common/stores.ts | 2 ++
src/webpack/common/types/stores.d.ts | 8 ++++++++
5 files changed, 39 insertions(+), 8 deletions(-)
diff --git a/src/components/VencordSettings/ThemesTab.tsx b/src/components/VencordSettings/ThemesTab.tsx
index bb9d37894..f718ab11f 100644
--- a/src/components/VencordSettings/ThemesTab.tsx
+++ b/src/components/VencordSettings/ThemesTab.tsx
@@ -77,8 +77,16 @@ function Validators({ themeLinks }: { themeLinks: string[]; }) {
Validator
This section will tell you whether your themes can successfully be loaded
- {themeLinks.map(link => (
- {
+ const { label, link } = (() => {
+ const match = /^@(light|dark) (.*)/.exec(rawLink);
+ if (!match) return { label: rawLink, link: rawLink };
+
+ const [, mode, link] = match;
+ return { label: `[${mode} mode only] ${link}`, link };
+ })();
+
+ return
- {link}
+ {label}
-
- ))}
+ ;
+ })}
>
);
@@ -296,6 +304,7 @@ function ThemesTab() {
Paste links to css files here
One link per line
+ You can prefix lines with @light or @dark to toggle them based on your Discord theme
Make sure to use direct links to files (raw or github.io)!
diff --git a/src/plugins/clientTheme/index.tsx b/src/plugins/clientTheme/index.tsx
index 358bae017..59f3d5fe2 100644
--- a/src/plugins/clientTheme/index.tsx
+++ b/src/plugins/clientTheme/index.tsx
@@ -12,7 +12,7 @@ import { Margins } from "@utils/margins";
import { classes } from "@utils/misc";
import definePlugin, { OptionType, StartAt } from "@utils/types";
import { findByCodeLazy, findComponentByCodeLazy, findStoreLazy } from "@webpack";
-import { Button, Forms, useStateFromStores } from "@webpack/common";
+import { Button, Forms, ThemeStore, useStateFromStores } from "@webpack/common";
const ColorPicker = findComponentByCodeLazy(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
@@ -36,7 +36,6 @@ function setTheme(theme: string) {
saveClientTheme({ theme });
}
-const ThemeStore = findStoreLazy("ThemeStore");
const NitroThemeStore = findStoreLazy("ClientThemesBackgroundStore");
function ThemeSettings() {
diff --git a/src/utils/quickCss.ts b/src/utils/quickCss.ts
index 99f06004c..6a18948d1 100644
--- a/src/utils/quickCss.ts
+++ b/src/utils/quickCss.ts
@@ -17,6 +17,7 @@
*/
import { Settings, SettingsStore } from "@api/Settings";
+import { ThemeStore } from "@webpack/common";
let style: HTMLStyleElement;
@@ -59,7 +60,18 @@ async function initThemes() {
const { themeLinks, enabledThemes } = Settings;
- const links: string[] = [...themeLinks];
+ // "darker" and "midnight" both count as dark
+ const activeTheme = ThemeStore.theme === "light" ? "light" : "dark";
+
+ const links = themeLinks
+ .map(rawLink => {
+ const match = /^@(light|dark) (.*)/.exec(rawLink);
+ if (!match) return rawLink;
+
+ const [, mode, link] = match;
+ return mode === activeTheme ? link : null;
+ })
+ .filter(link => link !== null);
if (IS_WEB) {
for (const theme of enabledThemes) {
@@ -85,6 +97,7 @@ document.addEventListener("DOMContentLoaded", () => {
SettingsStore.addChangeListener("themeLinks", initThemes);
SettingsStore.addChangeListener("enabledThemes", initThemes);
+ ThemeStore.addChangeListener(initThemes);
if (!IS_WEB)
VencordNative.quickCss.addThemeChangeListener(initThemes);
diff --git a/src/webpack/common/stores.ts b/src/webpack/common/stores.ts
index 74813357a..8579f8b92 100644
--- a/src/webpack/common/stores.ts
+++ b/src/webpack/common/stores.ts
@@ -53,6 +53,7 @@ export let RelationshipStore: Stores.RelationshipStore & t.FluxStore & {
};
export let EmojiStore: t.EmojiStore;
+export let ThemeStore: t.ThemeStore;
export let WindowStore: t.WindowStore;
export let DraftStore: t.DraftStore;
@@ -84,3 +85,4 @@ waitForStore("GuildChannelStore", m => GuildChannelStore = m);
waitForStore("MessageStore", m => MessageStore = m);
waitForStore("WindowStore", m => WindowStore = m);
waitForStore("EmojiStore", m => EmojiStore = m);
+waitForStore("ThemeStore", m => ThemeStore = m);
diff --git a/src/webpack/common/types/stores.d.ts b/src/webpack/common/types/stores.d.ts
index 037b2d81c..9ca7dfc94 100644
--- a/src/webpack/common/types/stores.d.ts
+++ b/src/webpack/common/types/stores.d.ts
@@ -220,6 +220,14 @@ export class GuildStore extends FluxStore {
getAllGuildRoles(): Record>;
}
+export class ThemeStore extends FluxStore {
+ theme: "light" | "dark" | "darker" | "midnight";
+ darkSidebar: boolean;
+ isSystemThemeAvailable: boolean;
+ systemPrefersColorScheme: "light" | "dark";
+ systemTheme: null;
+}
+
export type useStateFromStores = (
stores: t.FluxStore[],
mapper: () => T,
From accfc15125c5a611cb5835815a6e36d6bd4e8f89 Mon Sep 17 00:00:00 2001
From: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
Date: Mon, 2 Sep 2024 01:54:16 -0300
Subject: [PATCH 18/32] Ban ts-pattern normal import
---
scripts/build/common.mjs | 1 +
src/plugins/permissionsViewer/index.tsx | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/scripts/build/common.mjs b/scripts/build/common.mjs
index 247557e3c..e88f1e2b9 100644
--- a/scripts/build/common.mjs
+++ b/scripts/build/common.mjs
@@ -334,5 +334,6 @@ export const commonRendererPlugins = [
banImportPlugin(builtinModuleRegex, "Cannot import node inbuilt modules in browser code. You need to use a native.ts file"),
banImportPlugin(/^react$/, "Cannot import from react. React and hooks should be imported from @webpack/common"),
banImportPlugin(/^electron(\/.*)?$/, "Cannot import electron in browser code. You need to use a native.ts file"),
+ banImportPlugin(/^ts-pattern$/, "Cannot import from ts-pattern. match and P should be imported from @webpack/common"),
...commonOpts.plugins
];
diff --git a/src/plugins/permissionsViewer/index.tsx b/src/plugins/permissionsViewer/index.tsx
index 44dfd5f54..ca28f845f 100644
--- a/src/plugins/permissionsViewer/index.tsx
+++ b/src/plugins/permissionsViewer/index.tsx
@@ -73,7 +73,8 @@ function MenuItem(guildId: string, id?: string, type?: MenuItemParentType) {
action={() => {
const guild = GuildStore.getGuild(guildId);
- const { permissions, header }: { permissions: RoleOrUserPermission[], header: string; } = match(type)
+ const { permissions, header } = match(type)
+ .returnType<{ permissions: RoleOrUserPermission[], header: string; }>()
.with(MenuItemParentType.User, () => {
const member = GuildMemberStore.getMember(guildId, id!);
From c51d7b8fb4ea38f0ada2fe210f21263d2f2dd711 Mon Sep 17 00:00:00 2001
From: June Park
Date: Mon, 2 Sep 2024 17:09:45 +0900
Subject: [PATCH 19/32] ReviewDB: Fix wording in server reviews (#2826)
---
src/plugins/reviewDB/components/ReviewModal.tsx | 7 +++++--
src/plugins/reviewDB/components/ReviewsView.tsx | 9 ++++++---
src/plugins/reviewDB/index.tsx | 8 ++++----
3 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/src/plugins/reviewDB/components/ReviewModal.tsx b/src/plugins/reviewDB/components/ReviewModal.tsx
index e12a98acd..71ac021f0 100644
--- a/src/plugins/reviewDB/components/ReviewModal.tsx
+++ b/src/plugins/reviewDB/components/ReviewModal.tsx
@@ -22,12 +22,13 @@ import { useForceUpdater } from "@utils/react";
import { Paginator, Text, useRef, useState } from "@webpack/common";
import { Auth } from "../auth";
+import { ReviewType } from "../entities";
import { Response, REVIEWS_PER_PAGE } from "../reviewDbApi";
import { cl } from "../utils";
import ReviewComponent from "./ReviewComponent";
import ReviewsView, { ReviewsInputComponent } from "./ReviewsView";
-function Modal({ modalProps, modalKey, discordId, name }: { modalProps: any; modalKey: string, discordId: string; name: string; }) {
+function Modal({ modalProps, modalKey, discordId, name, type }: { modalProps: any; modalKey: string, discordId: string; name: string; type: ReviewType; }) {
const [data, setData] = useState();
const [signal, refetch] = useForceUpdater(true);
const [page, setPage] = useState(1);
@@ -58,6 +59,7 @@ function Modal({ modalProps, modalKey, discordId, name }: { modalProps: any; mod
onFetchReviews={setData}
scrollToTop={() => ref.current?.scrollTo({ top: 0, behavior: "smooth" })}
hideOwnReview
+ type={type}
/>
@@ -95,7 +97,7 @@ function Modal({ modalProps, modalKey, discordId, name }: { modalProps: any; mod
);
}
-export function openReviewsModal(discordId: string, name: string) {
+export function openReviewsModal(discordId: string, name: string, type: ReviewType) {
const modalKey = "vc-rdb-modal-" + Date.now();
openModal(props => (
@@ -104,6 +106,7 @@ export function openReviewsModal(discordId: string, name: string) {
modalProps={props}
discordId={discordId}
name={name}
+ type={type}
/>
), { modalKey });
}
diff --git a/src/plugins/reviewDB/components/ReviewsView.tsx b/src/plugins/reviewDB/components/ReviewsView.tsx
index 76a0be475..7a7d8d020 100644
--- a/src/plugins/reviewDB/components/ReviewsView.tsx
+++ b/src/plugins/reviewDB/components/ReviewsView.tsx
@@ -21,7 +21,7 @@ import { findByCodeLazy, findByPropsLazy, findComponentByCodeLazy } from "@webpa
import { Forms, React, RelationshipStore, useRef, UserStore } from "@webpack/common";
import { Auth, authorize } from "../auth";
-import { Review } from "../entities";
+import { Review, ReviewType } from "../entities";
import { addReview, getReviews, Response, REVIEWS_PER_PAGE } from "../reviewDbApi";
import { settings } from "../settings";
import { cl, showToast } from "../utils";
@@ -45,6 +45,7 @@ interface Props extends UserProps {
page?: number;
scrollToTop?(): void;
hideOwnReview?: boolean;
+ type: ReviewType;
}
export default function ReviewsView({
@@ -56,6 +57,7 @@ export default function ReviewsView({
page = 1,
showInput = false,
hideOwnReview = false,
+ type,
}: Props) {
const [signal, refetch] = useForceUpdater(true);
@@ -80,6 +82,7 @@ export default function ReviewsView({
reviews={reviewData!.reviews}
hideOwnReview={hideOwnReview}
profileId={discordId}
+ type={type}
/>
{showInput && (
@@ -94,7 +97,7 @@ export default function ReviewsView({
);
}
-function ReviewList({ refetch, reviews, hideOwnReview, profileId }: { refetch(): void; reviews: Review[]; hideOwnReview: boolean; profileId: string; }) {
+function ReviewList({ refetch, reviews, hideOwnReview, profileId, type }: { refetch(): void; reviews: Review[]; hideOwnReview: boolean; profileId: string; type: ReviewType; }) {
const myId = UserStore.getCurrentUser().id;
return (
@@ -111,7 +114,7 @@ function ReviewList({ refetch, reviews, hideOwnReview, profileId }: { refetch():
{reviews?.length === 0 && (
- Looks like nobody reviewed this user yet. You could be the first!
+ Looks like nobody reviewed this {type === ReviewType.User ? "user" : "server"} yet. You could be the first!
)}
diff --git a/src/plugins/reviewDB/index.tsx b/src/plugins/reviewDB/index.tsx
index caf9bacba..1164a2c5b 100644
--- a/src/plugins/reviewDB/index.tsx
+++ b/src/plugins/reviewDB/index.tsx
@@ -30,7 +30,7 @@ import { Guild, User } from "discord-types/general";
import { Auth, initAuth, updateAuth } from "./auth";
import { openReviewsModal } from "./components/ReviewModal";
-import { NotificationType } from "./entities";
+import { NotificationType, ReviewType } from "./entities";
import { getCurrentUserInfo, readNotification } from "./reviewDbApi";
import { settings } from "./settings";
import { showToast } from "./utils";
@@ -44,7 +44,7 @@ const guildPopoutPatch: NavContextMenuPatchCallback = (children, { guild }: { gu
label="View Reviews"
id="vc-rdb-server-reviews"
icon={OpenExternalIcon}
- action={() => openReviewsModal(guild.id, guild.name)}
+ action={() => openReviewsModal(guild.id, guild.name, ReviewType.Server)}
/>
);
};
@@ -56,7 +56,7 @@ const userContextPatch: NavContextMenuPatchCallback = (children, { user }: { use
label="View Reviews"
id="vc-rdb-user-reviews"
icon={OpenExternalIcon}
- action={() => openReviewsModal(user.id, user.username)}
+ action={() => openReviewsModal(user.id, user.username, ReviewType.User)}
/>
);
};
@@ -157,7 +157,7 @@ export default definePlugin({
return (
)
}
-
-
+
);
}, { noop: true }),
});
From 244cb26c328828503835c680fa294917cb7d5f9b Mon Sep 17 00:00:00 2001
From: ElectricSteve <96793824+electricsteve@users.noreply.github.com>
Date: Wed, 4 Sep 2024 14:00:49 +0200
Subject: [PATCH 25/32] Dearrow: Add option to not dearrow by default (#2818)
---
src/plugins/dearrow/index.tsx | 25 ++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/src/plugins/dearrow/index.tsx b/src/plugins/dearrow/index.tsx
index 5fb438256..10175c846 100644
--- a/src/plugins/dearrow/index.tsx
+++ b/src/plugins/dearrow/index.tsx
@@ -46,7 +46,7 @@ const embedUrlRe = /https:\/\/www\.youtube\.com\/embed\/([a-zA-Z0-9_-]{11})/;
async function embedDidMount(this: Component