Browse Source

more parsing updates

imwald
Silberengel 5 months ago
parent
commit
88bcaf3e15
  1. 2
      src/components/ContentPreview/Content.tsx
  2. 1
      src/components/Embedded/EmbeddedMention.tsx
  3. 12
      src/components/Note/index.tsx
  4. 20
      src/components/Username/index.tsx
  5. 23
      src/lib/nostr-parser.tsx
  6. 13
      src/pages/secondary/NotePage/index.tsx

2
src/components/ContentPreview/Content.tsx

@ -32,7 +32,7 @@ export default function Content({ @@ -32,7 +32,7 @@ export default function Content({
}, [content])
return (
<span className={cn('pointer-events-none', className)}>
<span className={cn(className)}>
{nodes.map((node, index) => {
if (node.type === 'image' || node.type === 'images') {
return index > 0 ? ` [${t('Image')}]` : `[${t('Image')}]`

1
src/components/Embedded/EmbeddedMention.tsx

@ -7,6 +7,7 @@ export function EmbeddedMention({ userId, className }: { userId: string; classNa @@ -7,6 +7,7 @@ export function EmbeddedMention({ userId, className }: { userId: string; classNa
userId={userId}
showAt
className={cn('text-primary font-normal inline', className)}
style={{ verticalAlign: 'baseline' }}
withoutSkeleton
/>
)

12
src/components/Note/index.tsx

@ -156,7 +156,17 @@ export default function Note({ @@ -156,7 +156,17 @@ export default function Note({
}
return (
<div className={className}>
<div
className={`${className} clickable`}
onClick={(e) => {
// Don't navigate if clicking on interactive elements
const target = e.target as HTMLElement
if (target.closest('button') || target.closest('[role="button"]') || target.closest('a')) {
return
}
navigateToNote(toNote(event))
}}
>
<div className="flex justify-between items-start gap-2">
<div className="flex items-center space-x-2 flex-1">
<UserAvatar userId={event.pubkey} size={size === 'small' ? 'medium' : 'normal'} />

20
src/components/Username/index.tsx

@ -9,13 +9,15 @@ export default function Username({ @@ -9,13 +9,15 @@ export default function Username({
showAt = false,
className,
skeletonClassName,
withoutSkeleton = false
withoutSkeleton = false,
style
}: {
userId: string
showAt?: boolean
className?: string
skeletonClassName?: string
withoutSkeleton?: boolean
style?: React.CSSProperties
}) {
const { profile } = useFetchProfile(userId)
const { navigateToProfile } = useSmartProfileNavigation()
@ -35,13 +37,14 @@ export default function Username({ @@ -35,13 +37,14 @@ export default function Username({
const { username, pubkey } = profile
return (
<div
<span
className={cn('truncate hover:underline cursor-pointer', className)}
style={{ verticalAlign: 'baseline', ...style }}
onClick={() => navigateToProfile(toProfile(pubkey))}
>
{showAt && '@'}
{username}
</div>
</span>
)
}
@ -50,13 +53,15 @@ export function SimpleUsername({ @@ -50,13 +53,15 @@ export function SimpleUsername({
showAt = false,
className,
skeletonClassName,
withoutSkeleton = false
withoutSkeleton = false,
style
}: {
userId: string
showAt?: boolean
className?: string
skeletonClassName?: string
withoutSkeleton?: boolean
style?: React.CSSProperties
}) {
const { profile } = useFetchProfile(userId)
@ -75,9 +80,12 @@ export function SimpleUsername({ @@ -75,9 +80,12 @@ export function SimpleUsername({
const { username } = profile
return (
<div className={cn('truncate', className)}>
<span
className={cn('truncate', className)}
style={{ verticalAlign: 'baseline', ...style }}
>
{showAt && '@'}
{username}
</div>
</span>
)
}

23
src/lib/nostr-parser.tsx

@ -173,12 +173,33 @@ export function parseNostrContent(content: string, event?: Event): ParsedNostrCo @@ -173,12 +173,33 @@ export function parseNostrContent(content: string, event?: Event): ParsedNostrCo
const bech32Id = match[1]
const nostrType = getNostrType(bech32Id)
// Add spacing around handles if they're not at the beginning or end of a line
const isAtStart = start === 0 || content[start - 1] === '\n'
const isAtEnd = end === content.length || content[end] === '\n'
const needsSpaceBefore = !isAtStart && content[start - 1] !== ' '
const needsSpaceAfter = !isAtEnd && content[end] !== ' '
if (needsSpaceBefore) {
elements.push({
type: 'text',
content: ' '
})
}
elements.push({
type: 'nostr',
content: match[0],
bech32Id,
nostrType: nostrType || undefined
})
if (needsSpaceAfter) {
elements.push({
type: 'text',
content: ' '
})
}
} else if (['image', 'video', 'audio'].includes(type) && url) {
elements.push({
type: type as 'image' | 'video' | 'audio',
@ -485,7 +506,7 @@ export function renderNostrContent(parsedContent: ParsedNostrContent, className? @@ -485,7 +506,7 @@ export function renderNostrContent(parsedContent: ParsedNostrContent, className?
<EmbeddedMention
key={index}
userId={element.bech32Id}
className="not-prose inline-block"
className="inline"
/>
)
} else if (['nevent', 'naddr', 'note'].includes(element.nostrType)) {

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

@ -201,12 +201,21 @@ function ParentNote({ @@ -201,12 +201,21 @@ function ParentNote({
'flex space-x-1 px-[0.4375rem] py-1 items-center rounded-full border clickable text-sm text-muted-foreground',
event && 'hover:text-foreground'
)}
onClick={() => {
onClick={(e) => {
e.stopPropagation()
navigateToNote(toNote(event ?? eventBech32Id))
}}
>
{event && <UserAvatar userId={event.pubkey} size="tiny" className="shrink-0" />}
<ContentPreview className="truncate" event={event} />
<div
className="truncate flex-1"
onClick={(e) => {
e.stopPropagation()
navigateToNote(toNote(event ?? eventBech32Id))
}}
>
<ContentPreview event={event} />
</div>
</div>
{isConsecutive ? (
<div className="ml-5 w-px h-3 bg-border" />

Loading…
Cancel
Save