@memori.ai/memori-react 8.30.1 → 8.32.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.
Files changed (123) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/components/DrawerFooter/DrawerFooter.css +62 -0
  3. package/dist/components/DrawerFooter/DrawerFooter.d.ts +12 -0
  4. package/dist/components/DrawerFooter/DrawerFooter.js +10 -0
  5. package/dist/components/DrawerFooter/DrawerFooter.js.map +1 -0
  6. package/dist/components/Header/Header.css +53 -0
  7. package/dist/components/Header/Header.d.ts +1 -0
  8. package/dist/components/Header/Header.js +74 -3
  9. package/dist/components/Header/Header.js.map +1 -1
  10. package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js +5 -17
  11. package/dist/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js.map +1 -1
  12. package/dist/components/MemoriWidget/MemoriWidget.js +1 -0
  13. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  14. package/dist/components/PositionPopover/PositionPopover.css +194 -0
  15. package/dist/components/PositionPopover/PositionPopover.d.ts +15 -0
  16. package/dist/components/PositionPopover/PositionPopover.js +181 -0
  17. package/dist/components/PositionPopover/PositionPopover.js.map +1 -0
  18. package/dist/components/icons/GasStation.d.ts +6 -0
  19. package/dist/components/icons/GasStation.js +6 -0
  20. package/dist/components/icons/GasStation.js.map +1 -0
  21. package/dist/components/layouts/WebsiteAssistant/WebsiteAssistant.d.ts +4 -0
  22. package/dist/components/layouts/WebsiteAssistant/WebsiteAssistant.js +37 -0
  23. package/dist/components/layouts/WebsiteAssistant/WebsiteAssistant.js.map +1 -0
  24. package/dist/components/layouts/WebsiteAssistant/website-assistant.css +671 -0
  25. package/dist/components/layouts/chat.css +14 -0
  26. package/dist/components/layouts/fullpage.css +119 -0
  27. package/dist/helpers/userMessage.d.ts +2 -0
  28. package/dist/helpers/userMessage.js +23 -0
  29. package/dist/helpers/userMessage.js.map +1 -0
  30. package/dist/icons/FacebookIcon.d.ts +3 -0
  31. package/dist/icons/FacebookIcon.js +6 -0
  32. package/dist/icons/FacebookIcon.js.map +1 -0
  33. package/dist/icons/LinkedinIcon.d.ts +3 -0
  34. package/dist/icons/LinkedinIcon.js +6 -0
  35. package/dist/icons/LinkedinIcon.js.map +1 -0
  36. package/dist/icons/TelegramIcon.d.ts +3 -0
  37. package/dist/icons/TelegramIcon.js +6 -0
  38. package/dist/icons/TelegramIcon.js.map +1 -0
  39. package/dist/icons/TwitterIcon.d.ts +3 -0
  40. package/dist/icons/TwitterIcon.js +6 -0
  41. package/dist/icons/TwitterIcon.js.map +1 -0
  42. package/dist/icons/WhatsappIcon.d.ts +3 -0
  43. package/dist/icons/WhatsappIcon.js +6 -0
  44. package/dist/icons/WhatsappIcon.js.map +1 -0
  45. package/dist/locales/de.json +1 -0
  46. package/dist/locales/en.json +1 -0
  47. package/dist/locales/es.json +1 -0
  48. package/dist/locales/fr.json +1 -0
  49. package/dist/locales/it.json +1 -0
  50. package/dist/testUtils.d.ts +5 -0
  51. package/dist/testUtils.js +18 -0
  52. package/dist/testUtils.js.map +1 -0
  53. package/dist/version.d.ts +1 -1
  54. package/dist/version.js +1 -1
  55. package/esm/components/DrawerFooter/DrawerFooter.css +62 -0
  56. package/esm/components/DrawerFooter/DrawerFooter.d.ts +12 -0
  57. package/esm/components/DrawerFooter/DrawerFooter.js +8 -0
  58. package/esm/components/DrawerFooter/DrawerFooter.js.map +1 -0
  59. package/esm/components/Header/Header.css +53 -0
  60. package/esm/components/Header/Header.d.ts +1 -0
  61. package/esm/components/Header/Header.js +75 -4
  62. package/esm/components/Header/Header.js.map +1 -1
  63. package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js +5 -17
  64. package/esm/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.js.map +1 -1
  65. package/esm/components/MemoriWidget/MemoriWidget.js +1 -0
  66. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  67. package/esm/components/PositionPopover/PositionPopover.css +194 -0
  68. package/esm/components/PositionPopover/PositionPopover.d.ts +15 -0
  69. package/esm/components/PositionPopover/PositionPopover.js +178 -0
  70. package/esm/components/PositionPopover/PositionPopover.js.map +1 -0
  71. package/esm/components/icons/GasStation.d.ts +6 -0
  72. package/esm/components/icons/GasStation.js +4 -0
  73. package/esm/components/icons/GasStation.js.map +1 -0
  74. package/esm/components/layouts/WebsiteAssistant/WebsiteAssistant.d.ts +4 -0
  75. package/esm/components/layouts/WebsiteAssistant/WebsiteAssistant.js +34 -0
  76. package/esm/components/layouts/WebsiteAssistant/WebsiteAssistant.js.map +1 -0
  77. package/esm/components/layouts/WebsiteAssistant/website-assistant.css +671 -0
  78. package/esm/components/layouts/chat.css +14 -0
  79. package/esm/components/layouts/fullpage.css +119 -0
  80. package/esm/helpers/userMessage.d.ts +2 -0
  81. package/esm/helpers/userMessage.js +18 -0
  82. package/esm/helpers/userMessage.js.map +1 -0
  83. package/esm/icons/FacebookIcon.d.ts +3 -0
  84. package/esm/icons/FacebookIcon.js +4 -0
  85. package/esm/icons/FacebookIcon.js.map +1 -0
  86. package/esm/icons/LinkedinIcon.d.ts +3 -0
  87. package/esm/icons/LinkedinIcon.js +4 -0
  88. package/esm/icons/LinkedinIcon.js.map +1 -0
  89. package/esm/icons/TelegramIcon.d.ts +3 -0
  90. package/esm/icons/TelegramIcon.js +4 -0
  91. package/esm/icons/TelegramIcon.js.map +1 -0
  92. package/esm/icons/TwitterIcon.d.ts +3 -0
  93. package/esm/icons/TwitterIcon.js +4 -0
  94. package/esm/icons/TwitterIcon.js.map +1 -0
  95. package/esm/icons/WhatsappIcon.d.ts +3 -0
  96. package/esm/icons/WhatsappIcon.js +4 -0
  97. package/esm/icons/WhatsappIcon.js.map +1 -0
  98. package/esm/locales/de.json +1 -0
  99. package/esm/locales/en.json +1 -0
  100. package/esm/locales/es.json +1 -0
  101. package/esm/locales/fr.json +1 -0
  102. package/esm/locales/it.json +1 -0
  103. package/esm/testUtils.d.ts +5 -0
  104. package/esm/testUtils.js +15 -0
  105. package/esm/testUtils.js.map +1 -0
  106. package/esm/version.d.ts +1 -1
  107. package/esm/version.js +1 -1
  108. package/package.json +1 -1
  109. package/src/components/Header/Header.css +53 -0
  110. package/src/components/Header/Header.stories.tsx +46 -0
  111. package/src/components/Header/Header.tsx +151 -2
  112. package/src/components/MemoriArtifactSystem/ArtifactDrawer.stories.tsx +71 -0
  113. package/src/components/MemoriArtifactSystem/components/ArtifactPreview/ArtifactPreview.tsx +10 -24
  114. package/src/components/MemoriWidget/MemoriWidget.tsx +1 -0
  115. package/src/components/icons/GasStation.tsx +36 -0
  116. package/src/components/layouts/chat.css +14 -0
  117. package/src/components/layouts/layouts.stories.tsx +14 -14
  118. package/src/locales/de.json +1 -0
  119. package/src/locales/en.json +1 -0
  120. package/src/locales/es.json +1 -0
  121. package/src/locales/fr.json +1 -0
  122. package/src/locales/it.json +1 -0
  123. package/src/version.ts +1 -1
