mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-24 05:09:29 +00:00
V2 Fix subcategory names in All Tools (and search) pane (#4252)
# Description of Changes Because we used string typing for IDs and names, it was really easy to make mistakes where variables named like `subcategory` would be stored as an ID in one file, but then read assuming it's a name in another file. This PR changes the code to consistently use enum cases when referring to IDs of categories, subcategories, and tools (at least in as many places as I can find them, ~I had to add a `ToolId` enum for this work~ I originally added a `ToolId` type for this work, but it caused too many issues when merging with #4222 so I've pulled it back out for now). Making that change made it obvious where we were inconsistently passing IDs and reading them as names etc. allowing me to fix rendering issues in the All Tools pane, where the subcategory IDs were being rendered directly (instead of being translated) or where IDs were being translated into names, but were then being re-translated, causing warnings in the log.
This commit is contained in:
parent
949ffa01ad
commit
7d9c0b0298
@ -1925,18 +1925,23 @@
|
|||||||
"noToolsFound": "No tools found",
|
"noToolsFound": "No tools found",
|
||||||
"allTools": "ALL TOOLS",
|
"allTools": "ALL TOOLS",
|
||||||
"quickAccess": "QUICK ACCESS",
|
"quickAccess": "QUICK ACCESS",
|
||||||
|
"categories": {
|
||||||
|
"standardTools": "Standard Tools",
|
||||||
|
"advancedTools": "Advanced Tools",
|
||||||
|
"recommendedTools": "Recommended Tools"
|
||||||
|
},
|
||||||
"subcategories": {
|
"subcategories": {
|
||||||
"Signing": "Signing",
|
"signing": "Signing",
|
||||||
"Document Security": "Document Security",
|
"documentSecurity": "Document Security",
|
||||||
"Verification": "Verification",
|
"verification": "Verification",
|
||||||
"Document Review": "Document Review",
|
"documentReview": "Document Review",
|
||||||
"Page Formatting": "Page Formatting",
|
"pageFormatting": "Page Formatting",
|
||||||
"Extraction": "Extraction",
|
"extraction": "Extraction",
|
||||||
"Removal": "Removal",
|
"removal": "Removal",
|
||||||
"Automation": "Automation",
|
"automation": "Automation",
|
||||||
"General": "General",
|
"general": "General",
|
||||||
"Advanced Formatting": "Advanced Formatting",
|
"advancedFormatting": "Advanced Formatting",
|
||||||
"Developer Tools": "Developer Tools"
|
"developerTools": "Developer Tools"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"quickAccess": {
|
"quickAccess": {
|
||||||
|
@ -13,9 +13,9 @@ import { ButtonConfig } from '../../types/sidebar';
|
|||||||
import './quickAccessBar/QuickAccessBar.css';
|
import './quickAccessBar/QuickAccessBar.css';
|
||||||
import AllToolsNavButton from './AllToolsNavButton';
|
import AllToolsNavButton from './AllToolsNavButton';
|
||||||
import ActiveToolButton from "./quickAccessBar/ActiveToolButton";
|
import ActiveToolButton from "./quickAccessBar/ActiveToolButton";
|
||||||
import {
|
import {
|
||||||
isNavButtonActive,
|
isNavButtonActive,
|
||||||
getNavButtonStyle,
|
getNavButtonStyle,
|
||||||
getActiveNavButton,
|
getActiveNavButton,
|
||||||
} from './quickAccessBar/QuickAccessBar';
|
} from './quickAccessBar/QuickAccessBar';
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ const QuickAccessBar = forwardRef<HTMLDivElement>(({
|
|||||||
openFilesModal();
|
openFilesModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const buttonConfigs: ButtonConfig[] = [
|
const buttonConfigs: ButtonConfig[] = [
|
||||||
{
|
{
|
||||||
id: 'read',
|
id: 'read',
|
||||||
@ -226,4 +226,4 @@ const QuickAccessBar = forwardRef<HTMLDivElement>(({
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default QuickAccessBar;
|
export default QuickAccessBar;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { Box, Stack, Text } from '@mantine/core';
|
import { Box, Stack, Text } from '@mantine/core';
|
||||||
import { ToolRegistryEntry } from '../../data/toolsTaxonomy';
|
import { getSubcategoryLabel, ToolRegistryEntry } from '../../data/toolsTaxonomy';
|
||||||
import ToolButton from './toolPicker/ToolButton';
|
import ToolButton from './toolPicker/ToolButton';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useToolSections } from '../../hooks/useToolSections';
|
import { useToolSections } from '../../hooks/useToolSections';
|
||||||
@ -23,8 +23,8 @@ const SearchResults: React.FC<SearchResultsProps> = ({ filteredTools, onSelect }
|
|||||||
return (
|
return (
|
||||||
<Stack p="sm" gap="xs">
|
<Stack p="sm" gap="xs">
|
||||||
{searchGroups.map(group => (
|
{searchGroups.map(group => (
|
||||||
<Box key={group.subcategory} w="100%">
|
<Box key={group.subcategoryId} w="100%">
|
||||||
<SubcategoryHeader label={t(`toolPicker.subcategories.${group.subcategory}`, group.subcategory)} />
|
<SubcategoryHeader label={getSubcategoryLabel(t, group.subcategoryId)} />
|
||||||
<Stack gap="xs">
|
<Stack gap="xs">
|
||||||
{group.tools.map(({ id, tool }) => (
|
{group.tools.map(({ id, tool }) => (
|
||||||
<ToolButton
|
<ToolButton
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import React, { useMemo, useRef, useLayoutEffect, useState } from "react";
|
import React, { useMemo, useRef, useLayoutEffect, useState } from "react";
|
||||||
import { Box, Text, Stack } from "@mantine/core";
|
import { Box, Text, Stack } from "@mantine/core";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { ToolRegistryEntry } from "../../data/toolsTaxonomy";
|
import { getSubcategoryLabel, ToolRegistryEntry } from "../../data/toolsTaxonomy";
|
||||||
import ToolButton from "./toolPicker/ToolButton";
|
import ToolButton from "./toolPicker/ToolButton";
|
||||||
import "./toolPicker/ToolPicker.css";
|
import "./toolPicker/ToolPicker.css";
|
||||||
import { useToolSections } from "../../hooks/useToolSections";
|
import { SubcategoryGroup, useToolSections } from "../../hooks/useToolSections";
|
||||||
import SubcategoryHeader from "./shared/SubcategoryHeader";
|
import SubcategoryHeader from "./shared/SubcategoryHeader";
|
||||||
import NoToolsFound from "./shared/NoToolsFound";
|
import NoToolsFound from "./shared/NoToolsFound";
|
||||||
|
import { TFunction } from "i18next";
|
||||||
|
|
||||||
interface ToolPickerProps {
|
interface ToolPickerProps {
|
||||||
selectedToolKey: string | null;
|
selectedToolKey: string | null;
|
||||||
@ -17,14 +18,15 @@ interface ToolPickerProps {
|
|||||||
|
|
||||||
// Helper function to render tool buttons for a subcategory
|
// Helper function to render tool buttons for a subcategory
|
||||||
const renderToolButtons = (
|
const renderToolButtons = (
|
||||||
subcategory: any,
|
t: TFunction,
|
||||||
|
subcategory: SubcategoryGroup,
|
||||||
selectedToolKey: string | null,
|
selectedToolKey: string | null,
|
||||||
onSelect: (id: string) => void,
|
onSelect: (id: string) => void,
|
||||||
showSubcategoryHeader: boolean = true
|
showSubcategoryHeader: boolean = true
|
||||||
) => (
|
) => (
|
||||||
<Box key={subcategory.subcategory} w="100%">
|
<Box key={subcategory.subcategoryId} w="100%">
|
||||||
{showSubcategoryHeader && (
|
{showSubcategoryHeader && (
|
||||||
<SubcategoryHeader label={subcategory.subcategory} />
|
<SubcategoryHeader label={getSubcategoryLabel(t, subcategory.subcategoryId)} />
|
||||||
)}
|
)}
|
||||||
<Stack gap="xs">
|
<Stack gap="xs">
|
||||||
{subcategory.tools.map(({ id, tool }: { id: string; tool: any }) => (
|
{subcategory.tools.map(({ id, tool }: { id: string; tool: any }) => (
|
||||||
@ -69,11 +71,11 @@ const ToolPicker = ({ selectedToolKey, onSelect, filteredTools, isSearching = fa
|
|||||||
const { sections: visibleSections } = useToolSections(filteredTools);
|
const { sections: visibleSections } = useToolSections(filteredTools);
|
||||||
|
|
||||||
const quickSection = useMemo(
|
const quickSection = useMemo(
|
||||||
() => visibleSections.find(s => (s as any).key === 'quick'),
|
() => visibleSections.find(s => s.key === 'quick'),
|
||||||
[visibleSections]
|
[visibleSections]
|
||||||
);
|
);
|
||||||
const allSection = useMemo(
|
const allSection = useMemo(
|
||||||
() => visibleSections.find(s => (s as any).key === 'all'),
|
() => visibleSections.find(s => s.key === 'all'),
|
||||||
[visibleSections]
|
[visibleSections]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -120,7 +122,7 @@ const ToolPicker = ({ selectedToolKey, onSelect, filteredTools, isSearching = fa
|
|||||||
{searchGroups.length === 0 ? (
|
{searchGroups.length === 0 ? (
|
||||||
<NoToolsFound />
|
<NoToolsFound />
|
||||||
) : (
|
) : (
|
||||||
searchGroups.map(group => renderToolButtons(group, selectedToolKey, onSelect))
|
searchGroups.map(group => renderToolButtons(t, group, selectedToolKey, onSelect))
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
) : (
|
) : (
|
||||||
@ -164,8 +166,8 @@ const ToolPicker = ({ selectedToolKey, onSelect, filteredTools, isSearching = fa
|
|||||||
|
|
||||||
<Box ref={quickAccessRef} w="100%">
|
<Box ref={quickAccessRef} w="100%">
|
||||||
<Stack p="sm" gap="xs">
|
<Stack p="sm" gap="xs">
|
||||||
{quickSection?.subcategories.map(sc =>
|
{quickSection?.subcategories.map(sc =>
|
||||||
renderToolButtons(sc, selectedToolKey, onSelect, false)
|
renderToolButtons(t, sc, selectedToolKey, onSelect, false)
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
@ -210,8 +212,8 @@ const ToolPicker = ({ selectedToolKey, onSelect, filteredTools, isSearching = fa
|
|||||||
|
|
||||||
<Box ref={allToolsRef} w="100%">
|
<Box ref={allToolsRef} w="100%">
|
||||||
<Stack p="sm" gap="xs">
|
<Stack p="sm" gap="xs">
|
||||||
{allSection?.subcategories.map(sc =>
|
{allSection?.subcategories.map(sc =>
|
||||||
renderToolButtons(sc, selectedToolKey, onSelect, true)
|
renderToolButtons(t, sc, selectedToolKey, onSelect, true)
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -21,7 +21,7 @@ export function SuggestedToolsSection(): React.ReactElement {
|
|||||||
const IconComponent = tool.icon;
|
const IconComponent = tool.icon;
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
key={tool.name}
|
key={tool.id}
|
||||||
p="sm"
|
p="sm"
|
||||||
withBorder
|
withBorder
|
||||||
style={{ cursor: 'pointer' }}
|
style={{ cursor: 'pointer' }}
|
||||||
|
@ -14,9 +14,9 @@ interface ToolButtonProps {
|
|||||||
const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect }) => {
|
const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect }) => {
|
||||||
const handleClick = (id: string) => {
|
const handleClick = (id: string) => {
|
||||||
if (tool.link) {
|
if (tool.link) {
|
||||||
// Open external link in new tab
|
// Open external link in new tab
|
||||||
window.open(tool.link, '_blank', 'noopener,noreferrer');
|
window.open(tool.link, '_blank', 'noopener,noreferrer');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Normal tool selection
|
// Normal tool selection
|
||||||
onSelect(id);
|
onSelect(id);
|
||||||
@ -47,4 +47,4 @@ const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ToolButton;
|
export default ToolButton;
|
||||||
|
@ -72,7 +72,7 @@ interface ToolWorkflowContextValue extends ToolWorkflowState {
|
|||||||
selectedToolKey: string | null;
|
selectedToolKey: string | null;
|
||||||
selectedTool: ToolRegistryEntry | null;
|
selectedTool: ToolRegistryEntry | null;
|
||||||
toolRegistry: any; // From useToolManagement
|
toolRegistry: any; // From useToolManagement
|
||||||
|
|
||||||
// UI Actions
|
// UI Actions
|
||||||
setSidebarsVisible: (visible: boolean) => void;
|
setSidebarsVisible: (visible: boolean) => void;
|
||||||
setLeftPanelView: (view: 'toolPicker' | 'toolContent') => void;
|
setLeftPanelView: (view: 'toolPicker' | 'toolContent') => void;
|
||||||
@ -230,4 +230,4 @@ export function useToolWorkflow(): ToolWorkflowContextValue {
|
|||||||
throw new Error('useToolWorkflow must be used within a ToolWorkflowProvider');
|
throw new Error('useToolWorkflow must be used within a ToolWorkflowProvider');
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
@ -3,101 +3,101 @@ import React from 'react';
|
|||||||
import { BaseToolProps } from '../types/tool';
|
import { BaseToolProps } from '../types/tool';
|
||||||
|
|
||||||
export enum SubcategoryId {
|
export enum SubcategoryId {
|
||||||
SIGNING = 'signing',
|
SIGNING = 'signing',
|
||||||
DOCUMENT_SECURITY = 'documentSecurity',
|
DOCUMENT_SECURITY = 'documentSecurity',
|
||||||
VERIFICATION = 'verification',
|
VERIFICATION = 'verification',
|
||||||
DOCUMENT_REVIEW = 'documentReview',
|
DOCUMENT_REVIEW = 'documentReview',
|
||||||
PAGE_FORMATTING = 'pageFormatting',
|
PAGE_FORMATTING = 'pageFormatting',
|
||||||
EXTRACTION = 'extraction',
|
EXTRACTION = 'extraction',
|
||||||
REMOVAL = 'removal',
|
REMOVAL = 'removal',
|
||||||
AUTOMATION = 'automation',
|
AUTOMATION = 'automation',
|
||||||
GENERAL = 'general',
|
GENERAL = 'general',
|
||||||
ADVANCED_FORMATTING = 'advancedFormatting',
|
ADVANCED_FORMATTING = 'advancedFormatting',
|
||||||
DEVELOPER_TOOLS = 'developerTools'
|
DEVELOPER_TOOLS = 'developerTools'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ToolCategory {
|
export enum ToolCategoryId {
|
||||||
STANDARD_TOOLS = 'Standard Tools',
|
STANDARD_TOOLS = 'standardTools',
|
||||||
ADVANCED_TOOLS = 'Advanced Tools',
|
ADVANCED_TOOLS = 'advancedTools',
|
||||||
RECOMMENDED_TOOLS = 'Recommended Tools'
|
RECOMMENDED_TOOLS = 'recommendedTools'
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ToolRegistryEntry = {
|
export type ToolRegistryEntry = {
|
||||||
icon: React.ReactNode;
|
icon: React.ReactNode;
|
||||||
name: string;
|
name: string;
|
||||||
component: React.ComponentType<BaseToolProps> | null;
|
component: React.ComponentType<BaseToolProps> | null;
|
||||||
view: 'sign' | 'security' | 'format' | 'extract' | 'view' | 'merge' | 'pageEditor' | 'convert' | 'redact' | 'split' | 'convert' | 'remove' | 'compress' | 'external';
|
view: 'sign' | 'security' | 'format' | 'extract' | 'view' | 'merge' | 'pageEditor' | 'convert' | 'redact' | 'split' | 'convert' | 'remove' | 'compress' | 'external';
|
||||||
description: string;
|
description: string;
|
||||||
category: ToolCategory;
|
categoryId: ToolCategoryId;
|
||||||
subcategory: SubcategoryId;
|
subcategoryId: SubcategoryId;
|
||||||
maxFiles?: number;
|
maxFiles?: number;
|
||||||
supportedFormats?: string[];
|
supportedFormats?: string[];
|
||||||
endpoints?: string[];
|
endpoints?: string[];
|
||||||
link?: string;
|
link?: string;
|
||||||
type?: string;
|
type?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ToolRegistry = Record<string, ToolRegistryEntry>;
|
export type ToolRegistry = Record<string /* FIX ME: Should be ToolId */, ToolRegistryEntry>;
|
||||||
|
|
||||||
export const SUBCATEGORY_ORDER: SubcategoryId[] = [
|
export const SUBCATEGORY_ORDER: SubcategoryId[] = [
|
||||||
SubcategoryId.SIGNING,
|
SubcategoryId.SIGNING,
|
||||||
SubcategoryId.DOCUMENT_SECURITY,
|
SubcategoryId.DOCUMENT_SECURITY,
|
||||||
SubcategoryId.VERIFICATION,
|
SubcategoryId.VERIFICATION,
|
||||||
SubcategoryId.DOCUMENT_REVIEW,
|
SubcategoryId.DOCUMENT_REVIEW,
|
||||||
SubcategoryId.PAGE_FORMATTING,
|
SubcategoryId.PAGE_FORMATTING,
|
||||||
SubcategoryId.EXTRACTION,
|
SubcategoryId.EXTRACTION,
|
||||||
SubcategoryId.REMOVAL,
|
SubcategoryId.REMOVAL,
|
||||||
SubcategoryId.AUTOMATION,
|
SubcategoryId.AUTOMATION,
|
||||||
SubcategoryId.GENERAL,
|
SubcategoryId.GENERAL,
|
||||||
SubcategoryId.ADVANCED_FORMATTING,
|
SubcategoryId.ADVANCED_FORMATTING,
|
||||||
SubcategoryId.DEVELOPER_TOOLS,
|
SubcategoryId.DEVELOPER_TOOLS,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const SUBCATEGORY_COLOR_MAP: Record<SubcategoryId, string> = {
|
export const SUBCATEGORY_COLOR_MAP: Record<SubcategoryId, string> = {
|
||||||
[SubcategoryId.SIGNING]: '#FF7892',
|
[SubcategoryId.SIGNING]: '#FF7892',
|
||||||
[SubcategoryId.DOCUMENT_SECURITY]: '#FF7892',
|
[SubcategoryId.DOCUMENT_SECURITY]: '#FF7892',
|
||||||
[SubcategoryId.VERIFICATION]: '#1BB1D4',
|
[SubcategoryId.VERIFICATION]: '#1BB1D4',
|
||||||
[SubcategoryId.DOCUMENT_REVIEW]: '#48BD54',
|
[SubcategoryId.DOCUMENT_REVIEW]: '#48BD54',
|
||||||
[SubcategoryId.PAGE_FORMATTING]: '#7882FF',
|
[SubcategoryId.PAGE_FORMATTING]: '#7882FF',
|
||||||
[SubcategoryId.EXTRACTION]: '#1BB1D4',
|
[SubcategoryId.EXTRACTION]: '#1BB1D4',
|
||||||
[SubcategoryId.REMOVAL]: '#7882FF',
|
[SubcategoryId.REMOVAL]: '#7882FF',
|
||||||
[SubcategoryId.AUTOMATION]: '#69DC95',
|
[SubcategoryId.AUTOMATION]: '#69DC95',
|
||||||
[SubcategoryId.GENERAL]: '#69DC95',
|
[SubcategoryId.GENERAL]: '#69DC95',
|
||||||
[SubcategoryId.ADVANCED_FORMATTING]: '#F55454',
|
[SubcategoryId.ADVANCED_FORMATTING]: '#F55454',
|
||||||
[SubcategoryId.DEVELOPER_TOOLS]: '#F55454',
|
[SubcategoryId.DEVELOPER_TOOLS]: '#F55454',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getSubcategoryColor = (subcategory: SubcategoryId): string => SUBCATEGORY_COLOR_MAP[subcategory] || '#7882FF';
|
export const getCategoryLabel = (t: TFunction, id: ToolCategoryId): string => t(`toolPicker.categories.${id}`, id);
|
||||||
|
|
||||||
export const getSubcategoryLabel = (t: TFunction, id: SubcategoryId): string => t(`toolPicker.subcategories.${id}`, id);
|
export const getSubcategoryLabel = (t: TFunction, id: SubcategoryId): string => t(`toolPicker.subcategories.${id}`, id);
|
||||||
|
export const getSubcategoryColor = (subcategory: SubcategoryId): string => SUBCATEGORY_COLOR_MAP[subcategory] || '#7882FF';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const getAllEndpoints = (registry: ToolRegistry): string[] => {
|
export const getAllEndpoints = (registry: ToolRegistry): string[] => {
|
||||||
const lists: string[][] = [];
|
const lists: string[][] = [];
|
||||||
Object.values(registry).forEach(entry => {
|
Object.values(registry).forEach(entry => {
|
||||||
if (entry.endpoints && entry.endpoints.length > 0) {
|
if (entry.endpoints && entry.endpoints.length > 0) {
|
||||||
lists.push(entry.endpoints);
|
lists.push(entry.endpoints);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return Array.from(new Set(lists.flat()));
|
return Array.from(new Set(lists.flat()));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getConversionEndpoints = (extensionToEndpoint: Record<string, Record<string, string>>): string[] => {
|
export const getConversionEndpoints = (extensionToEndpoint: Record<string, Record<string, string>>): string[] => {
|
||||||
const endpoints = new Set<string>();
|
const endpoints = new Set<string>();
|
||||||
Object.values(extensionToEndpoint).forEach(toEndpoints => {
|
Object.values(extensionToEndpoint).forEach(toEndpoints => {
|
||||||
Object.values(toEndpoints).forEach(endpoint => {
|
Object.values(toEndpoints).forEach(endpoint => {
|
||||||
endpoints.add(endpoint);
|
endpoints.add(endpoint);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return Array.from(endpoints);
|
return Array.from(endpoints);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getAllApplicationEndpoints = (
|
export const getAllApplicationEndpoints = (
|
||||||
registry: ToolRegistry,
|
registry: ToolRegistry,
|
||||||
extensionToEndpoint?: Record<string, Record<string, string>>
|
extensionToEndpoint?: Record<string, Record<string, string>>
|
||||||
): string[] => {
|
): string[] => {
|
||||||
const toolEp = getAllEndpoints(registry);
|
const toolEp = getAllEndpoints(registry);
|
||||||
const convEp = extensionToEndpoint ? getConversionEndpoints(extensionToEndpoint) : [];
|
const convEp = extensionToEndpoint ? getConversionEndpoints(extensionToEndpoint) : [];
|
||||||
return Array.from(new Set([...toolEp, ...convEp]));
|
return Array.from(new Set([...toolEp, ...convEp]));
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import React from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import SplitPdfPanel from "../tools/Split";
|
import SplitPdfPanel from "../tools/Split";
|
||||||
import CompressPdfPanel from "../tools/Compress";
|
import CompressPdfPanel from "../tools/Compress";
|
||||||
@ -8,7 +7,7 @@ import Sanitize from '../tools/Sanitize';
|
|||||||
import AddPassword from '../tools/AddPassword';
|
import AddPassword from '../tools/AddPassword';
|
||||||
import ChangePermissions from '../tools/ChangePermissions';
|
import ChangePermissions from '../tools/ChangePermissions';
|
||||||
import RemovePassword from '../tools/RemovePassword';
|
import RemovePassword from '../tools/RemovePassword';
|
||||||
import { SubcategoryId, ToolCategory, ToolRegistry } from './toolsTaxonomy';
|
import { SubcategoryId, ToolCategoryId, ToolRegistry } from './toolsTaxonomy';
|
||||||
import AddWatermark from '../tools/AddWatermark';
|
import AddWatermark from '../tools/AddWatermark';
|
||||||
import Repair from '../tools/Repair';
|
import Repair from '../tools/Repair';
|
||||||
import SingleLargePage from '../tools/SingleLargePage';
|
import SingleLargePage from '../tools/SingleLargePage';
|
||||||
@ -30,8 +29,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "sign",
|
view: "sign",
|
||||||
description: t("home.certSign.desc", "Signs a PDF with a Certificate/Key (PEM/P12)"),
|
description: t("home.certSign.desc", "Signs a PDF with a Certificate/Key (PEM/P12)"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.SIGNING
|
subcategoryId: SubcategoryId.SIGNING
|
||||||
},
|
},
|
||||||
"sign": {
|
"sign": {
|
||||||
icon: <span className="material-symbols-rounded">signature</span>,
|
icon: <span className="material-symbols-rounded">signature</span>,
|
||||||
@ -39,8 +38,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "sign",
|
view: "sign",
|
||||||
description: t("home.sign.desc", "Adds signature to PDF by drawing, text or image"),
|
description: t("home.sign.desc", "Adds signature to PDF by drawing, text or image"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.SIGNING
|
subcategoryId: SubcategoryId.SIGNING
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
@ -52,8 +51,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: AddPassword,
|
component: AddPassword,
|
||||||
view: "security",
|
view: "security",
|
||||||
description: t("home.addPassword.desc", "Add password protection and restrictions to PDF files"),
|
description: t("home.addPassword.desc", "Add password protection and restrictions to PDF files"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.DOCUMENT_SECURITY,
|
subcategoryId: SubcategoryId.DOCUMENT_SECURITY,
|
||||||
maxFiles: -1,
|
maxFiles: -1,
|
||||||
endpoints: ["add-password"]
|
endpoints: ["add-password"]
|
||||||
},
|
},
|
||||||
@ -64,8 +63,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
view: "format",
|
view: "format",
|
||||||
maxFiles: -1,
|
maxFiles: -1,
|
||||||
description: t("home.watermark.desc", "Add a custom watermark to your PDF document."),
|
description: t("home.watermark.desc", "Add a custom watermark to your PDF document."),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.DOCUMENT_SECURITY,
|
subcategoryId: SubcategoryId.DOCUMENT_SECURITY,
|
||||||
endpoints: ["add-watermark"]
|
endpoints: ["add-watermark"]
|
||||||
},
|
},
|
||||||
"add-stamp": {
|
"add-stamp": {
|
||||||
@ -74,8 +73,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.AddStampRequest.desc", "Add text or add image stamps at set locations"),
|
description: t("home.AddStampRequest.desc", "Add text or add image stamps at set locations"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.DOCUMENT_SECURITY
|
subcategoryId: SubcategoryId.DOCUMENT_SECURITY
|
||||||
},
|
},
|
||||||
"sanitize": {
|
"sanitize": {
|
||||||
icon: <span className="material-symbols-rounded">cleaning_services</span>,
|
icon: <span className="material-symbols-rounded">cleaning_services</span>,
|
||||||
@ -83,8 +82,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: Sanitize,
|
component: Sanitize,
|
||||||
view: "security",
|
view: "security",
|
||||||
maxFiles: -1,
|
maxFiles: -1,
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.DOCUMENT_SECURITY,
|
subcategoryId: SubcategoryId.DOCUMENT_SECURITY,
|
||||||
description: t("home.sanitize.desc", "Remove potentially harmful elements from PDF files"),
|
description: t("home.sanitize.desc", "Remove potentially harmful elements from PDF files"),
|
||||||
endpoints: ["sanitize-pdf"]
|
endpoints: ["sanitize-pdf"]
|
||||||
},
|
},
|
||||||
@ -94,8 +93,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.flatten.desc", "Remove all interactive elements and forms from a PDF"),
|
description: t("home.flatten.desc", "Remove all interactive elements and forms from a PDF"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.DOCUMENT_SECURITY
|
subcategoryId: SubcategoryId.DOCUMENT_SECURITY
|
||||||
},
|
},
|
||||||
"unlock-pdf-forms": {
|
"unlock-pdf-forms": {
|
||||||
icon: <span className="material-symbols-rounded">preview_off</span>,
|
icon: <span className="material-symbols-rounded">preview_off</span>,
|
||||||
@ -103,8 +102,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: UnlockPdfForms,
|
component: UnlockPdfForms,
|
||||||
view: "security",
|
view: "security",
|
||||||
description: t("home.unlockPDFForms.desc", "Remove read-only property of form fields in a PDF document."),
|
description: t("home.unlockPDFForms.desc", "Remove read-only property of form fields in a PDF document."),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.DOCUMENT_SECURITY,
|
subcategoryId: SubcategoryId.DOCUMENT_SECURITY,
|
||||||
maxFiles: -1,
|
maxFiles: -1,
|
||||||
endpoints: ["unlock-pdf-forms"]
|
endpoints: ["unlock-pdf-forms"]
|
||||||
},
|
},
|
||||||
@ -114,8 +113,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "security",
|
view: "security",
|
||||||
description: t("home.manageCertificates.desc", "Import, export, or delete digital certificate files used for signing PDFs."),
|
description: t("home.manageCertificates.desc", "Import, export, or delete digital certificate files used for signing PDFs."),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.DOCUMENT_SECURITY
|
subcategoryId: SubcategoryId.DOCUMENT_SECURITY
|
||||||
},
|
},
|
||||||
"change-permissions": {
|
"change-permissions": {
|
||||||
icon: <span className="material-symbols-rounded">lock</span>,
|
icon: <span className="material-symbols-rounded">lock</span>,
|
||||||
@ -123,8 +122,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: ChangePermissions,
|
component: ChangePermissions,
|
||||||
view: "security",
|
view: "security",
|
||||||
description: t("home.changePermissions.desc", "Change document restrictions and permissions"),
|
description: t("home.changePermissions.desc", "Change document restrictions and permissions"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.DOCUMENT_SECURITY,
|
subcategoryId: SubcategoryId.DOCUMENT_SECURITY,
|
||||||
maxFiles: -1,
|
maxFiles: -1,
|
||||||
endpoints: ["add-password"]
|
endpoints: ["add-password"]
|
||||||
},
|
},
|
||||||
@ -136,8 +135,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "extract",
|
view: "extract",
|
||||||
description: t("home.getPdfInfo.desc", "Grabs any and all information possible on PDFs"),
|
description: t("home.getPdfInfo.desc", "Grabs any and all information possible on PDFs"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.VERIFICATION
|
subcategoryId: SubcategoryId.VERIFICATION
|
||||||
},
|
},
|
||||||
"validate-pdf-signature": {
|
"validate-pdf-signature": {
|
||||||
icon: <span className="material-symbols-rounded">verified</span>,
|
icon: <span className="material-symbols-rounded">verified</span>,
|
||||||
@ -145,8 +144,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "security",
|
view: "security",
|
||||||
description: t("home.validateSignature.desc", "Verify digital signatures and certificates in PDF documents"),
|
description: t("home.validateSignature.desc", "Verify digital signatures and certificates in PDF documents"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.VERIFICATION
|
subcategoryId: SubcategoryId.VERIFICATION
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
@ -158,8 +157,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "view",
|
view: "view",
|
||||||
description: t("home.read.desc", "View and annotate PDFs. Highlight text, draw, or insert comments for review and collaboration."),
|
description: t("home.read.desc", "View and annotate PDFs. Highlight text, draw, or insert comments for review and collaboration."),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.DOCUMENT_REVIEW
|
subcategoryId: SubcategoryId.DOCUMENT_REVIEW
|
||||||
},
|
},
|
||||||
"change-metadata": {
|
"change-metadata": {
|
||||||
icon: <span className="material-symbols-rounded">assignment</span>,
|
icon: <span className="material-symbols-rounded">assignment</span>,
|
||||||
@ -167,8 +166,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.changeMetadata.desc", "Change/Remove/Add metadata from a PDF document"),
|
description: t("home.changeMetadata.desc", "Change/Remove/Add metadata from a PDF document"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.DOCUMENT_REVIEW
|
subcategoryId: SubcategoryId.DOCUMENT_REVIEW
|
||||||
},
|
},
|
||||||
// Page Formatting
|
// Page Formatting
|
||||||
|
|
||||||
@ -178,8 +177,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.crop.desc", "Crop a PDF to reduce its size (maintains text!)"),
|
description: t("home.crop.desc", "Crop a PDF to reduce its size (maintains text!)"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.PAGE_FORMATTING
|
subcategoryId: SubcategoryId.PAGE_FORMATTING
|
||||||
},
|
},
|
||||||
"rotate": {
|
"rotate": {
|
||||||
icon: <span className="material-symbols-rounded">rotate_right</span>,
|
icon: <span className="material-symbols-rounded">rotate_right</span>,
|
||||||
@ -187,8 +186,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.rotate.desc", "Easily rotate your PDFs."),
|
description: t("home.rotate.desc", "Easily rotate your PDFs."),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.PAGE_FORMATTING
|
subcategoryId: SubcategoryId.PAGE_FORMATTING
|
||||||
},
|
},
|
||||||
"splitPdf": {
|
"splitPdf": {
|
||||||
icon: <span className="material-symbols-rounded">content_cut</span>,
|
icon: <span className="material-symbols-rounded">content_cut</span>,
|
||||||
@ -196,8 +195,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: SplitPdfPanel,
|
component: SplitPdfPanel,
|
||||||
view: "split",
|
view: "split",
|
||||||
description: t("home.split.desc", "Split PDFs into multiple documents"),
|
description: t("home.split.desc", "Split PDFs into multiple documents"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.PAGE_FORMATTING
|
subcategoryId: SubcategoryId.PAGE_FORMATTING
|
||||||
},
|
},
|
||||||
"reorganize-pages": {
|
"reorganize-pages": {
|
||||||
icon: <span className="material-symbols-rounded">move_down</span>,
|
icon: <span className="material-symbols-rounded">move_down</span>,
|
||||||
@ -205,8 +204,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "pageEditor",
|
view: "pageEditor",
|
||||||
description: t("home.reorganizePages.desc", "Rearrange, duplicate, or delete PDF pages with visual drag-and-drop control."),
|
description: t("home.reorganizePages.desc", "Rearrange, duplicate, or delete PDF pages with visual drag-and-drop control."),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.PAGE_FORMATTING
|
subcategoryId: SubcategoryId.PAGE_FORMATTING
|
||||||
},
|
},
|
||||||
"adjust-page-size-scale": {
|
"adjust-page-size-scale": {
|
||||||
icon: <span className="material-symbols-rounded">crop_free</span>,
|
icon: <span className="material-symbols-rounded">crop_free</span>,
|
||||||
@ -214,8 +213,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.scalePages.desc", "Change the size/scale of a page and/or its contents."),
|
description: t("home.scalePages.desc", "Change the size/scale of a page and/or its contents."),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.PAGE_FORMATTING
|
subcategoryId: SubcategoryId.PAGE_FORMATTING
|
||||||
},
|
},
|
||||||
"addPageNumbers": {
|
"addPageNumbers": {
|
||||||
icon: <span className="material-symbols-rounded">123</span>,
|
icon: <span className="material-symbols-rounded">123</span>,
|
||||||
@ -223,8 +222,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.addPageNumbers.desc", "Add Page numbers throughout a document in a set location"),
|
description: t("home.addPageNumbers.desc", "Add Page numbers throughout a document in a set location"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.PAGE_FORMATTING
|
subcategoryId: SubcategoryId.PAGE_FORMATTING
|
||||||
},
|
},
|
||||||
"multi-page-layout": {
|
"multi-page-layout": {
|
||||||
icon: <span className="material-symbols-rounded">dashboard</span>,
|
icon: <span className="material-symbols-rounded">dashboard</span>,
|
||||||
@ -232,8 +231,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.pageLayout.desc", "Merge multiple pages of a PDF document into a single page"),
|
description: t("home.pageLayout.desc", "Merge multiple pages of a PDF document into a single page"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.PAGE_FORMATTING
|
subcategoryId: SubcategoryId.PAGE_FORMATTING
|
||||||
},
|
},
|
||||||
"single-large-page": {
|
"single-large-page": {
|
||||||
icon: <span className="material-symbols-rounded">looks_one</span>,
|
icon: <span className="material-symbols-rounded">looks_one</span>,
|
||||||
@ -241,8 +240,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: SingleLargePage,
|
component: SingleLargePage,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.pdfToSinglePage.desc", "Merges all PDF pages into one large single page"),
|
description: t("home.pdfToSinglePage.desc", "Merges all PDF pages into one large single page"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.PAGE_FORMATTING,
|
subcategoryId: SubcategoryId.PAGE_FORMATTING,
|
||||||
maxFiles: -1,
|
maxFiles: -1,
|
||||||
endpoints: ["pdf-to-single-page"]
|
endpoints: ["pdf-to-single-page"]
|
||||||
},
|
},
|
||||||
@ -252,8 +251,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.attachments.desc", "Add or remove embedded files (attachments) to/from a PDF"),
|
description: t("home.attachments.desc", "Add or remove embedded files (attachments) to/from a PDF"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.PAGE_FORMATTING,
|
subcategoryId: SubcategoryId.PAGE_FORMATTING,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
@ -265,8 +264,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "extract",
|
view: "extract",
|
||||||
description: t("home.extractPages.desc", "Extract specific pages from a PDF document"),
|
description: t("home.extractPages.desc", "Extract specific pages from a PDF document"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.EXTRACTION
|
subcategoryId: SubcategoryId.EXTRACTION
|
||||||
},
|
},
|
||||||
"extract-images": {
|
"extract-images": {
|
||||||
icon: <span className="material-symbols-rounded">filter</span>,
|
icon: <span className="material-symbols-rounded">filter</span>,
|
||||||
@ -274,8 +273,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "extract",
|
view: "extract",
|
||||||
description: t("home.extractImages.desc", "Extract images from PDF documents"),
|
description: t("home.extractImages.desc", "Extract images from PDF documents"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.EXTRACTION
|
subcategoryId: SubcategoryId.EXTRACTION
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
@ -287,8 +286,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "remove",
|
view: "remove",
|
||||||
description: t("home.removePages.desc", "Remove specific pages from a PDF document"),
|
description: t("home.removePages.desc", "Remove specific pages from a PDF document"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.REMOVAL
|
subcategoryId: SubcategoryId.REMOVAL
|
||||||
},
|
},
|
||||||
"remove-blank-pages": {
|
"remove-blank-pages": {
|
||||||
icon: <span className="material-symbols-rounded">scan_delete</span>,
|
icon: <span className="material-symbols-rounded">scan_delete</span>,
|
||||||
@ -296,8 +295,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "remove",
|
view: "remove",
|
||||||
description: t("home.removeBlanks.desc", "Remove blank pages from PDF documents"),
|
description: t("home.removeBlanks.desc", "Remove blank pages from PDF documents"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.REMOVAL
|
subcategoryId: SubcategoryId.REMOVAL
|
||||||
},
|
},
|
||||||
"remove-annotations": {
|
"remove-annotations": {
|
||||||
icon: <span className="material-symbols-rounded">thread_unread</span>,
|
icon: <span className="material-symbols-rounded">thread_unread</span>,
|
||||||
@ -305,8 +304,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "remove",
|
view: "remove",
|
||||||
description: t("home.removeAnnotations.desc", "Remove annotations and comments from PDF documents"),
|
description: t("home.removeAnnotations.desc", "Remove annotations and comments from PDF documents"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.REMOVAL
|
subcategoryId: SubcategoryId.REMOVAL
|
||||||
},
|
},
|
||||||
"remove-image": {
|
"remove-image": {
|
||||||
icon: <span className="material-symbols-rounded">remove_selection</span>,
|
icon: <span className="material-symbols-rounded">remove_selection</span>,
|
||||||
@ -314,8 +313,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.removeImagePdf.desc", "Remove images from PDF documents"),
|
description: t("home.removeImagePdf.desc", "Remove images from PDF documents"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.REMOVAL
|
subcategoryId: SubcategoryId.REMOVAL
|
||||||
},
|
},
|
||||||
"remove-password": {
|
"remove-password": {
|
||||||
icon: <span className="material-symbols-rounded">lock_open_right</span>,
|
icon: <span className="material-symbols-rounded">lock_open_right</span>,
|
||||||
@ -323,8 +322,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: RemovePassword,
|
component: RemovePassword,
|
||||||
view: "security",
|
view: "security",
|
||||||
description: t("home.removePassword.desc", "Remove password protection from PDF documents"),
|
description: t("home.removePassword.desc", "Remove password protection from PDF documents"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.REMOVAL,
|
subcategoryId: SubcategoryId.REMOVAL,
|
||||||
endpoints: ["remove-password"],
|
endpoints: ["remove-password"],
|
||||||
maxFiles: -1,
|
maxFiles: -1,
|
||||||
|
|
||||||
@ -335,8 +334,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: RemoveCertificateSign,
|
component: RemoveCertificateSign,
|
||||||
view: "security",
|
view: "security",
|
||||||
description: t("home.removeCertSign.desc", "Remove digital signature from PDF documents"),
|
description: t("home.removeCertSign.desc", "Remove digital signature from PDF documents"),
|
||||||
category: ToolCategory.STANDARD_TOOLS,
|
categoryId: ToolCategoryId.STANDARD_TOOLS,
|
||||||
subcategory: SubcategoryId.REMOVAL,
|
subcategoryId: SubcategoryId.REMOVAL,
|
||||||
maxFiles: -1,
|
maxFiles: -1,
|
||||||
endpoints: ["remove-certificate-sign"]
|
endpoints: ["remove-certificate-sign"]
|
||||||
},
|
},
|
||||||
@ -350,8 +349,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.automate.desc", "Build multi-step workflows by chaining together PDF actions. Ideal for recurring tasks."),
|
description: t("home.automate.desc", "Build multi-step workflows by chaining together PDF actions. Ideal for recurring tasks."),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.AUTOMATION
|
subcategoryId: SubcategoryId.AUTOMATION
|
||||||
},
|
},
|
||||||
"auto-rename-pdf-file": {
|
"auto-rename-pdf-file": {
|
||||||
icon: <span className="material-symbols-rounded">match_word</span>,
|
icon: <span className="material-symbols-rounded">match_word</span>,
|
||||||
@ -359,8 +358,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.auto-rename.desc", "Automatically rename PDF files based on their content"),
|
description: t("home.auto-rename.desc", "Automatically rename PDF files based on their content"),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.AUTOMATION
|
subcategoryId: SubcategoryId.AUTOMATION
|
||||||
},
|
},
|
||||||
"auto-split-pages": {
|
"auto-split-pages": {
|
||||||
icon: <span className="material-symbols-rounded">split_scene_right</span>,
|
icon: <span className="material-symbols-rounded">split_scene_right</span>,
|
||||||
@ -368,8 +367,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.autoSplitPDF.desc", "Automatically split PDF pages based on content detection"),
|
description: t("home.autoSplitPDF.desc", "Automatically split PDF pages based on content detection"),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.AUTOMATION
|
subcategoryId: SubcategoryId.AUTOMATION
|
||||||
},
|
},
|
||||||
"auto-split-by-size-count": {
|
"auto-split-by-size-count": {
|
||||||
icon: <span className="material-symbols-rounded">content_cut</span>,
|
icon: <span className="material-symbols-rounded">content_cut</span>,
|
||||||
@ -377,8 +376,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.autoSizeSplitPDF.desc", "Automatically split PDFs by file size or page count"),
|
description: t("home.autoSizeSplitPDF.desc", "Automatically split PDFs by file size or page count"),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.AUTOMATION
|
subcategoryId: SubcategoryId.AUTOMATION
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
@ -390,8 +389,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.adjustContrast.desc", "Adjust colors and contrast of PDF documents"),
|
description: t("home.adjustContrast.desc", "Adjust colors and contrast of PDF documents"),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.ADVANCED_FORMATTING
|
subcategoryId: SubcategoryId.ADVANCED_FORMATTING
|
||||||
},
|
},
|
||||||
"repair": {
|
"repair": {
|
||||||
icon: <span className="material-symbols-rounded">build</span>,
|
icon: <span className="material-symbols-rounded">build</span>,
|
||||||
@ -399,8 +398,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: Repair,
|
component: Repair,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.repair.desc", "Repair corrupted or damaged PDF files"),
|
description: t("home.repair.desc", "Repair corrupted or damaged PDF files"),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.ADVANCED_FORMATTING,
|
subcategoryId: SubcategoryId.ADVANCED_FORMATTING,
|
||||||
maxFiles: -1,
|
maxFiles: -1,
|
||||||
endpoints: ["repair"]
|
endpoints: ["repair"]
|
||||||
},
|
},
|
||||||
@ -410,8 +409,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.ScannerImageSplit.desc", "Detect and split scanned photos into separate pages"),
|
description: t("home.ScannerImageSplit.desc", "Detect and split scanned photos into separate pages"),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.ADVANCED_FORMATTING
|
subcategoryId: SubcategoryId.ADVANCED_FORMATTING
|
||||||
},
|
},
|
||||||
"overlay-pdfs": {
|
"overlay-pdfs": {
|
||||||
icon: <span className="material-symbols-rounded">layers</span>,
|
icon: <span className="material-symbols-rounded">layers</span>,
|
||||||
@ -419,8 +418,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.overlay-pdfs.desc", "Overlay one PDF on top of another"),
|
description: t("home.overlay-pdfs.desc", "Overlay one PDF on top of another"),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.ADVANCED_FORMATTING
|
subcategoryId: SubcategoryId.ADVANCED_FORMATTING
|
||||||
},
|
},
|
||||||
"replace-and-invert-color": {
|
"replace-and-invert-color": {
|
||||||
icon: <span className="material-symbols-rounded">format_color_fill</span>,
|
icon: <span className="material-symbols-rounded">format_color_fill</span>,
|
||||||
@ -428,8 +427,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.replaceColorPdf.desc", "Replace or invert colors in PDF documents"),
|
description: t("home.replaceColorPdf.desc", "Replace or invert colors in PDF documents"),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.ADVANCED_FORMATTING
|
subcategoryId: SubcategoryId.ADVANCED_FORMATTING
|
||||||
},
|
},
|
||||||
"add-image": {
|
"add-image": {
|
||||||
icon: <span className="material-symbols-rounded">image</span>,
|
icon: <span className="material-symbols-rounded">image</span>,
|
||||||
@ -437,8 +436,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.addImage.desc", "Add images to PDF documents"),
|
description: t("home.addImage.desc", "Add images to PDF documents"),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.ADVANCED_FORMATTING
|
subcategoryId: SubcategoryId.ADVANCED_FORMATTING
|
||||||
},
|
},
|
||||||
"edit-table-of-contents": {
|
"edit-table-of-contents": {
|
||||||
icon: <span className="material-symbols-rounded">bookmark_add</span>,
|
icon: <span className="material-symbols-rounded">bookmark_add</span>,
|
||||||
@ -446,8 +445,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.editTableOfContents.desc", "Add or edit bookmarks and table of contents in PDF documents"),
|
description: t("home.editTableOfContents.desc", "Add or edit bookmarks and table of contents in PDF documents"),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.ADVANCED_FORMATTING
|
subcategoryId: SubcategoryId.ADVANCED_FORMATTING
|
||||||
},
|
},
|
||||||
"scanner-effect": {
|
"scanner-effect": {
|
||||||
icon: <span className="material-symbols-rounded">scanner</span>,
|
icon: <span className="material-symbols-rounded">scanner</span>,
|
||||||
@ -455,8 +454,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.fakeScan.desc", "Create a PDF that looks like it was scanned"),
|
description: t("home.fakeScan.desc", "Create a PDF that looks like it was scanned"),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.ADVANCED_FORMATTING
|
subcategoryId: SubcategoryId.ADVANCED_FORMATTING
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
@ -468,8 +467,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "extract",
|
view: "extract",
|
||||||
description: t("home.showJS.desc", "Extract and display JavaScript code from PDF documents"),
|
description: t("home.showJS.desc", "Extract and display JavaScript code from PDF documents"),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.DEVELOPER_TOOLS
|
subcategoryId: SubcategoryId.DEVELOPER_TOOLS
|
||||||
},
|
},
|
||||||
"dev-api": {
|
"dev-api": {
|
||||||
icon: <span className="material-symbols-rounded" style={{ color: '#2F7BF6' }}>open_in_new</span>,
|
icon: <span className="material-symbols-rounded" style={{ color: '#2F7BF6' }}>open_in_new</span>,
|
||||||
@ -477,8 +476,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "external",
|
view: "external",
|
||||||
description: t("home.devApi.desc", "Link to API documentation"),
|
description: t("home.devApi.desc", "Link to API documentation"),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.DEVELOPER_TOOLS,
|
subcategoryId: SubcategoryId.DEVELOPER_TOOLS,
|
||||||
link: "https://stirlingpdf.io/swagger-ui/5.21.0/index.html"
|
link: "https://stirlingpdf.io/swagger-ui/5.21.0/index.html"
|
||||||
},
|
},
|
||||||
"dev-folder-scanning": {
|
"dev-folder-scanning": {
|
||||||
@ -487,8 +486,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "external",
|
view: "external",
|
||||||
description: t("home.devFolderScanning.desc", "Link to automated folder scanning guide"),
|
description: t("home.devFolderScanning.desc", "Link to automated folder scanning guide"),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.DEVELOPER_TOOLS,
|
subcategoryId: SubcategoryId.DEVELOPER_TOOLS,
|
||||||
link: "https://docs.stirlingpdf.com/Advanced%20Configuration/Folder%20Scanning/"
|
link: "https://docs.stirlingpdf.com/Advanced%20Configuration/Folder%20Scanning/"
|
||||||
},
|
},
|
||||||
"dev-sso-guide": {
|
"dev-sso-guide": {
|
||||||
@ -497,8 +496,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "external",
|
view: "external",
|
||||||
description: t("home.devSsoGuide.desc", "Link to SSO guide"),
|
description: t("home.devSsoGuide.desc", "Link to SSO guide"),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.DEVELOPER_TOOLS,
|
subcategoryId: SubcategoryId.DEVELOPER_TOOLS,
|
||||||
link: "https://docs.stirlingpdf.com/Advanced%20Configuration/Single%20Sign-On%20Configuration",
|
link: "https://docs.stirlingpdf.com/Advanced%20Configuration/Single%20Sign-On%20Configuration",
|
||||||
},
|
},
|
||||||
"dev-airgapped": {
|
"dev-airgapped": {
|
||||||
@ -507,8 +506,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "external",
|
view: "external",
|
||||||
description: t("home.devAirgapped.desc", "Link to air-gapped setup guide"),
|
description: t("home.devAirgapped.desc", "Link to air-gapped setup guide"),
|
||||||
category: ToolCategory.ADVANCED_TOOLS,
|
categoryId: ToolCategoryId.ADVANCED_TOOLS,
|
||||||
subcategory: SubcategoryId.DEVELOPER_TOOLS,
|
subcategoryId: SubcategoryId.DEVELOPER_TOOLS,
|
||||||
link: "https://docs.stirlingpdf.com/Pro/#activation"
|
link: "https://docs.stirlingpdf.com/Pro/#activation"
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -520,8 +519,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "format",
|
view: "format",
|
||||||
description: t("home.compare.desc", "Compare two PDF documents and highlight differences"),
|
description: t("home.compare.desc", "Compare two PDF documents and highlight differences"),
|
||||||
category: ToolCategory.RECOMMENDED_TOOLS,
|
categoryId: ToolCategoryId.RECOMMENDED_TOOLS,
|
||||||
subcategory: SubcategoryId.GENERAL
|
subcategoryId: SubcategoryId.GENERAL
|
||||||
},
|
},
|
||||||
"compress": {
|
"compress": {
|
||||||
icon: <span className="material-symbols-rounded">zoom_in_map</span>,
|
icon: <span className="material-symbols-rounded">zoom_in_map</span>,
|
||||||
@ -529,8 +528,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: CompressPdfPanel,
|
component: CompressPdfPanel,
|
||||||
view: "compress",
|
view: "compress",
|
||||||
description: t("home.compress.desc", "Compress PDFs to reduce their file size."),
|
description: t("home.compress.desc", "Compress PDFs to reduce their file size."),
|
||||||
category: ToolCategory.RECOMMENDED_TOOLS,
|
categoryId: ToolCategoryId.RECOMMENDED_TOOLS,
|
||||||
subcategory: SubcategoryId.GENERAL,
|
subcategoryId: SubcategoryId.GENERAL,
|
||||||
maxFiles: -1
|
maxFiles: -1
|
||||||
},
|
},
|
||||||
"convert": {
|
"convert": {
|
||||||
@ -539,8 +538,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: ConvertPanel,
|
component: ConvertPanel,
|
||||||
view: "convert",
|
view: "convert",
|
||||||
description: t("home.convert.desc", "Convert files to and from PDF format"),
|
description: t("home.convert.desc", "Convert files to and from PDF format"),
|
||||||
category: ToolCategory.RECOMMENDED_TOOLS,
|
categoryId: ToolCategoryId.RECOMMENDED_TOOLS,
|
||||||
subcategory: SubcategoryId.GENERAL,
|
subcategoryId: SubcategoryId.GENERAL,
|
||||||
maxFiles: -1,
|
maxFiles: -1,
|
||||||
endpoints: [
|
endpoints: [
|
||||||
"pdf-to-img",
|
"pdf-to-img",
|
||||||
@ -583,8 +582,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "merge",
|
view: "merge",
|
||||||
description: t("home.merge.desc", "Merge multiple PDFs into a single document"),
|
description: t("home.merge.desc", "Merge multiple PDFs into a single document"),
|
||||||
category: ToolCategory.RECOMMENDED_TOOLS,
|
categoryId: ToolCategoryId.RECOMMENDED_TOOLS,
|
||||||
subcategory: SubcategoryId.GENERAL,
|
subcategoryId: SubcategoryId.GENERAL,
|
||||||
maxFiles: -1
|
maxFiles: -1
|
||||||
},
|
},
|
||||||
"multi-tool": {
|
"multi-tool": {
|
||||||
@ -593,8 +592,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "pageEditor",
|
view: "pageEditor",
|
||||||
description: t("home.multiTool.desc", "Use multiple tools on a single PDF document"),
|
description: t("home.multiTool.desc", "Use multiple tools on a single PDF document"),
|
||||||
category: ToolCategory.RECOMMENDED_TOOLS,
|
categoryId: ToolCategoryId.RECOMMENDED_TOOLS,
|
||||||
subcategory: SubcategoryId.GENERAL,
|
subcategoryId: SubcategoryId.GENERAL,
|
||||||
maxFiles: -1
|
maxFiles: -1
|
||||||
},
|
},
|
||||||
"ocr": {
|
"ocr": {
|
||||||
@ -603,8 +602,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: OCRPanel,
|
component: OCRPanel,
|
||||||
view: "convert",
|
view: "convert",
|
||||||
description: t("home.ocr.desc", "Extract text from scanned PDFs using Optical Character Recognition"),
|
description: t("home.ocr.desc", "Extract text from scanned PDFs using Optical Character Recognition"),
|
||||||
category: ToolCategory.RECOMMENDED_TOOLS,
|
categoryId: ToolCategoryId.RECOMMENDED_TOOLS,
|
||||||
subcategory: SubcategoryId.GENERAL,
|
subcategoryId: SubcategoryId.GENERAL,
|
||||||
maxFiles: -1
|
maxFiles: -1
|
||||||
},
|
},
|
||||||
"redact": {
|
"redact": {
|
||||||
@ -613,8 +612,8 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
component: null,
|
component: null,
|
||||||
view: "redact",
|
view: "redact",
|
||||||
description: t("home.redact.desc", "Permanently remove sensitive information from PDF documents"),
|
description: t("home.redact.desc", "Permanently remove sensitive information from PDF documents"),
|
||||||
category: ToolCategory.RECOMMENDED_TOOLS,
|
categoryId: ToolCategoryId.RECOMMENDED_TOOLS,
|
||||||
subcategory: SubcategoryId.GENERAL
|
subcategoryId: SubcategoryId.GENERAL
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import CropIcon from '@mui/icons-material/Crop';
|
|||||||
import TextFieldsIcon from '@mui/icons-material/TextFields';
|
import TextFieldsIcon from '@mui/icons-material/TextFields';
|
||||||
|
|
||||||
export interface SuggestedTool {
|
export interface SuggestedTool {
|
||||||
name: string;
|
id: string /* FIX ME: Should be ToolId */;
|
||||||
title: string;
|
title: string;
|
||||||
icon: React.ComponentType<any>;
|
icon: React.ComponentType<any>;
|
||||||
navigate: () => void;
|
navigate: () => void;
|
||||||
@ -17,27 +17,27 @@ export interface SuggestedTool {
|
|||||||
|
|
||||||
const ALL_SUGGESTED_TOOLS: Omit<SuggestedTool, 'navigate'>[] = [
|
const ALL_SUGGESTED_TOOLS: Omit<SuggestedTool, 'navigate'>[] = [
|
||||||
{
|
{
|
||||||
name: 'compress',
|
id: 'compress',
|
||||||
title: 'Compress',
|
title: 'Compress',
|
||||||
icon: CompressIcon
|
icon: CompressIcon
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'convert',
|
id: 'convert',
|
||||||
title: 'Convert',
|
title: 'Convert',
|
||||||
icon: SwapHorizIcon
|
icon: SwapHorizIcon
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'sanitize',
|
id: 'sanitize',
|
||||||
title: 'Sanitize',
|
title: 'Sanitize',
|
||||||
icon: CleaningServicesIcon
|
icon: CleaningServicesIcon
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'split',
|
id: 'split',
|
||||||
title: 'Split',
|
title: 'Split',
|
||||||
icon: CropIcon
|
icon: CropIcon
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'ocr',
|
id: 'ocr',
|
||||||
title: 'OCR',
|
title: 'OCR',
|
||||||
icon: TextFieldsIcon
|
icon: TextFieldsIcon
|
||||||
}
|
}
|
||||||
@ -48,12 +48,12 @@ export function useSuggestedTools(): SuggestedTool[] {
|
|||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
// Filter out the current tool
|
// Filter out the current tool
|
||||||
const filteredTools = ALL_SUGGESTED_TOOLS.filter(tool => tool.name !== selectedToolKey);
|
const filteredTools = ALL_SUGGESTED_TOOLS.filter(tool => tool.id !== selectedToolKey);
|
||||||
|
|
||||||
// Add navigation function to each tool
|
// Add navigation function to each tool
|
||||||
return filteredTools.map(tool => ({
|
return filteredTools.map(tool => ({
|
||||||
...tool,
|
...tool,
|
||||||
navigate: () => handleToolSelect(tool.name)
|
navigate: () => handleToolSelect(tool.id)
|
||||||
}));
|
}));
|
||||||
}, [selectedToolKey, handleToolSelect]);
|
}, [selectedToolKey, handleToolSelect]);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ interface ToolManagementResult {
|
|||||||
export const useToolManagement = (): ToolManagementResult => {
|
export const useToolManagement = (): ToolManagementResult => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [selectedToolKey, setSelectedToolKey] = useState<string | null>(null);
|
const [selectedToolKey, setSelectedToolKey] = useState<string /* FIX ME: Should be ToolId */ | null>(null);
|
||||||
const [toolSelectedFileIds, setToolSelectedFileIds] = useState<string[]>([]);
|
const [toolSelectedFileIds, setToolSelectedFileIds] = useState<string[]>([]);
|
||||||
|
|
||||||
// Build endpoints list from registry entries with fallback to legacy mapping
|
// Build endpoints list from registry entries with fallback to legacy mapping
|
||||||
|
@ -1,65 +1,87 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { SUBCATEGORY_ORDER, ToolCategory, ToolRegistryEntry } from '../data/toolsTaxonomy';
|
import { SUBCATEGORY_ORDER, SubcategoryId, ToolCategoryId, ToolRegistryEntry } from '../data/toolsTaxonomy';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
type SubcategoryIdMap = {
|
||||||
|
[subcategoryId in SubcategoryId]: Array<{ id: string /* FIX ME: Should be ToolId */; tool: ToolRegistryEntry }>;
|
||||||
|
}
|
||||||
|
|
||||||
type GroupedTools = {
|
type GroupedTools = {
|
||||||
[category: string]: {
|
[categoryId in ToolCategoryId]: SubcategoryIdMap;
|
||||||
[subcategory: string]: Array<{ id: string; tool: ToolRegistryEntry }>;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useToolSections(filteredTools: [string, ToolRegistryEntry][]) {
|
export interface SubcategoryGroup {
|
||||||
|
subcategoryId: SubcategoryId;
|
||||||
|
tools: {
|
||||||
|
id: string /* FIX ME: Should be ToolId */;
|
||||||
|
tool: ToolRegistryEntry;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ToolSectionKey = 'quick' | 'all';
|
||||||
|
|
||||||
|
export interface ToolSection {
|
||||||
|
key: ToolSectionKey;
|
||||||
|
title: string;
|
||||||
|
subcategories: SubcategoryGroup[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useToolSections(filteredTools: [string /* FIX ME: Should be ToolId */, ToolRegistryEntry][]) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const groupedTools = useMemo(() => {
|
const groupedTools = useMemo(() => {
|
||||||
const grouped: GroupedTools = {};
|
const grouped = {} as GroupedTools;
|
||||||
filteredTools.forEach(([id, tool]) => {
|
filteredTools.forEach(([id, tool]) => {
|
||||||
const category = tool.category;
|
const categoryId = tool.categoryId;
|
||||||
const subcategory = tool.subcategory;
|
const subcategoryId = tool.subcategoryId;
|
||||||
if (!grouped[category]) grouped[category] = {};
|
if (!grouped[categoryId]) grouped[categoryId] = {} as SubcategoryIdMap;
|
||||||
if (!grouped[category][subcategory]) grouped[category][subcategory] = [];
|
if (!grouped[categoryId][subcategoryId]) grouped[categoryId][subcategoryId] = [];
|
||||||
grouped[category][subcategory].push({ id, tool });
|
grouped[categoryId][subcategoryId].push({ id, tool });
|
||||||
});
|
});
|
||||||
return grouped;
|
return grouped;
|
||||||
}, [filteredTools]);
|
}, [filteredTools]);
|
||||||
|
|
||||||
const sections = useMemo(() => {
|
const sections: ToolSection[] = useMemo(() => {
|
||||||
const getOrderIndex = (name: string) => {
|
const getOrderIndex = (id: SubcategoryId) => {
|
||||||
const idx = SUBCATEGORY_ORDER.indexOf(name as any);
|
const idx = SUBCATEGORY_ORDER.indexOf(id);
|
||||||
return idx === -1 ? Number.MAX_SAFE_INTEGER : idx;
|
return idx === -1 ? Number.MAX_SAFE_INTEGER : idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
const quick: Record<string, Array<{ id: string; tool: ToolRegistryEntry }>> = {};
|
const quick = {} as SubcategoryIdMap;
|
||||||
const all: Record<string, Array<{ id: string; tool: ToolRegistryEntry }>> = {};
|
const all = {} as SubcategoryIdMap;
|
||||||
|
|
||||||
Object.entries(groupedTools).forEach(([origCat, subs]) => {
|
Object.entries(groupedTools).forEach(([c, subs]) => {
|
||||||
const upperCat = origCat.toUpperCase();
|
const categoryId = c as ToolCategoryId;
|
||||||
|
|
||||||
Object.entries(subs).forEach(([sub, tools]) => {
|
Object.entries(subs).forEach(([s, tools]) => {
|
||||||
if (!all[sub]) all[sub] = [];
|
const subcategoryId = s as SubcategoryId;
|
||||||
all[sub].push(...tools);
|
if (!all[subcategoryId]) all[subcategoryId] = [];
|
||||||
|
all[subcategoryId].push(...tools);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (upperCat === ToolCategory.RECOMMENDED_TOOLS.toUpperCase()) {
|
if (categoryId === ToolCategoryId.RECOMMENDED_TOOLS) {
|
||||||
Object.entries(subs).forEach(([sub, tools]) => {
|
Object.entries(subs).forEach(([s, tools]) => {
|
||||||
if (!quick[sub]) quick[sub] = [];
|
const subcategoryId = s as SubcategoryId;
|
||||||
quick[sub].push(...tools);
|
if (!quick[subcategoryId]) quick[subcategoryId] = [];
|
||||||
|
quick[subcategoryId].push(...tools);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const sortSubs = (obj: Record<string, Array<{ id: string; tool: ToolRegistryEntry }>>) =>
|
const sortSubs = (obj: SubcategoryIdMap) =>
|
||||||
Object.entries(obj)
|
Object.entries(obj)
|
||||||
.sort(([a], [b]) => {
|
.sort(([a], [b]) => {
|
||||||
const ai = getOrderIndex(a);
|
const aId = a as SubcategoryId;
|
||||||
const bi = getOrderIndex(b);
|
const bId = b as SubcategoryId;
|
||||||
|
const ai = getOrderIndex(aId);
|
||||||
|
const bi = getOrderIndex(bId);
|
||||||
if (ai !== bi) return ai - bi;
|
if (ai !== bi) return ai - bi;
|
||||||
return a.localeCompare(b);
|
return aId.localeCompare(bId);
|
||||||
})
|
})
|
||||||
.map(([subcategory, tools]) => ({ subcategory, tools }));
|
.map(([subcategoryId, tools]) => ({ subcategoryId, tools } as SubcategoryGroup));
|
||||||
|
|
||||||
const built = [
|
const built: ToolSection[] = [
|
||||||
{ key: 'quick', title: t('toolPicker.quickAccess', 'QUICK ACCESS'), subcategories: sortSubs(quick) },
|
{ key: 'quick', title: t('toolPicker.quickAccess', 'QUICK ACCESS'), subcategories: sortSubs(quick) },
|
||||||
{ key: 'all', title: t('toolPicker.allTools', 'ALL TOOLS'), subcategories: sortSubs(all) }
|
{ key: 'all', title: t('toolPicker.allTools', 'ALL TOOLS'), subcategories: sortSubs(all) }
|
||||||
];
|
];
|
||||||
@ -67,19 +89,20 @@ export function useToolSections(filteredTools: [string, ToolRegistryEntry][]) {
|
|||||||
return built.filter(section => section.subcategories.some(sc => sc.tools.length > 0));
|
return built.filter(section => section.subcategories.some(sc => sc.tools.length > 0));
|
||||||
}, [groupedTools]);
|
}, [groupedTools]);
|
||||||
|
|
||||||
const searchGroups = useMemo(() => {
|
const searchGroups: SubcategoryGroup[] = useMemo(() => {
|
||||||
const subMap: Record<string, Array<{ id: string; tool: ToolRegistryEntry }>> = {};
|
const subMap = {} as SubcategoryIdMap;
|
||||||
const seen = new Set<string>();
|
const seen = new Set<string /* FIX ME: Should be ToolId */>();
|
||||||
filteredTools.forEach(([id, tool]) => {
|
filteredTools.forEach(([id, tool]) => {
|
||||||
if (seen.has(id)) return;
|
const toolId = id as string /* FIX ME: Should be ToolId */;
|
||||||
seen.add(id);
|
if (seen.has(toolId)) return;
|
||||||
const sub = tool.subcategory;
|
seen.add(toolId);
|
||||||
|
const sub = tool.subcategoryId;
|
||||||
if (!subMap[sub]) subMap[sub] = [];
|
if (!subMap[sub]) subMap[sub] = [];
|
||||||
subMap[sub].push({ id, tool });
|
subMap[sub].push({ id: toolId, tool });
|
||||||
});
|
});
|
||||||
return Object.entries(subMap)
|
return Object.entries(subMap)
|
||||||
.sort(([a], [b]) => a.localeCompare(b))
|
.sort(([a], [b]) => a.localeCompare(b))
|
||||||
.map(([subcategory, tools]) => ({ subcategory, tools }));
|
.map(([subcategoryId, tools]) => ({ subcategoryId, tools } as SubcategoryGroup));
|
||||||
}, [filteredTools]);
|
}, [filteredTools]);
|
||||||
|
|
||||||
return { sections, searchGroups };
|
return { sections, searchGroups };
|
||||||
|
Loading…
x
Reference in New Issue
Block a user