Add collapsible components and feed filter functionality

- Introduced Collapsible, CollapsibleContent, and CollapsibleTrigger components for improved UI interactions.
- Added FeedFilters component to allow users to customize content visibility in the NostrFeed.
- Updated NostrFeed and Home components to integrate new filtering capabilities, enhancing user experience with customizable content display.
- Implemented content filter logic in FeedService to support dynamic filtering based on user selections.

These changes enhance the modularity and interactivity of the feed system, providing users with greater control over the content they see.
This commit is contained in:
padreug 2025-09-16 21:58:24 +02:00
parent a5e6c301e1
commit e90c4992da
10 changed files with 574 additions and 24 deletions

View file

@ -15,10 +15,20 @@ export interface FeedPost {
replyTo?: string
}
export interface ContentFilter {
id: string
label: string
kinds: number[]
description: string
requiresAuth?: boolean
filterByAuthor?: 'admin' | 'exclude-admin' | 'none'
}
export interface FeedConfig {
feedType: 'announcements' | 'general' | 'mentions' | 'events' | 'all'
feedType: 'announcements' | 'general' | 'mentions' | 'events' | 'all' | 'custom'
maxPosts?: number
adminPubkeys?: string[]
contentFilters?: ContentFilter[]
}
export class FeedService extends BaseService {
@ -109,29 +119,55 @@ export class FeedService extends BaseService {
// Create subscription ID
const subscriptionId = `feed-service-${config.feedType}-${Date.now()}`
// Create filter
const filter: Filter = {
kinds: [1], // Text notes
limit: config.maxPosts || 50
}
// Create filters based on feed type and content filters
const filters: Filter[] = []
if (config.feedType === 'announcements') {
if (config.adminPubkeys && config.adminPubkeys.length > 0) {
filter.authors = config.adminPubkeys
} else {
// No admin pubkeys configured for announcements - don't subscribe
console.log('No admin pubkeys configured for announcements feed')
this._isLoading.value = false
return
if (config.feedType === 'custom' && config.contentFilters) {
// Use custom content filters
for (const contentFilter of config.contentFilters) {
const filter: Filter = {
kinds: contentFilter.kinds,
limit: Math.floor((config.maxPosts || 50) / config.contentFilters.length)
}
// Apply author filtering if specified
if (contentFilter.filterByAuthor === 'admin' && config.adminPubkeys?.length) {
filter.authors = config.adminPubkeys
} else if (contentFilter.filterByAuthor === 'exclude-admin' && config.adminPubkeys?.length) {
// Note: Nostr doesn't support negative filters natively,
// we'll filter these out in post-processing
}
filters.push(filter)
}
} else {
// Use legacy feed types
const filter: Filter = {
kinds: [1], // Text notes by default
limit: config.maxPosts || 50
}
// Handle legacy feed types
if (config.feedType === 'announcements') {
if (config.adminPubkeys && config.adminPubkeys.length > 0) {
filter.authors = config.adminPubkeys
} else {
// No admin pubkeys configured for announcements - don't subscribe
console.log('No admin pubkeys configured for announcements feed')
this._isLoading.value = false
return
}
}
filters.push(filter)
}
console.log(`Creating feed subscription for ${config.feedType} with filter:`, filter)
console.log(`Creating feed subscription for ${config.feedType} with filters:`, filters)
// Subscribe to events with deduplication
const unsubscribe = this.relayHub.subscribe({
id: subscriptionId,
filters: [filter],
filters: filters,
onEvent: (event: NostrEvent) => {
this.handleNewEvent(event, config)
},
@ -223,6 +259,26 @@ export class FeedService extends BaseService {
private shouldIncludeEvent(event: NostrEvent, config: FeedConfig): boolean {
const isAdminPost = config.adminPubkeys?.includes(event.pubkey) || false
// For custom content filters, check if event matches any active filter
if (config.feedType === 'custom' && config.contentFilters) {
return config.contentFilters.some(filter => {
// Check if event kind matches
if (!filter.kinds.includes(event.kind)) {
return false
}
// Apply author filtering
if (filter.filterByAuthor === 'admin') {
return isAdminPost
} else if (filter.filterByAuthor === 'exclude-admin') {
return !isAdminPost
}
return true
})
}
// Legacy feed type handling
switch (config.feedType) {
case 'announcements':
return isAdminPost