// Теория под себя — интерактив: сценарии, чат Töre, форма ожидания (function () { "use strict"; var STORE_KEY = "tore-theory-chat-v1"; var WAIT_KEY = "tore-theory-wait-v1"; var MAX_STORED = 30; var SCENARIOS = { habits: { title: "Привычки", question: "Покажи, какие мои утренние привычки повторяются каждый день.", answer: "Собрал за 14 дней подряд: подъём до 08:00 — 12 раз, прогулка 20 минут — 10, кофе до работы — 14 из 14.", points: [ "Самая устойчивая связка: подъём + прогулка до 09:00.", "В дни без прогулки уровень энергии к обеду заметно ниже.", "Предлагаю закрепить прогулку в 08:15 на этой неделе." ], followups: ["Что добавить в утро?", "Как выглядит типичный день?"] }, time: { title: "Распределение времени", question: "Куда уходит больше всего времени по будням?", answer: "Разложил 24 рабочих часа по блокам. Топ: фокус-задачи — 9 ч, переписки и звонки — 6 ч, обучение — 3 ч.", points: [ "Больше всего «съедает» переписка по средам и пятницам.", "Фокус-задачи лучше всего получаются до 11:00.", "Если собрать переписку в один слот в 13:00, высвобождается около 1,5 ч." ], followups: [ "Где я теряю время?", "Что сдвинуть, чтобы найти час на обучение?" ] }, results: { title: "Результаты за неделю", question: "Сравни мою неделю с прошлой: что выросло?", answer: "Сверил две недели по трём метрикам: закрытых задач 18 против 14, новых навыков в работе 2 против 0, просроченных — 1 против 3.", points: [ "Рост стабильный третий период подряд: в среднем +12% по закрытым задачам.", "Просрочки упали после того, как приоритеты стали меняться только утром.", "На следующей неделе стоит добавить ещё один глубокий фокус-слот." ], followups: ["Составь план на след. неделю", "Что мешает росту?"] } }; var GENERAL_ANSWERS = [ { keys: ["привычк", "утро", "подъём"], text: { answer: "Посмотрел по дням: устойчивых повторов больше, чем кажется. Твоя «сильная» зона — начало дня.", points: [ "Регулярнее всего повторяются подъём, кофе и короткая разминка.", "Новые вещи закрепляются, если ставить их сразу после устойчивого шага." ] } }, { keys: ["время", "час", "растор", "потеря"], text: { answer: "Посчитаю по блокам времени: где оно собирается, а где разбивается на мелкие куски.", points: [ "Длинные фокус-блоки редки: чаще 25–35 минут до прерывания.", "Лучший приём недели — собрать мелкие дела в один вечерний слот." ] } }, { keys: ["результат", "недел", "рост", "показател", "сравн"], text: { answer: "По последним периодам динамика вверх: ключевые цифры растут второй период кряду.", points: [ "Рост ровный, без провалов — значит, методика сработала.", "Следующая точка роста — добавить один новый фокус-слот." ] } }, { keys: ["план", "рекомендац", "что делать", "совет"], text: { answer: "Вот короткая рекомендация на ближайшие 7 дней, под твой текущий ритм.", points: [ "Фиксировать утро: два шага, без выбора и откладывания.", "Один большой блок работы до обеда, без переписок.", "В воскресенье — 15 минут на сверку: что сработало, что нет." ], followups: ["Составь план на неделю", "Что мешает росту?"] } }, { keys: ["план", "след"], text: { answer: "Собрал план на неделю по твоим метрикам.", points: [ "Пн–чт: по одному фокус-блоку на главную задачу.", "Пт: разбор недели, 20 минут, без новых задач." ], } } ]; function byId(id) { return document.getElementById(id); } function esc(s) { return String(s).replace(/[&<>"]/g, function (c) { return { "&": "&", "<": "<", ">": ">", '"': """ }[c]; }); } function loadChat() { try { var raw = localStorage.getItem(STORE_KEY); if (!raw) return []; var arr = JSON.parse(raw); return Array.isArray(arr) ? arr : []; } catch (e) { return []; } } function saveChat(list) { try { if (list.length > MAX_STORED) list = list.slice(list.length - MAX_STORED); localStorage.setItem(STORE_KEY, JSON.stringify(list)); } catch (e) { /* квота — молча пропускаем */ } } function msgHtml(m) { if (m.role === "user") { return '
Ты
' + esc(m.text) + "
"; } var html = '
' + '' + "Töre · " + esc(m.time) + "
"; if (m.text) html += "

" + esc(m.text) + "

