From ca4b63c3862d14058b89b74dc5b65f6f0bce0aa2 Mon Sep 17 00:00:00 2001 From: thororen1234 <78185467+thororen1234@users.noreply.github.com> Date: Mon, 31 Mar 2025 17:36:21 -0400 Subject: [PATCH] Visual Refresh Co-Authored-By: sadan4 <117494111+sadan4@users.noreply.github.com> Co-Authored-By: doyle31 Co-Authored-By: iilwy Co-Authored-By: Noa <164402463+nroggendorff@users.noreply.github.com> Co-Authored-By: rini c Co-Authored-By: Cassie <37855219+codef53@users.noreply.github.com> Co-Authored-By: jamesbt365 Co-Authored-By: khcrysalis <97859147+khcrysalis@users.noreply.github.com> Co-Authored-By: nin0dev <75569739+nin0-dev@users.noreply.github.com> --- src/Vencord.ts | 19 ++++- src/components/VencordSettings/addonCard.css | 9 ++ .../VencordSettings/quickActions.css | 10 ++- src/main/patcher.ts | 20 +++-- src/plugins/_api/messageDecorations/index.tsx | 2 +- .../accountPanelServerProfile/index.tsx | 4 +- src/plugins/betterFolders/FolderSideBar.tsx | 1 + src/plugins/betterFolders/index.tsx | 64 +++++++++++++-- src/plugins/clientTheme/index.tsx | 56 ++----------- src/plugins/consoleShortcuts/index.ts | 10 ++- src/plugins/gameActivityToggle/index.tsx | 2 + src/plugins/gameActivityToggle/style.css | 6 +- src/plugins/nsfwGateBypass/index.ts | 7 ++ src/plugins/pauseInvitesForever/index.tsx | 12 ++- src/plugins/plainFolderIcon/index.ts | 18 +++- .../spotifyControls/PlayerComponent.tsx | 7 +- src/plugins/spotifyControls/index.tsx | 2 +- src/plugins/spotifyControls/spotifyStyles.css | 4 +- .../visualRefreshSpotifyStyles.css | 82 +++++++++++++++++++ src/plugins/themeAttributes/index.ts | 4 +- src/plugins/typingTweaks/index.tsx | 25 ++---- src/plugins/typingTweaks/styles.css | 5 ++ src/utils/settingsSync.ts | 15 +++- 23 files changed, 283 insertions(+), 101 deletions(-) create mode 100644 src/plugins/spotifyControls/visualRefreshSpotifyStyles.css create mode 100644 src/plugins/typingTweaks/styles.css diff --git a/src/Vencord.ts b/src/Vencord.ts index 88a83ba9..586d732c 100644 --- a/src/Vencord.ts +++ b/src/Vencord.ts @@ -49,10 +49,27 @@ if (IS_REPORTER) { } async function syncSettings() { + // Check if cloud auth exists for current user before attempting sync + const hasCloudAuth = await dsGet("Vencord_cloudSecret"); + if (!hasCloudAuth) { + if (Settings.cloud.authenticated) { + // User switched to an account that isn't connected to cloud + showNotification({ + title: "Cloud Settings", + body: "Cloud sync was disabled because this account isn't connected to the Vencloud App. You can enable it again by connecting this account in Cloud Settings. (note: it will store your preferences separately)", + color: "var(--yellow-360)", + onClick: () => SettingsRouter.open("VencordCloud") + }); + // Disable cloud sync globally + Settings.cloud.authenticated = false; + } + return; + } + // pre-check for local shared settings if ( Settings.cloud.authenticated && - !await dsGet("Vencord_cloudSecret") // this has been enabled due to local settings share or some other bug + !hasCloudAuth // this has been enabled due to local settings share or some other bug ) { // show a notification letting them know and tell them how to fix it showNotification({ diff --git a/src/components/VencordSettings/addonCard.css b/src/components/VencordSettings/addonCard.css index e46e4c29..8a260ae5 100644 --- a/src/components/VencordSettings/addonCard.css +++ b/src/components/VencordSettings/addonCard.css @@ -11,6 +11,11 @@ box-sizing: border-box; } +.visual-refresh .vc-addon-card { + background-color: var(--button-secondary-background); + border: 1px solid var(--border-subtle); +} + .vc-addon-card-disabled { opacity: 0.6; } @@ -21,6 +26,10 @@ box-shadow: var(--elevation-high); } +.visual-refresh .vc-addon-card:hover { + background-color: var(--button-secondary-background-hover); +} + .vc-addon-header { margin-top: auto; display: flex; diff --git a/src/components/VencordSettings/quickActions.css b/src/components/VencordSettings/quickActions.css index b8bc0071..2b97368b 100644 --- a/src/components/VencordSettings/quickActions.css +++ b/src/components/VencordSettings/quickActions.css @@ -36,7 +36,15 @@ 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; -} \ No newline at end of file +} diff --git a/src/main/patcher.ts b/src/main/patcher.ts index 6178478f..822dab49 100644 --- a/src/main/patcher.ts +++ b/src/main/patcher.ts @@ -85,6 +85,11 @@ if (!IS_VANILLA) { options.backgroundColor = "#00000000"; } + if (settings.disableMinSize) { + options.minWidth = 0; + options.minHeight = 0; + } + const needsVibrancy = process.platform === "darwin" && settings.macosVibrancyStyle; if (needsVibrancy) { @@ -97,6 +102,12 @@ if (!IS_VANILLA) { process.env.DISCORD_PRELOAD = original; super(options); + + if (settings.disableMinSize) { + // Disable the Electron call entirely so that Discord can't override it + this.setMinimumSize = () => { }; + } + initIpc(this); } else super(options); } @@ -115,16 +126,9 @@ if (!IS_VANILLA) { BrowserWindow }; - // Patch appSettings to force enable devtools and optionally disable min size + // Patch appSettings to force enable devtools onceDefined(global, "appSettings", s => { s.set("DANGEROUS_ENABLE_DEVTOOLS_ONLY_ENABLE_IF_YOU_KNOW_WHAT_YOURE_DOING", true); - if (settings.disableMinSize) { - s.set("MIN_WIDTH", 0); - s.set("MIN_HEIGHT", 0); - } else { - s.set("MIN_WIDTH", 940); - s.set("MIN_HEIGHT", 500); - } }); process.env.DATA_DIR = join(app.getPath("userData"), "..", "Equicord"); diff --git a/src/plugins/_api/messageDecorations/index.tsx b/src/plugins/_api/messageDecorations/index.tsx index 739579c0..590e50bd 100644 --- a/src/plugins/_api/messageDecorations/index.tsx +++ b/src/plugins/_api/messageDecorations/index.tsx @@ -32,7 +32,7 @@ export default definePlugin({ { find: '"Message Username"', replacement: { - match: /#{intl::GUILD_COMMUNICATION_DISABLED_BOTTOM_SHEET_TITLE}.+?}\)\)(?=\])/, + match: /#{intl::GUILD_COMMUNICATION_DISABLED_BOTTOM_SHEET_TITLE}.+?renderPopout:.+?(?=\])/, replace: "$&,Vencord.Api.MessageDecorations.__addDecorationsToMessage(arguments[0])" } } diff --git a/src/plugins/accountPanelServerProfile/index.tsx b/src/plugins/accountPanelServerProfile/index.tsx index 30403f84..406f32b4 100644 --- a/src/plugins/accountPanelServerProfile/index.tsx +++ b/src/plugins/accountPanelServerProfile/index.tsx @@ -81,8 +81,8 @@ export default definePlugin({ replace: (_, rest, popoutProps, originalPopout, currentUser) => `${rest}$self.UserProfile({popoutProps:${popoutProps},currentUser:${currentUser},originalRenderPopout:()=>{${originalPopout}}})` }, { - match: /\.AVATAR,children:.+?(?=renderPopout:)/, - replace: "$&onRequestClose:$self.onPopoutClose," + match: /(\.AVATAR,children:.+?onRequestClose:\(\)=>\{)/, + replace: "$&onRequestClose:$self.onPopoutClose();" }, { match: /(?<=#{intl::SET_STATUS}\),)/, diff --git a/src/plugins/betterFolders/FolderSideBar.tsx b/src/plugins/betterFolders/FolderSideBar.tsx index 5203b14d..63a04ca3 100644 --- a/src/plugins/betterFolders/FolderSideBar.tsx +++ b/src/plugins/betterFolders/FolderSideBar.tsx @@ -45,6 +45,7 @@ export default ErrorBoundary.wrap(guildsBarProps => { // Also display flex otherwise to fix scrolling const barStyle = { display: isFullscreen ? "none" : "flex", + gridArea: "sidebar" } as CSSProperties; if (!guilds || !settings.store.sidebarAnim) { diff --git a/src/plugins/betterFolders/index.tsx b/src/plugins/betterFolders/index.tsx index a4675095..97d643f3 100644 --- a/src/plugins/betterFolders/index.tsx +++ b/src/plugins/betterFolders/index.tsx @@ -104,10 +104,14 @@ export const settings = definePluginSettings({ } }); +let cssMade = false; + +const cssElementId = "VC-BetterFolders"; + export default definePlugin({ name: "BetterFolders", description: "Shows server folders on dedicated sidebar and adds folder related improvements", - authors: [Devs.juby, Devs.AutumnVN, Devs.Nuckyz], + authors: [Devs.juby, Devs.AutumnVN, Devs.Nuckyz, Devs.sadan], settings, @@ -213,11 +217,18 @@ export default definePlugin({ { find: "#{intl::DISCODO_DISABLED}", predicate: () => settings.store.closeAllHomeButton, - replacement: { - // Close all folders when clicking the home button - match: /(?<=onClick:\(\)=>{)(?=.{0,300}"discodo")/, - replace: "$self.closeFolders();" - } + group: true, + replacement: [ + { + // Render the Better Folders sidebar + match: /(?<=[[,])((?:!?\i&&)+)\(.{0,50}({className:\i\.guilds,themeOverride:\i})\)/g, + replace: (_, conditions, props) => `${_},${conditions}$self.FolderSideBar({...${props}})` + }, + { + match: /(?<=className:)(\i\.base)(?=,)/, + replace: "($self.makePatchedBaseCSS($1))" + } + ] } ], @@ -265,6 +276,47 @@ export default definePlugin({ } }, + gridStyle: "vc-BetterFolders-sidebar-grid", + makePatchedBaseCSS(className: string) { + done: try { + if (cssMade) break done; + const rule = [...document.styleSheets] + .flatMap(x => [...x.cssRules]) + // cant do includes because they have a `not ((grid-template-columns` + // dumb type inference + .filter((x): x is CSSSupportsRule => x instanceof CSSSupportsRule && x.conditionText.startsWith("(grid-template-columns")) + .flatMap(x => [...x.cssRules]) + .filter(x => x instanceof CSSStyleRule) + .find(x => x.selectorText.endsWith(`.${className}`)); + if (!rule) { + console.error("Failed to find css rule for betterFolders"); + break done; + } + const areas = rule.style.gridTemplateAreas + .split('" "') + .map(x => x.replace(/"/g, "").split(" ")); + areas[0].splice(1, 0, areas[0][0]); + areas[1].splice(1, 0, "sidebar"); + areas[2].splice(1, 0, "sidebar"); + const css = ` + .visual-refresh .${this.gridStyle} { + grid-template-areas: ${areas.map(x => `"${x.join(" ")}"`).join(" ")}; + grid-template-columns: ${rule.style.gridTemplateColumns.replace(/(?<=guildsEnd\])/, " min-content [sidebarEnd]")}; + } + `; + const element = document.createElement("style"); + element.id = cssElementId; + element.textContent = css; + document.getElementById(cssElementId)?.remove(); + document.head.appendChild(element); + cssMade = true; + } catch (e) { + console.error(e); + return className; + } + return `${className} ${this.gridStyle}`; + }, + getGuildTree(isBetterFolders: boolean, originalTree: any, expandedFolderIds?: Set) { return useMemo(() => { if (!isBetterFolders || expandedFolderIds == null) return originalTree; diff --git a/src/plugins/clientTheme/index.tsx b/src/plugins/clientTheme/index.tsx index c7e0e50d..e8d00043 100644 --- a/src/plugins/clientTheme/index.tsx +++ b/src/plugins/clientTheme/index.tsx @@ -120,7 +120,7 @@ export default definePlugin({ const styles = await getStyles(); generateColorOffsets(styles); - generateLightModeFixes(styles); + // generateLightModeFixes(styles); }, stop() { @@ -130,15 +130,12 @@ export default definePlugin({ } }); -const variableRegex = /(--primary-\d{3}-hsl):.*?(\S*)%;/g; -const lightVariableRegex = /^--primary-[1-5]\d{2}-hsl/g; -const darkVariableRegex = /^--primary-[5-9]\d{2}-hsl/g; +const variableRegex = /(--neutral-\d{1,3}-hsl):.*?(\S*)%;/g; // generates variables per theme by: -// - matching regex (so we can limit what variables are included in light/dark theme, otherwise text becomes unreadable) // - offset from specified center (light/dark theme get different offsets because light uses 100 for background-primary, while dark uses 600) -function genThemeSpecificOffsets(variableLightness: Record, regex: RegExp, centerVariable: string): string { - return Object.entries(variableLightness).filter(([key]) => key.search(regex) > -1) +function genThemeSpecificOffsets(variableLightness: Record, centerVariable: string): string { + return Object.entries(variableLightness) .map(([key, lightness]) => { const lightnessOffset = lightness - variableLightness[centerVariable]; const plusOrMinus = lightnessOffset >= 0 ? "+" : "-"; @@ -147,7 +144,6 @@ function genThemeSpecificOffsets(variableLightness: Record, rege .join("\n"); } - function generateColorOffsets(styles) { const variableLightness = {} as Record; @@ -160,50 +156,12 @@ function generateColorOffsets(styles) { } createStyleSheet("clientThemeOffsets", [ - `.theme-light {\n ${genThemeSpecificOffsets(variableLightness, lightVariableRegex, "--primary-345-hsl")} \n}`, - `.theme-dark {\n ${genThemeSpecificOffsets(variableLightness, darkVariableRegex, "--primary-600-hsl")} \n}`, + // you can determine the "center color" by looking at the variable used by `--background-primary` + `.theme-light {\n ${genThemeSpecificOffsets(variableLightness, "--neutral-2-hsl")} \n}`, + `.theme-dark {\n ${genThemeSpecificOffsets(variableLightness, "--neutral-69-hsl")} \n}`, ].join("\n\n")); } -function generateLightModeFixes(styles) { - const groupLightUsesW500Regex = /\.theme-light[^{]*\{[^}]*var\(--white-500\)[^}]*}/gm; - // get light capturing groups that mention --white-500 - const relevantStyles = [...styles.matchAll(groupLightUsesW500Regex)].flat(); - - const groupBackgroundRegex = /^([^{]*)\{background:var\(--white-500\)/m; - const groupBackgroundColorRegex = /^([^{]*)\{background-color:var\(--white-500\)/m; - // find all capturing groups that assign background or background-color directly to w500 - const backgroundGroups = mapReject(relevantStyles, entry => captureOne(entry, groupBackgroundRegex)).join(",\n"); - const backgroundColorGroups = mapReject(relevantStyles, entry => captureOne(entry, groupBackgroundColorRegex)).join(",\n"); - // create css to reassign them to --primary-100 - const reassignBackgrounds = `${backgroundGroups} {\n background: var(--primary-100) \n}`; - const reassignBackgroundColors = `${backgroundColorGroups} {\n background-color: var(--primary-100) \n}`; - - const groupBgVarRegex = /\.theme-light\{([^}]*--[^:}]*(?:background|bg)[^:}]*:var\(--white-500\)[^}]*)\}/m; - const bgVarRegex = /^(--[^:]*(?:background|bg)[^:]*):var\(--white-500\)/m; - // get all global variables used for backgrounds - const lightVars = mapReject(relevantStyles, style => captureOne(style, groupBgVarRegex)) // get the insides of capture groups that have at least one background var with w500 - .map(str => str.split(";")).flat(); // captureGroupInsides[] -> cssRule[] - const lightBgVars = mapReject(lightVars, variable => captureOne(variable, bgVarRegex)); // remove vars that aren't for backgrounds or w500 - // create css to reassign every var - const reassignVariables = `.theme-light {\n ${lightBgVars.map(variable => `${variable}: var(--primary-100);`).join("\n")} \n}`; - - createStyleSheet("clientThemeLightModeFixes", [ - reassignBackgrounds, - reassignBackgroundColors, - reassignVariables, - ].join("\n\n")); -} - -function captureOne(str, regex) { - const result = str.match(regex); - return (result === null) ? null : result[1]; -} - -function mapReject(arr, mapFunc) { - return arr.map(mapFunc).filter(Boolean); -} - function updateColorVars(color: string) { const { hue, saturation, lightness } = hexToHSL(color); diff --git a/src/plugins/consoleShortcuts/index.ts b/src/plugins/consoleShortcuts/index.ts index f85d649a..900b481b 100644 --- a/src/plugins/consoleShortcuts/index.ts +++ b/src/plugins/consoleShortcuts/index.ts @@ -153,7 +153,15 @@ function makeShortcuts() { openModal: { getter: () => ModalAPI.openModal }, openModalLazy: { getter: () => ModalAPI.openModalLazy }, - Stores: Webpack.fluxStores + Stores: Webpack.fluxStores, + + setExperiment: (id: string, bucket: number) => { + Common.FluxDispatcher.dispatch({ + type: "EXPERIMENT_OVERRIDE_BUCKET", + experimentId: id, + experimentBucket: bucket, + }); + }, }; } diff --git a/src/plugins/gameActivityToggle/index.tsx b/src/plugins/gameActivityToggle/index.tsx index c1301411..9c0a2429 100644 --- a/src/plugins/gameActivityToggle/index.tsx +++ b/src/plugins/gameActivityToggle/index.tsx @@ -65,10 +65,12 @@ function GameActivityToggleButton() { return (