- extract_outline_entries: filter PDF bookmarks by depth and major structural headings, avoiding 550 micro-snippets - renderContinuousBook: load current chapter and seamlessly append next chapters on scroll (virtual continuous) instead of dumping all chapters into DOM synchronously - renderInteractiveSpans: use native HTML template fragment instead of new DOMParser per paragraph - event delegation: handle word clicks on readerContentBody instead of adding hundreds of thousands of individual DOM event listeners - consolidate existing CCNA book in DB into 68 clean chapters
1082 lines
64 KiB
HTML
1082 lines
64 KiB
HTML
<!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, viewport-fit=cover">
|
||
<title>Notes — Персональный тренажер и словарь английского языка</title>
|
||
<meta name="description" content="Защищённый персональный тренажёр и словарь английского языка с интервальными повторениями SRS SM-2, контекстным поиском и озвучкой">
|
||
<link rel="stylesheet" href="/static/css/style.css?v=3.9">
|
||
|
||
<!-- 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">
|
||
<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>
|
||
<button id="mobile-menu-toggle-btn" class="icon-btn mobile-only-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>
|
||
<span id="res-in-library" class="badge-library-star hidden" title="Это слово уже есть в вашей библиотеке">⭐ В библиотеке</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">< 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 / PDF / TXT
|
||
<input type="file" id="book-file-input" accept=".epub,.pdf,.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 или PDF, текстовый файл 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>
|
||
<span id="reader-scroll-pct-badge" class="reader-progress-badge" title="Прогресс чтения главы">0%</span>
|
||
</div>
|
||
|
||
<div class="reader-toolbar-right">
|
||
<button id="reader-settings-btn" class="btn btn-xs btn-outline reader-settings-btn" title="Настройки оформления текста (шрифт, поля, тема)">
|
||
<span style="font-weight: 700; font-family: serif; font-size: 13px;">Aa</span>
|
||
<span class="btn-subtext-inline">Шрифт</span>
|
||
</button>
|
||
<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>
|
||
|
||
<div id="reader-chapter-progress-bar" class="reader-chapter-progress-bar">
|
||
<div id="reader-chapter-progress-fill" class="reader-chapter-progress-fill" style="width: 0%;"></div>
|
||
</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>
|
||
|
||
<!-- Mobile Bottom Navigation Tab Bar (iOS style) -->
|
||
<nav class="mobile-tab-bar" id="mobile-tab-bar">
|
||
<button class="tab-item active" data-view="dictionary-view" id="tab-nav-dict">
|
||
<span class="tab-icon">📖</span>
|
||
<span class="tab-label">Словарь</span>
|
||
</button>
|
||
<button class="tab-item" data-view="srs-view" id="tab-nav-srs">
|
||
<span class="tab-icon">🎓</span>
|
||
<span class="tab-label">Тренажёр</span>
|
||
<span id="tab-srs-badge" class="tab-badge hidden">0</span>
|
||
</button>
|
||
<button class="tab-item" data-view="reader-view" id="tab-nav-reader">
|
||
<span class="tab-icon">📚</span>
|
||
<span class="tab-label">Читалка</span>
|
||
</button>
|
||
<button class="tab-item" id="tab-nav-stats">
|
||
<span class="tab-icon">📊</span>
|
||
<span class="tab-label">Прогресс</span>
|
||
</button>
|
||
<button class="tab-item" id="tab-nav-menu">
|
||
<span class="tab-icon">⚙️</span>
|
||
<span class="tab-label">Меню</span>
|
||
</button>
|
||
</nav>
|
||
</div>
|
||
|
||
<!-- Mobile Menu / Profile Sheet Modal -->
|
||
<div id="mobile-menu-modal" class="modal-backdrop hidden">
|
||
<div class="modal-window mobile-sheet-window">
|
||
<div class="modal-header">
|
||
<h3>⚙️ Профиль & Меню</h3>
|
||
<button class="modal-close-btn" id="mobile-menu-close-btn">✕</button>
|
||
</div>
|
||
<div class="modal-body mobile-menu-body">
|
||
<div class="mobile-user-card">
|
||
<span class="mobile-user-avatar">👤</span>
|
||
<div class="mobile-user-info">
|
||
<strong id="mobile-user-name">user</strong>
|
||
<p class="subtitle">Личный словарь English Lexicon</p>
|
||
</div>
|
||
</div>
|
||
<div class="mobile-menu-actions">
|
||
<button id="mobile-stats-btn" class="btn btn-outline btn-block">📊 Статистика & Календарь</button>
|
||
<button id="mobile-export-btn" class="btn btn-outline btn-block">📤 Экспорт словаря</button>
|
||
<button id="mobile-pwd-btn" class="btn btn-outline btn-block">🔑 Сменить пароль</button>
|
||
<button id="mobile-theme-btn" class="btn btn-outline btn-block">🌓 Переключить тему</button>
|
||
<button id="mobile-logout-btn" class="btn btn-danger btn-block">Выйти из аккаунта</button>
|
||
</div>
|
||
</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>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 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>
|
||
|
||
<!-- Reader Appearance Settings Popover / Bottom Sheet -->
|
||
<div id="reader-settings-panel" class="reader-settings-panel hidden">
|
||
<div class="sheet-drag-handle mobile-only"></div>
|
||
<div class="reader-settings-header">
|
||
<h4>🔤 Настройки текста</h4>
|
||
<button id="reader-settings-close-btn" class="popup-close-btn">✕</button>
|
||
</div>
|
||
<div class="reader-settings-body">
|
||
<!-- Reading Flow Mode -->
|
||
<div class="setting-row">
|
||
<span class="setting-label">Режим чтения</span>
|
||
<div class="setting-segmented-control" id="reader-mode-group">
|
||
<button type="button" class="seg-btn active" data-flow="chapters">📖 По главам</button>
|
||
<button type="button" class="seg-btn" data-flow="continuous">📜 Вся книга</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Autoload next chapter toggle (active in chapters mode) -->
|
||
<div class="setting-row" id="setting-autoload-row">
|
||
<span class="setting-label">Переход между главами</span>
|
||
<div class="setting-segmented-control" id="reader-autoload-group">
|
||
<button type="button" class="seg-btn active" data-autoload="true">⚡ Автоподгрузка</button>
|
||
<button type="button" class="seg-btn" data-autoload="false">🔘 По кнопке</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Font Family -->
|
||
<div class="setting-row">
|
||
<span class="setting-label">Шрифт</span>
|
||
<div class="setting-segmented-control" id="reader-font-family-group">
|
||
<button class="seg-btn" data-font="sans" style="font-family: var(--font-family);">Sans</button>
|
||
<button class="seg-btn active" data-font="serif" style="font-family: Georgia, serif;">Serif</button>
|
||
<button class="seg-btn" data-font="mono" style="font-family: monospace;">Mono</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Font Size & Text Alignment (Compact 2-col Grid) -->
|
||
<div class="setting-row-grid">
|
||
<div class="setting-row">
|
||
<span class="setting-label">Размер</span>
|
||
<div class="setting-stepper">
|
||
<button id="setting-font-dec-btn" class="step-btn">A−</button>
|
||
<span id="setting-font-size-val" class="step-val">18 px</span>
|
||
<button id="setting-font-inc-btn" class="step-btn">A+</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="setting-row">
|
||
<span class="setting-label">Выравнивание</span>
|
||
<div class="setting-segmented-control" id="reader-align-group">
|
||
<button class="seg-btn active" data-align="left" title="По левому краю">По краю</button>
|
||
<button class="seg-btn" data-align="justify" title="По ширине (Justified)">По ширине</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Line Height -->
|
||
<div class="setting-row">
|
||
<span class="setting-label">Межстрочный интервал</span>
|
||
<div class="setting-segmented-control" id="reader-line-height-group">
|
||
<button class="seg-btn" data-lh="1.35">Компакт</button>
|
||
<button class="seg-btn active" data-lh="1.65">Оптимум</button>
|
||
<button class="seg-btn" data-lh="1.95">Широкий</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Margins / Width -->
|
||
<div class="setting-row">
|
||
<span class="setting-label">Ширина и поля страницы</span>
|
||
<div class="setting-segmented-control" id="reader-margins-group">
|
||
<button class="seg-btn" data-margin="narrow">Узкие</button>
|
||
<button class="seg-btn active" data-margin="normal">Стандарт</button>
|
||
<button class="seg-btn" data-margin="wide">Книга</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Reading Theme -->
|
||
<div class="setting-row">
|
||
<span class="setting-label">Цветовая тема читалки</span>
|
||
<div class="theme-palette" id="reader-theme-group">
|
||
<button class="theme-chip theme-chip-dark active" data-theme="dark" title="Тёмная (Dark Slate)">🌙 Тёмная</button>
|
||
<button class="theme-chip theme-chip-sepia" data-theme="sepia" title="Сепия (Тёплый пергамент)">📜 Сепия</button>
|
||
<button class="theme-chip theme-chip-light" data-theme="light" title="Светлая (Чистый лист)">☀️ Светлая</button>
|
||
<button class="theme-chip theme-chip-oled" data-theme="oled" title="OLED (Абсолютный чёрный)">🖤 OLED</button>
|
||
</div>
|
||
</div>
|
||
</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="sheet-drag-handle mobile-only"></div>
|
||
<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>
|
||
<span id="popup-in-library" class="popup-in-library-badge hidden" title="Это слово уже есть в вашей библиотеке">⭐ В библиотеке</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>
|
||
<button id="popup-add-context-btn" class="btn btn-xs btn-outline btn-block hidden" style="margin-top: 6px;">+ Добавить эту цитату к карточке</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Audio Element for native streaming -->
|
||
<audio id="global-audio-player" preload="none"></audio>
|
||
|
||
<script src="/static/js/app.js?v=4.0"></script>
|
||
</body>
|
||
</html>
|
||
|