Initial commit

This commit is contained in:
Тимур Абайдулин
2025-11-21 00:16:32 +03:00
commit 8ceb9e8781
33 changed files with 5940 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
import { useState, useMemo } from 'react';
import { syntaxHighlight } from '../utils/syntaxHighlight';
import './JsonViewer.css';
export type FontFamily = 'jetbrains' | 'fira';
interface JsonViewerProps {
value: string;
title?: string;
placeholder?: string;
fontFamily?: FontFamily;
}
const FONT_FAMILIES = {
jetbrains: "'JetBrains Mono', monospace",
fira: "'Fira Mono', monospace"
};
export function JsonViewer({
value,
title = 'Форматированный JSON',
placeholder = 'Форматированный результат появится здесь...',
fontFamily = 'jetbrains'
}: JsonViewerProps) {
const [copied, setCopied] = useState(false);
const highlightedValue = useMemo(() => {
return value ? syntaxHighlight(value) : '';
}, [value]);
const handleCopy = async () => {
if (!value) return;
try {
await navigator.clipboard.writeText(value);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch (err) {
console.error('Ошибка копирования:', err);
}
};
return (
<div className="json-viewer">
<div className="viewer-header">
<h2>{title}</h2>
{value && (
<button
className="copy-button"
onClick={handleCopy}
title="Копировать в буфер обмена"
>
{copied ? (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<polyline points="20 6 9 17 4 12" />
</svg>
) : (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
</svg>
)}
</button>
)}
</div>
{value ? (
<pre
className="viewer-content"
dangerouslySetInnerHTML={{ __html: highlightedValue }}
style={{ fontFamily: FONT_FAMILIES[fontFamily] }}
/>
) : (
<pre
className="viewer-content"
style={{ fontFamily: FONT_FAMILIES[fontFamily] }}
>
{placeholder}
</pre>
)}
{copied && <div className="copy-notification">Скопировано!</div>}
</div>
);
}