mailscope 0.1.0 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db87fb72ccde481718a35a6a8902eeb1e2fbfc423c8292e17b0d5fb3b97afa0e
4
- data.tar.gz: 85b4a41a9c9afb1231092a1030e631ca22fef3b9113a24b8b734281343dd6de7
3
+ metadata.gz: 19f786326def785dfcd3da7cb0b4e41bfb4397a0f98c9fe45ad9f12b04414f45
4
+ data.tar.gz: d1c3d1b5eb0f9d13cba31bc51827fad2ab41ce734acd8dd591b09b6cf1fdfa50
5
5
  SHA512:
6
- metadata.gz: df401455be0fd9677dbd74b2c2aed038277370f61b8f15ec8f0e841bb31c39365fafdaa20ea691d1faa9660d0eb93fb0b29c53f010037e2f59b8fabe29916430
7
- data.tar.gz: ea923fff2de475991245b5850b26ef21a9619588f3b4b922e9989d95d75d546c7319ba220d0c7fb861736f79a0231ca5833a29b8953cfdb2a9c3e6d2b39f1e6b
6
+ metadata.gz: bf9af26bdcb82142354e62d7ab4a1398dde03952473207a48e86b4966acacd8c917553614f89fee7319f3c8bafad99f4edaea417482e2dda68d41897cc237527
7
+ data.tar.gz: b37911850eb6b561d12c4ea4ca8b56caa37b68a7e6a20a34bbdd3acf44142a71d90136944f6d976ecc66099e36f139fa20a96a9bf86c7396255e14196e46f895
data/CHANGELOG.md CHANGED
@@ -2,7 +2,25 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
- [Unreleased]: https://github.com/renatomeloferraz/mailscope/compare/v0.1.0...HEAD
5
+ [Unreleased]: https://github.com/renatomeloferraz/mailscope/compare/v0.1.1...HEAD
6
+
7
+ ## [0.1.1] — 2026-08-22
8
+
9
+ [0.1.1]: https://github.com/renatomeloferraz/mailscope/compare/v0.1.0...v0.1.1
10
+
11
+ ### Changed
12
+
13
+ - Clearing the inbox asks through an in-app dialog instead of `window.confirm`,
14
+ which could not be themed and prefixed the browser origin. Escape and the
15
+ backdrop cancel, focus starts on Cancel and is trapped while it is open.
16
+ - The header's utility controls (refresh, live, theme, shortcuts) sit in one
17
+ group, with the destructive Clear action kept outside it.
18
+ - The empty-inbox notice sits near the top of the message list, centred, and
19
+ now says how to make messages appear; centring it vertically in a tall empty
20
+ column read as a loading state.
21
+ - Dropped the rail's "no recipients yet" line and the reading pane's "no
22
+ message selected" notice when nothing has been captured — three empty states
23
+ for one empty inbox, and the pane invited you to pick from an empty list.
6
24
 
7
25
  ## [0.1.0] — 2026-08-22
8
26
 
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Mailscope
2
2
 
