guardia-messenger/components/MarkdownViewer.tsx

50 lines
2.5 KiB
TypeScript

import React from 'react'
import { View, Text, ScrollView, StyleSheet } from 'react-native'
import { COLORS } from '../constants/Config'
interface Props { content: string; style?: object }
export default function MarkdownViewer({ content, style }: Props) {
const lines = content.split('\n')
return (
<ScrollView style={[s.wrap, style]}>
{lines.map((line, i) => {
if (line.startsWith('### ')) return <Text key={i} style={s.h3}>{line.slice(4)}</Text>
if (line.startsWith('## ')) return <Text key={i} style={s.h2}>{line.slice(3)}</Text>
if (line.startsWith('# ')) return <Text key={i} style={s.h1}>{line.slice(2)}</Text>
if (line.startsWith('---')) return <View key={i} style={s.hr} />
if (line.startsWith('> ')) return <View key={i} style={s.blockquote}><Text style={s.bqText}>{line.slice(2)}</Text></View>
if (line.startsWith('- ') || line.startsWith('* ')) return <Text key={i} style={s.li}>{' • '}{renderInline(line.slice(2))}</Text>
if (/^\d+\. /.test(line)) {
const [num, ...rest] = line.split('. ')
return <Text key={i} style={s.li}>{` ${num}. `}{renderInline(rest.join('. '))}</Text>
}
if (line.startsWith('```')) return <View key={i} style={s.codeBlock}><Text style={s.code}>{line.slice(3)}</Text></View>
if (line === '') return <View key={i} style={{ height: 8 }} />
return <Text key={i} style={s.body}>{renderInline(line)}</Text>
})}
</ScrollView>
)
}
function renderInline(text: string): string {
return text
.replace(/\*\*(.+?)\*\*/g, '$1')
.replace(/`(.+?)`/g, '$1')
.replace(/_(.+?)_/g, '$1')
}
const s = StyleSheet.create({
wrap: { flex: 1 },
h1: { fontSize: 20, fontWeight: '800', color: COLORS.text, marginVertical: 8 },
h2: { fontSize: 17, fontWeight: '700', color: COLORS.text, marginVertical: 6 },
h3: { fontSize: 15, fontWeight: '700', color: COLORS.primary, marginVertical: 4 },
body: { fontSize: 14, color: COLORS.text, lineHeight: 22, marginVertical: 1 },
li: { fontSize: 14, color: COLORS.text, lineHeight: 22 },
hr: { height: 1, backgroundColor: COLORS.border, marginVertical: 8 },
blockquote: { borderLeftWidth: 3, borderLeftColor: COLORS.accent, paddingLeft: 10, marginVertical: 4 },
bqText: { fontSize: 13, color: COLORS.muted, fontStyle: 'italic' },
codeBlock: { backgroundColor: '#1E293B', borderRadius: 6, padding: 10, marginVertical: 6 },
code: { fontSize: 12, color: '#E2E8F0', fontFamily: 'monospace' },
})