@newfold/wp-module-ai-chat 1.0.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 (51) hide show
  1. package/README.md +98 -0
  2. package/package.json +51 -0
  3. package/src/components/chat/ChatHeader.jsx +63 -0
  4. package/src/components/chat/ChatHistoryDropdown.jsx +182 -0
  5. package/src/components/chat/ChatHistoryList.jsx +257 -0
  6. package/src/components/chat/ChatInput.jsx +157 -0
  7. package/src/components/chat/ChatMessage.jsx +157 -0
  8. package/src/components/chat/ChatMessages.jsx +137 -0
  9. package/src/components/chat/WelcomeScreen.jsx +115 -0
  10. package/src/components/icons/CloseIcon.jsx +27 -0
  11. package/src/components/icons/SparklesOutlineIcon.jsx +30 -0
  12. package/src/components/icons/index.js +5 -0
  13. package/src/components/ui/AILogo.jsx +47 -0
  14. package/src/components/ui/BluBetaHeading.jsx +18 -0
  15. package/src/components/ui/ErrorAlert.jsx +30 -0
  16. package/src/components/ui/HeaderBar.jsx +34 -0
  17. package/src/components/ui/SuggestionButton.jsx +28 -0
  18. package/src/components/ui/ToolExecutionList.jsx +264 -0
  19. package/src/components/ui/TypingIndicator.jsx +268 -0
  20. package/src/constants/nfdAgents/input.js +13 -0
  21. package/src/constants/nfdAgents/storageKeys.js +102 -0
  22. package/src/constants/nfdAgents/typingStatus.js +40 -0
  23. package/src/constants/nfdAgents/websocket.js +44 -0
  24. package/src/hooks/useAIChat.js +432 -0
  25. package/src/hooks/useNfdAgentsWebSocket.js +964 -0
  26. package/src/index.js +66 -0
  27. package/src/services/mcpClient.js +433 -0
  28. package/src/services/openaiClient.js +416 -0
  29. package/src/styles/_branding.scss +151 -0
  30. package/src/styles/_history.scss +180 -0
  31. package/src/styles/_input.scss +170 -0
  32. package/src/styles/_messages.scss +272 -0
  33. package/src/styles/_mixins.scss +21 -0
  34. package/src/styles/_typing-indicator.scss +162 -0
  35. package/src/styles/_ui.scss +173 -0
  36. package/src/styles/_vars.scss +103 -0
  37. package/src/styles/_welcome.scss +81 -0
  38. package/src/styles/app.scss +10 -0
  39. package/src/utils/helpers.js +75 -0
  40. package/src/utils/markdownParser.js +319 -0
  41. package/src/utils/nfdAgents/archiveConversation.js +82 -0
  42. package/src/utils/nfdAgents/chatHistoryList.js +130 -0
  43. package/src/utils/nfdAgents/configFetcher.js +137 -0
  44. package/src/utils/nfdAgents/greeting.js +55 -0
  45. package/src/utils/nfdAgents/jwtUtils.js +59 -0
  46. package/src/utils/nfdAgents/messageHandler.js +328 -0
  47. package/src/utils/nfdAgents/storage.js +112 -0
  48. package/src/utils/nfdAgents/typingIndicatorToolDisplay.js +180 -0
  49. package/src/utils/nfdAgents/url.js +101 -0
  50. package/src/utils/restApi.js +87 -0
  51. package/src/utils/sanitizeHtml.js +94 -0
