mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 11:23:10 +02:00
Posthog, scarf and url navigation overhaul (#4318)
Added post hog project - always enabled Added scarf pixel - Always enabled Reworked Url navigation Forward and back now works without reloading page --------- Co-authored-by: Connor Yoh <[email protected]>
This commit is contained in:
@@ -1,167 +1,127 @@
|
||||
/**
|
||||
* URL routing utilities for tool navigation
|
||||
* Provides clean URL routing for the V2 tool system
|
||||
* URL routing utilities for tool navigation with registry support
|
||||
*/
|
||||
|
||||
import { ModeType, isValidMode as isValidModeType, getDefaultMode, ToolRoute } from '../types/navigation';
|
||||
import { ToolRoute } from '../types/navigation';
|
||||
import { ToolId, isValidToolId } from '../types/toolId';
|
||||
import { getDefaultWorkbench } from '../types/workbench';
|
||||
import { ToolRegistry, getToolWorkbench, getToolUrlPath } from '../data/toolsTaxonomy';
|
||||
import { firePixel } from './scarfTracking';
|
||||
import { URL_TO_TOOL_MAP } from './urlMapping';
|
||||
|
||||
/**
|
||||
* Parse the current URL to extract tool routing information
|
||||
*/
|
||||
export function parseToolRoute(): ToolRoute {
|
||||
export function parseToolRoute(registry: ToolRegistry): ToolRoute {
|
||||
const path = window.location.pathname;
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
|
||||
// Extract tool from URL path (e.g., /split-pdf -> split)
|
||||
const toolMatch = path.match(/\/([a-zA-Z-]+)(?:-pdf)?$/);
|
||||
if (toolMatch) {
|
||||
const toolKey = toolMatch[1].toLowerCase();
|
||||
|
||||
// Map URL paths to tool keys and modes (excluding internal UI modes)
|
||||
const toolMappings: Record<string, { mode: ModeType; toolKey: string }> = {
|
||||
'split': { mode: 'split', toolKey: 'split' },
|
||||
'merge': { mode: 'merge', toolKey: 'merge' },
|
||||
'compress': { mode: 'compress', toolKey: 'compress' },
|
||||
'convert': { mode: 'convert', toolKey: 'convert' },
|
||||
'add-password': { mode: 'addPassword', toolKey: 'addPassword' },
|
||||
'change-permissions': { mode: 'changePermissions', toolKey: 'changePermissions' },
|
||||
'sanitize': { mode: 'sanitize', toolKey: 'sanitize' },
|
||||
'ocr': { mode: 'ocr', toolKey: 'ocr' }
|
||||
|
||||
// First, check URL mapping for multiple URL aliases
|
||||
const mappedToolId = URL_TO_TOOL_MAP[path];
|
||||
if (mappedToolId && registry[mappedToolId]) {
|
||||
const tool = registry[mappedToolId];
|
||||
return {
|
||||
workbench: getToolWorkbench(tool),
|
||||
toolId: mappedToolId
|
||||
};
|
||||
|
||||
const mapping = toolMappings[toolKey];
|
||||
if (mapping) {
|
||||
}
|
||||
|
||||
// Fallback: Try to find tool by primary URL path in registry
|
||||
for (const [toolId, tool] of Object.entries(registry)) {
|
||||
const toolUrlPath = getToolUrlPath(toolId, tool);
|
||||
if (path === toolUrlPath && isValidToolId(toolId)) {
|
||||
return {
|
||||
mode: mapping.mode,
|
||||
toolKey: mapping.toolKey
|
||||
workbench: getToolWorkbench(tool),
|
||||
toolId
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check for query parameter fallback (e.g., ?tool=split)
|
||||
const toolParam = searchParams.get('tool');
|
||||
if (toolParam && isValidModeType(toolParam)) {
|
||||
if (toolParam && isValidToolId(toolParam) && registry[toolParam]) {
|
||||
const tool = registry[toolParam];
|
||||
return {
|
||||
mode: toolParam as ModeType,
|
||||
toolKey: toolParam
|
||||
workbench: getToolWorkbench(tool),
|
||||
toolId: toolParam
|
||||
};
|
||||
}
|
||||
|
||||
// Default to page editor for home page
|
||||
|
||||
// Default to fileEditor workbench for home page
|
||||
return {
|
||||
mode: getDefaultMode(),
|
||||
toolKey: null
|
||||
workbench: getDefaultWorkbench(),
|
||||
toolId: null
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the URL to reflect the current tool selection
|
||||
* Internal UI modes (viewer, fileEditor, pageEditor) don't get URLs
|
||||
* Update URL and fire analytics pixel
|
||||
*/
|
||||
export function updateToolRoute(mode: ModeType, toolKey?: string): void {
|
||||
function updateUrl(newPath: string, searchParams: URLSearchParams, replace: boolean = false): void {
|
||||
const currentPath = window.location.pathname;
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
|
||||
// Don't create URLs for internal UI modes
|
||||
if (mode === 'viewer' || mode === 'fileEditor' || mode === 'pageEditor') {
|
||||
// If we're switching to an internal mode, clear any existing tool URL
|
||||
if (currentPath !== '/') {
|
||||
clearToolRoute();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let newPath = '/';
|
||||
|
||||
// Map modes to URL paths (only for actual tools)
|
||||
if (toolKey) {
|
||||
const pathMappings: Record<string, string> = {
|
||||
'split': '/split-pdf',
|
||||
'merge': '/merge-pdf',
|
||||
'compress': '/compress-pdf',
|
||||
'convert': '/convert-pdf',
|
||||
'addPassword': '/add-password-pdf',
|
||||
'changePermissions': '/change-permissions-pdf',
|
||||
'sanitize': '/sanitize-pdf',
|
||||
'ocr': '/ocr-pdf'
|
||||
};
|
||||
|
||||
newPath = pathMappings[toolKey] || `/${toolKey}`;
|
||||
}
|
||||
|
||||
// Remove tool query parameter since we're using path-based routing
|
||||
searchParams.delete('tool');
|
||||
|
||||
// Construct final URL
|
||||
const queryString = searchParams.toString();
|
||||
const fullUrl = newPath + (queryString ? `?${queryString}` : '');
|
||||
|
||||
// Update URL without triggering page reload
|
||||
|
||||
// Only update URL and fire pixel if something actually changed
|
||||
if (currentPath !== newPath || window.location.search !== (queryString ? `?${queryString}` : '')) {
|
||||
window.history.replaceState(null, '', fullUrl);
|
||||
if (replace) {
|
||||
window.history.replaceState(null, '', fullUrl);
|
||||
} else {
|
||||
window.history.pushState(null, '', fullUrl);
|
||||
}
|
||||
firePixel(newPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the URL to reflect the current tool selection
|
||||
*/
|
||||
export function updateToolRoute(toolId: ToolId, registry: ToolRegistry, replace: boolean = false): void {
|
||||
const tool = registry[toolId];
|
||||
if (!tool) {
|
||||
console.warn(`Tool ${toolId} not found in registry`);
|
||||
return;
|
||||
}
|
||||
|
||||
const newPath = getToolUrlPath(toolId, tool);
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
|
||||
// Remove tool query parameter since we're using path-based routing
|
||||
searchParams.delete('tool');
|
||||
|
||||
updateUrl(newPath, searchParams, replace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear tool routing and return to home page
|
||||
*/
|
||||
export function clearToolRoute(): void {
|
||||
export function clearToolRoute(replace: boolean = false): void {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
searchParams.delete('tool');
|
||||
|
||||
const queryString = searchParams.toString();
|
||||
const url = '/' + (queryString ? `?${queryString}` : '');
|
||||
|
||||
window.history.replaceState(null, '', url);
|
||||
|
||||
updateUrl('/', searchParams, replace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get clean tool name for display purposes
|
||||
* Get clean tool name for display purposes using registry
|
||||
*/
|
||||
export function getToolDisplayName(toolKey: string): string {
|
||||
const displayNames: Record<string, string> = {
|
||||
'split': 'Split PDF',
|
||||
'merge': 'Merge PDF',
|
||||
'compress': 'Compress PDF',
|
||||
'convert': 'Convert PDF',
|
||||
'addPassword': 'Add Password',
|
||||
'changePermissions': 'Change Permissions',
|
||||
'sanitize': 'Sanitize PDF',
|
||||
'ocr': 'OCR PDF'
|
||||
};
|
||||
|
||||
return displayNames[toolKey] || toolKey;
|
||||
export function getToolDisplayName(toolId: ToolId, registry: ToolRegistry): string {
|
||||
const tool = registry[toolId];
|
||||
return tool ? tool.name : toolId;
|
||||
}
|
||||
|
||||
// Note: isValidMode is now imported from types/navigation.ts
|
||||
|
||||
/**
|
||||
* Generate shareable URL for current tool state
|
||||
* Only generates URLs for actual tools, not internal UI modes
|
||||
* Generate shareable URL for current tool state using registry
|
||||
*/
|
||||
export function generateShareableUrl(mode: ModeType, toolKey?: string): string {
|
||||
export function generateShareableUrl(toolId: ToolId | null, registry: ToolRegistry): string {
|
||||
const baseUrl = window.location.origin;
|
||||
|
||||
// Don't generate URLs for internal UI modes
|
||||
if (mode === 'viewer' || mode === 'fileEditor' || mode === 'pageEditor') {
|
||||
|
||||
if (!toolId || !registry[toolId]) {
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
if (toolKey) {
|
||||
const pathMappings: Record<string, string> = {
|
||||
'split': '/split-pdf',
|
||||
'merge': '/merge-pdf',
|
||||
'compress': '/compress-pdf',
|
||||
'convert': '/convert-pdf',
|
||||
'addPassword': '/add-password-pdf',
|
||||
'changePermissions': '/change-permissions-pdf',
|
||||
'sanitize': '/sanitize-pdf',
|
||||
'ocr': '/ocr-pdf'
|
||||
};
|
||||
|
||||
const path = pathMappings[toolKey] || `/${toolKey}`;
|
||||
return `${baseUrl}${path}`;
|
||||
}
|
||||
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
const tool = registry[toolId];
|
||||
|
||||
const path = getToolUrlPath(toolId, tool);
|
||||
return `${baseUrl}${path}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user