@@ -0,0 +1,119 @@
1
+ /* FullPage layout – spacing, typography and structure using global design tokens */
2
+
3
+ .memori-widget.memori-layout-fullpage {
4
+ max-width: var(--memori-layout-max-width);
5
+ padding: var(--memori-spacing-md);
6
+ margin-right: auto;
7
+ margin-left: auto;
8
+ }
9
+
10
+ .memori-widget.memori-layout-fullpage > .memori-spin {
11
+ display: flex;
12
+ height: 100%;
13
+ flex-direction: column;
14
+ gap: var(--memori-spacing-lg);
15
+ }
16
+
17
+ /* Header spacing */
18
+ .memori-widget.memori-layout-fullpage .memori-chat-layout--header {
19
+ min-width: 100%;
20
+ flex-shrink: 0;
21
+ border-radius: var(--memori-radius-box);
22
+ margin-bottom: var(--memori-spacing-md);
23
+ }
24
+
25
+ /* Grid: main + left column (avatar) */
26
+ .memori-widget.memori-layout-fullpage .memori--grid {
27
+ display: flex;
28
+ height: auto;
29
+ height: 95vh;
30
+ min-height: 0;
31
+ flex: 1 1 auto;
32
+ align-items: stretch;
33
+ justify-content: center;
34
+ gap: var(--memori-spacing-xl);
35
+ }
36
+
37
+ .memori-widget.memori-layout-fullpage .memori--grid-column-left {
38
+ width: 50%;
39
+ max-width: 420px;
40
+ flex-shrink: 0;
41
+ margin-right: 0;
42
+ }
43
+
44
+ .memori-widget.memori-layout-fullpage .memori-chat-layout--main {
45
+ display: flex;
46
+ min-width: 0;
47
+ flex: 1;
48
+ flex-direction: column;
49
+ align-items: center;
50
+ justify-content: center;
51
+ }
52
+
53
+ .memori-widget.memori-layout-fullpage .memori-chat-layout--controls {
54
+ display: flex;
55
+ width: 100%;
56
+ max-width: 720px;
57
+ flex-direction: column;
58
+ align-items: center;
59
+ padding: var(--memori-spacing-md);
60
+ }
61
+
62
+ .memori-widget.memori-layout-fullpage .memori-chat-layout--controls .memori--start-panel,
63
+ .memori-widget.memori-layout-fullpage .memori-chat-layout--controls .memori-chat--wrapper {
64
+ width: 100%;
65
+ max-width: 100%;
66
+ padding: 0 !important;
67
+ margin-right: 0;
68
+ margin-left: 0;
69
+ }
70
+
71
+ /* Typography: title and description in fullpage left column */
72
+ .memori-widget.memori-layout-fullpage .memori--title {
73
+ margin-bottom: var(--memori-spacing-xs);
74
+ color: var(--memori-text-color);
75
+ font-size: var(--memori-text-size-heading-large);
76
+ font-weight: var(--memori-text-weight-semibold);
77
+ line-height: var(--memori-text-line-tight);
78
+ }
79
+
80
+ .memori-widget.memori-layout-fullpage .memori--description,
81
+ .memori-widget.memori-layout-fullpage .memori--needsPosition {
82
+ padding: var(--memori-spacing-lg);
83
+ padding-top: var(--memori-spacing-xs);
84
+ color: var(--memori-text-color);
85
+ font-size: var(--memori-text-size-base);
86
+ line-height: var(--memori-text-line-relaxed);
87
+ }
88
+
89
+ /* Powered-by position in fullpage */
90
+ .memori-widget.memori-layout-fullpage .memori--powered-by {
91
+ flex-shrink: 0;
92
+ padding: var(--memori-spacing-sm) var(--memori-spacing-md);
93
+ border-radius: var(--memori-radius-box);
94
+ font-size: var(--memori-text-size-small);
95
+ }
96
+
97
+ @media (max-width: 870px) {
98
+ .memori-widget.memori-layout-fullpage {
99
+ padding: var(--memori-spacing-sm);
100
+ }
101
+
102
+ .memori-widget.memori-layout-fullpage > .memori-spin {
103
+ gap: var(--memori-spacing-md);
104
+ }
105
+
106
+ .memori-widget.memori-layout-fullpage .memori--grid-column-left {
107
+ display: none;
108
+ }
109
+
110
+ .memori-widget.memori-layout-fullpage .memori-chat-layout--controls {
111
+ padding: var(--memori-spacing-sm);
112
+ }
113
+ }
114
+
115
+ @media (max-width: 480px) {
116
+ .memori-widget.memori-layout-fullpage .memori-chat-layout--controls {
117
+ padding: var(--memori-spacing-xs);
118
+ }
119
+ }
@@ -0,0 +1,2 @@
1
+ export declare function sanitizeUserMessageInput(raw: string): string;
2
+ export declare function formatUserBubbleHtml(cleanText: string): string;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sanitizeUserMessageInput = sanitizeUserMessageInput;
4
+ exports.formatUserBubbleHtml = formatUserBubbleHtml;
5
+ const tslib_1 = require("tslib");
6
+ const dompurify_1 = tslib_1.__importDefault(require("dompurify"));
7
+ const utils_1 = require("./utils");
8
+ const message_1 = require("./message");
9
+ function sanitizeUserMessageInput(raw) {
10
+ if (raw == null || typeof raw !== 'string') {
11
+ return '';
12
+ }
13
+ const stripped = dompurify_1.default.sanitize(raw, {
14
+ ALLOWED_TAGS: [],
15
+ ALLOWED_ATTR: [],
16
+ });
17
+ return stripped.trim();
18
+ }
19
+ function formatUserBubbleHtml(cleanText) {
20
+ const truncated = (0, message_1.truncateMessagePlain)(cleanText);
21
+ return (0, utils_1.escapeHTML)(truncated).replace(/\n/g, '<br />');
22
+ }
23
+ //# sourceMappingURL=userMessage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"userMessage.js","sourceRoot":"","sources":["../../src/helpers/userMessage.ts"],"names":[],"mappings":";;AAQA,4DASC;AAGD,oDAGC;;AAvBD,kEAAkC;AAClC,mCAAqC;AACrC,uCAAiD;AAMjD,SAAgB,wBAAwB,CAAC,GAAW;IAClD,IAAI,GAAG,IAAI,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC3C,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,QAAQ,GAAG,mBAAS,CAAC,QAAQ,CAAC,GAAG,EAAE;QACvC,YAAY,EAAE,EAAE;QAChB,YAAY,EAAE,EAAE;KACjB,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAGD,SAAgB,oBAAoB,CAAC,SAAiB;IACpD,MAAM,SAAS,GAAG,IAAA,8BAAoB,EAAC,SAAS,CAAC,CAAC;IAClD,OAAO,IAAA,kBAAU,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AACxD,CAAC"}
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ declare const FacebookIcon: (props: React.SVGProps<SVGSVGElement>) => JSX.Element;
3
+ export default FacebookIcon;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jsx_runtime_1 = require("react/jsx-runtime");
4
+ const FacebookIcon = (props) => ((0, jsx_runtime_1.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: 800, height: 800, fill: "currentColor", viewBox: "0 0 24 24", ...props, children: [(0, jsx_runtime_1.jsx)("path", { fill: "currentColor", d: "M17.3 9.6a1 1 0 1 0-1.6-1.2l-2.308 3.078-2.185-2.185A1 1 0 0 0 9.7 9.4l-3 4a1 1 0 0 0 1.6 1.2l2.308-3.078 2.185 2.185A1 1 0 0 0 14.3 13.6l3-4Z" }), (0, jsx_runtime_1.jsx)("path", { fill: "currentColor", fillRule: "evenodd", d: "M12 23c-1.224 0-1.9-.131-3-.5l-2.106 1.053A2 2 0 0 1 4 21.763V19.5c-2.153-2.008-3-4.323-3-7.5C1 5.925 5.925 1 12 1s11 4.925 11 11-4.925 11-11 11Zm-6-4.37-.636-.593C3.691 16.477 3 14.733 3 12a9 9 0 1 1 9 9c-.986 0-1.448-.089-2.364-.396l-.788-.264L6 21.764V18.63Z", clipRule: "evenodd" })] }));
5
+ exports.default = FacebookIcon;
6
+ //# sourceMappingURL=FacebookIcon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FacebookIcon.js","sourceRoot":"","sources":["../../src/icons/FacebookIcon.tsx"],"names":[],"mappings":";;;AACA,MAAM,YAAY,GAAG,CAAC,KAAoC,EAAE,EAAE,CAAC,CAC7D,iCACE,KAAK,EAAC,4BAA4B,EAClC,KAAK,EAAE,GAAG,EACV,MAAM,EAAE,GAAG,EACX,IAAI,EAAC,cAAc,EACnB,OAAO,EAAC,WAAW,KACf,KAAK,aAET,iCACE,IAAI,EAAC,cAAc,EACnB,CAAC,EAAC,gJAAgJ,GAClJ,EACF,iCACE,IAAI,EAAC,cAAc,EACnB,QAAQ,EAAC,SAAS,EAClB,CAAC,EAAC,uQAAuQ,EACzQ,QAAQ,EAAC,SAAS,GAClB,IACE,CACP,CAAA;AACD,kBAAe,YAAY,CAAA"}
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ declare const LinkedinIcon: (props: React.SVGProps<SVGSVGElement>) => JSX.Element;
3
+ export default LinkedinIcon;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jsx_runtime_1 = require("react/jsx-runtime");
4
+ const LinkedinIcon = (props) => ((0, jsx_runtime_1.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: 800, height: 800, fill: "currentColor", viewBox: "0 0 24 24", ...props, children: [(0, jsx_runtime_1.jsx)("path", { fill: "currentColor", d: "M6.5 8a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM5 10a1 1 0 0 1 1-1h1a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1v-8ZM11 19h1a1 1 0 0 0 1-1v-4.5c0-1.5 3-2.5 3-.5v5a1 1 0 0 0 1 1h1a1 1 0 0 0 1-1v-6c0-2-1.5-3-3.5-3S13 10.5 13 10.5V10a1 1 0 0 0-1-1h-1a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1Z" }), (0, jsx_runtime_1.jsx)("path", { fill: "currentColor", fillRule: "evenodd", d: "M20 1a3 3 0 0 1 3 3v16a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V4a3 3 0 0 1 3-3h16Zm0 2a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h16Z", clipRule: "evenodd" })] }));
5
+ exports.default = LinkedinIcon;
6
+ //# sourceMappingURL=LinkedinIcon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LinkedinIcon.js","sourceRoot":"","sources":["../../src/icons/LinkedinIcon.tsx"],"names":[],"mappings":";;;AACA,MAAM,YAAY,GAAG,CAAC,KAAoC,EAAE,EAAE,CAAC,CAC7D,iCACE,KAAK,EAAC,4BAA4B,EAClC,KAAK,EAAE,GAAG,EACV,MAAM,EAAE,GAAG,EACX,IAAI,EAAC,cAAc,EACnB,OAAO,EAAC,WAAW,KACf,KAAK,aAET,iCACE,IAAI,EAAC,cAAc,EACnB,CAAC,EAAC,sRAAsR,GACxR,EACF,iCACE,IAAI,EAAC,cAAc,EACnB,QAAQ,EAAC,SAAS,EAClB,CAAC,EAAC,iJAAiJ,EACnJ,QAAQ,EAAC,SAAS,GAClB,IACE,CACP,CAAA;AACD,kBAAe,YAAY,CAAA"}
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ declare const TelegramIcon: (props: React.SVGProps<SVGSVGElement>) => JSX.Element;
3
+ export default TelegramIcon;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jsx_runtime_1 = require("react/jsx-runtime");
4
+ const TelegramIcon = (props) => ((0, jsx_runtime_1.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", width: 800, height: 800, fill: "currentColor", viewBox: "0 0 24 24", ...props, children: (0, jsx_runtime_1.jsx)("path", { fill: "currentColor", fillRule: "evenodd", d: "M23.112 4.494c.318-1.55-1.205-2.837-2.68-2.267L2.342 9.216c-1.647.637-1.72 2.941-.117 3.682l3.94 1.818 1.873 6.559a1 1 0 0 0 1.67.432l2.886-2.887 4.043 3.033a2 2 0 0 0 3.16-1.198l3.315-16.16ZM3.063 11.082l18.09-6.99-3.316 16.161L13.1 16.7a1 1 0 0 0-1.307.093l-1.236 1.236.371-2.043 7.28-7.279a1 1 0 0 0-1.204-1.575L6.95 12.876l-3.888-1.794Zm5.114 3.397.606 2.123.233-1.281a1 1 0 0 1 .277-.528l2.22-2.22-3.336 1.906Z", clipRule: "evenodd" }) }));
5
+ exports.default = TelegramIcon;
6
+ //# sourceMappingURL=TelegramIcon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TelegramIcon.js","sourceRoot":"","sources":["../../src/icons/TelegramIcon.tsx"],"names":[],"mappings":";;;AACA,MAAM,YAAY,GAAG,CAAC,KAAoC,EAAE,EAAE,CAAC,CAC7D,gCACE,KAAK,EAAC,4BAA4B,EAClC,KAAK,EAAE,GAAG,EACV,MAAM,EAAE,GAAG,EACX,IAAI,EAAC,cAAc,EACnB,OAAO,EAAC,WAAW,KACf,KAAK,YAET,iCACE,IAAI,EAAC,cAAc,EACnB,QAAQ,EAAC,SAAS,EAClB,CAAC,EAAC,iaAAia,EACna,QAAQ,EAAC,SAAS,GAClB,GACE,CACP,CAAA;AACD,kBAAe,YAAY,CAAA"}
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ declare const TwitterIcon: (props: React.SVGProps<SVGSVGElement>) => JSX.Element;
3
+ export default TwitterIcon;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jsx_runtime_1 = require("react/jsx-runtime");
4
+ const TwitterIcon = (props) => ((0, jsx_runtime_1.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: 800, height: 800, fill: "currentColor", viewBox: "0 0 100 100", ...props, children: [(0, jsx_runtime_1.jsx)("path", { fill: "currentColor", d: "M69.7 8.7H30.4C18.7 8.7 9.1 18.2 9.1 30v41.2c0 11.7 9.5 21.3 21.3 21.3h39.4c11.7 0 21.3-9.5 21.3-21.3V29.9C91 18.2 81.5 8.7 69.7 8.7zm7.1 69.6H61.4c-.1 0-.2 0-.2-.1L46.8 57.3h-.1C40.9 64 35.2 70.6 29.6 77.1c-.3.4-.7.7-1 1-.1.1-.2.1-.3.1h-4.2c-.1 0-.2 0-.1-.1l20.5-23.8c.1-.1.1-.2 0-.3L24.1 24.3v-.1h15.5c.1 0 .1 0 .2.1L53.4 44h.1l16.9-19.7c.1-.1.2-.1.3-.1h4.2c.2 0 .2.1.1.2L55.6 46.9c-.1.1-.1.2 0 .3l21.3 31s0 .1-.1.1z" }), (0, jsx_runtime_1.jsx)("path", { d: "M37.8 27.8h-6.7c-.1 0-.1.1-.1.2l32.2 46.7H69.9c.1 0 .1-.1.1-.2L37.8 27.8z" })] }));
5
+ exports.default = TwitterIcon;
6
+ //# sourceMappingURL=TwitterIcon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TwitterIcon.js","sourceRoot":"","sources":["../../src/icons/TwitterIcon.tsx"],"names":[],"mappings":";;;AACA,MAAM,WAAW,GAAG,CAAC,KAAoC,EAAE,EAAE,CAAC,CAC5D,iCAAK,KAAK,EAAC,4BAA4B,EAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAC,cAAc,EAAC,OAAO,EAAC,aAAa,KAAK,KAAK,aAClH,iCAAM,IAAI,EAAC,cAAc,EAAC,CAAC,EAAC,oaAAoa,GAAG,EACnc,iCAAM,CAAC,EAAC,2EAA2E,GAAG,IAClF,CACP,CAAA;AACD,kBAAe,WAAW,CAAA"}
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ declare const WhatsappIcon: (props: React.SVGProps<SVGSVGElement>) => JSX.Element;
3
+ export default WhatsappIcon;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jsx_runtime_1 = require("react/jsx-runtime");
4
+ const WhatsappIcon = (props) => ((0, jsx_runtime_1.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: 800, height: 800, fill: "currentColor", viewBox: "0 0 24 24", ...props, children: [(0, jsx_runtime_1.jsx)("path", { fill: "currentColor", d: "M6.014 8.006c.114-.904 1.289-2.132 2.22-1.996V6.01c.907.172 1.625 1.734 2.03 2.436.286.509.1 1.025-.167 1.243-.361.29-.926.692-.808 1.095C9.5 11.5 12 14 13.23 14.711c.466.269.804-.44 1.092-.804.21-.28.726-.447 1.234-.171.759.442 1.474.956 2.135 1.534.33.276.408.684.179 1.115-.403.76-1.569 1.76-2.415 1.557C13.976 17.587 8 15.27 6.08 8.558c-.108-.318-.08-.438-.066-.552Z" }), (0, jsx_runtime_1.jsx)("path", { fill: "currentColor", fillRule: "evenodd", d: "M12 23c-1.224 0-1.9-.131-3-.5l-2.106 1.053A2 2 0 0 1 4 21.763V19.5c-2.153-2.008-3-4.323-3-7.5C1 5.925 5.925 1 12 1s11 4.925 11 11-4.925 11-11 11Zm-6-4.37-.636-.593C3.691 16.477 3 14.733 3 12a9 9 0 1 1 9 9c-.986 0-1.448-.089-2.364-.396l-.788-.264L6 21.764V18.63Z", clipRule: "evenodd" })] }));
5
+ exports.default = WhatsappIcon;
6
+ //# sourceMappingURL=WhatsappIcon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WhatsappIcon.js","sourceRoot":"","sources":["../../src/icons/WhatsappIcon.tsx"],"names":[],"mappings":";;;AACA,MAAM,YAAY,GAAG,CAAC,KAAoC,EAAE,EAAE,CAAC,CAC7D,iCACE,KAAK,EAAC,4BAA4B,EAClC,KAAK,EAAE,GAAG,EACV,MAAM,EAAE,GAAG,EACX,IAAI,EAAC,cAAc,EACnB,OAAO,EAAC,WAAW,KACf,KAAK,aAET,iCACE,IAAI,EAAC,cAAc,EACnB,CAAC,EAAC,oXAAoX,GACtX,EACF,iCACE,IAAI,EAAC,cAAc,EACnB,QAAQ,EAAC,SAAS,EAClB,CAAC,EAAC,uQAAuQ,EACzQ,QAAQ,EAAC,SAAS,GAClB,IACE,CACP,CAAA;AACD,kBAAe,YAAY,CAAA"}
@@ -383,6 +383,7 @@
383
383
  "co2": "CO2",
