[wip] added channel explore page

This commit is contained in:
Ren Amamiya 2023-04-19 15:24:52 +07:00
parent dd0c794ebc
commit e6b6ab38e0
6 changed files with 119 additions and 46 deletions

View File

@ -0,0 +1,67 @@
'use client';
import { BrowseChannelItem } from '@components/channels/browseChannelItem';
import { getChannels } from '@utils/storage';
import { Suspense, useCallback, useEffect, useRef, useState } from 'react';
import { VirtuosoGrid } from 'react-virtuoso';
export default function Page() {
const [data, setData] = useState([]);
const virtuosoRef = useRef(null);
const limit = useRef(20);
const offset = useRef(0);
const itemContent: any = useCallback(
(index: string | number) => {
return <BrowseChannelItem key={data[index].event_id} data={data[index]} />;
},
[data]
);
const computeItemKey = useCallback(
(index: string | number) => {
return data[index].event_id;
},
[data]
);
const initialData = useCallback(async () => {
const result: any = await getChannels(limit.current, offset.current);
console.log(result);
setData((data) => [...data, ...result]);
}, [setData]);
const loadMore = useCallback(async () => {
offset.current += limit.current;
// query next page
const result: any = await getChannels(limit.current, offset.current);
setData((data) => [...data, ...result]);
}, [setData]);
useEffect(() => {
initialData().catch(console.error);
}, [initialData]);
return (
<div className="h-full w-full">
<div className="mx-auto h-full w-full max-w-2xl px-4">
<Suspense fallback={<>Loading...</>}>
<VirtuosoGrid
ref={virtuosoRef}
data={data}
itemContent={itemContent}
itemClassName="col-span-1"
listClassName="grid grid-cols-2 gap-4"
computeItemKey={computeItemKey}
overscan={200}
endReached={loadMore}
className="scrollbar-hide h-full w-full overflow-y-auto overflow-x-hidden"
/>
</Suspense>
</div>
</div>
);
}

View File

@ -0,0 +1,23 @@
import AppHeader from '@components/appHeader';
import MultiAccounts from '@components/multiAccounts';
export default function NostrLayout({ children }: { children: React.ReactNode }) {
return (
<div className="h-screen w-screen bg-zinc-50 text-zinc-900 dark:bg-black dark:text-white">
<div className="flex h-screen w-full flex-col">
<div
data-tauri-drag-region
className="relative h-11 shrink-0 border-b border-zinc-100 bg-white dark:border-zinc-900 dark:bg-black"
>
<AppHeader collector={true} />
</div>
<div className="relative flex min-h-0 w-full flex-1">
<div className="relative w-[68px] shrink-0 border-r border-zinc-900">
<MultiAccounts />
</div>
<div className="w-full">{children}</div>
</div>
</div>
</div>
);
}

View File

@ -1,25 +0,0 @@
'use client';
import { BrowseChannelItem } from '@components/channels/browseChannelItem';
import { getChannels } from '@utils/storage';
import { useEffect, useState } from 'react';
export default function Page() {
const [list, setList] = useState([]);
useEffect(() => {
getChannels(100, 0)
.then((res) => setList(res))
.catch(console.error);
}, []);
return (
<div className="h-full w-full overflow-y-auto">
{list.map((channel) => (
<BrowseChannelItem key={channel.id} data={channel} />
))}
</div>
);
}

View File

@ -1,6 +1,6 @@
import { ImageWithFallback } from '@components/imageWithFallback';
import { DEFAULT_AVATAR } from '@stores/constants';
import { DEFAULT_AVATAR, DEFAULT_CHANNEL_BANNER } from '@stores/constants';
import { useChannelMetadata } from '@utils/hooks/useChannelMetadata';
@ -19,26 +19,32 @@ export const BrowseChannelItem = ({ data }: { data: any }) => {
);
return (
<div
onClick={() => openChannel(data.event_id)}
className="group relative flex items-center gap-2 border-b border-zinc-800 px-3 py-2.5 hover:bg-black/20"
>
<div className="relative h-11 w-11 shrink overflow-hidden rounded-md border border-white/10">
<ImageWithFallback
src={channel?.picture || DEFAULT_AVATAR}
alt={data.id}
fill={true}
className="rounded-md object-cover"
/>
<div className="h-64 w-full rounded-md bg-zinc-900">
<div className="relative h-24">
<div className="h-24 w-full rounded-t-md bg-zinc-800">
<ImageWithFallback
src={channel?.banner || DEFAULT_CHANNEL_BANNER}
alt={data.id}
fill={true}
className="h-full w-full rounded-t-md object-cover"
/>
</div>
<div className="relative -top-6 z-10 px-4">
<div className="relative h-11 w-11 rounded-md bg-white">
<ImageWithFallback
src={channel?.picture || DEFAULT_AVATAR}
alt={data.id}
fill={true}
className="rounded-md object-cover ring-1 ring-black/50"
/>
</div>
</div>
</div>
<div className="flex w-full flex-1 flex-col items-start text-start">
<span className="truncate font-medium leading-tight text-zinc-200">{channel?.name}</span>
<span className="text-sm leading-tight text-zinc-400">{channel?.about}</span>
</div>
<div className="absolute right-2 top-1/2 hidden -translate-y-1/2 transform group-hover:inline-flex">
<button className="inline-flex h-8 w-16 items-center justify-center rounded-md bg-fuchsia-500 px-4 text-sm font-medium shadow-button hover:bg-fuchsia-600 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50">
Join
</button>
<div className="mt-7 px-4">
<div className="flex flex-col">
<h3 className="w-full truncate font-semibold leading-tight text-zinc-100">{channel?.name}</h3>
</div>
<div className="line-clamp-3 text-sm text-zinc-400">{channel?.about}</div>
</div>
</div>
);

View File

@ -11,7 +11,7 @@ export default function ChannelList() {
return (
<div className="flex flex-col gap-px">
<Link
href="/nostr/channels"
href="/explore/channels"
className="group inline-flex items-center gap-2 rounded-md px-2.5 py-1.5 hover:bg-zinc-900"
>
<div className="inline-flex h-5 w-5 shrink items-center justify-center rounded bg-zinc-900 group-hover:bg-zinc-800">

View File

@ -1,2 +1,4 @@
export const APP_VERSION = '0.2.5';
export const DEFAULT_AVATAR = 'https://void.cat/d/KmypFh2fBdYCEvyJrPiN89.webp';
export const DEFAULT_CHANNEL_BANNER =
'https://bafybeiacwit7hjmdefqggxqtgh6ht5dhth7ndptwn2msl5kpkodudsr7py.ipfs.w3s.link/banner-1.jpg';