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.
- package/LICENSE +21 -0
- package/README.md +152 -2
- package/client.js +4101 -0
- package/cordis.patch.yml +5 -0
- package/docs/ARCHITECTURE.md +114 -0
- package/docs/COMPATIBILITY.md +61 -0
- package/docs/INSTALL.md +84 -0
- package/docs/PRIVACY.md +50 -0
- package/docs/ROADMAP.md +57 -0
- package/docs/TOKENS.md +118 -0
- package/docs/TROUBLESHOOTING.md +68 -0
- package/docs/images/hero.png +0 -0
- package/index.js +84 -0
- package/package.json +70 -4
- package/plugins/dsh-gkb-ru-ui/cordis.patch.yml +6 -0
- package/plugins/dsh-gkb-ru-ui/lib/client.js +1331 -0
- package/plugins/dsh-gkb-ru-ui/lib/index.js +186 -0
- package/plugins/dsh-gkb-ru-ui/lib/skills.js +570 -0
- package/plugins/dsh-gkb-ru-ui/package.json +28 -0
- package/plugins/dsh-gkb-ru-ui/screenshots/01-home-tiles-1440-light.png +0 -0
- package/plugins/dsh-gkb-ru-ui/screenshots/02-skills-1440-light.png +0 -0
- package/plugins/dsh-gkb-ru-ui/screenshots/03-skills-editor-1440-light.png +0 -0
- package/plugins/dsh-gkb-ru-ui/screenshots/04-skills-1440-dark.png +0 -0
- package/plugins/dsh-gkb-ru-ui/screenshots/05-skills-390-light.png +0 -0
- package/plugins/dsh-gkb-ru-ui/screenshots/06-home-tiles-1440-dark.png +0 -0
- package/plugins/dsh-peak-guard/README.md +70 -0
- package/plugins/dsh-peak-guard/client.js +741 -0
- package/plugins/dsh-peak-guard/cordis.patch.yml +5 -0
- package/plugins/dsh-peak-guard/icon.svg +12 -0
- package/plugins/dsh-peak-guard/index.js +2 -0
- package/plugins/dsh-peak-guard/locale/en.json +6 -0
- package/plugins/dsh-peak-guard/locale/ru.json +6 -0
- package/plugins/dsh-peak-guard/locale/zh.json +6 -0
- package/plugins/dsh-peak-guard/package.json +33 -0
- package/plugins/dsh-peak-guard/screenshots/01-real-time-peak-start.png +0 -0
- package/plugins/dsh-peak-guard/screenshots/02-real-time-peak-end.png +0 -0
- package/plugins/dsh-peak-guard/screenshots/03-peak-card-1440-light.png +0 -0
- package/plugins/dsh-peak-guard/screenshots/04-peak-card-1440-dark.png +0 -0
- package/plugins/dsh-peak-guard/screenshots/05-peak-card-390-light.png +0 -0
- package/plugins/dsh-peak-guard/screenshots/05-peak-card-768-light.png +0 -0
- package/plugins/dsh-peak-guard/screenshots/06-peak-card-390-light.png +0 -0
- package/plugins/dsh-peak-guard/screenshots/07-live-preview-check.png +0 -0
- package/plugins/dsh-peak-guard/screenshots/07-pre-peak-1440-light.png +0 -0
- package/plugins/dsh-peak-guard/screenshots/08-peak-start-1440-light.png +0 -0
- package/plugins/dsh-peak-guard/screenshots/09-peak-end-1440-light.png +0 -0
- package/plugins/dsh-peak-guard/screenshots/10-pre-peak-card-1440-light.png +0 -0
- package/plugins/dsh-peak-guard/screenshots/11-pre-peak-card-1440-dark.png +0 -0
- package/plugins/dsh-peak-guard/screenshots/12-pre-peak-card-390-light.png +0 -0
- package/plugins/dsh-peak-guard/screenshots/qa-report.json +74 -0
- package/plugins/dsh-profile-transfer/README.md +62 -0
- package/plugins/dsh-profile-transfer/bootstrap/01-INSTALL.cmd +7 -0
- package/plugins/dsh-profile-transfer/bootstrap/README-ARCHIVE.md +54 -0
- 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
- package/plugins/dsh-profile-transfer/bootstrap/install-on-clean-machine.ps1 +119 -0
- 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
- package/plugins/dsh-profile-transfer/client.js +806 -0
- package/plugins/dsh-profile-transfer/cordis.patch.yml +3 -0
- package/plugins/dsh-profile-transfer/icon.svg +13 -0
- package/plugins/dsh-profile-transfer/index.js +375 -0
- package/plugins/dsh-profile-transfer/locale/en.json +6 -0
- package/plugins/dsh-profile-transfer/locale/ru.json +6 -0
- package/plugins/dsh-profile-transfer/locale/zh.json +6 -0
- package/plugins/dsh-profile-transfer/package.json +36 -0
- package/plugins/dsh-profile-transfer/screenshots/01-settings-transfer-1440-light.png +0 -0
- package/plugins/dsh-profile-transfer/screenshots/02-settings-transfer-preview-1440-light.png +0 -0
- package/plugins/dsh-profile-transfer/screenshots/03-settings-transfer-1440-dark.png +0 -0
- package/plugins/dsh-profile-transfer/screenshots/04-settings-transfer-390-light.png +0 -0
- package/plugins/dsh-profile-transfer/screenshots/05-settings-transfer-768-light.png +0 -0
- package/plugins/dsh-profile-transfer/screenshots/06-settings-transfer-390-dark.png +0 -0
- package/plugins/dsh-profile-transfer/screenshots/07-settings-transfer-export-result.png +0 -0
- package/plugins/dsh-profile-transfer/screenshots/08-settings-transfer-workspaces-1440-light.png +0 -0
- package/plugins/dsh-profile-transfer/screenshots/09-settings-transfer-workspaces-1440-dark.png +0 -0
- package/plugins/dsh-profile-transfer/screenshots/10-settings-transfer-workspaces-390-light.png +0 -0
- package/plugins/dsh-profile-transfer/transfer.js +1004 -0
- package/plugins/dsh-project-memory/README.md +71 -0
- package/plugins/dsh-project-memory/cordis.patch.yml +4 -0
- package/plugins/dsh-project-memory/icon.svg +12 -0
- package/plugins/dsh-project-memory/index.js +1240 -0
- package/plugins/dsh-project-memory/locale/en.json +6 -0
- package/plugins/dsh-project-memory/locale/ru.json +6 -0
- package/plugins/dsh-project-memory/locale/zh.json +6 -0
- package/plugins/dsh-project-memory/package.json +26 -0
- package/plugins/dsh-session-move/README.md +67 -0
- package/plugins/dsh-session-move/client.js +719 -0
- package/plugins/dsh-session-move/cordis.patch.yml +5 -0
- package/plugins/dsh-session-move/icon.svg +14 -0
- package/plugins/dsh-session-move/index.js +497 -0
- package/plugins/dsh-session-move/locale/en.json +6 -0
- package/plugins/dsh-session-move/locale/ru.json +6 -0
- package/plugins/dsh-session-move/locale/zh.json +6 -0
- package/plugins/dsh-session-move/package.json +31 -0
- package/plugins/dsh-session-move/screenshots/01-row-menu-1440-light.png +0 -0
- package/plugins/dsh-session-move/screenshots/02-dialog-1440-light.png +0 -0
- package/plugins/dsh-session-move/screenshots/03-dialog-390-light.png +0 -0
- package/plugins/dsh-session-move/screenshots/04-dialog-1440-dark.png +0 -0
- package/plugins/dsh-session-move/screenshots/05-drag-highlight-1440-light.png +0 -0
- package/plugins/dsh-session-move/screenshots/06-drop-ungrouped-highlight.png +0 -0
- package/plugins/dsh-session-move/screenshots/07-after-drop-ungrouped.png +0 -0
- package/plugins/dsh-session-move/screenshots/08-move-dialog.png +0 -0
- package/plugins/dsh-session-move/screenshots/09-moved-to-second-workspace.png +0 -0
- package/plugins/dsh-session-move/screenshots/qa-report.json +62 -0
- package/plugins/dsh-skill-autopilot/cordis.patch.yml +3 -0
- package/plugins/dsh-skill-autopilot/index.js +444 -0
- package/plugins/dsh-skill-autopilot/package.json +19 -0
- package/plugins/dsh-token-lab/cordis.patch.yml +3 -0
- package/plugins/dsh-token-lab/lib/client.js +504 -0
- package/plugins/dsh-token-lab/lib/index.js +275 -0
- package/plugins/dsh-token-lab/package.json +26 -0
- package/plugins/dsh-token-lab/screenshots/01-token-lab-1440-light.png +0 -0
- package/plugins/dsh-token-lab/screenshots/02-token-lab-1440-dark.png +0 -0
- package/skills/code-review-checklist/SKILL.md +55 -0
- package/skills/content-writing/README.md +87 -0
- package/skills/content-writing/SKILL.md +85 -0
- package/skills/content-writing/assets/checklists/fact-check.md +53 -0
- package/skills/content-writing/assets/checklists/publish.md +65 -0
- package/skills/content-writing/assets/checklists/social.md +40 -0
- package/skills/content-writing/assets/templates/article.md +47 -0
- package/skills/content-writing/assets/templates/brief.md +44 -0
- package/skills/content-writing/assets/templates/doctor-card.md +41 -0
- package/skills/content-writing/assets/templates/image-prompts.md +128 -0
- package/skills/content-writing/assets/templates/post-telegram.md +36 -0
- package/skills/content-writing/assets/templates/post-vk.md +42 -0
- package/skills/content-writing/assets/templates/press-release.md +56 -0
- package/skills/content-writing/assets/templates/science-pop-note.md +55 -0
- package/skills/content-writing/assets/templates/service-card.md +46 -0
- package/skills/content-writing/references/anti-ai-style.md +248 -0
- package/skills/content-writing/references/editing.md +185 -0
- package/skills/content-writing/references/fact-checking.md +205 -0
- package/skills/content-writing/references/government-medical.md +246 -0
- package/skills/content-writing/references/images.md +212 -0
- package/skills/content-writing/references/journalism.md +252 -0
- package/skills/content-writing/references/process.md +123 -0
- package/skills/content-writing/references/quick-recipes.md +99 -0
- package/skills/content-writing/references/rules.md +85 -0
- package/skills/content-writing/references/science-popular.md +218 -0
- package/skills/content-writing/references/seo-content.md +172 -0
- package/skills/content-writing/references/social-media.md +253 -0
- package/skills/content-writing/references/sources.md +49 -0
- package/skills/content-writing/references/templates.md +291 -0
- package/skills/context-economy/SKILL.md +60 -0
- package/skills/context-economy/references/long-session.md +35 -0
- package/skills/context-economy/references/token-math.md +42 -0
- package/skills/context-economy/references/tool-recipes.md +34 -0
- package/skills/database-safety/SKILL.md +47 -0
- package/skills/debugging-playbook/SKILL.md +42 -0
- package/skills/design-critique/SKILL.md +65 -0
- package/skills/design-critique/references/a11y.md +25 -0
- package/skills/design-critique/references/diagnoses.md +33 -0
- package/skills/design-critique/references/quick-tests.md +30 -0
- package/skills/design-critique/references/report-template.md +63 -0
- package/skills/design-critique/references/rubric-fast.md +73 -0
- package/skills/dev-workflow/SKILL.md +48 -0
- package/skills/dev-workflow/references/definition-of-done.md +44 -0
- package/skills/dev-workflow/references/memory-and-boundaries.md +31 -0
- package/skills/dev-workflow/references/stages.md +67 -0
- package/skills/git-and-ci/SKILL.md +60 -0
- package/skills/pg-upgrade-verify/SKILL.md +67 -0
- package/skills/project-deep-dive/SKILL.md +45 -0
- package/skills/project-deep-dive/references/recon-commands.md +90 -0
- package/skills/project-deep-dive/references/section-templates.md +104 -0
- package/skills/project-deep-dive/references/tool-and-process.md +86 -0
- package/skills/project-memory-maintenance/SKILL.md +55 -0
- package/skills/project-memory-maintenance/references/api-and-checklist.md +99 -0
- package/skills/project-memory-maintenance/references/journal-template.md +50 -0
- package/skills/project-memory-maintenance/references/section-rules.md +59 -0
- package/skills/release-and-deploy/SKILL.md +53 -0
- package/skills/requirements-and-planning/SKILL.md +49 -0
- package/skills/requirements-and-planning/references/antipatterns-and-checklist.md +20 -0
- package/skills/requirements-and-planning/references/process-steps.md +52 -0
- package/skills/requirements-and-planning/references/templates-and-estimates.md +29 -0
- package/skills/security-review/SKILL.md +40 -0
- package/skills/seo/README.md +60 -0
- package/skills/seo/SKILL.md +77 -0
- package/skills/seo/assets/README.md +66 -0
- package/skills/seo/assets/scripts/LICENSE-playwright-core.txt +202 -0
- package/skills/seo/assets/scripts/README.md +179 -0
- package/skills/seo/assets/scripts/lib/args.mjs +105 -0
- package/skills/seo/assets/scripts/lib/browser.mjs +620 -0
- package/skills/seo/assets/scripts/lib/zip.mjs +191 -0
- package/skills/seo/assets/scripts/seo-audit.mjs +1675 -0
- package/skills/seo/assets/snippets/jsonld-breadcrumb.json +30 -0
- package/skills/seo/assets/snippets/jsonld-faq.json +39 -0
- package/skills/seo/assets/snippets/jsonld-medical-clinic.json +49 -0
- package/skills/seo/assets/snippets/jsonld-medical-webpage.json +33 -0
- package/skills/seo/assets/snippets/jsonld-organization.json +74 -0
- package/skills/seo/assets/snippets/jsonld-physician.json +46 -0
- package/skills/seo/assets/snippets/meta.blade.php +61 -0
- package/skills/seo/assets/snippets/robots.txt +61 -0
- package/skills/seo/assets/snippets/sitemap-urlset-example.xml +72 -0
- package/skills/seo/assets/snippets/sitemap.xml +36 -0
- package/skills/seo/references/antipatterns.md +66 -0
- package/skills/seo/references/audit-checklist.md +319 -0
- package/skills/seo/references/content-seo.md +204 -0
- package/skills/seo/references/eeat-medical.md +219 -0
- package/skills/seo/references/measurement.md +250 -0
- package/skills/seo/references/on-page.md +214 -0
- package/skills/seo/references/page-templates.md +56 -0
- package/skills/seo/references/stack-recipes.md +695 -0
- package/skills/seo/references/structured-data.md +487 -0
- package/skills/seo/references/technical-seo.md +296 -0
- package/skills/service-desk-conventions/SKILL.md +52 -0
- package/skills/service-desk-db-safety/SKILL.md +63 -0
- package/skills/service-desk-release/SKILL.md +61 -0
- package/skills/service-desk-testing/SKILL.md +61 -0
- package/skills/service-desk-ui/SKILL.md +52 -0
- package/skills/skills-router/SKILL.md +53 -0
- package/skills/skills-router/references/applying-skills.md +25 -0
- package/skills/skills-router/references/routing-matrix.md +52 -0
- package/skills/testing-strategy/SKILL.md +52 -0
- package/skills/ui-design-system/SKILL.md +50 -0
- package/skills/ui-design-system/references/accessibility-and-responsive.md +50 -0
- package/skills/ui-design-system/references/tokens-and-components.md +67 -0
- package/skills/ui-design-system/references/visual-qa.md +44 -0
- package/skills/web-research/SKILL.md +47 -0
- package/skills/web-research/references/answer-and-citations.md +60 -0
- package/skills/web-research/references/query-recipes.md +44 -0
- package/skills/wow-design/SKILL.md +89 -0
- package/skills/wow-design/assets/kit/README.md +195 -0
- package/skills/wow-design/assets/kit/assets/css/base.css +158 -0
- package/skills/wow-design/assets/kit/assets/css/components.css +1001 -0
- package/skills/wow-design/assets/kit/assets/css/fonts.css +73 -0
- package/skills/wow-design/assets/kit/assets/css/pages.css +737 -0
- package/skills/wow-design/assets/kit/assets/css/tokens.css +218 -0
- package/skills/wow-design/assets/kit/assets/fonts/LICENSE-golos-text.txt +93 -0
- package/skills/wow-design/assets/kit/assets/fonts/LICENSE-lora.txt +93 -0
- package/skills/wow-design/assets/kit/assets/fonts/LICENSE-unbounded.txt +93 -0
- package/skills/wow-design/assets/kit/assets/fonts/golos-text-cyrillic-400-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/golos-text-cyrillic-500-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/golos-text-cyrillic-600-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/golos-text-cyrillic-700-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/golos-text-latin-400-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/golos-text-latin-500-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/golos-text-latin-600-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/golos-text-latin-700-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/lora-cyrillic-400-italic.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/lora-cyrillic-400-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/lora-cyrillic-500-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/lora-cyrillic-600-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/lora-latin-400-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/lora-latin-500-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/lora-latin-600-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/unbounded-cyrillic-400-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/unbounded-cyrillic-500-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/unbounded-cyrillic-600-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/unbounded-latin-400-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/unbounded-latin-500-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/fonts/unbounded-latin-600-normal.woff2 +0 -0
- package/skills/wow-design/assets/kit/assets/js/kit.js +550 -0
- package/skills/wow-design/assets/kit/pages/dashboard.html +539 -0
- package/skills/wow-design/assets/kit/pages/hospital.html +430 -0
- package/skills/wow-design/assets/kit/showcase.html +1164 -0
- package/skills/wow-design/assets/scripts/LICENSE-axe-core.txt +362 -0
- package/skills/wow-design/assets/scripts/LICENSE-playwright-core.txt +202 -0
- package/skills/wow-design/assets/scripts/README.md +312 -0
- package/skills/wow-design/assets/scripts/audit.mjs +1200 -0
- package/skills/wow-design/assets/scripts/capture.mjs +337 -0
- package/skills/wow-design/assets/scripts/package.json +30 -0
- package/skills/wow-design/references/anti-patterns.md +252 -0
- package/skills/wow-design/references/critique-rubric.md +262 -0
- package/skills/wow-design/references/design-brief-template.md +48 -0
- package/skills/wow-design/references/inspiration.md +203 -0
- package/skills/wow-design/references/presets.md +99 -0
- package/skills/wow-design/references/principles.md +371 -0
- package/skills/wow-design/references/quick-presets.md +50 -0
- package/skills/wow-design/references/report-template.md +21 -0
- package/skills/wow-design/references/stack-recipes.md +96 -0
- package/skills/wow-design/references/visual-qa.md +82 -0
- package/skills/wow-design/references/wow-levers.md +43 -0
- 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
|
+
})();
|