Add NIP-05 badges, hashtag pages, keyword muting, suggestion dismissal, notification poller

- Article cover: aspect-video replaces max-h-72 for consistent 16:9
- NIP-05 verification badge on note cards with 1-hour TTL cache
- Dedicated hashtag feed pages (clicking #tag opens live feed, not search)
- Keyword muting: word-boundary matching, applied across all feed views
- Follow suggestion dismissal: persistent "don't suggest again" per person
- Background notification poller (60s): mentions, zaps, new followers
- All notification types independently toggleable in settings
- Centralized notification firing (removed inline store notifications)
This commit is contained in:
Jure
2026-03-20 12:09:11 +01:00
parent 989ed01dfc
commit 57630227e1
20 changed files with 499 additions and 35 deletions

View File

@@ -2,6 +2,7 @@ import { useEffect, useRef, useState } from "react";
import { NDKEvent } from "@nostr-dev-kit/ndk";
import { useUIStore } from "../../stores/ui";
import { useUserStore } from "../../stores/user";
import { useMuteStore } from "../../stores/mute";
import { useProfile } from "../../hooks/useProfile";
import { useReactionCount } from "../../hooks/useReactionCount";
import { useZapCount } from "../../hooks/useZapCount";
@@ -145,6 +146,7 @@ function RootNote({ event }: { event: NDKEvent }) {
export function ThreadView() {
const { selectedNote, goBack } = useUIStore();
const { loggedIn } = useUserStore();
const { mutedPubkeys, contentMatchesMutedKeyword } = useMuteStore();
if (!selectedNote) { goBack(); return null; }
const event = selectedNote;
@@ -239,7 +241,9 @@ export function ThreadView() {
</div>
)}
{replies.map((reply) => (
{replies
.filter((r) => !mutedPubkeys.includes(r.pubkey) && !contentMatchesMutedKeyword(r.content))
.map((reply) => (
<NoteCard key={reply.id} event={reply} />
))}
</div>