Browse Source

add rss icon to menus, ensure hiding when set to OFF

imwald
Silberengel 4 months ago
parent
commit
a37efe5821
  1. 4
      package-lock.json
  2. 2
      package.json
  3. 14
      src/PageManager.tsx
  4. 26
      src/components/NormalFeed/index.tsx
  5. 35
      src/components/Sidebar/RssButton.tsx
  6. 4
      src/components/Sidebar/index.tsx
  7. 6
      src/components/Tabs/index.tsx
  8. 33
      src/pages/primary/NoteListPage/index.tsx

4
package-lock.json generated

@ -1,12 +1,12 @@
{ {
"name": "jumble-imwald", "name": "jumble-imwald",
"version": "13.1", "version": "13.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "jumble-imwald", "name": "jumble-imwald",
"version": "13.1", "version": "13.2",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@asciidoctor/core": "^3.0.4", "@asciidoctor/core": "^3.0.4",

2
package.json

@ -1,6 +1,6 @@
{ {
"name": "jumble-imwald", "name": "jumble-imwald",
"version": "13.1", "version": "13.2",
"description": "A user-friendly Nostr client focused on relay feed browsing and relay discovery, forked from Jumble", "description": "A user-friendly Nostr client focused on relay feed browsing and relay discovery, forked from Jumble",
"private": true, "private": true,
"type": "module", "type": "module",

14
src/PageManager.tsx

@ -283,25 +283,25 @@ export function useSmartSettingsNavigation() {
// Use primary note view to show settings since secondary panel is disabled // Use primary note view to show settings since secondary panel is disabled
if (url === '/settings') { if (url === '/settings') {
window.history.pushState(null, '', url) window.history.pushState(null, '', url)
setPrimaryNoteView(<SettingsPage index={0} hideTitlebar={true} />, 'settings') setPrimaryNoteView(<SettingsPage key="settings" index={0} hideTitlebar={true} />, 'settings')
} else if (url.startsWith('/settings/relays')) { } else if (url.startsWith('/settings/relays')) {
window.history.pushState(null, '', url) window.history.pushState(null, '', url)
setPrimaryNoteView(<RelaySettingsPage index={0} hideTitlebar={true} />, 'settings-sub') setPrimaryNoteView(<RelaySettingsPage key="relay-settings" index={0} hideTitlebar={true} />, 'settings-sub')
} else if (url === '/settings/wallet') { } else if (url === '/settings/wallet') {
window.history.pushState(null, '', url) window.history.pushState(null, '', url)
setPrimaryNoteView(<WalletPage index={0} hideTitlebar={true} />, 'settings-sub') setPrimaryNoteView(<WalletPage key="wallet" index={0} hideTitlebar={true} />, 'settings-sub')
} else if (url === '/settings/posts') { } else if (url === '/settings/posts') {
window.history.pushState(null, '', url) window.history.pushState(null, '', url)
setPrimaryNoteView(<PostSettingsPage index={0} hideTitlebar={true} />, 'settings-sub') setPrimaryNoteView(<PostSettingsPage key="post-settings" index={0} hideTitlebar={true} />, 'settings-sub')
} else if (url === '/settings/general') { } else if (url === '/settings/general') {
window.history.pushState(null, '', url) window.history.pushState(null, '', url)
setPrimaryNoteView(<GeneralSettingsPage index={0} hideTitlebar={true} />, 'settings-sub') setPrimaryNoteView(<GeneralSettingsPage key="general-settings" index={0} hideTitlebar={true} />, 'settings-sub')
} else if (url === '/settings/translation') { } else if (url === '/settings/translation') {
window.history.pushState(null, '', url) window.history.pushState(null, '', url)
setPrimaryNoteView(<TranslationPage index={0} hideTitlebar={true} />, 'settings-sub') setPrimaryNoteView(<TranslationPage key="translation" index={0} hideTitlebar={true} />, 'settings-sub')
} else if (url === '/settings/rss-feeds') { } else if (url === '/settings/rss-feeds') {
window.history.pushState(null, '', url) window.history.pushState(null, '', url)
setPrimaryNoteView(<RssFeedSettingsPage index={0} hideTitlebar={true} />, 'settings-sub') setPrimaryNoteView(<RssFeedSettingsPage key="rss-feed-settings" index={0} hideTitlebar={true} />, 'settings-sub')
} }
} }

26
src/components/NormalFeed/index.tsx

@ -1,5 +1,5 @@
import NoteList, { TNoteListRef } from '@/components/NoteList' import NoteList, { TNoteListRef } from '@/components/NoteList'
import Tabs from '@/components/Tabs' import Tabs, { TabDefinition } from '@/components/Tabs'
import logger from '@/lib/logger' import logger from '@/lib/logger'
import { useKindFilter } from '@/providers/KindFilterProvider' import { useKindFilter } from '@/providers/KindFilterProvider'
import { useUserTrust } from '@/providers/UserTrustProvider' import { useUserTrust } from '@/providers/UserTrustProvider'
@ -12,6 +12,7 @@ import RssFeedList from '../RssFeedList'
import { useNostr } from '@/providers/NostrProvider' import { useNostr } from '@/providers/NostrProvider'
import rssFeedService from '@/services/rss-feed.service' import rssFeedService from '@/services/rss-feed.service'
import { DEFAULT_RSS_FEEDS } from '@/constants' import { DEFAULT_RSS_FEEDS } from '@/constants'
import { Rss } from 'lucide-react'
const NormalFeed = forwardRef<TNoteListRef, { const NormalFeed = forwardRef<TNoteListRef, {
subRequests: TFeedSubRequest[] subRequests: TFeedSubRequest[]
@ -66,6 +67,23 @@ const NormalFeed = forwardRef<TNoteListRef, {
} }
}, [showRssFeed, activeTab]) }, [showRssFeed, activeTab])
// Listen for custom event to switch to RSS tab
useEffect(() => {
const handleSwitchToRss = () => {
if (showRssFeed) {
setActiveTab('rss')
if (noteListRef && typeof noteListRef !== 'function') {
noteListRef.current?.scrollToTop('smooth')
}
}
}
window.addEventListener('switchToRssFeed', handleSwitchToRss)
return () => {
window.removeEventListener('switchToRssFeed', handleSwitchToRss)
}
}, [showRssFeed, noteListRef])
const handleListModeChange = (mode: TNoteListMode | string) => { const handleListModeChange = (mode: TNoteListMode | string) => {
if (mode === 'rss') { if (mode === 'rss') {
setActiveTab('rss') setActiveTab('rss')
@ -90,14 +108,14 @@ const NormalFeed = forwardRef<TNoteListRef, {
} }
// Build tabs array conditionally // Build tabs array conditionally
const tabs = useMemo(() => { const tabs = useMemo((): TabDefinition[] => {
const baseTabs = [ const baseTabs: TabDefinition[] = [
{ value: 'posts', label: 'Notes' }, { value: 'posts', label: 'Notes' },
{ value: 'postsAndReplies', label: 'Replies' } { value: 'postsAndReplies', label: 'Replies' }
] ]
if (showRssFeed) { if (showRssFeed) {
baseTabs.push({ value: 'rss', label: 'RSS' }) baseTabs.push({ value: 'rss', label: 'RSS', icon: <Rss className="size-4" /> })
} }
return baseTabs return baseTabs

35
src/components/Sidebar/RssButton.tsx

@ -0,0 +1,35 @@
import { usePrimaryPage, usePrimaryNoteView } from '@/PageManager'
import { Rss } from 'lucide-react'
import SidebarItem from './SidebarItem'
import storage from '@/services/local-storage.service'
export default function RssButton() {
const { navigate, current, display } = usePrimaryPage()
const { primaryViewType } = usePrimaryNoteView()
const showRssFeed = storage.getShowRssFeed()
// RSS is active when on home page and RSS tab would be active
// We can't directly check if RSS tab is active, so we'll just check if we're on home
const isActive = display && current === 'home' && primaryViewType === null && showRssFeed
const handleClick = () => {
// 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 (
<SidebarItem title="RSS Feed" onClick={handleClick} active={isActive}>
<Rss strokeWidth={3} />
</SidebarItem>
)
}

4
src/components/Sidebar/index.tsx

@ -8,11 +8,14 @@ import HomeButton from './HomeButton'
import NotificationsButton from './NotificationButton' import NotificationsButton from './NotificationButton'
import PostButton from './PostButton' import PostButton from './PostButton'
import ProfileButton from './ProfileButton' import ProfileButton from './ProfileButton'
import RssButton from './RssButton'
import SearchButton from './SearchButton' import SearchButton from './SearchButton'
import SettingsButton from './SettingsButton' import SettingsButton from './SettingsButton'
import storage from '@/services/local-storage.service'
export default function PrimaryPageSidebar() { export default function PrimaryPageSidebar() {
const { isSmallScreen } = useScreenSize() const { isSmallScreen } = useScreenSize()
const showRssFeed = storage.getShowRssFeed()
if (isSmallScreen) return null if (isSmallScreen) return null
return ( return (
@ -33,6 +36,7 @@ export default function PrimaryPageSidebar() {
<NotificationsButton /> <NotificationsButton />
<SearchButton /> <SearchButton />
<ProfileButton /> <ProfileButton />
{showRssFeed && <RssButton />}
<SettingsButton /> <SettingsButton />
<PostButton /> <PostButton />
</div> </div>

6
src/components/Tabs/index.tsx

@ -3,9 +3,10 @@ import { useDeepBrowsing } from '@/providers/DeepBrowsingProvider'
import { ReactNode, useCallback, useEffect, useRef, useState } from 'react' import { ReactNode, useCallback, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
type TabDefinition = { export type TabDefinition = {
value: string value: string
label: string label: string
icon?: ReactNode
} }
export default function Tabs({ export default function Tabs({
@ -134,13 +135,14 @@ export default function Tabs({
key={tab.value} key={tab.value}
ref={(el) => (tabRefs.current[index] = el)} ref={(el) => (tabRefs.current[index] = el)}
className={cn( className={cn(
`text-center py-2 px-2 sm:px-4 md:px-6 font-semibold whitespace-nowrap clickable cursor-pointer rounded-lg text-xs sm:text-sm md:text-base shrink-0`, `text-center py-2 px-2 sm:px-4 md:px-6 font-semibold whitespace-nowrap clickable cursor-pointer rounded-lg text-xs sm:text-sm md:text-base shrink-0 flex items-center gap-2 justify-center`,
value === tab.value ? '' : 'text-muted-foreground' value === tab.value ? '' : 'text-muted-foreground'
)} )}
onClick={() => { onClick={() => {
onTabChange?.(tab.value) onTabChange?.(tab.value)
}} }}
> >
{tab.icon && <span className="shrink-0">{tab.icon}</span>}
{t(tab.label)} {t(tab.label)}
</div> </div>
))} ))}

33
src/pages/primary/NoteListPage/index.tsx

@ -1,4 +1,3 @@
import { usePrimaryNoteView } from '@/PageManager'
import BookmarkList from '@/components/BookmarkList' import BookmarkList from '@/components/BookmarkList'
import RelayInfo from '@/components/RelayInfo' import RelayInfo from '@/components/RelayInfo'
import VersionUpdateBanner from '@/components/VersionUpdateBanner' import VersionUpdateBanner from '@/components/VersionUpdateBanner'
@ -9,7 +8,7 @@ import { useFeed } from '@/providers/FeedProvider'
import { useNostr } from '@/providers/NostrProvider' import { useNostr } from '@/providers/NostrProvider'
import { useScreenSize } from '@/providers/ScreenSizeProvider' import { useScreenSize } from '@/providers/ScreenSizeProvider'
import { TPageRef } from '@/types' import { TPageRef } from '@/types'
import { Info } from 'lucide-react' import { Info, Rss } from 'lucide-react'
import { import {
Dispatch, Dispatch,
forwardRef, forwardRef,
@ -26,6 +25,8 @@ import AccountButton from '@/components/Titlebar/AccountButton'
import FollowingFeed from './FollowingFeed' import FollowingFeed from './FollowingFeed'
import RelaysFeed from './RelaysFeed' import RelaysFeed from './RelaysFeed'
import logger from '@/lib/logger' import logger from '@/lib/logger'
import { usePrimaryPage, usePrimaryNoteView } from '@/PageManager'
import storage from '@/services/local-storage.service'
const NoteListPage = forwardRef((_, ref) => { const NoteListPage = forwardRef((_, ref) => {
logger.debug('NoteListPage component rendering') logger.debug('NoteListPage component rendering')
@ -130,6 +131,24 @@ function NoteListPageTitlebar({
}) { }) {
const { isSmallScreen } = useScreenSize() const { isSmallScreen } = useScreenSize()
const { setPrimaryNoteView } = usePrimaryNoteView() 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 ( return (
<div className="relative flex gap-1 items-center h-full justify-between"> <div className="relative flex gap-1 items-center h-full justify-between">
@ -153,6 +172,16 @@ function NoteListPageTitlebar({
</div> </div>
)} )}
<div className="shrink-0 flex gap-1 items-center"> <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 && ( {setShowRelayDetails && (
<Button <Button
variant="ghost" variant="ghost"

Loading…
Cancel
Save