diff --git a/README.md b/README.md index 95828ac4..e5dc4aab 100644 --- a/README.md +++ b/README.md @@ -92,23 +92,21 @@ docker compose up --build -d Then open: http://localhost:8089 -## Sponsors (original Jumble) +## Linux desktop (`.deb` / AppImage) - - open-sats-logo - +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 diff --git a/src/PageManager.tsx b/src/PageManager.tsx index 0acd4c48..ca6e4129 100644 --- a/src/PageManager.tsx +++ b/src/PageManager.tsx @@ -22,7 +22,6 @@ import { NotificationProvider } from '@/providers/NotificationProvider' import { TPageRef } from '@/types' import { cloneElement, - createContext, createRef, isValidElement, lazy, @@ -31,7 +30,6 @@ import { RefObject, Suspense, useCallback, - useContext, useEffect, useMemo, useRef, @@ -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( 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 diff --git a/src/components/AccountManager/index.tsx b/src/components/AccountManager/index.tsx index 8a953d19..ccc4eb31 100644 --- a/src/components/AccountManager/index.tsx +++ b/src/components/AccountManager/index.tsx @@ -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({ - {isDevEnv() && ( - - )} + diff --git a/src/components/BottomNavigationBar/HomeButton.tsx b/src/components/BottomNavigationBar/HomeButton.tsx index 5b92bde1..fda2ffe5 100644 --- a/src/components/BottomNavigationBar/HomeButton.tsx +++ b/src/components/BottomNavigationBar/HomeButton.tsx @@ -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' diff --git a/src/components/BottomNavigationBar/RssButton.tsx b/src/components/BottomNavigationBar/RssButton.tsx index f92ea7ac..46d8f8ad 100644 --- a/src/components/BottomNavigationBar/RssButton.tsx +++ b/src/components/BottomNavigationBar/RssButton.tsx @@ -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' diff --git a/src/components/BottomNavigationBar/SearchButton.tsx b/src/components/BottomNavigationBar/SearchButton.tsx index 44e025b0..cbc4b09c 100644 --- a/src/components/BottomNavigationBar/SearchButton.tsx +++ b/src/components/BottomNavigationBar/SearchButton.tsx @@ -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' diff --git a/src/components/BottomNavigationBar/SpellsButton.tsx b/src/components/BottomNavigationBar/SpellsButton.tsx index 9eb24f32..a34b087b 100644 --- a/src/components/BottomNavigationBar/SpellsButton.tsx +++ b/src/components/BottomNavigationBar/SpellsButton.tsx @@ -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' diff --git a/src/components/NormalFeed/index.tsx b/src/components/NormalFeed/index.tsx index 2cd3858c..ebf6a7e4 100644 --- a/src/components/NormalFeed/index.tsx +++ b/src/components/NormalFeed/index.tsx @@ -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 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 handleListModeChange(tab)} - options={} + options={ +
+ {onSubHeaderRefresh != null && } + +
+ } /> ) @@ -78,7 +87,7 @@ const NormalFeed = forwardRef setSubHeader(null) - }, [isMainFeed, setSubHeader, listMode, temporaryShowKinds]) + }, [isMainFeed, setSubHeader, listMode, temporaryShowKinds, onSubHeaderRefresh]) const renderTabsInFeed = !(isMainFeed && setSubHeader) diff --git a/src/components/Sidebar/DiscussionsButton.tsx b/src/components/Sidebar/DiscussionsButton.tsx index db4d75df..f9c1ae7b 100644 --- a/src/components/Sidebar/DiscussionsButton.tsx +++ b/src/components/Sidebar/DiscussionsButton.tsx @@ -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' diff --git a/src/components/Sidebar/FeedButton.tsx b/src/components/Sidebar/FeedButton.tsx index 149b659b..ccefe841 100644 --- a/src/components/Sidebar/FeedButton.tsx +++ b/src/components/Sidebar/FeedButton.tsx @@ -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' diff --git a/src/components/Sidebar/HomeButton.tsx b/src/components/Sidebar/HomeButton.tsx index d358ee5c..3ca2c101 100644 --- a/src/components/Sidebar/HomeButton.tsx +++ b/src/components/Sidebar/HomeButton.tsx @@ -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' diff --git a/src/components/Sidebar/NotificationButton.tsx b/src/components/Sidebar/NotificationButton.tsx index 8edf0167..652ff7b8 100644 --- a/src/components/Sidebar/NotificationButton.tsx +++ b/src/components/Sidebar/NotificationButton.tsx @@ -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' diff --git a/src/components/Sidebar/RssButton.tsx b/src/components/Sidebar/RssButton.tsx index 73a38706..f249c6b8 100644 --- a/src/components/Sidebar/RssButton.tsx +++ b/src/components/Sidebar/RssButton.tsx @@ -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' diff --git a/src/components/Sidebar/SearchButton.tsx b/src/components/Sidebar/SearchButton.tsx index ef96718e..4da8e7a1 100644 --- a/src/components/Sidebar/SearchButton.tsx +++ b/src/components/Sidebar/SearchButton.tsx @@ -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' diff --git a/src/components/Sidebar/SpellsButton.tsx b/src/components/Sidebar/SpellsButton.tsx index 1c0c0122..c0671cf6 100644 --- a/src/components/Sidebar/SpellsButton.tsx +++ b/src/components/Sidebar/SpellsButton.tsx @@ -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' diff --git a/src/contexts/note-drawer-context.tsx b/src/contexts/note-drawer-context.tsx new file mode 100644 index 00000000..b648320d --- /dev/null +++ b/src/contexts/note-drawer-context.tsx @@ -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(undefined) + +export function useNoteDrawer(): NoteDrawerContextValue { + const context = useContext(NoteDrawerContext) + if (!context) { + throw new Error('useNoteDrawer must be used within a NoteDrawerContext.Provider') + } + return context +} diff --git a/src/contexts/primary-note-view-context.tsx b/src/contexts/primary-note-view-context.tsx new file mode 100644 index 00000000..60a90608 --- /dev/null +++ b/src/contexts/primary-note-view-context.tsx @@ -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(undefined) + +export function usePrimaryNoteView(): PrimaryNoteViewContextValue { + const context = useContext(PrimaryNoteViewContext) + if (!context) { + throw new Error('usePrimaryNoteView must be used within a PrimaryNoteViewContext.Provider') + } + return context +} diff --git a/src/i18n/locales/ar.ts b/src/i18n/locales/ar.ts index 6d16b9af..93c0c2bb 100644 --- a/src/i18n/locales/ar.ts +++ b/src/i18n/locales/ar.ts @@ -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': 'إضافة حساب', diff --git a/src/i18n/locales/de.ts b/src/i18n/locales/de.ts index bdda244c..af240697 100644 --- a/src/i18n/locales/de.ts +++ b/src/i18n/locales/de.ts @@ -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', diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index d33f176d..789cfddc 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -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', diff --git a/src/i18n/locales/es.ts b/src/i18n/locales/es.ts index e831efad..52da15bb 100644 --- a/src/i18n/locales/es.ts +++ b/src/i18n/locales/es.ts @@ -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', diff --git a/src/i18n/locales/fa.ts b/src/i18n/locales/fa.ts index b1f73833..d4ee0252 100644 --- a/src/i18n/locales/fa.ts +++ b/src/i18n/locales/fa.ts @@ -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': 'افزودن حساب', diff --git a/src/i18n/locales/fr.ts b/src/i18n/locales/fr.ts index a5117b59..bf8a28d6 100644 --- a/src/i18n/locales/fr.ts +++ b/src/i18n/locales/fr.ts @@ -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', diff --git a/src/i18n/locales/hi.ts b/src/i18n/locales/hi.ts index 12fb8d9d..4c14c82c 100644 --- a/src/i18n/locales/hi.ts +++ b/src/i18n/locales/hi.ts @@ -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': 'अकाउंट जोड़ें', diff --git a/src/i18n/locales/it.ts b/src/i18n/locales/it.ts index ec9958d1..4ebb0f19 100644 --- a/src/i18n/locales/it.ts +++ b/src/i18n/locales/it.ts @@ -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', diff --git a/src/i18n/locales/ja.ts b/src/i18n/locales/ja.ts index 23015099..d945fdd3 100644 --- a/src/i18n/locales/ja.ts +++ b/src/i18n/locales/ja.ts @@ -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': 'アカウントを追加', diff --git a/src/i18n/locales/ko.ts b/src/i18n/locales/ko.ts index 54ec58c6..e7c17aa1 100644 --- a/src/i18n/locales/ko.ts +++ b/src/i18n/locales/ko.ts @@ -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': '계정 추가', diff --git a/src/i18n/locales/pl.ts b/src/i18n/locales/pl.ts index c2ab1e49..5004d69f 100644 --- a/src/i18n/locales/pl.ts +++ b/src/i18n/locales/pl.ts @@ -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', diff --git a/src/i18n/locales/pt-BR.ts b/src/i18n/locales/pt-BR.ts index 6a149f5a..3d4a8467 100644 --- a/src/i18n/locales/pt-BR.ts +++ b/src/i18n/locales/pt-BR.ts @@ -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', diff --git a/src/i18n/locales/pt-PT.ts b/src/i18n/locales/pt-PT.ts index 74e68cc4..dc3d9927 100644 --- a/src/i18n/locales/pt-PT.ts +++ b/src/i18n/locales/pt-PT.ts @@ -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', diff --git a/src/i18n/locales/ru.ts b/src/i18n/locales/ru.ts index 9b6e3335..05f9a8c7 100644 --- a/src/i18n/locales/ru.ts +++ b/src/i18n/locales/ru.ts @@ -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': 'Добавить аккаунт', diff --git a/src/i18n/locales/th.ts b/src/i18n/locales/th.ts index 6114fa27..fba9e4e9 100644 --- a/src/i18n/locales/th.ts +++ b/src/i18n/locales/th.ts @@ -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': 'เพิ่มบัญชี', diff --git a/src/i18n/locales/zh.ts b/src/i18n/locales/zh.ts index 39308ba0..be67108a 100644 --- a/src/i18n/locales/zh.ts +++ b/src/i18n/locales/zh.ts @@ -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': '添加账户', diff --git a/src/pages/primary/NoteListPage/FollowingFeed.tsx b/src/pages/primary/NoteListPage/FollowingFeed.tsx index 6261546e..ecea59cc 100644 --- a/src/pages/primary/NoteListPage/FollowingFeed.tsx +++ b/src/pages/primary/NoteListPage/FollowingFeed.tsx @@ -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< void init() }, [feedInfo.feedType, pubkey, favoriteRelays, blockedRelays, relayList]) - return + return ( + + ) }) FollowingFeed.displayName = 'FollowingFeed' diff --git a/src/pages/primary/NoteListPage/RelaysFeed.tsx b/src/pages/primary/NoteListPage/RelaysFeed.tsx index 3637ee78..9084cd93 100644 --- a/src/pages/primary/NoteListPage/RelaysFeed.tsx +++ b/src/pages/primary/NoteListPage/RelaysFeed.tsx @@ -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< areAlgoRelays={areAlgoRelays} isMainFeed setSubHeader={setSubHeader} + onSubHeaderRefresh={onSubHeaderRefresh} /> ) }) diff --git a/src/pages/primary/NoteListPage/index.tsx b/src/pages/primary/NoteListPage/index.tsx index f876ad15..64e89152 100644 --- a/src/pages/primary/NoteListPage/index.tsx +++ b/src/pages/primary/NoteListPage/index.tsx @@ -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((_, ref) => { const { t } = useTranslation() @@ -40,6 +40,12 @@ const NoteListPage = forwardRef((_, ref) => { const [showRelayDetails, setShowRelayDetails] = useState(false) const [homeSubHeader, setHomeSubHeader] = useState(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((_, 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((_, ref) => { content = } } else if (feedInfo.feedType === 'following') { - content = + content = ( + + ) } else { content = ( <> {showRelayDetails && feedInfo.feedType === 'relay' && !!feedInfo.id && ( )} - + ) } @@ -143,6 +154,7 @@ const NoteListPage = forwardRef((_, ref) => { onFeedRefresh: () => void + showTitlebarRefresh: boolean showRelayDetails?: boolean setShowRelayDetails?: Dispatch> }) { @@ -217,7 +231,7 @@ function NoteListPageTitlebar({ )}
- + {showTitlebarRefresh && } {setShowRelayDetails && (