2026-01-19 12:51:53 -05:00
/ *
* Vencord , a Discord client mod
* Copyright ( c ) 2025 Vendicated and contributors
* SPDX - License - Identifier : GPL - 3.0 - or - later
* /
2026-01-19 12:54:10 -05:00
import "./styles.css" ;
import { definePluginSettings , migratePluginSettings } from "@api/Settings" ;
2026-01-19 12:51:53 -05:00
import { Devs } from "@utils/constants" ;
2026-01-19 12:54:10 -05:00
import definePlugin , { makeRange , OptionType } from "@utils/types" ;
2026-01-19 12:51:53 -05:00
const settings = definePluginSettings ( {
reactionCount : {
description : "Number of reactions (0-42)" ,
type : OptionType . NUMBER ,
default : 5
} ,
2026-01-19 12:54:10 -05:00
frequentEmojis : {
description : "Use frequently used emojis instead of favourite emojis" ,
type : OptionType . BOOLEAN ,
restartNeeded : true ,
default : true
} ,
rows : {
description : "Rows of quick reactions to display" ,
type : OptionType . SLIDER ,
default : 2 ,
markers : makeRange ( 1 , 16 , 1 ) ,
stickToMarkers : true
} ,
columns : {
description : "Columns of quick reactions to display" ,
type : OptionType . SLIDER ,
default : 4 ,
markers : makeRange ( 1 , 12 , 1 ) ,
stickToMarkers : true
} ,
compactMode : {
description : "Scales the buttons to 75% of their original scale, whilst increasing the inner emoji to 125% scale. Emojis will be 93.75% of the original size. Recommended to have a minimum of 5 columns" ,
type : OptionType . BOOLEAN ,
default : false
} ,
scroll : {
description : "Enable scrolling the list of emojis" ,
type : OptionType . BOOLEAN ,
default : true
}
2026-01-19 12:51:53 -05:00
} ) ;
2026-01-19 12:54:10 -05:00
migratePluginSettings ( "MoreQuickReactions" , "BetterQuickReact" ) ;
2026-01-19 12:51:53 -05:00
export default definePlugin ( {
name : "MoreQuickReactions" ,
2026-01-19 12:54:10 -05:00
description : "Improves the quick react buttons in the message context menu." ,
2026-04-16 13:45:58 -04:00
tags : [ "Emotes" , "Reactions" , "Customisation" , "Shortcuts" ] ,
2026-01-19 12:54:10 -05:00
authors : [ Devs . Ven , Devs . Sqaaakoi , Devs . iamme ] ,
isModified : true ,
2026-01-19 12:51:53 -05:00
settings ,
patches : [
{
find : "#{intl::MESSAGE_UTILITIES_A11Y_LABEL}" ,
replacement : {
match : /(?<=length>=3\?.{0,40})\.slice\(0,3\)/ ,
replace : ".slice(0,$self.reactionCount)"
}
2026-01-19 12:54:10 -05:00
} ,
// Remove favourite emojis from being inserted at the start of the reaction list
{
find : "this.favoriteEmojisWithoutFetchingLatest.concat" ,
replacement : {
match : /(this\.favoriteEmojisWithoutFetchingLatest)\.concat/ ,
replace : "[].concat"
} ,
predicate : ( ) = > settings . store . frequentEmojis
} ,
{
find : "#{intl::ADD_REACTION_NAMED}" ,
group : true ,
replacement : [
{
match : /isEmojiPremiumLocked\(\{.{0,25}channel:(\i),/ ,
replace : "$&guild_id:$1?.guild_id??null,"
} ,
// Override limit of emojis to display with offset hook.
{
2026-04-24 11:41:23 -04:00
match : /"MessageContextMenu"\},\{autoTrackExposure.{0,5}\}\),/ ,
replace : "$&[moreQuickReactionsScrollValue,setMoreQuickReactionsScrollValue]=Vencord.Webpack.Common.React.useState(0),"
} ,
{
match : /\.length>4&&\(\i\.length=4\)/ ,
replace : ""
2026-01-19 12:54:10 -05:00
} ,
// Add a custom class to identify the quick reactions have been modified and a CSS variable for the number of columns to display
{
2026-01-23 11:49:39 -05:00
match : /className:(\i\.\i),(?=children:)/ ,
2026-05-19 21:57:34 -04:00
replace : 'className:"vc-better-quick-react "+($self.settings.store.compactMode?"vc-better-quick-react-compact ":"")+$1,style:{"--vc-better-quick-react-columns":$self.settings.store.columns},'
2026-01-19 12:54:10 -05:00
} ,
// Scroll handler + Apply the emoji count limit from earlier with custom logic
{
match : /children:(\i)\.map\(/ ,
replace : "onWheel:$self.onWheelWrapper(moreQuickReactionsScrollValue,setMoreQuickReactionsScrollValue,$1.length),children:$self.applyScroll($1,moreQuickReactionsScrollValue).map("
}
]
} ,
// MenuGroup doesn't accept styles or anything special by default :/
{
find : /\.groupLabel,\i\.hideInteraction,/ ,
replacement : {
match : /role:"group",/ ,
replace : "$&style:arguments[0].style,onWheel:arguments[0].onWheel,"
}
2026-05-19 21:57:34 -04:00
} ,
{
find : '"--custom-menu-viewport-padding"' ,
replacement : {
match : /className:\i\(\)\(\i\.menu/ ,
replace : '$&,"vc-better-quick-react-padding"'
}
2026-01-19 12:51:53 -05:00
}
] ,
2026-01-19 12:54:10 -05:00
getMaxQuickReactions() {
return settings . store . rows * settings . store . columns ;
} ,
get reactionCount() {
return settings . store . reactionCount ;
} ,
applyScroll ( emojis : any [ ] , index : number ) {
return emojis . slice ( index , index + this . getMaxQuickReactions ( ) ) ;
} ,
onWheelWrapper ( currentScrollValue : number , setScrollHook : ( value : number ) = > void , emojisLength : number ) {
if ( settings . store . scroll ) return ( e : WheelEvent ) = > {
if ( e . deltaY === 0 || e . shiftKey ) return ;
e . stopPropagation ( ) ; // does this do anything?
const modifier = e . deltaY < 0 ? - 1 : 1 ;
const newValue = currentScrollValue + ( modifier * settings . store . columns ) ;
setScrollHook ( Math . max ( 0 , Math . min ( newValue , emojisLength - this . getMaxQuickReactions ( ) ) ) ) ;
} ;
} ,
2026-01-19 12:51:53 -05:00
} ) ;