mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-09-18 09:29:24 +00:00
Redesign tools to be data-driven
This commit is contained in:
parent
1a3e8e7ecf
commit
a16ee308e5
@ -669,7 +669,16 @@
|
|||||||
"8": "Document #6: Page 10"
|
"8": "Document #6: Page 10"
|
||||||
},
|
},
|
||||||
"splitPages": "Enter pages to split on:",
|
"splitPages": "Enter pages to split on:",
|
||||||
"submit": "Split"
|
"submit": "Split",
|
||||||
|
"settings": {
|
||||||
|
"title": "Split"
|
||||||
|
},
|
||||||
|
"results": {
|
||||||
|
"title": "Split Results"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"failed": "An error occurred while splitting the PDF."
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"rotate": {
|
"rotate": {
|
||||||
"tags": "server side",
|
"tags": "server side",
|
||||||
@ -1787,7 +1796,32 @@
|
|||||||
"4": "Auto mode - Auto adjusts quality to get PDF to exact size",
|
"4": "Auto mode - Auto adjusts quality to get PDF to exact size",
|
||||||
"5": "Expected PDF Size (e.g. 25MB, 10.8MB, 25KB)"
|
"5": "Expected PDF Size (e.g. 25MB, 10.8MB, 25KB)"
|
||||||
},
|
},
|
||||||
"submit": "Compress"
|
"submit": "Compress",
|
||||||
|
"tooltip": {
|
||||||
|
"header": {
|
||||||
|
"title": "Compress Settings Overview"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"title": "Description",
|
||||||
|
"text": "Compression is an easy way to reduce your file size. Pick File Size to enter a target size and have us adjust quality for you. Pick Quality to set compression strength manually."
|
||||||
|
},
|
||||||
|
"qualityAdjustment": {
|
||||||
|
"title": "Quality Adjustment",
|
||||||
|
"text": "Drag the slider to adjust the compression strength. Lower values (1-3) preserve quality but result in larger files. Higher values (7-9) shrink the file more but reduce image clarity.",
|
||||||
|
"bullet1": "Lower values preserve quality",
|
||||||
|
"bullet2": "Higher values reduce file size"
|
||||||
|
},
|
||||||
|
"grayscale": {
|
||||||
|
"title": "Grayscale",
|
||||||
|
"text": "Select this option to convert all images to black and white, which can significantly reduce file size especially for scanned PDFs or image-heavy documents."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"title": "Settings"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"failed": "An error occurred while compressing the PDF."
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"decrypt": {
|
"decrypt": {
|
||||||
"passwordPrompt": "This file is password-protected. Please enter the password:",
|
"passwordPrompt": "This file is password-protected. Please enter the password:",
|
||||||
|
69
frontend/src/components/tools/shared/GenericTool.tsx
Normal file
69
frontend/src/components/tools/shared/GenericTool.tsx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { GenericToolProps } from './toolDefinition';
|
||||||
|
import { useBaseTool } from '../../../hooks/tools/shared/useBaseTool';
|
||||||
|
import { createToolFlow, MiddleStepConfig } from './createToolFlow';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic tool component that renders any tool from its definition.
|
||||||
|
* Eliminates boilerplate by using declarative configuration.
|
||||||
|
*/
|
||||||
|
function GenericTool<TParams>(props: GenericToolProps<TParams>) {
|
||||||
|
const { definition } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
// Use the base tool hook with the definition's hooks
|
||||||
|
const base = useBaseTool(
|
||||||
|
definition.id,
|
||||||
|
definition.useParameters,
|
||||||
|
definition.useOperation,
|
||||||
|
props
|
||||||
|
);
|
||||||
|
|
||||||
|
// Build steps from definition - filter and map in separate operations for better typing
|
||||||
|
const visibleSteps = definition.steps.filter((stepDef) => {
|
||||||
|
const isVisible = typeof stepDef.isVisible === 'function'
|
||||||
|
? stepDef.isVisible(base.params.parameters, base.hasFiles, base.hasResults)
|
||||||
|
: stepDef.isVisible ?? true;
|
||||||
|
return isVisible;
|
||||||
|
});
|
||||||
|
|
||||||
|
const steps: MiddleStepConfig[] = visibleSteps.map((stepDef) => ({
|
||||||
|
title: stepDef.title(t),
|
||||||
|
isCollapsed: base.settingsCollapsed,
|
||||||
|
onCollapsedClick: base.hasResults ? base.handleSettingsReset : undefined,
|
||||||
|
tooltip: stepDef.tooltip?.(t),
|
||||||
|
content: (
|
||||||
|
<stepDef.component
|
||||||
|
parameters={base.params.parameters}
|
||||||
|
onParameterChange={base.params.updateParameter}
|
||||||
|
disabled={base.endpointLoading}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
|
||||||
|
return createToolFlow({
|
||||||
|
files: {
|
||||||
|
selectedFiles: base.selectedFiles,
|
||||||
|
isCollapsed: base.hasResults,
|
||||||
|
},
|
||||||
|
steps,
|
||||||
|
executeButton: {
|
||||||
|
text: definition.executeButton.text(t),
|
||||||
|
isVisible: !base.hasResults,
|
||||||
|
loadingText: definition.executeButton.loadingText?.(t) || t("loading"),
|
||||||
|
onClick: base.handleExecute,
|
||||||
|
disabled: !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled,
|
||||||
|
testId: definition.executeButton.testId,
|
||||||
|
},
|
||||||
|
review: {
|
||||||
|
isVisible: base.hasResults,
|
||||||
|
operation: base.operation,
|
||||||
|
title: definition.review.title(t),
|
||||||
|
onFileClick: base.handleThumbnailClick,
|
||||||
|
onUndo: base.handleUndo,
|
||||||
|
testId: definition.review.testId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GenericTool;
|
119
frontend/src/components/tools/shared/toolDefinition.ts
Normal file
119
frontend/src/components/tools/shared/toolDefinition.ts
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { TFunction } from 'i18next';
|
||||||
|
import { BaseParametersHook } from '../../../hooks/tools/shared/useBaseParameters';
|
||||||
|
import { ToolOperationHook } from '../../../hooks/tools/shared/useToolOperation';
|
||||||
|
import { BaseToolProps } from '../../../types/tool';
|
||||||
|
import { TooltipTip } from '../../../types/tips';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for a single tool step/section
|
||||||
|
*/
|
||||||
|
export interface ToolStepDefinition<TParams> {
|
||||||
|
/** Unique identifier for this step */
|
||||||
|
key: string;
|
||||||
|
|
||||||
|
/** Display title for the step */
|
||||||
|
title: (t: TFunction) => string;
|
||||||
|
|
||||||
|
/** Settings component to render in this step */
|
||||||
|
component: React.ComponentType<{
|
||||||
|
parameters: TParams;
|
||||||
|
onParameterChange: (key: keyof TParams, value: TParams[keyof TParams]) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
/** Tooltip configuration for this step */
|
||||||
|
tooltip?: (t: TFunction) => {
|
||||||
|
content?: React.ReactNode;
|
||||||
|
tips?: TooltipTip[];
|
||||||
|
header?: {
|
||||||
|
title: string;
|
||||||
|
logo?: React.ReactNode;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Whether this step is visible (defaults to true) */
|
||||||
|
isVisible?: boolean | ((params: TParams, hasFiles: boolean, hasResults: boolean) => boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for the execute button
|
||||||
|
*/
|
||||||
|
export interface ToolExecuteButtonDefinition {
|
||||||
|
/** Button text */
|
||||||
|
text: (t: TFunction) => string;
|
||||||
|
|
||||||
|
/** Loading state text */
|
||||||
|
loadingText?: (t: TFunction) => string;
|
||||||
|
|
||||||
|
/** Test ID for the button */
|
||||||
|
testId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for the review/results section
|
||||||
|
*/
|
||||||
|
export interface ToolReviewDefinition {
|
||||||
|
/** Title for the review section */
|
||||||
|
title: (t: TFunction) => string;
|
||||||
|
|
||||||
|
/** Test ID for the review section */
|
||||||
|
testId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Complete tool definition for declarative tool creation
|
||||||
|
*/
|
||||||
|
export interface ToolDefinition<TParams> {
|
||||||
|
/** Unique tool identifier */
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/** Hook that provides parameter management */
|
||||||
|
useParameters: () => BaseParametersHook<TParams>;
|
||||||
|
|
||||||
|
/** Hook that provides operation execution */
|
||||||
|
useOperation: () => ToolOperationHook<TParams>;
|
||||||
|
|
||||||
|
/** Configuration steps for the tool */
|
||||||
|
steps: ToolStepDefinition<TParams>[];
|
||||||
|
|
||||||
|
/** Execute button configuration */
|
||||||
|
executeButton: ToolExecuteButtonDefinition;
|
||||||
|
|
||||||
|
/** Review section configuration */
|
||||||
|
review: ToolReviewDefinition;
|
||||||
|
|
||||||
|
/** Optional tooltip for when using this tool */
|
||||||
|
tooltip?: (t: TFunction) => {
|
||||||
|
content?: React.ReactNode;
|
||||||
|
tips?: TooltipTip[];
|
||||||
|
header?: {
|
||||||
|
title: string;
|
||||||
|
logo?: React.ReactNode;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Props for GenericTool component
|
||||||
|
*/
|
||||||
|
export interface GenericToolProps<TParams> extends BaseToolProps {
|
||||||
|
/** Tool definition to render */
|
||||||
|
definition: ToolDefinition<TParams>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registry entry for a tool
|
||||||
|
*/
|
||||||
|
export interface ToolRegistryEntry<TParams> {
|
||||||
|
/** Tool definition */
|
||||||
|
definition: ToolDefinition<TParams>;
|
||||||
|
|
||||||
|
/** Display metadata */
|
||||||
|
metadata: {
|
||||||
|
name: string;
|
||||||
|
category: string;
|
||||||
|
description?: string;
|
||||||
|
icon?: React.ReactNode;
|
||||||
|
};
|
||||||
|
}
|
@ -1,30 +0,0 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { TooltipContent } from '../../types/tips';
|
|
||||||
|
|
||||||
export const useCompressTips = (): TooltipContent => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return {
|
|
||||||
header: {
|
|
||||||
title: t("compress.tooltip.header.title", "Compress Settings Overview")
|
|
||||||
},
|
|
||||||
tips: [
|
|
||||||
{
|
|
||||||
title: t("compress.tooltip.description.title", "Description"),
|
|
||||||
description: t("compress.tooltip.description.text", "Compression is an easy way to reduce your file size. Pick File Size to enter a target size and have us adjust quality for you. Pick Quality to set compression strength manually.")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("compress.tooltip.qualityAdjustment.title", "Quality Adjustment"),
|
|
||||||
description: t("compress.tooltip.qualityAdjustment.text", "Drag the slider to adjust the compression strength. Lower values (1-3) preserve quality but result in larger files. Higher values (7-9) shrink the file more but reduce image clarity."),
|
|
||||||
bullets: [
|
|
||||||
t("compress.tooltip.qualityAdjustment.bullet1", "Lower values preserve quality"),
|
|
||||||
t("compress.tooltip.qualityAdjustment.bullet2", "Higher values reduce file size")
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t("compress.tooltip.grayscale.title", "Grayscale"),
|
|
||||||
description: t("compress.tooltip.grayscale.text", "Select this option to convert all images to black and white, which can significantly reduce file size especially for scanned PDFs or image-heavy documents.")
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,59 +1,12 @@
|
|||||||
import { useTranslation } from "react-i18next";
|
import GenericTool from '../components/tools/shared/GenericTool';
|
||||||
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
import { compressDefinition } from './definitions/compressDefinition';
|
||||||
import CompressSettings from "../components/tools/compress/CompressSettings";
|
import { BaseToolProps, ToolComponent } from '../types/tool';
|
||||||
import { useCompressParameters } from "../hooks/tools/compress/useCompressParameters";
|
|
||||||
import { useCompressOperation } from "../hooks/tools/compress/useCompressOperation";
|
|
||||||
import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
|
|
||||||
import { BaseToolProps, ToolComponent } from "../types/tool";
|
|
||||||
import { useCompressTips } from "../components/tooltips/useCompressTips";
|
|
||||||
|
|
||||||
const Compress = (props: BaseToolProps) => {
|
const Compress = (props: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
return <GenericTool definition={compressDefinition} {...props} />;
|
||||||
const compressTips = useCompressTips();
|
|
||||||
|
|
||||||
const base = useBaseTool(
|
|
||||||
'compress',
|
|
||||||
useCompressParameters,
|
|
||||||
useCompressOperation,
|
|
||||||
props
|
|
||||||
);
|
|
||||||
|
|
||||||
return createToolFlow({
|
|
||||||
files: {
|
|
||||||
selectedFiles: base.selectedFiles,
|
|
||||||
isCollapsed: base.hasResults,
|
|
||||||
},
|
|
||||||
steps: [
|
|
||||||
{
|
|
||||||
title: "Settings",
|
|
||||||
isCollapsed: base.settingsCollapsed,
|
|
||||||
onCollapsedClick: base.settingsCollapsed ? base.handleSettingsReset : undefined,
|
|
||||||
tooltip: compressTips,
|
|
||||||
content: (
|
|
||||||
<CompressSettings
|
|
||||||
parameters={base.params.parameters}
|
|
||||||
onParameterChange={base.params.updateParameter}
|
|
||||||
disabled={base.endpointLoading}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
executeButton: {
|
|
||||||
text: t("compress.submit", "Compress"),
|
|
||||||
isVisible: !base.hasResults,
|
|
||||||
loadingText: t("loading"),
|
|
||||||
onClick: base.handleExecute,
|
|
||||||
disabled: !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled,
|
|
||||||
},
|
|
||||||
review: {
|
|
||||||
isVisible: base.hasResults,
|
|
||||||
operation: base.operation,
|
|
||||||
title: t("compress.title", "Compression Results"),
|
|
||||||
onFileClick: base.handleThumbnailClick,
|
|
||||||
onUndo: base.handleUndo,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Static method to get the operation hook for automation
|
||||||
|
Compress.tool = () => compressDefinition.useOperation;
|
||||||
|
|
||||||
export default Compress as ToolComponent;
|
export default Compress as ToolComponent;
|
||||||
|
@ -1,45 +1,12 @@
|
|||||||
import { useTranslation } from "react-i18next";
|
import GenericTool from '../components/tools/shared/GenericTool';
|
||||||
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
import { repairDefinition } from './definitions/repairDefinition';
|
||||||
import { useRepairParameters } from "../hooks/tools/repair/useRepairParameters";
|
import { BaseToolProps, ToolComponent } from '../types/tool';
|
||||||
import { useRepairOperation } from "../hooks/tools/repair/useRepairOperation";
|
|
||||||
import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
|
|
||||||
import { BaseToolProps, ToolComponent } from "../types/tool";
|
|
||||||
|
|
||||||
const Repair = (props: BaseToolProps) => {
|
const Repair = (props: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
return <GenericTool definition={repairDefinition} {...props} />;
|
||||||
|
|
||||||
const base = useBaseTool(
|
|
||||||
'repair',
|
|
||||||
useRepairParameters,
|
|
||||||
useRepairOperation,
|
|
||||||
props
|
|
||||||
);
|
|
||||||
|
|
||||||
return createToolFlow({
|
|
||||||
files: {
|
|
||||||
selectedFiles: base.selectedFiles,
|
|
||||||
isCollapsed: base.hasResults,
|
|
||||||
placeholder: t("repair.files.placeholder", "Select a PDF file in the main view to get started"),
|
|
||||||
},
|
|
||||||
steps: [],
|
|
||||||
executeButton: {
|
|
||||||
text: t("repair.submit", "Repair PDF"),
|
|
||||||
isVisible: !base.hasResults,
|
|
||||||
loadingText: t("loading"),
|
|
||||||
onClick: base.handleExecute,
|
|
||||||
disabled: !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled,
|
|
||||||
},
|
|
||||||
review: {
|
|
||||||
isVisible: base.hasResults,
|
|
||||||
operation: base.operation,
|
|
||||||
title: t("repair.results.title", "Repair Results"),
|
|
||||||
onFileClick: base.handleThumbnailClick,
|
|
||||||
onUndo: base.handleUndo,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Static method to get the operation hook for automation
|
// Static method to get the operation hook for automation
|
||||||
Repair.tool = () => useRepairOperation;
|
Repair.tool = () => repairDefinition.useOperation;
|
||||||
|
|
||||||
export default Repair as ToolComponent;
|
export default Repair as ToolComponent;
|
||||||
|
@ -1,56 +1,12 @@
|
|||||||
import { useEffect } from "react";
|
import GenericTool from '../components/tools/shared/GenericTool';
|
||||||
import { useTranslation } from "react-i18next";
|
import { splitDefinition } from './definitions/splitDefinition';
|
||||||
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
import { BaseToolProps, ToolComponent } from '../types/tool';
|
||||||
import SplitSettings from "../components/tools/split/SplitSettings";
|
|
||||||
import { useSplitParameters } from "../hooks/tools/split/useSplitParameters";
|
|
||||||
import { useSplitOperation } from "../hooks/tools/split/useSplitOperation";
|
|
||||||
import { useBaseTool } from "../hooks/tools/shared/useBaseTool";
|
|
||||||
import { BaseToolProps, ToolComponent } from "../types/tool";
|
|
||||||
|
|
||||||
const Split = (props: BaseToolProps) => {
|
const Split = (props: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
return <GenericTool definition={splitDefinition} {...props} />;
|
||||||
|
|
||||||
const base = useBaseTool(
|
|
||||||
'split',
|
|
||||||
useSplitParameters,
|
|
||||||
useSplitOperation,
|
|
||||||
props
|
|
||||||
);
|
|
||||||
|
|
||||||
return createToolFlow({
|
|
||||||
files: {
|
|
||||||
selectedFiles: base.selectedFiles,
|
|
||||||
isCollapsed: base.hasResults,
|
|
||||||
},
|
|
||||||
steps: [
|
|
||||||
{
|
|
||||||
title: "Settings",
|
|
||||||
isCollapsed: base.settingsCollapsed,
|
|
||||||
onCollapsedClick: base.hasResults ? base.handleSettingsReset : undefined,
|
|
||||||
content: (
|
|
||||||
<SplitSettings
|
|
||||||
parameters={base.params.parameters}
|
|
||||||
onParameterChange={base.params.updateParameter}
|
|
||||||
disabled={base.endpointLoading}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
executeButton: {
|
|
||||||
text: t("split.submit", "Split PDF"),
|
|
||||||
loadingText: t("loading"),
|
|
||||||
onClick: base.handleExecute,
|
|
||||||
isVisible: !base.hasResults,
|
|
||||||
disabled: !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled,
|
|
||||||
},
|
|
||||||
review: {
|
|
||||||
isVisible: base.hasResults,
|
|
||||||
operation: base.operation,
|
|
||||||
title: "Split Results",
|
|
||||||
onFileClick: base.handleThumbnailClick,
|
|
||||||
onUndo: base.handleUndo,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Static method to get the operation hook for automation
|
||||||
|
Split.tool = () => splitDefinition.useOperation;
|
||||||
|
|
||||||
export default Split as ToolComponent;
|
export default Split as ToolComponent;
|
||||||
|
51
frontend/src/tools/definitions/compressDefinition.ts
Normal file
51
frontend/src/tools/definitions/compressDefinition.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { ToolDefinition } from '../../components/tools/shared/toolDefinition';
|
||||||
|
import { CompressParameters, useCompressParameters } from '../../hooks/tools/compress/useCompressParameters';
|
||||||
|
import { useCompressOperation } from '../../hooks/tools/compress/useCompressOperation';
|
||||||
|
import CompressSettings from '../../components/tools/compress/CompressSettings';
|
||||||
|
|
||||||
|
export const compressDefinition: ToolDefinition<CompressParameters> = {
|
||||||
|
id: 'compress',
|
||||||
|
|
||||||
|
useParameters: useCompressParameters,
|
||||||
|
useOperation: useCompressOperation,
|
||||||
|
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
key: 'settings',
|
||||||
|
title: (t) => t("compress.settings.title", "Settings"),
|
||||||
|
component: CompressSettings,
|
||||||
|
tooltip: (t) => ({
|
||||||
|
header: {
|
||||||
|
title: t("compress.tooltip.header.title", "Compress Settings Overview")
|
||||||
|
},
|
||||||
|
tips: [
|
||||||
|
{
|
||||||
|
title: t("compress.tooltip.description.title", "Description"),
|
||||||
|
description: t("compress.tooltip.description.text", "Compression is an easy way to reduce your file size. Pick File Size to enter a target size and have us adjust quality for you. Pick Quality to set compression strength manually.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("compress.tooltip.qualityAdjustment.title", "Quality Adjustment"),
|
||||||
|
description: t("compress.tooltip.qualityAdjustment.text", "Drag the slider to adjust the compression strength. Lower values (1-3) preserve quality but result in larger files. Higher values (7-9) shrink the file more but reduce image clarity."),
|
||||||
|
bullets: [
|
||||||
|
t("compress.tooltip.qualityAdjustment.bullet1", "Lower values preserve quality"),
|
||||||
|
t("compress.tooltip.qualityAdjustment.bullet2", "Higher values reduce file size")
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("compress.tooltip.grayscale.title", "Grayscale"),
|
||||||
|
description: t("compress.tooltip.grayscale.text", "Select this option to convert all images to black and white, which can significantly reduce file size especially for scanned PDFs or image-heavy documents.")
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
executeButton: {
|
||||||
|
text: (t) => t("compress.submit", "Compress"),
|
||||||
|
loadingText: (t) => t("loading"),
|
||||||
|
},
|
||||||
|
|
||||||
|
review: {
|
||||||
|
title: (t) => t("compress.title", "Compression Results"),
|
||||||
|
},
|
||||||
|
};
|
28
frontend/src/tools/definitions/repairDefinition.ts
Normal file
28
frontend/src/tools/definitions/repairDefinition.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { ToolDefinition } from '../../components/tools/shared/toolDefinition';
|
||||||
|
import { RepairParameters, useRepairParameters } from '../../hooks/tools/repair/useRepairParameters';
|
||||||
|
import { useRepairOperation } from '../../hooks/tools/repair/useRepairOperation';
|
||||||
|
import RepairSettings from '../../components/tools/repair/RepairSettings';
|
||||||
|
|
||||||
|
export const repairDefinition: ToolDefinition<RepairParameters> = {
|
||||||
|
id: 'repair',
|
||||||
|
|
||||||
|
useParameters: useRepairParameters,
|
||||||
|
useOperation: useRepairOperation,
|
||||||
|
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
key: 'settings',
|
||||||
|
title: (t) => t("repair.settings.title", "Settings"),
|
||||||
|
component: RepairSettings,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
executeButton: {
|
||||||
|
text: (t) => t("repair.submit", "Repair PDF"),
|
||||||
|
loadingText: (t) => t("loading"),
|
||||||
|
},
|
||||||
|
|
||||||
|
review: {
|
||||||
|
title: (t) => t("repair.results.title", "Repair Results"),
|
||||||
|
},
|
||||||
|
};
|
28
frontend/src/tools/definitions/splitDefinition.ts
Normal file
28
frontend/src/tools/definitions/splitDefinition.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { ToolDefinition } from '../../components/tools/shared/toolDefinition';
|
||||||
|
import { SplitParameters, useSplitParameters } from '../../hooks/tools/split/useSplitParameters';
|
||||||
|
import { useSplitOperation } from '../../hooks/tools/split/useSplitOperation';
|
||||||
|
import SplitSettings from '../../components/tools/split/SplitSettings';
|
||||||
|
|
||||||
|
export const splitDefinition: ToolDefinition<SplitParameters> = {
|
||||||
|
id: 'split',
|
||||||
|
|
||||||
|
useParameters: useSplitParameters,
|
||||||
|
useOperation: useSplitOperation,
|
||||||
|
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
key: 'settings',
|
||||||
|
title: (t) => t("split.settings.title", "Settings"),
|
||||||
|
component: SplitSettings,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
executeButton: {
|
||||||
|
text: (t) => t("split.submit", "Split PDF"),
|
||||||
|
loadingText: (t) => t("loading"),
|
||||||
|
},
|
||||||
|
|
||||||
|
review: {
|
||||||
|
title: (t) => t("split.results.title", "Split Results"),
|
||||||
|
},
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user