mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Admin ring on comments/channel + pending-submissions dots on Admin tab & Submissions subtab
- adminBadge.js: add applyAdminRing(el, id) for surfaces that already place the star on a specific element and just need the ring. - comments: ring + star on admin authors' avatars; round the comment avatar box so the ring reads as a circle. - channel page: ring the inner rounded avatar box (star already on the wrap). - Notification dots: red dot on the profile modal's Admin nav tab and on the Submissions subtab button when there are pending submissions, so admins know where to look. profileModalController.setSubmissionsUnreadIndicator toggles both (Admin nav dot gated on the tab being visible); driven from applyProfileNotificationDot off app._submissionsPending. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
37edbd18d2
commit
d091ce8bac
7 files changed
+100
-7
No files matched your search
@@ -423,6 +423,11 @@
|
||||
/>
|
||||
</svg>
|
||||
Admin (Moderation)
|
||||
<span
|
||||
id="profileNavAdminUnreadDot"
|
||||
class="profile-nav__unread-dot"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
</button>
|
||||
<button
|
||||
id="profileMobileLockNowBtn"
|
||||
@@ -1884,9 +1889,14 @@
|
||||
data-admin-subtab="submissions"
|
||||
aria-controls="adminSubmissionsSection"
|
||||
aria-selected="false"
|
||||
class="btn-ghost focus-ring px-3 py-1.5 text-sm font-medium hidden"
|
||||
class="admin-subtab-has-dot btn-ghost focus-ring px-3 py-1.5 text-sm font-medium hidden"
|
||||
>
|
||||
Submissions
|
||||
<span
|
||||
id="adminSubtabSubmissionsDot"
|
||||
class="admin-subtab-dot"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -2764,6 +2764,8 @@
|
||||
position: relative;
|
||||
inline-size: var(--comment-avatar-size);
|
||||
block-size: var(--comment-avatar-size);
|
||||
/* rounded so the admin ring (box-shadow) reads as a circle */
|
||||
border-radius: var(--radius-full);
|
||||
}
|
||||
|
||||
.comment-thread__avatar img {
|
||||
@@ -3561,6 +3563,30 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Pending-submissions dot on the Admin pane's "Submissions" subtab. The
|
||||
subtabs sit in a horizontal row, so this dot rides the top-right corner
|
||||
(not the left edge like the vertical nav dots). */
|
||||
.admin-subtab-has-dot {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.admin-subtab-dot {
|
||||
position: absolute;
|
||||
top: calc(-1 * var(--space-3xs));
|
||||
right: calc(-1 * var(--space-3xs));
|
||||
width: var(--space-sm);
|
||||
height: var(--space-sm);
|
||||
border-radius: var(--radius-full);
|
||||
border: var(--border-width-hairline) solid var(--surface-panel);
|
||||
background-color: var(--status-danger);
|
||||
display: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.admin-subtab-dot.is-visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.profile-modal__panes {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
|
||||
@@ -10,7 +10,7 @@ import { subscriptions } from "./subscriptions.js";
|
||||
import { attachHealthBadges } from "./gridHealth.js";
|
||||
import { attachUrlHealthBadges } from "./urlHealthObserver.js";
|
||||
import { accessControl } from "./accessControl.js";
|
||||
import { applyAdminStar } from "./ui/adminBadge.js";
|
||||
import { applyAdminStar, applyAdminRing } from "./ui/adminBadge.js";
|
||||
import { getApplication } from "./applicationContext.js";
|
||||
import { escapeHTML } from "./utils/domUtils.js";
|
||||
import { formatShortNpub } from "./utils/formatters.js";
|
||||
@@ -5161,6 +5161,9 @@ function applyChannelProfileMetadata({
|
||||
|
||||
const blurPubkey = pubkey || currentChannelHex || "";
|
||||
applyAdminStar(document.getElementById("channelAvatarWrap"), blurPubkey);
|
||||
// Ring the inner rounded avatar box (the wrap is a non-clipped positioning
|
||||
// shell; the box-shadow ring belongs on the circular element itself).
|
||||
applyAdminRing(avatarEl?.parentElement, blurPubkey);
|
||||
updateChannelModerationVisuals({
|
||||
bannerEl,
|
||||
avatarEl,
|
||||
|
||||
@@ -90,6 +90,23 @@ export function applyAdminStar(
|
||||
return setAdminStar(container, isAdminActor(pubkeyOrNpub), { doc, label });
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle just the gold ring on a circular element (for surfaces that already
|
||||
* place the star on a specific element and only need the ring added). The
|
||||
* element should be circular (border-radius) for the ring to read right.
|
||||
* @param {Element|null} el
|
||||
* @param {string} pubkeyOrNpub
|
||||
* @returns {boolean} whether the ring is applied
|
||||
*/
|
||||
export function applyAdminRing(el, pubkeyOrNpub) {
|
||||
if (!el || !el.classList) {
|
||||
return false;
|
||||
}
|
||||
const isAdmin = isAdminActor(pubkeyOrNpub);
|
||||
el.classList.toggle(ADMIN_RING_CLASS, isAdmin);
|
||||
return isAdmin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorate a circular avatar element with BOTH the admin ring and the corner
|
||||
* star. `avatarEl` is the circular element (an <img> or a clip container). The
|
||||
@@ -138,5 +155,6 @@ export default {
|
||||
ADMIN_WRAP_CLASS,
|
||||
isAdminActor,
|
||||
applyAdminStar,
|
||||
applyAdminRing,
|
||||
decorateAdminAvatar,
|
||||
};
|
||||
@@ -879,6 +879,16 @@ export default class ApplicationBootstrap {
|
||||
) {
|
||||
app.profileController.setMessagesUnreadIndicator(app._dmUnread);
|
||||
}
|
||||
// Pending-submissions dots on the Admin tab + Submissions subtab so an
|
||||
// admin knows exactly where to look.
|
||||
if (
|
||||
app.profileController &&
|
||||
typeof app.profileController.setSubmissionsUnreadIndicator === "function"
|
||||
) {
|
||||
app.profileController.setSubmissionsUnreadIndicator(
|
||||
app._submissionsPending,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
app.refreshUnreadDmIndicator = async ({ reason = "" } = {}) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { UI_FEEDBACK_DELAY_MS } from "../../../constants.js";
|
||||
import { formatAbsoluteTimestamp, formatTimeAgo } from "../../../utils/formatters.js";
|
||||
import { registerCommentAvatarFailure as registerCommentAvatarFailureUtil } from "./utils/commentAvatar.js";
|
||||
import { applyAdminStar } from "../../adminBadge.js";
|
||||
import { applyAdminStar, applyAdminRing } from "../../adminBadge.js";
|
||||
|
||||
export class CommentNodeFactory {
|
||||
constructor({ document, window, logger, dispatch, DEFAULT_PROFILE_AVATAR }) {
|
||||
@@ -46,11 +46,11 @@ export class CommentNodeFactory {
|
||||
const avatarLabel = this.document.createElement("span");
|
||||
avatarWrapper.appendChild(avatarLabel);
|
||||
|
||||
// Gold admin star for comments authored by a bitvid admin.
|
||||
// Gold admin ring + star for comments authored by a bitvid admin.
|
||||
if (typeof event.pubkey === "string" && event.pubkey.trim()) {
|
||||
applyAdminStar(avatarWrapper, event.pubkey.trim(), {
|
||||
doc: this.document,
|
||||
});
|
||||
const authorKey = event.pubkey.trim();
|
||||
applyAdminRing(avatarWrapper, authorKey);
|
||||
applyAdminStar(avatarWrapper, authorKey, { doc: this.document });
|
||||
}
|
||||
|
||||
const content = this.document.createElement("div");
|
||||
|
||||
@@ -721,6 +721,12 @@ export class ProfileModalController {
|
||||
this.navButtons.admin = document.getElementById("profileNavAdmin") || null;
|
||||
this.navButtons.safety = document.getElementById("profileNavSafety") || null;
|
||||
|
||||
// Pending-submissions dots: on the Admin nav tab and the Submissions subtab.
|
||||
this.adminNavUnreadDot =
|
||||
document.getElementById("profileNavAdminUnreadDot") || null;
|
||||
this.adminSubmissionsDot =
|
||||
document.getElementById("adminSubtabSubmissionsDot") || null;
|
||||
|
||||
this.profileEditBtn = document.getElementById("profileEditBtn") || null;
|
||||
this.profileEditBackBtn = document.getElementById("profileEditBackBtn") || null;
|
||||
|
||||
@@ -1353,6 +1359,26 @@ export class ProfileModalController {
|
||||
);
|
||||
}
|
||||
|
||||
// Pending-submissions dots for admins: on the Admin nav tab (gated on that tab
|
||||
// being visible) and on the Submissions subtab button inside the admin pane.
|
||||
setSubmissionsUnreadIndicator(visible) {
|
||||
const show = Boolean(visible);
|
||||
const adminButton = this.navButtons.admin;
|
||||
const adminNavVisible =
|
||||
adminButton instanceof HTMLElement &&
|
||||
!adminButton.classList.contains("hidden") &&
|
||||
!adminButton.hasAttribute("hidden");
|
||||
if (this.adminNavUnreadDot instanceof HTMLElement) {
|
||||
this.adminNavUnreadDot.classList.toggle(
|
||||
"is-visible",
|
||||
show && adminNavVisible,
|
||||
);
|
||||
}
|
||||
if (this.adminSubmissionsDot instanceof HTMLElement) {
|
||||
this.adminSubmissionsDot.classList.toggle("is-visible", show);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user