@devchitchat/chat 4.1.2 → 4.2.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devchitchat/chat",
3
- "version": "4.1.2",
3
+ "version": "4.2.1",
4
4
  "description": "A small chat app. p2p video and screenshare.",
5
5
  "scripts": {
6
6
  "dev": "bun --watch index.js",
@@ -165,6 +165,9 @@ export default function CallIsland(root) {
165
165
  if (!article.querySelector('.message-hover-actions')) {
166
166
  const toolbar = document.createElement('div')
167
167
  toolbar.className = 'message-hover-actions'
168
+ const quickPicks = document.createElement('span')
169
+ quickPicks.className = 'quick-picks'
170
+ toolbar.appendChild(quickPicks)
168
171
  const reactBtn = document.createElement('button')
169
172
  reactBtn.className = 'btn-react btn-icon'
170
173
  reactBtn.type = 'button'
@@ -181,6 +184,7 @@ export default function CallIsland(root) {
181
184
  toolbar.appendChild(actionsBtn)
182
185
  }
183
186
  article.appendChild(toolbar)
187
+ renderQuickPicks(toolbar)
184
188
  }
185
189
 
186
190
  // Apply inline rendering (URLs, @mentions) to server-rendered message text.
@@ -695,6 +699,8 @@ export default function CallIsland(root) {
695
699
  }
696
700
 
697
701
  enableTaskCheckboxes(article)
702
+ const toolbar = article.querySelector('.message-hover-actions')
703
+ if (toolbar) renderQuickPicks(toolbar)
698
704
  messages.appendChild(article)
699
705
  renderReactionBar(article, reactions ?? [], msg_id)
700
706
  messages.scrollTop = messages.scrollHeight
@@ -736,6 +742,22 @@ export default function CallIsland(root) {
736
742
  recents.unshift(emoji)
737
743
  if (recents.length > RECENT_MAX) recents = recents.slice(0, RECENT_MAX)
738
744
  localStorage.setItem(RECENT_KEY, JSON.stringify(recents))
745
+ refreshAllQuickPicks()
746
+ }
747
+
748
+ function renderQuickPicks(toolbar) {
749
+ const slot = toolbar.querySelector('.quick-picks')
750
+ if (!slot) return
751
+ const recents = loadRecentEmoji().slice(0, 4)
752
+ slot.innerHTML = recents.map(emoji =>
753
+ `<button class="btn-quick-react btn-icon" data-emoji="${escHtml(emoji)}" type="button" title="${escHtml(emoji)}">${emoji}</button>`
754
+ ).join('')
755
+ }
756
+
757
+ function refreshAllQuickPicks() {
758
+ for (const toolbar of messages.querySelectorAll('.message-hover-actions')) {
759
+ renderQuickPicks(toolbar)
760
+ }
739
761
  }
740
762
 
741
763
  let emojiPickerEl = null
@@ -913,6 +935,18 @@ export default function CallIsland(root) {
913
935
  ws.send({ t: 'msg.edit', body: { msg_id: article.dataset.msgId, channel_id: channelId, text: newText } })
914
936
  })
915
937
 
938
+ // Delegated click on .btn-quick-react — send reaction without opening picker
939
+ messages.addEventListener('click', e => {
940
+ const btn = e.target.closest('.btn-quick-react')
941
+ if (!btn) return
942
+ e.stopPropagation()
943
+ const emoji = btn.dataset.emoji
944
+ const msgId = btn.closest('article.message')?.dataset.msgId
945
+ if (!emoji || !msgId) return
946
+ saveRecentEmoji(emoji)
947
+ ws.send({ t: 'reaction.add', body: { msg_id: msgId, channel_id: channelId, emoji } })
948
+ })
949
+
916
950
  // Delegated click on .reaction-pill — toggle reaction
917
951
  messages.addEventListener('click', e => {
918
952
  const pill = e.target.closest('.reaction-pill')
@@ -134,7 +134,7 @@ export function makeMessageEl({ msg_id, seq, user_id, user_display_name, ts, tex
134
134
  const isSelf = userId != null && user_id === userId
135
135
  const attachmentHtml = (attachments ?? []).map(a => renderAttachment(a)).join('')
136
136
  const editedHtml = edited_at ? '<span class="message-edited">(edited)</span>' : ''
137
- const actionsHtml = `<div class="message-hover-actions"><button class="btn-react btn-icon" type="button" title="Add reaction" aria-label="Add reaction">🙂</button>${isSelf ? '<button class="btn-msg-actions btn-icon" type="button" title="Message actions">…</button>' : ''}</div>`
137
+ const actionsHtml = `<div class="message-hover-actions"><span class="quick-picks"></span><button class="btn-react btn-icon" type="button" title="Add reaction" aria-label="Add reaction">🙂</button>${isSelf ? '<button class="btn-msg-actions btn-icon" type="button" title="Message actions">…</button>' : ''}</div>`
138
138
  const textHtml = rendered_text ?? (text ? renderText(text, { userHandle }) : '')
139
139
  article.innerHTML = `
140
140
  <span class="message-handle${isSelf ? '' : ' dm-trigger'}" data-user-id="${escHtml(user_id)}" title="${isSelf ? '' : 'Send a direct message'}">${escHtml(user_display_name ?? user_id)}</span>
@@ -499,7 +499,10 @@ details summary {
499
499
  font-size: 1rem;
500
500
  margin-bottom: 7px;
501
501
  }
502
- .chat-topic { color: var(--text-secondary); }
502
+ .chat-topic {
503
+ color: var(--text-secondary);
504
+ display: none; /* don't show this for now.*/
505
+ }
503
506
  .chat-header-actions { margin-left: auto; display: flex; gap: 6px; }
504
507
 
505
508
  .search-bar { padding: 8px 20px; background: var(--bg-topbar); border-bottom: 1px solid var(--border); }
@@ -848,8 +851,11 @@ details summary {
848
851
  }
849
852
  .btn-primary:hover { opacity: 0.85; }
850
853
  .btn-ghost {
851
- background: none; border: none; padding: 6px 12px; border-radius: var(--radius-sm);
852
- color: var(--text-muted); cursor: pointer;
854
+ border: none;
855
+ padding: 6px 12px;
856
+ border-radius: var(--radius-sm);
857
+ color: var(--text-muted);
858
+ cursor: pointer;
853
859
  }
854
860
  .btn-ghost:hover { background: var(--bg-hover); color: var(--text-primary); }
855
861
  .btn-icon {
@@ -1508,7 +1514,6 @@ body:has(.admin-topbar) main {
1508
1514
  border: 1px solid var(--border);
1509
1515
  border-radius: 6px;
1510
1516
  margin-bottom: 8px;
1511
- overflow: hidden;
1512
1517
  }
1513
1518
 
1514
1519
  .hub-group__summary {
@@ -1803,6 +1808,9 @@ article.message { position: relative; }
1803
1808
  z-index: 10;
1804
1809
  }
1805
1810
  article.message:hover .message-hover-actions { opacity: 1; pointer-events: auto; }
1811
+ .quick-picks { display: contents; }
1812
+ .quick-picks:not(:empty) + .btn-react { border-left: 1px solid var(--border); margin-left: 1px; padding-left: 6px; }
1813
+ .btn-quick-react,
1806
1814
  .btn-react,
1807
1815
  .btn-msg-actions {
1808
1816
  background: none;
@@ -1815,6 +1823,7 @@ article.message:hover .message-hover-actions { opacity: 1; pointer-events: auto;
1815
1823
  color: var(--text-secondary);
1816
1824
  transition: background var(--transition), color var(--transition);
1817
1825
  }
1826
+ .btn-quick-react:hover,
1818
1827
  .btn-react:hover,
1819
1828
  .btn-msg-actions:hover {
1820
1829
  background: color-mix(in srgb, var(--accent) 15%, transparent);