@dzhechkov/keysarium 1.4.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -5
- package/README.ru.md +541 -0
- package/bin/cli.js +0 -0
- package/package.json +11 -9
- package/templates/.claude/commands/analyst-manual.md +38 -0
- package/templates/.claude/commands/casarium.md +55 -4
- package/templates/.claude/commands/feature-adr.md +8 -0
- package/templates/.claude/rules/trust-tiers.md +5 -0
- package/templates/.claude/shards/feature-adr.shard.md +64 -10
- package/templates/.claude/shards/phase-ai-factory.shard.md +109 -0
- package/templates/.claude/skills/ai-factory-mapper/README.md +90 -0
- package/templates/.claude/skills/ai-factory-mapper/SKILL.md +309 -0
- package/templates/.claude/skills/ai-factory-mapper/assets/report-template.md +123 -0
- package/templates/.claude/skills/ai-factory-mapper/references/catalog.md +230 -0
- package/templates/.claude/skills/ai-factory-mapper/references/coverage-formula.md +219 -0
- package/templates/.claude/skills/ai-factory-mapper/references/decomposition-checklist.md +183 -0
- package/templates/.claude/skills/ai-factory-mapper/references/pattern-library.md +312 -0
- package/templates/.claude/skills/ai-factory-mapper/scripts/build_docx_report.js +423 -0
- package/templates/.claude/skills/analyst-manual-full/SKILL.md +286 -0
- package/templates/.claude/skills/edu-site-generator/SKILL.md +254 -0
- package/templates/.claude/skills/edu-site-generator/examples/sample-course-structure.md +116 -0
- package/templates/.claude/skills/edu-site-generator/modules/00-content-analysis.md +84 -0
- package/templates/.claude/skills/edu-site-generator/modules/01-course-structure.md +75 -0
- package/templates/.claude/skills/edu-site-generator/modules/02-data-generation.md +186 -0
- package/templates/.claude/skills/edu-site-generator/modules/03-scaffold.md +249 -0
- package/templates/.claude/skills/edu-site-generator/modules/04-components.md +130 -0
- package/templates/.claude/skills/edu-site-generator/modules/05-gamification.md +163 -0
- package/templates/.claude/skills/edu-site-generator/modules/06-deploy.md +88 -0
- package/templates/.claude/skills/edu-site-generator/modules/07-verification.md +97 -0
- package/templates/.claude/skills/edu-site-generator/references/component-templates.md +436 -0
- package/templates/.claude/skills/edu-site-generator/references/data-schemas.md +164 -0
- package/templates/.claude/skills/edu-site-generator/references/exercise-catalog.md +110 -0
- package/templates/.claude/skills/edu-site-generator/references/tech-stack.md +69 -0
- package/templates/.claude/skills/feature-adr/SKILL.md +245 -59
- package/templates/.claude/skills/feature-adr/modules/03-adr.md +43 -0
- package/templates/.claude/skills/feature-adr/modules/03.5-ideation-swarm.md +180 -0
- package/templates/.claude/skills/feature-adr/modules/06-implementation-plan.md +56 -7
- package/templates/.claude/skills/feature-adr/modules/08-qe.md +87 -23
- package/templates/.claude/skills/feature-adr/modules/09-fleet-qe.md +305 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/README.md +143 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/brutal-honesty-review.md +240 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/chaos-engineering-resilience.md +163 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/code-goal-planner.md +446 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/enterprise-integration-testing.md +111 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/mutation-testing.md +236 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/performance-testing.md +315 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qcsd-ideation-swarm.md +126 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qcsd-production-swarm.md +108 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-coverage-analysis.md +193 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-requirements-validation.md +254 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/regression-testing.md +233 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/risk-based-testing.md +212 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/security-testing.md +311 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/shift-left-testing.md +231 -0
- package/templates/.claude/skills/feature-adr/references/agentic-qe/tdd-london-chicago.md +249 -0
- package/templates/.claude/skills/transcript-site-generator/SKILL.md +287 -0
- package/templates/.claude/skills/transcript-site-generator/examples/sample-text-only-site.md +123 -0
- package/templates/.claude/skills/transcript-site-generator/examples/sample-transcript-site.md +134 -0
- package/templates/.claude/skills/transcript-site-generator/modules/00-input-analysis.md +132 -0
- package/templates/.claude/skills/transcript-site-generator/modules/01-content-parsing.md +117 -0
- package/templates/.claude/skills/transcript-site-generator/modules/02-site-generation.md +293 -0
- package/templates/.claude/skills/transcript-site-generator/modules/03-interactivity.md +406 -0
- package/templates/.claude/skills/transcript-site-generator/modules/04-deploy.md +130 -0
- package/templates/.claude/skills/transcript-site-generator/modules/05-verification.md +155 -0
- package/templates/.claude/skills/transcript-site-generator/references/component-catalog.md +86 -0
- package/templates/.claude/skills/transcript-site-generator/references/data-schemas.md +123 -0
- package/templates/.claude/skills/transcript-site-generator/references/tech-stack.md +132 -0
- package/templates/CLAUDE.md +9 -2
- package/templates/docs/edu-site-generator/01-deployment-guide.md +911 -0
- package/templates/docs/edu-site-generator/02-admin-guide.md +901 -0
- package/templates/docs/edu-site-generator/03-user-guide.md +1008 -0
- package/templates/docs/edu-site-generator/04-infrastructure-requirements.md +489 -0
- package/templates/docs/edu-site-generator/05-architecture.md +902 -0
- package/templates/docs/edu-site-generator/06-user-flows.md +759 -0
- package/templates/docs/transcript-site-generator/01-deployment-guide.md +1042 -0
- package/templates/docs/transcript-site-generator/02-admin-guide.md +918 -0
- package/templates/docs/transcript-site-generator/03-user-guide.md +925 -0
- package/templates/docs/transcript-site-generator/04-infrastructure-requirements.md +482 -0
- package/templates/docs/transcript-site-generator/05-architecture.md +1068 -0
- package/templates/docs/transcript-site-generator/06-user-flows.md +855 -0
|
@@ -0,0 +1,1068 @@
|
|
|
1
|
+
# Архитектура @dzhechkov/skills-transcript-site
|
|
2
|
+
|
|
3
|
+
## Содержание
|
|
4
|
+
|
|
5
|
+
1. [Обзор системы и философия проектирования](#1-обзор-системы-и-философия-проектирования)
|
|
6
|
+
2. [Компоненты системы](#2-компоненты-системы)
|
|
7
|
+
3. [MODULE: Input Analysis](#3-module-input-analysis)
|
|
8
|
+
4. [MODULE: Content Parsing](#4-module-content-parsing)
|
|
9
|
+
5. [MODULE: Site Generation](#5-module-site-generation)
|
|
10
|
+
6. [MODULE: Interactivity](#6-module-interactivity)
|
|
11
|
+
7. [MODULE: Deploy](#7-module-deploy)
|
|
12
|
+
8. [MODULE: Verification](#8-module-verification)
|
|
13
|
+
9. [Поток данных (Data Flow)](#9-поток-данных-data-flow)
|
|
14
|
+
10. [Выбор технологического стека](#10-выбор-технологического-стека)
|
|
15
|
+
11. [Архитектура безопасности](#11-архитектура-безопасности)
|
|
16
|
+
12. [SEO архитектура](#12-seo-архитектура)
|
|
17
|
+
13. [Доступность (Accessibility)](#13-доступность-accessibility)
|
|
18
|
+
14. [Расширяемость](#14-расширяемость)
|
|
19
|
+
15. [Проектные решения и компромиссы](#15-проектные-решения-и-компромиссы)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 1. Обзор системы и философия проектирования
|
|
24
|
+
|
|
25
|
+
`@dzhechkov/skills-transcript-site` -- это скилл для Claude Code, генерирующий интерактивные веб-сайты из текстовых транскриптов и YouTube-видео. Ключевая идея: **zero-build, CDN-first, vanilla JS**. Выходной артефакт -- один (или несколько) HTML-файл(ов), готовых к открытию в браузере или деплою на GitHub Pages.
|
|
26
|
+
|
|
27
|
+
### Фундаментальные принципы
|
|
28
|
+
|
|
29
|
+
**1. Zero Build Step (нулевой шаг сборки)**
|
|
30
|
+
|
|
31
|
+
Никаких webpack, vite, esbuild, rollup. Никаких node_modules. Никаких package.json в выходной директории. Результат -- plain HTML, который открывается в браузере напрямую. Это критически важно для аудитории, которая не является фронтенд-разработчиками.
|
|
32
|
+
|
|
33
|
+
**2. CDN-First (CDN в приоритете)**
|
|
34
|
+
|
|
35
|
+
Tailwind CSS подключается через Play CDN. Font Awesome -- через cdnjs. YouTube -- через iframe API. Никаких локальных зависимостей. Это позволяет генерировать один self-contained файл без дополнительных assets.
|
|
36
|
+
|
|
37
|
+
**3. Vanilla JS (чистый JavaScript)**
|
|
38
|
+
|
|
39
|
+
Никаких React, Vue, Svelte, jQuery. Вся интерактивность реализована на vanilla JavaScript с event delegation. Это обеспечивает:
|
|
40
|
+
- Нулевую зависимость от фреймворков
|
|
41
|
+
- Минимальный размер JS-кода (~5-10 KB)
|
|
42
|
+
- Полную прозрачность и читаемость кода
|
|
43
|
+
- Отсутствие необходимости в системе модулей
|
|
44
|
+
|
|
45
|
+
**4. Static-Only Output (только статика)**
|
|
46
|
+
|
|
47
|
+
Выходные файлы не требуют сервера для работы. Нет API-эндпоинтов, нет серверного рендеринга, нет баз данных. Файл `index.html` открывается через `file://` протокол или любой статический хостинг.
|
|
48
|
+
|
|
49
|
+
**5. Progressive Enhancement (прогрессивное улучшение)**
|
|
50
|
+
|
|
51
|
+
Базовый HTML-контент (текст транскрипта) читается без JavaScript. Интерактивные фичи (поиск, dark mode, timestamp sync) добавляются как enhancement -- сайт остаётся функциональным при их отключении.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 2. Компоненты системы
|
|
56
|
+
|
|
57
|
+
### Текстовая карта компонентов
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
@dzhechkov/skills-transcript-site
|
|
61
|
+
+-- SKILL.md <-- Точка входа, оркестратор 6 шагов
|
|
62
|
+
|
|
|
63
|
+
+-- modules/ <-- 6 модулей пайплайна
|
|
64
|
+
| +-- input-analysis.md <-- Шаг 1: source detection, yt-dlp, language
|
|
65
|
+
| +-- content-parsing.md <-- Шаг 2: sections, speakers, timestamps
|
|
66
|
+
| +-- site-generation.md <-- Шаг 3: HTML template, Tailwind, SEO
|
|
67
|
+
| +-- interactivity.md <-- Шаг 4: search, TOC, dark mode, sync
|
|
68
|
+
| +-- deploy.md <-- Шаг 5: GitHub Pages, robots, sitemap
|
|
69
|
+
| +-- verification.md <-- Шаг 6: HTML/JS/CSS/SEO/a11y checks
|
|
70
|
+
|
|
|
71
|
+
+-- references/ <-- Справочные материалы
|
|
72
|
+
| +-- html-template.md <-- Базовый HTML шаблон
|
|
73
|
+
| +-- tailwind-config.md <-- Конфигурация Tailwind CDN
|
|
74
|
+
| +-- seo-checklist.md <-- OG, Twitter Cards, JSON-LD
|
|
75
|
+
| +-- accessibility-guide.md <-- Skip-nav, ARIA, keyboard nav
|
|
76
|
+
|
|
|
77
|
+
+-- examples/ <-- Примеры
|
|
78
|
+
+-- sample-podcast.md <-- Пример: подкаст
|
|
79
|
+
+-- sample-youtube.md <-- Пример: YouTube видео
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
.claude/commands/ <-- Slash-команды
|
|
84
|
+
+-- transcript-site.md <-- /transcript-site -- полный пайплайн
|
|
85
|
+
+-- transcript-site-generate.md <-- /transcript-site-generate -- только HTML
|
|
86
|
+
+-- transcript-site-deploy.md <-- /transcript-site-deploy -- только деплой
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
.claude/rules/
|
|
91
|
+
+-- transcript-site-quality.md <-- Автоматические правила качества
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Mermaid-диаграмма компонентов
|
|
95
|
+
|
|
96
|
+
```mermaid
|
|
97
|
+
graph TB
|
|
98
|
+
subgraph "Точки входа (Commands)"
|
|
99
|
+
FULL["/transcript-site<br/>Полный пайплайн"]
|
|
100
|
+
GEN["/transcript-site-generate<br/>Только генерация"]
|
|
101
|
+
DEP["/transcript-site-deploy<br/>Только деплой"]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
subgraph "Ядро Skill"
|
|
105
|
+
SKILL["SKILL.md<br/>Оркестратор"]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
subgraph "Модули (6 шагов)"
|
|
109
|
+
M1["modules/input-analysis.md<br/>Шаг 1"]
|
|
110
|
+
M2["modules/content-parsing.md<br/>Шаг 2"]
|
|
111
|
+
M3["modules/site-generation.md<br/>Шаг 3"]
|
|
112
|
+
M4["modules/interactivity.md<br/>Шаг 4"]
|
|
113
|
+
M5["modules/deploy.md<br/>Шаг 5"]
|
|
114
|
+
M6["modules/verification.md<br/>Шаг 6"]
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
subgraph "Справочники"
|
|
118
|
+
HTML["references/html-template.md"]
|
|
119
|
+
TW["references/tailwind-config.md"]
|
|
120
|
+
SEO["references/seo-checklist.md"]
|
|
121
|
+
A11Y["references/accessibility-guide.md"]
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
subgraph "Правила (автоматически)"
|
|
125
|
+
RULES["rules/transcript-site-quality.md"]
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
FULL --> SKILL
|
|
129
|
+
GEN --> SKILL
|
|
130
|
+
DEP --> SKILL
|
|
131
|
+
SKILL --> M1 --> M2 --> M3 --> M4 --> M5 --> M6
|
|
132
|
+
M3 --> HTML
|
|
133
|
+
M3 --> TW
|
|
134
|
+
M3 --> SEO
|
|
135
|
+
M4 --> A11Y
|
|
136
|
+
RULES -.->|"автоматически"| M3
|
|
137
|
+
RULES -.->|"автоматически"| M6
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 3. MODULE: Input Analysis
|
|
143
|
+
|
|
144
|
+
### Назначение
|
|
145
|
+
|
|
146
|
+
Определение типа входных данных (YouTube URL, текст, файл), извлечение метаданных и подготовка сырого транскрипта для парсинга.
|
|
147
|
+
|
|
148
|
+
### Архитектура определения источника
|
|
149
|
+
|
|
150
|
+
```mermaid
|
|
151
|
+
graph LR
|
|
152
|
+
INPUT["Входные данные"] --> DETECT{"Определение типа"}
|
|
153
|
+
DETECT -->|"youtube.com / youtu.be"| YOUTUBE["YouTube URL"]
|
|
154
|
+
DETECT -->|"Путь к файлу"| FILE["Файл"]
|
|
155
|
+
DETECT -->|"Текст в чате"| TEXT["Вставленный текст"]
|
|
156
|
+
DETECT -->|"URL + --text путь"| COMBINED["Комбинированный"]
|
|
157
|
+
|
|
158
|
+
YOUTUBE --> YTDLP["yt-dlp extraction"]
|
|
159
|
+
YTDLP --> META["Метаданные:<br/>title, duration, channel,<br/>upload date, thumbnail"]
|
|
160
|
+
YTDLP --> SUBS["Субтитры:<br/>auto or manual"]
|
|
161
|
+
|
|
162
|
+
FILE --> FREAD["Чтение файла"]
|
|
163
|
+
FREAD --> FDETECT["Определение формата:<br/>plain, SRT, VTT, speaker-labeled"]
|
|
164
|
+
|
|
165
|
+
TEXT --> TDETECT["Определение формата"]
|
|
166
|
+
|
|
167
|
+
COMBINED --> YTDLP
|
|
168
|
+
COMBINED --> FREAD
|
|
169
|
+
|
|
170
|
+
META --> LANG["Language Detection"]
|
|
171
|
+
SUBS --> LANG
|
|
172
|
+
FDETECT --> LANG
|
|
173
|
+
TDETECT --> LANG
|
|
174
|
+
|
|
175
|
+
LANG --> OUTPUT["Output:<br/>sourceType, metadata,<br/>rawTranscript, language"]
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Language Detection
|
|
179
|
+
|
|
180
|
+
Определение языка использует трёхуровневый подход:
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
Уровень 1: Метаданные YouTube (если доступны)
|
|
184
|
+
-> subtitle lang: "en" -> English
|
|
185
|
+
-> subtitle lang: "ru" -> Russian
|
|
186
|
+
|
|
187
|
+
Уровень 2: Кодировка символов
|
|
188
|
+
-> Кириллица (U+0400-U+04FF) > 30% -> Russian
|
|
189
|
+
-> CJK (U+4E00-U+9FFF) > 10% -> Chinese/Japanese/Korean
|
|
190
|
+
-> Latin -> дальнейший анализ
|
|
191
|
+
|
|
192
|
+
Уровень 3: Стоп-слова
|
|
193
|
+
-> Высокая частотность "the", "and", "is" -> English
|
|
194
|
+
-> Высокая частотность "и", "в", "на" -> Russian
|
|
195
|
+
-> ...
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### yt-dlp Integration Protocol
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# Шаг 1: Извлечение метаданных (JSON)
|
|
202
|
+
yt-dlp --dump-json --no-download "URL"
|
|
203
|
+
|
|
204
|
+
# Шаг 2: Извлечение субтитров
|
|
205
|
+
yt-dlp --write-auto-sub --sub-lang "DETECTED_LANG" \
|
|
206
|
+
--sub-format vtt --skip-download \
|
|
207
|
+
--output "/tmp/transcript" "URL"
|
|
208
|
+
|
|
209
|
+
# Шаг 3: Парсинг VTT файла
|
|
210
|
+
# Удаление дублей, нормализация timestamps, объединение фрагментов
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Anti-Patterns модуля
|
|
214
|
+
|
|
215
|
+
| Anti-Pattern | Сигнал обнаружения | Обязательное исправление |
|
|
216
|
+
|-------------|--------------------|-----------------------|
|
|
217
|
+
| Пустой транскрипт | Менее 50 слов после извлечения | Предложить ввод вручную |
|
|
218
|
+
| Битая кодировка | Наличие U+FFFD (replacement character) | Предложить повторное извлечение или конвертацию |
|
|
219
|
+
| Неопределённый язык | Confidence < 0.6 | Запросить у пользователя |
|
|
220
|
+
| yt-dlp timeout | Нет ответа > 30 секунд | Предложить ввод вручную |
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## 4. MODULE: Content Parsing
|
|
225
|
+
|
|
226
|
+
### Назначение
|
|
227
|
+
|
|
228
|
+
Разбиение сырого транскрипта на структурированные секции с определением спикеров, извлечением временных меток и ключевых цитат.
|
|
229
|
+
|
|
230
|
+
### Алгоритм секционирования
|
|
231
|
+
|
|
232
|
+
```mermaid
|
|
233
|
+
flowchart TD
|
|
234
|
+
RAW["Сырой транскрипт"] --> HAS_TS{"Есть\nтайм-коды?"}
|
|
235
|
+
|
|
236
|
+
HAS_TS -->|"Да"| TS_SPLIT["Анализ пауз и смены тем:<br/>1. Паузы > 5 сек = boundary candidate<br/>2. Смена спикера = boundary<br/>3. Тематический сдвиг (keyword analysis)"]
|
|
237
|
+
HAS_TS -->|"Нет"| PARA_SPLIT["Анализ параграфов:<br/>1. Двойной перенос строки = boundary<br/>2. Каждые 500-800 слов если нет переносов<br/>3. Markdown заголовки (#) = boundary"]
|
|
238
|
+
|
|
239
|
+
TS_SPLIT --> SECTIONS["Массив секций"]
|
|
240
|
+
PARA_SPLIT --> SECTIONS
|
|
241
|
+
|
|
242
|
+
SECTIONS --> SPEAKERS{"Определение\nспикеров"}
|
|
243
|
+
|
|
244
|
+
SPEAKERS -->|"Именованные<br/>(Host:, Guest:)"| NAMED["Именованные спикеры"]
|
|
245
|
+
SPEAKERS -->|"Неявные<br/>(чередование)"| UNNAMED["Speaker A, Speaker B"]
|
|
246
|
+
SPEAKERS -->|"Один спикер"| SINGLE["Без меток спикеров"]
|
|
247
|
+
|
|
248
|
+
NAMED --> QUOTES["Извлечение ключевых цитат:<br/>- Длинные предложения (> 20 слов)<br/>- Вопросительные предложения<br/>- Предложения с числами/статистикой"]
|
|
249
|
+
UNNAMED --> QUOTES
|
|
250
|
+
SINGLE --> QUOTES
|
|
251
|
+
|
|
252
|
+
QUOTES --> OUTPUT["Output:<br/>sections[], speakers[],<br/>timestamps[], quotes[]"]
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Формат секции (внутренний)
|
|
256
|
+
|
|
257
|
+
```json
|
|
258
|
+
{
|
|
259
|
+
"id": "section-03",
|
|
260
|
+
"title": "Main Discussion Part 1",
|
|
261
|
+
"startTime": 225,
|
|
262
|
+
"endTime": 372,
|
|
263
|
+
"speaker": "Guest",
|
|
264
|
+
"wordCount": 1204,
|
|
265
|
+
"content": "...",
|
|
266
|
+
"timestamps": [
|
|
267
|
+
{ "time": 225, "label": "3:45", "text": "Let me explain..." },
|
|
268
|
+
{ "time": 245, "label": "4:05", "text": "The key insight is..." }
|
|
269
|
+
],
|
|
270
|
+
"quotes": [
|
|
271
|
+
{ "text": "The key insight is that...", "time": 245 }
|
|
272
|
+
]
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Speaker Detection
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
Паттерн 1: Явные метки
|
|
280
|
+
"Host:" / "Guest:" / "Dr. Smith:" -> Именованные
|
|
281
|
+
|
|
282
|
+
Паттерн 2: SRT/VTT метаданные
|
|
283
|
+
<v Speaker 1> -> Извлечь имена из voice tags
|
|
284
|
+
|
|
285
|
+
Паттерн 3: Чередование
|
|
286
|
+
Абзац 1 -> Speaker A
|
|
287
|
+
Абзац 2 -> Speaker B (если стиль отличается)
|
|
288
|
+
Абзац 3 -> Speaker A (возврат)
|
|
289
|
+
|
|
290
|
+
Паттерн 4: Монолог
|
|
291
|
+
Один голос -> Без меток спикеров
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## 5. MODULE: Site Generation
|
|
297
|
+
|
|
298
|
+
### Назначение
|
|
299
|
+
|
|
300
|
+
Трансформация структурированных данных (секции, спикеры, timestamps) в полноценную HTML-страницу с Tailwind CSS, SEO-тегами и семантической разметкой.
|
|
301
|
+
|
|
302
|
+
### HTML Template Architecture
|
|
303
|
+
|
|
304
|
+
```mermaid
|
|
305
|
+
graph TB
|
|
306
|
+
subgraph "HTML Document"
|
|
307
|
+
HEAD["head<br/>- charset, viewport<br/>- SEO meta (OG, Twitter, JSON-LD)<br/>- Tailwind CDN script<br/>- Font Awesome CDN<br/>- tailwind.config<br/>- Print stylesheet<br/>- CSP meta tag"]
|
|
308
|
+
|
|
309
|
+
BODY["body<br/>class: bg-white dark:bg-gray-900"]
|
|
310
|
+
|
|
311
|
+
subgraph "Layout"
|
|
312
|
+
SKIP["a.skip-nav<br/>(screen-reader only)"]
|
|
313
|
+
NAV["nav<br/>- Title<br/>- Dark mode toggle<br/>- Search button<br/>- Hamburger (mobile)"]
|
|
314
|
+
PROGRESS["div.progress-bar<br/>(reading progress)"]
|
|
315
|
+
|
|
316
|
+
subgraph "Content area"
|
|
317
|
+
ASIDE["aside<br/>Table of Contents<br/>(sticky sidebar desktop,<br/>drawer mobile)"]
|
|
318
|
+
MAIN["main<br/>- Stats bar<br/>- YouTube embed (optional)<br/>- Section 1..N<br/> - Section heading<br/> - Timestamp links<br/> - Speaker labels<br/> - Transcript text<br/> - Copy quote buttons"]
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
FOOTER["footer<br/>- Credits<br/>- Print button<br/>- Stats"]
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
BTT["button#back-to-top<br/>(floating)"]
|
|
325
|
+
|
|
326
|
+
SEARCH_MODAL["div#search-modal<br/>- Input field<br/>- Results count<br/>- Navigation arrows"]
|
|
327
|
+
|
|
328
|
+
JS["script<br/>- Dark mode logic<br/>- Search logic<br/>- TOC scroll-spy<br/>- YouTube sync<br/>- Copy logic<br/>- Back-to-top<br/>- Progress bar"]
|
|
329
|
+
end
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Tailwind Configuration
|
|
333
|
+
|
|
334
|
+
```javascript
|
|
335
|
+
tailwind.config = {
|
|
336
|
+
darkMode: 'class',
|
|
337
|
+
theme: {
|
|
338
|
+
extend: {
|
|
339
|
+
colors: {
|
|
340
|
+
primary: {
|
|
341
|
+
50: '#eef2ff',
|
|
342
|
+
100: '#e0e7ff',
|
|
343
|
+
200: '#c7d2fe',
|
|
344
|
+
300: '#a5b4fc',
|
|
345
|
+
400: '#818cf8',
|
|
346
|
+
500: '#6366f1',
|
|
347
|
+
600: '#4f46e5',
|
|
348
|
+
700: '#4338ca',
|
|
349
|
+
800: '#3730a3',
|
|
350
|
+
900: '#312e81',
|
|
351
|
+
950: '#1e1b4e'
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Цвета `primary` автоматически заменяются на выбранную тему (indigo, emerald, rose, etc.).
|
|
360
|
+
|
|
361
|
+
### SEO Meta Generation
|
|
362
|
+
|
|
363
|
+
```mermaid
|
|
364
|
+
graph LR
|
|
365
|
+
SOURCE{"Тип<br/>источника"} -->|"YouTube"| YT_SEO["og:type = video<br/>JSON-LD: VideoObject<br/>og:image = thumbnail<br/>og:video = embed URL"]
|
|
366
|
+
SOURCE -->|"Текст"| TEXT_SEO["og:type = article<br/>JSON-LD: Article<br/>og:image = placeholder<br/>article:word_count"]
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## 6. MODULE: Interactivity
|
|
372
|
+
|
|
373
|
+
### Назначение
|
|
374
|
+
|
|
375
|
+
Добавление интерактивных JavaScript-фич к сгенерированному HTML. Все фичи реализованы на vanilla JS без фреймворков и без build-шагов.
|
|
376
|
+
|
|
377
|
+
### Архитектура фич
|
|
378
|
+
|
|
379
|
+
```
|
|
380
|
+
+-- Dark Mode
|
|
381
|
+
| +-- Toggle button (sun/moon icons)
|
|
382
|
+
| +-- CSS class on <html> element
|
|
383
|
+
| +-- localStorage persistence
|
|
384
|
+
| +-- System preference detection (prefers-color-scheme)
|
|
385
|
+
|
|
|
386
|
+
+-- Search (Ctrl+K)
|
|
387
|
+
| +-- Modal dialog
|
|
388
|
+
| +-- Debounced input (300ms)
|
|
389
|
+
| +-- Regex-based matching (escapeRegex)
|
|
390
|
+
| +-- <mark> tag highlighting
|
|
391
|
+
| +-- Result count display
|
|
392
|
+
| +-- Enter/Shift+Enter navigation
|
|
393
|
+
| +-- Escape to close
|
|
394
|
+
|
|
|
395
|
+
+-- Table of Contents
|
|
396
|
+
| +-- Desktop: sticky sidebar
|
|
397
|
+
| +-- Mobile: hamburger drawer
|
|
398
|
+
| +-- IntersectionObserver scroll-spy
|
|
399
|
+
| +-- Active section highlighting
|
|
400
|
+
| +-- Click-to-scroll with smooth behavior
|
|
401
|
+
|
|
|
402
|
+
+-- YouTube Sync
|
|
403
|
+
| +-- iframe API (enablejsapi=1)
|
|
404
|
+
| +-- data-seek attributes on timestamp links
|
|
405
|
+
| +-- Event delegation for clicks
|
|
406
|
+
| +-- postMessage for seekTo()
|
|
407
|
+
| +-- Origin restriction on message handler
|
|
408
|
+
|
|
|
409
|
+
+-- Copy Quote
|
|
410
|
+
| +-- data-copy attributes on buttons
|
|
411
|
+
| +-- Clipboard API (navigator.clipboard.writeText)
|
|
412
|
+
| +-- Visual feedback (button text change, timeout reset)
|
|
413
|
+
| +-- Fallback: document.execCommand('copy')
|
|
414
|
+
|
|
|
415
|
+
+-- Back-to-Top
|
|
416
|
+
| +-- Floating button (fixed position)
|
|
417
|
+
| +-- Appears on scroll > 300px
|
|
418
|
+
| +-- Smooth scroll to top
|
|
419
|
+
|
|
|
420
|
+
+-- Progress Bar
|
|
421
|
+
| +-- Fixed position at top of page
|
|
422
|
+
| +-- Width = scrollY / (scrollHeight - clientHeight) * 100%
|
|
423
|
+
| +-- Primary color fill
|
|
424
|
+
|
|
|
425
|
+
+-- Reading Stats
|
|
426
|
+
| +-- Word count (computed from transcript text)
|
|
427
|
+
| +-- Reading time (wordCount / 200)
|
|
428
|
+
| +-- Section count
|
|
429
|
+
| +-- Speaker count
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Event Delegation Pattern
|
|
433
|
+
|
|
434
|
+
Все интерактивные элементы используют единый паттерн event delegation через `data-*` атрибуты:
|
|
435
|
+
|
|
436
|
+
```javascript
|
|
437
|
+
document.addEventListener('click', function(e) {
|
|
438
|
+
// YouTube timestamp sync
|
|
439
|
+
const seekTarget = e.target.closest('[data-seek]');
|
|
440
|
+
if (seekTarget) {
|
|
441
|
+
e.preventDefault();
|
|
442
|
+
const seconds = parseInt(seekTarget.dataset.seek);
|
|
443
|
+
if (player && player.seekTo) {
|
|
444
|
+
player.seekTo(seconds, true);
|
|
445
|
+
}
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Copy quote
|
|
450
|
+
const copyTarget = e.target.closest('[data-copy]');
|
|
451
|
+
if (copyTarget) {
|
|
452
|
+
e.preventDefault();
|
|
453
|
+
const text = copyTarget.dataset.copy;
|
|
454
|
+
navigator.clipboard.writeText(text).then(function() {
|
|
455
|
+
const original = copyTarget.textContent;
|
|
456
|
+
copyTarget.textContent = strings.copy_success;
|
|
457
|
+
setTimeout(function() { copyTarget.textContent = original; }, 2000);
|
|
458
|
+
});
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// TOC section navigation
|
|
463
|
+
const tocTarget = e.target.closest('[data-section]');
|
|
464
|
+
if (tocTarget) {
|
|
465
|
+
e.preventDefault();
|
|
466
|
+
const sectionId = tocTarget.dataset.section;
|
|
467
|
+
document.getElementById(sectionId).scrollIntoView({ behavior: 'smooth' });
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Dark mode toggle
|
|
472
|
+
if (e.target.closest('#dark-mode-toggle')) {
|
|
473
|
+
toggleDarkMode();
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
Этот паттерн:
|
|
480
|
+
1. Не использует inline event handlers (безопасно для CSP)
|
|
481
|
+
2. Работает с динамически добавленными элементами
|
|
482
|
+
3. Минимизирует количество event listeners
|
|
483
|
+
4. Легко расширяется новыми `data-*` атрибутами
|
|
484
|
+
|
|
485
|
+
### Search Implementation
|
|
486
|
+
|
|
487
|
+
```mermaid
|
|
488
|
+
sequenceDiagram
|
|
489
|
+
actor U as Пользователь
|
|
490
|
+
participant I as Input Field
|
|
491
|
+
participant D as Debounce (300ms)
|
|
492
|
+
participant S as performSearch()
|
|
493
|
+
participant DOM as DOM
|
|
494
|
+
|
|
495
|
+
U->>I: Ctrl+K (открыть modal)
|
|
496
|
+
U->>I: Ввод текста "machine learning"
|
|
497
|
+
|
|
498
|
+
I->>D: onChange event
|
|
499
|
+
Note over D: Ждём 300ms без новых событий
|
|
500
|
+
|
|
501
|
+
D->>S: performSearch("machine learning")
|
|
502
|
+
|
|
503
|
+
S->>S: escapeRegex("machine learning")
|
|
504
|
+
S->>S: new RegExp(escaped, 'gi')
|
|
505
|
+
|
|
506
|
+
S->>DOM: Удалить все <mark> теги
|
|
507
|
+
S->>DOM: Найти совпадения в .transcript-text
|
|
508
|
+
S->>DOM: Обернуть совпадения в <mark>
|
|
509
|
+
S->>DOM: Обновить счётчик: "Найдено: 12"
|
|
510
|
+
S->>DOM: Скролл к первому совпадению
|
|
511
|
+
|
|
512
|
+
U->>I: Enter (следующий результат)
|
|
513
|
+
I->>DOM: Скролл к следующему <mark>
|
|
514
|
+
|
|
515
|
+
U->>I: Escape (закрыть)
|
|
516
|
+
I->>DOM: Удалить все <mark>
|
|
517
|
+
I->>DOM: Скрыть modal
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### IntersectionObserver Scroll-Spy
|
|
521
|
+
|
|
522
|
+
```javascript
|
|
523
|
+
const observer = new IntersectionObserver(function(entries) {
|
|
524
|
+
entries.forEach(function(entry) {
|
|
525
|
+
if (entry.isIntersecting) {
|
|
526
|
+
// Убрать подсветку со всех TOC-элементов
|
|
527
|
+
document.querySelectorAll('[data-section]').forEach(function(el) {
|
|
528
|
+
el.classList.remove('bg-primary-100', 'dark:bg-primary-900', 'font-bold');
|
|
529
|
+
});
|
|
530
|
+
// Подсветить текущий
|
|
531
|
+
const tocLink = document.querySelector('[data-section="' + entry.target.id + '"]');
|
|
532
|
+
if (tocLink) {
|
|
533
|
+
tocLink.classList.add('bg-primary-100', 'dark:bg-primary-900', 'font-bold');
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
}, {
|
|
538
|
+
rootMargin: '-20% 0px -70% 0px',
|
|
539
|
+
threshold: 0
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
document.querySelectorAll('section[id^="section-"]').forEach(function(section) {
|
|
543
|
+
observer.observe(section);
|
|
544
|
+
});
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
## 7. MODULE: Deploy
|
|
550
|
+
|
|
551
|
+
### Назначение
|
|
552
|
+
|
|
553
|
+
Генерация конфигурации для деплоя сайта. Основная цель -- GitHub Pages через `docs/` директорию.
|
|
554
|
+
|
|
555
|
+
### Архитектура деплоя
|
|
556
|
+
|
|
557
|
+
```mermaid
|
|
558
|
+
graph TD
|
|
559
|
+
SITE["docs/index.html"] --> GIT["git add docs/"]
|
|
560
|
+
GIT --> PUSH["git push origin main"]
|
|
561
|
+
PUSH --> GH["GitHub Repository"]
|
|
562
|
+
GH --> PAGES["GitHub Pages<br/>Settings > Pages<br/>Source: main, /docs"]
|
|
563
|
+
PAGES --> CDN["GitHub CDN"]
|
|
564
|
+
CDN --> USER["Пользователь<br/>https://user.github.io/repo/"]
|
|
565
|
+
|
|
566
|
+
SITE --> ROBOTS["docs/robots.txt"]
|
|
567
|
+
SITE --> SITEMAP["docs/sitemap.xml"]
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### GitHub Actions автоматизация (опционально)
|
|
571
|
+
|
|
572
|
+
```yaml
|
|
573
|
+
# .github/workflows/deploy-pages.yml
|
|
574
|
+
name: Deploy Pages
|
|
575
|
+
on:
|
|
576
|
+
push:
|
|
577
|
+
branches: [main]
|
|
578
|
+
paths: ['docs/**']
|
|
579
|
+
|
|
580
|
+
permissions:
|
|
581
|
+
pages: write
|
|
582
|
+
id-token: write
|
|
583
|
+
|
|
584
|
+
jobs:
|
|
585
|
+
deploy:
|
|
586
|
+
environment:
|
|
587
|
+
name: github-pages
|
|
588
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
589
|
+
runs-on: ubuntu-latest
|
|
590
|
+
steps:
|
|
591
|
+
- uses: actions/checkout@v4
|
|
592
|
+
- uses: actions/configure-pages@v4
|
|
593
|
+
- uses: actions/upload-pages-artifact@v3
|
|
594
|
+
with:
|
|
595
|
+
path: docs/
|
|
596
|
+
- id: deployment
|
|
597
|
+
uses: actions/deploy-pages@v4
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
602
|
+
## 8. MODULE: Verification
|
|
603
|
+
|
|
604
|
+
### Назначение
|
|
605
|
+
|
|
606
|
+
Валидация сгенерированного сайта по 7 категориям: HTML, JavaScript, CSS, SEO, Accessibility, Security, Performance.
|
|
607
|
+
|
|
608
|
+
### Архитектура проверок
|
|
609
|
+
|
|
610
|
+
```mermaid
|
|
611
|
+
graph TD
|
|
612
|
+
HTML_FILE["docs/index.html"] --> HTML_CHECK["HTML Checks (8)"]
|
|
613
|
+
HTML_FILE --> JS_CHECK["JS Checks (6)"]
|
|
614
|
+
HTML_FILE --> CSS_CHECK["CSS Checks (4)"]
|
|
615
|
+
HTML_FILE --> SEO_CHECK["SEO Checks (5)"]
|
|
616
|
+
HTML_FILE --> A11Y_CHECK["A11y Checks (5)"]
|
|
617
|
+
HTML_FILE --> SEC_CHECK["Security Checks (4)"]
|
|
618
|
+
HTML_FILE --> PERF_CHECK["Performance Checks (3)"]
|
|
619
|
+
|
|
620
|
+
HTML_CHECK --> REPORT
|
|
621
|
+
JS_CHECK --> REPORT
|
|
622
|
+
CSS_CHECK --> REPORT
|
|
623
|
+
SEO_CHECK --> REPORT
|
|
624
|
+
A11Y_CHECK --> REPORT
|
|
625
|
+
SEC_CHECK --> REPORT
|
|
626
|
+
PERF_CHECK --> REPORT
|
|
627
|
+
|
|
628
|
+
REPORT["Verification Report<br/>35 total checks"]
|
|
629
|
+
REPORT --> PASS{"Все<br/>прошли?"}
|
|
630
|
+
PASS -->|"Да"| DONE["PIPELINE COMPLETE"]
|
|
631
|
+
PASS -->|"Нет"| FIX["Отчёт с ошибками<br/>+ рекомендации исправления"]
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### Полный перечень проверок
|
|
635
|
+
|
|
636
|
+
**HTML (8 проверок):**
|
|
637
|
+
|
|
638
|
+
| ID | Проверка |
|
|
639
|
+
|----|---------|
|
|
640
|
+
| HTML-01 | Валидная HTML5 структура (DOCTYPE, html, head, body) |
|
|
641
|
+
| HTML-02 | Все теги правильно закрыты |
|
|
642
|
+
| HTML-03 | Нет deprecated атрибутов (align, bgcolor, etc.) |
|
|
643
|
+
| HTML-04 | Атрибут lang на html элементе |
|
|
644
|
+
| HTML-05 | Charset meta tag (UTF-8) |
|
|
645
|
+
| HTML-06 | Viewport meta tag |
|
|
646
|
+
| HTML-07 | Семантические элементы (nav, main, aside, footer) |
|
|
647
|
+
| HTML-08 | Уникальные id атрибуты (нет дубликатов) |
|
|
648
|
+
|
|
649
|
+
**JavaScript (6 проверок):**
|
|
650
|
+
|
|
651
|
+
| ID | Проверка |
|
|
652
|
+
|----|---------|
|
|
653
|
+
| JS-01 | Нет синтаксических ошибок (парсинг скрипт-блока) |
|
|
654
|
+
| JS-02 | Event delegation (нет inline handlers) |
|
|
655
|
+
| JS-03 | escapeHtml() функция присутствует |
|
|
656
|
+
| JS-04 | escapeRegex() функция присутствует |
|
|
657
|
+
| JS-05 | Нет eval(), document.write() |
|
|
658
|
+
| JS-06 | Нет innerHTML с пользовательскими данными без escapeHtml |
|
|
659
|
+
|
|
660
|
+
**CSS (4 проверки):**
|
|
661
|
+
|
|
662
|
+
| ID | Проверка |
|
|
663
|
+
|----|---------|
|
|
664
|
+
| CSS-01 | Tailwind CDN или inline CSS загружен |
|
|
665
|
+
| CSS-02 | Dark mode классы присутствуют (dark:bg-*, dark:text-*) |
|
|
666
|
+
| CSS-03 | Print stylesheet присутствует (@media print) |
|
|
667
|
+
| CSS-04 | Responsive utilities (sm:, md:, lg:) используются |
|
|
668
|
+
|
|
669
|
+
**SEO (5 проверок):**
|
|
670
|
+
|
|
671
|
+
| ID | Проверка |
|
|
672
|
+
|----|---------|
|
|
673
|
+
| SEO-01 | Open Graph теги (og:title, og:description, og:image) |
|
|
674
|
+
| SEO-02 | Twitter Card теги |
|
|
675
|
+
| SEO-03 | JSON-LD structured data (Article или VideoObject) |
|
|
676
|
+
| SEO-04 | Canonical URL |
|
|
677
|
+
| SEO-05 | robots.txt и sitemap.xml сгенерированы |
|
|
678
|
+
|
|
679
|
+
**Accessibility (5 проверок):**
|
|
680
|
+
|
|
681
|
+
| ID | Проверка |
|
|
682
|
+
|----|---------|
|
|
683
|
+
| A11Y-01 | Skip-nav ссылка в начале body |
|
|
684
|
+
| A11Y-02 | ARIA roles на навигации и основном контенте |
|
|
685
|
+
| A11Y-03 | Keyboard navigation для search (Escape для закрытия) |
|
|
686
|
+
| A11Y-04 | aria-label на иконических кнопках |
|
|
687
|
+
| A11Y-05 | Контрастность текста (Tailwind default палитра проверена) |
|
|
688
|
+
|
|
689
|
+
**Security (4 проверки):**
|
|
690
|
+
|
|
691
|
+
| ID | Проверка |
|
|
692
|
+
|----|---------|
|
|
693
|
+
| SEC-01 | Нет inline event handlers (onclick, onload, onerror) |
|
|
694
|
+
| SEC-02 | SRI хеши на CDN-ресурсах |
|
|
695
|
+
| SEC-03 | CSP meta-тег |
|
|
696
|
+
| SEC-04 | postMessage origin проверка |
|
|
697
|
+
|
|
698
|
+
**Performance (3 проверки):**
|
|
699
|
+
|
|
700
|
+
| ID | Проверка |
|
|
701
|
+
|----|---------|
|
|
702
|
+
| PERF-01 | HTML размер < 200 KB |
|
|
703
|
+
| PERF-02 | Нет render-blocking ресурсов (кроме Tailwind CDN) |
|
|
704
|
+
| PERF-03 | Изображения с lazy loading (если есть) |
|
|
705
|
+
|
|
706
|
+
---
|
|
707
|
+
|
|
708
|
+
## 9. Поток данных (Data Flow)
|
|
709
|
+
|
|
710
|
+
### End-to-end pipeline
|
|
711
|
+
|
|
712
|
+
```mermaid
|
|
713
|
+
flowchart LR
|
|
714
|
+
subgraph "Input"
|
|
715
|
+
YT["YouTube URL"]
|
|
716
|
+
TXT["Text"]
|
|
717
|
+
FILE["File"]
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
subgraph "Step 1: Input Analysis"
|
|
721
|
+
YTDLP["yt-dlp"]
|
|
722
|
+
LANG["Language<br/>Detection"]
|
|
723
|
+
META["Metadata"]
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
subgraph "Step 2: Content Parsing"
|
|
727
|
+
SPLIT["Section<br/>Splitting"]
|
|
728
|
+
SPEAK["Speaker<br/>Detection"]
|
|
729
|
+
TS["Timestamp<br/>Mapping"]
|
|
730
|
+
QUOTE["Quote<br/>Extraction"]
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
subgraph "Step 3: Site Generation"
|
|
734
|
+
TMPL["HTML<br/>Template"]
|
|
735
|
+
TW["Tailwind<br/>Config"]
|
|
736
|
+
SEOG["SEO<br/>Meta Tags"]
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
subgraph "Step 4: Interactivity"
|
|
740
|
+
SEARCH["Search JS"]
|
|
741
|
+
TOC["TOC JS"]
|
|
742
|
+
DM["Dark Mode JS"]
|
|
743
|
+
SYNC["YouTube Sync JS"]
|
|
744
|
+
COPY["Copy JS"]
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
subgraph "Step 5: Deploy"
|
|
748
|
+
ROBOT["robots.txt"]
|
|
749
|
+
SMAP["sitemap.xml"]
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
subgraph "Step 6: Verification"
|
|
753
|
+
CHECK["35 Checks"]
|
|
754
|
+
end
|
|
755
|
+
|
|
756
|
+
subgraph "Output"
|
|
757
|
+
HTML["docs/index.html"]
|
|
758
|
+
end
|
|
759
|
+
|
|
760
|
+
YT --> YTDLP
|
|
761
|
+
TXT --> LANG
|
|
762
|
+
FILE --> LANG
|
|
763
|
+
YTDLP --> META
|
|
764
|
+
YTDLP --> LANG
|
|
765
|
+
|
|
766
|
+
META --> SPLIT
|
|
767
|
+
LANG --> SPLIT
|
|
768
|
+
SPLIT --> SPEAK
|
|
769
|
+
SPEAK --> TS
|
|
770
|
+
TS --> QUOTE
|
|
771
|
+
|
|
772
|
+
QUOTE --> TMPL
|
|
773
|
+
META --> SEOG
|
|
774
|
+
TMPL --> TW
|
|
775
|
+
TW --> SEOG
|
|
776
|
+
|
|
777
|
+
SEOG --> SEARCH
|
|
778
|
+
SEARCH --> TOC
|
|
779
|
+
TOC --> DM
|
|
780
|
+
DM --> SYNC
|
|
781
|
+
SYNC --> COPY
|
|
782
|
+
|
|
783
|
+
COPY --> ROBOT
|
|
784
|
+
ROBOT --> SMAP
|
|
785
|
+
|
|
786
|
+
SMAP --> CHECK
|
|
787
|
+
CHECK --> HTML
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
### Формат данных между шагами
|
|
791
|
+
|
|
792
|
+
| Шаг | Output | Формат |
|
|
793
|
+
|-----|--------|--------|
|
|
794
|
+
| 1 -> 2 | sourceType, metadata, rawTranscript, language | Internal object |
|
|
795
|
+
| 2 -> 3 | sections[], speakers[], timestamps[], quotes[] | Structured arrays |
|
|
796
|
+
| 3 -> 4 | htmlContent (string) | HTML string |
|
|
797
|
+
| 4 -> 5 | htmlWithJS (string), features[] | HTML string + feature list |
|
|
798
|
+
| 5 -> 6 | files (index.html, robots.txt, sitemap.xml) | File paths |
|
|
799
|
+
| 6 -> output | validationReport, status | Report + pass/fail |
|
|
800
|
+
|
|
801
|
+
---
|
|
802
|
+
|
|
803
|
+
## 10. Выбор технологического стека
|
|
804
|
+
|
|
805
|
+
### Почему Tailwind CDN, а не другие CSS-решения?
|
|
806
|
+
|
|
807
|
+
| Альтернатива | Почему отвергнута |
|
|
808
|
+
|-------------|-------------------|
|
|
809
|
+
| Bootstrap CDN | Более тяжёлый (~200 KB CSS), менее гибкий для кастомизации |
|
|
810
|
+
| Plain CSS | Требует ~3x больше кода, сложнее поддерживать responsive и dark mode |
|
|
811
|
+
| Tailwind CLI | Требует Node.js для build-шага, противоречит zero-build философии |
|
|
812
|
+
| Inline styles | Не масштабируются, не поддерживают responsive и pseudo-классы |
|
|
813
|
+
|
|
814
|
+
Tailwind Play CDN -- единственное решение, которое сочетает мощность utility CSS с zero-build deployment.
|
|
815
|
+
|
|
816
|
+
### Почему vanilla JS, а не React/Vue/Svelte?
|
|
817
|
+
|
|
818
|
+
| Альтернатива | Почему отвергнута |
|
|
819
|
+
|-------------|-------------------|
|
|
820
|
+
| React | Требует build (JSX -> JS), runtime ~130 KB, противоречит zero-build |
|
|
821
|
+
| Vue | Требует build или runtime compiler (~60 KB), избыточен для задачи |
|
|
822
|
+
| Svelte | Требует build (compile step), хотя компилируется в vanilla JS |
|
|
823
|
+
| Alpine.js | Ближайший кандидат (~15 KB), но добавляет ещё одну CDN-зависимость |
|
|
824
|
+
| jQuery | Устаревший, +87 KB, все нужные API есть в vanilla JS |
|
|
825
|
+
|
|
826
|
+
Vanilla JS достаточен для всех фич (search, dark mode, TOC, YouTube sync). Общий объём JS-кода: ~5-10 KB, что меньше, чем любой фреймворк.
|
|
827
|
+
|
|
828
|
+
### Почему не React + Next.js + Vercel?
|
|
829
|
+
|
|
830
|
+
Это антитеза нашей архитектуры. Next.js требует:
|
|
831
|
+
- `npm install` (node_modules: ~200 MB)
|
|
832
|
+
- Build step (`next build`)
|
|
833
|
+
- Runtime server (SSR/ISR) или static export
|
|
834
|
+
- Framework lock-in
|
|
835
|
+
- Continuous deployment pipeline
|
|
836
|
+
|
|
837
|
+
Наше решение: один HTML-файл, открываемый в браузере.
|
|
838
|
+
|
|
839
|
+
---
|
|
840
|
+
|
|
841
|
+
## 11. Архитектура безопасности
|
|
842
|
+
|
|
843
|
+
### XSS Prevention
|
|
844
|
+
|
|
845
|
+
Все пользовательские данные проходят через `escapeHtml()`:
|
|
846
|
+
|
|
847
|
+
```
|
|
848
|
+
Транскрипт текст -> escapeHtml() -> innerHTML
|
|
849
|
+
Метаданные YouTube -> escapeHtml() -> innerHTML
|
|
850
|
+
Имена спикеров -> escapeHtml() -> innerHTML
|
|
851
|
+
Поисковые запросы -> escapeRegex() -> RegExp constructor
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
Точки инъекции и их защита:
|
|
855
|
+
|
|
856
|
+
| Точка | Защита |
|
|
857
|
+
|-------|--------|
|
|
858
|
+
| Transcript content | `escapeHtml()` при вставке в DOM |
|
|
859
|
+
| Speaker names | `escapeHtml()` при вставке в DOM |
|
|
860
|
+
| Video title | `escapeHtml()` при вставке в DOM |
|
|
861
|
+
| Search input | `escapeRegex()` перед созданием RegExp |
|
|
862
|
+
| `data-*` атрибуты | Только числовые значения (timestamps) или pre-escaped |
|
|
863
|
+
| YouTube iframe src | Только `youtube.com/embed/` + alphanumeric video ID |
|
|
864
|
+
|
|
865
|
+
### Event Delegation Security
|
|
866
|
+
|
|
867
|
+
```
|
|
868
|
+
ЗАПРЕЩЕНО:
|
|
869
|
+
<button onclick="handleClick()"> -- inline handler
|
|
870
|
+
element.setAttribute('onclick', ...) -- dynamic inline handler
|
|
871
|
+
|
|
872
|
+
РАЗРЕШЕНО:
|
|
873
|
+
document.addEventListener('click', function(e) {
|
|
874
|
+
const target = e.target.closest('[data-action]');
|
|
875
|
+
...
|
|
876
|
+
});
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
### SRI (Subresource Integrity)
|
|
880
|
+
|
|
881
|
+
Каждый CDN-ресурс включает `integrity` атрибут:
|
|
882
|
+
|
|
883
|
+
```html
|
|
884
|
+
<script src="https://cdn.tailwindcss.com"
|
|
885
|
+
integrity="sha384-HASH"
|
|
886
|
+
crossorigin="anonymous"></script>
|
|
887
|
+
```
|
|
888
|
+
|
|
889
|
+
### postMessage Origin Restriction
|
|
890
|
+
|
|
891
|
+
```javascript
|
|
892
|
+
window.addEventListener('message', function(event) {
|
|
893
|
+
// ОБЯЗАТЕЛЬНО: проверка origin
|
|
894
|
+
if (event.origin !== 'https://www.youtube.com') {
|
|
895
|
+
return; // Отклонить сообщения от других origins
|
|
896
|
+
}
|
|
897
|
+
// Обработка YouTube API events
|
|
898
|
+
});
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
---
|
|
902
|
+
|
|
903
|
+
## 12. SEO архитектура
|
|
904
|
+
|
|
905
|
+
### Тройная SEO-стратегия
|
|
906
|
+
|
|
907
|
+
```
|
|
908
|
+
1. Open Graph (Facebook, LinkedIn, Telegram, WhatsApp)
|
|
909
|
+
-> og:title, og:description, og:image, og:type, og:url
|
|
910
|
+
|
|
911
|
+
2. Twitter Cards (Twitter/X)
|
|
912
|
+
-> twitter:card, twitter:title, twitter:description, twitter:image
|
|
913
|
+
|
|
914
|
+
3. JSON-LD Structured Data (Google, Bing, Yandex)
|
|
915
|
+
-> @type: VideoObject (YouTube) или Article (text)
|
|
916
|
+
-> headline, description, datePublished, wordCount
|
|
917
|
+
-> transcript (для VideoObject)
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
### JSON-LD Architecture
|
|
921
|
+
|
|
922
|
+
```mermaid
|
|
923
|
+
graph LR
|
|
924
|
+
SOURCE{"Тип<br/>источника"} -->|"YouTube"| VIDEO["@type: VideoObject"]
|
|
925
|
+
SOURCE -->|"Текст"| ARTICLE["@type: Article"]
|
|
926
|
+
|
|
927
|
+
VIDEO --> FIELDS_V["name, description,<br/>thumbnailUrl, uploadDate,<br/>duration, embedUrl,<br/>transcript"]
|
|
928
|
+
|
|
929
|
+
ARTICLE --> FIELDS_A["headline, description,<br/>datePublished, wordCount,<br/>articleBody"]
|
|
930
|
+
|
|
931
|
+
FIELDS_V --> JSONLD["script type=application/ld+json"]
|
|
932
|
+
FIELDS_A --> JSONLD
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
---
|
|
936
|
+
|
|
937
|
+
## 13. Доступность (Accessibility)
|
|
938
|
+
|
|
939
|
+
### Skip Navigation
|
|
940
|
+
|
|
941
|
+
```html
|
|
942
|
+
<a href="#main-content" class="sr-only focus:not-sr-only focus:absolute focus:top-0 focus:left-0 focus:z-50 focus:bg-white focus:p-4">
|
|
943
|
+
Skip to main content
|
|
944
|
+
</a>
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
### ARIA Roles
|
|
948
|
+
|
|
949
|
+
```html
|
|
950
|
+
<nav role="navigation" aria-label="Main navigation">
|
|
951
|
+
<main role="main" id="main-content">
|
|
952
|
+
<aside role="complementary" aria-label="Table of contents">
|
|
953
|
+
<footer role="contentinfo">
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
### Keyboard Navigation
|
|
957
|
+
|
|
958
|
+
| Клавиша | Действие |
|
|
959
|
+
|---------|---------|
|
|
960
|
+
| Ctrl+K / Cmd+K | Открыть поиск |
|
|
961
|
+
| Escape | Закрыть поиск / закрыть мобильное меню |
|
|
962
|
+
| Enter | Следующий результат поиска |
|
|
963
|
+
| Shift+Enter | Предыдущий результат поиска |
|
|
964
|
+
| Tab | Навигация между интерактивными элементами |
|
|
965
|
+
|
|
966
|
+
### Контрастность
|
|
967
|
+
|
|
968
|
+
Tailwind default палитра обеспечивает WCAG AA контрастность:
|
|
969
|
+
- Текст `gray-900` на `white`: ratio 17.15:1
|
|
970
|
+
- Текст `gray-100` на `gray-900`: ratio 15.39:1
|
|
971
|
+
- Primary-600 на white: ratio > 4.5:1
|
|
972
|
+
|
|
973
|
+
---
|
|
974
|
+
|
|
975
|
+
## 14. Расширяемость
|
|
976
|
+
|
|
977
|
+
### Кастомные темы
|
|
978
|
+
|
|
979
|
+
Создайте reference-файл с кастомной палитрой:
|
|
980
|
+
|
|
981
|
+
```
|
|
982
|
+
.claude/skills/transcript-site-generator/references/custom-theme-corporate.md
|
|
983
|
+
```
|
|
984
|
+
|
|
985
|
+
Содержимое:
|
|
986
|
+
|
|
987
|
+
```markdown
|
|
988
|
+
# Custom Theme: Corporate
|
|
989
|
+
|
|
990
|
+
## Tailwind Config Override
|
|
991
|
+
|
|
992
|
+
colors.primary = {
|
|
993
|
+
50: '#f0fdf4',
|
|
994
|
+
...
|
|
995
|
+
900: '#14532d'
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
fontFamily.sans = ['Inter', 'system-ui']
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
Использование:
|
|
1002
|
+
|
|
1003
|
+
```
|
|
1004
|
+
/transcript-site [source] --theme custom-theme-corporate
|
|
1005
|
+
```
|
|
1006
|
+
|
|
1007
|
+
### Кастомные exercise types
|
|
1008
|
+
|
|
1009
|
+
Для обучающих транскриптов можно добавить интерактивные упражнения:
|
|
1010
|
+
|
|
1011
|
+
```markdown
|
|
1012
|
+
# Custom Exercise: Quiz
|
|
1013
|
+
|
|
1014
|
+
## HTML Template
|
|
1015
|
+
<div data-exercise="quiz" data-question="What was the main point?">
|
|
1016
|
+
<button data-answer="a">Option A</button>
|
|
1017
|
+
<button data-answer="b">Option B</button>
|
|
1018
|
+
</div>
|
|
1019
|
+
|
|
1020
|
+
## JS Handler
|
|
1021
|
+
// Add to event delegation
|
|
1022
|
+
const exercise = e.target.closest('[data-answer]');
|
|
1023
|
+
if (exercise) { ... }
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
### Кастомные verification checks
|
|
1027
|
+
|
|
1028
|
+
Добавьте проверки в `modules/verification.md`:
|
|
1029
|
+
|
|
1030
|
+
```markdown
|
|
1031
|
+
## Custom Checks
|
|
1032
|
+
|
|
1033
|
+
| ID | Проверка |
|
|
1034
|
+
|----|---------|
|
|
1035
|
+
| CUSTOM-01 | [Ваша проверка] |
|
|
1036
|
+
```
|
|
1037
|
+
|
|
1038
|
+
---
|
|
1039
|
+
|
|
1040
|
+
## 15. Проектные решения и компромиссы
|
|
1041
|
+
|
|
1042
|
+
### Почему один HTML-файл, а не SPA с роутингом?
|
|
1043
|
+
|
|
1044
|
+
Один файл проще деплоить, не требует серверного роутинга, работает через `file://`, не ломается при 404. Для транскриптов до 30K слов один файл достаточен. Multi-page chunking используется только для очень длинных транскриптов.
|
|
1045
|
+
|
|
1046
|
+
### Почему Tailwind Play CDN, а не Tailwind CLI?
|
|
1047
|
+
|
|
1048
|
+
Tailwind CLI требует Node.js и build-шаг. Play CDN работает прямо в браузере. Документация Tailwind не рекомендует Play CDN для production, но для наших целей (50-100 KB HTML, посещаемость < 1000/день) это оправданный trade-off.
|
|
1049
|
+
|
|
1050
|
+
### Почему event delegation, а не component-based?
|
|
1051
|
+
|
|
1052
|
+
Event delegation через `data-*` атрибуты:
|
|
1053
|
+
1. Совместимо со строгим CSP (нет inline handlers)
|
|
1054
|
+
2. Работает с одним event listener вместо десятков
|
|
1055
|
+
3. Не требует framework для привязки событий
|
|
1056
|
+
4. Прозрачно для отладки
|
|
1057
|
+
|
|
1058
|
+
### Почему IntersectionObserver для scroll-spy?
|
|
1059
|
+
|
|
1060
|
+
Альтернативы:
|
|
1061
|
+
- `scroll` event + `getBoundingClientRect()` -- дорого по CPU, throttle необходим
|
|
1062
|
+
- `position: sticky` + CSS -- не даёт информации о текущей секции для TOC подсветки
|
|
1063
|
+
|
|
1064
|
+
IntersectionObserver -- нативный API, работает асинхронно, не блокирует main thread.
|
|
1065
|
+
|
|
1066
|
+
### Почему не SSG (Hugo, Jekyll, Eleventy)?
|
|
1067
|
+
|
|
1068
|
+
SSG требуют установки, конфигурации, шаблонов. Наш скилл генерирует HTML напрямую через Claude Code -- это и есть "генератор статических сайтов", только AI-driven вместо template-driven.
|