You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

215 lines
6.7 KiB

import BookmarkList from '@/components/BookmarkList'
import RelayInfo from '@/components/RelayInfo'
import VersionUpdateBanner from '@/components/VersionUpdateBanner'
import { Button } from '@/components/ui/button'
import PrimaryPageLayout from '@/layouts/PrimaryPageLayout'
import { useCurrentRelays } from '@/providers/CurrentRelaysProvider'
import { useFeed } from '@/providers/FeedProvider'
import { useNostr } from '@/providers/NostrProvider'
import { useScreenSize } from '@/providers/ScreenSizeProvider'
import { TPageRef } from '@/types'
import { Info, Rss } from 'lucide-react'
import React, {
Dispatch,
forwardRef,
SetStateAction,
useEffect,
useImperativeHandle,
useRef,
useState
} from 'react'
import { useTranslation } from 'react-i18next'
import FeedButton from './FeedButton'
import ExploreButton from '@/components/Titlebar/ExploreButton'
import AccountButton from '@/components/Titlebar/AccountButton'
import FollowingFeed from './FollowingFeed'
import RelaysFeed from './RelaysFeed'
import logger from '@/lib/logger'
import { usePrimaryPage, usePrimaryNoteView } from '@/PageManager'
import storage from '@/services/local-storage.service'
const NoteListPage = forwardRef((_, ref) => {
logger.debug('NoteListPage component rendering')
const { t } = useTranslation()
const { addRelayUrls, removeRelayUrls } = useCurrentRelays()
const layoutRef = useRef<TPageRef>(null)
const { pubkey, checkLogin } = useNostr()
const { feedInfo, relayUrls, isReady } = useFeed()
const [showRelayDetails, setShowRelayDetails] = useState(false)
const [homeSubHeader, setHomeSubHeader] = useState<React.ReactNode>(null)
useImperativeHandle(ref, () => layoutRef.current)
// Clear subHeader when switching away from relay/relays/all-favorites feed
useEffect(() => {
const isRelaysFeed =
feedInfo.feedType === 'relay' || feedInfo.feedType === 'relays' || feedInfo.feedType === 'all-favorites'
if (!isRelaysFeed) setHomeSubHeader(null)
}, [feedInfo.feedType])
// REMOVED: Scroll-to-top logic - feed should NEVER scroll to top when drawer opens/closes
// The feed stays mounted and maintains scroll position at all times
useEffect(() => {
if (relayUrls.length) {
addRelayUrls(relayUrls)
return () => {
removeRelayUrls(relayUrls)
}
}
}, [relayUrls])
// Debug logging
logger.debug('NoteListPage debug:', {
isReady,
feedInfo,
relayUrls,
pubkey: !!pubkey
})
let content: React.ReactNode = null
if (!isReady) {
content = <div className="text-center text-sm text-muted-foreground">{t('loading...')}</div>
} else if (feedInfo.feedType === 'following' && !pubkey) {
content = (
<div className="flex justify-center w-full">
<Button size="lg" onClick={() => checkLogin()}>
{t('Please login to view following feed')}
</Button>
</div>
)
} else if (feedInfo.feedType === 'bookmarks') {
if (!pubkey) {
content = (
<div className="flex justify-center w-full">
<Button size="lg" onClick={() => checkLogin()}>
{t('Please login to view bookmarks')}
</Button>
</div>
)
} else {
content = <BookmarkList />
}
} else if (feedInfo.feedType === 'following') {
content = <FollowingFeed />
} else {
content = (
<>
{showRelayDetails && feedInfo.feedType === 'relay' && !!feedInfo.id && (
<RelayInfo url={feedInfo.id!} className="mb-2 pt-3" />
)}
<RelaysFeed setSubHeader={setHomeSubHeader} />
</>
)
}
return (
<PrimaryPageLayout
pageName="home"
ref={layoutRef}
titlebar={
<NoteListPageTitlebar
layoutRef={layoutRef}
showRelayDetails={showRelayDetails}
setShowRelayDetails={
feedInfo.feedType === 'relay' && !!feedInfo.id ? setShowRelayDetails : undefined
}
/>
}
subHeader={homeSubHeader ?? undefined}
displayScrollToTopButton
>
<div className="min-w-0 pt-2">
<VersionUpdateBanner />
{content}
</div>
</PrimaryPageLayout>
)
})
NoteListPage.displayName = 'NoteListPage'
export default NoteListPage
function NoteListPageTitlebar({
layoutRef,
showRelayDetails,
setShowRelayDetails
}: {
layoutRef?: React.RefObject<TPageRef>
showRelayDetails?: boolean
setShowRelayDetails?: Dispatch<SetStateAction<boolean>>
}) {
const { isSmallScreen } = useScreenSize()
const { setPrimaryNoteView } = usePrimaryNoteView()
const { navigate, current } = usePrimaryPage()
const { primaryViewType } = usePrimaryNoteView()
const showRssFeed = storage.getShowRssFeed()
const handleRssClick = (e: React.MouseEvent) => {
e.stopPropagation()
// Navigate to home if not already there
if (current !== 'home' || primaryViewType !== null) {
navigate('home')
// Wait a bit for navigation to complete, then switch to RSS
setTimeout(() => {
window.dispatchEvent(new CustomEvent('switchToRssFeed'))
}, 100)
} else {
// Already on home, just switch to RSS tab
window.dispatchEvent(new CustomEvent('switchToRssFeed'))
}
}
return (
<div className="relative flex gap-1 items-center h-full justify-between">
<div className="flex gap-1 items-center">
<ExploreButton />
<FeedButton className="flex-1 max-w-fit w-0" />
</div>
{isSmallScreen && (
<div className="absolute left-1/2 transform -translate-x-1/2 z-10">
<button
className="text-green-600 dark:text-green-500 font-semibold text-sm hover:text-green-700 dark:hover:text-green-400 transition-colors cursor-pointer"
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
logger.debug('Im Wald button clicked, clearing overlay')
setPrimaryNoteView(null)
}}
>
Im Wald
</button>
</div>
)}
<div className="shrink-0 flex gap-1 items-center">
{isSmallScreen && showRssFeed && (
<Button
variant="ghost"
size="titlebar-icon"
onClick={handleRssClick}
title="RSS Feed"
>
<Rss />
</Button>
)}
{setShowRelayDetails && (
<Button
variant="ghost"
size="titlebar-icon"
onClick={(e) => {
e.stopPropagation()
setShowRelayDetails((show) => !show)
if (!showRelayDetails) {
layoutRef?.current?.scrollToTop('smooth')
}
}}
className={showRelayDetails ? 'bg-accent/50' : ''}
>
<Info />
</Button>
)}
<AccountButton />
</div>
</div>
)
}