diff --git a/desktop/src/features/onboarding/ui/BackupStep.tsx b/desktop/src/features/onboarding/ui/BackupStep.tsx index aecc128dd..54c8f45cd 100644 --- a/desktop/src/features/onboarding/ui/BackupStep.tsx +++ b/desktop/src/features/onboarding/ui/BackupStep.tsx @@ -1,12 +1,14 @@ -import { AlertTriangle, Info, RefreshCw } from "lucide-react"; +import { ArrowLeft, Check, Copy, Eye, EyeOff, Info } from "lucide-react"; import * as React from "react"; import { getNsec } from "@/shared/api/tauriIdentity"; import { cn } from "@/shared/lib/cn"; +import { writeTextToClipboard } from "@/shared/lib/clipboard"; import { Button } from "@/shared/ui/button"; import { FuzzyLogo } from "@/shared/ui/buzz-logo/FuzzyLogo"; import { Card } from "@/shared/ui/card"; import { Spinner } from "@/shared/ui/spinner"; +import { Tooltip, TooltipContent, TooltipTrigger } from "@/shared/ui/tooltip"; import { ONBOARDING_PRIMARY_CTA_CLASS } from "./OnboardingChrome"; import { OnboardingFooter } from "./OnboardingFooter"; import { @@ -14,9 +16,7 @@ import { OnboardingSlideTransition, } from "./OnboardingSlideTransition"; import { EncryptedBackupCreator } from "./EncryptedBackupCreator"; -import { NsecMaskedDisplay } from "./NsecMaskedDisplay"; - -export type BackupStepMode = "encrypted" | "raw"; +import { ONBOARDING_KEY_TEXT_CLASS } from "./NsecMaskedDisplay"; /** * How long the "Creating your identity key" loader holds the stage before the @@ -25,9 +25,44 @@ export type BackupStepMode = "encrypted" | "raw"; */ const INTRO_HOLD_MS = 1400; +/** + * The creation moment should only be sold once per app session. Module-level + * so remounts (e.g. navigating Back and returning to this step) skip the fake + * hold and show the finished state instantly. + */ +let introPlayed = false; + const REVEAL_ANIMATION_CLASS = "animate-in fade-in duration-700 motion-reduce:animate-none"; +/** Quicker fade for switching between the chooser and a backup method. */ +const VIEW_ANIMATION_CLASS = + "animate-in fade-in duration-300 motion-reduce:animate-none"; + +/** + * The chooser offers both backup methods: copying happens in place, while the + * encrypted download flow expands into its own view. + */ +type BackupView = "choose" | "download"; + +function BackToOptions({ onClick }: { onClick: () => void }) { + return ( +
- A Keycase is still private. Never publish or share it. You - need both the file and password to restore your identity. -
+ {view === "choose" ? ( ++ {isRevealed && nsec ? nsec : maskedKey} +
++ Could not retrieve your private key: {copyError}. You can + continue and find it later in Settings > Profile > + Identity. +
+ ) : null} + + +
+
- No key available to back up. -
- )} - - {mode === "encrypted" ? ( -+ Your key is encrypted with your password before it + downloads. Keep the file private — you need both it and + the password to restore your identity. +
+
-
- Keycase saved to {savedPath} + Saved to {savedPath}
) : null}{saveError}
) : null}- Keep this Keycase private. You need both the file and its password to + Keep this file private. You need both the file and its password to restore your identity. Buzz cannot reset the password.
- Save this generated passphrase as your Keycase password. Store it - separately from the private Keycase file. + Save this generated passphrase as your encryption password. Store it + separately from the downloaded key file.
) : (- Your password protects the Keycase. Buzz cannot reset it if lost. + Your password protects your downloaded key. Buzz cannot reset it if + lost.