[eric] chat: visible fullscreen exit chip, Dictate in the composer menu, dedupe browser status rows, calmer live tool border

This commit is contained in:
ciregenz
2026-07-24 11:57:08 -07:00
parent da0ca09c1a
commit 6952d3d05e
4 changed files with 27 additions and 6 deletions
@@ -7,6 +7,8 @@ import StopIcon from '@mui/icons-material/Stop';
import AttachFileIcon from '@mui/icons-material/AttachFile';
import AdsClickIcon from '@mui/icons-material/AdsClick';
import LanguageIcon from '@mui/icons-material/Language';
import MicNoneOutlinedIcon from '@mui/icons-material/MicNoneOutlined';
import { useVoice } from '@/shared/voice/VoiceDictationContext';
import { useElementSelection } from '@/app/components/editor/ElementSelectionContext';
import { ClaudeTokens } from '@/shared/styles/claudeTokens';
import { ComposerPlusMenu, ActiveTogglePills, PlusMenuItem } from './ComposerPlusMenu';
@@ -49,6 +51,7 @@ export const ToolbarActions: React.FC<Props> = ({
elementSelection.setSelectMode(true);
}
};
const { state: voiceState, toggle: voiceToggle } = useVoice();
const plusItems: PlusMenuItem[] = [];
plusItems.push({
key: 'attach',
@@ -56,6 +59,15 @@ export const ToolbarActions: React.FC<Props> = ({
icon: <AttachFileIcon sx={{ fontSize: 17 }} />,
onSelect: () => generalFileInputRef.current?.click(),
});
// A menu click can't be held, so this entry always toggles regardless of the hold-to-talk setting.
plusItems.push({
key: 'dictate',
label: voiceState === 'recording' ? 'Stop dictation' : 'Dictate',
icon: <MicNoneOutlinedIcon sx={{ fontSize: 17 }} />,
toggle: true,
active: voiceState === 'recording',
onSelect: voiceToggle,
});
if (onToggleWebSearch) {
plusItems.push({
key: 'web',
@@ -219,7 +219,12 @@ const BrowserAgentInlineFeed: React.FC<Props> = ({ parentSessionId, browserId })
const entries: FeedEntry[] = [];
for (const msg of session.messages) {
const entry = formatMessage(msg);
if (entry) entries.push(entry);
if (!entry) continue;
// Retries emit the same status line back-to-back ("Picking up what I learned..." x4); one
// row carries the information, the repeats were pure noise in the transcript.
const prev = entries[entries.length - 1];
if (prev && prev.type === entry.type && prev.text === entry.text) continue;
entries.push(entry);
}
return { session, entries };
});
@@ -80,7 +80,9 @@ export const DefaultToolBubble: React.FC<DefaultToolBubbleProps> = ({
bgcolor: mcpCompact ? 'transparent' : c.bg.elevated,
border: mcpCompact ? 'none' : `1px solid ${
isPending || isStreaming
? c.accent.primary
// Half-strength accent: still clearly "working", but a saturated user accent (greens
// especially) at full strength read as a loud alarm ring around a routine tool call.
? c.accent.primary + '66'
: isDenied
? c.status.error + '60'
: c.border.subtle
@@ -76,10 +76,12 @@ function WindowControls({ onClose, onMinimize, onTile, tiled, fullscreen, noTile
onPointerDown={stop}
sx={{
display: 'flex', alignItems: 'center', justifyContent: 'center',
width: 22, height: 22, p: 0, border: 'none', borderRadius: '6px',
background: 'transparent', color: 'inherit', opacity: 0.65, cursor: 'pointer',
transition: 'opacity 120ms, background 120ms',
'&:hover': { opacity: 1, background: 'rgba(136,136,136,0.18)' },
width: 24, height: 24, p: 0, border: 'none', borderRadius: '7px',
// Neutral chip at rest so it reads on ANY ground (the fullscreen chat wash is dark, the
// browser chrome is light); hover goes explicit white-on-dark so it can never disappear.
background: 'rgba(128,128,128,0.28)', color: 'inherit', opacity: 0.9, cursor: 'pointer',
transition: 'opacity 120ms, background 120ms, color 120ms',
'&:hover': { opacity: 1, background: 'rgba(0,0,0,0.5)', color: '#fff' },
}}
>
<FullscreenExitRoundedIcon sx={{ fontSize: 16 }} />