Add Alyona curator results sharing
AI Just committed 2026-08-28 16:43:03 +0000

Analyzing diff...

plans/alyona/weeks-9-10/index.html+56 −0
index 7176a28..33c98d7 100644
--- a/plans/alyona/weeks-9-10/index.html
+++ b/plans/alyona/weeks-9-10/index.html
@@ -164,6 +164,16 @@
         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;
@@ -626,6 +636,7 @@
       </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
@@ -638,6 +649,17 @@
           ><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>
+        <p id="resultsStatus" role="status" aria-live="polite"></p>
+      </dialog>
 
       <div class="weeks-grid">
         <section class="week" data-week="8">
@@ -944,6 +966,40 @@
         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();
       function renderWeek(target, data, week) {
         const root = document.getElementById(target);
         data.forEach((d, di) => {