feat: P3 PostTemplates — 7 post structure presets in ChannelView

This commit is contained in:
Nik (Claude)
2026-06-08 10:58:56 +03:00
parent 0c8ca23015
commit b8a570f04a
2 changed files with 192 additions and 10 deletions
+170
View File
@@ -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 (
<div className="relative">
<button
onClick={() => setOpen(v => !v)}
disabled={disabled}
className="text-xs inline-flex items-center gap-1 text-accent hover:underline disabled:opacity-50"
>
{open ? <ChevronUp className="w-3.5 h-3.5" /> : <ChevronDown className="w-3.5 h-3.5" />}
Шаблоны
</button>
{open && (
<div className="absolute left-0 top-6 z-20 w-72 rounded-xl border border-border bg-surface shadow-xl p-2">
<div className="text-xs font-semibold text-text-mute uppercase tracking-wide px-2 py-1 mb-1">
Выбери структуру поста
</div>
{TEMPLATES.map(tpl => (
<button
key={tpl.id}
onClick={() => pick(tpl)}
className="w-full flex items-start gap-2.5 px-2.5 py-2 rounded-lg hover:bg-surface2 text-left transition-colors"
>
<tpl.Icon className="w-4 h-4 text-accent mt-0.5 shrink-0" />
<div>
<div className="text-sm font-medium text-text">{tpl.label}</div>
<div className="text-xs text-text-mute">{tpl.hint}</div>
</div>
</button>
))}
</div>
)}
</div>
);
}