feat: add markdown rendering support for Content component

Detect markdown-formatted posts (from bots etc.) and render them
with react-markdown instead of plain text, with feed-friendly
styles (flattened headings, compact lists, scrollable tables).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
codytseng 2026-03-04 10:49:18 +08:00
parent fc8a160d9a
commit cc1aa7f989
3 changed files with 196 additions and 7 deletions

43
src/lib/markdown.ts Normal file
View file

@ -0,0 +1,43 @@
/**
* Detects whether a string contains meaningful Markdown formatting.
* Strips URLs and nostr: references first to avoid false positives.
*/
export function containsMarkdown(content: string): boolean {
// Remove URLs and nostr: references to avoid false positives
const cleaned = content
.replace(/https?:\/\/[^\s)>\]]+/g, '')
.replace(/nostr:[a-z0-9]+/g, '')
// Strong signals — any single one triggers markdown
const strongPatterns = [
/^```/m, // code fence
/\|[\s]*:?-+:?[\s]*\|/ // table separator |---|
]
for (const pattern of strongPatterns) {
if (pattern.test(cleaned)) return true
}
// Medium signals — need 2+ different types
const mediumPatterns = [
/^#{1,6}\s+\S/m, // ATX heading (# text), not #hashtag
/\*\*[^*\n]+\*\*/, // bold **text**
/__[^_\n]+__/, // bold __text__
/\[[^\]]+\]\([^)]+\)/, // link [text](url)
/^>\s+\S/m, // blockquote > text
/^[-*]\s+\S/m, // unordered list - item or * item
/^\d+\.\s+\S/m, // ordered list 1. item
/^---$/m, // horizontal rule
/~~[^~\n]+~~/ // strikethrough ~~text~~
]
let matchCount = 0
for (const pattern of mediumPatterns) {
if (pattern.test(cleaned)) {
matchCount++
if (matchCount >= 2) return true
}
}
return false
}