24b44033cfda
smooth collapse toggle and enter animation on identity suggestion lists
- time
- 2026-05-10 20:50 UTC · 5 months ago
- machine
- koh2
- parent
- bb3cc8fd3352
↓ peach-browser-24b44033.tar.gzatlas at this save
files changed6 files
manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/content/inject.ts+36 −4src/popup/styles/popup.css+44 −0src/popup/views/Add.tsx+27 −9manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "2.38.6",4+ "version": "2.38.7",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.6",4+ "version": "2.38.7",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.6",3+ "version": "2.38.7",44 "description": "Zero-knowledge password manager",55 "type": "module",66 "scripts": {src/content/inject.ts+36 −4
@@ -1088,8 +1088,25 @@10881088 background: transparent; border: none; border-bottom: 1px solid var(--peach-accent);10891089 outline: none; padding: 0; min-width: 22px;10901090 }1091- .identity-suggest-list { display: flex; flex-direction: column; gap: 1px; margin-top: 3px; }1092- .identity-filter-row { display: flex; gap: 4px; padding: 2px 0 4px; }1091+ @keyframes identity-suggest-in {1092+ from { opacity: 0; transform: translateY(-4px); }1093+ to { opacity: 1; transform: none; }1094+ }1095+ .identity-suggest-list { display: flex; flex-direction: column; gap: 1px; margin-top: 3px;1096+ animation: identity-suggest-in 180ms cubic-bezier(0.16,1,0.3,1) both; }1097+ .identity-filter-row { display: flex; align-items: center; gap: 4px; padding: 2px 0 4px; }1098+ .identity-collapse-btn {1099+ margin-left: auto; background: transparent; border: none; cursor: pointer;1100+ color: var(--peach-text-muted); padding: 2px 4px; display: flex; align-items: center;1101+ line-height: 0; border-radius: 3px;1102+ transition: color 100ms ease, transform 220ms cubic-bezier(0.16,1,0.3,1);1103+ }1104+ .identity-collapse-btn:hover { color: var(--peach-text); }1105+ .identity-collapse-btn.is-collapsed { transform: rotate(-90deg); }1106+ .identity-rows { display: grid; grid-template-rows: 1fr;1107+ transition: grid-template-rows 220ms cubic-bezier(0.16,1,0.3,1); }1108+ .identity-rows.is-collapsed { grid-template-rows: 0fr; }1109+ .identity-rows-inner { overflow: hidden; min-height: 0; }10931110 .identity-filter-pill {10941111 padding: 2px 7px; border-radius: 999px;10951112 border: 1px solid var(--peach-input-border);@@ -1592,12 +1609,13 @@15921609 function attachIdentitySuggestions(g: HTMLDivElement, inp: HTMLInputElement, identities: SavedIdentity[]): void {15931610 if (!identities.length) return;15941611 let activeFilter: "all" | "username" | "email" = "all";1612+ let collapsed = false;15951613 15961614 const list = g.appendChild(document.createElement("div"));15971615 list.className = "identity-suggest-list";15981616 list.style.display = "none";15991617 1600- // Filter pill row1618+ // Filter pill row + collapse toggle16011619 const filterRow = list.appendChild(document.createElement("div"));16021620 filterRow.className = "identity-filter-row";16031621 function makePill(label: string, value: "all" | "username" | "email") {@@ -1617,7 +1635,21 @@16171635 makePill("user", "username");16181636 makePill("email", "email");16191637 1620- const rows = list.appendChild(document.createElement("div"));1638+ const collapseBtn = filterRow.appendChild(document.createElement("button"));1639+ collapseBtn.type = "button";1640+ collapseBtn.className = "identity-collapse-btn";1641+ collapseBtn.innerHTML = `<svg width="10" height="6" viewBox="0 0 10 6" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 1L5 5L9 1"/></svg>`;1642+ collapseBtn.addEventListener("mousedown", (e) => {1643+ e.preventDefault();1644+ collapsed = !collapsed;1645+ collapseBtn.classList.toggle("is-collapsed", collapsed);1646+ rowsWrapper.classList.toggle("is-collapsed", collapsed);1647+ });1648+1649+ const rowsWrapper = list.appendChild(document.createElement("div"));1650+ rowsWrapper.className = "identity-rows";1651+ const rows = rowsWrapper.appendChild(document.createElement("div"));1652+ rows.className = "identity-rows-inner";16211653 16221654 function render() {16231655 const q = inp.value.toLowerCase();src/popup/styles/popup.css+44 −0
@@ -5128,17 +5128,61 @@51285128 }51295129 51305130 /* Identity suggestions — shown below username/email inputs in new-entry form */5131+@keyframes peach-suggest-in {5132+ from { opacity: 0; transform: translateY(-4px); }5133+ to { opacity: 1; transform: none; }5134+}5135+51315136 .peach-identity-suggestions {51325137 display: flex;51335138 flex-direction: column;51345139 gap: 1px;51355140 margin-top: 4px;5141+ animation: peach-suggest-in 180ms cubic-bezier(0.16, 1, 0.3, 1) both;51365142 }51375143 51385144 .peach-identity-filter-row {51395145 display: flex;5146+ align-items: center;51405147 gap: 4px;51415148 padding: 2px 0 5px;5149+}5150+5151+.peach-identity-collapse-btn {5152+ margin-left: auto;5153+ background: transparent;5154+ border: none;5155+ cursor: pointer;5156+ color: var(--peach-t3);5157+ padding: 2px 4px;5158+ display: flex;5159+ align-items: center;5160+ line-height: 0;5161+ border-radius: 3px;5162+ transition: color 100ms ease, transform 220ms cubic-bezier(0.16, 1, 0.3, 1);5163+}5164+5165+.peach-identity-collapse-btn:hover {5166+ color: var(--peach-t1);5167+}5168+5169+.peach-identity-collapse-btn.is-collapsed {5170+ transform: rotate(-90deg);5171+}5172+5173+.peach-identity-rows {5174+ display: grid;5175+ grid-template-rows: 1fr;5176+ transition: grid-template-rows 220ms cubic-bezier(0.16, 1, 0.3, 1);5177+}5178+5179+.peach-identity-rows.is-collapsed {5180+ grid-template-rows: 0fr;5181+}5182+5183+.peach-identity-rows-inner {5184+ overflow: hidden;5185+ min-height: 0;51425186 }51435187 51445188 .peach-identity-filter-pill {src/popup/views/Add.tsx+27 −9
@@ -631,22 +631,40 @@631631 }632632 633633 function IdentitySuggestList(props: IdentitySuggestListProps) {634+ const [collapsed, setCollapsed] = createSignal(false);635+ const ChevronIcon = () => (636+ <svg width="10" height="6" viewBox="0 0 10 6" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round">637+ <path d="M1 1L5 5L9 1" />638+ </svg>639+ );634640 return (635641 <div class="peach-identity-suggestions">636642 <div class="peach-identity-filter-row">637643 <button class={`peach-identity-filter-pill ${props.filter === "all" ? "is-on" : ""}`} type="button" onMouseDown={() => props.onFilter("all")}>all</button>638644 <button class={`peach-identity-filter-pill ${props.filter === "username" ? "is-on" : ""}`} type="button" onMouseDown={() => props.onFilter("username")}>user</button>639645 <button class={`peach-identity-filter-pill ${props.filter === "email" ? "is-on" : ""}`} type="button" onMouseDown={() => props.onFilter("email")}>email</button>646+ <button647+ class={`peach-identity-collapse-btn${collapsed() ? " is-collapsed" : ""}`}648+ type="button"649+ onMouseDown={(e) => { e.preventDefault(); setCollapsed(c => !c); }}650+ aria-label={collapsed() ? "Show suggestions" : "Hide suggestions"}651+ >652+ <ChevronIcon />653+ </button>640654 </div>641- <For each={props.suggestions}>642- {(s) => (643- <button class="peach-identity-suggestion" type="button" onMouseDown={() => props.onPick(s.value)}>644- <span class="peach-identity-suggestion-value">{s.value}</span>645- <span class={`peach-identity-suggestion-type peach-identity-suggestion-type--${s.type}`}>{s.type === "email" ? "@" : "u"}</span>646- <span class="peach-identity-suggestion-meta">{s.count}×</span>647- </button>648- )}649- </For>655+ <div class={`peach-identity-rows${collapsed() ? " is-collapsed" : ""}`}>656+ <div class="peach-identity-rows-inner">657+ <For each={props.suggestions}>658+ {(s) => (659+ <button class="peach-identity-suggestion" type="button" onMouseDown={() => props.onPick(s.value)}>660+ <span class="peach-identity-suggestion-value">{s.value}</span>661+ <span class={`peach-identity-suggestion-type peach-identity-suggestion-type--${s.type}`}>{s.type === "email" ? "@" : "u"}</span>662+ <span class="peach-identity-suggestion-meta">{s.count}×</span>663+ </button>664+ )}665+ </For>666+ </div>667+ </div>650668 </div>651669 );652670 }