kyd-shared-badge 0.3.56 → 0.3.59
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
|
@@ -76,7 +76,7 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
|
|
|
76
76
|
const isHeadless = !!headless;
|
|
77
77
|
|
|
78
78
|
// Overall and genre scores
|
|
79
|
-
const overallFinalPercent = assessmentResult?.final_percent || 0;
|
|
79
|
+
const overallFinalPercent = Math.round(assessmentResult?.final_percent || 0);
|
|
80
80
|
|
|
81
81
|
// Build category display grouped by genres from scoring_summary.config.genre_mapping
|
|
82
82
|
const genreMapping = (scoringSummary?.config?.genre_mapping) || {};
|
|
@@ -18,9 +18,8 @@ const BusinessRuleLink = ({ uid, label, className }: { uid?: string; label: stri
|
|
|
18
18
|
{tooltip && (
|
|
19
19
|
<div className="hidden group-hover:block absolute z-30 left-1/2 -translate-x-1/2 top-full mt-2 w-72">
|
|
20
20
|
<div style={{ background: 'var(--content-card-background)', border: '1px solid var(--icon-button-secondary)', color: 'var(--text-main)', padding: 10, borderRadius: 6, fontSize: 12 }}>
|
|
21
|
-
<div style={{ fontWeight: 600, color: 'var(--text-
|
|
22
|
-
|
|
23
|
-
</div>
|
|
21
|
+
<div style={{ fontWeight: 600, color: 'var(--text-main)' }}>{meta?.category || ''}</div>
|
|
22
|
+
<div style={{ fontSize: 12, color: 'var(--text-secondary)', marginTop: 4 }}>{meta?.likert_label || ''}</div>
|
|
24
23
|
</div>
|
|
25
24
|
</div>
|
|
26
25
|
)}
|
|
@@ -6,7 +6,6 @@ import { GraphInsightsPayload, ScoringSummary } from '../types';
|
|
|
6
6
|
import { green1, green2, green3, green4, green5 } from '../colors';
|
|
7
7
|
import {
|
|
8
8
|
ResponsiveContainer,
|
|
9
|
-
Tooltip,
|
|
10
9
|
PieChart,
|
|
11
10
|
Pie,
|
|
12
11
|
Cell,
|
|
@@ -22,6 +21,7 @@ import {
|
|
|
22
21
|
// CartesianGrid,
|
|
23
22
|
// Legend,
|
|
24
23
|
} from 'recharts';
|
|
24
|
+
import { ChartTooltip, ChartLegend } from './ui/chart';
|
|
25
25
|
|
|
26
26
|
// avoid platform based charts.
|
|
27
27
|
// target over arching insights that can
|
|
@@ -272,7 +272,7 @@ const GraphInsights = ({
|
|
|
272
272
|
<Radar name="Category Score" dataKey="score" stroke={'var(--text-main)'} fill={'var(--text-main)'} fillOpacity={0.22} isAnimationActive={!disableAnimations} />
|
|
273
273
|
{/* Subtle average ring (arbitrary benchmark for comparison) */}
|
|
274
274
|
<Radar name="Avg" dataKey="avg" stroke="rgba(128,128,128,0.6)" fill="rgba(128,128,128,0.08)" strokeDasharray="4 4" fillOpacity={1} isAnimationActive={!disableAnimations} />
|
|
275
|
-
<
|
|
275
|
+
<ChartTooltip content={<RadarCategoryTooltip />} />
|
|
276
276
|
</RadarChart>
|
|
277
277
|
</ResponsiveContainer>
|
|
278
278
|
{!headless && labelHover && (
|
|
@@ -357,35 +357,28 @@ const GraphInsights = ({
|
|
|
357
357
|
</Pie>
|
|
358
358
|
);
|
|
359
359
|
})()}
|
|
360
|
-
<
|
|
360
|
+
<ChartTooltip content={<CategoryPieTooltip />} />
|
|
361
361
|
</PieChart>
|
|
362
362
|
</ResponsiveContainer>
|
|
363
363
|
|
|
364
364
|
</div>
|
|
365
365
|
{/* Legend below the pie chart: includes 0% categories */}
|
|
366
366
|
<div className="mt-3">
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
</div>
|
|
383
|
-
);
|
|
384
|
-
})}
|
|
385
|
-
</div>
|
|
386
|
-
);
|
|
387
|
-
})()}
|
|
388
|
-
</div>
|
|
367
|
+
{(() => {
|
|
368
|
+
const palette = [green1, green2, green3, green4, green5];
|
|
369
|
+
const pieNames = categoryData.map((d) => d.category);
|
|
370
|
+
const getColor = (name: string) => {
|
|
371
|
+
const idx = pieNames.indexOf(name);
|
|
372
|
+
return idx >= 0 ? palette[idx % palette.length] : 'rgba(128,128,128,0.5)';
|
|
373
|
+
};
|
|
374
|
+
const items = legendData.map((item) => ({
|
|
375
|
+
color: getColor(item.name),
|
|
376
|
+
label: item.name,
|
|
377
|
+
value: `${Math.round(((item?.share ?? 0) * 100))}%`,
|
|
378
|
+
}));
|
|
379
|
+
return <ChartLegend items={items} />;
|
|
380
|
+
})()}
|
|
381
|
+
</div>
|
|
389
382
|
</div>
|
|
390
383
|
</div>
|
|
391
384
|
</div>
|
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
XAxis,
|
|
11
11
|
YAxis,
|
|
12
12
|
CartesianGrid,
|
|
13
|
-
Tooltip,
|
|
14
13
|
} from 'recharts';
|
|
14
|
+
import { ChartTooltip } from './ui/chart';
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
type SkillsRadarPoint = {
|
|
@@ -389,7 +389,7 @@ const Skills = ({ skillsCategoryRadar, headless }: { skillsMatrix?: SkillsMatrix
|
|
|
389
389
|
<CartesianGrid strokeDasharray="3 3" stroke={'var(--icon-button-secondary)'} />
|
|
390
390
|
<XAxis dataKey="axis" tick={{ fill: 'var(--text-secondary)', fontSize: 12 }} interval={0} angle={-20} textAnchor="end" height={50} />
|
|
391
391
|
<YAxis domain={[0, 100]} tick={{ fill: 'var(--text-secondary)' }} />
|
|
392
|
-
<
|
|
392
|
+
<ChartTooltip />
|
|
393
393
|
<Bar dataKey="observed" name="Observed" fill={'var(--bar-observed)'} isAnimationActive={!disableAnimations} />
|
|
394
394
|
<Bar dataKey="self_reported" name="Self-reported" fill={'var(--bar-self-reported)'} isAnimationActive={!disableAnimations} />
|
|
395
395
|
<Bar dataKey="certified" name="Certified" fill={'var(--bar-certified)'} isAnimationActive={!disableAnimations} />
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { Tooltip as RechartsTooltip } from 'recharts';
|
|
5
|
+
|
|
6
|
+
type ChartContainerProps = {
|
|
7
|
+
className?: string;
|
|
8
|
+
style?: React.CSSProperties;
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Lightweight shadcn-like chart container.
|
|
14
|
+
* Provides a consistent surface, border, and color variables for charts.
|
|
15
|
+
*/
|
|
16
|
+
export function ChartContainer({ className, style, children }: ChartContainerProps) {
|
|
17
|
+
return (
|
|
18
|
+
<div
|
|
19
|
+
className={`rounded-lg border ${className || ''}`}
|
|
20
|
+
style={{
|
|
21
|
+
backgroundColor: 'var(--content-card-background)',
|
|
22
|
+
borderColor: 'var(--icon-button-secondary)',
|
|
23
|
+
...style,
|
|
24
|
+
}}
|
|
25
|
+
>
|
|
26
|
+
{children}
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type ChartTooltipProps = {
|
|
32
|
+
// passthrough props accepted by Recharts Tooltip
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
|
+
content?: any;
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
|
+
cursor?: any;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* shadcn-style tooltip wrapper for Recharts Tooltip.
|
|
41
|
+
* Ensures consistent content styling (background, border, text, radius).
|
|
42
|
+
*/
|
|
43
|
+
export function ChartTooltip({ content, cursor }: ChartTooltipProps) {
|
|
44
|
+
return (
|
|
45
|
+
<RechartsTooltip
|
|
46
|
+
cursor={cursor}
|
|
47
|
+
content={content}
|
|
48
|
+
wrapperStyle={{ outline: 'none' }}
|
|
49
|
+
contentStyle={{
|
|
50
|
+
background: 'var(--content-card-background)',
|
|
51
|
+
border: '1px solid var(--icon-button-secondary)',
|
|
52
|
+
color: 'var(--text-main)',
|
|
53
|
+
borderRadius: 6,
|
|
54
|
+
padding: 10,
|
|
55
|
+
}}
|
|
56
|
+
itemStyle={{ color: 'var(--text-secondary)' }}
|
|
57
|
+
labelStyle={{ color: 'var(--text-main)', fontWeight: 600 }}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type ChartTooltipContentProps = {
|
|
63
|
+
title?: string;
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
65
|
+
children?: any;
|
|
66
|
+
// Optional compact body text for simpler tooltips
|
|
67
|
+
body?: string;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Generic content frame for tooltips used by charts.
|
|
72
|
+
*/
|
|
73
|
+
export function ChartTooltipContent({ title, body, children }: ChartTooltipContentProps) {
|
|
74
|
+
return (
|
|
75
|
+
<div style={{ maxWidth: 320 }}>
|
|
76
|
+
{title ? <div style={{ fontWeight: 600, color: 'var(--text-main)' }}>{title}</div> : null}
|
|
77
|
+
{body ? (
|
|
78
|
+
<div style={{ fontSize: 12, color: 'var(--text-secondary)', marginTop: title ? 6 : 0 }}>{body}</div>
|
|
79
|
+
) : null}
|
|
80
|
+
{children}
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
type LegendItem = { color: string; label: string; value?: string };
|
|
86
|
+
|
|
87
|
+
export function ChartLegend({ items }: { items: LegendItem[] }) {
|
|
88
|
+
return (
|
|
89
|
+
<div className="mt-3 flex flex-wrap items-center justify-center gap-x-4 gap-y-2" style={{ color: 'var(--text-secondary)', fontSize: 12 }}>
|
|
90
|
+
{items.map((it, idx) => (
|
|
91
|
+
<div key={idx} className="flex items-center gap-2">
|
|
92
|
+
<span
|
|
93
|
+
style={{
|
|
94
|
+
display: 'inline-block',
|
|
95
|
+
width: 10,
|
|
96
|
+
height: 10,
|
|
97
|
+
background: it.color,
|
|
98
|
+
border: '1px solid var(--icon-button-secondary)',
|
|
99
|
+
}}
|
|
100
|
+
/>
|
|
101
|
+
<span>
|
|
102
|
+
{it.label} {it.value}
|
|
103
|
+
</span>
|
|
104
|
+
</div>
|
|
105
|
+
))}
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
package/src/types.ts
CHANGED
|
@@ -476,4 +476,12 @@ export type Role = {
|
|
|
476
476
|
createdAt?: string;
|
|
477
477
|
userId?: string;
|
|
478
478
|
}
|
|
479
|
+
|
|
480
|
+
// Timeseries for dashboard trends
|
|
481
|
+
export type TimeseriesPoint = { date: string; value: number };
|
|
482
|
+
export interface AssessmentTimeseries {
|
|
483
|
+
final_percent: TimeseriesPoint[];
|
|
484
|
+
genres: Record<string, TimeseriesPoint[]>;
|
|
485
|
+
categories: Record<string, TimeseriesPoint[]>;
|
|
486
|
+
}
|
|
479
487
|
|