50 lines
2.5 KiB
TypeScript
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' },
|
|
})
|