Browse Source

fix page manager

move refresh button to the next menu line
imwald
Silberengel 1 month ago
parent
commit
e06115c98d
  1. 22
      README.md
  2. 38
      src/PageManager.tsx
  3. 5
      src/components/AccountManager/index.tsx
  4. 2
      src/components/BottomNavigationBar/HomeButton.tsx
  5. 2
      src/components/BottomNavigationBar/RssButton.tsx
  6. 2
      src/components/BottomNavigationBar/SearchButton.tsx
  7. 2
      src/components/BottomNavigationBar/SpellsButton.tsx
  8. 15
      src/components/NormalFeed/index.tsx
  9. 2
      src/components/Sidebar/DiscussionsButton.tsx
  10. 2
      src/components/Sidebar/FeedButton.tsx
  11. 2
      src/components/Sidebar/HomeButton.tsx
  12. 2
      src/components/Sidebar/NotificationButton.tsx
  13. 2
      src/components/Sidebar/RssButton.tsx
  14. 2
      src/components/Sidebar/SearchButton.tsx
  15. 2
      src/components/Sidebar/SpellsButton.tsx
  16. 22
      src/contexts/note-drawer-context.tsx
  17. 38
      src/contexts/primary-note-view-context.tsx
  18. 1
      src/i18n/locales/ar.ts
  19. 1
      src/i18n/locales/de.ts
  20. 1
      src/i18n/locales/en.ts
  21. 1
      src/i18n/locales/es.ts
  22. 1
      src/i18n/locales/fa.ts
  23. 1
      src/i18n/locales/fr.ts
  24. 1
      src/i18n/locales/hi.ts
  25. 1
      src/i18n/locales/it.ts
  26. 1
      src/i18n/locales/ja.ts
  27. 1
      src/i18n/locales/ko.ts
  28. 1
      src/i18n/locales/pl.ts
  29. 1
      src/i18n/locales/pt-BR.ts
  30. 1
      src/i18n/locales/pt-PT.ts
  31. 1
      src/i18n/locales/ru.ts
  32. 1
      src/i18n/locales/th.ts
  33. 1
      src/i18n/locales/zh.ts
  34. 13
      src/pages/primary/NoteListPage/FollowingFeed.tsx
  35. 4
      src/pages/primary/NoteListPage/RelaysFeed.tsx
  36. 34
      src/pages/primary/NoteListPage/index.tsx
  37. 2
      src/pages/secondary/CacheSettingsPage/index.tsx
  38. 2
      src/pages/secondary/FollowingListPage/index.tsx
  39. 2
      src/pages/secondary/GeneralSettingsPage/index.tsx
  40. 2
      src/pages/secondary/MuteListPage/index.tsx
  41. 3
      src/pages/secondary/NoteListPage/index.tsx
  42. 3
      src/pages/secondary/NotePage/index.tsx
  43. 2
      src/pages/secondary/OthersRelaySettingsPage/index.tsx
  44. 2
      src/pages/secondary/PostSettingsPage/index.tsx
  45. 2
      src/pages/secondary/ProfilePage/index.tsx
  46. 2
      src/pages/secondary/RelayPage/index.tsx
  47. 2
      src/pages/secondary/RelayReviewsPage/index.tsx
  48. 2
      src/pages/secondary/RelaySettingsPage/index.tsx
  49. 2
      src/pages/secondary/RssArticlePage/index.tsx
  50. 2
      src/pages/secondary/RssFeedSettingsPage/index.tsx
  51. 3
      src/pages/secondary/SearchPage/index.tsx
  52. 2
      src/pages/secondary/SettingsPage/index.tsx
  53. 2
      src/pages/secondary/TranslationPage/index.tsx
  54. 2
      src/pages/secondary/WalletPage/index.tsx

22
README.md

