Merge remote-tracking branch 'upstream/dev' into dev

This commit is contained in:
thororen1234 2025-08-06 08:43:29 -04:00
commit c79d6e110b
No known key found for this signature in database
33 changed files with 207 additions and 296 deletions

View file

@ -20,4 +20,8 @@
}
],
"equicord-companion.showSidebar": true,
"css.format.spaceAroundSelectorSeparator": true,
"[css]": {
"editor.defaultFormatter": "vscode.css-language-features"
}
}

View file

@ -476,19 +476,66 @@ export type MaskedLink = ComponentType<PropsWithChildren<{
channelId?: string;
}>>;
export type ScrollerThin = ComponentType<PropsWithChildren<{
export interface ScrollerBaseProps {
className?: string;
style?: CSSProperties;
dir?: "ltr";
orientation?: "horizontal" | "vertical" | "auto";
paddingFix?: boolean;
fade?: boolean;
onClose?(): void;
onScroll?(): void;
}
export type ScrollerThin = ComponentType<PropsWithChildren<ScrollerBaseProps & {
orientation?: "horizontal" | "vertical" | "auto";
fade?: boolean;
}>>;
interface BaseListItem {
anchorId: any;
listIndex: number;
offsetTop: number;
section: number;
}
interface ListSection extends BaseListItem {
type: "section";
}
interface ListRow extends BaseListItem {
type: "row";
row: number;
rowIndex: number;
}
export type ListScrollerThin = ComponentType<ScrollerBaseProps & {
sections: number[];
renderSection?: (item: ListSection) => React.ReactNode;
renderRow: (item: ListRow) => React.ReactNode;
renderFooter?: (item: any) => React.ReactNode;
renderSidebar?: (listVisible: boolean, sidebarVisible: boolean) => React.ReactNode;
wrapSection?: (section: number, children: React.ReactNode) => React.ReactNode;
sectionHeight: number;
rowHeight: number;
footerHeight?: number;
sidebarHeight?: number;
chunkSize?: number;
paddingTop?: number;
paddingBottom?: number;
fade?: boolean;
onResize?: Function;
getAnchorId?: any;
innerTag?: string;
innerId?: string;
innerClassName?: string;
innerRole?: string;
innerAriaLabel?: string;
// Yes, Discord uses this casing
innerAriaMultiselectable?: boolean;
innerAriaOrientation?: "vertical" | "horizontal";
}>;
export type Clickable = <T extends "a" | "div" | "span" | "li" = "div">(props: PropsWithChildren<ComponentPropsWithRef<T>> & {
tag?: T;
}) => ReactNode;

View file

@ -104,9 +104,7 @@ export default ErrorBoundary.wrap(function NotificationComponent({
</svg>
</button>
</div>
<div>
{richBody ?? <p className="vc-notification-p">{body}</p>}
</div>
{richBody ?? <p className="vc-notification-p">{body}</p>}
</div>
</div>
{image && <img className="vc-notification-img" src={image} alt="" />}

View file

@ -21,9 +21,9 @@ import { Settings } from "@api/Settings";
import { classNameFactory } from "@api/Styles";
import { Flex } from "@components/Flex";
import { openNotificationSettingsModal } from "@components/settings/tabs/vencord/NotificationSettings";
import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { closeModal, ModalCloseButton, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { useAwaiter } from "@utils/react";
import { Alerts, Button, Forms, React, Text, Timestamp, useEffect, useReducer, useState } from "@webpack/common";
import { Alerts, Button, Forms, ListScrollerThin, React, Text, Timestamp, useEffect, useReducer, useState } from "@webpack/common";
import { nanoid } from "nanoid";
import type { DispatchWithoutAction } from "react";
@ -103,21 +103,9 @@ export function useLogs() {
function NotificationEntry({ data }: { data: PersistentNotificationData; }) {
const [removing, setRemoving] = useState(false);
const ref = React.useRef<HTMLDivElement>(null);
useEffect(() => {
const div = ref.current!;
const setHeight = () => {
if (div.clientHeight === 0) return requestAnimationFrame(setHeight);
div.style.height = `${div.clientHeight}px`;
};
setHeight();
}, []);
return (
<div className={cl("wrapper", { removing })} ref={ref}>
<div className={cl("wrapper", { removing })}>
<NotificationComponent
{...data}
permanent={true}
@ -129,13 +117,13 @@ function NotificationEntry({ data }: { data: PersistentNotificationData; }) {
setTimeout(() => deleteNotification(data.timestamp), 200);
}}
richBody={
<div className={cl("body")}>
{data.body}
<div className={cl("body-wrapper")}>
<div className={cl("body")}>{data.body}</div>
<Timestamp timestamp={new Date(data.timestamp)} className={cl("timestamp")} />
</div>
}
/>
</div>
</div >
);
}
@ -151,9 +139,14 @@ export function NotificationLog({ log, pending }: { log: PersistentNotificationD
);
return (
<div className={cl("container")}>
{log.map(n => <NotificationEntry data={n} key={n.id} />)}
</div>
<ListScrollerThin
className={cl("container")}
sections={[log.length]}
sectionHeight={0}
rowHeight={120}
renderSection={() => null}
renderRow={item => <NotificationEntry data={log[item.row]} key={log[item.row].id} />}
/>
);
}
@ -161,15 +154,15 @@ function LogModal({ modalProps, close }: { modalProps: ModalProps; close(): void
const [log, pending] = useLogs();
return (
<ModalRoot {...modalProps} size={ModalSize.LARGE}>
<ModalRoot {...modalProps} size={ModalSize.LARGE} className={cl("modal")}>
<ModalHeader>
<Text variant="heading-lg/semibold" style={{ flexGrow: 1 }}>Notification Log</Text>
<ModalCloseButton onClick={close} />
</ModalHeader>
<ModalContent>
<div style={{ width: "100%" }}>
<NotificationLog log={log} pending={pending} />
</ModalContent>
</div>
<ModalFooter>
<Flex>

View file

@ -4,17 +4,13 @@
display: flex;
flex-direction: column;
color: var(--text-default);
background-color: var(--background-base-lower-alt);
background-color: var(--background-base-low);
border-radius: 6px;
overflow: hidden;
cursor: pointer;
width: 100%;
}
.visual-refresh .vc-notification-root {
background-color: var(--background-base-low);
}
.vc-notification-root:not(.vc-notification-log-wrapper > .vc-notification-root) {
position: absolute;
z-index: 2147483647;
@ -32,6 +28,7 @@
.vc-notification-content {
width: 100%;
overflow: hidden;
}
.vc-notification-header {
@ -81,6 +78,11 @@
width: 100%;
}
.vc-notification-log-modal {
max-width: 962px;
width: clamp(var(--modal-width-large, 800px), 962px, 85vw);
}
.vc-notification-log-empty {
height: 218px;
background: url("/assets/b36de980b174d7b798c89f35c116e5c6.svg") center no-repeat;
@ -88,19 +90,23 @@
}
.vc-notification-log-container {
display: flex;
flex-direction: column;
padding: 1em;
overflow: hidden;
max-height: min(750px, 75vh);
width: 100%;
}
.vc-notification-log-wrapper {
height: 120px;
width: 100%;
padding-bottom: 16px;
box-sizing: border-box;
transition: 200ms ease;
transition-property: height, opacity;
}
.vc-notification-log-wrapper:not(:last-child) {
margin-bottom: 1em;
/* stylelint-disable-next-line no-descending-specificity */
.vc-notification-root {
height: 104px;
}
}
.vc-notification-log-removing {
@ -109,9 +115,18 @@
margin-bottom: 1em;
}
.vc-notification-log-body {
.vc-notification-log-body-wrapper {
display: flex;
flex-direction: column;
width: 100%;
box-sizing: border-box;
}
.vc-notification-log-body {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
line-height: 1.2em;
}
.vc-notification-log-timestamp {

View file

@ -18,7 +18,6 @@
import { React, TextInput } from "@webpack/common";
// TODO: Refactor settings to use this as well
interface TextInputProps {
/**
* WARNING: Changing this between renders will have no effect!

View file

@ -1,6 +1,7 @@
.vc-addon-card {
background-color: var(--background-base-lower-alt);
background-color: var(--card-primary-bg);
color: var(--interactive-active);
border: 1px solid var(--border-subtle);
border-radius: 8px;
display: block;
height: 100%;
@ -11,26 +12,15 @@
box-sizing: border-box;
}
.visual-refresh .vc-addon-card {
background-color: var(--card-primary-bg);
border: 1px solid var(--border-subtle);
}
.vc-addon-card-disabled {
opacity: 0.6;
}
.vc-addon-card:hover {
background-color: var(--background-tertiary);
transform: translateY(-1px);
box-shadow: var(--elevation-high);
}
.visual-refresh .vc-addon-card:hover {
/* same as non-hover, here to overwrite the non-refresh hover background */
background-color: var(--card-primary-bg);
}
.vc-addon-header {
margin-top: auto;
display: flex;

View file

@ -14,7 +14,7 @@
.vc-settings-quickActions-pill {
all: unset;
background: var(--background-base-lower);
background: var(--button-secondary-background);
color: var(--header-secondary);
display: flex;
align-items: center;
@ -26,7 +26,7 @@
}
.vc-settings-quickActions-pill:hover {
background: var(--background-base-lower-alt);
background: var(--button-secondary-background-hover);
transform: translateY(-1px);
box-shadow: var(--elevation-high);
}
@ -36,14 +36,6 @@
outline-offset: 2px;
}
.visual-refresh .vc-settings-quickActions-pill {
background: var(--button-secondary-background);
}
.visual-refresh .vc-settings-quickActions-pill:hover {
background: var(--button-secondary-background-hover);
}
.vc-settings-quickActions-img {
width: 24px;
height: 24px;

View file

@ -11,7 +11,7 @@
.vc-author-modal-name {
text-transform: none;
flex-grow: 0;
background: var(--background-tertiary);
background: var(--background-base-lowest);
border-radius: 0 9999px 9999px 0;
padding: 6px 0.8em 6px 0.5em;
font-size: 20px;
@ -26,7 +26,7 @@
position: absolute;
height: 100%;
width: 32px;
background: var(--background-tertiary);
background: var(--background-base-lowest);
z-index: -1;
left: -32px;
top: 0;

View file

@ -2,7 +2,7 @@
height: 32px;
width: 32px;
border-radius: 50%;
border: 4px solid var(--background-tertiary);
border: 4px solid var(--background-base-lowest);
box-sizing: border-box
}

View file

@ -65,7 +65,7 @@
}
.vc-settings-theme-links:focus {
background-color: var(--background-tertiary);
background-color: var(--background-base-lowest);
}
.vc-cloud-settings-sync-grid {

View file

@ -16,11 +16,8 @@ export default definePlugin({
{
find: '"sticker")',
replacement: {
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /return\((!)?\i\.\i(?:\|\||&&)(?=\(.+?(\i)\.push)/,
replace: (m, not, children) => not
? `${m}(Vencord.Api.ChatButtons._injectButtons(${children},arguments[0]),true)&&`
: `${m}(Vencord.Api.ChatButtons._injectButtons(${children},arguments[0]),false)||`
match: /return\(\i\.\i\|\|(?=\(.+?(\i)\.push)/,
replace: "$&(Vencord.Api.ChatButtons._injectButtons($1,arguments[0]),false)||"
}
}
]

View file

@ -60,8 +60,7 @@ export default definePlugin({
replace: (_, sectionTypes, commaOrSemi, elements, element) => `${commaOrSemi} $self.addSettings(${elements}, ${element}, ${sectionTypes}) ${commaOrSemi}`
},
{
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /({(?=.+?function (\i).{0,160}(\i)=\i\.useMemo.{0,140}return \i\.useMemo\(\(\)=>\i\(\3).+?(?:function\(\){return |\(\)=>))\2/,
match: /({(?=.+?function (\i).{0,160}(\i)=\i\.useMemo.{0,140}return \i\.useMemo\(\(\)=>\i\(\3).+?\(\)=>)\2/,
replace: (_, rest, settingsHook) => `${rest}$self.wrapSettingsHook(${settingsHook})`
}
]

View file

@ -3,7 +3,7 @@
}
/* These area names need to be hardcoded. Only betterFoldersSidebar is added by the plugin. */
.visual-refresh .vc-betterFolders-sidebar-grid {
.vc-betterFolders-sidebar-grid {
/* stylelint-disable-next-line value-keyword-case */
grid-template-columns: [start] min-content [guildsEnd] min-content [sidebarEnd] min-content [channelsEnd] 1fr [end];
grid-template-areas:

View file

@ -75,8 +75,8 @@ function createColorsOverrides(styles: string) {
const darkThemeBaseLightness = visualRefreshColorsLightness["--neutral-69-hsl"];
createOrUpdateStyle(OVERRIDES_STYLE_ID, [
`.visual-refresh.theme-light {\n ${generateNewColorVars(visualRefreshColorsLightness, lightThemeBaseLightness)} \n}`,
`.visual-refresh.theme-dark {\n ${generateNewColorVars(visualRefreshColorsLightness, darkThemeBaseLightness)} \n}`,
`.theme-light {\n ${generateNewColorVars(visualRefreshColorsLightness, lightThemeBaseLightness)} \n}`,
`.theme-dark {\n ${generateNewColorVars(visualRefreshColorsLightness, darkThemeBaseLightness)} \n}`,
].join("\n\n"));
}

View file

@ -44,9 +44,8 @@ export default definePlugin({
{
find: ".selectPreviousCommandOption(",
replacement: {
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /(?<=(\i)\.which(?:!==|===)\i\.\i.ENTER(\|\||&&)).{0,100}(\(0,\i\.\i\)\(\i\)).{0,100}(?=(?:\|\||&&)\(\i\.preventDefault)/,
replace: (_, event, condition, codeblock) => `${condition === "||" ? "!" : ""}$self.shouldSubmit(${event},${codeblock})`
match: /(?<=(\i)\.which!==\i\.\i.ENTER\|\|).{0,100}(\(0,\i\.\i\)\(\i\)).{0,100}(?=\|\|\(\i\.preventDefault)/,
replace: "!$self.shouldSubmit($1,$2)"
}
},
{

View file

@ -257,11 +257,8 @@ export default definePlugin({
},
{
// Disallow the emoji for premium locked if the intention doesn't allow it
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /(!)?(\i\.\i\.canUseEmojisEverywhere\(\i\))/,
replace: (m, not) => not
? `(${m}&&!${IS_BYPASSEABLE_INTENTION})`
: `(${m}||${IS_BYPASSEABLE_INTENTION})`
match: /!(\i\.\i\.canUseEmojisEverywhere\(\i\))/,
replace: m => `(${m}&&!${IS_BYPASSEABLE_INTENTION})`
},
{
// Allow animated emojis to be used if the intention allows it

View file

@ -75,8 +75,8 @@ export default definePlugin({
{
find: "#{intl::GUILD_OWNER}),children:",
replacement: {
match: /(?<=roleName:\i,)(colorString:)/,
replace: "$1$self.calculateNameColorForListContext(arguments[0]),originalColor:"
match: /(?<=roleName:\i,)colorString:/,
replace: "colorString:$self.calculateNameColorForListContext(arguments[0]),originalColor:"
},
predicate: () => settings.store.memberListColors
}

View file

@ -17,7 +17,6 @@
*/
import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, registerCommand, sendBotMessage, unregisterCommand } from "@api/Commands";
import * as DataStore from "@api/DataStore";
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
@ -90,14 +89,6 @@ export default definePlugin({
settings,
async start() {
// TODO(OptionType.CUSTOM Related): Remove DataStore tags migration once enough time has passed
const oldTags = await DataStore.get<Tag[]>(DATA_KEY);
if (oldTags != null) {
// @ts-expect-error
settings.store.tagsList = Object.fromEntries(oldTags.map(oldTag => (delete oldTag.enabled, [oldTag.name, oldTag])));
await DataStore.del(DATA_KEY);
}
const tags = getTags();
for (const tagName in tags) {
createTagCommand(tags[tagName]);

View file

@ -100,9 +100,8 @@ export default definePlugin({
replace: "true"
},
{
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /(!)?\(0,\i\.isDesktop\)\(\)/,
replace: (_, not) => not ? "false" : "true"
match: /\(0,\i\.isDesktop\)\(\)/,
replace: "true"
}
]
},

View file

@ -46,9 +46,8 @@ export default definePlugin({
find: "#{intl::ONBOARDING_CHANNEL_THRESHOLD_WARNING}",
replacement: [
{
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /{(?:\i:(?:function\(\){return |\(\)=>)\i}?,?){2}}/,
replace: m => m.replaceAll(canonicalizeMatch(/(function\(\){return |\(\)=>)\i/g), "$1()=>Promise.resolve(true)")
match: /{(?:\i:\(\)=>\i,?){2}}/,
replace: m => m.replaceAll(canonicalizeMatch(/\(\)=>\i/g), "()=>Promise.resolve(true)")
}
],
predicate: () => settings.store.onboarding

View file

@ -29,7 +29,7 @@ export const { getGuildPermissionSpecMap } = findByPropsLazy("getGuildPermission
export const cl = classNameFactory("vc-permviewer-");
export function getSortedRolesForMember({ id: guildId }: Guild, member: GuildMember) {
// the guild id is the @everyone role
// The guild id is the @everyone role
return GuildRoleStore
.getSortedRoles(guildId)
.filter(role => role.id === guildId || member.roles.includes(role.id));

View file

@ -4,8 +4,6 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import * as DataStore from "@api/DataStore";
import { Settings } from "@api/Settings";
import { useForceUpdater } from "@utils/react";
import { UserStore } from "@webpack/common";
@ -28,8 +26,6 @@ let forceUpdateDms: (() => void) | undefined = undefined;
export let currentUserCategories: Category[] = [];
export async function init() {
await migrateData();
const userId = UserStore.getCurrentUser()?.id;
if (userId == null) return;
@ -154,28 +150,3 @@ export function moveChannel(channelId: string, direction: -1 | 1) {
swapElementsInArray(category.channels, a, b);
}
// TODO(OptionType.CUSTOM Related): Remove DataStore PinnedDms migration once enough time has passed
async function migrateData() {
if (Settings.plugins.PinDMs.dmSectioncollapsed != null) {
settings.store.dmSectionCollapsed = Settings.plugins.PinDMs.dmSectioncollapsed;
delete Settings.plugins.PinDMs.dmSectioncollapsed;
}
const dataStoreKeys = await DataStore.keys();
const pinDmsKeys = dataStoreKeys.map(key => String(key)).filter(key => key.startsWith(CATEGORY_BASE_KEY));
if (pinDmsKeys.length === 0) return;
for (const pinDmsKey of pinDmsKeys) {
const categories = await DataStore.get<Category[]>(pinDmsKey);
if (categories == null) continue;
const userId = pinDmsKey.replace(CATEGORY_BASE_KEY, "");
settings.store.userBasedCategoryList[userId] = categories;
await DataStore.del(pinDmsKey);
}
await Promise.all([DataStore.del(CATEGORY_MIGRATED_PINDMS_KEY), DataStore.del(CATEGORY_MIGRATED_KEY), DataStore.del(OLD_CATEGORY_KEY)]);
}

View file

@ -126,11 +126,8 @@ export default definePlugin({
},
{
// Prevent Discord from trying to connect to hidden voice channels
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /(?=(\|\||&&)\i\.\i\.selectVoiceChannel\((\i)\.id\))/,
replace: (_, condition, channel) => condition === "||"
? `||$self.isHiddenChannel(${channel})`
: `&&!$self.isHiddenChannel(${channel})`
match: /(?=\|\|\i\.\i\.selectVoiceChannel\((\i)\.id\))/,
replace: (_, channel) => `||$self.isHiddenChannel(${channel})`
},
{
// Make Discord show inside the channel if clicking on a hidden or locked channel
@ -143,11 +140,8 @@ export default definePlugin({
{
find: ".AUDIENCE),{isSubscriptionGated",
replacement: {
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /(!)?(\i)\.isRoleSubscriptionTemplatePreviewChannel\(\)/,
replace: (m, not, channel) => not
? `${m}&&!$self.isHiddenChannel(${channel})`
: `${m}||$self.isHiddenChannel(${channel})`
match: /(\i)\.isRoleSubscriptionTemplatePreviewChannel\(\)/,
replace: (m, channel) => `${m}||$self.isHiddenChannel(${channel})`
}
},
{
@ -210,18 +204,8 @@ export default definePlugin({
},
// Make voice channels also appear as muted if they are muted
{
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /(?<=\.wrapper:\i\.notInteractive,)(.+?)(if\()?(\i)(?:\)return |\?)(\i\.MUTED)/,
replace: (_, otherClasses, isIf, isMuted, mutedClassExpression) => isIf
? `${isMuted}?${mutedClassExpression}:"",${otherClasses}if(${isMuted})return ""`
: `${isMuted}?${mutedClassExpression}:"",${otherClasses}${isMuted}?""`
},
{
// Make muted channels also appear as unread if hide unreads is false and the channel is hidden
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
predicate: () => settings.store.channelStyle === ChannelStyle.MutedUnread || settings.store.channelStyle === ChannelStyle.Unread,
match: /(?<=\.LOCKED(?:;if\(|:))(?<={channel:(\i).+?)/,
replace: (_, channel) => `!$self.isHiddenChannel(${channel})&&`
match: /(?<=\.wrapper:\i\.notInteractive,)(.+?)if\((\i)(?:\)return |\?)(\i\.MUTED)/,
replace: (_, otherClasses, isMuted, mutedClassExpression) => `${isMuted}?${mutedClassExpression}:"",${otherClasses}if(${isMuted})return ""`
}
]
},
@ -230,8 +214,7 @@ export default definePlugin({
predicate: () => settings.store.channelStyle !== ChannelStyle.Unread && settings.store.channelStyle !== ChannelStyle.MutedUnread,
replacement: [
{
// FIXME(Bundler change related): Remove old compatiblity once enough time has passed
match: /(?<=\.LOCKED(?:;if\(|:))(?<={channel:(\i).+?)/,
match: /(?<=\.LOCKED;if\()(?<={channel:(\i).+?)/,
replace: (_, channel) => `!$self.isHiddenChannel(${channel})&&`
},
{
@ -324,8 +307,8 @@ export default definePlugin({
replacement: [
{
// Change the role permission check to CONNECT if the channel is locked
match: /\i\.\i\(\i\.\i\.ADMINISTRATOR,\i\.\i\.VIEW_CHANNEL\)(?<=context:(\i)}.+?)/,
replace: (m, channel) => `$self.fixPermCheck(${m},${channel})`
match: /(forceRoles:.+?)(\i\.\i\(\i\.\i\.ADMINISTRATOR,\i\.\i\.VIEW_CHANNEL\))(?<=context:(\i)}.+?)/,
replace: (_, rest, mergedPermissions, channel) => `${rest}$self.swapViewChannelWithConnectPermission(${mergedPermissions},${channel})`
},
{
// Change the permissionOverwrite check to CONNECT if the channel is locked
@ -335,7 +318,7 @@ export default definePlugin({
{
// Include the @everyone role in the allowed roles list for Hidden Channels
match: /getSortedRoles.+?\.filter\(\i=>(?=!)/,
replace: m => `${m}$self.isHiddenChannel(arguments[0].channel)?true:`
replace: m => `${m}$self.isHiddenChannel(arguments[0]?.channel)?true:`
},
{
// If the @everyone role has the required permissions, make the array only contain it
@ -519,13 +502,13 @@ export default definePlugin({
],
fixPermCheck(originalPerms: bigint, channel: Channel) {
swapViewChannelWithConnectPermission(mergedPermissions: bigint, channel: Channel) {
if (!PermissionStore.can(PermissionsBits.CONNECT, channel)) {
originalPerms &= ~PermissionsBits.VIEW_CHANNEL;
originalPerms |= PermissionsBits.CONNECT;
mergedPermissions &= ~PermissionsBits.VIEW_CHANNEL;
mergedPermissions |= PermissionsBits.CONNECT;
}
return originalPerms;
return mergedPermissions;
},
isHiddenChannel(channel: Channel & { channelId?: string; }, checkConnect = false) {

View file

@ -72,8 +72,8 @@ export default definePlugin({
find: "#{intl::GUILD_MEMBER_MOD_VIEW_PERMISSION_GRANTED_BY_ARIA_LABEL}),allowOverflow:",
predicate: () => settings.store.showModView,
replacement: {
match: /(role:)\i(?<=\i\.roles,\i\.highestRoleId,(\i)\].+)/,
replace: "$1$self.findHighestRole(arguments[0],$2)",
match: /(?<=\.highestRole\),)role:\i(?<=\[\i\.roles,\i\.highestRoleId,(\i)\].+)/,
replace: "role:$self.getHighestRole(arguments[0],$2)",
}
},
// allows you to open mod view on yourself
@ -87,7 +87,7 @@ export default definePlugin({
}
],
findHighestRole({ member }: { member: GuildMember; }, roles: Role[]): Role | undefined {
getHighestRole({ member }: { member: GuildMember; }, roles: Role[]): Role | undefined {
try {
return roles.find(role => role.id === member.highestRoleId);
} catch (e) {

View file

@ -17,7 +17,6 @@
*/
import "./spotifyStyles.css";
import "./visualRefreshSpotifyStyles.css"; // TODO: merge with spotifyStyles.css and remove when old UI is discontinued
import { Settings } from "@api/Settings";
import { classNameFactory } from "@api/Styles";

View file

@ -1,10 +1,13 @@
#vc-spotify-player {
padding: 0.375rem 0.5rem;
padding: 12px;
background: var(--bg-overlay-floating, var(--background-base-low, var(--background-base-lower-alt)));
margin: 0;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
border-bottom: 1px solid var(--border-subtle);
--vc-spotify-green: var(--spotify, #1db954);
/* so custom themes can easily change it */
--vc-spotify-green: var(--spotify, #1db954);
--vc-spotify-green-90: color-mix(in hsl, var(--vc-spotify-green), transparent 90%);
--vc-spotify-green-80: color-mix(in hsl, var(--vc-spotify-green), transparent 80%);
}
@ -18,12 +21,13 @@
}
.vc-spotify-button {
margin: 0 2px;
border-radius: var(--radius-sm);
background: none;
color: var(--interactive-normal);
padding: 0;
width: 32px;
height: 32px;
border-radius: 100%;
display: flex;
justify-content: center;
align-items: center;
@ -49,13 +53,16 @@
filter: brightness(1.3);
} */
.vc-spotify-shuffle-on,
.vc-spotify-repeat-context,
.vc-spotify-repeat-track,
.vc-spotify-shuffle-on:hover,
.vc-spotify-shuffle-on {
background-color: var(--vc-spotify-green-90);
}
.vc-spotify-repeat-context:hover,
.vc-spotify-repeat-track:hover {
color: var(--vc-spotify-green);
.vc-spotify-repeat-track:hover,
.vc-spotify-shuffle-on:hover {
background-color: var(--vc-spotify-green-80);
}
.vc-spotify-tooltip-text {
@ -76,6 +83,15 @@
.vc-spotify-button-row {
justify-content: center;
margin-top: 14px;
}
.vc-spotify-secondary-song-info {
font-size: 12px;
}
.vc-spotify-song-info-prefix {
display: none;
}
#vc-spotify-info-wrapper {
@ -129,7 +145,7 @@
.vc-spotify-album {
font-size: 12px;
text-decoration: none;
color: var(--header-secondary);
color: var(--header-primary);
}
.vc-spotify-comma {
@ -157,16 +173,26 @@
padding: 0 !important;
}
#vc-spotify-progress-bar>[class^="slider"] [class^="bar-"] {
height: 4px !important;
#vc-spotify-progress-bar > [class^="slider"] [class^="bar"] {
height: 3px !important;
top: calc(12px - 4px / 2 + var(--bar-offset));
}
#vc-spotify-progress-bar > [class^="slider"] [class^="barFill"] {
background-color: var(--interactive-active);
}
#vc-spotify-progress-bar > [class^="slider"]:hover [class^="barFill"] {
background-color: var(--vc-spotify-green);
}
#vc-spotify-progress-bar>[class^="slider"] [class^="grabber"] {
/* these importants are necessary, it applies a width and height through inline styles */
height: 10px !important;
width: 10px !important;
margin-top: 4px;
background-color: var(--interactive-normal);
height: 16px !important;
width: 16px !important;
margin-top: calc(17px/-2 + var(--bar-offset)/2);
margin-left: -0.5px;
background-color: var(--interactive-active);
border-color: var(--interactive-normal);
color: var(--interactive-normal);
opacity: 0;
@ -185,6 +211,8 @@
font-size: 12px;
top: 10px;
position: absolute;
margin-top: 8px;
font-family: var(--font-code);
}
.vc-spotify-time-left {

View file

@ -1,82 +0,0 @@
/* TODO: merge with spotifyStyles.css and remove when old UI is discontinued */
.visual-refresh {
#vc-spotify-player {
padding: 12px;
background: var(--bg-overlay-floating, var(--background-base-low, var(--background-base-lower-alt)));
margin: 0;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
}
.vc-spotify-song-info-prefix {
display: none;
}
.vc-spotify-artist,
.vc-spotify-album {
color: var(--header-primary);
}
.vc-spotify-secondary-song-info {
font-size: 12px;
}
#vc-spotify-progress-bar {
position: relative;
color: var(--text-default);
width: 100%;
}
#vc-spotify-progress-bar>[class^="slider"] {
flex-grow: 1;
width: 100%;
padding: 0 !important;
}
#vc-spotify-progress-bar>[class^="slider"] [class^="bar"] {
height: 3px !important;
top: calc(12px - 4px / 2 + var(--bar-offset));
}
#vc-spotify-progress-bar>[class^="slider"] [class^="barFill"] {
background-color: var(--interactive-active);
}
#vc-spotify-progress-bar>[class^="slider"]:hover [class^="barFill"] {
background-color: var(--vc-spotify-green);
}
#vc-spotify-progress-bar>[class^="slider"] [class^="grabber"] {
background-color: var(--interactive-active);
width: 16px !important;
height: 16px !important;
margin-top: calc(17px/-2 + var(--bar-offset)/2);
margin-left: -0.5px;
}
.vc-spotify-progress-time {
margin-top: 8px;
font-family: var(--font-code);
}
.vc-spotify-button-row {
margin-top: 14px;
}
.vc-spotify-button {
margin: 0 2px;
border-radius: var(--radius-sm);
}
.vc-spotify-repeat-context,
.vc-spotify-repeat-track,
.vc-spotify-shuffle-on {
background-color: var(--vc-spotify-green-90);
}
.vc-spotify-repeat-context:hover,
.vc-spotify-repeat-track:hover,
.vc-spotify-shuffle-on:hover {
background-color: var(--vc-spotify-green-80);
}
}

View file

@ -25,6 +25,7 @@ export default definePlugin({
name: "StartupTimings",
description: "Adds Startup Timings to the Settings menu",
authors: [Devs.Megu],
patches: [{
find: "#{intl::ACTIVITY_SETTINGS}",
replacement: [
@ -36,5 +37,6 @@ export default definePlugin({
},
]
}],
StartupTimingPage
});

View file

@ -16,7 +16,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { DataStore } from "@api/index";
import { definePluginSettings } from "@api/Settings";
import { Flex } from "@components/Flex";
import { DeleteIcon } from "@components/Icons";
@ -243,20 +242,5 @@ export default definePlugin({
// Channel used for sharing rules, applying rules here would be messy
if (channelId === TEXT_REPLACE_RULES_CHANNEL_ID) return;
msg.content = applyRules(msg.content);
},
async start() {
// TODO(OptionType.CUSTOM Related): Remove DataStore rules migrations once enough time has passed
const oldStringRules = await DataStore.get<Rule[]>(STRING_RULES_KEY);
if (oldStringRules != null) {
settings.store.stringRules = oldStringRules;
await DataStore.del(STRING_RULES_KEY);
}
const oldRegexRules = await DataStore.get<Rule[]>(REGEX_RULES_KEY);
if (oldRegexRules != null) {
settings.store.regexRules = oldRegexRules;
await DataStore.del(REGEX_RULES_KEY);
}
}
});

View file

@ -112,9 +112,9 @@ export const Devs = /* #__PURE__*/ Object.freeze({
name: "Mai",
id: 722647978577363026n
},
echo: {
name: "ECHO",
id: 712639419785412668n
amy: {
name: "Amy",
id: 603229858612510720n
},
katlyn: {
name: "katlyn",

View file

@ -70,14 +70,23 @@ export const ColorPicker = waitForComponent<t.ColorPicker>("ColorPicker", filter
export const UserSummaryItem = waitForComponent("UserSummaryItem", filters.componentByCode("defaultRenderUser", "showDefaultAvatarsForNullUsers"));
export let createScroller: (scrollbarClassName: string, fadeClassName: string, customThemeClassName: string) => t.ScrollerThin;
export let createListScroller: (scrollBarClassName: string, fadeClassName: string, someOtherClassIdkMan: string, resizeObserverClass: typeof ResizeObserver) => t.ListScrollerThin;
export let scrollerClasses: Record<string, string>;
export let listScrollerClasses: Record<string, string>;
waitFor(filters.byCode('="ltr",orientation:', "customTheme:", "forwardRef"), m => createScroller = m);
waitFor(filters.byCode("getScrollerNode:", "resizeObserver:", "sectionHeight:"), m => createListScroller = m);
waitFor(["thin", "auto", "customTheme"], m => scrollerClasses = m);
waitFor(m => m.thin && m.auto && !m.customTheme, m => listScrollerClasses = m);
export const ScrollerNone = LazyComponent(() => createScroller(scrollerClasses.none, scrollerClasses.fade, scrollerClasses.customTheme));
export const ScrollerThin = LazyComponent(() => createScroller(scrollerClasses.thin, scrollerClasses.fade, scrollerClasses.customTheme));
export const ScrollerAuto = LazyComponent(() => createScroller(scrollerClasses.auto, scrollerClasses.fade, scrollerClasses.customTheme));
export const ListScrollerNone = LazyComponent(() => createListScroller(listScrollerClasses.none, listScrollerClasses.fade, "", ResizeObserver));
export const ListScrollerThin = LazyComponent(() => createListScroller(listScrollerClasses.thin, listScrollerClasses.fade, "", ResizeObserver));
export const ListScrollerAuto = LazyComponent(() => createListScroller(listScrollerClasses.auto, listScrollerClasses.fade, "", ResizeObserver));
const { FocusLock_ } = mapMangledModuleLazy('document.getElementById("app-mount"))', {
FocusLock_: filters.componentByCode(".containerRef")
}) as {

View file

@ -31,8 +31,6 @@ export let MessageStore: Omit<t.MessageStore, "getMessages"> & GenericStore & {
getMessages(chanId: string): any;
};
// TODO: The correct name for this is ChannelActionCreators and it has already been exported again from utils. Remove this export once enough time has passed
export const PrivateChannelsStore = findByPropsLazy("openPrivateChannel");
export let PermissionStore: GenericStore;
export let GuildChannelStore: GenericStore;
export let ReadStateStore: GenericStore;