feat(users): govern profiles and access

Normalize fixed profile fields, profile actions, and the five-column capability matrix for comments, uploads, and downloads.
This commit is contained in:
2026-08-13 00:24:54 +08:00
parent 0b06b2c7df
commit 8241570ca2
67 changed files with 780 additions and 1127 deletions
+42
View File
@@ -258,8 +258,50 @@
});
}
function initCoverMenus() {
document.querySelectorAll('[data-aksrt-menu]').forEach(function (menu) {
if (menu.dataset.aksrtMenuBound === '1') return;
menu.dataset.aksrtMenuBound = '1';
var trigger = menu.querySelector('.aksrt-cover-menu__trigger');
var panel = menu.querySelector('.aksrt-cover-menu__panel');
if (!trigger || !panel) return;
function close() { panel.hidden = true; trigger.setAttribute('aria-expanded', 'false'); }
function open() {
document.querySelectorAll('[data-aksrt-menu]').forEach(function (otherMenu) {
if (otherMenu === menu) return;
var otherPanel = otherMenu.querySelector('.aksrt-cover-menu__panel');
var otherTrigger = otherMenu.querySelector('.aksrt-cover-menu__trigger');
if (otherPanel) otherPanel.hidden = true;
if (otherTrigger) otherTrigger.setAttribute('aria-expanded', 'false');
});
panel.hidden = false;
trigger.setAttribute('aria-expanded', 'true');
var first = panel.querySelector('[role="menuitem"]');
if (first) first.focus();
}
trigger.addEventListener('click', function () { panel.hidden ? open() : close(); });
menu.addEventListener('keydown', function (event) { if (event.key === 'Escape') { close(); trigger.focus(); } });
document.addEventListener('pointerdown', function (event) { if (!menu.contains(event.target)) close(); });
});
}
function initProfileDetailsModal() {
var modal = document.getElementById('aksrt-profile-details-modal');
if (!modal) return;
var dialog = modal.querySelector('.aksrt-profile-details-modal__dialog');
var returnFocus = null;
function close() { modal.hidden = true; if (returnFocus) returnFocus.focus(); }
document.querySelectorAll('[data-aksrt-profile-details]').forEach(function (button) {
button.addEventListener('click', function () { returnFocus = button; modal.hidden = false; if (dialog) dialog.focus(); });
});
modal.querySelectorAll('[data-aksrt-modal-close]').forEach(function (button) { button.addEventListener('click', close); });
document.addEventListener('keydown', function (event) { if (event.key === 'Escape' && !modal.hidden) close(); });
}
function init() {
initPublicDashboards();
initCoverMenus();
initProfileDetailsModal();
initCoverUpload();
initAvatarUpload();
}