From a5deb0ea8ba0bb3e346b8f504ec05ab741b0e526 Mon Sep 17 00:00:00 2001 From: Andy Charlwood Date: Sat, 14 Feb 2026 02:34:26 +0000 Subject: [PATCH] US-021: Create SkillsAllDetail renderer for detail panel --- src/components/DetailPanel.tsx | 5 +- src/components/detail/SkillsAllDetail.tsx | 252 ++++++++++++++++++++++ 2 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 src/components/detail/SkillsAllDetail.tsx diff --git a/src/components/DetailPanel.tsx b/src/components/DetailPanel.tsx index 490a1ea..890f370 100644 --- a/src/components/DetailPanel.tsx +++ b/src/components/DetailPanel.tsx @@ -7,6 +7,7 @@ import type { CardHeaderProps } from './Card' import { KPIDetail } from './detail/KPIDetail' import { ConsultationDetail } from './detail/ConsultationDetail' import { SkillDetail } from './detail/SkillDetail' +import { SkillsAllDetail } from './detail/SkillsAllDetail' // Width mapping from content type const widthMap: Record = { @@ -217,12 +218,14 @@ export function DetailPanel() { )} {content.type === 'skill' && } + {content.type === 'skills-all' && } {/* Other content types - placeholder for future stories */} {content.type !== 'kpi' && content.type !== 'consultation' && content.type !== 'career-role' && - content.type !== 'skill' && ( + content.type !== 'skill' && + content.type !== 'skills-all' && (
= { + BarChart3, Code2, Database, PieChart, FileCode2, + Sheet, GitBranch, Workflow, Pill, Users, FileCheck, + TrendingUp, Route, ShieldAlert, Banknote, Handshake, + MessageSquare, UserPlus, RefreshCw, Calculator, Presentation, +} + +const categoryConfig: { id: SkillCategory; label: string }[] = [ + { id: 'Technical', label: 'Technical' }, + { id: 'Domain', label: 'Healthcare Domain' }, + { id: 'Leadership', label: 'Strategic & Leadership' }, +] + +interface SkillsAllDetailProps { + category?: SkillCategory +} + +export function SkillsAllDetail({ category }: SkillsAllDetailProps) { + const { openPanel } = useDetailPanel() + const categoryRefs = useRef>({}) + + // Scroll to highlighted category on mount + useEffect(() => { + if (category && categoryRefs.current[category]) { + categoryRefs.current[category]?.scrollIntoView({ behavior: 'smooth', block: 'start' }) + } + }, [category]) + + const groupedSkills = categoryConfig.map(({ id, label }) => ({ + id, + label, + skills: skills + .filter((s) => s.category === id) + .sort((a, b) => b.proficiency - a.proficiency), + })) + + const handleSkillClick = (skill: SkillMedication) => { + openPanel({ type: 'skill', skill }) + } + + return ( +
+ {groupedSkills.map((group) => { + const isHighlighted = category === group.id + + return ( +
{ categoryRefs.current[group.id] = el }} + > + {/* Category header — matches CoreSkillsTile divider style */} +
+ + {group.label} + +
+ + {group.skills.length} items + +
+ + {/* Skill rows */} +
+ {group.skills.map((skill) => ( + handleSkillClick(skill)} + /> + ))} +
+
+ ) + })} +
+ ) +} + +interface SkillRowProps { + skill: SkillMedication + onClick: () => void +} + +function SkillRow({ skill, onClick }: SkillRowProps) { + const IconComponent = iconMap[skill.icon] + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault() + onClick() + } + } + + return ( +
{ + e.currentTarget.style.borderColor = 'var(--accent-border)' + e.currentTarget.style.boxShadow = 'var(--shadow-md)' + }} + onMouseLeave={(e) => { + e.currentTarget.style.borderColor = 'var(--border-light)' + e.currentTarget.style.boxShadow = 'none' + }} + > + {/* Icon */} +
+ {IconComponent && } +
+ + {/* Text */} +
+
+ {skill.name} +
+
+ {skill.frequency} · {skill.yearsOfExperience} yrs +
+
+ + {/* Proficiency */} +
+
+
= 90 ? 'var(--success)' : skill.proficiency >= 75 ? 'var(--accent)' : 'var(--amber)', + borderRadius: '2px', + }} + /> +
+ + {skill.proficiency}% + +
+ + {/* Chevron */} + +
+ ) +}