Files
hyprcrd/public/plugins/chat/chat.css
T
thandClaude Opus 4.6 81d9ce0e87 chat: peer-switch strip, back button moved to flyout header
Switching conversations used to require bouncing back to the list view
and picking from there. Now the thread view has a horizontal peer
strip at the top: one click hops to another conversation, active tab
is highlighted and auto-scrolls into view, unread peers show a dot.
Scrollbar is hidden — vertical wheel delta is redirected to horizontal
scroll so the user can slide the strip with the mouse wheel when it
overflows.

In-thread header is gone; the back button moved next to "chat" in the
flyout header and only shows while a thread is open. Peer name stays
visible via the active tab.

Bumps to 1.9.3.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 19:30:38 +02:00

402 lines
8.7 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ── Chat plugin styles ── */
#chat-flyout {
position: fixed;
bottom: 48px;
right: 16px;
width: 340px;
height: 460px;
max-height: calc(100vh - 100px);
background: var(--t-surface);
border: 1px solid var(--t-border);
border-radius: var(--ui-radius-modal);
box-shadow: var(--ui-shadow-modal);
z-index: 100;
display: flex;
flex-direction: column;
overflow: hidden;
}
#chat-flyout.hidden { display: none; }
#chat-flyout-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-view {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
}
.chat-view.hidden { display: none; }
/* ── Conversation list ── */
.chat-list {
flex: 1;
overflow-y: auto;
}
/* When empty, collapse so the `.chat-empty` placeholder can fill and center
properly instead of being pushed into the lower half of the view. */
.chat-list:empty {
flex: 0 0 0;
display: none;
}
.chat-list-row {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
border-bottom: 1px solid var(--t-border);
cursor: pointer;
transition: background 0.1s;
}
.chat-list-row:hover {
background: var(--t-raised);
}
.chat-list-row .chat-list-avatar {
width: 28px;
height: 28px;
border-radius: 50%;
background: var(--t-raised);
display: flex;
align-items: center;
justify-content: center;
color: var(--t-accent);
flex-shrink: 0;
}
.chat-list-row .chat-list-info {
flex: 1;
min-width: 0;
}
.chat-list-row .chat-list-peer {
font-family: var(--t-font-pixel);
font-size: 10px;
color: var(--t-bright);
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 6px;
}
.chat-list-row .chat-list-time {
font-size: 9px;
color: var(--t-dim);
flex-shrink: 0;
}
.chat-list-row .chat-list-preview {
font-size: 10px;
color: var(--t-muted);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-top: 2px;
}
.chat-list-row .chat-list-preview.outgoing::before {
content: "› ";
color: var(--t-dim);
}
.chat-list-row .chat-unread-badge {
background: var(--t-accent);
color: var(--t-bg);
font-family: var(--t-font-pixel);
font-size: 9px;
padding: 1px 5px;
border-radius: 8px;
flex-shrink: 0;
}
.chat-empty {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 24px;
user-select: none;
-webkit-user-select: none;
}
.chat-empty > p {
margin: 0;
}
#chat-empty-start {
margin-top: 20px;
}
/* ── Thread view ── */
/* Horizontal peer strip above the thread header. Lets the user hop
between conversations without bouncing back to the list. Scrollbar
hidden — wheel-over scrolls horizontally (see chat.js). */
.chat-thread-peers {
display: flex;
gap: 5px;
padding: 6px 8px;
border-bottom: 1px solid var(--t-border);
background: var(--t-bg);
overflow-x: auto;
overflow-y: hidden;
flex-shrink: 0;
scrollbar-width: none;
-ms-overflow-style: none;
}
.chat-thread-peers::-webkit-scrollbar { display: none; }
.chat-thread-peers:empty { display: none; }
.chat-peer-tab {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 3px 8px;
border: 1px solid var(--t-border);
border-radius: var(--ui-radius-button, 3px);
background: var(--t-surface);
color: var(--t-muted);
font-family: var(--t-font-pixel);
font-size: 10px;
cursor: pointer;
flex-shrink: 0;
white-space: nowrap;
transition: border-color 0.12s, color 0.12s, background 0.12s;
position: relative;
}
.chat-peer-tab:hover {
border-color: var(--t-accent);
color: var(--t-accent);
}
.chat-peer-tab.active {
border-color: var(--t-accent);
background: var(--t-accent);
color: var(--t-bg);
}
.chat-peer-tab .chat-peer-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--t-accent);
flex-shrink: 0;
}
.chat-peer-tab.active .chat-peer-dot { background: var(--t-bg); }
.chat-thread-messages {
flex: 1;
overflow-y: auto;
padding: 12px;
display: flex;
flex-direction: column;
gap: 6px;
}
.chat-bubble {
max-width: 80%;
padding: 6px 10px;
font-size: 11px;
font-family: var(--t-font-mono, monospace);
word-wrap: break-word;
white-space: pre-wrap;
line-height: 1.4;
border: 1px solid var(--t-border);
/* Pick up the user's card-radius design token so chat bubbles look
consistent with the rest of the surface (sharp / rounded / pill). */
border-radius: var(--ui-radius-card, 0px);
}
.chat-bubble.in {
align-self: flex-start;
background: var(--t-raised);
color: var(--t-bright);
border-top-left-radius: 0;
}
.chat-bubble.out {
align-self: flex-end;
background: var(--t-accent);
color: var(--t-bg);
border-color: var(--t-accent);
border-top-right-radius: 0;
}
.chat-bubble-time {
font-size: 8px;
color: var(--t-dim);
margin-top: 2px;
font-family: var(--t-font-pixel);
display: flex;
align-items: center;
gap: 4px;
}
.chat-bubble.out + .chat-bubble-time { align-self: flex-end; }
.chat-bubble.in + .chat-bubble-time { align-self: flex-start; }
/* Read receipts: clock = sent (relay not yet acked), single check =
delivered (recipient polled), double check = seen (recipient opened
the thread). Single/double share the same icon size as the timestamp. */
.chat-receipt {
font-size: 11px;
line-height: 1;
}
.chat-receipt.pending { color: var(--t-dim); }
.chat-receipt.delivered { color: var(--t-muted); }
.chat-receipt.seen { color: var(--t-accent); }
#chat-thread-form {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 10px;
border-top: 1px solid var(--t-border);
background: var(--t-bg);
flex-shrink: 0;
}
#chat-thread-input {
flex: 1;
background: var(--t-surface);
border: 1px solid var(--t-border);
color: var(--t-bright);
padding: 6px 10px;
font-size: 11px;
font-family: var(--t-font-mono, monospace);
outline: none;
}
#chat-thread-input:focus {
border-color: var(--t-accent);
}
#chat-thread-send {
background: none;
border: none;
cursor: pointer;
padding: 4px 6px;
}
#chat-thread-send:disabled {
opacity: 0.3;
cursor: not-allowed;
}
/* ── Pick recipient view ── */
#chat-pick-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-pick-list {
flex: 1;
overflow-y: auto;
}
.chat-pick-row {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
border-bottom: 1px solid var(--t-border);
cursor: pointer;
font-family: var(--t-font-pixel);
font-size: 10px;
color: var(--t-bright);
transition: background 0.1s;
}
.chat-pick-row:hover {
background: var(--t-raised);
color: var(--t-accent);
}
/* ── Footer button ── */
#chat-footer-btn {
display: flex;
align-items: center;
gap: 6px;
padding: 4px 10px;
font-size: 12px;
border: 1px solid var(--t-border);
border-radius: var(--ui-radius-button);
color: var(--t-muted);
background: transparent;
cursor: pointer;
transition: all 0.15s;
position: relative;
}
#chat-footer-btn:hover {
border-color: var(--t-accent);
color: var(--t-accent);
}
#chat-footer-btn .chat-footer-label {
font-family: var(--t-font-pixel);
font-size: 10px;
}
#chat-footer-btn.has-unread {
border-color: var(--t-accent);
color: var(--t-accent);
}
#chat-footer-btn .chat-unread-dot {
position: absolute;
top: -3px;
right: -3px;
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--t-accent);
display: none;
}
#chat-footer-btn.has-unread .chat-unread-dot {
display: block;
}
@keyframes chatBlink {
0%, 100% {
border-color: var(--t-accent);
color: var(--t-accent);
box-shadow: 0 0 0 0 var(--t-accent);
}
50% {
border-color: var(--t-accent);
color: var(--t-bright);
box-shadow: 0 0 8px 1px var(--t-accent);
}
}
#chat-footer-btn.blinking {
animation: chatBlink 1.2s ease-in-out infinite;
}
/* Ignore the global anim-speed override — the unread blink has a
deliberate cadence that becomes an unreadable strobe when sped up. */
body.anim-fast #chat-footer-btn.blinking,
body.anim-slow #chat-footer-btn.blinking {
animation: chatBlink 1.2s ease-in-out infinite !important;
animation-duration: 1.2s !important;
}