From b8a570f04af5a1dbaa625cf7d94463ef4a126fca Mon Sep 17 00:00:00 2001 From: "Nik (Claude)" Date: Mon, 8 Jun 2026 10:58:56 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20P3=20PostTemplates=20=E2=80=94=207=20po?= =?UTF-8?q?st=20structure=20presets=20in=20ChannelView?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/ChannelView.js | 32 ++++--- components/PostTemplates.js | 170 ++++++++++++++++++++++++++++++++++++ 2 files changed, 192 insertions(+), 10 deletions(-) create mode 100644 components/PostTemplates.js diff --git a/components/ChannelView.js b/components/ChannelView.js index d30e5e7..2989177 100644 --- a/components/ChannelView.js +++ b/components/ChannelView.js @@ -8,6 +8,7 @@ import { } from 'lucide-react'; import PhotoSearchModal from './PhotoSearchModal'; import PostPreview from './PostPreview'; +import PostTemplates from './PostTemplates'; const GOAL_LABELS = { educational: 'Обучение', news: 'Новости', @@ -191,6 +192,14 @@ export default function ChannelView({ channel }) { setTopic(''); } + function applyTemplate({ topicHint, structure }) { + // Если тема не задана — подставляем подсказку + if (!topic.trim()) setTopic(topicHint); + // В textarea вставляем структуру как отправную точку + setPost(structure); + setSavedPostId(null); + } + async function generate(asVariant = false) { if (!topic.trim() && !asVariant) return; if (asVariant && !post) return; @@ -328,14 +337,17 @@ export default function ChannelView({ channel }) { Сгенерировать пост - +
+ + +
{showIdeas && ideas.length > 0 && ( @@ -588,7 +600,7 @@ export default function ChannelView({ channel }) { ))} - {/* конец левой колонки */} + {/* Правая колонка — превью */}
- {/* конец грида */} + )} {/* Photo search modal */} diff --git a/components/PostTemplates.js b/components/PostTemplates.js new file mode 100644 index 0000000..8caf3e9 --- /dev/null +++ b/components/PostTemplates.js @@ -0,0 +1,170 @@ +'use client'; + +/** + * PostTemplates — 7 кнопок-пресетов структуры поста. + * Props: + * onSelect(template) — вызывается с объектом { label, topic, structure } + * disabled — bool + */ + +import { useState } from 'react'; +import { ChevronDown, ChevronUp, Newspaper, Megaphone, + Briefcase, BookOpen, List, HelpCircle, User } from 'lucide-react'; + +const TEMPLATES = [ + { + id: 'news', + label: 'Новость', + Icon: Newspaper, + hint: 'Факт → контекст → вывод', + topicHint: 'Новость или событие в нише', + structure: `[ЗАГОЛОВОК — суть в одной строке] + +[2–3 предложения: что произошло, ключевые цифры] + +[Почему это важно для читателя] + +[Личный вывод или вопрос к аудитории]`, + }, + { + id: 'announce', + label: 'Анонс', + Icon: Megaphone, + hint: 'Интрига → суть → CTA', + topicHint: 'Анонс события, релиза, запуска', + structure: `[Интригующий первый абзац — зачем читать дальше] + +📅 [Дата и что именно происходит] + +✅ [3–4 буллита: что будет / что получит читатель] + +👉 [Призыв к действию со ссылкой]`, + }, + { + id: 'case', + label: 'Кейс', + Icon: Briefcase, + hint: 'Ситуация → решение → результат', + topicHint: 'Реальный пример из практики', + structure: `[Задача: что было за проблема] + +[Что попробовал, что не сработало] + +[Что сработало — конкретные шаги] + +📊 Результат: [цифры или конкретный итог] + +[Вывод — что можно повторить]`, + }, + { + id: 'longread', + label: 'Лонгрид', + Icon: BookOpen, + hint: 'Глубокий разбор темы', + topicHint: 'Тема для развёрнутого объяснения', + structure: `[Провокационный или неожиданный тезис] + +[Почему стандартный взгляд ошибается] + +[Аргумент 1 + пример] + +[Аргумент 2 + пример] + +[Аргумент 3 + пример] + +[Заключение: к чему приходим]`, + }, + { + id: 'list', + label: 'Подборка', + Icon: List, + hint: 'N полезных штук', + topicHint: 'Список инструментов, советов, ресурсов', + structure: `[Почему эта подборка полезна] + +1. [Название] — [1 предложение почему] +2. [Название] — [1 предложение почему] +3. [Название] — [1 предложение почему] +4. [Название] — [1 предложение почему] +5. [Название] — [1 предложение почему] + +[Итог или личная рекомендация #1]`, + }, + { + id: 'poll', + label: 'Опрос-разбор', + Icon: HelpCircle, + hint: 'Вопрос → варианты → разбор', + topicHint: 'Дискуссионный вопрос для аудитории', + structure: `[Провокационный вопрос к читателю] + +Как бы ты поступил? + +А) [Вариант 1] +Б) [Вариант 2] +В) [Вариант 3] + +[Мой ответ и почему именно так] + +[Приглашение высказаться в комментариях]`, + }, + { + id: 'personal', + label: 'Личное', + Icon: User, + hint: 'История → урок → применение', + topicHint: 'Личный опыт или наблюдение', + structure: `[Конкретная ситуация из жизни — детали, дата, место] + +[Что почувствовал / что понял в тот момент] + +[Урок, который из этого вынес] + +[Как это меняет то, что я делаю сейчас] + +[Вопрос читателю — было ли у него похожее?]`, + }, +]; + +export default function PostTemplates({ onSelect, disabled }) { + const [open, setOpen] = useState(false); + + function pick(tpl) { + onSelect({ label: tpl.label, topicHint: tpl.topicHint, structure: tpl.structure }); + setOpen(false); + } + + return ( +
+ + + {open && ( +
+
+ Выбери структуру поста +
+ {TEMPLATES.map(tpl => ( + + ))} +
+ )} +
+ ); +}