wineater-bot 3.0.10 → 3.0.11
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 +700 -682
- package/dist/wineater-chatbot.umd.js +70 -80
- package/index.html +1 -1
- package/package.json +1 -1
- package/src/js/i18n.js +15 -0
- package/src/js/widget-styles.js +19 -0
- package/src/js/widget.js +58 -38
package/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Chatbot</title>
|
|
7
7
|
<!-- <script type="module" src="./dist/wineater-chatbot.umd.js"></script> -->
|
|
8
|
-
<script>window.wineaterData = {CLIENT_TOKEN: 'Y3I8Pi1FruGjVmIBqpV24PtOLYjzdROuxWX9tCXh82zjz7uUPxV3ETvHhoeiLS17', position: 'right-center', TYPE: 'widget', WIDGET_TYPE: '
|
|
8
|
+
<script>window.wineaterData = {CLIENT_TOKEN: 'Y3I8Pi1FruGjVmIBqpV24PtOLYjzdROuxWX9tCXh82zjz7uUPxV3ETvHhoeiLS17', position: 'right-center', TYPE: 'widget', WIDGET_TYPE: 'store'};</script>
|
|
9
9
|
<script type="module" src="./src/index.js"></script>
|
|
10
10
|
</head>
|
|
11
11
|
<body style="margin: 0;">
|
package/package.json
CHANGED
package/src/js/i18n.js
CHANGED
|
@@ -46,6 +46,11 @@ class Translator {
|
|
|
46
46
|
barResetButton: "Réinitialiser",
|
|
47
47
|
barName: "Nom du bar",
|
|
48
48
|
barNotesPlaceholder: "Entrez vos souhaits ici...",
|
|
49
|
+
placeholderSuggestions: [
|
|
50
|
+
"Vin pour les pâtes",
|
|
51
|
+
"Parfait avec du poisson",
|
|
52
|
+
"Recommandé pour une soirée"
|
|
53
|
+
],
|
|
49
54
|
},
|
|
50
55
|
es: {
|
|
51
56
|
welcomeMessage: "¿Qué vas a comer? Cuéntame tu plato y te recomendaré el maridaje perfecto.",
|
|
@@ -88,6 +93,11 @@ class Translator {
|
|
|
88
93
|
barResetButton: "Reiniciar",
|
|
89
94
|
barName: "Nombre del bar",
|
|
90
95
|
barNotesPlaceholder: "Agrega tus comentarios aquí...",
|
|
96
|
+
placeholderSuggestions: [
|
|
97
|
+
"Vino para pasta",
|
|
98
|
+
"Perfecto con pescado",
|
|
99
|
+
"Recomendado para una fiesta"
|
|
100
|
+
],
|
|
91
101
|
},
|
|
92
102
|
en: {
|
|
93
103
|
welcomeMessage: "What are you planning to eat? Share your dish and I'll recommend the perfect wine pairing for your meal.",
|
|
@@ -130,6 +140,11 @@ class Translator {
|
|
|
130
140
|
barResetButton: "Reset",
|
|
131
141
|
barName: "Bar Name",
|
|
132
142
|
barNotesPlaceholder: "Add your wishes here...",
|
|
143
|
+
placeholderSuggestions: [
|
|
144
|
+
"Wine for pasta",
|
|
145
|
+
"Perfect with fish",
|
|
146
|
+
"Recommended for a party"
|
|
147
|
+
],
|
|
133
148
|
},
|
|
134
149
|
de: {
|
|
135
150
|
welcomeMessage: "Was möchten Sie essen? Beschreiben Sie Ihr Gericht und ich empfehle Ihnen den perfekten Wein dazu.",
|
package/src/js/widget-styles.js
CHANGED
|
@@ -17,6 +17,9 @@ const widgetStyles = `
|
|
|
17
17
|
margin: 40px auto;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
.wine-widget-wrapper {
|
|
21
|
+
width: 100%;
|
|
22
|
+
}
|
|
20
23
|
/* Левая часть */
|
|
21
24
|
#wine-widget-left {
|
|
22
25
|
flex: 0 0 40%;
|
|
@@ -34,6 +37,7 @@ const widgetStyles = `
|
|
|
34
37
|
display: grid;
|
|
35
38
|
grid-template-columns: repeat(2, 1fr);
|
|
36
39
|
gap: 24px;
|
|
40
|
+
min-height: 300px;
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
/* Заголовок */
|
|
@@ -42,12 +46,14 @@ const widgetStyles = `
|
|
|
42
46
|
font-weight: bold;
|
|
43
47
|
margin: 0;
|
|
44
48
|
color: #333;
|
|
49
|
+
text-align: center;
|
|
45
50
|
}
|
|
46
51
|
|
|
47
52
|
#wine-widget-header p {
|
|
48
53
|
font-size: 16px;
|
|
49
54
|
color: #666;
|
|
50
55
|
margin-top: 8px;
|
|
56
|
+
text-align: center;
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
/* Поле ввода */
|
|
@@ -57,6 +63,19 @@ const widgetStyles = `
|
|
|
57
63
|
align-items: center;
|
|
58
64
|
margin: 12px 0;
|
|
59
65
|
}
|
|
66
|
+
#wine-search-input::placeholder {
|
|
67
|
+
opacity: 1;
|
|
68
|
+
color: #7B2BEB; /* Фиолетовый цвет для текста placeholder */
|
|
69
|
+
font-style: normal;
|
|
70
|
+
transition: color 0.3s ease, opacity 0.3s ease-in-out;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* При активном фокусе инпута */
|
|
74
|
+
#wine-search-input:focus::placeholder {
|
|
75
|
+
opacity: 0.5; /* Полупрозрачный эффект */
|
|
76
|
+
color: linear-gradient(90deg, #7B2BEB, #0044FF); /* Более светлый фиолетовый */
|
|
77
|
+
font-style: normal;
|
|
78
|
+
}
|
|
60
79
|
|
|
61
80
|
#wine-search-input {
|
|
62
81
|
flex: 1;
|
package/src/js/widget.js
CHANGED
|
@@ -28,6 +28,7 @@ export class WineWidget {
|
|
|
28
28
|
|
|
29
29
|
// Инициализируем виджет
|
|
30
30
|
this.initializeWidget();
|
|
31
|
+
this.initializeSearchAnimation();
|
|
31
32
|
|
|
32
33
|
// Если нужна мгновенная загрузка рекомендаций только в store
|
|
33
34
|
if (this.widgetType === 'store') {
|
|
@@ -40,8 +41,8 @@ export class WineWidget {
|
|
|
40
41
|
if (this.widgetType === 'store') {
|
|
41
42
|
const widgetHTML = `
|
|
42
43
|
<div id="wine-widget-container">
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
<div class="wine-widget-wrapper">
|
|
45
|
+
<div id="wine-widget-header">
|
|
45
46
|
<h1>${translator.translate('widgetTitle')}</h1>
|
|
46
47
|
<p>${translator.translate('widgetSubtitle')}</p>
|
|
47
48
|
</div>
|
|
@@ -49,42 +50,6 @@ export class WineWidget {
|
|
|
49
50
|
<input type="text" id="wine-search-input" placeholder="${translator.translate('searchPlaceholder')}">
|
|
50
51
|
<button id="wine-search-button">${translator.translate('searchButton')}</button>
|
|
51
52
|
</div>
|
|
52
|
-
<div id="wine-widget-filters">
|
|
53
|
-
<div class="filter-group">
|
|
54
|
-
<span class="filter-label">${translator.translate('priceRange')}:</span>
|
|
55
|
-
<div class="filter-buttons" id="price-buttons">
|
|
56
|
-
<button data-value="< 500">< $500</button>
|
|
57
|
-
<button data-value="500 - 1000">$500 - $1000</button>
|
|
58
|
-
<button data-value="> 1000">> $1000</button>
|
|
59
|
-
<button data-value=" " class="selected">Any</button>
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
<div class="filter-group">
|
|
63
|
-
<span class="filter-label">${translator.translate('wineColor')}:</span>
|
|
64
|
-
<div class="filter-buttons" id="color-buttons">
|
|
65
|
-
<button data-value="red">${translator.translate('red')}</button>
|
|
66
|
-
<button data-value="white">${translator.translate('white')}</button>
|
|
67
|
-
<button data-value="rose">${translator.translate('rose')}</button>
|
|
68
|
-
<button data-value=" " class="selected">${translator.translate('Any')}</button>
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
71
|
-
<div class="filter-group">
|
|
72
|
-
<span class="filter-label">${translator.translate('intensity')}:</span>
|
|
73
|
-
<div class="filter-buttons" id="intensity-buttons">
|
|
74
|
-
<button data-value="light">${translator.translate('light')}</button>
|
|
75
|
-
<button data-value="medium">${translator.translate('medium')}</button>
|
|
76
|
-
<button data-value="full">${translator.translate('full')}</button>
|
|
77
|
-
<button data-value=" " class="selected">${translator.translate('Any')}</button>
|
|
78
|
-
</div>
|
|
79
|
-
</div>
|
|
80
|
-
</div>
|
|
81
|
-
<div id="powered-by-widget">
|
|
82
|
-
<a href="https://wineater.com" target="_blank">
|
|
83
|
-
<span>${translator.translate('poweredBy')}</span>
|
|
84
|
-
<img src="https://czvgkhagwvmknscoerfy.supabase.co/storage/v1/object/public/static-media/logo.svg" alt="Wineater Logo">
|
|
85
|
-
</a>
|
|
86
|
-
</div>
|
|
87
|
-
</div>
|
|
88
53
|
<div id="wine-widget-right">
|
|
89
54
|
<div id="loading-indicator" class="hidden">
|
|
90
55
|
<div id="typing-indicator" class="typing-indicator">
|
|
@@ -93,6 +58,13 @@ export class WineWidget {
|
|
|
93
58
|
</div>
|
|
94
59
|
<div id="wine-placeholder"></div>
|
|
95
60
|
</div>
|
|
61
|
+
<div id="powered-by-widget">
|
|
62
|
+
<a href="https://wineater.com" target="_blank">
|
|
63
|
+
<span>${translator.translate('poweredBy')}</span>
|
|
64
|
+
<img src="https://czvgkhagwvmknscoerfy.supabase.co/storage/v1/object/public/static-media/logo.svg" alt="Wineater Logo">
|
|
65
|
+
</a>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
96
68
|
</div>
|
|
97
69
|
`;
|
|
98
70
|
widgetContainer.insertAdjacentHTML('beforeend', widgetHTML);
|
|
@@ -147,6 +119,7 @@ export class WineWidget {
|
|
|
147
119
|
// Привязка обработчиков "плиток" и кнопки
|
|
148
120
|
this.addEventListenersBarVersion();
|
|
149
121
|
}
|
|
122
|
+
this.initializeSearchAnimation();
|
|
150
123
|
}
|
|
151
124
|
|
|
152
125
|
addEventListenersStoreVersion() {
|
|
@@ -408,4 +381,51 @@ export class WineWidget {
|
|
|
408
381
|
// 6) «Отправить» и дальше на месте, не меняется
|
|
409
382
|
});
|
|
410
383
|
}
|
|
384
|
+
|
|
385
|
+
initializeSearchAnimation() {
|
|
386
|
+
const searchInput = document.getElementById('wine-search-input');
|
|
387
|
+
const suggestions = translator.translate('placeholderSuggestions');
|
|
388
|
+
let index = 0;
|
|
389
|
+
let charIndex = 0;
|
|
390
|
+
let typingForward = true;
|
|
391
|
+
let isInputFocused = false;
|
|
392
|
+
|
|
393
|
+
const typeEffect = () => {
|
|
394
|
+
if (isInputFocused) return; // Если фокус в поле ввода, эффект останавливается
|
|
395
|
+
if (typingForward) {
|
|
396
|
+
searchInput.placeholder = suggestions[index].substring(0, charIndex++);
|
|
397
|
+
if (charIndex > suggestions[index].length) {
|
|
398
|
+
typingForward = false;
|
|
399
|
+
setTimeout(typeEffect, 2000); // Пауза после завершения строки
|
|
400
|
+
} else {
|
|
401
|
+
setTimeout(typeEffect, 100); // Скорость ввода
|
|
402
|
+
}
|
|
403
|
+
} else {
|
|
404
|
+
searchInput.placeholder = suggestions[index].substring(0, charIndex--);
|
|
405
|
+
if (charIndex < 0) {
|
|
406
|
+
typingForward = true;
|
|
407
|
+
index = (index + 1) % suggestions.length; // Переход к следующей подсказке
|
|
408
|
+
setTimeout(typeEffect, 500); // Пауза перед началом следующей строки
|
|
409
|
+
} else {
|
|
410
|
+
setTimeout(typeEffect, 50); // Скорость удаления
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
typeEffect();
|
|
416
|
+
|
|
417
|
+
// Очистка строки и остановка эффекта при фокусе
|
|
418
|
+
searchInput.addEventListener('focus', () => {
|
|
419
|
+
searchInput.placeholder = '';
|
|
420
|
+
isInputFocused = true; // Останавливаем эффект
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
// Возобновление эффекта при потере фокуса
|
|
424
|
+
searchInput.addEventListener('blur', () => {
|
|
425
|
+
isInputFocused = false; // Возобновляем эффект
|
|
426
|
+
charIndex = 0;
|
|
427
|
+
typingForward = true;
|
|
428
|
+
typeEffect();
|
|
429
|
+
});
|
|
430
|
+
}
|
|
411
431
|
}
|