livechat 0.9.1 → 0.10.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.
- checksums.yaml +4 -4
- data/AGENTS.md +1 -1
- data/CHANGELOG.md +16 -0
- data/app/views/livechat/conversations/_thread_panel.html.erb +18 -15
- data/lib/livechat/dashboard.css +18 -16
- 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: 63ba0ec549bbfac094a6a507ac4e3525c01b9b8926dbbf4e7822e7db05c2472d
|
|
4
|
+
data.tar.gz: 7afeeacda8689b6335c87a06a9fe0fecb50388379fc32d7255ab0fec16afe04e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 26d8a59095979df9546eaa12aee10d828b50677a2b32e199c2b25a9820cfa7d3e8a4b24f9ec53e4f19c286f49948ab8bb4ea1756bfea3818d849240b8221f080
|
|
7
|
+
data.tar.gz: e287d3e63e218974245e0c5e495603aee5ae4ddd3b3b9c91af2ebc6ca103aa2d0ffdea731f39003ad79e10c52101bf9f187afba64cb4ded94e07c17ab6bb8cd0
|
data/AGENTS.md
CHANGED
|
@@ -176,6 +176,6 @@ Conventions this codebase holds to — follow them rather than the first thing t
|
|
|
176
176
|
- **The widget is plain ES5-style JS served by the engine**, no build step, no framework, config read from a JSON block so a Turbo visit re-reads the current page's settings.
|
|
177
177
|
- **Visitor scoping is never by conversation id.** The widget's endpoints resolve the thread from the signed-in id or the guest cookie, so no id in a request can address someone else's conversation. Keep it that way.
|
|
178
178
|
- **The dummy app pins `config.active_job.queue_adapter = :test`.** Do not remove it or let it drift back to the `:async` default. Attaching a file enqueues Active Storage's analysis job, and `:async` runs it on a background thread that checks out its own connection — writes no test transaction covers, landing in the middle of whatever runs next. That is a suite that fails order-dependently in a test which never created a row, and it is miserable to trace back.
|
|
179
|
-
- **`lib/livechat/dashboard.css` is half shared.** Everything above the `GEM-SPECIFIC` banner is the design system all five gems in the family ship — the same tokens, the same `.page-head`/`.tabs`/`.filters`/`.card`/`.badge`/`button`, the same `.dashboard-shell` + `.record-row` + `.detail-panel` two-pane dashboard — identical in every repo apart from the `lvc` prefix. Diff it against a sibling before changing it, and carry the change to the other four. Anything only this gem has goes below the banner. New dashboard markup reuses the shared class names rather than inventing a domain-specific one.
|
|
179
|
+
- **`lib/livechat/dashboard.css` is half shared.** Everything above the `GEM-SPECIFIC` banner is the design system all five gems in the family ship — the same tokens, the same `.page-head`/`.tabs`/`.filters`/`.card`/`.badge`/`button`/`.status-switch`, the same `.dashboard-shell` + `.record-row` + `.detail-panel` two-pane dashboard — identical in every repo apart from the `lvc` prefix. Diff it against a sibling before changing it, and carry the change to the other four. Anything only this gem has goes below the banner. New dashboard markup reuses the shared class names rather than inventing a domain-specific one.
|
|
180
180
|
- Every user-facing change bumps `lib/livechat/version.rb` and adds a `CHANGELOG.md` entry that says what it costs, not only what it adds.
|
|
181
181
|
- Commit messages are prose that explains the tradeoff — read `git log` before writing one.
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.0
|
|
4
|
+
|
|
5
|
+
- **The open/resolved switch is now the family's shared component.** It looks the
|
|
6
|
+
same and sits where it sat, but it is `.status-switch` in the shared core of
|
|
7
|
+
`dashboard.css` rather than this gem's own `.status-toggle`, so ideasbugs could
|
|
8
|
+
adopt it for its three statuses instead of growing a second near-identical
|
|
9
|
+
control. `.status-toggle`, `.status-toggle-form`, `.is-open` and `.is-resolved`
|
|
10
|
+
are gone — that is the breaking change if you styled them.
|
|
11
|
+
- Each half is now its own target: `Open` reopens, `Resolved` resolves, via
|
|
12
|
+
`formaction` on two submit buttons in one form. Before, the whole pill was one
|
|
13
|
+
button that flipped whichever way it was not. The half that is already current
|
|
14
|
+
is inert, so clicking it can no longer log a reopen of an open chat. The
|
|
15
|
+
sliding highlight went with the rewrite — it never animated anyway, since
|
|
16
|
+
resolving reloads the page and the pill arrives already in its new position.
|
|
17
|
+
`POST /:id/resolve` and `POST /:id/reopen` are unchanged.
|
|
18
|
+
|
|
3
19
|
## 0.9.1
|
|
4
20
|
|
|
5
21
|
- **The conversation heading reads as one block.** The visitor's email and locale
|
|
@@ -12,21 +12,24 @@
|
|
|
12
12
|
<%= safe_join(context, ' · ') %>
|
|
13
13
|
</p>
|
|
14
14
|
</div>
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
15
|
+
<%# The shared status switch: the state it is in is lit and inert, the other
|
|
16
|
+
one submits to its own route via `formaction`. One form, no JS, and
|
|
17
|
+
clicking the lit half cannot log a reopen of an already-open chat. %>
|
|
18
|
+
<%= form_with url: resolve_conversation_path(conversation), method: :post, class: 'status-switch' do %>
|
|
19
|
+
<% if conversation.open? %>
|
|
20
|
+
<button type="button" class="status-open current" aria-current="true">
|
|
21
|
+
<%= t('livechat.statuses.open', default: 'Open') %>
|
|
22
|
+
</button>
|
|
23
|
+
<button formaction="<%= resolve_conversation_path(conversation) %>" class="status-resolved">
|
|
24
|
+
<%= t('livechat.statuses.resolved', default: 'Resolved') %>
|
|
25
|
+
</button>
|
|
26
|
+
<% else %>
|
|
27
|
+
<button formaction="<%= reopen_conversation_path(conversation) %>" class="status-open">
|
|
28
|
+
<%= t('livechat.statuses.open', default: 'Open') %>
|
|
29
|
+
</button>
|
|
30
|
+
<button type="button" class="status-resolved current" aria-current="true">
|
|
31
|
+
<%= t('livechat.statuses.resolved', default: 'Resolved') %>
|
|
32
|
+
</button>
|
|
30
33
|
<% end %>
|
|
31
34
|
<% end %>
|
|
32
35
|
</div>
|
data/lib/livechat/dashboard.css
CHANGED
|
@@ -144,6 +144,19 @@
|
|
|
144
144
|
& .actions form { display: inline; }
|
|
145
145
|
& .form-actions { padding-top: 12px; }
|
|
146
146
|
|
|
147
|
+
/* Status switch: one pill holding every state a record can be in, the state it
|
|
148
|
+
is in now lit. Each other segment is a submit button, so moving a record
|
|
149
|
+
takes one click and no JavaScript; the current segment is a `type="button"`
|
|
150
|
+
so clicking it cannot re-file the record it is already filed under. Two
|
|
151
|
+
states or five, the pill sizes itself. A gem tints the lit segment with its
|
|
152
|
+
own status colour — see the `GEM-SPECIFIC` section. */
|
|
153
|
+
& .status-switch { display: inline-flex; flex: 0 0 auto; margin: 0; padding: 3px; border: 1px solid var(--lvc-border); border-radius: 999px; background: var(--lvc-bg); }
|
|
154
|
+
& .status-switch button { min-height: 30px; padding: 0 12px; border: 0; border-radius: 999px; background: none; color: var(--lvc-muted); font-size: 13px; font-weight: 700; white-space: nowrap; transition: background .16s ease, color .16s ease; }
|
|
155
|
+
& .status-switch button:hover { border: 0; background: color-mix(in srgb, var(--lvc-muted) 12%, transparent); color: var(--lvc-text); }
|
|
156
|
+
& .status-switch button.current { background: var(--lvc-surface); color: var(--lvc-text); box-shadow: 0 1px 2px rgba(15, 23, 42, .12); cursor: default; }
|
|
157
|
+
& .status-switch button.current:hover { background: var(--lvc-surface); }
|
|
158
|
+
& .panel-head .status-switch { margin-left: auto; }
|
|
159
|
+
|
|
147
160
|
& .card { overflow: hidden; border: 1px solid var(--lvc-border); border-radius: 12px; background: var(--lvc-surface); }
|
|
148
161
|
& .card.pad { padding: 16px; overflow: visible; }
|
|
149
162
|
& table { width: 100%; border-collapse: collapse; }
|
|
@@ -266,6 +279,7 @@
|
|
|
266
279
|
& .dashboard-detail .detail-panel { min-height: calc(100vh - 64px); }
|
|
267
280
|
& .mobile-back { display: block; flex: 0 0 auto; margin: 4px 0 10px; font-size: 13px; }
|
|
268
281
|
& .panel-head h1 { font-size: 18px; }
|
|
282
|
+
& .status-switch button { padding: 0 9px; font-size: 12px; }
|
|
269
283
|
& dl { grid-template-columns: 1fr; gap: 3px; }
|
|
270
284
|
& dd { margin-bottom: 8px; }
|
|
271
285
|
}
|
|
@@ -291,22 +305,12 @@
|
|
|
291
305
|
& .record-side .avatars { min-height: 26px; }
|
|
292
306
|
|
|
293
307
|
/* The panel heading: the name with the visitor's context directly under it,
|
|
294
|
-
and the switch pushed to the far right of the row whatever the
|
|
295
|
-
|
|
296
|
-
third element in the row could never pull the switch back in. */
|
|
308
|
+
and the shared status switch pushed to the far right of the row whatever the
|
|
309
|
+
name's length. */
|
|
297
310
|
& .panel-titles { display: flex; min-width: 0; flex-direction: column; gap: 2px; }
|
|
298
311
|
& .context-line { margin: 0; overflow-wrap: anywhere; }
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
& .status-toggle-form { flex: 0 0 auto; margin-left: auto; }
|
|
302
|
-
& .status-toggle { position: relative; display: grid; grid-template-columns: 1fr 1fr; gap: 0; width: 176px; min-height: 36px; padding: 3px; border-radius: 999px; border: 1px solid var(--lvc-border); background: var(--lvc-bg); color: var(--lvc-muted); overflow: hidden; }
|
|
303
|
-
& .status-toggle::before { content: ""; position: absolute; z-index: 0; top: 3px; bottom: 3px; width: calc(50% - 3px); border-radius: 999px; background: var(--lvc-surface); box-shadow: 0 1px 2px rgba(15, 23, 42, .12); transition: left .16s ease; }
|
|
304
|
-
& .status-toggle.is-open::before { left: 3px; }
|
|
305
|
-
& .status-toggle.is-resolved::before { left: 50%; }
|
|
306
|
-
& .status-toggle span { position: relative; z-index: 1; display: flex; align-items: center; justify-content: center; min-width: 0; padding: 0 10px; font-size: 13px; font-weight: 700; white-space: nowrap; }
|
|
307
|
-
& .status-toggle.is-open span:first-child { color: var(--lvc-open); }
|
|
308
|
-
& .status-toggle.is-resolved span:last-child { color: var(--lvc-text); }
|
|
309
|
-
& .status-toggle:hover { text-decoration: none; color: var(--lvc-text); }
|
|
312
|
+
/* An open conversation is the one that wants an answer, so say so in green. */
|
|
313
|
+
& .status-switch button.current.status-open { color: var(--lvc-open); }
|
|
310
314
|
|
|
311
315
|
& .avatars { display: inline-flex; }
|
|
312
316
|
& .avatars .avatar { width: 26px; height: 26px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700; color: #fff; border: 2px solid var(--lvc-surface); cursor: default; }
|
|
@@ -387,8 +391,6 @@
|
|
|
387
391
|
@media (max-width: 760px) {
|
|
388
392
|
.lvc-dashboard {
|
|
389
393
|
& .detail-panel .panel-head h1 { font-size: 18px; }
|
|
390
|
-
& .status-toggle { width: 152px; min-height: 34px; }
|
|
391
|
-
& .status-toggle span { padding: 0 7px; font-size: 12px; }
|
|
392
394
|
& .thread .msg { max-width: 88%; }
|
|
393
395
|
}
|
|
394
396
|
}
|
data/lib/livechat/version.rb
CHANGED