Feature: Load more (#28)

* load more button on global feed

* load more button on follower feed

* load more button on follower feed

* load more button on profile feed

* only show first 20 instead of 100 images in profile quick view feed

* load more button on profile text feed
This commit is contained in:
mroxso
2025-01-19 17:55:28 +01:00
committed by GitHub
parent 0520dbb7ec
commit 226da74232
6 changed files with 158 additions and 92 deletions

View File

@@ -1,8 +1,8 @@
import { useRef } from "react";
import { useRef, useState } from "react";
import { useNostrEvents, dateToUnix } from "nostr-react";
import NoteCard from './NoteCard';
import KIND20Card from "./KIND20Card";
import { getImageUrl } from "@/utils/utils";
import { Button } from "@/components/ui/button";
interface FollowerFeedProps {
pubkey: string;
@@ -10,6 +10,7 @@ interface FollowerFeedProps {
const FollowerFeed: React.FC<FollowerFeedProps> = ({ pubkey }) => {
const now = useRef(new Date());
const [limit, setLimit] = useState(20);
const { events: following, isLoading: followingLoading } = useNostrEvents({
filter: {
@@ -21,31 +22,42 @@ const FollowerFeed: React.FC<FollowerFeedProps> = ({ pubkey }) => {
let followingPubkeys = following.flatMap((event) => event.tags.map(tag => tag[1])).slice(0, 500);
const { events } = useNostrEvents({
const { events, isLoading } = useNostrEvents({
filter: {
limit: 20,
limit: limit,
kinds: [20],
authors: followingPubkeys,
},
});
const loadMore = () => {
setLimit(prevLimit => prevLimit + 20);
};
return (
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 px-2 md:px-4">
{events.map((event) => (
<div key={event.id} className="mb-4 md:mb-6">
<KIND20Card
key={event.id}
pubkey={event.pubkey}
text={event.content}
image={getImageUrl(event.tags)}
eventId={event.id}
tags={event.tags}
event={event}
showViewNoteCardButton={true}
/>
<>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 px-2 md:px-4">
{events.map((event) => (
<div key={event.id} className="mb-4 md:mb-6">
<KIND20Card
key={event.id}
pubkey={event.pubkey}
text={event.content}
image={getImageUrl(event.tags)}
eventId={event.id}
tags={event.tags}
event={event}
showViewNoteCardButton={true}
/>
</div>
))}
</div>
{!isLoading && (
<div className="flex justify-center p-4">
<Button className="w-full md:w-auto" onClick={loadMore}>Load More</Button>
</div>
))}
</div>
)}
</>
);
}

View File

@@ -1,6 +1,7 @@
import { useRef } from "react";
import { useRef, useState } from "react";
import { useNostrEvents, dateToUnix } from "nostr-react";
import { Skeleton } from "@/components/ui/skeleton";
import { Button } from "@/components/ui/button";
import QuickViewNoteCard from "./QuickViewNoteCard";
import QuickViewKind20NoteCard from "./QuickViewKind20NoteCard";
import { getImageUrl } from "@/utils/utils";
@@ -11,6 +12,7 @@ interface FollowerQuickViewFeedProps {
const FollowerQuickViewFeed: React.FC<FollowerQuickViewFeedProps> = ({ pubkey }) => {
const now = useRef(new Date()); // Make sure current time isn't re-rendered
const [limit, setLimit] = useState(25);
const { events: following, isLoading: followingLoading } = useNostrEvents({
filter: {
@@ -19,51 +21,65 @@ const FollowerQuickViewFeed: React.FC<FollowerQuickViewFeedProps> = ({ pubkey })
limit: 1,
},
});
// let followingPubkeys = following.map((event) => event.tags[event.tags.length - 1][1]);
// let followingPubkeys = following.flatMap((event) => event.tags.map(tag => tag[1])).slice(0, 50);
let followingPubkeys = following.flatMap((event) => event.tags.map(tag => tag[1])).slice(0, 500);
const { events } = useNostrEvents({
const { events, isLoading } = useNostrEvents({
filter: {
// since: dateToUnix(now.current), // all new events from now
// since: 0,
limit: 25,
limit: limit,
kinds: [20],
authors: followingPubkeys,
},
});
const loadMore = () => {
setLimit(prevLimit => prevLimit + 25);
};
return (
<>
<div className="grid grid-cols-3 gap-2">
{events.length === 0 ? (
{events.length === 0 && isLoading ? (
<>
<div>
<Skeleton className="h-[125px] rounded-xl" />
<div className="space-y-2 py-2">
<Skeleton className="h-4 w-1/3" />
<Skeleton className="h-4 w-1/3" />
<div>
<Skeleton className="h-[33vh] rounded-xl" />
</div>
</div>
<div>
<Skeleton className="h-[125px] rounded-xl" />
<div className="space-y-2 py-2">
<Skeleton className="h-4 w-1/3" />
<Skeleton className="h-4 w-1/3" />
<div>
<Skeleton className="h-[33vh] rounded-xl" />
</div>
</div>
<div>
<Skeleton className="h-[125px] rounded-xl" />
<div className="space-y-2 py-2">
<Skeleton className="h-4 w-1/3" />
<Skeleton className="h-4 w-1/3" />
<div>
<Skeleton className="h-[33vh] rounded-xl" />
</div>
<div>
<Skeleton className="h-[33vh] rounded-xl" />
</div>
<div>
<Skeleton className="h-[33vh] rounded-xl" />
</div>
<div>
<Skeleton className="h-[33vh] rounded-xl" />
</div>
</div>
</>
) : (events.map((event) => (
<QuickViewKind20NoteCard key={event.id} pubkey={event.pubkey} text={event.content} image={getImageUrl(event.tags)} event={event} tags={event.tags} eventId={event.id} linkToNote={true} />
)))}
) : (
events.map((event) => (
<QuickViewKind20NoteCard
key={event.id}
pubkey={event.pubkey}
text={event.content}
image={getImageUrl(event.tags)}
event={event}
tags={event.tags}
eventId={event.id}
linkToNote={true}
/>
))
)}
</div>
{!isLoading && (
<div className="flex justify-center p-4">
<Button className="w-full md:w-auto" onClick={loadMore}>Load More</Button>
</div>
)}
</>
);
}

View File

@@ -1,16 +1,24 @@
import { useNostrEvents } from "nostr-react";
import KIND20Card from "./KIND20Card";
import { getImageUrl } from "@/utils/utils";
import QuickViewKind20NoteCard from "./QuickViewKind20NoteCard";
import { useState, useRef } from "react";
import { Button } from "@/components/ui/button";
const GlobalFeed: React.FC = () => {
const { events } = useNostrEvents({
const now = useRef(new Date());
const [limit, setLimit] = useState(20);
const { events, isLoading } = useNostrEvents({
filter: {
limit: 20,
limit: limit,
kinds: [20],
},
});
const loadMore = () => {
setLimit(prevLimit => prevLimit + 20);
};
return (
<>
<h2 className="text-2xl font-bold mb-4 px-2 md:px-4">Global Feed</h2>
@@ -29,20 +37,15 @@ const GlobalFeed: React.FC = () => {
event={event}
showViewNoteCardButton={true}
/>
{/* <QuickViewKind20NoteCard
key={event.id}
pubkey={event.pubkey}
text={event.content}
image={imageUrl}
eventId={event.id}
tags={event.tags}
event={event}
linkToNote={true}
/> */}
</div>
);
})}
</div>
{!isLoading && (
<div className="flex justify-center p-4">
<Button className="w-full md:w-auto" onClick={loadMore}>Load More</Button>
</div>
)}
</>
);
}

View File

@@ -1,7 +1,8 @@
import { useRef } from "react";
import { useRef, useState } from "react";
import { useNostrEvents, dateToUnix } from "nostr-react";
import NoteCard from '@/components/NoteCard';
import { Skeleton } from "@/components/ui/skeleton";
import { Button } from "@/components/ui/button";
import KIND20Card from "./KIND20Card";
import { getImageUrl } from "@/utils/utils";
@@ -10,23 +11,24 @@ interface ProfileFeedProps {
}
const ProfileFeed: React.FC<ProfileFeedProps> = ({ pubkey }) => {
const now = useRef(new Date()); // Make sure current time isn't re-rendered
const now = useRef(new Date());
const [limit, setLimit] = useState(10);
const { events } = useNostrEvents({
const { events, isLoading } = useNostrEvents({
filter: {
// since: dateToUnix(now.current), // all new events from now
authors: [pubkey],
// since: 0,
// limit: 10,
kinds: [20],
limit: limit,
},
});
const loadMore = () => {
setLimit(prevLimit => prevLimit + 10);
};
return (
<>
{/* <h2>Profile Feed</h2> */}
{events.length === 0 ? (
{events.length === 0 && isLoading ? (
<div className="flex flex-col space-y-3">
<Skeleton className="h-[125px] rounded-xl" />
<div className="space-y-2">
@@ -34,13 +36,29 @@ const ProfileFeed: React.FC<ProfileFeedProps> = ({ pubkey }) => {
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
) : (events.map((event) => (
// <p key={event.id}>{event.pubkey} posted: {event.content}</p>
// <ProfileNoteCard key={event.id} pubkey={event.pubkey} text={event.content} event={event} tags={event.tags} />
<div key={event.id} className="py-6">
<KIND20Card key={event.id} pubkey={event.pubkey} text={event.content} image={getImageUrl(event.tags)} event={event} tags={event.tags} eventId={event.id} showViewNoteCardButton={true}/>
</div>
)))}
) : (
<>
{events.map((event) => (
<div key={event.id} className="py-6">
<KIND20Card
key={event.id}
pubkey={event.pubkey}
text={event.content}
image={getImageUrl(event.tags)}
event={event}
tags={event.tags}
eventId={event.id}
showViewNoteCardButton={true}
/>
</div>
))}
{!isLoading && (
<div className="flex justify-center p-4">
<Button className="w-full md:w-auto" onClick={loadMore}>Load More</Button>
</div>
)}
</>
)}
</>
);
}

View File

@@ -11,7 +11,7 @@ interface ProfileQuickViewFeedProps {
const ProfileQuickViewFeed: React.FC<ProfileQuickViewFeedProps> = ({ pubkey }) => {
const now = useRef(new Date()); // Make sure current time isn't re-rendered
const [limit, setLimit] = useState(100);
const [limit, setLimit] = useState(20);
const { isLoading, events } = useNostrEvents({
filter: {

View File

@@ -1,22 +1,22 @@
import { useRef } from "react";
import { useRef, useState } from "react";
import { useNostrEvents, dateToUnix } from "nostr-react";
import NoteCard from '@/components/NoteCard';
import { Skeleton } from "@/components/ui/skeleton";
import { Button } from "@/components/ui/button";
interface ProfileTextFeedProps {
pubkey: string;
}
const ProfileTextFeed: React.FC<ProfileTextFeedProps> = ({ pubkey }) => {
const now = useRef(new Date()); // Make sure current time isn't re-rendered
const now = useRef(new Date());
const [limit, setLimit] = useState(10);
const { events, isLoading } = useNostrEvents({
filter: {
// since: dateToUnix(now.current), // all new events from now
authors: [pubkey],
// since: 0,
// limit: 10,
kinds: [1],
limit: limit,
},
});
@@ -25,10 +25,12 @@ const ProfileTextFeed: React.FC<ProfileTextFeedProps> = ({ pubkey }) => {
// filter out all replies (tag[0] == e)
filteredEvents = filteredEvents.filter((event) => !event.tags.some((tag) => { return tag[0] == 'e' }));
const loadMore = () => {
setLimit(prevLimit => prevLimit + 10);
};
return (
<>
{/* <h2>Profile Feed</h2> */}
{filteredEvents.length === 0 && isLoading ? (
<div className="flex flex-col space-y-3">
<Skeleton className="h-[125px] rounded-xl" />
@@ -37,13 +39,28 @@ const ProfileTextFeed: React.FC<ProfileTextFeedProps> = ({ pubkey }) => {
<Skeleton className="h-4 w-[200px]" />
</div>
</div>
) : (filteredEvents.map((event) => (
// <p key={event.id}>{event.pubkey} posted: {event.content}</p>
// <ProfileNoteCard key={event.id} pubkey={event.pubkey} text={event.content} event={event} tags={event.tags} />
<div key={event.id} className="py-6">
<NoteCard key={event.id} pubkey={event.pubkey} text={event.content} event={event} tags={event.tags} eventId={event.id} showViewNoteCardButton={true} />
</div>
)))}
) : (
<>
{filteredEvents.map((event) => (
<div key={event.id} className="py-6">
<NoteCard
key={event.id}
pubkey={event.pubkey}
text={event.content}
event={event}
tags={event.tags}
eventId={event.id}
showViewNoteCardButton={true}
/>
</div>
))}
{!isLoading && filteredEvents.length > 0 && (
<div className="flex justify-center p-4">
<Button className="w-full md:w-auto" onClick={loadMore}>Load More</Button>
</div>
)}
</>
)}
</>
);
}