livechat 0.5.2 → 0.5.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 +13 -0
- data/app/views/layouts/livechat/application.html.erb +16 -6
- data/lib/livechat/dashboard.js +25 -4
- data/lib/livechat/version.rb +1 -1
- data/lib/livechat/widget.js +42 -15
- 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: 4f04a8c3aee0c2e7c9f4f3eff556bf450f4f81844750d8ebfb80d058ac49e180
|
|
4
|
+
data.tar.gz: 0f62d39bd16d1e02836fe8dbd8a777652e466db06406c60108a3ef75c3321161
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2c3cbfefe5b627c5e919b9306ea72509026e107d28e5a69c5e83923286d6bf7e360ee5c8bfb5b0481883267dbf61630e1cfae40819d31760e0121463602e2cc6
|
|
7
|
+
data.tar.gz: b1c8c7782956dd04291838094131f904970011cfb92ed08473a359ad02046af18c88fc04b38d3c0e917361db5e7de3b79871fcb15c49a13d1d666d94a751a248
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.4
|
|
4
|
+
|
|
5
|
+
- Balanced the recording controls visually: the stop/finish square now uses
|
|
6
|
+
the same icon box as the cancel control, so the actions read with equal
|
|
7
|
+
weight in the composer.
|
|
8
|
+
|
|
9
|
+
## 0.5.3
|
|
10
|
+
|
|
11
|
+
- Refined the audio recording controls. While recording, the composer now
|
|
12
|
+
shows a compact REC pill with a stable timer, an icon-only discard control,
|
|
13
|
+
and an icon-only stop control. Sending is disabled until recording is
|
|
14
|
+
stopped or cancelled.
|
|
15
|
+
|
|
3
16
|
## 0.5.2
|
|
4
17
|
|
|
5
18
|
- Added audio messages. Visitors can record a voice note from the widget, send
|
|
@@ -111,6 +111,7 @@
|
|
|
111
111
|
display: flex; align-items: center; justify-content: center; }
|
|
112
112
|
.reply .attach:hover { background: var(--border); color: var(--text); }
|
|
113
113
|
.reply .attach.recording-on { color: var(--danger); }
|
|
114
|
+
.reply.is-recording .attach { display: none; }
|
|
114
115
|
.reply .chips { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
115
116
|
.reply .chip { display: inline-flex; align-items: center; gap: 6px; max-width: 100%;
|
|
116
117
|
padding: 4px 6px 4px 10px; border: 1px solid var(--border); border-radius: 999px;
|
|
@@ -119,14 +120,23 @@
|
|
|
119
120
|
.reply .chip-x { padding: 0 2px; border: none; background: none; color: var(--muted);
|
|
120
121
|
font-size: 16px; line-height: 1; cursor: pointer; }
|
|
121
122
|
.reply .chip-x:hover { color: var(--text); }
|
|
122
|
-
.reply .recording { display: flex; align-items: center;
|
|
123
|
-
padding:
|
|
123
|
+
.reply .recording { display: inline-flex; align-items: center; gap: 8px; height: 32px;
|
|
124
|
+
padding: 0 4px 0 8px; border: 1px solid var(--border); border-radius: 999px;
|
|
125
|
+
background: var(--surface); color: var(--muted); font-size: 12px;
|
|
126
|
+
white-space: nowrap; }
|
|
124
127
|
.reply .recording[hidden] { display: none; }
|
|
125
|
-
.reply .recording-status { display: inline-
|
|
126
|
-
|
|
128
|
+
.reply .recording-status { display: inline-grid; grid-template-columns: 8px 24px 34px;
|
|
129
|
+
align-items: center; gap: 6px; font-variant-numeric: tabular-nums; }
|
|
130
|
+
.reply .recording-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--danger);
|
|
131
|
+
box-shadow: 0 0 0 3px rgba(220,38,38,.12); }
|
|
132
|
+
.reply .recording-rec { font-size: 10px; font-weight: 700; letter-spacing: .04em; color: var(--danger); }
|
|
127
133
|
.reply .recording-actions { display: flex; align-items: center; gap: 4px; }
|
|
128
|
-
.reply .recording-actions button {
|
|
129
|
-
|
|
134
|
+
.reply .recording-actions button { width: 24px; height: 24px; padding: 0; border: none;
|
|
135
|
+
border-radius: 50%; background: none; color: var(--muted);
|
|
136
|
+
display: flex; align-items: center; justify-content: center; }
|
|
137
|
+
.reply .recording-actions button:hover { background: var(--border); color: var(--text); }
|
|
138
|
+
.reply .recording-actions .stop-recording { background: var(--danger); color: #fff; }
|
|
139
|
+
.reply .recording-actions .stop-recording:hover { background: #b91c1c; color: #fff; }
|
|
130
140
|
.reply .send { width: 32px; min-width: 32px; height: 32px; padding: 0; border: none; border-radius: 50%;
|
|
131
141
|
background: var(--accent); color: var(--accent-text); cursor: pointer;
|
|
132
142
|
display: flex; align-items: center; justify-content: center; }
|
data/lib/livechat/dashboard.js
CHANGED
|
@@ -134,25 +134,40 @@
|
|
|
134
134
|
bar.hidden = true;
|
|
135
135
|
var status = document.createElement("span");
|
|
136
136
|
status.className = "recording-status";
|
|
137
|
+
status.setAttribute("aria-live", "polite");
|
|
137
138
|
var dot = document.createElement("span");
|
|
138
139
|
dot.className = "recording-dot";
|
|
140
|
+
var rec = document.createElement("span");
|
|
141
|
+
rec.className = "recording-rec";
|
|
142
|
+
rec.textContent = "REC";
|
|
139
143
|
var time = document.createElement("span");
|
|
140
144
|
status.appendChild(dot);
|
|
145
|
+
status.appendChild(rec);
|
|
141
146
|
status.appendChild(time);
|
|
142
147
|
bar.appendChild(status);
|
|
143
148
|
var actions = document.createElement("div");
|
|
144
149
|
actions.className = "recording-actions";
|
|
145
150
|
var cancel = document.createElement("button");
|
|
146
151
|
cancel.type = "button";
|
|
147
|
-
cancel.
|
|
152
|
+
cancel.setAttribute("aria-label", labels.cancelRecording);
|
|
153
|
+
cancel.title = labels.cancelRecording;
|
|
154
|
+
cancel.innerHTML =
|
|
155
|
+
'<svg viewBox="0 0 24 24" width="15" height="15" aria-hidden="true">' +
|
|
156
|
+
'<path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" ' +
|
|
157
|
+
'd="M6 6l12 12M18 6 6 18"/></svg>';
|
|
148
158
|
var stop = document.createElement("button");
|
|
149
159
|
stop.type = "button";
|
|
150
160
|
stop.className = "stop-recording";
|
|
151
|
-
stop.
|
|
161
|
+
stop.setAttribute("aria-label", labels.stopRecording);
|
|
162
|
+
stop.title = labels.stopRecording;
|
|
163
|
+
stop.innerHTML =
|
|
164
|
+
'<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">' +
|
|
165
|
+
'<rect x="5" y="5" width="14" height="14" rx="2" fill="currentColor"/></svg>';
|
|
152
166
|
actions.appendChild(cancel);
|
|
153
167
|
actions.appendChild(stop);
|
|
154
168
|
bar.appendChild(actions);
|
|
155
|
-
|
|
169
|
+
tools.appendChild(bar);
|
|
170
|
+
var sendButton = form.querySelector(".send");
|
|
156
171
|
|
|
157
172
|
recordButton.addEventListener("click", start);
|
|
158
173
|
stop.addEventListener("click", function () {
|
|
@@ -190,6 +205,8 @@
|
|
|
190
205
|
recorder.start();
|
|
191
206
|
startedAt = Date.now();
|
|
192
207
|
recordButton.classList.add("recording-on");
|
|
208
|
+
form.classList.add("is-recording");
|
|
209
|
+
if (sendButton) sendButton.disabled = true;
|
|
193
210
|
bar.hidden = false;
|
|
194
211
|
tick();
|
|
195
212
|
timer = setInterval(tick, 500);
|
|
@@ -209,6 +226,8 @@
|
|
|
209
226
|
bar.hidden = true;
|
|
210
227
|
recordButton.disabled = false;
|
|
211
228
|
recordButton.classList.remove("recording-on");
|
|
229
|
+
form.classList.remove("is-recording");
|
|
230
|
+
if (sendButton) sendButton.disabled = false;
|
|
212
231
|
|
|
213
232
|
if (!cancelled && chunks.length && typeof DataTransfer !== "undefined") {
|
|
214
233
|
var kept = new DataTransfer();
|
|
@@ -222,7 +241,9 @@
|
|
|
222
241
|
}
|
|
223
242
|
|
|
224
243
|
function tick() {
|
|
225
|
-
|
|
244
|
+
var elapsed = formatDuration(Date.now() - startedAt);
|
|
245
|
+
time.textContent = elapsed;
|
|
246
|
+
status.setAttribute("aria-label", labels.recording.replace("%{time}", elapsed));
|
|
226
247
|
}
|
|
227
248
|
|
|
228
249
|
function stopTracks() {
|
data/lib/livechat/version.rb
CHANGED
data/lib/livechat/widget.js
CHANGED
|
@@ -349,6 +349,9 @@
|
|
|
349
349
|
'M5 11a7 7 0 0 0 14 0M12 18v3M8.5 21h7"/></svg>';
|
|
350
350
|
recordBtnEl.addEventListener("click", startRecording);
|
|
351
351
|
tools.appendChild(recordBtnEl);
|
|
352
|
+
|
|
353
|
+
recordingBarEl = buildRecordingBar();
|
|
354
|
+
tools.appendChild(recordingBarEl);
|
|
352
355
|
}
|
|
353
356
|
toolbar.appendChild(tools);
|
|
354
357
|
|
|
@@ -367,10 +370,6 @@
|
|
|
367
370
|
toolbar.appendChild(sendButton);
|
|
368
371
|
|
|
369
372
|
formEl.appendChild(toolbar);
|
|
370
|
-
if (config.attachments) {
|
|
371
|
-
recordingBarEl = buildRecordingBar();
|
|
372
|
-
formEl.appendChild(recordingBarEl);
|
|
373
|
-
}
|
|
374
373
|
formEl.addEventListener("submit", function (event) {
|
|
375
374
|
event.preventDefault();
|
|
376
375
|
send();
|
|
@@ -390,11 +389,16 @@
|
|
|
390
389
|
|
|
391
390
|
var status = document.createElement("span");
|
|
392
391
|
status.className = "lvc-recording-status";
|
|
392
|
+
status.setAttribute("aria-live", "polite");
|
|
393
393
|
var dot = document.createElement("span");
|
|
394
394
|
dot.className = "lvc-recording-dot";
|
|
395
|
+
var rec = document.createElement("span");
|
|
396
|
+
rec.className = "lvc-recording-rec";
|
|
397
|
+
rec.textContent = "REC";
|
|
395
398
|
recordingTimeEl = document.createElement("span");
|
|
396
399
|
recordingTimeEl.textContent = formatDuration(0);
|
|
397
400
|
status.appendChild(dot);
|
|
401
|
+
status.appendChild(rec);
|
|
398
402
|
status.appendChild(recordingTimeEl);
|
|
399
403
|
bar.appendChild(status);
|
|
400
404
|
|
|
@@ -403,12 +407,21 @@
|
|
|
403
407
|
var cancel = document.createElement("button");
|
|
404
408
|
cancel.type = "button";
|
|
405
409
|
cancel.className = "lvc-recording-cancel";
|
|
406
|
-
cancel.
|
|
410
|
+
cancel.setAttribute("aria-label", config.labels.cancelRecording);
|
|
411
|
+
cancel.title = config.labels.cancelRecording;
|
|
412
|
+
cancel.innerHTML =
|
|
413
|
+
'<svg viewBox="0 0 24 24" width="15" height="15" aria-hidden="true">' +
|
|
414
|
+
'<path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" ' +
|
|
415
|
+
'd="M6 6l12 12M18 6 6 18"/></svg>';
|
|
407
416
|
cancel.addEventListener("click", cancelRecording);
|
|
408
417
|
var stop = document.createElement("button");
|
|
409
418
|
stop.type = "button";
|
|
410
419
|
stop.className = "lvc-recording-stop";
|
|
411
|
-
stop.
|
|
420
|
+
stop.setAttribute("aria-label", config.labels.stopRecording);
|
|
421
|
+
stop.title = config.labels.stopRecording;
|
|
422
|
+
stop.innerHTML =
|
|
423
|
+
'<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">' +
|
|
424
|
+
'<rect x="5" y="5" width="14" height="14" rx="2" fill="currentColor"/></svg>';
|
|
412
425
|
stop.addEventListener("click", stopRecording);
|
|
413
426
|
actions.appendChild(cancel);
|
|
414
427
|
actions.appendChild(stop);
|
|
@@ -505,11 +518,17 @@
|
|
|
505
518
|
function showRecordingBar(show) {
|
|
506
519
|
if (recordingBarEl) recordingBarEl.hidden = !show;
|
|
507
520
|
if (recordBtnEl) recordBtnEl.classList.toggle("lvc-recording-on", show);
|
|
521
|
+
if (formEl) formEl.classList.toggle("lvc-is-recording", show);
|
|
522
|
+
var sendButton = formEl && formEl.querySelector("button[type=submit]");
|
|
523
|
+
if (sendButton) sendButton.disabled = show;
|
|
508
524
|
}
|
|
509
525
|
|
|
510
526
|
function tickRecording() {
|
|
511
527
|
if (!recordingTimeEl) return;
|
|
512
|
-
|
|
528
|
+
var elapsed = formatDuration(Date.now() - recordingStartedAt);
|
|
529
|
+
recordingTimeEl.textContent = elapsed;
|
|
530
|
+
var status = recordingTimeEl.closest(".lvc-recording-status");
|
|
531
|
+
if (status) status.setAttribute("aria-label", config.labels.recording.replace("%{time}", elapsed));
|
|
513
532
|
}
|
|
514
533
|
|
|
515
534
|
function formatDuration(ms) {
|
|
@@ -1215,6 +1234,8 @@
|
|
|
1215
1234
|
"display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;padding:0}" +
|
|
1216
1235
|
"#lvc-root .lvc-tool:hover{background:var(--lvc-border);color:var(--lvc-text)}" +
|
|
1217
1236
|
"#lvc-root #lvc-record.lvc-recording-on{color:#dc2626}" +
|
|
1237
|
+
"#lvc-root #lvc-form.lvc-is-recording #lvc-attach,#lvc-root #lvc-form.lvc-is-recording #lvc-record" +
|
|
1238
|
+
"{display:none}" +
|
|
1218
1239
|
"#lvc-send{border:none;border-radius:50%;background:var(--lvc-accent);color:var(--lvc-accent-text);" +
|
|
1219
1240
|
"width:32px;height:32px;min-width:32px;display:flex;align-items:center;justify-content:center;" +
|
|
1220
1241
|
"cursor:pointer;padding:0}" +
|
|
@@ -1230,16 +1251,22 @@
|
|
|
1230
1251
|
"#lvc-root .lvc-chip-x{border:none;background:none;color:var(--lvc-muted);font-size:16px;" +
|
|
1231
1252
|
"line-height:1;cursor:pointer;padding:0 2px}" +
|
|
1232
1253
|
"#lvc-root .lvc-chip-x:hover{color:var(--lvc-text)}" +
|
|
1233
|
-
"#lvc-recording{display:flex;align-items:center;
|
|
1234
|
-
"
|
|
1254
|
+
"#lvc-recording{display:inline-flex;align-items:center;gap:8px;height:32px;padding:0 4px 0 8px;" +
|
|
1255
|
+
"border:1px solid var(--lvc-border);border-radius:999px;background:var(--lvc-surface);" +
|
|
1256
|
+
"color:var(--lvc-muted);font-size:12px;white-space:nowrap}" +
|
|
1235
1257
|
"#lvc-recording[hidden]{display:none}" +
|
|
1236
|
-
"#lvc-root .lvc-recording-status{display:inline-
|
|
1237
|
-
"
|
|
1258
|
+
"#lvc-root .lvc-recording-status{display:inline-grid;grid-template-columns:8px 24px 34px;" +
|
|
1259
|
+
"align-items:center;gap:6px;font-variant-numeric:tabular-nums}" +
|
|
1260
|
+
"#lvc-root .lvc-recording-dot{width:8px;height:8px;border-radius:50%;background:#dc2626;" +
|
|
1261
|
+
"box-shadow:0 0 0 3px rgba(220,38,38,.12)}" +
|
|
1262
|
+
"#lvc-root .lvc-recording-rec{font-size:10px;font-weight:700;letter-spacing:.04em;color:#dc2626}" +
|
|
1238
1263
|
"#lvc-root .lvc-recording-actions{display:flex;align-items:center;gap:4px}" +
|
|
1239
|
-
"#lvc-root .lvc-recording-actions button{border:
|
|
1240
|
-
"background:
|
|
1241
|
-
"padding:
|
|
1242
|
-
"#lvc-root .lvc-recording-
|
|
1264
|
+
"#lvc-root .lvc-recording-actions button{width:24px;height:24px;border:none;border-radius:50%;" +
|
|
1265
|
+
"background:none;color:var(--lvc-muted);display:flex;align-items:center;justify-content:center;" +
|
|
1266
|
+
"padding:0;cursor:pointer}" +
|
|
1267
|
+
"#lvc-root .lvc-recording-actions button:hover{background:var(--lvc-border);color:var(--lvc-text)}" +
|
|
1268
|
+
"#lvc-root .lvc-recording-stop{background:#dc2626;color:#fff}" +
|
|
1269
|
+
"#lvc-root .lvc-recording-stop:hover{background:#b91c1c;color:#fff}" +
|
|
1243
1270
|
// Attachments inside a message bubble: thumbnails and file links.
|
|
1244
1271
|
"#lvc-root .lvc-atts{display:flex;flex-direction:column;gap:6px;margin-top:6px}" +
|
|
1245
1272
|
"#lvc-root .lvc-att-img{display:block}" +
|