1c24140227f4
click-to-edit length number in GeneratorDrawer — both compact and full layouts, Enter/blur commits clamped to 8-128, Escape cancels, slider stays synced (v2.38.3)
- time
- 2026-05-10 18:41 UTC · 5 months ago
- machine
- koh2
- parent
- 104b98beeb6a
↓ peach-browser-1c241402.tar.gzatlas at this save
files changed5 files
manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/popup/components/GeneratorDrawer.tsx+51 −2src/popup/styles/popup.css+16 −0manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "2.38.2",4+ "version": "2.38.3",55 "description": "Zero-knowledge password manager",66 "browser_specific_settings": {77 "gecko": {manifest.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "2.38.2",4+ "version": "2.38.3",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": "2.38.2",3+ "version": "2.38.3",44 "description": "Zero-knowledge password manager",55 "type": "module",66 "scripts": {src/popup/components/GeneratorDrawer.tsx+51 −2
@@ -21,6 +21,8 @@2121 const [symbols, setSymbols] = createSignal(true);2222 const [forbiddenChars, setForbiddenChars] = createSignal("");2323 const [copied, setCopied] = createSignal(false);24+ const [editingLength, setEditingLength] = createSignal(false);25+ const [lengthDraft, setLengthDraft] = createSignal("");2426 2527 function initFromPolicy(policy: PasswordPolicy) {2628 let nextLength = length();@@ -119,6 +121,21 @@119121 regenerate({ symbols: next });120122 }121123 124+ function startEditingLength() {125+ setLengthDraft(String(length()));126+ setEditingLength(true);127+ }128+129+ function commitLength() {130+ const n = parseInt(lengthDraft(), 10);131+ if (!isNaN(n)) {132+ const clamped = Math.max(8, Math.min(128, n));133+ setLength(clamped);134+ regenerate({ length: clamped });135+ }136+ setEditingLength(false);137+ }138+122139 const passwordFontSize = () => {123140 const value = password();124141 if (value.length > 48) return "16px";@@ -179,7 +196,23 @@179196 regenerate({ length: n });180197 }}181198 />182- <span class="peach-pwgen-len-num">{length()}</span>199+ <Show200+ when={editingLength()}201+ fallback={202+ <span class="peach-pwgen-len-num peach-pwgen-len-num--edit" onClick={startEditingLength}>{length()}</span>203+ }204+ >205+ <input206+ class="peach-pwgen-len-input"207+ type="text"208+ inputmode="numeric"209+ value={lengthDraft()}210+ ref={(el) => requestAnimationFrame(() => el.select())}211+ onInput={(e) => setLengthDraft((e.currentTarget as HTMLInputElement).value)}212+ onKeyDown={(e) => { if (e.key === "Enter") commitLength(); else if (e.key === "Escape") setEditingLength(false); }}213+ onBlur={commitLength}214+ />215+ </Show>183216 <div class="peach-pwgen-compact-pills">184217 <button class={`peach-pwgen-pill ${upper() ? "is-on" : ""}`} onClick={toggleUppercase} type="button">A-Z</button>185218 <button class={`peach-pwgen-pill ${lower() ? "is-on" : ""}`} onClick={toggleLowercase} type="button">a-z</button>@@ -225,7 +258,23 @@225258 <div class="peach-pwgen-length-row">226259 <div class="peach-pwgen-length-labels">227260 <span class="peach-label">length</span>228- <span class="peach-pwgen-len-num">{length()}</span>261+ <Show262+ when={editingLength()}263+ fallback={264+ <span class="peach-pwgen-len-num peach-pwgen-len-num--edit" onClick={startEditingLength}>{length()}</span>265+ }266+ >267+ <input268+ class="peach-pwgen-len-input"269+ type="text"270+ inputmode="numeric"271+ value={lengthDraft()}272+ ref={(el) => requestAnimationFrame(() => el.select())}273+ onInput={(e) => setLengthDraft((e.currentTarget as HTMLInputElement).value)}274+ onKeyDown={(e) => { if (e.key === "Enter") commitLength(); else if (e.key === "Escape") setEditingLength(false); }}275+ onBlur={commitLength}276+ />277+ </Show>229278 </div>230279 <input231280 type="range"src/popup/styles/popup.css+16 −0
@@ -3125,6 +3125,22 @@31253125 font-family: "IBM Plex Mono", monospace;31263126 font-size: 0.75rem; color: var(--peach-accent);31273127 }3128+.peach-pwgen-len-num--edit {3129+ cursor: text;3130+ border-bottom: 1px dotted color-mix(in srgb, var(--peach-accent) 50%, transparent);3131+}3132+.peach-pwgen-len-input {3133+ font-family: "IBM Plex Mono", monospace;3134+ font-size: 0.75rem;3135+ color: var(--peach-accent);3136+ background: transparent;3137+ border: none;3138+ border-bottom: 1px solid var(--peach-accent);3139+ outline: none;3140+ width: 32px;3141+ text-align: right;3142+ padding: 0;3143+}31283144 .peach-pwgen-slider { width: 100%; accent-color: var(--peach-accent); cursor: pointer; height: 2px; }31293145 .peach-pwgen-toggles { display: flex; flex-direction: column; }31303146 .peach-pwgen-charset-pills {