kyd-shared-badge 0.3.33 → 0.3.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kyd-shared-badge",
3
- "version": "0.3.33",
3
+ "version": "0.3.35",
4
4
  "private": false,
5
5
  "main": "./src/index.ts",
6
6
  "module": "./src/index.ts",
@@ -72,6 +72,14 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
72
72
  const genreMapping = (scoringSummary?.config?.genre_mapping) || {};
73
73
  const categoryScores = (scoringSummary?.category_scores) || {};
74
74
  const categoryTopByGraph = (graphInsights?.categoryTopBusiness) || {};
75
+ const roleTargets: Record<string, number> | undefined = (() => {
76
+ try {
77
+ const em: any = (assessmentResult as any)?.enterprise_match;
78
+ return (em && em.role && em.role.categoryTargets) ? (em.role.categoryTargets as Record<string, number>) : undefined;
79
+ } catch {
80
+ return undefined;
81
+ }
82
+ })();
75
83
 
76
84
  const topBusinessForGenre = (genre: string) => {
77
85
  const cats: string[] = (genreMapping)?.[genre] || [];
@@ -295,6 +303,7 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
295
303
  barColor={barColor}
296
304
  getCategoryTooltipCopy={getCategoryTooltipCopy}
297
305
  barHeight={16}
306
+ categoryTargets={roleTargets}
298
307
  />
299
308
  </Reveal>
300
309
 
@@ -370,6 +379,7 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
370
379
  barColor={barColor}
371
380
  getCategoryTooltipCopy={getCategoryTooltipCopy}
372
381
  barHeight={16}
382
+ categoryTargets={roleTargets}
373
383
  />
374
384
  </Reveal>
375
385
  {/* Right: Contributing Factors (hidden on small screens) */}
@@ -11,6 +11,7 @@ type CategoryBarsProps = {
11
11
  barColor: (percent: number) => string;
12
12
  getCategoryTooltipCopy: (category: string) => string;
13
13
  barHeight?: number; // px height for the filled bar
14
+ categoryTargets?: Record<string, number>; // desired target lengths (0-100)
14
15
  };
15
16
 
16
17
  const CategoryBars: React.FC<CategoryBarsProps> = ({
@@ -19,12 +20,18 @@ const CategoryBars: React.FC<CategoryBarsProps> = ({
19
20
  categoryScores,
20
21
  getCategoryTooltipCopy,
21
22
  barHeight = 6,
23
+ categoryTargets,
22
24
  }) => {
23
25
  return (
24
26
  <div className="relative flex flex-col h-full">
25
27
  <div className="font-semibold text-xl mb-2" style={{ color: 'var(--text-main)' }}>{title}</div>
26
28
  <div className="text-sm mb-6" style={{ color: 'var(--text-secondary)' }}>
27
29
  Each bar represents a category's net evidence: positive values extend right in green, negative values extend left, and bar length denotes contribution magnitude.
30
+ {categoryTargets && Object.keys(categoryTargets).length > 0 ? (
31
+ <>
32
+ {' '}Target overlays indicate desired evidence lengths for this role.
33
+ </>
34
+ ) : null}
28
35
  </div>
29
36
  <div className="flex-1 flex flex-col justify-between relative">
30
37
  <div
@@ -56,6 +63,10 @@ const CategoryBars: React.FC<CategoryBarsProps> = ({
56
63
  'Strong Evidence';
57
64
  const fillWidth = absPercent / 2; // half-bar represents 100%
58
65
  const left = isNegative ? `calc(50% - ${fillWidth}%)` : '50%';
66
+ const targetRaw = categoryTargets?.[category];
67
+ const hasTarget = typeof targetRaw === 'number' && isFinite(targetRaw);
68
+ const targetClamp = hasTarget ? Math.max(0, Math.min(100, Math.round(targetRaw as number))) : 0;
69
+ const targetWidth = targetClamp / 2; // same scale as fillWidth
59
70
  return (
60
71
  <div key={category} className="first:pt-0 group relative">
61
72
  <div className={'font-semibold mb-1'} style={{ color: 'var(--text-main)' }}>
@@ -72,6 +83,20 @@ const CategoryBars: React.FC<CategoryBarsProps> = ({
72
83
  >
73
84
  {/* signed fill originating from center */}
74
85
  <div className="absolute top-0 h-full" style={{ left, width: `${fillWidth}%`, backgroundColor: isNegative ? `var(--status-negative, ${red})` : `var(--status-positive, ${green})` }} />
86
+ {/* role target overlay: positive side only, dashed outline */}
87
+ {hasTarget && (
88
+ <div
89
+ className="absolute top-0 h-full"
90
+ style={{
91
+ left: '50%',
92
+ width: `${targetWidth}%`,
93
+ borderTop: '2px dashed var(--icon-accent)',
94
+ borderBottom: '2px dashed var(--icon-accent)',
95
+ opacity: 0.7,
96
+ }}
97
+ aria-hidden="true"
98
+ />
99
+ )}
75
100
  </div>
76
101
  </div>
77
102
  <div className="hidden group-hover:block absolute z-30 left-1/2 -translate-x-1/2 top-full mt-2 w-80">
@@ -89,6 +114,11 @@ const CategoryBars: React.FC<CategoryBarsProps> = ({
89
114
  <div style={{ marginTop: 6, fontSize: 12, color: 'var(--text-secondary)' }}>
90
115
  {getCategoryTooltipCopy(category)}
91
116
  </div>
117
+ {hasTarget && (
118
+ <div style={{ marginTop: 6, fontSize: 12, color: 'var(--text-secondary)' }}>
119
+ Target: {targetClamp}%
120
+ </div>
121
+ )}
92
122
  </div>
93
123
  </div>
94
124
  </div>
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { FiThumbsUp, FiTrendingUp, FiInfo } from 'react-icons/fi';
4
+ import { red, yellow, green, hexToRgba } from '../colors';
4
5
 
5
6
  type CoachingItem = {
6
7
  headline: string;
@@ -22,18 +23,18 @@ export default function EnterpriseCoaching({
22
23
 
23
24
  const toneTint = (label?: string) => {
24
25
  const l = (label || '').toLowerCase();
25
- if (l.includes('optimal') || l.includes('strong')) return 'rgba(2,163,137,0.10)';
26
- if (l.includes('moderate')) return 'rgba(255,187,84,0.10)';
27
- return 'rgba(236,102,98,0.10)';
26
+ const base = (l.includes('optimal') || l.includes('strong'))
27
+ ? green
28
+ : (l.includes('moderate'))
29
+ ? yellow
30
+ : red;
31
+ return hexToRgba(base, 0.10);
28
32
  };
29
33
 
30
34
  return (
31
35
  <div className={'mt-4 p-4 rounded-lg border'} style={{ background: toneTint(matchLabel), borderColor: 'var(--icon-button-secondary)' }}>
32
36
  <div className="flex items-center justify-between mb-2">
33
37
  <div className="flex items-center gap-2">
34
- <span className={'px-2 py-1 rounded text-xs font-semibold'} style={{ backgroundColor: 'var(--content-card-background)', border: '1px solid var(--icon-button-secondary)', color: 'var(--text-main)' }}>
35
- {matchLabel || 'Role Match'}
36
- </span>
37
38
  <div className={'text-sm font-semibold'} style={{ color: 'var(--text-main)' }}>
38
39
  {roleName ? `Role Alignment — ${roleName}` : 'Role Alignment'}
39
40
  </div>
package/src/types.ts CHANGED
@@ -170,6 +170,7 @@ export interface EnterpriseMatch {
170
170
  role: {
171
171
  name: string;
172
172
  description: string;
173
+ categoryTargets?: Record<string, number>;
173
174
  };
174
175
  label: string;
175
176
  description: string;