384
384
  "water": "Wasser",
385
385
  "usageBadgesHint": "Klicke auf einen dieser Buttons, um mehr Informationen zu sehen",
386
+ "totalChatConsumptionTitle": "Gesamter Chat-Verbrauch",
386
387
  "impactComparisonUnavailable": "Indikativer Vergleich nicht verfuegbar.",
387
388
  "impactComparisonEnergy": "Indikativer Vergleich: in etwa wie eine 10-W-LED-Lampe fuer {{duration}} eingeschaltet lassen.",
388
389
  "impactComparisonCo2": "Indikativer Vergleich: etwa {{distance}} mit einem durchschnittlichen Benzinauto gefahren.",
@@ -454,6 +454,7 @@
454
454
  "co2": "CO2",
455
455
  "water": "Water",
456
456
  "usageBadgesHint": "Click one of these buttons to show more information",
457
+ "totalChatConsumptionTitle": "Total Chat Consumption",
457
458
  "impactComparisonUnavailable": "Indicative comparison unavailable.",
458
459
  "impactComparisonEnergy": "Indicative comparison: roughly like keeping a 10 W LED bulb on for {{duration}}.",
459
460
  "impactComparisonCo2": "Indicative comparison: about {{distance}} traveled by an average gasoline car.",
@@ -410,6 +410,7 @@
410
410
  "co2": "CO2",
