wineater-bot 4.11.0 → 4.16.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wineater-bot",
3
- "version": "4.11.0",
3
+ "version": "4.16.0",
4
4
  "description": "",
5
5
  "main": "dist/wineater-chatbot.mjs",
6
6
  "module": "src/index.js",
package/src/App.svelte CHANGED
@@ -44,6 +44,9 @@
44
44
  // должен повторять именно тот запрос, что дал текущие results.
45
45
  let lastSearchedQuery = $state('');
46
46
  let hasMore = $state(false);
47
+ // Всё, что уже показывали по текущему запросу — «Try again» заменяет выдачу,
48
+ // и без накопления повторный клик вернул бы те же вина.
49
+ let seenIds = $state<string[]>([]);
47
50
  let appLanguage = $derived(appStore.getAppLanguage());
48
51
  let storeLanguage = $derived(appStore.getStoreLanguage());
49
52
  let apiKey = $derived(appStore.getApiKey());
@@ -138,6 +141,7 @@
138
141
  results = [];
139
142
  isAnimating = false;
140
143
  hasMore = false;
144
+ seenIds = [];
141
145
 
142
146
  query = searchQuery.trim() + ';';
143
147
  lastSearchedQuery = query;
@@ -182,24 +186,40 @@
182
186
 
183
187
  async function handleShowMore() {
184
188
  if (isLoadingMore || !hasMore) return;
189
+ // Выдача заменяется целиком, поэтому держим предыдущую под рукой: если
190
+ // новых вин не нашлось или запрос упал, покупатель не должен остаться
191
+ // перед пустой сеткой.
192
+ const previousResults = results;
185
193
  try {
186
194
  isLoadingMore = true;
187
- const excludeIds = results.map((w) => w.id);
195
+ isLoading = true;
196
+
197
+ // Карточки заменяются, а не дописываются, поэтому исключать надо всё
198
+ // показанное за сессию — иначе следующий клик вернёт те же вина.
199
+ seenIds = [...new Set([...seenIds, ...results.map((w) => w.id)])];
200
+
201
+ // Тот же жест, что и при поиске: карточки уезжают вверх, дальше лоадер
202
+ await animateClearAll(220);
203
+ results = [];
204
+ isAnimating = false;
205
+
188
206
  const { recommendations, hasMore: more } = await wineaterApi.getMoreWineRecommendations(
189
207
  lastSearchedQuery,
190
- excludeIds
208
+ seenIds
191
209
  );
192
210
  trackWidgetEvent(WIDGET_EVENTS.SHOW_MORE_CLICKED, storeId, {
193
211
  query: lastSearchedQuery,
194
212
  results_count: recommendations.length
195
213
  });
196
- results = [...results, ...recommendations];
214
+ results = recommendations.length > 0 ? recommendations : previousResults;
197
215
  hasMore = more;
198
216
  } catch (error) {
199
- console.error('[wineater] show more error:', error);
217
+ console.error('[wineater] try again error:', error);
218
+ results = previousResults;
200
219
  hasMore = false;
201
220
  } finally {
202
221
  isLoadingMore = false;
222
+ isLoading = false;
203
223
  }
204
224
  }
205
225
 
@@ -406,7 +426,7 @@
406
426
  {#if hasMore}
407
427
  <div class="wr-App-showMore">
408
428
  <Action handleClick={handleShowMore} variant="outlined">
409
- {getTranslation({ key: 'showMore', lang: appLanguage })}
429
+ {getTranslation({ key: 'tryAgain', lang: appLanguage })}
410
430
  </Action>
411
431
  </div>
412
432
  {/if}
@@ -287,11 +287,37 @@
287
287
  gap: 8px;
288
288
  }
289
289
 
