chat: group chat UI — room tabs, creation flow, member mgmt
Generalises the flyout from peer-only to a thread abstraction
({kind: 'peer'|'room', key, label}). Conversations list and peer
strip render rooms with a group icon alongside 1:1 peers; clicking
either opens the same thread view.
New UI surface:
- Pick view gets a 1:1 / group mode switch. Group mode reveals a
name field + multi-select member list and a Create button.
- Room threads show an info icon in the flyout header that opens a
member list; owners can add/remove members, rename-later, or
delete the room; non-owners can leave.
- 1:1 threads show a disposable toggle (ph-fire) in the header;
flipping it tells the relay to drop future sends after delivery
instead of persisting.
- Group bubbles show the author's username above each message when
it changes, matching common chat UX.
Thread open triggers a backfill fetch so cold caches / second
devices catch up on older history from the relay.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
52da9abd44
commit
9267c7c6a1
3 files changed
+592
-108
No files matched your search
@@ -329,6 +329,144 @@
|
||||
color: var(--t-accent);
|
||||
}
|
||||
|
||||
.chat-pick-row.selected {
|
||||
background: var(--t-raised);
|
||||
color: var(--t-accent);
|
||||
}
|
||||
.chat-pick-row .chat-pick-check {
|
||||
margin-left: auto;
|
||||
color: var(--t-accent);
|
||||
font-size: 12px;
|
||||
}
|
||||
.chat-pick-row:not(.selected) .chat-pick-check { visibility: hidden; }
|
||||
|
||||
/* Picker mode switch (1:1 vs. group). */
|
||||
.chat-pick-mode {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
padding: 6px 10px;
|
||||
border-bottom: 1px solid var(--t-border);
|
||||
background: var(--t-bg);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.chat-pick-mode-btn {
|
||||
flex: 1;
|
||||
padding: 3px 8px;
|
||||
border: 1px solid var(--t-border);
|
||||
background: transparent;
|
||||
color: var(--t-muted);
|
||||
font-family: var(--t-font-pixel);
|
||||
font-size: 10px;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.12s, color 0.12s, background 0.12s;
|
||||
}
|
||||
.chat-pick-mode-btn:hover { color: var(--t-accent); border-color: var(--t-accent); }
|
||||
.chat-pick-mode-btn.active {
|
||||
border-color: var(--t-accent);
|
||||
background: var(--t-accent);
|
||||
color: var(--t-bg);
|
||||
}
|
||||
|
||||
.chat-group-name {
|
||||
margin: 8px 10px 4px;
|
||||
padding: 5px 8px;
|
||||
background: var(--t-surface);
|
||||
border: 1px solid var(--t-border);
|
||||
color: var(--t-bright);
|
||||
font-size: 11px;
|
||||
font-family: var(--t-font-mono, monospace);
|
||||
outline: none;
|
||||
}
|
||||
.chat-group-name:focus { border-color: var(--t-accent); }
|
||||
.chat-group-name.hidden { display: none; }
|
||||
|
||||
.chat-group-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 10px;
|
||||
border-top: 1px solid var(--t-border);
|
||||
background: var(--t-bg);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.chat-group-actions.hidden { display: none; }
|
||||
|
||||
/* Room-info view: member list + owner actions. */
|
||||
#chat-room-info-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid var(--t-border);
|
||||
background: var(--t-bg);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.chat-room-info-body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
.chat-room-info-body .section-label {
|
||||
font-family: var(--t-font-pixel);
|
||||
font-size: 9px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--t-dim);
|
||||
margin-top: 4px;
|
||||
}
|
||||
.chat-room-member-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 11px;
|
||||
color: var(--t-bright);
|
||||
padding: 3px 0;
|
||||
}
|
||||
.chat-room-member-row .owner-badge {
|
||||
font-family: var(--t-font-pixel);
|
||||
font-size: 8px;
|
||||
color: var(--t-accent);
|
||||
background: var(--t-raised);
|
||||
padding: 1px 5px;
|
||||
border: 1px solid var(--t-accent);
|
||||
margin-left: 4px;
|
||||
}
|
||||
.chat-room-info-body .btn {
|
||||
padding: 4px 10px;
|
||||
font-size: 10px;
|
||||
font-family: var(--t-font-pixel);
|
||||
border: 1px solid var(--t-border);
|
||||
background: transparent;
|
||||
color: var(--t-muted);
|
||||
cursor: pointer;
|
||||
transition: all 0.12s;
|
||||
}
|
||||
.chat-room-info-body .btn:hover { border-color: var(--t-accent); color: var(--t-accent); }
|
||||
.chat-room-info-body .btn.danger:hover { border-color: var(--t-danger); color: var(--t-danger); }
|
||||
|
||||
/* Author name above group-thread bubbles. */
|
||||
.chat-bubble-author {
|
||||
font-family: var(--t-font-pixel);
|
||||
font-size: 8px;
|
||||
color: var(--t-dim);
|
||||
margin-top: 4px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
|
||||
/* Peer-tab variant for rooms — group icon instead of initial. */
|
||||
.chat-peer-tab .chat-peer-tab-icon {
|
||||
font-size: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Disposable / info icons in flyout header. */
|
||||
#chat-thread-disposable.active {
|
||||
color: var(--t-accent);
|
||||
}
|
||||
|
||||
/* ── Footer button ── */
|
||||
|
||||
#chat-footer-btn {
|
||||
|
||||
Reference in new issue
Block a user