Files
lume/src/app/home/index.tsx
2023-11-30 17:24:07 +07:00

140 lines
4.0 KiB
TypeScript

import { useQuery } from '@tanstack/react-query';
import { useCallback, useRef, useState } from 'react';
import { VList, VListHandle } from 'virtua';
import { useStorage } from '@libs/storage/provider';
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 { Widget } from '@utils/types';
export function HomeScreen() {
const ref = useRef<VListHandle>(null);
const [selectedIndex, setSelectedIndex] = useState(-1);
const { db } = useStorage();
const { status, data } = useQuery({
queryKey: ['widgets'],
queryFn: async () => {
const dbWidgets = await db.getWidgets();
const defaultWidgets = [
{
id: '9999',
title: 'Newsfeed',
content: '',
kind: WIDGET_KIND.newsfeed,
},
{
id: '9998',
title: 'Notification',
content: '',
kind: WIDGET_KIND.notification,
},
];
return [...defaultWidgets, ...dbWidgets];
},
refetchOnMount: false,
refetchOnReconnect: false,
refetchOnWindowFocus: false,
staleTime: Infinity,
});
const renderItem = useCallback((widget: Widget) => {
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} widget={widget} />;
case WIDGET_KIND.user:
return <UserWidget key={widget.id} widget={widget} />;
case WIDGET_KIND.thread:
return <ThreadWidget key={widget.id} widget={widget} />;
case WIDGET_KIND.article:
return <ArticleWidget key={widget.id} widget={widget} />;
case WIDGET_KIND.file:
return <FileWidget key={widget.id} widget={widget} />;
case WIDGET_KIND.hashtag:
return <HashtagWidget key={widget.id} widget={widget} />;
case WIDGET_KIND.group:
return <GroupWidget key={widget.id} widget={widget} />;
case WIDGET_KIND.trendingNotes:
return <TrendingNotesWidget key={widget.id} widget={widget} />;
case WIDGET_KIND.trendingAccounts:
return <TrendingAccountsWidget key={widget.id} widget={widget} />;
case WIDGET_KIND.list:
return <WidgetList key={widget.id} widget={widget} />;
default:
return null;
}
}, []);
if (status === 'pending') {
return (
<div className="flex h-full w-full items-center justify-center bg-white dark:bg-black">
<LoaderIcon className="h-5 w-5 animate-spin" />
</div>
);
}
return (
<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(selectedIndex - 1, 0);
setSelectedIndex(prevIndex);
ref.current.scrollToIndex(prevIndex, {
align: 'center',
smooth: true,
});
break;
}
case 'ArrowDown':
case 'ArrowRight': {
e.preventDefault();
const nextIndex = Math.min(selectedIndex + 1, data.length - 1);
setSelectedIndex(nextIndex);
ref.current.scrollToIndex(nextIndex, {
align: 'center',
smooth: true,
});
break;
}
default:
break;
}
}}
>
{data.map((widget) => renderItem(widget))}
<ToggleWidgetList />
</VList>
);
}