add topic widget

This commit is contained in:
reya 2023-11-09 09:12:42 +07:00
parent 108ecafab7
commit cb9006abb2
16 changed files with 489 additions and 96 deletions

View File

@ -6,7 +6,7 @@ import { useStorage } from '@libs/storage/provider';
import { ArrowLeftIcon, CheckCircleIcon, LoaderIcon } from '@shared/icons';
import { HASHTAGS, WidgetKinds } from '@stores/constants';
import { HASHTAGS, WIDGET_KIND } from '@stores/constants';
import { useOnboarding } from '@stores/onboarding';
export function OnboardHashtagScreen() {
@ -35,7 +35,7 @@ export function OnboardHashtagScreen() {
setLoading(true);
for (const tag of tags) {
await db.createWidget(WidgetKinds.global.hashtag, tag, tag.replace('#', ''));
await db.createWidget(WIDGET_KIND.global.hashtag, tag, tag.replace('#', ''));
}
setHashtag();

View File

@ -1,7 +1,7 @@
import { PlusIcon } from '@shared/icons';
import { WidgetWrapper } from '@shared/widgets';
import { WidgetKinds } from '@stores/constants';
import { WIDGET_KIND } from '@stores/constants';
import { useWidget } from '@utils/hooks/useWidget';
@ -14,7 +14,7 @@ export function ToggleWidgetList() {
<button
type="button"
onClick={() =>
addWidget.mutate({ kind: WidgetKinds.tmp.list, title: '', content: '' })
addWidget.mutate({ kind: WIDGET_KIND.tmp.list, title: '', content: '' })
}
className="inline-flex h-9 items-center gap-2 rounded-full bg-neutral-200 px-3 text-neutral-900 hover:bg-neutral-300 dark:bg-neutral-800 dark:text-neutral-100 dark:hover:bg-neutral-700"
>

View File

@ -13,7 +13,7 @@ import {
import { TitleBar } from '@shared/titleBar';
import { WidgetWrapper } from '@shared/widgets';
import { DefaultWidgets, WidgetKinds } from '@stores/constants';
import { DEFAULT_WIDGETS, WIDGET_KIND } from '@stores/constants';
import { useWidget } from '@utils/hooks/useWidget';
import { Widget, WidgetGroup, WidgetGroupItem } from '@utils/types';
@ -22,55 +22,48 @@ export function WidgetList({ params }: { params: Widget }) {
const { addWidget, removeWidget } = useWidget();
const open = (item: WidgetGroupItem) => {
addWidget.mutate({ kind: item.kind, title: item.title, content: '' });
addWidget.mutate({
kind: item.kind,
title: item.title,
content: JSON.stringify(item.content),
});
removeWidget.mutate(params.id);
};
const renderIcon = useCallback(
(kind: number) => {
switch (kind) {
case WidgetKinds.tmp.xfeed:
return (
<GroupFeedsIcon className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />
);
case WidgetKinds.local.follows:
return (
<FollowsIcon className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />
);
case WidgetKinds.local.files:
case WidgetKinds.global.files:
return <FileIcon className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />;
case WidgetKinds.local.articles:
case WidgetKinds.global.articles:
return (
<ArticleIcon className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />
);
case WidgetKinds.tmp.xhashtag:
return (
<HashtagIcon className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />
);
case WidgetKinds.nostrBand.trendingAccounts:
case WidgetKinds.nostrBand.trendingNotes:
return (
<TrendingIcon className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />
);
case WidgetKinds.local.notification:
return <BellIcon className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />;
case WidgetKinds.other.learnNostr:
return (
<ThreadsIcon className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />
);
default:
return null;
}
},
[DefaultWidgets]
);
const renderIcon = useCallback((kind: number) => {
switch (kind) {
case WIDGET_KIND.tmp.xfeed:
return (
<GroupFeedsIcon className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />
);
case WIDGET_KIND.local.follows:
return <FollowsIcon className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />;
case WIDGET_KIND.local.files:
case WIDGET_KIND.global.files:
return <FileIcon className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />;
case WIDGET_KIND.local.articles:
case WIDGET_KIND.global.articles:
return <ArticleIcon className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />;
case WIDGET_KIND.tmp.xhashtag:
return <HashtagIcon className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />;
case WIDGET_KIND.nostrBand.trendingAccounts:
case WIDGET_KIND.nostrBand.trendingNotes:
return (
<TrendingIcon className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />
);
case WIDGET_KIND.local.notification:
return <BellIcon className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />;
case WIDGET_KIND.other.learnNostr:
return <ThreadsIcon className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />;
default:
return null;
}
}, []);
const renderItem = useCallback((row: WidgetGroup, index: number) => {
return (
<div key={index} className="flex flex-col gap-2">
<h3 className="text-sm font-semibold">{row.title}</h3>
<h3 className="font-semibold">{row.title}</h3>
<div className="flex flex-col divide-y divide-neutral-200 overflow-hidden rounded-xl bg-neutral-100 dark:divide-neutral-800 dark:bg-neutral-900">
{row.data.map((item, index) => (
<button
@ -111,7 +104,7 @@ export function WidgetList({ params }: { params: Widget }) {
<TitleBar id={params.id} title="Add widget" />
<div className="flex-1 overflow-y-auto pb-10 scrollbar-none">
<div className="flex flex-col gap-6 px-3">
{DefaultWidgets.map((row: WidgetGroup, index: number) =>
{DEFAULT_WIDGETS.map((row: WidgetGroup, index: number) =>
renderItem(row, index)
)}
<div className="border-t border-neutral-200 pt-6 dark:border-neutral-800">

View File

@ -25,7 +25,7 @@ import {
XhashtagWidget,
} from '@shared/widgets';
import { WidgetKinds } from '@stores/constants';
import { WIDGET_KIND } from '@stores/constants';
import { Widget } from '@utils/types';
@ -43,13 +43,13 @@ export function SpaceScreen() {
id: '9998',
title: 'Notification',
content: '',
kind: WidgetKinds.local.notification,
kind: WIDGET_KIND.local.notification,
},
{
id: '9999',
title: 'Newsfeed',
content: '',
kind: WidgetKinds.local.network,
kind: WIDGET_KIND.local.network,
},
];
@ -63,35 +63,35 @@ export function SpaceScreen() {
const renderItem = useCallback((widget: Widget) => {
switch (widget.kind) {
case WidgetKinds.local.feeds:
case WIDGET_KIND.local.feeds:
return <LocalFeedsWidget key={widget.id} params={widget} />;
case WidgetKinds.local.files:
case WIDGET_KIND.local.files:
return <LocalFilesWidget key={widget.id} params={widget} />;
case WidgetKinds.local.articles:
case WIDGET_KIND.local.articles:
return <LocalArticlesWidget key={widget.id} params={widget} />;
case WidgetKinds.local.user:
case WIDGET_KIND.local.user:
return <LocalUserWidget key={widget.id} params={widget} />;
case WidgetKinds.local.thread:
case WIDGET_KIND.local.thread:
return <LocalThreadWidget key={widget.id} params={widget} />;
case WidgetKinds.global.hashtag:
case WIDGET_KIND.global.hashtag:
return <GlobalHashtagWidget key={widget.id} params={widget} />;
case WidgetKinds.global.articles:
case WIDGET_KIND.global.articles:
return <GlobalArticlesWidget key={widget.id} params={widget} />;
case WidgetKinds.global.files:
case WIDGET_KIND.global.files:
return <GlobalFilesWidget key={widget.id} params={widget} />;
case WidgetKinds.nostrBand.trendingAccounts:
case WIDGET_KIND.nostrBand.trendingAccounts:
return <TrendingAccountsWidget key={widget.id} params={widget} />;
case WidgetKinds.nostrBand.trendingNotes:
case WIDGET_KIND.nostrBand.trendingNotes:
return <TrendingNotesWidget key={widget.id} params={widget} />;
case WidgetKinds.tmp.xfeed:
case WIDGET_KIND.tmp.xfeed:
return <XfeedsWidget key={widget.id} params={widget} />;
case WidgetKinds.tmp.xhashtag:
case WIDGET_KIND.tmp.xhashtag:
return <XhashtagWidget key={widget.id} params={widget} />;
case WidgetKinds.tmp.list:
case WIDGET_KIND.tmp.list:
return <WidgetList key={widget.id} params={widget} />;
case WidgetKinds.local.notification:
case WIDGET_KIND.local.notification:
return <NotificationWidget key={widget.id} />;
case WidgetKinds.local.network:
case WIDGET_KIND.local.network:
return <NewsfeedWidget key={widget.id} />;
default:
return null;

View File

@ -6,7 +6,7 @@ import { NoteReply } from '@shared/notes/actions/reply';
import { NoteRepost } from '@shared/notes/actions/repost';
import { NoteZap } from '@shared/notes/actions/zap';
import { WidgetKinds } from '@stores/constants';
import { WIDGET_KIND } from '@stores/constants';
import { useWidget } from '@utils/hooks/useWidget';
@ -34,7 +34,7 @@ export function NoteActions({
type="button"
onClick={() =>
addWidget.mutate({
kind: WidgetKinds.local.thread,
kind: WIDGET_KIND.local.thread,
title: 'Thread',
content: id,
})

View File

@ -1,4 +1,4 @@
import { WidgetKinds } from '@stores/constants';
import { WIDGET_KIND } from '@stores/constants';
import { useWidget } from '@utils/hooks/useWidget';
@ -10,7 +10,7 @@ export function Hashtag({ tag }: { tag: string }) {
type="button"
onClick={() =>
addWidget.mutate({
kind: WidgetKinds.global.hashtag,
kind: WIDGET_KIND.global.hashtag,
title: tag,
content: tag.replace('#', ''),
})

View File

@ -9,7 +9,7 @@ import {
} from '@shared/notes';
import { User } from '@shared/user';
import { WidgetKinds } from '@stores/constants';
import { WIDGET_KIND } from '@stores/constants';
import { useEvent } from '@utils/hooks/useEvent';
import { useWidget } from '@utils/hooks/useWidget';
@ -50,7 +50,7 @@ export const MentionNote = memo(function MentionNote({ id }: { id: string }) {
type="button"
onClick={() =>
addWidget.mutate({
kind: WidgetKinds.local.thread,
kind: WIDGET_KIND.local.thread,
title: 'Thread',
content: data.id,
})

View File

@ -1,6 +1,6 @@
import { memo } from 'react';
import { WidgetKinds } from '@stores/constants';
import { WIDGET_KIND } from '@stores/constants';
import { useProfile } from '@utils/hooks/useProfile';
import { useWidget } from '@utils/hooks/useWidget';
@ -14,14 +14,14 @@ export const MentionUser = memo(function MentionUser({ pubkey }: { pubkey: strin
type="button"
onClick={() =>
addWidget.mutate({
kind: WidgetKinds.local.user,
kind: WIDGET_KIND.local.user,
title: user?.name || user?.display_name || user?.displayName,
content: pubkey,
})
}
onKeyDown={() =>
addWidget.mutate({
kind: WidgetKinds.local.user,
kind: WIDGET_KIND.local.user,
title: user?.name || user?.display_name || user?.displayName,
content: pubkey,
})

View File

@ -10,7 +10,7 @@ import {
} from '@shared/notes';
import { User } from '@shared/user';
import { WidgetKinds } from '@stores/constants';
import { WIDGET_KIND } from '@stores/constants';
import { formatCreatedAt } from '@utils/createdAt';
import { useEvent } from '@utils/hooks/useEvent';
@ -91,7 +91,7 @@ export function NotifyNote({ event }: { event: NDKEvent }) {
type="button"
onClick={() =>
addWidget.mutate({
kind: WidgetKinds.local.thread,
kind: WIDGET_KIND.local.thread,
title: 'Thread',
content: data.id,
})

View File

@ -4,7 +4,7 @@ import { memo } from 'react';
import { ChildNote, NoteActions } from '@shared/notes';
import { User } from '@shared/user';
import { WidgetKinds } from '@stores/constants';
import { WIDGET_KIND } from '@stores/constants';
import { useNostr } from '@utils/hooks/useNostr';
import { useRichContent } from '@utils/hooks/useRichContent';
@ -30,7 +30,7 @@ export function TextNote({ event }: { event: NDKEvent }) {
type="button"
onClick={() =>
addWidget.mutate({
kind: WidgetKinds.local.thread,
kind: WIDGET_KIND.local.thread,
title: 'Thread',
content: thread.rootEventId,
})

View File

@ -14,3 +14,4 @@ export * from './tmp/hashtag';
export * from './newsfeed';
export * from './notification';
export * from './liveUpdater';
export * from './topic';

View File

@ -6,7 +6,7 @@ import { ArrowRightCircleIcon, CancelIcon, CheckCircleIcon } from '@shared/icons
import { User } from '@shared/user';
import { WidgetWrapper } from '@shared/widgets';
import { WidgetKinds } from '@stores/constants';
import { WIDGET_KIND } from '@stores/constants';
import { useWidget } from '@utils/hooks/useWidget';
import { Widget } from '@utils/types';
@ -28,7 +28,7 @@ export function XfeedsWidget({ params }: { params: Widget }) {
const submit = async () => {
addWidget.mutate({
kind: WidgetKinds.local.feeds,
kind: WIDGET_KIND.local.feeds,
title: title || 'Group',
content: JSON.stringify(groups),
});

View File

@ -3,7 +3,7 @@ import { Resolver, useForm } from 'react-hook-form';
import { ArrowRightCircleIcon, CancelIcon } from '@shared/icons';
import { WidgetWrapper } from '@shared/widgets';
import { HASHTAGS, WidgetKinds } from '@stores/constants';
import { HASHTAGS, WIDGET_KIND } from '@stores/constants';
import { useWidget } from '@utils/hooks/useWidget';
import { Widget } from '@utils/types';
@ -39,7 +39,7 @@ export function XhashtagWidget({ params }: { params: Widget }) {
const onSubmit = async (data: FormValues) => {
try {
addWidget.mutate({
kind: WidgetKinds.global.hashtag,
kind: WIDGET_KIND.global.hashtag,
title: data.hashtag,
content: data.hashtag.replace('#', ''),
});

View File

@ -0,0 +1,128 @@
import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
import { useInfiniteQuery } from '@tanstack/react-query';
import { useCallback, useMemo } from 'react';
import { VList } from 'virtua';
import { useNDK } from '@libs/ndk/provider';
import { ArrowRightCircleIcon, LoaderIcon } from '@shared/icons';
import {
MemoizedRepost,
MemoizedTextNote,
NoteSkeleton,
UnknownNote,
} from '@shared/notes';
import { TitleBar } from '@shared/titleBar';
import { WidgetWrapper } from '@shared/widgets';
import { FETCH_LIMIT } from '@stores/constants';
import { Widget } from '@utils/types';
export function TopicWidget({ widget }: { widget: Widget }) {
const { relayUrls, ndk, fetcher } = useNDK();
const { status, data, hasNextPage, isFetchingNextPage, fetchNextPage } =
useInfiniteQuery({
queryKey: [widget.title],
initialPageParam: 0,
queryFn: async ({
signal,
pageParam,
}: {
signal: AbortSignal;
pageParam: number;
}) => {
const hashtags: string[] = JSON.parse(widget.content as string);
const rootIds = new Set();
const dedupQueue = new Set();
const events = await fetcher.fetchLatestEvents(
relayUrls,
{
kinds: [NDKKind.Text, NDKKind.Repost],
'#t': hashtags,
},
FETCH_LIMIT,
{ asOf: pageParam === 0 ? undefined : pageParam, abortSignal: signal }
);
const ndkEvents = events.map((event) => {
return new NDKEvent(ndk, event);
});
ndkEvents.forEach((event) => {
const tags = event.tags.filter((el) => el[0] === 'e');
if (tags && tags.length > 0) {
const rootId = tags.filter((el) => el[3] === 'root')[1] ?? tags[0][1];
if (rootIds.has(rootId)) return dedupQueue.add(event.id);
rootIds.add(rootId);
}
});
return ndkEvents
.filter((event) => !dedupQueue.has(event.id))
.sort((a, b) => b.created_at - a.created_at);
},
getNextPageParam: (lastPage) => {
const lastEvent = lastPage.at(-1);
if (!lastEvent) return;
return lastEvent.created_at - 1;
},
refetchOnWindowFocus: false,
});
const allEvents = useMemo(
() => (data ? data.pages.flatMap((page) => page) : []),
[data]
);
const renderItem = useCallback(
(event: NDKEvent) => {
switch (event.kind) {
case NDKKind.Text:
return <MemoizedTextNote key={event.id} event={event} />;
case NDKKind.Repost:
return <MemoizedRepost key={event.id} event={event} />;
default:
return <UnknownNote key={event.id} event={event} />;
}
},
[data]
);
return (
<WidgetWrapper>
<TitleBar id={widget.id} title={widget.title} />
<VList className="flex-1" overscan={2}>
{status === 'pending' ? (
<div className="px-3 py-1.5">
<div className="rounded-xl bg-neutral-100 px-3 py-3 dark:bg-neutral-900">
<NoteSkeleton />
</div>
</div>
) : (
allEvents.map((item) => renderItem(item))
)}
<div className="flex h-16 items-center justify-center px-3 pb-3">
{hasNextPage ? (
<button
type="button"
onClick={() => fetchNextPage()}
disabled={!hasNextPage || isFetchingNextPage}
className="inline-flex h-10 w-max items-center justify-center gap-2 rounded-full bg-blue-500 px-6 font-medium text-white hover:bg-blue-600 focus:outline-none"
>
{isFetchingNextPage ? (
<LoaderIcon className="h-4 w-4 animate-spin" />
) : (
<>
<ArrowRightCircleIcon className="h-5 w-5" />
Load more
</>
)}
</button>
) : null}
</div>
</VList>
</WidgetWrapper>
);
}

View File

@ -41,7 +41,7 @@ export const HASHTAGS = [
{ hashtag: '#primal' },
];
export const WidgetKinds = {
export const WIDGET_KIND = {
local: {
network: 100,
feeds: 101,
@ -57,6 +57,7 @@ export const WidgetKinds = {
files: 1001,
articles: 1002,
hashtag: 1003,
topic: 108,
},
nostrBand: {
trendingAccounts: 1,
@ -72,24 +73,293 @@ export const WidgetKinds = {
},
};
export const DefaultWidgets: Array<WidgetGroup> = [
export const TOPICS = [
{
title: 'Gaming',
description: '',
kind: WIDGET_KIND.global.topic,
content: [
'#gamestr',
'#gaming',
'#gamer',
'#ps',
'#playstation',
'#videogames',
'#game',
'#xbox',
'#games',
'#twitch',
'#fortnite',
'#pc',
'#memes',
'#pcgaming',
'#gamers',
'#gamingcommunity',
'#youtube',
'#switch',
'#gamergirl',
'#nintendo',
'#gta',
'#callofduty',
'#streamer',
'#follow',
'#pubg',
'#videogame',
'#esports',
'#bhfyp',
'#meme',
'#twitchstreamer',
'#art',
'#genshinimpact',
'#honkaiimpact',
'#warthunder',
'#hovoverse',
'#arknights',
'#soul',
'#eldenring',
'#steam',
'#pubg',
'#cs2',
'#apexlegends',
'#baldurgate3',
'#starfield',
'#gta6',
'#gameoftheyear',
],
},
{
title: 'Music',
description: '',
kind: WIDGET_KIND.global.topic,
content: [
'#audiostr',
'#musicstr',
'#music',
'#love',
'#hiphop',
'#rap',
'#art',
'#musician',
'#artist',
'#musica',
'#instagood',
'#singer',
'#dj',
'#follow',
'#rock',
'#like',
'#dance',
'#guitar',
'#s',
'#photography',
'#song',
'#bhfyp',
'#newmusic',
'#producer',
'#life',
'#rapper',
'#party',
'#fashion',
'#explorepage',
'#viral',
'#beats',
],
},
{
title: 'Photography',
description: '',
kind: WIDGET_KIND.global.topic,
content: [
'#photography',
'#photooftheday',
'#love',
'#photo',
'#nature',
'#picoftheday',
'#like',
'#photographer',
'#beautiful',
'#follow',
'#art',
'#fashion',
'#travel',
'#bhfyp',
'#photoshoot',
'#likeforlikes',
'#instadaily',
'#naturephotography',
'#model',
'#me',
'#smile',
'#style',
'#instalike',
'#happy',
'#likes',
'#myself',
'#followme',
'#followforfollowback',
],
},
{
title: 'Art',
description: '',
kind: WIDGET_KIND.global.topic,
content: [
'#artstr',
'#art',
'#artist',
'#love',
'#drawing',
'#photography',
'#artwork',
'#instagood',
'#photooftheday',
'#painting',
'#fashion',
'#like',
'#artistsoninstagram',
'#beautiful',
'#illustration',
'#digitalart',
'#follow',
'#design',
'#nature',
'#picoftheday',
'#photo',
'#bhfyp',
'#sketch',
'#style',
'#arte',
'#happy',
'#cute',
'#draw',
'#artoftheday',
],
},
{
title: 'Movie',
description: '',
kind: WIDGET_KIND.global.topic,
content: [
'#filmstr',
'#moviestr',
'#movies',
'#movie',
'#film',
'#cinema',
'#films',
'#hollywood',
'#actor',
'#love',
'#s',
'#art',
'#cinematography',
'#actress',
'#netflix',
'#moviescenes',
'#music',
'#filmmaking',
'#horror',
'#instagood',
'#bollywood',
'#movienight',
'#photography',
'#comedy',
'#cinephile',
'#cine',
'#tv',
'#director',
'#horrormovies',
'#drama',
'#filmmaker',
],
},
{
title: 'Technology',
description: '',
kind: WIDGET_KIND.global.topic,
content: [
'#apple',
'#xiaomi',
'#huawei',
'#ai',
'#oppo',
'#nostr',
'#technology',
'#tech',
'#innovation',
'#engineering',
'#business',
'#iphone',
'#technews',
'#science',
'#design',
'#gadgets',
'#electronics',
'#android',
'#software',
'#programming',
'#smartphone',
'#bhfyp',
'#samsung',
'#instagood',
'#coding',
'#computer',
'#pro',
'#education',
'#security',
'#gadget',
'#mobile',
'#technologynews',
],
},
{
title: 'Anime',
description: '',
kind: WIDGET_KIND.global.topic,
content: [
'#animestr',
'#anime',
'#manga',
'#ntr',
'#otaku',
'#animeart',
'#animegirl',
'#cosplay',
'#kawaii',
'#weeb',
'#onepiece',
'#demonslayer',
'#animeworld',
'#aot',
'#hentai',
'#fanart',
],
},
];
export const DEFAULT_WIDGETS: Array<WidgetGroup> = [
{
title: 'Topics',
data: TOPICS,
},
{
title: 'Local',
data: [
{
kind: WidgetKinds.tmp.xfeed,
kind: WIDGET_KIND.tmp.xfeed,
title: 'Group feeds',
description: 'All posts from specific people you want to keep up with',
},
{
kind: WidgetKinds.local.files,
kind: WIDGET_KIND.local.files,
title: 'Files',
description: 'All files shared by people in your circle',
description: 'All files shared by people you follow',
},
{
kind: WidgetKinds.local.articles,
kind: WIDGET_KIND.local.articles,
title: 'Articles',
description: 'All articles shared by people in your circle',
description: 'All articles shared by people you follow',
},
],
},
@ -97,17 +367,17 @@ export const DefaultWidgets: Array<WidgetGroup> = [
title: 'Global',
data: [
{
kind: WidgetKinds.tmp.xhashtag,
kind: WIDGET_KIND.tmp.xhashtag,
title: 'Hashtag',
description: 'All posts have a specific hashtag',
},
{
kind: WidgetKinds.global.files,
kind: WIDGET_KIND.global.files,
title: 'Files',
description: 'All files shared by people in your current relay set',
},
{
kind: WidgetKinds.global.articles,
kind: WIDGET_KIND.global.articles,
title: 'Articles',
description: 'All articles shared by people in your current relay set',
},
@ -117,12 +387,12 @@ export const DefaultWidgets: Array<WidgetGroup> = [
title: 'nostr.band',
data: [
{
kind: WidgetKinds.nostrBand.trendingAccounts,
kind: WIDGET_KIND.nostrBand.trendingAccounts,
title: 'Accounts',
description: 'Trending accounts from the last 24 hours',
},
{
kind: WidgetKinds.nostrBand.trendingNotes,
kind: WIDGET_KIND.nostrBand.trendingNotes,
title: 'Notes',
description: 'Trending notes from the last 24 hours',
},
@ -132,7 +402,7 @@ export const DefaultWidgets: Array<WidgetGroup> = [
title: 'Other',
data: [
{
kind: WidgetKinds.local.notification,
kind: WIDGET_KIND.local.notification,
title: 'Notification',
description: 'Everything happens around you',
},

View File

@ -43,6 +43,7 @@ export interface WidgetGroup {
export interface WidgetGroupItem {
title: string;
description: string;
content: string;
kind: number;
icon?: string;
}