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
5 files manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/popup/styles/popup.css+25 −1src/popup/views/Panic.tsx+124 −102
manifest.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": {

view file

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",

view file

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": {

view file

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 {

view file

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 }

view file