diff --git a/package.json b/package.json index 4b9dd7af..d958daf3 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "@getalby/sdk": "^2.7.0", "@nostr-dev-kit/ndk": "^2.1.1", "@nostr-fetch/adapter-ndk": "^0.13.1", + "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-collapsible": "^1.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fbb842dd..ae41afd1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ dependencies: '@nostr-fetch/adapter-ndk': specifier: ^0.13.1 version: 0.13.1(@nostr-dev-kit/ndk@2.1.1)(nostr-fetch@0.13.1) + '@radix-ui/react-accordion': + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@18.2.17)(@types/react@18.2.39)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-alert-dialog': specifier: ^1.0.5 version: 1.0.5(@types/react-dom@18.2.17)(@types/react@18.2.39)(react-dom@18.2.0)(react@18.2.0) @@ -888,6 +891,35 @@ packages: '@babel/runtime': 7.23.4 dev: false + /@radix-ui/react-accordion@1.1.2(@types/react-dom@18.2.17)(@types/react@18.2.39)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-fDG7jcoNKVjSK6yfmuAs0EnPDro0WMXIhMtXdTBWqEioVW206ku+4Lw07e+13lUkFkpoEQ2PdeMIAGpdqEAmDg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.4 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-collapsible': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.39)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.39)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.39)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.39)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.39)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.39)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.17)(@types/react@18.2.39)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.39)(react@18.2.0) + '@types/react': 18.2.39 + '@types/react-dom': 18.2.17 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-alert-dialog@1.0.5(@types/react-dom@18.2.17)(@types/react@18.2.39)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-OrVIOcZL0tl6xibeuGt5/+UxoT2N27KCFOPjFyfXMnchxSHZ/OW7cCX2nGlIYJrbHK/fczPcFzAwvNBB6XBNMA==} peerDependencies: diff --git a/src/app.tsx b/src/app.tsx index d421a6cb..54390789 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -3,7 +3,6 @@ import { fetch } from '@tauri-apps/plugin-http'; import { RouterProvider, createBrowserRouter, defer, redirect } from 'react-router-dom'; import { ReactFlowProvider } from 'reactflow'; -import { OnboardingScreen } from '@app/auth/onboarding'; import { ChatsScreen } from '@app/chats'; import { ErrorScreen } from '@app/error'; import { ExploreScreen } from '@app/explore'; @@ -15,6 +14,7 @@ import { AppLayout } from '@shared/layouts/app'; import { AuthLayout } from '@shared/layouts/auth'; import { NewLayout } from '@shared/layouts/new'; import { NoteLayout } from '@shared/layouts/note'; +import { OnboardingLayout } from '@shared/layouts/onboarding'; import { SettingsLayout } from '@shared/layouts/settings'; import './app.css'; @@ -197,34 +197,21 @@ export default function App() { }, { path: 'onboarding', - element: , + element: , errorElement: , children: [ { path: '', async lazy() { - const { OnboardingListScreen } = await import( - '@app/auth/onboarding/list' - ); - return { Component: OnboardingListScreen }; + const { OnboardingScreen } = await import('@app/auth/onboarding'); + return { Component: OnboardingScreen }; }, }, { - path: 'enrich', + path: 'follow', async lazy() { - const { OnboardEnrichScreen } = await import( - '@app/auth/onboarding/enrich' - ); - return { Component: OnboardEnrichScreen }; - }, - }, - { - path: 'hashtag', - async lazy() { - const { OnboardHashtagScreen } = await import( - '@app/auth/onboarding/hashtag' - ); - return { Component: OnboardHashtagScreen }; + const { FollowScreen } = await import('@app/auth/follow'); + return { Component: FollowScreen }; }, }, ], diff --git a/src/app/auth/components/features/allowNotification.tsx b/src/app/auth/components/features/allowNotification.tsx deleted file mode 100644 index 4e23bc1b..00000000 --- a/src/app/auth/components/features/allowNotification.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { isPermissionGranted, requestPermission } from '@tauri-apps/plugin-notification'; - -import { CheckCircleIcon } from '@shared/icons'; - -import { useOnboarding } from '@stores/onboarding'; - -export function AllowNotification() { - const [notification, setNotification] = useOnboarding((state) => [ - state.notification, - state.toggleNotification, - ]); - - const allow = async () => { - let permissionGranted = await isPermissionGranted(); - if (!permissionGranted) { - const permission = await requestPermission(); - permissionGranted = permission === 'granted'; - } - if (permissionGranted) { - setNotification(); - } - }; - - return ( -
-
-
-
Allow notification
-

