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
+ +
+
+ ); +} 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 + +
+ + + + +
+
+
+
+ (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" + /> + +
+ {tmpMembers.value.map((member) => ( +
+ + +
+ ))} +
+
+
+
+
+ ); +} 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
+ +
+
+ ); +} 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 ( +
+
+

{relaySize} relays

+
+
+
Relay List
+ +
+
+ ); +} 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. -

-
- +

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)

-
-
-
-

Relay Hint

-

- Instruct other Nostr client find your events in this depot. -

-
- -
-
-
-

Invite

-

- By default, only you can write event to Depot, but you can invite other - user to your Depot. -

-
- -
-
-
-

Customize

-

- Depot also provide plenty config to customize your experiences. -

-
-
+
+
+

+ Actions +

+
+
+ + +
+

Expose

+

+ Make your Depot visible in the Internet, everyone can connect into it. +

+
+ +
+ +
+
+

ngrok

+ +
+
+

Cloudflare Tunnel

+ +
+
+

Local Tunnel

+ +
+
+
+ +

+ 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" + /> + +
+
+
+
+
+
+ + +
+

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() {
) : (
-
+
+ (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}