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

This commit is contained in:
thororen1234 2026-03-19 07:56:49 -04:00
commit c6e542e595
No known key found for this signature in database
11 changed files with 71 additions and 48 deletions

View file

@ -1,6 +1,8 @@
.vc-text-base { .vc-text-base {
font-family: var(--font-primary); font-family: var(--font-primary);
color: var(--text-default); line-height: normal;
/* Discord puts an insane default margin on p tags, so reset that here */
margin: 0; margin: 0;
} }
@ -24,3 +26,7 @@
.vc-text-tabular-numbers { .vc-text-tabular-numbers {
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
} }
.vc-text-defaultColor {
color: var(--text-default);
}

View file

@ -82,6 +82,7 @@ export type BaseTextProps<Tag extends TextTag = "div"> = ComponentPropsWithoutRe
selectable?: boolean; selectable?: boolean;
lineClamp?: number; lineClamp?: number;
tabularNumbers?: boolean; tabularNumbers?: boolean;
defaultColor?: boolean;
}; };
export function BaseText<T extends TextTag = "div">(props: BaseTextProps<T>): ReactNode { export function BaseText<T extends TextTag = "div">(props: BaseTextProps<T>): ReactNode {
@ -93,6 +94,7 @@ export function BaseText<T extends TextTag = "div">(props: BaseTextProps<T>): Re
selectable = false, selectable = false,
lineClamp, lineClamp,
tabularNumbers = false, tabularNumbers = false,
defaultColor = true,
children, children,
className, className,
style, style,
@ -107,6 +109,7 @@ export function BaseText<T extends TextTag = "div">(props: BaseTextProps<T>): Re
lineClamp === 1 && textCls("line-clamp-1"), lineClamp === 1 && textCls("line-clamp-1"),
lineClamp != null && lineClamp > 1 && textCls("line-clamp"), lineClamp != null && lineClamp > 1 && textCls("line-clamp"),
tabularNumbers && textCls("tabular-numbers"), tabularNumbers && textCls("tabular-numbers"),
defaultColor && textCls("defaultColor"),
className className
)} )}
style={{ style={{

View file

@ -52,7 +52,7 @@ export default definePlugin({
patches: [ patches: [
{ {
find: ".DISPLAY_NAME_STYLES_COACHMARK),", find: ".DISPLAY_NAME_STYLES_COACHMARK)",
replacement: { replacement: {
// react.jsx)(AccountPanel, { ..., showTaglessAccountPanel: blah }) // react.jsx)(AccountPanel, { ..., showTaglessAccountPanel: blah })
match: /(?<=\i\.jsxs?\)\()(\i),{(?=[^}]*?userTag:\i,occluded:)/, match: /(?<=\i\.jsxs?\)\()(\i),{(?=[^}]*?userTag:\i,occluded:)/,

View file

@ -75,11 +75,11 @@ export default definePlugin({
patches: [ patches: [
{ {
find: ".WIDGETS_RTC_UPSELL_COACHMARK)", find: "handleOpenSettingsContextMenu=",
group: true, group: true,
replacement: [ replacement: [
{ {
match: /(\.AVATAR,children:.+?renderPopout:\(?(\i).{0,5}=>){(.+?)}(?=,position)(?<=currentUser:(\i).+?)/, match: /(\.AVATAR,children:.+?renderPopout:(\i)=>){(.+?)}(?=,position)(?<=currentUser:(\i).+?)/,
replace: (_, rest, popoutProps, originalPopout, currentUser) => `${rest}$self.UserProfile({popoutProps:${popoutProps},currentUser:${currentUser},originalRenderPopout:()=>{${originalPopout}}})` replace: (_, rest, popoutProps, originalPopout, currentUser) => `${rest}$self.UserProfile({popoutProps:${popoutProps},currentUser:${currentUser},originalRenderPopout:()=>{${originalPopout}}})`
}, },
{ {

View file

@ -60,7 +60,7 @@ const settings = definePluginSettings({
randomisedLength: { randomisedLength: {
description: "Random characters length", description: "Random characters length",
type: OptionType.NUMBER, type: OptionType.NUMBER,
default: 10, default: 7,
disabled: () => settings.store.method !== Methods.Random, disabled: () => settings.store.method !== Methods.Random,
}, },
consistent: { consistent: {
@ -134,7 +134,7 @@ export default definePlugin({
const newFilename = (() => { const newFilename = (() => {
switch (settings.store.method) { switch (settings.store.method) {
case Methods.Random: case Methods.Random:
const chars = "ABCDEFabcdef0123456789"; const chars = "0123456789bdfhjkmnpqrstvwxz";
const returnedName = Array.from( const returnedName = Array.from(
{ length: settings.store.randomisedLength }, { length: settings.store.randomisedLength },
() => chars[Math.floor(Math.random() * chars.length)] () => chars[Math.floor(Math.random() * chars.length)]

View file

@ -87,7 +87,7 @@ export default definePlugin({
}, },
// Current user area, at bottom of channels/dm list // Current user area, at bottom of channels/dm list
{ {
find: ".DISPLAY_NAME_STYLES_COACHMARK),", find: ".DISPLAY_NAME_STYLES_COACHMARK)",
replacement: [ replacement: [
// Use Decor avatar decoration hook // Use Decor avatar decoration hook
{ {

View file

@ -26,7 +26,7 @@ import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import { Guild } from "@vencord/discord-types"; import { Guild } from "@vencord/discord-types";
import { findByCodeLazy, findByPropsLazy, findStoreLazy, mapMangledModuleLazy } from "@webpack"; import { findByCodeLazy, findByPropsLazy, findStoreLazy, mapMangledModuleLazy } from "@webpack";
import { ChannelStore, Menu } from "@webpack/common"; import { ChannelStore, Menu, UserStore } from "@webpack/common";
const { updateGuildNotificationSettings } = findByPropsLazy("updateGuildNotificationSettings"); const { updateGuildNotificationSettings } = findByPropsLazy("updateGuildNotificationSettings");
const { toggleShowAllChannels } = mapMangledModuleLazy(".onboardExistingMember(", { const { toggleShowAllChannels } = mapMangledModuleLazy(".onboardExistingMember(", {
@ -175,5 +175,11 @@ export default definePlugin({
} }
], ],
settings, settings,
applyDefaultSettings applyDefaultSettings,
flux: {
GUILD_JOIN_REQUEST_UPDATE({ guildId, request, status }) {
if (status === "APPROVED" && request.user_id === UserStore.getCurrentUser().id)
applyDefaultSettings(guildId);
}
}
}); });

View file

@ -24,7 +24,7 @@ import { canBlockReviewAuthor, canDeleteReview, canReportReview, cl, showToast }
import { openUserProfile } from "@utils/discord"; import { openUserProfile } from "@utils/discord";
import { classes } from "@utils/misc"; import { classes } from "@utils/misc";
import { findCssClassesLazy } from "@webpack"; import { findCssClassesLazy } from "@webpack";
import { Alerts, Parser, Timestamp, useState } from "@webpack/common"; import { Alerts, IconUtils, Parser, Timestamp, useState } from "@webpack/common";
import { openBlockModal } from "./BlockedUserModal"; import { openBlockModal } from "./BlockedUserModal";
import { BlockButton, DeleteButton, ReportButton } from "./MessageButton"; import { BlockButton, DeleteButton, ReportButton } from "./MessageButton";
@ -116,8 +116,9 @@ export default function ReviewComponent({ review, refetch, profileId }: { review
<img <img
className={classes(AvatarClasses.avatar, AvatarClasses.clickable)} className={classes(AvatarClasses.avatar, AvatarClasses.clickable)}
onClick={openModal} onClick={openModal}
src={review.sender.profilePhoto || "/assets/1f0bfc0865d324c2587920a7d80c609b.png?size=128"} src={review.sender.profilePhoto || IconUtils.getDefaultAvatarURL(review.sender.discordID)}
style={{ left: "0px", zIndex: 0 }} style={{ left: "0px", zIndex: 0 }}
onError={e => e.currentTarget.src = IconUtils.getDefaultAvatarURL(review.sender.discordID)}
/> />
<div style={{ display: "inline-flex", justifyContent: "center", alignItems: "center" }}> <div style={{ display: "inline-flex", justifyContent: "center", alignItems: "center" }}>
<span <span

View file

@ -62,13 +62,14 @@ export default function ReviewsView({
}: Props) { }: Props) {
const [signal, refetch] = useForceUpdater(true); const [signal, refetch] = useForceUpdater(true);
const [reviewData] = useAwaiter(() => getReviews(discordId, (page - 1) * REVIEWS_PER_PAGE), { const [reviewData] = useAwaiter(() => getReviews(discordId, { offset: (page - 1) * REVIEWS_PER_PAGE }), {
fallbackValue: null, fallbackValue: null,
deps: [refetchSignal, signal, page], deps: [refetchSignal, signal, page],
onSuccess: data => { onSuccess: data => {
if (settings.store.hideBlockedUsers) if (settings.store.hideBlockedUsers)
data!.reviews = data!.reviews?.filter(r => !RelationshipStore.isBlocked(r.sender.discordID)); data!.reviews = data!.reviews?.filter(r => !RelationshipStore.isBlocked(r.sender.discordID));
data!.reviews.reverse();
scrollToTop?.(); scrollToTop?.();
onFetchReviews(data!); onFetchReviews(data!);
} }

View file

@ -29,7 +29,7 @@ import { useAwaiter } from "@utils/react";
import definePlugin from "@utils/types"; import definePlugin from "@utils/types";
import { Guild, User } from "@vencord/discord-types"; import { Guild, User } from "@vencord/discord-types";
import { findCssClassesLazy } from "@webpack"; import { findCssClassesLazy } from "@webpack";
import { Alerts, Clickable, Menu, Parser } from "@webpack/common"; import { Alerts, Clickable, IconUtils, Menu, Parser } from "@webpack/common";
import { Auth, initAuth, updateAuth } from "./auth"; import { Auth, initAuth, updateAuth } from "./auth";
import { openReviewsModal } from "./components/ReviewModal"; import { openReviewsModal } from "./components/ReviewModal";
@ -157,7 +157,7 @@ export default definePlugin({
}, },
renderProfileComponent: ErrorBoundary.wrap(({ user, isSideBar = false }: { user: User; isSideBar?: boolean; }) => { renderProfileComponent: ErrorBoundary.wrap(({ user, isSideBar = false }: { user: User; isSideBar?: boolean; }) => {
const [reviewData] = useAwaiter(() => getReviews(user.id, 0, true), { deps: [user.id], fallbackValue: null }); const [reviewData] = useAwaiter(() => getReviews(user.id, { limit: 4 }), { deps: [user.id], fallbackValue: null });
// Discord are masters at using a crap ton of html elements and css classes to create a simple ui that could have // Discord are masters at using a crap ton of html elements and css classes to create a simple ui that could have
// been made with less than half of the number of elements, so we have to do this insanity to replicate their ui // been made with less than half of the number of elements, so we have to do this insanity to replicate their ui
@ -166,37 +166,43 @@ export default definePlugin({
<ul className={ProfileCardClasses.cardsList} tabIndex={-1}> <ul className={ProfileCardClasses.cardsList} tabIndex={-1}>
<li className={ProfileCardClasses.firstCardContainer}> <li className={ProfileCardClasses.firstCardContainer}>
<Clickable <Clickable
className={classes(ProfileCardContainerClasses.breadcrumb, reviewData?.hasOptedOut ? cl("profile-popout-disabled") : null)} className={classes(ProfileCardContainerClasses.breadcrumb, reviewData?.hasOptedOut && cl("profile-popout-disabled"))}
onClick={() => !reviewData?.hasOptedOut && openReviewsModal(user.id, user.username, ReviewType.User)} onClick={() => !reviewData?.hasOptedOut && openReviewsModal(user.id, user.username, ReviewType.User)}
> >
<div className={classes(ProfileCardOverlayClasses.overlay, ProfileCardContainerClasses.innerContainer, ProfileCardClasses.card)}> <div className={classes(ProfileCardOverlayClasses.overlay, ProfileCardContainerClasses.innerContainer, ProfileCardClasses.card)}>
<Paragraph size={isSideBar ? "sm" : "xs"} weight="medium">User Reviews</Paragraph> <Paragraph size={isSideBar ? "sm" : "xs"} weight="medium">User Reviews</Paragraph>
{reviewData?.hasOptedOut ? ( {!!reviewData?.reviewCount
<Paragraph size={isSideBar ? "sm" : "xs"}>User disabled reviews</Paragraph> ? (
) : !reviewData?.reviewCount ? ( <div className={ProfileCardContainerClasses.icons}>
<Paragraph size={isSideBar ? "sm" : "xs"}>No reviews yet</Paragraph> {reviewData.reviews
) : !!reviewData?.reviewCount && ( .filter(review => review.id !== 0)
<div className={ProfileCardContainerClasses.icons}> .slice(0, 4)
{reviewData.reviews .reverse()
.filter(review => review.id !== 0) .map((review, idx) => {
.slice(0, 4) const showCount = idx === 3 && reviewData.reviewCount > 4;
.reverse()
.map((review, idx) => {
const showCount = idx === 3 && reviewData.reviewCount > 4;
return ( return (
<div className={ProfileCardContainerClasses.icon} key={review.id}> <div className={ProfileCardContainerClasses.icon} key={review.id}>
<img src={review.sender.profilePhoto} alt={review.sender.username} className={showCount ? ProfileCardContainerClasses.displayCount : undefined} /> <img
{showCount && ( src={review.sender.profilePhoto}
<div className={ProfileCardContainerClasses.displayCountText}> alt={review.sender.username}
<Span className={ProfileCardContainerClasses.displayCountTextColor} size="xs" weight="medium">+{reviewData.reviewCount - 3}</Span> className={showCount ? ProfileCardContainerClasses.displayCount : undefined}
</div> onError={e => e.currentTarget.src = IconUtils.getDefaultAvatarURL(review.sender.discordID)}
)} />
</div> {showCount && (
); <div className={ProfileCardContainerClasses.displayCountText}>
})} <Span className={ProfileCardContainerClasses.displayCountTextColor} size="xs" weight="medium" defaultColor={false}>
</div> +{reviewData.reviewCount - 3}
)} </Span>
</div>
)}
</div>
);
})}
</div>
)
: <Paragraph size={isSideBar ? "sm" : "xs"}>{reviewData?.hasOptedOut ? "User opted out" : "No reviews yet"}</Paragraph>
}
</div> </div>
</Clickable> </Clickable>
</li> </li>

View file

@ -29,10 +29,10 @@ export const REVIEWS_PER_PAGE = 50;
export interface UserReviewsData { export interface UserReviewsData {
message: string; message: string;
hasNextPage: boolean;
reviewCount: number;
reviews: Review[]; reviews: Review[];
updated: boolean; updated: boolean;
hasNextPage: boolean;
reviewCount: number;
hasOptedOut: boolean; hasOptedOut: boolean;
} }
@ -48,15 +48,15 @@ async function rdbRequest(path: string, options: RequestInit = {}) {
}); });
} }
export async function getReviews(id: string, offset = 0, isProfileComponent = false): Promise<UserReviewsData> { export async function getReviews(id: string, { limit, offset = 0 }: { limit?: number; offset?: number; } = {}): Promise<UserReviewsData> {
let flags = 0; let flags = 0;
if (!settings.store.showWarning) flags |= WarningFlag; if (!settings.store.showWarning) flags |= WarningFlag;
const params = new URLSearchParams({ const params = new URLSearchParams();
flags: String(flags), if (flags) params.append("flags", String(flags));
offset: String(offset), if (offset) params.append("offset", String(offset));
...(isProfileComponent ? { limit: "4" } : {}) if (limit) params.append("limit", String(limit));
});
const req = await fetch(`${API_URL}/users/${id}/reviews?${params}`); const req = await fetch(`${API_URL}/users/${id}/reviews?${params}`);
const res = (req.ok) const res = (req.ok)