From c6504f70d1c770f1627be6e0a4c3948194513401 Mon Sep 17 00:00:00 2001 From: Zaki <18zaki18@gmail.com> Date: Fri, 8 May 2026 23:35:59 +0100 Subject: [PATCH] UI improvements: fix keyboard shortcuts, search highlighting, strength meter on register, colored folders, shortcut help - Rewrite keyboard shortcuts using e.code and early preventDefault() to reliably override browser defaults - Add ? key and toolbar button for shortcuts help modal - Add password strength meter to register form - Add search highlighting in all view modes (grid/list/compact/table) - Add hash-based color coding for folder chips - Add highlightText utility with regex escaping --- css/style.css | 4 +- index.html | 4 +- js/app.js | 108 +++++++++++++++++++++++++++++---------------- security-issues.md | 8 ++++ 4 files changed, 84 insertions(+), 40 deletions(-) create mode 100644 security-issues.md diff --git a/css/style.css b/css/style.css index 74e9ed0..64aa8df 100644 --- a/css/style.css +++ b/css/style.css @@ -115,8 +115,8 @@ input:focus, select:focus { border-color:var(--accent); } /* Folders */ .folders-bar { display:flex; gap:0.4rem; margin-bottom:0.8rem; flex-wrap:wrap; align-items:center; padding:0.4rem 0.6rem; background:rgba(0,0,0,0.2); border-radius:1rem; } .folder-chip { background:var(--bg2); border:1px solid var(--border); color:var(--text2); padding:0.3rem 0.8rem; border-radius:2rem; cursor:pointer; font-size:0.78rem; transition:0.2s; white-space:nowrap; } -.folder-chip:hover { background:var(--accent); color:#fff; border-color:var(--accent); } -.folder-chip.active { background:var(--accent); color:#fff; border-color:var(--accent); } +.folder-chip:hover { background:var(--chip-color, var(--accent)); color:#fff; border-color:var(--chip-color, var(--accent)); } +.folder-chip.active { background:var(--chip-color, var(--accent)); color:#fff; border-color:var(--chip-color, var(--accent)); } .folder-count { background:rgba(0,0,0,0.3); padding:0.1rem 0.4rem; border-radius:1rem; margin-left:0.3rem; font-size:0.7rem; } .folder-delete-btn { background:transparent; border:none; color:var(--danger); cursor:pointer; font-size:0.7rem; margin-left:0.2rem; opacity:0.7; } .folder-delete-btn:hover { opacity:1; } diff --git a/index.html b/index.html index 2756ccb..78555f7 100644 --- a/index.html +++ b/index.html @@ -77,9 +77,10 @@ @@ -149,6 +150,7 @@
+
diff --git a/js/app.js b/js/app.js index c63bcec..1a110f2 100644 --- a/js/app.js +++ b/js/app.js @@ -13,6 +13,7 @@ let entries = []; let folders = ['All']; let genPwdVal = ''; let cryptoKey = null; +let searchQuery = ''; let idleT, warnT, countT; let draggedId = null; let showTrash = false; @@ -185,6 +186,13 @@ async function deleteFolderFromServer(name) { } catch (e) { toast('⚠️ Connection error', 'error'); return false; } } +function folderColor(name) { + if (name === 'All') return ''; + let hash = 0; + for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash); + const hue = ((hash % 360) + 360) % 360; + return `style="--chip-color:hsl(${hue},60%,55%)"`; +} function renderFolders() { const bar = document.getElementById('foldersBar'); if (!bar) return; @@ -195,7 +203,8 @@ function renderFolders() { folders.forEach(f => { if (!f) return; const count = counts[f] || 0; - html += `📁 ${esc(f)}${count}${f !== 'All' ? `` : ''}`; + const color = folderColor(f); + html += `📁 ${esc(f)}${count}${f !== 'All' ? `` : ''}`; }); html += ``; bar.innerHTML = html; @@ -366,6 +375,17 @@ function closeAdd() { playSound('close'); } +function checkRegStrength() { + const p = document.getElementById('regPassword').value; + const bar = document.getElementById('regStrengthBar'); + let s = 0; + if (p.length >= 8) s++; + if (p.length >= 12) s++; + if (/[A-Z]/.test(p) && /[a-z]/.test(p)) s++; + if (/\d/.test(p)) s++; + if (/[!@#$%^&*()_+\-=\[\]{}|;:,.<>?]/.test(p)) s++; + bar.className = 'strength-bar s' + Math.min(4, s); +} function checkAddStrength() { const p = document.getElementById('addPassword').value; const bar = document.getElementById('addStrengthBar'); @@ -507,8 +527,8 @@ function render() { let h = '' + (showMail ? '' : '') + '' + (!showTrash ? '' : '') + ''; filtered.forEach(e => { h += '' + - '' + - (showMail ? '' : '') + + '' + + (showMail ? '' : '') + ''; if (!showTrash) { h += '' + @@ -556,8 +576,8 @@ function gridC(e) { html += ''; } html += ''; - html += '
🌐 ' + esc(e.site) + '
'; - if (showMail) html += '
👤 ' + esc(e.username) + '
'; + html += '
🌐 ' + highlightText(e.site, searchQuery) + '
'; + if (showMail) html += '
👤 ' + highlightText(e.username, searchQuery) + '
'; html += '
📁 ' + esc(e.folder || 'All') + '
'; if (!showTrash) { html += '
••••••••
' + @@ -583,8 +603,8 @@ function listC(e) { html += ''; } html += '
'; - html += '
SiteUserPasswordFolderDeletedActions
🌐 ' + esc(e.site) + '👤 ' + esc(e.username) + '🌐 ' + highlightText(e.site, searchQuery) + '👤 ' + highlightText(e.username, searchQuery) + '••••••••📁 ' + esc(e.folder || 'All') + '