9edde75430a8
sync settings: remove ✦ badge from nav, add network note, promote Add a device row, flip Show to when={isPro()}, fix App.tsx v=view() used before declaration (v2.35.8)
- time
- 2026-05-09 01:49 UTC · 5 months ago
- machine
- koh2
- parent
- b05386777208
↓ peach-browser-9edde754.tar.gzatlas at this save
files changed6 files
manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/popup/App.tsx+1 −1src/popup/styles/popup.css+20 −0src/popup/views/Settings.tsx+153 −156manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "2.35.7",4+ "version": "2.35.8",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.35.7",4+ "version": "2.35.8",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.35.7",3+ "version": "2.35.8",44 "description": "Zero-knowledge password manager",55 "type": "module",66 "scripts": {src/popup/App.tsx+1 −1
@@ -577,6 +577,7 @@577577 const wasCaptured = captured;578578 dragging = false;579579 captured = false;580+ const v = view();580581 581582 if (!wasCaptured) {582583 // Tap in the peek strip while in entry view → open the vault list.@@ -587,7 +588,6 @@587588 588589 const restClosed = window.innerHeight - PEEK_PX;589590 const current = sheetTranslate() ?? restClosed;590- const v = view();591591 592592 // Snap rules:593593 // - Strong upward velocity → opensrc/popup/styles/popup.css+20 −0
@@ -4028,6 +4028,26 @@40284028 letter-spacing: 0.05em;40294029 }40304030 4031+.peach-sync-network-note {4032+ margin: 0 0 6px;4033+ font-size: 0.75rem;4034+ color: var(--peach-t2);4035+ line-height: 1.4;4036+}4037+4038+.peach-settings-row--tappable {4039+ background: none;4040+ border: none;4041+ width: 100%;4042+ text-align: left;4043+ cursor: pointer;4044+ color: var(--peach-t1);4045+ font-size: 0.8125rem;4046+}4047+.peach-settings-row--tappable:hover {4048+ color: var(--peach-t0);4049+}4050+40314051 .peach-sync-pro-hint {40324052 display: flex;40334053 flex-direction: column;src/popup/views/Settings.tsx+153 −156
@@ -769,7 +769,7 @@769769 770770 <p class="peach-settings-nav-label">VAULT</p>771771 {renderCatRow({ section: "vault", name: "Vault", desc: "Entries, health, import & export", icon: iconLock })}772- {renderCatRow({ section: "sync", name: "Sync", desc: "Paired devices & trusted networks", icon: iconSync, pro: true })}772+ {renderCatRow({ section: "sync", name: "Sync", desc: "Pair devices · sync is free", icon: iconSync })}773773 774774 <p class="peach-settings-nav-label">PREFERENCES</p>775775 {renderCatRow({ section: "appearance", name: "Appearance", desc: "Theme & accent color", icon: iconSun })}@@ -1300,180 +1300,177 @@13001300 return (13011301 <div class="peach-settings-body">13021302 <div class="peach-settings-group">1303- {/* Pairing is free — always show Add a device and paired list */}1304- <div class="peach-settings-row peach-settings-row--meta peach-settings-row--stack">1305- <span class="peach-sync-section-label">Paired devices ({pairedDevices().length})</span>1306- <Show when={pairedDevices().length === 0}>1307- <p class="peach-settings-hint">1308- No paired devices yet. Add a device to start syncing.1309- </p>1310- </Show>1311- <Show when={pairedDevices().length > 0}>1312- <div class="peach-history-list">1313- <For each={pairedDevices()}>1314- {(device) => (1315- <div class="peach-history-row">1316- <div class="peach-history-meta">1317- <span class="peach-history-time">{device.displayName}</span>1318- <span class="peach-history-sub">1319- {device.lastSyncAt1320- ? `Last synced: ${formatSnapshotTime(device.lastSyncAt)}`1321- : "Never synced"}1322- </span>1323- </div>1324- <button1325- class="peach-btn peach-btn--subtle peach-btn--sm peach-history-btn"1326- onClick={() => void handleRemoveDevice(device.deviceId)}1327- >1328- Remove1329- </button>1303+ <p class="peach-sync-network-note">1304+ Sync works on your home and trusted networks. Some public or1305+ corporate networks block device connections.1306+ </p>1307+1308+ {/* Add a device — FREE, always shown */}1309+ <button1310+ class="peach-settings-row peach-settings-row--tappable"1311+ onClick={() => props.onOpenSyncPairing?.()}1312+ >1313+ <span>Add a device</span>1314+ <svg width="6" height="10" viewBox="0 0 6 10" fill="none" stroke="currentColor" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round">1315+ <path d="M1 1l4 4-4 4" />1316+ </svg>1317+ </button>1318+1319+ {/* Paired devices list — shown when any exist */}1320+ <Show when={pairedDevices().length > 0}>1321+ <div class="peach-history-list">1322+ <For each={pairedDevices()}>1323+ {(device) => (1324+ <div class="peach-history-row">1325+ <div class="peach-history-meta">1326+ <span class="peach-history-time">{device.displayName}</span>1327+ <span class="peach-history-sub">1328+ {device.lastSyncAt1329+ ? `Last synced ${formatRelativeTime(device.lastSyncAt)}`1330+ : "Never synced"}1331+ </span>13301332 </div>1331- )}1332- </For>1333- </div>1334- </Show>1335- <div class="peach-settings-actions--row">1336- <button1337- class="peach-btn peach-btn--subtle peach-btn--sm"1338- onClick={() => props.onOpenSyncPairing?.()}1339- >1340- Add a device1341- </button>1333+ <button1334+ class="peach-btn peach-btn--subtle peach-btn--sm peach-history-btn"1335+ onClick={() => void handleRemoveDevice(device.deviceId)}1336+ >1337+ Remove1338+ </button>1339+ </div>1340+ )}1341+ </For>13421342 </div>1343- </div>1343+ </Show>13441344 1345- {/* Automatic sync is Pro-gated */}1345+ {/* Automatic sync — PRO only */}13461346 <Show1347- when={!isPro()}1347+ when={isPro()}13481348 fallback={1349- <>1350- <div class="peach-settings-row">1351- <span>Status</span>1352- <span class="peach-settings-value peach-settings-value--status">1353- <span class="peach-sync-status-dot" style={{ background: getStatusColor(syncStatus()) }}></span>1354- {getStatusLabel(syncStatus())}1355- </span>1356- </div>1357- <div class="peach-settings-row peach-settings-row--meta">1358- <span>Last sync</span>1359- <span class="peach-settings-value">{lastSyncAt() ? formatRelativeTime(lastSyncAt()) : "Never synced"}</span>1360- </div>1361- <div class="peach-settings-row peach-settings-row--meta">1349+ <Show when={pairedDevices().length > 0}>1350+ <div class="peach-sync-pro-hint">1351+ <p class="peach-settings-hint">1352+ Upgrade to Pro for automatic background sync across all your devices.1353+ </p>13621354 <button13631355 class="peach-btn peach-btn--subtle peach-btn--sm"1364- onClick={() => void handleSyncNow()}1365- disabled={syncStatus() === "not_trusted" || syncingNow()}1356+ onClick={() => setActiveSection("license")}13661357 >1367- <Switch>1368- <Match when={syncingNow()}>Syncing…</Match>1369- <Match when={syncFeedback()?.kind === "ok"}>✓ {syncFeedback()!.text}</Match>1370- <Match when={syncFeedback()?.kind === "err"}>{syncFeedback()!.text}</Match>1371- <Match when={true}>Sync now</Match>1372- </Switch>1358+ Upgrade to Pro13731359 </button>13741360 </div>1375- <p class="peach-settings-hint">1376- If you edit on multiple devices before syncing, the most recently1377- changed device wins. Use Vault History above to recover older1378- versions if needed.1379- </p>1361+ </Show>1362+ }1363+ >1364+ <div class="peach-settings-row">1365+ <span>Status</span>1366+ <span class="peach-settings-value peach-settings-value--status">1367+ <span class="peach-sync-status-dot" style={{ background: getStatusColor(syncStatus()) }}></span>1368+ {getStatusLabel(syncStatus())}1369+ </span>1370+ </div>1371+ <div class="peach-settings-row peach-settings-row--meta">1372+ <span>Last sync</span>1373+ <span class="peach-settings-value">{lastSyncAt() ? formatRelativeTime(lastSyncAt()) : "Never synced"}</span>1374+ </div>1375+ <div class="peach-settings-row peach-settings-row--meta">1376+ <button1377+ class="peach-btn peach-btn--subtle peach-btn--sm"1378+ onClick={() => void handleSyncNow()}1379+ disabled={syncStatus() === "not_trusted" || syncingNow()}1380+ >1381+ <Switch>1382+ <Match when={syncingNow()}>Syncing…</Match>1383+ <Match when={syncFeedback()?.kind === "ok"}>✓ {syncFeedback()!.text}</Match>1384+ <Match when={syncFeedback()?.kind === "err"}>{syncFeedback()!.text}</Match>1385+ <Match when={true}>Sync now</Match>1386+ </Switch>1387+ </button>1388+ </div>1389+ <p class="peach-settings-hint">1390+ If you edit on multiple devices before syncing, the most recently1391+ changed device wins. Use Vault History to recover older versions.1392+ </p>13801393 1381- <div class="peach-settings-row peach-settings-row--meta peach-settings-row--stack">1382- <span class="peach-sync-section-label">Trusted networks ({trustedNetworks().length})</span>1383- <For each={trustedNetworks()}>1384- {(network) => (1385- <div class="peach-sync-device-row">1386- <span class="peach-sync-device-name">1387- {network.isTailscale ? "Tailscale" : (network.ssid ?? "Unknown network")}1388- </span>1389- <Show1390- when={!network.isTailscale}1391- fallback={<span class="peach-sync-device-meta">Always trusted</span>}1392- >1393- <button1394- class="peach-btn peach-btn--ghost peach-btn--sm peach-sync-remove-btn"1395- onClick={() => void handleRemoveNetwork(network.ssid, network.bssid, network.isTailscale)}1396- >1397- Remove1398- </button>1399- </Show>1400- </div>1401- )}1402- </For>1403- <div class="peach-settings-actions--row">1404- <Show when={!isCurrentNetworkTrusted()}>1394+ <div class="peach-settings-row peach-settings-row--meta peach-settings-row--stack">1395+ <span class="peach-sync-section-label">Trusted networks ({trustedNetworks().length})</span>1396+ <For each={trustedNetworks()}>1397+ {(network) => (1398+ <div class="peach-sync-device-row">1399+ <span class="peach-sync-device-name">1400+ {network.isTailscale ? "Tailscale" : (network.ssid ?? "Unknown network")}1401+ </span>1402+ <Show1403+ when={!network.isTailscale}1404+ fallback={<span class="peach-sync-device-meta">Always trusted</span>}1405+ >14051406 <button1406- class="peach-btn peach-btn--subtle peach-btn--sm"1407- onClick={() => void handleMarkNetworkTrusted()}1408- disabled={markingNetwork()}1407+ class="peach-btn peach-btn--ghost peach-btn--sm peach-sync-remove-btn"1408+ onClick={() => void handleRemoveNetwork(network.ssid, network.bssid, network.isTailscale)}14091409 >1410- {markingNetwork() ? "Marking…" : "Mark current network as trusted"}1410+ Remove14111411 </button>14121412 </Show>14131413 </div>1414- </div>1415-1416- <div class="peach-settings-row peach-settings-row--meta peach-settings-row--stack">1417- <span class="peach-sync-section-label">Advanced</span>1418- <Show1419- when={resetIdentityConfirm()}1420- fallback={1421- <div class="peach-sync-advanced-row">1422- <div class="peach-sync-advanced-info">1423- <span class="peach-sync-advanced-name">Reset sync identity</span>1424- <span class="peach-sync-device-meta">1425- Generates a new keypair and unpairs every device.1426- </span>1427- </div>1428- <button1429- class="peach-btn peach-btn--ghost peach-btn--sm peach-sync-remove-btn"1430- onClick={() => setResetIdentityConfirm(true)}1431- >1432- Reset1433- </button>1434- </div>1435- }1414+ )}1415+ </For>1416+ <div class="peach-settings-actions--row">1417+ <Show when={!isCurrentNetworkTrusted()}>1418+ <button1419+ class="peach-btn peach-btn--subtle peach-btn--sm"1420+ onClick={() => void handleMarkNetworkTrusted()}1421+ disabled={markingNetwork()}14361422 >1437- <div class="peach-sync-reset-confirm">1438- <p class="peach-sync-reset-confirm-headline">Reset sync identity?</p>1439- <p class="peach-sync-reset-confirm-body">1440- This will unpair all devices. You will need to pair them again from scratch.1441- </p>1442- <div class="peach-settings-actions--row">1443- <button1444- class="peach-btn peach-btn--ghost peach-btn--sm"1445- onClick={() => setResetIdentityConfirm(false)}1446- disabled={resetIdentityRunning()}1447- >1448- Cancel1449- </button>1450- <button1451- class="peach-btn peach-btn--danger peach-btn--sm"1452- onClick={() => void handleResetSyncIdentity()}1453- disabled={resetIdentityRunning()}1454- >1455- {resetIdentityRunning() ? "Resetting..." : "Reset"}1456- </button>1457- </div>1423+ {markingNetwork() ? "Marking…" : "Mark current network as trusted"}1424+ </button>1425+ </Show>1426+ </div>1427+ </div>1428+1429+ <div class="peach-settings-row peach-settings-row--meta peach-settings-row--stack">1430+ <span class="peach-sync-section-label">Advanced</span>1431+ <Show1432+ when={resetIdentityConfirm()}1433+ fallback={1434+ <div class="peach-sync-advanced-row">1435+ <div class="peach-sync-advanced-info">1436+ <span class="peach-sync-advanced-name">Reset sync identity</span>1437+ <span class="peach-sync-device-meta">1438+ Generates a new keypair and unpairs every device.1439+ </span>14581440 </div>1459- </Show>1441+ <button1442+ class="peach-btn peach-btn--ghost peach-btn--sm peach-sync-remove-btn"1443+ onClick={() => setResetIdentityConfirm(true)}1444+ >1445+ Reset1446+ </button>1447+ </div>1448+ }1449+ >1450+ <div class="peach-sync-reset-confirm">1451+ <p class="peach-sync-reset-confirm-headline">Reset sync identity?</p>1452+ <p class="peach-sync-reset-confirm-body">1453+ This will unpair all devices. You will need to pair them again from scratch.1454+ </p>1455+ <div class="peach-settings-actions--row">1456+ <button1457+ class="peach-btn peach-btn--ghost peach-btn--sm"1458+ onClick={() => setResetIdentityConfirm(false)}1459+ disabled={resetIdentityRunning()}1460+ >1461+ Cancel1462+ </button>1463+ <button1464+ class="peach-btn peach-btn--danger peach-btn--sm"1465+ onClick={() => void handleResetSyncIdentity()}1466+ disabled={resetIdentityRunning()}1467+ >1468+ {resetIdentityRunning() ? "Resetting..." : "Reset"}1469+ </button>1470+ </div>14601471 </div>1461- </>1462- }1463- >1464- <Show when={pairedDevices().length > 0}>1465- <div class="peach-sync-pro-hint">1466- <p class="peach-settings-hint">1467- Upgrade to Pro for automatic background sync across all your devices.1468- </p>1469- <button1470- class="peach-btn peach-btn--subtle peach-btn--sm"1471- onClick={() => setActiveSection("license")}1472- >1473- Upgrade to Pro1474- </button>1475- </div>1476- </Show>1472+ </Show>1473+ </div>14771474 </Show>14781475 </div>14791476 </div>