'use client';
/**
* PostPreview — рендерит пост так, как он будет выглядеть в TG / VK / MAX.
* Props:
* text — текст поста (Markdown-разметка TG)
* imageUrl — URL картинки (опционально)
* platform — 'telegram' | 'vk' | 'max'
* channelName — название канала (для шапки)
*/
import { useState } from 'react';
import { Eye, EyeOff, MessageCircle, Heart, Share2, Bookmark,
ThumbsUp, BarChart2, AlertCircle } from 'lucide-react';
// ── Лимиты платформ ───────────────────────────────────────────────────────────
const LIMITS = {
telegram: { text: 4096, caption: 1024, label: 'Telegram' },
vk: { text: 16384, caption: 2048, label: 'ВКонтакте' },
max: { text: 4096, caption: 1024, label: 'MAX' },
};
// ── Парсер разметки → HTML ────────────────────────────────────────────────────
function parseTgMarkdown(text) {
// Экранируем HTML-спецсимволы
let s = text
.replace(/&/g, '&')
.replace(//g, '>');
// **bold** или __bold__
s = s.replace(/\*\*(.+?)\*\*/gs, '$1 ');
s = s.replace(/__(.+?)__/gs, '$1 ');
// _italic_ или *italic*
s = s.replace(/(?$1');
s = s.replace(/(?$1');
// `code`
s = s.replace(/`([^`]+)`/g, '$1');
// ```block```
s = s.replace(/```[\w]*\n?([\s\S]*?)```/g, '
$1 ');
// [text](url)
s = s.replace(/\[([^\]]+)\]\((https?:\/\/[^\)]+)\)/g,
'$1 ');
// Переносы строк →
s = s.replace(/\n/g, ' ');
return s;
}
function parseVkMarkdown(text) {
// VK не поддерживает Markdown — убираем разметку, оставляем текст
let s = text
.replace(/\*\*(.+?)\*\*/gs, '$1')
.replace(/__(.+?)__/gs, '$1')
.replace(/(?/g, '>')
.replace(/\n/g, ' ');
return s;
}
function renderMarkdown(text, platform) {
if (!text) return '';
if (platform === 'vk') return parseVkMarkdown(text);
return parseTgMarkdown(text); // telegram + max
}
// ── Счётчик символов ──────────────────────────────────────────────────────────
function CharCounter({ text, imageUrl, platform }) {
const limits = LIMITS[platform] || LIMITS.telegram;
const limit = imageUrl ? limits.caption : limits.text;
const len = (text || '').length;
const pct = Math.min(len / limit, 1);
const over = len > limit;
const color = over ? 'text-red-400' : pct > 0.85 ? 'text-yellow-400' : 'text-text-mute';
return (
{over &&
}
{len} / {limit}{imageUrl ? ' (caption)' : ''}
{over &&
превышен лимит }
);
}
// ── TG Preview ────────────────────────────────────────────────────────────────
function TelegramPreview({ text, imageUrl, channelName }) {
const html = renderMarkdown(text, 'telegram');
return (
{/* Header */}
{(channelName || 'Z').slice(0, 1).toUpperCase()}
{channelName || 'Канал'}
только что
{/* Контент */}
{imageUrl && (
{ e.target.style.display = 'none'; }}
/>
)}
Текст поста появится здесь…' }}
/>
{/* Footer */}
{/* TG inline styles */}
);
}
// ── VK Preview ────────────────────────────────────────────────────────────────
function VkPreview({ text, imageUrl, channelName }) {
const html = renderMarkdown(text, 'vk');
return (
{/* Header */}
{(channelName || 'K').slice(0, 1).toUpperCase()}
{channelName || 'Сообщество'}
только что
···
{/* Контент */}
Текст поста появится здесь…' }}
/>
{imageUrl && (
{ e.target.style.display = 'none'; }}
/>
)}
{/* Footer */}
24
3
Поделиться
891
);
}
// ── MAX Preview ───────────────────────────────────────────────────────────────
function MaxPreview({ text, imageUrl, channelName }) {
const html = renderMarkdown(text, 'max');
return (
{/* Header */}
{(channelName || 'M').slice(0, 1).toUpperCase()}
{channelName || 'Канал MAX'}
только что
{/* Контент */}
{imageUrl && (
{ e.target.style.display = 'none'; }}
/>
)}
Текст поста появится здесь…' }}
/>
{/* Footer */}
432
18
Опрос
);
}
// ── Главный экспорт ───────────────────────────────────────────────────────────
const PLATFORM_ORDER = ['telegram', 'vk', 'max'];
const PLATFORM_LABELS = { telegram: 'TG', vk: 'VK', max: 'MAX' };
export default function PostPreview({ text, imageUrl, platform: defaultPlatform = 'telegram', channelName }) {
const [visible, setVisible] = useState(true);
const [platform, setPlatform] = useState(defaultPlatform);
if (!visible) {
return (
setVisible(true)}
className="flex items-center gap-1.5 text-xs text-text-mute hover:text-text transition-colors"
>
Показать превью
);
}
return (
{/* Тулбар */}
Превью
{/* Переключатель платформы */}
{PLATFORM_ORDER.map(p => (
setPlatform(p)}
className={`px-2.5 py-1 font-medium transition-colors
${platform === p
? 'bg-accent text-white'
: 'bg-surface2 text-text-mute hover:text-text'
}`}
>
{PLATFORM_LABELS[p]}
))}
{/* Скрыть */}
setVisible(false)}
className="btn-ghost p-1.5 rounded-lg"
title="Скрыть превью"
>
{/* Счётчик символов */}
{/* Превью платформы */}
{platform === 'telegram' && (
)}
{platform === 'vk' && (
)}
{platform === 'max' && (
)}
{/* Лимит */}
{LIMITS[platform].label}: текст до {LIMITS[platform].text.toLocaleString()} симв.
{', caption (с фото) до '}{LIMITS[platform].caption.toLocaleString()} симв.
);
}