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:
parent
9ac311f138
commit
002b55c3c0
@ -37,6 +37,7 @@
|
|||||||
"@bytelyst/notifications-ui": "workspace:*",
|
"@bytelyst/notifications-ui": "workspace:*",
|
||||||
"@bytelyst/telemetry-client": "workspace:*",
|
"@bytelyst/telemetry-client": "workspace:*",
|
||||||
"@bytelyst/logger": "workspace:*",
|
"@bytelyst/logger": "workspace:*",
|
||||||
|
"@bytelyst/motion": "workspace:*",
|
||||||
"@bytelyst/ui": "workspace:*",
|
"@bytelyst/ui": "workspace:*",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"next": "16.1.6",
|
"next": "16.1.6",
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { useEffect, useState, useCallback, useMemo } from 'react';
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { DataTable, type ColumnDef } from '@bytelyst/data-table';
|
import { DataTable, type ColumnDef } from '@bytelyst/data-table';
|
||||||
import { PageHeader, LoadingSpinner } from '@bytelyst/dashboard-components';
|
import { PageHeader, LoadingSpinner } from '@bytelyst/dashboard-components';
|
||||||
|
import { Reveal } from '@bytelyst/motion';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Input,
|
Input,
|
||||||
@ -290,17 +291,19 @@ export default function ItemsListPage() {
|
|||||||
<LoadingSpinner />
|
<LoadingSpinner />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<DataTable
|
<Reveal>
|
||||||
ariaLabel="Tracker items"
|
<DataTable
|
||||||
columns={columns}
|
ariaLabel="Tracker items"
|
||||||
data={items}
|
columns={columns}
|
||||||
getRowId={item => item.id}
|
data={items}
|
||||||
enableFilter={false}
|
getRowId={item => item.id}
|
||||||
enableSorting
|
enableFilter={false}
|
||||||
enablePagination
|
enableSorting
|
||||||
pageSize={15}
|
enablePagination
|
||||||
emptyState="No items found. Create one to get started."
|
pageSize={15}
|
||||||
/>
|
emptyState="No items found. Create one to get started."
|
||||||
|
/>
|
||||||
|
</Reveal>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Create modal */}
|
{/* Create modal */}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { PageHeader, LoadingSpinner } from '@bytelyst/dashboard-components';
|
import { PageHeader, LoadingSpinner } from '@bytelyst/dashboard-components';
|
||||||
import { KpiCard } from '@bytelyst/data-viz';
|
import { KpiCard } from '@bytelyst/data-viz';
|
||||||
|
import { Reveal, NumberFlow } from '@bytelyst/motion';
|
||||||
import { Skeleton, toast } from '@/components/ui/Primitives';
|
import { Skeleton, toast } from '@/components/ui/Primitives';
|
||||||
import { useAuth } from '@/lib/auth-context';
|
import { useAuth } from '@/lib/auth-context';
|
||||||
import { getStats, type TrackerStats } from '@/lib/tracker-client';
|
import { getStats, type TrackerStats } from '@/lib/tracker-client';
|
||||||
@ -39,14 +40,22 @@ export default function DashboardOverview() {
|
|||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{/* KPI row */}
|
{/* KPI row */}
|
||||||
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
<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} />
|
{ label: `Total · ${stats.productId}`, value: kpis.total },
|
||||||
<KpiCard label="In Progress" value={kpis.inProgress} />
|
{ label: 'Open', value: kpis.open },
|
||||||
<KpiCard label="Done" value={kpis.done} />
|
{ 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>
|
</div>
|
||||||
|
|
||||||
{/* Charts */}
|
{/* Charts */}
|
||||||
<OverviewCharts stats={stats} />
|
<Reveal delay={120}>
|
||||||
|
<OverviewCharts stats={stats} />
|
||||||
|
</Reveal>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex justify-center py-10">
|
<div className="flex justify-center py-10">
|
||||||
|
|||||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@ -273,6 +273,9 @@ importers:
|
|||||||
'@bytelyst/logger':
|
'@bytelyst/logger':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/logger
|
version: link:../../packages/logger
|
||||||
|
'@bytelyst/motion':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../../packages/motion
|
||||||
'@bytelyst/notifications-ui':
|
'@bytelyst/notifications-ui':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/notifications-ui
|
version: link:../../packages/notifications-ui
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user