import { Fragment, useMemo } from 'react'
import type { ReactNode } from 'react'
/**
* Dil anahtarlarında tutulan düz açıklama metnini okunur bir yapıya çevirir.
* Metnin kendisi HTML taşımaz; biçim yalnızca aşağıdaki sözleşmeden türetilir,
* böylece veritabanından gelen içerik sayfaya HTML olarak enjekte edilmez.
*
* - `\n` ile ayrılmış her satır bir blok,
* - `• ` ile başlayan ardışık satırlar madde listesi,
* - `Etiket: ...` biçimindeki satır başlığı kalın,
* - madde içindeki `Ad → açıklama` kalıbında ok öncesi kalın,
* - nokta içeren kod benzeri belirteçler ve adresler tek aralıklı rozet.
*/
const CODE_TOKEN = /((?:https?:\/\/\S+)|(?:[A-Za-z][\w-]*(?:\.[\w*-]+)+))/g
const LABEL_LINE = /^([^:]{2,48}):\s+(.*)$/
const BULLET_HEAD = /^(.+?)\s→\s(.*)$/
const withCode = (text: string, keyPrefix: string): ReactNode[] =>
text.split(CODE_TOKEN).map((part, index) => {
if (index % 2 === 0) return {part}
// Cümle sonundaki noktalama rozetin içinde kalmasın.
const trimmed = part.replace(/[.,;:]+$/, '')
// "e.g." gibi kısaltmalar kod değildir; rozet yalnızca adres ve tanımlayıcılara.
if (!/^https?:/.test(trimmed) && !/[A-Z]/.test(trimmed)) {
return {part}
}
const rest = part.slice(trimmed.length)
return (
{trimmed}
{rest}
)
})
const Bullet = ({ text, itemKey }: { text: string; itemKey: string }) => {
const head = BULLET_HEAD.exec(text)
if (!head) {
return
{withCode(text, itemKey)}
}
return (
{head[1]}
{' → '}
{withCode(head[2], itemKey)}
)
}
const RichText = ({ text }: { text: string }) => {
const blocks = useMemo(() => {
const lines = text.split('\n').filter((line) => line.trim().length > 0)
const grouped: { type: 'line' | 'list'; items: string[] }[] = []
lines.forEach((line) => {
const trimmed = line.trim()
const isBullet = trimmed.startsWith('•')
const last = grouped[grouped.length - 1]
if (isBullet && last?.type === 'list') {
last.items.push(trimmed.replace(/^•\s*/, ''))
} else if (isBullet) {
grouped.push({ type: 'list', items: [trimmed.replace(/^•\s*/, '')] })
} else {
grouped.push({ type: 'line', items: [trimmed] })
}
})
return grouped
}, [text])
return (
{blocks.map((block, blockIndex) => {
if (block.type === 'list') {
return (
{block.items.map((item, itemIndex) => (
))}
)
}
const line = block.items[0]
const label = LABEL_LINE.exec(line)
if (blockIndex === 0) {
return (
{withCode(line, `b${blockIndex}`)}
)
}
if (!label) {
return
{withCode(line, `b${blockIndex}`)}
}
return (
{label[1]}: {withCode(label[2], `b${blockIndex}`)}
)
})}
)
}
RichText.displayName = 'TooltipRichText'
export default RichText