mirror of
https://github.com/hoornet/vega.git
synced 2026-05-11 06:39:10 -07:00
Add follows view with followers/following tabs and new follower badges
Followers tab fetches kind 3 events referencing the user, following tab shows the contact list. Each row has avatar, NIP-05 badge, follow/unfollow button, and "follows you" indicator. New follower notifications from the background poller increment a sidebar badge that clears on view open.
This commit is contained in:
@@ -14,6 +14,7 @@ interface NotificationsState {
|
||||
currentPubkey: string | null;
|
||||
dmLastSeen: Record<string, number>;
|
||||
dmUnreadCount: number;
|
||||
newFollowersCount: number;
|
||||
|
||||
fetchNotifications: (pubkey: string) => Promise<void>;
|
||||
markRead: (eventId: string) => void;
|
||||
@@ -21,6 +22,8 @@ interface NotificationsState {
|
||||
isRead: (eventId: string) => boolean;
|
||||
markDMRead: (partnerPubkey: string) => void;
|
||||
computeDMUnread: (conversations: Array<{ partnerPubkey: string; lastAt: number }>) => void;
|
||||
incrementNewFollowers: () => void;
|
||||
clearNewFollowers: () => void;
|
||||
}
|
||||
|
||||
function loadReadIds(): Set<string> {
|
||||
@@ -54,6 +57,7 @@ export const useNotificationsStore = create<NotificationsState>((set, get) => ({
|
||||
currentPubkey: null,
|
||||
dmLastSeen: loadDMLastSeen(),
|
||||
dmUnreadCount: 0,
|
||||
newFollowersCount: 0,
|
||||
|
||||
fetchNotifications: async (pubkey: string) => {
|
||||
const state = get();
|
||||
@@ -120,4 +124,7 @@ export const useNotificationsStore = create<NotificationsState>((set, get) => ({
|
||||
const dmUnreadCount = unreadConvos.length;
|
||||
set({ dmUnreadCount });
|
||||
},
|
||||
|
||||
incrementNewFollowers: () => set((s) => ({ newFollowersCount: s.newFollowersCount + 1 })),
|
||||
clearNewFollowers: () => set({ newFollowersCount: 0 }),
|
||||
}));
|
||||
|
||||
@@ -2,7 +2,7 @@ import { create } from "zustand";
|
||||
|
||||
import { NDKEvent } from "@nostr-dev-kit/ndk";
|
||||
|
||||
type View = "feed" | "search" | "relays" | "settings" | "profile" | "thread" | "article-editor" | "article" | "articles" | "media" | "podcasts" | "about" | "zaps" | "dm" | "notifications" | "bookmarks" | "hashtag";
|
||||
type View = "feed" | "search" | "relays" | "settings" | "profile" | "thread" | "article-editor" | "article" | "articles" | "media" | "podcasts" | "about" | "zaps" | "dm" | "notifications" | "bookmarks" | "hashtag" | "follows";
|
||||
type FeedTab = "global" | "following" | "trending";
|
||||
|
||||
interface ViewStackEntry {
|
||||
@@ -29,9 +29,11 @@ interface UIState {
|
||||
showHelp: boolean;
|
||||
showDebugPanel: boolean;
|
||||
feedLanguageFilter: string | null;
|
||||
followsTab: "followers" | "following";
|
||||
fontSize: number;
|
||||
themeId: string;
|
||||
setView: (view: View) => void;
|
||||
setFollowsTab: (tab: "followers" | "following") => void;
|
||||
setFeedTab: (tab: FeedTab) => void;
|
||||
openProfile: (pubkey: string) => void;
|
||||
openThread: (note: NDKEvent, from?: View) => void;
|
||||
@@ -68,10 +70,12 @@ export const useUIStore = create<UIState>((set, _get) => ({
|
||||
showHelp: false,
|
||||
showDebugPanel: false,
|
||||
feedLanguageFilter: null,
|
||||
followsTab: "followers",
|
||||
fontSize: parseInt(localStorage.getItem(FONT_SIZE_KEY) || "14", 10),
|
||||
themeId: localStorage.getItem(THEME_KEY) || "midnight",
|
||||
setView: (currentView) => set({ currentView }),
|
||||
setFeedTab: (feedTab) => set({ feedTab }),
|
||||
setFollowsTab: (followsTab) => set({ followsTab }),
|
||||
openProfile: (pubkey) => set((s) => {
|
||||
const stack = [...s.viewStack, { view: s.currentView, selectedNote: s.selectedNote, selectedPubkey: s.selectedPubkey }].slice(-MAX_STACK);
|
||||
return { currentView: "profile", selectedPubkey: pubkey, previousView: s.currentView as View, viewStack: stack };
|
||||
|
||||
Reference in New Issue
Block a user