5e39562986ae
panic overlay, Step 1 header, Step 3 rune backdrop, scrollbar hiding (v2.11.14)
- time
- 2026-04-29 06:41 UTC · 6 months ago
- machine
- koh2
- parent
- 63c701ea0f83
↓ peach-browser-5e395629.tar.gzatlas at this save
files changed5 files
manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/popup/styles/popup.css+25 −1src/popup/views/Panic.tsx+124 −102manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "2.11.13",4+ "version": "2.11.14",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.13",4+ "version": "2.11.14",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.13",3+ "version": "2.11.14",44 "description": "Zero-knowledge password manager",55 "type": "module",66 "scripts": {src/popup/styles/popup.css+25 −1
@@ -1617,7 +1617,11 @@16171617 min-height: 96px;16181618 resize: vertical;16191619 word-break: break-all;1620+ scrollbar-width: none;1621+ -ms-overflow-style: none;16201622 }1623+1624+.peach-script-input::-webkit-scrollbar { display: none; }16211625 .peach-qr-canvas-wrap {16221626 display: flex;16231627 justify-content: center;@@ -6294,19 +6298,39 @@62946298 .peach-panic {62956299 display: flex;62966300 flex-direction: column;6297- height: 100%;6301+ flex: 1;6302+ min-height: 0;62986303 padding: 28px 20px 20px;62996304 gap: 18px;63006305 overflow-y: auto;6306+ scrollbar-width: none;6307+ -ms-overflow-style: none;63016308 }63026309 6310+.peach-panic::-webkit-scrollbar { display: none; }6311+63036312 .peach-panic-step2 {63046313 background: rgba(220, 38, 38, 0.04);63056314 }63066315 63076316 .peach-panic-step3 {6317+ position: relative;63086318 background: #0f0505;63096319 color: #ffffff;6320+ overflow: hidden;6321+}6322+6323+.peach-panic-rune-bg {6324+ position: absolute;6325+ inset: 0;6326+ opacity: 0.22;6327+ pointer-events: none;6328+ overflow: hidden;6329+}6330+6331+.peach-panic-rune-bg canvas {6332+ width: 100% !important;6333+ height: 100% !important;63106334 }63116335 63126336 .peach-panic-icon {src/popup/views/Panic.tsx+124 −102
@@ -1,5 +1,6 @@11 import { createSignal, Show, Switch, Match } from "solid-js";22 import { sendMessage } from "../App";3+import { RuneCanvas } from "../components/RuneCanvas";34 45 interface PanicProps {56 onCancel: () => void;@@ -7,6 +8,29 @@78 onDestroyed: () => void | Promise<void>;89 }910 11+// Pseudo-random spread of PeachScript PUA codepoints for the Step 3 backdrop.12+const PANIC_RUNES = Array.from({ length: 80 }, (_, i) =>13+ String.fromCodePoint(0xe000 + (i * 19 + 7) % 256)14+).join("");15+16+function OverlayHeader(props: { title: string; onBack: () => void }) {17+ return (18+ <div class="peach-overlay-header">19+ <button20+ class="peach-btn peach-btn--ghost peach-btn--sm peach-icon-btn"21+ onClick={props.onBack}22+ aria-label="Back"23+ >24+ <svg width="7" height="12" viewBox="0 0 7 12" fill="none" stroke="currentColor" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round">25+ <path d="M6 1L1 6L6 11" />26+ </svg>27+ </button>28+ <span class="peach-overlay-title">{props.title}</span>29+ <div class="peach-overlay-spacer"></div>30+ </div>31+ );32+}33+1034 export function PanicView(props: PanicProps) {1135 const [step, setStep] = createSignal<1 | 2 | 3>(1);1236 const [confirmText, setConfirmText] = createSignal("");@@ -26,121 +50,119 @@2650 }2751 2852 return (29- <Switch>30- <Match when={step() === 1}>31- <div class="peach-panic">32- <h2 class="peach-panic-title">Before you destroy your vault</h2>33- <p class="peach-panic-body">34- Once destroyed, your vault cannot be recovered. Ever. There is no35- undo, no support ticket, no way back.36- </p>37- <p class="peach-panic-body">38- If you haven't already, export your vault now. It takes ten seconds39- and you'll be glad you did.40- </p>41- <button42- class="peach-panic-button peach-panic-button--primary"43- onClick={() => props.onOpenExport()}44- >45- Export my vault first46- </button>47- <div class="peach-panic-divider"></div>48- <p class="peach-panic-body">49- I have already exported my vault or I don't want to.50- </p>51- <button class="peach-panic-link" onClick={() => setStep(2)}>52- Continue to destruction →53- </button>54- <div class="peach-panic-actions">53+ <div class="peach-overlay-view ov-enter-right" style="display:flex;flex-direction:column">54+ <Switch>55+ <Match when={step() === 1}>56+ <OverlayHeader title="danger zone" onBack={props.onCancel} />57+ <div class="peach-panic">58+ <h2 class="peach-panic-title">Before you destroy your vault</h2>59+ <p class="peach-panic-body">60+ Once destroyed, your vault cannot be recovered. Ever. There is no61+ undo, no support ticket, no way back.62+ </p>63+ <p class="peach-panic-body">64+ If you haven't already, export your vault now. It takes ten65+ seconds and you'll be glad you did.66+ </p>5567 <button56- class="peach-panic-button peach-panic-button--ghost"57- onClick={() => props.onCancel()}68+ class="peach-panic-button peach-panic-button--primary"69+ onClick={() => props.onOpenExport()}5870 >59- Back to settings71+ Export my vault first6072 </button>61- </div>62- </div>63- </Match>64-65- <Match when={step() === 2}>66- <div class="peach-panic peach-panic-step2">67- <span class="peach-panic-icon" aria-hidden="true">⚠</span>68- <h2 class="peach-panic-title peach-panic-title--severe">69- This will permanently destroy your vault.70- </h2>71- <p class="peach-panic-body peach-panic-body--severe">72- Every password, card, passkey, note, and setting will be wiped from73- this device. This cannot be undone.74- </p>75- <p class="peach-panic-confirm-label">Type DESTROY to confirm:</p>76- <input77- class="peach-panic-confirm-input"78- classList={{ "peach-panic-confirm-input--match": canDestroy() }}79- type="text"80- value={confirmText()}81- onInput={(e) => setConfirmText(e.currentTarget.value)}82- autocomplete="off"83- spellcheck={false}84- autocapitalize="off"85- aria-label="Type DESTROY to confirm"86- />87- <div class="peach-panic-actions">88- <button89- class="peach-panic-button peach-panic-button--danger"90- disabled={!canDestroy()}91- onClick={() => setStep(3)}92- >93- Yes, destroy my vault73+ <div class="peach-panic-divider"></div>74+ <p class="peach-panic-body">75+ I have already exported my vault or I don't want to.76+ </p>77+ <button class="peach-panic-link" onClick={() => setStep(2)}>78+ Continue to destruction →9479 </button>95- <button96- class="peach-panic-button peach-panic-button--ghost"97- onClick={() => {98- setConfirmText("");99- props.onCancel();100- }}101- >102- Cancel — keep my vault103- </button>10480 </div>105- </div>106- </Match>81+ </Match>10782 108- <Match when={step() === 3}>109- <div class="peach-panic peach-panic-step3">110- <div class="peach-panic-bar">THIS IS YOUR LAST CHANCE</div>111- <p class="peach-panic-body peach-panic-body--final-intro">112- Your vault is about to be permanently destroyed.113- </p>114- <p class="peach-panic-body peach-panic-body--final">115- There is no recovery.116- <br />117- There is no support.118- <br />119- There is no undo.120- </p>121- <div class="peach-panic-divider"></div>122- <div class="peach-panic-actions">123- <button124- class="peach-panic-final-button"125- disabled={destroying()}126- onClick={() => void handleDestroy()}127- >128- {destroying() ? "Destroying…" : "Destroy my vault forever"}129- </button>130- <Show when={!destroying()}>83+ <Match when={step() === 2}>84+ <div class="peach-panic peach-panic-step2">85+ <span class="peach-panic-icon" aria-hidden="true">⚠</span>86+ <h2 class="peach-panic-title peach-panic-title--severe">87+ This will permanently destroy your vault.88+ </h2>89+ <p class="peach-panic-body peach-panic-body--severe">90+ Every password, card, passkey, note, and setting will be wiped91+ from this device. This cannot be undone.92+ </p>93+ <p class="peach-panic-confirm-label">Type DESTROY to confirm:</p>94+ <input95+ class="peach-panic-confirm-input"96+ classList={{ "peach-panic-confirm-input--match": canDestroy() }}97+ type="text"98+ value={confirmText()}99+ onInput={(e) => setConfirmText(e.currentTarget.value)}100+ autocomplete="off"101+ spellcheck={false}102+ autocapitalize="off"103+ aria-label="Type DESTROY to confirm"104+ />105+ <div class="peach-panic-actions">131106 <button107+ class="peach-panic-button peach-panic-button--danger"108+ disabled={!canDestroy()}109+ onClick={() => setStep(3)}110+ >111+ Yes, destroy my vault112+ </button>113+ <button132114 class="peach-panic-button peach-panic-button--ghost"133115 onClick={() => {134116 setConfirmText("");135- setStep(1);117+ props.onCancel();136118 }}137119 >138- No — take me back120+ Cancel — keep my vault139121 </button>140- </Show>122+ </div>141123 </div>142- </div>143- </Match>144- </Switch>124+ </Match>125+126+ <Match when={step() === 3}>127+ <div class="peach-panic peach-panic-step3">128+ <div class="peach-panic-rune-bg" aria-hidden="true">129+ <RuneCanvas runeString={PANIC_RUNES} width={320} height={480} />130+ </div>131+ <div class="peach-panic-bar">THIS IS YOUR LAST CHANCE</div>132+ <p class="peach-panic-body peach-panic-body--final-intro">133+ Your vault is about to be permanently destroyed.134+ </p>135+ <p class="peach-panic-body peach-panic-body--final">136+ There is no recovery.137+ <br />138+ There is no support.139+ <br />140+ There is no undo.141+ </p>142+ <div class="peach-panic-divider"></div>143+ <div class="peach-panic-actions">144+ <button145+ class="peach-panic-final-button"146+ disabled={destroying()}147+ onClick={() => void handleDestroy()}148+ >149+ {destroying() ? "Destroying…" : "Destroy my vault forever"}150+ </button>151+ <Show when={!destroying()}>152+ <button153+ class="peach-panic-button peach-panic-button--ghost"154+ onClick={() => {155+ setConfirmText("");156+ setStep(1);157+ }}158+ >159+ No — take me back160+ </button>161+ </Show>162+ </div>163+ </div>164+ </Match>165+ </Switch>166+ </div>145167 );146168 }