Files
CA/frontend/src/components/ui/Panel.tsx
Akiba So 3db3b12480 feat(frontend): Phase 1 UX foundation — react-router v6 + responsive AppShell
Atomic foundation for the consensus-approved UX modernization (makes the
platform URL-addressable, refresh-safe, and mobile-usable for hospital demos).

- Migrate hand-rolled useState page switching → react-router v6 (routes.tsx,
  thin App.tsx auth gate, NavLink SideNav, lazy+Suspense per route)
- Add responsive AppShell: persistent rail (lg:) ⇄ off-canvas drawer + hamburger
  (<lg); kills hardcoded ml-[200px]; usable at 375px
- Add ui primitive kit (Skeleton/LoadingState/EmptyState/Card/Panel/Segmented)
- Sweep all raw "加载中..." text loaders → skeleton primitives (G4)
- Centralize test ids (utils/testids.ts); rewrite e2e for URL nav (17/17 pass:
  deep-link, refresh-preserves-page, back, 375px drawer/no-scroll)
- Harden DemographicAnalysis against API shape mismatch (defensive normalize)
- gitignore playwright-report/ and test-results/

Gates: tsc --noEmit 0 · pnpm build ok · e2e 17/17 · grep 加载中 zero outside ui/

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 20:12:13 +08:00

23 lines
406 B
TypeScript

import React, { memo } from 'react';
export const Panel = memo(function Panel({
children,
className,
testid,
}: {
children: React.ReactNode;
className?: string;
testid?: string;
}): JSX.Element {
return (
<div
data-testid={testid}
className={['bg-bg-hover/50 rounded-md p-3', className]
.filter(Boolean)
.join(' ')}
>
{children}
</div>
);
});