import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { Resizable } from 're-resizable' import { MouseEventHandler, useCallback, useMemo } from 'react' import { useHotkeys } from 'react-hotkeys-hook' import { SidebarType, sidebarPanes } from './ModelingPanes' import Tooltip from 'components/Tooltip' import { ActionIcon } from 'components/ActionIcon' import styles from './ModelingSidebar.module.css' import { ModelingPane } from './ModelingPane' import { isDesktop } from 'lib/isDesktop' import { useModelingContext } from 'hooks/useModelingContext' import { CustomIconName } from 'components/CustomIcon' import { useCommandsContext } from 'hooks/useCommandsContext' import { IconDefinition } from '@fortawesome/free-solid-svg-icons' import { useKclContext } from 'lang/KclProvider' import { machineManager } from 'lib/machineManager' interface ModelingSidebarProps { paneOpacity: '' | 'opacity-20' | 'opacity-40' } interface BadgeInfoComputed { value: number | boolean onClick?: MouseEventHandler } export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) { const { commandBarSend } = useCommandsContext() const kclContext = useKclContext() const { settings } = useSettingsAuthContext() const onboardingStatus = settings.context.app.onboardingStatus const { send, context } = useModelingContext() const pointerEventsCssClass = context.store?.buttonDownInStream || onboardingStatus.current === 'camera' || context.store?.openPanes.length === 0 ? 'pointer-events-none ' : 'pointer-events-auto ' const showDebugPanel = settings.context.modeling.showDebugPanel const sidebarActions: SidebarAction[] = [ { id: 'export', title: 'Export part', icon: 'floppyDiskArrow', iconClassName: '!p-0', keybinding: 'Ctrl + Shift + E', action: () => commandBarSend({ type: 'Find and select command', data: { name: 'Export', groupId: 'modeling' }, }), }, { id: 'make', title: 'Make part', icon: 'printer3d', iconClassName: '!p-0', keybinding: 'Ctrl + Shift + M', // eslint-disable-next-line @typescript-eslint/no-misused-promises action: async () => { commandBarSend({ type: 'Find and select command', data: { name: 'Make', groupId: 'modeling' }, }) }, hide: () => !isDesktop(), disable: () => { return machineManager.noMachinesReason() }, }, ] const filteredActions: SidebarAction[] = sidebarActions.filter( (action) => (!action.hide || (action.hide instanceof Function && !action.hide())) && (!action.hideOnPlatform || (isDesktop() ? action.hideOnPlatform === 'web' : action.hideOnPlatform === 'desktop')) ) // // Filter out the debug panel if it's not supposed to be shown // // TODO: abstract out for allowing user to configure which panes to show const filteredPanes = useMemo( () => (showDebugPanel.current ? sidebarPanes : sidebarPanes.filter((pane) => pane.id !== 'debug') ).filter( (pane) => !pane.hideOnPlatform || (isDesktop() ? pane.hideOnPlatform === 'web' : pane.hideOnPlatform === 'desktop') ), [sidebarPanes, showDebugPanel.current] ) const paneBadgeMap: Record = useMemo(() => { return filteredPanes.reduce((acc, pane) => { if (pane.showBadge) { acc[pane.id] = { value: pane.showBadge.value({ kclContext }), onClick: pane.showBadge.onClick, } } return acc }, {} as Record) }, [kclContext.errors]) const togglePane = useCallback( (newPane: SidebarType) => { send({ type: 'Set context', data: { openPanes: context.store?.openPanes.includes(newPane) ? context.store?.openPanes.filter((pane) => pane !== newPane) : [...context.store?.openPanes, newPane], }, }) }, [context.store?.openPanes, send] ) return (
      = 1 ? 'pr-0.5' : '') } > {filteredPanes.map((pane) => ( togglePane(pane.id)} aria-pressed={context.store?.openPanes.includes(pane.id)} showBadge={paneBadgeMap[pane.id]} /> ))}
    {filteredActions.length > 0 && ( <>
    )}
    = 1 ? `row-start-1 row-end-3` : `hidden`) } > {filteredPanes .filter((pane) => context?.store.openPanes.includes(pane.id)) .map((pane) => ( togglePane(pane.id)} > {pane.Content instanceof Function ? ( ) : ( pane.Content )} ))}
) } interface ModelingPaneButtonProps extends React.HTMLAttributes { paneConfig: { id: string title: string icon: CustomIconName | IconDefinition keybinding: string iconClassName?: string iconSize?: 'sm' | 'md' | 'lg' } onClick: () => void paneIsOpen?: boolean showBadge?: BadgeInfoComputed disabledText?: string } function ModelingPaneButton({ paneConfig, onClick, paneIsOpen, showBadge, disabledText, ...props }: ModelingPaneButtonProps) { useHotkeys(paneConfig.keybinding, onClick, { scopes: ['modeling'], }) return (
{!!showBadge?.value && (

1 ? 's' : '' }`} >  has  {typeof showBadge.value === 'number' ? ( {showBadge.value} ) : ( a )}  notification{Number(showBadge.value) > 1 ? 's' : ''}

)}
) } export type SidebarAction = { id: string title: string icon: CustomIconName iconClassName?: string // Just until we get rid of FontAwesome icons keybinding: string action: () => void hideOnPlatform?: 'desktop' | 'web' hide?: boolean | (() => boolean) disable?: () => string | undefined }