feat(composer): add emoji picker and browser mic STT to composer toolbar#77
Open
adroidian wants to merge 3 commits into
Open
feat(composer): add emoji picker and browser mic STT to composer toolbar#77adroidian wants to merge 3 commits into
adroidian wants to merge 3 commits into
Conversation
Add two new buttons to the onscreen agent composer toolbar (full mode only): **Emoji picker** - Smiley face button opens a popover with 90+ emoji across 7 categories - Picker is positioned via the existing positionPopover() utility, matching the composerActionMenu pattern (anchor-aware, top/end alignment) - Emoji inserts at cursor position with correct UTF-16 cursor advancement - Teleported to body via x-teleport to escape stacking contexts - Closes on outside click, Escape, or after insertion - Button shows active state while picker is open **Browser mic / STT** - Mic button uses the Web Speech API (webkitSpeechRecognition / SpeechRecognition) - Button hidden automatically when the API is not available (Firefox, etc.) - Click to start, auto-stops after speech pause; click again to cancel - Transcript appended to draft with smart spacing - Pulsing red animation while recording **Implementation notes** - All state lives in the Alpine store (model object): emojiPickerAnchor, emojiPickerPosition, isEmojiPickerVisible, isRecording, sttSupported, _sttRecognition - No external dependencies; CSS uses existing space design tokens with sensible hard-coded fallbacks - Tested in Chrome (full functionality) and Firefox (emoji only, mic button correctly hidden); Brave blocks the STT network request by default
Author
|
Heads up: this was written with AI assistance, but I personally tested it on our own deployment and verified the behavior described. Sharing in the spirit of transparency given how many repos are thinking about this. |
The composer uses display:grid with align-items:stretch, so the input-wrap grows taller than the textarea when action buttons are tall. Clicks in the dead zone below the textarea were swallowed. Adds @click.self on the input-wrap to forward those clicks to the textarea, and cursor:text in CSS to match.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
Two new buttons in the onscreen agent composer toolbar, visible in full mode only:
😊 Emoji picker
positionPopover()utility with{ align: 'end', placement: 'top' }— same pattern as the composer action menuemoji.length, not[...emoji].length) so stacking multiple emoji works correctlybodyviax-teleportto escape stacking contexts🎤 Browser mic / STT
webkitSpeechRecognition/SpeechRecognition)Implementation notes
State — all lives in the Alpine store
modelobject, no new top-level globals:emojiPickerAnchor,emojiPickerPosition,isEmojiPickerVisible— picker positioningisRecording,sttSupported,_sttRecognition— mic stateNo external dependencies. CSS uses existing space design tokens (
--space-danger,--space-accent,--space-surface-2,--space-border,--space-popover-z) with hard-coded fallbacks for themes that don't define them.STT note:
webkitSpeechRecognitionstreams audio to Google's cloud STT service and requires network access tospeech.googleapis.com. Users behind strict firewalls or using privacy-focused browsers (Brave with default settings) may not be able to use the mic feature — the emoji picker is unaffected.Bug fix bundled with this PR
While adding the mic button (which made the composer actions column taller), we noticed clicks in the dead zone below the textarea were being swallowed. Root cause: the composer uses
display:gridwithalign-items:stretch, so.onscreen-agent-composer-input-wrapgrows taller than the single-row textarea. Two-line fix:@click.self="$refs.input.focus()"on the input-wrap forwards dead-zone clicks to the textareacursor:texton the input-wrap so the dead zone looks interactiveFiles changed
store.jsisEmojiPickerOpen,emojiPickerStyle,emojiList), 7 methodspanel.htmlonscreen-agent.cssTesting
Tested in:
networkerror due to Brave blockingspeech.googleapis.com