f45fccde9c90
Vault Health: hide platform scrollbar to match other popup surfaces, add shimmering skeleton (queue head + 3 rows) while GET_ADVANCED_HEALTH_REPORT computes; bump v2.11.9
- time
- 2026-04-29 01:29 UTC · 6 months ago
- machine
- koh2
- parent
- 7c1bd58db8ea
↓ peach-browser-f45fccde.tar.gzatlas at this save
files changed5 files
manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/popup/styles/popup.css+102 −0src/popup/views/Health.tsx+42 −4manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "2.11.8",4+ "version": "2.11.9",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.11.8",4+ "version": "2.11.9",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.11.8",3+ "version": "2.11.9",44 "description": "Zero-knowledge password manager",55 "type": "module",66 "scripts": {src/popup/styles/popup.css+102 −0
@@ -4183,6 +4183,108 @@41834183 overflow-y: auto;41844184 display: flex;41854185 flex-direction: column;4186+ /* Hide the platform scrollbar — every other scrollable surface in the4187+ * popup hides it; the Health view was the one outlier and it ruined the4188+ * polish. Behavior unchanged, just no rail rendered. */4189+ scrollbar-width: none;4190+ -ms-overflow-style: none;4191+}4192+.peach-health-body::-webkit-scrollbar { display: none; }4193+4194+/* Loading skeleton for the remediation queue — shown while the background4195+ * computes the advanced health report on Pro vaults. Shimmer + pulse so the4196+ * view doesn't read as "empty/broken" during the (sometimes multi-second)4197+ * scan. */4198+.peach-health-skeleton {4199+ display: flex;4200+ flex-direction: column;4201+ gap: 10px;4202+ padding: 14px 16px;4203+}4204+4205+.peach-health-skeleton-head {4206+ display: flex;4207+ align-items: center;4208+ justify-content: space-between;4209+ margin-bottom: 4px;4210+}4211+4212+.peach-health-skeleton-title {4213+ font-family: "IBM Plex Mono", monospace;4214+ font-size: 9px;4215+ letter-spacing: 0.16em;4216+ text-transform: uppercase;4217+ color: var(--peach-accent);4218+ opacity: 0.85;4219+}4220+4221+.peach-health-skeleton-meta {4222+ font-family: "IBM Plex Mono", monospace;4223+ font-size: 10px;4224+ color: var(--peach-t2);4225+ display: inline-flex;4226+ align-items: center;4227+ gap: 6px;4228+}4229+4230+.peach-health-skeleton-dot {4231+ width: 6px;4232+ height: 6px;4233+ border-radius: 50%;4234+ background: var(--peach-accent);4235+ animation: peach-health-skeleton-pulse 1.2s ease-in-out infinite;4236+}4237+4238+.peach-health-skeleton-row {4239+ display: flex;4240+ align-items: center;4241+ gap: 12px;4242+ padding: 12px;4243+ border-radius: 10px;4244+ background: rgba(0, 0, 0, 0.18);4245+ animation: peach-health-skeleton-pulse 1.6s ease-in-out infinite;4246+}4247+4248+.peach-health-skeleton-row:nth-child(2) { animation-delay: 0.10s; }4249+.peach-health-skeleton-row:nth-child(3) { animation-delay: 0.20s; }4250+.peach-health-skeleton-row:nth-child(4) { animation-delay: 0.30s; }4251+4252+.peach-health-skeleton-bar {4253+ height: 10px;4254+ border-radius: 4px;4255+ background: linear-gradient(4256+ 90deg,4257+ rgba(240, 232, 216, 0.04) 0%,4258+ rgba(240, 232, 216, 0.10) 50%,4259+ rgba(240, 232, 216, 0.04) 100%4260+ );4261+ background-size: 240% 100%;4262+ animation: peach-health-skeleton-shimmer 1.6s ease-in-out infinite;4263+}4264+4265+.peach-health-skeleton-bar--name { width: 55%; }4266+.peach-health-skeleton-bar--meta { width: 40%; height: 7px; opacity: 0.6; margin-top: 6px; }4267+.peach-health-skeleton-bar--cta { width: 90px; height: 26px; border-radius: 6px; flex-shrink: 0; margin-left: auto; }4268+4269+.peach-health-skeleton-row > div:first-child {4270+ flex: 1;4271+ min-width: 0;4272+}4273+4274+@keyframes peach-health-skeleton-pulse {4275+ 0%, 100% { opacity: 0.55; }4276+ 50% { opacity: 1; }4277+}4278+4279+@keyframes peach-health-skeleton-shimmer {4280+ 0% { background-position: 200% 50%; }4281+ 100% { background-position: -100% 50%; }4282+}4283+4284+[data-motion="reduce"] .peach-health-skeleton-row,4285+[data-motion="reduce"] .peach-health-skeleton-bar,4286+[data-motion="reduce"] .peach-health-skeleton-dot {4287+ animation: none;41864288 }41874289 41884290 .peach-health-summary {src/popup/views/Health.tsx+42 −4
@@ -66,13 +66,19 @@6666 });6767 const [viewingReusedGroup, setViewingReusedGroup] = createSignal<VaultEntry[] | null>(null);6868 const [advancedReport, setAdvancedReport] = createSignal<AdvancedHealthReport | null>(null);69+ const [advancedLoading, setAdvancedLoading] = createSignal<boolean>(false);6970 const [smartChangingId, setSmartChangingId] = createSignal<string | null>(null);7071 7172 onMount(async () => {7273 if (!props.isPro) return;73- const res = await sendMessage({ type: "GET_ADVANCED_HEALTH_REPORT" });74- if ((res as { ok: boolean }).ok) {75- setAdvancedReport((res as { ok: boolean; data?: AdvancedHealthReport }).data ?? null);74+ setAdvancedLoading(true);75+ try {76+ const res = await sendMessage({ type: "GET_ADVANCED_HEALTH_REPORT" });77+ if ((res as { ok: boolean }).ok) {78+ setAdvancedReport((res as { ok: boolean; data?: AdvancedHealthReport }).data ?? null);79+ }80+ } finally {81+ setAdvancedLoading(false);7682 }7783 });7884 @@ -203,7 +209,39 @@203209 </div>204210 205211 <div class="peach-health-body">206- <Show when={props.isPro && advancedReport() && advancedReport()!.remediation.length > 0}>212+ <Show when={props.isPro && advancedLoading()}>213+ <div class="peach-health-skeleton" aria-busy="true" aria-live="polite">214+ <div class="peach-health-skeleton-head">215+ <span class="peach-health-skeleton-title">Remediation queue</span>216+ <span class="peach-health-skeleton-meta">217+ <span class="peach-health-skeleton-dot" aria-hidden="true"></span>218+ Scanning vault…219+ </span>220+ </div>221+ <div class="peach-health-skeleton-row">222+ <div>223+ <div class="peach-health-skeleton-bar peach-health-skeleton-bar--name"></div>224+ <div class="peach-health-skeleton-bar peach-health-skeleton-bar--meta"></div>225+ </div>226+ <div class="peach-health-skeleton-bar peach-health-skeleton-bar--cta"></div>227+ </div>228+ <div class="peach-health-skeleton-row">229+ <div>230+ <div class="peach-health-skeleton-bar peach-health-skeleton-bar--name"></div>231+ <div class="peach-health-skeleton-bar peach-health-skeleton-bar--meta"></div>232+ </div>233+ <div class="peach-health-skeleton-bar peach-health-skeleton-bar--cta"></div>234+ </div>235+ <div class="peach-health-skeleton-row">236+ <div>237+ <div class="peach-health-skeleton-bar peach-health-skeleton-bar--name"></div>238+ <div class="peach-health-skeleton-bar peach-health-skeleton-bar--meta"></div>239+ </div>240+ <div class="peach-health-skeleton-bar peach-health-skeleton-bar--cta"></div>241+ </div>242+ </div>243+ </Show>244+ <Show when={props.isPro && !advancedLoading() && advancedReport() && advancedReport()!.remediation.length > 0}>207245 <div class="peach-health-pro-queue">208246 <div class="peach-health-pro-queue-head">209247 <span class="peach-health-pro-queue-title">Remediation queue</span>