3
+ [![Gem Version](https://img.shields.io/gem/v/mailscope)](https://rubygems.org/gems/mailscope)
4
+ [![CI](https://github.com/renatomeloferraz/mailscope/actions/workflows/main.yml/badge.svg)](https://github.com/renatomeloferraz/mailscope/actions/workflows/main.yml)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE.txt)
6
+
3
7
  A mail inspector for Rails development and staging environments. It captures
4
8
  everything your app sends and gives you a fast web UI to **search, preview and
5
9
  inspect** it: HTML, plain text, the raw `.eml`, real headers and attachments —
@@ -193,7 +193,24 @@ kbd {
193
193
  .ms-search__kbd { flex: none; }
194
194
  .ms-search:focus-within .ms-search__kbd { opacity: 0; }
195
195
 
196
- .ms-topbar__actions { display: flex; align-items: center; gap: 6px; margin-left: auto; flex: none; }
196
+ .ms-topbar__actions { display: flex; align-items: center; gap: 10px; margin-left: auto; flex: none; }
197
+
198
+ /* One surface for the utility controls, so they stop floating loose next to
199
+ the destructive one. */
200
+ .ms-cluster {
201
+ display: flex; align-items: center; gap: 1px;
202
+ padding: 2px;
203
+ background: var(--sunken);
204
+ border: 1px solid var(--border-soft);
205
+ border-radius: 9px;
206
+ }
207
+ .ms-cluster .ms-btn,
208
+ .ms-cluster .ms-live { height: 28px; border-radius: 7px; }
209
+ .ms-cluster .ms-btn:hover,
210
+ .ms-cluster .ms-live:hover { background: var(--surface); }
211
+ .ms-cluster .ms-live:has(input:checked) { background: var(--surface); }
212
+ .ms-topbar__actions > .ms-btn--danger { border: 1px solid transparent; }
213
+ .ms-topbar__actions > .ms-btn--danger:hover { border-color: color-mix(in oklab, var(--danger) 30%, transparent); }
197
214
 
198
215
  /* Opens the mailbox rail once it stops fitting beside the list. */
199
216
  .ms-topbar .ms-rail-toggle { display: none; }
@@ -271,7 +288,6 @@ kbd {
271
288
  font-size: 10.5px; font-weight: 680; letter-spacing: .07em; text-transform: uppercase;
272
289
  color: var(--muted);
273
290
  }
274
- .ms-rail__hint { padding: 6px 8px; font-size: 12.5px; color: var(--muted); }
275
291
 
276
292
  .ms-box {
277
293
  display: flex; align-items: center; gap: 9px;
@@ -516,9 +532,14 @@ kbd {
516
532
 
517
533
  /* ── empty states ───────────────────────────────────────────────────── */
518
534
  .ms-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; text-align: center; padding: 40px 24px; }
519
- .ms-empty--list { flex: 1; }
535
+ /* Anchored to the top of the list column: centring it in a tall, otherwise
536
+ empty column reads as a loading state. */
537
+ .ms-empty--list { justify-content: flex-start; padding: 48px 22px; }
538
+ .ms-empty--list .ms-empty__text { max-width: 34ch; }
539
+ .ms-empty--list .ms-empty__text strong { color: var(--text-2); font-weight: 600; }
520
540
  .ms-empty--pane { height: 100%; }
521
541
  .ms-empty__icon { display: grid; place-items: center; width: 52px; height: 52px; margin-bottom: 6px; border-radius: 14px; background: var(--sunken); color: var(--muted); }
542
+ .ms-empty--list .ms-empty__icon { width: 34px; height: 34px; border-radius: 10px; margin-bottom: 4px; }
522
543
  .ms-empty__icon--lg { width: 66px; height: 66px; border-radius: 18px; }
523
544
  .ms-empty__title { font-size: 14.5px; font-weight: 620; color: var(--text); }
524
545
  .ms-empty__text { font-size: 13px; color: var(--muted); line-height: 1.6; }
@@ -535,6 +556,18 @@ kbd {
535
556
  }
536
557
  .ms-modal__card header { display: flex; align-items: center; padding: 14px 12px 14px 18px; border-bottom: 1px solid var(--border-soft); }
537
558
  .ms-modal__card h2 { flex: 1; font-size: 14.5px; font-weight: 620; }
559
+ /* Confirmation dialog */
560
+ .ms-modal__card--confirm { width: min(400px, calc(100vw - 32px)); }
561
+ .ms-modal__card--confirm header { gap: 10px; border-bottom: 0; padding: 18px 18px 0; }
562
+ .ms-confirm__icon {
563
+ display: grid; place-items: center; width: 32px; height: 32px; flex: none;
564
+ border-radius: 9px; background: var(--danger-soft); color: var(--danger);
565
+ }
566
+ .ms-confirm__body { padding: 8px 18px 0; color: var(--text-2); font-size: 13px; line-height: 1.55; }
567
+ .ms-confirm__actions { display: flex; justify-content: flex-end; gap: 8px; padding: 18px; }
568
+ .ms-btn--solid-danger { background: var(--danger); color: #fff; font-weight: 600; }
569
+ .ms-btn--solid-danger:hover { background: color-mix(in oklab, var(--danger) 85%, #000); color: #fff; }
570
+
538
571
  .ms-shortcuts { padding: 8px 18px 18px; }
539
572
  .ms-shortcuts > div { display: flex; align-items: center; gap: 12px; padding: 6px 0; }
540
573
  .ms-shortcuts dt { flex: none; width: 88px; display: flex; gap: 4px; }
@@ -78,6 +78,55 @@
78
78
  function hide() { node.classList.remove('is-visible'); }
79
79
  })();
80
80
 
81
+ // ── confirmation dialog ──────────────────────────────────────────────
82
+ // Replaces window.confirm: that one cannot be themed, ignores the app's
83
+ // typography and prefixes the origin, so it reads as a browser warning
84
+ // rather than a deliberate action inside the tool.
85
+ var confirmDialog = (function () {
86
+ var modal = $('[data-confirm]');
87
+ var pending = null;
88
+ var lastFocused = null;
89
+
90
+ function close(accepted) {
91
+ if (!pending) return;
92
+ var resolve = pending;
93
+ pending = null;
94
+ modal.hidden = true;
95
+ if (lastFocused && lastFocused.isConnected) lastFocused.focus();
96
+ resolve(accepted);
97
+ }
98
+
99
+ function open(options) {
100
+ if (!modal) return Promise.resolve(window.confirm(options.body)); // no markup: degrade
101
+
102
+ $('[data-confirm-title]', modal).textContent = options.title;
103
+ $('[data-confirm-body]', modal).textContent = options.body;
104
+ $('[data-confirm-accept]', modal).textContent = options.accept;
105
+
106
+ lastFocused = document.activeElement;
107
+ modal.hidden = false;
108
+ // Focus the safe option, so Enter never destroys anything by reflex.
109
+ $('[data-confirm-cancel]', modal).focus();
110
+
111
+ return new Promise(function (resolve) { pending = resolve; });
112
+ }
113
+
114
+ if (modal) {
115
+ // Keep Tab inside the dialog while it is open.
116
+ modal.addEventListener('keydown', function (event) {
117
+ if (event.key !== 'Tab') return;
118
+ var focusable = $$('button', modal);
119
+ var first = focusable[0];
120
+ var last = focusable[focusable.length - 1];
121
+ if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); }
122
+ else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); }
123
+ });
124
+ }
125
+
126
+ return { open: open, cancel: function () { close(false); }, accept: function () { close(true); },
127
+ get isOpen() { return !!pending; } };
128
+ })();
129
+
81
130
  // ── theme ────────────────────────────────────────────────────────────
82
131
  function currentTheme() { return document.documentElement.dataset.theme || 'system'; }
83
132
 
@@ -345,9 +394,15 @@
345
394
  .catch(function () { toast(t('deleteFailed')); });
346
395
  }
347
396
 
348
- function clearAll(url) {
349
- if (!window.confirm(t('clearConfirm'))) return;
397
+ function clearAll(url, count) {
398
+ confirmDialog.open({
399
+ title: t('confirmClearTitle'),
400
+ body: count === 1 ? t('confirmClearBodyOne') : t('confirmClearBody', { count: count }),
401
+ accept: t('confirmClearAccept')
402
+ }).then(function (accepted) { if (accepted) performClear(url); });
403
+ }
350
404
 
405
+ function performClear(url) {
351
406
  request(url, { method: 'DELETE', headers: { Accept: 'application/json' } })
352
407
  .then(function (r) { return r.ok ? r.json() : Promise.reject(r.status); })
353
408
  .then(function (data) {
@@ -417,13 +472,14 @@
417
472
  if (event.metaKey || event.ctrlKey || event.altKey) return;
418
473
 
419
474
  if (event.key === 'Escape') {
475
+ if (confirmDialog.isOpen) { confirmDialog.cancel(); return; }
420
476
  if (!$('[data-shortcuts]').hidden) { $('[data-shortcuts]').hidden = true; return; }
421
477
  closeRail();
422
478
  if (typingInField(event)) event.target.blur();
423
479
  return;
424
480
  }
425
481
 
426
- if (typingInField(event)) return;
482
+ if (typingInField(event) || confirmDialog.isOpen) return;
427
483
 
428
484
  switch (event.key) {
429
485
  case 'j': case 'ArrowDown': event.preventDefault(); moveSelection(1); break;
@@ -494,7 +550,12 @@
494
550
  }
495
551
  case 'shortcuts': event.preventDefault(); $('[data-shortcuts]').hidden = false; break;
496
552
  case 'close-shortcuts': event.preventDefault(); $('[data-shortcuts]').hidden = true; break;
497
- case 'clear': event.preventDefault(); clearAll(action.dataset.url); break;
553
+ case 'clear':
554
+ event.preventDefault();
555
+ clearAll(action.dataset.url, parseInt(action.dataset.count, 10) || 0);
556
+ break;
557
+ case 'confirm-cancel': event.preventDefault(); confirmDialog.cancel(); break;
558
+ case 'confirm-accept': event.preventDefault(); confirmDialog.accept(); break;
498
559
  case 'delete-item': {
499
560
  event.preventDefault();
500
561
  var item = action.closest('[data-item]');
@@ -49,7 +49,10 @@ module Mailscope
49
49
  # bundle stays a static, cacheable asset with no locale baked in.
50
50
  def mailscope_js_strings
51
51
  {
52
- clearConfirm: ms_t('actions.clear_confirm'),
52
+ confirmClearTitle: ms_t('confirm.clear_title'),
53
+ confirmClearBodyOne: ms_t('confirm.clear_body', count: 1),
54
+ confirmClearBody: ms_t('confirm.clear_body', count: 2).sub('2', '%{count}'),
55
+ confirmClearAccept: ms_t('confirm.clear_accept'),
53
56
  deleted: ms_t('toasts.deleted'),
54
57
  deleteFailed: ms_t('toasts.delete_failed'),
55
58
  clearedOne: ms_t('toasts.cleared', count: 1),
@@ -0,0 +1,20 @@
1
+ <%# Generic confirmation dialog. The copy is filled in by mailscope.js so one
2
+ element serves every destructive action. %>
3
+ <div class="ms-modal" data-confirm hidden>
4
+ <div class="ms-modal__backdrop" data-action="confirm-cancel"></div>
5
+ <div class="ms-modal__card ms-modal__card--confirm" role="alertdialog" aria-modal="true"
6
+ aria-labelledby="ms-confirm-title" aria-describedby="ms-confirm-body">
7
+ <header>
8
+ <span class="ms-confirm__icon" aria-hidden="true"><%= mailscope_icon('i-trash', size: 18) %></span>
9
+ <h2 id="ms-confirm-title" data-confirm-title></h2>
10
+ </header>
11
+ <p class="ms-confirm__body" id="ms-confirm-body" data-confirm-body></p>
12
+ <footer class="ms-confirm__actions">
13
+ <button type="button" class="ms-btn ms-btn--soft" data-action="confirm-cancel" data-confirm-cancel>
14
+ <%= ms_t('actions.cancel') %>
15
+ </button>
16
+ <button type="button" class="ms-btn ms-btn--solid-danger" data-action="confirm-accept" data-confirm-accept>
17
+ </button>
18
+ </footer>
19
+ </div>
20
+ </div>
@@ -11,24 +11,27 @@
11
11
  </div>
12
12
  </header>
13
13
 
14
- <ol class="ms-list__items" data-list role="listbox" tabindex="0"
15
- aria-label="<%= ms_t('list.listbox') %>">
16
- <% @messages.each do |message| %>
17
- <%= render 'mailscope/messages/list_item', message: message, selected: @message&.id == message.id %>
18
- <% end %>
19
- </ol>
20
-
21
- <% if @messages.empty? %>
22
- <div class="ms-empty ms-empty--list">
23
- <span class="ms-empty__icon"><%= mailscope_icon('i-inbox', size: 28) %></span>
24
- <% if @query.filtered? %>
25
- <p class="ms-empty__title"><%= ms_t('empty.no_results_title') %></p>
26
- <p class="ms-empty__text"><%= ms_t('empty.no_results_text') %></p>
27
- <a class="ms-btn ms-btn--soft" href="<%= root_path %>"><%= ms_t('actions.clear_filters_button') %></a>
28
- <% else %>
29
- <p class="ms-empty__title"><%= ms_t('empty.inbox_title') %></p>
30
- <p class="ms-empty__text"><%= ms_t('empty.inbox_text') %></p>
14
+ <% if @messages.any? %>
15
+ <ol class="ms-list__items" data-list role="listbox" tabindex="0"
16
+ aria-label="<%= ms_t('list.listbox') %>">
17
+ <% @messages.each do |message| %>
18
+ <%= render 'mailscope/messages/list_item', message: message, selected: @message&.id == message.id %>
31
19
  <% end %>
20
+ </ol>
21
+ <% elsif @query.filtered? %>
22
+ <div class="ms-empty ms-empty--list">
23
+ <span class="ms-empty__icon"><%= mailscope_icon('i-search', size: 24) %></span>
24
+ <p class="ms-empty__title"><%= ms_t('empty.no_results_title') %></p>
25
+ <p class="ms-empty__text"><%= ms_t('empty.no_results_text') %></p>
26
+ <a class="ms-btn ms-btn--soft" href="<%= root_path %>"><%= ms_t('actions.clear_filters_button') %></a>
27
+ </div>
28
+ <% else %>
29
+ <div class="ms-empty ms-empty--list">
30
+ <span class="ms-empty__icon"><%= mailscope_icon('i-inbox', size: 24) %></span>
31
+ <p class="ms-empty__title"><%= ms_t('empty.inbox_title') %></p>
32
+ <p class="ms-empty__text">
33
+ <%= ms_t('empty.inbox_text_html', live: tag.strong(ms_t('actions.live'))) %>
34
+ </p>
32
35
  </div>
33
36
  <% end %>
34
37
  </section>
@@ -8,10 +8,6 @@
8
8
  <span class="ms-box__count"><%= @all.size %></span>
9
9
  </a>
10
10
 
11
- <% if @mailboxes.empty? %>
12
- <p class="ms-rail__hint"><%= ms_t('rail.empty') %></p>
13
- <% end %>
14
-
15
11
  <% @mailboxes.each do |box| %>
16
12
  <a class="ms-box <%= 'is-active' if @mailbox == box.address %>"
17
13
  href="<%= mailscope_filter_url(mailbox: box.address) %>"
@@ -22,28 +22,32 @@
22
22
  </form>
23
23
 
24
24
  <div class="ms-topbar__actions">
25
- <button type="button" class="ms-btn ms-btn--ghost" data-action="refresh" title="<%= ms_t('actions.refresh_hint') %>">
26
- <%= mailscope_icon('i-refresh') %><span class="ms-sr"><%= ms_t('actions.refresh') %></span>
27
- </button>
25
+ <%# Utilities travel together; the destructive action stands apart. %>
26
+ <div class="ms-cluster">
27
+ <button type="button" class="ms-btn ms-btn--ghost" data-action="refresh" title="<%= ms_t('actions.refresh_hint') %>">
28
+ <%= mailscope_icon('i-refresh') %><span class="ms-sr"><%= ms_t('actions.refresh') %></span>
29
+ </button>
28
30
 
29
- <label class="ms-live" title="<%= ms_t('actions.live_hint') %>">
30
- <input type="checkbox" data-live-toggle <%= 'checked' if mailscope_config.auto_refresh %>>
31
- <span class="ms-live__dot" aria-hidden="true"></span>
32
- <span class="ms-live__label"><%= ms_t('actions.live') %></span>
33
- </label>
31
+ <label class="ms-live" title="<%= ms_t('actions.live_hint') %>">
32
+ <input type="checkbox" data-live-toggle <%= 'checked' if mailscope_config.auto_refresh %>>
33
+ <span class="ms-live__dot" aria-hidden="true"></span>
34
+ <span class="ms-live__label"><%= ms_t('actions.live') %></span>
35
+ </label>
34
36
 
35
- <button type="button" class="ms-btn ms-btn--ghost" data-action="theme" title="<%= ms_t('actions.theme') %>">
36
- <span data-theme-icon="light"><%= mailscope_icon('i-sun') %></span>
37
- <span data-theme-icon="dark"><%= mailscope_icon('i-moon') %></span>
38
- <span class="ms-sr"><%= ms_t('actions.theme') %></span>
39
- </button>
37
+ <button type="button" class="ms-btn ms-btn--ghost" data-action="theme" title="<%= ms_t('actions.theme') %>">
38
+ <span data-theme-icon="light"><%= mailscope_icon('i-sun') %></span>
39
+ <span data-theme-icon="dark"><%= mailscope_icon('i-moon') %></span>
40
+ <span class="ms-sr"><%= ms_t('actions.theme') %></span>
41
+ </button>
40
42
 
41
- <button type="button" class="ms-btn ms-btn--ghost" data-action="shortcuts" title="<%= ms_t('actions.shortcuts_hint') %>">
42
- <%= mailscope_icon('i-keyboard') %><span class="ms-sr"><%= ms_t('actions.shortcuts') %></span>
43
- </button>
43
+ <button type="button" class="ms-btn ms-btn--ghost" data-action="shortcuts" title="<%= ms_t('actions.shortcuts_hint') %>">
44
+ <%= mailscope_icon('i-keyboard') %><span class="ms-sr"><%= ms_t('actions.shortcuts') %></span>
45
+ </button>
46
+ </div>
44
47
 
45
48
  <button type="button" class="ms-btn ms-btn--danger" data-action="clear"
46
- data-url="<%= clear_messages_path %>" <%= 'disabled' if @all.empty? %>>
49
+ data-url="<%= clear_messages_path %>" data-count="<%= @all.size %>"
50
+ <%= 'disabled' if @all.empty? %>>
47
51
  <%= mailscope_icon('i-trash') %><span><%= ms_t('actions.clear') %></span>
48
52
  </button>
49
53
  </div>
@@ -56,11 +60,12 @@
56
60
  <section class="ms-pane" data-pane aria-live="polite">
57
61
  <% if @message %>
58
62
  <%= render 'mailscope/messages/pane', message: @message %>
59
- <% else %>
63
+ <% elsif @all.any? %>
60
64
  <%= render 'mailscope/messages/blank_pane' %>
61
65
  <% end %>
62
66
  </section>
63
67
  </div>
64
68
 
65
69
  <%= render 'mailscope/messages/shortcuts' %>
70
+ <%= render 'mailscope/messages/confirm' %>
66
71
  </div>
@@ -12,7 +12,6 @@ en:
12
12
  shortcuts: "Shortcuts"
13
13
  shortcuts_hint: "Shortcuts (?)"
14
14
  clear: "Clear"
15
- clear_confirm: "Delete every captured message? This cannot be undone."
16
15
  clear_filters: "clear filters"
17
16
  clear_filters_button: "Clear filters"
18
17
  delete: "Delete"
@@ -23,11 +22,17 @@ en:
23
22
  open_preview: "Open the preview"
24
23
  allow_remote: "Load anyway"
25
24
  close: "Close"
25
+ cancel: "Cancel"
26
+ confirm:
27
+ clear_title: "Delete every captured message?"
28
+ clear_body:
29
+ one: "The message is removed from disk. This cannot be undone."
30
+ other: "All %{count} messages are removed from disk. This cannot be undone."
31
+ clear_accept: "Delete all"
26
32
  rail:
27
33
  heading: "Mailboxes"
28
34
  label: "Mailboxes"
29
35
  all: "All messages"
30
- empty: "No recipients yet."
31
36
  list:
32
37
  label: "Messages"
33
38
  listbox: "Message list"
@@ -42,8 +47,8 @@ en:
42
47
  empty:
43
48
  no_results_title: "Nothing found"
44
49
  no_results_text: "No message matches these filters."
45
- inbox_title: "Empty inbox"
46
- inbox_text: "Send an email from your app and it shows up here."
50
+ inbox_title: "No messages yet"
51
+ inbox_text_html: "Anything your app sends lands here. Turn on %{live} in the header to watch messages arrive without reloading."
47
52
  no_selection_title: "No message selected"
48
53
  no_selection_text_html: "Pick a message on the left, or send a new one from your app.<br>Use %{keys} to move around and %{search} to search."
49
54
  message:
@@ -12,7 +12,6 @@ pt-BR:
12
12
  shortcuts: "Atalhos"
13
13
  shortcuts_hint: "Atalhos (?)"
14
14
  clear: "Limpar"
15
- clear_confirm: "Apagar todas as mensagens capturadas? Isso não tem volta."
16
15
  clear_filters: "limpar filtros"
17
16
  clear_filters_button: "Limpar filtros"
18
17
  delete: "Apagar"
@@ -23,11 +22,17 @@ pt-BR:
23
22
  open_preview: "Abrir a pré-visualização"
24
23
  allow_remote: "Carregar mesmo assim"
25
24
  close: "Fechar"
25
+ cancel: "Cancelar"
26
+ confirm:
27
+ clear_title: "Apagar todas as mensagens capturadas?"
28
+ clear_body:
29
+ one: "A mensagem é removida do disco. Isso não tem volta."
30
+ other: "As %{count} mensagens são removidas do disco. Isso não tem volta."
31
+ clear_accept: "Apagar tudo"
26
32
  rail:
27
33
  heading: "Caixas"
28
34
  label: "Caixas de e-mail"
29
35
  all: "Todas as mensagens"
30
- empty: "Nenhum destinatário ainda."
31
36
  list:
32
37
  label: "Mensagens"
33
38
  listbox: "Lista de mensagens"
@@ -42,8 +47,8 @@ pt-BR:
42
47
  empty:
43
48
  no_results_title: "Nada encontrado"
44
49
  no_results_text: "Nenhuma mensagem bate com esses filtros."
45
- inbox_title: "Caixa vazia"
46
- inbox_text: "Envie um e-mail pela aplicação e ele aparece aqui."
50
+ inbox_title: "Nenhuma mensagem ainda"
51
+ inbox_text_html: "Tudo que a aplicação enviar cai aqui. Ative %{live} no topo para ver as mensagens chegarem sem recarregar."
47
52
  no_selection_title: "Nenhuma mensagem selecionada"
48
53
  no_selection_text_html: "Escolha uma mensagem à esquerda, ou envie uma nova pela aplicação.<br>Use %{keys} para navegar e %{search} para buscar."
49
54
  message:
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mailscope
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.1'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mailscope
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Renato Ferraz
@@ -76,6 +76,7 @@ files:
76
76
  - app/helpers/mailscope/application_helper.rb
77
77
  - app/views/layouts/mailscope/application.html.erb
78
78
  - app/views/mailscope/messages/_blank_pane.html.erb
79
+ - app/views/mailscope/messages/_confirm.html.erb
79
80
  - app/views/mailscope/messages/_list.html.erb
80
81
  - app/views/mailscope/messages/_list_item.html.erb
81
82
  - app/views/mailscope/messages/_pane.html.erb