web: re-instate large bubble-less rendering for short all-emoji messages (#45)
A message whose entire content is up to 3 emoji again renders large with no surrounding bubble (à la Messages). The pure `emojiOnlyCount` helper in format.js and its tests survived the multi-thread rebuild, but the render wiring in fillContent (and the `.jumbo-emoji` CSS, later swept up in the dead-CSS cleanup) had been dropped. This re-wires both: - chat.js: import `emojiOnlyCount`; apply `jumbo-emoji` to a text-only message (no attachments) of 1–3 emoji, so a photo-with-emoji caption keeps its bubble. - style.css: restore the `.bubble.jumbo-emoji` rule (44px, no background/padding). Claude-Session: https://claude.ai/code/session_01QqaTw3kgGRRwSqxHLi9Ram
Co-authored-by: Claude <noreply@anthropic.com>
2 files changed,
+10
−2
web/static/chat.js+7 −2web/static/style.css+3 −0
diff --git a/web/static/chat.js b/web/static/chat.js| index 8d76cc7..c2140f5 100644 |
| --- a/web/static/chat.js |
| +++ b/web/static/chat.js |
| @@ -29,7 +29,7 @@ import { |
| colorScheme, |
| composerToken, |
| } from "/static/ui.js"; |
| -import { richTokens, typingSummary, replySnippet, formatBytes, autoGroupTitle } from "/static/format.js"; |
| +import { richTokens, typingSummary, replySnippet, formatBytes, autoGroupTitle, emojiOnlyCount } from "/static/format.js"; |
| import { emojify, emojiMatches } from "/static/emoji.js"; |
| import { MESSAGE_TYPE_TYPING } from "/static/message.js"; |
| import { qrCanvas } from "/static/qrcode.js"; |
| @@ -1293,7 +1293,12 @@ async function appendMessage(threadId, m, scroll = true) { |
| } |
| if (data.text) { |
| const bubble = document.createElement("div"); |
| - bubble.className = "bubble"; |
| + // A message that's nothing but a few emoji renders large and bubble-less |
| + // (à la Messages). Anything alongside it — an attachment — makes it a |
| + // normal captioned message, so it keeps its bubble. |
| + const hasAttachments = Array.isArray(data.attachments) && data.attachments.length > 0; |
| + const jumbo = !hasAttachments && emojiOnlyCount(data.text) > 0; |
| + bubble.className = jumbo ? "bubble jumbo-emoji" : "bubble"; |
| renderText(bubble, data.text); |
| content.appendChild(bubble); |
| const link = (richTokens(data.text).find((t) => t.href) || {}).href; |
diff --git a/web/static/style.css b/web/static/style.css| index dcf3b17..27e0abd 100644 |
| --- a/web/static/style.css |
| +++ b/web/static/style.css |
| @@ -339,6 +339,9 @@ input:focus, textarea:focus { outline: 2px solid var(--accent); border-color: tr |
| .msg.me .bubble { background: var(--bubble-me); color: var(--bubble-me-ink); border-bottom-right-radius: 6px; } |
| .msg.them .bubble { border-bottom-left-radius: 6px; } |
| .msg .bubble a { color: inherit; text-decoration: underline; text-underline-offset: 2px; } |
| +/* a message of just a few emoji: large and bubble-less, no background or padding (see fillContent) */ |
| +.msg .bubble.jumbo-emoji, |
| +.msg.me .bubble.jumbo-emoji { background: none; color: inherit; padding: 2px 0; font-size: 44px; line-height: 1.15; } |
| /* centered time separator that opens a burst (replaces per-message timestamps) */ |
| .time-sep { |