kyd-shared-badge 0.3.46 → 0.3.48

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.46",
3
+ "version": "0.3.48",
4
4
  "private": false,
5
5
  "main": "./src/index.ts",
6
6
  "module": "./src/index.ts",
@@ -8,13 +8,13 @@ import EnterpriseCoaching from './components/EnterpriseCoaching';
8
8
  import AppendixTables from './components/AppendixTables';
9
9
  import BusinessRuleLink from './components/BusinessRuleLink';
10
10
  import IpRiskAnalysisDisplay from './components/IpRiskAnalysisDisplay';
11
- // import Image from 'next/image';
12
11
  import GraphInsights from './components/GraphInsights';
13
12
  import ConnectedPlatforms from './components/ConnectedPlatforms';
14
13
  import { FaGithub, FaGitlab, FaStackOverflow, FaLinkedin, FaGoogle, FaKaggle } from 'react-icons/fa';
15
14
  import { SiCredly, SiFiverr } from 'react-icons/si';
16
15
  import GaugeCard from './components/GaugeCard';
17
16
  import RiskCard from './components/RiskCard';
17
+ import Image from 'next/image';
18
18
 
19
19
  import { yellow, green } from './colors';
20
20
  import Skills from './components/Skills';
@@ -115,7 +115,7 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
115
115
  const tabs = useMemo(() => {
116
116
  const arr = [
117
117
  { key: 'overview', label: 'Overview' },
118
- ...(showRoleFit ? [{ key: 'role', label: 'Role Fit & Coaching' }] : []),
118
+ { key: 'role', label: 'Role Fit & Coaching' },
119
119
  { key: 'technical', label: 'KYD Technical' },
120
120
  { key: 'risk', label: 'KYD Risk' },
121
121
  { key: 'ai', label: 'KYD AI' },
@@ -133,7 +133,7 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
133
133
  const keys = new Set(tabs.map(t => t.key));
134
134
  if (hash && keys.has(hash)) setActiveTab(hash);
135
135
  // If the hash targets a skills appendix anchor, switch to Appendix
136
- if (hash && (hash.startsWith('appendix-skills') || hash.includes('appendix-skills-cat-'))) {
136
+ if (hash && (hash.startsWith('appendix-skills') || hash.includes('appendix-skills-cat-') || hash.includes('appendix-connected'))) {
137
137
  setActiveTab('appendix');
138
138
  }
139
139
  } catch {}
@@ -162,24 +162,41 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
162
162
  <div className={'sticky z-10'} style={{ top: computeStickyTop(), background: 'var(--background)', borderBottom: '1px solid var(--icon-button-secondary)' }}>
163
163
  <div className={`${wrapperMaxWidth} mx-auto px-2 sm:px-0 overflow-x-auto`}>
164
164
  <div className="flex gap-1 sm:gap-2">
165
- {tabs.map(t => (
166
- <button
167
- key={t.key}
168
- onClick={() => {
169
- setActiveTab(t.key);
170
- try { if (typeof window !== 'undefined') window.history.replaceState(null, '', `#${t.key}`); } catch {}
171
- }}
172
- className={`px-3 sm:px-4 py-2 text-sm rounded-t ${activeTab === t.key ? 'font-semibold' : ''}`}
173
- style={{
174
- color: 'var(--text-main)',
175
- background: activeTab === t.key ? 'var(--content-card-background)' : 'transparent',
176
- border: activeTab === t.key ? '1px solid var(--icon-button-secondary)' : '1px solid transparent',
177
- borderBottomColor: 'transparent'
178
- }}
179
- >
180
- {t.label}
181
- </button>
182
- ))}
165
+ {tabs.map(t => {
166
+ // Determine if this tab should have an icon
167
+ let iconSrc: string | null = null;
168
+ if (t.key === 'ai') iconSrc = '/badge/ai.svg';
169
+ if (t.key === 'technical') iconSrc = '/badge/code.svg';
170
+ if (t.key === 'risk') iconSrc = '/badge/risk.svg';
171
+ return (
172
+ <button
173
+ key={t.key}
174
+ onClick={() => {
175
+ setActiveTab(t.key);
176
+ try { if (typeof window !== 'undefined') window.history.replaceState(null, '', `#${t.key}`); } catch {}
177
+ }}
178
+ className={`px-3 sm:px-4 py-2 text-sm rounded-t flex items-center gap-2 ${activeTab === t.key ? 'font-semibold' : ''}`}
179
+ style={{
180
+ color: 'var(--text-main)',
181
+ background: activeTab === t.key ? 'var(--content-card-background)' : 'transparent',
182
+ border: activeTab === t.key ? '1px solid var(--icon-button-secondary)' : '1px solid transparent',
183
+ borderBottomColor: 'transparent'
184
+ }}
185
+ >
186
+ {iconSrc && (
187
+ <Image
188
+ src={iconSrc}
189
+ alt=""
190
+ width={18}
191
+ height={18}
192
+ className="text-[var(--text-main)]"
193
+ style={{ display: 'inline-block', verticalAlign: 'middle', color: 'var(--text-main)' }}
194
+ />
195
+ )}
196
+ {t.label}
197
+ </button>
198
+ );
199
+ })}
183
200
  </div>
184
201
  </div>
185
202
  </div>
@@ -219,8 +236,9 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
219
236
  const RoleFitSection = () => {
220
237
  // Local state for expanding long role descriptions
221
238
  const [showFullRoleDescription, setShowFullRoleDescription] = useState(false);
239
+ const rec = assessmentResult?.recommendations;
222
240
 
223
- return !showRoleFit ? null : (
241
+ return (
224
242
  <div className={`${wrapperMaxWidth} mx-auto`}>
225
243
  <div className={'rounded-xl shadow-xl p-6 sm:p-8 mt-6 border'} style={{ backgroundColor: 'var(--content-card-background)', borderColor: 'var(--icon-button-secondary)' }}>
226
244
  <div className="space-y-10">
@@ -237,19 +255,8 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
237
255
  const isLong = primaryDescription.length > 500;
238
256
  const visibleText = isLong && !showFullRoleDescription ? `${primaryDescription.slice(0, 500)}…` : primaryDescription;
239
257
  return (
240
- <div className={'text-sm'} style={{ color: 'var(--text-secondary)' }}>
241
- <div className="flex items-center text-start gap-2 py-3">
242
- <div className={'text-base font-semibold'} style={{ color: 'var(--text-main)' }}>{roleName}</div>
243
- <span>-</span>
244
- <div
245
- className={
246
- `px-3 py-1 inline-block rounded-md font-semibold shadow-sm text-[var(--text-main)] border`
247
- }
248
- style={{ borderColor: matchLabelToColor(em.label) }}
249
- >
250
- {em.label}
251
- </div>
252
- </div>
258
+ <div className='mt-3' style={{ color: 'var(--text-secondary)' }}>
259
+ <div className={'text-base font-semibold'} style={{ color: 'var(--text-main)' }}>{roleName}</div>
253
260
  {primaryDescription ? (
254
261
  <div>
255
262
  <span>{visibleText}</span>
@@ -265,6 +272,22 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
265
272
  )}
266
273
  </div>
267
274
  ) : null}
275
+
276
+ {em.description ? (
277
+ <div>
278
+ <div className="flex items-center text-start gap-2 mt-3">
279
+ <div className={'text-base font-semibold'} style={{ color: 'var(--text-main)' }}>Alignment Description</div>
280
+ <span>-</span>
281
+ <div
282
+ className={`px-2 py-1 inline-block rounded-md font-semibold shadow-sm text-[var(--text-main)] border`}
283
+ style={{ borderColor: matchLabelToColor(em.label) }}
284
+ >
285
+ {em.label}
286
+ </div>
287
+ </div>
288
+ <div className={'text-sm'} style={{ color: 'var(--text-secondary)' }}>{em.description}</div>
289
+ </div>
290
+ ) : null}
268
291
  </div>
269
292
  );
270
293
  })()}
@@ -289,6 +312,25 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
289
312
  <UseCases useCases={assessmentResult?.enterprise_use_cases} headless={isHeadless} badgeId={badgeId} />
290
313
  </div>
291
314
  )}
