From 7c96b952e97bd42a79aafcf99ac307de570b2e67 Mon Sep 17 00:00:00 2001 From: David Dyer Date: Sun, 30 Aug 2026 23:07:24 -0400 Subject: [PATCH] Add password visibility toggle to user and admin forms --- admin/login.php | 29 +++++++++++++++++++++++++- admin/menu.js | 12 ----------- admin/users.js | 54 ++++++++++++++++++++++++++++++++++++++++--------- admin/users.php | 50 ++++++++++++++++++++++++++++++++++++++++----- styles.css | 48 ++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 165 insertions(+), 28 deletions(-) diff --git a/admin/login.php b/admin/login.php index 28d9612..867f1ba 100644 --- a/admin/login.php +++ b/admin/login.php @@ -45,12 +45,39 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
- +
+ + +
← Return to Pub Website + + diff --git a/admin/menu.js b/admin/menu.js index e48a2bc..2709fd4 100644 --- a/admin/menu.js +++ b/admin/menu.js @@ -101,18 +101,6 @@ document.getElementById('btn-cancel-item').addEventListener('click', closeItemMo document.getElementById('btn-close-cat-modal').addEventListener('click', closeCategoryModal); document.getElementById('btn-cancel-cat').addEventListener('click', closeCategoryModal); -// Close on backdrop click -itemModal.addEventListener('click', (e) => { if (e.target === itemModal) closeItemModal(); }); -catModal.addEventListener('click', (e) => { if (e.target === catModal) closeCategoryModal(); }); - -// Close on Escape key -window.addEventListener('keydown', (e) => { - if (e.key === 'Escape') { - closeItemModal(); - closeCategoryModal(); - } -}); - // Form submit: Save Item (Async Fetch) document.getElementById('form-item').addEventListener('submit', async (e) => { e.preventDefault(); diff --git a/admin/users.js b/admin/users.js index 5d731db..547a64e 100644 --- a/admin/users.js +++ b/admin/users.js @@ -23,9 +23,36 @@ async function postForm(formData) { return response.json(); } +const EYE_OPEN_SVG = ` + + + + +`; + +const EYE_OFF_SVG = ` + + + + + + +`; + +function resetPasswordVisibility(form) { + form.querySelectorAll('.password-toggle-btn').forEach((btn) => { + const input = document.getElementById(btn.dataset.target); + if (input) input.type = 'password'; + btn.setAttribute('aria-label', 'Show password'); + btn.innerHTML = EYE_OPEN_SVG; + }); +} + // Add User modal function openUserModal() { - document.getElementById('form-user').reset(); + const form = document.getElementById('form-user'); + form.reset(); + resetPasswordVisibility(form); userModal.classList.add('is-open'); document.getElementById('user-field-username').focus(); } @@ -37,8 +64,10 @@ function closeUserModal() { // Change Password modal function openPasswordModal(userId, username) { const isSelf = String(userId) === currentUserId; + const form = document.getElementById('form-password'); - document.getElementById('form-password').reset(); + form.reset(); + resetPasswordVisibility(form); document.getElementById('password-field-user-id').value = userId; document.getElementById('modal-password-title').textContent = isSelf ? '🔑 Change Your Password' @@ -60,14 +89,21 @@ document.getElementById('btn-cancel-user').addEventListener('click', closeUserMo document.getElementById('btn-close-password-modal').addEventListener('click', closePasswordModal); document.getElementById('btn-cancel-password').addEventListener('click', closePasswordModal); -userModal.addEventListener('click', (e) => { if (e.target === userModal) closeUserModal(); }); -passwordModal.addEventListener('click', (e) => { if (e.target === passwordModal) closePasswordModal(); }); +// Password visibility toggles (works inside both modals) +document.addEventListener('click', (e) => { + const toggleBtn = e.target.closest('.password-toggle-btn'); + if (!toggleBtn) return; -window.addEventListener('keydown', (e) => { - if (e.key === 'Escape') { - closeUserModal(); - closePasswordModal(); - } + const targetId = toggleBtn.dataset.target; + const input = document.getElementById(targetId); + if (!input) return; + + const isPassword = input.type === 'password'; + input.type = isPassword ? 'text' : 'password'; + + toggleBtn.setAttribute('aria-label', isPassword ? 'Hide password' : 'Show password'); + toggleBtn.innerHTML = isPassword ? EYE_OFF_SVG : EYE_OPEN_SVG; + input.focus(); }); // Create user diff --git a/admin/users.php b/admin/users.php index 020f56a..d56561d 100644 --- a/admin/users.php +++ b/admin/users.php @@ -255,12 +255,28 @@ $users = get_all_users();
- +
+ + +
- +
+ + +
@@ -287,17 +303,41 @@ $users = get_all_users();
- +
+ + +
- +
+ + +
- +
+ + +
diff --git a/styles.css b/styles.css index 86f27a2..449c70f 100644 --- a/styles.css +++ b/styles.css @@ -1209,6 +1209,7 @@ .status-badge { display: inline-flex; + flex-direction: row; align-items: center; gap: 0.4rem; font-family: var(--font-mono); @@ -1217,6 +1218,8 @@ text-transform: uppercase; padding: 0.25rem 0.6rem; border-radius: 0.125rem; + white-space: nowrap; + line-height: 1.2; } .status-badge.active { @@ -1268,7 +1271,12 @@ display: inline-flex; gap: 0.5rem; align-items: center; - flex-wrap: wrap; + flex-wrap: nowrap; + white-space: nowrap; + } + + .admin-table-actions .btn { + white-space: nowrap; } .btn-sm { @@ -1536,6 +1544,44 @@ margin-bottom: 2rem; } + /* password toggle input wrapper */ + .password-input-wrap { + position: relative; + display: flex; + align-items: center; + } + + .password-input-wrap .form-control, + .password-input-wrap .form-input { + padding-right: 2.75rem; + } + + .password-toggle-btn { + position: absolute; + right: 0.5rem; + top: 50%; + transform: translateY(-50%); + background: transparent; + border: none; + color: var(--ink-muted); + cursor: pointer; + padding: 0.35rem; + display: flex; + align-items: center; + justify-content: center; + border-radius: 0.125rem; + transition: color .15s ease; + } + + .password-toggle-btn:hover { + color: var(--gold-bright); + } + + .password-toggle-btn svg { + width: 1.15rem; + height: 1.15rem; + } + /* menu page specific headers & spacing */ .menu-page-header { padding-block: 4.5rem 2.5rem;