- By allowing Lume to send notifications in your OS settings, you will receive - notification messages when someone interacts with you or your content. -

-
- {notification ? ( -
- -
- ) : ( - - )} -
-
- ); -} diff --git a/src/app/auth/components/features/enableCircle.tsx b/src/app/auth/components/features/enableCircle.tsx deleted file mode 100644 index 42694f7e..00000000 --- a/src/app/auth/components/features/enableCircle.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk'; -import { LRUCache } from 'lru-cache'; -import { useState } from 'react'; -import { toast } from 'sonner'; - -import { useNDK } from '@libs/ndk/provider'; -import { useStorage } from '@libs/storage/provider'; - -import { CheckCircleIcon, LoaderIcon } from '@shared/icons'; - -import { useOnboarding } from '@stores/onboarding'; - -export function Circle() { - const { db } = useStorage(); - const { ndk } = useNDK(); - - const [circle, setCircle] = useOnboarding((state) => [ - state.circle, - state.toggleCircle, - ]); - const [loading, setLoading] = useState(false); - - const enableLinks = async () => { - setLoading(true); - - const users = ndk.getUser({ pubkey: db.account.pubkey }); - const follows = await users.follows(); - - if (follows.size === 0) { - setLoading(false); - return toast('You need to follow at least 1 account'); - } - - const lru = new LRUCache({ max: 300 }); - const followsAsArr = []; - - // add user's follows to lru - follows.forEach((user) => { - lru.set(user.pubkey, user.pubkey); - followsAsArr.push(user.pubkey); - }); - - // get follows from follows - const events = await ndk.fetchEvents({ - kinds: [NDKKind.Contacts], - authors: followsAsArr, - limit: 300, - }); - - events.forEach((event: NDKEvent) => { - event.tags.forEach((tag) => { - if (tag[0] === 'p') lru.set(tag[1], tag[1]); - }); - }); - - // get lru values - const circleList = [...lru.values()] as string[]; - - // update db - await db.updateAccount('follows', JSON.stringify(followsAsArr)); - await db.updateAccount('circles', JSON.stringify(circleList)); - - db.account.follows = followsAsArr; - db.account.circles = circleList; - - // clear lru - lru.clear(); - - // done - await db.createSetting('circles', '1'); - setCircle(); - }; - - return ( -
-
-
-
Enable Circle
-

- Beside newsfeed from your follows, you will see more content from all people - that followed by your follows. -

