@stokelp/ui 2.108.0 → 2.110.0
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/dist/components/chat/ChatScoreBreakdown.cjs +1 -1
- package/dist/components/chat/ChatScoreBreakdown.cjs.map +1 -1
- package/dist/components/chat/ChatScoreBreakdown.d.ts +9 -3
- package/dist/components/chat/ChatScoreBreakdown.js +94 -28
- package/dist/components/chat/ChatScoreBreakdown.js.map +1 -1
- package/dist/ui.css +1 -1
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";const e=require("../text/Text.cjs");let t=require("@stokelp/styled-system/jsx"),n=require("react/jsx-runtime");var r=[`origin`,`rawMaterialOrigin`,`temperature`,`cutting`,`cooking`,`treatment`,`label`,`packaging`];function
|
|
1
|
+
"use client";const e=require("../text/Text.cjs");let t=require("@stokelp/styled-system/jsx"),n=require("react/jsx-runtime");var r=[`origin`,`rawMaterialOrigin`,`temperature`,`cutting`,`cooking`,`treatment`,`label`,`packaging`,`grammageGsm`,`recycledPct`,`thicknessMicron`],i=[`temperature`,`cutting`,`cooking`],a=[`grammageGsm`,`recycledPct`,`thicknessMicron`],o={egal:{bg:`#E6F3D9`,color:`#3B6D11`},proche:{bg:`#F0F6DC`,color:`#5E8516`},eloigne:{bg:`#FDF0E0`,color:`#C2740C`},non_correspondant:{bg:`#FCEBEB`,color:`#A32D2D`}};function s(e){return e>=70?`#3B6D11`:e>=40?`#854F0B`:`#A32D2D`}function c(e){return e>=70?`#639922`:e>=40?`#BA7517`:`#E24B4A`}function l(e){return e?.level!=null}function u(e){return e?.matched!=null&&e?.total!=null}function d(e){return l(e)||u(e)}var f=({percent:u,detail:f,labels:p})=>{let m=a.some(e=>f[e]?.level!=null),h=new Set(m?i:a),g=r.filter(e=>!h.has(e)),_=g.filter(e=>d(f[e])),v=g.filter(e=>!d(f[e])&&p.attributes[e]!=null);return(0,n.jsxs)(t.Box,{bg:`white`,borderRadius:`radius-8`,p:`space-16`,minW:`220px`,maxW:`240px`,css:{"& *":{fontFamily:`inherit`}},children:[(0,n.jsxs)(t.HStack,{justify:`space-between`,alignItems:`baseline`,mb:`space-8`,children:[(0,n.jsx)(e.Text,{as:`span`,fontSize:`body.md`,fontWeight:`bold`,children:p.title}),(0,n.jsxs)(e.Text,{as:`span`,fontSize:`body.lg`,fontWeight:`medium`,style:{color:s(u)},children:[Math.round(u),` %`]})]}),(0,n.jsx)(t.Box,{h:`1px`,bg:`grey.100`,mb:`space-8`}),_.length>0&&(0,n.jsxs)(t.VStack,{alignItems:`stretch`,gap:`space-4`,mb:`space-8`,children:[(0,n.jsx)(e.Text,{as:`span`,fontSize:`body.sm`,fontWeight:`bold`,color:`grey.400`,children:p.compared}),_.map(r=>{let i=f[r];if(l(i)){let a=i.level,s=o[a];return(0,n.jsxs)(t.HStack,{alignItems:`center`,gap:`space-8`,justify:`space-between`,children:[(0,n.jsx)(e.Text,{as:`span`,fontSize:`body.sm`,color:`grey.500`,minW:`80px`,children:p.attributes[r]}),(0,n.jsx)(t.Box,{px:`space-8`,py:`2px`,borderRadius:`full`,flexShrink:`0`,style:{backgroundColor:s.bg},children:(0,n.jsx)(e.Text,{as:`span`,fontSize:`body.sm`,fontWeight:`medium`,style:{color:s.color,whiteSpace:`nowrap`},children:p.levels?.[a]??a})})]},r)}let a=i.matched,s=i.total,u=s>0?a/s*100:0;return(0,n.jsxs)(t.HStack,{alignItems:`center`,gap:`space-8`,children:[(0,n.jsx)(e.Text,{as:`span`,fontSize:`body.sm`,color:`grey.500`,minW:`80px`,children:p.attributes[r]}),(0,n.jsx)(t.Box,{flex:`1`,h:`3px`,bg:`grey.100`,borderRadius:`full`,overflow:`hidden`,children:(0,n.jsx)(t.Box,{h:`100%`,borderRadius:`full`,style:{width:`${u}%`,background:c(u)}})}),(0,n.jsxs)(e.Text,{as:`span`,fontSize:`body.sm`,fontWeight:`medium`,minW:`40px`,textAlign:`right`,style:{color:c(u)},children:[a,`/`,s]})]},r)})]}),_.length>0&&v.length>0&&(0,n.jsx)(t.Box,{h:`1px`,bg:`grey.100`,mb:`space-8`}),v.length>0&&(0,n.jsxs)(t.VStack,{alignItems:`stretch`,gap:`space-4`,children:[(0,n.jsx)(e.Text,{as:`span`,fontSize:`body.sm`,fontWeight:`bold`,color:`grey.400`,children:p.notSpecified}),(0,n.jsx)(t.HStack,{flexWrap:`wrap`,gap:`space-4`,children:v.map(t=>(0,n.jsx)(e.Text,{as:`span`,fontSize:`body.sm`,color:`grey.400`,border:`1px solid`,borderColor:`grey.100`,px:`space-8`,py:`2px`,borderRadius:`full`,children:p.attributes[t]},t))})]}),p.footer&&(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.Box,{h:`1px`,bg:`grey.100`,mt:`space-8`,mb:`space-8`}),(0,n.jsx)(e.Text,{as:`span`,fontSize:`9px`,color:`grey.300`,style:{lineHeight:1},children:p.footer})]})]})};exports.ChatScoreBreakdown=f;
|
|
2
2
|
//# sourceMappingURL=ChatScoreBreakdown.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatScoreBreakdown.cjs","names":[],"sources":["../../../src/components/chat/ChatScoreBreakdown.tsx"],"sourcesContent":["import { Box, HStack, VStack } from '@stokelp/styled-system/jsx'\nimport { Text } from '~/components'\n\nexport type ScoreAttributeKey =\n | 'origin'\n | 'rawMaterialOrigin'\n | 'temperature'\n | 'cutting'\n | 'cooking'\n | 'treatment'\n | 'label'\n | 'packaging'\n\nexport type ScoreAttributeDetail = {\n matched: number | null\n total: number | null\n}\n\nexport type ChatScoreBreakdownLabels = {\n title: string\n compared: string\n notSpecified: string\n attributes: Record<ScoreAttributeKey, string>\n footer?: string\n}\n\nexport type ChatScoreBreakdownProps = {\n percent: number\n detail: Record<ScoreAttributeKey, ScoreAttributeDetail>\n labels: ChatScoreBreakdownLabels\n}\n\nconst ATTRIBUTE_ORDER: ScoreAttributeKey[] = [\n 'origin',\n 'rawMaterialOrigin',\n 'temperature',\n 'cutting',\n 'cooking',\n 'treatment',\n 'label',\n 'packaging',\n]\n\nfunction getHeadlineColor(percent: number): string {\n if (percent >= 70) return '#3B6D11'\n if (percent >= 40) return '#854F0B'\n return '#A32D2D'\n}\n\nfunction getBarColor(ratioPercent: number): string {\n if (ratioPercent >= 70) return '#639922'\n if (ratioPercent >= 40) return '#BA7517'\n return '#E24B4A'\n}\n\nfunction isComparable(detail?: ScoreAttributeDetail): boolean {\n return detail?.matched != null && detail?.total != null\n}\n\nexport const ChatScoreBreakdown = ({ percent, detail, labels }: ChatScoreBreakdownProps) => {\n const compared = ATTRIBUTE_ORDER.filter(key => isComparable(detail[key]))\n const notSpecified = ATTRIBUTE_ORDER.filter(key => !isComparable(detail[key]))\n\n return (\n <Box\n bg=\"white\"\n borderRadius=\"radius-8\"\n p=\"space-16\"\n minW=\"220px\"\n maxW=\"240px\"\n css={{ '& *': { fontFamily: 'inherit' } }}\n >\n <HStack justify=\"space-between\" alignItems=\"baseline\" mb=\"space-8\">\n <Text as=\"span\" fontSize=\"body.md\" fontWeight=\"bold\">\n {labels.title}\n </Text>\n <Text as=\"span\" fontSize=\"body.lg\" fontWeight=\"medium\" style={{ color: getHeadlineColor(percent) }}>\n {Math.round(percent)} %\n </Text>\n </HStack>\n\n <Box h=\"1px\" bg=\"grey.100\" mb=\"space-8\" />\n\n {compared.length > 0 && (\n <VStack alignItems=\"stretch\" gap=\"space-4\" mb=\"space-8\">\n <Text as=\"span\" fontSize=\"body.sm\" fontWeight=\"bold\" color=\"grey.400\">\n {labels.compared}\n </Text>\n {compared.map(key => {\n const matched = detail[key].matched as number\n const total = detail[key].total as number\n const ratioPercent = total > 0 ? (matched / total) * 100 : 0\n return (\n <HStack key={key} alignItems=\"center\" gap=\"space-8\">\n <Text as=\"span\" fontSize=\"body.sm\" color=\"grey.500\" minW=\"80px\">\n {labels.attributes[key]}\n </Text>\n <Box flex=\"1\" h=\"3px\" bg=\"grey.100\" borderRadius=\"full\" overflow=\"hidden\">\n <Box\n h=\"100%\"\n borderRadius=\"full\"\n style={{ width: `${ratioPercent}%`, background: getBarColor(ratioPercent) }}\n />\n </Box>\n <Text\n as=\"span\"\n fontSize=\"body.sm\"\n fontWeight=\"medium\"\n minW=\"40px\"\n textAlign=\"right\"\n style={{ color: getBarColor(ratioPercent) }}\n >\n {matched}/{total}\n </Text>\n </HStack>\n )\n })}\n </VStack>\n )}\n\n {compared.length > 0 && notSpecified.length > 0 && <Box h=\"1px\" bg=\"grey.100\" mb=\"space-8\" />}\n\n {notSpecified.length > 0 && (\n <VStack alignItems=\"stretch\" gap=\"space-4\">\n <Text as=\"span\" fontSize=\"body.sm\" fontWeight=\"bold\" color=\"grey.400\">\n {labels.notSpecified}\n </Text>\n <HStack flexWrap=\"wrap\" gap=\"space-4\">\n {notSpecified.map(key => (\n <Text\n key={key}\n as=\"span\"\n fontSize=\"body.sm\"\n color=\"grey.400\"\n border=\"1px solid\"\n borderColor=\"grey.100\"\n px=\"space-8\"\n py=\"2px\"\n borderRadius=\"full\"\n >\n {labels.attributes[key]}\n </Text>\n ))}\n </HStack>\n </VStack>\n )}\n\n {labels.footer && (\n <>\n <Box h=\"1px\" bg=\"grey.100\" mt=\"space-8\" mb=\"space-8\" />\n <Text as=\"span\" fontSize=\"9px\" color=\"grey.300\" style={{ lineHeight: 1 }}>\n {labels.footer}\n </Text>\n </>\n )}\n </Box>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ChatScoreBreakdown.cjs","names":[],"sources":["../../../src/components/chat/ChatScoreBreakdown.tsx"],"sourcesContent":["import { Box, HStack, VStack } from '@stokelp/styled-system/jsx'\nimport { Text } from '~/components'\n\nexport type ScoreSetAttributeKey =\n | 'origin'\n | 'rawMaterialOrigin'\n | 'temperature'\n | 'cutting'\n | 'cooking'\n | 'treatment'\n | 'label'\n | 'packaging'\n\nexport type ScoreNumericAttributeKey = 'grammageGsm' | 'recycledPct' | 'thicknessMicron'\n\nexport type ScoreAttributeKey = ScoreSetAttributeKey | ScoreNumericAttributeKey\n\n/** Proximity bucket for free numeric packaging specs: egal (equal) → non_correspondant (no match). */\nexport type ScoreLevel = 'egal' | 'proche' | 'eloigne' | 'non_correspondant'\n\nexport type ScoreAttributeDetail = {\n matched: number | null\n total: number | null\n level?: ScoreLevel | null\n}\n\nexport type ChatScoreBreakdownLabels = {\n title: string\n compared: string\n notSpecified: string\n attributes: Record<ScoreSetAttributeKey, string> & Partial<Record<ScoreNumericAttributeKey, string>>\n levels?: Record<ScoreLevel, string>\n footer?: string\n}\n\nexport type ChatScoreBreakdownProps = {\n percent: number\n detail: Record<string, ScoreAttributeDetail>\n labels: ChatScoreBreakdownLabels\n}\n\nconst ATTRIBUTE_ORDER: ScoreAttributeKey[] = [\n 'origin',\n 'rawMaterialOrigin',\n 'temperature',\n 'cutting',\n 'cooking',\n 'treatment',\n 'label',\n 'packaging',\n 'grammageGsm',\n 'recycledPct',\n 'thicknessMicron',\n]\n\n// Attributes that only exist for food products; hidden for packaging products.\nconst FOOD_ONLY_KEYS: ScoreAttributeKey[] = ['temperature', 'cutting', 'cooking']\n// Free numeric specs that only exist for packaging products; hidden for food products.\nconst PACKAGING_ONLY_KEYS: ScoreNumericAttributeKey[] = ['grammageGsm', 'recycledPct', 'thicknessMicron']\n\nconst LEVEL_COLORS: Record<ScoreLevel, { bg: string; color: string }> = {\n egal: { bg: '#E6F3D9', color: '#3B6D11' },\n proche: { bg: '#F0F6DC', color: '#5E8516' },\n eloigne: { bg: '#FDF0E0', color: '#C2740C' },\n non_correspondant: { bg: '#FCEBEB', color: '#A32D2D' },\n}\n\nfunction getHeadlineColor(percent: number): string {\n if (percent >= 70) return '#3B6D11'\n if (percent >= 40) return '#854F0B'\n return '#A32D2D'\n}\n\nfunction getBarColor(ratioPercent: number): string {\n if (ratioPercent >= 70) return '#639922'\n if (ratioPercent >= 40) return '#BA7517'\n return '#E24B4A'\n}\n\nfunction hasLevel(detail?: ScoreAttributeDetail): boolean {\n return detail?.level != null\n}\n\nfunction isFraction(detail?: ScoreAttributeDetail): boolean {\n return detail?.matched != null && detail?.total != null\n}\n\nfunction isComparable(detail?: ScoreAttributeDetail): boolean {\n return hasLevel(detail) || isFraction(detail)\n}\n\nexport const ChatScoreBreakdown = ({ percent, detail, labels }: ChatScoreBreakdownProps) => {\n // A packaging product exposes the numeric specs (comparable via level); food attributes\n // then come back fully null and must be hidden entirely, and vice versa.\n const isPackaging = PACKAGING_ONLY_KEYS.some(key => detail[key]?.level != null)\n const hiddenKeys = new Set<ScoreAttributeKey>(isPackaging ? FOOD_ONLY_KEYS : PACKAGING_ONLY_KEYS)\n const visibleKeys = ATTRIBUTE_ORDER.filter(key => !hiddenKeys.has(key))\n\n const compared = visibleKeys.filter(key => isComparable(detail[key]))\n const notSpecified = visibleKeys.filter(key => !isComparable(detail[key]) && labels.attributes[key] != null)\n\n return (\n <Box\n bg=\"white\"\n borderRadius=\"radius-8\"\n p=\"space-16\"\n minW=\"220px\"\n maxW=\"240px\"\n css={{ '& *': { fontFamily: 'inherit' } }}\n >\n <HStack justify=\"space-between\" alignItems=\"baseline\" mb=\"space-8\">\n <Text as=\"span\" fontSize=\"body.md\" fontWeight=\"bold\">\n {labels.title}\n </Text>\n <Text as=\"span\" fontSize=\"body.lg\" fontWeight=\"medium\" style={{ color: getHeadlineColor(percent) }}>\n {Math.round(percent)} %\n </Text>\n </HStack>\n\n <Box h=\"1px\" bg=\"grey.100\" mb=\"space-8\" />\n\n {compared.length > 0 && (\n <VStack alignItems=\"stretch\" gap=\"space-4\" mb=\"space-8\">\n <Text as=\"span\" fontSize=\"body.sm\" fontWeight=\"bold\" color=\"grey.400\">\n {labels.compared}\n </Text>\n {compared.map(key => {\n const entry = detail[key]\n if (hasLevel(entry)) {\n const level = entry.level as ScoreLevel\n const colors = LEVEL_COLORS[level]\n return (\n <HStack key={key} alignItems=\"center\" gap=\"space-8\" justify=\"space-between\">\n <Text as=\"span\" fontSize=\"body.sm\" color=\"grey.500\" minW=\"80px\">\n {labels.attributes[key]}\n </Text>\n <Box px=\"space-8\" py=\"2px\" borderRadius=\"full\" flexShrink=\"0\" style={{ backgroundColor: colors.bg }}>\n <Text\n as=\"span\"\n fontSize=\"body.sm\"\n fontWeight=\"medium\"\n style={{ color: colors.color, whiteSpace: 'nowrap' }}\n >\n {labels.levels?.[level] ?? level}\n </Text>\n </Box>\n </HStack>\n )\n }\n\n const matched = entry.matched as number\n const total = entry.total as number\n const ratioPercent = total > 0 ? (matched / total) * 100 : 0\n return (\n <HStack key={key} alignItems=\"center\" gap=\"space-8\">\n <Text as=\"span\" fontSize=\"body.sm\" color=\"grey.500\" minW=\"80px\">\n {labels.attributes[key]}\n </Text>\n <Box flex=\"1\" h=\"3px\" bg=\"grey.100\" borderRadius=\"full\" overflow=\"hidden\">\n <Box\n h=\"100%\"\n borderRadius=\"full\"\n style={{ width: `${ratioPercent}%`, background: getBarColor(ratioPercent) }}\n />\n </Box>\n <Text\n as=\"span\"\n fontSize=\"body.sm\"\n fontWeight=\"medium\"\n minW=\"40px\"\n textAlign=\"right\"\n style={{ color: getBarColor(ratioPercent) }}\n >\n {matched}/{total}\n </Text>\n </HStack>\n )\n })}\n </VStack>\n )}\n\n {compared.length > 0 && notSpecified.length > 0 && <Box h=\"1px\" bg=\"grey.100\" mb=\"space-8\" />}\n\n {notSpecified.length > 0 && (\n <VStack alignItems=\"stretch\" gap=\"space-4\">\n <Text as=\"span\" fontSize=\"body.sm\" fontWeight=\"bold\" color=\"grey.400\">\n {labels.notSpecified}\n </Text>\n <HStack flexWrap=\"wrap\" gap=\"space-4\">\n {notSpecified.map(key => (\n <Text\n key={key}\n as=\"span\"\n fontSize=\"body.sm\"\n color=\"grey.400\"\n border=\"1px solid\"\n borderColor=\"grey.100\"\n px=\"space-8\"\n py=\"2px\"\n borderRadius=\"full\"\n >\n {labels.attributes[key]}\n </Text>\n ))}\n </HStack>\n </VStack>\n )}\n\n {labels.footer && (\n <>\n <Box h=\"1px\" bg=\"grey.100\" mt=\"space-8\" mb=\"space-8\" />\n <Text as=\"span\" fontSize=\"9px\" color=\"grey.300\" style={{ lineHeight: 1 }}>\n {labels.footer}\n </Text>\n </>\n )}\n </Box>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
export type
|
|
1
|
+
export type ScoreSetAttributeKey = 'origin' | 'rawMaterialOrigin' | 'temperature' | 'cutting' | 'cooking' | 'treatment' | 'label' | 'packaging';
|
|
2
|
+
export type ScoreNumericAttributeKey = 'grammageGsm' | 'recycledPct' | 'thicknessMicron';
|
|
3
|
+
export type ScoreAttributeKey = ScoreSetAttributeKey | ScoreNumericAttributeKey;
|
|
4
|
+
/** Proximity bucket for free numeric packaging specs: egal (equal) → non_correspondant (no match). */
|
|
5
|
+
export type ScoreLevel = 'egal' | 'proche' | 'eloigne' | 'non_correspondant';
|
|
2
6
|
export type ScoreAttributeDetail = {
|
|
3
7
|
matched: number | null;
|
|
4
8
|
total: number | null;
|
|
9
|
+
level?: ScoreLevel | null;
|
|
5
10
|
};
|
|
6
11
|
export type ChatScoreBreakdownLabels = {
|
|
7
12
|
title: string;
|
|
8
13
|
compared: string;
|
|
9
14
|
notSpecified: string;
|
|
10
|
-
attributes: Record<
|
|
15
|
+
attributes: Record<ScoreSetAttributeKey, string> & Partial<Record<ScoreNumericAttributeKey, string>>;
|
|
16
|
+
levels?: Record<ScoreLevel, string>;
|
|
11
17
|
footer?: string;
|
|
12
18
|
};
|
|
13
19
|
export type ChatScoreBreakdownProps = {
|
|
14
20
|
percent: number;
|
|
15
|
-
detail: Record<
|
|
21
|
+
detail: Record<string, ScoreAttributeDetail>;
|
|
16
22
|
labels: ChatScoreBreakdownLabels;
|
|
17
23
|
};
|
|
18
24
|
export declare const ChatScoreBreakdown: ({ percent, detail, labels }: ChatScoreBreakdownProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -11,19 +11,53 @@ var s = [
|
|
|
11
11
|
"cooking",
|
|
12
12
|
"treatment",
|
|
13
13
|
"label",
|
|
14
|
-
"packaging"
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
"packaging",
|
|
15
|
+
"grammageGsm",
|
|
16
|
+
"recycledPct",
|
|
17
|
+
"thicknessMicron"
|
|
18
|
+
], c = [
|
|
19
|
+
"temperature",
|
|
20
|
+
"cutting",
|
|
21
|
+
"cooking"
|
|
22
|
+
], l = [
|
|
23
|
+
"grammageGsm",
|
|
24
|
+
"recycledPct",
|
|
25
|
+
"thicknessMicron"
|
|
26
|
+
], u = {
|
|
27
|
+
egal: {
|
|
28
|
+
bg: "#E6F3D9",
|
|
29
|
+
color: "#3B6D11"
|
|
30
|
+
},
|
|
31
|
+
proche: {
|
|
32
|
+
bg: "#F0F6DC",
|
|
33
|
+
color: "#5E8516"
|
|
34
|
+
},
|
|
35
|
+
eloigne: {
|
|
36
|
+
bg: "#FDF0E0",
|
|
37
|
+
color: "#C2740C"
|
|
38
|
+
},
|
|
39
|
+
non_correspondant: {
|
|
40
|
+
bg: "#FCEBEB",
|
|
41
|
+
color: "#A32D2D"
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
function d(e) {
|
|
17
45
|
return e >= 70 ? "#3B6D11" : e >= 40 ? "#854F0B" : "#A32D2D";
|
|
18
46
|
}
|
|
19
|
-
function
|
|
47
|
+
function f(e) {
|
|
20
48
|
return e >= 70 ? "#639922" : e >= 40 ? "#BA7517" : "#E24B4A";
|
|
21
49
|
}
|
|
22
|
-
function
|
|
50
|
+
function p(e) {
|
|
51
|
+
return e?.level != null;
|
|
52
|
+
}
|
|
53
|
+
function m(e) {
|
|
23
54
|
return e?.matched != null && e?.total != null;
|
|
24
55
|
}
|
|
25
|
-
|
|
26
|
-
|
|
56
|
+
function h(e) {
|
|
57
|
+
return p(e) || m(e);
|
|
58
|
+
}
|
|
59
|
+
var g = ({ percent: m, detail: g, labels: _ }) => {
|
|
60
|
+
let v = l.some((e) => g[e]?.level != null), y = new Set(v ? c : l), b = s.filter((e) => !y.has(e)), x = b.filter((e) => h(g[e])), S = b.filter((e) => !h(g[e]) && _.attributes[e] != null);
|
|
27
61
|
return /* @__PURE__ */ o(t, {
|
|
28
62
|
bg: "white",
|
|
29
63
|
borderRadius: "radius-8",
|
|
@@ -40,13 +74,13 @@ var d = ({ percent: d, detail: f, labels: p }) => {
|
|
|
40
74
|
as: "span",
|
|
41
75
|
fontSize: "body.md",
|
|
42
76
|
fontWeight: "bold",
|
|
43
|
-
children:
|
|
77
|
+
children: _.title
|
|
44
78
|
}), /* @__PURE__ */ o(e, {
|
|
45
79
|
as: "span",
|
|
46
80
|
fontSize: "body.lg",
|
|
47
81
|
fontWeight: "medium",
|
|
48
|
-
style: { color:
|
|
49
|
-
children: [Math.round(
|
|
82
|
+
style: { color: d(m) },
|
|
83
|
+
children: [Math.round(m), " %"]
|
|
50
84
|
})]
|
|
51
85
|
}),
|
|
52
86
|
/* @__PURE__ */ a(t, {
|
|
@@ -54,7 +88,7 @@ var d = ({ percent: d, detail: f, labels: p }) => {
|
|
|
54
88
|
bg: "grey.100",
|
|
55
89
|
mb: "space-8"
|
|
56
90
|
}),
|
|
57
|
-
|
|
91
|
+
x.length > 0 && /* @__PURE__ */ o(r, {
|
|
58
92
|
alignItems: "stretch",
|
|
59
93
|
gap: "space-4",
|
|
60
94
|
mb: "space-8",
|
|
@@ -63,9 +97,41 @@ var d = ({ percent: d, detail: f, labels: p }) => {
|
|
|
63
97
|
fontSize: "body.sm",
|
|
64
98
|
fontWeight: "bold",
|
|
65
99
|
color: "grey.400",
|
|
66
|
-
children:
|
|
67
|
-
}),
|
|
68
|
-
let i =
|
|
100
|
+
children: _.compared
|
|
101
|
+
}), x.map((r) => {
|
|
102
|
+
let i = g[r];
|
|
103
|
+
if (p(i)) {
|
|
104
|
+
let s = i.level, c = u[s];
|
|
105
|
+
return /* @__PURE__ */ o(n, {
|
|
106
|
+
alignItems: "center",
|
|
107
|
+
gap: "space-8",
|
|
108
|
+
justify: "space-between",
|
|
109
|
+
children: [/* @__PURE__ */ a(e, {
|
|
110
|
+
as: "span",
|
|
111
|
+
fontSize: "body.sm",
|
|
112
|
+
color: "grey.500",
|
|
113
|
+
minW: "80px",
|
|
114
|
+
children: _.attributes[r]
|
|
115
|
+
}), /* @__PURE__ */ a(t, {
|
|
116
|
+
px: "space-8",
|
|
117
|
+
py: "2px",
|
|
118
|
+
borderRadius: "full",
|
|
119
|
+
flexShrink: "0",
|
|
120
|
+
style: { backgroundColor: c.bg },
|
|
121
|
+
children: /* @__PURE__ */ a(e, {
|
|
122
|
+
as: "span",
|
|
123
|
+
fontSize: "body.sm",
|
|
124
|
+
fontWeight: "medium",
|
|
125
|
+
style: {
|
|
126
|
+
color: c.color,
|
|
127
|
+
whiteSpace: "nowrap"
|
|
128
|
+
},
|
|
129
|
+
children: _.levels?.[s] ?? s
|
|
130
|
+
})
|
|
131
|
+
})]
|
|
132
|
+
}, r);
|
|
133
|
+
}
|
|
134
|
+
let s = i.matched, c = i.total, l = c > 0 ? s / c * 100 : 0;
|
|
69
135
|
return /* @__PURE__ */ o(n, {
|
|
70
136
|
alignItems: "center",
|
|
71
137
|
gap: "space-8",
|
|
@@ -75,7 +141,7 @@ var d = ({ percent: d, detail: f, labels: p }) => {
|
|
|
75
141
|
fontSize: "body.sm",
|
|
76
142
|
color: "grey.500",
|
|
77
143
|
minW: "80px",
|
|
78
|
-
children:
|
|
144
|
+
children: _.attributes[r]
|
|
79
145
|
}),
|
|
80
146
|
/* @__PURE__ */ a(t, {
|
|
81
147
|
flex: "1",
|
|
@@ -87,8 +153,8 @@ var d = ({ percent: d, detail: f, labels: p }) => {
|
|
|
87
153
|
h: "100%",
|
|
88
154
|
borderRadius: "full",
|
|
89
155
|
style: {
|
|
90
|
-
width: `${
|
|
91
|
-
background: l
|
|
156
|
+
width: `${l}%`,
|
|
157
|
+
background: f(l)
|
|
92
158
|
}
|
|
93
159
|
})
|
|
94
160
|
}),
|
|
@@ -98,23 +164,23 @@ var d = ({ percent: d, detail: f, labels: p }) => {
|
|
|
98
164
|
fontWeight: "medium",
|
|
99
165
|
minW: "40px",
|
|
100
166
|
textAlign: "right",
|
|
101
|
-
style: { color: l
|
|
167
|
+
style: { color: f(l) },
|
|
102
168
|
children: [
|
|
103
|
-
|
|
169
|
+
s,
|
|
104
170
|
"/",
|
|
105
|
-
|
|
171
|
+
c
|
|
106
172
|
]
|
|
107
173
|
})
|
|
108
174
|
]
|
|
109
175
|
}, r);
|
|
110
176
|
})]
|
|
111
177
|
}),
|
|
112
|
-
|
|
178
|
+
x.length > 0 && S.length > 0 && /* @__PURE__ */ a(t, {
|
|
113
179
|
h: "1px",
|
|
114
180
|
bg: "grey.100",
|
|
115
181
|
mb: "space-8"
|
|
116
182
|
}),
|
|
117
|
-
|
|
183
|
+
S.length > 0 && /* @__PURE__ */ o(r, {
|
|
118
184
|
alignItems: "stretch",
|
|
119
185
|
gap: "space-4",
|
|
120
186
|
children: [/* @__PURE__ */ a(e, {
|
|
@@ -122,11 +188,11 @@ var d = ({ percent: d, detail: f, labels: p }) => {
|
|
|
122
188
|
fontSize: "body.sm",
|
|
123
189
|
fontWeight: "bold",
|
|
124
190
|
color: "grey.400",
|
|
125
|
-
children:
|
|
191
|
+
children: _.notSpecified
|
|
126
192
|
}), /* @__PURE__ */ a(n, {
|
|
127
193
|
flexWrap: "wrap",
|
|
128
194
|
gap: "space-4",
|
|
129
|
-
children:
|
|
195
|
+
children: S.map((t) => /* @__PURE__ */ a(e, {
|
|
130
196
|
as: "span",
|
|
131
197
|
fontSize: "body.sm",
|
|
132
198
|
color: "grey.400",
|
|
@@ -135,11 +201,11 @@ var d = ({ percent: d, detail: f, labels: p }) => {
|
|
|
135
201
|
px: "space-8",
|
|
136
202
|
py: "2px",
|
|
137
203
|
borderRadius: "full",
|
|
138
|
-
children:
|
|
204
|
+
children: _.attributes[t]
|
|
139
205
|
}, t))
|
|
140
206
|
})]
|
|
141
207
|
}),
|
|
142
|
-
|
|
208
|
+
_.footer && /* @__PURE__ */ o(i, { children: [/* @__PURE__ */ a(t, {
|
|
143
209
|
h: "1px",
|
|
144
210
|
bg: "grey.100",
|
|
145
211
|
mt: "space-8",
|
|
@@ -149,12 +215,12 @@ var d = ({ percent: d, detail: f, labels: p }) => {
|
|
|
149
215
|
fontSize: "9px",
|
|
150
216
|
color: "grey.300",
|
|
151
217
|
style: { lineHeight: 1 },
|
|
152
|
-
children:
|
|
218
|
+
children: _.footer
|
|
153
219
|
})] })
|
|
154
220
|
]
|
|
155
221
|
});
|
|
156
222
|
};
|
|
157
223
|
//#endregion
|
|
158
|
-
export {
|
|
224
|
+
export { g as ChatScoreBreakdown };
|
|
159
225
|
|
|
160
226
|
//# sourceMappingURL=ChatScoreBreakdown.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatScoreBreakdown.js","names":[],"sources":["../../../src/components/chat/ChatScoreBreakdown.tsx"],"sourcesContent":["import { Box, HStack, VStack } from '@stokelp/styled-system/jsx'\nimport { Text } from '~/components'\n\nexport type ScoreAttributeKey =\n | 'origin'\n | 'rawMaterialOrigin'\n | 'temperature'\n | 'cutting'\n | 'cooking'\n | 'treatment'\n | 'label'\n | 'packaging'\n\nexport type ScoreAttributeDetail = {\n matched: number | null\n total: number | null\n}\n\nexport type ChatScoreBreakdownLabels = {\n title: string\n compared: string\n notSpecified: string\n attributes: Record<ScoreAttributeKey, string>\n footer?: string\n}\n\nexport type ChatScoreBreakdownProps = {\n percent: number\n detail: Record<ScoreAttributeKey, ScoreAttributeDetail>\n labels: ChatScoreBreakdownLabels\n}\n\nconst ATTRIBUTE_ORDER: ScoreAttributeKey[] = [\n 'origin',\n 'rawMaterialOrigin',\n 'temperature',\n 'cutting',\n 'cooking',\n 'treatment',\n 'label',\n 'packaging',\n]\n\nfunction getHeadlineColor(percent: number): string {\n if (percent >= 70) return '#3B6D11'\n if (percent >= 40) return '#854F0B'\n return '#A32D2D'\n}\n\nfunction getBarColor(ratioPercent: number): string {\n if (ratioPercent >= 70) return '#639922'\n if (ratioPercent >= 40) return '#BA7517'\n return '#E24B4A'\n}\n\nfunction isComparable(detail?: ScoreAttributeDetail): boolean {\n return detail?.matched != null && detail?.total != null\n}\n\nexport const ChatScoreBreakdown = ({ percent, detail, labels }: ChatScoreBreakdownProps) => {\n const compared = ATTRIBUTE_ORDER.filter(key => isComparable(detail[key]))\n const notSpecified = ATTRIBUTE_ORDER.filter(key => !isComparable(detail[key]))\n\n return (\n <Box\n bg=\"white\"\n borderRadius=\"radius-8\"\n p=\"space-16\"\n minW=\"220px\"\n maxW=\"240px\"\n css={{ '& *': { fontFamily: 'inherit' } }}\n >\n <HStack justify=\"space-between\" alignItems=\"baseline\" mb=\"space-8\">\n <Text as=\"span\" fontSize=\"body.md\" fontWeight=\"bold\">\n {labels.title}\n </Text>\n <Text as=\"span\" fontSize=\"body.lg\" fontWeight=\"medium\" style={{ color: getHeadlineColor(percent) }}>\n {Math.round(percent)} %\n </Text>\n </HStack>\n\n <Box h=\"1px\" bg=\"grey.100\" mb=\"space-8\" />\n\n {compared.length > 0 && (\n <VStack alignItems=\"stretch\" gap=\"space-4\" mb=\"space-8\">\n <Text as=\"span\" fontSize=\"body.sm\" fontWeight=\"bold\" color=\"grey.400\">\n {labels.compared}\n </Text>\n {compared.map(key => {\n const matched = detail[key].matched as number\n const total = detail[key].total as number\n const ratioPercent = total > 0 ? (matched / total) * 100 : 0\n return (\n <HStack key={key} alignItems=\"center\" gap=\"space-8\">\n <Text as=\"span\" fontSize=\"body.sm\" color=\"grey.500\" minW=\"80px\">\n {labels.attributes[key]}\n </Text>\n <Box flex=\"1\" h=\"3px\" bg=\"grey.100\" borderRadius=\"full\" overflow=\"hidden\">\n <Box\n h=\"100%\"\n borderRadius=\"full\"\n style={{ width: `${ratioPercent}%`, background: getBarColor(ratioPercent) }}\n />\n </Box>\n <Text\n as=\"span\"\n fontSize=\"body.sm\"\n fontWeight=\"medium\"\n minW=\"40px\"\n textAlign=\"right\"\n style={{ color: getBarColor(ratioPercent) }}\n >\n {matched}/{total}\n </Text>\n </HStack>\n )\n })}\n </VStack>\n )}\n\n {compared.length > 0 && notSpecified.length > 0 && <Box h=\"1px\" bg=\"grey.100\" mb=\"space-8\" />}\n\n {notSpecified.length > 0 && (\n <VStack alignItems=\"stretch\" gap=\"space-4\">\n <Text as=\"span\" fontSize=\"body.sm\" fontWeight=\"bold\" color=\"grey.400\">\n {labels.notSpecified}\n </Text>\n <HStack flexWrap=\"wrap\" gap=\"space-4\">\n {notSpecified.map(key => (\n <Text\n key={key}\n as=\"span\"\n fontSize=\"body.sm\"\n color=\"grey.400\"\n border=\"1px solid\"\n borderColor=\"grey.100\"\n px=\"space-8\"\n py=\"2px\"\n borderRadius=\"full\"\n >\n {labels.attributes[key]}\n </Text>\n ))}\n </HStack>\n </VStack>\n )}\n\n {labels.footer && (\n <>\n <Box h=\"1px\" bg=\"grey.100\" mt=\"space-8\" mb=\"space-8\" />\n <Text as=\"span\" fontSize=\"9px\" color=\"grey.300\" style={{ lineHeight: 1 }}>\n {labels.footer}\n </Text>\n </>\n )}\n </Box>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ChatScoreBreakdown.js","names":[],"sources":["../../../src/components/chat/ChatScoreBreakdown.tsx"],"sourcesContent":["import { Box, HStack, VStack } from '@stokelp/styled-system/jsx'\nimport { Text } from '~/components'\n\nexport type ScoreSetAttributeKey =\n | 'origin'\n | 'rawMaterialOrigin'\n | 'temperature'\n | 'cutting'\n | 'cooking'\n | 'treatment'\n | 'label'\n | 'packaging'\n\nexport type ScoreNumericAttributeKey = 'grammageGsm' | 'recycledPct' | 'thicknessMicron'\n\nexport type ScoreAttributeKey = ScoreSetAttributeKey | ScoreNumericAttributeKey\n\n/** Proximity bucket for free numeric packaging specs: egal (equal) → non_correspondant (no match). */\nexport type ScoreLevel = 'egal' | 'proche' | 'eloigne' | 'non_correspondant'\n\nexport type ScoreAttributeDetail = {\n matched: number | null\n total: number | null\n level?: ScoreLevel | null\n}\n\nexport type ChatScoreBreakdownLabels = {\n title: string\n compared: string\n notSpecified: string\n attributes: Record<ScoreSetAttributeKey, string> & Partial<Record<ScoreNumericAttributeKey, string>>\n levels?: Record<ScoreLevel, string>\n footer?: string\n}\n\nexport type ChatScoreBreakdownProps = {\n percent: number\n detail: Record<string, ScoreAttributeDetail>\n labels: ChatScoreBreakdownLabels\n}\n\nconst ATTRIBUTE_ORDER: ScoreAttributeKey[] = [\n 'origin',\n 'rawMaterialOrigin',\n 'temperature',\n 'cutting',\n 'cooking',\n 'treatment',\n 'label',\n 'packaging',\n 'grammageGsm',\n 'recycledPct',\n 'thicknessMicron',\n]\n\n// Attributes that only exist for food products; hidden for packaging products.\nconst FOOD_ONLY_KEYS: ScoreAttributeKey[] = ['temperature', 'cutting', 'cooking']\n// Free numeric specs that only exist for packaging products; hidden for food products.\nconst PACKAGING_ONLY_KEYS: ScoreNumericAttributeKey[] = ['grammageGsm', 'recycledPct', 'thicknessMicron']\n\nconst LEVEL_COLORS: Record<ScoreLevel, { bg: string; color: string }> = {\n egal: { bg: '#E6F3D9', color: '#3B6D11' },\n proche: { bg: '#F0F6DC', color: '#5E8516' },\n eloigne: { bg: '#FDF0E0', color: '#C2740C' },\n non_correspondant: { bg: '#FCEBEB', color: '#A32D2D' },\n}\n\nfunction getHeadlineColor(percent: number): string {\n if (percent >= 70) return '#3B6D11'\n if (percent >= 40) return '#854F0B'\n return '#A32D2D'\n}\n\nfunction getBarColor(ratioPercent: number): string {\n if (ratioPercent >= 70) return '#639922'\n if (ratioPercent >= 40) return '#BA7517'\n return '#E24B4A'\n}\n\nfunction hasLevel(detail?: ScoreAttributeDetail): boolean {\n return detail?.level != null\n}\n\nfunction isFraction(detail?: ScoreAttributeDetail): boolean {\n return detail?.matched != null && detail?.total != null\n}\n\nfunction isComparable(detail?: ScoreAttributeDetail): boolean {\n return hasLevel(detail) || isFraction(detail)\n}\n\nexport const ChatScoreBreakdown = ({ percent, detail, labels }: ChatScoreBreakdownProps) => {\n // A packaging product exposes the numeric specs (comparable via level); food attributes\n // then come back fully null and must be hidden entirely, and vice versa.\n const isPackaging = PACKAGING_ONLY_KEYS.some(key => detail[key]?.level != null)\n const hiddenKeys = new Set<ScoreAttributeKey>(isPackaging ? FOOD_ONLY_KEYS : PACKAGING_ONLY_KEYS)\n const visibleKeys = ATTRIBUTE_ORDER.filter(key => !hiddenKeys.has(key))\n\n const compared = visibleKeys.filter(key => isComparable(detail[key]))\n const notSpecified = visibleKeys.filter(key => !isComparable(detail[key]) && labels.attributes[key] != null)\n\n return (\n <Box\n bg=\"white\"\n borderRadius=\"radius-8\"\n p=\"space-16\"\n minW=\"220px\"\n maxW=\"240px\"\n css={{ '& *': { fontFamily: 'inherit' } }}\n >\n <HStack justify=\"space-between\" alignItems=\"baseline\" mb=\"space-8\">\n <Text as=\"span\" fontSize=\"body.md\" fontWeight=\"bold\">\n {labels.title}\n </Text>\n <Text as=\"span\" fontSize=\"body.lg\" fontWeight=\"medium\" style={{ color: getHeadlineColor(percent) }}>\n {Math.round(percent)} %\n </Text>\n </HStack>\n\n <Box h=\"1px\" bg=\"grey.100\" mb=\"space-8\" />\n\n {compared.length > 0 && (\n <VStack alignItems=\"stretch\" gap=\"space-4\" mb=\"space-8\">\n <Text as=\"span\" fontSize=\"body.sm\" fontWeight=\"bold\" color=\"grey.400\">\n {labels.compared}\n </Text>\n {compared.map(key => {\n const entry = detail[key]\n if (hasLevel(entry)) {\n const level = entry.level as ScoreLevel\n const colors = LEVEL_COLORS[level]\n return (\n <HStack key={key} alignItems=\"center\" gap=\"space-8\" justify=\"space-between\">\n <Text as=\"span\" fontSize=\"body.sm\" color=\"grey.500\" minW=\"80px\">\n {labels.attributes[key]}\n </Text>\n <Box px=\"space-8\" py=\"2px\" borderRadius=\"full\" flexShrink=\"0\" style={{ backgroundColor: colors.bg }}>\n <Text\n as=\"span\"\n fontSize=\"body.sm\"\n fontWeight=\"medium\"\n style={{ color: colors.color, whiteSpace: 'nowrap' }}\n >\n {labels.levels?.[level] ?? level}\n </Text>\n </Box>\n </HStack>\n )\n }\n\n const matched = entry.matched as number\n const total = entry.total as number\n const ratioPercent = total > 0 ? (matched / total) * 100 : 0\n return (\n <HStack key={key} alignItems=\"center\" gap=\"space-8\">\n <Text as=\"span\" fontSize=\"body.sm\" color=\"grey.500\" minW=\"80px\">\n {labels.attributes[key]}\n </Text>\n <Box flex=\"1\" h=\"3px\" bg=\"grey.100\" borderRadius=\"full\" overflow=\"hidden\">\n <Box\n h=\"100%\"\n borderRadius=\"full\"\n style={{ width: `${ratioPercent}%`, background: getBarColor(ratioPercent) }}\n />\n </Box>\n <Text\n as=\"span\"\n fontSize=\"body.sm\"\n fontWeight=\"medium\"\n minW=\"40px\"\n textAlign=\"right\"\n style={{ color: getBarColor(ratioPercent) }}\n >\n {matched}/{total}\n </Text>\n </HStack>\n )\n })}\n </VStack>\n )}\n\n {compared.length > 0 && notSpecified.length > 0 && <Box h=\"1px\" bg=\"grey.100\" mb=\"space-8\" />}\n\n {notSpecified.length > 0 && (\n <VStack alignItems=\"stretch\" gap=\"space-4\">\n <Text as=\"span\" fontSize=\"body.sm\" fontWeight=\"bold\" color=\"grey.400\">\n {labels.notSpecified}\n </Text>\n <HStack flexWrap=\"wrap\" gap=\"space-4\">\n {notSpecified.map(key => (\n <Text\n key={key}\n as=\"span\"\n fontSize=\"body.sm\"\n color=\"grey.400\"\n border=\"1px solid\"\n borderColor=\"grey.100\"\n px=\"space-8\"\n py=\"2px\"\n borderRadius=\"full\"\n >\n {labels.attributes[key]}\n </Text>\n ))}\n </HStack>\n </VStack>\n )}\n\n {labels.footer && (\n <>\n <Box h=\"1px\" bg=\"grey.100\" mt=\"space-8\" mb=\"space-8\" />\n <Text as=\"span\" fontSize=\"9px\" color=\"grey.300\" style={{ lineHeight: 1 }}>\n {labels.footer}\n </Text>\n </>\n )}\n </Box>\n )\n}\n"],"mappings":"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"}
|