@@ -0,0 +1,180 @@
1
+ /* Chat history list and dropdown - shared across help center and editor chat */
2
+
3
+ .nfd-ai-chat-history-dropdown-wrapper {
4
+ display: flex;
5
+ align-items: center;
6
+ }
7
+
8
+ .nfd-ai-chat-history-dropdown-trigger {
9
+ display: flex;
10
+ align-items: center;
11
+ justify-content: center;
12
+ width: 28px;
13
+ height: 28px;
14
+ padding: 0;
15
+ border: none;
16
+ background: transparent;
17
+ color: #1e1e1e;
18
+ cursor: pointer;
19
+ border-radius: 4px;
20
+ transition: background-color 0.15s ease, color 0.15s ease;
21
+
22
+ &:disabled {
23
+ opacity: 0.5;
24
+ cursor: not-allowed;
25
+ }
26
+
27
+ &:hover:not(:disabled) {
28
+ background-color: #f5f5f5;
29
+ }
30
+
31
+ &.is-open {
32
+ background-color: #f5f5f5;
33
+ }
34
+
35
+ svg {
36
+ display: block;
37
+ }
38
+ }
39
+
40
+ .nfd-ai-chat-history-dropdown {
41
+ min-width: 220px;
42
+ max-width: min(280px, calc(100vw - 16px));
43
+ max-height: 240px;
44
+ overflow: hidden;
45
+ display: flex;
46
+ flex-direction: column;
47
+ background: #fff;
48
+ border: 1px solid #e5e7eb;
49
+ border-radius: 6px;
50
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
51
+
52
+ [dir="rtl"] & {
53
+ left: auto;
54
+ right: auto;
55
+ inset-inline-end: 0;
56
+ }
57
+ }
58
+
59
+ .nfd-ai-chat-history-dropdown-inner {
60
+ overflow-y: auto;
61
+ max-height: 240px;
62
+ padding: 4px 0;
63
+ }
64
+
65
+ .nfd-ai-chat-history-list {
66
+ margin-top: 20px;
67
+ padding-top: 20px;
68
+ border-top: 1px solid #e0e0e0;
69
+ }
70
+
71
+ .nfd-ai-chat-history-dropdown-inner .nfd-ai-chat-history-list {
72
+ margin-top: 0;
73
+ padding-top: 0;
74
+ border-top: none;
75
+ padding-left: 8px;
76
+ padding-right: 8px;
77
+ }
78
+
79
+ .nfd-ai-chat-history-dropdown-inner .nfd-ai-chat-history-list--empty {
80
+ padding: 12px 8px;
81
+ font-size: 12px;
82
+ color: #6b7280;
83
+ text-align: center;
84
+ }
85
+
86
+ .nfd-ai-chat-history-item__title {
87
+ flex: 1;
88
+ min-width: 0;
89
+ overflow: hidden;
90
+ text-overflow: ellipsis;
91
+ white-space: nowrap;
92
+ color: #336ad7;
93
+ }
94
+
95
+ .nfd-ai-chat-history-item {
96
+ display: flex;
97
+ align-items: center;
98
+ gap: 6px;
99
+ cursor: pointer;
100
+ color: #374151;
101
+ font-size: 12px;
102
+ padding: 6px 4px;
103
+ transition: background-color 0.12s ease, color 0.12s ease;
104
+ border-radius: 4px;
105
+
106
+ &:hover {
107
+ background-color: #f3f4f6;
108
+ color: #1d4ed8;
109
+
110
+ .nfd-ai-chat-history-item__title {
111
+ text-decoration: underline;
112
+ }
113
+ }
114
+
115
+ &--disabled {
116
+ opacity: 0.5;
117
+ cursor: not-allowed;
118
+ }
119
+
120
+ svg:not(.nfd-ai-chat-history-item__delete-icon) {
121
+ width: 14px;
122
+ height: 14px;
123
+ flex-shrink: 0;
124
+ stroke: currentcolor;
125
+ }
126
+ }
127
+
128
+ .nfd-ai-chat-history-dropdown-inner .nfd-ai-chat-history-item {
129
+ min-height: 36px;
130
+ padding: 6px 4px;
131
+ box-sizing: border-box;
132
+ gap: 8px;
133
+ }
134
+
135
+ .nfd-ai-chat-history-item__content {
136
+ flex: 1;
137
+ min-width: 0;
138
+ display: flex;
139
+ align-items: center;
140
+ gap: 6px;
141
+ }
142
+
143
+ .nfd-ai-chat-history-item__meta {
144
+ display: flex;
145
+ align-items: center;
146
+ gap: 6px;
147
+ flex-shrink: 0;
148
+ }
149
+
150
+ .nfd-ai-chat-history-item__time {
151
+ font-size: 11px;
152
+ color: #9ca3af;
153
+ font-weight: 400;
154
+ }
155
+
156
+ .nfd-ai-chat-history-item__delete {
157
+ display: flex;
158
+ align-items: center;
159
+ justify-content: center;
160
+ width: 22px;
161
+ height: 22px;
162
+ padding: 0;
163
+ border: none;
164
+ background: transparent;
165
+ color: #9ca3af;
166
+ cursor: pointer;
167
+ border-radius: 4px;
168
+ transition: color 0.12s ease, background-color 0.12s ease;
169
+ flex-shrink: 0;
170
+
171
+ &:hover {
172
+ color: #dc2626;
173
+ background-color: #fef2f2;
174
+ }
175
+
176
+ &:focus-visible {
177
+ outline: 1px solid #2563eb;
178
+ outline-offset: 1px;
179
+ }
180
+ }
@@ -0,0 +1,170 @@
1
+ @use "mixins";
2
+
3
+ .nfd-ai-chat-input {
4
+ padding: 16px;
5
+ background: var(--nfd-ai-chat-color-white);
6
+ z-index: 25;
7
+ position: relative;
8
+ border-top: 1px solid var(--nfd-ai-chat-color-border);
9
+
10
+ // Optional: remove top border via modifier or showTopBorder={false}
11
+ &--no-top-border {
12
+ border-top: none;
13
+ }
14
+ }
15
+
16
+ .nfd-ai-chat-input__disclaimer {
17
+ text-align: center;
18
+ font-size: 12px;
19
+ color: var(--nfd-ai-chat-color-grey-medium);
20
+ margin-top: 8px;
21
+ line-height: 1.4;
22
+
23
+ a {
24
+ color: var(--nfd-ai-chat-color-grey-dark);
25
+ text-decoration: none;
26
+ font-weight: 500;
27
+
28
+ &:hover {
29
+ text-decoration: underline;
30
+ }
31
+ }
32
+ }
33
+
34
+ .nfd-ai-chat-input__container {
35
+ display: flex;
36
+ flex-direction: column;
37
+ gap: 8px;
38
+ background: var(--nfd-ai-chat-color-white);
39
+ border-radius: 12px;
40
+ padding: 12px;
41
+ border: 1px solid var(--nfd-ai-chat-color-border);
42
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
43
+ transition: all 0.2s ease;
44
+
45
+ &:focus-within {
46
+ box-shadow: 0 2px 12px rgba(34, 113, 177, 0.25);
47
+ }
48
+ }
49
+
50
+ .nfd-ai-chat-input__textarea {
51
+ width: 100%;
52
+ border: none;
53
+ background: transparent;
54
+ resize: none;
55
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
56
+ font-size: var(--nfd-ai-chat-font-size-base);
57
+ line-height: 1.5;
58
+ padding: 4px;
59
+ color: var(--nfd-ai-chat-color-text);
60
+ min-height: 24px;
61
+ max-height: 200px;
62
+ overflow-y: hidden; // Default to hidden, will be set to auto via JS when content overflows
63
+
64
+ &:focus {
65
+ outline: none;
66
+ border: none;
67
+ box-shadow: none;
68
+ }
69
+
70
+ &::placeholder {
71
+ color: var(--nfd-ai-chat-color-grey-placeholder);
72
+ }
73
+
74
+ &:disabled {
75
+ opacity: 0.6;
76
+ cursor: not-allowed;
77
+ box-shadow: none;
78
+ }
79
+
80
+ @include mixins.custom-scrollbar;
81
+ }
82
+
83
+ .nfd-ai-chat-input__actions {
84
+ display: flex;
85
+ justify-content: space-between;
86
+ align-items: center;
87
+ gap: 4px;
88
+ flex-wrap: wrap;
89
+ }
90
+
91
+ .components-button.nfd-ai-chat-input__submit,
92
+ .components-button.nfd-ai-chat-input__stop {
93
+ flex-shrink: 0;
94
+ min-width: auto;
95
+ width: 28px;
96
+ height: 28px;
97
+ padding: 0;
98
+ stroke: var(--nfd-ai-chat-color-grey-dark);
99
+ background: var(--nfd-ai-chat-color-background);
100
+ border: none;
101
+ border-radius: 50%;
102
+ cursor: pointer;
103
+ display: flex;
104
+ align-items: center;
105
+ justify-content: center;
106
+ transition: all 0.15s ease;
107
+ margin-left: auto;
108
+
109
+ svg {
110
+ display: block;
111
+ fill: none;
112
+ width: 16px;
113
+ height: 16px;
114
+ }
115
+ }
116
+
117
+ .components-button.nfd-ai-chat-input__submit {
118
+
119
+ &:disabled {
120
+ opacity: 0.4;
121
+ stroke: var(--nfd-ai-chat-color-grey-medium);
122
+ background: var(--nfd-ai-chat-color-background);
123
+ cursor: not-allowed;
124
+ }
125
+
126
+ &:hover:not(:disabled) {
127
+ stroke: var(--nfd-ai-chat-color-primary);
128
+ background: var(--nfd-ai-chat-color-primary-light-12);
129
+ transform: translateY(-1px);
130
+ box-shadow: var(--nfd-ai-chat-shadow-sm);
131
+ transition: all 0.15s ease;
132
+ }
133
+
134
+ &:focus:not(:disabled) {
135
+ outline: none;
136
+ stroke: var(--nfd-ai-chat-color-primary);
137
+ background: var(--nfd-ai-chat-color-primary-light-16);
138
+ }
139
+
140
+ &:active:not(:disabled) {
141
+ transform: translateY(0);
142
+ stroke: var(--nfd-ai-chat-color-primary-hover);
143
+ background: var(--nfd-ai-chat-color-primary-light-20);
144
+ }
145
+ }
146
+
147
+ .components-button.nfd-ai-chat-input__stop {
148
+ stroke: var(--nfd-ai-chat-color-error);
149
+ color: var(--nfd-ai-chat-color-error);
150
+
151
+ &:disabled,
152
+ &[aria-busy="true"] {
153
+ opacity: 0.5;
154
+ cursor: not-allowed;
155
+ pointer-events: none;
156
+ }
157
+
158
+ &:hover:not(:disabled) {
159
+ background: var(--nfd-ai-chat-color-error-alpha-10);
160
+ stroke: var(--nfd-ai-chat-color-error-hover);
161
+ color: var(--nfd-ai-chat-color-error-hover);
162
+ transform: translateY(-1px);
163
+ box-shadow: var(--nfd-ai-chat-shadow-sm);
164
+ }
165
+
166
+ &:active:not(:disabled) {
167
+ transform: translateY(0);
168
+ background: var(--nfd-ai-chat-color-error-alpha-15);
169
+ }
170
+ }
@@ -0,0 +1,272 @@
1
+ @use "mixins";
2
+
3
+ .nfd-ai-chat-messages {
4
+ display: flex;
5
+ flex: 1 1 0%; // Use 0% basis to properly fill flex container
6
+ flex-direction: column;
7
+ overflow-y: auto;
8
+ overflow-x: hidden;
9
+ scroll-behavior: smooth;
10
+ padding: var(--nfd-ai-chat-spacing-lg) var(--nfd-ai-chat-spacing-lg);
11
+ gap: var(--nfd-ai-chat-spacing-md);
12
+ min-height: 0;
13
+ max-height: 100%; // Don't exceed parent height
14
+ background: var(--nfd-ai-chat-color-white);
15
+
16
+ @include mixins.custom-scrollbar;
17
+
18
+ &__retry {
19
+ margin: 0 0 var(--nfd-ai-chat-spacing-sm);
20
+ }
21
+
22
+ &__retry-button {
23
+ background: none;
24
+ border: none;
25
+ padding: 0;
26
+ font-size: inherit;
27
+ font-family: inherit;
28
+ color: var(--nfd-ai-chat-color-primary);
29
+ cursor: pointer;
30
+ text-decoration: underline;
31
+
32
+ &:hover {
33
+ text-decoration: none;
34
+ }
35
+ }
36
+
37
+ // Minimal style: transparent container; user = grey bubble only; assistant = no background (plain text).
38
+ &--minimal {
39
+ background: transparent;
40
+
41
+ .nfd-ai-chat-message--assistant .nfd-ai-chat-message__content {
42
+ background: transparent;
43
+ border: none;
44
+ box-shadow: none;
45
+ padding: 4px 0 0 0;
46
+ }
47
+
48
+ .nfd-ai-chat-message--user .nfd-ai-chat-message__content {
49
+ background: var(--nfd-ai-chat-color-background);
50
+ color: var(--nfd-ai-chat-color-text);
51
+ box-shadow: none;
52
+ }
53
+ }
54
+ }
55
+
56
+ .nfd-ai-chat-message {
57
+ display: flex;
58
+ gap: 12px;
59
+ align-items: flex-start;
60
+ font-size: var(--nfd-ai-chat-font-size-base);
61
+
62
+ .nfd-ai-chat-message__content {
63
+
64
+ > * {
65
+ margin-bottom: 1rem;
66
+ }
67
+
68
+ h1,
69
+ h2,
70
+ h3,
71
+ h4,
72
+ h5,
73
+ h6 {
74
+ line-height: 1.2;
75
+ font-weight: 600;
76
+ margin-top: 1.5rem;
77
+ margin-bottom: 0.75rem;
78
+ color: var(--nfd-ai-chat-color-text);
79
+ }
80
+
81
+ h1 {
82
+ font-size: var(--nfd-ai-chat-font-size-xl);
83
+ margin-top: 0;
84
+ }
85
+
86
+ h2 {
87
+ font-size: var(--nfd-ai-chat-font-size-lg);
88
+ }
89
+
90
+ h3 {
91
+ font-size: var(--nfd-ai-chat-font-size-md);
92
+ text-transform: initial;
93
+ }
94
+
95
+ h4 {
96
+ font-size: var(--nfd-ai-chat-font-size-md);
97
+ }
98
+
99
+ h5 {
100
+ font-size: var(--nfd-ai-chat-font-size-sm);
101
+ }
102
+
103
+ h6 {
104
+ font-size: var(--nfd-ai-chat-font-size-sm);
105
+ font-weight: 500;
106
+ }
107
+
108
+ p {
109
+ font-size: var(--nfd-ai-chat-font-size-base);
110
+ line-height: 1.6;
111
+ margin-bottom: 1rem;
112
+ }
113
+
114
+ strong {
115
+ font-weight: 600;
116
+ }
117
+
118
+ em {
119
+ font-style: italic;
120
+ }
121
+
122
+ u {
123
+ text-decoration: underline;
124
+ }
125
+
126
+ s {
127
+ text-decoration: line-through;
128
+ }
129
+
130
+ mark {
131
+ background-color: var(--nfd-ai-chat-color-primary-light-20);
132
+ padding: 0.1em 0.2em;
133
+ border-radius: 2px;
134
+ }
135
+
136
+ small {
137
+ font-size: 0.875em;
138
+ }
139
+
140
+ a {
141
+ color: var(--nfd-ai-chat-color-primary);
142
+ text-decoration: none;
143
+
144
+ &:hover {
145
+ text-decoration: underline;
146
+ }
147
+ }
148
+
149
+ code {
150
+ background-color: var(--nfd-ai-chat-color-border);
151
+ padding: 0.2em 0.4em;
152
+ border-radius: 3px;
153
+ font-family: "Courier New", Courier, monospace;
154
+ font-size: 0.9em;
155
+ }
156
+
157
+ code.inline-code {
158
+ background-color: rgba(0, 0, 0, 0.06);
159
+ color: var(--nfd-ai-chat-color-text);
160
+ font-weight: 500;
161
+ }
162
+
163
+ ul,
164
+ ol {
165
+ margin: 1rem 0;
166
+ padding-left: 1.5rem;
167
+ }
168
+
169
+ ul {
170
+ list-style-type: disc;
171
+ }
172
+
173
+ ol {
174
+ list-style-type: decimal;
175
+ }
176
+
177
+ li {
178
+ margin-bottom: 0.5rem;
179
+ line-height: 1.5;
180
+ }
181
+
182
+ blockquote {
183
+ margin: 1.5rem 0;
184
+ padding: 1rem 1.5rem;
185
+ background-color: var(--nfd-ai-chat-color-background);
186
+ border-left: 4px solid var(--nfd-ai-chat-color-primary);
187
+ font-style: italic;
188
+ line-height: 1.6;
189
+ }
190
+
191
+ pre {
192
+ background-color: var(--nfd-ai-chat-color-background);
193
+ padding: 1rem;
194
+ border-radius: 4px;
195
+ overflow-x: auto;
196
+ margin: 1rem 0;
197
+ font-family: "Courier New", Courier, monospace;
198
+ font-size: 0.9em;
199
+ line-height: 1.4;
200
+ }
201
+
202
+ pre code {
203
+ background: none;
204
+ padding: 0;
205
+ border-radius: 0;
206
+ }
207
+
208
+ hr {
209
+ border: none;
210
+ border-top: 1px solid var(--nfd-ai-chat-color-grey-light);
211
+ margin: 2rem 0;
212
+ }
213
+
214
+ }
215
+
216
+ &--assistant {
217
+ flex-direction: column;
218
+ justify-content: flex-start;
219
+
220
+ .nfd-ai-chat-message__content {
221
+ flex: 1;
222
+ width: 100%;
223
+ min-width: 0; // Allow flex item to shrink so long text wraps
224
+ max-width: 85%;
225
+ line-height: 1.6;
226
+ color: var(--nfd-ai-chat-color-text);
227
+ background: var(--nfd-ai-chat-color-background);
228
+ padding: var(--nfd-ai-chat-spacing-md) var(--nfd-ai-chat-spacing-lg);
229
+ border-radius: var(--nfd-ai-chat-radius-lg);
230
+ border: 1px solid var(--nfd-ai-chat-color-border);
231
+ box-shadow: var(--nfd-ai-chat-shadow-sm);
232
+ white-space: pre-wrap;
233
+ overflow-wrap: break-word;
234
+ word-break: break-word;
235
+ overflow: hidden; // Prevent content from overflowing dialog
236
+
237
+ &--rich {
238
+ white-space: normal;
239
+
240
+ > *:first-child {
241
+ margin-top: 0;
242
+ }
243
+
244
+ > *:last-child {
245
+ margin-bottom: 0;
246
+ }
247
+ }
248
+
249
+ @media (max-width: 480px) {
250
+ max-width: 95%;
251
+ }
252
+ }
253
+ }
254
+
255
+ &--user {
256
+ justify-content: flex-end;
257
+
258
+ .nfd-ai-chat-message__content {
259
+ background: var(--nfd-ai-chat-color-primary, var(--nfd-ai-chat-color-background));
260
+ padding: 10px 16px;
261
+ border-radius: var(--nfd-ai-chat-radius-lg);
262
+ line-height: 1.5;
263
+ color: var(--nfd-ai-chat-color-white, var(--nfd-ai-chat-color-text-secondary));
264
+ max-width: 70%;
265
+ white-space: pre-wrap;
266
+ position: relative;
267
+ overflow-wrap: break-word;
268
+ box-shadow: var(--nfd-ai-chat-shadow-sm);
269
+ transition: transform 0.15s ease, box-shadow 0.15s ease;
270
+ }
271
+ }
272
+ }
@@ -0,0 +1,21 @@
1
+ // Custom scrollbar mixin
2
+ @mixin custom-scrollbar {
3
+
4
+ &::-webkit-scrollbar {
5
+ width: 8px;
6
+ }
7
+
8
+ &::-webkit-scrollbar-track {
9
+ background: transparent;
10
+ }
11
+
12
+ &::-webkit-scrollbar-thumb {
13
+ background: var(--nfd-ai-chat-color-border);
14
+ opacity: 0.8;
15
+ border-radius: 4px;
16
+
17
+ &:hover {
18
+ opacity: 1;
19
+ }
20
+ }
21
+ }