dsh-desktop-kit 0.0.0-stage → 2.0.0

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.
Files changed (269) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +152 -2
  3. package/client.js +4101 -0
  4. package/cordis.patch.yml +5 -0
  5. package/docs/ARCHITECTURE.md +114 -0
  6. package/docs/COMPATIBILITY.md +61 -0
  7. package/docs/INSTALL.md +84 -0
  8. package/docs/PRIVACY.md +50 -0
  9. package/docs/ROADMAP.md +57 -0
  10. package/docs/TOKENS.md +118 -0
  11. package/docs/TROUBLESHOOTING.md +68 -0
  12. package/docs/images/hero.png +0 -0
  13. package/index.js +84 -0
  14. package/package.json +70 -4
  15. package/plugins/dsh-gkb-ru-ui/cordis.patch.yml +6 -0
  16. package/plugins/dsh-gkb-ru-ui/lib/client.js +1331 -0
  17. package/plugins/dsh-gkb-ru-ui/lib/index.js +186 -0
  18. package/plugins/dsh-gkb-ru-ui/lib/skills.js +570 -0
  19. package/plugins/dsh-gkb-ru-ui/package.json +28 -0
  20. package/plugins/dsh-gkb-ru-ui/screenshots/01-home-tiles-1440-light.png +0 -0
  21. package/plugins/dsh-gkb-ru-ui/screenshots/02-skills-1440-light.png +0 -0
  22. package/plugins/dsh-gkb-ru-ui/screenshots/03-skills-editor-1440-light.png +0 -0
  23. package/plugins/dsh-gkb-ru-ui/screenshots/04-skills-1440-dark.png +0 -0
  24. package/plugins/dsh-gkb-ru-ui/screenshots/05-skills-390-light.png +0 -0
  25. package/plugins/dsh-gkb-ru-ui/screenshots/06-home-tiles-1440-dark.png +0 -0
  26. package/plugins/dsh-peak-guard/README.md +70 -0
  27. package/plugins/dsh-peak-guard/client.js +741 -0
  28. package/plugins/dsh-peak-guard/cordis.patch.yml +5 -0
  29. package/plugins/dsh-peak-guard/icon.svg +12 -0
  30. package/plugins/dsh-peak-guard/index.js +2 -0
  31. package/plugins/dsh-peak-guard/locale/en.json +6 -0
  32. package/plugins/dsh-peak-guard/locale/ru.json +6 -0
  33. package/plugins/dsh-peak-guard/locale/zh.json +6 -0
  34. package/plugins/dsh-peak-guard/package.json +33 -0
  35. package/plugins/dsh-peak-guard/screenshots/01-real-time-peak-start.png +0 -0
  36. package/plugins/dsh-peak-guard/screenshots/02-real-time-peak-end.png +0 -0
  37. package/plugins/dsh-peak-guard/screenshots/03-peak-card-1440-light.png +0 -0
  38. package/plugins/dsh-peak-guard/screenshots/04-peak-card-1440-dark.png +0 -0
  39. package/plugins/dsh-peak-guard/screenshots/05-peak-card-390-light.png +0 -0
  40. package/plugins/dsh-peak-guard/screenshots/05-peak-card-768-light.png +0 -0
  41. package/plugins/dsh-peak-guard/screenshots/06-peak-card-390-light.png +0 -0
  42. package/plugins/dsh-peak-guard/screenshots/07-live-preview-check.png +0 -0
  43. package/plugins/dsh-peak-guard/screenshots/07-pre-peak-1440-light.png +0 -0
  44. package/plugins/dsh-peak-guard/screenshots/08-peak-start-1440-light.png +0 -0
  45. package/plugins/dsh-peak-guard/screenshots/09-peak-end-1440-light.png +0 -0
  46. package/plugins/dsh-peak-guard/screenshots/10-pre-peak-card-1440-light.png +0 -0
  47. package/plugins/dsh-peak-guard/screenshots/11-pre-peak-card-1440-dark.png +0 -0
  48. package/plugins/dsh-peak-guard/screenshots/12-pre-peak-card-390-light.png +0 -0
  49. package/plugins/dsh-peak-guard/screenshots/qa-report.json +74 -0
  50. package/plugins/dsh-profile-transfer/README.md +62 -0
  51. package/plugins/dsh-profile-transfer/bootstrap/01-INSTALL.cmd +7 -0
  52. package/plugins/dsh-profile-transfer/bootstrap/README-ARCHIVE.md +54 -0
  53. package/plugins/dsh-profile-transfer/bootstrap/README-/320/243/320/241/320/242/320/220/320/235/320/236/320/222/320/232/320/220.md +42 -0
  54. package/plugins/dsh-profile-transfer/bootstrap/install-on-clean-machine.ps1 +119 -0
  55. package/plugins/dsh-profile-transfer/bootstrap//320/243/320/241/320/242/320/220/320/235/320/236/320/222/320/230/320/242/320/254.cmd +5 -0
  56. package/plugins/dsh-profile-transfer/client.js +806 -0
  57. package/plugins/dsh-profile-transfer/cordis.patch.yml +3 -0
  58. package/plugins/dsh-profile-transfer/icon.svg +13 -0
  59. package/plugins/dsh-profile-transfer/index.js +375 -0
  60. package/plugins/dsh-profile-transfer/locale/en.json +6 -0
  61. package/plugins/dsh-profile-transfer/locale/ru.json +6 -0
  62. package/plugins/dsh-profile-transfer/locale/zh.json +6 -0
  63. package/plugins/dsh-profile-transfer/package.json +36 -0
  64. package/plugins/dsh-profile-transfer/screenshots/01-settings-transfer-1440-light.png +0 -0
  65. package/plugins/dsh-profile-transfer/screenshots/02-settings-transfer-preview-1440-light.png +0 -0
  66. package/plugins/dsh-profile-transfer/screenshots/03-settings-transfer-1440-dark.png +0 -0
  67. package/plugins/dsh-profile-transfer/screenshots/04-settings-transfer-390-light.png +0 -0
  68. package/plugins/dsh-profile-transfer/screenshots/05-settings-transfer-768-light.png +0 -0
  69. package/plugins/dsh-profile-transfer/screenshots/06-settings-transfer-390-dark.png +0 -0
  70. package/plugins/dsh-profile-transfer/screenshots/07-settings-transfer-export-result.png +0 -0
  71. package/plugins/dsh-profile-transfer/screenshots/08-settings-transfer-workspaces-1440-light.png +0 -0
  72. package/plugins/dsh-profile-transfer/screenshots/09-settings-transfer-workspaces-1440-dark.png +0 -0
  73. package/plugins/dsh-profile-transfer/screenshots/10-settings-transfer-workspaces-390-light.png +0 -0
  74. package/plugins/dsh-profile-transfer/transfer.js +1004 -0
  75. package/plugins/dsh-project-memory/README.md +71 -0
  76. package/plugins/dsh-project-memory/cordis.patch.yml +4 -0
  77. package/plugins/dsh-project-memory/icon.svg +12 -0
  78. package/plugins/dsh-project-memory/index.js +1240 -0
  79. package/plugins/dsh-project-memory/locale/en.json +6 -0
  80. package/plugins/dsh-project-memory/locale/ru.json +6 -0
  81. package/plugins/dsh-project-memory/locale/zh.json +6 -0
  82. package/plugins/dsh-project-memory/package.json +26 -0
  83. package/plugins/dsh-session-move/README.md +67 -0
  84. package/plugins/dsh-session-move/client.js +719 -0
  85. package/plugins/dsh-session-move/cordis.patch.yml +5 -0
  86. package/plugins/dsh-session-move/icon.svg +14 -0
  87. package/plugins/dsh-session-move/index.js +497 -0
  88. package/plugins/dsh-session-move/locale/en.json +6 -0
  89. package/plugins/dsh-session-move/locale/ru.json +6 -0
  90. package/plugins/dsh-session-move/locale/zh.json +6 -0
  91. package/plugins/dsh-session-move/package.json +31 -0
  92. package/plugins/dsh-session-move/screenshots/01-row-menu-1440-light.png +0 -0
  93. package/plugins/dsh-session-move/screenshots/02-dialog-1440-light.png +0 -0
  94. package/plugins/dsh-session-move/screenshots/03-dialog-390-light.png +0 -0
  95. package/plugins/dsh-session-move/screenshots/04-dialog-1440-dark.png +0 -0
  96. package/plugins/dsh-session-move/screenshots/05-drag-highlight-1440-light.png +0 -0
  97. package/plugins/dsh-session-move/screenshots/06-drop-ungrouped-highlight.png +0 -0
  98. package/plugins/dsh-session-move/screenshots/07-after-drop-ungrouped.png +0 -0
  99. package/plugins/dsh-session-move/screenshots/08-move-dialog.png +0 -0
  100. package/plugins/dsh-session-move/screenshots/09-moved-to-second-workspace.png +0 -0
  101. package/plugins/dsh-session-move/screenshots/qa-report.json +62 -0
  102. package/plugins/dsh-skill-autopilot/cordis.patch.yml +3 -0
  103. package/plugins/dsh-skill-autopilot/index.js +444 -0
  104. package/plugins/dsh-skill-autopilot/package.json +19 -0
  105. package/plugins/dsh-token-lab/cordis.patch.yml +3 -0
  106. package/plugins/dsh-token-lab/lib/client.js +504 -0
  107. package/plugins/dsh-token-lab/lib/index.js +275 -0
  108. package/plugins/dsh-token-lab/package.json +26 -0
  109. package/plugins/dsh-token-lab/screenshots/01-token-lab-1440-light.png +0 -0
  110. package/plugins/dsh-token-lab/screenshots/02-token-lab-1440-dark.png +0 -0
  111. package/skills/code-review-checklist/SKILL.md +55 -0
  112. package/skills/content-writing/README.md +87 -0
  113. package/skills/content-writing/SKILL.md +85 -0
  114. package/skills/content-writing/assets/checklists/fact-check.md +53 -0
  115. package/skills/content-writing/assets/checklists/publish.md +65 -0
  116. package/skills/content-writing/assets/checklists/social.md +40 -0
  117. package/skills/content-writing/assets/templates/article.md +47 -0
  118. package/skills/content-writing/assets/templates/brief.md +44 -0
  119. package/skills/content-writing/assets/templates/doctor-card.md +41 -0
  120. package/skills/content-writing/assets/templates/image-prompts.md +128 -0
  121. package/skills/content-writing/assets/templates/post-telegram.md +36 -0
  122. package/skills/content-writing/assets/templates/post-vk.md +42 -0
  123. package/skills/content-writing/assets/templates/press-release.md +56 -0
  124. package/skills/content-writing/assets/templates/science-pop-note.md +55 -0
  125. package/skills/content-writing/assets/templates/service-card.md +46 -0
  126. package/skills/content-writing/references/anti-ai-style.md +248 -0
  127. package/skills/content-writing/references/editing.md +185 -0
  128. package/skills/content-writing/references/fact-checking.md +205 -0
  129. package/skills/content-writing/references/government-medical.md +246 -0
  130. package/skills/content-writing/references/images.md +212 -0
  131. package/skills/content-writing/references/journalism.md +252 -0
  132. package/skills/content-writing/references/process.md +123 -0
  133. package/skills/content-writing/references/quick-recipes.md +99 -0
  134. package/skills/content-writing/references/rules.md +85 -0
  135. package/skills/content-writing/references/science-popular.md +218 -0
  136. package/skills/content-writing/references/seo-content.md +172 -0
  137. package/skills/content-writing/references/social-media.md +253 -0
  138. package/skills/content-writing/references/sources.md +49 -0
  139. package/skills/content-writing/references/templates.md +291 -0
  140. package/skills/context-economy/SKILL.md +60 -0
  141. package/skills/context-economy/references/long-session.md +35 -0
  142. package/skills/context-economy/references/token-math.md +42 -0
  143. package/skills/context-economy/references/tool-recipes.md +34 -0
  144. package/skills/database-safety/SKILL.md +47 -0
  145. package/skills/debugging-playbook/SKILL.md +42 -0
  146. package/skills/design-critique/SKILL.md +65 -0
  147. package/skills/design-critique/references/a11y.md +25 -0
  148. package/skills/design-critique/references/diagnoses.md +33 -0
  149. package/skills/design-critique/references/quick-tests.md +30 -0
  150. package/skills/design-critique/references/report-template.md +63 -0
  151. package/skills/design-critique/references/rubric-fast.md +73 -0
  152. package/skills/dev-workflow/SKILL.md +48 -0
  153. package/skills/dev-workflow/references/definition-of-done.md +44 -0
  154. package/skills/dev-workflow/references/memory-and-boundaries.md +31 -0
  155. package/skills/dev-workflow/references/stages.md +67 -0
  156. package/skills/git-and-ci/SKILL.md +60 -0
  157. package/skills/pg-upgrade-verify/SKILL.md +67 -0
  158. package/skills/project-deep-dive/SKILL.md +45 -0
  159. package/skills/project-deep-dive/references/recon-commands.md +90 -0
  160. package/skills/project-deep-dive/references/section-templates.md +104 -0
  161. package/skills/project-deep-dive/references/tool-and-process.md +86 -0
  162. package/skills/project-memory-maintenance/SKILL.md +55 -0
  163. package/skills/project-memory-maintenance/references/api-and-checklist.md +99 -0
  164. package/skills/project-memory-maintenance/references/journal-template.md +50 -0
  165. package/skills/project-memory-maintenance/references/section-rules.md +59 -0
  166. package/skills/release-and-deploy/SKILL.md +53 -0
  167. package/skills/requirements-and-planning/SKILL.md +49 -0
  168. package/skills/requirements-and-planning/references/antipatterns-and-checklist.md +20 -0
  169. package/skills/requirements-and-planning/references/process-steps.md +52 -0
  170. package/skills/requirements-and-planning/references/templates-and-estimates.md +29 -0
  171. package/skills/security-review/SKILL.md +40 -0
  172. package/skills/seo/README.md +60 -0
  173. package/skills/seo/SKILL.md +77 -0
  174. package/skills/seo/assets/README.md +66 -0
  175. package/skills/seo/assets/scripts/LICENSE-playwright-core.txt +202 -0
  176. package/skills/seo/assets/scripts/README.md +179 -0
  177. package/skills/seo/assets/scripts/lib/args.mjs +105 -0
  178. package/skills/seo/assets/scripts/lib/browser.mjs +620 -0
  179. package/skills/seo/assets/scripts/lib/zip.mjs +191 -0
  180. package/skills/seo/assets/scripts/seo-audit.mjs +1675 -0
  181. package/skills/seo/assets/snippets/jsonld-breadcrumb.json +30 -0
  182. package/skills/seo/assets/snippets/jsonld-faq.json +39 -0
  183. package/skills/seo/assets/snippets/jsonld-medical-clinic.json +49 -0
  184. package/skills/seo/assets/snippets/jsonld-medical-webpage.json +33 -0
  185. package/skills/seo/assets/snippets/jsonld-organization.json +74 -0
  186. package/skills/seo/assets/snippets/jsonld-physician.json +46 -0
  187. package/skills/seo/assets/snippets/meta.blade.php +61 -0
  188. package/skills/seo/assets/snippets/robots.txt +61 -0
  189. package/skills/seo/assets/snippets/sitemap-urlset-example.xml +72 -0
  190. package/skills/seo/assets/snippets/sitemap.xml +36 -0
  191. package/skills/seo/references/antipatterns.md +66 -0
  192. package/skills/seo/references/audit-checklist.md +319 -0
  193. package/skills/seo/references/content-seo.md +204 -0
  194. package/skills/seo/references/eeat-medical.md +219 -0
  195. package/skills/seo/references/measurement.md +250 -0
  196. package/skills/seo/references/on-page.md +214 -0
  197. package/skills/seo/references/page-templates.md +56 -0
  198. package/skills/seo/references/stack-recipes.md +695 -0
  199. package/skills/seo/references/structured-data.md +487 -0
  200. package/skills/seo/references/technical-seo.md +296 -0
  201. package/skills/service-desk-conventions/SKILL.md +52 -0
  202. package/skills/service-desk-db-safety/SKILL.md +63 -0
  203. package/skills/service-desk-release/SKILL.md +61 -0
  204. package/skills/service-desk-testing/SKILL.md +61 -0
  205. package/skills/service-desk-ui/SKILL.md +52 -0
  206. package/skills/skills-router/SKILL.md +53 -0
  207. package/skills/skills-router/references/applying-skills.md +25 -0
  208. package/skills/skills-router/references/routing-matrix.md +52 -0
  209. package/skills/testing-strategy/SKILL.md +52 -0
  210. package/skills/ui-design-system/SKILL.md +50 -0
  211. package/skills/ui-design-system/references/accessibility-and-responsive.md +50 -0
  212. package/skills/ui-design-system/references/tokens-and-components.md +67 -0
  213. package/skills/ui-design-system/references/visual-qa.md +44 -0
  214. package/skills/web-research/SKILL.md +47 -0
  215. package/skills/web-research/references/answer-and-citations.md +60 -0
  216. package/skills/web-research/references/query-recipes.md +44 -0
  217. package/skills/wow-design/SKILL.md +89 -0
  218. package/skills/wow-design/assets/kit/README.md +195 -0
  219. package/skills/wow-design/assets/kit/assets/css/base.css +158 -0
  220. package/skills/wow-design/assets/kit/assets/css/components.css +1001 -0
  221. package/skills/wow-design/assets/kit/assets/css/fonts.css +73 -0
  222. package/skills/wow-design/assets/kit/assets/css/pages.css +737 -0
  223. package/skills/wow-design/assets/kit/assets/css/tokens.css +218 -0
  224. package/skills/wow-design/assets/kit/assets/fonts/LICENSE-golos-text.txt +93 -0
  225. package/skills/wow-design/assets/kit/assets/fonts/LICENSE-lora.txt +93 -0
  226. package/skills/wow-design/assets/kit/assets/fonts/LICENSE-unbounded.txt +93 -0
  227. package/skills/wow-design/assets/kit/assets/fonts/golos-text-cyrillic-400-normal.woff2 +0 -0
  228. package/skills/wow-design/assets/kit/assets/fonts/golos-text-cyrillic-500-normal.woff2 +0 -0
  229. package/skills/wow-design/assets/kit/assets/fonts/golos-text-cyrillic-600-normal.woff2 +0 -0
  230. package/skills/wow-design/assets/kit/assets/fonts/golos-text-cyrillic-700-normal.woff2 +0 -0
  231. package/skills/wow-design/assets/kit/assets/fonts/golos-text-latin-400-normal.woff2 +0 -0
  232. package/skills/wow-design/assets/kit/assets/fonts/golos-text-latin-500-normal.woff2 +0 -0
  233. package/skills/wow-design/assets/kit/assets/fonts/golos-text-latin-600-normal.woff2 +0 -0
  234. package/skills/wow-design/assets/kit/assets/fonts/golos-text-latin-700-normal.woff2 +0 -0
  235. package/skills/wow-design/assets/kit/assets/fonts/lora-cyrillic-400-italic.woff2 +0 -0
  236. package/skills/wow-design/assets/kit/assets/fonts/lora-cyrillic-400-normal.woff2 +0 -0
  237. package/skills/wow-design/assets/kit/assets/fonts/lora-cyrillic-500-normal.woff2 +0 -0
  238. package/skills/wow-design/assets/kit/assets/fonts/lora-cyrillic-600-normal.woff2 +0 -0
  239. package/skills/wow-design/assets/kit/assets/fonts/lora-latin-400-normal.woff2 +0 -0
  240. package/skills/wow-design/assets/kit/assets/fonts/lora-latin-500-normal.woff2 +0 -0
  241. package/skills/wow-design/assets/kit/assets/fonts/lora-latin-600-normal.woff2 +0 -0
  242. package/skills/wow-design/assets/kit/assets/fonts/unbounded-cyrillic-400-normal.woff2 +0 -0
  243. package/skills/wow-design/assets/kit/assets/fonts/unbounded-cyrillic-500-normal.woff2 +0 -0
  244. package/skills/wow-design/assets/kit/assets/fonts/unbounded-cyrillic-600-normal.woff2 +0 -0
  245. package/skills/wow-design/assets/kit/assets/fonts/unbounded-latin-400-normal.woff2 +0 -0
  246. package/skills/wow-design/assets/kit/assets/fonts/unbounded-latin-500-normal.woff2 +0 -0
  247. package/skills/wow-design/assets/kit/assets/fonts/unbounded-latin-600-normal.woff2 +0 -0
  248. package/skills/wow-design/assets/kit/assets/js/kit.js +550 -0
  249. package/skills/wow-design/assets/kit/pages/dashboard.html +539 -0
  250. package/skills/wow-design/assets/kit/pages/hospital.html +430 -0
  251. package/skills/wow-design/assets/kit/showcase.html +1164 -0
  252. package/skills/wow-design/assets/scripts/LICENSE-axe-core.txt +362 -0
  253. package/skills/wow-design/assets/scripts/LICENSE-playwright-core.txt +202 -0
  254. package/skills/wow-design/assets/scripts/README.md +312 -0
  255. package/skills/wow-design/assets/scripts/audit.mjs +1200 -0
  256. package/skills/wow-design/assets/scripts/capture.mjs +337 -0
  257. package/skills/wow-design/assets/scripts/package.json +30 -0
  258. package/skills/wow-design/references/anti-patterns.md +252 -0
  259. package/skills/wow-design/references/critique-rubric.md +262 -0
  260. package/skills/wow-design/references/design-brief-template.md +48 -0
  261. package/skills/wow-design/references/inspiration.md +203 -0
  262. package/skills/wow-design/references/presets.md +99 -0
  263. package/skills/wow-design/references/principles.md +371 -0
  264. package/skills/wow-design/references/quick-presets.md +50 -0
  265. package/skills/wow-design/references/report-template.md +21 -0
  266. package/skills/wow-design/references/stack-recipes.md +96 -0
  267. package/skills/wow-design/references/visual-qa.md +82 -0
  268. package/skills/wow-design/references/wow-levers.md +43 -0
  269. package/tools/skill-cost.mjs +76 -0