411
411
  "water": "Agua",
412
412
  "usageBadgesHint": "Haz clic en uno de estos botones para ver más información",
413
+ "totalChatConsumptionTitle": "Consumo Total del Chat",
413
414
  "impactComparisonUnavailable": "Comparacion indicativa no disponible.",
414
415
  "impactComparisonEnergy": "Comparacion indicativa: aproximadamente como mantener encendida una bombilla LED de 10 W durante {{duration}}.",
415
416
  "impactComparisonCo2": "Comparacion indicativa: aproximadamente {{distance}} recorridos en un coche de gasolina promedio.",
@@ -418,6 +418,7 @@
418
418
  "co2": "CO2",
419
419
  "water": "Eau",
420
420
  "usageBadgesHint": "Cliquez sur un de ces boutons pour afficher plus d'informations",
421
+ "totalChatConsumptionTitle": "Consommation Totale du Chat",
421
422
  "impactComparisonUnavailable": "Comparaison indicative non disponible.",
422
423
  "impactComparisonEnergy": "Comparaison indicative : environ comme laisser allumee une ampoule LED de 10 W pendant {{duration}}.",
423
424
  "impactComparisonCo2": "Comparaison indicative : environ {{distance}} parcourus en voiture essence moyenne.",
@@ -450,6 +450,7 @@
450
450
  "co2": "CO2",
