c1f231e00063
always-show history toggle + empty state in both edit surfaces (v3.7.1); record outcome
- time
- 2026-06-07 15:39 UTC · 4 months ago
- machine
- koh2
- agent
- claude-opus-4-8
- session
- password history
- parent
- ba3bcf1cd545
↓ peach-browser-c1f231e0.tar.gzatlas at this save
files changed6 files
manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/content/inject.ts+21 −4src/popup/styles/popup.css+10 −0src/popup/views/Entry.tsx+19 −14manifest.firefox.json+1 −1
@@ -2,7 +2,7 @@22 "_comment_audio_capture": "Firefox does not honor the Chrome 'audioCapture' optional_permission — getUserMedia in WebExtensions is gated solely by the runtime permission prompt. Microphone access for chirp pairing works from the popup under the existing '<all_urls>' host permission; no manifest entry is required or accepted here.",33 "manifest_version": 3,44 "name": "Peach Password Manager",5- "version": "3.7.0",5+ "version": "3.7.1",66 "description": "Zero-knowledge password manager",77 "browser_specific_settings": {88 "gecko": {manifest.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach Password Manager",4- "version": "3.7.0",4+ "version": "3.7.1",55 "description": "Zero-knowledge password manager",66 "action": {77 "default_popup": "src/popup/index.html",package.json+1 −1
@@ -1,6 +1,6 @@11 {22 "name": "peach",3- "version": "3.7.0",3+ "version": "3.7.1",44 "description": "Zero-knowledge password manager",55 "type": "module",66 "scripts": {src/content/inject.ts+21 −4
@@ -823,6 +823,13 @@823823 color: var(--peach-accent);824824 background: color-mix(in srgb, var(--peach-accent) 12%, transparent);825825 }826+ .pw-history-empty {827+ font-family: "IBM Plex Mono", monospace; font-size: 10px; line-height: 1.45;828+ color: color-mix(in srgb, var(--peach-accent) 55%, transparent);829+ padding: 6px 8px; border-radius: 7px;830+ background: color-mix(in srgb, var(--peach-accent) 5%, transparent);831+ border: 1px solid color-mix(in srgb, var(--peach-accent) 9%, transparent);832+ }826833 .save-btn {827834 width: 100%; padding: 8px; border-radius: 8px; border: none;828835 background: var(--peach-accent); color: #fff; font-size: 12px;@@ -2907,23 +2914,33 @@29072914 29082915 // Past-password history: reveal, copy, or restore a previously-used value.29092916 // Rows are masked by default; "use" loads the old value into the editor so2910- // the standard save flow records the swap (no separate write path).2917+ // the standard save flow records the swap (no separate write path). The2918+ // toggle is always present (matching the main popup) so the affordance is2919+ // discoverable — even before any history exists it explains how it fills.29112920 const history = entryRes.data.passwordHistory ?? [];2912- if (history.length > 0) {2921+ {29132922 const histList = document.createElement("div");29142923 histList.className = "pw-history";29152924 histList.style.display = "none";29162925 let histVisible = false;29172926 2927+ const restLabel = history.length ? `↺ history (${history.length})` : "↺ history";29182928 const histToggle = document.createElement("button");29192929 histToggle.className = "gen-toggle-link";29202930 histToggle.type = "button";2921- histToggle.textContent = `↺ history (${history.length})`;2931+ histToggle.textContent = restLabel;29222932 histToggle.addEventListener("click", () => {29232933 histVisible = !histVisible;29242934 histList.style.display = histVisible ? "" : "none";2925- histToggle.textContent = histVisible ? "↺ hide history" : `↺ history (${history.length})`;2935+ histToggle.textContent = histVisible ? "↺ hide history" : restLabel;29262936 });2937+2938+ if (history.length === 0) {2939+ const empty = document.createElement("div");2940+ empty.className = "pw-history-empty";2941+ empty.textContent = "No earlier passwords yet. When you change this password, the old one is saved here so you can copy or restore it.";2942+ histList.appendChild(empty);2943+ }29272944 29282945 for (const item of history) {29292946 const row = document.createElement("div");src/popup/styles/popup.css+10 −0
@@ -2423,6 +2423,16 @@24232423 letter-spacing: 0.05em;24242424 padding: 3px 7px;24252425 }2426+.peach-history-empty {2427+ font-family: "IBM Plex Mono", monospace;2428+ font-size: 0.625rem;2429+ line-height: 1.45;2430+ color: var(--peach-t2);2431+ padding: 6px 8px;2432+ border-radius: 7px;2433+ background: color-mix(in srgb, var(--peach-accent) 4%, transparent);2434+ border: 1px solid color-mix(in srgb, var(--peach-accent) 8%, transparent);2435+}24262436 24272437 /* ── New entry body (Add.tsx — mirrors .peach-stage) ─────────────────── */24282438 .peach-entry-body {src/popup/views/Entry.tsx+19 −14
@@ -1175,20 +1175,20 @@11751175 </svg>11761176 {showGenerator() ? "hide generator" : "generate"}11771177 </button>1178- <Show when={(entry().passwordHistory?.length ?? 0) > 0}>1179- <button1180- class="peach-generate-toggle-link"1181- type="button"1182- onClick={() => { setShowHistory(!showHistory()); if (!showHistory()) setShowGenerator(false); }}1183- >1184- <svg width="10" height="10" viewBox="0 0 13 13" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round">1185- <path d="M6.5 1a5.5 5.5 0 1 0 5.5 5.5" />1186- <path d="M6.5 3.5V6.5L8.5 8" />1187- <path d="M1 1.5V4H3.5" />1188- </svg>1189- {showHistory() ? "hide history" : `history (${entry().passwordHistory!.length})`}1190- </button>1191- </Show>1178+ <button1179+ class="peach-generate-toggle-link"1180+ type="button"1181+ onClick={() => { setShowHistory(!showHistory()); if (!showHistory()) setShowGenerator(false); }}1182+ >1183+ <svg width="10" height="10" viewBox="0 0 13 13" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round">1184+ <path d="M6.5 1a5.5 5.5 0 1 0 5.5 5.5" />1185+ <path d="M6.5 3.5V6.5L8.5 8" />1186+ <path d="M1 1.5V4H3.5" />1187+ </svg>1188+ {showHistory()1189+ ? "hide history"1190+ : (entry().passwordHistory?.length ? `history (${entry().passwordHistory!.length})` : "history")}1191+ </button>11921192 </div>11931193 <Show when={showGenerator()}>11941194 <GeneratorDrawer@@ -1199,6 +1199,11 @@11991199 </Show>12001200 <Show when={showHistory()}>12011201 <div class="peach-password-history">1202+ <Show when={(entry().passwordHistory?.length ?? 0) === 0}>1203+ <div class="peach-history-empty">1204+ No earlier passwords yet. When you change this password, the old one is saved here so you can copy or restore it.1205+ </div>1206+ </Show>12021207 <For each={entry().passwordHistory ?? []}>12031208 {(item, i) => (12041209 <div class="peach-history-row">