@@ -215,7 +232,7 @@ export function ImportAccountScreen() {
autoCorrect="off"
autoCapitalize="off"
placeholder="nsec1"
- className="h-11 w-full rounded-lg bg-neutral-200 px-3 placeholder:text-neutral-500 dark:bg-neutral-800 dark:placeholder:text-neutral-400"
+ className="h-11 w-full rounded-lg border-transparent bg-neutral-200 px-3 placeholder:text-neutral-500 focus:border-blue-500 focus:ring focus:ring-blue-200 dark:bg-neutral-800 dark:placeholder:text-neutral-400 dark:focus:ring-blue-800"
/>
{nsec.length < 5 ? (
@@ -282,11 +299,9 @@ export function ImportAccountScreen() {
opacity: 1,
y: 0,
}}
- className="inline-flex h-9 w-full shrink-0 items-center justify-center rounded-lg bg-blue-500 font-semibold text-white hover:bg-blue-600"
+ className="inline-flex h-11 w-full shrink-0 items-center justify-center rounded-lg bg-blue-500 font-semibold text-white hover:bg-blue-600"
type="button"
- onClick={() =>
- navigate('/auth/onboarding', { state: { newuser: false } })
- }
+ onClick={() => navigate('/auth/onboarding')}
>
Continue
diff --git a/src/app/auth/onboarding.tsx b/src/app/auth/onboarding.tsx
new file mode 100644
index 00000000..9b2e1b22
--- /dev/null
+++ b/src/app/auth/onboarding.tsx
@@ -0,0 +1,148 @@
+import * as Switch from '@radix-ui/react-switch';
+import { isPermissionGranted, requestPermission } from '@tauri-apps/plugin-notification';
+import { useEffect, useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+
+import { useStorage } from '@libs/storage/provider';
+
+import { InfoIcon } from '@shared/icons';
+
+export function OnboardingScreen() {
+ const { db } = useStorage();
+ const navigate = useNavigate();
+
+ const [settings, setSettings] = useState({
+ autoupdate: false,
+ outbox: false,
+ notification: false,
+ });
+
+ const next = () => {
+ if (!db.account.contacts) return navigate('/auth/onboarding/follow');
+ return navigate('/');
+ };
+
+ const toggleOutbox = async () => {
+ await db.createSetting('outbox', String(+!settings.outbox));
+ // update state
+ setSettings((prev) => ({ ...prev, outbox: !settings.outbox }));
+ };
+
+ const toggleAutoupdate = async () => {
+ await db.createSetting('autoupdate', String(+!settings.autoupdate));
+ db.settings.autoupdate = !settings.autoupdate;
+ // update state
+ setSettings((prev) => ({ ...prev, autoupdate: !settings.autoupdate }));
+ };
+
+ const toggleNofitication = async () => {
+ await requestPermission();
+ // update state
+ setSettings((prev) => ({ ...prev, notification: !settings.notification }));
+ };
+
+ useEffect(() => {
+ async function loadSettings() {
+ const permissionGranted = await isPermissionGranted();
+ setSettings((prev) => ({ ...prev, notification: permissionGranted }));
+
+ const data = await db.getAllSettings();
+ if (!data) return;
+
+ data.forEach((item) => {
+ if (item.key === 'autoupdate')
+ setSettings((prev) => ({
+ ...prev,
+ autoupdate: !!parseInt(item.value),
+ }));
+
+ if (item.key === 'outbox')
+ setSettings((prev) => ({
+ ...prev,
+ outbox: !!parseInt(item.value),
+ }));
+ });
+ }
+
+ loadSettings();
+ }, []);
+
+ return (
+
+
+
+
+ You're almost ready to use Lume.
+
+
+ Let's start personalizing your experience.
+
+
+
+
+
toggleAutoupdate()}
+ className="relative mt-1 h-7 w-12 shrink-0 cursor-default rounded-full bg-neutral-200 outline-none data-[state=checked]:bg-blue-500 dark:bg-neutral-800"
+ >
+
+
+
+
Auto check for update on Login
+
+ Keep Lume up to date with latest version, always have new features and bug
+ free.
+
+
+
+
+
toggleNofitication()}
+ className="relative mt-1 h-7 w-12 shrink-0 cursor-default rounded-full bg-neutral-200 outline-none data-[state=checked]:bg-blue-500 dark:bg-neutral-800"
+ >
+
+
+
+
Push notification
+
+ Enabling push notifications will allow you to receive notifications from
+ Lume directly on your device.
+
+
+
+
+
toggleOutbox()}
+ className="relative mt-1 h-7 w-12 shrink-0 cursor-default rounded-full bg-neutral-200 outline-none data-[state=checked]:bg-blue-500 dark:bg-neutral-800"
+ >
+
+
+
+
Use Gossip model (recommended)
+
+ Automatically discover relays to connect based on the preferences of each
+ author.
+
+
+
+
+
+
+ There are many more settings you can configure from the "Settings"
+ screen. Be sure to visit it later.
+
+
+
+ Continue
+
+
+
+
+ );
+}
diff --git a/src/app/auth/onboarding/enrich.tsx b/src/app/auth/onboarding/enrich.tsx
deleted file mode 100644
index 8716ebda..00000000
--- a/src/app/auth/onboarding/enrich.tsx
+++ /dev/null
@@ -1,140 +0,0 @@
-import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
-import { useQuery } from '@tanstack/react-query';
-import { useState } from 'react';
-import { useNavigate } from 'react-router-dom';
-import { toast } from 'sonner';
-
-import { useNDK } from '@libs/ndk/provider';
-import { useStorage } from '@libs/storage/provider';
-
-import { ArrowLeftIcon, CheckCircleIcon, LoaderIcon } from '@shared/icons';
-import { User } from '@shared/user';
-
-import { useOnboarding } from '@stores/onboarding';
-
-import { arrayToNIP02 } from '@utils/transform';
-
-export function OnboardEnrichScreen() {
- const { ndk } = useNDK();
- const { db } = useStorage();
- const { status, data } = useQuery({
- queryKey: ['trending-profiles-widget'],
- queryFn: async () => {
- const res = await fetch('https://api.nostr.band/v0/trending/profiles');
- if (!res.ok) {
- throw new Error('Error');
- }
- return res.json();
- },
- });
-
- const [loading, setLoading] = useState(false);
- const [follows, setFollows] = useState([]);
-
- const navigate = useNavigate();
- const setEnrich = useOnboarding((state) => state.toggleEnrich);
-
- // toggle follow state
- const toggleFollow = (pubkey: string) => {
- const arr = follows.includes(pubkey)
- ? follows.filter((i) => i !== pubkey)
- : [...follows, pubkey];
- setFollows(arr);
- };
-
- const submit = async () => {
- try {
- setLoading(true);
-
- const tags = arrayToNIP02(follows);
- const event = new NDKEvent(ndk);
- event.content = '';
- event.kind = NDKKind.Contacts;
- event.created_at = Math.floor(Date.now() / 1000);
- event.tags = tags;
-
- const publish = await event.publish();
-
- // redirect to next step
- if (publish) {
- db.account.follows = follows;
-
- await db.updateAccount('follows', JSON.stringify(follows));
- await db.updateAccount('circles', JSON.stringify(follows));
-
- setEnrich();
- navigate(-1);
- } else {
- setLoading(false);
- }
- } catch (e) {
- setLoading(false);
- toast(e);
- }
- };
-
- return (
-
-
-
navigate(-1)}
- className="inline-flex items-center gap-2 text-sm font-medium"
- >
-
- Back
-
-
-
-
- Enrich your network
-
-
-
- {status === 'pending' ? (
-
-
-
- ) : (
- data?.profiles.map((item: { pubkey: string; profile: { content: string } }) => (
-
toggleFollow(item.pubkey)}
- className="relative h-[300px] shrink-0 grow-0 basis-[250px] overflow-hidden rounded-lg bg-neutral-200 px-4 py-4 hover:bg-neutral-300 dark:bg-neutral-800 dark:hover:bg-neutral-700"
- >
-
- {follows.includes(item.pubkey) && (
-
-
-
- )}
-
- ))
- )}
-
-
-
- {loading ? (
- <>
-
- It might take a bit, please patient...
- >
- ) : (
- Follow {follows.length} accounts & Continue
- )}
-
-
-
- );
-}
diff --git a/src/app/auth/onboarding/hashtag.tsx b/src/app/auth/onboarding/hashtag.tsx
deleted file mode 100644
index b1df5f3d..00000000
--- a/src/app/auth/onboarding/hashtag.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-import { message } from '@tauri-apps/plugin-dialog';
-import { useState } from 'react';
-import { useNavigate } from 'react-router-dom';
-
-import { ArrowLeftIcon, CheckCircleIcon, LoaderIcon } from '@shared/icons';
-
-import { TOPICS, WIDGET_KIND } from '@stores/constants';
-import { useOnboarding } from '@stores/onboarding';
-
-import { useWidget } from '@utils/hooks/useWidget';
-
-export function OnboardHashtagScreen() {
- const [loading, setLoading] = useState(false);
- const [topic, setTopic] = useState(null);
-
- const navigate = useNavigate();
- const setHashtag = useOnboarding((state) => state.toggleHashtag);
-
- const { addWidget } = useWidget();
-
- const submit = async () => {
- try {
- setLoading(true);
- setHashtag();
-
- addWidget.mutate({
- kind: WIDGET_KIND.topic,
- title: topic.title,
- content: JSON.stringify(topic.content),
- });
-
- navigate(-1);
- } catch (e) {
- setLoading(false);
- await message(e, { title: 'Lume', type: 'error' });
- }
- };
-
- return (
-
-
-
navigate(-1)}
- className="inline-flex items-center gap-2 text-sm font-medium"
- >
-
- Back
-
-
-
-
- Choose your favorite topic
-
-
-
- {TOPICS.map((item) => (
-
setTopic(item)}
- className="inline-flex h-14 items-center justify-between rounded-xl bg-neutral-100 px-4 hover:bg-neutral-200 dark:bg-neutral-900 dark:hover:bg-neutral-800"
- >
- {item.title}
- {topic && topic.title === item.title && (
-
-
-
- )}
-
- ))}
-
-
- {loading ? (
- <>
-
- Adding...
- >
- ) : (
- Add & Continue
- )}
-
-
-
-
- );
-}
diff --git a/src/app/auth/onboarding/list.tsx b/src/app/auth/onboarding/list.tsx
deleted file mode 100644
index 19127ce4..00000000
--- a/src/app/auth/onboarding/list.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import { useState } from 'react';
-import { useLocation, useNavigate } from 'react-router-dom';
-
-import { AllowNotification } from '@app/auth/components/features/allowNotification';
-import { OutboxModel } from '@app/auth/components/features/enableOutbox';
-import { FavoriteHashtag } from '@app/auth/components/features/favoriteHashtag';
-import { FollowList } from '@app/auth/components/features/followList';
-import { SuggestFollow } from '@app/auth/components/features/suggestFollow';
-
-import { LoaderIcon } from '@shared/icons';
-
-export function OnboardingListScreen() {
- const { state } = useLocation();
- const { newuser }: { newuser: boolean } = state;
-
- const [loading, setLoading] = useState(false);
-
- const navigate = useNavigate();
-
- const completed = () => {
- setLoading(true);
-
- const timeout = setTimeout(() => setLoading(false), 200);
- clearTimeout(timeout);
-
- navigate('/');
- };
-
- return (
-
-
-
-
- You're almost ready to use Lume.
-
-
- Let's start personalizing your experience.
-
-
-
- {newuser ?
:
}
-
-
-
-
- {loading ? : ' Continue'}
-
-
-
-
- );
-}
diff --git a/src/app/auth/onboarding/relays.tsx b/src/app/auth/onboarding/relays.tsx
deleted file mode 100644
index 04f38471..00000000
--- a/src/app/auth/onboarding/relays.tsx
+++ /dev/null
@@ -1,160 +0,0 @@
-import { NDKEvent } from '@nostr-dev-kit/ndk';
-import { useQuery } from '@tanstack/react-query';
-import { useState } from 'react';
-import { useNavigate } from 'react-router-dom';
-import { toast } from 'sonner';
-
-import { useNDK } from '@libs/ndk/provider';
-import { useStorage } from '@libs/storage/provider';
-
-import { ArrowLeftIcon, CheckCircleIcon, LoaderIcon } from '@shared/icons';
-import { User } from '@shared/user';
-
-import { useOnboarding } from '@stores/onboarding';
-
-import { useNostr } from '@utils/hooks/useNostr';
-
-export function OnboardRelaysScreen() {
- const navigate = useNavigate();
- const toggleRelays = useOnboarding((state) => state.toggleRelays);
-
- const [loading, setLoading] = useState(false);
- const [relays, setRelays] = useState(new Set
());
-
- const { db } = useStorage();
- const { ndk } = useNDK();
- const { getAllRelaysByUsers } = useNostr();
- const { status, data } = useQuery({
- queryKey: ['relays'],
- queryFn: async () => {
- return await getAllRelaysByUsers();
- },
- refetchOnWindowFocus: false,
- });
-
- const toggleRelay = (relay: string) => {
- if (relays.has(relay)) {
- setRelays((prev) => {
- prev.delete(relay);
- return new Set(prev);
- });
- } else {
- setRelays((prev) => new Set(prev.add(relay)));
- }
- };
-
- const submit = async () => {
- try {
- setLoading(true);
-
- for (const relay of relays) {
- await db.createRelay(relay);
- }
-
- const tags = Array.from(relays).map((relay) => ['r', relay.replace(/\/+$/, '')]);
- const event = new NDKEvent(ndk);
- event.content = '';
- event.kind = 10002;
- event.created_at = Math.floor(Date.now() / 1000);
- event.tags = tags;
-
- await event.publish();
-
- toggleRelays();
- navigate(-1);
- } catch (e) {
- setLoading(false);
- toast.error(e);
- }
- };
-
- return (
-
-
-
navigate(-1)}
- className="inline-flex items-center gap-2 text-sm font-medium"
- >
-
- Back
-
-
-
-
- Relay discovery
-
-
-
- {status === 'pending' ? (
-
-
-
- ) : data.size === 0 ? (
-
-
- Lume couldn't find any relays from your follows.
-
- You can skip this step and use default relays instead.
-
-
- ) : (
- [...data].map(([key, value]) => (
-
toggleRelay(key)}
- className="inline-flex transform items-start justify-between px-4 py-2 hover:bg-neutral-300 dark:hover:bg-neutral-700"
- >
-
-
-
- {relays.has(key) ? (
-
- ) : (
-
- )}
-
-
{key.replace(/\/+$/, '')}
-
-
-
- Used by
-
-
- {value.slice(0, 3).map((item) => (
-
- ))}
- {value.length > 3 ? (
-
- +{value.length}
-
- ) : null}
-
-
-
-
- ))
- )}
-
-
submit()}
- disabled={loading}
- className="inline-flex h-9 w-full items-center justify-center gap-2 rounded-lg bg-blue-500 font-medium text-white hover:bg-blue-600 focus:outline-none disabled:opacity-50"
- >
- {loading ? (
- <>
-
- Adding...
- >
- ) : (
- Add {relays.size} relays & Continue
- )}
-
-
-
-
- );
-}
diff --git a/src/app/auth/welcome.tsx b/src/app/auth/welcome.tsx
index a0d192ff..fb1b0f43 100644
--- a/src/app/auth/welcome.tsx
+++ b/src/app/auth/welcome.tsx
@@ -7,7 +7,7 @@ export function WelcomeScreen() {
- Welcome to Lume
+ Welcome to Lume
diff --git a/src/app/explore/components/userWithDrawer.tsx b/src/app/explore/components/userWithDrawer.tsx
index 2ab72955..9feb6035 100644
--- a/src/app/explore/components/userWithDrawer.tsx
+++ b/src/app/explore/components/userWithDrawer.tsx
@@ -67,7 +67,7 @@ export const UserWithDrawer = memo(function UserWithDrawer({
};
useEffect(() => {
- if (db.account.follows.includes(pubkey)) {
+ if (db.account.contacts.includes(pubkey)) {
setFollowed(true);
}
}, []);
diff --git a/src/app/explore/index.tsx b/src/app/explore/index.tsx
index b6248328..2ec9400d 100644
--- a/src/app/explore/index.tsx
+++ b/src/app/explore/index.tsx
@@ -28,7 +28,7 @@ export function ExploreScreen() {
const { getContactsByPubkey } = useNostr();
const { project } = useReactFlow();
- const defaultContacts = useMemo(() => getMultipleRandom(db.account.follows, 10), []);
+ const defaultContacts = useMemo(() => getMultipleRandom(db.account.contacts, 10), []);
const reactFlowWrapper = useRef(null);
const connectingNodeId = useRef(null);
diff --git a/src/app/new/components/mentionPopup.tsx b/src/app/new/components/mentionPopup.tsx
index 01be4ae3..26c07eb0 100644
--- a/src/app/new/components/mentionPopup.tsx
+++ b/src/app/new/components/mentionPopup.tsx
@@ -32,8 +32,8 @@ export function MentionPopup({ editor }: { editor: Editor }) {
className="h-full max-h-[200px] w-[250px] overflow-hidden overflow-y-auto rounded-lg border border-neutral-200 bg-neutral-100 focus:outline-none dark:border-neutral-800 dark:bg-neutral-900"
>
- {db.account.follows.length > 0 ? (
- db.account.follows.map((item) => (
+ {db.account.contacts.length > 0 ? (
+ db.account.contacts.map((item) => (
insertMention(item)}>
diff --git a/src/app/settings/general.tsx b/src/app/settings/general.tsx
index 529b3cc0..a8f6437e 100644
--- a/src/app/settings/general.tsx
+++ b/src/app/settings/general.tsx
@@ -113,12 +113,6 @@ export function GeneralSettingScreen() {
...prev,
hashtag: !!parseInt(item.value),
}));
-
- if (item.key === 'notification')
- setSettings((prev) => ({
- ...prev,
- notification: !!parseInt(item.value),
- }));
});
}
diff --git a/src/app/users/components/profile.tsx b/src/app/users/components/profile.tsx
index f3d46d08..57bcf132 100644
--- a/src/app/users/components/profile.tsx
+++ b/src/app/users/components/profile.tsx
@@ -72,7 +72,7 @@ export function UserProfile({ pubkey }: { pubkey: string }) {
};
useEffect(() => {
- if (db.account.follows.includes(pubkey)) {
+ if (db.account.contacts.includes(pubkey)) {
setFollowed(true);
}
}, []);
diff --git a/src/libs/ndk/instance.ts b/src/libs/ndk/instance.ts
index 26df8a2f..6c11b339 100644
--- a/src/libs/ndk/instance.ts
+++ b/src/libs/ndk/instance.ts
@@ -20,7 +20,7 @@ export const NDKInstance = () => {
[ndk]
);
- // TODO: fully support NIP-11
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
async function getExplicitRelays() {
try {
// get relays
@@ -68,13 +68,13 @@ export const NDKInstance = () => {
// NIP-46 Signer
if (nsecbunker) {
const localSignerPrivkey = await db.secureLoad(db.account.pubkey + '-nsecbunker');
+ if (!localSignerPrivkey) return null;
const localSigner = new NDKPrivateKeySigner(localSignerPrivkey);
- if (!localSigner) return null;
// await remoteSigner.blockUntilReady();
return new NDKNip46Signer(ndk, db.account.id, localSigner);
}
- // Private key Signer
+ // Private Key Signer
const userPrivkey = await db.secureLoad(db.account.pubkey);
if (!userPrivkey) return null;
return new NDKPrivateKeySigner(userPrivkey);
@@ -84,18 +84,23 @@ export const NDKInstance = () => {
try {
const outboxSetting = await db.getSettingValue('outbox');
const bunkerSetting = await db.getSettingValue('nsecbunker');
- const signer = await getSigner(!!parseInt(bunkerSetting));
- const explicitRelayUrls = await getExplicitRelays();
+
+ const bunker = !!parseInt(bunkerSetting);
+ const outbox = !!parseInt(outboxSetting);
+
+ const signer = await getSigner(bunker);
+ const explicitRelayUrls = await db.getExplicitRelayUrls();
const tauriAdapter = new NDKCacheAdapterTauri(db);
const instance = new NDK({
explicitRelayUrls,
cacheAdapter: tauriAdapter,
outboxRelayUrls: ['wss://purplepag.es'],
- blacklistRelayUrls: [],
- enableOutboxModel: !!parseInt(outboxSetting),
+ enableOutboxModel: outbox,
});
- instance.signer = signer;
+
+ // add signer if exist
+ if (signer) instance.signer = signer;
// connect
await instance.connect();
@@ -104,17 +109,8 @@ export const NDKInstance = () => {
if (db.account) {
const user = instance.getUser({ pubkey: db.account.pubkey });
if (user) {
- const follows = [...(await user.follows())].map((user) => user.pubkey);
- const relayList = await user.relayList();
-
- // update user's follows
- await db.updateAccount('follows', JSON.stringify(follows));
-
- if (relayList)
- // update user's relays
- for (const relay of relayList.relays) {
- await db.createRelay(relay);
- }
+ db.account.contacts = [...(await user.follows())].map((user) => user.pubkey);
+ db.account.relayList = await user.relayList();
}
}
@@ -129,7 +125,6 @@ export const NDKInstance = () => {
okLabel: 'Yes',
}
);
-
if (yes) relaunch();
}
}
diff --git a/src/libs/storage/instance.ts b/src/libs/storage/instance.ts
index c3d3e5e2..a69ac239 100644
--- a/src/libs/storage/instance.ts
+++ b/src/libs/storage/instance.ts
@@ -188,20 +188,9 @@ export class LumeStorage {
'SELECT * FROM accounts WHERE is_active = "1" ORDER BY id DESC LIMIT 1;'
);
- if (results.length > 0) {
- const account = results[0];
-
- if (typeof account.follows === 'string')
- account.follows = JSON.parse(account.follows) ?? [];
-
- if (typeof account.circles === 'string')
- account.circles = JSON.parse(account.circles) ?? [];
-
- if (typeof account.last_login_at === 'string')
- account.last_login_at = parseInt(account.last_login_at);
-
- this.account = account;
- return account;
+ if (results.length) {
+ this.account = results[0];
+ this.account.contacts = [];
} else {
console.log('no active account, please create new account');
return null;
@@ -214,7 +203,7 @@ export class LumeStorage {
[pubkey]
);
- if (existAccounts.length > 0) {
+ if (existAccounts.length) {
await this.db.execute("UPDATE accounts SET is_active = '1' WHERE pubkey = $1;", [
pubkey,
]);
@@ -225,8 +214,7 @@ export class LumeStorage {
);
}
- const account = await this.getActiveAccount();
- return account;
+ return await this.getActiveAccount();
}
public async updateAccount(column: string, value: string) {
@@ -241,15 +229,6 @@ export class LumeStorage {
}
}
- public async updateLastLogin() {
- const now = Math.floor(Date.now() / 1000);
- this.account.last_login_at = now;
- return await this.db.execute(
- 'UPDATE accounts SET last_login_at = $1 WHERE id = $2;',
- [now, this.account.id]
- );
- }
-
public async getWidgets() {
const widgets: Array
= await this.db.select(
'SELECT * FROM widgets WHERE account_id = $1 ORDER BY created_at DESC;',
diff --git a/src/shared/avatarUploader.tsx b/src/shared/avatarUploader.tsx
index f5e3ea3f..2f4e15d8 100644
--- a/src/shared/avatarUploader.tsx
+++ b/src/shared/avatarUploader.tsx
@@ -1,7 +1,7 @@
import { message } from '@tauri-apps/plugin-dialog';
import { Dispatch, SetStateAction, useState } from 'react';
-import { LoaderIcon, PlusIcon } from '@shared/icons';
+import { LoaderIcon } from '@shared/icons';
import { useNostr } from '@utils/hooks/useNostr';
@@ -37,14 +37,9 @@ export function AvatarUploader({
uploadAvatar()}
- className="inline-flex items-center gap-1 rounded-lg border border-blue-200 bg-blue-100 px-1.5 py-1 text-sm font-medium text-blue-500 hover:border-blue-300 hover:bg-blue-200 dark:border-blue-800 dark:bg-blue-900 dark:text-blue-500 dark:hover:border-blue-800 dark:hover:bg-blue-800"
+ className="inline-flex items-center justify-center rounded-lg border border-blue-200 bg-blue-100 px-2 py-1.5 text-sm font-medium text-blue-500 hover:border-blue-300 hover:bg-blue-200 dark:border-blue-800 dark:bg-blue-900 dark:text-blue-500 dark:hover:border-blue-800 dark:hover:bg-blue-800"
>
- {loading ? (
-
- ) : (
-
- )}
- Change avatar
+ {loading ? : 'Change avatar'}
);
}
diff --git a/src/shared/layouts/auth.tsx b/src/shared/layouts/auth.tsx
index 988d8ed0..4296eca1 100644
--- a/src/shared/layouts/auth.tsx
+++ b/src/shared/layouts/auth.tsx
@@ -7,15 +7,17 @@ export function AuthLayout() {
const { db } = useStorage();
return (
-
+
{db.platform !== 'macos' ? (
) : (
)}
-
);
diff --git a/src/app/auth/onboarding/index.tsx b/src/shared/layouts/onboarding.tsx
similarity index 64%
rename from src/app/auth/onboarding/index.tsx
rename to src/shared/layouts/onboarding.tsx
index 58fd243e..79c5155a 100644
--- a/src/app/auth/onboarding/index.tsx
+++ b/src/shared/layouts/onboarding.tsx
@@ -1,5 +1,5 @@
import { Outlet } from 'react-router-dom';
-export function OnboardingScreen() {
+export function OnboardingLayout() {
return
;
}
diff --git a/src/shared/titleBar.tsx b/src/shared/titleBar.tsx
index fa038ffd..bc76f916 100644
--- a/src/shared/titleBar.tsx
+++ b/src/shared/titleBar.tsx
@@ -33,13 +33,13 @@ export function TitleBar({
{id === '9999' ? (
- {db.account.follows
+ {db.account.contacts
?.slice(0, 8)
.map((item) =>
)}
- {db.account.follows?.length > 8 ? (
+ {db.account.contacts?.length > 8 ? (
- +{db.account.follows?.length - 8}
+ +{db.account.contacts?.length - 8}
) : null}
diff --git a/src/shared/user.tsx b/src/shared/user.tsx
index 693d1d07..4baa6535 100644
--- a/src/shared/user.tsx
+++ b/src/shared/user.tsx
@@ -4,7 +4,7 @@ import { minidenticon } from 'minidenticons';
import { memo, useMemo } from 'react';
import { Link } from 'react-router-dom';
-import { RepostIcon, WorldIcon } from '@shared/icons';
+import { RepostIcon } from '@shared/icons';
import { NIP05 } from '@shared/nip05';
import { MoreActions } from '@shared/notes';
@@ -133,10 +133,9 @@ export const User = memo(function User({
return (
-
);
@@ -150,37 +149,23 @@ export const User = memo(function User({
alt={pubkey}
loading="lazy"
decoding="async"
- className="h-14 w-14 rounded-lg object-cover"
+ className="h-11 w-11 rounded-lg object-cover"
/>
-
-
-
- {user?.name || user?.display_name || user?.displayName}
-
-
- {user?.about || user?.bio || 'No bio'}
-
-
-
- {user?.website ? (
-
-
-
{user?.website}
-
- ) : null}
-
+
+
+ {user?.name || user?.display_name || user?.displayName}
+
+
+ {user?.about || user?.bio || 'No bio'}
+
);
diff --git a/src/shared/userProfile.tsx b/src/shared/userProfile.tsx
index 200a0a6c..8e0f84f7 100644
--- a/src/shared/userProfile.tsx
+++ b/src/shared/userProfile.tsx
@@ -61,7 +61,7 @@ export function UserProfile({ pubkey }: { pubkey: string }) {
};
useEffect(() => {
- if (db.account.follows.includes(pubkey)) {
+ if (db.account.contacts.includes(pubkey)) {
setFollowed(true);
}
}, []);
diff --git a/src/shared/widgets/article.tsx b/src/shared/widgets/article.tsx
index aeeb6227..7b5d17eb 100644
--- a/src/shared/widgets/article.tsx
+++ b/src/shared/widgets/article.tsx
@@ -40,7 +40,7 @@ export function ArticleWidget({ widget }: { widget: Widget }) {
} else {
filter = {
kinds: [NDKKind.Article],
- authors: db.account.follows,
+ authors: db.account.contacts,
};
}
diff --git a/src/shared/widgets/file.tsx b/src/shared/widgets/file.tsx
index bd60adcf..fbf8dea7 100644
--- a/src/shared/widgets/file.tsx
+++ b/src/shared/widgets/file.tsx
@@ -40,7 +40,7 @@ export function FileWidget({ widget }: { widget: Widget }) {
} else {
filter = {
kinds: [1063],
- authors: db.account.follows,
+ authors: db.account.contacts,
};
}
diff --git a/src/shared/widgets/newsfeed.tsx b/src/shared/widgets/newsfeed.tsx
index 5c0e9a49..8bbe3c0e 100644
--- a/src/shared/widgets/newsfeed.tsx
+++ b/src/shared/widgets/newsfeed.tsx
@@ -39,7 +39,7 @@ export function NewsfeedWidget() {
relayUrls,
{
kinds: [NDKKind.Text, NDKKind.Repost],
- authors: db.account.follows,
+ authors: db.account.contacts,
},
FETCH_LIMIT,
{ asOf: pageParam === 0 ? undefined : pageParam, abortSignal: signal }
diff --git a/src/shared/widgets/notification.tsx b/src/shared/widgets/notification.tsx
index 0139650c..9c7815fd 100644
--- a/src/shared/widgets/notification.tsx
+++ b/src/shared/widgets/notification.tsx
@@ -54,7 +54,6 @@ export function NotificationWidget() {
if (!lastEvent) return;
return lastEvent.created_at - 1;
},
- enabled: false,
refetchOnWindowFocus: false,
refetchOnMount: false,
refetchOnReconnect: false,
diff --git a/src/shared/widgets/other/addGroupFeeds.tsx b/src/shared/widgets/other/addGroupFeeds.tsx
index 270628cd..c85596eb 100644
--- a/src/shared/widgets/other/addGroupFeeds.tsx
+++ b/src/shared/widgets/other/addGroupFeeds.tsx
@@ -96,7 +96,7 @@ export function AddGroupFeeds({ currentWidgetId }: { currentWidgetId: string })
Users
- {db.account.follows.map((item: string) => (
+ {db.account.contacts.map((item: string) => (
{
- if (db.account.follows.includes(data.pubkey)) {
+ if (db.account.contacts.includes(data.pubkey)) {
setFollowed(true);
}
}, []);
diff --git a/src/utils/hooks/useNostr.ts b/src/utils/hooks/useNostr.ts
index ddb22411..678f1692 100644
--- a/src/utils/hooks/useNostr.ts
+++ b/src/utils/hooks/useNostr.ts
@@ -219,7 +219,7 @@ export function useNostr() {
const relayMap = new Map();
const relayEvents = fetcher.fetchLatestEventsPerAuthor(
{
- authors: db.account.follows,
+ authors: db.account.contacts,
relayUrls: relayUrls,
},
{ kinds: [NDKKind.RelayList] },
diff --git a/src/utils/hooks/useProfile.ts b/src/utils/hooks/useProfile.ts
index ebf984ec..f8523733 100644
--- a/src/utils/hooks/useProfile.ts
+++ b/src/utils/hooks/useProfile.ts
@@ -1,5 +1,6 @@
import { NDKUserProfile } from '@nostr-dev-kit/ndk';
import { useQuery } from '@tanstack/react-query';
+import { nip19 } from 'nostr-tools';
import { useNDK } from '@libs/ndk/provider';
@@ -17,10 +18,13 @@ export function useProfile(pubkey: string, embed?: string) {
return profile;
}
- const cleanPubkey = pubkey.replace(/[^a-zA-Z0-9]/g, '');
- const user = ndk.getUser({ pubkey: cleanPubkey });
+ let hexstring = pubkey.replace(/[^a-zA-Z0-9]/g, '');
+ if (hexstring.startsWith('npub1'))
+ hexstring = nip19.decode(hexstring).data as string;
+ const user = ndk.getUser({ pubkey: hexstring });
if (!user) return Promise.reject(new Error("user's profile not found"));
+
return await user.fetchProfile();
},
staleTime: Infinity,
diff --git a/src/utils/types.d.ts b/src/utils/types.d.ts
index 59b8dba9..2b9874ac 100644
--- a/src/utils/types.d.ts
+++ b/src/utils/types.d.ts
@@ -1,4 +1,4 @@
-import { type NDKEvent, type NDKUserProfile } from '@nostr-dev-kit/ndk';
+import { type NDKEvent, NDKRelayList, type NDKUserProfile } from '@nostr-dev-kit/ndk';
import { type Response } from '@tauri-apps/plugin-http';
export interface RichContent {
@@ -21,18 +21,16 @@ export interface DBEvent {
richContent?: RichContent;
}
-export interface Account extends NDKUserProfile {
+export interface Account {
id: string;
pubkey: string;
- follows: null | string[];
- circles: null | string[];
is_active: number;
- last_login_at: number;
-}
-
-export interface Profile extends NDKUserProfile {
- ident?: string;
- pubkey?: string;
+ contacts: string[];
+ relayList: NDKRelayList;
+ /**
+ * @deprecated Use contacts instead
+ */
+ follows: string[];
}
export interface WidgetGroup {