Limit motion to one animated element per page (DS-2)
- Course navigation: only the completion percent animates; the "N of M lessons" counter is static. NumberFlow is enabled only in the visible copy of the navigation (drawer on phones, sidebar otherwise). - globals.css: disable Vaul drawer and overlay animation under prefers-reduced-motion. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -298,3 +298,14 @@
|
|||||||
margin: 0 0 0.5rem;
|
margin: 0 0 0.5rem;
|
||||||
}
|
}
|
||||||
.comment-md pre code { background: none; padding: 0; }
|
.comment-md pre code { background: none; padding: 0; }
|
||||||
|
|
||||||
|
/* DS-2 §8: with prefers-reduced-motion there is no motion at all.
|
||||||
|
Vaul animates the sheet via injected CSS and inline transitions while
|
||||||
|
dragging — !important overrides both, the sheet just appears/disappears. */
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
[data-vaul-drawer],
|
||||||
|
[data-vaul-overlay] {
|
||||||
|
animation: none !important;
|
||||||
|
transition: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import Link from "next/link";
|
|||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Menu, X } from "lucide-react";
|
import { Menu, X } from "lucide-react";
|
||||||
import NumberFlow, { NumberFlowGroup } from "@number-flow/react";
|
import NumberFlow from "@number-flow/react";
|
||||||
import { AubadeDrawer, ResponsiveDialogTitle } from "@/components/shared/responsive-dialog";
|
import { AubadeDrawer, ResponsiveDialogTitle } from "@/components/shared/responsive-dialog";
|
||||||
import { useIsMobile } from "@/hooks/use-media-query";
|
import { useIsMobile } from "@/hooks/use-media-query";
|
||||||
|
|
||||||
@@ -30,11 +30,14 @@ function CourseNavBody({
|
|||||||
completedLessonIds,
|
completedLessonIds,
|
||||||
pathname,
|
pathname,
|
||||||
onNavigate,
|
onNavigate,
|
||||||
|
animateProgress,
|
||||||
}: {
|
}: {
|
||||||
course: Course;
|
course: Course;
|
||||||
completedLessonIds: Set<string>;
|
completedLessonIds: Set<string>;
|
||||||
pathname: string;
|
pathname: string;
|
||||||
onNavigate: () => void;
|
onNavigate: () => void;
|
||||||
|
/** DS-2: one animated moment per page — only the visible copy animates. */
|
||||||
|
animateProgress: boolean;
|
||||||
}) {
|
}) {
|
||||||
const totalLessons = course.modules.reduce((s, m) => s + m.lessons.length, 0);
|
const totalLessons = course.modules.reduce((s, m) => s + m.lessons.length, 0);
|
||||||
const completedCount = course.modules
|
const completedCount = course.modules
|
||||||
@@ -66,14 +69,18 @@ function CourseNavBody({
|
|||||||
{totalLessons > 0 && (
|
{totalLessons > 0 && (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center justify-between mb-1">
|
<div className="flex items-center justify-between mb-1">
|
||||||
<NumberFlowGroup>
|
<span className="text-xs" style={{ color: "var(--muted-foreground)" }}>
|
||||||
<span className="text-xs" style={{ color: "var(--muted-foreground)" }}>
|
{completedCount} из {totalLessons} уроков
|
||||||
<NumberFlow value={completedCount} respectMotionPreference /> из {totalLessons} уроков
|
</span>
|
||||||
</span>
|
<span className="text-xs font-bold" style={{ color: "var(--foreground)" }}>
|
||||||
<span className="text-xs font-bold" style={{ color: "var(--foreground)" }}>
|
{/* The page's single animated moment (DS-2 §8); static under reduced motion. */}
|
||||||
<NumberFlow value={progressPct} suffix="%" respectMotionPreference />
|
<NumberFlow
|
||||||
</span>
|
value={progressPct}
|
||||||
</NumberFlowGroup>
|
suffix="%"
|
||||||
|
animated={animateProgress}
|
||||||
|
respectMotionPreference
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="h-1.5 w-full"
|
className="h-1.5 w-full"
|
||||||
@@ -207,6 +214,7 @@ export function CourseSidebar({
|
|||||||
completedLessonIds={completedLessonIds}
|
completedLessonIds={completedLessonIds}
|
||||||
pathname={pathname}
|
pathname={pathname}
|
||||||
onNavigate={() => setOpen(false)}
|
onNavigate={() => setOpen(false)}
|
||||||
|
animateProgress={!isMobile}
|
||||||
/>
|
/>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
@@ -218,6 +226,7 @@ export function CourseSidebar({
|
|||||||
completedLessonIds={completedLessonIds}
|
completedLessonIds={completedLessonIds}
|
||||||
pathname={pathname}
|
pathname={pathname}
|
||||||
onNavigate={() => setSheetOpen(false)}
|
onNavigate={() => setSheetOpen(false)}
|
||||||
|
animateProgress
|
||||||
/>
|
/>
|
||||||
</AubadeDrawer>
|
</AubadeDrawer>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user