mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-05-11 00:02:38 +02:00
fix sticky browser issue
This commit is contained in:
parent
0bd234ddf6
commit
a76f8bae14
3 changed files with 58 additions and 17 deletions
|
|
@ -2400,6 +2400,10 @@ function App() {
|
|||
}
|
||||
}, [runId])
|
||||
|
||||
const dismissBrowserOverlay = useCallback(() => {
|
||||
setIsBrowserOpen(false)
|
||||
}, [])
|
||||
|
||||
const handleNewChat = useCallback(() => {
|
||||
// Invalidate any in-flight run loads (rapid switching can otherwise "pop" old conversations back in)
|
||||
loadRunRequestIdRef.current += 1
|
||||
|
|
@ -2623,6 +2627,7 @@ function App() {
|
|||
|
||||
// File tab operations
|
||||
const openFileInNewTab = useCallback((path: string) => {
|
||||
dismissBrowserOverlay()
|
||||
const existingTab = fileTabs.find(t => t.path === path)
|
||||
if (existingTab) {
|
||||
setActiveFileTabId(existingTab.id)
|
||||
|
|
@ -2635,11 +2640,12 @@ function App() {
|
|||
setActiveFileTabId(id)
|
||||
setIsGraphOpen(false)
|
||||
setSelectedPath(path)
|
||||
}, [fileTabs])
|
||||
}, [fileTabs, dismissBrowserOverlay])
|
||||
|
||||
const switchFileTab = useCallback((tabId: string) => {
|
||||
const tab = fileTabs.find(t => t.id === tabId)
|
||||
if (!tab) return
|
||||
dismissBrowserOverlay()
|
||||
setActiveFileTabId(tabId)
|
||||
setSelectedBackgroundTask(null)
|
||||
setExpandedFrom(null)
|
||||
|
|
@ -2662,7 +2668,7 @@ function App() {
|
|||
setIsGraphOpen(false)
|
||||
setIsSuggestedTopicsOpen(false)
|
||||
setSelectedPath(tab.path)
|
||||
}, [fileTabs, isRightPaneMaximized])
|
||||
}, [fileTabs, isRightPaneMaximized, dismissBrowserOverlay])
|
||||
|
||||
const closeFileTab = useCallback((tabId: string) => {
|
||||
const closingTab = fileTabs.find(t => t.id === tabId)
|
||||
|
|
@ -2736,6 +2742,7 @@ function App() {
|
|||
setChatTabs(prev => [...prev, { id, runId: null }])
|
||||
setActiveChatTabId(id)
|
||||
}
|
||||
dismissBrowserOverlay()
|
||||
handleNewChat()
|
||||
// Left-pane "new chat" should always open full chat view.
|
||||
if (selectedPath || isGraphOpen || isSuggestedTopicsOpen) {
|
||||
|
|
@ -2747,7 +2754,7 @@ function App() {
|
|||
setSelectedPath(null)
|
||||
setIsGraphOpen(false)
|
||||
setIsSuggestedTopicsOpen(false)
|
||||
}, [chatTabs, activeChatTabId, handleNewChat, selectedPath, isGraphOpen, isSuggestedTopicsOpen])
|
||||
}, [chatTabs, activeChatTabId, dismissBrowserOverlay, handleNewChat, selectedPath, isGraphOpen, isSuggestedTopicsOpen])
|
||||
|
||||
// Sidebar variant: create/switch chat tab without leaving file/graph context.
|
||||
const handleNewChatTabInSidebar = useCallback(() => {
|
||||
|
|
@ -2865,11 +2872,12 @@ function App() {
|
|||
if (selectedPath || isGraphOpen || isSuggestedTopicsOpen) {
|
||||
setExpandedFrom({ path: selectedPath, graph: isGraphOpen, suggestedTopics: isSuggestedTopicsOpen })
|
||||
}
|
||||
dismissBrowserOverlay()
|
||||
setIsRightPaneMaximized(false)
|
||||
setSelectedPath(null)
|
||||
setIsGraphOpen(false)
|
||||
setIsSuggestedTopicsOpen(false)
|
||||
}, [selectedPath, isGraphOpen, isSuggestedTopicsOpen])
|
||||
}, [selectedPath, isGraphOpen, isSuggestedTopicsOpen, dismissBrowserOverlay])
|
||||
|
||||
const handleCloseFullScreenChat = useCallback(() => {
|
||||
if (expandedFrom) {
|
||||
|
|
@ -3004,8 +3012,7 @@ function App() {
|
|||
case 'chat':
|
||||
setSelectedPath(null)
|
||||
setIsGraphOpen(false)
|
||||
// Don't touch isBrowserOpen here — chat navigation should land in
|
||||
// the right sidebar when the browser overlay is active.
|
||||
setIsBrowserOpen(false)
|
||||
setExpandedFrom(null)
|
||||
setIsRightPaneMaximized(false)
|
||||
setSelectedBackgroundTask(null)
|
||||
|
|
@ -3021,7 +3028,12 @@ function App() {
|
|||
|
||||
const navigateToView = useCallback(async (nextView: ViewState) => {
|
||||
const current = currentViewState
|
||||
if (viewStatesEqual(current, nextView)) return
|
||||
if (viewStatesEqual(current, nextView)) {
|
||||
if (isBrowserOpen) {
|
||||
dismissBrowserOverlay()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
cancelRecordingIfActive()
|
||||
const nextHistory = {
|
||||
|
|
@ -3030,7 +3042,7 @@ function App() {
|
|||
}
|
||||
setHistory(nextHistory)
|
||||
await applyViewState(nextView)
|
||||
}, [appendUnique, applyViewState, cancelRecordingIfActive, currentViewState, setHistory])
|
||||
}, [appendUnique, applyViewState, cancelRecordingIfActive, currentViewState, setHistory, isBrowserOpen, dismissBrowserOverlay])
|
||||
|
||||
const navigateBack = useCallback(async () => {
|
||||
const { back, forward } = historyRef.current
|
||||
|
|
@ -4329,6 +4341,8 @@ function App() {
|
|||
meetingSummarizing={meetingSummarizing}
|
||||
meetingAvailable={voiceAvailable}
|
||||
onToggleMeeting={() => { void handleToggleMeeting() }}
|
||||
isSearchOpen={isSearchOpen}
|
||||
isMeetingActionActive={showMeetingPermissions || meetingSummarizing || meetingTranscription.state !== 'idle'}
|
||||
isBrowserOpen={isBrowserOpen}
|
||||
onToggleBrowser={handleToggleBrowser}
|
||||
isSuggestedTopicsOpen={isSuggestedTopicsOpen}
|
||||
|
|
@ -4463,7 +4477,10 @@ function App() {
|
|||
</ContentHeader>
|
||||
|
||||
{isBrowserOpen ? (
|
||||
<BrowserPane onClose={handleCloseBrowser} />
|
||||
<BrowserPane
|
||||
onClose={handleCloseBrowser}
|
||||
forceHidden={isSearchOpen || showMeetingPermissions}
|
||||
/>
|
||||
) : isSuggestedTopicsOpen ? (
|
||||
<div className="flex-1 min-h-0 flex flex-col overflow-hidden">
|
||||
<SuggestedTopicsView
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ const BLOCKING_OVERLAY_SLOTS = new Set([
|
|||
|
||||
interface BrowserPaneProps {
|
||||
onClose: () => void
|
||||
forceHidden?: boolean
|
||||
}
|
||||
|
||||
const getActiveTab = (state: BrowserState) =>
|
||||
|
|
@ -85,7 +86,7 @@ const getBrowserTabTitle = (tab: BrowserTabState) => {
|
|||
}
|
||||
}
|
||||
|
||||
export function BrowserPane({ onClose }: BrowserPaneProps) {
|
||||
export function BrowserPane({ onClose, forceHidden = false }: BrowserPaneProps) {
|
||||
const [state, setState] = useState<BrowserState>(EMPTY_STATE)
|
||||
const [addressValue, setAddressValue] = useState('')
|
||||
|
||||
|
|
@ -175,6 +176,12 @@ export function BrowserPane({ onClose }: BrowserPaneProps) {
|
|||
}, [])
|
||||
|
||||
const syncView = useCallback(() => {
|
||||
if (forceHidden) {
|
||||
lastBoundsRef.current = null
|
||||
setViewVisible(false)
|
||||
return null
|
||||
}
|
||||
|
||||
const doc = viewportRef.current?.ownerDocument
|
||||
if (doc && hasBlockingOverlay(doc)) {
|
||||
lastBoundsRef.current = null
|
||||
|
|
@ -191,7 +198,7 @@ export function BrowserPane({ onClose }: BrowserPaneProps) {
|
|||
pushBounds(bounds)
|
||||
setViewVisible(true)
|
||||
return bounds
|
||||
}, [measureBounds, pushBounds, setViewVisible])
|
||||
}, [forceHidden, measureBounds, pushBounds, setViewVisible])
|
||||
|
||||
useEffect(() => {
|
||||
syncView()
|
||||
|
|
|
|||
|
|
@ -186,6 +186,8 @@ type SidebarContentPanelProps = {
|
|||
meetingSummarizing?: boolean
|
||||
meetingAvailable?: boolean
|
||||
onToggleMeeting?: () => void
|
||||
isSearchOpen?: boolean
|
||||
isMeetingActionActive?: boolean
|
||||
isBrowserOpen?: boolean
|
||||
onToggleBrowser?: () => void
|
||||
isSuggestedTopicsOpen?: boolean
|
||||
|
|
@ -420,6 +422,8 @@ export function SidebarContentPanel({
|
|||
meetingSummarizing = false,
|
||||
meetingAvailable = false,
|
||||
onToggleMeeting,
|
||||
isSearchOpen = false,
|
||||
isMeetingActionActive = false,
|
||||
isBrowserOpen = false,
|
||||
onToggleBrowser,
|
||||
isSuggestedTopicsOpen = false,
|
||||
|
|
@ -436,6 +440,9 @@ export function SidebarContentPanel({
|
|||
const [loggingIn, setLoggingIn] = useState(false)
|
||||
const [appUrl, setAppUrl] = useState<string | null>(null)
|
||||
const { billing } = useBilling(isRowboatConnected)
|
||||
const isMeetingQuickActionSelected = isMeetingActionActive
|
||||
const isBrowserQuickActionSelected = isBrowserOpen && !isSearchOpen && !isMeetingQuickActionSelected
|
||||
const isSuggestedTopicsQuickActionSelected = isSuggestedTopicsOpen && !isBrowserOpen
|
||||
|
||||
const handleRowboatLogin = useCallback(async () => {
|
||||
try {
|
||||
|
|
@ -533,7 +540,12 @@ export function SidebarContentPanel({
|
|||
<button
|
||||
type="button"
|
||||
onClick={onOpenSearch}
|
||||
className="flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground transition-colors"
|
||||
className={cn(
|
||||
"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors",
|
||||
isSearchOpen
|
||||
? "bg-sidebar-accent text-sidebar-accent-foreground"
|
||||
: "text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
|
||||
)}
|
||||
>
|
||||
<SearchIcon className="size-4" />
|
||||
<span>Search</span>
|
||||
|
|
@ -546,9 +558,14 @@ export function SidebarContentPanel({
|
|||
disabled={meetingState === 'connecting' || meetingState === 'stopping' || meetingSummarizing}
|
||||
className={cn(
|
||||
"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors disabled:pointer-events-none",
|
||||
isMeetingQuickActionSelected
|
||||
? "bg-sidebar-accent"
|
||||
: "hover:bg-sidebar-accent",
|
||||
meetingState === 'recording'
|
||||
? "text-red-500 hover:bg-sidebar-accent"
|
||||
: "text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
|
||||
? "text-red-500"
|
||||
: isMeetingQuickActionSelected
|
||||
? "text-sidebar-accent-foreground"
|
||||
: "text-sidebar-foreground/80 hover:text-sidebar-accent-foreground"
|
||||
)}
|
||||
>
|
||||
{meetingSummarizing || meetingState === 'connecting' ? (
|
||||
|
|
@ -575,7 +592,7 @@ export function SidebarContentPanel({
|
|||
onClick={onToggleBrowser}
|
||||
className={cn(
|
||||
"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors",
|
||||
isBrowserOpen
|
||||
isBrowserQuickActionSelected
|
||||
? "bg-sidebar-accent text-sidebar-accent-foreground"
|
||||
: "text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
|
||||
)}
|
||||
|
|
@ -590,7 +607,7 @@ export function SidebarContentPanel({
|
|||
onClick={onOpenSuggestedTopics}
|
||||
className={cn(
|
||||
"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors",
|
||||
isSuggestedTopicsOpen
|
||||
isSuggestedTopicsQuickActionSelected
|
||||
? "bg-sidebar-accent text-sidebar-accent-foreground"
|
||||
: "text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
|
||||
)}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue