Animate page navigation with content

This commit is contained in:
Server 2026-08-14 11:45:35 +00:00
parent 624f62f25e
commit 825f261354
6 changed files with 19 additions and 12 deletions

View file

@ -17,7 +17,7 @@ UI не содержит языко-зависимых служебных под
На десктопе компактный header содержит toggle боковой панели, полное название документации, поиск и переключатель темы. Sidebar по умолчанию открыт, его состояние не сохраняется между загрузками. Поисковый placeholder медленно печатает первые слова случайного названия, добавляет троеточие только в конце и сохраняет готовый текст 5 секунд; при вводе поле раскрывает ранжированные результаты вниз. Проверка manifest выполняется автоматически в фоне без отдельной кнопки обновления.
На мобильных устройствах используется viewport `100dvh` и нижний dock. Кнопка `☰` заменяет содержимое страницы копией desktop-sidebar, которая выезжает с левой границы экрана. Ввод в нижний поиск заменяет содержимое результатами, расположенными снизу вверх по релевантности. При переходе между страницами контент плавно смещается на 30 px по направлению навигации и меняет прозрачность; тема и обновление на мобильном скрыты.
На мобильных устройствах используется viewport `100dvh` и нижний dock. Кнопка `☰` заменяет содержимое страницы копией desktop-sidebar, которая выезжает с левой границы экрана. Ввод в нижний поиск заменяет содержимое результатами, расположенными снизу вверх по релевантности. При переходе между страницами контент вместе с кнопками предыдущей и следующей страницы плавно смещается на 30 px по направлению навигации и меняет прозрачность; тема и обновление на мобильном скрыты.
## Установка из Git

View file

@ -1,3 +1,3 @@
"""Single source of truth for the SharedDocsLib package version."""
__version__ = "0.4.0"
__version__ = "0.4.1"

View file

@ -103,6 +103,7 @@ body.desktop-sidebar-collapsed .desktop-sidebar { width: 0; flex-basis: 0; paddi
@keyframes refresh-spin { to { transform: rotate(360deg); } }
.page-surface { min-height: 0; flex: 1; overflow-x: hidden; overflow-y: auto; overscroll-behavior-y: contain; border-radius: 36px 0 0; background: var(--surface); scroll-behavior: smooth; -webkit-overflow-scrolling: touch; }
.page-transition { min-width: 0; }
.content { width: min(1120px, calc(100% - 72px)); margin: 0 auto; padding: 42px 0 44px; outline: none; }
.content > :first-child { margin-top: 0; }
.content h1 { margin: 0 0 1.5rem; font-size: clamp(2.15rem, 2.7vw, 3.35rem); font-weight: 400; line-height: 1.08; letter-spacing: -.035em; }

View file

@ -22,6 +22,7 @@
mobileSearchButton: document.getElementById("mobile-search-button"),
mobileSearchResults: document.getElementById("mobile-search-results"),
content: document.getElementById("content"),
pageTransition: document.getElementById("page-transition"),
pageSurface: document.getElementById("page-surface"),
previous: document.getElementById("previous-page"),
next: document.getElementById("next-page"),
@ -384,13 +385,13 @@
const currentIndex = manifest.pages.findIndex((candidate) => candidate.number === currentNumber);
const direction = currentIndex >= 0 && index < currentIndex ? -1 : 1;
const animate = currentIndex >= 0 && !reducedMotion.matches && typeof elements.content.animate === "function";
const animate = currentIndex >= 0 && !reducedMotion.matches && typeof elements.pageTransition.animate === "function";
const transitionId = ++pageTransitionId;
pageAnimation?.cancel();
pageAnimation = null;
if (animate) {
const outgoing = elements.content.animate(
const outgoing = elements.pageTransition.animate(
[
{ opacity: 1, transform: "translateX(0)" },
{ opacity: 0, transform: `translateX(${-30 * direction}px)` },
@ -405,7 +406,7 @@
applyPage(page, index);
if (!animate || transitionId !== pageTransitionId) return;
const incoming = elements.content.animate(
const incoming = elements.pageTransition.animate(
[
{ opacity: 0, transform: `translateX(${30 * direction}px)` },
{ opacity: 1, transform: "translateX(0)" },

View file

@ -51,11 +51,13 @@
<section class="workspace">
<section id="page-surface" class="page-surface">
<main id="content" class="content" tabindex="-1"></main>
<footer class="page-navigation">
<button id="previous-page" class="nav-card"></button>
<button id="next-page" class="nav-card"></button>
</footer>
<div id="page-transition" class="page-transition">
<main id="content" class="content" tabindex="-1"></main>
<footer class="page-navigation">
<button id="previous-page" class="nav-card"></button>
<button id="next-page" class="nav-card"></button>
</footer>
</div>
</section>
<section id="mobile-menu-view" class="mobile-view mobile-menu-view">

View file

@ -97,7 +97,7 @@ def test_all_endpoints_and_self_contained_build(tmp_path):
assert html_response.status_code == 200
assert "http://127.0.0.1:9000/manifest.json" in html
assert "http://127.0.0.1:9000/version" in html
assert 'globalThis.COMPILED_FROM_VERSION = "0.4.0";' in html
assert 'globalThis.COMPILED_FROM_VERSION = "0.4.1";' in html
assert ".content { --custom-test: yes; }" in html
assert r'document.body.dataset.customTest = \"yes\";' in html
assert 'id="docslib-loading"' in html
@ -177,6 +177,7 @@ def test_all_endpoints_and_self_contained_build(tmp_path):
assert "--shell: #000000" in html
assert 'id="desktop-search-input"' in html
assert '<header class="desktop-header">' in html
assert 'id="page-transition" class="page-transition"' in html
assert 'id="desktop-sidebar-toggle"' in html
assert 'aria-label="" aria-expanded="true">☰</button>' in html
assert '<aside class="desktop-sidebar">' in html
@ -213,6 +214,8 @@ def test_all_endpoints_and_self_contained_build(tmp_path):
assert "animation: mobile-menu-enter .26s" in html
assert "transform: translateX(-100%)" in html
assert "const direction = currentIndex >= 0 && index < currentIndex ? -1 : 1" in system_js
assert 'const outgoing = elements.pageTransition.animate(' in system_js
assert 'const incoming = elements.pageTransition.animate(' in system_js
assert 'transform: `translateX(${-30 * direction}px)`' in system_js
assert 'transform: `translateX(${30 * direction}px)`' in system_js
assert 'opacity: 0' in system_js
@ -232,7 +235,7 @@ def test_all_endpoints_and_self_contained_build(tmp_path):
def test_build_writes_static_bundle(tmp_path):
assert __version__ == "0.4.0"
assert __version__ == "0.4.1"
@Page("1", "Static page")
def static_page():