-
- {circle ? ( -
- -
- ) : ( - - )} -
-
- ); -} diff --git a/src/app/auth/components/features/enableOutbox.tsx b/src/app/auth/components/features/enableOutbox.tsx deleted file mode 100644 index 7e0fb17f..00000000 --- a/src/app/auth/components/features/enableOutbox.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { useStorage } from '@libs/storage/provider'; - -import { CheckCircleIcon } from '@shared/icons'; - -import { useOnboarding } from '@stores/onboarding'; - -export function OutboxModel() { - const { db } = useStorage(); - - const [outbox, setOutbox] = useOnboarding((state) => [ - state.outbox, - state.toggleOutbox, - ]); - - const enableOutbox = async () => { - await db.createSetting('outbox', '1'); - setOutbox(); - }; - - return ( -
-
-
-
Enable Outbox
-

- When you request information about a user, Lume will automatically query the - user's outbox relays and subsequent queries will favour using those - relays for queries with that user's pubkey. -

-
- {outbox ? ( -
- -
- ) : ( - - )} -
-
- ); -} diff --git a/src/app/auth/components/features/favoriteHashtag.tsx b/src/app/auth/components/features/favoriteHashtag.tsx deleted file mode 100644 index 928d3c96..00000000 --- a/src/app/auth/components/features/favoriteHashtag.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { Link } from 'react-router-dom'; - -import { CheckCircleIcon } from '@shared/icons'; - -import { useOnboarding } from '@stores/onboarding'; - -export function FavoriteHashtag() { - const hashtag = useOnboarding((state) => state.hashtag); - - return ( -
-
-
-
Favorite topic
-

- By adding favorite topic, Lume will display all contents related to this topic - for you -

-
- {hashtag ? ( -
- -
- ) : ( - - Add - - )} -
-
- ); -} diff --git a/src/app/auth/components/features/followList.tsx b/src/app/auth/components/features/followList.tsx deleted file mode 100644 index 03a7c29f..00000000 --- a/src/app/auth/components/features/followList.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; - -import { useNDK } from '@libs/ndk/provider'; -import { useStorage } from '@libs/storage/provider'; - -import { LoaderIcon } from '@shared/icons'; -import { User } from '@shared/user'; - -export function FollowList() { - const { db } = useStorage(); - const { ndk } = useNDK(); - const { status, data } = useQuery({ - queryKey: ['follows'], - queryFn: async () => { - const user = ndk.getUser({ pubkey: db.account.pubkey }); - const follows = [...(await user.follows())].map((user) => user.pubkey); - - // update db - await db.updateAccount('follows', JSON.stringify(follows)); - db.account.follows = follows; - - return follows; - }, - refetchOnWindowFocus: false, - }); - - return ( -
-
Your follows
-
- {status === 'pending' ? ( - - ) : ( -
- {data.slice(0, 16).map((item) => ( - - ))} - {data.length > 16 ? ( -
- +{data.length} -
- ) : null} -
- )} -
-
- ); -} diff --git a/src/app/auth/components/features/suggestFollow.tsx b/src/app/auth/components/features/suggestFollow.tsx deleted file mode 100644 index 8884baa2..00000000 --- a/src/app/auth/components/features/suggestFollow.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { Link } from 'react-router-dom'; - -import { CheckCircleIcon } from '@shared/icons'; - -import { useOnboarding } from '@stores/onboarding'; - -export function SuggestFollow() { - const enrich = useOnboarding((state) => state.enrich); - - return ( -
-
-
-
Enrich your network
-

- Follow more people to stay up to date with everything happening around the - world. -

-
- {enrich ? ( -
- -
- ) : ( - - Check - - )} -
-
- ); -} diff --git a/src/app/auth/create.tsx b/src/app/auth/create.tsx index d5bad9ee..a5e38ab4 100644 --- a/src/app/auth/create.tsx +++ b/src/app/auth/create.tsx @@ -15,7 +15,7 @@ import { useNDK } from '@libs/ndk/provider'; import { useStorage } from '@libs/storage/provider'; import { AvatarUploader } from '@shared/avatarUploader'; -import { ArrowLeftIcon, LoaderIcon } from '@shared/icons'; +import { ArrowLeftIcon, InfoIcon, LoaderIcon } from '@shared/icons'; import { User } from '@shared/user'; export function CreateAccountScreen() { @@ -123,33 +123,33 @@ export function CreateAccountScreen() { {!keys ? ( ) : null}
-

+

Let's set up your account.

{!keys ? ( -
+
Avatar -
+
{picture.length > 0 ? ( user's avatar ) : ( )} -
- -
+
@@ -174,7 +172,7 @@ export function CreateAccountScreen() { minLength: 1, })} spellCheck={false} - className="h-11 rounded-lg bg-neutral-200 px-3 placeholder:text-neutral-500 dark:bg-neutral-800 dark:placeholder:text-neutral-400" + className="h-11 rounded-lg border-transparent bg-neutral-100 px-3 placeholder:text-neutral-500 focus:border-blue-500 focus:ring focus:ring-blue-200 dark:bg-neutral-900 dark:placeholder:text-neutral-400 dark:focus:ring-blue-800" />
@@ -184,20 +182,29 @@ export function CreateAccountScreen() {