{text}
+ + // Собираем все вхождения с их индексами + const marks = [] + issues.forEach((issue, issueIdx) => { + if (!issue.original) return + let start = 0 + while (true) { + const idx = text.indexOf(issue.original, start) + if (idx === -1) break + marks.push({ + from: idx, + to: idx + issue.original.length, + color: CATEGORY_COLORS[issue.category] || '#E2E8F0', + issueIdx + }) + start = idx + 1 + } + }) + + // Сортируем по позиции + marks.sort((a, b) => a.from - b.from) + + // Строим части текста + const parts = [] + let cursor = 0 + + marks.forEach(({ from, to, color, issueIdx }) => { + if (from < cursor) return // перекрытие — пропускаем + if (cursor < from) { + parts.push( + {text.slice(cursor, from)} + ) + } + parts.push( + + {text.slice(from, to)} + + ) + cursor = to + }) + + if (cursor < text.length) { + parts.push({text.slice(cursor)}) + } + + return ( ++ {parts} +
+ ) +} + +export default function ReportModal({ result, text, language, onClose, onExport }) { + const [selectedFormat, setSelectedFormat] = useState('docx') + const [activeCategory, setActiveCategory] = useState(null) + + if (!result) return null + + const issues = result.issues || [] + const stats = result.statistics || {} + const grouped = issues.reduce((acc, issue) => { + if (!acc[issue.category]) acc[issue.category] = [] + acc[issue.category].push(issue) + return acc + }, {}) + + const categories = Object.keys(grouped) + const filteredIssues = activeCategory + ? grouped[activeCategory] || [] + : issues + + return ( + // Затемнённый фон ++ {issue.description} +
+