refactor: move bookmarks entry location

This commit is contained in:
codytseng
2025-10-19 15:46:45 +08:00
parent a847c4dc56
commit 5c2a016d4b
13 changed files with 95 additions and 69 deletions

View File

@@ -20,6 +20,7 @@ import BottomNavigationBar from './components/BottomNavigationBar'
import CreateWalletGuideToast from './components/CreateWalletGuideToast' import CreateWalletGuideToast from './components/CreateWalletGuideToast'
import TooManyRelaysAlertDialog from './components/TooManyRelaysAlertDialog' import TooManyRelaysAlertDialog from './components/TooManyRelaysAlertDialog'
import { normalizeUrl } from './lib/url' import { normalizeUrl } from './lib/url'
import BookmarkPage from './pages/primary/BookmarkPage'
import ExplorePage from './pages/primary/ExplorePage' import ExplorePage from './pages/primary/ExplorePage'
import MePage from './pages/primary/MePage' import MePage from './pages/primary/MePage'
import NotificationListPage from './pages/primary/NotificationListPage' import NotificationListPage from './pages/primary/NotificationListPage'
@@ -61,7 +62,8 @@ const PRIMARY_PAGE_REF_MAP = {
me: createRef<TPageRef>(), me: createRef<TPageRef>(),
profile: createRef<TPageRef>(), profile: createRef<TPageRef>(),
relay: createRef<TPageRef>(), relay: createRef<TPageRef>(),
search: createRef<TPageRef>() search: createRef<TPageRef>(),
bookmark: createRef<TPageRef>()
} }
const PRIMARY_PAGE_MAP = { const PRIMARY_PAGE_MAP = {
@@ -71,7 +73,8 @@ const PRIMARY_PAGE_MAP = {
me: <MePage ref={PRIMARY_PAGE_REF_MAP.me} />, me: <MePage ref={PRIMARY_PAGE_REF_MAP.me} />,
profile: <ProfilePage ref={PRIMARY_PAGE_REF_MAP.profile} />, profile: <ProfilePage ref={PRIMARY_PAGE_REF_MAP.profile} />,
relay: <RelayPage ref={PRIMARY_PAGE_REF_MAP.relay} />, relay: <RelayPage ref={PRIMARY_PAGE_REF_MAP.relay} />,
search: <SearchPage ref={PRIMARY_PAGE_REF_MAP.search} /> search: <SearchPage ref={PRIMARY_PAGE_REF_MAP.search} />,
bookmark: <BookmarkPage ref={PRIMARY_PAGE_REF_MAP.bookmark} />
} }
const PrimaryPageContext = createContext<TPrimaryPageContext | undefined>(undefined) const PrimaryPageContext = createContext<TPrimaryPageContext | undefined>(undefined)

View File

@@ -4,7 +4,7 @@ import { SecondaryPageLink } from '@/PageManager'
import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider' import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider'
import { useFeed } from '@/providers/FeedProvider' import { useFeed } from '@/providers/FeedProvider'
import { useNostr } from '@/providers/NostrProvider' import { useNostr } from '@/providers/NostrProvider'
import { BookmarkIcon, UsersRound } from 'lucide-react' import { UsersRound } from 'lucide-react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import RelayIcon from '../RelayIcon' import RelayIcon from '../RelayIcon'
import RelaySetCard from '../RelaySetCard' import RelaySetCard from '../RelaySetCard'
@@ -35,24 +35,6 @@ export default function FeedSwitcher({ close }: { close?: () => void }) {
</FeedSwitcherItem> </FeedSwitcherItem>
)} )}
{pubkey && (
<FeedSwitcherItem
isActive={feedInfo.feedType === 'bookmarks'}
onClick={() => {
if (!pubkey) return
switchFeed('bookmarks', { pubkey })
close?.()
}}
>
<div className="flex gap-2 items-center">
<div className="flex justify-center items-center w-6 h-6 shrink-0">
<BookmarkIcon className="size-4" />
</div>
<div>{t('Bookmarks')}</div>
</div>
</FeedSwitcherItem>
)}
<div className="flex justify-end items-center text-sm"> <div className="flex justify-end items-center text-sm">
<SecondaryPageLink <SecondaryPageLink
to={toRelaySettings()} to={toRelaySettings()}

View File

@@ -0,0 +1,20 @@
import { usePrimaryPage } from '@/PageManager'
import { useNostr } from '@/providers/NostrProvider'
import { Bookmark } from 'lucide-react'
import SidebarItem from './SidebarItem'
export default function BookmarkButton({ collapse }: { collapse: boolean }) {
const { navigate, current } = usePrimaryPage()
const { checkLogin } = useNostr()
return (
<SidebarItem
title="Bookmarks"
onClick={() => checkLogin(() => navigate('bookmark'))}
active={current === 'bookmark'}
collapse={collapse}
>
<Bookmark />
</SidebarItem>
)
}

