Fix lag caused by poorly written CSS rules (#3198)

Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
This commit is contained in:
v 2025-02-02 01:37:54 +01:00 committed by GitHub
parent 4f5ebec4bb
commit 6cccb54ffc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 270 additions and 330 deletions

View file

@ -69,7 +69,7 @@ function ReloadRequiredCard({ required }: { required: boolean; }) {
<Forms.FormText className={cl("dep-text")}>
Restart now to apply new plugins and their settings
</Forms.FormText>
<Button onClick={() => location.reload()}>
<Button onClick={() => location.reload()} className={cl("restart-button")}>
Restart
</Button>
</>
@ -158,8 +158,8 @@ export function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, on
className={classes(ButtonClasses.button, cl("info-button"))}
>
{plugin.options && !isObjectEmpty(plugin.options)
? <CogWheel />
: <InfoIcon />}
? <CogWheel className={cl("info-icon")} />
: <InfoIcon className={cl("info-icon")} />}
</button>
}
/>

View file

@ -63,10 +63,7 @@
height: 8em;
display: flex;
flex-direction: column;
}
.vc-plugins-info-card div {
line-height: 32px;
gap: 0.25em;
}
.vc-plugins-restart-card {
@ -76,11 +73,11 @@
color: var(--info-warning-text);
}
.vc-plugins-restart-card button {
.vc-plugins-restart-button {
margin-top: 0.5em;
background: var(--info-warning-foreground) !important;
}
.vc-plugins-info-button svg:not(:hover, :focus) {
.vc-plugins-info-icon:not(:hover, :focus) {
color: var(--text-muted);
}

View file

@ -24,14 +24,14 @@ let style: HTMLStyleElement;
function setCss() {
style.textContent = `
.vc-nsfw-img [class^=imageWrapper] img,
.vc-nsfw-img [class^=wrapperPaused] video {
.vc-nsfw-img [class^=imageContainer],
.vc-nsfw-img [class^=wrapperPaused] {
filter: blur(${Settings.plugins.BlurNSFW.blurAmount}px);
transition: filter 0.2s;
}
.vc-nsfw-img [class^=imageWrapper]:hover img,
.vc-nsfw-img [class^=wrapperPaused]:hover video {
filter: unset;
&:hover {
filter: blur(0);
}
}
`;
}
@ -54,7 +54,7 @@ export default definePlugin({
options: {
blurAmount: {
type: OptionType.NUMBER,
description: "Blur Amount",
description: "Blur Amount (in pixels)",
default: 10,
onChange: setCss
}

View file

@ -1,29 +1,29 @@
.client-theme-settings {
.vc-clientTheme-settings {
display: flex;
flex-direction: column;
}
.client-theme-container {
.vc-clientTheme-container {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.client-theme-settings-labels {
.vc-clientTheme-labels {
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.client-theme-container > [class^="colorSwatch"] > [class^="swatch"] {
.vc-clientTheme-container [class^="swatch"] {
border: thin solid var(--background-modifier-accent) !important;
}
.client-theme-warning * {
.vc-clientTheme-warning-text {
color: var(--text-danger);
}
.client-theme-contrast-warning {
.vc-clientTheme-contrast-warning {
background-color: var(--background-primary);
padding: 0.5rem;
border-radius: .5rem;

View file

@ -7,6 +7,7 @@
import "./clientTheme.css";
import { definePluginSettings } from "@api/Settings";
import { classNameFactory } from "@api/Styles";
import { Devs } from "@utils/constants";
import { Margins } from "@utils/margins";
import { classes } from "@utils/misc";
@ -14,6 +15,8 @@ import definePlugin, { OptionType, StartAt } from "@utils/types";
import { findByCodeLazy, findComponentByCodeLazy, findStoreLazy } from "@webpack";
import { Button, Forms, ThemeStore, useStateFromStores } from "@webpack/common";
const cl = classNameFactory("vc-clientTheme-");
const ColorPicker = findComponentByCodeLazy("#{intl::USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR}", ".BACKGROUND_PRIMARY)");
const colorPresets = [
@ -60,9 +63,9 @@ function ThemeSettings() {
}
return (
<div className="client-theme-settings">
<div className="client-theme-container">
<div className="client-theme-settings-labels">
<div className={cl("settings")}>
<div className={cl("container")}>
<div className={cl("settings-labels")}>
<Forms.FormTitle tag="h3">Theme Color</Forms.FormTitle>
<Forms.FormText>Add a color to your Discord client theme</Forms.FormText>
</div>
@ -76,10 +79,10 @@ function ThemeSettings() {
{(contrastWarning || nitroThemeEnabled) && (<>
<Forms.FormDivider className={classes(Margins.top8, Margins.bottom8)} />
<div className={`client-theme-contrast-warning ${contrastWarning ? (isLightTheme ? "theme-dark" : "theme-light") : ""}`}>
<div className="client-theme-warning">
<Forms.FormText>Warning, your theme won't look good:</Forms.FormText>
{contrastWarning && <Forms.FormText>Selected color won't contrast well with text</Forms.FormText>}
{nitroThemeEnabled && <Forms.FormText>Nitro themes aren't supported</Forms.FormText>}
<div className={cl("warning")}>
<Forms.FormText className={cl("warning-text")}>Warning, your theme won't look good:</Forms.FormText>
{contrastWarning && <Forms.FormText className={cl("warning-text")}>Selected color won't contrast well with text</Forms.FormText>}
{nitroThemeEnabled && <Forms.FormText className={cl("warning-text")}>Nitro themes aren't supported</Forms.FormText>}
</div>
{(contrastWarning && fixableContrast) && <Button onClick={() => setTheme(oppositeTheme)} color={Button.Colors.RED}>Switch to {oppositeTheme} mode</Button>}
{(nitroThemeEnabled) && <Button onClick={() => setTheme(theme)} color={Button.Colors.RED}>Disable Nitro Theme</Button>}
@ -123,6 +126,7 @@ export default definePlugin({
stop() {
document.getElementById("clientThemeVars")?.remove();
document.getElementById("clientThemeOffsets")?.remove();
document.getElementById("clientThemeLightModeFixes")?.remove();
}
});

View file

@ -121,6 +121,7 @@ function DearrowButton({ component }: { component: Component<Props>; }) {
height="24px"
viewBox="0 0 36 36"
aria-label="Toggle Dearrow"
className="vc-dearrow-icon"
>
<path
fill="#1213BD"

View file

@ -1,4 +1,4 @@
.vc-dearrow-toggle-off svg {
.vc-dearrow-toggle-off .vc-dearrow-icon {
filter: grayscale(1);
}

View file

@ -16,28 +16,44 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import "./styles.css";
import { get, set } from "@api/DataStore";
import { updateMessage } from "@api/MessageUpdater";
import { migratePluginSettings } from "@api/Settings";
import { ImageInvisible, ImageVisible } from "@components/Icons";
import { Devs } from "@utils/constants";
import { classes } from "@utils/misc";
import definePlugin from "@utils/types";
import { ChannelStore } from "@webpack/common";
import { MessageSnapshot } from "@webpack/types";
let style: HTMLStyleElement;
const KEY = "HideAttachments_HiddenIds";
let hiddenMessages: Set<string> = new Set();
const getHiddenMessages = () => get(KEY).then(set => {
hiddenMessages = set ?? new Set<string>();
let hiddenMessages = new Set<string>();
async function getHiddenMessages() {
hiddenMessages = await get(KEY) ?? new Set();
return hiddenMessages;
});
}
const saveHiddenMessages = (ids: Set<string>) => set(KEY, ids);
migratePluginSettings("HideMedia", "HideAttachments");
export default definePlugin({
name: "HideAttachments",
description: "Hide attachments and Embeds for individual messages via hover button",
name: "HideMedia",
description: "Hide attachments and embeds for individual messages via hover button",
authors: [Devs.Ven],
dependencies: ["MessageUpdaterAPI"],
patches: [{
find: "this.renderAttachments(",
replacement: {
match: /(?<=\i=)this\.render(?:Attachments|Embeds|StickersAccessories)\((\i)\)/g,
replace: "$self.shouldHide($1?.id)?null:$&"
}
}],
renderMessagePopoverButton(msg) {
// @ts-ignore - discord-types lags behind discord.
@ -50,49 +66,42 @@ export default definePlugin({
const isHidden = hiddenMessages.has(msg.id);
return {
label: isHidden ? "Show Attachments" : "Hide Attachments",
label: isHidden ? "Show Media" : "Hide Media",
icon: isHidden ? ImageVisible : ImageInvisible,
message: msg,
channel: ChannelStore.getChannel(msg.channel_id),
onClick: () => this.toggleHide(msg.id)
onClick: () => this.toggleHide(msg.channel_id, msg.id)
};
},
async start() {
style = document.createElement("style");
style.id = "VencordHideAttachments";
document.head.appendChild(style);
renderMessageAccessory({ message }) {
if (!this.shouldHide(message.id)) return null;
return (
<span className={classes("vc-hideAttachments-accessory", !message.content && "vc-hideAttachments-no-content")}>
Media Hidden
</span>
);
},
async start() {
await getHiddenMessages();
await this.buildCss();
},
stop() {
style.remove();
hiddenMessages.clear();
},
async buildCss() {
const elements = [...hiddenMessages].map(id => `#message-accessories-${id}`).join(",");
style.textContent = `
:is(${elements}) :is([class*="embedWrapper"], [class*="clickableSticker"]) {
/* important is not necessary, but add it to make sure bad themes won't break it */
display: none !important;
}
:is(${elements})::after {
content: "Attachments hidden";
color: var(--text-muted);
font-size: 80%;
}
`;
shouldHide(messageId: string) {
return hiddenMessages.has(messageId);
},
async toggleHide(id: string) {
async toggleHide(channelId: string, messageId: string) {
const ids = await getHiddenMessages();
if (!ids.delete(id))
ids.add(id);
if (!ids.delete(messageId))
ids.add(messageId);
await saveHiddenMessages(ids);
await this.buildCss();
updateMessage(channelId, messageId);
}
});

View file

@ -0,0 +1,10 @@
.vc-hideAttachments-accessory {
color: var(--text-muted);
margin-top: 0.5em;
font-style: italic;
font-weight: 400;
}
.vc-hideAttachments-no-content {
margin-top: 0;
}

View file

@ -195,6 +195,7 @@ export const Magnifier = ErrorBoundary.wrap<MagnifierProps>(({ instance, size: i
/>
) : (
<img
className={cl("image")}
ref={imageRef}
style={{
position: "absolute",

View file

@ -18,7 +18,7 @@
border-radius: 0;
}
.vc-imgzoom-nearest-neighbor>img {
.vc-imgzoom-nearest-neighbor > .vc-imgzoom-image {
image-rendering: pixelated;
/* https://googlechrome.github.io/samples/image-rendering-pixelated/index.html */

View file

@ -1,24 +1,8 @@
/* Message content highlighting */
.messagelogger-deleted [class*="contents"] > :is(div, h1, h2, h3, p) {
color: var(--status-danger, #f04747) !important;
}
/* Markdown title highlighting */
.messagelogger-deleted [class*="contents"] :is(h1, h2, h3) {
color: var(--status-danger, #f04747) !important;
}
/* Bot "thinking" text highlighting */
.messagelogger-deleted [class*="colorStandard"] {
color: var(--status-danger, #f04747) !important;
}
/* Embed highlighting */
.messagelogger-deleted article :is(div, span, h1, h2, h3, p) {
color: var(--status-danger, #f04747) !important;
}
.messagelogger-deleted a {
color: var(--red-460, #be3535) !important;
text-decoration: underline;
.messagelogger-deleted {
--text-normal: var(--status-danger, #f04747);
--interactive-normal: var(--status-danger, #f04747);
--text-muted: var(--status-danger, #f04747);
--embed-title: var(--red-460, #be3535);
--text-link: var(--red-460, #be3535);
--header-primary: var(--red-460, #be3535);
}

View file

@ -442,15 +442,10 @@ export default definePlugin({
{
// Attachment renderer
find: ".removeMosaicItemHoverButton",
group: true,
replacement: [
{
match: /(className:\i,item:\i),/,
replace: "$1,item: deleted,"
},
{
match: /\[\i\.obscured\]:.+?,/,
replace: "$& 'messagelogger-deleted-attachment': deleted,"
match: /\[\i\.obscured\]:.+?,(?<=item:(\i).+?)/,
replace: '$&"messagelogger-deleted-attachment":$1.originalItem?.deleted,'
}
]
},

View file

@ -4,12 +4,12 @@
.messagelogger-deleted
:is(
video,
.messagelogger-deleted-attachment,
.emoji,
[data-type="sticker"],
iframe,
.messagelogger-deleted-attachment,
[class|="inlineMediaEmbed"]
[class*="embedIframe"],
[class*="embedSpotify"],
[class*="imageContainer"]
) {
filter: grayscale(1) !important;
transition: 150ms filter ease-in-out;
@ -17,18 +17,14 @@
&[class*="hiddenMosaicItem_"] {
filter: grayscale(1) blur(var(--custom-message-attachment-spoiler-blur-radius, 44px)) !important;
}
&:hover {
filter: grayscale(0) !important;
}
}
.messagelogger-deleted
:is(
video,
.emoji,
[data-type="sticker"],
iframe,
.messagelogger-deleted-attachment,
[class|="inlineMediaEmbed"]
):hover {
filter: grayscale(0) !important;
.messagelogger-deleted [class*="spoilerWarning"] {
color: var(--status-danger);
}
.theme-dark .messagelogger-edited {

View file

@ -157,7 +157,7 @@ function RolesAndUsersPermissionsComponent({ permissions, guild, modalProps, hea
src={user.getAvatarURL(void 0, void 0, false)}
/>
)}
<Text variant="text-md/normal">
<Text variant="text-md/normal" className={cl("modal-list-item-text")}>
{
permission.type === PermissionType.Role
? role?.name ?? "Unknown Role"

View file

@ -73,7 +73,7 @@
background-color: var(--background-modifier-selected);
}
.vc-permviewer-modal-list-item > div {
.vc-permviewer-modal-list-item-text {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;

View file

@ -39,7 +39,7 @@ function BlockedUser({ user, isBusy, setIsBusy }: { user: ReviewDBUser; isBusy:
return (
<div className={cl("block-modal-row")}>
<img src={user.profilePhoto} alt="" />
<img className={cl("block-modal-avatar")} src={user.profilePhoto} alt="" />
<Forms.FormText className={cl("block-modal-username")}>{user.username}</Forms.FormText>
<UnblockButton
onClick={isBusy ? undefined : async () => {

View file

@ -65,7 +65,7 @@ function Modal({ modalProps, modalKey, discordId, name, type }: { modalProps: an
</ModalContent>
<ModalFooter className={cl("modal-footer")}>
<div>
<div className={cl("modal-footer-wrapper")}>
{ownReview && (
<ReviewComponent
refetch={refetch}

View file

@ -16,16 +16,11 @@
border: 1px solid var(--profile-message-input-border-color);
}
.vc-rdb-modal-footer > div {
.vc-rdb-modal-footer-wrapper {
width: 100%;
margin: 6px 16px;
}
/* When input becomes disabled(while sending review), input adds unneccesary padding to left, this prevents it */
.vc-rdb-input > div > div {
padding-left: 0 !important;
}
.vc-rdb-placeholder {
margin-bottom: 4px;
font-weight: bold;
@ -69,7 +64,7 @@
border-radius: 8px;
}
.vc-rdb-review-comment img {
.vc-rdb-review-comment [class*="avatar"] {
vertical-align: text-top;
}
@ -117,13 +112,13 @@
align-items: center;
}
.vc-rdb-block-modal-row img {
.vc-rdb-block-modal-avatar {
border-radius: 50%;
height: 2em;
width: 2em;
}
.vc-rdb-block-modal img::before {
.vc-rdb-block-modal-avatar::before {
content: "";
display: block;
width: 100%;

View file

@ -68,15 +68,16 @@ function PickerModal({ rootProps, close }: { rootProps: ModalProps, close(): voi
return (
<ModalRoot {...rootProps}>
<ModalHeader className={cl("modal-header")}>
<Forms.FormTitle tag="h2">
<Forms.FormTitle tag="h2" className={cl("modal-title")}>
Timestamp Picker
</Forms.FormTitle>
<ModalCloseButton onClick={close} />
<ModalCloseButton onClick={close} className={cl("modal-close-button")} />
</ModalHeader>
<ModalContent className={cl("modal-content")}>
<input
className={cl("date-picker")}
type="datetime-local"
value={value}
onChange={e => setValue(e.currentTarget.value)}
@ -86,23 +87,25 @@ function PickerModal({ rootProps, close }: { rootProps: ModalProps, close(): voi
/>
<Forms.FormTitle>Timestamp Format</Forms.FormTitle>
<Select
options={
Formats.map(m => ({
label: m,
value: m
}))
}
isSelected={v => v === format}
select={v => setFormat(v)}
serialize={v => v}
renderOptionLabel={o => (
<div className={cl("format-label")}>
{Parser.parse(formatTimestamp(time, o.value))}
</div>
)}
renderOptionValue={() => rendered}
/>
<div className={cl("format-select")}>
<Select
options={
Formats.map(m => ({
label: m,
value: m
}))
}
isSelected={v => v === format}
select={v => setFormat(v)}
serialize={v => v}
renderOptionLabel={o => (
<div className={cl("format-label")}>
{Parser.parse(formatTimestamp(time, o.value))}
</div>
)}
renderOptionValue={() => rendered}
/>
</div>
<Forms.FormTitle className={Margins.bottom8}>Preview</Forms.FormTitle>
<Forms.FormText className={cl("preview-text")}>

View file

@ -1,4 +1,4 @@
.vc-st-modal-content input {
.vc-st-date-picker {
background-color: var(--input-background);
color: var(--text-normal);
width: 95%;
@ -12,35 +12,28 @@
font-size: 100%;
}
.vc-st-format-label,
.vc-st-format-label span {
background-color: transparent;
}
.vc-st-modal-content [class|="select"] {
.vc-st-format-select {
margin-bottom: 1em;
--background-modifier-accent: transparent;
}
.vc-st-modal-content [class|="select"] span {
background-color: var(--input-background);
.vc-st-format-label {
--background-modifier-accent: transparent;
}
.vc-st-modal-header {
place-content: center space-between;
}
.vc-st-modal-header h1 {
.vc-st-modal-title {
margin: 0;
}
.vc-st-modal-header button {
.vc-st-modal-close-button {
padding: 0;
}
.vc-st-preview-text {
margin-bottom: 1em;
}
.vc-st-button svg {
transform: scale(1.1) translateY(1px);
}

View file

@ -94,6 +94,7 @@ function GuildInfoModal({ guild }: GuildProps) {
<div className={cl("header")}>
{iconUrl
? <img
className={cl("icon")}
src={iconUrl}
alt=""
onClick={() => openImageModal({
@ -170,6 +171,7 @@ function Owner(guildId: string, owner: User) {
return (
<div className={cl("owner")}>
<img
className={cl("owner-avatar")}
src={ownerAvatarUrl}
alt=""
onClick={() => openImageModal({

View file

@ -21,7 +21,7 @@
margin: 0.5em;
}
.vc-gp-header img {
.vc-gp-icon {
width: 48px;
height: 48px;
cursor: pointer;
@ -82,7 +82,7 @@
gap: 0.2em;
}
.vc-gp-owner img {
.vc-gp-owner-avatar {
height: 20px;
border-radius: 50%;
cursor: pointer;

View file

@ -84,9 +84,9 @@ export const Code = ({
}
const codeTableRows = lines.map((line, i) => (
<tr key={i}>
<td style={{ color: theme.plainColor }}>{i + 1}</td>
<td>{line}</td>
<tr className={cl("table-row")} key={i}>
<td className={cl("table-cell")} style={{ color: theme.plainColor }}>{i + 1}</td>
<td className={cl("table-cell")}>{line}</td>
</tr>
));

View file

@ -102,7 +102,7 @@ export const Highlighter = ({
color: themeBase.plainColor,
}}
>
<code>
<code className={cl("code")}>
<Header
langName={langName}
useDevIcon={useDevIcon}

View file

@ -1,13 +1,13 @@
.shiki-container {
.vc-shiki-container {
border: 4px;
background-color: var(--background-secondary);
}
.shiki-root {
.vc-shiki-root {
border-radius: 4px;
}
.shiki-root code {
.vc-shiki-root .vc-shiki-code {
display: block;
overflow-x: auto;
padding: 0.5em;
@ -20,16 +20,16 @@
border: none;
}
.shiki-devicon {
.vc-shiki-devicon {
margin-right: 8px;
user-select: none;
}
.shiki-plain code {
.vc-shiki-plain .vc-shiki-code {
padding-top: 8px;
}
.shiki-btns {
.vc-shiki-btns {
font-size: 1em;
position: absolute;
right: 0;
@ -37,25 +37,25 @@
opacity: 0;
}
.shiki-root:hover .shiki-btns {
.vc-shiki-root:hover .vc-shiki-btns {
opacity: 1;
}
.shiki-btn {
.vc-shiki-btn {
border-radius: 4px 4px 0 0;
padding: 4px 8px;
user-select: none;
}
.shiki-btn ~ .shiki-btn {
.vc-shiki-btn ~ .vc-shiki-btn {
margin-left: 4px;
}
.shiki-btn:last-child {
.vc-shiki-btn:last-child {
border-radius: 4px 0;
}
.shiki-spinner-container {
.vc-shiki-spinner-container {
align-items: center;
background-color: rgb(0 0 0 / 60%);
display: flex;
@ -64,11 +64,11 @@
inset: 0;
}
.shiki-preview {
.vc-shiki-preview {
margin-bottom: 2em;
}
.shiki-lang {
.vc-shiki-lang {
padding: 0 5px;
margin-bottom: 6px;
font-weight: bold;
@ -77,24 +77,24 @@
align-items: center;
}
.shiki-table {
.vc-shiki-table {
border-collapse: collapse;
width: 100%;
}
.shiki-table tr {
.vc-shiki-table-row {
height: 19px;
width: 100%;
}
.shiki-root td:first-child {
.vc-shiki-root .vc-shiki-table-cell:first-child {
border-right: 1px solid transparent;
padding-left: 5px;
padding-right: 8px;
user-select: none;
}
.shiki-root td:last-child {
.vc-shiki-root .vc-shiki-table-cell:last-child {
padding-left: 8px;
word-break: break-word;
width: 100%;

View file

@ -23,7 +23,7 @@ import { resolveLang } from "../api/languages";
import { HighlighterProps } from "../components/Highlighter";
import { HljsSetting } from "../types";
export const cl = classNameFactory("shiki-");
export const cl = classNameFactory("vc-shiki-");
export const shouldUseHljs = ({
lang,

View file

@ -33,6 +33,7 @@ export function VerifiedIcon() {
forcedIconColor={forcedIconColor}
size={16}
tooltipText={getIntlMessage("CONNECTION_VERIFIED")}
className="vc-sc-tooltip-icon"
/>
);
}

View file

@ -125,7 +125,7 @@ function CompactConnectionComponent({ connection, theme }: { connection: Connect
<span className="vc-sc-tooltip">
<span className="vc-sc-connection-name">{connection.name}</span>
{connection.verified && <VerifiedIcon />}
<TooltipIcon height={16} width={16} />
<TooltipIcon height={16} width={16} className="vc-sc-tooltip-icon" />
</span>
}
key={connection.id}

View file

@ -14,6 +14,6 @@
word-break: break-all;
}
.vc-sc-tooltip svg {
.vc-sc-tooltip-icon {
min-width: 16px;
}

View file

@ -18,6 +18,7 @@
import { Settings } from "@api/Settings";
import ErrorBoundary from "@components/ErrorBoundary";
import { classes } from "@utils/misc";
import { formatDuration } from "@utils/text";
import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
import { EmojiStore, FluxDispatcher, GuildMemberStore, GuildStore, Parser, PermissionsBits, PermissionStore, SnowflakeUtils, Text, Timestamp, Tooltip, useEffect, useState } from "@webpack/common";
@ -25,7 +26,7 @@ import type { Channel } from "discord-types/general";
import openRolesAndUsersPermissionsModal, { PermissionType, RoleOrUserPermission } from "../../permissionsViewer/components/RolesAndUsersPermissions";
import { sortPermissionOverwrites } from "../../permissionsViewer/utils";
import { settings } from "..";
import { cl, settings } from "..";
const enum SortOrderTypes {
LATEST_ACTIVITY = 0,
@ -168,19 +169,19 @@ function HiddenChannelLockScreen({ channel }: { channel: ExtendedChannel; }) {
}, [channelId]);
return (
<div className={ChatScrollClasses.auto + " " + ChatScrollClasses.customTheme + " " + ChatClasses.chatContent + " " + "shc-lock-screen-outer-container"}>
<div className="shc-lock-screen-container">
<img className="shc-lock-screen-logo" src={HiddenChannelLogo} />
<div className={classes(ChatScrollClasses.auto, ChatScrollClasses.customTheme, ChatScrollClasses.managedReactiveScroller)}>
<div className={cl("container")}>
<img className={cl("logo")} src={HiddenChannelLogo} />
<div className="shc-lock-screen-heading-container">
<Text variant="heading-xxl/bold">This is a {!PermissionStore.can(PermissionsBits.VIEW_CHANNEL, channel) ? "hidden" : "locked"} {ChannelTypesToChannelNames[type]} channel.</Text>
<div className={cl("heading-container")}>
<Text variant="heading-xxl/bold">This is a {!PermissionStore.can(PermissionsBits.VIEW_CHANNEL, channel) ? "hidden" : "locked"} {ChannelTypesToChannelNames[type]} channel</Text>
{channel.isNSFW() &&
<Tooltip text="NSFW">
{({ onMouseLeave, onMouseEnter }) => (
<svg
onMouseLeave={onMouseLeave}
onMouseEnter={onMouseEnter}
className="shc-lock-screen-heading-nsfw-icon"
className={cl("heading-nsfw-icon")}
width="32"
height="32"
viewBox="0 0 48 48"
@ -202,7 +203,7 @@ function HiddenChannelLockScreen({ channel }: { channel: ExtendedChannel; }) {
)}
{channel.isForumChannel() && topic && topic.length > 0 && (
<div className="shc-lock-screen-topic-container">
<div className={cl("topic-container")}>
{Parser.parseTopic(topic, false, { channelId })}
</div>
)}
@ -213,7 +214,6 @@ function HiddenChannelLockScreen({ channel }: { channel: ExtendedChannel; }) {
<Timestamp timestamp={new Date(SnowflakeUtils.extractTimestamp(lastMessageId))} />
</Text>
}
{lastPinTimestamp &&
<Text variant="text-md/normal">Last message pin: <Timestamp timestamp={new Date(lastPinTimestamp)} /></Text>
}
@ -247,7 +247,7 @@ function HiddenChannelLockScreen({ channel }: { channel: ExtendedChannel; }) {
<Text variant="text-md/normal">Default sort order: {SortOrderTypesToNames[defaultSortOrder]}</Text>
}
{defaultReactionEmoji != null &&
<div className="shc-lock-screen-default-emoji-container">
<div className={cl("default-emoji-container")}>
<Text variant="text-md/normal">Default reaction emoji:</Text>
{Parser.defaultRules[defaultReactionEmoji.emojiName ? "emoji" : "customEmoji"].react({
name: defaultReactionEmoji.emojiName
@ -258,29 +258,29 @@ function HiddenChannelLockScreen({ channel }: { channel: ExtendedChannel; }) {
src: defaultReactionEmoji.emojiName
? EmojiUtils.getURL(defaultReactionEmoji.emojiName)
: void 0
}, void 0, { key: "0" })}
}, void 0, { key: 0 })}
</div>
}
{channel.hasFlag(ChannelFlags.REQUIRE_TAG) &&
<Text variant="text-md/normal">Posts on this forum require a tag to be set.</Text>
}
{availableTags && availableTags.length > 0 &&
<div className="shc-lock-screen-tags-container">
<div className={cl("tags-container")}>
<Text variant="text-lg/bold">Available tags:</Text>
<div className="shc-lock-screen-tags">
<div className={cl("tags")}>
{availableTags.map(tag => <TagComponent tag={tag} key={tag.id} />)}
</div>
</div>
}
<div className="shc-lock-screen-allowed-users-and-roles-container">
<div className="shc-lock-screen-allowed-users-and-roles-container-title">
{Settings.plugins.PermissionsViewer.enabled && (
<div className={cl("allowed-users-and-roles-container")}>
<div className={cl("allowed-users-and-roles-container-title")}>
{Vencord.Plugins.isPluginEnabled("PermissionsViewer") && (
<Tooltip text="Permission Details">
{({ onMouseLeave, onMouseEnter }) => (
<button
onMouseLeave={onMouseLeave}
onMouseEnter={onMouseEnter}
className="shc-lock-screen-allowed-users-and-roles-container-permdetails-btn"
className={cl("allowed-users-and-roles-container-permdetails-btn")}
onClick={() => openRolesAndUsersPermissionsModal(permissions, GuildStore.getGuild(channel.guild_id), channel.name)}
>
<svg
@ -300,7 +300,7 @@ function HiddenChannelLockScreen({ channel }: { channel: ExtendedChannel; }) {
<button
onMouseLeave={onMouseLeave}
onMouseEnter={onMouseEnter}
className="shc-lock-screen-allowed-users-and-roles-container-toggle-btn"
className={cl("allowed-users-and-roles-container-toggle-btn")}
onClick={() => settings.store.defaultAllowedUsersAndRolesDropdownState = !defaultAllowedUsersAndRolesDropdownState}
>
<svg

View file

@ -19,8 +19,10 @@
import "./style.css";
import { definePluginSettings } from "@api/Settings";
import { classNameFactory } from "@api/Styles";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import { classes } from "@utils/misc";
import { canonicalizeMatch } from "@utils/patches";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy } from "@webpack";
@ -31,6 +33,8 @@ import HiddenChannelLockScreen from "./components/HiddenChannelLockScreen";
const ChannelListClasses = findByPropsLazy("modeMuted", "modeSelected", "unread", "icon");
export const cl = classNameFactory("vc-shc-");
const enum ShowMode {
LockIcon,
HiddenIconWithMutedStyle
@ -549,7 +553,7 @@ export default definePlugin({
aria-hidden={true}
role="img"
>
<path className="shc-evenodd-fill-current-color" d="M17 11V7C17 4.243 14.756 2 12 2C9.242 2 7 4.243 7 7V11C5.897 11 5 11.896 5 13V20C5 21.103 5.897 22 7 22H17C18.103 22 19 21.103 19 20V13C19 11.896 18.103 11 17 11ZM12 18C11.172 18 10.5 17.328 10.5 16.5C10.5 15.672 11.172 15 12 15C12.828 15 13.5 15.672 13.5 16.5C13.5 17.328 12.828 18 12 18ZM15 11H9V7C9 5.346 10.346 4 12 4C13.654 4 15 5.346 15 7V11Z" />
<path fill="currentcolor" fillRule="evenodd" d="M17 11V7C17 4.243 14.756 2 12 2C9.242 2 7 4.243 7 7V11C5.897 11 5 11.896 5 13V20C5 21.103 5.897 22 7 22H17C18.103 22 19 21.103 19 20V13C19 11.896 18.103 11 17 11ZM12 18C11.172 18 10.5 17.328 10.5 16.5C10.5 15.672 11.172 15 12 15C12.828 15 13.5 15.672 13.5 16.5C13.5 17.328 12.828 18 12 18ZM15 11H9V7C9 5.346 10.346 4 12 4C13.654 4 15 5.346 15 7V11Z" />
</svg>
), { noop: true }),
@ -559,14 +563,14 @@ export default definePlugin({
<svg
onMouseLeave={onMouseLeave}
onMouseEnter={onMouseEnter}
className={ChannelListClasses.icon + " " + "shc-hidden-channel-icon"}
className={classes(ChannelListClasses.icon, cl("hidden-channel-icon"))}
width="24"
height="24"
viewBox="0 0 24 24"
aria-hidden={true}
role="img"
>
<path className="shc-evenodd-fill-current-color" d="m19.8 22.6-4.2-4.15q-.875.275-1.762.413Q12.95 19 12 19q-3.775 0-6.725-2.087Q2.325 14.825 1 11.5q.525-1.325 1.325-2.463Q3.125 7.9 4.15 7L1.4 4.2l1.4-1.4 18.4 18.4ZM12 16q.275 0 .512-.025.238-.025.513-.1l-5.4-5.4q-.075.275-.1.513-.025.237-.025.512 0 1.875 1.312 3.188Q10.125 16 12 16Zm7.3.45-3.175-3.15q.175-.425.275-.862.1-.438.1-.938 0-1.875-1.312-3.188Q13.875 7 12 7q-.5 0-.938.1-.437.1-.862.3L7.65 4.85q1.025-.425 2.1-.638Q10.825 4 12 4q3.775 0 6.725 2.087Q21.675 8.175 23 11.5q-.575 1.475-1.512 2.738Q20.55 15.5 19.3 16.45Zm-4.625-4.6-3-3q.7-.125 1.288.112.587.238 1.012.688.425.45.613 1.038.187.587.087 1.162Z" />
<path fill="currentcolor" fillRule="evenodd" d="m19.8 22.6-4.2-4.15q-.875.275-1.762.413Q12.95 19 12 19q-3.775 0-6.725-2.087Q2.325 14.825 1 11.5q.525-1.325 1.325-2.463Q3.125 7.9 4.15 7L1.4 4.2l1.4-1.4 18.4 18.4ZM12 16q.275 0 .512-.025.238-.025.513-.1l-5.4-5.4q-.075.275-.1.513-.025.237-.025.512 0 1.875 1.312 3.188Q10.125 16 12 16Zm7.3.45-3.175-3.15q.175-.425.275-.862.1-.438.1-.938 0-1.875-1.312-3.188Q13.875 7 12 7q-.5 0-.938.1-.437.1-.862.3L7.65 4.85q1.025-.425 2.1-.638Q10.825 4 12 4q3.775 0 6.725 2.087Q21.675 8.175 23 11.5q-.575 1.475-1.512 2.738Q20.55 15.5 19.3 16.45Zm-4.625-4.6-3-3q.7-.125 1.288.112.587.238 1.012.688.425.45.613 1.038.187.587.087 1.162Z" />
</svg>
)}
</Tooltip>

View file

@ -1,43 +1,31 @@
.shc-lock-screen-outer-container {
overflow: hidden scroll;
flex: 1 1 auto;
height: 100%;
width: 100%;
}
.shc-lock-screen-container {
.vc-shc-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
gap: 0.65em;
margin: 0.5em 0;
min-height: 100%;
}
.shc-lock-screen-container > * {
margin: 5px;
.vc-shc-logo {
width: 12em;
height: 12em;
}
.shc-lock-screen-logo {
width: 180px;
height: 180px;
}
.shc-lock-screen-heading-container {
.vc-shc-heading-container {
display: flex;
flex-direction: row;
align-items: center;
gap: 0.5em;
}
.shc-lock-screen-heading-container > * {
margin: inherit;
}
.shc-lock-screen-heading-nsfw-icon {
.vc-shc-heading-nsfw-icon {
color: var(--text-normal);
}
.shc-lock-screen-topic-container {
.vc-shc-topic-container {
color: var(--text-normal);
background: var(--bg-overlay-3, var(--background-secondary));
border-radius: 5px;
@ -45,91 +33,75 @@
max-width: 70vw;
}
.shc-lock-screen-tags-container {
.vc-shc-default-emoji-container {
display: flex;
flex-direction: row;
align-items: center;
background: var(--bg-overlay-3, var(--background-secondary));
border-radius: 8px;
padding: 0.75em;
margin-left: 0.75em;
}
.vc-shc-tags-container {
display: flex;
flex-direction: column;
background: var(--bg-overlay-3, var(--background-secondary));
border-radius: 5px;
padding: 10px;
padding: 0.75em;
gap: 0.75em;
max-width: 70vw;
}
.shc-lock-screen-tags-container > * {
margin: inherit;
}
.shc-lock-screen-tags {
.vc-shc-tags {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
gap: 8px;
gap: 0.35em;
}
.shc-evenodd-fill-current-color {
fill-rule: evenodd;
fill: currentcolor;
}
.shc-hidden-channel-icon {
margin-left: 6px;
z-index: 0;
cursor: not-allowed;
}
.shc-lock-screen-default-emoji-container {
display: flex;
flex-direction: row;
align-items: center;
}
.shc-lock-screen-default-emoji-container > [class^="emojiContainer"] {
background: var(--bg-overlay-3, var(--background-secondary));
border-radius: 8px;
padding: 5px 6px;
margin-left: 5px;
}
.shc-lock-screen-allowed-users-and-roles-container {
.vc-shc-allowed-users-and-roles-container {
display: flex;
flex-direction: column;
align-items: center;
background: var(--bg-overlay-3, var(--background-secondary));
border-radius: 5px;
padding: 10px;
padding: 0.75em;
max-width: 70vw;
}
.shc-lock-screen-allowed-users-and-roles-container-title {
.vc-shc-allowed-users-and-roles-container-title {
display: flex;
flex-direction: row;
align-items: center;
gap: 0.5em;
}
.shc-lock-screen-allowed-users-and-roles-container-toggle-btn {
.vc-shc-allowed-users-and-roles-container-toggle-btn {
all: unset;
margin-left: 5px;
cursor: pointer;
display: flex;
align-items: center;
}
.shc-lock-screen-allowed-users-and-roles-container-toggle-btn > svg {
color: var(--text-normal);
}
.shc-lock-screen-allowed-users-and-roles-container-permdetails-btn {
.vc-shc-allowed-users-and-roles-container-permdetails-btn {
all: unset;
margin-right: 5px;
cursor: pointer;
display: flex;
align-items: center;
}
.shc-lock-screen-allowed-users-and-roles-container-permdetails-btn > svg {
color: var(--text-normal);
}
.shc-lock-screen-allowed-users-and-roles-container > [class^="members"] {
margin-left: 10px;
.vc-shc-allowed-users-and-roles-container > [class^="members"] {
margin-left: 12px;
flex-wrap: wrap;
justify-content: center;
}
.vc-shc-hidden-channel-icon {
cursor: not-allowed;
margin-left: 6px;
z-index: 0;
}

View file

@ -19,6 +19,7 @@
import "./spotifyStyles.css";
import { Settings } from "@api/Settings";
import { classNameFactory } from "@api/Styles";
import { Flex } from "@components/Flex";
import { ImageIcon, LinkIcon, OpenExternalIcon } from "@components/Icons";
import { debounce } from "@shared/debounce";
@ -28,7 +29,7 @@ import { ContextMenuApi, FluxDispatcher, Forms, Menu, React, useEffect, useState
import { SpotifyStore, Track } from "./SpotifyStore";
const cl = (className: string) => `vc-spotify-${className}`;
const cl = classNameFactory("vc-spotify-");
function msToHuman(ms: number) {
const minutes = ms / 1000 / 60;
@ -40,7 +41,7 @@ function msToHuman(ms: number) {
function Svg(path: string, label: string) {
return () => (
<svg
className={classes(cl("button-icon"), cl(label))}
className={cl("button-icon", label)}
height="24"
width="24"
viewBox="0 0 24 24"
@ -126,7 +127,7 @@ function Controls() {
return (
<Flex className={cl("button-row")} style={{ gap: 0 }}>
<Button
className={classes(cl("button"), cl(shuffle ? "shuffle-on" : "shuffle-off"))}
className={classes(cl("button"), cl("shuffle"), cl(shuffle ? "shuffle-on" : "shuffle-off"))}
onClick={() => SpotifyStore.setShuffle(!shuffle)}
>
<Shuffle />
@ -143,7 +144,7 @@ function Controls() {
<SkipNext />
</Button>
<Button
className={classes(cl("button"), cl(repeatClassName))}
className={classes(cl("button"), cl("repeat"), cl(repeatClassName))}
onClick={() => SpotifyStore.setRepeat(nextRepeat)}
style={{ position: "relative" }}
>
@ -285,11 +286,12 @@ function Info({ track }: { track: Track; }) {
</>
);
if (coverExpanded && img) return (
<div id={cl("album-expanded-wrapper")}>
{i}
</div>
);
if (coverExpanded && img)
return (
<div id={cl("album-expanded-wrapper")}>
{i}
</div>
);
return (
<div id={cl("info-wrapper")}>

View file

@ -30,22 +30,17 @@
background-color: var(--background-modifier-selected);
}
.vc-spotify-button svg {
.vc-spotify-button-icon {
height: 24px;
width: 24px;
}
[class*="vc-spotify-shuffle"] > svg,
[class*="vc-spotify-repeat"] > svg {
.vc-spotify-shuffle .vc-spotify-button-icon,
.vc-spotify-repeat .vc-spotify-button-icon {
width: 22px;
height: 22px;
}
.vc-spotify-button svg path {
width: 100%;
height: 100%;
}
/* .vc-spotify-button:hover {
filter: brightness(1.3);
} */
@ -87,12 +82,19 @@
gap: 0.5em;
}
#vc-spotify-info-wrapper img {
#vc-spotify-album-image {
height: 90%;
object-fit: contain;
border-radius: 3px;
transition: filter 0.2s;
}
#vc-spotify-album-expanded-wrapper img {
#vc-spotify-album-image:hover {
filter: brightness(1.2);
cursor: pointer;
}
#vc-spotify-album-expanded-wrapper #vc-spotify-album-image {
width: 100%;
object-fit: contain;
}
@ -137,16 +139,6 @@
cursor: pointer;
}
#vc-spotify-album-image {
border-radius: 3px;
transition: filter 0.2s;
}
#vc-spotify-album-image:hover {
filter: brightness(1.2);
cursor: pointer;
}
#vc-spotify-progress-bar {
position: relative;
color: var(--text-normal);

View file

@ -76,7 +76,7 @@ export function TranslateModal({ rootProps }: { rootProps: ModalProps; }) {
return (
<ModalRoot {...rootProps}>
<ModalHeader className={cl("modal-header")}>
<Forms.FormTitle tag="h2">
<Forms.FormTitle tag="h2" className={cl("modal-title")}>
Translate
</Forms.FormTitle>
<ModalCloseButton onClick={rootProps.onClose} />

View file

@ -55,7 +55,7 @@ export function TranslationAccessory({ message }: { message: Message; }) {
return (
<span className={cl("accessory")}>
<TranslateIcon width={16} height={16} />
<TranslateIcon width={16} height={16} className={cl("accessory-icon")} />
{Parser.parse(translation.text)}
{" "}
(translated from {translation.sourceLanguage} - <Dismiss onDismiss={() => setTranslation(undefined)} />)

View file

@ -6,7 +6,7 @@
place-content: center space-between;
}
.vc-trans-modal-header h1 {
.vc-trans-modal-title {
margin: 0;
}
@ -17,7 +17,7 @@
font-weight: 400;
}
.vc-trans-accessory svg {
.vc-trans-accessory-icon {
margin-right: 0.25em;
}

View file

@ -1,12 +0,0 @@
:is([class*="userProfile"], [class*="userPopout"]) [class*="bannerPremium"] {
background: center / cover no-repeat;
}
[class*="NonPremium"]:has([class*="bannerPremium"]) [class*="avatarPositionNormal"],
[class*="PremiumWithoutBanner"]:has([class*="bannerPremium"]) [class*="avatarPositionPremiumNoBanner"] {
top: 76px;
}
[style*="background-image"] [class*="background_"] {
background-color: transparent !important;
}

View file

@ -17,13 +17,10 @@
*/
import { definePluginSettings } from "@api/Settings";
import { enableStyle } from "@api/Styles";
import { Link } from "@components/Link";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import style from "./index.css?managed";
const API_URL = "https://usrbg.is-hardly.online/users";
interface UsrbgApiReturn {
@ -115,8 +112,6 @@ export default definePlugin({
},
async start() {
enableStyle(style);
const res = await fetch(API_URL);
if (res.ok) {
this.data = await res.json();

View file

@ -1,16 +1,16 @@
.vc-toolbox-btn,
.vc-toolbox-btn>svg {
.vc-toolbox-icon {
-webkit-app-region: no-drag;
}
.vc-toolbox-btn>svg {
.vc-toolbox-icon {
color: var(--interactive-normal);
}
.vc-toolbox-btn[class*="selected"]>svg {
.vc-toolbox-btn[class*="selected"] .vc-toolbox-icon {
color: var(--interactive-active);
}
.vc-toolbox-btn:hover>svg {
.vc-toolbox-btn:hover .vc-toolbox-icon {
color: var(--interactive-hover);
}

View file

@ -88,7 +88,7 @@ function VencordPopout(onClose: () => void) {
function VencordPopoutIcon(isShown: boolean) {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 27" width={24} height={24}>
<svg viewBox="0 0 27 27" width={24} height={24} className="vc-toolbox-icon">
<path fill="currentColor" d={isShown ? "M9 0h1v1h1v2h1v2h3V3h1V1h1V0h1v2h1v2h1v7h-1v-1h-3V9h1V6h-1v4h-3v1h1v-1h2v1h3v1h-1v1h-3v2h1v1h1v1h1v3h-1v4h-2v-1h-1v-4h-1v4h-1v1h-2v-4H9v-3h1v-1h1v-1h1v-2H9v-1H8v-1h3V6h-1v3h1v1H8v1H7V4h1V2h1M5 19h2v1h1v1h1v3H4v-1h2v-1H4v-2h1m15-1h2v1h1v2h-2v1h2v1h-5v-3h1v-1h1m4 3h4v1h-4" : "M0 0h7v1H6v1H5v1H4v1H3v1H2v1h5v1H0V6h1V5h1V4h1V3h1V2h1V1H0m13 2h5v1h-1v1h-1v1h-1v1h3v1h-5V7h1V6h1V5h1V4h-3m8 5h1v5h1v-1h1v1h-1v1h1v-1h1v1h-1v3h-1v1h-2v1h-1v1h1v-1h2v-1h1v2h-1v1h-2v1h-1v-1h-1v1h-6v-1h-1v-1h-1v-2h1v1h2v1h3v1h1v-1h-1v-1h-3v-1h-4v-4h1v-2h1v-1h1v-1h1v2h1v1h1v-1h1v1h-1v1h2v-2h1v-2h1v-1h1M8 14h2v1H9v4h1v2h1v1h1v1h1v1h4v1h-6v-1H5v-1H4v-5h1v-1h1v-2h2m17 3h1v3h-1v1h-1v1h-1v2h-2v-2h2v-1h1v-1h1m1 0h1v3h-1v1h-2v-1h1v-1h1"} />
</svg>
);

View file

@ -9,10 +9,6 @@
margin-bottom: 1em;
}
.vc-vmsg-modal audio {
width: 100%;
}
.vc-vmsg-preview {
color: var(--text-normal);
border-radius: 24px;