Skip to content

Commit 26f70c2

Browse files
ralyodioclaude
andcommitted
feat(ai-sidebar): highlight channels with unread IRC activity (v3.6.1)
Channels (and the status window) in the sidebar now highlight when a new message arrives while you're not viewing them, and clear when you click in: - bold name + cyan dot for any unread activity - stronger red dot + bold-cyan name for a DM or a mention of your nick - selecting a channel clears its highlight Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent c1e3ffe commit 26f70c2

27 files changed

Lines changed: 50 additions & 29 deletions

File tree

apps/desktop/extensions/ai-sidebar/chat.css

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,13 @@ a { color:var(--cyan); }
3939
border-bottom:1px solid var(--line); font-size:12px; color:var(--green); }
4040
.chans-head button { background:transparent; border:1px solid var(--line); color:var(--muted); border-radius:6px; cursor:pointer; }
4141
#chan-list { list-style:none; margin:0; padding:6px; overflow-y:auto; flex:1; }
42-
#chan-list li { padding:6px 10px; border-radius:6px; cursor:pointer; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
42+
#chan-list li { display:flex; align-items:center; gap:6px; padding:6px 10px; border-radius:6px; cursor:pointer; }
43+
#chan-list li .name { flex:1; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
4344
#chan-list li.active { background:#0b1530; color:var(--cyan); }
44-
#chan-list li .unread { color:var(--cyan); float:right; }
45+
#chan-list li.unread .name { color:var(--fg); font-weight:600; }
46+
#chan-list li.mention .name { color:var(--cyan); font-weight:700; }
47+
#chan-list li .dot { flex:none; width:8px; height:8px; border-radius:50%; background:var(--cyan); }
48+
#chan-list li.mention .dot { background:#ff5d73; box-shadow:0 0 6px #ff5d73; }
4549
.join { padding:8px; border-top:1px solid var(--line); }
4650
.join input { width:100%; background:#04060c; color:var(--fg); border:1px solid var(--line); border-radius:6px; padding:6px; font:inherit; }
4751

apps/desktop/extensions/ai-sidebar/chat.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ const STATUS = '✻ status'; // server/system window (always present, pinned fir
2727
const irc = new IrcClient();
2828
const buffers = new Map(); // channel -> [{from,text,time,...}]
2929
let active = null;
30+
const unread = new Set(); // channels/status with new activity since last viewed
31+
const mentions = new Set(); // subset: a DM or a mention of our nick (stronger highlight)
3032

3133
function logStatus(text) { appendMsg({ channel: STATUS, sys: true, text, time: Date.now() }); }
3234

@@ -39,14 +41,21 @@ function ensureBuffer(chan) {
3941
function renderChanList() {
4042
const ul = $('chan-list'); ul.innerHTML = '';
4143
for (const chan of buffers.keys()) {
42-
const li = el('li', chan === active ? 'active' : '', chan);
44+
let cls = 'chan';
45+
if (chan === active) cls += ' active';
46+
else if (mentions.has(chan)) cls += ' unread mention';
47+
else if (unread.has(chan)) cls += ' unread';
48+
const li = el('li', cls);
49+
li.append(el('span', 'name', chan));
50+
if (chan !== active && (unread.has(chan) || mentions.has(chan))) li.append(el('span', 'dot'));
4351
li.addEventListener('click', () => selectChannel(chan));
4452
ul.appendChild(li);
4553
}
4654
}
4755

4856
function selectChannel(chan) {
4957
active = chan;
58+
unread.delete(chan); mentions.delete(chan); // viewing it clears the highlight
5059
$('chan-title').textContent = chan;
5160
renderChanList();
5261
const m = $('msgs'); m.innerHTML = '';
@@ -56,7 +65,15 @@ function selectChannel(chan) {
5665
}
5766

5867
function appendMsg(line, store = true) {
59-
if (store) { ensureBuffer(line.channel); buffers.get(line.channel).push(line); }
68+
if (store) {
69+
ensureBuffer(line.channel);
70+
buffers.get(line.channel).push(line);
71+
if (line.channel && line.channel !== active) {
72+
unread.add(line.channel);
73+
if (!line.sys && (isDM(line) || isMention(line))) mentions.add(line.channel);
74+
renderChanList();
75+
}
76+
}
6077
if (line.channel !== active) return;
6178
const m = $('msgs');
6279
const div = el('div', 'msg' + (line.sys ? ' sys' : '') + (line.self ? ' self' : '') + (line.notice ? ' notice' : ''));

apps/desktop/extensions/ai-sidebar/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"manifest_version": 3,
33
"name": "TronBrowser",
4-
"version": "3.6.0",
4+
"version": "3.6.1",
55
"description": "TronBrowser — privacy-first, AI-native. Branded new tab, private search, CoinPay login, and a bring-your-own-keys AI sidebar.",
66
"icons": {
77
"16": "icons/icon-16.png",

apps/desktop/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tronbrowser/desktop",
3-
"version": "3.6.0",
3+
"version": "3.6.1",
44
"private": true,
55
"description": "Desktop shell for the TronBrowser Chromium fork",
66
"type": "module",

apps/docs/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tronbrowser/docs",
3-
"version": "3.6.0",
3+
"version": "3.6.1",
44
"private": true,
55
"description": "Documentation site",
66
"type": "module",

apps/extensions/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tronbrowser/extensions",
3-
"version": "3.6.0",
3+
"version": "3.6.1",
44
"private": true,
55
"description": "TronBrowser extension store — pay $1, list your MV3 extension (tronbrowser.dev/store)",
66
"type": "module",

apps/mobile/app.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"slug": "tronbrowserdev",
55
"owner": "profullstack",
66
"scheme": "tronbrowser",
7-
"version": "3.6.0",
7+
"version": "3.6.1",
88
"orientation": "portrait",
99
"userInterfaceStyle": "dark",
1010
"platforms": [

apps/mobile/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tronbrowser/mobile",
3-
"version": "3.6.0",
3+
"version": "3.6.1",
44
"private": true,
55
"description": "TronBrowser mobile (Expo / React Native) — Phase 2",
66
"type": "module",

apps/web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tronbrowser/web",
3-
"version": "3.6.0",
3+
"version": "3.6.1",
44
"private": true,
55
"description": "TronBrowser marketing site + web dashboard",
66
"type": "module",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tronbrowser",
3-
"version": "3.6.0",
3+
"version": "3.6.1",
44
"private": true,
55
"description": "TronBrowser.dev — open-source, privacy-first, AI-native browser",
66
"packageManager": "pnpm@9.12.0",

0 commit comments

Comments
 (0)