View File

@@ -1,11 +1,13 @@
import Icon from '@/assets/Icon' import Icon from '@/assets/Icon'
import Logo from '@/assets/Logo' import Logo from '@/assets/Logo'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { useNostr } from '@/providers/NostrProvider'
import { useScreenSize } from '@/providers/ScreenSizeProvider' import { useScreenSize } from '@/providers/ScreenSizeProvider'
import { useTheme } from '@/providers/ThemeProvider' import { useTheme } from '@/providers/ThemeProvider'
import { useUserPreferences } from '@/providers/UserPreferencesProvider' import { useUserPreferences } from '@/providers/UserPreferencesProvider'
import { ChevronsLeft, ChevronsRight } from 'lucide-react' import { ChevronsLeft, ChevronsRight } from 'lucide-react'
import AccountButton from './AccountButton' import AccountButton from './AccountButton'
import BookmarkButton from './BookmarkButton'
import RelaysButton from './ExploreButton' import RelaysButton from './ExploreButton'
import HomeButton from './HomeButton' import HomeButton from './HomeButton'
import NotificationsButton from './NotificationButton' import NotificationsButton from './NotificationButton'
@@ -18,6 +20,7 @@ export default function PrimaryPageSidebar() {
const { isSmallScreen } = useScreenSize() const { isSmallScreen } = useScreenSize()
const { themeSetting } = useTheme() const { themeSetting } = useTheme()
const { sidebarCollapse, updateSidebarCollapse, enableSingleColumnLayout } = useUserPreferences() const { sidebarCollapse, updateSidebarCollapse, enableSingleColumnLayout } = useUserPreferences()
const { pubkey } = useNostr()
if (isSmallScreen) return null if (isSmallScreen) return null
@@ -43,6 +46,7 @@ export default function PrimaryPageSidebar() {
<NotificationsButton collapse={sidebarCollapse && !enableSingleColumnLayout} /> <NotificationsButton collapse={sidebarCollapse && !enableSingleColumnLayout} />
<SearchButton collapse={sidebarCollapse && !enableSingleColumnLayout} /> <SearchButton collapse={sidebarCollapse && !enableSingleColumnLayout} />
<ProfileButton collapse={sidebarCollapse && !enableSingleColumnLayout} /> <ProfileButton collapse={sidebarCollapse && !enableSingleColumnLayout} />
{pubkey && <BookmarkButton collapse={sidebarCollapse && !enableSingleColumnLayout} />}
<SettingsButton collapse={sidebarCollapse && !enableSingleColumnLayout} /> <SettingsButton collapse={sidebarCollapse && !enableSingleColumnLayout} />
<PostButton collapse={sidebarCollapse && !enableSingleColumnLayout} /> <PostButton collapse={sidebarCollapse && !enableSingleColumnLayout} />
</div> </div>

View File

@@ -1,6 +1,6 @@
import { TSearchParams } from '@/types'
import { Event, nip19 } from 'nostr-tools' import { Event, nip19 } from 'nostr-tools'
import { getNoteBech32Id } from './event' import { getNoteBech32Id } from './event'
import { TSearchParams } from '@/types'
export const toHome = () => '/' export const toHome = () => '/'
export const toNote = (eventOrId: Event | string) => { export const toNote = (eventOrId: Event | string) => {
@@ -76,6 +76,7 @@ export const toRelay = (url: string) => `/relays/${encodeURIComponent(url)}`
export const toRelayReviews = (url: string) => `/relays/${encodeURIComponent(url)}/reviews` export const toRelayReviews = (url: string) => `/relays/${encodeURIComponent(url)}/reviews`
export const toMuteList = () => '/mutes' export const toMuteList = () => '/mutes'
export const toRizful = () => '/rizful' export const toRizful = () => '/rizful'
export const toBookmarks = () => '/bookmarks'
export const toChachiChat = (relay: string, d: string) => { export const toChachiChat = (relay: string, d: string) => {
return `https://chachi.chat/${relay.replace(/^wss?:\/\//, '').replace(/\/$/, '')}/${d}` return `https://chachi.chat/${relay.replace(/^wss?:\/\//, '').replace(/\/$/, '')}/${d}`

View File

@@ -0,0 +1,35 @@
import BookmarkList from '@/components/BookmarkList'
import PrimaryPageLayout from '@/layouts/PrimaryPageLayout'
import { TPageRef } from '@/types'
import { BookmarkIcon } from 'lucide-react'
import { forwardRef, useImperativeHandle, useRef } from 'react'
import { useTranslation } from 'react-i18next'
const BookmarkPage = forwardRef((_, ref) => {
const layoutRef = useRef<TPageRef>(null)
useImperativeHandle(ref, () => layoutRef.current)
return (
<PrimaryPageLayout
pageName="bookmark"
ref={layoutRef}
titlebar={<BookmarkPageTitlebar />}
displayScrollToTopButton
>
<BookmarkList />
</PrimaryPageLayout>
)
})
BookmarkPage.displayName = 'BookmarkPage'
export default BookmarkPage
function BookmarkPageTitlebar() {
const { t } = useTranslation()
return (
<div className="flex gap-2 items-center h-full pl-3">
<BookmarkIcon />
<div className="text-lg font-semibold">{t('Bookmarks')}</div>
</div>
)
}

View File

@@ -1,19 +1,20 @@
import AccountManager from '@/components/AccountManager' import AccountManager from '@/components/AccountManager'
import LoginDialog from '@/components/LoginDialog' import LoginDialog from '@/components/LoginDialog'
import LogoutDialog from '@/components/LogoutDialog' import LogoutDialog from '@/components/LogoutDialog'
import PubkeyCopy from '@/components/PubkeyCopy'
import NpubQrCode from '@/components/NpubQrCode' import NpubQrCode from '@/components/NpubQrCode'
import PubkeyCopy from '@/components/PubkeyCopy'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { Separator } from '@/components/ui/separator' import { Separator } from '@/components/ui/separator'
import { SimpleUserAvatar } from '@/components/UserAvatar' import { SimpleUserAvatar } from '@/components/UserAvatar'
import { SimpleUsername } from '@/components/Username' import { SimpleUsername } from '@/components/Username'
import PrimaryPageLayout from '@/layouts/PrimaryPageLayout' import PrimaryPageLayout from '@/layouts/PrimaryPageLayout'
import { toProfile, toRelaySettings, toSettings, toWallet } from '@/lib/link' import { toBookmarks, toProfile, toRelaySettings, toSettings, toWallet } from '@/lib/link'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { useSecondaryPage } from '@/PageManager' import { useSecondaryPage } from '@/PageManager'
import { useNostr } from '@/providers/NostrProvider' import { useNostr } from '@/providers/NostrProvider'
import { import {
ArrowDownUp, ArrowDownUp,
Bookmark,
ChevronRight, ChevronRight,
LogOut, LogOut,
Server, Server,
@@ -75,6 +76,9 @@ const MePage = forwardRef((_, ref) => {
<Item onClick={() => push(toRelaySettings())}> <Item onClick={() => push(toRelaySettings())}>
<Server /> {t('Relays')} <Server /> {t('Relays')}
</Item> </Item>
<Item onClick={() => push(toBookmarks())}>
<Bookmark /> {t('Bookmarks')}
</Item>
<Item onClick={() => push(toWallet())}> <Item onClick={() => push(toWallet())}>
<Wallet /> <Wallet />
{t('Wallet')} {t('Wallet')}

View File

@@ -6,7 +6,7 @@ import { cn } from '@/lib/utils'
import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider' import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider'
import { useFeed } from '@/providers/FeedProvider' import { useFeed } from '@/providers/FeedProvider'
import { useScreenSize } from '@/providers/ScreenSizeProvider' import { useScreenSize } from '@/providers/ScreenSizeProvider'
import { BookmarkIcon, ChevronDown, Server, UsersRound } from 'lucide-react' import { ChevronDown, Server, UsersRound } from 'lucide-react'
import { forwardRef, HTMLAttributes, useMemo, useState } from 'react' import { forwardRef, HTMLAttributes, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@@ -62,9 +62,6 @@ const FeedSwitcherTrigger = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivEle
if (feedInfo.feedType === 'following') { if (feedInfo.feedType === 'following') {
return t('Following') return t('Following')
} }
if (feedInfo.feedType === 'bookmarks') {
return t('Bookmarks')
}
if (relayUrls.length === 0) { if (relayUrls.length === 0) {
return t('Choose a relay') return t('Choose a relay')
} }
@@ -82,13 +79,7 @@ const FeedSwitcherTrigger = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivEle
ref={ref} ref={ref}
{...props} {...props}
> >
{feedInfo.feedType === 'following' ? ( {feedInfo.feedType === 'following' ? <UsersRound /> : <Server />}
<UsersRound />
) : feedInfo.feedType === 'bookmarks' ? (
<BookmarkIcon />
) : (
<Server />
)}
<div className="text-lg font-semibold truncate">{title}</div> <div className="text-lg font-semibold truncate">{title}</div>
<ChevronDown /> <ChevronDown />
</div> </div>

View File

@@ -1,5 +1,4 @@
import { useSecondaryPage } from '@/PageManager' import { useSecondaryPage } from '@/PageManager'
import BookmarkList from '@/components/BookmarkList'
import PostEditor from '@/components/PostEditor' import PostEditor from '@/components/PostEditor'
import RelayInfo from '@/components/RelayInfo' import RelayInfo from '@/components/RelayInfo'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
@@ -60,18 +59,6 @@ const NoteListPage = forwardRef((_, ref) => {
</Button> </Button>
</div> </div>
) )
} else if (feedInfo.feedType === 'bookmarks') {
if (!pubkey) {
content = (
<div className="flex justify-center w-full">
<Button size="lg" onClick={() => checkLogin()}>
{t('Please login to view bookmarks')}
</Button>
</div>
)
} else {
content = <BookmarkList />
}
} else if (feedInfo.feedType === 'following') { } else if (feedInfo.feedType === 'following') {
content = <FollowingFeed /> content = <FollowingFeed />
} else { } else {

View File

@@ -0,0 +1,16 @@
import BookmarkList from '@/components/BookmarkList'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { forwardRef } from 'react'
import { useTranslation } from 'react-i18next'
const BookmarkPage = forwardRef(({ index }: { index?: number }, ref) => {
const { t } = useTranslation()
return (
<SecondaryPageLayout index={index} title={t('Bookmarks')} displayScrollToTopButton ref={ref}>
<BookmarkList />
</SecondaryPageLayout>
)
})
BookmarkPage.displayName = 'BookmarkPage'
export default BookmarkPage

View File

@@ -69,10 +69,6 @@ export function FeedProvider({ children }: { children: React.ReactNode }) {
if (feedInfo.feedType === 'following' && pubkey) { if (feedInfo.feedType === 'following' && pubkey) {
return await switchFeed('following', { pubkey }) return await switchFeed('following', { pubkey })
} }
if (feedInfo.feedType === 'bookmarks' && pubkey) {
return await switchFeed('bookmarks', { pubkey })
}
} }
init() init()
@@ -147,21 +143,6 @@ export function FeedProvider({ children }: { children: React.ReactNode }) {
setIsReady(true) setIsReady(true)
return return
} }
if (feedType === 'bookmarks') {
if (!options.pubkey) {
setIsReady(true)
return
}
const newFeedInfo = { feedType }
setFeedInfo(newFeedInfo)
feedInfoRef.current = newFeedInfo
storage.setFeedInfo(newFeedInfo, pubkey)
setRelayUrls([])
setIsReady(true)
return
}
setIsReady(true) setIsReady(true)
} }

View File

@@ -1,6 +1,7 @@
import { match } from 'path-to-regexp' import { match } from 'path-to-regexp'
import { isValidElement } from 'react' import { isValidElement } from 'react'
import AppearanceSettingsPage from './pages/secondary/AppearanceSettingsPage' import AppearanceSettingsPage from './pages/secondary/AppearanceSettingsPage'
import BookmarkPage from './pages/secondary/BookmarkPage'
import FollowingListPage from './pages/secondary/FollowingListPage' import FollowingListPage from './pages/secondary/FollowingListPage'
import GeneralSettingsPage from './pages/secondary/GeneralSettingsPage' import GeneralSettingsPage from './pages/secondary/GeneralSettingsPage'
import MuteListPage from './pages/secondary/MuteListPage' import MuteListPage from './pages/secondary/MuteListPage'
@@ -39,7 +40,8 @@ const ROUTES = [
{ path: '/settings/translation', element: <TranslationPage /> }, { path: '/settings/translation', element: <TranslationPage /> },
{ path: '/profile-editor', element: <ProfileEditorPage /> }, { path: '/profile-editor', element: <ProfileEditorPage /> },
{ path: '/mutes', element: <MuteListPage /> }, { path: '/mutes', element: <MuteListPage /> },
{ path: '/rizful', element: <RizfulPage /> } { path: '/rizful', element: <RizfulPage /> },
{ path: '/bookmarks', element: <BookmarkPage /> }
] ]
export const routes = ROUTES.map(({ path, element }) => ({ export const routes = ROUTES.map(({ path, element }) => ({

View File

@@ -106,7 +106,7 @@ export type TAccount = {
export type TAccountPointer = Pick<TAccount, 'pubkey' | 'signerType'> export type TAccountPointer = Pick<TAccount, 'pubkey' | 'signerType'>
export type TFeedType = 'following' | 'relays' | 'relay' | 'bookmarks' export type TFeedType = 'following' | 'relays' | 'relay'
export type TFeedInfo = { feedType: TFeedType; id?: string } export type TFeedInfo = { feedType: TFeedType; id?: string }
export type TLanguage = 'en' | 'zh' | 'pl' export type TLanguage = 'en' | 'zh' | 'pl'