wineater-bot 1.0.0 → 1.1.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/wineater-chatbot.mjs +277 -42
- package/dist/wineater-chatbot.umd.js +234 -2
- package/index.html +2 -1
- package/package.json +8 -2
- package/src/index.js +1 -1
- package/src/js/styles.js +238 -0
- package/dist/style.css +0 -1
|
@@ -1,54 +1,289 @@
|
|
|
1
|
-
|
|
1
|
+
const c = `
|
|
2
|
+
@font-face {
|
|
3
|
+
font-family: 'Poppins';
|
|
4
|
+
src: url('https://fonts.googleapis.com/css2?family=Poppins:wght@400&display=swap');
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/* Overall chatbot styles */
|
|
8
|
+
#chatbot-container {
|
|
9
|
+
position: fixed;
|
|
10
|
+
bottom: 20px;
|
|
11
|
+
right: 20px;
|
|
12
|
+
font-family: 'Poppins', sans-serif; /* Use Poppins as the main font */
|
|
13
|
+
z-index: 1000; /* Ensure chat is above other content */
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Styling the chat icon */
|
|
17
|
+
#chat-icon {
|
|
18
|
+
width: 60px;
|
|
19
|
+
height: 60px;
|
|
20
|
+
background-color: #7E27ED; /* Purple background color */
|
|
21
|
+
border-radius: 50%;
|
|
22
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
|
23
|
+
display: flex;
|
|
24
|
+
justify-content: center;
|
|
25
|
+
align-items: center;
|
|
26
|
+
cursor: pointer;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#chat-icon img {
|
|
30
|
+
width: 80%; /* Adjust icon size as needed */
|
|
31
|
+
height: auto;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Chat window styles */
|
|
35
|
+
#chat-window {
|
|
36
|
+
width: 350px; /* Width of the chat window */
|
|
37
|
+
background-color: white;
|
|
38
|
+
border-radius: 8px;
|
|
39
|
+
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
|
40
|
+
position: absolute;
|
|
41
|
+
bottom: 80px; /* Positioning from the bottom */
|
|
42
|
+
right: 0;
|
|
43
|
+
display: none; /* Initially hidden */
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Header of the chat window */
|
|
47
|
+
#chat-header {
|
|
48
|
+
background-color: #7E27ED;
|
|
49
|
+
color: white;
|
|
50
|
+
padding: 16px;
|
|
51
|
+
border-top-left-radius: 8px;
|
|
52
|
+
border-top-right-radius: 8px;
|
|
53
|
+
display: flex;
|
|
54
|
+
justify-content: space-between;
|
|
55
|
+
align-items: center;
|
|
56
|
+
position: relative; /* Needed for absolute positioning of the close button */
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
/* Style for the close button */
|
|
61
|
+
#close-btn {
|
|
62
|
+
font-size: 24px; /* Size of the close button */
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
padding: 0 10px;
|
|
65
|
+
line-height: 24px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Container for messages */
|
|
69
|
+
#message-container {
|
|
70
|
+
max-height: 300px;
|
|
71
|
+
overflow-y: auto;
|
|
72
|
+
padding: 15px;
|
|
73
|
+
background: #f7f7f7; /* Light grey background for the message area */
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* Input area */
|
|
77
|
+
#input-container {
|
|
78
|
+
border-top: 2px solid #ececec; /* Light border for input area */
|
|
79
|
+
background-color: white; /* White background for input area */
|
|
80
|
+
padding: 12px;
|
|
81
|
+
display: flex;
|
|
82
|
+
align-items: center; /* Align button and input vertically */
|
|
83
|
+
gap: 10px; /* Adds space between input and button */
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
#input-container input {
|
|
87
|
+
flex-grow: 1;
|
|
88
|
+
border: 2px solid #B928EB; /* Input border color based on style guide */
|
|
89
|
+
padding: 10px;
|
|
90
|
+
border-radius: 4px;
|
|
91
|
+
font-family: 'Poppins', sans-serif; /* Use Poppins font */
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
#input-container button {
|
|
95
|
+
padding: 10px 20px; /* Larger padding for a larger button */
|
|
96
|
+
background-color: #5F82FF; /* Button background color from style guide */
|
|
97
|
+
border: none;
|
|
98
|
+
color: white;
|
|
99
|
+
border-radius: 4px;
|
|
100
|
+
font-family: 'Poppins', sans-serif; /* Use Poppins font */
|
|
101
|
+
font-size: 1rem; /* Adjust font size as needed */
|
|
102
|
+
cursor: pointer;
|
|
103
|
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); /* Add subtle shadow for depth */
|
|
104
|
+
transition: background-color 0.3s ease; /* Smooth transition for background color */
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
#input-container button:hover {
|
|
108
|
+
background-color: #2FC0BF; /* Hover color based on style guide */
|
|
109
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); /* Darker shadow for hover state */
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* Message bubble styling */
|
|
113
|
+
.message {
|
|
114
|
+
margin-bottom: 8px;
|
|
115
|
+
padding: 12px;
|
|
116
|
+
background-color: #e0e0e0; /* Light grey for message bubbles */
|
|
117
|
+
border-radius: 16px;
|
|
118
|
+
font-size: 14px;
|
|
119
|
+
line-height: 1.4;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.message.user {
|
|
123
|
+
background-color: #B928EB; /* User message bubble color */
|
|
124
|
+
color: white;
|
|
125
|
+
align-self: flex-end;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.message.api {
|
|
129
|
+
background-color: #e0e0e0; /* API message bubble color */
|
|
130
|
+
color: black;
|
|
131
|
+
align-self: flex-start;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* Wine item styling */
|
|
135
|
+
.wine-item {
|
|
136
|
+
display: flex;
|
|
137
|
+
align-items: center;
|
|
138
|
+
border: 1px solid #ddd;
|
|
139
|
+
border-radius: 8px;
|
|
140
|
+
padding: 10px;
|
|
141
|
+
margin-top: 10px;
|
|
142
|
+
background: white; /* White background for wine items */
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.wine-item img {
|
|
146
|
+
width: 80px; /* Smaller wine image size */
|
|
147
|
+
height: auto;
|
|
148
|
+
border-radius: 4px; /* Rounded corners for images */
|
|
149
|
+
margin-right: 12px;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.wine-item div {
|
|
153
|
+
font-size: 0.9rem; /* Smaller font size for wine info */
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* Ensure the chat window is visible when the 'visible' class is added */
|
|
157
|
+
#chat-window.visible {
|
|
158
|
+
display: block;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/* Loader Styles */
|
|
162
|
+
.loader {
|
|
163
|
+
display: none; /* Loader is hidden by default */
|
|
164
|
+
border: 4px solid #f3f3f3; /* Light grey */
|
|
165
|
+
border-top: 4px solid #3498db; /* Blue, could be your primary color */
|
|
166
|
+
border-radius: 50%;
|
|
167
|
+
width: 40px;
|
|
168
|
+
height: 40px;
|
|
169
|
+
animation: spin 2s linear infinite;
|
|
170
|
+
margin: 20px auto; /* Centered horizontally */
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.loader.visible {
|
|
174
|
+
display: block;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@keyframes spin {
|
|
178
|
+
0% { transform: rotate(0deg); }
|
|
179
|
+
100% { transform: rotate(360deg); }
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* Typing indicator styles */
|
|
183
|
+
.typing-indicator {
|
|
184
|
+
display: flex;
|
|
185
|
+
justify-content: center;
|
|
186
|
+
align-items: center;
|
|
187
|
+
height: 0; /* Adjust as needed */
|
|
188
|
+
visibility: hidden; /* Start off invisible */
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.typing-indicator span {
|
|
192
|
+
display: block;
|
|
193
|
+
width: 8px;
|
|
194
|
+
height: 8px;
|
|
195
|
+
margin: 0 4px;
|
|
196
|
+
background-color: #3498db; /* Or use a color from your style guide */
|
|
197
|
+
border-radius: 50%;
|
|
198
|
+
opacity: 0.4;
|
|
199
|
+
animation: typing 1.5s infinite;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* Animation keyframes */
|
|
203
|
+
@keyframes typing {
|
|
204
|
+
0% { transform: translateY(0); }
|
|
205
|
+
20% { transform: translateY(-10px); }
|
|
206
|
+
40% { transform: translateY(0); }
|
|
207
|
+
60% { transform: translateY(-10px); }
|
|
208
|
+
80% { transform: translateY(0); }
|
|
209
|
+
100% { transform: translateY(0); }
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/* To stagger the animation for each dot */
|
|
213
|
+
.typing-indicator span:nth-child(1) {
|
|
214
|
+
animation-delay: 0s;
|
|
215
|
+
}
|
|
216
|
+
.typing-indicator span:nth-child(2) {
|
|
217
|
+
animation-delay: 0.2s;
|
|
218
|
+
}
|
|
219
|
+
.typing-indicator span:nth-child(3) {
|
|
220
|
+
animation-delay: 0.4s;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/* Show the typing indicator */
|
|
224
|
+
.typing-indicator.visible {
|
|
225
|
+
visibility: visible;
|
|
226
|
+
height: 50px;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
#message-container {
|
|
230
|
+
overflow-y: auto;
|
|
231
|
+
height: 300px; /* adjust based on your UI needs */
|
|
232
|
+
padding: 10px;
|
|
233
|
+
}`, r = document.createElement("style");
|
|
234
|
+
r.textContent = c;
|
|
235
|
+
document.head.appendChild(r);
|
|
236
|
+
function d() {
|
|
2
237
|
document.getElementById("chat-window").classList.toggle("visible");
|
|
3
238
|
}
|
|
4
|
-
function
|
|
239
|
+
function l() {
|
|
5
240
|
document.getElementById("chat-window").classList.remove("visible");
|
|
6
241
|
}
|
|
7
|
-
function
|
|
242
|
+
function p() {
|
|
8
243
|
document.getElementById("chat-window").classList.add("visible");
|
|
9
244
|
}
|
|
10
245
|
document.addEventListener("DOMContentLoaded", () => {
|
|
11
246
|
setupCloseButton(), setupOutsideClick();
|
|
12
247
|
});
|
|
13
|
-
class
|
|
248
|
+
class g {
|
|
14
249
|
constructor(n) {
|
|
15
250
|
this.apiEndpoint = n || "https://api.wineater.com/dish/recommendations";
|
|
16
251
|
}
|
|
17
252
|
async getWineRecommendations(n) {
|
|
18
253
|
try {
|
|
19
|
-
const
|
|
254
|
+
const t = await fetch(this.apiEndpoint, {
|
|
20
255
|
method: "POST",
|
|
21
256
|
headers: {
|
|
22
257
|
"Content-Type": "application/json"
|
|
23
258
|
},
|
|
24
259
|
body: JSON.stringify({ text: n })
|
|
25
|
-
}),
|
|
26
|
-
if (!
|
|
27
|
-
throw new Error(`API call failed with status ${
|
|
28
|
-
return
|
|
29
|
-
} catch (
|
|
30
|
-
throw console.error("Fetching wine recommendations failed:",
|
|
260
|
+
}), e = await t.json();
|
|
261
|
+
if (!t.ok)
|
|
262
|
+
throw new Error(`API call failed with status ${t.status}: ${e.message || "No additional error information"}`);
|
|
263
|
+
return e;
|
|
264
|
+
} catch (t) {
|
|
265
|
+
throw console.error("Fetching wine recommendations failed:", t.message), new Error(`Error in getWineRecommendations: ${t.message}`);
|
|
31
266
|
}
|
|
32
267
|
}
|
|
33
268
|
}
|
|
34
269
|
class h {
|
|
35
270
|
constructor() {
|
|
36
|
-
this.api = new
|
|
271
|
+
this.api = new g();
|
|
37
272
|
}
|
|
38
273
|
initialize() {
|
|
39
|
-
document.getElementById("send-button").addEventListener("click", () => this.handleUserInput()), document.getElementById("user-input").addEventListener("keypress", (
|
|
40
|
-
|
|
274
|
+
document.getElementById("send-button").addEventListener("click", () => this.handleUserInput()), document.getElementById("user-input").addEventListener("keypress", (e) => {
|
|
275
|
+
e.key === "Enter" && this.handleUserInput();
|
|
41
276
|
});
|
|
42
277
|
}
|
|
43
278
|
async handleUserInput() {
|
|
44
|
-
const n = document.getElementById("user-input"),
|
|
45
|
-
if (
|
|
46
|
-
this.displayMessage(
|
|
279
|
+
const n = document.getElementById("user-input"), t = n.value.trim();
|
|
280
|
+
if (t) {
|
|
281
|
+
this.displayMessage(t, "user"), n.value = "", this.showTypingIndicator();
|
|
47
282
|
try {
|
|
48
|
-
const
|
|
49
|
-
this.hideTypingIndicator(),
|
|
50
|
-
} catch (
|
|
51
|
-
this.hideTypingIndicator(), console.error("Error fetching wine recommendations:",
|
|
283
|
+
const e = await this.api.getWineRecommendations(t);
|
|
284
|
+
this.hideTypingIndicator(), e && e.length ? this.displayResults(e) : this.displayMessage("No results found.", "api");
|
|
285
|
+
} catch (e) {
|
|
286
|
+
this.hideTypingIndicator(), console.error("Error fetching wine recommendations:", e), this.displayMessage("Sorry, something went wrong.", "api");
|
|
52
287
|
}
|
|
53
288
|
}
|
|
54
289
|
}
|
|
@@ -58,26 +293,26 @@ class h {
|
|
|
58
293
|
hideTypingIndicator() {
|
|
59
294
|
document.getElementById("typing-indicator").classList.remove("visible");
|
|
60
295
|
}
|
|
61
|
-
displayMessage(n,
|
|
62
|
-
const
|
|
63
|
-
o.textContent = n, o.className = "message " +
|
|
296
|
+
displayMessage(n, t) {
|
|
297
|
+
const e = document.getElementById("message-container"), o = document.createElement("div");
|
|
298
|
+
o.textContent = n, o.className = "message " + t, e.appendChild(o), e.scrollTop = e.scrollHeight;
|
|
64
299
|
}
|
|
65
300
|
displayResults(n) {
|
|
66
|
-
const
|
|
67
|
-
n.forEach((
|
|
301
|
+
const t = document.getElementById("message-container");
|
|
302
|
+
n.forEach((e) => {
|
|
68
303
|
const o = document.createElement("div");
|
|
69
304
|
o.className = "wine-item";
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
}),
|
|
305
|
+
const a = document.createElement("img");
|
|
306
|
+
a.src = e.Image, o.appendChild(a);
|
|
307
|
+
const s = document.createElement("div");
|
|
308
|
+
s.innerHTML = `<strong>${e.Title}</strong><br>Price: ${e.Price}<br>Region: ${e.Region}<br>Type: ${e.Type}<br><a href="${e.Url}" target="_blank">More Info</a>`, o.appendChild(s), t.appendChild(o);
|
|
309
|
+
}), t.scrollTop = t.scrollHeight;
|
|
75
310
|
}
|
|
76
311
|
}
|
|
77
312
|
document.addEventListener("DOMContentLoaded", () => {
|
|
78
|
-
window.toggleChatWindow =
|
|
313
|
+
window.toggleChatWindow = d, window.closeChatWindow = l, window.openChatWindow = p;
|
|
79
314
|
});
|
|
80
|
-
function
|
|
315
|
+
function u() {
|
|
81
316
|
document.body.insertAdjacentHTML("beforeend", `
|
|
82
317
|
<div id="chatbot-container">
|
|
83
318
|
<div id="chat-icon" onclick="toggleChatWindow()">
|
|
@@ -101,20 +336,20 @@ function m() {
|
|
|
101
336
|
</div>
|
|
102
337
|
`);
|
|
103
338
|
}
|
|
104
|
-
function
|
|
105
|
-
document.getElementById("close-btn").addEventListener("click",
|
|
339
|
+
function m() {
|
|
340
|
+
document.getElementById("close-btn").addEventListener("click", d);
|
|
106
341
|
}
|
|
107
|
-
function
|
|
342
|
+
function b() {
|
|
108
343
|
window.addEventListener("click", function(i) {
|
|
109
|
-
const n = document.getElementById("chat-window"),
|
|
110
|
-
!n.contains(i.target) && !
|
|
344
|
+
const n = document.getElementById("chat-window"), t = document.getElementById("chat-icon");
|
|
345
|
+
!n.contains(i.target) && !t.contains(i.target) && n.classList.remove("visible");
|
|
111
346
|
});
|
|
112
347
|
}
|
|
113
348
|
typeof window < "u" && window.addEventListener("DOMContentLoaded", () => {
|
|
114
|
-
|
|
349
|
+
u(), m(), b(), new h().initialize();
|
|
115
350
|
});
|
|
116
351
|
export {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
352
|
+
l as closeChatWindow,
|
|
353
|
+
p as openChatWindow,
|
|
354
|
+
d as toggleChatWindow
|
|
120
355
|
};
|
|
@@ -1,4 +1,236 @@
|
|
|
1
|
-
(function(o,
|
|
1
|
+
(function(o,s){typeof exports=="object"&&typeof module<"u"?s(exports):typeof define=="function"&&define.amd?define(["exports"],s):(o=typeof globalThis<"u"?globalThis:o||self,s(o.WineaterChatbot={}))})(this,function(o){"use strict";const s=`
|
|
2
|
+
@font-face {
|
|
3
|
+
font-family: 'Poppins';
|
|
4
|
+
src: url('https://fonts.googleapis.com/css2?family=Poppins:wght@400&display=swap');
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/* Overall chatbot styles */
|
|
8
|
+
#chatbot-container {
|
|
9
|
+
position: fixed;
|
|
10
|
+
bottom: 20px;
|
|
11
|
+
right: 20px;
|
|
12
|
+
font-family: 'Poppins', sans-serif; /* Use Poppins as the main font */
|
|
13
|
+
z-index: 1000; /* Ensure chat is above other content */
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Styling the chat icon */
|
|
17
|
+
#chat-icon {
|
|
18
|
+
width: 60px;
|
|
19
|
+
height: 60px;
|
|
20
|
+
background-color: #7E27ED; /* Purple background color */
|
|
21
|
+
border-radius: 50%;
|
|
22
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
|
23
|
+
display: flex;
|
|
24
|
+
justify-content: center;
|
|
25
|
+
align-items: center;
|
|
26
|
+
cursor: pointer;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#chat-icon img {
|
|
30
|
+
width: 80%; /* Adjust icon size as needed */
|
|
31
|
+
height: auto;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Chat window styles */
|
|
35
|
+
#chat-window {
|
|
36
|
+
width: 350px; /* Width of the chat window */
|
|
37
|
+
background-color: white;
|
|
38
|
+
border-radius: 8px;
|
|
39
|
+
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
|
40
|
+
position: absolute;
|
|
41
|
+
bottom: 80px; /* Positioning from the bottom */
|
|
42
|
+
right: 0;
|
|
43
|
+
display: none; /* Initially hidden */
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Header of the chat window */
|
|
47
|
+
#chat-header {
|
|
48
|
+
background-color: #7E27ED;
|
|
49
|
+
color: white;
|
|
50
|
+
padding: 16px;
|
|
51
|
+
border-top-left-radius: 8px;
|
|
52
|
+
border-top-right-radius: 8px;
|
|
53
|
+
display: flex;
|
|
54
|
+
justify-content: space-between;
|
|
55
|
+
align-items: center;
|
|
56
|
+
position: relative; /* Needed for absolute positioning of the close button */
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
/* Style for the close button */
|
|
61
|
+
#close-btn {
|
|
62
|
+
font-size: 24px; /* Size of the close button */
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
padding: 0 10px;
|
|
65
|
+
line-height: 24px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Container for messages */
|
|
69
|
+
#message-container {
|
|
70
|
+
max-height: 300px;
|
|
71
|
+
overflow-y: auto;
|
|
72
|
+
padding: 15px;
|
|
73
|
+
background: #f7f7f7; /* Light grey background for the message area */
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* Input area */
|
|
77
|
+
#input-container {
|
|
78
|
+
border-top: 2px solid #ececec; /* Light border for input area */
|
|
79
|
+
background-color: white; /* White background for input area */
|
|
80
|
+
padding: 12px;
|
|
81
|
+
display: flex;
|
|
82
|
+
align-items: center; /* Align button and input vertically */
|
|
83
|
+
gap: 10px; /* Adds space between input and button */
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
#input-container input {
|
|
87
|
+
flex-grow: 1;
|
|
88
|
+
border: 2px solid #B928EB; /* Input border color based on style guide */
|
|
89
|
+
padding: 10px;
|
|
90
|
+
border-radius: 4px;
|
|
91
|
+
font-family: 'Poppins', sans-serif; /* Use Poppins font */
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
#input-container button {
|
|
95
|
+
padding: 10px 20px; /* Larger padding for a larger button */
|
|
96
|
+
background-color: #5F82FF; /* Button background color from style guide */
|
|
97
|
+
border: none;
|
|
98
|
+
color: white;
|
|
99
|
+
border-radius: 4px;
|
|
100
|
+
font-family: 'Poppins', sans-serif; /* Use Poppins font */
|
|
101
|
+
font-size: 1rem; /* Adjust font size as needed */
|
|
102
|
+
cursor: pointer;
|
|
103
|
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); /* Add subtle shadow for depth */
|
|
104
|
+
transition: background-color 0.3s ease; /* Smooth transition for background color */
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
#input-container button:hover {
|
|
108
|
+
background-color: #2FC0BF; /* Hover color based on style guide */
|
|
109
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); /* Darker shadow for hover state */
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* Message bubble styling */
|
|
113
|
+
.message {
|
|
114
|
+
margin-bottom: 8px;
|
|
115
|
+
padding: 12px;
|
|
116
|
+
background-color: #e0e0e0; /* Light grey for message bubbles */
|
|
117
|
+
border-radius: 16px;
|
|
118
|
+
font-size: 14px;
|
|
119
|
+
line-height: 1.4;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.message.user {
|
|
123
|
+
background-color: #B928EB; /* User message bubble color */
|
|
124
|
+
color: white;
|
|
125
|
+
align-self: flex-end;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.message.api {
|
|
129
|
+
background-color: #e0e0e0; /* API message bubble color */
|
|
130
|
+
color: black;
|
|
131
|
+
align-self: flex-start;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* Wine item styling */
|
|
135
|
+
.wine-item {
|
|
136
|
+
display: flex;
|
|
137
|
+
align-items: center;
|
|
138
|
+
border: 1px solid #ddd;
|
|
139
|
+
border-radius: 8px;
|
|
140
|
+
padding: 10px;
|
|
141
|
+
margin-top: 10px;
|
|
142
|
+
background: white; /* White background for wine items */
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.wine-item img {
|
|
146
|
+
width: 80px; /* Smaller wine image size */
|
|
147
|
+
height: auto;
|
|
148
|
+
border-radius: 4px; /* Rounded corners for images */
|
|
149
|
+
margin-right: 12px;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.wine-item div {
|
|
153
|
+
font-size: 0.9rem; /* Smaller font size for wine info */
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* Ensure the chat window is visible when the 'visible' class is added */
|
|
157
|
+
#chat-window.visible {
|
|
158
|
+
display: block;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/* Loader Styles */
|
|
162
|
+
.loader {
|
|
163
|
+
display: none; /* Loader is hidden by default */
|
|
164
|
+
border: 4px solid #f3f3f3; /* Light grey */
|
|
165
|
+
border-top: 4px solid #3498db; /* Blue, could be your primary color */
|
|
166
|
+
border-radius: 50%;
|
|
167
|
+
width: 40px;
|
|
168
|
+
height: 40px;
|
|
169
|
+
animation: spin 2s linear infinite;
|
|
170
|
+
margin: 20px auto; /* Centered horizontally */
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.loader.visible {
|
|
174
|
+
display: block;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@keyframes spin {
|
|
178
|
+
0% { transform: rotate(0deg); }
|
|
179
|
+
100% { transform: rotate(360deg); }
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* Typing indicator styles */
|
|
183
|
+
.typing-indicator {
|
|
184
|
+
display: flex;
|
|
185
|
+
justify-content: center;
|
|
186
|
+
align-items: center;
|
|
187
|
+
height: 0; /* Adjust as needed */
|
|
188
|
+
visibility: hidden; /* Start off invisible */
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.typing-indicator span {
|
|
192
|
+
display: block;
|
|
193
|
+
width: 8px;
|
|
194
|
+
height: 8px;
|
|
195
|
+
margin: 0 4px;
|
|
196
|
+
background-color: #3498db; /* Or use a color from your style guide */
|
|
197
|
+
border-radius: 50%;
|
|
198
|
+
opacity: 0.4;
|
|
199
|
+
animation: typing 1.5s infinite;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* Animation keyframes */
|
|
203
|
+
@keyframes typing {
|
|
204
|
+
0% { transform: translateY(0); }
|
|
205
|
+
20% { transform: translateY(-10px); }
|
|
206
|
+
40% { transform: translateY(0); }
|
|
207
|
+
60% { transform: translateY(-10px); }
|
|
208
|
+
80% { transform: translateY(0); }
|
|
209
|
+
100% { transform: translateY(0); }
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/* To stagger the animation for each dot */
|
|
213
|
+
.typing-indicator span:nth-child(1) {
|
|
214
|
+
animation-delay: 0s;
|
|
215
|
+
}
|
|
216
|
+
.typing-indicator span:nth-child(2) {
|
|
217
|
+
animation-delay: 0.2s;
|
|
218
|
+
}
|
|
219
|
+
.typing-indicator span:nth-child(3) {
|
|
220
|
+
animation-delay: 0.4s;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/* Show the typing indicator */
|
|
224
|
+
.typing-indicator.visible {
|
|
225
|
+
visibility: visible;
|
|
226
|
+
height: 50px;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
#message-container {
|
|
230
|
+
overflow-y: auto;
|
|
231
|
+
height: 300px; /* adjust based on your UI needs */
|
|
232
|
+
padding: 10px;
|
|
233
|
+
}`,r=document.createElement("style");r.textContent=s,document.head.appendChild(r);function d(){document.getElementById("chat-window").classList.toggle("visible")}function c(){document.getElementById("chat-window").classList.remove("visible")}function l(){document.getElementById("chat-window").classList.add("visible")}document.addEventListener("DOMContentLoaded",()=>{setupCloseButton(),setupOutsideClick()});class h{constructor(n){this.apiEndpoint=n||"https://api.wineater.com/dish/recommendations"}async getWineRecommendations(n){try{const t=await fetch(this.apiEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({text:n})}),e=await t.json();if(!t.ok)throw new Error(`API call failed with status ${t.status}: ${e.message||"No additional error information"}`);return e}catch(t){throw console.error("Fetching wine recommendations failed:",t.message),new Error(`Error in getWineRecommendations: ${t.message}`)}}}class u{constructor(){this.api=new h}initialize(){document.getElementById("send-button").addEventListener("click",()=>this.handleUserInput()),document.getElementById("user-input").addEventListener("keypress",e=>{e.key==="Enter"&&this.handleUserInput()})}async handleUserInput(){const n=document.getElementById("user-input"),t=n.value.trim();if(t){this.displayMessage(t,"user"),n.value="",this.showTypingIndicator();try{const e=await this.api.getWineRecommendations(t);this.hideTypingIndicator(),e&&e.length?this.displayResults(e):this.displayMessage("No results found.","api")}catch(e){this.hideTypingIndicator(),console.error("Error fetching wine recommendations:",e),this.displayMessage("Sorry, something went wrong.","api")}}}showTypingIndicator(){document.getElementById("typing-indicator").classList.add("visible")}hideTypingIndicator(){document.getElementById("typing-indicator").classList.remove("visible")}displayMessage(n,t){const e=document.getElementById("message-container"),a=document.createElement("div");a.textContent=n,a.className="message "+t,e.appendChild(a),e.scrollTop=e.scrollHeight}displayResults(n){const t=document.getElementById("message-container");n.forEach(e=>{const a=document.createElement("div");a.className="wine-item";const p=document.createElement("img");p.src=e.Image,a.appendChild(p);const g=document.createElement("div");g.innerHTML=`<strong>${e.Title}</strong><br>Price: ${e.Price}<br>Region: ${e.Region}<br>Type: ${e.Type}<br><a href="${e.Url}" target="_blank">More Info</a>`,a.appendChild(g),t.appendChild(a)}),t.scrollTop=t.scrollHeight}}document.addEventListener("DOMContentLoaded",()=>{window.toggleChatWindow=d,window.closeChatWindow=c,window.openChatWindow=l});function m(){document.body.insertAdjacentHTML("beforeend",`
|
|
2
234
|
<div id="chatbot-container">
|
|
3
235
|
<div id="chat-icon" onclick="toggleChatWindow()">
|
|
4
236
|
<img src="/src/assets/images/chat-icon.svg" alt="Chat Icon">
|
|
@@ -19,4 +251,4 @@
|
|
|
19
251
|
</div>
|
|
20
252
|
</div>
|
|
21
253
|
</div>
|
|
22
|
-
`)}function
|
|
254
|
+
`)}function b(){document.getElementById("close-btn").addEventListener("click",d)}function f(){window.addEventListener("click",function(i){const n=document.getElementById("chat-window"),t=document.getElementById("chat-icon");!n.contains(i.target)&&!t.contains(i.target)&&n.classList.remove("visible")})}typeof window<"u"&&window.addEventListener("DOMContentLoaded",()=>{m(),b(),f(),new u().initialize()}),o.closeChatWindow=c,o.openChatWindow=l,o.toggleChatWindow=d,Object.defineProperty(o,Symbol.toStringTag,{value:"Module"})});
|
package/index.html
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Chatbot</title>
|
|
7
|
-
<
|
|
7
|
+
<!-- <script type="module" src="https://unpkg.com/wineater-bot@1.0.0/dist/wineater-chatbot.umd.js"></script> -->
|
|
8
8
|
<script type="module" src="./src/index.js"></script>
|
|
9
|
+
|
|
9
10
|
</head>
|
|
10
11
|
<body>
|
|
11
12
|
</body>
|
package/package.json
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wineater-bot",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "src/index.js",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"dev": "vite",
|
|
9
|
-
"build": "vite build"
|
|
9
|
+
"build": "vite build",
|
|
10
|
+
"release:patch": "npm version patch && npm publish",
|
|
11
|
+
"release:minor": "npm version minor && npm publish",
|
|
12
|
+
"release:major": "npm version major && npm publish"
|
|
10
13
|
},
|
|
11
14
|
"keywords": [],
|
|
12
15
|
"author": "",
|
|
13
16
|
"license": "ISC",
|
|
14
17
|
"dependencies": {
|
|
15
18
|
"vite": "^5.2.9"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"rollup-plugin-postcss": "^4.0.2"
|
|
16
22
|
}
|
|
17
23
|
}
|
package/src/index.js
CHANGED
package/src/js/styles.js
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
// src/styles.js
|
|
2
|
+
const css = `
|
|
3
|
+
@font-face {
|
|
4
|
+
font-family: 'Poppins';
|
|
5
|
+
src: url('https://fonts.googleapis.com/css2?family=Poppins:wght@400&display=swap');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/* Overall chatbot styles */
|
|
9
|
+
#chatbot-container {
|
|
10
|
+
position: fixed;
|
|
11
|
+
bottom: 20px;
|
|
12
|
+
right: 20px;
|
|
13
|
+
font-family: 'Poppins', sans-serif; /* Use Poppins as the main font */
|
|
14
|
+
z-index: 1000; /* Ensure chat is above other content */
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* Styling the chat icon */
|
|
18
|
+
#chat-icon {
|
|
19
|
+
width: 60px;
|
|
20
|
+
height: 60px;
|
|
21
|
+
background-color: #7E27ED; /* Purple background color */
|
|
22
|
+
border-radius: 50%;
|
|
23
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
|
24
|
+
display: flex;
|
|
25
|
+
justify-content: center;
|
|
26
|
+
align-items: center;
|
|
27
|
+
cursor: pointer;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#chat-icon img {
|
|
31
|
+
width: 80%; /* Adjust icon size as needed */
|
|
32
|
+
height: auto;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* Chat window styles */
|
|
36
|
+
#chat-window {
|
|
37
|
+
width: 350px; /* Width of the chat window */
|
|
38
|
+
background-color: white;
|
|
39
|
+
border-radius: 8px;
|
|
40
|
+
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
|
41
|
+
position: absolute;
|
|
42
|
+
bottom: 80px; /* Positioning from the bottom */
|
|
43
|
+
right: 0;
|
|
44
|
+
display: none; /* Initially hidden */
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Header of the chat window */
|
|
48
|
+
#chat-header {
|
|
49
|
+
background-color: #7E27ED;
|
|
50
|
+
color: white;
|
|
51
|
+
padding: 16px;
|
|
52
|
+
border-top-left-radius: 8px;
|
|
53
|
+
border-top-right-radius: 8px;
|
|
54
|
+
display: flex;
|
|
55
|
+
justify-content: space-between;
|
|
56
|
+
align-items: center;
|
|
57
|
+
position: relative; /* Needed for absolute positioning of the close button */
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
/* Style for the close button */
|
|
62
|
+
#close-btn {
|
|
63
|
+
font-size: 24px; /* Size of the close button */
|
|
64
|
+
cursor: pointer;
|
|
65
|
+
padding: 0 10px;
|
|
66
|
+
line-height: 24px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Container for messages */
|
|
70
|
+
#message-container {
|
|
71
|
+
max-height: 300px;
|
|
72
|
+
overflow-y: auto;
|
|
73
|
+
padding: 15px;
|
|
74
|
+
background: #f7f7f7; /* Light grey background for the message area */
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Input area */
|
|
78
|
+
#input-container {
|
|
79
|
+
border-top: 2px solid #ececec; /* Light border for input area */
|
|
80
|
+
background-color: white; /* White background for input area */
|
|
81
|
+
padding: 12px;
|
|
82
|
+
display: flex;
|
|
83
|
+
align-items: center; /* Align button and input vertically */
|
|
84
|
+
gap: 10px; /* Adds space between input and button */
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
#input-container input {
|
|
88
|
+
flex-grow: 1;
|
|
89
|
+
border: 2px solid #B928EB; /* Input border color based on style guide */
|
|
90
|
+
padding: 10px;
|
|
91
|
+
border-radius: 4px;
|
|
92
|
+
font-family: 'Poppins', sans-serif; /* Use Poppins font */
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
#input-container button {
|
|
96
|
+
padding: 10px 20px; /* Larger padding for a larger button */
|
|
97
|
+
background-color: #5F82FF; /* Button background color from style guide */
|
|
98
|
+
border: none;
|
|
99
|
+
color: white;
|
|
100
|
+
border-radius: 4px;
|
|
101
|
+
font-family: 'Poppins', sans-serif; /* Use Poppins font */
|
|
102
|
+
font-size: 1rem; /* Adjust font size as needed */
|
|
103
|
+
cursor: pointer;
|
|
104
|
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); /* Add subtle shadow for depth */
|
|
105
|
+
transition: background-color 0.3s ease; /* Smooth transition for background color */
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#input-container button:hover {
|
|
109
|
+
background-color: #2FC0BF; /* Hover color based on style guide */
|
|
110
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); /* Darker shadow for hover state */
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* Message bubble styling */
|
|
114
|
+
.message {
|
|
115
|
+
margin-bottom: 8px;
|
|
116
|
+
padding: 12px;
|
|
117
|
+
background-color: #e0e0e0; /* Light grey for message bubbles */
|
|
118
|
+
border-radius: 16px;
|
|
119
|
+
font-size: 14px;
|
|
120
|
+
line-height: 1.4;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.message.user {
|
|
124
|
+
background-color: #B928EB; /* User message bubble color */
|
|
125
|
+
color: white;
|
|
126
|
+
align-self: flex-end;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.message.api {
|
|
130
|
+
background-color: #e0e0e0; /* API message bubble color */
|
|
131
|
+
color: black;
|
|
132
|
+
align-self: flex-start;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* Wine item styling */
|
|
136
|
+
.wine-item {
|
|
137
|
+
display: flex;
|
|
138
|
+
align-items: center;
|
|
139
|
+
border: 1px solid #ddd;
|
|
140
|
+
border-radius: 8px;
|
|
141
|
+
padding: 10px;
|
|
142
|
+
margin-top: 10px;
|
|
143
|
+
background: white; /* White background for wine items */
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.wine-item img {
|
|
147
|
+
width: 80px; /* Smaller wine image size */
|
|
148
|
+
height: auto;
|
|
149
|
+
border-radius: 4px; /* Rounded corners for images */
|
|
150
|
+
margin-right: 12px;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.wine-item div {
|
|
154
|
+
font-size: 0.9rem; /* Smaller font size for wine info */
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* Ensure the chat window is visible when the 'visible' class is added */
|
|
158
|
+
#chat-window.visible {
|
|
159
|
+
display: block;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* Loader Styles */
|
|
163
|
+
.loader {
|
|
164
|
+
display: none; /* Loader is hidden by default */
|
|
165
|
+
border: 4px solid #f3f3f3; /* Light grey */
|
|
166
|
+
border-top: 4px solid #3498db; /* Blue, could be your primary color */
|
|
167
|
+
border-radius: 50%;
|
|
168
|
+
width: 40px;
|
|
169
|
+
height: 40px;
|
|
170
|
+
animation: spin 2s linear infinite;
|
|
171
|
+
margin: 20px auto; /* Centered horizontally */
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.loader.visible {
|
|
175
|
+
display: block;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@keyframes spin {
|
|
179
|
+
0% { transform: rotate(0deg); }
|
|
180
|
+
100% { transform: rotate(360deg); }
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/* Typing indicator styles */
|
|
184
|
+
.typing-indicator {
|
|
185
|
+
display: flex;
|
|
186
|
+
justify-content: center;
|
|
187
|
+
align-items: center;
|
|
188
|
+
height: 0; /* Adjust as needed */
|
|
189
|
+
visibility: hidden; /* Start off invisible */
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.typing-indicator span {
|
|
193
|
+
display: block;
|
|
194
|
+
width: 8px;
|
|
195
|
+
height: 8px;
|
|
196
|
+
margin: 0 4px;
|
|
197
|
+
background-color: #3498db; /* Or use a color from your style guide */
|
|
198
|
+
border-radius: 50%;
|
|
199
|
+
opacity: 0.4;
|
|
200
|
+
animation: typing 1.5s infinite;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/* Animation keyframes */
|
|
204
|
+
@keyframes typing {
|
|
205
|
+
0% { transform: translateY(0); }
|
|
206
|
+
20% { transform: translateY(-10px); }
|
|
207
|
+
40% { transform: translateY(0); }
|
|
208
|
+
60% { transform: translateY(-10px); }
|
|
209
|
+
80% { transform: translateY(0); }
|
|
210
|
+
100% { transform: translateY(0); }
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/* To stagger the animation for each dot */
|
|
214
|
+
.typing-indicator span:nth-child(1) {
|
|
215
|
+
animation-delay: 0s;
|
|
216
|
+
}
|
|
217
|
+
.typing-indicator span:nth-child(2) {
|
|
218
|
+
animation-delay: 0.2s;
|
|
219
|
+
}
|
|
220
|
+
.typing-indicator span:nth-child(3) {
|
|
221
|
+
animation-delay: 0.4s;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* Show the typing indicator */
|
|
225
|
+
.typing-indicator.visible {
|
|
226
|
+
visibility: visible;
|
|
227
|
+
height: 50px;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
#message-container {
|
|
231
|
+
overflow-y: auto;
|
|
232
|
+
height: 300px; /* adjust based on your UI needs */
|
|
233
|
+
padding: 10px;
|
|
234
|
+
}`;
|
|
235
|
+
|
|
236
|
+
const style = document.createElement('style');
|
|
237
|
+
style.textContent = css;
|
|
238
|
+
document.head.appendChild(style);
|
package/dist/style.css
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@font-face{font-family:Poppins;src:url(https://fonts.googleapis.com/css2?family=Poppins:wght@400&display=swap)}#chatbot-container{position:fixed;bottom:20px;right:20px;font-family:Poppins,sans-serif;z-index:1000}#chat-icon{width:60px;height:60px;background-color:#7e27ed;border-radius:50%;box-shadow:0 4px 8px #0003;display:flex;justify-content:center;align-items:center;cursor:pointer}#chat-icon img{width:80%;height:auto}#chat-window{width:350px;background-color:#fff;border-radius:8px;box-shadow:0 5px 15px #0000001a;position:absolute;bottom:80px;right:0;display:none}#chat-header{background-color:#7e27ed;color:#fff;padding:16px;border-top-left-radius:8px;border-top-right-radius:8px;display:flex;justify-content:space-between;align-items:center;position:relative}#close-btn{font-size:24px;cursor:pointer;padding:0 10px;line-height:24px}#message-container{max-height:300px;overflow-y:auto;padding:15px;background:#f7f7f7}#input-container{border-top:2px solid #ececec;background-color:#fff;padding:12px;display:flex;align-items:center;gap:10px}#input-container input{flex-grow:1;border:2px solid #B928EB;padding:10px;border-radius:4px;font-family:Poppins,sans-serif}#input-container button{padding:10px 20px;background-color:#5f82ff;border:none;color:#fff;border-radius:4px;font-family:Poppins,sans-serif;font-size:1rem;cursor:pointer;box-shadow:0 2px 5px #0003;transition:background-color .3s ease}#input-container button:hover{background-color:#2fc0bf;box-shadow:0 4px 8px #0000004d}.message{margin-bottom:8px;padding:12px;background-color:#e0e0e0;border-radius:16px;font-size:14px;line-height:1.4}.message.user{background-color:#b928eb;color:#fff;align-self:flex-end}.message.api{background-color:#e0e0e0;color:#000;align-self:flex-start}.wine-item{display:flex;align-items:center;border:1px solid #ddd;border-radius:8px;padding:10px;margin-top:10px;background:#fff}.wine-item img{width:80px;height:auto;border-radius:4px;margin-right:12px}.wine-item div{font-size:.9rem}#chat-window.visible{display:block}.loader{display:none;border:4px solid #f3f3f3;border-top:4px solid #3498db;border-radius:50%;width:40px;height:40px;animation:spin 2s linear infinite;margin:20px auto}.loader.visible{display:block}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.typing-indicator{display:flex;justify-content:center;align-items:center;height:0;visibility:hidden}.typing-indicator span{display:block;width:8px;height:8px;margin:0 4px;background-color:#3498db;border-radius:50%;opacity:.4;animation:typing 1.5s infinite}@keyframes typing{0%{transform:translateY(0)}20%{transform:translateY(-10px)}40%{transform:translateY(0)}60%{transform:translateY(-10px)}80%{transform:translateY(0)}to{transform:translateY(0)}}.typing-indicator span:nth-child(1){animation-delay:0s}.typing-indicator span:nth-child(2){animation-delay:.2s}.typing-indicator span:nth-child(3){animation-delay:.4s}.typing-indicator.visible{visibility:visible;height:50px}#message-container{overflow-y:auto;height:300px;padding:10px}
|