mirror of
https://github.com/dergigi/boris.git
synced 2026-01-07 17:04:34 +01:00
feat: parse and display summary tag for nostr articles
- Extract 'summary' tag from kind:30023 article bookmarks - Display summary in place of truncated content for articles - Show summary in all view modes (compact, cards, large) - Add article-summary CSS class for potential styling - Follows NIP-23 long-form content specification
This commit is contained in:
@@ -37,11 +37,12 @@ export const BookmarkItem: React.FC<BookmarkItemProps> = ({ bookmark, index, onS
|
||||
const firstUrl = hasUrls ? extractedUrls[0] : null
|
||||
const firstUrlClassification = firstUrl ? classifyUrl(firstUrl) : null
|
||||
|
||||
// For kind:30023 articles, extract image tag (per NIP-23)
|
||||
// For kind:30023 articles, extract image and summary tags (per NIP-23)
|
||||
// Note: We extract directly from tags here since we don't have the full event.
|
||||
// When we have full events, we use getArticleImage() helper (see articleService.ts)
|
||||
const isArticle = bookmark.kind === 30023
|
||||
const articleImage = isArticle ? bookmark.tags.find(t => t[0] === 'image')?.[1] : undefined
|
||||
const articleSummary = isArticle ? bookmark.tags.find(t => t[0] === 'summary')?.[1] : undefined
|
||||
|
||||
// Fetch OG image for large view (hook must be at top level)
|
||||
const instantPreview = firstUrl ? getPreviewImage(firstUrl, firstUrlClassification?.type || '') : null
|
||||
@@ -113,7 +114,8 @@ export const BookmarkItem: React.FC<BookmarkItemProps> = ({ bookmark, index, onS
|
||||
eventNevent,
|
||||
getAuthorDisplayName,
|
||||
handleReadNow,
|
||||
articleImage
|
||||
articleImage,
|
||||
articleSummary
|
||||
}
|
||||
|
||||
if (viewMode === 'compact') {
|
||||
|
||||
@@ -21,6 +21,7 @@ interface CardViewProps {
|
||||
getAuthorDisplayName: () => string
|
||||
handleReadNow: (e: React.MouseEvent<HTMLButtonElement>) => void
|
||||
articleImage?: string
|
||||
articleSummary?: string
|
||||
}
|
||||
|
||||
export const CardView: React.FC<CardViewProps> = ({
|
||||
@@ -35,7 +36,8 @@ export const CardView: React.FC<CardViewProps> = ({
|
||||
eventNevent,
|
||||
getAuthorDisplayName,
|
||||
handleReadNow,
|
||||
articleImage
|
||||
articleImage,
|
||||
articleSummary
|
||||
}) => {
|
||||
const [expanded, setExpanded] = useState(false)
|
||||
const [urlsExpanded, setUrlsExpanded] = useState(false)
|
||||
@@ -122,7 +124,11 @@ export const CardView: React.FC<CardViewProps> = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{bookmark.parsedContent ? (
|
||||
{isArticle && articleSummary ? (
|
||||
<div className="bookmark-content article-summary">
|
||||
<ContentWithResolvedProfiles content={articleSummary} />
|
||||
</div>
|
||||
) : bookmark.parsedContent ? (
|
||||
<div className="bookmark-content">
|
||||
{shouldTruncate && bookmark.content
|
||||
? <ContentWithResolvedProfiles content={`${bookmark.content.slice(0, 210).trimEnd()}…`} />
|
||||
|
||||
@@ -15,6 +15,7 @@ interface CompactViewProps {
|
||||
getIconForUrlType: IconGetter
|
||||
firstUrlClassification: { buttonText: string } | null
|
||||
articleImage?: string
|
||||
articleSummary?: string
|
||||
}
|
||||
|
||||
export const CompactView: React.FC<CompactViewProps> = ({
|
||||
@@ -24,7 +25,8 @@ export const CompactView: React.FC<CompactViewProps> = ({
|
||||
extractedUrls,
|
||||
onSelectUrl,
|
||||
getIconForUrlType,
|
||||
firstUrlClassification
|
||||
firstUrlClassification,
|
||||
articleSummary
|
||||
}) => {
|
||||
const isArticle = bookmark.kind === 30023
|
||||
const isWebBookmark = bookmark.kind === 39701
|
||||
@@ -40,6 +42,11 @@ export const CompactView: React.FC<CompactViewProps> = ({
|
||||
}
|
||||
}
|
||||
|
||||
// For articles, prefer summary; for others, use content
|
||||
const displayText = isArticle && articleSummary
|
||||
? articleSummary
|
||||
: bookmark.content
|
||||
|
||||
return (
|
||||
<div key={`${bookmark.id}-${index}`} className={`individual-bookmark compact ${bookmark.isPrivate ? 'private-bookmark' : ''}`}>
|
||||
<div
|
||||
@@ -63,9 +70,9 @@ export const CompactView: React.FC<CompactViewProps> = ({
|
||||
<FontAwesomeIcon icon={faBookmark} className="bookmark-visibility public" />
|
||||
)}
|
||||
</span>
|
||||
{bookmark.content && (
|
||||
{displayText && (
|
||||
<div className="compact-text">
|
||||
<ContentWithResolvedProfiles content={bookmark.content.slice(0, 60) + (bookmark.content.length > 60 ? '…' : '')} />
|
||||
<ContentWithResolvedProfiles content={displayText.slice(0, 60) + (displayText.length > 60 ? '…' : '')} />
|
||||
</div>
|
||||
)}
|
||||
<span className="bookmark-date-compact">{formatDate(bookmark.created_at)}</span>
|
||||
|
||||
@@ -18,6 +18,7 @@ interface LargeViewProps {
|
||||
eventNevent?: string
|
||||
getAuthorDisplayName: () => string
|
||||
handleReadNow: (e: React.MouseEvent<HTMLButtonElement>) => void
|
||||
articleSummary?: string
|
||||
}
|
||||
|
||||
export const LargeView: React.FC<LargeViewProps> = ({
|
||||
@@ -32,7 +33,8 @@ export const LargeView: React.FC<LargeViewProps> = ({
|
||||
authorNpub,
|
||||
eventNevent,
|
||||
getAuthorDisplayName,
|
||||
handleReadNow
|
||||
handleReadNow,
|
||||
articleSummary
|
||||
}) => {
|
||||
const isArticle = bookmark.kind === 30023
|
||||
|
||||
@@ -59,7 +61,11 @@ export const LargeView: React.FC<LargeViewProps> = ({
|
||||
)}
|
||||
|
||||
<div className="large-content">
|
||||
{bookmark.content && (
|
||||
{isArticle && articleSummary ? (
|
||||
<div className="large-text article-summary">
|
||||
<ContentWithResolvedProfiles content={articleSummary} />
|
||||
</div>
|
||||
) : bookmark.content && (
|
||||
<div className="large-text">
|
||||
<ContentWithResolvedProfiles content={bookmark.content} />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user