import { useViewportTier } from "$hooks/useViewportTier"; import type { IconSize } from "$icons"; import { AtSignIcon, CheckIcon, CollapseIcon, DocumentIcon, ExpandIcon, EyeIcon, FocusIcon, IconProps, ImageIcon, NewDocumentIcon, PenIcon, RefreshIcon, SaveIcon, SettingsIcon, SplitViewIcon, } from "$icons"; import { useLayoutChromeActions, useLayoutChromeState, useLayoutSettingsUiState, useToolbarState, } from "$state/selectors"; import { AtProtoSession, SaveStatus } from "$types"; import { formatShortcut } from "$utils/shortcuts"; import { useCallback, useMemo } from "react"; import { SaveStatusIndicator } from "./SaveStatusIndicator"; import { ToolbarButton } from "./ToolbarButton"; import { ToolbarDropdown } from "./ToolbarDropdown"; export type ToolbarProps = { saveStatus: SaveStatus; atProtoSession?: AtProtoSession | null; hasActiveDocument?: boolean; onSave: () => void; onAtProtoAuth?: () => void; onNewDocument?: () => void; isNewDocumentDisabled?: boolean; onExportPdf?: () => void; isExportingPdf?: boolean; isPdfExportDisabled?: boolean; onInsertImage?: () => void; onRefresh?: () => void; }; const CHECK_ICON = ; export function Toolbar( { saveStatus, atProtoSession = null, hasActiveDocument = false, onSave, onAtProtoAuth = () => {}, onNewDocument, isNewDocumentDisabled = false, onExportPdf, isExportingPdf = false, isPdfExportDisabled = false, onInsertImage, onRefresh, }: ToolbarProps, ) { const { isSplitView, isFocusMode, isPreviewVisible, setEditorOnlyMode, toggleSplitView, toggleFocusMode, togglePreviewVisible, } = useToolbarState(); const { toggleSidebarCollapsed } = useLayoutChromeActions(); const { setOpen: openSettings } = useLayoutSettingsUiState(); const { sidebarCollapsed } = useLayoutChromeState(); const { isNarrow } = useViewportTier(); const icons: Record; size: IconSize }> = useMemo( () => ({ save: { Component: SaveIcon, size: "sm" }, openSidebar: { Component: ExpandIcon, size: "sm" }, closeSidebar: { Component: CollapseIcon, size: "sm" }, newDoc: { Component: NewDocumentIcon, size: "sm" }, refresh: { Component: RefreshIcon, size: "sm" }, editor: { Component: PenIcon, size: "sm" }, splitView: { Component: SplitViewIcon, size: "sm" }, eye: { Component: EyeIcon, size: "sm" }, focus: { Component: FocusIcon, size: "sm" }, export: { Component: DocumentIcon, size: "sm" }, image: { Component: ImageIcon, size: "sm" }, atproto: { Component: AtSignIcon, size: "sm" }, settings: { Component: SettingsIcon, size: "sm" }, }), [], ); const isEditorOnly = useMemo(() => !isSplitView && !isPreviewVisible, [isSplitView, isPreviewVisible]); const currentViewIcon = useMemo(() => { if (isFocusMode) return icons.focus; if (isSplitView) return icons.splitView; if (isPreviewVisible) return icons.eye; return icons.editor; }, [isFocusMode, isSplitView, isPreviewVisible, icons]); const handleOpenSettings = useCallback(() => openSettings(true), [openSettings]); const viewModeItems = useMemo( () => [ { label: "Editor", onClick: setEditorOnlyMode, icon: isEditorOnly && !isFocusMode ? CHECK_ICON : undefined }, { label: "Split", onClick: toggleSplitView, icon: isSplitView ? CHECK_ICON : undefined }, { label: "Preview", onClick: togglePreviewVisible, icon: isPreviewVisible ? CHECK_ICON : undefined }, { divider: true as const }, { label: "Focus", onClick: toggleFocusMode, icon: isFocusMode ? CHECK_ICON : undefined }, ], [ isEditorOnly, isFocusMode, isSplitView, isPreviewVisible, setEditorOnlyMode, toggleSplitView, togglePreviewVisible, toggleFocusMode, ], ); const toolsItems = useMemo(() => { const items: Parameters[0]["items"] = [{ label: atProtoSession ? atProtoSession.handle : "Login to AT Proto", onClick: onAtProtoAuth, icon: , }]; if (onExportPdf) { items.push({ label: isExportingPdf ? "Exporting..." : "Export PDF", onClick: onExportPdf ?? (() => {}), disabled: isExportingPdf || isPdfExportDisabled, icon: , }); } items.push({ divider: true as const }); items.push({ label: "Settings", onClick: handleOpenSettings, icon: }); return items; }, [atProtoSession, onAtProtoAuth, onExportPdf, isExportingPdf, isPdfExportDisabled, handleOpenSettings]); return (
{onNewDocument && ( )} {onRefresh && } {onInsertImage && } {hasActiveDocument && ( )}
); }