mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-09-18 09:29:24 +00:00
Reset route on all tools
This commit is contained in:
parent
79c50f4bc5
commit
83400dc6a7
@ -144,12 +144,14 @@ export const NavigationProvider: React.FC<{
|
|||||||
|
|
||||||
clearToolSelection: useCallback(() => {
|
clearToolSelection: useCallback(() => {
|
||||||
dispatch({ type: 'SET_SELECTED_TOOL', payload: { toolKey: null } });
|
dispatch({ type: 'SET_SELECTED_TOOL', payload: { toolKey: null } });
|
||||||
|
dispatch({ type: 'SET_MODE', payload: { mode: getDefaultMode() } });
|
||||||
}, []),
|
}, []),
|
||||||
|
|
||||||
handleToolSelect: useCallback((toolId: string) => {
|
handleToolSelect: useCallback((toolId: string) => {
|
||||||
// Handle special cases
|
// Handle special cases
|
||||||
if (toolId === 'allTools') {
|
if (toolId === 'allTools') {
|
||||||
dispatch({ type: 'SET_SELECTED_TOOL', payload: { toolKey: null } });
|
dispatch({ type: 'SET_SELECTED_TOOL', payload: { toolKey: null } });
|
||||||
|
dispatch({ type: 'SET_MODE', payload: { mode: getDefaultMode() } });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,129 +0,0 @@
|
|||||||
// src/hooks/useToolUrlRouting.ts
|
|
||||||
// Focused hook for URL <-> tool-key mapping and browser history sync.
|
|
||||||
|
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
||||||
|
|
||||||
export interface UseToolUrlRoutingOpts {
|
|
||||||
/** Currently selected tool key (from context). */
|
|
||||||
selectedToolKey: string | null;
|
|
||||||
/** Registry of available tools (key -> tool metadata). */
|
|
||||||
toolRegistry: Record<string, any> | null | undefined;
|
|
||||||
/** Select a tool (no extra side-effects). */
|
|
||||||
selectTool: (toolKey: string) => void;
|
|
||||||
/** Clear selection. */
|
|
||||||
clearToolSelection: () => void;
|
|
||||||
/** Called once during initialization if URL contains a tool; may trigger UI changes. */
|
|
||||||
onInitSelect?: (toolKey: string) => void;
|
|
||||||
/** Called when navigating via back/forward (popstate). Defaults to selectTool. */
|
|
||||||
onPopStateSelect?: (toolKey: string) => void;
|
|
||||||
/** Optional base path if the app isn't served at "/" (no trailing slash). Default: "" (root). */
|
|
||||||
basePath?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useToolUrlRouting(opts: UseToolUrlRoutingOpts) {
|
|
||||||
const {
|
|
||||||
selectedToolKey,
|
|
||||||
toolRegistry,
|
|
||||||
selectTool,
|
|
||||||
clearToolSelection,
|
|
||||||
onInitSelect,
|
|
||||||
onPopStateSelect,
|
|
||||||
basePath = '',
|
|
||||||
} = opts;
|
|
||||||
|
|
||||||
// Central slug map; keep here to co-locate routing policy.
|
|
||||||
const urlMap = useMemo(
|
|
||||||
() =>
|
|
||||||
new Map<string, string>([
|
|
||||||
['compress', 'compress-pdf'],
|
|
||||||
['split', 'split-pdf'],
|
|
||||||
['convert', 'convert-pdf'],
|
|
||||||
['ocr', 'ocr-pdf'],
|
|
||||||
['merge', 'merge-pdf'],
|
|
||||||
['rotate', 'rotate-pdf'],
|
|
||||||
]),
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const getToolUrlSlug = useCallback(
|
|
||||||
(toolKey: string) => urlMap.get(toolKey) ?? toolKey,
|
|
||||||
[urlMap]
|
|
||||||
);
|
|
||||||
|
|
||||||
const getToolKeyFromSlug = useCallback(
|
|
||||||
(slug: string) => {
|
|
||||||
for (const [key, value] of urlMap) {
|
|
||||||
if (value === slug) return key;
|
|
||||||
}
|
|
||||||
return slug; // fall back to raw key
|
|
||||||
},
|
|
||||||
[urlMap]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Internal flag to avoid clearing URL on initial mount.
|
|
||||||
const [hasInitialized, setHasInitialized] = useState(false);
|
|
||||||
|
|
||||||
// Normalize a pathname by stripping basePath and leading slash.
|
|
||||||
const normalizePath = useCallback(
|
|
||||||
(fullPath: string) => {
|
|
||||||
let p = fullPath;
|
|
||||||
if (basePath && p.startsWith(basePath)) {
|
|
||||||
p = p.slice(basePath.length);
|
|
||||||
}
|
|
||||||
if (p.startsWith('/')) p = p.slice(1);
|
|
||||||
return p;
|
|
||||||
},
|
|
||||||
[basePath]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update URL when tool changes (but not on first paint before any selection happens).
|
|
||||||
useEffect(() => {
|
|
||||||
if (selectedToolKey) {
|
|
||||||
const slug = getToolUrlSlug(selectedToolKey);
|
|
||||||
const newUrl = `${basePath}/${slug}`.replace(/\/+/, '/');
|
|
||||||
window.history.replaceState({}, '', newUrl);
|
|
||||||
setHasInitialized(true);
|
|
||||||
} else if (hasInitialized) {
|
|
||||||
const rootUrl = basePath || '/';
|
|
||||||
window.history.replaceState({}, '', rootUrl);
|
|
||||||
}
|
|
||||||
}, [selectedToolKey, getToolUrlSlug, hasInitialized, basePath]);
|
|
||||||
|
|
||||||
// Initialize from URL when the registry is ready and nothing is selected yet.
|
|
||||||
useEffect(() => {
|
|
||||||
if (!toolRegistry || Object.keys(toolRegistry).length === 0) return;
|
|
||||||
if (selectedToolKey) return; // don't override explicit selection
|
|
||||||
|
|
||||||
const currentPath = normalizePath(window.location.pathname);
|
|
||||||
if (currentPath) {
|
|
||||||
const toolKey = getToolKeyFromSlug(currentPath);
|
|
||||||
if (toolRegistry[toolKey]) {
|
|
||||||
(onInitSelect ?? selectTool)(toolKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [toolRegistry, selectedToolKey, getToolKeyFromSlug, selectTool, onInitSelect, normalizePath]);
|
|
||||||
|
|
||||||
// Handle browser back/forward. NOTE: useRef needs an initial value in TS.
|
|
||||||
const popHandlerRef = useRef<((this: Window, ev: PopStateEvent) => any) | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
popHandlerRef.current = () => {
|
|
||||||
const path = normalizePath(window.location.pathname);
|
|
||||||
if (path) {
|
|
||||||
const toolKey = getToolKeyFromSlug(path);
|
|
||||||
if (toolRegistry && toolRegistry[toolKey]) {
|
|
||||||
(onPopStateSelect ?? selectTool)(toolKey);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
clearToolSelection();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handler = (e: PopStateEvent) => popHandlerRef.current?.call(window, e);
|
|
||||||
window.addEventListener('popstate', handler);
|
|
||||||
return () => window.removeEventListener('popstate', handler);
|
|
||||||
}, [toolRegistry, selectTool, clearToolSelection, getToolKeyFromSlug, onPopStateSelect, normalizePath]);
|
|
||||||
|
|
||||||
// Expose pure helpers if you want them elsewhere (optional).
|
|
||||||
return { getToolUrlSlug, getToolKeyFromSlug };
|
|
||||||
}
|
|
@ -28,9 +28,9 @@ export function useNavigationUrlSync(
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!enableSync) return;
|
if (!enableSync) return;
|
||||||
|
|
||||||
if (currentMode === 'pageEditor') {
|
// Only update URL for actual tool modes, not internal UI modes
|
||||||
clearToolRoute();
|
// URL clearing is handled by useToolWorkflowUrlSync when selectedToolKey becomes null
|
||||||
} else {
|
if (currentMode !== 'fileEditor' && currentMode !== 'pageEditor' && currentMode !== 'viewer') {
|
||||||
updateToolRoute(currentMode, currentMode);
|
updateToolRoute(currentMode, currentMode);
|
||||||
}
|
}
|
||||||
}, [currentMode, enableSync]);
|
}, [currentMode, enableSync]);
|
||||||
@ -81,6 +81,9 @@ export function useToolWorkflowUrlSync(
|
|||||||
if (route.toolKey !== selectedToolKey) {
|
if (route.toolKey !== selectedToolKey) {
|
||||||
updateToolRoute(selectedToolKey as ModeType, selectedToolKey);
|
updateToolRoute(selectedToolKey as ModeType, selectedToolKey);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Clear URL when no tool is selected - always clear regardless of current URL
|
||||||
|
clearToolRoute();
|
||||||
}
|
}
|
||||||
}, [selectedToolKey, enableSync]);
|
}, [selectedToolKey, enableSync]);
|
||||||
}
|
}
|
||||||
|
@ -96,14 +96,20 @@ export function updateToolRoute(mode: ModeType, toolKey?: string): void {
|
|||||||
// Map modes to URL paths (only for actual tools)
|
// Map modes to URL paths (only for actual tools)
|
||||||
if (toolKey) {
|
if (toolKey) {
|
||||||
const pathMappings: Record<string, string> = {
|
const pathMappings: Record<string, string> = {
|
||||||
'split': '/split-pdf',
|
'split': '/split-pdfs',
|
||||||
'merge': '/merge-pdf',
|
'merge': '/merge-pdf',
|
||||||
'compress': '/compress-pdf',
|
'compress': '/compress-pdf',
|
||||||
'convert': '/convert-pdf',
|
'convert': '/convert-pdf',
|
||||||
'addPassword': '/add-password-pdf',
|
'addPassword': '/add-password-pdf',
|
||||||
'changePermissions': '/change-permissions-pdf',
|
'changePermissions': '/change-permissions-pdf',
|
||||||
'sanitize': '/sanitize-pdf',
|
'sanitize': '/sanitize-pdf',
|
||||||
'ocr': '/ocr-pdf'
|
'ocr': '/ocr-pdf',
|
||||||
|
'addWatermark': '/watermark',
|
||||||
|
'removePassword': '/remove-password',
|
||||||
|
'single-large-page': '/single-large-page',
|
||||||
|
'repair': '/repair',
|
||||||
|
'unlockPdfForms': '/unlock-pdf-forms',
|
||||||
|
'removeCertificateSign': '/remove-certificate-sign'
|
||||||
};
|
};
|
||||||
|
|
||||||
newPath = pathMappings[toolKey] || `/${toolKey}`;
|
newPath = pathMappings[toolKey] || `/${toolKey}`;
|
||||||
@ -176,7 +182,13 @@ export function generateShareableUrl(mode: ModeType, toolKey?: string): string {
|
|||||||
'addPassword': '/add-password-pdf',
|
'addPassword': '/add-password-pdf',
|
||||||
'changePermissions': '/change-permissions-pdf',
|
'changePermissions': '/change-permissions-pdf',
|
||||||
'sanitize': '/sanitize-pdf',
|
'sanitize': '/sanitize-pdf',
|
||||||
'ocr': '/ocr-pdf'
|
'ocr': '/ocr-pdf',
|
||||||
|
'addWatermark': '/watermark',
|
||||||
|
'removePassword': '/remove-password',
|
||||||
|
'single-large-page': '/single-large-page',
|
||||||
|
'repair': '/repair',
|
||||||
|
'unlockPdfForms': '/unlock-pdf-forms',
|
||||||
|
'removeCertificateSign': '/remove-certificate-sign'
|
||||||
};
|
};
|
||||||
|
|
||||||
const path = pathMappings[toolKey] || `/${toolKey}`;
|
const path = pathMappings[toolKey] || `/${toolKey}`;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user