- chat
-
+
+
diff --git a/public/plugins/chat/chat.js b/public/plugins/chat/chat.js
index 5a778c3..0e264aa 100644
--- a/public/plugins/chat/chat.js
+++ b/public/plugins/chat/chat.js
@@ -179,11 +179,18 @@ function hideAllViews() {
.forEach(id => $(id)?.classList.add('hidden'));
}
+// Toggle the caret + make the "chat" trigger look/feel clickable only
+// when there's actually somewhere to go back to.
+function setNavState(canBack) {
+ $('chat-header-back-caret')?.classList.toggle('hidden', !canBack);
+ $('chat-header-nav')?.classList.toggle('navigable', canBack);
+}
+
function showListView() {
hideAllViews();
$('chat-list-view').classList.remove('hidden');
$('chat-flyout-title').textContent = 'chat';
- $('chat-header-back')?.classList.add('hidden');
+ setNavState(false);
$('chat-thread-disposable')?.classList.add('hidden');
$('chat-thread-info')?.classList.add('hidden');
currentThread = null;
@@ -193,7 +200,7 @@ function showThreadView(thread) {
hideAllViews();
$('chat-thread-view').classList.remove('hidden');
$('chat-flyout-title').textContent = 'chat';
- $('chat-header-back')?.classList.remove('hidden');
+ setNavState(true);
currentThread = thread;
// Room-only: info icon. 1:1-only: disposable icon.
$('chat-thread-info')?.classList.toggle('hidden', thread.kind !== 'room');
@@ -205,7 +212,7 @@ function showThreadView(thread) {
function showPickView() {
hideAllViews();
$('chat-pick-view').classList.remove('hidden');
- $('chat-header-back')?.classList.add('hidden');
+ setNavState(false);
$('chat-thread-disposable')?.classList.add('hidden');
$('chat-thread-info')?.classList.add('hidden');
}
@@ -213,7 +220,7 @@ function showPickView() {
function showRoomInfoView() {
hideAllViews();
$('chat-room-info-view').classList.remove('hidden');
- $('chat-header-back')?.classList.add('hidden');
+ setNavState(false);
$('chat-thread-disposable')?.classList.add('hidden');
$('chat-thread-info')?.classList.add('hidden');
}
@@ -749,12 +756,14 @@ function init() {
$('chat-refresh-btn').addEventListener('click', () => pollOnce().then(loadConversations));
$('chat-new-btn').addEventListener('click', openPickView);
$('chat-empty-start')?.addEventListener('click', openPickView);
- const gotoList = () => { showListView(); loadConversations(); };
- $('chat-header-back').addEventListener('click', gotoList);
- // Clicking the "chat" title is the same as hitting the back caret —
- // a second affordance so users don't have to aim at a small icon.
- // No-op when already on the list (showListView is idempotent).
- $('chat-flyout-title')?.addEventListener('click', gotoList);
+ // Caret + "chat" label are one button with one tooltip. Click is a
+ // no-op when the caret is hidden (already on the list) — the CSS
+ // .navigable class tracks whether the button looks clickable.
+ $('chat-header-nav')?.addEventListener('click', () => {
+ if (!$('chat-header-nav')?.classList.contains('navigable')) return;
+ showListView();
+ loadConversations();
+ });
$('chat-pick-back').addEventListener('click', showListView);
$('chat-thread-form').addEventListener('submit', sendMessage);
$('chat-thread-info')?.addEventListener('click', openRoomInfo);
diff --git a/public/plugins/tests/chat.test.js b/public/plugins/tests/chat.test.js
index fa44953..7e9498a 100644
--- a/public/plugins/tests/chat.test.js
+++ b/public/plugins/tests/chat.test.js
@@ -30,20 +30,20 @@ describe('Chat: flyout', () => {
expect(f.classList.contains('hidden')).toBe(true);
});
- it('header-back visibility matches active view', async () => {
+ it('header back-caret visibility matches active view', async () => {
await ensureFlyoutClosed();
click('#chat-footer-btn');
await waitFor(() => !$('#chat-flyout').classList.contains('hidden'));
// Wait for loadConversations + initial view pick to settle.
await sleep(150);
- const back = $('#chat-header-back');
+ const caret = $('#chat-header-back-caret');
const threadShown = !$('#chat-thread-view').classList.contains('hidden');
const listShown = !$('#chat-list-view').classList.contains('hidden');
// Exactly one of thread / list should be active here (pick view
// is only reached via the + button).
expect(threadShown || listShown).toBe(true);
- if (threadShown) expect(back.classList.contains('hidden')).toBe(false);
- if (listShown) expect(back.classList.contains('hidden')).toBe(true);
+ if (threadShown) expect(caret.classList.contains('hidden')).toBe(false);
+ if (listShown) expect(caret.classList.contains('hidden')).toBe(true);
await ensureFlyoutClosed();
});
@@ -57,9 +57,9 @@ describe('Chat: flyout', () => {
expect($('#chat-pick-view').classList.contains('hidden')).toBe(false);
expect($('#chat-list-view').classList.contains('hidden')).toBe(true);
expect($('#chat-thread-view').classList.contains('hidden')).toBe(true);
- // Header back is only for thread view — not needed when pick has
+ // Back caret is only for thread view — not needed when pick has
// its own dedicated back button.
- expect($('#chat-header-back').classList.contains('hidden')).toBe(true);
+ expect($('#chat-header-back-caret').classList.contains('hidden')).toBe(true);
click('#chat-pick-back');
await sleep(50);
expect($('#chat-pick-view').classList.contains('hidden')).toBe(true);