@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.
- package/README.md +98 -0
- package/package.json +51 -0
- package/src/components/chat/ChatHeader.jsx +63 -0
- package/src/components/chat/ChatHistoryDropdown.jsx +182 -0
- package/src/components/chat/ChatHistoryList.jsx +257 -0
- package/src/components/chat/ChatInput.jsx +157 -0
- package/src/components/chat/ChatMessage.jsx +157 -0
- package/src/components/chat/ChatMessages.jsx +137 -0
- package/src/components/chat/WelcomeScreen.jsx +115 -0
- package/src/components/icons/CloseIcon.jsx +27 -0
- package/src/components/icons/SparklesOutlineIcon.jsx +30 -0
- package/src/components/icons/index.js +5 -0
- package/src/components/ui/AILogo.jsx +47 -0
- package/src/components/ui/BluBetaHeading.jsx +18 -0
- package/src/components/ui/ErrorAlert.jsx +30 -0
- package/src/components/ui/HeaderBar.jsx +34 -0
- package/src/components/ui/SuggestionButton.jsx +28 -0
- package/src/components/ui/ToolExecutionList.jsx +264 -0
- package/src/components/ui/TypingIndicator.jsx +268 -0
- package/src/constants/nfdAgents/input.js +13 -0
- package/src/constants/nfdAgents/storageKeys.js +102 -0
- package/src/constants/nfdAgents/typingStatus.js +40 -0
- package/src/constants/nfdAgents/websocket.js +44 -0
- package/src/hooks/useAIChat.js +432 -0
- package/src/hooks/useNfdAgentsWebSocket.js +964 -0
- package/src/index.js +66 -0
- package/src/services/mcpClient.js +433 -0
- package/src/services/openaiClient.js +416 -0
- package/src/styles/_branding.scss +151 -0
- package/src/styles/_history.scss +180 -0
- package/src/styles/_input.scss +170 -0
- package/src/styles/_messages.scss +272 -0
- package/src/styles/_mixins.scss +21 -0
- package/src/styles/_typing-indicator.scss +162 -0
- package/src/styles/_ui.scss +173 -0
- package/src/styles/_vars.scss +103 -0
- package/src/styles/_welcome.scss +81 -0
- package/src/styles/app.scss +10 -0
- package/src/utils/helpers.js +75 -0
- package/src/utils/markdownParser.js +319 -0
- package/src/utils/nfdAgents/archiveConversation.js +82 -0
- package/src/utils/nfdAgents/chatHistoryList.js +130 -0
- package/src/utils/nfdAgents/configFetcher.js +137 -0
- package/src/utils/nfdAgents/greeting.js +55 -0
- package/src/utils/nfdAgents/jwtUtils.js +59 -0
- package/src/utils/nfdAgents/messageHandler.js +328 -0
- package/src/utils/nfdAgents/storage.js +112 -0
- package/src/utils/nfdAgents/typingIndicatorToolDisplay.js +180 -0
- package/src/utils/nfdAgents/url.js +101 -0
- package/src/utils/restApi.js +87 -0
- package/src/utils/sanitizeHtml.js +94 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/* Typing Indicator */
|
|
2
|
+
.nfd-ai-chat-typing-indicator {
|
|
3
|
+
display: flex;
|
|
4
|
+
align-items: center;
|
|
5
|
+
gap: var(--nfd-ai-chat-spacing-sm);
|
|
6
|
+
padding: var(--nfd-ai-chat-spacing-xs) 0;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.nfd-ai-chat-typing-indicator__dots {
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
gap: var(--nfd-ai-chat-spacing-xs);
|
|
13
|
+
|
|
14
|
+
span {
|
|
15
|
+
width: 6px;
|
|
16
|
+
height: 6px;
|
|
17
|
+
border-radius: 50%;
|
|
18
|
+
background: var(--nfd-ai-chat-color-grey-dark);
|
|
19
|
+
animation: nfd-ai-chat-typing-bounce 1.4s ease-in-out infinite both;
|
|
20
|
+
|
|
21
|
+
&:nth-child(2) {
|
|
22
|
+
animation-delay: 0.2s;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
&:nth-child(3) {
|
|
26
|
+
animation-delay: 0.4s;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@keyframes nfd-ai-chat-typing-bounce {
|
|
32
|
+
|
|
33
|
+
0%,
|
|
34
|
+
60%,
|
|
35
|
+
100% {
|
|
36
|
+
transform: translateY(0);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
30% {
|
|
40
|
+
transform: translateY(-4px);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.nfd-ai-chat-typing-indicator__text {
|
|
45
|
+
font-size: var(--nfd-ai-chat-font-size-base);
|
|
46
|
+
color: var(--nfd-ai-chat-color-grey-dark);
|
|
47
|
+
min-width: 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.nfd-ai-chat-typing-indicator__reasoning {
|
|
51
|
+
font-size: var(--nfd-ai-chat-font-size-sm);
|
|
52
|
+
color: var(--nfd-ai-chat-color-grey-medium);
|
|
53
|
+
font-style: italic;
|
|
54
|
+
line-height: 1.4;
|
|
55
|
+
margin-top: 4px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@keyframes nfd-ai-chat-spin {
|
|
59
|
+
|
|
60
|
+
from {
|
|
61
|
+
transform: rotate(0deg);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
to {
|
|
65
|
+
transform: rotate(360deg);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Tool Execution */
|
|
70
|
+
.nfd-ai-chat-tool-execution {
|
|
71
|
+
width: 100%;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.nfd-ai-chat-tool-execution__header {
|
|
75
|
+
display: flex;
|
|
76
|
+
align-items: center;
|
|
77
|
+
gap: 6px;
|
|
78
|
+
padding: 4px 0;
|
|
79
|
+
background: none;
|
|
80
|
+
border: none;
|
|
81
|
+
cursor: pointer;
|
|
82
|
+
font-size: var(--nfd-ai-chat-font-size-sm);
|
|
83
|
+
color: var(--nfd-ai-chat-color-grey-dark);
|
|
84
|
+
width: 100%;
|
|
85
|
+
text-align: left;
|
|
86
|
+
|
|
87
|
+
&:hover {
|
|
88
|
+
color: var(--nfd-ai-chat-color-text);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.nfd-ai-chat-tool-execution__chevron {
|
|
93
|
+
flex-shrink: 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.nfd-ai-chat-tool-execution__header-count {
|
|
97
|
+
color: var(--nfd-ai-chat-color-grey-medium);
|
|
98
|
+
margin-left: 4px;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.nfd-ai-chat-tool-execution__list {
|
|
102
|
+
display: flex;
|
|
103
|
+
flex-direction: column;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.nfd-ai-chat-tool-execution__item {
|
|
107
|
+
display: flex;
|
|
108
|
+
flex-direction: column;
|
|
109
|
+
gap: 2px;
|
|
110
|
+
padding: 4px 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.nfd-ai-chat-tool-execution__item-header {
|
|
114
|
+
display: flex;
|
|
115
|
+
align-items: center;
|
|
116
|
+
gap: 6px;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.nfd-ai-chat-tool-execution__icon {
|
|
120
|
+
flex-shrink: 0;
|
|
121
|
+
|
|
122
|
+
&--active {
|
|
123
|
+
color: var(--nfd-ai-chat-color-primary);
|
|
124
|
+
animation: nfd-ai-chat-spin 1s linear infinite;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
&--success {
|
|
128
|
+
color: var(--nfd-ai-chat-color-success);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
&--error {
|
|
132
|
+
color: var(--nfd-ai-chat-color-error);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
&--pending {
|
|
136
|
+
color: var(--nfd-ai-chat-color-grey-medium);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.nfd-ai-chat-tool-execution__item-title {
|
|
141
|
+
font-size: var(--nfd-ai-chat-font-size-sm);
|
|
142
|
+
color: var(--nfd-ai-chat-color-text);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.nfd-ai-chat-tool-execution__item-params {
|
|
146
|
+
font-size: var(--nfd-ai-chat-font-size-sm);
|
|
147
|
+
color: var(--nfd-ai-chat-color-grey-medium);
|
|
148
|
+
margin-left: 4px;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.nfd-ai-chat-tool-execution__item-progress {
|
|
152
|
+
font-size: var(--nfd-ai-chat-font-size-sm);
|
|
153
|
+
color: var(--nfd-ai-chat-color-grey-dark);
|
|
154
|
+
padding-left: 18px;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.nfd-ai-chat-tool-execution__item-summary {
|
|
158
|
+
font-size: var(--nfd-ai-chat-font-size-sm);
|
|
159
|
+
color: var(--nfd-ai-chat-color-grey-medium);
|
|
160
|
+
padding-left: 18px;
|
|
161
|
+
margin-top: 2px;
|
|
162
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/* AI Avatar */
|
|
2
|
+
.nfd-ai-chat-avatar {
|
|
3
|
+
display: flex;
|
|
4
|
+
align-items: center;
|
|
5
|
+
justify-content: center;
|
|
6
|
+
border-radius: var(--nfd-ai-chat-radius-full);
|
|
7
|
+
background: linear-gradient(135deg, var(--nfd-ai-chat-color-primary) 0%, var(--nfd-ai-chat-color-primary-hover) 100%);
|
|
8
|
+
color: var(--nfd-ai-chat-color-white);
|
|
9
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
10
|
+
|
|
11
|
+
svg {
|
|
12
|
+
fill: currentcolor;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Chat header - white background, AILogo + pill + actions */
|
|
17
|
+
.nfd-ai-chat-header {
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: space-between;
|
|
21
|
+
gap: 12px;
|
|
22
|
+
background-color: var(--nfd-ai-chat-color-white);
|
|
23
|
+
padding: 12px 16px;
|
|
24
|
+
flex-shrink: 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* Header logo: no background, plain icon (override brand) */
|
|
28
|
+
.nfd-ai-chat-header .nfd-ai-chat-header__brand .nfd-ai-chat-avatar {
|
|
29
|
+
background: none;
|
|
30
|
+
color: var(--nfd-ai-chat-color-text, #1e1e1e);
|
|
31
|
+
box-shadow: none;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.nfd-ai-chat-header__brand {
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
gap: 8px;
|
|
38
|
+
color: var(--nfd-ai-chat-color-text, #1e1e1e);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.nfd-ai-chat-header__title {
|
|
42
|
+
font-size: var(--nfd-ai-chat-font-size-base);
|
|
43
|
+
font-weight: 600;
|
|
44
|
+
color: var(--nfd-ai-chat-color-text, #1e1e1e);
|
|
45
|
+
line-height: 1;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.nfd-ai-chat-header__actions {
|
|
49
|
+
display: flex;
|
|
50
|
+
align-items: center;
|
|
51
|
+
gap: 8px;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.nfd-ai-chat-header__btn {
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: center;
|
|
58
|
+
width: 28px;
|
|
59
|
+
height: 28px;
|
|
60
|
+
padding: 0;
|
|
61
|
+
border: none;
|
|
62
|
+
background: transparent;
|
|
63
|
+
color: var(--nfd-ai-chat-color-text, #1e1e1e);
|
|
64
|
+
cursor: pointer;
|
|
65
|
+
border-radius: var(--nfd-ai-chat-radius-sm, 4px);
|
|
66
|
+
transition: background-color 0.15s ease, color 0.15s ease;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.nfd-ai-chat-header__btn:disabled {
|
|
70
|
+
opacity: 0.5;
|
|
71
|
+
cursor: not-allowed;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.nfd-ai-chat-header__btn:hover:not(:disabled) {
|
|
75
|
+
background-color: var(--nfd-ai-chat-color-background, #f5f5f5);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.nfd-ai-chat-header__btn--new {
|
|
79
|
+
font-size: 16px;
|
|
80
|
+
line-height: 1;
|
|
81
|
+
font-weight: 300;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.nfd-ai-chat-header__btn--close svg {
|
|
85
|
+
display: block;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* BETA badge - solid dark blue pill (matches editor-chat sidebar) */
|
|
89
|
+
.nfd-ai-chat-blu-beta-badge {
|
|
90
|
+
display: inline-flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
justify-content: center;
|
|
93
|
+
font-size: 10px;
|
|
94
|
+
font-weight: 600;
|
|
95
|
+
padding: 4px 8px;
|
|
96
|
+
border-radius: 4px;
|
|
97
|
+
background-color: var(--nfd-ai-chat-color-primary);
|
|
98
|
+
color: var(--nfd-ai-chat-color-white);
|
|
99
|
+
text-transform: uppercase;
|
|
100
|
+
letter-spacing: 0.25px;
|
|
101
|
+
line-height: 1;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Error Alert */
|
|
105
|
+
.nfd-ai-chat-error-alert {
|
|
106
|
+
display: flex;
|
|
107
|
+
align-items: flex-start;
|
|
108
|
+
gap: 12px;
|
|
109
|
+
padding: 12px 16px;
|
|
110
|
+
background: rgba(214, 54, 56, 0.08);
|
|
111
|
+
border: 1px solid var(--nfd-ai-chat-color-error);
|
|
112
|
+
border-radius: 8px;
|
|
113
|
+
margin: 8px 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.nfd-ai-chat-error-alert__icon {
|
|
117
|
+
flex-shrink: 0;
|
|
118
|
+
color: var(--nfd-ai-chat-color-error);
|
|
119
|
+
margin-top: 2px;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.nfd-ai-chat-error-alert__content {
|
|
123
|
+
flex: 1;
|
|
124
|
+
min-width: 0;
|
|
125
|
+
overflow: hidden;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.nfd-ai-chat-error-alert__message {
|
|
129
|
+
font-size: var(--nfd-ai-chat-font-size-base);
|
|
130
|
+
color: var(--nfd-ai-chat-color-error);
|
|
131
|
+
line-height: 1.5;
|
|
132
|
+
overflow-wrap: break-word;
|
|
133
|
+
word-break: break-word;
|
|
134
|
+
min-width: 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* Suggestion Button */
|
|
138
|
+
.components-button.nfd-ai-chat-suggestion {
|
|
139
|
+
display: flex;
|
|
140
|
+
align-items: center;
|
|
141
|
+
gap: var(--nfd-ai-chat-spacing-sm);
|
|
142
|
+
padding: var(--nfd-ai-chat-spacing-sm) var(--nfd-ai-chat-spacing-md);
|
|
143
|
+
background: var(--nfd-ai-chat-color-white);
|
|
144
|
+
border: 1px solid var(--nfd-ai-chat-color-border);
|
|
145
|
+
border-radius: var(--nfd-ai-chat-radius-full);
|
|
146
|
+
font-size: var(--nfd-ai-chat-font-size-sm);
|
|
147
|
+
color: var(--nfd-ai-chat-color-text-secondary);
|
|
148
|
+
cursor: pointer;
|
|
149
|
+
transition: all 0.15s ease;
|
|
150
|
+
box-shadow: var(--nfd-ai-chat-shadow-sm);
|
|
151
|
+
|
|
152
|
+
&:hover {
|
|
153
|
+
background: var(--nfd-ai-chat-color-background);
|
|
154
|
+
border-color: var(--nfd-ai-chat-color-primary);
|
|
155
|
+
color: var(--nfd-ai-chat-color-primary);
|
|
156
|
+
transform: translateY(-1px);
|
|
157
|
+
box-shadow: var(--nfd-ai-chat-shadow-md);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
&:active {
|
|
161
|
+
transform: translateY(0);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.nfd-ai-chat-suggestion__icon {
|
|
166
|
+
display: flex;
|
|
167
|
+
align-items: center;
|
|
168
|
+
justify-content: center;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.nfd-ai-chat-suggestion__text {
|
|
172
|
+
white-space: nowrap;
|
|
173
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/* -------------------------------------------------------------------------- */
|
|
2
|
+
|
|
3
|
+
/* AI Chat CSS Variables */
|
|
4
|
+
|
|
5
|
+
/* -------------------------------------------------------------------------- */
|
|
6
|
+
|
|
7
|
+
:root {
|
|
8
|
+
|
|
9
|
+
/* Default/Base colors - can be overridden by brand-specific variables */
|
|
10
|
+
--nfd-ai-chat-color-primary: #2271b1;
|
|
11
|
+
--nfd-ai-chat-color-primary-hover: #135e96;
|
|
12
|
+
--nfd-ai-chat-color-primary-active: #0e4b72;
|
|
13
|
+
--nfd-ai-chat-color-primary-light-8: rgba(34, 113, 177, 0.08);
|
|
14
|
+
--nfd-ai-chat-color-primary-light-12: rgba(34, 113, 177, 0.12);
|
|
15
|
+
--nfd-ai-chat-color-primary-light-16: rgba(34, 113, 177, 0.16);
|
|
16
|
+
--nfd-ai-chat-color-primary-light-20: rgba(34, 113, 177, 0.2);
|
|
17
|
+
|
|
18
|
+
/* Grey colors */
|
|
19
|
+
--nfd-ai-chat-color-grey-dark: #666;
|
|
20
|
+
--nfd-ai-chat-color-grey-medium: #999;
|
|
21
|
+
--nfd-ai-chat-color-grey-light: #ddd;
|
|
22
|
+
--nfd-ai-chat-color-grey-placeholder: #9e9e9e;
|
|
23
|
+
|
|
24
|
+
/* Error/Danger colors */
|
|
25
|
+
--nfd-ai-chat-color-error: #d63638;
|
|
26
|
+
--nfd-ai-chat-color-error-hover: #b32d2e;
|
|
27
|
+
--nfd-ai-chat-color-error-active: #8a2424;
|
|
28
|
+
--nfd-ai-chat-color-error-alpha-10: rgba(214, 54, 56, 0.1);
|
|
29
|
+
--nfd-ai-chat-color-error-alpha-15: rgba(214, 54, 56, 0.15);
|
|
30
|
+
|
|
31
|
+
/* Success colors */
|
|
32
|
+
--nfd-ai-chat-color-success: #00a32a;
|
|
33
|
+
|
|
34
|
+
/* UI colors */
|
|
35
|
+
--nfd-ai-chat-color-border: #e0e0e0;
|
|
36
|
+
--nfd-ai-chat-color-background: #f5f5f5;
|
|
37
|
+
--nfd-ai-chat-color-text: #1e1e1e;
|
|
38
|
+
--nfd-ai-chat-color-text-secondary: #424242;
|
|
39
|
+
--nfd-ai-chat-color-white: #fff;
|
|
40
|
+
|
|
41
|
+
/* Typography */
|
|
42
|
+
--nfd-ai-chat-font-size-base: 14px;
|
|
43
|
+
--nfd-ai-chat-font-size-xl: 22px;
|
|
44
|
+
--nfd-ai-chat-font-size-lg: 20px;
|
|
45
|
+
--nfd-ai-chat-font-size-md: 16px;
|
|
46
|
+
--nfd-ai-chat-font-size-sm: 12px;
|
|
47
|
+
--nfd-ai-chat-font-size-xs: 10px;
|
|
48
|
+
|
|
49
|
+
/* Spacing */
|
|
50
|
+
--nfd-ai-chat-spacing-xs: 4px;
|
|
51
|
+
--nfd-ai-chat-spacing-sm: 8px;
|
|
52
|
+
--nfd-ai-chat-spacing-md: 16px;
|
|
53
|
+
--nfd-ai-chat-spacing-lg: 24px;
|
|
54
|
+
--nfd-ai-chat-spacing-xl: 32px;
|
|
55
|
+
|
|
56
|
+
/* Border radius */
|
|
57
|
+
--nfd-ai-chat-radius-sm: 4px;
|
|
58
|
+
--nfd-ai-chat-radius-md: 8px;
|
|
59
|
+
--nfd-ai-chat-radius-lg: 12px;
|
|
60
|
+
--nfd-ai-chat-radius-xl: 16px;
|
|
61
|
+
--nfd-ai-chat-radius-full: 9999px;
|
|
62
|
+
|
|
63
|
+
/* Shadows */
|
|
64
|
+
--nfd-ai-chat-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
65
|
+
--nfd-ai-chat-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
66
|
+
--nfd-ai-chat-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* -------------------------------------------------------------------------- */
|
|
70
|
+
|
|
71
|
+
/* Brand-Specific Variables */
|
|
72
|
+
|
|
73
|
+
/* -------------------------------------------------------------------------- */
|
|
74
|
+
|
|
75
|
+
/* Bluehost Brand */
|
|
76
|
+
.nfd-brand-bluehost,
|
|
77
|
+
[data-brand="bluehost"] {
|
|
78
|
+
|
|
79
|
+
/* Primary Bluehost Blue - #0075FA */
|
|
80
|
+
--nfd-ai-chat-color-primary: #0075fa;
|
|
81
|
+
--nfd-ai-chat-color-primary-hover: #0066e0;
|
|
82
|
+
--nfd-ai-chat-color-primary-active: #0055c2;
|
|
83
|
+
--nfd-ai-chat-color-primary-light-8: rgba(0, 117, 250, 0.08);
|
|
84
|
+
--nfd-ai-chat-color-primary-light-12: rgba(0, 117, 250, 0.12);
|
|
85
|
+
--nfd-ai-chat-color-primary-light-16: rgba(0, 117, 250, 0.16);
|
|
86
|
+
--nfd-ai-chat-color-primary-light-20: rgba(0, 117, 250, 0.2);
|
|
87
|
+
|
|
88
|
+
/* Enhanced UI colors for professional look */
|
|
89
|
+
--nfd-ai-chat-color-background: #f8f9fa;
|
|
90
|
+
--nfd-ai-chat-color-border: #e5e7eb;
|
|
91
|
+
--nfd-ai-chat-color-text: #111827;
|
|
92
|
+
--nfd-ai-chat-color-text-secondary: #6b7280;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Add more brands here as needed */
|
|
96
|
+
|
|
97
|
+
/* Example:
|
|
98
|
+
.nfd-brand-hostgator,
|
|
99
|
+
[data-brand="hostgator"] {
|
|
100
|
+
--nfd-ai-chat-color-primary: #FF6600;
|
|
101
|
+
...
|
|
102
|
+
}
|
|
103
|
+
*/
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
.nfd-ai-chat-welcome {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
align-items: center;
|
|
5
|
+
justify-content: center;
|
|
6
|
+
text-align: center;
|
|
7
|
+
padding: var(--nfd-ai-chat-spacing-xl) var(--nfd-ai-chat-spacing-md);
|
|
8
|
+
flex: 1;
|
|
9
|
+
background: var(--nfd-ai-chat-color-white);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.nfd-ai-chat-welcome__content {
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
align-items: center;
|
|
16
|
+
gap: 16px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.nfd-ai-chat-welcome__avatar {
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
margin-bottom: 24px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Purplish gradient logo on welcome — higher specificity to override brand */
|
|
27
|
+
.nfd-ai-chat-welcome .nfd-ai-chat-welcome__avatar .nfd-ai-chat-avatar {
|
|
28
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
29
|
+
color: #fff;
|
|
30
|
+
box-shadow: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.nfd-ai-chat-welcome__message {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
gap: 4px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.nfd-ai-chat-welcome__title {
|
|
40
|
+
font-size: var(--nfd-ai-chat-font-size-lg);
|
|
41
|
+
font-weight: 600;
|
|
42
|
+
color: var(--nfd-ai-chat-color-text);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.nfd-ai-chat-welcome__subtitle {
|
|
46
|
+
font-size: var(--nfd-ai-chat-font-size-base);
|
|
47
|
+
color: var(--nfd-ai-chat-color-text-secondary);
|
|
48
|
+
line-height: 1.5;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.nfd-ai-chat-welcome__cursor {
|
|
52
|
+
display: inline-block;
|
|
53
|
+
width: 2px;
|
|
54
|
+
height: 1em;
|
|
55
|
+
margin-left: 2px;
|
|
56
|
+
vertical-align: text-bottom;
|
|
57
|
+
background: currentcolor;
|
|
58
|
+
animation: nfd-ai-chat-cursor-blink 0.8s step-end infinite;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@keyframes nfd-ai-chat-cursor-blink {
|
|
62
|
+
|
|
63
|
+
0%,
|
|
64
|
+
50% {
|
|
65
|
+
opacity: 1;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
51%,
|
|
69
|
+
100% {
|
|
70
|
+
opacity: 0;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.nfd-ai-chat-suggestions {
|
|
75
|
+
display: flex;
|
|
76
|
+
flex-wrap: wrap;
|
|
77
|
+
justify-content: center;
|
|
78
|
+
gap: var(--nfd-ai-chat-spacing-sm);
|
|
79
|
+
margin-top: var(--nfd-ai-chat-spacing-lg);
|
|
80
|
+
max-width: 400px;
|
|
81
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unescape AI response text so display shows normal quotes instead of \"
|
|
3
|
+
* Handles JSON-style escaped quotes that can appear in model/tool output.
|
|
4
|
+
*
|
|
5
|
+
* @param {string} text - Raw message text that may contain \" or \'
|
|
6
|
+
* @return {string} Text with escaped quotes replaced for display
|
|
7
|
+
*/
|
|
8
|
+
export const unescapeAiResponse = (text) => {
|
|
9
|
+
if (!text || typeof text !== "string") {
|
|
10
|
+
return text;
|
|
11
|
+
}
|
|
12
|
+
return text.replace(/\\"/g, '"').replace(/\\'/g, "'");
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Simple hash function to create a unique identifier from a string
|
|
17
|
+
* Uses a variation of the djb2 hash algorithm
|
|
18
|
+
*
|
|
19
|
+
* @param {string} str - The string to hash
|
|
20
|
+
* @return {string} A hexadecimal hash string
|
|
21
|
+
*/
|
|
22
|
+
export const simpleHash = (str) => {
|
|
23
|
+
// Handle null, undefined, or empty strings
|
|
24
|
+
if (!str || typeof str !== "string") {
|
|
25
|
+
return "0";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let hash = 5381;
|
|
29
|
+
for (let i = 0; i < str.length; i++) {
|
|
30
|
+
// eslint-disable-next-line no-bitwise
|
|
31
|
+
hash = (hash << 5) + hash + str.charCodeAt(i); // hash * 33 + c
|
|
32
|
+
// eslint-disable-next-line no-bitwise
|
|
33
|
+
hash = hash | 0; // Convert to 32-bit integer
|
|
34
|
+
}
|
|
35
|
+
// Convert to unsigned and then to hex
|
|
36
|
+
// eslint-disable-next-line no-bitwise
|
|
37
|
+
return (hash >>> 0).toString(16);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Generate a unique session ID
|
|
42
|
+
*
|
|
43
|
+
* @return {string} New session ID
|
|
44
|
+
*/
|
|
45
|
+
export const generateSessionId = () => {
|
|
46
|
+
return crypto.randomUUID
|
|
47
|
+
? crypto.randomUUID()
|
|
48
|
+
: `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Debounce function
|
|
53
|
+
*
|
|
54
|
+
* @param {Function} func - Function to debounce
|
|
55
|
+
* @param {number} wait - Wait time in milliseconds
|
|
56
|
+
* @return {Function} Debounced function
|
|
57
|
+
*/
|
|
58
|
+
export const debounce = (func, wait) => {
|
|
59
|
+
let timeout;
|
|
60
|
+
return function executedFunction(...args) {
|
|
61
|
+
const later = () => {
|
|
62
|
+
clearTimeout(timeout);
|
|
63
|
+
func(...args);
|
|
64
|
+
};
|
|
65
|
+
clearTimeout(timeout);
|
|
66
|
+
timeout = setTimeout(later, wait);
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export default {
|
|
71
|
+
unescapeAiResponse,
|
|
72
|
+
simpleHash,
|
|
73
|
+
generateSessionId,
|
|
74
|
+
debounce,
|
|
75
|
+
};
|