diff --git a/AGENTS.md b/AGENTS.md index d6c7d58..eefdcfa 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1527,10 +1527,15 @@ session with **no other memory of this project**. So: `min-width: 1024px`, after ~900 ms) as a welcome/sign-in offer; dismissal is remembered in `skatespots:desktop-welcome-dismissed`, and it also offers the normal `SignupDialog`. It reuses the existing methods (browser extension, - bunker/signer, Amber on Android, nsec, and the **NostrConnect QR**), which is - what the reference screenshot showed — the dialog is still **tabbed**, not - the reference's 3-card layout (a restyle would need a visual QA pass). - ⚠️ `SignupDialog` is a **default-only** export, so lazy-load it as + bunker/signer, Amber on Android, nsec, and the **NostrConnect QR**). + **3-card restyle (2026-10-26):** `LoginDialog` now leads with a **three-card + chooser** — Browser extension / Signer (Bunker on desktop, Amber on Android) / + **Sign in with your phone** (NostrConnect) — plus a quiet **Secret Key** link; + the cards are a **controlled tab chooser** (`loginTab` state) over the existing + panels, and the NostrConnect QR moved from the bunker tab into its own + `connect` panel. Verified with a headless 1280×900 screenshot of the + auto-opened welcome modal. ⚠️ `SignupDialog` is a **default-only** export, so + lazy-load it as `lazy(() => import('…/SignupDialog'))`. - **First-run checklist + backup-reminder gating (fixed 2026-10-12).** Two onboarding prompts nagged returning users: @@ -2288,6 +2293,17 @@ Rules: `xlsx@0.18.5` (two high; **no fix published**) and `zod` (patch). Dev-dep CVEs don't ship to users; `xlsx` is lazy-loaded for exports. Run `--force` to apply the fixable ones (gated on tests). + ⚠️ **`--force` on 2026-10-26 failed the gate and auto-reverted:** the blind + `npm update` cut OSV findings 107 → 13 but produced **duplicate transitive + copies** (`@tanstack/query-core` nested under `react-query-persist-client`; + `@nostrify/nostrify`/`@nostrify/types` nested under `@nostrify/react`) and a + **TypeScript bump** (TS 5.9 typed-array errors in `stashBackup`/`usePushNotifications`), + so `tsc` failed. The remaining fixes are mostly **major** (vitest 4, + react-router 7, zod 4) plus **`xlsx@0.18.5` with no fix** (we only *write* + XLSX for export, so the parse-side CVEs likely don't apply — verify before + replacing). Lesson: do NOT rely on a blanket `npm update`; update in curated + batches (pin `typescript`, add `overrides`/`npm dedupe` for the duplicated + packages, keep majors as their own migrations) and let the timer gate each. ### Community relay — self-hosted Newlay (2026-10-12) diff --git a/src/components/auth/LoginDialog.tsx b/src/components/auth/LoginDialog.tsx index 6184819..c9e6919 100644 --- a/src/components/auth/LoginDialog.tsx +++ b/src/components/auth/LoginDialog.tsx @@ -11,7 +11,7 @@ import { Shield, UserPlus, Sparkles, Cloud, Smartphone, Check, Loader2, KeyRound import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; +import { Tabs, TabsContent } from '@/components/ui/tabs'; import { useLoginActions } from '@/hooks/useLoginActions'; import { useToast } from '@/hooks/useToast'; import { cn } from '@/lib/utils'; @@ -64,6 +64,10 @@ export const LoginDialog: React.FC = ({ isOpen, onClose, onLog const { toast } = useToast(); const isAndroid = /Android/i.test(navigator.userAgent); + // Which login method panel is showing. The three method cards below switch it. + const [loginTab, setLoginTab] = useState<'amber' | 'bunker' | 'nsec' | 'extension' | 'connect'>( + isAndroid ? 'amber' : 'bunker', + ); // Step 1: open Amber // - On Capacitor (ZapStore APK): use the native plugin — direct Promise, no redirects needed @@ -349,21 +353,46 @@ export const LoginDialog: React.FC = ({ isOpen, onClose, onLog
- - - - Amber - - - Bunker - - - nsec - - - Ext - - + setLoginTab(v as typeof loginTab)} className="w-full"> + {/* Method cards — a clear three-way choice (the old 4-tab strip was + jargon-heavy). The secret-key option stays as a quiet link. */} +
+ {([ + { id: 'extension', Icon: Shield, label: t('settingsUi.loginDialog.browserExtensionTitle') }, + { id: isAndroid ? 'amber' : 'bunker', Icon: isAndroid ? Smartphone : Cloud, label: isAndroid ? t('settingsUi.loginDialog.loginWithAmber') : t('settingsUi.loginDialog.bunkerTitle') }, + { id: 'connect', Icon: QrCode, label: t('settingsUi.loginDialog.signInWithPhone') }, + ] as const).map(({ id, Icon, label }) => { + const active = loginTab === id; + return ( + + ); + })} +
+
+ +
{/* ── AMBER TAB ── */} @@ -476,8 +505,8 @@ export const LoginDialog: React.FC = ({ isOpen, onClose, onLog - {/* ── BUNKER TAB ── */} - + {/* ── NOSTR CONNECT TAB ── */} + {/* Phone pairing — the canonical "log in on desktop with the key already on your phone" flow. Client-generated URI; the signer scans and pairs over a relay. */} @@ -545,7 +574,10 @@ export const LoginDialog: React.FC = ({ isOpen, onClose, onLog )} + + {/* ── BUNKER TAB ── */} +
{t('settingsUi.loginDialog.orPasteBunker')}