Browse Source

fix navigation desktop

imwald
Silberengel 5 months ago
parent
commit
1344d3107c
  1. 77
      src/PageManager.tsx
  2. 60
      src/components/Profile/ProfileBookmarksAndHashtags.tsx
  3. 7
      src/components/SearchBar/index.tsx
  4. 1
      src/pages/primary/SearchPage/index.tsx
  5. 2
      src/pages/secondary/GeneralSettingsPage/index.tsx
  6. 3
      src/pages/secondary/HomePage/index.tsx
  7. 51
      src/pages/secondary/NoteListPage/index.tsx
  8. 4
      src/pages/secondary/SearchPage/index.tsx

77
src/PageManager.tsx

@ -4,6 +4,7 @@ import { cn } from '@/lib/utils' @@ -4,6 +4,7 @@ import { cn } from '@/lib/utils'
import logger from '@/lib/logger'
import { ChevronLeft } from 'lucide-react'
import NoteListPage from '@/pages/primary/NoteListPage'
import SecondaryNoteListPage from '@/pages/secondary/NoteListPage'
// Page imports needed for primary note view
import SettingsPage from '@/pages/secondary/SettingsPage'
import RelaySettingsPage from '@/pages/secondary/RelaySettingsPage'
@ -131,7 +132,7 @@ export function useSmartNoteNavigation() { @@ -131,7 +132,7 @@ export function useSmartNoteNavigation() {
// Use primary note view to show notes since secondary panel is disabled
// Extract note ID from URL (e.g., "/notes/note1..." -> "note1...")
const noteId = url.replace('/notes/', '')
window.history.replaceState(null, '', url)
window.history.pushState(null, '', url)
setPrimaryNoteView(<NotePage id={noteId} index={0} hideTitlebar={true} />, 'note')
}
@ -145,8 +146,8 @@ export function useSmartRelayNavigation() { @@ -145,8 +146,8 @@ export function useSmartRelayNavigation() {
const navigateToRelay = (url: string) => {
// Use primary note view to show relay pages since secondary panel is disabled
// Extract relay URL from the URL (e.g., "/relays/wss://..." -> "wss://...")
const relayUrl = url.replace('/relays/', '')
window.history.replaceState(null, '', url)
const relayUrl = decodeURIComponent(url.replace('/relays/', ''))
window.history.pushState(null, '', url)
setPrimaryNoteView(<SecondaryRelayPage url={relayUrl} index={0} hideTitlebar={true} />, 'relay')
}
@ -160,7 +161,7 @@ export function useSmartProfileNavigation() { @@ -160,7 +161,7 @@ export function useSmartProfileNavigation() {
const navigateToProfile = (url: string) => {
// Use primary note view to show profiles since secondary panel is disabled
const profileId = url.replace('/users/', '')
window.history.replaceState(null, '', url)
window.history.pushState(null, '', url)
setPrimaryNoteView(<SecondaryProfilePage id={profileId} index={0} hideTitlebar={true} />, 'profile')
}
@ -173,8 +174,8 @@ export function useSmartHashtagNavigation() { @@ -173,8 +174,8 @@ export function useSmartHashtagNavigation() {
const navigateToHashtag = (url: string) => {
// Use primary note view to show hashtag feed since secondary panel is disabled
window.history.replaceState(null, '', url)
setPrimaryNoteView(<NoteListPage />, 'hashtag')
window.history.pushState(null, '', url)
setPrimaryNoteView(<SecondaryNoteListPage hideTitlebar={true} />, 'hashtag')
}
return { navigateToHashtag }
@ -187,7 +188,7 @@ export function useSmartFollowingListNavigation() { @@ -187,7 +188,7 @@ export function useSmartFollowingListNavigation() {
const navigateToFollowingList = (url: string) => {
// Use primary note view to show following list since secondary panel is disabled
const profileId = url.replace('/users/', '').replace('/following', '')
window.history.replaceState(null, '', url)
window.history.pushState(null, '', url)
setPrimaryNoteView(<FollowingListPage id={profileId} index={0} hideTitlebar={true} />, 'profile')
}
@ -200,7 +201,7 @@ export function useSmartMuteListNavigation() { @@ -200,7 +201,7 @@ export function useSmartMuteListNavigation() {
const navigateToMuteList = (url: string) => {
// Use primary note view to show mute list since secondary panel is disabled
window.history.replaceState(null, '', url)
window.history.pushState(null, '', url)
setPrimaryNoteView(<MuteListPage index={0} hideTitlebar={true} />, 'settings')
}
@ -214,7 +215,7 @@ export function useSmartOthersRelaySettingsNavigation() { @@ -214,7 +215,7 @@ export function useSmartOthersRelaySettingsNavigation() {
const navigateToOthersRelaySettings = (url: string) => {
// Use primary note view to show others relay settings since secondary panel is disabled
const profileId = url.replace('/users/', '').replace('/relays', '')
window.history.replaceState(null, '', url)
window.history.pushState(null, '', url)
setPrimaryNoteView(<OthersRelaySettingsPage id={profileId} index={0} hideTitlebar={true} />, 'profile')
}
@ -228,22 +229,22 @@ export function useSmartSettingsNavigation() { @@ -228,22 +229,22 @@ export function useSmartSettingsNavigation() {
const navigateToSettings = (url: string) => {
// Use primary note view to show settings since secondary panel is disabled
if (url === '/settings') {
window.history.replaceState(null, '', url)
window.history.pushState(null, '', url)
setPrimaryNoteView(<SettingsPage index={0} hideTitlebar={true} />, 'settings')
} else if (url === '/settings/relays') {
window.history.replaceState(null, '', url)
window.history.pushState(null, '', url)
setPrimaryNoteView(<RelaySettingsPage index={0} hideTitlebar={true} />, 'settings-sub')
} else if (url === '/settings/wallet') {
window.history.replaceState(null, '', url)
window.history.pushState(null, '', url)
setPrimaryNoteView(<WalletPage index={0} hideTitlebar={true} />, 'settings-sub')
} else if (url === '/settings/posts') {
window.history.replaceState(null, '', url)
window.history.pushState(null, '', url)
setPrimaryNoteView(<PostSettingsPage index={0} hideTitlebar={true} />, 'settings-sub')
} else if (url === '/settings/general') {
window.history.replaceState(null, '', url)
window.history.pushState(null, '', url)
setPrimaryNoteView(<GeneralSettingsPage index={0} hideTitlebar={true} />, 'settings-sub')
} else if (url === '/settings/translation') {
window.history.replaceState(null, '', url)
window.history.pushState(null, '', url)
setPrimaryNoteView(<TranslationPage index={0} hideTitlebar={true} />, 'settings-sub')
}
}
@ -285,13 +286,13 @@ function MainContentArea({ @@ -285,13 +286,13 @@ function MainContentArea({
currentPrimaryPage,
primaryNoteView,
primaryViewType,
setPrimaryNoteView
goBack
}: {
primaryPages: { name: TPrimaryPageName; element: ReactNode; props?: any }[]
currentPrimaryPage: TPrimaryPageName
primaryNoteView: ReactNode | null
primaryViewType: 'note' | 'settings' | 'settings-sub' | 'profile' | 'hashtag' | 'relay' | null
setPrimaryNoteView: (view: ReactNode | null, type?: 'note' | 'settings' | 'settings-sub' | 'profile' | 'hashtag' | 'relay') => void
goBack: () => void
}) {
logger.debug('MainContentArea rendering:', {
currentPrimaryPage,
@ -313,16 +314,7 @@ function MainContentArea({ @@ -313,16 +314,7 @@ function MainContentArea({
variant="ghost"
size="titlebar-icon"
title="Back"
onClick={() => {
if (primaryViewType === 'settings-sub') {
// For settings sub-pages, navigate back to main settings page
window.history.replaceState(null, '', '/settings')
setPrimaryNoteView(<SettingsPage index={0} hideTitlebar={true} />, 'settings')
} else {
// For other pages, go back to feed
setPrimaryNoteView(null)
}
}}
onClick={goBack}
>
<ChevronLeft />
<div className="truncate text-lg font-semibold">
@ -405,8 +397,37 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) { @@ -405,8 +397,37 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
window.history.replaceState(null, '', newUrl)
}
}
const goBack = () => {
// Special handling for settings sub-pages - go back to main settings page
if (primaryViewType === 'settings-sub') {
window.history.pushState(null, '', '/settings')
setPrimaryNoteView(<SettingsPage index={0} hideTitlebar={true} />, 'settings')
} else {
// Use browser's back functionality for other pages
window.history.back()
}
}
const ignorePopStateRef = useRef(false)
// Handle browser back button
useEffect(() => {
const handlePopState = () => {
if (ignorePopStateRef.current) {
ignorePopStateRef.current = false
return
}
// If we have a primary note view open, close it and go back to the main page
if (primaryNoteView) {
setPrimaryNoteView(null)
}
}
window.addEventListener('popstate', handlePopState)
return () => window.removeEventListener('popstate', handlePopState)
}, [primaryNoteView])
useEffect(() => {
if (['/npub1', '/nprofile1'].some((prefix) => window.location.pathname.startsWith(prefix))) {
window.history.replaceState(
@ -709,7 +730,7 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) { @@ -709,7 +730,7 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
currentPrimaryPage={currentPrimaryPage}
primaryNoteView={primaryNoteView}
primaryViewType={primaryViewType}
setPrimaryNoteView={setPrimaryNoteView}
goBack={goBack}
/>
</div>
</div>

60
src/components/Profile/ProfileBookmarksAndHashtags.tsx

@ -317,15 +317,17 @@ export default function ProfileBookmarksAndHashtags({ @@ -317,15 +317,17 @@ export default function ProfileBookmarksAndHashtags({
}
return (
<div className="space-y-2">
{pinEvents.map((event) => (
<NoteCard
key={event.id}
className="w-full"
event={event}
filterMutedNotes={false}
/>
))}
<div className="min-h-screen">
<div className="space-y-2">
{pinEvents.map((event) => (
<NoteCard
key={event.id}
className="w-full"
event={event}
filterMutedNotes={false}
/>
))}
</div>
</div>
)
}
@ -350,15 +352,17 @@ export default function ProfileBookmarksAndHashtags({ @@ -350,15 +352,17 @@ export default function ProfileBookmarksAndHashtags({
}
return (
<div className="space-y-2">
{bookmarkEvents.map((event) => (
<NoteCard
key={event.id}
className="w-full"
event={event}
filterMutedNotes={false}
/>
))}
<div className="min-h-screen">
<div className="space-y-2">
{bookmarkEvents.map((event) => (
<NoteCard
key={event.id}
className="w-full"
event={event}
filterMutedNotes={false}
/>
))}
</div>
</div>
)
}
@ -383,15 +387,17 @@ export default function ProfileBookmarksAndHashtags({ @@ -383,15 +387,17 @@ export default function ProfileBookmarksAndHashtags({
}
return (
<div className="space-y-2">
{hashtagEvents.map((event) => (
<NoteCard
key={event.id}
className="w-full"
event={event}
filterMutedNotes={false}
/>
))}
<div className="min-h-screen">
<div className="space-y-2">
{hashtagEvents.map((event) => (
<NoteCard
key={event.id}
className="w-full"
event={event}
filterMutedNotes={false}
/>
))}
</div>
</div>
)
}

7
src/components/SearchBar/index.tsx

@ -1,10 +1,10 @@ @@ -1,10 +1,10 @@
import SearchInput from '@/components/SearchInput'
import { useSearchProfiles } from '@/hooks'
import { toNote } from '@/lib/link'
import { toNote, toNoteList } from '@/lib/link'
import { randomString } from '@/lib/random'
import { normalizeUrl } from '@/lib/url'
import { cn } from '@/lib/utils'
import { useSmartNoteNavigation } from '@/PageManager'
import { useSmartNoteNavigation, useSmartHashtagNavigation } from '@/PageManager'
import { useScreenSize } from '@/providers/ScreenSizeProvider'
import modalManager from '@/services/modal-manager.service'
import { TSearchParams } from '@/types'
@ -33,6 +33,7 @@ const SearchBar = forwardRef< @@ -33,6 +33,7 @@ const SearchBar = forwardRef<
>(({ input, setInput, onSearch }, ref) => {
const { t } = useTranslation()
const { navigateToNote } = useSmartNoteNavigation()
const { navigateToHashtag } = useSmartHashtagNavigation()
const { isSmallScreen } = useScreenSize()
const [debouncedInput, setDebouncedInput] = useState(input)
const { profiles, isFetching: isFetchingProfiles } = useSearchProfiles(debouncedInput, 5)
@ -89,6 +90,8 @@ const SearchBar = forwardRef< @@ -89,6 +90,8 @@ const SearchBar = forwardRef<
if (params.type === 'note') {
navigateToNote(toNote(params.search))
} else if (params.type === 'hashtag') {
navigateToHashtag(toNoteList({ hashtag: params.search }))
} else {
onSearch(params)
}

1
src/pages/primary/SearchPage/index.tsx

@ -39,6 +39,7 @@ const SearchPage = forwardRef((_, ref) => { @@ -39,6 +39,7 @@ const SearchPage = forwardRef((_, ref) => {
<PrimaryPageLayout
ref={layoutRef}
pageName="search"
titlebar={null}
displayScrollToTopButton
>
<div className="px-4 pt-4">

2
src/pages/secondary/GeneralSettingsPage/index.tsx

@ -6,7 +6,6 @@ import { LocalizedLanguageNames, TLanguage } from '@/i18n' @@ -6,7 +6,6 @@ import { LocalizedLanguageNames, TLanguage } from '@/i18n'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { cn, isSupportCheckConnectionType } from '@/lib/utils'
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
import { useScreenSize } from '@/providers/ScreenSizeProvider'
import { useTheme } from '@/providers/ThemeProvider'
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
import { useUserTrust } from '@/providers/UserTrustProvider'
@ -20,7 +19,6 @@ const GeneralSettingsPage = forwardRef(({ index, hideTitlebar = false }: { index @@ -20,7 +19,6 @@ const GeneralSettingsPage = forwardRef(({ index, hideTitlebar = false }: { index
const { t, i18n } = useTranslation()
const [language, setLanguage] = useState<TLanguage>(i18n.language as TLanguage)
const { themeSetting, setThemeSetting } = useTheme()
const { isSmallScreen } = useScreenSize()
const {
autoplay,
setAutoplay,

3
src/pages/secondary/HomePage/index.tsx

@ -4,10 +4,9 @@ import { Button } from '@/components/ui/button' @@ -4,10 +4,9 @@ import { Button } from '@/components/ui/button'
import { RECOMMENDED_RELAYS } from '@/constants'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { toRelay } from '@/lib/link'
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
import relayInfoService from '@/services/relay-info.service'
import { TRelayInfo } from '@/types'
import { ArrowRight, Server, X } from 'lucide-react'
import { ArrowRight, Server } from 'lucide-react'
import { forwardRef, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'

51
src/pages/secondary/NoteListPage/index.tsx

@ -15,7 +15,12 @@ import { UserRound, Plus } from 'lucide-react' @@ -15,7 +15,12 @@ import { UserRound, Plus } from 'lucide-react'
import React, { forwardRef, useEffect, useState, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
const NoteListPage = forwardRef(({ index, hideTitlebar = false }: { index?: number; hideTitlebar?: boolean }, ref) => {
interface NoteListPageProps {
index?: number
hideTitlebar?: boolean
}
const NoteListPage = forwardRef<HTMLDivElement, NoteListPageProps>(({ index, hideTitlebar = false }, ref) => {
const { t } = useTranslation()
const { push } = useSecondaryPage()
const { relayList, pubkey } = useNostr()
@ -149,6 +154,40 @@ const NoteListPage = forwardRef(({ index, hideTitlebar = false }: { index?: numb @@ -149,6 +154,40 @@ const NoteListPage = forwardRef(({ index, hideTitlebar = false }: { index?: numb
init()
}, [])
// Listen for URL changes to re-initialize the page
useEffect(() => {
const handlePopState = () => {
const searchParams = new URLSearchParams(window.location.search)
const hashtag = searchParams.get('t')
if (hashtag) {
setData({ type: 'hashtag' })
setTitle(`# ${hashtag}`)
setSubRequests([
{
filter: { '#t': [hashtag] },
urls: BIG_RELAY_URLS
}
])
// Set controls for hashtag subscribe button
if (pubkey) {
setControls(
<Button
variant="ghost"
className="h-10 [&_svg]:size-3"
onClick={handleSubscribeHashtag}
disabled={isHashtagSubscribed}
>
{isHashtagSubscribed ? t('Subscribed') : t('Subscribe')} <Plus />
</Button>
)
}
}
}
window.addEventListener('popstate', handlePopState)
return () => window.removeEventListener('popstate', handlePopState)
}, [pubkey, isHashtagSubscribed, t])
// Update controls when subscription status changes
useEffect(() => {
if (data?.type === 'hashtag' && pubkey) {
@ -183,9 +222,17 @@ const NoteListPage = forwardRef(({ index, hideTitlebar = false }: { index?: numb @@ -183,9 +222,17 @@ const NoteListPage = forwardRef(({ index, hideTitlebar = false }: { index?: numb
ref={ref}
index={index}
title={hideTitlebar ? undefined : title}
controls={controls}
controls={hideTitlebar ? undefined : controls}
displayScrollToTopButton
>
{hideTitlebar && data?.type === 'hashtag' && (
<div className="px-4 py-2 border-b">
<div className="flex items-center justify-between">
<div className="text-lg font-semibold">{title}</div>
{controls}
</div>
</div>
)}
{content}
</SecondaryPageLayout>
)

4
src/pages/secondary/SearchPage/index.tsx

@ -1,15 +1,13 @@ @@ -1,15 +1,13 @@
import SearchBar, { TSearchBarRef } from '@/components/SearchBar'
import SearchResult from '@/components/SearchResult'
import { Button } from '@/components/ui/button'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { toSearch } from '@/lib/link'
import { useSecondaryPage } from '@/PageManager'
import { TSearchParams } from '@/types'
import { ChevronLeft } from 'lucide-react'
import { forwardRef, useEffect, useMemo, useRef, useState } from 'react'
const SearchPage = forwardRef(({ index, hideTitlebar = false }: { index?: number; hideTitlebar?: boolean }, ref) => {
const { push, pop } = useSecondaryPage()
const { push } = useSecondaryPage()
const [input, setInput] = useState('')
const searchBarRef = useRef<TSearchBarRef>(null)
const searchParams = useMemo(() => {

Loading…
Cancel
Save