Browse Source

publication export

imwald
Silberengel 5 months ago
parent
commit
0ba08f7a28
  1. 162
      src/components/ArticleExportMenu/ArticleExportMenu.tsx
  2. 2
      src/components/KindFilter/index.tsx
  3. 8
      src/components/Note/AsciidocArticle/AsciidocArticle.tsx
  4. 7
      src/components/Note/LongFormArticlePreview.tsx
  5. 26
      src/components/Note/MarkdownArticle/MarkdownArticle.tsx
  6. 7
      src/components/Note/PublicationCard.tsx
  7. 174
      src/components/Note/PublicationIndex/PublicationIndex.tsx
  8. 4
      src/components/Note/WikiCard.tsx
  9. 10
      src/components/Note/index.tsx
  10. 14
      src/services/local-storage.service.ts

162
src/components/ArticleExportMenu/ArticleExportMenu.tsx

@ -0,0 +1,162 @@
import { Button } from '@/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { MoreVertical, FileDown } from 'lucide-react'
import { contentParserService } from '@/services/content-parser.service'
import logger from '@/lib/logger'
import { Event } from 'nostr-tools'
interface ArticleExportMenuProps {
event: Event
title: string
}
export default function ArticleExportMenu({ event, title }: ArticleExportMenuProps) {
const exportArticle = async (format: 'pdf' | 'epub' | 'latex' | 'adoc' | 'html') => {
try {
const content = event.content
const filename = `${title}.${format}`
let blob: Blob = new Blob([''])
if (format === 'adoc') {
// Export raw AsciiDoc content
blob = new Blob([content], { type: 'text/plain' })
} else if (format === 'html') {
// Parse the AsciiDoc content to HTML
const parsedContent = await contentParserService.parseContent(content, {
eventKind: event.kind,
enableMath: true,
enableSyntaxHighlighting: true
})
const htmlDocument = `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${title}</title>
<style>
body { font-family: Georgia, serif; max-width: 800px; margin: 0 auto; padding: 20px; line-height: 1.6; }
h1 { color: #333; border-bottom: 2px solid #333; padding-bottom: 10px; }
h2 { color: #555; margin-top: 30px; }
code { background: #f4f4f4; padding: 2px 6px; border-radius: 3px; font-family: monospace; }
pre { background: #f4f4f4; padding: 15px; border-radius: 5px; overflow-x: auto; }
blockquote { border-left: 4px solid #ddd; margin-left: 0; padding-left: 20px; color: #666; }
</style>
</head>
<body>
<article>
<h1>${title}</h1>
${parsedContent.html}
</article>
</body>
</html>`
blob = new Blob([htmlDocument], { type: 'text/html' })
} else if (format === 'latex') {
// Basic LaTeX conversion
let processedContent = content.replace(/^= (.+)$/gm, '\\section{$1}')
processedContent = processedContent.replace(/^== (.+)$/gm, '\\subsection{$1}')
processedContent = processedContent.replace(/^=== (.+)$/gm, '\\subsubsection{$1}')
blob = new Blob([processedContent], { type: 'text/plain' })
} else if (format === 'pdf' || format === 'epub') {
// Parse the AsciiDoc content to HTML using the content parser
const parsedContent = await contentParserService.parseContent(content, {
eventKind: event.kind,
enableMath: true,
enableSyntaxHighlighting: true
})
const htmlDocument = `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${title}</title>
<style>
body { font-family: Georgia, serif; max-width: 800px; margin: 0 auto; padding: 20px; line-height: 1.6; }
h1 { color: #333; border-bottom: 2px solid #333; padding-bottom: 10px; }
h2 { color: #555; margin-top: 30px; }
code { background: #f4f4f4; padding: 2px 6px; border-radius: 3px; font-family: monospace; }
pre { background: #f4f4f4; padding: 15px; border-radius: 5px; overflow-x: auto; }
blockquote { border-left: 4px solid #ddd; margin-left: 0; padding-left: 20px; color: #666; }
</style>
</head>
<body>
<article>
<h1>${title}</h1>
${parsedContent.html}
</article>
</body>
</html>`
blob = new Blob([htmlDocument], { type: 'text/html' })
}
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = filename
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(url)
logger.info(`[ArticleExportMenu] Exported article as ${format}`)
} catch (error) {
logger.error('[ArticleExportMenu] Error exporting article:', error)
alert('Failed to export article. Please try again.')
}
}
return (
<DropdownMenu>
<DropdownMenuTrigger asChild onClick={(e) => e.stopPropagation()}>
<Button variant="ghost" size="icon" className="shrink-0">
<MoreVertical className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" onClick={(e) => e.stopPropagation()} className="w-56">
<DropdownMenuItem onClick={() => exportArticle('html')}>
<FileDown className="mr-2 h-4 w-4" />
<div>
<div>Export as HTML</div>
<div className="text-xs text-muted-foreground">Ready to view in browser</div>
</div>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => exportArticle('adoc')}>
<FileDown className="mr-2 h-4 w-4" />
<div>
<div>Export as AsciiDoc</div>
<div className="text-xs text-muted-foreground">Raw .adoc file</div>
</div>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => exportArticle('pdf')}>
<FileDown className="mr-2 h-4 w-4" />
<div>
<div>Export as PDF</div>
<div className="text-xs text-muted-foreground">HTML - use browser Print to PDF</div>
</div>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => exportArticle('epub')}>
<FileDown className="mr-2 h-4 w-4" />
<div>
<div>Export as EPUB</div>
<div className="text-xs text-muted-foreground">HTML - convert with Calibre</div>
</div>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => exportArticle('latex')}>
<FileDown className="mr-2 h-4 w-4" />
<div>
<div>Export as LaTeX</div>
<div className="text-xs text-muted-foreground">Basic conversion</div>
</div>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}