290
- .wr-WineTile-action--similar {
291
- font-size: 13px;
290
+ /* :global обязателен — класс уезжает внутрь <Action>, а скоуп Svelte
291
+ действует только на разметку этого компонента, иначе правило отбрасывается
292
+ как неиспользуемое. Цвет тот же, что у Buy; подчёркивание выезжает слева. */
293
+ :global(.wr-WineTile-action--similar) {
294
+ /* Заметно легче кнопки Buy (14px/500) — это вторичное действие, не кнопка */
295
+ font-size: 12px;
296
+ font-weight: 400;
292
297
  color: var(--wr-brand-color, #7b2beb);
293
- text-decoration: underline;
298
+ text-decoration: none;
299
+ background: transparent;
300
+ border: none;
294
301
  padding: 0;
302
+ position: relative;
303
+ }
304
+
305
+ :global(.wr-WineTile-action--similar)::after {
306
+ content: '';
307
+ position: absolute;
308
+ left: 0;
309
+ bottom: -2px;
310
+ width: 100%;
311
+ height: 1px;
312
+ background-color: currentColor;
313
+ transform: scaleX(0);
314
+ transform-origin: left;
315
+ transition: transform 180ms cubic-bezier(0.22, 0.61, 0.36, 1);
316
+ }
317
+
318
+ :global(.wr-WineTile-action--similar:hover)::after,
319
+ :global(.wr-WineTile-action--similar:focus-visible)::after {
320
+ transform: scaleX(1);
295
321
  }
296
322
 
297
323
  /* Hover popup inside tile */
@@ -17,7 +17,7 @@
17
17
  "type": "Type",
18
18
  "reason": "Suggestion",
19
19
  "moreInfo": "Plus d'infos",
20
- "showMore": "Plus de vins",
20
+ "tryAgain": "Réessayer",
21
21
  "similarWines": "Vins similaires",
22
22
  "byTheGlass": "Au verre",
23
23
  "winePairingIntro": "Pour ce vin, voici quelques suggestions de plats :",
@@ -83,7 +83,7 @@
83
83
  "type": "Tipo",
84
84
  "reason": "Sugerencia",
85
85
  "moreInfo": "Más info",
86
- "showMore": "Ver más",
86
+ "tryAgain": "Probar otra vez",
87
87
  "similarWines": "Vinos similares",
88
88
  "byTheGlass": "Por copa",
89
89
  "winePairingIntro": "Para este vino, aquí tienes algunas sugerencias de platos:",
@@ -149,7 +149,7 @@
149
149
  "type": "Type",
150
150
  "reason": "Suggestion",
151
151
  "moreInfo": "More info",
152
- "showMore": "Show more",
152
+ "tryAgain": "Try again",
153
153
  "similarWines": "Similar wines",
154
154
  "byTheGlass": "By the glass",
155
155
  "winePairingIntro": "For this wine, here are some suggested dishes:",
@@ -215,7 +215,7 @@
215
215
  "type": "Tip",
216
216
  "reason": "Preporuka",
217
217
  "moreInfo": "Više informacija",
218
- "showMore": "Prikaži još",
218
+ "tryAgain": "Pokušaj ponovo",
219
219
  "similarWines": "Slična vina",
220
220
  "byTheGlass": "Na čašu",
221
221
  "winePairingIntro": "Za ovo vino, preporučuju se sledeća jela:",
@@ -281,7 +281,7 @@
281
281
  "type": "Typ",
282
282
  "reason": "Anregung",
283
283
  "moreInfo": "Mehr Info",
284
- "showMore": "Mehr anzeigen",
284
+ "tryAgain": "Nochmal versuchen",
285
285
  "similarWines": "Ähnliche Weine",
286
286
  "byTheGlass": "Glasweise",
287
287
  "winePairingIntro": "Für diesen Wein gibt es folgende Essensvorschläge:",
@@ -346,7 +346,7 @@
346
346
  "type": "Тип",
347
347
  "reason": "Рекомендація",
348
348
  "moreInfo": "Докладніше",
349
- "showMore": "Показати ще",
349
+ "tryAgain": "Спробувати ще",
350
350
  "similarWines": "Схожі вина",
351
351
  "byTheGlass": "На келих",
352
352
  "winePairingIntro": "До цього вина підходять такі страви:",
@@ -412,7 +412,7 @@
412
412
  "type": "Тип",
413
413
  "reason": "Рекомендация",
414
414
  "moreInfo": "Подробнее",
415
- "showMore": "Ещё варианты",
415
+ "tryAgain": "Попробовать ещё",
416
416
  "similarWines": "Похожие вина",
417
417
  "byTheGlass": "По бокалам",
418
418
  "winePairingIntro": "К этому вину подходят следующие блюда:",
@@ -478,7 +478,7 @@
478
478
  "type": "Түрі",
479
479
  "reason": "Ұсыныс",
480
480
  "moreInfo": "Толығырақ",
481
- "showMore": "Тағы көрсету",
481
+ "tryAgain": "Қайта көру",
482
482
  "similarWines": "Ұқсас шараптар",
483
483
  "byTheGlass": "Бокалмен",
484
484
  "winePairingIntro": "Бұл шарапқа келесі тағамдар сәйкес келеді:",
@@ -544,7 +544,7 @@
544
544
  "type": "Tipo",
545
545
  "reason": "Sugestão",
546
546
  "moreInfo": "Mais informações",
547
- "showMore": "Mostrar mais",
547
+ "tryAgain": "Tentar de novo",
548
548
  "similarWines": "Vinhos semelhantes",
549
549
  "byTheGlass": "Por taça",
550
550
  "winePairingIntro": "Para este vinho, aqui estão algumas sugestões de pratos:",
@@ -124,7 +124,7 @@ export const projectConfigs: Record<string, ProjectUiConfig> = {
124
124
  logoUrl: null,
125
125
  brandColor: "#8bae98",
126
126
  wineaterColor: "#8bae98",
127
- titleText: "Looking for the perfect bottle? Ask our AI Sommelier for personalised recommendations, whatever the meal, mood or occasion.",
127
+ titleText: "Looking for the perfect bottle? Ask our AI Wine Geek for personalised recommendations, whatever the meal, mood or occasion.",
128
128
  customCss: `
129
129
  @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500&display=swap');
130
130
  :root { --wineater-font-primary: 'Montserrat', Verdana, Helvetica, Arial, sans-serif; }
@@ -1,72 +0,0 @@
1
- import type { ProjectUiConfig } from "./types";
2
-
3
- export const projectConfigs: Record<string, ProjectUiConfig> = {
4
- "0": {
5
- logoUrl: null,
6
- brandColor: "#7B2BEB",
7
- },
8
- "25": {
9
- logoUrl: null,
10
- brandColor: "#000000",
11
- wineaterColor: "#000000",
12
- buttonUppercase: true,
13
- customCss: `
14
- @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
15
- :root { --wineater-font-primary: 'Roboto', sans-serif; }
16
- #wr-Custom {
17
- .wr-Search-input {
18
- border-color: #7c7c7c;
19
- color: #7c7c7c;
20
- }
21
- .wr-Search-button:hover {
22
- background: #E3BE8D;
23
- opacity: 1;
24
- }
25
-
26
- .wr-WineTile-params {
27
- color: #7c7c7c;
28
- }
29
-
30
- .wr-WineTilePopup-reason {
31
- color: #000000;
32
- }
33
- .wr-WineTilePopup-tag {
34
- color: #000000;
35
- background: rgba(239,239,239,0.7);
36
- border-color: transparent;
37
- }
38
-
39
- .wr-WineTile-action {
40
- background: transparent;
41
- }
42
-
43
- .wr-WineTile-action:hover {
44
- background: #000000;
45
- color: #ffffff;
46
- box-shadow: none;
47
- }
48
- }
49
- `,
50
- translations: {
51
- fr: {
52
- "wineDetails.buy": "voir plus"
53
- }
54
- }
55
- },
56
- "21": {
57
- logoUrl: "https://www.intermarche.com/images/logoIntermarche.svg",
58
- brandColor: "#B81242",
59
- wineaterColor: "#7B2BEB",
60
- buttonUppercase: true,
61
- customCss: "",
62
- translations: {}
63
- },
64
- "26": {
65
- logoUrl: "https://paladarlondon.com/wp-content/uploads/2021/05/cropped-cropped-Paladar-Logo-1473x464-min-768x219.png",
66
- brandColor: "#B81242",
67
- wineaterColor: "#7B2BEB",
68
- buttonUppercase: true,
69
- customCss: "",
70
- translations: {}
71
- }
72
- };