Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class GuildMemberRoleManager extends DataManager {
* @readonly
*/
get color() {
const coloredRoles = this.cache.filter(role => role.color);
const coloredRoles = this.cache.filter(role => role.colors.primaryColor);
if (!coloredRoles.size) return null;
return coloredRoles.reduce((prev, role) => (role.comparePositionTo(prev) > 0 ? role : prev));
}
Expand Down
48 changes: 42 additions & 6 deletions packages/discord.js/src/managers/RoleManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,22 @@ class RoleManager extends CachedManager {
* @returns {?Snowflake}
*/

/**
* @typedef {Object} RoleColorsResolvable
* @property {ColorResolvable} primaryColor The primary color of the role
* @property {ColorResolvable} [secondaryColor] The secondary color of the role.
* This will make the role a gradient between the other provided colors
* @property {ColorResolvable} [tertiaryColor] The tertiary color of the role.
* When sending `tertiaryColor` the API enforces the role color to be a holographic style with values of `primaryColor = 11127295`, `secondaryColor = 16759788`, and `tertiaryColor = 16761760`.
* These values are available as a constant: `Constants.HolographicStyle`
*/

/**
* Options used to create a new role.
*
* @typedef {Object} RoleCreateOptions
* @property {string} [name] The name of the new role
* @property {ColorResolvable} [color] The data to create the role with
* @property {RoleColorsResolvable} [colors] The colors to create the role with
* @property {boolean} [hoist] Whether or not the new role should be hoisted
* @property {PermissionResolvable} [permissions] The permissions for the new role
* @property {number} [position] The position of the new role
Expand All @@ -141,27 +151,47 @@ class RoleManager extends CachedManager {
* // Create a new role with data and a reason
* guild.roles.create({
* name: 'Super Cool Blue People',
* color: Colors.Blue,
* reason: 'we needed a role for Super Cool People',
* colors: {
* primaryColor: Colors.Blue,
* },
* })
* .then(console.log)
* .catch(console.error);
* @example
* // Create a role with holographic colors
* guild.roles.create({
* name: 'Holographic Role',
* reason: 'Creating a role with holographic effect',
* colors: {
* primaryColor: Constants.HolographicStyle.Primary,
* secondaryColor: Constants.HolographicStyle.Secondary,
* tertiaryColor: Constants.HolographicStyle.Tertiary,
* },
* })
* .then(console.log)
* .catch(console.error);
*/
async create(options = {}) {
let { color, permissions, icon } = options;
let { permissions, icon } = options;
const { name, hoist, position, mentionable, reason, unicodeEmoji } = options;
color &&= resolveColor(color);
if (permissions !== undefined) permissions = new PermissionsBitField(permissions);
if (icon) {
const guildEmojiURL = this.guild.emojis.resolve(icon)?.imageURL();
icon = guildEmojiURL ? await resolveImage(guildEmojiURL) : await resolveImage(icon);
if (typeof icon !== 'string') icon = undefined;
}

const colors = options.colors && {
primary_color: resolveColor(options.colors.primaryColor),
secondary_color: options.colors.secondaryColor && resolveColor(options.colors.secondaryColor),
tertiary_color: options.colors.tertiaryColor && resolveColor(options.colors.tertiaryColor),
};

const data = await this.client.rest.post(Routes.guildRoles(this.guild.id), {
body: {
name,
color,
colors,
hoist,
permissions,
mentionable,
Expand Down Expand Up @@ -212,9 +242,15 @@ class RoleManager extends CachedManager {
if (typeof icon !== 'string') icon = undefined;
}

const colors = options.colors && {
primary_color: resolveColor(options.colors.primaryColor),
secondary_color: options.colors.secondaryColor && resolveColor(options.colors.secondaryColor),
tertiary_color: options.colors.tertiaryColor && resolveColor(options.colors.tertiaryColor),
};

const body = {
name: options.name,
color: options.color === undefined ? undefined : resolveColor(options.color),
colors,
hoist: options.hoist,
permissions: options.permissions === undefined ? undefined : new PermissionsBitField(options.permissions),
mentionable: options.mentionable,
Expand Down
53 changes: 39 additions & 14 deletions packages/discord.js/src/structures/Role.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,27 @@ class Role extends Base {
this.name = data.name;
}

if ('color' in data) {
/**
* @typedef {Object} RoleColors
* @property {number} primaryColor The primary color of the role
* @property {?number} secondaryColor The secondary color of the role.
* This will make the role a gradient between the other provided colors
* @property {?number} tertiaryColor The tertiary color of the role.
* When sending `tertiaryColor` the API enforces the role color to be a holographic style with values of `primaryColor = 11127295`, `secondaryColor = 16759788`, and `tertiaryColor = 16761760`.
* These values are available as a constant: `Constants.HolographicStyle`
*/

if ('colors' in data) {
/**
* The base 10 color of the role
* The colors of the role
*
* @type {number}
* @type {RoleColors}
*/
this.color = data.color;
this.colors = {
primaryColor: data.colors.primary_color,
secondaryColor: data.colors.secondary_color,
tertiaryColor: data.colors.tertiary_color,
};
}

if ('hoist' in data) {
Expand Down Expand Up @@ -257,7 +271,7 @@ class Role extends Base {
*
* @typedef {Object} RoleData
* @property {string} [name] The name of the role
* @property {ColorResolvable} [color] The color of the role, either a hex string or a base 10 number
* @property {RoleColorsResolvable} [colors] The colors of the role
* @property {boolean} [hoist] Whether or not the role should be hoisted
* @property {number} [position] The position of the role
* @property {PermissionResolvable} [permissions] The permissions of the role
Expand Down Expand Up @@ -315,19 +329,28 @@ class Role extends Base {
}

/**
* Sets a new color for the role.
* Sets new colors for the role.
*
* @param {ColorResolvable} color The color of the role
* @param {string} [reason] Reason for changing the role's color
* @param {RoleColorsResolvable} colors The colors of the role
* @param {string} [reason] Reason for changing the role's colors
* @returns {Promise<Role>}
* @example
* // Set the color of a role
* role.setColor('#FF0000')
* .then(updated => console.log(`Set color of role to ${updated.color}`))
* // Set the colors of a role
* role.setColors({ primaryColor: '#FF0000', secondaryColor: '#00FF00', tertiaryColor: '#0000FF' })
* .then(updated => console.log(`Set colors of role to ${updated.colors}`))
* .catch(console.error);
* @example
* // Set holographic colors using constants
* role.setColors({
* primaryColor: Constants.HolographicStyle.Primary,
* secondaryColor: Constants.HolographicStyle.Secondary,
* tertiaryColor: Constants.HolographicStyle.Tertiary,
* })
* .then(updated => console.log(`Set holographic colors for role ${updated.name}`))
* .catch(console.error);
*/
async setColor(color, reason) {
return this.edit({ color, reason });
async setColors(colors, reason) {
return this.edit({ colors, reason });
}

/**
Expand Down Expand Up @@ -475,7 +498,9 @@ class Role extends Base {
role &&
this.id === role.id &&
this.name === role.name &&
this.color === role.color &&
this.colors.primaryColor === role.colors.primaryColor &&
this.colors.secondaryColor === role.colors.secondaryColor &&
this.colors.tertiaryColor === role.colors.tertiaryColor &&
this.hoist === role.hoist &&
this.position === role.position &&
this.permissions.bitfield === role.permissions.bitfield &&
Expand Down
16 changes: 16 additions & 0 deletions packages/discord.js/src/util/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,21 @@ exports.StickerFormatExtensionMap = {
[StickerFormatType.GIF]: ImageFormat.GIF,
};

/**
* Holographic color values for role styling.
* When using `tertiaryColor`, the API enforces these specific values for holographic effect.
*
* @typedef {Object} HolographicStyle
* @property {number} Primary 11127295 (0xA9FFFF)
* @property {number} Secondary 16759788 (0xFFCCCC)
* @property {number} Tertiary 16761760 (0xFFE0A0)
*/
exports.HolographicStyle = {
Primary: 11_127_295,
Secondary: 16_759_788,
Tertiary: 16_761_760,
};

/**
* @typedef {Object} Constants Constants that can be used in an enum or object-like way.
* @property {number} MaxBulkDeletableMessageAge Max bulk deletable message age
Expand All @@ -232,4 +247,5 @@ exports.StickerFormatExtensionMap = {
* @property {VoiceBasedChannelTypes} VoiceBasedChannelTypes The types of channels that are voice-based
* @property {SelectMenuTypes} SelectMenuTypes The types of components that are select menus.
* @property {Object} StickerFormatExtensionMap A mapping between sticker formats and their respective image formats.
* @property {HolographicStyle} HolographicStyle Holographic color values for role styling.
*/
23 changes: 20 additions & 3 deletions packages/discord.js/typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2823,9 +2823,21 @@ export class RichPresenceAssets {
public smallImageURL(options?: ImageURLOptions): string | null;
}

export interface RoleColors {
primaryColor: number;
secondaryColor: number | null;
tertiaryColor: number | null;
}

export interface RoleColorsResolvable {
primaryColor: ColorResolvable;
secondaryColor?: ColorResolvable;
tertiaryColor?: ColorResolvable;
}

export class Role extends Base {
private constructor(client: Client<true>, data: APIRole, guild: Guild);
public color: number;
public colors: RoleColors;
public get createdAt(): Date;
public get createdTimestamp(): number;
public get editable(): boolean;
Expand Down Expand Up @@ -2853,7 +2865,7 @@ export class Role extends Base {
channel: NonThreadGuildBasedChannel | Snowflake,
checkAdmin?: boolean,
): Readonly<PermissionsBitField>;
public setColor(color: ColorResolvable, reason?: string): Promise<Role>;
public setColors(colors: RoleColorsResolvable, reason?: string): Promise<Role>;
public setHoist(hoist?: boolean, reason?: string): Promise<Role>;
public setMentionable(mentionable?: boolean, reason?: string): Promise<Role>;
public setName(name: string, reason?: string): Promise<Role>;
Expand Down Expand Up @@ -3808,6 +3820,11 @@ export type UndeletableMessageType =

export const Constants: {
GuildTextBasedChannelTypes: GuildTextBasedChannelTypes[];
HolographicStyle: {
Primary: 11_127_295;
Secondary: 16_759_788;
Tertiary: 16_761_760;
};
MaxBulkDeletableMessageAge: 1_209_600_000;
NonSystemMessageTypes: NonSystemMessageType[];
SelectMenuTypes: SelectMenuType[];
Expand Down Expand Up @@ -6836,7 +6853,7 @@ export interface ResolvedOverwriteOptions {
}

export interface RoleData {
color?: ColorResolvable;
colors?: RoleColorsResolvable;
hoist?: boolean;
icon?: Base64Resolvable | BufferResolvable | EmojiResolvable | null;
mentionable?: boolean;
Expand Down