How to customize ChatMessageInfo / chat author CSS (there is no widget?)

AI-generated summary

The discussion is about customizing the ChatMessageInfo component in Discourse using a plugin. SkyeDragon wants to apply custom CSS to chat author names based on special site-specific logic, similar to what they achieved for forum posts using api.addPosterIcons. However, there is no equivalent method for real-time chat messages.

Arkshine suggests using api.modifyClass to add custom classnames to the ChatMessageInfo component, providing an example code snippet. SkyeDragon shares their own solution using api.decorateChatMessage, which accesses the chat message container and adds custom classnames to the username element.

Arkshine confirms that their suggested method also passes the this.args.message.user object, and praises SkyeDragon for finding a working solution. Both methods are viable, but Arkshine’s approach is considered cleaner and more straightforward.

Earlier today, I made a little plugin which lets me customize the author line of each forum post with some CSS based on some special site-specific logic. Example:

function initColorize(api)
{
	api.includePostAttributes('colorized_groups');

	// Hijacking post icons to sneak in CSS for forum posts
	api.addPosterIcons((cfs, attrs) => {
		// (A real icon could be specified by filling in the icon field.
		// I removed the icon though since it was getting a bit cluttered.
		// For now, with no icon specified, it's just for CSS highlighting of name.)	
		if (attrs.colorized_groups.indexOf("developer") > -1)
			return { icon: '', className: 'developer', title: 'Developer' };
		else if (attrs.colorized_groups.indexOf("wip_researcher") > -1)
			return { icon: '', className: 'wip_researcher', title: 'WIP Researcher' };
		else if (attrs.colorized_groups.indexOf("researcher") > -1)
			return { icon: '', className: 'researcher', title: 'Researcher' };
	});

Next, I want to do some similar customizations for real-time chat – but there is no api.addPosterIcons equivalent for real-time chat messages. Maybe I could use the api.decorateWidget, but the corresponding component for chat is ChatMessageInfo which is a component, not a widget.

Sorry if it is obvious, but what would be a good strategy for customizing ChatMessageInfo from a plugin?

(It is intentional that I am not relying on user primary group since there is some special logic for which one should take priority and I don’t want to have to rely on user/admin setting it properly manually.)

Thank you!

Hey,

I think it won’t be easy. There is no available PluginOutlet in this area (don’t hesitate to request it!)

If you want to add only classnames, you should be able to do this way:

api.modifyClass(
  "component:chat/message/info",
  (Superclass) =>
    class extends Superclass {
      get usernameClasses() {
        let classes = super.usernameClasses;

        // Add extra classes
        classes += " developer";

        return classes;
      }
    }
)

it overwrites this code:

Thanks for the reply! I actually had gone about it with another solution, but I appreciate you offering yours as it seems a bit cleaner (in mine I have to access the class name and my method feels a bit hacky). Here’s the strategy I used:

// Also colorize names in the real-time chat
api.decorateChatMessage(function (messageContainer, chatChannel) 
{
	let colorized_groups = this.args?.message?.user?.colorized_groups;

	if (colorized_groups == null)
		return; // no groups, nothing to do

	const nameClass = "chat-message-info__username__name";						

	let elements = messageContainer.getElementsByClassName(nameClass);
	if (elements.length == 0) // normal: this might be a second message that does not have the username header
		return; 

	let nameDiv = elements[0];

	if (colorized_groups.indexOf("developer") > -1)
		nameDiv.classList.add("developer");
	else if (colorized_groups.indexOf("wip_researcher") > -1)
		nameDiv.classList.add("wip_researcher");
	else if (colorized_groups.indexOf("researcher") > -1)
		nameDiv.classList.add("researcher");
});

I assume with your method, it also still passes the this.args.message.user ?

Good job for finding a way! It’s not that hacky. :smile:
But yes, overwriting the getter is straight and cleaner.

That’s correct. :slight_smile: