Browse Source

bug-fixes

imwald
Silberengel 1 month ago
parent
commit
c2bbf52aac
  1. 3
      src/components/PostEditor/PostContent.tsx
  2. 5
      src/components/PostEditor/PostRelaySelector.tsx
  3. 18
      src/components/PostEditor/PostTextarea/Preview.tsx
  4. 16
      src/components/PostEditor/PostTextarea/index.tsx
  5. 10
      src/components/Sidebar/AccountButton.tsx
  6. 3
      src/constants.ts
  7. 2
      src/lib/kind-description.ts
  8. 988
      src/pages/primary/DiscussionsPage/CreateThreadDialog.tsx
  9. 3
      src/pages/primary/DiscussionsPage/index.tsx
  10. 4
      src/pages/primary/NoteListPage/index.tsx
  11. 30
      src/providers/FavoriteRelaysProvider.tsx
  12. 24
      src/providers/FeedProvider.tsx
  13. 34
      src/providers/favorite-relays-context.tsx
  14. 30
      src/providers/feed-context.tsx

3
src/components/PostEditor/PostContent.tsx

@ -2432,9 +2432,6 @@ export default function PostContent({ @@ -2432,9 +2432,6 @@ export default function PostContent({
</NeventPickerProvider>
{createThreadOpen && (
<CreateThreadDialog
topic="general"
availableRelays={[]}
relaySets={[]}
onClose={() => setCreateThreadOpen(false)}
onThreadCreated={() => {
discussionFeedCache.clearDiscussionsListCache()

5
src/components/PostEditor/PostRelaySelector.tsx

@ -18,6 +18,9 @@ import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover @@ -18,6 +18,9 @@ import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet'
import logger from '@/lib/logger'
/** Stable default when `mentions` is omitted — inline `= []` is a new array every render and retriggers effects. */
const NO_MENTIONS: string[] = []
export default function PostRelaySelector({
parentEvent: _parentEvent,
openFrom,
@ -25,7 +28,7 @@ export default function PostRelaySelector({ @@ -25,7 +28,7 @@ export default function PostRelaySelector({
setAdditionalRelayUrls,
content: postContent = '',
isPublicMessage = false,
mentions = []
mentions = NO_MENTIONS
}: {
parentEvent?: NostrEvent
openFrom?: string[]

18
src/components/PostEditor/PostTextarea/Preview.tsx

@ -25,7 +25,8 @@ export default function Preview({ @@ -25,7 +25,8 @@ export default function Preview({
pollCreateData,
mediaImetaTags,
mediaUrl,
articleMetadata
articleMetadata,
extraPreviewTags
}: {
content: string
className?: string
@ -41,6 +42,8 @@ export default function Preview({ @@ -41,6 +42,8 @@ export default function Preview({
dTag?: string
topics?: string[]
}
/** Merged into the fake event (e.g. kind 11 discussion title / topic tags). */
extraPreviewTags?: string[][]
}) {
const { content: processedContent, emojiTags, highlightTags, pollTags } = useMemo(
() => {
@ -148,8 +151,11 @@ export default function Preview({ @@ -148,8 +151,11 @@ export default function Preview({
tags.push(...normalizedTopics.map((topic) => ['t', topic]))
}
}
if (extraPreviewTags?.length) {
tags.push(...extraPreviewTags)
}
return tags
}, [emojiTags, highlightTags, pollTags, mediaImetaTags, articleMetadata, kind])
}, [emojiTags, highlightTags, pollTags, mediaImetaTags, articleMetadata, kind, extraPreviewTags])
const fakeEvent = useMemo(() => {
// For voice comments, include the media URL in content if not already there
@ -194,6 +200,14 @@ export default function Preview({ @@ -194,6 +200,14 @@ export default function Preview({
)
}
if (kind === ExtendedKind.DISCUSSION) {
return (
<Card className={cn('p-3', className, selectableClass)}>
<MarkdownArticle event={fakeEvent} hideMetadata={true} />
</Card>
)
}
// For LongFormArticle, use MarkdownArticle
if (kind === kinds.LongFormArticle) {
return (

16
src/components/PostEditor/PostTextarea/index.tsx

@ -58,6 +58,7 @@ const PostTextarea = forwardRef< @@ -58,6 +58,7 @@ const PostTextarea = forwardRef<
dTag?: string
topics?: string[]
}
extraPreviewTags?: string[][]
}
>(
(
@ -78,7 +79,8 @@ const PostTextarea = forwardRef< @@ -78,7 +79,8 @@ const PostTextarea = forwardRef<
getDraftEventJson,
mediaImetaTags,
mediaUrl,
articleMetadata
articleMetadata,
extraPreviewTags
},
ref
) => {
@ -243,7 +245,17 @@ const PostTextarea = forwardRef< @@ -243,7 +245,17 @@ const PostTextarea = forwardRef<
<div className="text-xs text-muted-foreground">
kind {kindDescription.number}: {kindDescription.description}
</div>
<Preview content={text} className={className} kind={kind} highlightData={highlightData} pollCreateData={pollCreateData} mediaImetaTags={mediaImetaTags} mediaUrl={mediaUrl} articleMetadata={articleMetadata} />
<Preview
content={text}
className={className}
kind={kind}
highlightData={highlightData}
pollCreateData={pollCreateData}
mediaImetaTags={mediaImetaTags}
mediaUrl={mediaUrl}
articleMetadata={articleMetadata}
extraPreviewTags={extraPreviewTags}
/>
</div>
</TabsContent>
<TabsContent value="json">

10
src/components/Sidebar/AccountButton.tsx

@ -7,11 +7,10 @@ import { @@ -7,11 +7,10 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger
} from '@/components/ui/dropdown-menu'
import { toWallet } from '@/lib/link'
import { formatPubkey, generateImageByPubkey, pubkeyToNpub, formatNpub } from '@/lib/pubkey'
import { usePrimaryPage, useSecondaryPage } from '@/PageManager'
import { usePrimaryPage } from '@/PageManager'
import { useNostr } from '@/providers/NostrProvider'
import { ArrowDownUp, LogIn, LogOut, MoreVertical, Settings, Wallet } from 'lucide-react'
import { ArrowDownUp, LogIn, LogOut, MoreVertical, Settings } from 'lucide-react'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import LoginDialog from '../LoginDialog'
@ -33,7 +32,6 @@ function ProfileButton() { @@ -33,7 +32,6 @@ function ProfileButton() {
const { account, profile } = useNostr()
const pubkey = account?.pubkey
const { navigate } = usePrimaryPage()
const { push } = useSecondaryPage()
const [loginDialogOpen, setLoginDialogOpen] = useState(false)
const [logoutDialogOpen, setLogoutDialogOpen] = useState(false)
if (!pubkey) return null
@ -74,10 +72,6 @@ function ProfileButton() { @@ -74,10 +72,6 @@ function ProfileButton() {
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent side="top" align="end">
<DropdownMenuItem onClick={() => push(toWallet())}>
<Wallet />
{t('Wallet')}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => navigate('settings')}>
<Settings />
{t('Settings')}

3
src/constants.ts

@ -132,7 +132,8 @@ export const KIND_1_BLOCKED_RELAY_URLS = [ @@ -132,7 +132,8 @@ export const KIND_1_BLOCKED_RELAY_URLS = [
'wss://thecitadel.nostr1.com',
'wss://hist.nostr.land',
'wss://profiles.nostr1.com',
'wss://purplepag.es'
'wss://purplepag.es',
'wss://wikifreedia.xyz'
]
// Optimized relay list for read operations (includes aggregator)

2
src/lib/kind-description.ts

@ -44,6 +44,8 @@ export function getKindDescription(kind: number): { number: number; description: @@ -44,6 +44,8 @@ export function getKindDescription(kind: number): { number: number; description:
return { number: 1068, description: 'Poll' }
case ExtendedKind.PUBLIC_MESSAGE:
return { number: 24, description: 'Public Message' }
case ExtendedKind.DISCUSSION:
return { number: 11, description: 'Discussion' }
default:
return { number: kind, description: `Event (kind ${kind})` }
}

988
src/pages/primary/DiscussionsPage/CreateThreadDialog.tsx

File diff suppressed because it is too large Load Diff

3
src/pages/primary/DiscussionsPage/index.tsx

@ -1234,9 +1234,6 @@ const DiscussionsPage = forwardRef<TPageRef, { embedded?: boolean }>(function Di @@ -1234,9 +1234,6 @@ const DiscussionsPage = forwardRef<TPageRef, { embedded?: boolean }>(function Di
{/* Create Thread Dialog */}
{showCreateDialog && (
<CreateThreadDialog
topic="general"
availableRelays={[]}
relaySets={[]}
dynamicTopics={dynamicTopics}
onClose={handleCloseDialog}
onThreadCreated={handleCreateThread}

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

@ -173,8 +173,12 @@ function NoteListPageTitlebar({ @@ -173,8 +173,12 @@ function NoteListPageTitlebar({
<Info />
</Button>
)}
{isSmallScreen && (
<>
<KeyboardShortcutsHelpButton />
<AccountButton />
</>
)}
</div>
</div>
)

30
src/providers/FavoriteRelaysProvider.tsx

@ -9,34 +9,12 @@ import indexedDb from '@/services/indexed-db.service' @@ -9,34 +9,12 @@ import indexedDb from '@/services/indexed-db.service'
import storage from '@/services/local-storage.service'
import { TRelaySet } from '@/types'
import { Event, kinds } from 'nostr-tools'
import { createContext, useContext, useEffect, useState } from 'react'
import { useEffect, useState } from 'react'
import { FavoriteRelaysContext } from './favorite-relays-context'
import { useNostr } from './NostrProvider'
type TFavoriteRelaysContext = {
favoriteRelays: string[]
addFavoriteRelays: (relayUrls: string[]) => Promise<void>
deleteFavoriteRelays: (relayUrls: string[]) => Promise<void>
reorderFavoriteRelays: (reorderedRelays: string[]) => Promise<void>
blockedRelays: string[]
addBlockedRelays: (relayUrls: string[]) => Promise<void>
deleteBlockedRelays: (relayUrls: string[]) => Promise<void>
relaySets: TRelaySet[]
createRelaySet: (relaySetName: string, relayUrls?: string[]) => Promise<void>
addRelaySets: (newRelaySetEvents: Event[]) => Promise<void>
deleteRelaySet: (id: string) => Promise<void>
updateRelaySet: (newSet: TRelaySet) => Promise<void>
reorderRelaySets: (reorderedSets: TRelaySet[]) => Promise<void>
}
const FavoriteRelaysContext = createContext<TFavoriteRelaysContext | undefined>(undefined)
export const useFavoriteRelays = () => {
const context = useContext(FavoriteRelaysContext)
if (!context) {
throw new Error('useFavoriteRelays must be used within a FavoriteRelaysProvider')
}
return context
}
export { useFavoriteRelays } from './favorite-relays-context'
export type { TFavoriteRelaysContext } from './favorite-relays-context'
export function FavoriteRelaysProvider({ children }: { children: React.ReactNode }) {
const { favoriteRelaysEvent, blockedRelaysEvent, updateFavoriteRelaysEvent, updateBlockedRelaysEvent, pubkey, relayList, publish } = useNostr()

24
src/providers/FeedProvider.tsx

@ -6,29 +6,13 @@ import indexedDb from '@/services/indexed-db.service' @@ -6,29 +6,13 @@ import indexedDb from '@/services/indexed-db.service'
import storage from '@/services/local-storage.service'
import { TFeedInfo, TFeedType } from '@/types'
import { kinds } from 'nostr-tools'
import { createContext, useContext, useEffect, useRef, useState, useCallback } from 'react'
import { useEffect, useRef, useState, useCallback } from 'react'
import { FeedContext } from './feed-context'
import { useFavoriteRelays } from './FavoriteRelaysProvider'
import { useNostr } from './NostrProvider'
type TFeedContext = {
feedInfo: TFeedInfo
relayUrls: string[]
isReady: boolean
switchFeed: (
feedType: TFeedType,
options?: { activeRelaySetId?: string; pubkey?: string; relay?: string | null }
) => Promise<void>
}
const FeedContext = createContext<TFeedContext | undefined>(undefined)
export const useFeed = () => {
const context = useContext(FeedContext)
if (!context) {
throw new Error('useFeed must be used within a FeedProvider')
}
return context
}
export { useFeed } from './feed-context'
export type { TFeedContext } from './feed-context'
export function FeedProvider({ children }: { children: React.ReactNode }) {
const { pubkey, isInitialized } = useNostr()

34
src/providers/favorite-relays-context.tsx

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
/**
* Standalone React context for favorite relays so HMR on `FavoriteRelaysProvider.tsx` does not
* recreate `createContext()` (which breaks `useFavoriteRelays` in InterestListProvider,
* FeedProvider, etc. after Fast Refresh).
*/
import { TRelaySet } from '@/types'
import { Event } from 'nostr-tools'
import { createContext, useContext } from 'react'
export type TFavoriteRelaysContext = {
favoriteRelays: string[]
addFavoriteRelays: (relayUrls: string[]) => Promise<void>
deleteFavoriteRelays: (relayUrls: string[]) => Promise<void>
reorderFavoriteRelays: (reorderedRelays: string[]) => Promise<void>
blockedRelays: string[]
addBlockedRelays: (relayUrls: string[]) => Promise<void>
deleteBlockedRelays: (relayUrls: string[]) => Promise<void>
relaySets: TRelaySet[]
createRelaySet: (relaySetName: string, relayUrls?: string[]) => Promise<void>
addRelaySets: (newRelaySetEvents: Event[]) => Promise<void>
deleteRelaySet: (id: string) => Promise<void>
updateRelaySet: (newSet: TRelaySet) => Promise<void>
reorderRelaySets: (reorderedSets: TRelaySet[]) => Promise<void>
}
export const FavoriteRelaysContext = createContext<TFavoriteRelaysContext | undefined>(undefined)
export function useFavoriteRelays(): TFavoriteRelaysContext {
const context = useContext(FavoriteRelaysContext)
if (!context) {
throw new Error('useFavoriteRelays must be used within a FavoriteRelaysProvider')
}
return context
}

30
src/providers/feed-context.tsx

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
/**
* Standalone React context for feed state so HMR on `FeedProvider.tsx` does not recreate
* `createContext()` (which breaks `useFeed` after Fast Refresh).
*/
import { TFeedInfo, TFeedType } from '@/types'
import { createContext, useContext } from 'react'
export type TFeedContext = {
feedInfo: TFeedInfo
relayUrls: string[]
isReady: boolean
switchFeed: (
feedType: TFeedType,
options?: {
activeRelaySetId?: string | null
pubkey?: string | null
relay?: string | null
}
) => Promise<void>
}
export const FeedContext = createContext<TFeedContext | undefined>(undefined)
export function useFeed(): TFeedContext {
const context = useContext(FeedContext)
if (!context) {
throw new Error('useFeed must be used within a FeedProvider')
}
return context
}
Loading…
Cancel
Save