Import live Alyona weeks 9-10 as canonical source
OpenClaw Engineer committed 2026-09-08 14:37:02 +0000

Analyzing diff...

plans/alyona/weeks-9-10/index.html+149 −56
index 33c98d7..948f391 100644
--- a/plans/alyona/weeks-9-10/index.html
+++ b/plans/alyona/weeks-9-10/index.html
@@ -164,16 +164,6 @@
         box-shadow: var(--shadow);
         margin: 0 0 34px;
       }
-      .results-action { display: flex; justify-content: center; margin: -10px 0 26px; }
-      .results-button, .results-secondary { border: 0; border-radius: 999px; padding: 14px 22px; font: inherit; font-weight: 850; cursor: pointer; }
-      .results-button { background: var(--navy); color: #fff; box-shadow: var(--shadow); }
-      .results-secondary { background: #dfeaf5; color: var(--navy); }
-      .results-dialog { width: min(680px, calc(100% - 28px)); border: 0; border-radius: 24px; padding: 22px; box-shadow: 0 24px 80px rgba(20,48,75,.28); }
-      .results-dialog::backdrop { background: rgba(20,48,75,.55); }
-      .results-dialog h2 { margin: 0 0 8px; color: var(--navy); }
-      .results-dialog p { color: var(--muted); }
-      .results-preview { width: 100%; min-height: 270px; box-sizing: border-box; resize: vertical; border: 1px solid #c9d8e7; border-radius: 14px; padding: 12px; font: inherit; }
-      .results-dialog-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; }
       .progress-top {
         display: flex;
         justify-content: space-between;
@@ -210,6 +200,79 @@
         color: var(--muted);
         font-size: 0.85rem;
       }
+      .report-actions {
+        display: flex;
+        justify-content: flex-end;
+        margin-top: 14px;
+      }
+      .report-button,
+      .modal-button {
+        border: 0;
+        border-radius: 14px;
+        padding: 11px 16px;
+        background: var(--navy);
+        color: var(--white);
+        font-weight: 800;
+        cursor: pointer;
+      }
+      .report-button:hover,
+      .modal-button:hover {
+        background: var(--blue);
+      }
+      .modal-button.secondary {
+        background: var(--sky);
+        color: var(--navy);
+        border: 1px solid var(--line);
+      }
+      .report-dialog {
+        width: min(720px, calc(100% - 28px));
+        max-height: calc(100dvh - 28px);
+        padding: 0;
+        border: 0;
+        border-radius: 24px;
+        color: var(--ink);
+        box-shadow: 0 24px 80px rgba(16, 43, 85, 0.28);
+      }
+      .report-dialog::backdrop {
+        background: rgba(16, 43, 85, 0.58);
+        backdrop-filter: blur(4px);
+      }
+      .report-dialog-inner {
+        padding: 24px;
+      }
+      .report-dialog h2 {
+        margin: 0;
+        color: var(--navy);
+      }
+      .report-dialog p {
+        margin: 8px 0 16px;
+        color: var(--muted);
+      }
+      .report-preview {
+        display: block;
+        width: 100%;
+        min-height: 300px;
+        max-height: 48dvh;
+        resize: vertical;
+        padding: 14px;
+        border: 1px solid var(--line);
+        border-radius: 14px;
+        background: var(--paper);
+        color: var(--ink);
+      }
+      .report-dialog-actions {
+        display: flex;
+        flex-wrap: wrap;
+        justify-content: flex-end;
+        gap: 10px;
+        margin-top: 16px;
+      }
+      .copy-status {
+        min-height: 1.4em;
+        margin-top: 8px;
+        color: var(--ok);
+        font-weight: 700;
+      }
       .weeks-grid {
         display: grid;
         grid-template-columns: minmax(0, 1fr);
@@ -636,7 +699,6 @@
       </p>
     </header>
     <main class="shell">
-      <div class="results-action"><button class="results-button" id="openResults" type="button">Отправить итоги куратору</button></div>
       <section class="progress-panel" aria-label="Прогресс плана">
         <div class="progress-top">
           <span class="progress-title">Прогресс тренировок</span
@@ -648,18 +710,12 @@
           ><span id="week9Stat">Неделя 10: 0 из 7</span
           ><span id="practiceStat">Практики: 0 отметок</span>
         </div>
-      </section>
-      <dialog class="results-dialog" id="resultsDialog">
-        <h2>Итоги для @manoraya</h2>
-        <p>Проверьте текст. Ничего не отправляется автоматически: сначала скопируйте итоги, затем откройте чат и вставьте их.</p>
-        <textarea class="results-preview" id="resultsPreview" aria-label="Предпросмотр итогов"></textarea>
-        <div class="results-dialog-actions">
-          <button class="results-button" id="copyResults" type="button">Скопировать итоги</button>
-          <button class="results-button" id="openCurator" type="button">Открыть @manoraya в Telegram</button>
-          <button class="results-secondary" id="closeResults" type="button">Закрыть</button>
+        <div class="report-actions">
+          <button class="report-button" id="openReport" type="button">
+            Отправить итоги куратору
+          </button>
         </div>
-        <p id="resultsStatus" role="status" aria-live="polite"></p>
-      </dialog>
+      </section>
 
       <div class="weeks-grid">
         <section class="week" data-week="8">
@@ -748,6 +804,23 @@
       Все отметки и комментарии сохраняются только в браузере на этом
       устройстве.
     </footer>
+    <dialog class="report-dialog" id="reportDialog">
+      <div class="report-dialog-inner">
+        <h2>Итоги для куратора</h2>
+        <p>
+          Проверьте текст. Кнопка «Открыть чат» скопирует его и откроет
+          Telegram-диалог с @manoraya — останется вставить текст и подтвердить
+          отправку.
+        </p>
+        <textarea class="report-preview" id="reportPreview" aria-label="Текст итогов"></textarea>
+        <div class="copy-status" id="copyStatus" aria-live="polite"></div>
+        <div class="report-dialog-actions">
+          <button class="modal-button secondary" id="closeReport" type="button">Закрыть</button>
+          <button class="modal-button secondary" id="copyReport" type="button">Скопировать</button>
+          <button class="modal-button" id="sendReport" type="button">Открыть чат @manoraya</button>
+        </div>
+      </div>
+    </dialog>
     <script>
       const W8 = [
         [
@@ -966,40 +1039,7 @@
         localStorage.setItem(KEY, JSON.stringify(state));
         updateProgress();
       };
-      function buildResults() {
-        const completed = [...document.querySelectorAll(".check:checked")].map((check) => {
-          const workout = check.closest(".workout");
-          const day = check.closest(".day").querySelector("h3").textContent;
-          const week = check.dataset.id.startsWith("w8-") ? "Неделя 9" : "Неделя 10";
-          return `${week}, ${day}: ${workout.querySelector("a").textContent}`;
-        });
-        const comments = Object.entries(state.comments || {}).filter(([, value]) => String(value).trim()).map(([id, value]) => {
-          const field = document.querySelector(`[data-comment="${id}"]`);
-          const title = field ? field.closest(".workout").querySelector("a").textContent : id;
-          return `${title}: ${String(value).trim()}`;
-        });
-        const practices = [];
-        [8, 9].forEach((week) => TECH.forEach((title, technique) => {
-          const days = DAYS.filter((_, day) => state.practice[`w${week}-p${technique}-d${day}`]);
-          if (days.length) practices.push(`Неделя ${week === 8 ? 9 : 10}: ${title} — ${days.join(", ")}`);
-        }));
-        const total = document.querySelectorAll(".check").length;
-        return ["Итоги по плану Алёны · недели 9–10", `Тренировки: ${completed.length} из ${total}`, "", "Выполнено:", completed.length ? completed.map((x) => `• ${x}`).join("\n") : "— пока без отметок", "", "Техники:", practices.length ? practices.map((x) => `• ${x}`).join("\n") : "— пока без отметок", "", "Комментарии:", comments.length ? comments.map((x) => `• ${x}`).join("\n") : "— нет комментариев", "", location.href].join("\n");
-      }
-      const resultsDialog = document.getElementById("resultsDialog");
-      document.getElementById("openResults").onclick = () => {
-        document.getElementById("resultsPreview").value = buildResults();
-        document.getElementById("resultsStatus").textContent = "";
-        resultsDialog.showModal();
-      };
-      document.getElementById("copyResults").onclick = async () => {
-        const preview = document.getElementById("resultsPreview");
-        try { await navigator.clipboard.writeText(preview.value); }
-        catch (_) { preview.select(); document.execCommand("copy"); }
-        document.getElementById("resultsStatus").textContent = "Итоги скопированы. Теперь откройте чат и вставьте сообщение.";
-      };
-      document.getElementById("openCurator").onclick = () => window.open("https://t.me/manoraya", "_blank", "noopener");
-      document.getElementById("closeResults").onclick = () => resultsDialog.close();
+      const workoutLabels = {};
       function renderWeek(target, data, week) {
         const root = document.getElementById(target);
         data.forEach((d, di) => {
@@ -1008,6 +1048,7 @@
           day.innerHTML = `<div class="day-head"><h3>${d[0]}</h3><span class="day-type">${d[1]}</span></div>`;
           d[2].forEach((w, wi) => {
             const id = `w${week}-d${di}-t${wi}`;
+            workoutLabels[id] = `Неделя ${week === 8 ? 9 : 10}, ${d[0]} — ${w[0]}`;
             const row = document.createElement("div");
             row.className = "workout";
             row.innerHTML = `<input class="check" type="checkbox" aria-label="Отметить тренировку выполненной" data-id="${id}" ${state.done[id] ? "checked" : ""}><div><a href="${w[1]}" target="_blank" rel="noopener">${w[0]}</a><div class="meta">${w[3]}</div></div><span class="duration">${w[2]}</span><textarea class="comment" data-comment="${id}" placeholder="Комментарий после тренировки">${state.comments[id] || ""}</textarea>`;
@@ -1176,6 +1217,46 @@
         document.getElementById("practiceStat").textContent =
           `Практики: ${Object.values(state.practice).filter(Boolean).length} отметок`;
       }
+      function buildReport() {
+        const checks = [...document.querySelectorAll(".check")];
+        const done = checks.filter((c) => c.checked);
+        const comments = Object.entries(state.comments)
+          .filter(([, value]) => value && value.trim())
+          .map(([id, value]) => `• ${workoutLabels[id] || id}: ${value.trim()}`);
+        const practiceByWeek = [8, 9].map((week) => {
+          const items = TECH.map((label, technique) => {
+            const days = DAYS.filter((_, day) => state.practice[`w${week}-p${technique}-d${day}`]);
+            return days.length ? `• ${label}: ${days.join(", ")}` : null;
+          }).filter(Boolean);
+          return { label: week === 8 ? 9 : 10, items };
+        });
+        const lines = [
+          "Итоги плана за 9–10 недели",
+          "",
+          `Тренировки: ${done.length} из ${checks.length}`,
+          ...done.map((c) => `✓ ${workoutLabels[c.dataset.id]}`),
+          "",
+          "Комментарии:",
+          ...(comments.length ? comments : ["• Комментариев нет"]),
+          "",
+          "Практики саморегуляции:",
+        ];
+        practiceByWeek.forEach(({ label, items }) => {
+          lines.push(`Неделя ${label}:`);
+          lines.push(...(items.length ? items : ["• Отметок нет"]));
+        });
+        return lines.join("\n");
+      }
+      async function copyReportText() {
+        const preview = document.getElementById("reportPreview");
+        try {
+          await navigator.clipboard.writeText(preview.value);
+        } catch (_) {
+          preview.select();
+          document.execCommand("copy");
+        }
+        document.getElementById("copyStatus").textContent = "Текст скопирован";
+      }
       renderWeek("week8Days", W8, 8);
       renderWeek("week9Days", W9, 9);
       document.querySelectorAll(".check").forEach(
@@ -1195,6 +1276,18 @@
       document
         .querySelectorAll("[data-game]")
         .forEach((g) => renderBingo(g, g.dataset.game));
+      const reportDialog = document.getElementById("reportDialog");
+      document.getElementById("openReport").onclick = () => {
+        document.getElementById("reportPreview").value = buildReport();
+        document.getElementById("copyStatus").textContent = "";
+        reportDialog.showModal();
+      };
+      document.getElementById("closeReport").onclick = () => reportDialog.close();
+      document.getElementById("copyReport").onclick = copyReportText;
+      document.getElementById("sendReport").onclick = async () => {
+        await copyReportText();
+        window.open("https://t.me/manoraya", "_blank", "noopener");
+      };
       updateProgress();
     </script>
   </body>