diff --git a/bun.lockb b/bun.lockb index 78029912..d25561ea 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 30586057..f7163016 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "**/*.{ts, tsx, css, md, html, json}": "prettier --cache --write" }, "dependencies": { - "@ctrl/magnet-link": "^3.1.2", "@getalby/sdk": "^2.4.0", "@nostr-dev-kit/ndk": "^1.0.0", "@nostr-fetch/adapter-ndk": "^0.12.2", @@ -38,7 +37,6 @@ "@tiptap/react": "^2.1.8", "@tiptap/starter-kit": "^2.1.8", "@tiptap/suggestion": "^2.1.8", - "@void-cat/api": "^1.0.7", "dayjs": "^1.11.9", "destr": "^2.0.1", "get-urls": "^12.1.0", @@ -53,7 +51,6 @@ "react-currency-input-field": "^3.6.11", "react-dom": "^18.2.0", "react-hook-form": "^7.46.1", - "react-hotkeys-hook": "^4.4.1", "react-markdown": "^8.0.7", "react-player": "^2.13.0", "react-router-dom": "^6.15.0", @@ -64,7 +61,6 @@ "tauri-plugin-store-api": "github:tauri-apps/tauri-plugin-store#v1", "tauri-plugin-stronghold-api": "github:tauri-apps/tauri-plugin-stronghold#v1", "tauri-plugin-upload-api": "github:tauri-apps/tauri-plugin-upload#v1", - "tippy.js": "^6.3.7", "zustand": "^4.4.1" }, "devDependencies": { diff --git a/src/app.tsx b/src/app.tsx index 9c09fa2f..cd9c8897 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -205,15 +205,15 @@ const router = createBrowserRouter([ return { Component: OnboardStep2Screen }; }, }, - { - path: 'step-3', - async lazy() { - const { OnboardStep3Screen } = await import('@app/auth/onboarding/step-3'); - return { Component: OnboardStep3Screen }; - }, - }, ], }, + { + path: 'complete', + async lazy() { + const { CompleteScreen } = await import('@app/auth/complete'); + return { Component: CompleteScreen }; + }, + }, { path: 'unlock', async lazy() { @@ -235,13 +235,6 @@ const router = createBrowserRouter([ return { Component: ResetScreen }; }, }, - { - path: 'hard-reset', - async lazy() { - const { HardResetScreen } = await import('@app/auth/hardReset'); - return { Component: HardResetScreen }; - }, - }, ], }, { diff --git a/src/app/auth/complete.tsx b/src/app/auth/complete.tsx new file mode 100644 index 00000000..5a3a3291 --- /dev/null +++ b/src/app/auth/complete.tsx @@ -0,0 +1,43 @@ +import { useEffect, useState } from 'react'; +import { useNavigate } from 'react-router-dom'; + +export function CompleteScreen() { + const navigate = useNavigate(); + const [count, setCount] = useState(3); + + useEffect(() => { + let counter: NodeJS.Timeout; + + if (count > 0) { + counter = setTimeout(() => setCount(count - 1), 1000); + } + + if (count === 0) { + navigate('/', { replace: true }); + } + + return () => { + clearTimeout(counter); + }; + }, [count]); + + return ( +
+
+

+ You're ready, redirecting in {count} + ... +

+

+ Thank you for using Lume. Lume doesn't use telemetry. If you encounter any + problems, please submit a report via the "Report Issue" button. +
+ You can find it while using the application. +

+
+
+ lume +
+
+ ); +} diff --git a/src/app/auth/components/user.tsx b/src/app/auth/components/user.tsx index 66175688..bfded070 100644 --- a/src/app/auth/components/user.tsx +++ b/src/app/auth/components/user.tsx @@ -1,7 +1,9 @@ +import { Link } from 'react-router-dom'; + +import { WorldIcon } from '@shared/icons'; import { Image } from '@shared/image'; import { useProfile } from '@utils/hooks/useProfile'; -import { displayNpub } from '@utils/shortenKey'; export function User({ pubkey, fallback }: { pubkey: string; fallback?: string }) { const { status, user } = useProfile(pubkey, fallback); @@ -9,7 +11,7 @@ export function User({ pubkey, fallback }: { pubkey: string; fallback?: string } if (status === 'loading') { return (
-
+
@@ -19,19 +21,33 @@ export function User({ pubkey, fallback }: { pubkey: string; fallback?: string } } return ( -
+
{pubkey} -
-

- {user?.name || user?.display_name} -

- - {displayNpub(pubkey, 16)} - +
+
+

+ {user?.name || user?.display_name} +

+

+ {user?.about || user?.bio || 'No bio'} +

+
+
+ {user?.website ? ( + + +

{user.website}

+ + ) : null} +
); diff --git a/src/app/auth/components/userImport.tsx b/src/app/auth/components/userImport.tsx new file mode 100644 index 00000000..8801f8fe --- /dev/null +++ b/src/app/auth/components/userImport.tsx @@ -0,0 +1,38 @@ +import { Image } from '@shared/image'; + +import { useProfile } from '@utils/hooks/useProfile'; +import { displayNpub } from '@utils/shortenKey'; + +export function UserImport({ pubkey }: { pubkey: string }) { + const { status, user } = useProfile(pubkey); + + if (status === 'loading') { + return ( +
+
+
+ + +
+
+ ); + } + + return ( +
+ {pubkey} +
+

+ {user?.name || user?.display_name} +

+

+ {user?.nip05 || user?.username || displayNpub(pubkey, 16)} +

+
+
+ ); +} diff --git a/src/app/auth/create/step-1.tsx b/src/app/auth/create/step-1.tsx index 1276cec6..48c39bef 100644 --- a/src/app/auth/create/step-1.tsx +++ b/src/app/auth/create/step-1.tsx @@ -1,13 +1,14 @@ -import { BaseDirectory, writeTextFile } from '@tauri-apps/api/fs'; +import { writeText } from '@tauri-apps/api/clipboard'; +import { message, save } from '@tauri-apps/api/dialog'; +import { writeTextFile } from '@tauri-apps/api/fs'; +import { downloadDir } from '@tauri-apps/api/path'; import { generatePrivateKey, getPublicKey, nip19 } from 'nostr-tools'; import { useEffect, useMemo, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useStorage } from '@libs/storage/provider'; -import { Button } from '@shared/button'; -import { EyeOffIcon, EyeOnIcon, LoaderIcon } from '@shared/icons'; -import { ArrowRightCircleIcon } from '@shared/icons/arrowRightCircle'; +import { CopyIcon } from '@shared/icons'; import { useOnboarding } from '@stores/onboarding'; import { useStronghold } from '@stores/stronghold'; @@ -21,8 +22,8 @@ export function CreateStep1Screen() { const setPubkey = useOnboarding((state) => state.setPubkey); const setStep = useOnboarding((state) => state.setStep); - const [privkeyInput, setPrivkeyInput] = useState('password'); const [loading, setLoading] = useState(false); + const [copied, setCopied] = useState(false); const [downloaded, setDownloaded] = useState(false); const privkey = useMemo(() => generatePrivateKey(), []); @@ -30,27 +31,39 @@ export function CreateStep1Screen() { const npub = nip19.npubEncode(pubkey); const nsec = nip19.nsecEncode(privkey); - // toggle private key - const showPrivateKey = () => { - if (privkeyInput === 'password') { - setPrivkeyInput('text'); - } else { - setPrivkeyInput('password'); + const download = async () => { + try { + const downloadPath = await downloadDir(); + const fileName = `nostr_keys_${new Date().toISOString()}.txt`; + const filePath = await save({ + defaultPath: downloadPath + '/' + fileName, + }); + + if (filePath) { + await writeTextFile( + filePath, + `Generated by Lume (lume.nu)\nPublic key: ${npub}\nPrivate key: ${nsec}` + ); + + setDownloaded(true); + } // else { user cancel action } + } catch (e) { + await message(e, { title: 'Cannot download account keys', type: 'error' }); } }; - const download = async () => { - await writeTextFile( - `nostr_keys_${new Date().toISOString().slice(0, 10)}.txt`, - `Generated by Lume (lume.nu)\nPublic key: ${npub}\nPrivate key: ${nsec}`, - { - dir: BaseDirectory.Download, - } - ); - setDownloaded(true); + const copyPrivkey = async () => { + try { + await writeText(nsec); + setCopied(true); + + setTimeout(() => setCopied(false), 3000); + } catch (e) { + await message(e, { title: 'Cannot copy private key', type: 'error' }); + } }; - const submit = () => { + const submit = async () => { setLoading(true); // update state @@ -59,7 +72,7 @@ export function CreateStep1Screen() { setPubkey(pubkey); // save to database - db.createAccount(npub, pubkey); + await db.createAccount(npub, pubkey); // redirect to next step navigate('/auth/create/step-2', { replace: true }); @@ -72,76 +85,68 @@ export function CreateStep1Screen() { return (
-
-

Save your access key!

+
+

+ This is your new Nostr account +

+

+ Your private key is your password. If you lose this key, you will lose access to + your account! Copy it and keep it in a safe place. There is no way to reset your + private key. +

+

+ Public key is used for sharing with other people so that they can find you using + the public key. +

-
-
- Public Key - -
-
- Private Key -
+
+
+
+ Private Key +
+ + +
+
+
+ Public Key - -
-
-

- Your private key is your password. If you lose this key, you will lose - access to your account! Copy it and keep it in a safe place. There is no way - to reset your private key. -

- {downloaded ? ( - - Saved in Download folder - - ) : ( - - )} + + + By clicking 'Continue', you are ensuring that your keys are saved in + a safe place. You cannot recover these keys if they are lost. +
diff --git a/src/app/auth/create/step-2.tsx b/src/app/auth/create/step-2.tsx index 34586420..84e5dfab 100644 --- a/src/app/auth/create/step-2.tsx +++ b/src/app/auth/create/step-2.tsx @@ -86,10 +86,16 @@ export function CreateStep2Screen() { return (
-
-

+
+

Set password to secure your key

+

+ Password is not related to your Nostr account. It is only used to secure your + keys stored on your local machine and to unlock the app (like unlocking your + phone with a passcode). When you move to other Nostr clients, you just need to + copy your private key. +

@@ -98,12 +104,13 @@ export function CreateStep2Screen() {
-
-

- Password is use to secure your key store in local machine, when you move - to other clients, you just need to copy your private key as nsec or - hexstring -

-
{errors.password &&

{errors.password.message}

}
@@ -127,12 +127,12 @@ export function CreateStep2Screen() {