couple of small fixes for text editor (#5155)

# Description of Changes

- Workbench.tsx: Allow PDF text editor to handle it's own custom state
(this is a bit of a hotfix, we're going to handle the PDF text editors
file upload flow better in a future PR).
- PdfTextEditorView.tsx: Added a dropzone and some helper text to upload
the first file.
- PdfTextEditorView.tsx: Hide document view when isConverting is true.
Prevents showing stale content from previous file during conversion.
- useTranslatedToolRegistry.tsx: Moved PDF Text Editor to top of
Recommended tools list. Increased visibility of the new feature.
- PdfTextEditor.tsx: Removed auto-navigation to PDF Editor workbench on
file selection. Stops the "jumpy" behavior when selecting files.
- HomePage.tsx: Check specifically for pdfTextEditor tool instead of any
custom workbench. Prevents auto-switch to viewer when uploading files
while in PDF Text Editor.

<img width="2056" height="1073" alt="Screenshot 2025-12-03 at 6 01
14 PM"
src="https://github.com/user-attachments/assets/dfc63a46-7991-486c-ba00-0ce7637502f5"
/>


---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

---------

Co-authored-by: Anthony Stirling <[email protected]>
This commit is contained in:
EthanHealy01
2025-12-03 20:37:23 +00:00
committed by GitHub
co-authored by Anthony Stirling
parent f8dbf171e1
commit c9bf436895
14 changed files with 492 additions and 109 deletions
@@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next';
import { Tooltip } from '@app/components/shared/Tooltip';
import AppsIcon from '@mui/icons-material/AppsRounded';
import { useToolWorkflow } from '@app/contexts/ToolWorkflowContext';
import { useNavigationState, useNavigationActions } from '@app/contexts/NavigationContext';
import { useSidebarNavigation } from '@app/hooks/useSidebarNavigation';
import { handleUnlessSpecialClick } from '@app/utils/clickHandlers';
@@ -20,21 +21,36 @@ const AllToolsNavButton: React.FC<AllToolsNavButtonProps> = ({
}) => {
const { t } = useTranslation();
const { handleReaderToggle, handleBackToTools, selectedToolKey, leftPanelView } = useToolWorkflow();
const { hasUnsavedChanges } = useNavigationState();
const { actions: navigationActions } = useNavigationActions();
const { getHomeNavigation } = useSidebarNavigation();
const handleClick = () => {
const performNavigation = () => {
setActiveButton('tools');
// Preserve existing behavior used in QuickAccessBar header
handleReaderToggle();
handleBackToTools();
};
const handleClick = () => {
if (hasUnsavedChanges) {
navigationActions.requestNavigation(performNavigation);
return;
}
performNavigation();
};
// Do not highlight All Tools when a specific tool is open (indicator is shown)
const isActive = activeButton === 'tools' && !selectedToolKey && leftPanelView === 'toolPicker';
const navProps = getHomeNavigation();
const handleNavClick = (e: React.MouseEvent) => {
if (hasUnsavedChanges) {
e.preventDefault();
navigationActions.requestNavigation(performNavigation);
return;
}
handleUnlessSpecialClick(e, handleClick);
};
@@ -12,7 +12,7 @@ interface NavigationWarningModalProps {
const NavigationWarningModal = ({ onApplyAndContinue, onExportAndContinue }: NavigationWarningModalProps) => {
const { t } = useTranslation();
const { showNavigationWarning, hasUnsavedChanges, cancelNavigation, confirmNavigation, setHasUnsavedChanges } =
const { showNavigationWarning, hasUnsavedChanges, pendingNavigation, cancelNavigation, confirmNavigation, setHasUnsavedChanges } =
useNavigationGuard();
const handleKeepWorking = () => {
@@ -41,7 +41,9 @@ const NavigationWarningModal = ({ onApplyAndContinue, onExportAndContinue }: Nav
};
const BUTTON_WIDTH = "10rem";
if (!hasUnsavedChanges) {
// Only show modal if there are unsaved changes AND there's an actual pending navigation
// This prevents the modal from showing due to spurious state updates
if (!hasUnsavedChanges || !pendingNavigation) {
return null;
}
@@ -7,6 +7,7 @@ import { useRainbowThemeContext } from "@app/components/shared/RainbowThemeProvi
import { useIsOverflowing } from '@app/hooks/useIsOverflowing';
import { useFilesModalContext } from '@app/contexts/FilesModalContext';
import { useToolWorkflow } from '@app/contexts/ToolWorkflowContext';
import { useNavigationState, useNavigationActions } from '@app/contexts/NavigationContext';
import { useSidebarNavigation } from '@app/hooks/useSidebarNavigation';
import { handleUnlessSpecialClick } from '@app/utils/clickHandlers';
import { ButtonConfig } from '@app/types/sidebar';
@@ -32,6 +33,8 @@ const QuickAccessBar = forwardRef<HTMLDivElement>((_, ref) => {
const { isRainbowMode } = useRainbowThemeContext();
const { openFilesModal, isFilesModalOpen } = useFilesModalContext();
const { handleReaderToggle, handleToolSelect, selectedToolKey, leftPanelView, toolRegistry, readerMode, resetTool } = useToolWorkflow();
const { hasUnsavedChanges } = useNavigationState();
const { actions: navigationActions } = useNavigationActions();
const { getToolNavigation } = useSidebarNavigation();
const { config } = useAppConfig();
const licenseAlert = useLicenseAlert();
@@ -58,7 +61,7 @@ const QuickAccessBar = forwardRef<HTMLDivElement>((_, ref) => {
};
// Helper function to render navigation buttons with URL support
const renderNavButton = (config: ButtonConfig, index: number) => {
const renderNavButton = (config: ButtonConfig, index: number, shouldGuardNavigation = false) => {
const isActive = isNavButtonActive(config, activeButton, isFilesModalOpen, configModalOpen, selectedToolKey, leftPanelView);
// Check if this button has URL navigation support
@@ -67,6 +70,14 @@ const QuickAccessBar = forwardRef<HTMLDivElement>((_, ref) => {
: null;
const handleClick = (e?: React.MouseEvent) => {
// If there are unsaved changes and this button should guard navigation, show warning modal
if (shouldGuardNavigation && hasUnsavedChanges) {
e?.preventDefault();
navigationActions.requestNavigation(() => {
config.onClick();
});
return;
}
if (navProps && e) {
handleUnlessSpecialClick(e, config.onClick);
} else {
@@ -89,7 +100,7 @@ const QuickAccessBar = forwardRef<HTMLDivElement>((_, ref) => {
onClick: (e: React.MouseEvent) => handleClick(e),
'aria-label': config.name
} : {
onClick: () => handleClick(),
onClick: (e: React.MouseEvent) => handleClick(e),
'aria-label': config.name
})}
size={isActive ? 'lg' : 'md'}
@@ -222,7 +233,7 @@ const QuickAccessBar = forwardRef<HTMLDivElement>((_, ref) => {
<Stack gap="lg" align="center">
{mainButtons.map((config, index) => (
<React.Fragment key={config.id}>
{renderNavButton(config, index)}
{renderNavButton(config, index, config.id === 'read' || config.id === 'automate')}
</React.Fragment>
))}
</Stack>
@@ -16,6 +16,7 @@ import React, { useEffect, useRef, useState } from 'react';
import { ActionIcon } from '@mantine/core';
import ArrowBackRoundedIcon from '@mui/icons-material/ArrowBackRounded';
import { useToolWorkflow } from '@app/contexts/ToolWorkflowContext';
import { useNavigationState, useNavigationActions } from '@app/contexts/NavigationContext';
import { useSidebarNavigation } from '@app/hooks/useSidebarNavigation';
import { handleUnlessSpecialClick } from '@app/utils/clickHandlers';
import FitText from '@app/components/shared/FitText';
@@ -31,6 +32,8 @@ const NAV_IDS = ['read', 'sign', 'automate'];
const ActiveToolButton: React.FC<ActiveToolButtonProps> = ({ setActiveButton, tooltipPosition = 'right' }) => {
const { selectedTool, selectedToolKey, leftPanelView, handleBackToTools } = useToolWorkflow();
const { hasUnsavedChanges } = useNavigationState();
const { actions: navigationActions } = useNavigationActions();
const { getHomeNavigation } = useSidebarNavigation();
// Determine if the indicator should be visible (do not require selectedTool to be resolved yet)
@@ -150,10 +153,16 @@ const ActiveToolButton: React.FC<ActiveToolButtonProps> = ({ setActiveButton, to
component="a"
href={getHomeNavigation().href}
onClick={(e: React.MouseEvent) => {
handleUnlessSpecialClick(e, () => {
const performNavigation = () => {
setActiveButton('tools');
handleBackToTools();
});
};
if (hasUnsavedChanges) {
e.preventDefault();
navigationActions.requestNavigation(performNavigation);
return;
}
handleUnlessSpecialClick(e, performNavigation);
}}
size={'lg'}
variant="subtle"