The unboundClassNames()
method we used above is responsible for the classes added to the component element. In other words the .topic-list-item
or .latest-topic-list-item
HTML elements. You can see that here
discourse/app/assets/javascripts/discourse/app/components/topic-list-item.js at ad4faf637c9caf7e6ac60a614e3838a69c928e27 · discourse/discourse · GitHub
and here
discourse/app/assets/javascripts/discourse/app/components/latest-topic-list-item.js at 1472e47aae5bfdfb6fd9abfe89beb186c751f514 · discourse/discourse · GitHub
Ember takes whatever string that method returns and adds that as the class
attribute on the element itself.
You’ll have to use something else if you want to add classes to children of that element.
Each poster in the posters
property has a property called extras.
This property is used as a flag for extra classes to be added to the avatar when its rendered.
It’s set here
discourse/app/assets/javascripts/discourse/app/models/topic-list.js at d3a59e3f695c467c22d02db62532194e17ac827b · discourse/discourse · GitHub
and consumed here
discourse/app/assets/javascripts/discourse/app/templates/list/posters-column.hbr at 1472e47aae5bfdfb6fd9abfe89beb186c751f514 · discourse/discourse · GitHub
So, you can add classes to avatars in the topic list based on a condition if you extend that property.
You can use the @on
decorator when the component receives its attributes to call a method to do that. Since we’re already modifying those component Classes, we can do incorporate that new behavior into the code above.
Here’s what we end up with
in the initializer
import { apiInitializer } from "discourse/lib/api";
import discourseComputed, { on } from "discourse-common/utils/decorators";
export default apiInitializer("0.11.1", (api) => {
const PLUGIN_ID = "hide-ignored-op-topics";
const IGNORED_TOPIC_CLASS_STRING = " ignored-op-topic";
const IGNORED_AVATAR_CLASS_STRING = " ignored-user-avatar";
const user = api.getCurrentUser();
if (!user) {
return;
}
const ignoredUsers = user.ignored_users;
function isIgnoredUser(poster) {
return ignoredUsers.includes(poster.user.username);
}
function addIgnoredTopicClass() {
let classList = this._super(...arguments);
const topicCreator = this.topic.posters[0];
if (isIgnoredUser(topicCreator)) {
classList += IGNORED_TOPIC_CLASS_STRING;
}
return classList;
}
function addIgnoredAvatarClass() {
this.topic.posters.forEach((poster) => {
if (isIgnoredUser(poster)) {
// default raw topic-lists
poster.extras += IGNORED_AVATAR_CLASS_STRING;
// categories page topic lists
poster.user.set("extras", IGNORED_AVATAR_CLASS_STRING);
}
});
}
api.modifyClass("component:topic-list-item", {
pluginId: PLUGIN_ID,
@discourseComputed()
unboundClassNames() {
return addIgnoredTopicClass.call(this);
},
@on("didReceiveAttrs")
ignoredAvatarClass() {
addIgnoredAvatarClass.call(this);
},
});
api.modifyClass("component:latest-topic-list-item", {
pluginId: PLUGIN_ID,
@discourseComputed()
unboundClassNames() {
return addIgnoredTopicClass.call(this);
},
@on("didReceiveAttrs")
ignoredAvatarClass() {
addIgnoredAvatarClass.call(this);
},
});
});
This should give you a ignored-op-topic
CSS class on topic list items started by an ignored user and a ignored-user-avatar
CSS class on every ignored user avatar in the posters column.
We already have the CSS for the .ignored-op-topic
from above.
// we don't use display: none; here because we don't want to mess with load-more
.ignored-op-topic {
height: 0;
width: 0;
position: fixed;
bottom: 0;
}
Now, you want to hide ignored user avatars in the poster column.
Don’t do that. This will create a lot of confusion.
What if an ignored user replies to a topic, and it gets bumped, but you have their avatar hidden? It would make it look like someone else just bumped the topic.
Also, there’s only one avatar on the categories page next to topic titles. What happens if the last reply is by an ignored user? No avatar?
You can see how such cases would create an unpleasant experience for your users.
Instead of hiding ignored user avatars, you can swap them out with an SVG icon. All ignored users will have that same avatar. You can do that with CSS
.ignored-user-avatar {
background: white;
border: 1px solid transparent;
box-sizing: border-box;
opacity: 0.5;
content: svg-uri(
'<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m256 0c141.385 0 256 114.615 256 256s-114.615 256-256 256-256-114.615-256-256 114.615-256 256-256zm0 105c-83.262 0-151 67.74-151 151s67.737 151 151 151 151-67.736 151-151-67.74-151-151-151zm-52.816 130.621a22.119 22.119 0 1 0 0-44.237 22.119 22.119 0 0 0 0 44.237zm127.749-22.121a22.116 22.116 0 0 0 -22.12-22.12 22.119 22.119 0 1 0 22.12 22.12zm-40.233 70.79a9.439 9.439 0 0 0 -13.35-13.347l-21.35 21.357-21.352-21.357a9.438 9.438 0 1 0 -13.348 13.347l21.352 21.352-21.352 21.358a9.438 9.438 0 1 0 13.347 13.347l21.353-21.355 21.351 21.351a9.439 9.439 0 0 0 13.349-13.343l-21.352-21.354z"/></svg>'
);
}
and it will render like so
and the same on latest-topic-list-item
. Change the SVG to any icon you want to use.
With that out of the way…
I answered your question because it’s a good opportunity to talk about customizing the topic list and how you would do that. However, I have a lot of reservations about your use case. The need to hide the avatars of ignored users indicates an underlying problem. It’s one thing to say
“this person writes about subjects I’m not interested in. I will ignore them to reduce the noise.”
but it’s an entirely different thing to say
“even seeing this person’s avatar triggers an emotional response. I never want to see their avatar again.”
You know your community more than anyone… but it’s probably something worth looking into.