451
451
  "water": "Acqua",
452
452
  "usageBadgesHint": "Clicca uno di questi pulsanti per mostrare maggiori informazioni",
453
+ "totalChatConsumptionTitle": "Consumo Totale Chat",
453
454
  "impactComparisonUnavailable": "Confronto indicativo non disponibile.",
454
455
  "impactComparisonEnergy": "Confronto indicativo: circa quanto tenere accesa una lampadina LED da 10 W per {{duration}}.",
455
456
  "impactComparisonCo2": "Confronto indicativo: circa {{distance}} percorsi in auto a benzina media.",
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import { RenderOptions, RenderResult } from '@testing-library/react';
3
+ declare function render(ui: React.ReactElement, options?: Omit<RenderOptions, 'wrapper'>): RenderResult;
4
+ export * from '@testing-library/react';
5
+ export { render };
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.render = render;
4
+ const tslib_1 = require("tslib");
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const react_1 = require("@testing-library/react");
7
+ const ui_1 = require("@memori.ai/ui");
8
+ function AlertProviderWrapper({ children }) {
9
+ return ((0, jsx_runtime_1.jsxs)(ui_1.AlertProvider, { children: [children, (0, jsx_runtime_1.jsx)(ui_1.AlertViewport, {})] }));
10
+ }
11
+ function render(ui, options) {
12
+ return (0, react_1.render)(ui, {
13
+ wrapper: AlertProviderWrapper,
14
+ ...options,
15
+ });
16
+ }
17
+ tslib_1.__exportStar(require("@testing-library/react"), exports);
18
+ //# sourceMappingURL=testUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testUtils.js","sourceRoot":"","sources":["../src/testUtils.tsx"],"names":[],"mappings":";;AAyCS,wBAAM;;;AAxCf,kDAIgC;AAChC,sCAA6D;AAM7D,SAAS,oBAAoB,CAAC,EAAE,QAAQ,EAAiC;IACvE,OAAO,CACL,wBAAC,kBAAa,eACX,QAAQ,EACT,uBAAC,kBAAa,KAAG,IACH,CACjB,CAAC;AACJ,CAAC;AAUD,SAAS,MAAM,CACb,EAAsB,EACtB,OAAwC;IAExC,OAAO,IAAA,cAAS,EAAC,EAAE,EAAE;QACnB,OAAO,EAAE,oBAAoB;QAC7B,GAAG,OAAO;KACX,CAAC,CAAC;AACL,CAAC;AAGD,iEAAuC"}
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "8.30.1";
1
+ export declare const version = "8.32.0";
package/dist/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.version = void 0;
4
- exports.version = '8.30.1';
4
+ exports.version = '8.32.0';
5
5
  //# sourceMappingURL=version.js.map
