2026-02-28 20:42:40 +00:00
import { useShallow } from "zustand/react/shallow" ;
2026-02-27 04:29:51 +00:00
import { useAppState } from "../../store/appState" ;
2026-06-28 19:26:05 -07:00
import SttButton from "../terminal/SttButton" ;
import type { useSTT } from "../../hooks/useSTT" ;
2026-02-27 04:29:51 +00:00
2026-06-28 19:26:05 -07:00
interface Props {
stt : ReturnType < typeof useSTT >;
}
export default function StatusBar ({ stt } : Props ) {
const {
projects , sessions , terminalHasSelection , activeSessionId , sttEnabled ,
2026-09-08 11:02:33 -07:00
notesDockOpen , toggleNotesDock , terminalMouseCaptured , releaseActiveMouse ,
2026-06-28 19:26:05 -07:00
} = useAppState (
useShallow ( s => ({
projects : s.projects ,
sessions : s.sessions ,
terminalHasSelection : s.terminalHasSelection ,
activeSessionId : s.activeSessionId ,
sttEnabled : s.appSettings?.stt?.enabled ,
2026-09-01 13:15:13 -07:00
notesDockOpen : s.notesDockOpen ,
toggleNotesDock : s.toggleNotesDock ,
2026-09-08 11:02:33 -07:00
terminalMouseCaptured : s.terminalMouseCaptured ,
releaseActiveMouse : s.releaseActiveMouse ,
2026-06-28 19:26:05 -07:00
}))
2026-02-28 20:42:40 +00:00
);
2026-02-27 04:29:51 +00:00
const running = projects . filter (( p ) => p . status === "running" ). length ;
2026-08-23 08:31:39 -07:00
// Only in a Claude tab: the chord is bound there and nowhere else, and a hint
// for a key that does nothing is worse than no hint.
const inClaudeSession = sessions . some (
( s ) => s . id === activeSessionId && s . sessionType === "claude" ,
);
2026-02-27 04:29:51 +00:00
return (
2026-08-09 11:35:42 -07:00
< div className = "flex items-center h-6 px-4 bg-[var(--bg-tertiary)] border border-[var(--border-color)] rounded-[var(--radius-panel)] text-xs text-[var(--text-secondary)]" >
2026-02-27 04:29:51 +00:00
< span >
{ projects . length } project { projects . length !== 1 ? "s" : "" }
</ span >
< span className = "mx-2" > | </ span >
< span >
{ running } running
</ span >
< span className = "mx-2" > | </ span >
< span >
{ sessions . length } terminal { sessions . length !== 1 ? "s" : "" }
</ span >
2026-03-12 13:14:08 -07:00
{ terminalHasSelection && (
<>
< span className = "mx-2" > | </ span >
2026-04-17 08:58:56 -07:00
< span className = "text-[var(--accent)]" >
Ctrl + Shift + C : copy trimmed & middot ; Ctrl + Shift + Alt + C : copy raw
</ span >
2026-03-12 13:14:08 -07:00
</>
)}
2026-08-23 08:31:39 -07:00
{ ! terminalHasSelection && inClaudeSession && (
<>
< span className = "mx-2" > | </ span >
< span title = "Sends ESC+CR — the sequence Claude Code's own /terminal-setup installs. Alt+Enter does the same." >
Shift + Enter : newline
</ span >
</>
)}
2026-09-08 11:02:33 -07:00
{ /* Right-aligned controls: mouse release + Notes + STT mic */ }
2026-06-28 19:26:05 -07:00
< div className = "ml-auto flex items-center gap-3 pl-2" >
2026-09-08 11:02:33 -07:00
{ activeSessionId && terminalMouseCaptured && (
2026-06-28 19:26:05 -07:00
< button
2026-09-08 11:02:33 -07:00
data-mouse-release = "true"
onClick = {() => releaseActiveMouse ()}
2026-06-28 19:26:05 -07:00
className = "text-[var(--accent)] hover:text-[var(--accent-hover)] cursor-pointer"
2026-09-08 11:02:33 -07:00
title = "A program in the container is reading the mouse, so clicks and drags go to it instead of selecting text. Click, or press Ctrl+Shift+X, to take it back. To select text without taking it back, hold Shift while dragging (Option on macOS)."
2026-06-28 19:26:05 -07:00
>
2026-09-08 11:02:33 -07:00
🖱 Mouse captured — release
2026-06-28 19:26:05 -07:00
</ button >
)}
2026-09-01 13:15:13 -07:00
< button
onClick = { toggleNotesDock }
aria-pressed = { notesDockOpen }
className = "text-[var(--accent)] hover:text-[var(--accent-hover)] cursor-pointer"
title = "Show or hide the notes panel beside the current tab"
>
Notes
</ button >
2026-06-28 19:26:05 -07:00
{ sttEnabled && activeSessionId && (
< SttButton
state = { stt . state }
error = { stt . error }
onToggle = { stt . toggle }
onCancel = { stt . cancelRecording }
/>
)}
</ div >
2026-02-27 04:29:51 +00:00
</ div >
);
}