diff --git a/package.json b/package.json
index 467e41d1..a2cc1616 100644
--- a/package.json
+++ b/package.json
@@ -34,7 +34,7 @@
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-toolbar": "^1.0.4",
"@radix-ui/react-tooltip": "^1.0.7",
- "@tanstack/react-query": "^5.14.1",
+ "@tanstack/react-query": "^5.14.2",
"@tauri-apps/api": "2.0.0-alpha.11",
"@tauri-apps/cli": "2.0.0-alpha.17",
"@tauri-apps/plugin-autostart": "2.0.0-alpha.3",
@@ -115,9 +115,9 @@
"prop-types": "^15.8.1",
"tailwind-merge": "^1.14.0",
"tailwind-scrollbar": "^3.0.5",
- "tailwindcss": "^3.3.7",
+ "tailwindcss": "^3.4.0",
"typescript": "^5.3.3",
- "vite": "4",
+ "vite": "^4.5.1",
"vite-tsconfig-paths": "^4.2.2"
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index dd43fd5d..fc8fdb64 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -54,8 +54,8 @@ dependencies:
specifier: ^1.0.7
version: 1.0.7(@types/react-dom@18.2.18)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0)
'@tanstack/react-query':
- specifier: ^5.14.1
- version: 5.14.1(react@18.2.0)
+ specifier: ^5.14.2
+ version: 5.14.2(react@18.2.0)
'@tauri-apps/api':
specifier: 2.0.0-alpha.11
version: 2.0.0-alpha.11
@@ -213,10 +213,10 @@ dependencies:
devDependencies:
'@tailwindcss/forms':
specifier: ^0.5.7
- version: 0.5.7(tailwindcss@3.3.7)
+ version: 0.5.7(tailwindcss@3.4.0)
'@tailwindcss/typography':
specifier: ^0.5.10
- version: 0.5.10(tailwindcss@3.3.7)
+ version: 0.5.10(tailwindcss@3.4.0)
'@trivago/prettier-plugin-sort-imports':
specifier: ^4.3.0
version: 4.3.0(prettier@3.1.1)
@@ -291,15 +291,15 @@ devDependencies:
version: 1.14.0
tailwind-scrollbar:
specifier: ^3.0.5
- version: 3.0.5(tailwindcss@3.3.7)
+ version: 3.0.5(tailwindcss@3.4.0)
tailwindcss:
- specifier: ^3.3.7
- version: 3.3.7
+ specifier: ^3.4.0
+ version: 3.4.0
typescript:
specifier: ^5.3.3
version: 5.3.3
vite:
- specifier: '4'
+ specifier: ^4.5.1
version: 4.5.1(@types/node@20.10.5)
vite-tsconfig-paths:
specifier: ^4.2.2
@@ -1946,16 +1946,16 @@ packages:
resolution: {integrity: sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==}
dev: true
- /@tailwindcss/forms@0.5.7(tailwindcss@3.3.7):
+ /@tailwindcss/forms@0.5.7(tailwindcss@3.4.0):
resolution: {integrity: sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==}
peerDependencies:
tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1'
dependencies:
mini-svg-data-uri: 1.4.4
- tailwindcss: 3.3.7
+ tailwindcss: 3.4.0
dev: true
- /@tailwindcss/typography@0.5.10(tailwindcss@3.3.7):
+ /@tailwindcss/typography@0.5.10(tailwindcss@3.4.0):
resolution: {integrity: sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw==}
peerDependencies:
tailwindcss: '>=3.0.0 || insiders'
@@ -1964,19 +1964,19 @@ packages:
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
postcss-selector-parser: 6.0.10
- tailwindcss: 3.3.7
+ tailwindcss: 3.4.0
dev: true
- /@tanstack/query-core@5.14.1:
- resolution: {integrity: sha512-TlZarySCVEiap4K7BCvrsYZnX7jBbEkR55YMrk8ELcRbuAx6ydL+qoxqUt8Fq8VMvQyGt52icn6T7eJL1Q35KQ==}
+ /@tanstack/query-core@5.14.2:
+ resolution: {integrity: sha512-QmoJvC72sSWs3hgGis8JdmlDvqLfYGWUK4UG6OR9Q6t28JMN9m2FDwKPqoSJ9YVocELCSjMt/FGjEiLfk8000Q==}
dev: false
- /@tanstack/react-query@5.14.1(react@18.2.0):
- resolution: {integrity: sha512-v7jhe/3jhChiR0XJbGHaG5WNPd/cURwzDGBCr4rzpUTeudPzxrtVRKsF1xJRLcJK3qH/0gIwTYHIPZ3gj+01Yw==}
+ /@tanstack/react-query@5.14.2(react@18.2.0):
+ resolution: {integrity: sha512-SbOzV7UBW8ED3tOnyn6kqNGscnOAfoxShYlbvaQo/5528mDZKpvrwoL/1du1/ukSC6RMAiKmx95SrYqlwPzWDw==}
peerDependencies:
react: ^18.0.0
dependencies:
- '@tanstack/query-core': 5.14.1
+ '@tanstack/query-core': 5.14.2
react: 18.2.0
dev: false
@@ -5608,17 +5608,17 @@ packages:
resolution: {integrity: sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==}
dev: true
- /tailwind-scrollbar@3.0.5(tailwindcss@3.3.7):
+ /tailwind-scrollbar@3.0.5(tailwindcss@3.4.0):
resolution: {integrity: sha512-0ZwxTivevqq9BY9fRP9zDjHl7Tu+J5giBGbln+0O1R/7nHtBUKnjQcA1aTIhK7Oyjp6Uc/Dj6/dn8Dq58k5Uww==}
engines: {node: '>=12.13.0'}
peerDependencies:
tailwindcss: 3.x
dependencies:
- tailwindcss: 3.3.7
+ tailwindcss: 3.4.0
dev: true
- /tailwindcss@3.3.7:
- resolution: {integrity: sha512-pjgQxDZPvyS/nG3ZYkyCvsbONJl7GdOejfm24iMt2ElYQQw8Jc4p0m8RdMp7mznPD0kUhfzwV3zAwa80qI0zmQ==}
+ /tailwindcss@3.4.0:
+ resolution: {integrity: sha512-VigzymniH77knD1dryXbyxR+ePHihHociZbXnLZHUyzf2MMs2ZVqlUrZ3FvpXP8pno9JzmILt1sZPD19M3IxtA==}
engines: {node: '>=14.0.0'}
hasBin: true
dependencies:
diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs
new file mode 100644
index 00000000..2bea7d0b
--- /dev/null
+++ b/src-tauri/src/commands.rs
@@ -0,0 +1,48 @@
+use std::process::Command;
+
+#[tauri::command]
+pub async fn show_in_folder(path: String) {
+ #[cfg(target_os = "windows")]
+ {
+ Command::new("explorer")
+ .args(["/select,", &path]) // The comma after select is not a typo
+ .spawn()
+ .unwrap();
+ }
+
+ #[cfg(target_os = "linux")]
+ {
+ use std::fs::metadata;
+ use std::path::PathBuf;
+ if path.contains(",") {
+ // see https://gitlab.freedesktop.org/dbus/dbus/-/issues/76
+ let new_path = match metadata(&path).unwrap().is_dir() {
+ true => path,
+ false => {
+ let mut path2 = PathBuf::from(path);
+ path2.pop();
+ path2.into_os_string().into_string().unwrap()
+ }
+ };
+ Command::new("xdg-open").arg(&new_path).spawn().unwrap();
+ } else {
+ Command::new("dbus-send")
+ .args([
+ "--session",
+ "--dest=org.freedesktop.FileManager1",
+ "--type=method_call",
+ "/org/freedesktop/FileManager1",
+ "org.freedesktop.FileManager1.ShowItems",
+ format!("array:string:file://{path}").as_str(),
+ "string:\"\"",
+ ])
+ .spawn()
+ .unwrap();
+ }
+ }
+
+ #[cfg(target_os = "macos")]
+ {
+ Command::new("open").args(["-R", &path]).spawn().unwrap();
+ }
+}
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index 0d2b36ea..74f26bef 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -3,6 +3,8 @@
windows_subsystem = "windows"
)]
+mod commands;
+
use keyring::Entry;
use std::time::Duration;
use tauri_plugin_autostart::MacosLauncher;
@@ -161,7 +163,8 @@ fn main() {
opengraph,
secure_save,
secure_load,
- secure_remove
+ secure_remove,
+ commands::show_in_folder,
])
.run(ctx)
.expect("error while running tauri application");
diff --git a/src/app.tsx b/src/app.tsx
index 6f9fd09f..e61a98df 100644
--- a/src/app.tsx
+++ b/src/app.tsx
@@ -63,32 +63,6 @@ export default function App() {
return { Component: RelayScreen };
},
},
- {
- path: 'depot',
- children: [
- {
- index: true,
- loader: () => {
- const depot = ark.checkDepot();
- if (!depot) return redirect('/depot/onboarding/');
- return null;
- },
- async lazy() {
- const { DepotScreen } = await import('@app/depot');
- return { Component: DepotScreen };
- },
- },
- {
- path: 'onboarding',
- async lazy() {
- const { DepotOnboardingScreen } = await import(
- '@app/depot/onboarding'
- );
- return { Component: DepotOnboardingScreen };
- },
- },
- ],
- },
{
path: 'new',
element: ,
@@ -188,6 +162,30 @@ export default function App() {
},
],
},
+ {
+ path: 'depot',
+ children: [
+ {
+ index: true,
+ loader: () => {
+ const depot = ark.checkDepot();
+ if (!depot) return redirect('/depot/onboarding/');
+ return null;
+ },
+ async lazy() {
+ const { DepotScreen } = await import('@app/depot');
+ return { Component: DepotScreen };
+ },
+ },
+ {
+ path: 'onboarding',
+ async lazy() {
+ const { DepotOnboardingScreen } = await import('@app/depot/onboarding');
+ return { Component: DepotOnboardingScreen };
+ },
+ },
+ ],
+ },
],
},
{
diff --git a/src/app/auth/create.tsx b/src/app/auth/create.tsx
index abdf46d4..8fd44ecd 100644
--- a/src/app/auth/create.tsx
+++ b/src/app/auth/create.tsx
@@ -71,11 +71,6 @@ export function CreateAccountScreen() {
privkey: userPrivkey,
});
- await ark.createEvent({
- kind: NDKKind.RelayList,
- tags: ark.relays.map((item) => ['r', item, '']),
- });
-
setKeys({ npub: userNpub, nsec: userNsec });
setLoading(false);
} else {
diff --git a/src/app/depot/components/contact.tsx b/src/app/depot/components/contact.tsx
new file mode 100644
index 00000000..15df1be0
--- /dev/null
+++ b/src/app/depot/components/contact.tsx
@@ -0,0 +1,66 @@
+import { NDKKind } from '@nostr-dev-kit/ndk';
+import { useSignal } from '@preact/signals-react';
+import { toast } from 'sonner';
+import { useArk } from '@libs/ark';
+import { LoaderIcon, RunIcon } from '@shared/icons';
+import { User } from '@shared/user';
+
+export function DepotContactCard() {
+ const ark = useArk();
+ const status = useSignal(false);
+
+ const backupContact = async () => {
+ try {
+ status.value = true;
+
+ const event = await ark.getEventByFilter({
+ filter: { authors: [ark.account.pubkey], kinds: [NDKKind.Contacts] },
+ });
+
+ // broadcast to depot
+ const publish = await event.publish();
+
+ if (publish) {
+ status.value = false;
+ toast.success('Backup contact list successfully.');
+ }
+ } catch (e) {
+ status.value = false;
+ toast.error(e);
+ }
+ };
+
+ return (
+
+
+
+ {ark.account.contacts
+ ?.slice(0, 8)
+ .map((item) =>
)}
+ {ark.account.contacts?.length > 8 ? (
+
+
+ +{ark.account.contacts?.length - 8}
+
+
+ ) : null}
+
+
+
+
Contacts
+
+ {status.value ? (
+
+ ) : (
+
+ )}
+ Backup
+
+
+
+ );
+}
diff --git a/src/app/depot/components/members.tsx b/src/app/depot/components/members.tsx
new file mode 100644
index 00000000..531bb934
--- /dev/null
+++ b/src/app/depot/components/members.tsx
@@ -0,0 +1,145 @@
+import { useSignal } from '@preact/signals-react';
+import * as Dialog from '@radix-ui/react-dialog';
+import { resolveResource } from '@tauri-apps/api/path';
+import { readTextFile, writeTextFile } from '@tauri-apps/plugin-fs';
+import { nip19 } from 'nostr-tools';
+import { useEffect } from 'react';
+import { parse, stringify } from 'smol-toml';
+import { toast } from 'sonner';
+import { CancelIcon, PlusIcon, UserAddIcon, UserRemoveIcon } from '@shared/icons';
+import { User } from '@shared/user';
+
+export function DepotMembers() {
+ const members = useSignal>(null);
+ const tmpMembers = useSignal>([]);
+ const newMember = useSignal('');
+
+ const addMember = async () => {
+ if (!newMember.value.startsWith('npub1'))
+ return toast.error('You need to enter a valid npub');
+
+ try {
+ const pubkey = nip19.decode(newMember.value).data as string;
+ tmpMembers.value.push(pubkey);
+ } catch (e) {
+ console.error(e);
+ }
+ };
+
+ const removeMember = (member: string) => {
+ tmpMembers.value = tmpMembers.value.filter((item) => item !== member);
+ };
+
+ const updateMembers = async () => {
+ members.value = new Set(tmpMembers.value);
+
+ const defaultConfig = await resolveResource('resources/config.toml');
+ const config = await readTextFile(defaultConfig);
+ const configContent = parse(config);
+
+ configContent.authorization['pubkey_whitelist'] = [...members.value];
+
+ const newConfig = stringify(configContent);
+
+ return await writeTextFile(defaultConfig, newConfig);
+ };
+
+ useEffect(() => {
+ async function loadConfig() {
+ const defaultConfig = await resolveResource('resources/config.toml');
+ const config = await readTextFile(defaultConfig);
+ const configContent = parse(config);
+ tmpMembers.value = Array.from(configContent.authorization['pubkey_whitelist']);
+ }
+
+ loadConfig();
+ }, []);
+
+ return (
+
+
+
+
Members
+
+ Only allowed users can publish event to your Depot
+
+
+
+
+ {tmpMembers.value.slice(0, 5).map((item) => (
+
+ ))}
+ {tmpMembers.value.length > 5 ? (
+
+ +{tmpMembers.value.length}
+
+ ) : null}
+
+
+
+ Manage
+
+
+
+
+
+
+
+
+
+ Manage member
+
+
+
+ Update
+
+
+
+
+
+
+
+
+
(newMember.value = e.target.value)}
+ placeholder="npub1..."
+ className="h-11 w-full rounded-lg border-transparent bg-neutral-100 pl-3 pr-20 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"
+ />
+
+
+ Add
+
+
+ {tmpMembers.value.map((member) => (
+
+
+ removeMember(member)}
+ className="hidden size-6 items-center justify-center rounded-md bg-neutral-200 group-hover:inline-flex hover:bg-red-200 dark:bg-neutral-800 dark:hover:bg-red-800 dark:hover:text-red-200"
+ >
+
+
+
+ ))}
+
+
+
+
+
+ );
+}
diff --git a/src/app/depot/components/profile.tsx b/src/app/depot/components/profile.tsx
new file mode 100644
index 00000000..58d4b9ea
--- /dev/null
+++ b/src/app/depot/components/profile.tsx
@@ -0,0 +1,55 @@
+import { NDKKind } from '@nostr-dev-kit/ndk';
+import { useSignal } from '@preact/signals-react';
+import { toast } from 'sonner';
+import { useArk } from '@libs/ark';
+import { LoaderIcon, RunIcon } from '@shared/icons';
+import { User } from '@shared/user';
+
+export function DepotProfileCard() {
+ const ark = useArk();
+ const status = useSignal(false);
+
+ const backupProfile = async () => {
+ try {
+ status.value = true;
+
+ const event = await ark.getEventByFilter({
+ filter: { authors: [ark.account.pubkey], kinds: [NDKKind.Metadata] },
+ });
+
+ // broadcast to depot
+ const publish = await event.publish();
+
+ if (publish) {
+ status.value = false;
+ toast.success('Backup profile successfully.');
+ }
+ } catch (e) {
+ status.value = false;
+ toast.error(JSON.stringify(e));
+ }
+ };
+
+ return (
+
+
+
+
+
+
Profile
+
+ {status.value ? (
+
+ ) : (
+
+ )}
+ Backup
+
+
+
+ );
+}
diff --git a/src/app/depot/components/relays.tsx b/src/app/depot/components/relays.tsx
new file mode 100644
index 00000000..2f047ce3
--- /dev/null
+++ b/src/app/depot/components/relays.tsx
@@ -0,0 +1,67 @@
+import { NDKKind } from '@nostr-dev-kit/ndk';
+import { useSignal } from '@preact/signals-react';
+import { useEffect } from 'react';
+import { toast } from 'sonner';
+import { useArk } from '@libs/ark';
+import { LoaderIcon, RunIcon } from '@shared/icons';
+
+export function DepotRelaysCard() {
+ const ark = useArk();
+ const status = useSignal(false);
+ const relaySize = useSignal(0);
+
+ const backupRelays = async () => {
+ try {
+ status.value = true;
+
+ const event = await ark.getEventByFilter({
+ filter: { authors: [ark.account.pubkey], kinds: [NDKKind.RelayList] },
+ });
+
+ // broadcast to depot
+ const publish = await event.publish();
+
+ if (publish) {
+ status.value = false;
+ toast.success('Backup profile successfully.');
+ }
+ } catch (e) {
+ status.value = false;
+ toast.error(JSON.stringify(e));
+ }
+ };
+
+ useEffect(() => {
+ async function loadRelays() {
+ const event = await ark.getEventByFilter({
+ filter: { authors: [ark.account.pubkey], kinds: [NDKKind.RelayList] },
+ });
+ if (event) relaySize.value = event.tags.length;
+ }
+
+ loadRelays();
+ }, []);
+
+ return (
+
+
+
+
Relay List
+
+ {status.value ? (
+
+ ) : (
+
+ )}
+ Backup
+
+
+
+ );
+}
diff --git a/src/app/depot/index.tsx b/src/app/depot/index.tsx
index 320c4367..6eeba810 100644
--- a/src/app/depot/index.tsx
+++ b/src/app/depot/index.tsx
@@ -1,96 +1,215 @@
+import { NDKKind } from '@nostr-dev-kit/ndk';
+import { useSignal } from '@preact/signals-react';
+import * as Collapsible from '@radix-ui/react-collapsible';
+import { appConfigDir } from '@tauri-apps/api/path';
+import { invoke } from '@tauri-apps/api/primitives';
+import { useEffect } from 'react';
+import { toast } from 'sonner';
+import { DepotContactCard } from '@app/depot/components/contact';
+import { DepotMembers } from '@app/depot/components/members';
+import { DepotProfileCard } from '@app/depot/components/profile';
+import { DepotRelaysCard } from '@app/depot/components/relays';
+import { useArk } from '@libs/ark';
+import { ChevronDownIcon, DepotIcon, GossipIcon } from '@shared/icons';
+
export function DepotScreen() {
+ const ark = useArk();
+ const dataPath = useSignal('');
+ const tunnelUrl = useSignal('');
+
+ const openFolder = async () => {
+ await invoke('show_in_folder', {
+ path: dataPath.value + '/nostr.db',
+ });
+ };
+
+ const updateRelayList = async () => {
+ try {
+ if (tunnelUrl.value.length < 1) return toast.info('Please enter a valid relay url');
+ if (!tunnelUrl.value.startsWith('ws'))
+ return toast.info('Please enter a valid relay url');
+
+ const relayUrl = new URL(tunnelUrl.value.replace(/\s/g, ''));
+ if (!/^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/.test(relayUrl.host)) return;
+
+ const relayEvent = await ark.getEventByFilter({
+ filter: { authors: [ark.account.pubkey], kinds: [NDKKind.RelayList] },
+ });
+
+ let publish: { id: string; seens: string[] };
+
+ if (!relayEvent) {
+ publish = await ark.createEvent({
+ kind: NDKKind.RelayList,
+ tags: [['r', tunnelUrl.value, '']],
+ });
+ }
+
+ const newTags = relayEvent.tags ?? [];
+ newTags.push(['r', tunnelUrl.value, '']);
+
+ publish = await ark.createEvent({
+ kind: NDKKind.RelayList,
+ tags: newTags,
+ });
+
+ if (publish) {
+ await ark.createSetting('tunnel_url', tunnelUrl.value);
+ toast.success('Update relay list successfully.');
+
+ tunnelUrl.value = '';
+ }
+ } catch (e) {
+ console.error(e);
+ toast.error('Error');
+ }
+ };
+
+ useEffect(() => {
+ async function loadConfig() {
+ const appDir = await appConfigDir();
+ dataPath.value = appDir;
+ }
+
+ loadConfig();
+ }, []);
+
return (
-
-
-
-
-
- Your Depot is running
-
-
-
-
-
-
-
ws://localhost:6090
+
+
+
+
-
-
-
-
Backup
-
- Sync all your data to Depot.
-
-
-
- Sync
-
+
Depot is running
+
+
+
+
Relay URL
+
+ ws://localhost:6090
-
-
-
Expose
-
- Help other users can see your depot on Internet. You also can do it by
- yourself by using other service like ngrok or localtunnel.
-
-
+
+
+
Database
+
+
nostr.db (SQLite)
- Start
-
-
-
-
-
Relay Hint
-
- Instruct other Nostr client find your events in this depot.
-
-
-
- Add
-
-
-
-
-
Invite
-
- By default, only you can write event to Depot, but you can invite other
- user to your Depot.
-
-
-
- Invite
-
-
-
-
-
Customize
-
- Depot also provide plenty config to customize your experiences.
-
-
-
- Config
+ Open
+
+
+
+ Actions
+
+
+
+
+
+
+
Expose
+
+ Make your Depot visible in the Internet, everyone can connect into it.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Support Gossip Model (Recommended)
+
+
+
+
+
+ By adding to Relay List, other Nostr Client which support Gossip
+ Model will automatically connect to your Depot and improve the
+ discoverability.
+
+
+ (tunnelUrl.value = e.target.value)}
+ spellCheck={false}
+ placeholder="wss://"
+ className="h-10 flex-1 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"
+ />
+
+ Update
+
+
+
+
+
+
+
+
+
+
+
Backup (Recommended)
+
+ Backup all your data to Depot, it always live on your machine.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/src/app/depot/onboarding.tsx b/src/app/depot/onboarding.tsx
index 235e65e8..8156a127 100644
--- a/src/app/depot/onboarding.tsx
+++ b/src/app/depot/onboarding.tsx
@@ -51,7 +51,7 @@ export function DepotOnboardingScreen() {
};
return (
-
+
diff --git a/src/app/home/index.tsx b/src/app/home/index.tsx
index 37a39167..1dd495fd 100644
--- a/src/app/home/index.tsx
+++ b/src/app/home/index.tsx
@@ -3,7 +3,7 @@ import { useQuery } from '@tanstack/react-query';
import { useRef } from 'react';
import { VList, VListHandle } from 'virtua';
import { useArk } from '@libs/ark';
-import { LoaderIcon } from '@shared/icons';
+import { LoaderIcon, PlusIcon } from '@shared/icons';
import {
ArticleWidget,
FileWidget,
@@ -132,7 +132,7 @@ export function HomeScreen() {
}}
>
{data.map((widget) => renderItem(widget))}
-
+
);
diff --git a/src/app/settings/components/profileCard.tsx b/src/app/settings/components/profileCard.tsx
index 8ba6c8c7..5f2280e4 100644
--- a/src/app/settings/components/profileCard.tsx
+++ b/src/app/settings/components/profileCard.tsx
@@ -1,5 +1,7 @@
import * as Avatar from '@radix-ui/react-avatar';
+import { writeText } from '@tauri-apps/plugin-clipboard-manager';
import { minidenticon } from 'minidenticons';
+import { nip19 } from 'nostr-tools';
import { Link } from 'react-router-dom';
import { useArk } from '@libs/ark';
import { EditIcon, LoaderIcon } from '@shared/icons';
@@ -8,12 +10,16 @@ import { useProfile } from '@utils/hooks/useProfile';
export function ProfileCard() {
const ark = useArk();
- const { isLoading, user } = useProfile(ark.account.pubkey);
-
const svgURI =
'data:image/svg+xml;utf8,' +
encodeURIComponent(minidenticon(ark.account.pubkey, 90, 50));
+ const { isLoading, user } = useProfile(ark.account.pubkey);
+
+ const copyNpub = async () => {
+ return await writeText(nip19.npubEncode(ark.account.pubkey));
+ };
+
return (
{isLoading ? (
@@ -22,7 +28,14 @@ export function ProfileCard() {
) : (
-
+
+
+ Copy NPUB
+
(undefined);
@@ -36,12 +35,6 @@ const ArkProvider = ({ children }: PropsWithChildren
) => {
}
}
- // start depot
- if (_ark.settings.depot) {
- await _ark.launchDepot();
- await delay(2000);
- }
-
setArk(_ark);
} catch (e) {
console.error(e);
diff --git a/src/shared/icons/cancel.tsx b/src/shared/icons/cancel.tsx
index 445cccd9..b46e69ba 100644
--- a/src/shared/icons/cancel.tsx
+++ b/src/shared/icons/cancel.tsx
@@ -1,14 +1,18 @@
-import { SVGProps } from 'react';
-
-export function CancelIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+export function CancelIcon(props: JSX.IntrinsicElements['svg']) {
return (
-
-
+
+
);
}
diff --git a/src/shared/icons/gossip.tsx b/src/shared/icons/gossip.tsx
new file mode 100644
index 00000000..4276cb76
--- /dev/null
+++ b/src/shared/icons/gossip.tsx
@@ -0,0 +1,20 @@
+export function GossipIcon(props: JSX.IntrinsicElements['svg']) {
+ return (
+
+
+
+
+
+ );
+}
diff --git a/src/shared/icons/index.ts b/src/shared/icons/index.ts
index 77da9670..144def0e 100644
--- a/src/shared/icons/index.ts
+++ b/src/shared/icons/index.ts
@@ -87,3 +87,7 @@ export * from './system';
export * from './announcement';
export * from './depot';
export * from './search';
+export * from './run';
+export * from './gossip';
+export * from './userAdd';
+export * from './userRemove';
diff --git a/src/shared/icons/run.tsx b/src/shared/icons/run.tsx
new file mode 100644
index 00000000..200ea40e
--- /dev/null
+++ b/src/shared/icons/run.tsx
@@ -0,0 +1,18 @@
+export function RunIcon(props: JSX.IntrinsicElements['svg']) {
+ return (
+
+
+
+ );
+}
diff --git a/src/shared/icons/userAdd.tsx b/src/shared/icons/userAdd.tsx
new file mode 100644
index 00000000..c56a75e5
--- /dev/null
+++ b/src/shared/icons/userAdd.tsx
@@ -0,0 +1,18 @@
+export function UserAddIcon(props: JSX.IntrinsicElements['svg']) {
+ return (
+
+
+
+ );
+}
diff --git a/src/shared/icons/userRemove.tsx b/src/shared/icons/userRemove.tsx
new file mode 100644
index 00000000..bd4f7367
--- /dev/null
+++ b/src/shared/icons/userRemove.tsx
@@ -0,0 +1,18 @@
+export function UserRemoveIcon(props: JSX.IntrinsicElements['svg']) {
+ return (
+
+
+
+ );
+}
diff --git a/src/shared/layouts/app.tsx b/src/shared/layouts/app.tsx
index a3e43142..455d1ac7 100644
--- a/src/shared/layouts/app.tsx
+++ b/src/shared/layouts/app.tsx
@@ -1,6 +1,7 @@
import { type Platform } from '@tauri-apps/plugin-os';
-import { Outlet, ScrollRestoration } from 'react-router-dom';
+import { Outlet } from 'react-router-dom';
import { twMerge } from 'tailwind-merge';
+import { Navigation } from '@shared/navigation';
import { WindowTitleBar } from '@shared/titlebar';
export function AppLayout({ platform }: { platform: Platform }) {
@@ -8,7 +9,7 @@ export function AppLayout({ platform }: { platform: Platform }) {
{platform !== 'macos' ? (
@@ -16,9 +17,11 @@ export function AppLayout({ platform }: { platform: Platform }) {
) : (
)}
-
);
diff --git a/src/shared/layouts/home.tsx b/src/shared/layouts/home.tsx
index b8806015..332466cc 100644
--- a/src/shared/layouts/home.tsx
+++ b/src/shared/layouts/home.tsx
@@ -1,13 +1,9 @@
import { Outlet } from 'react-router-dom';
-import { Navigation } from '@shared/navigation';
export function HomeLayout() {
return (
-
-
-
-
-
+
+
);
}
diff --git a/src/shared/notes/child.tsx b/src/shared/notes/child.tsx
index 94098625..d9266712 100644
--- a/src/shared/notes/child.tsx
+++ b/src/shared/notes/child.tsx
@@ -24,12 +24,12 @@ export function ChildNote({ id, isRoot }: { id: string; isRoot?: boolean }) {
- {data.content}
+ {data?.content}