mirror of
https://github.com/luminous-devs/lume.git
synced 2024-10-01 09:21:07 +00:00
chore: remove signal
This commit is contained in:
parent
a882ead649
commit
ee4e6b1ee6
@ -22,7 +22,6 @@
|
|||||||
"@getalby/sdk": "^3.2.1",
|
"@getalby/sdk": "^3.2.1",
|
||||||
"@nostr-dev-kit/ndk": "^2.3.1",
|
"@nostr-dev-kit/ndk": "^2.3.1",
|
||||||
"@nostr-fetch/adapter-ndk": "^0.14.1",
|
"@nostr-fetch/adapter-ndk": "^0.14.1",
|
||||||
"@preact/signals-react": "^2.0.0",
|
|
||||||
"@radix-ui/react-accordion": "^1.1.2",
|
"@radix-ui/react-accordion": "^1.1.2",
|
||||||
"@radix-ui/react-alert-dialog": "^1.0.5",
|
"@radix-ui/react-alert-dialog": "^1.0.5",
|
||||||
"@radix-ui/react-avatar": "^1.0.4",
|
"@radix-ui/react-avatar": "^1.0.4",
|
||||||
|
@ -17,9 +17,6 @@ dependencies:
|
|||||||
'@nostr-fetch/adapter-ndk':
|
'@nostr-fetch/adapter-ndk':
|
||||||
specifier: ^0.14.1
|
specifier: ^0.14.1
|
||||||
version: 0.14.1(@nostr-dev-kit/ndk@2.3.1)(nostr-fetch@0.14.1)
|
version: 0.14.1(@nostr-dev-kit/ndk@2.3.1)(nostr-fetch@0.14.1)
|
||||||
'@preact/signals-react':
|
|
||||||
specifier: ^2.0.0
|
|
||||||
version: 2.0.0(react@18.2.0)
|
|
||||||
'@radix-ui/react-accordion':
|
'@radix-ui/react-accordion':
|
||||||
specifier: ^1.1.2
|
specifier: ^1.1.2
|
||||||
version: 1.1.2(@types/react-dom@18.2.18)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0)
|
version: 1.1.2(@types/react-dom@18.2.18)(@types/react@18.2.45)(react-dom@18.2.0)(react@18.2.0)
|
||||||
@ -881,20 +878,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
|
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@preact/signals-core@1.5.1:
|
|
||||||
resolution: {integrity: sha512-dE6f+WCX5ZUDwXzUIWNMhhglmuLpqJhuy3X3xHrhZYI0Hm2LyQwOu0l9mdPiWrVNsE+Q7txOnJPgtIqHCYoBVA==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@preact/signals-react@2.0.0(react@18.2.0):
|
|
||||||
resolution: {integrity: sha512-tMVi2SXFXlojaiPNWa8dlYaidR/XvEgMSp+iymKJgMssBM/QVtUQrodKZek1BJju+dkVHiyeuQHmkuLOI9oyNw==}
|
|
||||||
peerDependencies:
|
|
||||||
react: ^16.14.0 || 17.x || 18.x
|
|
||||||
dependencies:
|
|
||||||
'@preact/signals-core': 1.5.1
|
|
||||||
react: 18.2.0
|
|
||||||
use-sync-external-store: 1.2.0(react@18.2.0)
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@radix-ui/primitive@1.0.1:
|
/@radix-ui/primitive@1.0.1:
|
||||||
resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
|
resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -5894,14 +5877,6 @@ packages:
|
|||||||
tslib: 2.6.2
|
tslib: 2.6.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/use-sync-external-store@1.2.0(react@18.2.0):
|
|
||||||
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
|
|
||||||
peerDependencies:
|
|
||||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
|
||||||
dependencies:
|
|
||||||
react: 18.2.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/utf-8-validate@5.0.10:
|
/utf-8-validate@5.0.10:
|
||||||
resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==}
|
resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==}
|
||||||
engines: {node: '>=6.14.2'}
|
engines: {node: '>=6.14.2'}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { NDKKind } from '@nostr-dev-kit/ndk';
|
import { NDKKind } from '@nostr-dev-kit/ndk';
|
||||||
import { useSignal } from '@preact/signals-react';
|
import { useState } from 'react';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { useArk } from '@libs/ark';
|
import { useArk } from '@libs/ark';
|
||||||
import { LoaderIcon, RunIcon } from '@shared/icons';
|
import { LoaderIcon, RunIcon } from '@shared/icons';
|
||||||
@ -7,11 +7,11 @@ import { User } from '@shared/user';
|
|||||||
|
|
||||||
export function DepotContactCard() {
|
export function DepotContactCard() {
|
||||||
const ark = useArk();
|
const ark = useArk();
|
||||||
const status = useSignal(false);
|
const [status, setStatus] = useState(false);
|
||||||
|
|
||||||
const backupContact = async () => {
|
const backupContact = async () => {
|
||||||
try {
|
try {
|
||||||
status.value = true;
|
setStatus(true);
|
||||||
|
|
||||||
const event = await ark.getEventByFilter({
|
const event = await ark.getEventByFilter({
|
||||||
filter: { authors: [ark.account.pubkey], kinds: [NDKKind.Contacts] },
|
filter: { authors: [ark.account.pubkey], kinds: [NDKKind.Contacts] },
|
||||||
@ -21,11 +21,11 @@ export function DepotContactCard() {
|
|||||||
const publish = await event.publish();
|
const publish = await event.publish();
|
||||||
|
|
||||||
if (publish) {
|
if (publish) {
|
||||||
status.value = false;
|
setStatus(false);
|
||||||
toast.success('Backup contact list successfully.');
|
toast.success('Backup contact list successfully.');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
status.value = false;
|
setStatus(false);
|
||||||
toast.error(e);
|
toast.error(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -53,7 +53,7 @@ export function DepotContactCard() {
|
|||||||
onClick={backupContact}
|
onClick={backupContact}
|
||||||
className="inline-flex h-8 w-max items-center justify-center gap-2 rounded-md bg-blue-500 pl-2 pr-3 font-medium text-white shadow shadow-blue-500/50 hover:bg-blue-600"
|
className="inline-flex h-8 w-max items-center justify-center gap-2 rounded-md bg-blue-500 pl-2 pr-3 font-medium text-white shadow shadow-blue-500/50 hover:bg-blue-600"
|
||||||
>
|
>
|
||||||
{status.value ? (
|
{status ? (
|
||||||
<LoaderIcon className="size-4 animate-spin" />
|
<LoaderIcon className="size-4 animate-spin" />
|
||||||
) : (
|
) : (
|
||||||
<RunIcon className="size-4" />
|
<RunIcon className="size-4" />
|
||||||
|
@ -1,43 +1,42 @@
|
|||||||
import { useSignal } from '@preact/signals-react';
|
|
||||||
import * as Dialog from '@radix-ui/react-dialog';
|
import * as Dialog from '@radix-ui/react-dialog';
|
||||||
import { resolveResource } from '@tauri-apps/api/path';
|
import { resolveResource } from '@tauri-apps/api/path';
|
||||||
import { readTextFile, writeTextFile } from '@tauri-apps/plugin-fs';
|
import { readTextFile, writeTextFile } from '@tauri-apps/plugin-fs';
|
||||||
import { nip19 } from 'nostr-tools';
|
import { nip19 } from 'nostr-tools';
|
||||||
import { useEffect } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { parse, stringify } from 'smol-toml';
|
import { parse, stringify } from 'smol-toml';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { CancelIcon, PlusIcon, UserAddIcon, UserRemoveIcon } from '@shared/icons';
|
import { CancelIcon, PlusIcon, UserAddIcon, UserRemoveIcon } from '@shared/icons';
|
||||||
import { User } from '@shared/user';
|
import { User } from '@shared/user';
|
||||||
|
|
||||||
export function DepotMembers() {
|
export function DepotMembers() {
|
||||||
const members = useSignal<Set<string>>(null);
|
const [members, setMembers] = useState<Set<string>>(null);
|
||||||
const tmpMembers = useSignal<Array<string>>([]);
|
const [tmpMembers, setTmpMembers] = useState<Array<string>>([]);
|
||||||
const newMember = useSignal('');
|
const [newMember, setNewMember] = useState('');
|
||||||
|
|
||||||
const addMember = async () => {
|
const addMember = async () => {
|
||||||
if (!newMember.value.startsWith('npub1'))
|
if (!newMember.startsWith('npub1'))
|
||||||
return toast.error('You need to enter a valid npub');
|
return toast.error('You need to enter a valid npub');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const pubkey = nip19.decode(newMember.value).data as string;
|
const pubkey = nip19.decode(newMember).data as string;
|
||||||
tmpMembers.value.push(pubkey);
|
setTmpMembers((prev) => [...prev, pubkey]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeMember = (member: string) => {
|
const removeMember = (member: string) => {
|
||||||
tmpMembers.value = tmpMembers.value.filter((item) => item !== member);
|
setTmpMembers((prev) => prev.filter((item) => item !== member));
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateMembers = async () => {
|
const updateMembers = async () => {
|
||||||
members.value = new Set(tmpMembers.value);
|
setMembers(new Set(tmpMembers));
|
||||||
|
|
||||||
const defaultConfig = await resolveResource('resources/config.toml');
|
const defaultConfig = await resolveResource('resources/config.toml');
|
||||||
const config = await readTextFile(defaultConfig);
|
const config = await readTextFile(defaultConfig);
|
||||||
const configContent = parse(config);
|
const configContent = parse(config);
|
||||||
|
|
||||||
configContent.authorization['pubkey_whitelist'] = [...members.value];
|
configContent.authorization['pubkey_whitelist'] = [...members];
|
||||||
|
|
||||||
const newConfig = stringify(configContent);
|
const newConfig = stringify(configContent);
|
||||||
|
|
||||||
@ -49,7 +48,7 @@ export function DepotMembers() {
|
|||||||
const defaultConfig = await resolveResource('resources/config.toml');
|
const defaultConfig = await resolveResource('resources/config.toml');
|
||||||
const config = await readTextFile(defaultConfig);
|
const config = await readTextFile(defaultConfig);
|
||||||
const configContent = parse(config);
|
const configContent = parse(config);
|
||||||
tmpMembers.value = Array.from(configContent.authorization['pubkey_whitelist']);
|
setTmpMembers(Array.from(configContent.authorization['pubkey_whitelist']));
|
||||||
}
|
}
|
||||||
|
|
||||||
loadConfig();
|
loadConfig();
|
||||||
@ -66,12 +65,12 @@ export function DepotMembers() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="inline-flex items-center gap-2">
|
<div className="inline-flex items-center gap-2">
|
||||||
<div className="isolate flex -space-x-2">
|
<div className="isolate flex -space-x-2">
|
||||||
{tmpMembers.value.slice(0, 5).map((item) => (
|
{tmpMembers.slice(0, 5).map((item) => (
|
||||||
<User key={item} pubkey={item} variant="stacked" />
|
<User key={item} pubkey={item} variant="stacked" />
|
||||||
))}
|
))}
|
||||||
{tmpMembers.value.length > 5 ? (
|
{tmpMembers.length > 5 ? (
|
||||||
<div className="inline-flex h-8 w-8 items-center justify-center rounded-full bg-neutral-200 text-neutral-900 ring-1 ring-neutral-300 dark:bg-neutral-800 dark:text-neutral-100 dark:ring-neutral-700">
|
<div className="inline-flex h-8 w-8 items-center justify-center rounded-full bg-neutral-200 text-neutral-900 ring-1 ring-neutral-300 dark:bg-neutral-800 dark:text-neutral-100 dark:ring-neutral-700">
|
||||||
<span className="text-xs font-medium">+{tmpMembers.value.length}</span>
|
<span className="text-xs font-medium">+{tmpMembers.length}</span>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
@ -107,8 +106,8 @@ export function DepotMembers() {
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
value={newMember.value}
|
value={newMember}
|
||||||
onChange={(e) => (newMember.value = e.target.value)}
|
onChange={(e) => setNewMember(e.target.value)}
|
||||||
placeholder="npub1..."
|
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"
|
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"
|
||||||
/>
|
/>
|
||||||
@ -121,7 +120,7 @@ export function DepotMembers() {
|
|||||||
Add
|
Add
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{tmpMembers.value.map((member) => (
|
{tmpMembers.map((member) => (
|
||||||
<div
|
<div
|
||||||
key={member}
|
key={member}
|
||||||
className="group flex items-center justify-between px-5 py-2 hover:bg-neutral-100 dark:hover:bg-neutral-900"
|
className="group flex items-center justify-between px-5 py-2 hover:bg-neutral-100 dark:hover:bg-neutral-900"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { NDKKind } from '@nostr-dev-kit/ndk';
|
import { NDKKind } from '@nostr-dev-kit/ndk';
|
||||||
import { useSignal } from '@preact/signals-react';
|
import { useState } from 'react';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { useArk } from '@libs/ark';
|
import { useArk } from '@libs/ark';
|
||||||
import { LoaderIcon, RunIcon } from '@shared/icons';
|
import { LoaderIcon, RunIcon } from '@shared/icons';
|
||||||
@ -7,11 +7,11 @@ import { User } from '@shared/user';
|
|||||||
|
|
||||||
export function DepotProfileCard() {
|
export function DepotProfileCard() {
|
||||||
const ark = useArk();
|
const ark = useArk();
|
||||||
const status = useSignal(false);
|
const [status, setStatus] = useState(false);
|
||||||
|
|
||||||
const backupProfile = async () => {
|
const backupProfile = async () => {
|
||||||
try {
|
try {
|
||||||
status.value = true;
|
setStatus(true);
|
||||||
|
|
||||||
const event = await ark.getEventByFilter({
|
const event = await ark.getEventByFilter({
|
||||||
filter: { authors: [ark.account.pubkey], kinds: [NDKKind.Metadata] },
|
filter: { authors: [ark.account.pubkey], kinds: [NDKKind.Metadata] },
|
||||||
@ -21,11 +21,11 @@ export function DepotProfileCard() {
|
|||||||
const publish = await event.publish();
|
const publish = await event.publish();
|
||||||
|
|
||||||
if (publish) {
|
if (publish) {
|
||||||
status.value = false;
|
setStatus(false);
|
||||||
toast.success('Backup profile successfully.');
|
toast.success('Backup profile successfully.');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
status.value = false;
|
setStatus(false);
|
||||||
toast.error(JSON.stringify(e));
|
toast.error(JSON.stringify(e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -42,7 +42,7 @@ export function DepotProfileCard() {
|
|||||||
onClick={backupProfile}
|
onClick={backupProfile}
|
||||||
className="inline-flex h-8 w-max items-center justify-center gap-2 rounded-md bg-blue-500 pl-2 pr-3 font-medium text-white shadow shadow-blue-500/50 hover:bg-blue-600"
|
className="inline-flex h-8 w-max items-center justify-center gap-2 rounded-md bg-blue-500 pl-2 pr-3 font-medium text-white shadow shadow-blue-500/50 hover:bg-blue-600"
|
||||||
>
|
>
|
||||||
{status.value ? (
|
{status ? (
|
||||||
<LoaderIcon className="size-4 animate-spin" />
|
<LoaderIcon className="size-4 animate-spin" />
|
||||||
) : (
|
) : (
|
||||||
<RunIcon className="size-4" />
|
<RunIcon className="size-4" />
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
import { NDKKind } from '@nostr-dev-kit/ndk';
|
import { NDKKind } from '@nostr-dev-kit/ndk';
|
||||||
import { useSignal } from '@preact/signals-react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useEffect } from 'react';
|
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { useArk } from '@libs/ark';
|
import { useArk } from '@libs/ark';
|
||||||
import { LoaderIcon, RunIcon } from '@shared/icons';
|
import { LoaderIcon, RunIcon } from '@shared/icons';
|
||||||
|
|
||||||
export function DepotRelaysCard() {
|
export function DepotRelaysCard() {
|
||||||
const ark = useArk();
|
const ark = useArk();
|
||||||
const status = useSignal(false);
|
|
||||||
const relaySize = useSignal(0);
|
const [status, setStatus] = useState(false);
|
||||||
|
const [relaySize, setRelaySize] = useState(0);
|
||||||
|
|
||||||
const backupRelays = async () => {
|
const backupRelays = async () => {
|
||||||
try {
|
try {
|
||||||
status.value = true;
|
setStatus(true);
|
||||||
|
|
||||||
const event = await ark.getEventByFilter({
|
const event = await ark.getEventByFilter({
|
||||||
filter: { authors: [ark.account.pubkey], kinds: [NDKKind.RelayList] },
|
filter: { authors: [ark.account.pubkey], kinds: [NDKKind.RelayList] },
|
||||||
@ -22,11 +22,11 @@ export function DepotRelaysCard() {
|
|||||||
const publish = await event.publish();
|
const publish = await event.publish();
|
||||||
|
|
||||||
if (publish) {
|
if (publish) {
|
||||||
status.value = false;
|
setStatus(false);
|
||||||
toast.success('Backup profile successfully.');
|
toast.success('Backup profile successfully.');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
status.value = false;
|
setStatus(false);
|
||||||
toast.error(JSON.stringify(e));
|
toast.error(JSON.stringify(e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -36,7 +36,7 @@ export function DepotRelaysCard() {
|
|||||||
const event = await ark.getEventByFilter({
|
const event = await ark.getEventByFilter({
|
||||||
filter: { authors: [ark.account.pubkey], kinds: [NDKKind.RelayList] },
|
filter: { authors: [ark.account.pubkey], kinds: [NDKKind.RelayList] },
|
||||||
});
|
});
|
||||||
if (event) relaySize.value = event.tags.length;
|
if (event) setRelaySize(event.tags.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadRelays();
|
loadRelays();
|
||||||
@ -54,7 +54,7 @@ export function DepotRelaysCard() {
|
|||||||
onClick={backupRelays}
|
onClick={backupRelays}
|
||||||
className="inline-flex h-8 w-max items-center justify-center gap-2 rounded-md bg-blue-500 pl-2 pr-3 font-medium text-white shadow shadow-blue-500/50 hover:bg-blue-600"
|
className="inline-flex h-8 w-max items-center justify-center gap-2 rounded-md bg-blue-500 pl-2 pr-3 font-medium text-white shadow shadow-blue-500/50 hover:bg-blue-600"
|
||||||
>
|
>
|
||||||
{status.value ? (
|
{status ? (
|
||||||
<LoaderIcon className="size-4 animate-spin" />
|
<LoaderIcon className="size-4 animate-spin" />
|
||||||
) : (
|
) : (
|
||||||
<RunIcon className="size-4" />
|
<RunIcon className="size-4" />
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { NDKKind } from '@nostr-dev-kit/ndk';
|
import { NDKKind } from '@nostr-dev-kit/ndk';
|
||||||
import { useSignal } from '@preact/signals-react';
|
|
||||||
import * as Collapsible from '@radix-ui/react-collapsible';
|
import * as Collapsible from '@radix-ui/react-collapsible';
|
||||||
import { appConfigDir } from '@tauri-apps/api/path';
|
import { appConfigDir } from '@tauri-apps/api/path';
|
||||||
import { invoke } from '@tauri-apps/api/primitives';
|
import { invoke } from '@tauri-apps/api/primitives';
|
||||||
import { useEffect } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { DepotContactCard } from '@app/depot/components/contact';
|
import { DepotContactCard } from '@app/depot/components/contact';
|
||||||
import { DepotMembers } from '@app/depot/components/members';
|
import { DepotMembers } from '@app/depot/components/members';
|
||||||
@ -14,22 +13,23 @@ import { ChevronDownIcon, DepotIcon, GossipIcon } from '@shared/icons';
|
|||||||
|
|
||||||
export function DepotScreen() {
|
export function DepotScreen() {
|
||||||
const ark = useArk();
|
const ark = useArk();
|
||||||
const dataPath = useSignal('');
|
|
||||||
const tunnelUrl = useSignal('');
|
const [dataPath, setDataPath] = useState('');
|
||||||
|
const [tunnelUrl, setTunnelUrl] = useState('');
|
||||||
|
|
||||||
const openFolder = async () => {
|
const openFolder = async () => {
|
||||||
await invoke('show_in_folder', {
|
await invoke('show_in_folder', {
|
||||||
path: dataPath.value + '/nostr.db',
|
path: dataPath + '/nostr.db',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateRelayList = async () => {
|
const updateRelayList = async () => {
|
||||||
try {
|
try {
|
||||||
if (tunnelUrl.value.length < 1) return toast.info('Please enter a valid relay url');
|
if (tunnelUrl.length < 1) return toast.info('Please enter a valid relay url');
|
||||||
if (!tunnelUrl.value.startsWith('ws'))
|
if (!tunnelUrl.startsWith('ws'))
|
||||||
return toast.info('Please enter a valid relay url');
|
return toast.info('Please enter a valid relay url');
|
||||||
|
|
||||||
const relayUrl = new URL(tunnelUrl.value.replace(/\s/g, ''));
|
const relayUrl = new URL(tunnelUrl.replace(/\s/g, ''));
|
||||||
if (!/^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/.test(relayUrl.host)) return;
|
if (!/^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/.test(relayUrl.host)) return;
|
||||||
|
|
||||||
const relayEvent = await ark.getEventByFilter({
|
const relayEvent = await ark.getEventByFilter({
|
||||||
@ -41,12 +41,12 @@ export function DepotScreen() {
|
|||||||
if (!relayEvent) {
|
if (!relayEvent) {
|
||||||
publish = await ark.createEvent({
|
publish = await ark.createEvent({
|
||||||
kind: NDKKind.RelayList,
|
kind: NDKKind.RelayList,
|
||||||
tags: [['r', tunnelUrl.value, '']],
|
tags: [['r', tunnelUrl, '']],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const newTags = relayEvent.tags ?? [];
|
const newTags = relayEvent.tags ?? [];
|
||||||
newTags.push(['r', tunnelUrl.value, '']);
|
newTags.push(['r', tunnelUrl, '']);
|
||||||
|
|
||||||
publish = await ark.createEvent({
|
publish = await ark.createEvent({
|
||||||
kind: NDKKind.RelayList,
|
kind: NDKKind.RelayList,
|
||||||
@ -54,10 +54,10 @@ export function DepotScreen() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (publish) {
|
if (publish) {
|
||||||
await ark.createSetting('tunnel_url', tunnelUrl.value);
|
await ark.createSetting('tunnel_url', tunnelUrl);
|
||||||
toast.success('Update relay list successfully.');
|
toast.success('Update relay list successfully.');
|
||||||
|
|
||||||
tunnelUrl.value = '';
|
setTunnelUrl('');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
@ -68,7 +68,7 @@ export function DepotScreen() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function loadConfig() {
|
async function loadConfig() {
|
||||||
const appDir = await appConfigDir();
|
const appDir = await appConfigDir();
|
||||||
dataPath.value = appDir;
|
setDataPath(appDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadConfig();
|
loadConfig();
|
||||||
@ -170,8 +170,8 @@ export function DepotScreen() {
|
|||||||
<div className="mt-2 inline-flex w-full items-center gap-2">
|
<div className="mt-2 inline-flex w-full items-center gap-2">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={tunnelUrl.value}
|
value={tunnelUrl}
|
||||||
onChange={(e) => (tunnelUrl.value = e.target.value)}
|
onChange={(e) => setTunnelUrl(e.target.value)}
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
placeholder="wss://"
|
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"
|
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"
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { useSignal } from '@preact/signals-react';
|
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useRef } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
import { VList, VListHandle } from 'virtua';
|
import { VList, VListHandle } from 'virtua';
|
||||||
import { useArk } from '@libs/ark';
|
import { useArk } from '@libs/ark';
|
||||||
import { LoaderIcon, PlusIcon } from '@shared/icons';
|
import { LoaderIcon } from '@shared/icons';
|
||||||
import {
|
import {
|
||||||
ArticleWidget,
|
ArticleWidget,
|
||||||
FileWidget,
|
FileWidget,
|
||||||
@ -12,7 +11,6 @@ import {
|
|||||||
NewsfeedWidget,
|
NewsfeedWidget,
|
||||||
NotificationWidget,
|
NotificationWidget,
|
||||||
ThreadWidget,
|
ThreadWidget,
|
||||||
ToggleWidgetList,
|
|
||||||
TopicWidget,
|
TopicWidget,
|
||||||
TrendingAccountsWidget,
|
TrendingAccountsWidget,
|
||||||
TrendingNotesWidget,
|
TrendingNotesWidget,
|
||||||
@ -25,7 +23,6 @@ import { WidgetProps } from '@utils/types';
|
|||||||
export function HomeScreen() {
|
export function HomeScreen() {
|
||||||
const ark = useArk();
|
const ark = useArk();
|
||||||
const ref = useRef<VListHandle>(null);
|
const ref = useRef<VListHandle>(null);
|
||||||
const index = useSignal(-1);
|
|
||||||
|
|
||||||
const { isLoading, data } = useQuery({
|
const { isLoading, data } = useQuery({
|
||||||
queryKey: ['widgets'],
|
queryKey: ['widgets'],
|
||||||
@ -54,6 +51,8 @@ export function HomeScreen() {
|
|||||||
staleTime: Infinity,
|
staleTime: Infinity,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [selectedIndex, setSelectedIndex] = useState(-1);
|
||||||
|
|
||||||
const renderItem = (widget: WidgetProps) => {
|
const renderItem = (widget: WidgetProps) => {
|
||||||
switch (widget.kind) {
|
switch (widget.kind) {
|
||||||
case WIDGET_KIND.notification:
|
case WIDGET_KIND.notification:
|
||||||
@ -107,8 +106,8 @@ export function HomeScreen() {
|
|||||||
case 'ArrowUp':
|
case 'ArrowUp':
|
||||||
case 'ArrowLeft': {
|
case 'ArrowLeft': {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const prevIndex = Math.max(index.peek() - 1, 0);
|
const prevIndex = Math.max(selectedIndex - 1, 0);
|
||||||
index.value = prevIndex;
|
setSelectedIndex(prevIndex);
|
||||||
ref.current.scrollToIndex(prevIndex, {
|
ref.current.scrollToIndex(prevIndex, {
|
||||||
align: 'center',
|
align: 'center',
|
||||||
smooth: true,
|
smooth: true,
|
||||||
@ -118,8 +117,8 @@ export function HomeScreen() {
|
|||||||
case 'ArrowDown':
|
case 'ArrowDown':
|
||||||
case 'ArrowRight': {
|
case 'ArrowRight': {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const nextIndex = Math.min(index.peek() + 1, data.length - 1);
|
const nextIndex = Math.min(selectedIndex + 1, data.length - 1);
|
||||||
index.value = nextIndex;
|
setSelectedIndex(nextIndex);
|
||||||
ref.current.scrollToIndex(nextIndex, {
|
ref.current.scrollToIndex(nextIndex, {
|
||||||
align: 'center',
|
align: 'center',
|
||||||
smooth: true,
|
smooth: true,
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { useSignal } from '@preact/signals-react';
|
|
||||||
import { Resizable } from 're-resizable';
|
import { Resizable } from 're-resizable';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode, useState } from 'react';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
export function WidgetRoot({
|
export function WidgetRoot({
|
||||||
@ -10,14 +9,14 @@ export function WidgetRoot({
|
|||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
}) {
|
}) {
|
||||||
const width = useSignal(420);
|
const [width, setWidth] = useState(420);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Resizable
|
<Resizable
|
||||||
size={{ width: width.value, height: '100%' }}
|
size={{ width, height: '100%' }}
|
||||||
onResizeStart={(e) => e.preventDefault()}
|
onResizeStart={(e) => e.preventDefault()}
|
||||||
onResizeStop={(_e, _direction, _ref, d) => {
|
onResizeStop={(_e, _direction, _ref, d) => {
|
||||||
width.value = width.peek() + d.width;
|
setWidth((prevWidth) => prevWidth + d.width);
|
||||||
}}
|
}}
|
||||||
minWidth={420}
|
minWidth={420}
|
||||||
maxWidth={600}
|
maxWidth={600}
|
||||||
|
Loading…
Reference in New Issue
Block a user