315
+ <div>
316
+ <Reveal headless={isHeadless} as={'h4'} offsetY={8} className={'text-2xl font-semibold mb-3'} style={{ color: 'var(--text-main)' }}>Recommendations</Reveal>
317
+ <Reveal headless={isHeadless}>
318
+ <div className={'space-y-3'}>
319
+ {rec?.summary ? (
320
+ <div className={'text-sm'} style={{ color: 'var(--text-secondary)' }}>{rec.summary}</div>
321
+ ) : null}
322
+ {Array.isArray(rec?.bullet_points) && (rec?.bullet_points?.length || 0) > 0 ? (
323
+ <ul className={'list-disc pl-5 text-sm'} style={{ color: 'var(--text-secondary)' }}>
324
+ {rec?.bullet_points?.map((bp, idx) => (
325
+ <li key={idx}>{bp}</li>
326
+ ))}
327
+ </ul>
328
+ ) : (!rec?.summary ? (
329
+ <div className={'text-sm'} style={{ color: 'var(--text-secondary)' }}>No recommendations available.</div>
330
+ ) : null)}
331
+ </div>
332
+ </Reveal>
333
+ </div>
292
334
  </div>
293
335
  </div>
294
336
  </div>
@@ -459,7 +501,7 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
459
501
  })()}