@@ -0,0 +1,62 @@
1
+ .memori-drawer-footer {
2
+ flex-shrink: 0;
3
+ padding: var(--memori-spacing-md);
4
+ border-top: 1px solid var(--memori-border-color, #e5e7eb);
5
+ box-shadow: 0 -8px 24px -8px rgba(0, 0, 0, 0.06), 0 -2px 8px -2px rgba(0, 0, 0, 0.03);
6
+ }
7
+
8
+ .memori-drawer-footer__inner {
9
+ display: flex;
10
+ flex-direction: row;
11
+ flex-wrap: wrap;
12
+ align-items: center;
13
+ justify-content: space-between;
14
+ gap: var(--memori-spacing-lg);
15
+ }
16
+
17
+ .memori-drawer-footer__start {
18
+ display: flex;
19
+ align-items: center;
20
+ gap: var(--memori-spacing-md);
21
+ }
22
+
23
+ .memori-drawer-footer__end {
24
+ display: flex;
25
+ align-items: center;
26
+ justify-content: flex-end;
27
+ margin-left: auto;
28
+ gap: var(--memori-spacing-md);
29
+ }
30
+
31
+ .memori-drawer-footer__end .memori-button {
32
+ min-height: 44px;
33
+ padding: 10px var(--memori-spacing-lg);
34
+ border-radius: 10px;
35
+ font-weight: 500;
36
+ transition: transform 0.15s ease, box-shadow 0.15s ease;
37
+ }
38
+
39
+ .memori-drawer-footer__end .memori-button:hover:not([disabled]) {
40
+ transform: translateY(-1px);
41
+ }
42
+
43
+ .memori-drawer-footer__inner--centered {
44
+ justify-content: center;
45
+ }
46
+
47
+ @media (max-width: 768px) {
48
+ .memori-drawer-footer {
49
+ padding: var(--memori-spacing-md) var(--memori-spacing-lg);
50
+ }
51
+
52
+ .memori-drawer-footer__inner {
53
+ flex-direction: column;
54
+ align-items: stretch;
55
+ gap: var(--memori-spacing-md);
56
+ }
57
+
58
+ .memori-drawer-footer__end {
59
+ justify-content: flex-end;
60
+ margin-left: 0;
61
+ }
62
+ }
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ export interface DrawerFooterProps {
3
+ children?: React.ReactNode;
4
+ start?: React.ReactNode;
5
+ end?: React.ReactNode;
6
+ center?: React.ReactNode;
7
+ closeLabel?: string;
8
+ onClose?: () => void;
9
+ className?: string;
10
+ }
11
+ declare const DrawerFooter: React.FC<DrawerFooterProps>;
12
+ export default DrawerFooter;
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from '@memori.ai/ui';
3
+ const DrawerFooter = ({ children, start, end, center, closeLabel, onClose, className = '', }) => {
4
+ const hasSlots = start != null || end != null || center != null || closeLabel != null;
5
+ return (_jsx("footer", { className: `memori-drawer-footer ${className}`.trim(), role: "contentinfo", children: center != null ? (_jsx("div", { className: "memori-drawer-footer__inner memori-drawer-footer__inner--centered", children: center })) : children != null && !hasSlots ? (_jsx("div", { className: "memori-drawer-footer__inner memori-drawer-footer__inner--centered", children: children })) : (_jsxs("div", { className: "memori-drawer-footer__inner", children: [start != null && (_jsx("div", { className: "memori-drawer-footer__start", children: start })), _jsxs("div", { className: "memori-drawer-footer__end", children: [end, closeLabel != null && onClose != null && (_jsx(Button, { variant: "primary", onClick: onClose, children: closeLabel }))] })] })) }));
6
+ };
7
+ export default DrawerFooter;
8
+ //# sourceMappingURL=DrawerFooter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DrawerFooter.js","sourceRoot":"","sources":["../../../src/components/DrawerFooter/DrawerFooter.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAgBvC,MAAM,YAAY,GAAgC,CAAC,EACjD,QAAQ,EACR,KAAK,EACL,GAAG,EACH,MAAM,EACN,UAAU,EACV,OAAO,EACP,SAAS,GAAG,EAAE,GACf,EAAE,EAAE;IACH,MAAM,QAAQ,GAAG,KAAK,IAAI,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,UAAU,IAAI,IAAI,CAAC;IAEtF,OAAO,CACL,iBACE,SAAS,EAAE,wBAAwB,SAAS,EAAE,CAAC,IAAI,EAAE,EACrD,IAAI,EAAC,aAAa,YAEjB,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,CAChB,cAAK,SAAS,EAAC,mEAAmE,YAC/E,MAAM,GACH,CACP,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAClC,cAAK,SAAS,EAAC,mEAAmE,YAC/E,QAAQ,GACL,CACP,CAAC,CAAC,CAAC,CACF,eAAK,SAAS,EAAC,6BAA6B,aACzC,KAAK,IAAI,IAAI,IAAI,CAChB,cAAK,SAAS,EAAC,6BAA6B,YAAE,KAAK,GAAO,CAC3D,EACD,eAAK,SAAS,EAAC,2BAA2B,aACvC,GAAG,EACH,UAAU,IAAI,IAAI,IAAI,OAAO,IAAI,IAAI,IAAI,CACxC,KAAC,MAAM,IAAC,OAAO,EAAC,SAAS,EAAC,OAAO,EAAE,OAAO,YACvC,UAAU,GACJ,CACV,IACG,IACF,CACP,GACM,CACV,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -97,10 +97,18 @@
97
97
  }
98
98
  }
99
99
 
100
+ .memori-header--button--sustainability-icon {
101
+ width: 1em;
102
+ color: currentColor;
103
+ }
100
104
  .memori-header .memori-header--button--position {
101
105
  margin-right: 0;
102
106
  }
103
107
 
108
+ .memori-header--button--sustainability{
109
+ max-height: 37px;
110
+ }
111
+
104
112
 
