Admin star badge on admin avatars across the app

Show a small gold "verified admin" star in the corner opposite the red
notification dot whenever a rendered profile belongs to a bitvid admin
(the super admin or a current list editor).

- adminBadge.js (new): isAdminActor(hex|npub) sync check against
  accessControl, and applyAdminStar(container, id) which adds/removes a
  single `.admin-star` in a non-clipped, positioned container. Idempotent.
- CSS: `.admin-star` (top-left gold disc, mirrors the top-right dot),
  `.dm-avatar-wrap`, and position:relative on the comment avatar wrapper.
- Profile button: app.refreshAdminStar() lights the logged-in user's star;
  re-runs on login/logout and on accessControl.onEditorsChange (so a
  late-loading editor list still resolves).
- Comments: star on comment-author avatars (commentNodeFactory).
- Channel page: wrap the clipped avatar and star the channel owner.
- DMs: Avatar gains an opt-in adminId — only admin avatars get wrapped so
  non-admin rows are byte-identical; ContactRow passes the peer pubkey.
- tests: admin-badge unit coverage (recognition, idempotency, removal).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
thePR0M3TH3ANandClaude Opus 4.8 committed 2026-07-07 10:10:19 -04:00
1 parent 2803f6b56f
commit 610935ac03
10 files changed
+233 -10

No files matched your search

+22
View File
@@ -35,6 +35,7 @@ import { relayManager } from "../relayManager.js";
import { userBlocks } from "../userBlocks.js";
import { subscriptions } from "../subscriptions.js";
import { accessControl } from "../accessControl.js";
import { applyAdminStar } from "./adminBadge.js";
import moderationService from "../services/moderationService.js";
import ProfileIdentityController from "./profileIdentityController.js";
import VideoListViewController from "./videoListViewController.js";
@@ -977,6 +978,21 @@ export default class ApplicationBootstrap {
app.applyProfileNotificationDot();
};
// The profile button shows the logged-in user; light its admin star when
// that user is a bitvid admin. Re-runs on editor-list load so a moderator
// added after startup still gets the star.
app.refreshAdminStar = () => {
try {
const npub =
typeof app.getCurrentUserNpub === "function"
? app.getCurrentUserNpub()
: "";
applyAdminStar(app.profileButton, npub || "");
} catch (error) {
devLogger.warn("[Application] Failed to refresh admin star", error);
}
};
const nostrUnsubscribes = [];
nostrUnsubscribes.push(
app.nostrService.on("subscription:changed", ({ subscription }) => {
@@ -1050,6 +1066,12 @@ export default class ApplicationBootstrap {
}
nostrUnsubscribes.push(() => clearInterval(submissionsPollId));
void app.refreshSubmissionsIndicator({ reason: "startup" });
if (typeof accessControl.onEditorsChange === "function") {
nostrUnsubscribes.push(
accessControl.onEditorsChange(() => app.refreshAdminStar?.()),
);
}
app.refreshAdminStar();
app.unsubscribeFromNostrService = () => {
while (nostrUnsubscribes.length) {
const unsubscribe = nostrUnsubscribes.pop();