mirror of
https://github.com/luminous-devs/lume.git
synced 2024-09-19 11:43:30 +00:00
fix some bugs
This commit is contained in:
parent
10036500cb
commit
177e4c1ff7
@ -1,32 +1,25 @@
|
|||||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||||
import { useMemo } from 'react';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import { NotiContent } from '@app/notifications/components/content';
|
|
||||||
import { NotiUser } from '@app/notifications/components/user';
|
import { NotiUser } from '@app/notifications/components/user';
|
||||||
|
|
||||||
import { formatCreatedAt } from '@utils/createdAt';
|
import { formatCreatedAt } from '@utils/createdAt';
|
||||||
import { parser } from '@utils/parser';
|
|
||||||
|
|
||||||
export function NotiMention({ event }: { event: NDKEvent }) {
|
export function NotiMention({ event }: { event: NDKEvent }) {
|
||||||
const createdAt = formatCreatedAt(event.created_at);
|
const createdAt = formatCreatedAt(event.created_at);
|
||||||
const content = useMemo(() => parser(event), [event]);
|
const rootId = event.tags.find((el) => el[0])?.[1];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-min w-full px-3 py-1.5">
|
<Link to={`/notes/text/${rootId}`} className="h-min w-full px-3">
|
||||||
<div className="relative overflow-hidden rounded-xl bg-white/10 px-3 pt-3 backdrop-blur-xl">
|
<div className="group flex items-center justify-between rounded-xl px-3 py-3 hover:bg-white/10">
|
||||||
<div className="flex items-start justify-between">
|
<div className="flex items-center gap-2">
|
||||||
<div className="flex items-start gap-1">
|
|
||||||
<NotiUser pubkey={event.pubkey} />
|
<NotiUser pubkey={event.pubkey} />
|
||||||
<p className="leading-none text-white/50">has reply you post · {createdAt}</p>
|
<p className="leading-none text-white/50">has mention you · {createdAt}</p>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="f- relative z-10 -mt-6 flex gap-3">
|
|
||||||
<div className="h-11 w-11 shrink-0" />
|
|
||||||
<div className="mb-2 mt-3 w-full cursor-default rounded-lg bg-white/10 px-3 py-3 backdrop-blur-xl">
|
|
||||||
<NotiContent content={content} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<span className="hidden text-sm font-semibold text-fuchsia-500 group-hover:block">
|
||||||
|
View
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
</Link>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,27 @@
|
|||||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import { SimpleNote } from '@app/notifications/components/simpleNote';
|
|
||||||
import { NotiUser } from '@app/notifications/components/user';
|
import { NotiUser } from '@app/notifications/components/user';
|
||||||
|
|
||||||
import { formatCreatedAt } from '@utils/createdAt';
|
import { formatCreatedAt } from '@utils/createdAt';
|
||||||
|
|
||||||
export function NotiReaction({ event }: { event: NDKEvent }) {
|
export function NotiReaction({ event }: { event: NDKEvent }) {
|
||||||
const root = event.tags.find((e) => e[0] === 'e')?.[1];
|
|
||||||
const createdAt = formatCreatedAt(event.created_at);
|
const createdAt = formatCreatedAt(event.created_at);
|
||||||
|
const rootId = event.tags.find((el) => el[0])?.[1];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-min w-full px-3 py-1.5">
|
<Link to={`/notes/text/${rootId}`} className="h-min w-full px-3">
|
||||||
<div className="relative overflow-hidden rounded-xl bg-white/10 px-3 pt-3 backdrop-blur-xl">
|
<div className="group flex items-center justify-between rounded-xl px-3 py-3 hover:bg-white/10">
|
||||||
<div className="flex items-start justify-between">
|
<div className="flex items-center gap-2">
|
||||||
<div className="flex items-start gap-1">
|
|
||||||
<NotiUser pubkey={event.pubkey} />
|
<NotiUser pubkey={event.pubkey} />
|
||||||
<p className="leading-none text-white/50">
|
<p className="leading-none text-white/50">
|
||||||
reacted {event.content} · {createdAt}
|
reacted {event.content} · {createdAt}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<span className="hidden text-sm font-semibold text-fuchsia-500 group-hover:block">
|
||||||
|
View
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative z-10 -mt-6 flex gap-3">
|
</Link>
|
||||||
<div className="h-11 w-11 shrink-0" />
|
|
||||||
<div className="flex-1">{root && <SimpleNote id={root} />}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import { SimpleNote } from '@app/notifications/components/simpleNote';
|
|
||||||
import { NotiUser } from '@app/notifications/components/user';
|
import { NotiUser } from '@app/notifications/components/user';
|
||||||
|
|
||||||
import { useStorage } from '@libs/storage/provider';
|
import { useStorage } from '@libs/storage/provider';
|
||||||
@ -10,29 +10,24 @@ import { formatCreatedAt } from '@utils/createdAt';
|
|||||||
export function NotiRepost({ event }: { event: NDKEvent }) {
|
export function NotiRepost({ event }: { event: NDKEvent }) {
|
||||||
const { db } = useStorage();
|
const { db } = useStorage();
|
||||||
|
|
||||||
const root = event.tags.find((e) => e[0] === 'e')?.[1];
|
|
||||||
const createdAt = formatCreatedAt(event.created_at);
|
const createdAt = formatCreatedAt(event.created_at);
|
||||||
|
const rootId = event.tags.find((el) => el[0])?.[1];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-min w-full px-3 py-1.5">
|
<Link to={`/notes/text/${rootId}`} className="h-min w-full px-3">
|
||||||
<div className="relative overflow-hidden rounded-xl bg-white/10 px-3 pt-3 backdrop-blur-xl">
|
<div className="group flex items-center justify-between rounded-xl px-3 py-3 hover:bg-white/10">
|
||||||
<div className="flex items-start justify-between">
|
<div className="flex items-center gap-2">
|
||||||
<div className="flex items-start gap-1">
|
|
||||||
<NotiUser pubkey={event.pubkey} />
|
<NotiUser pubkey={event.pubkey} />
|
||||||
<p className="leading-none text-white/50">
|
<p className="leading-none text-white/50">
|
||||||
repost{' '}
|
repost{' '}
|
||||||
{event.pubkey !== db.account.pubkey
|
{event.pubkey !== db.account.pubkey ? 'a post that mention you' : 'your post'}{' '}
|
||||||
? 'a post that mention you'
|
|
||||||
: 'your post'}{' '}
|
|
||||||
· {createdAt}
|
· {createdAt}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<span className="hidden text-sm font-semibold text-fuchsia-500 group-hover:block">
|
||||||
|
View
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative z-10 -mt-6 flex gap-3">
|
</Link>
|
||||||
<div className="h-11 w-11 shrink-0" />
|
|
||||||
<div className="flex-1">{root && <SimpleNote id={root} />}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -18,13 +18,13 @@ export function NotiUser({ pubkey }: { pubkey: string }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex shrink-0 items-start justify-start gap-3">
|
<div className="flex shrink-0 items-center justify-start gap-2">
|
||||||
<Image
|
<Image
|
||||||
src={user?.picture || user?.image}
|
src={user?.picture || user?.image}
|
||||||
alt={pubkey}
|
alt={pubkey}
|
||||||
className="h-11 w-11 shrink-0 rounded-lg object-cover"
|
className="h-8 w-8 shrink-0 rounded-md object-cover"
|
||||||
/>
|
/>
|
||||||
<span className="max-w-[10rem] flex-1 truncate font-medium leading-none text-white">
|
<span className="max-w-[10rem] truncate font-medium leading-none text-white">
|
||||||
{user?.name || user?.display_name || displayNpub(pubkey, 16)}
|
{user?.name || user?.display_name || displayNpub(pubkey, 16)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,16 +1,24 @@
|
|||||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||||
import { useCallback } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
|
|
||||||
import { NotiMention } from '@app/notifications/components/mention';
|
import { NotiMention } from '@app/notifications/components/mention';
|
||||||
import { NotiReaction } from '@app/notifications/components/reaction';
|
import { NotiReaction } from '@app/notifications/components/reaction';
|
||||||
import { NotiRepost } from '@app/notifications/components/repost';
|
import { NotiRepost } from '@app/notifications/components/repost';
|
||||||
|
|
||||||
|
import { LoaderIcon } from '@shared/icons';
|
||||||
import { TitleBar } from '@shared/titleBar';
|
import { TitleBar } from '@shared/titleBar';
|
||||||
|
|
||||||
import { useActivities } from '@stores/activities';
|
import { useActivities } from '@stores/activities';
|
||||||
|
|
||||||
|
import { useNostr } from '@utils/hooks/useNostr';
|
||||||
|
|
||||||
export function NotificationScreen() {
|
export function NotificationScreen() {
|
||||||
const activities = useActivities((state) => state.activities);
|
const { fetchActivities } = useNostr();
|
||||||
|
const [activities, setActivities, clearTotalNewActivities] = useActivities((state) => [
|
||||||
|
state.activities,
|
||||||
|
state.setActivities,
|
||||||
|
state.clearTotalNewActivities,
|
||||||
|
]);
|
||||||
|
|
||||||
const renderItem = useCallback(
|
const renderItem = useCallback(
|
||||||
(event: NDKEvent) => {
|
(event: NDKEvent) => {
|
||||||
@ -28,14 +36,31 @@ export function NotificationScreen() {
|
|||||||
[activities]
|
[activities]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function getActivities() {
|
||||||
|
const events = await fetchActivities();
|
||||||
|
setActivities(events);
|
||||||
|
// clear total new activities
|
||||||
|
clearTotalNewActivities();
|
||||||
|
}
|
||||||
|
|
||||||
|
getActivities();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="scrollbar-hide h-full w-full overflow-y-auto bg-white/10 backdrop-blur-xl">
|
<div className="scrollbar-hide h-full w-full overflow-y-auto bg-white/10 backdrop-blur-xl">
|
||||||
<div className="grid h-full grid-cols-3">
|
<div className="grid h-full grid-cols-3">
|
||||||
<div className="col-span-2 flex flex-col border-r border-white/5">
|
<div className="col-span-2 flex flex-col border-r border-white/5">
|
||||||
<TitleBar title="Activities in the last 24 hours" />
|
<TitleBar title="Activities in the last 24 hours" />
|
||||||
<div className="flex h-full flex-col gap-1.5">
|
|
||||||
<div className="flex h-full flex-col">
|
<div className="flex h-full flex-col">
|
||||||
{activities?.length < 1 ? (
|
{!activities ? (
|
||||||
|
<div className="flex h-full w-full items-center justify-center">
|
||||||
|
<div className="flex flex-col items-center gap-1.5">
|
||||||
|
<LoaderIcon className="h-5 w-5 animate-spin text-white" />
|
||||||
|
<p className="text-sm font-medium text-white/50">Loading</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : activities.length < 1 ? (
|
||||||
<div className="flex h-full w-full flex-col items-center justify-center">
|
<div className="flex h-full w-full flex-col items-center justify-center">
|
||||||
<p className="mb-1 text-4xl">🎉</p>
|
<p className="mb-1 text-4xl">🎉</p>
|
||||||
<p className="font-medium text-white/50">
|
<p className="font-medium text-white/50">
|
||||||
@ -49,6 +74,5 @@ export function NotificationScreen() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import {
|
|||||||
XfeedsWidget,
|
XfeedsWidget,
|
||||||
XhashtagWidget,
|
XhashtagWidget,
|
||||||
} from '@shared/widgets';
|
} from '@shared/widgets';
|
||||||
|
import { LocalFollowsWidget } from '@shared/widgets/local/follows';
|
||||||
|
|
||||||
import { WidgetKinds, useWidgets } from '@stores/widgets';
|
import { WidgetKinds, useWidgets } from '@stores/widgets';
|
||||||
|
|
||||||
@ -40,6 +41,8 @@ export function SpaceScreen() {
|
|||||||
switch (widget.kind) {
|
switch (widget.kind) {
|
||||||
case WidgetKinds.local.network:
|
case WidgetKinds.local.network:
|
||||||
return <LocalNetworkWidget key={widget.id} />;
|
return <LocalNetworkWidget key={widget.id} />;
|
||||||
|
case WidgetKinds.local.follows:
|
||||||
|
return <LocalFollowsWidget key={widget.id} params={widget} />;
|
||||||
case WidgetKinds.local.feeds:
|
case WidgetKinds.local.feeds:
|
||||||
return <LocalFeedsWidget key={widget.id} params={widget} />;
|
return <LocalFeedsWidget key={widget.id} params={widget} />;
|
||||||
case WidgetKinds.local.files:
|
case WidgetKinds.local.files:
|
||||||
|
@ -7,17 +7,14 @@ import { useStorage } from '@libs/storage/provider';
|
|||||||
|
|
||||||
import { LoaderIcon } from '@shared/icons';
|
import { LoaderIcon } from '@shared/icons';
|
||||||
|
|
||||||
import { useActivities } from '@stores/activities';
|
|
||||||
|
|
||||||
import { useNostr } from '@utils/hooks/useNostr';
|
import { useNostr } from '@utils/hooks/useNostr';
|
||||||
|
|
||||||
export function SplashScreen() {
|
export function SplashScreen() {
|
||||||
const { db } = useStorage();
|
const { db } = useStorage();
|
||||||
const { ndk } = useNDK();
|
const { ndk } = useNDK();
|
||||||
const { fetchUserData, fetchActivities, prefetchEvents } = useNostr();
|
const { fetchUserData, prefetchEvents } = useNostr();
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||||
const setActivities = useActivities((state) => state.setActivities);
|
|
||||||
|
|
||||||
const skip = async () => {
|
const skip = async () => {
|
||||||
await invoke('close_splashscreen');
|
await invoke('close_splashscreen');
|
||||||
@ -27,11 +24,8 @@ export function SplashScreen() {
|
|||||||
try {
|
try {
|
||||||
const user = await fetchUserData();
|
const user = await fetchUserData();
|
||||||
const data = await prefetchEvents();
|
const data = await prefetchEvents();
|
||||||
const activities = await fetchActivities();
|
|
||||||
|
|
||||||
if (user.status === 'ok' && data.status === 'ok') {
|
if (user.status === 'ok' && data.status === 'ok') {
|
||||||
// set activities
|
|
||||||
setActivities(activities);
|
|
||||||
// update last login = current time
|
// update last login = current time
|
||||||
await db.updateLastLogin();
|
await db.updateLastLogin();
|
||||||
// close splash screen and open main app screen
|
// close splash screen and open main app screen
|
||||||
|
@ -11,10 +11,15 @@ import { ComposerModal } from '@shared/composer';
|
|||||||
import { Frame } from '@shared/frame';
|
import { Frame } from '@shared/frame';
|
||||||
import { BellIcon, NavArrowDownIcon, SpaceIcon } from '@shared/icons';
|
import { BellIcon, NavArrowDownIcon, SpaceIcon } from '@shared/icons';
|
||||||
|
|
||||||
|
import { useActivities } from '@stores/activities';
|
||||||
import { useSidebar } from '@stores/sidebar';
|
import { useSidebar } from '@stores/sidebar';
|
||||||
|
|
||||||
|
import { compactNumber } from '@utils/number';
|
||||||
|
|
||||||
export function Navigation() {
|
export function Navigation() {
|
||||||
const { db } = useStorage();
|
const { db } = useStorage();
|
||||||
|
|
||||||
|
const [totalNewActivities] = useActivities((state) => [state.totalNewActivities]);
|
||||||
const [chats, toggleChats] = useSidebar((state) => [state.chats, state.toggleChats]);
|
const [chats, toggleChats] = useSidebar((state) => [state.chats, state.toggleChats]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -47,17 +52,26 @@ export function Navigation() {
|
|||||||
preventScrollReset={true}
|
preventScrollReset={true}
|
||||||
className={({ isActive }) =>
|
className={({ isActive }) =>
|
||||||
twMerge(
|
twMerge(
|
||||||
'flex h-10 items-center gap-2.5 rounded-r-lg border-l-2 pl-4 pr-2',
|
'flex h-10 items-center justify-between rounded-r-lg border-l-2 pl-4 pr-2',
|
||||||
isActive
|
isActive
|
||||||
? 'border-fuchsia-500 bg-white/5 text-white'
|
? 'border-fuchsia-500 bg-white/5 text-white'
|
||||||
: 'border-transparent text-white/80'
|
: 'border-transparent text-white/80'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
<div className="flex items-center gap-2.5">
|
||||||
<span className="inline-flex h-7 w-7 shrink-0 items-center justify-center rounded bg-white/10 backdrop-blur-xl">
|
<span className="inline-flex h-7 w-7 shrink-0 items-center justify-center rounded bg-white/10 backdrop-blur-xl">
|
||||||
<BellIcon className="h-4 w-4 text-white" />
|
<BellIcon className="h-4 w-4 text-white" />
|
||||||
</span>
|
</span>
|
||||||
Notifications
|
Notifications
|
||||||
|
</div>
|
||||||
|
{totalNewActivities > 0 ? (
|
||||||
|
<div className="inline-flex h-5 w-8 items-center justify-center rounded bg-fuchsia-500">
|
||||||
|
<span className="text-xs font-medium text-white">
|
||||||
|
{compactNumber.format(totalNewActivities)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
<Collapsible.Root open={chats} onOpenChange={toggleChats}>
|
<Collapsible.Root open={chats} onOpenChange={toggleChats}>
|
||||||
|
@ -19,7 +19,7 @@ import { useEvent } from '@utils/hooks/useEvent';
|
|||||||
|
|
||||||
export function Repost({ event }: { event: NDKEvent }) {
|
export function Repost({ event }: { event: NDKEvent }) {
|
||||||
// @ts-expect-error, root_id isn't exist on NDKEvent
|
// @ts-expect-error, root_id isn't exist on NDKEvent
|
||||||
const { status, data } = useEvent(event.root_id, event.content);
|
const { status, data } = useEvent(event.root_id ?? event.id, event.content);
|
||||||
|
|
||||||
const renderKind = useCallback(
|
const renderKind = useCallback(
|
||||||
(repostEvent: NDKEvent) => {
|
(repostEvent: NDKEvent) => {
|
||||||
|
@ -42,7 +42,7 @@ export function TextNote({ content }: { content: string }) {
|
|||||||
const cleanURL = new URL(href);
|
const cleanURL = new URL(href);
|
||||||
cleanURL.search = '';
|
cleanURL.search = '';
|
||||||
return (
|
return (
|
||||||
<Link to={href} target="_blank">
|
<Link to={href} target="_blank" className="line-clamp-1">
|
||||||
{cleanURL.hostname + cleanURL.pathname}
|
{cleanURL.hostname + cleanURL.pathname}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
@ -17,9 +17,9 @@ import {
|
|||||||
import { NoteSkeleton } from '@shared/notes/skeleton';
|
import { NoteSkeleton } from '@shared/notes/skeleton';
|
||||||
import { TitleBar } from '@shared/titleBar';
|
import { TitleBar } from '@shared/titleBar';
|
||||||
|
|
||||||
import { DBEvent } from '@utils/types';
|
import { DBEvent, Widget } from '@utils/types';
|
||||||
|
|
||||||
export function LocalFollowsWidget() {
|
export function LocalFollowsWidget({ params }: { params: Widget }) {
|
||||||
const { db } = useStorage();
|
const { db } = useStorage();
|
||||||
const { status, data, hasNextPage, isFetchingNextPage, fetchNextPage } =
|
const { status, data, hasNextPage, isFetchingNextPage, fetchNextPage } =
|
||||||
useInfiniteQuery({
|
useInfiniteQuery({
|
||||||
@ -116,7 +116,7 @@ export function LocalFollowsWidget() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative shrink-0 grow-0 basis-[400px] bg-white/10 backdrop-blur-xl">
|
<div className="relative shrink-0 grow-0 basis-[400px] bg-white/10 backdrop-blur-xl">
|
||||||
<TitleBar title="👋 Network" />
|
<TitleBar id={params.id} title="Follows" />
|
||||||
<div ref={parentRef} className="scrollbar-hide h-full overflow-y-auto pb-20">
|
<div ref={parentRef} className="scrollbar-hide h-full overflow-y-auto pb-20">
|
||||||
{status === 'loading' ? (
|
{status === 'loading' ? (
|
||||||
<div className="px-3 py-1.5">
|
<div className="px-3 py-1.5">
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { createJSONStorage, persist } from 'zustand/middleware';
|
|
||||||
|
|
||||||
interface ActivitiesState {
|
interface ActivitiesState {
|
||||||
activities: null | Array<NDKEvent>;
|
activities: Array<NDKEvent>;
|
||||||
|
totalNewActivities: number;
|
||||||
setActivities: (events: NDKEvent[]) => void;
|
setActivities: (events: NDKEvent[]) => void;
|
||||||
addActivity: (event: NDKEvent) => void;
|
addActivity: (event: NDKEvent) => void;
|
||||||
|
clearTotalNewActivities: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useActivities = create<ActivitiesState>()(
|
export const useActivities = create<ActivitiesState>((set) => ({
|
||||||
persist(
|
|
||||||
(set) => ({
|
|
||||||
activities: null,
|
activities: null,
|
||||||
|
totalNewActivities: 0,
|
||||||
setActivities: (events: NDKEvent[]) => {
|
setActivities: (events: NDKEvent[]) => {
|
||||||
set(() => ({ activities: events }));
|
set(() => ({ activities: events }));
|
||||||
},
|
},
|
||||||
addActivity: (event: NDKEvent) => {
|
addActivity: (event: NDKEvent) => {
|
||||||
set((state) => ({ activities: [event, ...state.activities] }));
|
set((state) => ({
|
||||||
|
activities: state.activities ? [event, ...state.activities] : [event],
|
||||||
|
totalNewActivities: state.totalNewActivities++,
|
||||||
|
}));
|
||||||
},
|
},
|
||||||
}),
|
clearTotalNewActivities: () => {
|
||||||
{
|
set(() => ({ totalNewActivities: 0 }));
|
||||||
name: 'activities',
|
},
|
||||||
storage: createJSONStorage(() => localStorage),
|
}));
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
@ -12,7 +12,7 @@ export function useEvent(id: string, embed?: string) {
|
|||||||
const { status, data } = useQuery(
|
const { status, data } = useQuery(
|
||||||
['event', id],
|
['event', id],
|
||||||
async () => {
|
async () => {
|
||||||
// return embed event (nostr.band api)
|
// return embed event (nostr.band api) or repost
|
||||||
if (embed) {
|
if (embed) {
|
||||||
const event: NDKEvent = JSON.parse(embed);
|
const event: NDKEvent = JSON.parse(embed);
|
||||||
return event;
|
return event;
|
||||||
|
@ -3,17 +3,20 @@ import { EventPointer } from 'nostr-tools/lib/nip19';
|
|||||||
|
|
||||||
import { RichContent } from '@utils/types';
|
import { RichContent } from '@utils/types';
|
||||||
|
|
||||||
function isURL(str: string) {
|
function isURL(string: string) {
|
||||||
const pattern = new RegExp(
|
try {
|
||||||
'^(https?:\\/\\/)?' + // protocol
|
const url = new URL(string);
|
||||||
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
|
if (url.protocol.length > 0) {
|
||||||
'((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
|
if (url.protocol === 'https:' || url.protocol === 'http:') {
|
||||||
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
|
return true;
|
||||||
'(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
|
} else {
|
||||||
'(\\#[-a-z\\d_]*)?$', // fragment locator
|
return false;
|
||||||
'i'
|
}
|
||||||
);
|
}
|
||||||
return !!pattern.test(str);
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parser(eventContent: string) {
|
export function parser(eventContent: string) {
|
||||||
|
Loading…
Reference in New Issue
Block a user