// retoor <retoor@molodetz.nl>
const ROSTER_TOPIC = "public.presence.roster";
export class OnlineUsers {
constructor(pubsub) {
this.list = document.querySelector("[data-online-users-list]");
if (!this.list) return;
this.countEl = document.querySelector("[data-online-count]");
this.emptyText = this.list.dataset.emptyText || "No one online right now";
if (pubsub) {
pubsub.subscribe(ROSTER_TOPIC, (data) => this.render(data));
}
}
render(data) {
if (!data || !Array.isArray(data.users)) return;
if (this.countEl) {
this.countEl.textContent = data.count != null ? data.count : data.users.length;
}
this.list.textContent = "";
if (!data.users.length) {
const empty = document.createElement("span");
empty.className = "online-empty";
empty.textContent = this.emptyText;
this.list.appendChild(empty);
return;
}
for (const user of data.users) {
this.list.appendChild(this.buildItem(user));
}
}
buildItem(user) {
const seed = user.avatar_seed || user.username;
const link = document.createElement("a");
link.href = "/profile/" + user.username;
link.className = "online-user";
link.title = user.username;
const badge = document.createElement("span");
badge.className = "avatar-badge";
const img = document.createElement("img");
img.className = "avatar-img avatar-sm";
img.src = "/avatar/multiavatar/" + encodeURIComponent(seed) + "?size=32";
img.alt = user.username;
img.loading = "lazy";
const dot = document.createElement("span");
dot.className = "presence-dot online";
dot.setAttribute("aria-hidden", "true");
badge.appendChild(img);
badge.appendChild(dot);
if (user.award_prominent && user.last_award_slug) {
const award = document.createElement("img");
award.className = "award-badge";
award.src = `/awards/${encodeURIComponent(user.last_award_slug)}/64`;
award.alt = "Latest award";
award.loading = "lazy";
badge.appendChild(award);
}
link.appendChild(badge);
return link;
}
}