Метод unboundClassNames(), который мы использовали выше, отвечает за классы, добавляемые к элементу компонента. Иными словами, это HTML-элементы .topic-list-item или .latest-topic-list-item. Вы можете увидеть это здесь:
discourse/app/assets/javascripts/discourse/app/components/topic-list-item.js at ad4faf637c9caf7e6ac60a614e3838a69c928e27 · discourse/discourse · GitHub
и здесь:
discourse/app/assets/javascripts/discourse/app/components/latest-topic-list-item.js at 1472e47aae5bfdfb6fd9abfe89beb186c751f514 · discourse/discourse · GitHub
Ember берет любую строку, возвращаемую этим методом, и добавляет её как атрибут class самого элемента.
Если вы хотите добавить классы к дочерним элементам этого элемента, вам придется использовать что-то другое.
У каждого автора в свойстве posters есть свойство под названием extras. Это свойство используется как флаг для добавления дополнительных классов к аватару при его отображении.
Оно устанавливается здесь:
discourse/app/assets/javascripts/discourse/app/models/topic-list.js at d3a59e3f695c467c22d02db62532194e17ac827b · discourse/discourse · GitHub
и используется здесь:
discourse/app/assets/javascripts/discourse/app/templates/list/posters-column.hbr at 1472e47aae5bfdfb6fd9abfe89beb186c751f514 · discourse/discourse · GitHub
Таким образом, вы можете добавлять классы к аватарам в списке тем на основе условия, если расширите это свойство.
Вы можете использовать декоратор @on, когда компонент получает свои атрибуты, чтобы вызвать метод для этого. Поскольку мы уже изменяем классы этих компонентов, мы можем включить это новое поведение в код выше.
Вот что у нас получается:
в инициализаторе
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);
},
});
});
Это должно добавить CSS-класс ignored-op-topic к элементам списка тем, созданным игнорируемым пользователем, и CSS-класс ignored-user-avatar к каждому аватару игнорируемого пользователя в столбце авторов.
У нас уже есть CSS для .ignored-op-topic из предыдущего примера.
// мы не используем display: none; здесь, потому что не хотим нарушать работу load-more
.ignored-op-topic {
height: 0;
width: 0;
position: fixed;
bottom: 0;
}
Теперь вы хотите скрыть аватары игнорируемых пользователей в столбце авторов.
Не делайте этого. Это вызовет много путаницы.
Что, если игнорируемый пользователь ответит на тему, и она будет поднята, но вы скроете его аватар? Это создаст впечатление, что тему поднял кто-то другой.
Кроме того, на странице категорий рядом с заголовками тем есть только один аватар. Что произойдет, если последний ответ был от игнорируемого пользователя? Никакого аватара?
Вы можете понять, как такие случаи могут создать неприятный опыт для ваших пользователей.
Вместо того чтобы скрывать аватары игнорируемых пользователей, вы можете заменить их на SVG-иконку. У всех игнорируемых пользователей будет один и тот же аватар. Это можно сделать с помощью 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>'
);
}
и это будет отображаться так:
и то же самое для latest-topic-list-item. Замените SVG на любую иконку, которую вы хотите использовать.
Теперь, когда это сделано…
Я ответил на ваш вопрос, потому что это хорошая возможность поговорить о кастомизации списка тем и о том, как это сделать. Однако у меня есть много сомнений относительно вашего случая использования. Необходимость скрывать аватары игнорируемых пользователей указывает на лежащую в основе проблему. Одно дело сказать:
“этот человек пишет на темы, которые меня не интересуют. Я проигнорирую его, чтобы уменьшить шум.”
но это совершенно другое дело сказать:
“даже вид аватара этого человека вызывает эмоциональную реакцию. Я никогда больше не хочу видеть его аватар.”
Вы знаете свое сообщество лучше всех… но, возможно, стоит разобраться в этом.