- Each input now has a sibling .email-field-prefix span (To / Cc /
Bcc / Subject) absolute-positioned at the left edge in the
accent color. Inputs get padding-left:44px (64px for Subject)
so typed text doesn't slide under the prefix.
- Placeholders shrink back to just the example so only the
prefix gets the accent color, not the example text.
- Cc toggle moved another 2px up (calc(50% + 4px) → calc(50% + 2px)).
- Removed the <label>To/Cc/Bcc/Subject</label> elements — they
doubled what the placeholder said.
- Placeholders now carry both the field name AND an example so an
empty input still tells the user what to type:
To recipient@example.com
Cc cc@example.com, example2
Bcc bcc@example.com
Subject
Adds a per-field X (24x24 SVG, opacity 0.4 → 1 + accent on hover)
absolute-positioned at the right edge of each Cc/Bcc field. Click
hides both rows, clears their inputs, and restores the Cc opener
on the To row. Inputs get padding-right:32px so the close button
doesn't overlap typed text.
The document editor stores the AI-edit diff state (_diffModeActive,
_diffOldContent, _diffNewContent, _diffChunks) as a module-global
singleton bound to whatever document was active when the diff opened,
and every document shares one #doc-editor-textarea. When the active
document is switched while an unapproved diff is open, the stale diff
must be discarded first or a later exitDiffMode (tab switch /
Accept-Reject-All) flushes the old document's content into the new
active document and overwrites it (issue #2467).
Guard both paths that switch the active document for an AI update,
while activeDocId still points at the previously-active doc:
- handleDocUpdate(): a doc_update targeting a different document.
- streamDocOpen(): the AI streaming a NEW document — this runs first on
that path, so a guard only in handleDocUpdate would fire too late and
still overwrite the streamed document.
Both reuse the exact `if (_diffModeActive) exitDiffMode(true);` guard
switchToDoc() and enterDiffMode() already use.
Fixes#2467
* fix: prevent document link click from resetting active session
Clicking a #document-<uuid> link in chat caused the session to reset
because of two issues:
1. chatRenderer.js: clicking on the text inside an <a> yields a Text
node target whose .closest() is undefined, so preventDefault never
fires and the browser performs a default hash-navigation
2. sessions.js: the hashchange handler treated the entity hash
(document-<uuid>) as a session lookup, found no match, and the
subsequent loadSessions created a new default-model chat
Fix: walk past Text nodes before calling .closest(), and skip
entity-prefixed hashes in the hashchange handler.
Fixes#2035
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(documents): move isOpen=true after container check in openPanel
isOpen was set to true before the #chat-container existence check.
If the container was missing during a race, the function returned
early but isOpen stayed true, preventing the panel from ever
reopening on subsequent calls.
Move isOpen=true to after the container guard so a failed open
doesn't leave the flag stuck.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Chat models often emit GitHub/Slack-style :shortcode: text (e.g. 😊,
🎤) instead of the actual emoji. The renderer only converted real
Unicode emoji to the monochrome line icons, so shortcodes rendered as literal
text.
Add a pure, browser-free shortcode->Unicode map (emojiShortcodes.js) and run it
inside svgifyEmoji ahead of the existing Unicode->SVG pass, skipping <code>/<pre>
so code stays literal. Covers ~430 common shortcodes plus common aliases
(+1/thumbsup, etc.).
Keep the conversion from touching anything it shouldn't:
* Scope it to chat. mdToHtml/svgifyEmoji take a { shortcodes } option (default
on); document and email body rendering (compose, export, preview) pass it as
false so author-typed :shortcode: text stays literal. The Unicode->SVG pass
still runs there exactly as before.
* Only convert a :shortcode: that stands on its own. A word-boundary guard
leaves embedded colon runs alone, so "1:100:2", "10:30:45", "16:9" and
host:fire:port are never rewritten.
Tests: extend the node-driven unit test with the boundary/false-positive cases,
and fix the markdown-rendering test loader to resolve the new emojiShortcodes
import.
Add a hashchange handler for #document-<id> so refresh / URL-bar nav opens the document, and replace the silent console.error in loadDocument with a user-facing toast.
Closes#560