2
src/components/KindFilter/index.tsx

@ -16,6 +16,8 @@ const KIND_FILTER_OPTIONS = [
{ kindGroup: [kinds.ShortTextNote, ExtendedKind.COMMENT], label: 'Posts' }, { kindGroup: [kinds.ShortTextNote, ExtendedKind.COMMENT], label: 'Posts' },
{ kindGroup: [kinds.Repost], label: 'Reposts' }, { kindGroup: [kinds.Repost], label: 'Reposts' },
{ kindGroup: [kinds.LongFormArticle], label: 'Articles' }, { kindGroup: [kinds.LongFormArticle], label: 'Articles' },
{ kindGroup: [ExtendedKind.PUBLICATION], label: 'Publications' },
{ kindGroup: [ExtendedKind.WIKI_ARTICLE], label: 'Wiki Articles' },
{ kindGroup: [kinds.Highlights], label: 'Highlights' }, { kindGroup: [kinds.Highlights], label: 'Highlights' },
{ kindGroup: [ExtendedKind.POLL], label: 'Polls' }, { kindGroup: [ExtendedKind.POLL], label: 'Polls' },
{ kindGroup: [ExtendedKind.VOICE, ExtendedKind.VOICE_COMMENT], label: 'Voice Posts' }, { kindGroup: [ExtendedKind.VOICE, ExtendedKind.VOICE_COMMENT], label: 'Voice Posts' },

8
src/components/Note/AsciidocArticle/AsciidocArticle.tsx

@ -16,10 +16,12 @@ import { ExtendedKind } from '@/constants'
export default function AsciidocArticle({ export default function AsciidocArticle({
event, event,
className className,
hideImagesAndInfo = false
}: { }: {
event: Event event: Event
className?: string className?: string
hideImagesAndInfo?: boolean
}) { }) {
const { push } = useSecondaryPage() const { push } = useSecondaryPage()
const metadata = useMemo(() => getLongFormArticleMetadataFromEvent(event), [event]) const metadata = useMemo(() => getLongFormArticleMetadataFromEvent(event), [event])
@ -309,7 +311,7 @@ export default function AsciidocArticle({
/> />
{/* Image Carousel - Collapsible */} {/* Image Carousel - Collapsible */}
{allImages.length > 0 && ( {!hideImagesAndInfo && allImages.length > 0 && (
<Collapsible open={isImagesOpen} onOpenChange={setIsImagesOpen} className="mt-8"> <Collapsible open={isImagesOpen} onOpenChange={setIsImagesOpen} className="mt-8">
<CollapsibleTrigger asChild> <CollapsibleTrigger asChild>
<Button variant="outline" className="w-full justify-between"> <Button variant="outline" className="w-full justify-between">
@ -324,7 +326,7 @@ export default function AsciidocArticle({
)} )}
{/* Collapsible Article Info - only for article-type events */} {/* Collapsible Article Info - only for article-type events */}
{isArticleType && (parsedContent?.links?.length > 0 || parsedContent?.nostrLinks?.length > 0 || parsedContent?.highlightSources?.length > 0 || parsedContent?.hashtags?.length > 0) && ( {!hideImagesAndInfo && isArticleType && (parsedContent?.links?.length > 0 || parsedContent?.nostrLinks?.length > 0 || parsedContent?.highlightSources?.length > 0 || parsedContent?.hashtags?.length > 0) && (
<Collapsible open={isInfoOpen} onOpenChange={setIsInfoOpen} className="mt-4"> <Collapsible open={isInfoOpen} onOpenChange={setIsInfoOpen} className="mt-4">
<CollapsibleTrigger asChild> <CollapsibleTrigger asChild>
<Button variant="outline" className="w-full justify-between"> <Button variant="outline" className="w-full justify-between">

7
src/components/Note/LongFormArticlePreview.tsx

@ -6,6 +6,7 @@ import { useScreenSize } from '@/providers/ScreenSizeProvider'
import { Event, kinds } from 'nostr-tools' import { Event, kinds } from 'nostr-tools'
import { useMemo } from 'react' import { useMemo } from 'react'
import Image from '../Image' import Image from '../Image'
import ArticleExportMenu from '../ArticleExportMenu/ArticleExportMenu'
export default function LongFormArticlePreview({ export default function LongFormArticlePreview({
event, event,
@ -65,6 +66,9 @@ export default function LongFormArticlePreview({
{titleComponent} {titleComponent}
{summaryComponent} {summaryComponent}
{tagsComponent} {tagsComponent}
<div className="flex justify-end">
<ArticleExportMenu event={event} title={metadata.title || 'Article'} />
</div>
</div> </div>
</div> </div>
</div> </div>
@ -89,6 +93,9 @@ export default function LongFormArticlePreview({
{titleComponent} {titleComponent}
{summaryComponent} {summaryComponent}
{tagsComponent} {tagsComponent}
<div className="flex justify-end">
<ArticleExportMenu event={event} title={metadata.title || 'Article'} />
</div>
</div> </div>
</div> </div>
</div> </div>

26
src/components/Note/MarkdownArticle/MarkdownArticle.tsx

@ -20,10 +20,12 @@ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/component
export default function MarkdownArticle({ export default function MarkdownArticle({
event, event,
className className,
showImageGallery = false
}: { }: {
event: Event event: Event
className?: string className?: string
showImageGallery?: boolean
}) { }) {
const { push } = useSecondaryPage() const { push } = useSecondaryPage()
const metadata = useMemo(() => getLongFormArticleMetadataFromEvent(event), [event]) const metadata = useMemo(() => getLongFormArticleMetadataFromEvent(event), [event])
@ -164,12 +166,24 @@ export default function MarkdownArticle({
return <>{children}</> return <>{children}</>
}, },
img: () => { img: ({ src }) => {
// Don't render inline images - they'll be shown in the carousel if (!src) return null
// If showing image gallery, don't render inline images - they'll be shown in the carousel
if (showImageGallery) {
return null return null
} }
// For all other content, render images inline
return (
<ImageWithLightbox
image={{ url: src, pubkey: event.pubkey }}
className="max-w-full rounded-lg my-2"
/>
)
}
}) as Components, }) as Components,
[] [showImageGallery, event.pubkey]
) )
return ( return (
@ -273,8 +287,8 @@ export default function MarkdownArticle({
{event.content} {event.content}
</Markdown> </Markdown>
{/* Image Carousel - Collapsible */} {/* Image Carousel - Only show for article content (30023, 30041, 30818) */}
{allImages.length > 0 && ( {showImageGallery && allImages.length > 0 && (
<Collapsible open={isImagesOpen} onOpenChange={setIsImagesOpen} className="mt-8"> <Collapsible open={isImagesOpen} onOpenChange={setIsImagesOpen} className="mt-8">
<CollapsibleTrigger asChild> <CollapsibleTrigger asChild>
<Button variant="outline" className="w-full justify-between"> <Button variant="outline" className="w-full justify-between">

7
src/components/Note/PublicationCard.tsx

@ -8,6 +8,7 @@ import { nip19 } from 'nostr-tools'
import { useMemo } from 'react' import { useMemo } from 'react'
import { BookOpen } from 'lucide-react' import { BookOpen } from 'lucide-react'
import Image from '../Image' import Image from '../Image'
import ArticleExportMenu from '../ArticleExportMenu/ArticleExportMenu'
export default function PublicationCard({ export default function PublicationCard({
event, event,
@ -105,7 +106,8 @@ export default function PublicationCard({
{titleComponent} {titleComponent}
{summaryComponent} {summaryComponent}
{tagsComponent} {tagsComponent}
<div className="flex justify-end"> <div className="flex justify-end gap-2 items-center">
<ArticleExportMenu event={event} title={metadata.title || 'Article'} />
{alexandriaButton} {alexandriaButton}
</div> </div>
</div> </div>
@ -132,7 +134,8 @@ export default function PublicationCard({
{titleComponent} {titleComponent}
{summaryComponent} {summaryComponent}
{tagsComponent} {tagsComponent}
<div className="flex justify-end"> <div className="flex justify-end gap-2 items-center">
<ArticleExportMenu event={event} title={metadata.title || 'Article'} />
{alexandriaButton} {alexandriaButton}
</div> </div>
</div> </div>

174
src/components/Note/PublicationIndex/PublicationIndex.tsx

@ -6,6 +6,15 @@ import AsciidocArticle from '../AsciidocArticle/AsciidocArticle'
import { generateBech32IdFromATag } from '@/lib/tag' import { generateBech32IdFromATag } from '@/lib/tag'
import client from '@/services/client.service' import client from '@/services/client.service'
import logger from '@/lib/logger' import logger from '@/lib/logger'
import { Button } from '@/components/ui/button'
import { contentParserService } from '@/services/content-parser.service'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { MoreVertical, FileDown } from 'lucide-react'
interface PublicationReference { interface PublicationReference {
coordinate: string coordinate: string
@ -138,6 +147,136 @@ export default function PublicationIndex({
} }
} }
// Export publication in different formats
const exportPublication = async (format: 'pdf' | 'epub' | 'latex' | 'adoc' | 'html') => {
try {
// Collect all content from references
const contentParts: string[] = []
for (const ref of references) {
if (!ref.event) continue
// Extract title
const title = ref.event.tags.find(tag => tag[0] === 'title')?.[1] || 'Untitled'
// Extract raw content
let content = ref.event.content
if (format === 'adoc') {
// For AsciiDoc, output the raw content with title
contentParts.push(`= ${title}\n\n${content}\n\n`)
} else if (format === 'html') {
// For HTML, parse the AsciiDoc content to HTML
const parsedContent = await contentParserService.parseContent(content, {
eventKind: ref.kind,
enableMath: true,
enableSyntaxHighlighting: true
})
contentParts.push(`<article>
<h1>${title}</h1>
${parsedContent.html}
</article>`)
} else if (format === 'latex') {
// Convert to LaTeX
content = content.replace(/^= (.+)$/gm, '\\section{$1}')
content = content.replace(/^== (.+)$/gm, '\\subsection{$1}')
content = content.replace(/^=== (.+)$/gm, '\\subsubsection{$1}')
contentParts.push(`\\section*{${title}}\n\n${content}\n\n`)
} else if (format === 'pdf' || format === 'epub') {
// For PDF/EPUB, we need to export as HTML that can be converted
// Parse the AsciiDoc content to HTML using the content parser
const parsedContent = await contentParserService.parseContent(content, {
eventKind: ref.kind,
enableMath: true,
enableSyntaxHighlighting: true
})
contentParts.push(`<article>
<h1>${title}</h1>
${parsedContent.html}
</article>`)
}
}
const fullContent = contentParts.join('\n')
const filename = `${metadata.title || 'publication'}.${format}`
let blob: Blob = new Blob([''])
if (format === 'html') {
// For HTML, wrap the content in a full HTML document
const htmlDocument = `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${metadata.title || 'Publication'}</title>
<style>
body { font-family: Georgia, serif; max-width: 800px; margin: 0 auto; padding: 20px; line-height: 1.6; }
h1 { color: #333; border-bottom: 2px solid #333; padding-bottom: 10px; }
h2 { color: #555; margin-top: 30px; }
code { background: #f4f4f4; padding: 2px 6px; border-radius: 3px; font-family: monospace; }
pre { background: #f4f4f4; padding: 15px; border-radius: 5px; overflow-x: auto; }
blockquote { border-left: 4px solid #ddd; margin-left: 0; padding-left: 20px; color: #666; }
table { border-collapse: collapse; width: 100%; margin: 20px 0; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
${fullContent}
</body>
</html>`
blob = new Blob([htmlDocument], { type: 'text/html' })
} else if (format === 'pdf' || format === 'epub') {
// For PDF/EPUB, wrap the HTML content in a full HTML document
const htmlDocument = `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${metadata.title || 'Publication'}</title>
<style>
body { font-family: Georgia, serif; max-width: 800px; margin: 0 auto; padding: 20px; line-height: 1.6; }
h1 { color: #333; border-bottom: 2px solid #333; padding-bottom: 10px; }
h2 { color: #555; margin-top: 30px; }
code { background: #f4f4f4; padding: 2px 6px; border-radius: 3px; font-family: monospace; }
pre { background: #f4f4f4; padding: 15px; border-radius: 5px; overflow-x: auto; }
blockquote { border-left: 4px solid #ddd; margin-left: 0; padding-left: 20px; color: #666; }
table { border-collapse: collapse; width: 100%; margin: 20px 0; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
${fullContent}
</body>
</html>`
blob = new Blob([htmlDocument], { type: 'text/html' })
} else {
// For AsciiDoc or LaTeX formats, use the raw content
blob = new Blob([fullContent], {
type: format === 'latex' ? 'text/plain' : 'text/plain'
})
}
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = filename
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(url)
logger.info(`[PublicationIndex] Exported publication as ${format}`)
} catch (error) {
logger.error('[PublicationIndex] Error exporting publication:', error)
alert('Failed to export publication. Please try again.')
}
}
// Extract references from 'a' tags // Extract references from 'a' tags
const referencesData = useMemo(() => { const referencesData = useMemo(() => {
const refs: PublicationReference[] = [] const refs: PublicationReference[] = []
@ -225,7 +364,38 @@ export default function PublicationIndex({
{/* Publication Metadata */} {/* Publication Metadata */}
<div className="prose prose-zinc max-w-none dark:prose-invert"> <div className="prose prose-zinc max-w-none dark:prose-invert">
<header className="mb-8 border-b pb-6"> <header className="mb-8 border-b pb-6">
<h1 className="text-4xl font-bold mb-4 leading-tight break-words">{metadata.title}</h1> <div className="flex items-start justify-between gap-4 mb-4">
<h1 className="text-4xl font-bold leading-tight break-words flex-1">{metadata.title}</h1>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="shrink-0">
<MoreVertical className="h-5 w-5" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => exportPublication('html')}>
<FileDown className="mr-2 h-4 w-4" />
Export as HTML
</DropdownMenuItem>
<DropdownMenuItem onClick={() => exportPublication('adoc')}>
<FileDown className="mr-2 h-4 w-4" />
Export as AsciiDoc
</DropdownMenuItem>
<DropdownMenuItem onClick={() => exportPublication('pdf')}>
<FileDown className="mr-2 h-4 w-4" />
Export as PDF
</DropdownMenuItem>
<DropdownMenuItem onClick={() => exportPublication('epub')}>
<FileDown className="mr-2 h-4 w-4" />
Export as EPUB
</DropdownMenuItem>
<DropdownMenuItem onClick={() => exportPublication('latex')}>
<FileDown className="mr-2 h-4 w-4" />
Export as LaTeX
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
{metadata.summary && ( {metadata.summary && (
<blockquote className="border-l-4 border-primary pl-6 italic text-muted-foreground mb-4 text-lg leading-relaxed"> <blockquote className="border-l-4 border-primary pl-6 italic text-muted-foreground mb-4 text-lg leading-relaxed">
<p className="break-words">{metadata.summary}</p> <p className="break-words">{metadata.summary}</p>
@ -300,7 +470,7 @@ export default function PublicationIndex({
// Render 30041 or 30818 content as AsciidocArticle // Render 30041 or 30818 content as AsciidocArticle
return ( return (
<div key={index} id={sectionId} className="scroll-mt-4"> <div key={index} id={sectionId} className="scroll-mt-4">
<AsciidocArticle event={ref.event} /> <AsciidocArticle event={ref.event} hideImagesAndInfo={true} />
</div> </div>
) )
} else { } else {

4
src/components/Note/WikiCard.tsx

@ -8,6 +8,7 @@ import { nip19 } from 'nostr-tools'
import { useMemo } from 'react' import { useMemo } from 'react'
import { BookOpen, Globe } from 'lucide-react' import { BookOpen, Globe } from 'lucide-react'
import Image from '../Image' import Image from '../Image'
import ArticleExportMenu from '../ArticleExportMenu/ArticleExportMenu'
export default function WikiCard({ export default function WikiCard({
event, event,
@ -89,7 +90,8 @@ export default function WikiCard({
) )
const buttons = ( const buttons = (
<div className="flex gap-2 flex-wrap"> <div className="flex gap-2 flex-wrap items-center">
<ArticleExportMenu event={event} title={metadata.title || 'Article'} />
{dTag && ( {dTag && (
<button <button
onClick={handleWikistrClick} onClick={handleWikistrClick}

10
src/components/Note/index.tsx

@ -120,7 +120,7 @@ export default function Note({
) )
} else if (event.kind === kinds.LongFormArticle) { } else if (event.kind === kinds.LongFormArticle) {
content = showFull ? ( content = showFull ? (
<MarkdownArticle className="mt-2" event={event} /> <MarkdownArticle className="mt-2" event={event} showImageGallery={true} />
) : ( ) : (
<LongFormArticlePreview className="mt-2" event={event} /> <LongFormArticlePreview className="mt-2" event={event} />
) )
@ -159,8 +159,12 @@ export default function Note({
} else if (event.kind === ExtendedKind.ZAP_REQUEST || event.kind === ExtendedKind.ZAP_RECEIPT) { } else if (event.kind === ExtendedKind.ZAP_REQUEST || event.kind === ExtendedKind.ZAP_RECEIPT) {
content = <Zap className="mt-2" event={event} /> content = <Zap className="mt-2" event={event} />
} else { } else {
// Use MarkdownArticle for all other kinds (including kinds 1 and 11) // Use MarkdownArticle for all other kinds
content = <MarkdownArticle className="mt-2" event={event} /> // Only 30023, 30041, and 30818 will show image gallery and article info
const showImageGallery = event.kind === kinds.LongFormArticle ||
event.kind === ExtendedKind.PUBLICATION_CONTENT ||
event.kind === ExtendedKind.WIKI_ARTICLE
content = <MarkdownArticle className="mt-2" event={event} showImageGallery={showImageGallery} />
} }
return ( return (

14
src/services/local-storage.service.ts

@ -195,10 +195,22 @@ class LocalStorageService {
showKinds.splice(repostIndex, 1) showKinds.splice(repostIndex, 1)
} }
} }
if (showKindsVersion < 4) {
// Add publications and wiki articles to existing users' filters
if (!showKinds.includes(ExtendedKind.PUBLICATION)) {
showKinds.push(ExtendedKind.PUBLICATION)
}
if (!showKinds.includes(ExtendedKind.PUBLICATION_CONTENT)) {
showKinds.push(ExtendedKind.PUBLICATION_CONTENT)
}
if (!showKinds.includes(ExtendedKind.WIKI_ARTICLE)) {
showKinds.push(ExtendedKind.WIKI_ARTICLE)
}
}
this.showKinds = showKinds this.showKinds = showKinds
} }
window.localStorage.setItem(StorageKey.SHOW_KINDS, JSON.stringify(this.showKinds)) window.localStorage.setItem(StorageKey.SHOW_KINDS, JSON.stringify(this.showKinds))
window.localStorage.setItem(StorageKey.SHOW_KINDS_VERSION, '3') window.localStorage.setItem(StorageKey.SHOW_KINDS_VERSION, '4')
this.hideContentMentioningMutedUsers = this.hideContentMentioningMutedUsers =
window.localStorage.getItem(StorageKey.HIDE_CONTENT_MENTIONING_MUTED_USERS) === 'true' window.localStorage.getItem(StorageKey.HIDE_CONTENT_MENTIONING_MUTED_USERS) === 'true'

Loading…
Cancel
Save