livechat 0.4.2 → 0.4.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/config/locales/livechat.ar.yml +2 -0
- data/config/locales/livechat.bg.yml +2 -0
- data/config/locales/livechat.bn.yml +2 -0
- data/config/locales/livechat.de.yml +2 -0
- data/config/locales/livechat.el.yml +2 -0
- data/config/locales/livechat.en.yml +2 -0
- data/config/locales/livechat.es.yml +2 -0
- data/config/locales/livechat.fr.yml +2 -0
- data/config/locales/livechat.hi.yml +2 -0
- data/config/locales/livechat.hr.yml +2 -0
- data/config/locales/livechat.id.yml +2 -0
- data/config/locales/livechat.it.yml +2 -0
- data/config/locales/livechat.ja.yml +2 -0
- data/config/locales/livechat.ko.yml +2 -0
- data/config/locales/livechat.lb.yml +2 -0
- data/config/locales/livechat.nl.yml +2 -0
- data/config/locales/livechat.pl.yml +2 -0
- data/config/locales/livechat.pt.yml +2 -0
- data/config/locales/livechat.ro.yml +2 -0
- data/config/locales/livechat.ru.yml +2 -0
- data/config/locales/livechat.th.yml +2 -0
- data/config/locales/livechat.tr.yml +2 -0
- data/config/locales/livechat.uk.yml +2 -0
- data/config/locales/livechat.ur.yml +2 -0
- data/config/locales/livechat.vi.yml +2 -0
- data/config/locales/livechat.zh-CN.yml +2 -0
- data/lib/livechat/version.rb +1 -1
- data/lib/livechat/widget.js +142 -51
- data/lib/livechat/widget.rb +3 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fd6a72ade19436355c068f67d4c036f6f84b66e32cd163e36f3022619fa1587c
|
|
4
|
+
data.tar.gz: c7936d6b60c1bdc5f509f44e186a16e21368b1b2328d54ac7dc7918ee2ab7893
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 44f6a47b5879c17554031dc0d0f5a1e92943c180aaa08c855edc803682b3a558a3b232ab9fac16982f6bf2423505a72ca83e3173ad4e07491dc618bda43e24ef
|
|
7
|
+
data.tar.gz: 9c025865ff9824eac83660af0775e74e08a508472056ca29dffc5c129f6b69f3c291db006a31a1f8b26a43ba0dfea9f29bdfb992eb0f30ee6a91b5db4cf1d8bd
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.4
|
|
4
|
+
|
|
5
|
+
- Expand / collapse the chat on desktop. A new header control grows the panel
|
|
6
|
+
to a roomier size (and back) for long threads and image-heavy chats; the
|
|
7
|
+
choice is remembered across Turbo visits. Hidden on phones, where the panel
|
|
8
|
+
is already full-screen. Translated across all 26 locales.
|
|
9
|
+
- Composer polish: dropped the doubled focus ring (one quiet accent border
|
|
10
|
+
now), and flattened Safari's default textarea bevel that showed as a second
|
|
11
|
+
box inside the composer.
|
|
12
|
+
- Fixed a message bubble bleeding over the header's bottom edge while scrolling
|
|
13
|
+
a long thread (a flexbox scroll-containment + stacking fix).
|
|
14
|
+
|
|
15
|
+
## 0.4.3
|
|
16
|
+
|
|
17
|
+
- Unified composer. The message box, attach button and send button are now one
|
|
18
|
+
bordered container (the textarea on top, a toolbar row with the tools on the
|
|
19
|
+
left and a circular send on the right) that lights up on focus — instead of a
|
|
20
|
+
textarea flanked by loose buttons. Reads as a single control, closer to what
|
|
21
|
+
people expect from a chat composer. Pending-file chips ride inside the box.
|
|
22
|
+
|
|
3
23
|
## 0.4.2
|
|
4
24
|
|
|
5
25
|
- Breathing room between the widget's pending-file chips and the composer —
|
|
@@ -20,6 +20,8 @@ bg:
|
|
|
20
20
|
attach: "Прикачване на файлове"
|
|
21
21
|
remove_file: "Премахване на файла"
|
|
22
22
|
attachment_error: "Някои файлове не можаха да бъдат изпратени."
|
|
23
|
+
expand: "Уголеми"
|
|
24
|
+
collapse: "Смали"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "Твърде много файлове (макс. %{count})."
|
|
25
27
|
too_large: "%{name} е твърде голям."
|
|
@@ -20,6 +20,8 @@ de:
|
|
|
20
20
|
attach: "Dateien anhängen"
|
|
21
21
|
remove_file: "Datei entfernen"
|
|
22
22
|
attachment_error: "Einige Dateien konnten nicht gesendet werden."
|
|
23
|
+
expand: "Vergrößern"
|
|
24
|
+
collapse: "Verkleinern"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "Zu viele Dateien (max. %{count})."
|
|
25
27
|
too_large: "%{name} ist zu groß."
|
|
@@ -20,6 +20,8 @@ el:
|
|
|
20
20
|
attach: "Επισύναψη αρχείων"
|
|
21
21
|
remove_file: "Αφαίρεση αρχείου"
|
|
22
22
|
attachment_error: "Ορισμένα αρχεία δεν ήταν δυνατό να σταλούν."
|
|
23
|
+
expand: "Μεγέθυνση"
|
|
24
|
+
collapse: "Σμίκρυνση"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "Πάρα πολλά αρχεία (έως %{count})."
|
|
25
27
|
too_large: "Το %{name} είναι πολύ μεγάλο."
|
|
@@ -20,6 +20,8 @@ es:
|
|
|
20
20
|
attach: "Adjuntar archivos"
|
|
21
21
|
remove_file: "Quitar archivo"
|
|
22
22
|
attachment_error: "No se pudieron enviar algunos archivos."
|
|
23
|
+
expand: "Ampliar"
|
|
24
|
+
collapse: "Reducir"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "Demasiados archivos (máx. %{count})."
|
|
25
27
|
too_large: "%{name} es demasiado grande."
|
|
@@ -20,6 +20,8 @@ fr:
|
|
|
20
20
|
attach: "Joindre des fichiers"
|
|
21
21
|
remove_file: "Retirer le fichier"
|
|
22
22
|
attachment_error: "Certains fichiers n'ont pas pu être envoyés."
|
|
23
|
+
expand: "Agrandir"
|
|
24
|
+
collapse: "Réduire"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "Trop de fichiers (max %{count})."
|
|
25
27
|
too_large: "%{name} est trop volumineux."
|
|
@@ -20,6 +20,8 @@ hi:
|
|
|
20
20
|
attach: "फ़ाइलें संलग्न करें"
|
|
21
21
|
remove_file: "फ़ाइल हटाएं"
|
|
22
22
|
attachment_error: "कुछ फ़ाइलें भेजी नहीं जा सकीं।"
|
|
23
|
+
expand: "बड़ा करें"
|
|
24
|
+
collapse: "छोटा करें"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "बहुत सारी फ़ाइलें (अधिकतम %{count})।"
|
|
25
27
|
too_large: "%{name} बहुत बड़ी है।"
|
|
@@ -20,6 +20,8 @@ hr:
|
|
|
20
20
|
attach: "Priloži datoteke"
|
|
21
21
|
remove_file: "Ukloni datoteku"
|
|
22
22
|
attachment_error: "Neke datoteke nije bilo moguće poslati."
|
|
23
|
+
expand: "Povećaj"
|
|
24
|
+
collapse: "Smanji"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "Previše datoteka (najviše %{count})."
|
|
25
27
|
too_large: "%{name} je prevelika."
|
|
@@ -20,6 +20,8 @@ id:
|
|
|
20
20
|
attach: "Lampirkan file"
|
|
21
21
|
remove_file: "Hapus file"
|
|
22
22
|
attachment_error: "Beberapa file tidak dapat dikirim."
|
|
23
|
+
expand: "Perbesar"
|
|
24
|
+
collapse: "Perkecil"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "Terlalu banyak file (maks. %{count})."
|
|
25
27
|
too_large: "%{name} terlalu besar."
|
|
@@ -20,6 +20,8 @@ it:
|
|
|
20
20
|
attach: "Allega file"
|
|
21
21
|
remove_file: "Rimuovi file"
|
|
22
22
|
attachment_error: "Non è stato possibile inviare alcuni file."
|
|
23
|
+
expand: "Ingrandisci"
|
|
24
|
+
collapse: "Riduci"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "Troppi file (max %{count})."
|
|
25
27
|
too_large: "%{name} è troppo grande."
|
|
@@ -20,6 +20,8 @@ lb:
|
|
|
20
20
|
attach: "Dateien uschléissen"
|
|
21
21
|
remove_file: "Datei ewechhuelen"
|
|
22
22
|
attachment_error: "E puer Dateie konnten net geschéckt ginn."
|
|
23
|
+
expand: "Vergréisseren"
|
|
24
|
+
collapse: "Verklengeren"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "Ze vill Dateien (max %{count})."
|
|
25
27
|
too_large: "%{name} ass ze grouss."
|
|
@@ -20,6 +20,8 @@ nl:
|
|
|
20
20
|
attach: "Bestanden bijvoegen"
|
|
21
21
|
remove_file: "Bestand verwijderen"
|
|
22
22
|
attachment_error: "Sommige bestanden konden niet worden verzonden."
|
|
23
|
+
expand: "Vergroten"
|
|
24
|
+
collapse: "Verkleinen"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "Te veel bestanden (max. %{count})."
|
|
25
27
|
too_large: "%{name} is te groot."
|
|
@@ -20,6 +20,8 @@ pl:
|
|
|
20
20
|
attach: "Załącz pliki"
|
|
21
21
|
remove_file: "Usuń plik"
|
|
22
22
|
attachment_error: "Nie udało się wysłać niektórych plików."
|
|
23
|
+
expand: "Powiększ"
|
|
24
|
+
collapse: "Zmniejsz"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "Zbyt wiele plików (maks. %{count})."
|
|
25
27
|
too_large: "%{name} jest za duży."
|
|
@@ -20,6 +20,8 @@ pt:
|
|
|
20
20
|
attach: "Anexar arquivos"
|
|
21
21
|
remove_file: "Remover arquivo"
|
|
22
22
|
attachment_error: "Não foi possível enviar alguns arquivos."
|
|
23
|
+
expand: "Ampliar"
|
|
24
|
+
collapse: "Reduzir"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "Muitos arquivos (máx. %{count})."
|
|
25
27
|
too_large: "%{name} é muito grande."
|
|
@@ -20,6 +20,8 @@ ro:
|
|
|
20
20
|
attach: "Atașează fișiere"
|
|
21
21
|
remove_file: "Elimină fișierul"
|
|
22
22
|
attachment_error: "Unele fișiere nu au putut fi trimise."
|
|
23
|
+
expand: "Mărește"
|
|
24
|
+
collapse: "Micșorează"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "Prea multe fișiere (max. %{count})."
|
|
25
27
|
too_large: "%{name} este prea mare."
|
|
@@ -20,6 +20,8 @@ ru:
|
|
|
20
20
|
attach: "Прикрепить файлы"
|
|
21
21
|
remove_file: "Удалить файл"
|
|
22
22
|
attachment_error: "Некоторые файлы не удалось отправить."
|
|
23
|
+
expand: "Развернуть"
|
|
24
|
+
collapse: "Свернуть"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "Слишком много файлов (макс. %{count})."
|
|
25
27
|
too_large: "%{name} слишком большой."
|
|
@@ -20,6 +20,8 @@ uk:
|
|
|
20
20
|
attach: "Прикріпити файли"
|
|
21
21
|
remove_file: "Видалити файл"
|
|
22
22
|
attachment_error: "Деякі файли не вдалося надіслати."
|
|
23
|
+
expand: "Розгорнути"
|
|
24
|
+
collapse: "Згорнути"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "Забагато файлів (максимум %{count})."
|
|
25
27
|
too_large: "%{name} завеликий."
|
|
@@ -20,6 +20,8 @@ ur:
|
|
|
20
20
|
attach: "فائلیں منسلک کریں"
|
|
21
21
|
remove_file: "فائل ہٹائیں"
|
|
22
22
|
attachment_error: "کچھ فائلیں نہیں بھیجی جا سکیں۔"
|
|
23
|
+
expand: "بڑا کریں"
|
|
24
|
+
collapse: "چھوٹا کریں"
|
|
23
25
|
attachments:
|
|
24
26
|
too_many: "بہت زیادہ فائلیں (زیادہ سے زیادہ %{count})۔"
|
|
25
27
|
too_large: "%{name} بہت بڑی ہے۔"
|
data/lib/livechat/version.rb
CHANGED
data/lib/livechat/widget.js
CHANGED
|
@@ -39,6 +39,10 @@
|
|
|
39
39
|
var pendingFiles = [];
|
|
40
40
|
var isOpen = false;
|
|
41
41
|
var lastFocused = null;
|
|
42
|
+
var expandBtnEl = null;
|
|
43
|
+
// Desktop-only: a bigger panel, remembered across Turbo visits. Never
|
|
44
|
+
// applied on phones, where the panel is already full-screen.
|
|
45
|
+
var expanded = false;
|
|
42
46
|
// On phones the panel is a full-screen modal (focus trapped, page scroll
|
|
43
47
|
// locked); on desktop it stays a non-modal popover you can chat alongside.
|
|
44
48
|
var mobileModal = window.matchMedia ? window.matchMedia("(max-width: 480px)") : null;
|
|
@@ -70,6 +74,7 @@
|
|
|
70
74
|
}
|
|
71
75
|
|
|
72
76
|
ready(function () {
|
|
77
|
+
expanded = sessionGet("livechat_expanded") === "1";
|
|
73
78
|
document.addEventListener("keydown", function (event) {
|
|
74
79
|
if (event.key === "Escape" && isOpen) closePanel();
|
|
75
80
|
});
|
|
@@ -100,6 +105,7 @@
|
|
|
100
105
|
injectStyles();
|
|
101
106
|
mount();
|
|
102
107
|
applyBrandColor();
|
|
108
|
+
applyExpanded(); // a Turbo swap makes a fresh root — restore the size class
|
|
103
109
|
syncOpenerBadges(); // a Turbo visit brings fresh openers — restamp them
|
|
104
110
|
|
|
105
111
|
if (sessionGet("livechat_open") === "1") {
|
|
@@ -206,14 +212,27 @@
|
|
|
206
212
|
titles.appendChild(subtitle);
|
|
207
213
|
header.appendChild(titles);
|
|
208
214
|
|
|
215
|
+
var actions = document.createElement("div");
|
|
216
|
+
actions.id = "lvc-actions";
|
|
217
|
+
|
|
218
|
+
// Grow/shrink the desktop panel. Hidden on phones (already full-screen).
|
|
219
|
+
expandBtnEl = document.createElement("button");
|
|
220
|
+
expandBtnEl.type = "button";
|
|
221
|
+
expandBtnEl.id = "lvc-expand";
|
|
222
|
+
expandBtnEl.addEventListener("click", toggleExpand);
|
|
223
|
+
actions.appendChild(expandBtnEl);
|
|
224
|
+
|
|
209
225
|
var close = document.createElement("button");
|
|
210
226
|
close.type = "button";
|
|
211
227
|
close.id = "lvc-close";
|
|
212
228
|
close.setAttribute("aria-label", config.labels.close);
|
|
213
229
|
close.innerHTML = "×";
|
|
214
230
|
close.addEventListener("click", closePanel);
|
|
215
|
-
|
|
231
|
+
actions.appendChild(close);
|
|
232
|
+
|
|
233
|
+
header.appendChild(actions);
|
|
216
234
|
panel.appendChild(header);
|
|
235
|
+
applyExpanded(); // set the panel size + the button's icon/label
|
|
217
236
|
|
|
218
237
|
listEl = document.createElement("div");
|
|
219
238
|
listEl.id = "lvc-list";
|
|
@@ -245,9 +264,22 @@
|
|
|
245
264
|
emailRowEl = buildEmailRow();
|
|
246
265
|
panel.appendChild(emailRowEl);
|
|
247
266
|
|
|
267
|
+
// The composer is one bordered box: the textarea on top, a toolbar row
|
|
268
|
+
// (tools on the left, send on the right) below — so it reads as a single
|
|
269
|
+
// control, not a textarea flanked by loose buttons.
|
|
248
270
|
formEl = document.createElement("form");
|
|
249
271
|
formEl.id = "lvc-form";
|
|
272
|
+
|
|
273
|
+
// Pending-file chips sit at the top of the box, inside the border.
|
|
274
|
+
if (config.attachments) {
|
|
275
|
+
filesBarEl = document.createElement("div");
|
|
276
|
+
filesBarEl.id = "lvc-files";
|
|
277
|
+
filesBarEl.hidden = true;
|
|
278
|
+
formEl.appendChild(filesBarEl);
|
|
279
|
+
}
|
|
280
|
+
|
|
250
281
|
inputEl = document.createElement("textarea");
|
|
282
|
+
inputEl.id = "lvc-input";
|
|
251
283
|
inputEl.rows = 1;
|
|
252
284
|
inputEl.placeholder = config.labels.placeholder;
|
|
253
285
|
inputEl.setAttribute("aria-label", config.labels.placeholder);
|
|
@@ -258,32 +290,15 @@
|
|
|
258
290
|
send();
|
|
259
291
|
}
|
|
260
292
|
});
|
|
261
|
-
var sendButton = document.createElement("button");
|
|
262
|
-
sendButton.type = "submit";
|
|
263
|
-
sendButton.setAttribute("aria-label", config.labels.send);
|
|
264
|
-
sendButton.title = config.labels.send;
|
|
265
|
-
// Paper airplane (Heroicons, MIT). CSS mirrors it for RTL.
|
|
266
|
-
sendButton.innerHTML =
|
|
267
|
-
'<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">' +
|
|
268
|
-
'<path fill="currentColor" d="M3.478 2.404a.75.75 0 0 0-.926.941l2.432 ' +
|
|
269
|
-
"7.905H13.5a.75.75 0 0 1 0 1.5H4.984l-2.432 7.905a.75.75 0 0 0 .926.94 " +
|
|
270
|
-
"60.519 60.519 0 0 0 18.445-8.986.75.75 0 0 0 0-1.218A60.517 60.517 0 0 " +
|
|
271
|
-
'0 3.478 2.404Z"/></svg>';
|
|
272
293
|
formEl.appendChild(inputEl);
|
|
273
|
-
formEl.appendChild(sendButton);
|
|
274
|
-
formEl.addEventListener("submit", function (event) {
|
|
275
|
-
event.preventDefault();
|
|
276
|
-
send();
|
|
277
|
-
});
|
|
278
294
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
filesBarEl.id = "lvc-files";
|
|
284
|
-
filesBarEl.hidden = true;
|
|
285
|
-
panel.appendChild(filesBarEl);
|
|
295
|
+
var toolbar = document.createElement("div");
|
|
296
|
+
toolbar.id = "lvc-toolbar";
|
|
297
|
+
var tools = document.createElement("div");
|
|
298
|
+
tools.id = "lvc-tools";
|
|
286
299
|
|
|
300
|
+
// Attachments: a paperclip in the toolbar that opens the file picker.
|
|
301
|
+
if (config.attachments) {
|
|
287
302
|
fileInputEl = document.createElement("input");
|
|
288
303
|
fileInputEl.type = "file";
|
|
289
304
|
fileInputEl.multiple = true;
|
|
@@ -296,18 +311,40 @@
|
|
|
296
311
|
var attach = document.createElement("button");
|
|
297
312
|
attach.type = "button";
|
|
298
313
|
attach.id = "lvc-attach";
|
|
314
|
+
attach.className = "lvc-tool";
|
|
299
315
|
attach.setAttribute("aria-label", config.labels.attach);
|
|
300
316
|
attach.title = config.labels.attach;
|
|
301
317
|
// Paperclip (Heroicons, MIT).
|
|
302
318
|
attach.innerHTML =
|
|
303
|
-
'<svg viewBox="0 0 24 24" width="
|
|
319
|
+
'<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">' +
|
|
304
320
|
'<path fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" ' +
|
|
305
321
|
'stroke-linejoin="round" d="M18.4 8.6 9.9 17a3.5 3.5 0 0 1-5-5l8.5-8.4a2.3 2.3 0 0 1 ' +
|
|
306
322
|
'3.3 3.3l-8.5 8.4a1.1 1.1 0 0 1-1.6-1.6l7.8-7.8"/></svg>';
|
|
307
323
|
attach.addEventListener("click", function () { fileInputEl.click(); });
|
|
308
|
-
|
|
324
|
+
tools.appendChild(attach);
|
|
309
325
|
formEl.appendChild(fileInputEl);
|
|
310
326
|
}
|
|
327
|
+
toolbar.appendChild(tools);
|
|
328
|
+
|
|
329
|
+
var sendButton = document.createElement("button");
|
|
330
|
+
sendButton.type = "submit";
|
|
331
|
+
sendButton.id = "lvc-send";
|
|
332
|
+
sendButton.setAttribute("aria-label", config.labels.send);
|
|
333
|
+
sendButton.title = config.labels.send;
|
|
334
|
+
// Paper airplane (Heroicons, MIT). CSS mirrors it for RTL.
|
|
335
|
+
sendButton.innerHTML =
|
|
336
|
+
'<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">' +
|
|
337
|
+
'<path fill="currentColor" d="M3.478 2.404a.75.75 0 0 0-.926.941l2.432 ' +
|
|
338
|
+
"7.905H13.5a.75.75 0 0 1 0 1.5H4.984l-2.432 7.905a.75.75 0 0 0 .926.94 " +
|
|
339
|
+
"60.519 60.519 0 0 0 18.445-8.986.75.75 0 0 0 0-1.218A60.517 60.517 0 0 " +
|
|
340
|
+
'0 3.478 2.404Z"/></svg>';
|
|
341
|
+
toolbar.appendChild(sendButton);
|
|
342
|
+
|
|
343
|
+
formEl.appendChild(toolbar);
|
|
344
|
+
formEl.addEventListener("submit", function (event) {
|
|
345
|
+
event.preventDefault();
|
|
346
|
+
send();
|
|
347
|
+
});
|
|
311
348
|
|
|
312
349
|
panel.appendChild(formEl);
|
|
313
350
|
|
|
@@ -447,6 +484,38 @@
|
|
|
447
484
|
return !!(mobileModal && mobileModal.matches);
|
|
448
485
|
}
|
|
449
486
|
|
|
487
|
+
// --- expand / collapse (desktop) --------------------------------------------
|
|
488
|
+
|
|
489
|
+
var EXPAND_ICON =
|
|
490
|
+
'<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" ' +
|
|
491
|
+
'stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
|
|
492
|
+
'<polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/>' +
|
|
493
|
+
'<line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/></svg>';
|
|
494
|
+
var COLLAPSE_ICON =
|
|
495
|
+
'<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" ' +
|
|
496
|
+
'stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
|
|
497
|
+
'<polyline points="4 14 10 14 10 20"/><polyline points="20 10 14 10 14 4"/>' +
|
|
498
|
+
'<line x1="14" y1="10" x2="21" y2="3"/><line x1="10" y1="14" x2="3" y2="21"/></svg>';
|
|
499
|
+
|
|
500
|
+
function toggleExpand() {
|
|
501
|
+
if (isMobileModal()) return;
|
|
502
|
+
expanded = !expanded;
|
|
503
|
+
sessionSet("livechat_expanded", expanded ? "1" : "");
|
|
504
|
+
applyExpanded();
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Reflect the current state onto the panel and the header button. A no-op on
|
|
508
|
+
// phones — the class is never added there, so the full-screen panel stands.
|
|
509
|
+
function applyExpanded() {
|
|
510
|
+
var on = expanded && !isMobileModal();
|
|
511
|
+
if (root) root.classList.toggle("lvc-expanded", on);
|
|
512
|
+
if (!expandBtnEl) return;
|
|
513
|
+
var label = on ? config.labels.collapse : config.labels.expand;
|
|
514
|
+
expandBtnEl.setAttribute("aria-label", label);
|
|
515
|
+
expandBtnEl.title = label;
|
|
516
|
+
expandBtnEl.innerHTML = on ? COLLAPSE_ICON : EXPAND_ICON;
|
|
517
|
+
}
|
|
518
|
+
|
|
450
519
|
// Tab cycles inside the panel only while it is the full-screen mobile
|
|
451
520
|
// modal; the desktop popover deliberately lets focus reach the page.
|
|
452
521
|
function trapFocus(event) {
|
|
@@ -785,14 +854,28 @@
|
|
|
785
854
|
"#lvc-panel[hidden]{display:none}" +
|
|
786
855
|
"#lvc-root[dir=rtl] #lvc-panel{right:auto;left:20px}" +
|
|
787
856
|
"#lvc-root.lvc-no-launcher #lvc-panel{bottom:20px;max-height:calc(100dvh - 40px)}" +
|
|
788
|
-
|
|
789
|
-
|
|
857
|
+
// position/z-index keep the header above the scrolling list, and
|
|
858
|
+
// flex-shrink:0 stops it collapsing — together they stop a message
|
|
859
|
+
// bubble from bleeding over the header's rounded bottom edge.
|
|
860
|
+
"#lvc-header{position:relative;z-index:2;flex-shrink:0;display:flex;align-items:flex-start;" +
|
|
861
|
+
"justify-content:space-between;gap:8px;padding:14px 16px;background:var(--lvc-accent);" +
|
|
862
|
+
"color:var(--lvc-accent-text)}" +
|
|
790
863
|
"#lvc-header strong{display:block;font-size:15px}" +
|
|
791
864
|
"#lvc-header span{display:block;font-size:12px;opacity:.85;margin-top:2px}" +
|
|
865
|
+
"#lvc-actions{display:flex;align-items:center;gap:2px}" +
|
|
792
866
|
"#lvc-close{border:none;background:none;color:var(--lvc-accent-text);font-size:22px;" +
|
|
793
867
|
"line-height:1;cursor:pointer;padding:2px 6px;border-radius:6px}" +
|
|
794
868
|
"#lvc-close:hover{background:rgba(255,255,255,.15)}" +
|
|
795
|
-
"#lvc-
|
|
869
|
+
"#lvc-root #lvc-expand{border:none;background:none;color:var(--lvc-accent-text);cursor:pointer;" +
|
|
870
|
+
"padding:5px 6px;border-radius:6px;display:flex;align-items:center;justify-content:center;opacity:.9}" +
|
|
871
|
+
"#lvc-root #lvc-expand:hover{background:rgba(255,255,255,.15);opacity:1}" +
|
|
872
|
+
// Desktop only: a roomier panel for long threads and image-heavy chats.
|
|
873
|
+
// Guarded by min-width so it can never shrink the full-screen mobile panel.
|
|
874
|
+
"@media(min-width:481px){#lvc-root.lvc-expanded #lvc-panel{width:min(460px,92vw);" +
|
|
875
|
+
"height:min(680px,88dvh);max-height:88dvh}}" +
|
|
876
|
+
// min-height:0 lets this flex child actually scroll within the panel
|
|
877
|
+
// instead of overflowing it (the classic flexbox scroll gotcha).
|
|
878
|
+
"#lvc-list{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:14px;" +
|
|
796
879
|
"background:var(--lvc-bg);display:flex;flex-direction:column;gap:4px}" +
|
|
797
880
|
// Class rules carry the #lvc-root prefix so they outrank the
|
|
798
881
|
// id-level `#lvc-root *` reset above.
|
|
@@ -818,25 +901,31 @@
|
|
|
818
901
|
"background:var(--lvc-bg);color:var(--lvc-text);font:inherit}" +
|
|
819
902
|
"#lvc-email button{padding:6px 10px;border:1px solid var(--lvc-border);border-radius:8px;" +
|
|
820
903
|
"background:var(--lvc-surface);color:var(--lvc-text);font:inherit;cursor:pointer}" +
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
"
|
|
825
|
-
"
|
|
826
|
-
|
|
827
|
-
"color:var(--lvc-accent
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
"#lvc-root
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
"
|
|
837
|
-
"
|
|
838
|
-
|
|
839
|
-
"#lvc-
|
|
904
|
+
// The composer is one bordered box (Intercom-style): textarea on top, a
|
|
905
|
+
// toolbar row below. focus-within lights the whole box, so it reads as a
|
|
906
|
+
// single control.
|
|
907
|
+
"#lvc-form{display:flex;flex-direction:column;gap:6px;margin:10px 12px;padding:8px 10px;" +
|
|
908
|
+
"border:1px solid var(--lvc-border);border-radius:16px;background:var(--lvc-bg)}" +
|
|
909
|
+
// A single, quiet accent border on focus — no extra ring.
|
|
910
|
+
"#lvc-form:focus-within{border-color:var(--lvc-accent)}" +
|
|
911
|
+
// appearance:none flattens Safari's default textarea bevel, which would
|
|
912
|
+
// otherwise show as a second inset box inside the composer.
|
|
913
|
+
"#lvc-root #lvc-input{-webkit-appearance:none;appearance:none;border:none;background:none;" +
|
|
914
|
+
"resize:none;font:inherit;color:var(--lvc-text);padding:4px 4px 0;max-height:120px;outline:none}" +
|
|
915
|
+
"#lvc-toolbar{display:flex;align-items:center;justify-content:space-between;gap:8px}" +
|
|
916
|
+
"#lvc-tools{display:flex;align-items:center;gap:2px}" +
|
|
917
|
+
// Tool buttons (attach, and room for more) are quiet — the accent is the
|
|
918
|
+
// send button's alone.
|
|
919
|
+
"#lvc-root .lvc-tool{border:none;background:none;color:var(--lvc-muted);width:32px;height:32px;" +
|
|
920
|
+
"display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;padding:0}" +
|
|
921
|
+
"#lvc-root .lvc-tool:hover{background:var(--lvc-border);color:var(--lvc-text)}" +
|
|
922
|
+
"#lvc-send{border:none;border-radius:50%;background:var(--lvc-accent);color:var(--lvc-accent-text);" +
|
|
923
|
+
"width:32px;height:32px;min-width:32px;display:flex;align-items:center;justify-content:center;" +
|
|
924
|
+
"cursor:pointer;padding:0}" +
|
|
925
|
+
"#lvc-send:disabled{opacity:.5;cursor:default}" +
|
|
926
|
+
"#lvc-root[dir=rtl] #lvc-send svg{transform:scaleX(-1)}" +
|
|
927
|
+
// Pending-file chips ride at the top of the composer box.
|
|
928
|
+
"#lvc-files{display:flex;flex-wrap:wrap;gap:6px;padding:2px 2px 0}" +
|
|
840
929
|
"#lvc-files[hidden]{display:none}" +
|
|
841
930
|
"#lvc-root .lvc-chip{display:inline-flex;align-items:center;gap:6px;max-width:100%;" +
|
|
842
931
|
"padding:4px 6px 4px 10px;border:1px solid var(--lvc-border);border-radius:999px;" +
|
|
@@ -861,10 +950,12 @@
|
|
|
861
950
|
"#lvc-root #lvc-panel,#lvc-root[dir=rtl] #lvc-panel,#lvc-root.lvc-no-launcher #lvc-panel" +
|
|
862
951
|
"{left:0;right:0;top:0;bottom:0;width:100%;max-width:100%;height:100dvh;max-height:100dvh;" +
|
|
863
952
|
"border-radius:0;border:none}" +
|
|
953
|
+
// The panel is already full-screen here, so there's nothing to expand.
|
|
954
|
+
"#lvc-expand{display:none}" +
|
|
864
955
|
// 16px stops iOS Safari from zoom-jumping into focused fields.
|
|
865
|
-
"#lvc-root #lvc-
|
|
866
|
-
// Keep the composer above the iPhone home indicator.
|
|
867
|
-
"#lvc-root #lvc-form{
|
|
956
|
+
"#lvc-root #lvc-input,#lvc-root #lvc-email input{font-size:16px}" +
|
|
957
|
+
// Keep the composer box above the iPhone home indicator.
|
|
958
|
+
"#lvc-root #lvc-form{margin-bottom:calc(10px + env(safe-area-inset-bottom))}" +
|
|
868
959
|
"}" +
|
|
869
960
|
// Lives in host DOM (on data-livechat-open elements), so no #lvc-root prefix.
|
|
870
961
|
".lvc-opener-badge{display:inline-flex;min-width:18px;height:18px;padding:0 5px;" +
|
data/lib/livechat/widget.rb
CHANGED
|
@@ -104,7 +104,9 @@ module Livechat
|
|
|
104
104
|
unreadAria: t(:unread_aria, 'unread messages'),
|
|
105
105
|
attach: t(:attach, 'Attach files'),
|
|
106
106
|
removeFile: t(:remove_file, 'Remove file'),
|
|
107
|
-
attachmentError: t(:attachment_error, 'Some files could not be sent.')
|
|
107
|
+
attachmentError: t(:attachment_error, 'Some files could not be sent.'),
|
|
108
|
+
expand: t(:expand, 'Expand'),
|
|
109
|
+
collapse: t(:collapse, 'Collapse')
|
|
108
110
|
}
|
|
109
111
|
end
|
|
110
112
|
|