feat(tracker-web): reduced-motion-aware motion polish (UX-7)

Add @bytelyst/motion (workspace:* + minimal lockfile importer entry).
Apply Reveal to the dashboard overview cards/charts (staggered) and the
items DataTable, and NumberFlow to the overview KPI totals. All motion
primitives no-op under prefers-reduced-motion.

The public /roadmap is intentionally left without entrance motion: the
offline @axe-core gate scans the page synchronously and the Reveal
transient sub-1 opacity trips color-contrast (a hard CC.4 a11y gate). The
dashboard/items surfaces are auth-gated and not axe-scanned, so they keep
the motion.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
saravanakumardb1 2026-05-29 07:12:31 -07:00
parent 9ac311f138
commit 002b55c3c0
4 changed files with 32 additions and 16 deletions

View File

@ -37,6 +37,7 @@
"@bytelyst/notifications-ui": "workspace:*",
"@bytelyst/telemetry-client": "workspace:*",
"@bytelyst/logger": "workspace:*",
"@bytelyst/motion": "workspace:*",
"@bytelyst/ui": "workspace:*",
"clsx": "^2.1.1",
"next": "16.1.6",

View File

@ -4,6 +4,7 @@ import { useEffect, useState, useCallback, useMemo } from 'react';
import Link from 'next/link';
import { DataTable, type ColumnDef } from '@bytelyst/data-table';
import { PageHeader, LoadingSpinner } from '@bytelyst/dashboard-components';
import { Reveal } from '@bytelyst/motion';
import {
Button,
Input,
@ -290,17 +291,19 @@ export default function ItemsListPage() {
<LoadingSpinner />
</div>
) : (
<DataTable
ariaLabel="Tracker items"
columns={columns}
data={items}
getRowId={item => item.id}
enableFilter={false}
enableSorting
enablePagination
pageSize={15}
emptyState="No items found. Create one to get started."
/>
<Reveal>
<DataTable
ariaLabel="Tracker items"
columns={columns}
data={items}
getRowId={item => item.id}
enableFilter={false}
enableSorting
enablePagination
pageSize={15}
emptyState="No items found. Create one to get started."
/>
</Reveal>
)}
{/* Create modal */}

View File

@ -4,6 +4,7 @@ import { useEffect, useState } from 'react';
import dynamic from 'next/dynamic';
import { PageHeader, LoadingSpinner } from '@bytelyst/dashboard-components';
import { KpiCard } from '@bytelyst/data-viz';
import { Reveal, NumberFlow } from '@bytelyst/motion';
import { Skeleton, toast } from '@/components/ui/Primitives';
import { useAuth } from '@/lib/auth-context';
import { getStats, type TrackerStats } from '@/lib/tracker-client';
@ -39,14 +40,22 @@ export default function DashboardOverview() {
<div className="space-y-4">
{/* KPI row */}
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
<KpiCard label={`Total · ${stats.productId}`} value={kpis.total} />
<KpiCard label="Open" value={kpis.open} />
<KpiCard label="In Progress" value={kpis.inProgress} />
<KpiCard label="Done" value={kpis.done} />
{[
{ label: `Total · ${stats.productId}`, value: kpis.total },
{ label: 'Open', value: kpis.open },
{ label: 'In Progress', value: kpis.inProgress },
{ label: 'Done', value: kpis.done },
].map((k, i) => (
<Reveal key={k.label} delay={i * 60}>
<KpiCard label={k.label} value={<NumberFlow value={k.value} />} />
</Reveal>
))}
</div>
{/* Charts */}
<OverviewCharts stats={stats} />
<Reveal delay={120}>
<OverviewCharts stats={stats} />
</Reveal>
</div>
) : (
<div className="flex justify-center py-10">

3
pnpm-lock.yaml generated
View File

@ -273,6 +273,9 @@ importers:
'@bytelyst/logger':
specifier: workspace:*
version: link:../../packages/logger
'@bytelyst/motion':
specifier: workspace:*
version: link:../../packages/motion
'@bytelyst/notifications-ui':
specifier: workspace:*
version: link:../../packages/notifications-ui