fix: hide AssistantFAB during spec creation mode

The Chat AI Assistant button (AssistantFAB) was appearing on top of the
full-screen spec creation chat overlay, causing a visual bug where the
button would overlap with the Send input area.

Changes:
- Add onStepChange callback prop to NewProjectModal to notify parent
  when the modal step changes
- Add onSpecCreatingChange callback prop to ProjectSelector to propagate
  spec creation state up to App.tsx
- Add isSpecCreating state to App.tsx to track when spec creation chat
  is active
- Update AssistantFAB render condition to include !isSpecCreating
- Disable 'A' keyboard shortcut during spec creation mode

The fix propagates the spec creation state through the component
hierarchy: NewProjectModal -> ProjectSelector -> App.tsx, allowing
the FAB to be hidden when step === 'chat' in the new project modal.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Auto
2026-01-11 11:01:02 +02:00
parent 334b655472
commit b18ca80174
3 changed files with 29 additions and 16 deletions

View File

@@ -39,6 +39,7 @@ function App() {
const [debugPanelHeight, setDebugPanelHeight] = useState(288) // Default height const [debugPanelHeight, setDebugPanelHeight] = useState(288) // Default height
const [assistantOpen, setAssistantOpen] = useState(false) const [assistantOpen, setAssistantOpen] = useState(false)
const [showSettings, setShowSettings] = useState(false) const [showSettings, setShowSettings] = useState(false)
const [isSpecCreating, setIsSpecCreating] = useState(false)
const queryClient = useQueryClient() const queryClient = useQueryClient()
const { data: projects, isLoading: projectsLoading } = useProjects() const { data: projects, isLoading: projectsLoading } = useProjects()
@@ -100,8 +101,8 @@ function App() {
setShowExpandProject(true) setShowExpandProject(true)
} }
// A : Toggle assistant panel (when project selected) // A : Toggle assistant panel (when project selected and not in spec creation)
if ((e.key === 'a' || e.key === 'A') && selectedProject) { if ((e.key === 'a' || e.key === 'A') && selectedProject && !isSpecCreating) {
e.preventDefault() e.preventDefault()
setAssistantOpen(prev => !prev) setAssistantOpen(prev => !prev)
} }
@@ -132,7 +133,7 @@ function App() {
window.addEventListener('keydown', handleKeyDown) window.addEventListener('keydown', handleKeyDown)
return () => window.removeEventListener('keydown', handleKeyDown) return () => window.removeEventListener('keydown', handleKeyDown)
}, [selectedProject, showAddFeature, showExpandProject, selectedFeature, debugOpen, assistantOpen, features, showSettings]) }, [selectedProject, showAddFeature, showExpandProject, selectedFeature, debugOpen, assistantOpen, features, showSettings, isSpecCreating])
// Combine WebSocket progress with feature data // Combine WebSocket progress with feature data
const progress = wsState.progress.total > 0 ? wsState.progress : { const progress = wsState.progress.total > 0 ? wsState.progress : {
@@ -167,6 +168,7 @@ function App() {
selectedProject={selectedProject} selectedProject={selectedProject}
onSelectProject={handleSelectProject} onSelectProject={handleSelectProject}
isLoading={projectsLoading} isLoading={projectsLoading}
onSpecCreatingChange={setIsSpecCreating}
/> />
{selectedProject && ( {selectedProject && (
@@ -290,8 +292,8 @@ function App() {
/> />
)} )}
{/* Assistant FAB and Panel - hide FAB when expand modal is open */} {/* Assistant FAB and Panel - hide when expand modal or spec creation is open */}
{selectedProject && !showExpandProject && ( {selectedProject && !showExpandProject && !isSpecCreating && (
<> <>
<AssistantFAB <AssistantFAB
onClick={() => setAssistantOpen(!assistantOpen)} onClick={() => setAssistantOpen(!assistantOpen)}

View File

@@ -25,12 +25,14 @@ interface NewProjectModalProps {
isOpen: boolean isOpen: boolean
onClose: () => void onClose: () => void
onProjectCreated: (projectName: string) => void onProjectCreated: (projectName: string) => void
onStepChange?: (step: Step) => void
} }
export function NewProjectModal({ export function NewProjectModal({
isOpen, isOpen,
onClose, onClose,
onProjectCreated, onProjectCreated,
onStepChange,
}: NewProjectModalProps) { }: NewProjectModalProps) {
const [step, setStep] = useState<Step>('name') const [step, setStep] = useState<Step>('name')
const [projectName, setProjectName] = useState('') const [projectName, setProjectName] = useState('')
@@ -46,6 +48,12 @@ export function NewProjectModal({
const createProject = useCreateProject() const createProject = useCreateProject()
// Wrapper to notify parent of step changes
const changeStep = (newStep: Step) => {
setStep(newStep)
onStepChange?.(newStep)
}
if (!isOpen) return null if (!isOpen) return null
const handleNameSubmit = (e: React.FormEvent) => { const handleNameSubmit = (e: React.FormEvent) => {
@@ -63,18 +71,18 @@ export function NewProjectModal({
} }
setError(null) setError(null)
setStep('folder') changeStep('folder')
} }
const handleFolderSelect = (path: string) => { const handleFolderSelect = (path: string) => {
// Append project name to the selected path // Append project name to the selected path
const fullPath = path.endsWith('/') ? `${path}${projectName.trim()}` : `${path}/${projectName.trim()}` const fullPath = path.endsWith('/') ? `${path}${projectName.trim()}` : `${path}/${projectName.trim()}`
setProjectPath(fullPath) setProjectPath(fullPath)
setStep('method') changeStep('method')
} }
const handleFolderCancel = () => { const handleFolderCancel = () => {
setStep('name') changeStep('name')
} }
const handleMethodSelect = async (method: SpecMethod) => { const handleMethodSelect = async (method: SpecMethod) => {
@@ -82,7 +90,7 @@ export function NewProjectModal({
if (!projectPath) { if (!projectPath) {
setError('Please select a project folder first') setError('Please select a project folder first')
setStep('folder') changeStep('folder')
return return
} }
@@ -94,7 +102,7 @@ export function NewProjectModal({
path: projectPath, path: projectPath,
specMethod: 'manual', specMethod: 'manual',
}) })
setStep('complete') changeStep('complete')
setTimeout(() => { setTimeout(() => {
onProjectCreated(project.name) onProjectCreated(project.name)
handleClose() handleClose()
@@ -110,7 +118,7 @@ export function NewProjectModal({
path: projectPath, path: projectPath,
specMethod: 'claude', specMethod: 'claude',
}) })
setStep('chat') changeStep('chat')
} catch (err: unknown) { } catch (err: unknown) {
setError(err instanceof Error ? err.message : 'Failed to create project') setError(err instanceof Error ? err.message : 'Failed to create project')
} }
@@ -125,7 +133,7 @@ export function NewProjectModal({
try { try {
await startAgent(projectName.trim(), yoloMode) await startAgent(projectName.trim(), yoloMode)
// Success - navigate to project // Success - navigate to project
setStep('complete') changeStep('complete')
setTimeout(() => { setTimeout(() => {
onProjectCreated(projectName.trim()) onProjectCreated(projectName.trim())
handleClose() handleClose()
@@ -144,7 +152,7 @@ export function NewProjectModal({
const handleChatCancel = () => { const handleChatCancel = () => {
// Go back to method selection but keep the project // Go back to method selection but keep the project
setStep('method') changeStep('method')
setSpecMethod(null) setSpecMethod(null)
} }
@@ -155,7 +163,7 @@ export function NewProjectModal({
} }
const handleClose = () => { const handleClose = () => {
setStep('name') changeStep('name')
setProjectName('') setProjectName('')
setProjectPath(null) setProjectPath(null)
setSpecMethod(null) setSpecMethod(null)
@@ -168,10 +176,10 @@ export function NewProjectModal({
const handleBack = () => { const handleBack = () => {
if (step === 'method') { if (step === 'method') {
setStep('folder') changeStep('folder')
setSpecMethod(null) setSpecMethod(null)
} else if (step === 'folder') { } else if (step === 'folder') {
setStep('name') changeStep('name')
setProjectPath(null) setProjectPath(null)
} }
} }

View File

@@ -10,6 +10,7 @@ interface ProjectSelectorProps {
selectedProject: string | null selectedProject: string | null
onSelectProject: (name: string | null) => void onSelectProject: (name: string | null) => void
isLoading: boolean isLoading: boolean
onSpecCreatingChange?: (isCreating: boolean) => void
} }
export function ProjectSelector({ export function ProjectSelector({
@@ -17,6 +18,7 @@ export function ProjectSelector({
selectedProject, selectedProject,
onSelectProject, onSelectProject,
isLoading, isLoading,
onSpecCreatingChange,
}: ProjectSelectorProps) { }: ProjectSelectorProps) {
const [isOpen, setIsOpen] = useState(false) const [isOpen, setIsOpen] = useState(false)
const [showNewProjectModal, setShowNewProjectModal] = useState(false) const [showNewProjectModal, setShowNewProjectModal] = useState(false)
@@ -166,6 +168,7 @@ export function ProjectSelector({
isOpen={showNewProjectModal} isOpen={showNewProjectModal}
onClose={() => setShowNewProjectModal(false)} onClose={() => setShowNewProjectModal(false)}
onProjectCreated={handleProjectCreated} onProjectCreated={handleProjectCreated}
onStepChange={(step) => onSpecCreatingChange?.(step === 'chat')}
/> />
{/* Delete Confirmation Dialog */} {/* Delete Confirmation Dialog */}