d50aea6845
Replace view toggle buttons with dropdown menu containing all 7 views. Card view: 2-column grid with bigger cards. Grouped view: entries grouped by folder with sticky headers. Detail view: single entry at a time, large text, prev/next navigation. Arrow key navigation for detail view.
218 lines
14 KiB
HTML
218 lines
14 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>🔐 Vault</title>
|
||
<link rel="stylesheet" href="css/style.css">
|
||
</head>
|
||
<body>
|
||
<div class="toast-container" id="toastContainer"></div>
|
||
<div class="idle-warning" id="idleWarning">
|
||
<h3>⏰ Auto-lock</h3>
|
||
<p>Vault locks in <span id="idleCountdown">30</span>s</p>
|
||
<button class="btn btn-sm" onclick="resetIdle()">Stay Unlocked</button>
|
||
</div>
|
||
|
||
<div class="edit-modal" id="editModal">
|
||
<div class="edit-box">
|
||
<h3>✏️ Edit Entry</h3>
|
||
<label>Website / App</label><input type="text" id="editSite" placeholder="example.com">
|
||
<label style="margin-top:.6rem">Username / Email</label><input type="text" id="editUsername" placeholder="user@example.com">
|
||
<label style="margin-top:.6rem">Password</label>
|
||
<div style="position:relative">
|
||
<input type="password" id="editPassword" placeholder="Password" style="width:100%;padding-right:40px">
|
||
<button type="button" onclick="toggleEditPassword()" style="position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:.9rem">👁️</button>
|
||
</div>
|
||
<label style="margin-top:.6rem">Folder</label>
|
||
<select id="editFolder" style="width:100%;margin-bottom:.4rem"></select>
|
||
<input type="hidden" id="editId">
|
||
<div style="display:flex;gap:.5rem;margin-top:1rem">
|
||
<button class="btn" onclick="saveEdit()">💾 Save</button>
|
||
<button class="btn btn-outline" onclick="closeEdit()">Cancel</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- Add Password Modal -->
|
||
<div class="modal-overlay" id="addModal">
|
||
<div class="modal-box">
|
||
<h3>➕ New Password</h3>
|
||
<label>Website / App</label><input type="text" id="addSite" placeholder="example.com">
|
||
<label style="margin-top:.6rem">Username / Email (optional)</label><input type="text" id="addUsername" placeholder="user@example.com">
|
||
<label style="margin-top:.6rem">Password</label>
|
||
<div style="position:relative">
|
||
<input type="password" id="addPassword" placeholder="Password" style="width:100%;padding-right:40px" oninput="checkAddStrength()">
|
||
<button type="button" onclick="openGen()" style="position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:1.1rem;line-height:1" title="Generate">🎲</button>
|
||
</div>
|
||
<div class="strength-bar s0" id="addStrengthBar" style="margin-top:0.2rem;"></div>
|
||
<label style="margin-top:.6rem">Folder</label>
|
||
<select id="addFolder" style="width:100%;margin-bottom:.4rem"></select>
|
||
<div style="display:flex;gap:.5rem;margin-top:1rem">
|
||
<button class="btn" id="addEntryBtn" onclick="addEntry()">💾 Save</button>
|
||
<button class="btn btn-outline" onclick="closeAdd()">Cancel</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Floating action button -->
|
||
<button class="fab" onclick="openAdd()" title="Add password">+</button>
|
||
<div class="vault">
|
||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:0.6rem">
|
||
<h1 style="margin-bottom:0">🔐 Vault <span>XAMPP</span></h1>
|
||
<button class="btn btn-outline btn-xs" onclick="toggleTheme()" title="Toggle theme">🌓</button>
|
||
</div>
|
||
|
||
<!-- Auth Section -->
|
||
<div id="authSection" class="auth-section">
|
||
<div class="auth-tabs">
|
||
<button class="auth-tab active" onclick="switchTab('login')">Login</button>
|
||
<button class="auth-tab" onclick="switchTab('register')">Register</button>
|
||
</div>
|
||
<div id="loginForm">
|
||
<div class="input-group">
|
||
<input type="text" id="loginUsername" placeholder="Username" autocomplete="off">
|
||
<input type="password" id="loginPassword" placeholder="Master Password" autocomplete="off">
|
||
<button class="btn" id="loginBtn" onclick="login()">🔓 Unlock</button>
|
||
<button class="btn btn-outline btn-sm" onclick="loginWithPasskey()" title="Use passkey" style="white-space:nowrap">🔐 Passkey</button>
|
||
</div>
|
||
</div>
|
||
<div id="registerForm" class="hidden">
|
||
<div class="input-group">
|
||
<input type="text" id="regUsername" placeholder="Username (min 3)" autocomplete="off">
|
||
<input type="password" id="regPassword" placeholder="Password (min 8)" autocomplete="off" oninput="checkRegStrength()">
|
||
<button class="btn" id="registerBtn" onclick="register()">✨ Create</button>
|
||
</div>
|
||
<div class="strength-bar s0" id="regStrengthBar" style="margin-top:0.4rem;margin-bottom:0.2rem;flex-basis:100%"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Vault Section -->
|
||
<div id="vaultSection" class="hidden">
|
||
<!-- Top bar -->
|
||
<div style="display:flex;justify-content:space-between;margin-bottom:.5rem;align-items:center;flex-wrap:wrap;gap:.4rem">
|
||
<span class="status-badge" id="connectionStatus">🟢 Connected</span>
|
||
<span id="entryCount" style="color:var(--text2);font-size:.8rem"></span>
|
||
<div style="display:flex;gap:.4rem;align-items:center">
|
||
<span id="currentUser" style="color:var(--text2);font-size:.8rem"></span>
|
||
<div class="settings-dropdown">
|
||
<button class="btn btn-outline btn-sm" id="settingsBtn" onclick="toggleSettings()">⚙️</button>
|
||
<div class="settings-menu hidden" id="settingsMenu">
|
||
<div class="settings-item">
|
||
<span>Auto-lock</span>
|
||
<select id="autoLockTimer" onchange="setAutoLock()">
|
||
<option value="0">No lock</option>
|
||
<option value="1">1 min</option>
|
||
<option value="5" selected>5 min</option>
|
||
<option value="15">15 min</option>
|
||
<option value="30">30 min</option>
|
||
<option value="60">1 hour</option>
|
||
</select>
|
||
</div>
|
||
<div class="settings-item" onclick="toggleSound();event.stopPropagation();">
|
||
<span>Sound</span>
|
||
<div class="toggle-switch" id="soundToggleSwitch"></div>
|
||
</div>
|
||
<div class="settings-item" onclick="toggleTheme();event.stopPropagation();">
|
||
<span>Theme</span>
|
||
<div class="toggle-switch" id="themeToggleSwitch"></div>
|
||
</div>
|
||
<div class="settings-item" onclick="toggleViewBtn();event.stopPropagation();">
|
||
<span>👁️ View password</span>
|
||
<div class="toggle-switch active" id="showViewBtnToggle"></div>
|
||
</div>
|
||
<div class="settings-item" onclick="toggleShowEmail();event.stopPropagation();">
|
||
<span>📧 Show email</span>
|
||
<div class="toggle-switch active" id="showEmailToggle"></div>
|
||
</div>
|
||
<div class="settings-item" onclick="if(window.PublicKeyCredential){registerPasskey()}else{toast('Passkeys not supported','error')};event.stopPropagation();">
|
||
<span>🔐 Set up passkey</span>
|
||
<span style="color:var(--accent);font-size:0.7rem">⇗</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<button class="btn btn-outline btn-sm" onclick="doLogout()">🔒 Lock</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Add Entry Form -->
|
||
<!-- <form onsubmit="return false" class="input-group" autocomplete="off"> -->
|
||
<!-- <input type="text" id="siteInput" placeholder="Website *" autocomplete="off"> -->
|
||
<!-- <input type="text" id="usernameInput" placeholder="Username (optional)" autocomplete="off"> -->
|
||
<!-- <div style="flex:1;min-width:130px;position:relative"> -->
|
||
<!-- <input type="password" id="passwordInput" placeholder="Password *" autocomplete="new-password" style="width:100%;padding-right:40px" oninput="checkStrength()"> -->
|
||
<!-- <button type="button" onclick="openGen()" style="position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text2);cursor:pointer;font-size:1.1rem;line-height:1" title="Generate password">🎲</button> -->
|
||
<!-- </div> -->
|
||
<!-- <div class="strength-bar s0" id="strengthBar" style="flex-basis:100%;margin-top:-0.3rem;margin-bottom:0.3rem"></div> -->
|
||
<!-- <select id="addFolderSelect"></select> -->
|
||
<!-- <button type="button" class="btn" id="addBtn" onclick="addEntry()">➕ Add</button> -->
|
||
<!-- </form> -->
|
||
|
||
<!-- Toolbar with search + trash + views -->
|
||
<div class="toolbar">
|
||
<div class="search-box">
|
||
<input type="text" id="searchInput" placeholder="🔍 Search..." oninput="searchEntries()" autocomplete="off">
|
||
<button type="button" class="clear-search-btn" id="clearSearchBtn" onclick="clearSearch()" title="Clear search">✕</button>
|
||
</div>
|
||
<div style="display:flex;gap:.4rem;align-items:center;flex-wrap:wrap">
|
||
<button class="btn btn-outline btn-sm" id="trashBtn" onclick="toggleTrash()" title="Trash">🗑️</button>
|
||
<button class="btn btn-outline btn-sm" onclick="showShortcutsHelp()" title="Shortcuts">⌨️</button>
|
||
<div class="view-dropdown" id="viewDropdown">
|
||
<button class="btn btn-outline btn-sm" id="viewDropdownBtn">🟫 Grid ▾</button>
|
||
<div class="view-dropdown-menu hidden" id="viewDropdownMenu">
|
||
<button class="view-opt" data-view="grid">🟫 Grid</button>
|
||
<button class="view-opt" data-view="compact">📝 Compact</button>
|
||
<button class="view-opt" data-view="list">📋 List</button>
|
||
<button class="view-opt" data-view="table">📊 Table</button>
|
||
<button class="view-opt" data-view="card">🃏 Card</button>
|
||
<button class="view-opt" data-view="grouped">📂 Grouped</button>
|
||
<button class="view-opt" data-view="detail">🔍 Detail</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="folders-bar" id="foldersBar"></div>
|
||
<div id="trashActions" class="hidden" style="margin-bottom:.5rem;text-align:right;">
|
||
<button class="empty-trash-btn" onclick="emptyTrash()">🗑️ Empty Trash</button>
|
||
</div>
|
||
<div id="entriesContainer" class="grid-view">
|
||
<div style="text-align:center;color:var(--text2);padding:2rem;grid-column:1/-1">📭 No entries</div>
|
||
</div>
|
||
<div style="margin-top:.6rem;text-align:right">
|
||
<button class="btn btn-outline btn-sm" onclick="showExportModal()">📤 Export</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Generator Modal -->
|
||
<div id="genModal" style="position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.7);display:none;justify-content:center;align-items:center;z-index:2000">
|
||
<div style="background:var(--bg2);border-radius:1.5rem;padding:1.5rem;min-width:320px;max-width:90%">
|
||
<h3 style="margin-bottom:.8rem;color:var(--text)">🎲 Generator</h3>
|
||
<div style="background:var(--input);padding:.8rem;border-radius:1rem;font-family:monospace;text-align:center;color:#4ade80;margin:.6rem 0;word-break:break-all" id="genPreview">Click Generate</div>
|
||
<div style="display:flex;align-items:center;gap:.6rem;margin:.8rem 0">
|
||
<span>Length:</span>
|
||
<input type="range" id="pwdLen" min="8" max="64" value="16" oninput="onLenChange()" style="flex:1">
|
||
<span id="lenVal" style="background:var(--input);padding:.2rem .6rem;border-radius:1rem;min-width:30px;text-align:center">16</span>
|
||
</div>
|
||
<div style="display:flex;flex-wrap:wrap;gap:.5rem;margin:.5rem 0">
|
||
<label style="font-size:.8rem;color:var(--text2)"><input type="checkbox" id="useUpper" checked onchange="genPwd()"> A-Z</label>
|
||
<label style="font-size:.8rem;color:var(--text2)"><input type="checkbox" id="useLower" checked onchange="genPwd()"> a-z</label>
|
||
<label style="font-size:.8rem;color:var(--text2)"><input type="checkbox" id="useNum" checked onchange="genPwd()"> 0-9</label>
|
||
<label style="font-size:.8rem;color:var(--text2)"><input type="checkbox" id="useSym" checked onchange="genPwd()"> !@#$</label>
|
||
</div>
|
||
<div style="display:flex;gap:0.3rem;margin-top:0.8rem;flex-wrap:wrap">
|
||
<button class="btn btn-sm" onclick="genPreset(16,'upper+lower+num+sym')" style="flex:1;min-width:70px">🔒 Strong 16</button>
|
||
<button class="btn btn-sm" onclick="genPreset(20,'upper+lower+num+sym')" style="flex:1;min-width:70px">🔒 Strong 20</button>
|
||
<button class="btn btn-sm btn-danger" onclick="genPreset(32,'upper+lower+num+sym')" style="flex:1;min-width:70px">🛡️ Paranoid 32</button>
|
||
</div>
|
||
<div style="display:flex;gap:.4rem;margin-top:.6rem">
|
||
<button class="btn" onclick="genPwd()" style="flex:1">🔄</button>
|
||
<button class="btn" onclick="useGen()" style="flex:1">✅ Use</button>
|
||
<button class="btn btn-outline" onclick="closeGen()">Cancel</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="js/app.js"></script>
|
||
</body>
|
||
</html> |