105
113
  .memori-dropdown--avatar-input{
106
114
  position: absolute;
@@ -124,3 +132,48 @@
124
132
  .memori-dropdown--avatar-initial:hover + .memori-dropdown--avatar-input,.memori-dropdown--avatar:hover + .memori-dropdown--avatar-input{
125
133
  display: block;
126
134
  }
135
+
136
+ .memori-dropdown--sustainability {
137
+ min-width: 260px;
138
+ padding: 0.625rem 0.75rem;
139
+ border-radius: 8px;
140
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.96) 0%, rgba(247, 249, 252, 0.96) 100%);
141
+ }
142
+
143
+ .memori-dropdown--sustainability-title {
144
+ margin: 0 0 0.5rem 0;
145
+ font-size: 0.95rem;
146
+ font-weight: 700;
147
+ line-height: 1.2;
148
+ text-align: center;
149
+ }
150
+
151
+ .memori-dropdown--sustainability-metrics {
152
+ display: flex;
153
+ flex-direction: column;
154
+ gap: 0.35rem;
155
+ }
156
+
157
+ .memori-dropdown--sustainability-row {
158
+ display: flex;
159
+ align-items: center;
160
+ justify-content: space-between;
161
+ padding: 0.4rem 0.5rem;
162
+ border-radius: 6px;
163
+ background: rgba(255, 255, 255, 0.8);
164
+ gap: 1rem;
165
+ }
166
+
167
+ .memori-dropdown--sustainability-label {
168
+ display: inline-flex;
169
+ align-items: center;
170
+ font-size: 0.82rem;
171
+ font-weight: 500;
172
+ gap: 0.35rem;
173
+ opacity: 0.9;
174
+ }
175
+
176
+ .memori-dropdown--sustainability-value {
177
+ font-size: 0.85rem;
178
+ white-space: nowrap;
179
+ }
@@ -34,6 +34,7 @@ export interface Props {
34
34
  apiClient: ReturnType<typeof memoriApiClient>;
35
35
  layout?: WidgetProps['layout'];
36
36
  additionalSettings?: WidgetProps['additionalSettings'];
37
+ showMessageConsumption?: boolean;
37
38
  }
38
39
  declare const Header: React.FC<Props>;
39
40
  export default Header;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useState } from 'react';
2
+ import { useCallback, useEffect, useMemo, useState } from 'react';
3
3
  import cx from 'classnames';
4
4
  import Button from '../ui/Button';
5
5
  import Dropdown from '../ui/Dropdown';
@@ -17,15 +17,86 @@ import DeepThought from '../icons/DeepThought';
17
17
  import Group from '../icons/Group';
18
18
  import UserIcon from '../icons/User';
19
19
  import MessageIcon from '../icons/Message';
20
+ import GasStation from '../icons/GasStation';
20
21
  import Logout from '../icons/Logout';
21
22
  import { getErrori18nKey } from '../../helpers/error';
22
23
  import toast from 'react-hot-toast';
24
+ import { BADGE_EMOJI } from '../../helpers/llmUsage';
23
25
  const imgMimeTypes = ['image/jpeg', 'image/png', 'image/jpg', 'image/gif'];