460
502
  </div>
461
503
  )}
462
- <div>
504
+ <div id="appendix-connected">
463
505
  <ConnectedPlatforms accounts={connected} authenticity={assessmentResult?.account_authenticity} />
464
506
  </div>
465
507
  </div>
@@ -492,7 +534,7 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
492
534
  </style>
493
535
  {/* Long-form original layout retained for headless/print */}
494
536
  {OverviewSection()}
495
- {showRoleFit ? <RoleFitSection /> : null}
537
+ <RoleFitSection />
496
538
  {TechnicalSection()}
497
539
  {RiskSection()}
498
540
  {AiSection()}
@@ -70,7 +70,7 @@ const ReportHeader = ({ badgeId, developerName, updatedAt, score = 0, badgeImage
70
70
  <div className={'mb-4 rounded-md border p-3 flex items-start gap-2'} style={{ backgroundColor: 'var(--content-card-background)', borderColor: 'var(--icon-button-secondary)' }}>
71
71
  <span className={'mt-0.5'} style={{ color: isCritical ? '#B00020' : '#9f580a' }}><FiAlertTriangle size={18} /></span>
72
72
  <div className={'text-sm'}>
73
- <div className={'font-semibold'} style={{ color: 'var(--text-main)' }}>Account Authenticity {isCritical ? 'Warning' : 'Notice'}</div>
73
+ <div className={'font-semibold'} style={{ color: 'var(--text-main)' }}>{isCritical ? 'Warning' : 'Attention'}</div>
74
74
  <div className={'mt-1'} style={{ color: 'var(--text-secondary)' }}>{accountAuthenticity?.description || (isCritical ? 'We detected signals that some linked accounts may be inauthentic. Review sources below.' : 'Some inconsistencies were observed across linked accounts. Review sources below.')}</div>
75
75
  <div className={'mt-2'}>
76
76
  <a href="#appendix-connected" className={'text-xs font-medium underline underline-offset-2'} style={{ color: 'var(--text-secondary)' }}>See more</a>
@@ -35,7 +35,7 @@ export default function UseCases({ useCases, headless, badgeId }: { useCases?: E
35
35
  return (
36
36
  <Reveal headless={!!headless}>
37
37
  <div className={'pt-8 kyd-avoid-break'}>
38
- <h3 className={'text-2xl font-semibold mb-3'} style={{ color: 'var(--text-main)' }}>Potential Use Cases</h3>
38
+ <h3 className={'text-2xl font-semibold mb-3'} style={{ color: 'var(--text-main)' }}>Project Capabilities</h3>
39
39
  <div className={'grid grid-cols-1 md:grid-cols-2 gap-4'}>
40
40
  {items.map((uc, idx) => {
41
41
  const imgIndex = getUniqueIndex(idx);