diff --git a/app/channels/[id]/history/page.js b/app/channels/[id]/history/page.js
new file mode 100644
index 0000000..eb79e80
--- /dev/null
+++ b/app/channels/[id]/history/page.js
@@ -0,0 +1,28 @@
+import { notFound, redirect } from 'next/navigation';
+import { requireUser } from '@/lib/session';
+import { engine } from '@/lib/engine';
+import Header from '@/components/Header';
+import ChannelHistory from '@/components/ChannelHistory';
+
+export default async function ChannelHistoryPage({ params }) {
+ const user = await requireUser();
+ if (!user) redirect('/login');
+
+ const { id } = await params;
+
+ let channel, posts;
+ try {
+ channel = await engine.getChannel(user.id, id);
+ posts = await engine.listUserPosts(user.id, { channel_id: id, status: 'published', limit: 100 });
+ } catch {
+ notFound();
+ }
+ if (!channel) notFound();
+
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/components/ChannelHistory.js b/components/ChannelHistory.js
new file mode 100644
index 0000000..40a2bce
--- /dev/null
+++ b/components/ChannelHistory.js
@@ -0,0 +1,144 @@
+'use client';
+import { useState } from 'react';
+import Link from 'next/link';
+import { ArrowLeft, Clock, Image as ImageIcon, Copy, Check, Search } from 'lucide-react';
+
+function timeAgo(dateStr) {
+ if (!dateStr) return '';
+ const diff = Date.now() - new Date(dateStr).getTime();
+ const m = Math.floor(diff / 60000);
+ if (m < 60) return `${m} мин назад`;
+ const h = Math.floor(m / 60);
+ if (h < 24) return `${h} ч назад`;
+ const d = Math.floor(h / 24);
+ if (d < 30) return `${d} дн назад`;
+ return new Date(dateStr).toLocaleDateString('ru-RU', { day: 'numeric', month: 'short', year: 'numeric' });
+}
+
+function PostCard({ p }) {
+ const [copied, setCopied] = useState(false);
+ const [expanded, setExpanded] = useState(false);
+
+ const preview = p.content?.slice(0, 200) || '';
+ const isLong = (p.content?.length || 0) > 200;
+
+ function copy() {
+ navigator.clipboard.writeText(p.content || '');
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ }
+
+ return (
+
+ {/* Шапка */}
+
+
+
+ {timeAgo(p.published_at || p.updated_at || p.created_at)}
+
+
+
+
+ {/* Картинка */}
+ {p.image_url && (
+

+ )}
+ {!p.image_url && (
+
+
+ Без изображения
+
+ )}
+
+ {/* Текст */}
+
+ {expanded ? p.content : preview}
+ {isLong && !expanded && …}
+
+ {isLong && (
+
+ )}
+
+ );
+}
+
+export default function ChannelHistory({ channel, posts }) {
+ const [query, setQuery] = useState('');
+
+ const filtered = query.trim()
+ ? posts.filter(p => p.content?.toLowerCase().includes(query.toLowerCase()))
+ : posts;
+
+ return (
+
+ {/* Навигация */}
+
+
+
+ {channel.name}
+
+
/
+
История публикаций
+
+
+ {/* Статистика + поиск */}
+
+
+ {posts.length === 0
+ ? 'Публикаций пока нет'
+ : `${posts.length} ${posts.length === 1 ? 'публикация' : posts.length < 5 ? 'публикации' : 'публикаций'}`}
+
+ {posts.length > 0 && (
+
+
+ setQuery(e.target.value)}
+ className="pl-8 pr-3 py-1.5 text-sm border border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-900 text-gray-800 dark:text-gray-200 placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-300 w-48"
+ />
+
+ )}
+
+
+ {/* Список постов */}
+ {filtered.length === 0 && query ? (
+ Ничего не найдено
+ ) : filtered.length === 0 ? (
+
+
+
Опубликованных постов пока нет
+
+ Создать первый пост →
+
+
+ ) : (
+
+ {filtered.map(p =>
)}
+
+ )}
+
+ );
+}
diff --git a/components/ChannelView.js b/components/ChannelView.js
index e4a0586..9abce45 100644
--- a/components/ChannelView.js
+++ b/components/ChannelView.js
@@ -4,7 +4,7 @@ import Link from 'next/link';
import {
ArrowLeft, Sparkles, Wand2, Copy, Check, Loader2, Settings,
Image as ImageIcon, RefreshCw, Scissors, Maximize2, Zap, Heart,
- MessageSquare, Pencil, X, ChevronDown, Send, Clock, Trash2
+ MessageSquare, Pencil, X, ChevronDown, Send, Clock, Trash2, History
} from 'lucide-react';
const GOAL_LABELS = {
@@ -276,6 +276,10 @@ export default function ChannelView({ channel }) {
{channel.niche && {channel.niche}
}
+
+
+ История
+
Настройки