Files
lume/src/app/home/index.tsx

140 lines
4.1 KiB
TypeScript

import { useSignal } from '@preact/signals-react';
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 {
ArticleWidget,
FileWidget,
GroupWidget,
HashtagWidget,
NewsfeedWidget,
NotificationWidget,
ThreadWidget,
ToggleWidgetList,
TopicWidget,
TrendingAccountsWidget,
TrendingNotesWidget,
UserWidget,
WidgetList,
} from '@shared/widgets';
import { WIDGET_KIND } from '@utils/constants';
import { WidgetProps } from '@utils/types';
export function HomeScreen() {
const ark = useArk();
const ref = useRef<VListHandle>(null);
const index = useSignal(-1);
const { isLoading, data } = useQuery({
queryKey: ['widgets'],
queryFn: async () => {
const dbWidgets = await ark.getWidgets();
const defaultWidgets = [
{
id: '9998',
title: 'Notification',
content: '',
kind: WIDGET_KIND.notification,
},
{
id: '9999',
title: 'Newsfeed',
content: '',
kind: WIDGET_KIND.newsfeed,
},
];
return [...defaultWidgets, ...dbWidgets];
},
refetchOnMount: false,
refetchOnReconnect: false,
refetchOnWindowFocus: false,
staleTime: Infinity,
});
const renderItem = (widget: WidgetProps) => {
switch (widget.kind) {
case WIDGET_KIND.notification:
return <NotificationWidget key={widget.id} />;
case WIDGET_KIND.newsfeed:
return <NewsfeedWidget key={widget.id} />;
case WIDGET_KIND.topic:
return <TopicWidget key={widget.id} props={widget} />;
case WIDGET_KIND.user:
return <UserWidget key={widget.id} props={widget} />;
case WIDGET_KIND.thread:
return <ThreadWidget key={widget.id} props={widget} />;
case WIDGET_KIND.article:
return <ArticleWidget key={widget.id} props={widget} />;
case WIDGET_KIND.file:
return <FileWidget key={widget.id} props={widget} />;
case WIDGET_KIND.hashtag:
return <HashtagWidget key={widget.id} props={widget} />;
case WIDGET_KIND.group:
return <GroupWidget key={widget.id} props={widget} />;
case WIDGET_KIND.trendingNotes:
return <TrendingNotesWidget key={widget.id} props={widget} />;
case WIDGET_KIND.trendingAccounts:
return <TrendingAccountsWidget key={widget.id} props={widget} />;
case WIDGET_KIND.list:
return <WidgetList key={widget.id} props={widget} />;
default:
return <NewsfeedWidget key={widget.id} />;
}
};
if (isLoading) {
return (
<div className="flex h-full w-full items-center justify-center">
<LoaderIcon className="h-5 w-5 animate-spin" />
</div>
);
}
return (
<div className="h-full w-full">
<VList
ref={ref}
className="h-full w-full flex-nowrap overflow-x-auto !overflow-y-hidden scrollbar-none focus:outline-none"
initialItemSize={420}
tabIndex={0}
horizontal
onKeyDown={(e) => {
if (!ref.current) return;
switch (e.code) {
case 'ArrowUp':
case 'ArrowLeft': {
e.preventDefault();
const prevIndex = Math.max(index.peek() - 1, 0);
index.value = prevIndex;
ref.current.scrollToIndex(prevIndex, {
align: 'center',
smooth: true,
});
break;
}
case 'ArrowDown':
case 'ArrowRight': {
e.preventDefault();
const nextIndex = Math.min(index.peek() + 1, data.length - 1);
index.value = nextIndex;
ref.current.scrollToIndex(nextIndex, {
align: 'center',
smooth: true,
});
break;
}
default:
break;
}
}}
>
{data.map((widget) => renderItem(widget))}
<ToggleWidgetList />
</VList>
</div>
);
}