livechat 0.4.5 → 0.4.7
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 +16 -0
- data/app/views/layouts/livechat/application.html.erb +30 -15
- data/app/views/livechat/conversations/show.html.erb +21 -15
- data/lib/livechat/dashboard.js +13 -4
- data/lib/livechat/version.rb +1 -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: '09c824179376138fe658faa40d6cc57949c642e10f42338d442152d50ab4db38'
|
|
4
|
+
data.tar.gz: 0477a0b2e15986595aec854184f0d97ab72dc92fd8ced2738145cc985589490c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f356b2a55640050e11d295ccded406fe4f4698543241ed04bf0754ff9a11b079a566e889391c04bb4b9558fc5989c7a52fcd4a7fa36627ef506a0479e4e419c9
|
|
7
|
+
data.tar.gz: fd1edc5d3a0cd36fd8f03cf8ac7946d5615249e1d8da69bc43a9e6d2393aa61a1bde6c39ae65acc71aba70e21a26c80e60fb089433e4a87b0c654eff4c1c0266
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.7
|
|
4
|
+
|
|
5
|
+
- The inbox reply composer now matches the visitor widget: one bordered box
|
|
6
|
+
with the reply on top and a toolbar row (paperclip left, circular send
|
|
7
|
+
right) inside it, lit on focus — instead of a textarea flanked by loose
|
|
8
|
+
buttons. The reply field auto-grows as you type, and file chips ride inside
|
|
9
|
+
the box.
|
|
10
|
+
|
|
11
|
+
## 0.4.6
|
|
12
|
+
|
|
13
|
+
- Inbox conversation page no longer scrolls the whole page. It now fills the
|
|
14
|
+
viewport with the message thread as the only scrolling region and the reply
|
|
15
|
+
composer pinned at the bottom — so sending a reply keeps you at the newest
|
|
16
|
+
message instead of jumping the page up to the redirect anchor. (A real
|
|
17
|
+
chat-app layout, matching the visitor widget.)
|
|
18
|
+
|
|
3
19
|
## 0.4.5
|
|
4
20
|
|
|
5
21
|
- The widget's injected stylesheet now refreshes itself when its content
|
|
@@ -93,31 +93,46 @@
|
|
|
93
93
|
.thread .msg.agent .att-file { background: rgba(255,255,255,.2); }
|
|
94
94
|
#new-messages { margin: 12px 0 0; }
|
|
95
95
|
#new-messages a { font-weight: 600; }
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
/* Unified composer box (matches the visitor widget): the reply on top, a
|
|
97
|
+
toolbar row below (tools left, send right), all inside one bordered box
|
|
98
|
+
that lights up on focus. */
|
|
99
|
+
.reply { display: flex; flex-direction: column; gap: 6px; margin: 10px 12px; padding: 8px 10px;
|
|
100
|
+
border: 1px solid var(--border); border-radius: 14px; background: var(--bg); }
|
|
101
|
+
.reply:focus-within { border-color: var(--accent); }
|
|
102
|
+
.reply textarea { -webkit-appearance: none; appearance: none; border: none; background: none;
|
|
103
|
+
resize: none; outline: none; font: inherit; color: var(--text);
|
|
104
|
+
padding: 4px 4px 0; min-height: 40px; max-height: 160px; overflow-y: auto; }
|
|
101
105
|
.reply input[type=file].reply-file { font-size: 12px; color: var(--muted); }
|
|
102
|
-
.reply
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
.reply-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
|
|
107
|
+
.reply-tools { display: flex; align-items: center; gap: 2px; }
|
|
108
|
+
.reply .attach { width: 32px; height: 32px; padding: 0; border: none; background: none;
|
|
109
|
+
color: var(--muted); border-radius: 8px; cursor: pointer;
|
|
110
|
+
display: flex; align-items: center; justify-content: center; }
|
|
111
|
+
.reply .attach:hover { background: var(--border); color: var(--text); }
|
|
106
112
|
.reply .chips { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
107
113
|
.reply .chip { display: inline-flex; align-items: center; gap: 6px; max-width: 100%;
|
|
108
114
|
padding: 4px 6px 4px 10px; border: 1px solid var(--border); border-radius: 999px;
|
|
109
|
-
background: var(--
|
|
115
|
+
background: var(--surface); font-size: 12px; }
|
|
110
116
|
.reply .chip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 220px; }
|
|
111
117
|
.reply .chip-x { padding: 0 2px; border: none; background: none; color: var(--muted);
|
|
112
118
|
font-size: 16px; line-height: 1; cursor: pointer; }
|
|
113
119
|
.reply .chip-x:hover { color: var(--text); }
|
|
114
|
-
.reply
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
120
|
+
.reply .send { width: 32px; min-width: 32px; height: 32px; padding: 0; border: none; border-radius: 50%;
|
|
121
|
+
background: var(--accent); color: var(--accent-text); cursor: pointer;
|
|
122
|
+
display: flex; align-items: center; justify-content: center; }
|
|
123
|
+
/* Conversation page: fill the viewport and scroll the THREAD, not the
|
|
124
|
+
page — so a reply never jumps the page, and the composer stays put. */
|
|
125
|
+
.lvc-convo, .lvc-convo .container { height: 100vh; height: 100dvh; }
|
|
126
|
+
.lvc-convo { overflow: hidden; }
|
|
127
|
+
.lvc-convo .container { display: flex; flex-direction: column; padding-bottom: 16px; }
|
|
128
|
+
.lvc-convo .breadcrumb, .lvc-convo .head-row, .lvc-convo .context-line,
|
|
129
|
+
.lvc-convo .flash { flex: 0 0 auto; }
|
|
130
|
+
.lvc-convo .card { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
|
|
131
|
+
.lvc-convo .thread { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
|
|
132
|
+
.lvc-convo .reply { flex: 0 0 auto; }
|
|
118
133
|
</style>
|
|
119
134
|
</head>
|
|
120
|
-
<body>
|
|
135
|
+
<body class="<%= yield(:body_class) %>">
|
|
121
136
|
<div class="container">
|
|
122
137
|
<% if flash[:alert].present? %>
|
|
123
138
|
<p class="flash alert"><%= flash[:alert] %></p>
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
<%# Fill the viewport and scroll only the thread (see .lvc-convo in the layout). %>
|
|
2
|
+
<% content_for :body_class, 'lvc-convo' %>
|
|
3
|
+
|
|
1
4
|
<p class="breadcrumb">
|
|
2
5
|
<%= link_to "← #{t('livechat.dashboard.back', default: 'All conversations')}", conversations_path %>
|
|
3
6
|
</p>
|
|
@@ -60,23 +63,26 @@
|
|
|
60
63
|
<% end %>
|
|
61
64
|
</div>
|
|
62
65
|
|
|
66
|
+
<%# One bordered composer box (matches the visitor widget): the reply on top,
|
|
67
|
+
a toolbar row below with tools on the left and send on the right. %>
|
|
63
68
|
<%= form_with url: conversation_messages_path(@conversation), method: :post,
|
|
64
69
|
multipart: true, class: 'reply' do |form| %>
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
<%= form.text_area :body, rows: 2, autofocus: true, required: !Livechat.attachments_enabled?,
|
|
71
|
+
placeholder: t('livechat.dashboard.reply_placeholder', default: 'Write your reply…') %>
|
|
72
|
+
<%# dashboard.js hides this and swaps in a paperclip button (into .reply-tools)
|
|
73
|
+
plus file chips at the top of the box. Left plain as a no-JS fallback. %>
|
|
74
|
+
<% if Livechat.attachments_enabled? %>
|
|
75
|
+
<%= form.file_field :files, multiple: true, class: 'reply-file',
|
|
76
|
+
aria: { label: t('livechat.dashboard.attach', default: 'Attach files') } %>
|
|
77
|
+
<% end %>
|
|
78
|
+
<div class="reply-toolbar">
|
|
79
|
+
<div class="reply-tools"></div>
|
|
80
|
+
<button type="submit" class="send"
|
|
81
|
+
aria-label="<%= t('livechat.dashboard.send', default: 'Send') %>"
|
|
82
|
+
title="<%= t('livechat.dashboard.send', default: 'Send') %>">
|
|
83
|
+
<%# Paper airplane (Heroicons, MIT) — same icon as the widget. %>
|
|
84
|
+
<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true"><path fill="currentColor" d="M3.478 2.404a.75.75 0 0 0-.926.941l2.432 7.905H13.5a.75.75 0 0 1 0 1.5H4.984l-2.432 7.905a.75.75 0 0 0 .926.94 60.519 60.519 0 0 0 18.445-8.986.75.75 0 0 0 0-1.218A60.517 60.517 0 0 0 3.478 2.404Z"/></svg>
|
|
85
|
+
</button>
|
|
74
86
|
</div>
|
|
75
|
-
<button type="submit" class="primary send"
|
|
76
|
-
aria-label="<%= t('livechat.dashboard.send', default: 'Send') %>"
|
|
77
|
-
title="<%= t('livechat.dashboard.send', default: 'Send') %>">
|
|
78
|
-
<%# Paper airplane (Heroicons, MIT) — same icon as the widget. %>
|
|
79
|
-
<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true"><path fill="currentColor" d="M3.478 2.404a.75.75 0 0 0-.926.941l2.432 7.905H13.5a.75.75 0 0 1 0 1.5H4.984l-2.432 7.905a.75.75 0 0 0 .926.94 60.519 60.519 0 0 0 18.445-8.986.75.75 0 0 0 0-1.218A60.517 60.517 0 0 0 3.478 2.404Z"/></svg>
|
|
80
|
-
</button>
|
|
81
87
|
<% end %>
|
|
82
88
|
</div>
|
data/lib/livechat/dashboard.js
CHANGED
|
@@ -46,18 +46,19 @@
|
|
|
46
46
|
button.title = label;
|
|
47
47
|
// Paperclip (Heroicons, MIT) — same icon as the widget.
|
|
48
48
|
button.innerHTML =
|
|
49
|
-
'<svg viewBox="0 0 24 24" width="
|
|
49
|
+
'<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">' +
|
|
50
50
|
'<path fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" ' +
|
|
51
51
|
'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 ' +
|
|
52
52
|
'3.3 3.3l-8.5 8.4a1.1 1.1 0 0 1-1.6-1.6l7.8-7.8"/></svg>';
|
|
53
53
|
button.addEventListener("click", function () { input.click(); });
|
|
54
|
-
|
|
54
|
+
// The paperclip lives in the toolbar (left of send); chips sit at the top
|
|
55
|
+
// of the box — so it reads as one composer, like the visitor widget.
|
|
56
|
+
(form.querySelector(".reply-tools") || form).appendChild(button);
|
|
55
57
|
|
|
56
58
|
var chips = document.createElement("div");
|
|
57
59
|
chips.className = "chips";
|
|
58
60
|
chips.hidden = true;
|
|
59
|
-
|
|
60
|
-
compose.insertBefore(chips, compose.firstChild);
|
|
61
|
+
form.insertBefore(chips, form.firstChild);
|
|
61
62
|
|
|
62
63
|
input.addEventListener("change", render);
|
|
63
64
|
|
|
@@ -143,6 +144,14 @@
|
|
|
143
144
|
replyBox.form.requestSubmit();
|
|
144
145
|
}
|
|
145
146
|
});
|
|
147
|
+
// Grow the box with the reply, up to the CSS max-height — matching the
|
|
148
|
+
// widget composer instead of a fixed two-row field.
|
|
149
|
+
var autogrow = function () {
|
|
150
|
+
replyBox.style.height = "auto";
|
|
151
|
+
replyBox.style.height = Math.min(replyBox.scrollHeight, 160) + "px";
|
|
152
|
+
};
|
|
153
|
+
replyBox.addEventListener("input", autogrow);
|
|
154
|
+
autogrow();
|
|
146
155
|
}
|
|
147
156
|
|
|
148
157
|
// New messages are appended in place — never a reload — so a half-written
|
data/lib/livechat/version.rb
CHANGED