import React, { useMemo, useState } from "react";
import { motion } from "framer-motion";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
/**
* Система разговорных клубов — v3
* Автор: Котова Наталья
* Цвета: #96a890 (sage), #000000 (total black), #ffe84d (yellow)
* Обновления:
* - Динамическое расширение инструкций для КАЖДОГО задания (без изменения исходного текста):
* добавлены Цель, Материалы, Пошаговый план, Оценивание/рефлексия. Логика варьируется по типу задания.
* - Видимость: «Категория» — светлый цвет, подкатегории — светлый фон. Список всех заданий — белый текст.
*/
// ---------- ТИПЫ ----------
type Task = { title: string; instruction: string };
type Subcategory = { name: string; tasks: Task[] };
type Category = { name: string; subcategories: Subcategory[] };
// ---------- УТИЛИТЫ: расширение инструкций ----------
function expandInstruction(title: string, base: string, trail: { category: string; subcategory: string }) {
const commonTail = `\n\nОценивание/рефлексия:\n• Самопроверка/взаимопроверка по ключам/чек‑листу.\n• Мини‑рефлексия: что было легко/сложно, 1 инсайт, 1 вопрос.\n• Подготовьте 1–2 примера для устного обсуждения на встрече.`;
const materials = `Материалы: текст/видео/карточки по теме, таймер (по желанию), глоссарий.`;
const make = (goal: string, steps: string[]) =>
`Цель: ${goal}\n${materials}\n\nПорядок действий:\n${steps.map((s, i) => `${i + 1}) ${s}`).join("\n")}\n${commonTail}`;
const t = title.toLowerCase();
if (/gap[- ]?fill|fill in the gaps/.test(t)) {
return make(
"закрепить лексику/грамматику в контексте",
[
"Прочтите весь текст, не заполняя пропуски, чтобы уловить общий смысл.",
"Заполните пропуски, опираясь на контекст, подсказки (первая буква/дефиниция/часть речи).",
"Проверьте согласование времён, артикли, предлоги, коллокации.",
"Сверьтесь с ключами/подсказками. Исправьте и отметьте правила, которые сработали.",
]
);
}
if (/matching|collocation/.test(t)) {
return make(
"распознать значения и устойчивые сочетания",
[
"Разрежьте/подготовьте карточки: термины/дефиниции/части коллокаций.",
"Соотнесите пары. Объясните логику: смысл, часть речи, тип связи.",
"Сделайте 3 свои пары и поясните, где их можно использовать.",
]
);
}
if (/true\/?false|правда и ложь|fact/i.test(t)) {
return make(
"критически прочитывать и проверять утверждения",
[
"Прочитайте/посмотрите источник. Подчеркните факты и мнения.",
"Отметьте утверждения True/False/Not stated и укажите доказательство (цитата/кадр/данные).",
"Переформулируйте 2 ложных утверждения так, чтобы они стали истинными.",
]
);
}
if (/sort|сортируй|sorting|same \/ different|yes no maybe|flags|плюс|минус|\+|-/i.test(t)) {
return make(
"структурировать идеи по критериям",
[
"Определите категории сортировки (напр., плюсы/минусы/сомнения).",
"Разнесите элементы по колонкам, проговорив критерии.",
"Проверьте баланс: чего больше и почему. Сформулируйте вывод одним предложением.",
]
);
}
if (/ranking|от 1 до 10|priorit|elimination|tournament|time budget|life without|reverse ranking/i.test(t)) {
return make(
"выставить приоритеты и аргументировать оценку",
[
"Определите шкалу (1–10) и критерий (полезность/влияние/стоимость).",
"Оцените каждый пункт, затем составьте TOP‑3 с аргументами.",
"Сравните с партнёром: где расхождения? Попробуйте прийти к общему рейтингу.",
]
);
}
if (/video|who said it|main idea|ted|letter/i.test(t)) {
return make(
"извлекать ключевые идеи из видео и реагировать на них",
[
"Посмотрите видео один раз целиком без пауз.",
"На втором просмотре составьте конспект: тезисы, примеры, цитаты.",
"Выполните задание подтипа (бинго/‘кто сказал’/резюме/письмо автору).",
]
);
}
if (/text|текст|reading|paragraph|retell|rewrite|title|missing sentences/i.test(t) && trail.category === "Уроки") {
return make(
"читать вдумчиво и преобразовывать содержание",
[
"Прочтите текст и пометьте факты/мнения/неясности.",
"Выполните конкретную подзадачу (переставить абзацы/придумать заголовки/дописать пропуски).",
"Сделайте мини‑рекаст: одно ключевое предложение своими словами.",
]
);
}
if (/discussion|debate|change my mind|dilemma|jury|talk show|советы|неловк|дебаты|суд/i.test(t)) {
return make(
"аргументировать позицию и реагировать на возражения",
[
"Сформулируйте стартовую позицию/гипотезу в 1–2 предложениях.",
"Подготовьте по 2 аргумента ‘за’ и ‘против’ + пример/кейс.",
"Проведите мини‑дебаты/интервью, фиксируя сильные аргументы оппонента.",
]
);
}
if (/creative|инфограф|коллаж|гайд|брошюр|mind map|vision board|photo/i.test(t)) {
return make(
"создать визуальный/текстовый продукт по теме",
[
"Определите целевую аудиторию и цель продукта (информировать/вдохновить/убедить).",
"Соберите материал: 5–7 пунктов контента, 2–3 визуальных элемента.",
"Сверстайте финальную версию (A4/слайд/пост) и добавьте подписи/кредиты.",
]
);
}
// По умолчанию — универсальное расширение
return make(
"выполнить задание осознанно и подготовиться к обсуждению",
[
"Внимательно изучите исходник (текст/видео/инструкцию), отметив ключевые слова.",
"Следуйте базовой инструкции задания, фиксируя решения/примеры.",
"Подготовьте 3 тезиса и 1 вопрос для обсуждения на встрече.",
]
);
}
// ---------- ДАННЫЕ (скопированы из версии v1 — все элементы сохранены) ----------
const HOMEWORK_LANGUAGE: Task[] = [
{ title: "Matching", instruction: "ученики соотносят слова и определения, слова и синонимы/антонимы, фразы и иллюстрации, части предложений друг с другом." },
{ title: "True/false", instruction: "ученики читают статью и работают с утверждениями по статье, в которых есть нужный язык." },
{ title: "Find the word/phrase", instruction: "ученики ищут в статье слова по описанию, по определениям." },
{ title: "Sort out", instruction: "ученики сортируют лексику по нужным категориям." },
{ title: "Найди коллокации", instruction: "ученики ищут и выписывают коллокации из статьи или видео (можно предложить сделать collocation fork)." },
{ title: "Gap-fill", instruction: "ученики вставляют пропущенные слова из статьи/видео в текст. Можно давать подсказки в виде первой буквы, списка ЛЕ, определений и тд." },
{ title: "Перепиши с лексикой", instruction: "ученики переписывают предложения из статьи, используя синонимы, например." },
{ title: "Horizontal expansion", instruction: "напишите часть предложения с ЛЕ и попросите ученика его продолжить." },
{ title: "Исправь ошибку", instruction: "выпишите предложение из статьи, сделайте там ошибку (другое слово, отсутствие артикля и тд), попросите учеников исправить ошибку." },
{ title: "Collocation matching", instruction: "ученики соединяют части коллокации (например, take - a risk)." },
{ title: "Переведи обратно", instruction: "выпишите предложения с нужными ЛЕ, но вместо ЛЕ вставьте эквивалент на родном языке, попросите учеников восстановить." },
{ title: "Positive/negative/neutral", instruction: "выпишите язык из статьи или видео, попросите учеников рассортировать его по коннотации." },
{ title: "Создай предложение", instruction: "ученики составляют целые предложения из отдельных слов (то есть вы берёте предложение из статьи и меняете порядок слов)." },
{ title: "Write your own sentence", instruction: "выпишите нужный язык и попросите учеников создать свои предложения с ним по теме." },
{ title: "Vocabulary map", instruction: "ученики читают статью, выделяют полезный язык по теме и составляют с ним свою \"майнд-карту\"." },
];
const HOMEWORK_TEXT: Task[] = [
{ title: "Discourse marker hunt", instruction: "ученики находят в тексте связки по типу however, in contrast, as a result и объясняют, какую роль они играют (если они пригодятся)." },
{ title: "Agree/disagree", instruction: "ученики оценивают утверждения по теме и аргументируют своё согласие/несогласие." },
{ title: "Аргументы за и против", instruction: "ученики выписывают аргументы за и против из статьи, особенно, если у вас планируются дебаты на уроке." },
{ title: "Придумай вопросы", instruction: "ученик придумает X вопросов по статье для дальнейшего обсуждения на занятии." },
{ title: "Список инсайтов", instruction: "ученик составляет список 3–5 инсайтов, которые он получил из статьи." },
{ title: "Объясни использование", instruction: "выпишите список ЛЕ, которые вам пригодятся, предложите ученикам подумать, в каком контексте и упоминая что они смогут использовать ту или иную ЛЕ." },
{ title: "Составь таблицу + и -", instruction: "ученики составляют таблицу плюсов и минусов с контентом из статьи." },
{ title: "Bias detection", instruction: "ученики анализируют, есть ли у автора статьи предвзятое отношение к теме или же, возможно, он рассматривает тему только с одной стороны." },
{ title: "Дай комментарий по статье", instruction: "ученик читает статью и пишет своё мнение о ней: с чем согласен, с чем нет, что нового, какие инсайты." },
{ title: "Что откликается?", instruction: "ученик читает статью и пишет небольшой комментарий, как тема статьи связана с личным опытом ученика." },
{ title: "Создай квиз", instruction: "ученик создаёт по статье квиз или тест на основе контента." },
{ title: "Что не сходится?", instruction: "предложите ученикам противоречивую статью и попросите их найти контраргументы к информации из статьи или поработать с мифами." },
{ title: "Alternative perspective", instruction: "ученики читают статью и думают, как на неё посмотрел бы человек другой профессии, культуры и т.д." },
{ title: "I agree / disagree because..", instruction: "выпишите утверждения из статьи и добавьте sentence starter ‘I agree / disagree because..’, попросите учеников продолжить." },
{ title: "3 viewpoints", instruction: "напишите общую проблему/ситуацию из статьи, предложите описать её с трёх разных точек зрения." },
{ title: "Find the paragraph", instruction: "ученик ищет, в каком абзаце находится та или иная информация." },
{ title: "Find logical fallacies", instruction: "ученикам нужно найти логические ошибки (например, false cause, hasty generalization)." },
{ title: "Devil’s advocate", instruction: "ученик читает статью и придумывает 2–3 аргумента, чтобы опровергнуть точку зрения автора." },
{ title: "Ranking", instruction: "если в статье есть список/решения и т.д., попросите учеников расставить их по важности, эффективности и тд." },
{ title: "Interactive reading", instruction: "предложите читать статью и ставить разные эмодзи к разным фактам/советам/информации." },
];
const HOMEWORK_VIDEO: Task[] = [
{ title: "Who said it", instruction: "ученики сопоставляют цитаты с персонажами (если несколько спикеров)." },
{ title: "Identify the main idea", instruction: "ученики смотрят видео и выписывают главную идею видео." },
{ title: "Bingo", instruction: "составьте карточку ‘бинго’ со словами/идеями из видео, ученик отмечает услышанное." },
{ title: "One-minute note", instruction: "ученик после просмотра видео за одну минуту пишет максимум идей из видео." },
{ title: "Сравни со статьёй", instruction: "поработайте с видео и статьёй по одной теме. Найти одинаковую и разную информацию." },
{ title: "Complete the summary", instruction: "ученики дополняют краткий пересказ видео пропущенными словами/фразами." },
{ title: "Detect persuasive techniques", instruction: "ученики ищут приёмы убеждения (например, статистика, апелляция к эмоциям)." },
{ title: "Facial expression reading", instruction: "выберите 3 момента, где по лицу персонажа можно понять эмоции, предложите описать их." },
{ title: "TED-talk", instruction: "ученик создаёт короткое выступление по теме видео (план выступления)." },
{ title: "Write a letter", instruction: "предложите написать письмо герою видео или автору с отзывом/вопросами." },
];
const HOMEWORK_CREATIVE: Task[] = [
{ title: "Vision board", instruction: "предложите создать коллаж, который отражает тему/отношение/что-то по теме." },
{ title: "Mind map", instruction: "ученики создают карту с ключевыми моментами по теме." },
{ title: "Social media post", instruction: "ученики составляют твит/Instagram-пост по теме." },
{ title: "Гайд", instruction: "ученики составляют каждый свой гайд с решением какой-то проблемы." },
{ title: "Создание брошюры", instruction: "ученики создают брошюру по теме (текст, картинки и тд)." },
{ title: "Infographic", instruction: "ученики создают инфографику по теме." },
{ title: "Checklist", instruction: "ученики создают свой чеклист по теме." },
{ title: "Pitching", instruction: "ученики делают заметку по теме, чтобы ‘продать’ эту идею на занятии." },
{ title: "Photo essay", instruction: "ученики добавляют свои фотографии по теме и пишут описание к ним." },
{ title: "Колонка советов", instruction: "ученик пишет советы по теме или придумывает проблему для урока." },
];
const LESSONS_TEXT: Task[] = [
{ title: "Fill in the gaps", instruction: "Стандартное задание, где нужно вставить пропущенные лексические единицы в текст. Могут быть подсказки в виде первой буквы, количества слов или букв, дефиниции, могут быть даны варианты (в том числе лишние)." },
{ title: "Альтернативная концовка", instruction: "Дайте ученикам текст (история/письмо от героя). Прочитать и придумать альтернативную концовку или додумать, что случилось после." },
{ title: "Interactive step-by-step read", instruction: "Предложите расставить к фактам/мнениям эмодзи (знаю/новое/непонятно и т.п.) по мере чтения." },
{ title: "Сортировка лексики", instruction: "Создайте текст с целевым языком, который можно рассортировать (язык для плюсов/минусов и т.д.). Попросите рассортировать по блокам." },
{ title: "Абзацы в нужном порядке", instruction: "Предложите прочитать абзацы и расставить их в нужном порядке (подходит для историй с последовательностью)." },
{ title: "Текст в предложении", instruction: "Прочитать текст и в одном предложении выделить главную мысль/идею/ситуацию." },
{ title: "Идеи в текст", instruction: "Пустые пропуски в тексте ученики заполняют СВОИМИ идеями (советы, лайфхаки, списки и т.п.)." },
{ title: "Jigsaw writing", instruction: "Пары становятся экспертами по подтемам (симптомы/причины и т.п.), составляют абзацы и собирают общий текст, затем делятся выводами." },
{ title: "Retell from another perspective", instruction: "Прочитайте историю и попросите пересказать её от лица другого персонажа/объекта/животного." },
{ title: "Title match", instruction: "Ученики читают текст без заголовка, предлагают варианты, затем сравнивают с оригиналом или голосуют за лучший." },
{ title: "Rewrite in a different genre", instruction: "Превратите рассказ в другой жанр (криминальная хроника, комедия, Instagram-пост, новостной репортаж и т.д.)." },
{ title: "Emoji storytelling", instruction: "Перескажите текст, используя только эмодзи (или с добавлением). Остальные угадывают." },
{ title: "Text debate", instruction: "Выберите противоречивый текст/мнение. Одна группа ‘за’, другая ‘против’ — обсуждение." },
{ title: "Highlight & share", instruction: "Каждый выбирает 1 предложение из текста, которое его зацепило — и объясняет почему." },
{ title: "Missing sentences", instruction: "В текст вставлены пропуски: обсуждаем, что логично подошло бы. Сравнить с оригиналом." },
{ title: "Fact vs. feeling", instruction: "Выбираем фразы из текста и делим на факты/эмоции/интерпретации — обсуждаем согласие." },
{ title: "Fix the mistake (Fake text)", instruction: "Прочитайте ‘текст с ошибками’ (логическими, эмоциональными, фактологическими). Участники находят и обсуждают." },
{ title: "Speed retelling with timer", instruction: "Пересказ с таймером: 30 сек → 15 сек → 5 слов. Весело и эффективно." },
];
const LESSONS_RANKING: Task[] = [
{ title: "От 1 до 10", instruction: "Оценить список (лайфхаки/советы/решения) по шкале 1–7/9/10 с аргументацией." },
{ title: "The Elimination game", instruction: "10 вариантов на карточках — участники по очереди исключают по одному и объясняют выбор." },
{ title: "F*ck Marry Kill", instruction: "Оценивание людей/стратегий/советов через категории F*ck / Marry / Kill с аргументацией." },
{ title: "Would you keep it?", instruction: "Из 10 объектов/идей оставить только 5 — обосновать выбор." },
{ title: "He`s a 10, but..", instruction: "Тренд из TikTok: ‘Он 10/10, но …’. Использовать для спорных идей и ранжирования важности." },
{ title: "Priorities pyramid", instruction: "Выстроить пирамиду из 7–10 понятий: что вверху (самое важное), что внизу (менее важно)." },
{ title: "Что приоритетнее", instruction: "Список ценностей/решений — расположить по значимости лично или относительно предмета/профессии." },
{ title: "This or that – Tournament", instruction: "Парное сравнение: из 8/16 вещей выбирается победитель через дуэли (плей-офф)." },
{ title: "Time budget", instruction: "Распределить ‘24 часа’ между видами деятельности (работа, сон, соцсети…), обсудить приоритеты." },
{ title: "Life without…", instruction: "Отказываться от вещей по очереди (интернет, транспорт, кофе…) — что оставим последним?" },
{ title: "Convince the group", instruction: "Каждый получает пункт и убеждает остальных, что он должен быть в топ‑3; затем голосование." },
{ title: "Essential vs. optional", instruction: "Из общего списка выбрать ‘необходимое’ и ‘приятное, но некритичное’." },
{ title: "Reverse ranking", instruction: "Сначала отсортировать ‘от худшего к лучшему’, затем наоборот — обсудить, почему восприятие меняется." },
{ title: "Moral compass sorter", instruction: "Дилеммы/действия ранжируются по степени моральности/сложности — обсуждение." },
];
const LESSONS_SORTING: Task[] = [
{ title: "Рассортируй по категориям", instruction: "Сортировать лексику, идеи, решения, части текста, картинки (полезные/вредные, плюсы/минусы, было/не было и тд)." },
{ title: "Same / Different", instruction: "Сравнить два объекта/явления, сортируя характеристики на Общее/Отличия." },
{ title: "Yes No Maybe", instruction: "Рассортировать варианты по колонкам Yes / No / Maybe (например, анкеты ‘hubby material’)." },
{ title: "Мифы и факты", instruction: "Обсудить, где миф, а где факт (сон, питание, работа мозга и т.п.)." },
{ title: "Вопросы с нужным языком", instruction: "Создать вопросы с языком из подготовки/прошлых занятий и обсудить их." },
{ title: "Преимущества и недостатки (+ и -)", instruction: "По теме найти плюсы и минусы (например, соцсети в жизни) и дополнить своими идеями." },
{ title: "Red, green, beige flags", instruction: "Список характеристик по теме — обсудить, что красный/зелёный/бежевый флаг." },
{ title: "Правда и ложь", instruction: "Найти факты и создать ложные утверждения; угадать, где правда/ложь (с доказательствами)." },
{ title: "Can you relate?", instruction: "Утверждения/ситуации по теме — поделиться откликом (шкала/спидометр/процент)." },
{ title: "What makes (a good friend)?", instruction: "Составить портрет идеального друга/мужа/дома/путешествия и т.д." },
{ title: "Telltale signs", instruction: "Список ‘признаков’ по теме (например, нарциссизм) — обсудить, показатель это или нет." },
];
const LESSONS_DISCUSSION: Task[] = [
{ title: "Define it..", instruction: "Создать определение темы (можно через рисунок/emoji/картинки/метафорические карты)." },
{ title: "Me-not me", instruction: "Карточки-утверждения (например, ‘Я не могу жить без кофе’) — делимся, ‘про меня’ или нет (шкала/спидометр)." },
{ title: "Guessing (Fortune telling)", instruction: "Один — ‘предсказатель’ и рассказывает будущее по теме; остальные реагируют: Really? I hope so! No way!" },
{ title: "Is it a + or a -?", instruction: "Черта/привычка — плюс или минус? Аргументируем, голосуем, спорим." },
{ title: "Confession basket", instruction: "Анонимные признания/кейсы → обсуждение в парах и поиск решений." },
{ title: "Worth it?", instruction: "Назвать вещь/действие/ситуацию (‘Работать по выходным’) — стоит ли это того? Мини‑дебаты." },
{ title: "Find your type", instruction: "Карточки с типами (The Minimalist, The Workaholic). Описать себя фразами; другие угадывают." },
{ title: "Change my mind", instruction: "Список утверждений, ‘в которые верят’. Партнёр пытается разубедить." },
{ title: "The dilemma game", instruction: "Ситуации по теме (‘Нашёл кошелёк…’) — обсуждение ценностей, мнений, последствий." },
{ title: "Суд присяжных", instruction: "Роли: подсудимый, прокурор, адвокат, присяжные. Обсуждаем ‘за’ и ‘против’." },
{ title: "Неловкие моменты", instruction: "Поделиться неловкой ситуацией; остальные сочувствуют/делятся/смеются (доброжелательно)." },
{ title: "Советы себе в прошлом", instruction: "Придумать и озвучить совет себе ‘пять лет назад’ или ‘в 15 лет’." },
{ title: "Newsroom", instruction: "Дать заголовки по теме (реальные/выдуманные). В парах придумать сюжет новостного выпуска (интервью/репортаж)." },
{ title: "Советы незнакомцам", instruction: "Странные/житейские проблемы — участники дают советы и обсуждают." },
{ title: "Рецепт жизни", instruction: "Составить ‘рецепт счастливой жизни’/‘рецепт плохого дня’ в кулинарной метафоре." },
{ title: "Другими глазами", instruction: "Ситуация по теме — подумать с разных сторон (мама 2 детей, тех‑специалист соцсети, блогер и т.д.)." },
];
const LESSONS_GROUP: Task[] = [
{ title: "Story builders", instruction: "Совместно создаём историю: завязка → развитие → кульминация → развязка." },
{ title: "Role-Card Debate", instruction: "Тема (например, запрет соцсетей в школах). Роли: учитель, родитель, ученик, политик и т.д.; говорить только с этой позиции." },
{ title: "The Jury", instruction: "Один — ‘подсудимый’, остальные — присяжные и свидетели; выслушать и вынести решение." },
{ title: "Mock talk show", instruction: "Импровизированный эфир/подкаст/интервью. Роли: ведущий, эксперт, гость, слушатель с вопросом." },
{ title: "Expert Group / Jigsaw Reading", instruction: "Текст разбить на части. Каждый читает свою как ‘эксперт’, затем обучает остальных." },
{ title: "Specialists Meeting", instruction: "Есть проблема. Роли: инженер, эколог, политик, гражданин… — предложить решения и собрать общий список." },
{ title: "The Pitch", instruction: "Команда разрабатывает продукт/идею/стартап. Роли: дизайнер, маркетолог, презентатор, аналитик. Финальная презентация инвесторам." },
{ title: "Press conference simulation", instruction: "Один — герой/знаменитость/политик/виновник. Остальные — журналисты с разными типами вопросов; нужно отстаивать позицию." },
{ title: "6 thinking Hats", instruction: "Каждый ‘надевает’ шляпу и оценивает ситуацию с разных точек (эмоции, логика, факты, опасения, креатив, управление)." },
{ title: "Mystery roles storytelling", instruction: "Рассказываем историю по ролям, у каждого секретная миссия (быть драматичным, говорить только вопросами, вставлять ЛЕ и т.п.)." },
{ title: "The brainstorm machine", instruction: "Генератор идей → Критик → Фильтратор → Коммуникатор → Представитель. Генерируем и отбираем решения." },
{ title: "Lexical detectives", instruction: "Работа с текстом по ролям: Охотник за новыми словами, Анализатор значений, Примеромет, Антонимщик, Синонимщик — затем ‘шоу’ с презентацией." },
];
const LESSONS_TRENDS: Task[] = [
{ title: "Hot take", instruction: "Провокационное/непопулярное мнение для тренировки аргументации. Придумываем и обсуждаем ‘горячие тейки’." },
{ title: "Базовый минимум – роскошный максимум", instruction: "Противопоставление простого варианта и максимально ‘люксовой’ версии по теме (сон, уход за собой, рабочее место…)." },
{ title: "Пропаганда, на которую я не поведусь / на которую поведусь", instruction: "Списки модных увлечений, которым вы не поддаётесь/поддаётесь. Критическое мышление, границы." },
{ title: "He’s/It’s a 10 but…", instruction: "Игра с идеальным вариантом 10/10, но с минусом, снижающим балл. Карточки, оценки, обсуждение." },
{ title: "Сильная аура – слабая аура", instruction: "Придумать, что делает человек со слабой/сильной аурой (с юмором)." },
{ title: "Green flag / red flag / beige flag", instruction: "Сигналы, что подходит/не подходит/странно. Списки флагов для отношений, дружбы, работы." },
{ title: "Что живёт у меня в голове rent free", instruction: "Образы/мысли/установки, которые ‘живут в голове’. Списки, истории, делимся, что не уходит из головы." },
{ title: "I’m a girl of course / I`m a beach bum of course..", instruction: "Объясняем типичные привычки/‘слабости’ через формат ‘of course’." },
{ title: "Не хочу (работать), но хочу (иметь деньги)", instruction: "Обсуждение мечт/карьерных целей, которые противоречат друг другу." },
{ title: "Закон подлости", instruction: "Ситуации, где всё идёт не по плану — примеры и обсуждение." },
{ title: "Это 100 из 10", instruction: "Крайняя степень восторга: ‘10 из 10’, ‘100 из 10’ — описываем впечатления (фильмы, еда, поездки)." },
{ title: "Ожидание – реальность", instruction: "Классический контраст между планами и реальностью — делимся своими кейсами." },
{ title: "Тот самый голос в голове", instruction: "Внутренний диалог/‘inner critic’. Диалоги, обсуждение." },
{ title: "Она в своей (спортивной) эре", instruction: "‘Эра’ как период жизни/состояния. Считываем признаки и формулируем: ‘она в своей … era’." },
{ title: "Не то чтобы кто-то спрашивал, но…", instruction: "Говорим о личных предпочтениях ‘по собственной инициативе’." },
{ title: "Не хочу это признавать, но это правда", instruction: "Признание неловкой истины/слабости." },
{ title: "Список дел, которые я всё равно не сделаю", instruction: "Составляем честный список задач, которые, вероятно, не будут выполнены." },
{ title: "Вещи, которые делают меня…", instruction: "Списки того, что делает счастливым/злится/вдохновляет и т.д.; истории." },
{ title: "Типы людей, которые…", instruction: "Классификации людей по поведению/привычкам; инфографика; к какому типу относим себя." },
{ title: "Вливаться в общество – быть счастливой", instruction: "Внутренний конфликт между ‘соответствовать ожиданиям’ и ‘быть собой’." },
{ title: "Как мы представляем тех, кто …", instruction: "Создаём предложение и брейнстормим образ людей по теме (добавляем фото/текст)." },
{ title: "Атрибуты идеальной …", instruction: "Фрейм ‘атрибуты идеального ...’: писать/рисовать/добавлять картинки (у каждого свой набор)." },
{ title: "Норм или стрём", instruction: "Списки вещей/привычек/действий — обсуждаем, что норм, а что стрём." },
{ title: "Скажи, что ты (устал), не говоря, что ты (устал)", instruction: "Формулируем признаки состояния без прямого называния (‘не могу заставить себя пойти в душ’ и т.д.)." },
];
const DATA: Category[] = [
{ name: "Домашние задания", subcategories: [
{ name: "Идеи для работы с языком", tasks: HOMEWORK_LANGUAGE },
{ name: "Идеи для работы с текстом", tasks: HOMEWORK_TEXT },
{ name: "Идеи для работы с видео", tasks: HOMEWORK_VIDEO },
{ name: "Творческие задания", tasks: HOMEWORK_CREATIVE },
]},
{ name: "Уроки", subcategories: [
{ name: "Задания для работы с текстом", tasks: LESSONS_TEXT },
{ name: "Ranking activities", tasks: LESSONS_RANKING },
{ name: "Sorting activities", tasks: LESSONS_SORTING },
{ name: "Discussion activities", tasks: LESSONS_DISCUSSION },
{ name: "Group activities", tasks: LESSONS_GROUP },
{ name: "Тренды", tasks: LESSONS_TRENDS },
]},
];
// ---------- UI ----------
const App: React.FC = () => {
const [category, setCategory] = useState<string>(DATA[0].name);
const [subcategory, setSubcategory] = useState<string>(DATA[0].subcategories[0].name);
const [current, setCurrent] = useState<Task | null>(null);
const currentSubcat = useMemo(() => {
const cat = DATA.find(c => c.name === category)!;
return cat.subcategories.find(s => s.name === subcategory)!;
}, [category, subcategory]);
const drawRandom = () => {
const arr = currentSubcat.tasks;
if (!arr.length) return;
const idx = Math.floor(Math.random() * arr.length);
setCurrent(arr[idx]);
};
return (
<div className="min-h-screen w-full bg-[#000000] text-white">
{/* HEADER */}
<header className="sticky top-0 z-10 border-b border-white/10" style={{background: "linear-gradient(90deg,#96a89011,#000000,#ffe84d11)"}}>
<div className="max-w-5xl mx-auto px-4 py-5 flex items-center justify-between">
<div>
<h1 className="text-2xl md:text-3xl font-bold tracking-tight">Система разговорных клубов</h1>
<p className="text-sm opacity-80">Автор: Котова Наталья</p>
</div>
<Badge className="text-black" style={{backgroundColor: "#ffe84d"}}>v3</Badge>
</div>
</header>
{/* CONTROLS */}
<main className="max-w-5xl mx-auto px-4 py-8 space-y-6">
<Card className="bg-white/5 border-white/10 rounded-2xl shadow-xl">
<CardContent className="p-5 md:p-6">
<div className="grid md:grid-cols-2 gap-4">
<div className="space-y-2">
<label className="text-sm" style={{color: "#d9e0d0"}}>Категория</label>
<select
className="w-full rounded-xl px-4 py-3 bg-[#b7c6af] text-black focus:outline-none"
value={category}
onChange={(e) => {
setCategory(e.target.value);
const first = DATA.find(c => c.name === e.target.value)!.subcategories[0];
setSubcategory(first.name);
setCurrent(null);
}}
>
{DATA.map(c => (
<option key={c.name} value={c.name}>{c.name}</option>
))}
</select>
</div>
<div className="space-y-2">
<label className="text-sm" style={{color: "#d9e0d0"}}>Подкатегория</label>
<select
className="w-full rounded-xl px-4 py-3 bg-[#b7c6af] text-black focus:outline-none"
value={subcategory}
onChange={(e) => { setSubcategory(e.target.value); setCurrent(null); }}
>
{DATA.find(c => c.name === category)!.subcategories.map(s => (
<option key={s.name} value={s.name}>{s.name}</option>
))}
</select>
</div>
</div>
<div className="mt-6 flex items-center gap-3">
<Button onClick={drawRandom} className="rounded-2xl px-5 py-6 text-base font-semibold shadow-lg border-2"
style={{backgroundColor: "#96a890", color: "#000", borderColor: "#ffe84d"}}
asChild={false}
>
Случайное задание
</Button>
<Badge className="bg-white/10 border border-white/10 rounded-xl">{currentSubcat.tasks.length} заданий</Badge>
</div>
</CardContent>
</Card>
{/* RESULT */}
{current && (
<motion.div initial={{opacity: 0, y: 16}} animate={{opacity: 1, y: 0}} transition={{type: "spring", stiffness: 200, damping: 18}}>
<Card className="bg-white rounded-3xl text-black shadow-2xl border-4" style={{borderColor: "#96a890"}}>
<CardContent className="p-6 md:p-8">
<div className="flex items-center gap-3 mb-3">
<span className="inline-block w-2 h-6 rounded-full" style={{backgroundColor: "#ffe84d"}} />
<h2 className="text-xl md:text-2xl font-bold leading-tight">{current.title}</h2>
</div>
<p className="text-base leading-relaxed whitespace-pre-wrap">{expandInstruction(current.title, current.instruction, {category, subcategory})}</p>
</CardContent>
</Card>
</motion.div>
)}
{/* LIST */}
<details className="mt-6 group">
<summary className="cursor-pointer text-sm opacity-80 inline-flex items-center gap-2">Показать весь список заданий текущей подкатегории</summary>
<div className="mt-4 grid md:grid-cols-2 gap-4">
{currentSubcat.tasks.map((t, i) => (
<Card key={i} className="bg-[#1a1a1a] border border-white/10 rounded-2xl">
<CardContent className="p-5">
<h3 className="font-semibold mb-2 text-white">{t.title}</h3>
<p className="text-sm text-white/90 whitespace-pre-wrap">{expandInstruction(t.title, t.instruction, {category, subcategory})}</p>
</CardContent>
</Card>
))}
</div>
</details>
</main>
{/* FOOTER */}
<footer className="mt-10 pb-10">
<div className="max-w-5xl mx-auto px-4 flex items-center justify-between">
<p className="text-xs opacity-70">© {new Date().getFullYear()} «Система разговорных клубов». Автор: Котова Наталья.</p>
<div className="flex items-center gap-2">
<span className="inline-block w-2 h-2 rounded-full" style={{backgroundColor: "#96a890"}} />
<span className="inline-block w-2 h-2 rounded-full" style={{backgroundColor: "#ffe84d"}} />
</div>
</div>
</footer>
</div>
);
};
export default App;