@ -92,23 +92,21 @@ docker compose up --build -d @@ -92,23 +92,21 @@ docker compose up --build -d
Then open: http://localhost:8089
## Sponsors (original Jumble)
## Linux desktop (`.deb` / AppImage)
<a target="_blank" href="https://opensats.org/">
<img alt="open-sats-logo" src="./resources/open-sats-logo.svg" height="44">
</a>
Built packages are **not** committed to this repository (only source). They are published as **release assets** when a maintainer uploads them.
## Donate
- **Download:** [GitHub Releases — latest](https://github.com/Silberengel/jumble/releases/latest) — get the `*.deb` (or AppImage) attached to a release.
- **Install the `.deb`:** `sudo apt install ./Jumble_*_amd64.deb` (use the exact filename from the download folder; `./` is required so `apt` uses the local file). After install, Jumble should appear in your app menu (often under **Network**).
**Original author** — if you want to support the project Jumble was forked from:
**Maintainers — build artifacts locally:**
lightning: ⚡ codytseng@getalby.com ⚡
bitcoin: bc1qx8kvutghdhejx7vuvatmvw2ghypdungu0qm7ds
geyser: https://geyser.fund/project/jumble
```bash
npm install
npm run electron:pack
```
---
Outputs land in `release/` (`.deb`, `.AppImage`). Upload those files when you create or edit a GitHub Release for that version.
## License

38
src/PageManager.tsx

@ -22,7 +22,6 @@ import { NotificationProvider } from '@/providers/NotificationProvider' @@ -22,7 +22,6 @@ import { NotificationProvider } from '@/providers/NotificationProvider'
import { TPageRef } from '@/types'
import {
cloneElement,
createContext,
createRef,
isValidElement,
lazy,
@ -31,7 +30,6 @@ import { @@ -31,7 +30,6 @@ import {
RefObject,
Suspense,
useCallback,
useContext,
useEffect,
useMemo,
useRef,
@ -49,6 +47,8 @@ import modalManager from './services/modal-manager.service' @@ -49,6 +47,8 @@ import modalManager from './services/modal-manager.service'
import { decodeRssArticlePathSegment, encodeRssArticlePathSegment } from '@/lib/rss-article'
import { routes } from './routes'
import { useScreenSize } from './providers/ScreenSizeProvider'
import { NoteDrawerContext, useNoteDrawer } from '@/contexts/note-drawer-context'
import { PrimaryNoteViewContext, usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { SecondaryPageContext, useSecondaryPage } from '@/contexts/secondary-page-context'
/** Lazy-loaded so PageManager does not synchronously import SpellsPage (avoids HMR cycle: SpellsPage → PrimaryPageLayout → PageManager → SpellsPage). */
@ -196,42 +196,8 @@ function mergePrimaryPageEntry( @@ -196,42 +196,8 @@ function mergePrimaryPageEntry(
export { PrimaryPageContext, usePrimaryPage }
const PrimaryNoteViewContext = createContext<{
setPrimaryNoteView: (view: ReactNode | null, type?: 'note' | 'settings' | 'settings-sub' | 'profile' | 'hashtag' | 'relay' | 'following' | 'mute' | 'others-relay-settings') => void
primaryViewType: 'note' | 'settings' | 'settings-sub' | 'profile' | 'hashtag' | 'relay' | 'following' | 'mute' | 'others-relay-settings' | null
getNavigationCounter: () => number
/** Top URL in the secondary stack (right panel), or undefined if empty. Used so settings sub-pages open in the panel instead of behind it. */
getTopSecondaryUrl: () => string | undefined
/** Primary overlay (mobile / narrow): child calls this to expose refresh for the chrome bar. */
registerPrimaryPanelRefresh: (fn: (() => void) | null) => void
triggerPrimaryPanelRefresh: () => void
} | undefined>(undefined)
const NoteDrawerContext = createContext<{
openDrawer: (noteId: string) => void
closeDrawer: () => void
isDrawerOpen: boolean
drawerNoteId: string | null
} | undefined>(undefined)
export { useSecondaryPage }
export function usePrimaryNoteView() {
const context = useContext(PrimaryNoteViewContext)
if (!context) {
throw new Error('usePrimaryNoteView must be used within a PrimaryNoteViewContext.Provider')
}
return context
}
export function useNoteDrawer() {
const context = useContext(NoteDrawerContext)
if (!context) {
throw new Error('useNoteDrawer must be used within a NoteDrawerContext.Provider')
}
return context
}
// Helper function to build contextual note URL
function buildNoteUrl(noteId: string, currentPage: TPrimaryPageName | null): string {
// Pages that should preserve context in the URL

5
src/components/AccountManager/index.tsx

@ -1,6 +1,5 @@ @@ -1,6 +1,5 @@
import { Button } from '@/components/ui/button'
import { Separator } from '@/components/ui/separator'
import { isDevEnv } from '@/lib/utils'
import { useNostr } from '@/providers/NostrProvider'
import { useTheme } from '@/providers/ThemeProvider'
import { NstartModal } from 'nstart-modal'
@ -63,11 +62,9 @@ function AccountManagerNav({ @@ -63,11 +62,9 @@ function AccountManagerNav({
<Button variant="secondary" onClick={() => setPage('nsec')} className="w-full">
{t('Login with Private Key')}
</Button>
{isDevEnv() && (
<Button variant="secondary" onClick={() => setPage('npub')} className="w-full">
Login with Public key (for development)
{t('Login with npub (read-only)')}
</Button>
)}
</div>
</div>
<Separator />

2
src/components/BottomNavigationBar/HomeButton.tsx

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import { cn } from '@/lib/utils'
import { usePrimaryPage } from '@/contexts/primary-page-context'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { Star } from 'lucide-react'
import BottomNavigationBarItem from './BottomNavigationBarItem'

2
src/components/BottomNavigationBar/RssButton.tsx

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import { usePrimaryPage } from '@/contexts/primary-page-context'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import storage from '@/services/local-storage.service'
import { Rss } from 'lucide-react'
import BottomNavigationBarItem from './BottomNavigationBarItem'

2
src/components/BottomNavigationBar/SearchButton.tsx

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import { usePrimaryPage } from '@/contexts/primary-page-context'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { Search } from 'lucide-react'
import BottomNavigationBarItem from './BottomNavigationBarItem'

2
src/components/BottomNavigationBar/SpellsButton.tsx

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import { usePrimaryPage } from '@/contexts/primary-page-context'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { Wand2 } from 'lucide-react'
import BottomNavigationBarItem from './BottomNavigationBarItem'

15
src/components/NormalFeed/index.tsx

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
import NoteList, { TNoteListRef } from '@/components/NoteList'
import { RefreshButton } from '@/components/RefreshButton'
import Tabs, { TabDefinition } from '@/components/Tabs'
import { useKindFilter } from '@/providers/KindFilterProvider'
import { useUserTrust } from '@/providers/UserTrustProvider'
@ -13,12 +14,15 @@ const NormalFeed = forwardRef<TNoteListRef, { @@ -13,12 +14,15 @@ const NormalFeed = forwardRef<TNoteListRef, {
isMainFeed?: boolean
/** When set (e.g. on Home), tabs are rendered in layout subHeader instead of in-feed; avoids overlap */
setSubHeader?: (node: React.ReactNode) => void
/** Shown in the subHeader row to the left of the kind filter (mobile primary feed). */
onSubHeaderRefresh?: () => void
}>(function NormalFeed(
{
subRequests,
areAlgoRelays = false,
isMainFeed = false,
setSubHeader
setSubHeader,
onSubHeaderRefresh
},
ref
) {
@ -70,7 +74,12 @@ const NormalFeed = forwardRef<TNoteListRef, { @@ -70,7 +74,12 @@ const NormalFeed = forwardRef<TNoteListRef, {
value={listMode}
tabs={tabs}
onTabChange={(tab) => handleListModeChange(tab)}
options={<KindFilter showKinds={temporaryShowKinds} onShowKindsChange={handleShowKindsChange} />}
options={
<div className="flex items-center gap-1">
{onSubHeaderRefresh != null && <RefreshButton onClick={onSubHeaderRefresh} />}
<KindFilter showKinds={temporaryShowKinds} onShowKindsChange={handleShowKindsChange} />
</div>
}
/>
)
@ -78,7 +87,7 @@ const NormalFeed = forwardRef<TNoteListRef, { @@ -78,7 +87,7 @@ const NormalFeed = forwardRef<TNoteListRef, {
if (!isMainFeed || !setSubHeader) return
setSubHeader(tabsElement)
return () => setSubHeader(null)
}, [isMainFeed, setSubHeader, listMode, temporaryShowKinds])
}, [isMainFeed, setSubHeader, listMode, temporaryShowKinds, onSubHeaderRefresh])
const renderTabsInFeed = !(isMainFeed && setSubHeader)

2
src/components/Sidebar/DiscussionsButton.tsx

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import { usePrimaryPage } from '@/contexts/primary-page-context'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { MessageCircle } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import SidebarItem from './SidebarItem'

2
src/components/Sidebar/FeedButton.tsx

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import { usePrimaryPage } from '@/contexts/primary-page-context'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { Compass } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import SidebarItem from './SidebarItem'

2
src/components/Sidebar/HomeButton.tsx

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import { cn } from '@/lib/utils'
import { usePrimaryPage } from '@/contexts/primary-page-context'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { Star } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import SidebarItem from './SidebarItem'

2
src/components/Sidebar/NotificationButton.tsx

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import { usePrimaryPage } from '@/contexts/primary-page-context'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { useNostr } from '@/providers/NostrProvider'
import { Bell } from 'lucide-react'
import SidebarItem from './SidebarItem'

2
src/components/Sidebar/RssButton.tsx

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import { usePrimaryPage } from '@/contexts/primary-page-context'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { Rss } from 'lucide-react'
import SidebarItem from './SidebarItem'
import storage from '@/services/local-storage.service'

2
src/components/Sidebar/SearchButton.tsx

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import { usePrimaryPage } from '@/contexts/primary-page-context'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { Search } from 'lucide-react'
import SidebarItem from './SidebarItem'

2
src/components/Sidebar/SpellsButton.tsx

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import { usePrimaryPage } from '@/contexts/primary-page-context'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { Wand2 } from 'lucide-react'
import SidebarItem from './SidebarItem'

22
src/contexts/note-drawer-context.tsx

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
import { createContext, useContext } from 'react'
export type NoteDrawerContextValue = {
openDrawer: (noteId: string) => void
closeDrawer: () => void
isDrawerOpen: boolean
drawerNoteId: string | null
}
/**
* Same rationale as {@link PrimaryNoteViewContext}: keep context identity out of PageManager.tsx
* so lazy chunks never instantiate a duplicate context.
*/
export const NoteDrawerContext = createContext<NoteDrawerContextValue | undefined>(undefined)
export function useNoteDrawer(): NoteDrawerContextValue {
const context = useContext(NoteDrawerContext)
if (!context) {
throw new Error('useNoteDrawer must be used within a NoteDrawerContext.Provider')
}
return context
}

38
src/contexts/primary-note-view-context.tsx

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
import { createContext, useContext, type ReactNode } from 'react'
export type TPrimaryOverlayViewType =
| 'note'
| 'settings'
| 'settings-sub'
| 'profile'
| 'hashtag'
| 'relay'
| 'following'
| 'mute'
| 'others-relay-settings'
export type PrimaryNoteViewContextValue = {
setPrimaryNoteView: (view: ReactNode | null, type?: TPrimaryOverlayViewType) => void
primaryViewType: TPrimaryOverlayViewType | null
getNavigationCounter: () => number
/** Top URL in the secondary stack (right panel), or undefined if empty. */
getTopSecondaryUrl: () => string | undefined
/** Primary overlay (mobile / narrow): child calls this to expose refresh for the chrome bar. */
registerPrimaryPanelRefresh: (fn: (() => void) | null) => void
triggerPrimaryPanelRefresh: () => void
}
/**
* Dedicated module so lazy chunks (e.g. BottomNavigationBar) share the same context as PageManager.
* Importing these hooks from PageManager into those chunks can duplicate the module and break
* Provider matching ("must be used within PrimaryNoteViewContext.Provider").
*/
export const PrimaryNoteViewContext = createContext<PrimaryNoteViewContextValue | undefined>(undefined)
export function usePrimaryNoteView(): PrimaryNoteViewContextValue {
const context = useContext(PrimaryNoteViewContext)
if (!context) {
throw new Error('usePrimaryNoteView must be used within a PrimaryNoteViewContext.Provider')
}
return context
}

1
src/i18n/locales/ar.ts

@ -241,6 +241,7 @@ export default { @@ -241,6 +241,7 @@ export default {
'Login with Browser Extension': 'تسجيل الدخول باستخدام إضافة المتصفح',
'Login with Bunker': 'تسجيل الدخول باستخدام Bunker',
'Login with Private Key': 'تسجيل الدخول باستخدام المفتاح الخاص',
'Login with npub (read-only)': 'تسجيل الدخول بـ npub (للقراءة فقط)',
'reload notes': 'إعادة تحميل الملاحظات',
'Logged in Accounts': 'الحسابات المسجلة',
'Add an Account': 'إضافة حساب',

1
src/i18n/locales/de.ts

@ -248,6 +248,7 @@ export default { @@ -248,6 +248,7 @@ export default {
'Login with Browser Extension': 'Mit Browser-Erweiterung anmelden',
'Login with Bunker': 'Mit Bunker anmelden',
'Login with Private Key': 'Mit privatem Schlüssel anmelden',
'Login with npub (read-only)': 'Mit npub anmelden (nur lesen)',
'reload notes': 'Notizen neu laden',
'Logged in Accounts': 'Angemeldete Konten',
'Add an Account': 'Konto hinzufügen',

1
src/i18n/locales/en.ts

@ -243,6 +243,7 @@ export default { @@ -243,6 +243,7 @@ export default {
'Login with Browser Extension': 'Login with Browser Extension',
'Login with Bunker': 'Login with Bunker',
'Login with Private Key': 'Login with Private Key',
'Login with npub (read-only)': 'Login with npub (read-only)',
'reload notes': 'reload notes',
'Logged in Accounts': 'Logged in Accounts',
'Add an Account': 'Add an Account',

1
src/i18n/locales/es.ts

@ -242,6 +242,7 @@ export default { @@ -242,6 +242,7 @@ export default {
'Login with Browser Extension': 'Iniciar sesión con extensión de navegador',
'Login with Bunker': 'Iniciar sesión con Bunker',
'Login with Private Key': 'Iniciar sesión con clave privada',
'Login with npub (read-only)': 'Iniciar sesión con npub (solo lectura)',
'reload notes': 'recargar notas',
'Logged in Accounts': 'Cuentas conectadas',
'Add an Account': 'Agregar una cuenta',

1
src/i18n/locales/fa.ts

@ -242,6 +242,7 @@ export default { @@ -242,6 +242,7 @@ export default {
'Login with Browser Extension': 'ورود با افزونه مرورگر',
'Login with Bunker': 'ورود با Bunker',
'Login with Private Key': 'ورود با کلید خصوصی',
'Login with npub (read-only)': 'ورود با npub (فقط خواندن)',
'reload notes': 'بازخوانی یادداشتها',
'Logged in Accounts': 'حسابهای وارد شده',
'Add an Account': 'افزودن حساب',

1
src/i18n/locales/fr.ts

@ -242,6 +242,7 @@ export default { @@ -242,6 +242,7 @@ export default {
'Login with Browser Extension': 'Connexion avec une extension de navigateur',
'Login with Bunker': 'Connexion avec Bunker',
'Login with Private Key': 'Connexion avec clé privée',
'Login with npub (read-only)': 'Connexion avec npub (lecture seule)',
'reload notes': 'recharger les notes',
'Logged in Accounts': 'Comptes connectés',
'Add an Account': 'Ajouter un compte',

1
src/i18n/locales/hi.ts

@ -242,6 +242,7 @@ export default { @@ -242,6 +242,7 @@ export default {
'Login with Browser Extension': 'बउजर एकसटशन सिन कर',
'Login with Bunker': 'बकर सिन कर',
'Login with Private Key': 'पइवट किन कर',
'Login with npub (read-only)': 'npub सिन कर (कवल पढिए)',
'reload notes': 'नस रड कर',
'Logged in Accounts': 'लग इन अकट',
'Add an Account': 'अकट ज',

1
src/i18n/locales/it.ts

@ -242,6 +242,7 @@ export default { @@ -242,6 +242,7 @@ export default {
'Login with Browser Extension': 'Accedi con una estensione del Browser',
'Login with Bunker': 'Accedi con Bunker',
'Login with Private Key': 'Accedi con la Chiave Privata',
'Login with npub (read-only)': 'Accedi con npub (solo lettura)',
'reload notes': 'ricarica note',
'Logged in Accounts': 'Account collegati',
'Add an Account': 'Aggiungi un Account',

1
src/i18n/locales/ja.ts

@ -242,6 +242,7 @@ export default { @@ -242,6 +242,7 @@ export default {
'Login with Browser Extension': 'ブラウザ拡張でログイン',
'Login with Bunker': 'Bunkerでログイン',
'Login with Private Key': '秘密鍵でログイン',
'Login with npub (read-only)': 'npubでログイン(閲覧のみ)',
'reload notes': 'ノートを再読み込み',
'Logged in Accounts': 'ログイン中のアカウント',
'Add an Account': 'アカウントを追加',

1
src/i18n/locales/ko.ts

@ -242,6 +242,7 @@ export default { @@ -242,6 +242,7 @@ export default {
'Login with Browser Extension': '브라우저 확장으로 로그인',
'Login with Bunker': 'Bunker로 로그인',
'Login with Private Key': '개인 키로 로그인',
'Login with npub (read-only)': 'npub으로 로그인 (읽기 전용)',
'reload notes': '노트 다시 불러오기',
'Logged in Accounts': '로그인된 계정',
'Add an Account': '계정 추가',

1
src/i18n/locales/pl.ts

@ -242,6 +242,7 @@ export default { @@ -242,6 +242,7 @@ export default {
'Login with Browser Extension': 'Logowanie z rozszerzeniem przeglądarki',
'Login with Bunker': 'Logowanie z bunkrem',
'Login with Private Key': 'Logowanie z prywatnym kluczem (nsec)',
'Login with npub (read-only)': 'Logowanie z npub (tylko odczyt)',
'reload notes': 'Odśwież',
'Logged in Accounts': 'Zalogowane konta',
'Add an Account': 'Dodaj Konto',

1
src/i18n/locales/pt-BR.ts

@ -242,6 +242,7 @@ export default { @@ -242,6 +242,7 @@ export default {
'Login with Browser Extension': 'Entrar com extensão do navegador',
'Login with Bunker': 'Entrar com Bunker',
'Login with Private Key': 'Entrar com chave privada',
'Login with npub (read-only)': 'Entrar com npub (somente leitura)',
'reload notes': 'Recarregar notas',
'Logged in Accounts': 'Contas conectadas',
'Add an Account': 'Acessar conta',

1
src/i18n/locales/pt-PT.ts

@ -242,6 +242,7 @@ export default { @@ -242,6 +242,7 @@ export default {
'Login with Browser Extension': 'Entrar com Extensão do Navegador',
'Login with Bunker': 'Entrar com Bunker',
'Login with Private Key': 'Entrar com Chave Privada',
'Login with npub (read-only)': 'Entrar com npub (só leitura)',
'reload notes': 'recarregar notas',
'Logged in Accounts': 'Contas Conectadas',
'Add an Account': 'Adicionar uma Conta',

1
src/i18n/locales/ru.ts

@ -242,6 +242,7 @@ export default { @@ -242,6 +242,7 @@ export default {
'Login with Browser Extension': 'Войти через расширение браузера',
'Login with Bunker': 'Войти через Bunker',
'Login with Private Key': 'Войти с приватным ключом',
'Login with npub (read-only)': 'Войти по npub (только чтение)',
'reload notes': 'перезагрузить заметки',
'Logged in Accounts': 'Вошедшие аккаунты',
'Add an Account': 'Добавить аккаунт',

1
src/i18n/locales/th.ts

@ -242,6 +242,7 @@ export default { @@ -242,6 +242,7 @@ export default {
'Login with Browser Extension': 'เขาสระบบดวยสวนขยายเบราวเซอร',
'Login with Bunker': 'เขาสระบบดวย Bunker',
'Login with Private Key': 'เขาสระบบดวยควนตว',
'Login with npub (read-only)': 'เขาสระบบดวย npub (อานอยางเดยว)',
'reload notes': 'โหลดโนตใหม',
'Logged in Accounts': 'บญชเขาสระบบ',
'Add an Account': 'เพมบญช',

1
src/i18n/locales/zh.ts

@ -241,6 +241,7 @@ export default { @@ -241,6 +241,7 @@ export default {
'Login with Browser Extension': '浏览器插件登录',
'Login with Bunker': 'Bunker 登录',
'Login with Private Key': '私钥登录',
'Login with npub (read-only)': '使用 npub 登录(只读)',
'reload notes': '重新加载笔记',
'Logged in Accounts': '已登录账户',
'Add an Account': '添加账户',

13
src/pages/primary/NoteListPage/FollowingFeed.tsx

@ -13,8 +13,9 @@ const FollowingFeed = forwardRef< @@ -13,8 +13,9 @@ const FollowingFeed = forwardRef<
TNoteListRef,
{
setSubHeader?: (node: ReactNode) => void
onSubHeaderRefresh?: () => void
}
>(function FollowingFeed({ setSubHeader }, ref) {
>(function FollowingFeed({ setSubHeader, onSubHeaderRefresh }, ref) {
const { pubkey, relayList } = useNostr()
const { favoriteRelays, blockedRelays } = useFavoriteRelays()
const { feedInfo } = useFeed()
@ -43,7 +44,15 @@ const FollowingFeed = forwardRef< @@ -43,7 +44,15 @@ const FollowingFeed = forwardRef<
void init()
}, [feedInfo.feedType, pubkey, favoriteRelays, blockedRelays, relayList])
return <NormalFeed ref={ref} subRequests={subRequests} isMainFeed setSubHeader={setSubHeader} />
return (
<NormalFeed
ref={ref}
subRequests={subRequests}
isMainFeed
setSubHeader={setSubHeader}
onSubHeaderRefresh={onSubHeaderRefresh}
/>
)
})
FollowingFeed.displayName = 'FollowingFeed'

4
src/pages/primary/NoteListPage/RelaysFeed.tsx

@ -11,10 +11,11 @@ const RelaysFeed = forwardRef< @@ -11,10 +11,11 @@ const RelaysFeed = forwardRef<
TNoteListRef,
{
setSubHeader?: (node: React.ReactNode) => void
onSubHeaderRefresh?: () => void
/** When set, subscription kinds (fixed list); otherwise uses KindFilterProvider. */
kindsOverride?: number[]
}
>(function RelaysFeed({ setSubHeader, kindsOverride }, ref) {
>(function RelaysFeed({ setSubHeader, onSubHeaderRefresh, kindsOverride }, ref) {
const { feedInfo, relayUrls } = useFeed()
const { showKinds } = useKindFilter()
const [areAlgoRelays, setAreAlgoRelays] = useState(false)
@ -98,6 +99,7 @@ const RelaysFeed = forwardRef< @@ -98,6 +99,7 @@ const RelaysFeed = forwardRef<
areAlgoRelays={areAlgoRelays}
isMainFeed
setSubHeader={setSubHeader}
onSubHeaderRefresh={onSubHeaderRefresh}
/>
)
})

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

@ -27,7 +27,7 @@ import HelpAndAccountMenu from '@/components/HelpAndAccountMenu' @@ -27,7 +27,7 @@ import HelpAndAccountMenu from '@/components/HelpAndAccountMenu'
import FollowingFeed from './FollowingFeed'
import RelaysFeed from './RelaysFeed'
import { usePrimaryPage } from '@/contexts/primary-page-context'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
const NoteListPage = forwardRef<TPageRef>((_, ref) => {
const { t } = useTranslation()
@ -40,6 +40,12 @@ const NoteListPage = forwardRef<TPageRef>((_, ref) => { @@ -40,6 +40,12 @@ const NoteListPage = forwardRef<TPageRef>((_, ref) => {
const [showRelayDetails, setShowRelayDetails] = useState(false)
const [homeSubHeader, setHomeSubHeader] = useState<React.ReactNode>(null)
const usesSubHeader =
feedInfo.feedType === 'relay' ||
feedInfo.feedType === 'relays' ||
feedInfo.feedType === 'all-favorites' ||
feedInfo.feedType === 'following'
const runFeedRefresh = useCallback(() => {
if (feedInfo.feedType === 'bookmarks') {
void bookmarkRef.current?.refresh()
@ -63,13 +69,8 @@ const NoteListPage = forwardRef<TPageRef>((_, ref) => { @@ -63,13 +69,8 @@ const NoteListPage = forwardRef<TPageRef>((_, ref) => {
// Clear subHeader when switching to a feed that doesn't use it (e.g. bookmarks)
useEffect(() => {
const usesSubHeader =
feedInfo.feedType === 'relay' ||
feedInfo.feedType === 'relays' ||
feedInfo.feedType === 'all-favorites' ||
feedInfo.feedType === 'following'
if (!usesSubHeader) setHomeSubHeader(null)
}, [feedInfo.feedType])
}, [usesSubHeader])
// 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
@ -123,14 +124,24 @@ const NoteListPage = forwardRef<TPageRef>((_, ref) => { @@ -123,14 +124,24 @@ const NoteListPage = forwardRef<TPageRef>((_, ref) => {
content = <BookmarkList ref={bookmarkRef} />
}
} else if (feedInfo.feedType === 'following') {
content = <FollowingFeed ref={feedRef} setSubHeader={setHomeSubHeaderStable} />
content = (
<FollowingFeed
ref={feedRef}
setSubHeader={setHomeSubHeaderStable}
onSubHeaderRefresh={runFeedRefresh}
/>
)
} else {
content = (
<>
{showRelayDetails && feedInfo.feedType === 'relay' && !!feedInfo.id && (
<RelayInfo url={feedInfo.id!} className="mb-2 pt-3" />
)}
<RelaysFeed ref={feedRef} setSubHeader={setHomeSubHeaderStable} />
<RelaysFeed
ref={feedRef}
setSubHeader={setHomeSubHeaderStable}
onSubHeaderRefresh={runFeedRefresh}
/>
</>
)
}
@ -143,6 +154,7 @@ const NoteListPage = forwardRef<TPageRef>((_, ref) => { @@ -143,6 +154,7 @@ const NoteListPage = forwardRef<TPageRef>((_, ref) => {
<NoteListPageTitlebar
layoutRef={layoutRef}
onFeedRefresh={runFeedRefresh}
showTitlebarRefresh={!usesSubHeader}
showRelayDetails={showRelayDetails}
setShowRelayDetails={
feedInfo.feedType === 'relay' && !!feedInfo.id ? setShowRelayDetails : undefined
@ -165,11 +177,13 @@ export default NoteListPage @@ -165,11 +177,13 @@ export default NoteListPage
function NoteListPageTitlebar({
layoutRef,
onFeedRefresh,
showTitlebarRefresh,
showRelayDetails,
setShowRelayDetails
}: {
layoutRef?: React.RefObject<TPageRef>
onFeedRefresh: () => void
showTitlebarRefresh: boolean
showRelayDetails?: boolean
setShowRelayDetails?: Dispatch<SetStateAction<boolean>>
}) {
@ -217,7 +231,7 @@ function NoteListPageTitlebar({ @@ -217,7 +231,7 @@ function NoteListPageTitlebar({
</div>
)}
<div className="shrink-0 flex gap-1 items-center">
<RefreshButton onClick={onFeedRefresh} />
{showTitlebarRefresh && <RefreshButton onClick={onFeedRefresh} />}
{setShowRelayDetails && (
<Button
variant="ghost"

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

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
import CacheRelaysSetting from '@/components/CacheRelaysSetting'
import { RefreshButton } from '@/components/RefreshButton'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { forwardRef, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'

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

@ -2,7 +2,7 @@ import ProfileList from '@/components/ProfileList' @@ -2,7 +2,7 @@ import ProfileList from '@/components/ProfileList'
import { RefreshButton } from '@/components/RefreshButton'
import { useFetchFollowings, useFetchProfile } from '@/hooks'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { forwardRef, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'

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

@ -10,7 +10,7 @@ import { @@ -10,7 +10,7 @@ import {
} from '@/constants'
import { LocalizedLanguageNames, TLanguage } from '@/i18n'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { cn, isSupportCheckConnectionType } from '@/lib/utils'
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
import { useFontSize } from '@/providers/FontSizeProvider'

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

@ -7,7 +7,7 @@ import UserAvatar from '@/components/UserAvatar' @@ -7,7 +7,7 @@ import UserAvatar from '@/components/UserAvatar'
import Username from '@/components/Username'
import { useFetchProfile } from '@/hooks'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { useMuteList } from '@/providers/MuteListProvider'
import { useNostr } from '@/providers/NostrProvider'
import { Lock, Unlock } from 'lucide-react'

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

@ -11,7 +11,8 @@ import { @@ -11,7 +11,8 @@ import {
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { toProfileList } from '@/lib/link'
import { fetchPubkeysFromDomain, getWellKnownNip05Url } from '@/lib/nip05'
import { usePrimaryNoteView, useSecondaryPage } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { useSecondaryPage } from '@/PageManager'
import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider'
import { useNostr } from '@/providers/NostrProvider'
import { useInterestList } from '@/providers/InterestListProvider'

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

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
import { RefreshButton } from '@/components/RefreshButton'
import { usePrimaryNoteView, useSecondaryPage, useSmartNoteNavigation } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { useSecondaryPage, useSmartNoteNavigation } from '@/PageManager'
import { ExtendedKind } from '@/constants'
import ContentPreview from '@/components/ContentPreview'
import client from '@/services/client.service'

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

@ -2,7 +2,7 @@ import OthersRelayList from '@/components/OthersRelayList' @@ -2,7 +2,7 @@ import OthersRelayList from '@/components/OthersRelayList'
import { RefreshButton } from '@/components/RefreshButton'
import { useFetchProfile } from '@/hooks'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { forwardRef, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'

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

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import { RefreshButton } from '@/components/RefreshButton'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { forwardRef, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import MediaUploadServiceSetting from './MediaUploadServiceSetting'

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

@ -2,7 +2,7 @@ import Profile from '@/components/Profile' @@ -2,7 +2,7 @@ import Profile from '@/components/Profile'
import { RefreshButton } from '@/components/RefreshButton'
import { useFetchProfile } from '@/hooks'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { forwardRef, useCallback, useEffect, useRef } from 'react'
// Helper function to update or create meta tags

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

@ -2,7 +2,7 @@ import type { TNoteListRef } from '@/components/NoteList' @@ -2,7 +2,7 @@ import type { TNoteListRef } from '@/components/NoteList'
import Relay from '@/components/Relay'
import { RefreshButton } from '@/components/RefreshButton'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { normalizeUrl, simplifyUrl } from '@/lib/url'
import { forwardRef, useCallback, useEffect, useMemo, useRef } from 'react'
import NotFoundPage from '../NotFoundPage'

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

@ -3,7 +3,7 @@ import NoteList from '@/components/NoteList' @@ -3,7 +3,7 @@ import NoteList from '@/components/NoteList'
import { RefreshButton } from '@/components/RefreshButton'
import { FAST_READ_RELAY_URLS, ExtendedKind } from '@/constants'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { normalizeUrl, simplifyUrl } from '@/lib/url'
import { forwardRef, useCallback, useEffect, useMemo, useRef } from 'react'
import { useTranslation } from 'react-i18next'

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

@ -4,7 +4,7 @@ import SessionRelaysTab from '@/components/SessionRelaysTab' @@ -4,7 +4,7 @@ import SessionRelaysTab from '@/components/SessionRelaysTab'
import { RefreshButton } from '@/components/RefreshButton'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { forwardRef, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'

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

@ -7,7 +7,7 @@ import { Separator } from '@/components/ui/separator' @@ -7,7 +7,7 @@ import { Separator } from '@/components/ui/separator'
import indexedDb from '@/services/indexed-db.service'
import type { RssFeedItem as TRssFeedItem } from '@/services/rss-feed.service'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { decodeRssArticlePathSegment, createRssThreadRootEvent } from '@/lib/rss-article'
import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'

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

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import { RefreshButton } from '@/components/RefreshButton'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { ExtendedKind, FAST_WRITE_RELAY_URLS, PROFILE_RELAY_URLS } from '@/constants'
import { getLatestEvent } from '@/lib/event'
import { forwardRef, useCallback, useEffect, useState } from 'react'

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

@ -6,7 +6,8 @@ import SecondaryPageLayout from '@/layouts/SecondaryPageLayout' @@ -6,7 +6,8 @@ import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { toSearch } from '@/lib/link'
import { parseAdvancedSearch } from '@/lib/search-parser'
import { syncUserDeletionTombstones } from '@/lib/sync-user-deletions'
import { usePrimaryNoteView, useSecondaryPage } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { useSecondaryPage } from '@/PageManager'
import { useNostr } from '@/providers/NostrProvider'
import { TSearchParams } from '@/types'
import { BookOpen } from 'lucide-react'

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

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
import SettingsMenuBody from '@/components/Settings/SettingsMenuBody'
import { RefreshButton } from '@/components/RefreshButton'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { forwardRef, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'

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

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import { RefreshButton } from '@/components/RefreshButton'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { forwardRef, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'

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

@ -12,7 +12,7 @@ import { @@ -12,7 +12,7 @@ import {
import { RefreshButton } from '@/components/RefreshButton'
import { Button } from '@/components/ui/button'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { usePrimaryNoteView } from '@/PageManager'
import { usePrimaryNoteView } from '@/contexts/primary-note-view-context'
import { useZap } from '@/providers/ZapProvider'
import { disconnect, launchModal } from '@getalby/bitcoin-connect-react'
import { forwardRef, useCallback, useEffect, useState } from 'react'

Loading…
Cancel
Save