원클릭으로
nostr-infinite-scroll
Build feed interfaces, implement pagination for Nostr events, or create social media-style infinite scroll experiences.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Build feed interfaces, implement pagination for Nostr events, or create social media-style infinite scroll experiences.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Ditto's release and publishing pipeline — cutting a version tag, Zapstore APK publishing with NIP-46 bunker auth, nsite web deploys via nsyte, and Google Play AAB uploads via fastlane supply. Includes GitLab CI variable setup and credential rotation.
Operate the self-hosted GitLab Runner on the Mac that builds Ditto's iOS IPA. Covers SSH access, restarting the runner, viewing logs, updating Xcode, debugging fastlane locally, and rotating match certificates.
Publish a new app release with versioning, changelog, native build files, and git tagging. Triggered by "publish a new release" or similar requests.
Decide whether to reuse an existing NIP or mint a new kind, design tag structures that relays can index, choose what goes in content vs. tags, and document new kinds or extensions in NIP.md. Load when authoring a new schema — not when wiring up rendering for a kind that already exists (use nostr-kind-rendering for that).
Add UI rendering for an event kind Ditto doesn't yet display — feed cards, detail pages, embedded previews, notifications, routes, feed-toggle registration, and the several kind-label maps (KIND_LABELS, KIND_HEADER_MAP, NOTIFICATION_KIND_NOUNS, CommentContext) that must stay in sync. Load when asked to "support / display / render" a NIP or kind number, when a kind renders blank or as "Kind 12345", or when quote embeds of a kind show "This event kind is not supported".
Browser-API gotchas inside Capacitor's WKWebView (iOS) and Android WebView — which common web APIs silently fail, the downloadTextFile/openUrl helpers that bridge web and native, platform detection, and the installed Capacitor plugins. Load when writing code that interacts with file downloads, external URLs, or platform-specific behavior.
| name | nostr-infinite-scroll |
| description | Build feed interfaces, implement pagination for Nostr events, or create social media-style infinite scroll experiences. |
For feed-like interfaces, implement infinite scroll using TanStack Query's useInfiniteQuery with Nostr's timestamp-based pagination:
import { useNostr } from '@nostrify/react';
import { useInfiniteQuery } from '@tanstack/react-query';
export function useGlobalFeed() {
const { nostr } = useNostr();
return useInfiniteQuery({
queryKey: ['global-feed'],
queryFn: async ({ pageParam, signal }) => {
const filter = { kinds: [1], limit: 20 };
if (pageParam) filter.until = pageParam;
const events = await nostr.query([filter], {
signal: AbortSignal.any([signal, AbortSignal.timeout(1500)])
});
return events;
},
getNextPageParam: (lastPage) => {
if (lastPage.length === 0) return undefined;
return lastPage[lastPage.length - 1].created_at - 1; // Subtract 1 since 'until' is inclusive
},
initialPageParam: undefined,
});
}
Example usage with intersection observer for automatic loading:
import { useInView } from 'react-intersection-observer';
import { useMemo } from 'react';
function GlobalFeed() {
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useGlobalFeed();
const { ref, inView } = useInView();
useEffect(() => {
if (inView && hasNextPage && !isFetchingNextPage) {
fetchNextPage();
}
}, [inView, hasNextPage, isFetchingNextPage, fetchNextPage]);
// Remove duplicate events by ID
const posts = useMemo(() => {
const seen = new Set();
return data?.pages.flat().filter(event => {
if (!event.id || seen.has(event.id)) return false;
seen.add(event.id);
return true;
}) || [];
}, [data?.pages]);
return (
<div className="space-y-4">
{posts.map((post) => (
<PostCard key={post.id} post={post} />
))}
{hasNextPage && (
<div ref={ref} className="py-4">
{isFetchingNextPage && <Skeleton className="h-20 w-full" />}
</div>
)}
</div>
);
}