import React, { useEffect, useState } from 'react'; import { createRoot } from 'react-dom/client'; import Markdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import EngineResearch from './research'; import { resolveDocumentLink } from './file-links.mjs'; import './style.css'; function sourcePositions() { return (tree: any) => { const visit = (node: any) => { if (node.type === 'element' && node.position?.start?.line) node.properties = { ...node.properties, 'data-source-line': node.position.start.line }; node.children?.forEach(visit); }; visit(tree); }; } function DocumentViewer({ path, line }: {path: string, line: number}) { const [text, setText] = useState(null); const [documentPath, setDocumentPath] = useState(path); const [error, setError] = useState(''); useEffect(() => { setText(null); setError(''); const controller = new AbortController(); fetch('/api/file?' + new URLSearchParams({ path }), {signal: controller.signal}) .then(async r => { if (!r.ok) { const optionalSource = /^\.\.\/(UnrealEngine|godot|UnityCsReference|blender-source)\//.test(path); throw new Error(optionalSource && r.status === 404 ? 'Локальный исходник не найден. Sibling checkout движка необязателен и не входит в Faset. Вернитесь к карте или отчёту и используйте upstream-ссылку; для Unreal Engine нужен доступ Epic.' : 'Файл недоступен (' + r.status + ')'); } return r.json(); }) .then(data => { setDocumentPath(data.path); setText(data.text); }).catch(e => { if (e.name !== 'AbortError') setError(e.message); }); return () => controller.abort(); }, [path]); useEffect(() => { if (text === null || !line) return; const frame = requestAnimationFrame(() => { const exact = document.getElementById('L' + line); const nearest = Array.from(document.querySelectorAll('[data-source-line]')).filter(node => Number(node.dataset.sourceLine) <= line).sort((a, b) => Number(b.dataset.sourceLine) - Number(a.dataset.sourceLine))[0]; (exact || nearest)?.scrollIntoView({block: 'center'}); }); return () => cancelAnimationFrame(frame); }, [text, line]); const markdown = /\.md$/i.test(documentPath); return
← Карта исследования{documentPath}
{error &&

{error}

} {text === null && !error &&

Загрузка документа…

} {text !== null && (markdown ?
key === 'href' ? resolveDocumentLink(url, documentPath) || '' : ''} components={{ a: ({href, children}) => { if (!href) return {children}; if (/^https?:/.test(href)) return {children}; if (href.startsWith('#')) return {children}; return {children}; }}}>{text}
:
{text.split('\n').map((s, i) => 
{i + 1}{s || ' '}
)}
)}
; } const params = new URLSearchParams(location.search); createRoot(document.getElementById('root')!).render(params.has('file') ? : );