feat: 底部控制栏添加摄像头/麦克风开关,说话时麦克风脉冲动画

- useVisionSession 新增 isCameraOn/isMicOn 状态 + toggleCamera/toggleMic
- 底部控制栏添加 📷🎤 图标按钮,开启绿色/关闭红色
- 说话时麦克风按钮绿色脉冲缩放动画(micPulse)
- 按钮样式优化:nowrap 防换行,flex-wrap 自适应

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-06-13 20:01:37 +08:00
parent 188782fa66
commit 00f10088d0
3 changed files with 92 additions and 16 deletions

View File

@@ -54,6 +54,10 @@ function App() {
startSession,
stopSession,
interrupt,
isCameraOn,
isMicOn,
toggleCamera,
toggleMic,
} = useVisionSession();
const isConnected = connectionStatus === "connected";
@@ -97,21 +101,6 @@ function App() {
{stats.queryCount} · {stats.totalTokens} tokens
</span>
)}
<div className="lang-group">
{[
{ code: "zh-CN", label: "中文" },
{ code: "en-US", label: "EN" },
{ code: "ja-JP", label: "日" },
].map((l) => (
<button
key={l.code}
className={`lang-btn ${config.language === l.code ? "lang-btn--active" : ""}`}
onClick={() => updateConfig({ language: l.code })}
>
{l.label}
</button>
))}
</div>
<span className={`badge badge--${connectionStatus}`}>
{isConnected ? "已连接" : connectionStatus === "connecting" ? "连接中..." : "未连接"}
</span>
@@ -186,6 +175,20 @@ function App() {
</button>
) : (
<div className="video-controls__row">
<button
className={`btn btn--ctrl ${isCameraOn ? "btn--ctrl-on" : "btn--ctrl-off"}`}
onClick={toggleCamera}
title={isCameraOn ? "关闭摄像头" : "开启摄像头"}
>
📷
</button>
<button
className={`btn btn--ctrl ${isMicOn ? "btn--ctrl-on" : "btn--ctrl-off"} ${isSpeaking ? "btn--speaking" : ""}`}
onClick={toggleMic}
title={isMicOn ? "关闭麦克风" : "开启麦克风"}
>
🎤
</button>
<button
className={`btn ${mode === "observation" ? "btn--active" : "btn--secondary"}`}
onClick={toggleMode}