@@ -0,0 +1,550 @@
1
+ /* ==========================================================================
2
+ AURORA · KIT.JS · v1.0 · 2026-11-04
3
+ Ванильный ES2022-модуль без зависимостей: тема, пресет, reveal, tabs,
4
+ модалка (Escape + focus), мобильное меню, dropdown, toast, демо-состояния.
5
+
6
+ ВАЖНО: файл написан как ES-модуль (top-level, без импортов и экспортов),
7
+ но подключается классическим `<script defer src>`. Причина: Chrome
8
+ блокирует внешние <script type="module"> на протоколе file://, а страницы
9
+ кита обязаны открываться двойным кликом без ошибок в консоли.
10
+ В любом ESM-проекте достаточно заменить тег на type="module".
11
+ ========================================================================== */
12
+ (function () {
13
+ 'use strict';
14
+
15
+ var root = document.documentElement;
16
+ var STORAGE = { theme: 'aurora-theme', preset: 'aurora-preset' };
17
+ var schemeQuery = window.matchMedia('(prefers-color-scheme: dark)');
18
+ var reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
19
+
20
+ /* ---------- 1. Тема (light / dark) ---------------------------------- */
21
+ function getTheme() {
22
+ return root.getAttribute('data-theme') === 'dark' ? 'dark' : 'light';
23
+ }
24
+
25
+ function syncThemeControls() {
26
+ var dark = getTheme() === 'dark';
27
+ document.querySelectorAll('[data-theme-toggle]').forEach(function (btn) {
28
+ btn.setAttribute('aria-pressed', dark ? 'true' : 'false');
29
+ btn.setAttribute('aria-label', dark ? 'Включить светлую тему' : 'Включить тёмную тему');
30
+ btn.setAttribute('title', dark ? 'Светлая тема' : 'Тёмная тема');
31
+ });
32
+ }
33
+
34
+ function applyTheme(theme, persist) {
35
+ var next = theme === 'dark' ? 'dark' : 'light';
36
+ root.setAttribute('data-theme', next);
37
+ if (persist) {
38
+ try { localStorage.setItem(STORAGE.theme, next); } catch (e) { /* приватный режим */ }
39
+ }
40
+ syncThemeControls();
41
+ syncSwatches();
42
+ document.dispatchEvent(new CustomEvent('aurora:theme', { detail: { theme: next } }));
43
+ }
44
+
45
+ function initTheme() {
46
+ var stored = null;
47
+ try { stored = localStorage.getItem(STORAGE.theme); } catch (e) { /* ignore */ }
48
+ if (stored !== 'light' && stored !== 'dark') {
49
+ stored = schemeQuery.matches ? 'dark' : 'light';
50
+ }
51
+ applyTheme(stored, false);
52
+
53
+ document.querySelectorAll('[data-theme-toggle]').forEach(function (btn) {
54
+ btn.addEventListener('click', function () {
55
+ applyTheme(getTheme() === 'dark' ? 'light' : 'dark', true);
56
+ });
57
+ });
58
+ document.querySelectorAll('[data-theme-set]').forEach(function (btn) {
59
+ btn.addEventListener('click', function () {
60
+ applyTheme(btn.getAttribute('data-theme-set'), true);
61
+ });
62
+ });
63
+
64
+ schemeQuery.addEventListener('change', function (event) {
65
+ var hasChoice = false;
66
+ try { hasChoice = !!localStorage.getItem(STORAGE.theme); } catch (e) { /* ignore */ }
67
+ if (!hasChoice) applyTheme(event.matches ? 'dark' : 'light', false);
68
+ });
69
+ }
70
+
71
+ /* ---------- 2. Пресет (data-preset) --------------------------------- */
72
+ function getPreset() {
73
+ return root.getAttribute('data-preset') || 'aurora';
74
+ }
75
+
76
+ function syncPresetControls() {
77
+ var current = getPreset();
78
+ document.querySelectorAll('[data-preset-set]').forEach(function (btn) {
79
+ var on = btn.getAttribute('data-preset-set') === current;
80
+ btn.setAttribute('aria-pressed', on ? 'true' : 'false');
81
+ });
82
+ document.querySelectorAll('[data-preset-label]').forEach(function (el) {
83
+ el.textContent = current;
84
+ });
85
+ }
86
+
87
+ function applyPreset(preset, persist) {
88
+ root.setAttribute('data-preset', preset);
89
+ if (persist) {
90
+ try { localStorage.setItem(STORAGE.preset, preset); } catch (e) { /* ignore */ }
91
+ }
92
+ syncPresetControls();
93
+ syncSwatches();
94
+ document.dispatchEvent(new CustomEvent('aurora:preset', { detail: { preset: preset } }));
95
+ }
96
+
97
+ function initPreset() {
98
+ // Пресет запоминаем и восстанавливаем только на страницах с явным
99
+ // разрешением (витрина): у эталонных страниц пресет закреплён брифом.
100
+ if (root.hasAttribute('data-preset-allow')) {
101
+ var stored = null;
102
+ try { stored = localStorage.getItem(STORAGE.preset); } catch (e) { /* ignore */ }
103
+ if (stored) root.setAttribute('data-preset', stored);
104
+ }
105
+ syncPresetControls();
106
+ document.querySelectorAll('[data-preset-set]').forEach(function (btn) {
107
+ btn.addEventListener('click', function () {
108
+ applyPreset(btn.getAttribute('data-preset-set'), true);
109
+ });
110
+ });
111
+ }
112
+
113
+ /* ---------- 2b. Свотчи: подписи hex обновляются вместе с темой/пресетом - */
114
+ function syncSwatches() {
115
+ document.querySelectorAll('[data-swatch-var]').forEach(function (el) {
116
+ var name = el.getAttribute('data-swatch-var');
117
+ var value = window.getComputedStyle(root).getPropertyValue(name).trim();
118
+ if (!value) return;
119
+ el.textContent = value.toUpperCase();
120
+ var owner = el.closest('[data-copy]');
121
+ if (owner) owner.setAttribute('data-copy', value);
122
+ });
123
+ }
124
+
125
+ /* ---------- 3. Reveal on scroll ------------------------------------- */ function initReveal() {
126
+ var items = Array.prototype.slice.call(document.querySelectorAll('.reveal'));
127
+ if (!items.length) return;
128
+ if (reduceMotion.matches || !('IntersectionObserver' in window)) {
129
+ items.forEach(function (el) { el.classList.add('is-in'); });
130
+ return;
131
+ }
132
+ var observer = new IntersectionObserver(function (entries) {
133
+ entries.forEach(function (entry) {
134
+ if (!entry.isIntersecting) return;
135
+ entry.target.classList.add('is-in');
136
+ observer.unobserve(entry.target);
137
+ });
138
+ }, { threshold: 0.12, rootMargin: '0px 0px -6% 0px' });
139
+ items.forEach(function (el) { observer.observe(el); });
140
+ }
141
+
142
+ /* ---------- 4. Tabs ------------------------------------------------- */
143
+ function initTabs() {
144
+ document.querySelectorAll('[data-tabs]').forEach(function (group) {
145
+ var tabs = Array.prototype.slice.call(group.querySelectorAll('[role="tab"]'));
146
+ if (!tabs.length) return;
147
+ var panels = tabs.map(function (tab) {
148
+ return document.getElementById(tab.getAttribute('aria-controls'));
149
+ });
150
+
151
+ function select(index, focus) {
152
+ tabs.forEach(function (tab, i) {
153
+ var on = i === index;
154
+ tab.setAttribute('aria-selected', on ? 'true' : 'false');
155
+ tab.tabIndex = on ? 0 : -1;
156
+ if (panels[i]) panels[i].hidden = !on;
157
+ });
158
+ if (focus && tabs[index]) tabs[index].focus();
159
+ }
160
+
161
+ tabs.forEach(function (tab, i) {
162
+ tab.addEventListener('click', function () { select(i, false); });
163
+ });
164
+
165
+ group.addEventListener('keydown', function (event) {
166
+ var current = tabs.indexOf(document.activeElement);
167
+ if (current < 0) return;
168
+ var next = current;
169
+ if (event.key === 'ArrowRight' || event.key === 'ArrowDown') next = (current + 1) % tabs.length;
170
+ else if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') next = (current - 1 + tabs.length) % tabs.length;
171
+ else if (event.key === 'Home') next = 0;
172
+ else if (event.key === 'End') next = tabs.length - 1;
173
+ else return;
174
+ event.preventDefault();
175
+ select(next, true);
176
+ });
177
+
178
+ // гарантируем, что открыта ровно одна панель
179
+ var active = Math.max(0, tabs.findIndex(function (t) { return t.getAttribute('aria-selected') === 'true'; }));
180
+ select(active, false);
181
+ });
182
+ }
183
+
184
+ /* ---------- 5. Модальные окна --------------------------------------- */
185
+ var FOCUSABLE = 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
186
+ var activeModal = null;
187
+ var lastTrigger = null;
188
+
189
+ function focusables(modal) {
190
+ return Array.prototype.slice.call(modal.querySelectorAll(FOCUSABLE)).filter(function (el) {
191
+ return el.offsetParent !== null || el === document.activeElement;
192
+ });
193
+ }
194
+
195
+ function openModal(id, trigger) {
196
+ var modal = document.getElementById(String(id).replace(/^#/, ''));
197
+ if (!modal) return;
198
+ if (activeModal) closeModal(activeModal);
199
+ lastTrigger = trigger || document.activeElement;
200
+ modal.classList.add('is-open');
201
+ modal.removeAttribute('aria-hidden');
202
+ document.body.classList.add('modal-open');
203
+ var target = modal.querySelector('[data-autofocus]') || focusables(modal)[0] || modal;
204
+ window.setTimeout(function () { target.focus(); }, 60);
205
+ activeModal = modal;
206
+ document.dispatchEvent(new CustomEvent('aurora:modalopen', { detail: { modal: modal } }));
207
+ }
208
+
209
+ function closeModal(modal) {
210
+ var el = typeof modal === 'string' ? document.getElementById(modal) : modal;
211
+ if (!el) return;
212
+ el.classList.remove('is-open');
213
+ el.setAttribute('aria-hidden', 'true');
214
+ document.body.classList.remove('modal-open');
215
+ if (activeModal === el) activeModal = null;
216
+ if (lastTrigger && typeof lastTrigger.focus === 'function') lastTrigger.focus();
217
+ lastTrigger = null;
218
+ document.dispatchEvent(new CustomEvent('aurora:modalclose', { detail: { modal: el } }));
219
+ }
220
+
221
+ function initModals() {
222
+ document.querySelectorAll('.modal').forEach(function (modal) {
223
+ modal.setAttribute('aria-hidden', modal.classList.contains('is-open') ? 'false' : 'true');
224
+ });
225
+
226
+ document.addEventListener('click', function (event) {
227
+ var opener = event.target.closest('[data-modal-open]');
228
+ if (opener) {
229
+ event.preventDefault();
230
+ openModal(opener.getAttribute('data-modal-open'), opener);
231
+ return;
232
+ }
233
+ var closer = event.target.closest('[data-modal-close]');
234
+ if (closer) {
235
+ event.preventDefault();
236
+ var targetId = closer.getAttribute('data-modal-close');
237
+ closeModal(targetId && targetId !== 'true' ? targetId : closer.closest('.modal'));
238
+ }
239
+ });
240
+
241
+ document.addEventListener('keydown', function (event) {
242
+ if (!activeModal) return;
243
+ if (event.key === 'Escape') {
244
+ event.preventDefault();
245
+ closeModal(activeModal);
246
+ return;
247
+ }
248
+ if (event.key !== 'Tab') return;
249
+ var items = focusables(activeModal);
250
+ if (!items.length) return;
251
+ var first = items[0];
252
+ var last = items[items.length - 1];
253
+ if (event.shiftKey && document.activeElement === first) {
254
+ event.preventDefault();
255
+ last.focus();
256
+ } else if (!event.shiftKey && document.activeElement === last) {
257
+ event.preventDefault();
258
+ first.focus();
259
+ }
260
+ });
261
+ }
262
+
263
+ /* ---------- 6. Мобильное меню / drawer ------------------------------ */
264
+ function initNav() {
265
+ var toggles = Array.prototype.slice.call(document.querySelectorAll('[data-nav-toggle]'));
266
+ if (!toggles.length) return;
267
+
268
+ toggles.forEach(function (toggle) {
269
+ var selector = toggle.getAttribute('data-nav-toggle');
270
+ var target = selector ? document.querySelector(selector) : document.getElementById('app-sidebar');
271
+ if (!target) return;
272
+ var scrim = document.querySelector('[data-nav-scrim]');
273
+
274
+ function set(open) {
275
+ target.classList.toggle('is-open', open);
276
+ if (scrim) scrim.classList.toggle('is-open', open);
277
+ toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
278
+ document.documentElement.classList.toggle('nav-open', open);
279
+ }
280
+
281
+ toggle.addEventListener('click', function () {
282
+ set(!target.classList.contains('is-open'));
283
+ });
284
+ if (scrim) scrim.addEventListener('click', function () { set(false); });
285
+ document.addEventListener('keydown', function (event) {
286
+ if (event.key === 'Escape' && target.classList.contains('is-open')) set(false);
287
+ });
288
+ target.querySelectorAll('a').forEach(function (link) {
289
+ link.addEventListener('click', function () { set(false); });
290
+ });
291
+ window.addEventListener('resize', function () {
292
+ if (window.innerWidth > 1024 && target.classList.contains('is-open')) set(false);
293
+ });
294
+ });
295
+ }
296
+
297
+ /* ---------- 7. Dropdown-меню ---------------------------------------- */
298
+ function initDropdowns() {
299
+ var dropdowns = Array.prototype.slice.call(document.querySelectorAll('[data-dropdown]'));
300
+ if (!dropdowns.length) return;
301
+
302
+ function closeAll(except) {
303
+ dropdowns.forEach(function (dd) {
304
+ if (dd === except) return;
305
+ dd.classList.remove('is-open');
306
+ var btn = dd.querySelector('[data-dropdown-toggle]');
307
+ if (btn) btn.setAttribute('aria-expanded', 'false');
308
+ });
309
+ }
310
+
311
+ dropdowns.forEach(function (dd) {
312
+ var btn = dd.querySelector('[data-dropdown-toggle]');
313
+ if (!btn) return;
314
+ btn.addEventListener('click', function (event) {
315
+ event.stopPropagation();
316
+ var open = !dd.classList.contains('is-open');
317
+ closeAll(dd);
318
+ dd.classList.toggle('is-open', open);
319
+ btn.setAttribute('aria-expanded', open ? 'true' : 'false');
320
+ if (open) {
321
+ var firstItem = dd.querySelector('.menu__item');
322
+ if (firstItem) firstItem.focus();
323
+ }
324
+ });
325
+ dd.addEventListener('keydown', function (event) {
326
+ if (event.key === 'Escape' && dd.classList.contains('is-open')) {
327
+ dd.classList.remove('is-open');
328
+ btn.setAttribute('aria-expanded', 'false');
329
+ btn.focus();
330
+ }
331
+ });
332
+ dd.querySelectorAll('.menu__item').forEach(function (item) {
333
+ item.addEventListener('click', function () {
334
+ dd.classList.remove('is-open');
335
+ btn.setAttribute('aria-expanded', 'false');
336
+ });
337
+ });
338
+ });
339
+
340
+ document.addEventListener('click', function (event) {
341
+ if (!event.target.closest('[data-dropdown]')) closeAll(null);
342
+ });
343
+ }
344
+
345
+ /* ---------- 8. Toast ------------------------------------------------ */
346
+ var TOAST_ICONS = {
347
+ success: 'i-check-circle',
348
+ danger: 'i-alert-circle',
349
+ warning: 'i-alert-triangle',
350
+ info: 'i-info'
351
+ };
352
+
353
+ function ensureToastRegion() {
354
+ var region = document.querySelector('.toast-region');
355
+ if (!region) {
356
+ region = document.createElement('div');
357
+ region.className = 'toast-region';
358
+ region.setAttribute('aria-live', 'polite');
359
+ region.setAttribute('aria-atomic', 'false');
360
+ document.body.appendChild(region);
361
+ }
362
+ return region;
363
+ }
364
+
365
+ function toast(options) {
366
+ var opts = typeof options === 'string' ? { title: options } : (options || {});
367
+ var variant = opts.variant || 'success';
368
+ var region = ensureToastRegion();
369
+ var el = document.createElement('div');
370
+ el.className = 'toast toast--' + variant;
371
+ el.setAttribute('role', 'status');
372
+
373
+ var icon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
374
+ icon.setAttribute('class', 'icon icon--sm toast__icon');
375
+ icon.setAttribute('viewBox', '0 0 24 24');
376
+ icon.setAttribute('aria-hidden', 'true');
377
+ var use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
378
+ use.setAttribute('href', '#' + (TOAST_ICONS[variant] || TOAST_ICONS.info));
379
+ icon.appendChild(use);
380
+
381
+ var body = document.createElement('div');
382
+ body.className = 'toast__body';
383
+ var title = document.createElement('span');
384
+ title.className = 'toast__title';
385
+ title.textContent = opts.title || 'Готово';
386
+ body.appendChild(title);
387
+ if (opts.text) {
388
+ var text = document.createElement('span');
389
+ text.className = 'toast__text';
390
+ text.textContent = opts.text;
391
+ body.appendChild(text);
392
+ }
393
+
394
+ var close = document.createElement('button');
395
+ close.type = 'button';
396
+ close.className = 'toast__close';
397
+ close.setAttribute('aria-label', 'Закрыть уведомление');
398
+ close.innerHTML = '<svg class="icon icon--sm" viewBox="0 0 24 24" aria-hidden="true"><use href="#i-x"></use></svg>';
399
+ close.addEventListener('click', function () { dismiss(); });
400
+
401
+ el.appendChild(icon);
402
+ el.appendChild(body);
403
+ el.appendChild(close);
404
+ region.appendChild(el);
405
+
406
+ var timer = 0;
407
+ function dismiss() {
408
+ if (!el.isConnected) return;
409
+ window.clearTimeout(timer);
410
+ el.classList.add('is-leaving');
411
+ window.setTimeout(function () {
412
+ if (el.parentNode) el.parentNode.removeChild(el);
413
+ }, reduceMotion.matches ? 0 : 220);
414
+ }
415
+ timer = window.setTimeout(dismiss, opts.timeout || 4200);
416
+ return el;
417
+ }
418
+
419
+ /* ---------- 9. Демо-состояния и микродетали ------------------------- */
420
+ function initDemoStates() {
421
+ // Кнопка «показать загрузку»: спиннер 1,6 с, затем toast.
422
+ document.querySelectorAll('[data-demo-loading]').forEach(function (btn) {
423
+ btn.addEventListener('click', function () {
424
+ if (btn.classList.contains('is-loading')) return;
425
+ btn.classList.add('is-loading');
426
+ btn.setAttribute('aria-busy', 'true');
427
+ var done = btn.getAttribute('data-demo-loading') || 'Готово';
428
+ var note = btn.getAttribute('data-demo-text') || 'Демонстрация состояния загрузки завершена.';
429
+ window.setTimeout(function () {
430
+ btn.classList.remove('is-loading');
431
+ btn.removeAttribute('aria-busy');
432
+ toast({ title: done, text: note, variant: 'success' });
433
+ }, 1600);
434
+ });
435
+ });
436
+
437
+ // Демо-уведомления
438
+ document.querySelectorAll('[data-demo-toast]').forEach(function (btn) {
439
+ btn.addEventListener('click', function () {
440
+ var variant = btn.getAttribute('data-demo-toast') || 'info';
441
+ toast({
442
+ title: btn.getAttribute('data-demo-toast-title') || 'Готово',
443
+ text: btn.getAttribute('data-demo-toast-text') || '',
444
+ variant: variant
445
+ });
446
+ });
447
+ });
448
+
449
+ // Клик по свотчу/токену — копирование значения
450
+ document.querySelectorAll('[data-copy]').forEach(function (item) {
451
+ item.addEventListener('click', function () {
452
+ var value = item.getAttribute('data-copy');
453
+ function feedback() {
454
+ toast({ title: 'Скопировано', text: value, variant: 'info', timeout: 2200 });
455
+ }
456
+ if (navigator.clipboard && navigator.clipboard.writeText) {
457
+ navigator.clipboard.writeText(value).then(feedback, feedback);
458
+ } else {
459
+ feedback();
460
+ }
461
+ });
462
+ });
463
+
464
+ // Год в футере
465
+ document.querySelectorAll('[data-year]').forEach(function (el) {
466
+ el.textContent = String(new Date().getFullYear());
467
+ });
468
+ }
469
+
470
+ /* ---------- 10. Sticky-шапка ---------------------------------------- */
471
+ function initStickyHeader() {
472
+ var header = document.querySelector('[data-scrolled-header]');
473
+ if (!header) return;
474
+ function onScroll() {
475
+ header.classList.toggle('is-scrolled', window.scrollY > 8);
476
+ }
477
+ window.addEventListener('scroll', onScroll, { passive: true });
478
+ onScroll();
479
+ }
480
+
481
+ /* ---------- 11. Scrollspy для оглавлений ---------------------------- */
482
+ function initScrollspy() {
483
+ document.querySelectorAll('[data-scrollspy]').forEach(function (nav) {
484
+ var links = Array.prototype.slice.call(nav.querySelectorAll('a[href^="#"]'));
485
+ var pairs = links.map(function (link) {
486
+ return { link: link, section: document.getElementById(link.getAttribute('href').slice(1)) };
487
+ }).filter(function (pair) { return pair.section; });
488
+ if (!pairs.length || !('IntersectionObserver' in window)) return;
489
+ var observer = new IntersectionObserver(function (entries) {
490
+ entries.forEach(function (entry) {
491
+ if (!entry.isIntersecting) return;
492
+ var hit = pairs.filter(function (pair) { return pair.section === entry.target; })[0];
493
+ if (!hit) return;
494
+ links.forEach(function (link) { link.removeAttribute('aria-current'); });
495
+ hit.link.setAttribute('aria-current', 'true');
496
+ });
497
+ }, { rootMargin: '-25% 0px -65% 0px', threshold: 0 });
498
+ pairs.forEach(function (pair) { observer.observe(pair.section); });
499
+ });
500
+ }
501
+
502
+ /* ---------- 12. Плавный скролл к секциям (учёт sticky-шапки) -------- */
503
+ function initAnchors() {
504
+ document.querySelectorAll('a[href^="#"]').forEach(function (link) {
505
+ link.addEventListener('click', function (event) {
506
+ var id = link.getAttribute('href');
507
+ if (id.length < 2) return;
508
+ var target = document.getElementById(id.slice(1));
509
+ if (!target) return;
510
+ event.preventDefault();
511
+ var reduce = reduceMotion.matches;
512
+ target.scrollIntoView({ behavior: reduce ? 'auto' : 'smooth', block: 'start' });
513
+ history.replaceState(null, '', id);
514
+ });
515
+ });
516
+ }
517
+
518
+ /* ---------- Запуск -------------------------------------------------- */
519
+ function init() {
520
+ initTheme();
521
+ initPreset();
522
+ syncSwatches();
523
+ initReveal();
524
+ initTabs();
525
+ initModals();
526
+ initNav();
527
+ initDropdowns();
528
+ initDemoStates();
529
+ initStickyHeader();
530
+ initScrollspy();
531
+ initAnchors();
532
+ }
533
+
534
+ if (document.readyState === 'loading') {
535
+ document.addEventListener('DOMContentLoaded', init);
536
+ } else {
537
+ init();
538
+ }
539
+
540
+ // Публичный интерфейс для страниц кита.
541
+ window.AuroraKit = {
542
+ toast: toast,
543
+ openModal: openModal,
544
+ closeModal: closeModal,
545
+ applyTheme: function (theme) { applyTheme(theme, true); },
546
+ applyPreset: function (preset) { applyPreset(preset, true); },
547
+ getTheme: getTheme,
548
+ getPreset: getPreset
549
+ };
550
+ })();