24
- const Header = ({ className, memori, tenant, history, position, setShowPositionDrawer, setShowSettingsDrawer, setShowChatHistoryDrawer, setShowKnownFactsDrawer, setShowExpertsDrawer, enableAudio = true, speakerMuted, setSpeakerMuted, hasUserActivatedSpeak = false, showShare = true, showSettings = true, showReload = false, showClear = false, showLogin = true, setShowLoginDrawer, clearHistory, loginToken, user, sessionID, showChatHistory = true, fullScreenHandler, baseUrl, onLogout, apiClient, layout, additionalSettings, }) => {
25
- const { t } = useTranslation();
26
+ const Header = ({ className, memori, tenant, history, position, setShowPositionDrawer, setShowSettingsDrawer, setShowChatHistoryDrawer, setShowKnownFactsDrawer, setShowExpertsDrawer, enableAudio = true, speakerMuted, setSpeakerMuted, hasUserActivatedSpeak = false, showShare = true, showSettings = true, showReload = false, showClear = false, showLogin = true, setShowLoginDrawer, clearHistory, loginToken, user, sessionID, showChatHistory = true, fullScreenHandler, baseUrl, onLogout, apiClient, layout, additionalSettings, showMessageConsumption = false, }) => {
27
+ const { t, i18n } = useTranslation();
26
28
  const { uploadAsset, pwlUpdateUser } = apiClient.backend;
27
29
  const [fullScreenAvailable, setFullScreenAvailable] = useState(false);
28
30
  const [fullScreen, setFullScreen] = useState(false);
31
+ const getMetricValue = (metric) => {
32
+ if (typeof metric === 'number' && Number.isFinite(metric))
33
+ return metric;
34
+ if (!metric || typeof metric !== 'object')
35
+ return undefined;
36
+ if (typeof metric.parsedValue === 'number' &&
37
+ Number.isFinite(metric.parsedValue)) {
38
+ return metric.parsedValue;
39
+ }
40
+ if (typeof metric.source === 'string') {
41
+ const parsed = Number(metric.source);
42
+ if (Number.isFinite(parsed))
43
+ return parsed;
44
+ }
45
+ return undefined;
46
+ };
47
+ const formatMetricValue = (value, locale) => new Intl.NumberFormat(locale, {
48
+ minimumFractionDigits: 0,
49
+ maximumFractionDigits: Math.abs(value) >= 1 ? 3 : 4,
50
+ }).format(value);
51
+ const formatImpactInReadableUnit = (value, metricType, locale) => {
52
+ const absValue = Math.abs(value);
53
+ if (metricType === 'energy') {
54
+ if (absValue >= 1)
55
+ return `${formatMetricValue(value, locale)} kWh`;
56
+ const wh = value * 1000;
57
+ if (Math.abs(wh) >= 1)
58
+ return `${formatMetricValue(wh, locale)} Wh`;
59
+ return `${formatMetricValue(wh * 1000, locale)} mWh`;
60
+ }
61
+ if (metricType === 'co2') {
62
+ if (absValue >= 1)
63
+ return `${formatMetricValue(value, locale)} kg`;
64
+ const g = value * 1000;
65
+ if (Math.abs(g) >= 1)
66
+ return `${formatMetricValue(g, locale)} g`;
67
+ return `${formatMetricValue(g * 1000, locale)} mg`;
68
+ }
69
+ if (absValue >= 1)
70
+ return `${formatMetricValue(value, locale)} L`;
71
+ const ml = value * 1000;
72
+ if (Math.abs(ml) >= 1)
73
+ return `${formatMetricValue(ml, locale)} mL`;
74
+ return `${formatMetricValue(ml * 1000, locale)} μL`;
75
+ };
76
+ const currentLocale = i18n.language || navigator.language || 'en';
77
+ const chatLog = useMemo(() => ({ lines: history }), [history]);
78
+ const sustainabilityTotals = useMemo(() => {
79
+ var _a;
80
+ const totals = { energy: 0, gwp: 0, wcf: 0 };
81
+ ((_a = chatLog === null || chatLog === void 0 ? void 0 : chatLog.lines) !== null && _a !== void 0 ? _a : []).forEach(line => {
82
+ var _a, _b, _c, _d;
83
+ const energyImpact = (_a = line.llmUsage) === null || _a === void 0 ? void 0 : _a.energyImpact;
84
+ if (!energyImpact)
85
+ return;
86
+ totals.energy += (_b = getMetricValue(energyImpact.energy)) !== null && _b !== void 0 ? _b : 0;
87
+ totals.gwp += (_c = getMetricValue(energyImpact.gwp)) !== null && _c !== void 0 ? _c : 0;
88
+ totals.wcf += (_d = getMetricValue(energyImpact.wcf)) !== null && _d !== void 0 ? _d : 0;
89
+ });
90
+ return totals;
91
+ }, [chatLog]);
92
+ const hasSustainabilityData = useMemo(() => {
93
+ var _a;
94
+ return ((_a = chatLog === null || chatLog === void 0 ? void 0 : chatLog.lines) !== null && _a !== void 0 ? _a : []).some(line => {
95
+ var _a;
96
+ return !!((_a = line
97
+ .llmUsage) === null || _a === void 0 ? void 0 : _a.energyImpact);
98
+ });
99
+ }, [chatLog]);
29
100
  useEffect(() => {
30
101
  if (document.fullscreenEnabled) {
31
102
  setFullScreenAvailable(true);
@@ -76,7 +147,7 @@ const Header = ({ className, memori, tenant, history, position, setShowPositionD
76
147
  };
77
148
  return (_jsxs("div", { className: cx('memori-header', hasSpacedButtons && 'memori-header--spaced', className), children: [memori.needsPosition && position && (_jsxs("div", { className: "memori-header--position", children: [position.latitude !== 0 && position.longitude !== 0 && (_jsx("span", { className: "memori-header--position-placeName", children: position.placeName })), _jsx(Button, { primary: true, shape: "circle", className: cx('memori-header--button', 'memori-header--button--position', hasSpacedButtons && 'memori-header--button-spaced'), title: t('widget.position') || 'Position', icon: _jsx(MapMarker, {}), onClick: () => setShowPositionDrawer(true) })] })), showReload && (_jsx(Button, { primary: true, shape: "circle", className: cx('memori-header--button', 'memori-header--button--reload', hasSpacedButtons && 'memori-header--button-spaced'), title: t('reload') || 'Reload', icon: _jsx(Refresh, {}), onClick: () => {
78
149
  window.location.reload();
79
- } })), showClear && (_jsx(Button, { primary: true, shape: "circle", className: cx('memori-header--button', 'memori-header--button--clear', hasSpacedButtons && 'memori-header--button-spaced'), title: t('clearHistory') || 'Clear chat', icon: _jsx(Clear, {}), onClick: clearHistory })), showChatHistory && !!loginToken && (_jsx(Button, { primary: true, disabled: !loginToken, shape: "circle", className: cx('memori-header--button', 'memori-header--button--chat-history', hasSpacedButtons && 'memori-header--button-spaced'), title: t('write_and_speak.chatHistory') || 'Chat history', icon: _jsx(MessageIcon, {}), onClick: () => setShowChatHistoryDrawer(true) })), fullScreenAvailable && (_jsx(Button, { primary: true, shape: "circle", className: cx('memori-header--button', 'memori-header--button--fullscreen', hasSpacedButtons && 'memori-header--button-spaced'), title: fullScreen
150
+ } })), showClear && (_jsx(Button, { primary: true, shape: "circle", className: cx('memori-header--button', 'memori-header--button--clear', hasSpacedButtons && 'memori-header--button-spaced'), title: t('clearHistory') || 'Clear chat', icon: _jsx(Clear, {}), onClick: clearHistory })), showChatHistory && !!loginToken && (_jsx(Button, { primary: true, disabled: !loginToken, shape: "circle", className: cx('memori-header--button', 'memori-header--button--chat-history', hasSpacedButtons && 'memori-header--button-spaced'), title: t('write_and_speak.chatHistory') || 'Chat history', icon: _jsx(MessageIcon, {}), onClick: () => setShowChatHistoryDrawer(true) })), showMessageConsumption && hasSustainabilityData && (_jsx(Dropdown, { placement: "bottom-right", trigger: _jsx(Button, { primary: true, shape: "circle", className: cx('memori-header--button', 'memori-header--button--sustainability', hasSpacedButtons && 'memori-header--button-spaced'), title: t('write_and_speak.showMessageConsumptionLabel') || 'LLM consumption', icon: _jsx(GasStation, { className: "memori-header--button--sustainability-icon" }) }), children: _jsxs("div", { className: "memori-dropdown--sustainability", children: [_jsx("h4", { className: "memori-dropdown--sustainability-title", children: t('chatLogs.totalChatConsumptionTitle') || 'Consumo Totale Chat' }), _jsxs("div", { className: "memori-dropdown--sustainability-metrics", children: [_jsxs("div", { className: "memori-dropdown--sustainability-row", children: [_jsxs("span", { className: "memori-dropdown--sustainability-label", children: [_jsx("span", { "aria-hidden": "true", children: BADGE_EMOJI.energy }), ' ', t('chatLogs.energy') || 'Energy'] }), _jsx("strong", { className: "memori-dropdown--sustainability-value", children: formatImpactInReadableUnit(sustainabilityTotals.energy, 'energy', currentLocale) })] }), _jsxs("div", { className: "memori-dropdown--sustainability-row", children: [_jsxs("span", { className: "memori-dropdown--sustainability-label", children: [_jsx("span", { "aria-hidden": "true", children: BADGE_EMOJI.co2 }), ' ', t('chatLogs.co2') || 'CO2'] }), _jsx("strong", { className: "memori-dropdown--sustainability-value", children: formatImpactInReadableUnit(sustainabilityTotals.gwp, 'co2', currentLocale) })] }), _jsxs("div", { className: "memori-dropdown--sustainability-row", children: [_jsxs("span", { className: "memori-dropdown--sustainability-label", children: [_jsx("span", { "aria-hidden": "true", children: BADGE_EMOJI.water }), ' ', t('chatLogs.water') || 'Water'] }), _jsx("strong", { className: "memori-dropdown--sustainability-value", children: formatImpactInReadableUnit(sustainabilityTotals.wcf, 'water', currentLocale) })] })] })] }) })), fullScreenAvailable && (_jsx(Button, { primary: true, shape: "circle", className: cx('memori-header--button', 'memori-header--button--fullscreen', hasSpacedButtons && 'memori-header--button-spaced'), title: fullScreen
80
151
  ? t('fullscreenExit') || 'Exit fullscreen'
81
152
  : t('fullscreenEnter') || 'Enter fullscreen', icon: fullScreen ? _jsx(FullscreenExit, {}) : _jsx(Fullscreen, {}), onClick: fullScreenHandler ||
82
153
  (() => {