/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore, type PointerEvent as ReactPointerEvent, type ReactNode } from 'react'; import { Panel, Group as PanelGroup, Separator as PanelResizeHandle } from 'react-resizable-panels'; import type { PanelImperativeHandle } from 'react-resizable-panels'; import { TooltipProvider } from '@/components/ui/tooltip'; import { MainToolbar } from './MainToolbar'; import { MobileToolbar } from './MobileToolbar'; import { HierarchyPanel } from './HierarchyPanel'; import { PropertiesPanel } from './PropertiesPanel'; import { AddElementPanel } from './AddElementPanel'; import { StatusBar } from './StatusBar'; import { ViewportContainer } from './ViewportContainer'; import { KeyboardShortcutsDialog, useKeyboardShortcutsDialog } from './KeyboardShortcutsDialog'; import { useKeyboardShortcuts } from '@/hooks/useKeyboardShortcuts'; import { useActionLogger } from '@/hooks/useActionLogger'; import { usePrivacyDisclosure } from '@/hooks/usePrivacyDisclosure'; import { isSafeMode } from '@/lib/safe-mode'; import { ShieldAlert, Grip } from 'lucide-react'; import { usePanelDetachDrag } from '@/hooks/usePanelDetachDrag'; import { ExtensionDockHost } from '@/components/extensions/ExtensionDockHost'; import { useIfc } from '@/hooks/useIfc'; import { useViewerStore } from '@/store'; import { EntityContextMenu } from './EntityContextMenu'; import { useDuplicateShortcut } from './useDuplicateShortcut'; import { HoverTooltip } from './HoverTooltip'; import { BCFPanel } from './BCFPanel'; import { IDSPanel } from './IDSPanel'; import { LensPanel } from './LensPanel'; import { ClashPanel } from './ClashPanel'; import { ComparePanel } from './ComparePanel'; import { ListPanel } from './lists/ListPanel'; import { ScriptPanel } from './ScriptPanel'; import { GanttPanel } from './schedule/GanttPanel'; import { ExtensionsPanel } from '@/components/extensions/ExtensionsPanel'; import { CommandPalette } from './CommandPalette'; import { SearchModal } from './SearchModal'; import { SidebarDock } from './sidebar/SidebarDock'; import { FloatingPanelHost } from './dock/FloatingPanelHost'; import { PanelWindowHost } from './dock/PanelWindowHost'; import { closeActiveAnalysisExtension, getAnalysisExtensionById, getAnalysisExtensionsSnapshot, subscribeAnalysisExtensions, } from '@/services/analysis-extensions'; const BOTTOM_PANEL_MIN_HEIGHT = 120; const BOTTOM_PANEL_DEFAULT_HEIGHT = 300; const BOTTOM_PANEL_MAX_RATIO = 0.7; // max 70% of container /** Slim grip atop a bottom-strip panel — drag to lift it into a floating window, * or drag onto another screen to pop it out (#1208). */ function BottomPanelGrip({ id }: { id: 'gantt' | 'script' | 'lists' }) { const onPointerDown = usePanelDetachDrag(id); // Pointer-only drag affordance — not a real button (no keyboard action); // keyboard users dock / float via the sidebar rail / Alt+N (#1208). return (
?safe=0 or reload
without the flag to resume.