c18389e80430
drop onboarding rune opacity 60% and rework new vault screen to share onboarding card visual language (v2.8.1)
- time
- 2026-04-28 04:51 UTC · 6 months ago
- machine
- koh2
- parent
- 80afc813ba15
↓ peach-browser-c18389e8.tar.gzatlas at this save
files changed6 files
manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/popup/styles/popup.css+146 −0src/popup/views/Lock.tsx+96 −92src/popup/views/Onboarding.tsx+1 −1manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "2.8.0",4+ "version": "2.8.1",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.8.0",4+ "version": "2.8.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": "2.8.0",3+ "version": "2.8.1",44 "description": "Zero-knowledge password manager",55 "type": "module",66 "scripts": {src/popup/styles/popup.css+146 −0
@@ -5615,3 +5615,149 @@56155615 from { opacity: 1; transform: translateX(0); }56165616 to { opacity: 0; transform: translateX(-12px); }56175617 }5618+5619+/* ─── New vault screen — matched to onboarding card language ─────────── */5620+5621+.peach-newvault {5622+ position: relative;5623+ display: flex;5624+ flex-direction: column;5625+ gap: 12px;5626+ padding: 16px 16px 18px;5627+ overflow: hidden;5628+}5629+5630+/* Suppress the warm-blob ambient art inherited from .lock-screen — the5631+ new vault card now carries the visual weight. */5632+.peach-newvault::before {5633+ content: none;5634+}5635+5636+.peach-newvault-header {5637+ position: relative;5638+ z-index: 2;5639+ display: flex;5640+ align-items: center;5641+ margin-bottom: 2px;5642+}5643+5644+.peach-newvault-mark {5645+ position: absolute;5646+ right: -12px;5647+ top: 6px;5648+ width: 110px;5649+ height: 110px;5650+ pointer-events: none;5651+ opacity: 0.10;5652+ filter: saturate(0.9);5653+ z-index: 0;5654+}5655+.peach-newvault-mark-art {5656+ width: 100%;5657+ height: 100%;5658+}5659+.peach-newvault-mark-art path:nth-child(2),5660+.peach-newvault-mark-art path:nth-child(3) {5661+ stroke: rgba(123, 144, 96, 0.88);5662+ fill: rgba(123, 144, 96, 0.88);5663+}5664+5665+.peach-newvault-card {5666+ position: relative;5667+ z-index: 1;5668+ display: flex;5669+ flex-direction: column;5670+ gap: 12px;5671+ padding: 22px 20px 18px;5672+ border-radius: 16px;5673+ border: 1px solid var(--peach-t3);5674+ background:5675+ linear-gradient(180deg, rgba(240, 232, 216, 0.03), rgba(240, 232, 216, 0.015));5676+ box-shadow:5677+ inset 0 1px 0 rgba(240, 232, 216, 0.04),5678+ 0 12px 28px rgba(0, 0, 0, 0.12);5679+ animation: peach-onboard-enter 320ms cubic-bezier(0.16, 1, 0.3, 1) both;5680+}5681+5682+.peach-newvault-headline {5683+ margin: 0;5684+ font-family: var(--font-display);5685+ font-style: italic;5686+ font-weight: 400;5687+ font-size: 24px;5688+ line-height: 1.05;5689+ color: var(--peach-t0);5690+ white-space: pre-line;5691+}5692+5693+.peach-newvault-divider {5694+ margin: 2px 0 4px;5695+ border: 0;5696+ border-top: 1px solid var(--peach-t3);5697+ width: 100%;5698+}5699+5700+.peach-newvault-field {5701+ display: flex;5702+ flex-direction: column;5703+ gap: 4px;5704+}5705+5706+.peach-newvault-label-row {5707+ display: flex;5708+ align-items: center;5709+ justify-content: space-between;5710+}5711+5712+/* Monospace input scaled to the card. Replaces the 22px unlock-input5713+ so the placeholder no longer overflows and the field reads as part5714+ of the same surface as the body copy. */5715+.peach-newvault-input {5716+ font-size: 14px;5717+ letter-spacing: 0.18em;5718+ padding: 8px 0;5719+}5720+.peach-newvault-input::placeholder {5721+ letter-spacing: 0.18em;5722+ color: var(--peach-t2);5723+}5724+5725+.peach-newvault-hint {5726+ margin: 2px 0 0;5727+ font-family: "IBM Plex Mono", monospace;5728+ font-size: 10px;5729+ color: var(--peach-t2);5730+ letter-spacing: 0.04em;5731+}5732+5733+.peach-newvault-submit {5734+ margin-top: 4px;5735+}5736+5737+.peach-newvault-warning {5738+ display: flex;5739+ align-items: flex-start;5740+ gap: 8px;5741+ margin: 4px 0 0;5742+ padding-top: 10px;5743+ border-top: 1px dashed var(--peach-t3);5744+ font-size: 12px;5745+ line-height: 1.5;5746+ color: var(--peach-t1);5747+}5748+5749+.peach-newvault-warning-icon {5750+ color: var(--peach-accent);5751+ font-size: 13px;5752+ line-height: 1.4;5753+ flex: 0 0 auto;5754+}5755+5756+.peach-newvault-footer {5757+ position: relative;5758+ z-index: 1;5759+ display: flex;5760+ flex-direction: column;5761+ gap: 4px;5762+ padding: 4px 4px 0;5763+}src/popup/views/Lock.tsx+96 −92
@@ -238,10 +238,10 @@238238 {/* ── Onboarding (hasVault = false) ─────────────────────────── */}239239 <Match when={true}>240240 <section241- class="peach-screen peach-theme lock-screen lock-screen--vault-stage lock-screen--onboarding"241+ class="peach-screen peach-theme lock-screen lock-screen--vault-stage peach-newvault"242242 data-motion-phase="enter"243243 >244- <header class="peach-screen-header lock-screen-header">244+ <header class="peach-screen-header peach-newvault-header">245245 <div class="peach-wordmark-stack">246246 <PeachWordmark class="peach-wordmark-wrap" />247247 <Show when={props.isPro}>@@ -250,116 +250,120 @@250250 </div>251251 </header>252252 253- <div class="peach-lock-hero">254- <div class="peach-lock-hero-art" aria-hidden="true">255- <PeachMark class="peach-lock-hero-mark" />256- </div>257- <span class="peach-lock-eyebrow">new vault</span>258- <h1 class="peach-onboarding-headline">259- keep your260- <br />261- secrets.262- </h1>253+ <div class="peach-newvault-mark" aria-hidden="true">254+ <PeachMark class="peach-newvault-mark-art" />263255 </div>264256 265- <section class="peach-lock-panel peach-lock-panel--primary">266- <div class="peach-lock-label-row">267- <label class="peach-label" for="master-password">268- master password269- </label>270- <button271- class="peach-lock-reveal-btn"272- type="button"273- onClick={() => setShowPassword((value) => !value)}274- aria-label={showPassword() ? "Hide password" : "Show password"}275- >276- <Show277- when={showPassword()}278- fallback={257+ <div class="peach-newvault-card">258+ <h1 class="peach-newvault-headline">{"keep your\nsecrets."}</h1>259+ <hr class="peach-newvault-divider" />260+261+ <div class="peach-newvault-field">262+ <div class="peach-newvault-label-row">263+ <label class="peach-label" for="master-password">264+ master password265+ </label>266+ <button267+ class="peach-lock-reveal-btn"268+ type="button"269+ onClick={() => setShowPassword((value) => !value)}270+ aria-label={showPassword() ? "Hide password" : "Show password"}271+ >272+ <Show273+ when={showPassword()}274+ fallback={275+ <svg width="15" height="10" viewBox="0 0 14 10" fill="none" stroke="currentColor" stroke-width="0.9" stroke-linecap="round">276+ <path d="M1 5C1 5 2.8 1 7 1C11.2 1 13 5 13 5C13 5 11.2 9 7 9C2.8 9 1 5 1 5Z" />277+ <circle cx="7" cy="5" r="1.75" />278+ </svg>279+ }280+ >279281 <svg width="15" height="10" viewBox="0 0 14 10" fill="none" stroke="currentColor" stroke-width="0.9" stroke-linecap="round">280- <path d="M1 5C1 5 2.8 1 7 1C11.2 1 13 5 13 5C13 5 11.2 9 7 9C2.8 9 1 5 1 5Z" />281- <circle cx="7" cy="5" r="1.75" />282+ <path d="M1 2C3 4.5 5 6 7 6C9 6 11 4.5 13 2" />283+ <path d="M3.5 5.5L2.5 7.5" />284+ <path d="M7 6.5V8.5" />285+ <path d="M10.5 5.5L11.5 7.5" />282286 </svg>283- }284- >285- <svg width="15" height="10" viewBox="0 0 14 10" fill="none" stroke="currentColor" stroke-width="0.9" stroke-linecap="round">286- <path d="M1 2C3 4.5 5 6 7 6C9 6 11 4.5 13 2" />287- <path d="M3.5 5.5L2.5 7.5" />288- <path d="M7 6.5V8.5" />289- <path d="M10.5 5.5L11.5 7.5" />290- </svg>291- </Show>292- {showPassword() ? "hide" : "show"}293- </button>287+ </Show>288+ {showPassword() ? "hide" : "show"}289+ </button>290+ </div>291+ <input292+ id="master-password"293+ class="peach-underline-input peach-newvault-input lock-password-input"294+ type={showPassword() ? "text" : "password"}295+ placeholder="••••••••••••"296+ autocomplete="new-password"297+ value={password()}298+ disabled={!props.ready}299+ onInput={(event) => setPassword((event.target as HTMLInputElement).value)}300+ onKeyDown={(event) => {301+ if (event.key !== "Enter" || !props.ready) return;302+ void handleCreate();303+ }}304+ />305+ <Show306+ when={password().length > 0 && passwordStrength() !== null}307+ fallback={308+ <p class="peach-newvault-hint">at least 12 characters</p>309+ }310+ >311+ <div class="peach-password-strength">312+ <div class={`peach-strength-bar peach-strength-bar--${passwordStrength()}`}>313+ <div class="peach-strength-fill"></div>314+ </div>315+ <span class="peach-strength-label">{passwordStrength()}</span>316+ </div>317+ </Show>294318 </div>295- <input296- id="master-password"297- class="peach-underline-input peach-unlock-input lock-password-input"298- type={showPassword() ? "text" : "password"}299- placeholder="at least 12 characters"300- autocomplete="new-password"301- value={password()}302- disabled={!props.ready}303- onInput={(event) => setPassword((event.target as HTMLInputElement).value)}304- onKeyDown={(event) => {305- if (event.key !== "Enter" || !props.ready) return;306- void handleCreate();307- }}308- />309319 310- <Show when={password().length > 0 && passwordStrength() !== null}>311- <div class="peach-password-strength">312- <div class={`peach-strength-bar peach-strength-bar--${passwordStrength()}`}>313- <div class="peach-strength-fill"></div>314- </div>315- <span class="peach-strength-label">{passwordStrength()}</span>316- </div>317- </Show>320+ <div class="peach-newvault-field">321+ <label class="peach-label" for="confirm-password">322+ confirm password323+ </label>324+ <input325+ id="confirm-password"326+ class="peach-underline-input peach-newvault-input"327+ type={showPassword() ? "text" : "password"}328+ placeholder="••••••••••••"329+ autocomplete="new-password"330+ value={confirmPassword()}331+ disabled={!props.ready}332+ onInput={(event) => setConfirmPassword((event.target as HTMLInputElement).value)}333+ onKeyDown={(event) => {334+ if (event.key === "Enter" && props.ready) void handleCreate();335+ }}336+ />337+ </div>318338 319- <label class="peach-label" for="confirm-password">320- confirm password321- </label>322- <input323- id="confirm-password"324- class="peach-underline-input peach-unlock-input"325- type={showPassword() ? "text" : "password"}326- placeholder="••••••••••••"327- autocomplete="new-password"328- value={confirmPassword()}329- disabled={!props.ready}330- onInput={(event) => setConfirmPassword((event.target as HTMLInputElement).value)}331- onKeyDown={(event) => {332- if (event.key === "Enter" && props.ready) void handleCreate();333- }}334- />335-336339 <Show when={error()}>337340 <p class="peach-hint peach-hint-error">{error()}</p>338341 </Show>339342 340343 <button341- class="peach-btn peach-btn--accent peach-btn--md peach-lock-submit"344+ class="peach-btn peach-btn--accent peach-btn--md peach-lock-submit peach-newvault-submit"342345 onClick={() => void handleCreate()}343346 disabled={!props.ready || loading() || !canCreate()}344347 >345348 {loading() ? "creating..." : "create vault"}346349 </button>347350 348- <p class="peach-hint peach-hint-error peach-lock-warning">349- If you lose this password, Peach cannot recover your vault. There is no reset.351+ <p class="peach-newvault-warning">352+ <span class="peach-newvault-warning-icon" aria-hidden="true">⚠</span>353+ <span>If you forget it, your vault cannot be opened. There is no reset.</span>350354 </p>355+ </div>351356 352- <div class="peach-lock-panel-footer">353- <p class="peach-hint">Already have a backup?</p>354- <button355- class="peach-lock-restore-link"356- onClick={() => openRestore("restore")}357- disabled={!props.ready}358- >359- › restore from backup360- </button>361- </div>362- </section>357+ <div class="peach-newvault-footer">358+ <p class="peach-hint">Already have a backup?</p>359+ <button360+ class="peach-lock-restore-link"361+ onClick={() => openRestore("restore")}362+ disabled={!props.ready}363+ >364+ › restore from backup365+ </button>366+ </div>363367 </section>364368 </Match>365369 </Switch>src/popup/views/Onboarding.tsx+1 −1
@@ -75,7 +75,7 @@7575 class="peach-screen peach-theme peach-onboarding"7676 classList={{ "is-completing": completing() }}7777 >78- <RuneBackground opacity={0.07} />78+ <RuneBackground opacity={0.028} />7979 8080 <header class="peach-screen-header peach-onboarding-header">8181 <PeachWordmark class="peach-wordmark-wrap" />