"; if (m.points && m.points.length) { html += '"; } if (m.followups && m.followups.length) { html += '
'; for (var j = 0; j < m.followups.length; j++) { html += '"; } html += "
"; } return html + "
"; } function appendMsg(m, stored) { var log = byId("chat-log"); if (!log) return; var div = document.createElement("div"); div.innerHTML = msgHtml(m); var node = div.firstChild; log.appendChild(node); log.scrollTop = log.scrollHeight; if (stored) { var list = loadChat(); list.push(m); saveChat(list); } } function renderStored(list) { var log = byId("chat-log"); if (!log) return; log.innerHTML = ""; for (var i = 0; i < list.length; i++) { var div = document.createElement("div"); div.innerHTML = msgHtml(list[i]); log.appendChild(div.firstChild); } log.scrollTop = log.scrollHeight; } function answerFor(text) { var t = text.toLowerCase(); for (var i = 0; i < GENERAL_ANSWERS.length; i++) { var keys = GENERAL_ANSWERS[i].keys; for (var j = 0; j < keys.length; j++) { if (t.indexOf(keys[j]) !== -1) return GENERAL_ANSWERS[i].text; } } return FALLBACK; } function nowTime() { var d = new Date(); var hh = ("0" + d.getHours()).slice(-2); var mm = ("0" + d.getMinutes()).slice(-2); return hh + ":" + mm; } function sendUser(text) { if (!text) return; appendMsg({ role: "user", text: text, time: nowTime() }, true); setTimeout(function () { var res = answerFor(text); var msg = { role: "ai", text: res.answer, points: res.points || null, time: nowTime() }; if (res.points) msg.followups = res.followups || null; appendMsg(msg, true); }, 450); } function initChat() { var log = byId("chat-log"); if (!log) return; var stored = loadChat(); if (stored.length) { renderStored(stored); } else { appendMsg({ role: "ai", text: "Привет! Я Töre — ИИ-аналитик. Выбери сценарий выше или спроси меня о своих данных: привычки, время, результаты.", points: null, time: nowTime() }, false); } var form = byId("chat-form"); var input = byId("chat-input"); if (form && input) { form.addEventListener("submit", function (e) { e.preventDefault(); var v = input.value.trim(); if (!v) return; input.value = ""; input.style.height = "auto"; sendUser(v); }); input.addEventListener("keydown", function (e) { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); form.requestSubmit(); } }); input.addEventListener("input", function () { input.style.height = "auto"; input.style.height = Math.min(input.scrollHeight, 120) + "px"; }); } // Чипы-продолжения: делегирование log.addEventListener("click", function (e) { var btn = e.target; while (btn && btn.tagName !== "BUTTON") btn = btn.parentNode; if (!btn || !btn.classList || !btn.classList.contains("tk-prompt-chip")) return; var q = btn.getAttribute("data-q"); if (q) sendUser(q); }); } function initScenarios() { var tabs = document.querySelectorAll("#scenario-list .kt-ai-tab"); for (var i = 0; i < tabs.length; i++) { (function (tab) { tab.addEventListener("click", function () { var id = tab.getAttribute("data-scenario"); for (var k = 0; k < tabs.length; k++) tabs[k].setAttribute("data-active", "false"); tab.setAttribute("data-active", "true"); var s = SCENARIOS[id]; if (!s) return; sendUser(s.question); }); })(tabs[i]); } } function initWait() { var input = byId("wait-email"); var btn = byId("wait-submit"); var note = byId("wait-note"); var field = input ? input.closest(".kt-ai-field") : null; if (!input || !btn) return; var saved = ""; try { saved = localStorage.getItem(WAIT_KEY) || ""; } catch (e) {} if (saved) { input.value = saved; if (note) note.textContent = "Сохранено: " + saved + ". При запуске пришлём уведомление."; } btn.addEventListener("click", function () { var v = input.value.trim(); if (field) field.setAttribute("data-invalid", "false"); if (!v) { if (field) field.setAttribute("data-invalid", "true"); input.focus(); if (note) note.textContent = "Введите адрес, чтобы сохранить заявку."; return; } if (v.indexOf("@") === -1 || v.indexOf("@") === 0 || v.indexOf("@") === v.length - 1) { if (field) field.setAttribute("data-invalid", "true"); if (note) note.textContent = "Похоже, в адресе опечатка — проверь формат."; return; } try { localStorage.setItem(WAIT_KEY, v); } catch (e) {} if (note) note.textContent = "Сохранено: " + v + ". При запуске пришлём уведомление."; }); input.addEventListener("input", function () { if (field) field.setAttribute("data-invalid", "false"); }); } function initNav() { var links = document.querySelectorAll("a[href^='#']"); for (var i = 0; i < links.length; i++) { (function (a) { a.addEventListener("click", function () { var id = a.getAttribute("href"); if (id.length > 1) { var el = byId(id.slice(1)); if (el) el.scrollIntoView({ behavior: "smooth", block: "start" }); } }); })(links[i]); } } function init() { initChat(); initScenarios(); initWait(); initNav(); var hint = byId("chat-hint"); if (hint) hint.textContent = "Диалог сохраняется в этом браузере — можно вернуться позже."; } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", init); } else { init(); } })();