US-032: Reduced motion audit, final cleanup, and visual review
- Add prefers-reduced-motion overrides for SubNav button transitions - Add prefers-reduced-motion overrides for smooth scroll behavior - Fix connection status dot/text transitions to respect reduced motion - Create ProjectDetail.tsx renderer and wire into DetailPanel - Remove placeholder fallback from DetailPanel (all types now covered) - Delete unused files: useBreakpoint.ts, profile.ts - Remove unused legacy --pmr-* CSS variables (18 properties) - Remove unused .pmr-theme CSS utility class
This commit is contained in:
@@ -9,6 +9,7 @@ import { ConsultationDetail } from './detail/ConsultationDetail'
|
||||
import { SkillDetail } from './detail/SkillDetail'
|
||||
import { SkillsAllDetail } from './detail/SkillsAllDetail'
|
||||
import { EducationDetail } from './detail/EducationDetail'
|
||||
import { ProjectDetail } from './detail/ProjectDetail'
|
||||
|
||||
// Width mapping from content type
|
||||
const widthMap: Record<DetailPanelContent['type'], 'narrow' | 'wide'> = {
|
||||
@@ -221,29 +222,7 @@ export function DetailPanel() {
|
||||
{content.type === 'skill' && <SkillDetail skill={content.skill} />}
|
||||
{content.type === 'skills-all' && <SkillsAllDetail category={content.category} />}
|
||||
{content.type === 'education' && <EducationDetail document={content.document} />}
|
||||
|
||||
{/* Other content types - placeholder for future stories */}
|
||||
{content.type !== 'kpi' &&
|
||||
content.type !== 'consultation' &&
|
||||
content.type !== 'career-role' &&
|
||||
content.type !== 'skill' &&
|
||||
content.type !== 'skills-all' &&
|
||||
content.type !== 'education' && (
|
||||
<div
|
||||
style={{
|
||||
fontFamily: 'var(--font-ui)',
|
||||
color: 'var(--text-secondary)',
|
||||
fontSize: '14px',
|
||||
}}
|
||||
>
|
||||
<p>
|
||||
Detail panel for: <strong>{content.type}</strong>
|
||||
</p>
|
||||
<p style={{ marginTop: '8px', fontSize: '12px' }}>
|
||||
Content renderers will be implemented in subsequent user stories.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{content.type === 'project' && <ProjectDetail investigation={content.investigation} />}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -370,7 +370,7 @@ export function LoginScreen({ onComplete }: LoginScreenProps) {
|
||||
height: '6px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: connectionState === 'connected' ? '#059669' : '#DC2626',
|
||||
transition: 'background-color 300ms ease',
|
||||
transition: prefersReducedMotion ? 'none' : 'background-color 300ms ease',
|
||||
flexShrink: 0,
|
||||
}}
|
||||
/>
|
||||
@@ -379,7 +379,7 @@ export function LoginScreen({ onComplete }: LoginScreenProps) {
|
||||
fontFamily: "var(--font-geist-mono, 'Geist Mono', monospace)",
|
||||
fontSize: '10px',
|
||||
color: connectionState === 'connected' ? '#059669' : '#8DA8A5',
|
||||
transition: 'color 300ms ease',
|
||||
transition: prefersReducedMotion ? 'none' : 'color 300ms ease',
|
||||
}}
|
||||
>
|
||||
{connectionState === 'connected'
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
import { ExternalLink } from 'lucide-react'
|
||||
import type { Investigation } from '@/types/pmr'
|
||||
|
||||
interface ProjectDetailProps {
|
||||
investigation: Investigation
|
||||
}
|
||||
|
||||
const statusColorMap: Record<Investigation['status'], string> = {
|
||||
Complete: '#059669',
|
||||
Ongoing: '#D97706',
|
||||
Live: '#0D6E6E',
|
||||
}
|
||||
|
||||
const statusBgMap: Record<Investigation['status'], string> = {
|
||||
Complete: 'rgba(5,150,105,0.08)',
|
||||
Ongoing: 'rgba(217,119,6,0.08)',
|
||||
Live: 'rgba(10,128,128,0.08)',
|
||||
}
|
||||
|
||||
export function ProjectDetail({ investigation }: ProjectDetailProps) {
|
||||
const statusColor = statusColorMap[investigation.status]
|
||||
const statusBg = statusBgMap[investigation.status]
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
fontFamily: 'var(--font-ui)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '24px',
|
||||
}}
|
||||
>
|
||||
{/* Header: name + year + status */}
|
||||
<div>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '10px',
|
||||
flexWrap: 'wrap',
|
||||
marginBottom: '8px',
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontSize: '11px',
|
||||
fontFamily: 'var(--font-geist-mono)',
|
||||
color: 'var(--text-tertiary)',
|
||||
}}
|
||||
>
|
||||
{investigation.requestedYear}
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
padding: '2px 8px',
|
||||
fontSize: '11px',
|
||||
fontWeight: 600,
|
||||
color: statusColor,
|
||||
backgroundColor: statusBg,
|
||||
borderRadius: 'var(--radius-sm)',
|
||||
}}
|
||||
>
|
||||
{investigation.status}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: '12px',
|
||||
fontFamily: 'var(--font-geist-mono)',
|
||||
color: 'var(--text-tertiary)',
|
||||
}}
|
||||
>
|
||||
{investigation.requestingClinician}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Methodology */}
|
||||
<div>
|
||||
<h3
|
||||
style={{
|
||||
fontSize: '12px',
|
||||
fontWeight: 600,
|
||||
color: 'var(--text-secondary)',
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: '0.05em',
|
||||
marginBottom: '8px',
|
||||
}}
|
||||
>
|
||||
Methodology
|
||||
</h3>
|
||||
<p
|
||||
style={{
|
||||
fontSize: '14px',
|
||||
lineHeight: '1.6',
|
||||
color: 'var(--text-primary)',
|
||||
margin: 0,
|
||||
}}
|
||||
>
|
||||
{investigation.methodology}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Tech stack tags */}
|
||||
<div>
|
||||
<h3
|
||||
style={{
|
||||
fontSize: '12px',
|
||||
fontWeight: 600,
|
||||
color: 'var(--text-secondary)',
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: '0.05em',
|
||||
marginBottom: '8px',
|
||||
}}
|
||||
>
|
||||
Tech Stack
|
||||
</h3>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '6px' }}>
|
||||
{investigation.techStack.map((tech) => (
|
||||
<span
|
||||
key={tech}
|
||||
style={{
|
||||
padding: '3px 10px',
|
||||
fontSize: '11px',
|
||||
fontWeight: 500,
|
||||
fontFamily: 'var(--font-geist-mono)',
|
||||
color: 'var(--accent)',
|
||||
backgroundColor: 'var(--accent-light)',
|
||||
borderRadius: 'var(--radius-sm)',
|
||||
border: '1px solid var(--accent-border)',
|
||||
}}
|
||||
>
|
||||
{tech}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Results */}
|
||||
<div>
|
||||
<h3
|
||||
style={{
|
||||
fontSize: '12px',
|
||||
fontWeight: 600,
|
||||
color: 'var(--text-secondary)',
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: '0.05em',
|
||||
marginBottom: '8px',
|
||||
}}
|
||||
>
|
||||
Results
|
||||
</h3>
|
||||
<ul
|
||||
style={{
|
||||
margin: 0,
|
||||
paddingLeft: '20px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '8px',
|
||||
}}
|
||||
>
|
||||
{investigation.results.map((result, index) => (
|
||||
<li
|
||||
key={index}
|
||||
style={{
|
||||
fontSize: '14px',
|
||||
lineHeight: '1.6',
|
||||
color: 'var(--text-primary)',
|
||||
}}
|
||||
>
|
||||
{result}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* External link */}
|
||||
{investigation.externalUrl && (
|
||||
<a
|
||||
href={investigation.externalUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: '6px',
|
||||
padding: '8px 16px',
|
||||
fontSize: '13px',
|
||||
fontWeight: 600,
|
||||
fontFamily: 'var(--font-ui)',
|
||||
color: 'var(--surface)',
|
||||
backgroundColor: 'var(--accent)',
|
||||
borderRadius: 'var(--radius-sm)',
|
||||
textDecoration: 'none',
|
||||
alignSelf: 'flex-start',
|
||||
transition: 'background-color 150ms',
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.backgroundColor = 'var(--accent-hover)'
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.backgroundColor = 'var(--accent)'
|
||||
}}
|
||||
>
|
||||
<ExternalLink size={14} />
|
||||
View Live Project
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user