Files
notes-qpid-pro/app/static/index.html
T

928 lines
55 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ru" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Notes — Персональный тренажер и словарь английского языка</title>
<meta name="description" content="Защищённый персональный тренажёр и словарь английского языка с интервальными повторениями SRS SM-2, контекстным поиском и озвучкой">
<link rel="stylesheet" href="/static/css/style.css?v=2.6">
<!-- PWA meta and icons -->
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#0f172a">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Notes English">
<link rel="icon" type="image/png" href="/static/icons/icon-192.png">
<link rel="apple-touch-icon" href="/static/icons/icon-192.png">
</head>
<body>
<!-- Login Overlay / Page -->
<div id="login-overlay" class="login-overlay hidden">
<div class="login-card">
<div class="login-header">
<div class="login-logo">📖</div>
<h1>Notes</h1>
<p>Персональный словарь и тренажёр английского языка</p>
</div>
<form id="login-form" class="login-form">
<div class="form-group">
<label for="login-username">Имя пользователя</label>
<input type="text" id="login-username" class="input-styled" autocomplete="username" required autofocus placeholder="kopri">
</div>
<div class="form-group">
<label for="login-password">Пароль</label>
<input type="password" id="login-password" class="input-styled" autocomplete="current-password" required placeholder="••••••••">
</div>
<div id="login-error" class="login-error hidden"></div>
<button type="submit" id="login-submit-btn" class="btn btn-primary btn-block">
Войти в словарь
</button>
</form>
<div class="login-footer">
<small>Безопасное хранилище словаря • study.qpid.pro</small>
</div>
</div>
</div>
<!-- Main Application Shell -->
<div id="app-shell" class="app-shell hidden">
<!-- Top Navigation Bar -->
<header class="navbar">
<div class="nav-brand" id="nav-brand-home" title="На главную">
<span class="brand-icon">📖</span>
<span class="brand-title">Notes</span>
<span class="brand-sub">English Lexicon</span>
</div>
<div class="nav-center">
<div class="nav-stats" id="nav-stats">
<span class="stat-badge" title="Всего слов в словаре">Всего: <strong id="stat-total">0</strong></span>
<span class="stat-badge stat-today" title="Добавлено сегодня">Сегодня: <strong id="stat-today">+0</strong></span>
</div>
</div>
<div class="nav-actions">
<button id="nav-reader-btn" class="btn btn-outline btn-sm" title="Интерактивная читалка и библиотека книг">
<span>📚 Читалка</span>
</button>
<button id="srs-trainer-btn" class="btn btn-trainer" title="Интервальный тренажер (Flashcards, 4 варианта, диктант, ввод)">
<span class="trainer-icon">🎓</span>
<span class="trainer-text">Тренажёр SRS</span>
<span id="srs-badge" class="srs-due-badge">0</span>
</button>
<button id="stats-open-btn" class="btn btn-outline btn-sm stat-open-btn" title="Календарь активности и статистика">
<span>📊 Статистика</span>
</button>
<button id="export-open-btn" class="btn btn-outline btn-sm" title="Экспорт словаря">
<span>📤 Экспорт</span>
</button>
<button id="theme-toggle" class="icon-btn" title="Переключить тему">🌓</button>
<div class="user-profile">
<span id="user-display-name" class="user-badge">user</span>
<button id="change-pwd-open-btn" class="btn btn-sm btn-outline" title="Сменить пароль">🔑 Пароль</button>
<button id="logout-btn" class="btn btn-sm btn-outline" title="Выйти из аккаунта">Выход</button>
</div>
</div>
</header>
<!-- VIEW 1: Main Dictionary & Capture View -->
<main class="main-content" id="dictionary-view">
<!-- Search & Translation Section -->
<section class="search-section">
<div class="search-box-wrapper">
<div class="search-input-box">
<span class="search-icon">🔍</span>
<input type="text" id="term-input" placeholder="Введите слово, фразовый глагол или предложение..." autocomplete="off" autofocus>
<button id="clear-search-btn" class="clear-btn hidden" title="Очистить (Esc)">✕</button>
<button id="translate-btn" class="btn btn-primary translate-action-btn">Перевести</button>
</div>
<!-- Duplicate Warning Notification -->
<div id="duplicate-warning-box" class="duplicate-warning-box hidden">
<div class="dup-left">
<span class="dup-icon">⚠️</span>
<span class="dup-text">Это слово уже есть в вашем словаре: <strong id="dup-term-label"></strong> (<em id="dup-trans-label"></em>)</span>
</div>
<button id="dup-open-btn" class="btn btn-xs btn-outline">Посмотреть / Дополнить</button>
</div>
<div class="hotkey-hints">
<span class="hint-item"><kbd>Enter</kbd> перевод</span>
<span class="hint-item"><kbd>Ctrl</kbd>+<kbd>Enter</kbd> сохранить</span>
<span class="hint-item"><kbd>Esc</kbd> сброс</span>
<span class="hint-item"><kbd>Space</kbd> / <kbd>🔊</kbd> озвучить</span>
</div>
</div>
<!-- Live Translation & Dictionary Lookup Result Card -->
<div id="lookup-card" class="lookup-card hidden">
<div class="lookup-header">
<div class="lookup-term-group">
<h2 id="res-term" class="res-term">Word</h2>
<span id="res-phonetic" class="res-phonetic">/wɜːd/</span>
<button id="audio-play-btn" class="icon-btn audio-btn hidden" style="display: none;" title="Прослушать произношение">🔊</button>
</div>
<span id="res-pos" class="badge-pos">Noun</span>
</div>
<!-- English Definition if available -->
<div id="res-definition-wrap" class="definition-wrap hidden">
<div class="def-label">Толкование (EN):</div>
<div id="res-definition" class="res-definition"></div>
</div>
<!-- Primary Translation Field (Editable before saving) -->
<div class="form-group edit-translation-group">
<label for="edit-translation">Перевод на русский язык:</label>
<div class="input-with-button">
<input type="text" id="edit-translation" class="input-styled" placeholder="Русский перевод...">
</div>
</div>
<!-- Context & Extra Details Box -->
<div class="context-group">
<label for="edit-context">Контекстное предложение (где встретилось выражение):</label>
<textarea id="edit-context" class="input-styled textarea-context" rows="2" placeholder="He was reluctant to admit his mistake during the team retrospective..."></textarea>
</div>
<!-- Organization: Collection & Tags Row -->
<div class="meta-inputs-grid">
<div class="field-row">
<div class="form-group flex-1">
<label for="edit-collection">📁 Коллекция (папка):</label>
<input type="text" id="edit-collection" list="collections-datalist" class="input-styled" value="General" placeholder="General, IT, Work...">
<datalist id="collections-datalist"></datalist>
</div>
<div class="form-group flex-1">
<label for="edit-tags">🏷️ Теги (через запятую):</label>
<input type="text" id="edit-tags" class="input-styled" placeholder="#phrasal-verb, #work, #daily" value="general">
</div>
<div class="form-group flex-1">
<label for="edit-notes">💡 Заметка / Ассоциация:</label>
<input type="text" id="edit-notes" class="input-styled" placeholder="Ассоциация...">
</div>
</div>
</div>
<div class="result-actions">
<button id="save-card-btn" class="btn btn-success btn-lg">
💾 Сохранить в словарь <span class="btn-subtext">(Ctrl + Enter)</span>
</button>
</div>
</div>
</section>
<!-- Vocabulary Notebook & History -->
<section class="vocabulary-section">
<div class="section-header">
<div class="section-title-wrap">
<h3>📚 Мой словарь</h3>
<span id="cards-count-label" class="cards-count-label">(0 записей)</span>
</div>
<div class="list-controls">
<button id="batch-toggle-btn" class="btn btn-sm btn-outline batch-mode-btn" title="Режим множественного выбора">
☑️ Выбрать
</button>
<div class="search-mini-box">
<input type="text" id="filter-input" placeholder="Фильтр по слову, переводу, контексту...">
</div>
</div>
</div>
<!-- Collections Filter Bar -->
<div class="collections-filter-wrap">
<div class="filter-header-bar">
<span class="filter-title">📁 Коллекции:</span>
<button id="new-collection-btn" class="btn btn-xs btn-ghost">+ Новая папка</button>
</div>
<div id="collections-filter-bar" class="filter-chips-row">
<button class="col-chip active" data-col="">Все коллекции</button>
</div>
</div>
<!-- Active Tags Filter -->
<div class="tags-filter-wrap">
<span class="filter-title">🏷️ Теги:</span>
<div id="tags-filter-bar" class="filter-chips-row">
<button class="filter-chip active" data-tag="">Все теги</button>
</div>
</div>
<!-- Cards Grid/List -->
<div id="cards-list" class="cards-list">
<div class="empty-state" id="empty-state">
<div class="empty-icon">🌱</div>
<h4>Ваш словарь пока пуст</h4>
<p>Введите первое слово или фразу в поле поиска выше и сохраните её!</p>
</div>
</div>
</section>
</main>
<!-- VIEW 2: SRS Trainer Interactive View -->
<section id="srs-view" class="srs-view hidden">
<!-- SRS Top Bar -->
<header class="srs-topbar">
<div class="srs-topbar-left">
<button id="srs-exit-btn" class="btn btn-sm btn-outline">← В словарь</button>
<div class="srs-mode-switch">
<button class="srs-tab active" data-mode="flashcards">📇 Карточки</button>
<button class="srs-tab" data-mode="quiz">🎯 4 Варианта</button>
<button class="srs-tab" data-mode="typing">✍️ Набор слова</button>
<button class="srs-tab" data-mode="cloze">🧩 Пропуски</button>
<button class="srs-tab" data-mode="dictation" style="display: none;">🎧 Диктант</button>
</div>
</div>
<div class="srs-topbar-center">
<div class="srs-progress-container">
<div id="srs-progress-fill" class="srs-progress-fill" style="width: 0%;"></div>
</div>
<span id="srs-counter" class="srs-counter">Карточка 0 из 0</span>
</div>
<div class="srs-topbar-right">
<button id="srs-mix-btn" class="btn btn-sm btn-ghost" title="Умный микс дня: 10 новых + 10 повторов + 5 трудных слов">
<span id="srs-mix-label">🎲 Микс дня: ВКЛ</span>
</button>
<button id="srs-dir-btn" class="btn btn-sm btn-secondary" title="Сменить направление">
<span id="srs-dir-label">EN ➔ RU</span> ⇄
</button>
</div>
</header>
<!-- SRS Main Interactive Arena -->
<div class="srs-arena">
<!-- Loading State -->
<div id="srs-loading" class="srs-state-box hidden">
<div class="spinner"></div>
<p>Загрузка карточек для тренировки...</p>
</div>
<!-- Empty State -->
<div id="srs-empty" class="srs-state-box hidden">
<div class="srs-big-icon">🎉</div>
<h3>На сегодня всё повторено!</h3>
<p>В очереди нет слов, требующих интервального повторения.</p>
<div class="srs-empty-buttons">
<button id="srs-train-all-btn" class="btn btn-primary btn-lg">Тренировать все слова вне очереди</button>
<button id="srs-empty-back-btn" class="btn btn-outline btn-lg">Вернуться в словарь</button>
</div>
</div>
<!-- MODE 1: Flashcards -->
<div id="srs-mode-flashcards" class="srs-mode-container hidden">
<div class="flashcard-wrapper" id="flashcard-flip-wrap">
<div class="flashcard-inner" id="flashcard-inner">
<!-- Card Front -->
<div class="flashcard-face flashcard-front" id="flashcard-front">
<div class="fc-badge-row">
<span class="fc-dir-badge" id="fc-front-dir-badge">EN ➔ RU</span>
<span class="fc-pos-badge" id="fc-front-pos">Adjective</span>
</div>
<div class="fc-center">
<h1 class="fc-main-term" id="fc-front-main">reluctant</h1>
<div class="fc-phonetic-row" id="fc-front-phonetic-wrap">
<span class="res-phonetic" id="fc-front-phonetic">/rɪˈlʌktənt/</span>
<button id="fc-front-audio-btn" class="icon-btn audio-round-btn" style="display: none;" title="Озвучить (Ctrl+P / 🔊)">🔊</button>
</div>
<div class="fc-hint-wrapper">
<button id="fc-hint-btn" class="btn btn-xs btn-ghost">💡 Показать контекст</button>
<div id="fc-hint-box" class="fc-hint-content hidden"></div>
</div>
</div>
<div class="fc-footer-hint">
<kbd>Space</kbd> или клик по карточке — перевернуть
</div>
</div>
<!-- Card Back -->
<div class="flashcard-face flashcard-back" id="flashcard-back">
<div class="fc-badge-row">
<span class="fc-dir-badge">ОТВЕТ</span>
<span class="fc-pos-badge" id="fc-back-pos">Adjective</span>
</div>
<div class="fc-back-content">
<div class="fc-back-top">
<h2 class="fc-back-term" id="fc-back-term">reluctant</h2>
<button id="fc-back-audio-btn" class="icon-btn audio-round-btn" style="display: none;" title="Озвучить">🔊</button>
</div>
<div class="fc-back-translation" id="fc-back-translation">неохотный, нежелающий</div>
<div class="fc-back-detail-box" id="fc-back-def-box">
<span class="detail-label">Толкование:</span>
<p id="fc-back-def" class="detail-text"></p>
</div>
<div class="fc-back-detail-box" id="fc-back-context-box">
<span class="detail-label">Контекст:</span>
<p id="fc-back-context" class="detail-text"></p>
</div>
<div class="fc-back-detail-box" id="fc-back-notes-box">
<span class="detail-label">Заметка:</span>
<p id="fc-back-notes" class="detail-text"></p>
</div>
</div>
</div>
</div>
</div>
<!-- Flip button (mobile accessible) -->
<div id="fc-flip-btn-wrap" class="fc-flip-btn-wrap">
<button id="fc-flip-btn" class="btn btn-primary btn-block btn-lg">Показать ответ (Space)</button>
</div>
<!-- Rating Buttons -->
<div id="fc-rating-bar" class="srs-rating-bar hidden">
<button class="btn-rate btn-rate-1" data-rating="1" title="Горячая клавиша: 1">
<span class="rate-key">[1]</span>
<span class="rate-name">Снова</span>
<span class="rate-time">&lt; 1 мин</span>
</button>
<button class="btn-rate btn-rate-2" data-rating="2" title="Горячая клавиша: 2">
<span class="rate-key">[2]</span>
<span class="rate-name">Трудно</span>
<span class="rate-time">1 день</span>
</button>
<button class="btn-rate btn-rate-3" data-rating="3" title="Горячая клавиша: 3">
<span class="rate-key">[3]</span>
<span class="rate-name">Хорошо</span>
<span class="rate-time">3 дня</span>
</button>
<button class="btn-rate btn-rate-4" data-rating="4" title="Горячая клавиша: 4">
<span class="rate-key">[4]</span>
<span class="rate-name">Легко</span>
<span class="rate-time">7 дней</span>
</button>
</div>
</div>
<!-- MODE 2: Multiple Choice Quiz (4 options) -->
<div id="srs-mode-quiz" class="srs-mode-container hidden">
<div class="trainer-card quiz-card">
<div class="trainer-header">
<span class="mode-tag">🎯 Выбор из 4 вариантов</span>
<span class="trainer-pos" id="quiz-pos"></span>
</div>
<div class="quiz-hero">
<div class="quiz-prompt-row">
<h2 id="quiz-term-display" class="quiz-term-display">word</h2>
<button id="quiz-audio-btn" class="icon-btn audio-round-btn" style="display: none;" title="Озвучить">🔊</button>
</div>
<div id="quiz-phonetic-display" class="res-phonetic"></div>
<div id="quiz-context-hint" class="quiz-context-hint hidden"></div>
</div>
<div class="quiz-options-grid" id="quiz-options-grid">
<!-- 4 option buttons generated dynamically -->
</div>
<div id="quiz-feedback-box" class="trainer-feedback-box hidden"></div>
<div id="quiz-details-box" class="trainer-revealed-details hidden"></div>
<div id="quiz-next-bar" class="quiz-next-bar hidden">
<button id="quiz-next-btn" class="btn btn-primary btn-lg btn-block">Следующее слово (Enter / Space)</button>
</div>
</div>
</div>
<!-- MODE 3: Active Typing Mode (Ru -> En) -->
<div id="srs-mode-typing" class="srs-mode-container hidden">
<div class="trainer-card">
<div class="trainer-header">
<span class="mode-tag">✍️ Набор слова на английском</span>
<span class="trainer-pos" id="typing-pos"></span>
</div>
<div class="typing-hero">
<span class="hint-label">Переведите на английский язык:</span>
<h2 id="typing-prompt-ru" class="typing-prompt-ru">слово</h2>
<div id="typing-context-hint" class="typing-context-hint hidden"></div>
</div>
<form id="typing-form" class="trainer-form">
<div class="input-action-row">
<input type="text" id="typing-input" class="input-styled input-hero" placeholder="Напечатайте английское слово или связку..." autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" autofocus>
<button type="submit" id="typing-submit-btn" class="btn btn-primary">Проверить</button>
</div>
</form>
<div id="typing-feedback-box" class="trainer-feedback-box hidden"></div>
<div id="typing-details-box" class="trainer-revealed-details hidden"></div>
<!-- Rating bar for typing -->
<div id="typing-rating-bar" class="srs-rating-bar hidden"></div>
</div>
</div>
<!-- MODE 4: Cloze Deletion -->
<div id="srs-mode-cloze" class="srs-mode-container hidden">
<div class="trainer-card">
<div class="trainer-header">
<span class="mode-tag">🧩 Пропуски в контексте</span>
<span class="trainer-pos" id="cloze-pos"></span>
</div>
<div class="cloze-sentence-display" id="cloze-sentence-display">
The switch <span class="gap-placeholder">_____</span> the frame if invalid.
</div>
<div class="cloze-translation-hint">
<span class="hint-label">Перевод целевого слова:</span>
<strong id="cloze-target-translation">неохотный</strong>
</div>
<form id="cloze-form" class="trainer-form">
<div class="input-action-row">
<input type="text" id="cloze-input" class="input-styled input-hero" placeholder="Введите пропущенное слово..." autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" autofocus>
<button type="submit" id="cloze-submit-btn" class="btn btn-primary">Проверить</button>
</div>
</form>
<div id="cloze-feedback-box" class="trainer-feedback-box hidden"></div>
<div id="cloze-details-box" class="trainer-revealed-details hidden"></div>
<!-- Rating bar for cloze -->
<div id="cloze-rating-bar" class="srs-rating-bar hidden"></div>
</div>
</div>
<!-- MODE 5: Audio Dictation -->
<div id="srs-mode-dictation" class="srs-mode-container hidden">
<div class="trainer-card">
<div class="trainer-header">
<span class="mode-tag">🎧 Аудио-диктант</span>
<button id="dictation-replay-btn" class="btn btn-sm btn-ghost audio-replay-btn">
🔊 Повторить звук <span class="kbd-sub"><kbd>Space</kbd></span>
</button>
</div>
<div class="dictation-hero">
<button id="dictation-big-play-btn" class="dictation-pulse-btn" title="Слушать произношение">
🔊
</button>
<p class="dictation-instructions">Слушайте произношение нативного диктора и напечатайте слово</p>
</div>
<div class="dictation-hint-wrap">
<button id="dictation-toggle-hint-btn" class="btn btn-xs btn-ghost">💡 Показать перевод-подсказку</button>
<span id="dictation-hint-text" class="dictation-hint-text hidden"></span>
</div>
<form id="dictation-form" class="trainer-form">
<div class="input-action-row">
<input type="text" id="dictation-input" class="input-styled input-hero" placeholder="Напечатайте услышанное слово на английском..." autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" autofocus>
<button type="submit" id="dictation-submit-btn" class="btn btn-primary">Проверить</button>
</div>
</form>
<div id="dictation-feedback-box" class="trainer-feedback-box hidden"></div>
<div id="dictation-details-box" class="trainer-revealed-details hidden"></div>
<!-- Rating bar for dictation -->
<div id="dictation-rating-bar" class="srs-rating-bar hidden"></div>
</div>
</div>
<!-- Session Complete Summary Screen -->
<div id="srs-summary" class="srs-summary-card hidden">
<div class="summary-trophy">🏆</div>
<h2>Сессия завершена!</h2>
<p class="summary-lead">Вы успешно закрепили знания и освежили долговременную память.</p>
<div class="summary-metrics">
<div class="metric-card">
<span class="metric-val" id="sum-count">0</span>
<span class="metric-desc">Повторено слов</span>
</div>
<div class="metric-card">
<span class="metric-val text-success" id="sum-retention">100%</span>
<span class="metric-desc">Успешность (Хорошо/Легко)</span>
</div>
<div class="metric-card">
<span class="metric-val text-primary" id="sum-streak">🔥 1</span>
<span class="metric-desc">Серия дней</span>
</div>
</div>
<div class="summary-rates-bar" id="sum-rates-breakdown"></div>
<div class="summary-buttons">
<button id="sum-repeat-btn" class="btn btn-primary btn-lg">🔄 Повторить ещё сессию</button>
<button id="sum-return-btn" class="btn btn-outline btn-lg">📚 Вернуться в словарь</button>
</div>
</div>
</div>
</section>
<!-- VIEW 3: Interactive Reader & Bookshelf View -->
<section id="reader-view" class="reader-view hidden">
<!-- Bookshelf View -->
<div id="bookshelf-container" class="bookshelf-container">
<div class="bookshelf-header">
<div class="bookshelf-title-wrap">
<h2>📚 Библиотека & Интерактивная Читалка</h2>
<p class="subtitle">Читайте тексты и книги с мгновенным клик-переводом, озвучкой и авто-захватом контекста</p>
</div>
<div class="bookshelf-actions">
<button id="add-text-btn" class="btn btn-outline">✏️ Вставить текст</button>
<label for="book-file-input" class="btn btn-primary file-upload-label">
📁 Загрузить EPUB / TXT
<input type="file" id="book-file-input" accept=".epub,.txt,.md" style="display: none;">
</label>
</div>
</div>
<!-- Bookshelf Grid / Empty -->
<div id="bookshelf-empty" class="empty-state hidden">
<div class="empty-icon">📖</div>
<h3>Ваша библиотека пуста</h3>
<p>Загрузите книгу в формате EPUB, текстовый файл TXT/MD или вставьте текст статьи, чтобы начать интерактивное чтение.</p>
</div>
<div id="bookshelf-grid" class="bookshelf-grid"></div>
</div>
<!-- Reading Interface (Active when a book is open) -->
<div id="reader-interface" class="reader-interface hidden">
<header class="reader-toolbar">
<div class="reader-toolbar-left">
<button id="reader-back-btn" class="btn btn-sm btn-outline">← Библиотека</button>
<div class="reader-meta">
<h3 id="reader-book-title" class="reader-title">Книга</h3>
<span id="reader-book-author" class="reader-author">Автор</span>
</div>
</div>
<div class="reader-toolbar-center">
<button id="reader-prev-ch-btn" class="btn btn-xs btn-outline" title="Предыдущая глава">◀</button>
<select id="reader-chapter-select" class="reader-select"></select>
<button id="reader-next-ch-btn" class="btn btn-xs btn-outline" title="Следующая глава">▶</button>
</div>
<div class="reader-toolbar-right">
<div class="font-controls">
<button id="reader-font-dec-btn" class="btn btn-xs btn-outline" title="Уменьшить шрифт">A-</button>
<button id="reader-font-inc-btn" class="btn btn-xs btn-outline" title="Увеличить шрифт">A+</button>
</div>
<button id="reader-toggle-highlight-btn" class="btn btn-xs btn-outline" title="Вкл/Выкл подсветку изучаемых слов">✨ Подсветка</button>
<button id="reader-train-btn" class="btn btn-xs btn-trainer" title="Тренировать слова из этой книги">🎓 Слова книги</button>
</div>
</header>
<!-- Reading Container -->
<div class="reader-scroll-area" id="reader-scroll-area">
<div class="reader-content-body" id="reader-content-body">
<!-- Interactive paragraphs dynamically rendered here -->
</div>
</div>
</div>
</section>
<!-- Sticky Bulk Action Bar for Batch Selection Mode -->
<div id="batch-action-bar" class="batch-action-bar hidden">
<div class="batch-left">
<label class="batch-check-label">
<input type="checkbox" id="batch-select-all" class="batch-master-checkbox">
<span id="batch-count-label">Выбрано: 0</span>
</label>
</div>
<div class="batch-actions">
<button id="batch-move-btn" class="btn btn-sm btn-outline">📁 В коллекцию</button>
<button id="batch-tag-btn" class="btn btn-sm btn-outline">🏷️ Добавить тег</button>
<button id="batch-delete-btn" class="btn btn-sm btn-danger">🗑️ Удалить</button>
<button id="batch-cancel-btn" class="btn btn-sm btn-ghost">✕ Отмена</button>
</div>
</div>
</div>
<!-- Analytics & Activity Heatmap Modal -->
<div id="stats-modal" class="modal-backdrop hidden">
<div class="modal-window stats-modal-window">
<div class="modal-header">
<h3>📊 Аналитика обучения & Активность</h3>
<button id="close-stats-modal-btn" class="icon-btn">✕</button>
</div>
<div class="modal-body">
<!-- Streak & Core Stats Hero -->
<div class="stats-hero-grid">
<div class="stat-kpi-card streak-kpi">
<div class="kpi-icon">🔥</div>
<div class="kpi-value" id="kpi-current-streak">0</div>
<div class="kpi-label">Текущая серия дней</div>
<div class="kpi-sub" id="kpi-longest-streak">Рекорд: 0 дней</div>
</div>
<div class="stat-kpi-card">
<div class="kpi-icon">🎯</div>
<div class="kpi-value text-success" id="kpi-retention-rate">100%</div>
<div class="kpi-label">Точность запоминания</div>
<div class="kpi-sub" id="kpi-total-reviews">Всего повторений: 0</div>
</div>
<div class="stat-kpi-card">
<div class="kpi-icon">📚</div>
<div class="kpi-value" id="kpi-total-words">0</div>
<div class="kpi-label">Слов в словаре</div>
<div class="kpi-sub" id="kpi-today-added">Сегодня добавлено: +0</div>
</div>
<div class="stat-kpi-card">
<div class="kpi-icon">🎓</div>
<div class="kpi-value text-accent" id="kpi-cefr-level">A1</div>
<div class="kpi-label">Оценка уровня</div>
<div class="kpi-sub" id="kpi-cefr-desc">Начальный словарный запас</div>
</div>
</div>
<!-- Contribution Activity Heatmap -->
<div class="heatmap-section">
<div class="heatmap-header">
<h4>🟩 Календарь активности</h4>
<div class="heatmap-legend">
<span>Меньше</span>
<span class="legend-cell lvl-0" title="0 повторений"></span>
<span class="legend-cell lvl-1" title="1 повторение"></span>
<span class="legend-cell lvl-2" title="2-3 повторения"></span>
<span class="legend-cell lvl-3" title="4+ повторений"></span>
<span>Больше</span>
</div>
</div>
<div class="heatmap-container-wrap">
<div id="heatmap-grid" class="heatmap-grid">
<!-- Heatmap cells generated dynamically -->
</div>
</div>
<div class="heatmap-footer-note">
<small>Цвет ячейки показывает количество пройденных тестов и интервальных повторений за день.</small>
</div>
</div>
<!-- Mastery Distribution Progress -->
<div class="mastery-section">
<h4>📈 Стадии освоения слов (SM-2 SRS)</h4>
<div class="segmented-progress-bar">
<div id="prog-mastered" class="prog-segment seg-mastered" style="width: 0%;" title="Выучено (интервал > 21 дня)"></div>
<div id="prog-review" class="prog-segment seg-review" style="width: 0%;" title="Повторение"></div>
<div id="prog-learning" class="prog-segment seg-learning" style="width: 0%;" title="В процессе (1-3 повтора)"></div>
<div id="prog-new" class="prog-segment seg-new" style="width: 100%;" title="Новые слова"></div>
</div>
<div class="mastery-legend-row">
<div class="m-legend-item"><span class="dot dot-mastered"></span> Выучено: <strong id="cnt-mastered">0</strong></div>
<div class="m-legend-item"><span class="dot dot-review"></span> Закрепление: <strong id="cnt-review">0</strong></div>
<div class="m-legend-item"><span class="dot dot-learning"></span> В процессе: <strong id="cnt-learning">0</strong></div>
<div class="m-legend-item"><span class="dot dot-new"></span> Новые: <strong id="cnt-new">0</strong></div>
<div class="m-legend-item text-danger"><span class="dot dot-leech"></span> Трудные слова: <strong id="cnt-leeches">0</strong></div>
</div>
</div>
</div>
<div class="modal-footer">
<button id="close-stats-btn" class="btn btn-primary">Закрыть</button>
</div>
</div>
</div>
<!-- Edit Card Modal -->
<div id="edit-modal" class="modal-backdrop hidden">
<div class="modal-window">
<div class="modal-header">
<h3>✏️ Редактировать карточку</h3>
<button id="close-modal-btn" class="icon-btn">✕</button>
</div>
<div class="modal-body">
<input type="hidden" id="modal-card-id">
<div class="form-group">
<label>Слово / Выражение (EN)</label>
<input type="text" id="modal-term" class="input-styled" required>
</div>
<div class="form-group">
<label>Перевод (RU)</label>
<input type="text" id="modal-translation" class="input-styled" required>
</div>
<div class="form-group">
<label>Контекстное предложение</label>
<textarea id="modal-context" class="input-styled" rows="2"></textarea>
</div>
<div class="field-row">
<div class="form-group flex-1">
<label>Транскрипция (IPA)</label>
<input type="text" id="modal-phonetic" class="input-styled">
</div>
<div class="form-group flex-1">
<label>Часть речи</label>
<input type="text" id="modal-pos" class="input-styled">
</div>
</div>
<div class="form-group">
<label>Английское толкование</label>
<textarea id="modal-def" class="input-styled" rows="2"></textarea>
</div>
<div class="field-row">
<div class="form-group flex-1">
<label>Коллекция (Папка)</label>
<input type="text" id="modal-collection" class="input-styled">
</div>
<div class="form-group flex-1">
<label>Теги</label>
<input type="text" id="modal-tags" class="input-styled">
</div>
</div>
<div class="form-group">
<label>Заметки / Мнемоника</label>
<input type="text" id="modal-notes" class="input-styled">
</div>
</div>
<div class="modal-footer">
<button id="modal-cancel-btn" class="btn btn-outline">Отмена</button>
<button id="modal-save-btn" class="btn btn-primary">Сохранить изменения</button>
</div>
</div>
</div>
<!-- Export Modal -->
<div id="export-modal" class="modal-backdrop hidden">
<div class="modal-window export-modal-window">
<div class="modal-header">
<h3>📤 Экспорт словаря</h3>
<button id="close-export-modal-btn" class="icon-btn">✕</button>
</div>
<div class="modal-body">
<p class="modal-lead" id="export-modal-desc">Выберите удобный формат для выгрузки карточек:</p>
<div class="export-grid">
<div class="export-tile" data-format="csv">
<div class="export-tile-icon">📊</div>
<div class="export-tile-info">
<h4>CSV (Excel / Sheets)</h4>
<p>Таблица со всеми полями, переводами и примерами (UTF-8 BOM для русского языка).</p>
</div>
<button class="btn btn-sm btn-primary">Скачать</button>
</div>
<div class="export-tile" data-format="anki">
<div class="export-tile-icon">🗃️</div>
<div class="export-tile-info">
<h4>Колода для Anki (.tsv)</h4>
<p>Готовый файл для импорта в Anki с транскрипцией, озвучкой и контекстом.</p>
</div>
<button class="btn btn-sm btn-primary">Скачать</button>
</div>
<div class="export-tile" data-format="json">
<div class="export-tile-icon">📋</div>
<div class="export-tile-info">
<h4>JSON (Полный архив)</h4>
<p>Полная структурированная резервная копия данных словаря.</p>
</div>
<button class="btn btn-sm btn-primary">Скачать</button>
</div>
<div class="export-tile" data-format="md">
<div class="export-tile-icon">📝</div>
<div class="export-tile-info">
<h4>Markdown (.md)</h4>
<p>Красивый структурированный конспект для Obsidian, Notion или чтения.</p>
</div>
<button class="btn btn-sm btn-primary">Скачать</button>
</div>
</div>
</div>
<div class="modal-footer">
<span id="export-scope-label" class="text-dim">Объём экспорта: все карточки</span>
<button id="export-cancel-btn" class="btn btn-outline">Закрыть</button>
</div>
</div>
</div>
<!-- Move Collection Modal -->
<div id="move-col-modal" class="modal-backdrop hidden">
<div class="modal-window modal-sm">
<div class="modal-header">
<h3>📁 Переместить в коллекцию</h3>
<button id="close-move-modal-btn" class="icon-btn">✕</button>
</div>
<div class="modal-body">
<p class="modal-lead" id="move-modal-count-label">Выберите коллекцию для выбранных карточек:</p>
<div class="form-group">
<label for="move-col-input">Название коллекции</label>
<input type="text" id="move-col-input" list="move-collections-datalist" class="input-styled" placeholder="Например: Разговорный">
<datalist id="move-collections-datalist"></datalist>
</div>
<div class="quick-tags" id="move-col-quick-list"></div>
</div>
<div class="modal-footer">
<button id="move-col-cancel-btn" class="btn btn-outline">Отмена</button>
<button id="move-col-confirm-btn" class="btn btn-primary">Переместить</button>
</div>
</div>
</div>
<!-- New Collection Modal -->
<div id="new-col-modal" class="modal-backdrop hidden">
<div class="modal-window modal-sm">
<div class="modal-header">
<h3>📁 Новая коллекция</h3>
<button id="close-new-col-modal-btn" class="icon-btn">✕</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="new-col-name-input">Название новой коллекции</label>
<input type="text" id="new-col-name-input" class="input-styled" placeholder="Например: Сериалы / Netflix">
</div>
</div>
<div class="modal-footer">
<button id="new-col-cancel-btn" class="btn btn-outline">Отмена</button>
<button id="new-col-save-btn" class="btn btn-primary">Создать</button>
</div>
</div>
</div>
<!-- Change Password Modal -->
<div id="change-password-modal" class="modal-backdrop hidden">
<div class="modal-window modal-sm">
<div class="modal-header">
<h3>🔑 Смена пароля</h3>
<button id="close-change-pwd-btn" class="icon-btn">✕</button>
</div>
<form id="change-password-form">
<div class="modal-body">
<div class="form-group">
<label for="current-password-input">Текущий пароль</label>
<input type="password" id="current-password-input" class="input-styled" autocomplete="current-password" required placeholder="••••••••">
</div>
<div class="form-group">
<label for="new-password-input">Новый пароль</label>
<input type="password" id="new-password-input" class="input-styled" autocomplete="new-password" required minlength="6" placeholder="Минимум 6 символов">
</div>
<div class="form-group">
<label for="confirm-password-input">Подтвердите новый пароль</label>
<input type="password" id="confirm-password-input" class="input-styled" autocomplete="new-password" required minlength="6" placeholder="Повторите новый пароль">
</div>
<div id="change-pwd-error" class="error-banner hidden"></div>
<div id="change-pwd-success" class="success-banner hidden"></div>
</div>
<div class="modal-footer">
<button type="button" id="change-pwd-cancel-btn" class="btn btn-outline">Отмена</button>
<button type="submit" id="change-pwd-save-btn" class="btn btn-primary">Сохранить</button>
</div>
</form>
<!-- Add Book Modal (Paste Text) -->
<div id="add-book-modal" class="modal-backdrop hidden">
<div class="modal-window">
<div class="modal-header">
<h3>✏️ Добавить текст или статью</h3>
<button id="close-add-book-modal-btn" class="icon-btn">✕</button>
</div>
<form id="add-book-form">
<div class="modal-body">
<div class="form-group">
<label for="book-title-input">Название книги / статьи *</label>
<input type="text" id="book-title-input" class="input-styled" required placeholder="Например: Clean Code Principles">
</div>
<div class="form-group">
<label for="book-author-input">Автор / Источник</label>
<input type="text" id="book-author-input" class="input-styled" placeholder="Например: Robert C. Martin">
</div>
<div class="form-group">
<label for="book-content-input">Текст материала (English) *</label>
<textarea id="book-content-input" class="input-styled" rows="10" required placeholder="Вставьте английский текст книги, статьи или документации..."></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" id="cancel-add-book-btn" class="btn btn-outline">Отмена</button>
<button type="submit" id="submit-add-book-btn" class="btn btn-primary">📚 Сохранить в библиотеку</button>
</div>
</form>
</div>
</div>
<!-- Interactive Click-to-Translate Popup (Mounted at body root to prevent scroll clipping) -->
<div id="reader-word-popup" class="reader-word-popup hidden">
<div class="popup-header">
<div class="popup-term-wrap">
<strong id="popup-term" class="popup-term">word</strong>
<span id="popup-phonetic" class="popup-phonetic">/wɜːd/</span>
<button id="popup-audio-btn" class="icon-btn audio-btn" style="display: none;" title="Слушать произношение">🔊</button>
</div>
<button id="popup-close-btn" class="popup-close-btn">✕</button>
</div>
<div class="popup-body">
<div id="popup-loading" class="popup-loading hidden">Переводим...</div>
<div id="popup-content" class="popup-content">
<div class="popup-translation" id="popup-translation">перевод</div>
<div class="popup-context" id="popup-context">“Контекст из книги...”</div>
</div>
</div>
<div class="popup-footer">
<button id="popup-save-btn" class="btn btn-primary btn-sm btn-block">💾 Добавить в словарь</button>
<div id="popup-saved-badge" class="popup-saved-badge hidden">✅ Сохранено в словарь!</div>
</div>
</div>
<!-- Audio Element for native streaming -->
<audio id="global-audio-player" preload="none"></audio>
<script src="/static/js/app.js?v=2.6"></script>
</body>
</html>