diff --git a/frontend/src/components/shared/FileUploadButton.tsx b/frontend/src/components/shared/FileUploadButton.tsx
new file mode 100644
index 000000000..da7c3793a
--- /dev/null
+++ b/frontend/src/components/shared/FileUploadButton.tsx
@@ -0,0 +1,45 @@
+import React, { useRef } from "react";
+import { FileButton, Button } from "@mantine/core";
+import { useTranslation } from "react-i18next";
+
+interface FileUploadButtonProps {
+ file?: File;
+ onChange: (file: File | null) => void;
+ accept?: string;
+ disabled?: boolean;
+ placeholder?: string;
+ variant?: "outline" | "filled" | "light" | "default" | "subtle" | "gradient";
+ fullWidth?: boolean;
+}
+
+const FileUploadButton = ({
+ file,
+ onChange,
+ accept = "*/*",
+ disabled = false,
+ placeholder,
+ variant = "outline",
+ fullWidth = true
+}: FileUploadButtonProps) => {
+ const { t } = useTranslation();
+ const resetRef = useRef<() => void>(null);
+
+ const defaultPlaceholder = t('common.chooseFile', 'Choose File');
+
+ return (
+
+ {(props) => (
+
+ )}
+
+ );
+};
+
+export default FileUploadButton;
\ No newline at end of file
diff --git a/frontend/src/components/tools/addWatermark/AddWatermarkSettings.tsx b/frontend/src/components/tools/addWatermark/AddWatermarkSettings.tsx
deleted file mode 100644
index 3dcc63bfe..000000000
--- a/frontend/src/components/tools/addWatermark/AddWatermarkSettings.tsx
+++ /dev/null
@@ -1,174 +0,0 @@
-import React, { useRef } from "react";
-import { Button, Stack, Text, NumberInput, Select, TextInput, FileButton } from "@mantine/core";
-import { useTranslation } from "react-i18next";
-
-interface AddWatermarkParameters {
- watermarkType: 'text' | 'image';
- watermarkText: string;
- watermarkImage?: File;
- fontSize: number;
- rotation: number;
- opacity: number;
- widthSpacer: number;
- heightSpacer: number;
- position: string;
- overrideX?: number;
- overrideY?: number;
-}
-
-interface AddWatermarkSettingsProps {
- parameters: AddWatermarkParameters;
- onParameterChange: (key: keyof AddWatermarkParameters, value: any) => void;
- disabled?: boolean;
-}
-
-const AddWatermarkSettings = ({ parameters, onParameterChange, disabled = false }: AddWatermarkSettingsProps) => {
- const { t } = useTranslation();
- const resetRef = useRef<() => void>(null);
-
- const positionOptions = [
- { value: 'topLeft', label: 'Top Left' },
- { value: 'topCenter', label: 'Top Center' },
- { value: 'topRight', label: 'Top Right' },
- { value: 'centerLeft', label: 'Center Left' },
- { value: 'center', label: 'Center' },
- { value: 'centerRight', label: 'Center Right' },
- { value: 'bottomLeft', label: 'Bottom Left' },
- { value: 'bottomCenter', label: 'Bottom Center' },
- { value: 'bottomRight', label: 'Bottom Right' }
- ];
-
- return (
-
- {/* Watermark Type Selection */}
-
- Watermark Type
-
-
-
-
-
-
- {/* Text Watermark Settings */}
- {parameters.watermarkType === 'text' && (
-
- Watermark Text
- onParameterChange('watermarkText', e.target.value)}
- disabled={disabled}
- />
-
- Font Size
- onParameterChange('fontSize', value || 12)}
- min={8}
- max={72}
- disabled={disabled}
- />
-
- )}
-
- {/* Image Watermark Settings */}
- {parameters.watermarkType === 'image' && (
-
- Watermark Image
- onParameterChange('watermarkImage', file)}
- accept="image/*"
- disabled={disabled}
- >
- {(props) => (
-
- )}
-
- {parameters.watermarkImage && (
-
- Selected: {parameters.watermarkImage.name}
-
- )}
-
- )}
-
- {/* Position Settings */}
-
- Position
-
-
- {/* Appearance Settings */}
-
- Rotation (degrees)
- onParameterChange('rotation', value || 0)}
- min={-360}
- max={360}
- disabled={disabled}
- />
-
- Opacity (%)
- onParameterChange('opacity', value || 50)}
- min={0}
- max={100}
- disabled={disabled}
- />
-
-
- {/* Spacing Settings */}
-
- Width Spacing
- onParameterChange('widthSpacer', value || 50)}
- min={0}
- max={200}
- disabled={disabled}
- />
-
- Height Spacing
- onParameterChange('heightSpacer', value || 50)}
- min={0}
- max={200}
- disabled={disabled}
- />
-
-
- );
-};
-
-export default AddWatermarkSettings;
\ No newline at end of file
diff --git a/frontend/src/components/tools/addWatermark/WatermarkAdvancedSettings.tsx b/frontend/src/components/tools/addWatermark/WatermarkAdvancedSettings.tsx
deleted file mode 100644
index a691471a0..000000000
--- a/frontend/src/components/tools/addWatermark/WatermarkAdvancedSettings.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from "react";
-import { Stack, Checkbox } from "@mantine/core";
-import { useTranslation } from "react-i18next";
-import { AddWatermarkParameters } from "./types";
-
-interface WatermarkAdvancedSettingsProps {
- parameters: AddWatermarkParameters;
- onParameterChange: (key: keyof AddWatermarkParameters, value: any) => void;
- disabled?: boolean;
-}
-
-const WatermarkAdvancedSettings = ({ parameters, onParameterChange, disabled = false }: WatermarkAdvancedSettingsProps) => {
- const { t } = useTranslation();
-
- return (
-
- {/* Output Options */}
- onParameterChange('convertPDFToImage', event.currentTarget.checked)}
- disabled={disabled}
- />
-
- );
-};
-
-export default WatermarkAdvancedSettings;
\ No newline at end of file
diff --git a/frontend/src/components/tools/addWatermark/WatermarkFile.tsx b/frontend/src/components/tools/addWatermark/WatermarkFile.tsx
index 8aa27f28b..8c1428800 100644
--- a/frontend/src/components/tools/addWatermark/WatermarkFile.tsx
+++ b/frontend/src/components/tools/addWatermark/WatermarkFile.tsx
@@ -1,7 +1,8 @@
-import React, { useRef } from "react";
-import { Stack, Text, FileButton, Button } from "@mantine/core";
+import React from "react";
+import { Stack } from "@mantine/core";
import { useTranslation } from "react-i18next";
-import { AddWatermarkParameters } from "./types";
+import { AddWatermarkParameters } from "../../../hooks/tools/addWatermark/useAddWatermarkParameters";
+import FileUploadButton from "../../shared/FileUploadButton";
interface WatermarkFileProps {
parameters: AddWatermarkParameters;
@@ -11,22 +12,16 @@ interface WatermarkFileProps {
const WatermarkFile = ({ parameters, onParameterChange, disabled = false }: WatermarkFileProps) => {
const { t } = useTranslation();
- const resetRef = useRef<() => void>(null);
return (
- onParameterChange('watermarkImage', file)}
accept="image/*"
disabled={disabled}
- >
- {(props) => (
-
- )}
-
+ placeholder={t('watermark.settings.image.choose', 'Choose Image')}
+ />
);
};
diff --git a/frontend/src/components/tools/addWatermark/WatermarkFormatting.tsx b/frontend/src/components/tools/addWatermark/WatermarkFormatting.tsx
index 42e382559..a570efb19 100644
--- a/frontend/src/components/tools/addWatermark/WatermarkFormatting.tsx
+++ b/frontend/src/components/tools/addWatermark/WatermarkFormatting.tsx
@@ -1,7 +1,7 @@
import React from "react";
import { Stack, Checkbox, Group } from "@mantine/core";
import { useTranslation } from "react-i18next";
-import { AddWatermarkParameters } from "./types";
+import { AddWatermarkParameters } from "../../../hooks/tools/addWatermark/useAddWatermarkParameters";
import NumberInputWithUnit from "../shared/NumberInputWithUnit";
interface WatermarkFormattingProps {
diff --git a/frontend/src/components/tools/addWatermark/WatermarkTextStyle.tsx b/frontend/src/components/tools/addWatermark/WatermarkTextStyle.tsx
index 519ce1581..d79039675 100644
--- a/frontend/src/components/tools/addWatermark/WatermarkTextStyle.tsx
+++ b/frontend/src/components/tools/addWatermark/WatermarkTextStyle.tsx
@@ -1,7 +1,8 @@
import React from "react";
import { Stack, Text, Select, ColorInput, NumberInput, Group } from "@mantine/core";
import { useTranslation } from "react-i18next";
-import { AddWatermarkParameters } from "./types";
+import { AddWatermarkParameters } from "../../../hooks/tools/addWatermark/useAddWatermarkParameters";
+import { alphabetOptions } from "../../../constants/addWatermarkConstants";
interface WatermarkTextStyleProps {
parameters: AddWatermarkParameters;
@@ -12,14 +13,6 @@ interface WatermarkTextStyleProps {
const WatermarkTextStyle = ({ parameters, onParameterChange, disabled = false }: WatermarkTextStyleProps) => {
const { t } = useTranslation();
- const alphabetOptions = [
- { value: "roman", label: "Roman" },
- { value: "arabic", label: "العربية" },
- { value: "japanese", label: "日本語" },
- { value: "korean", label: "한국어" },
- { value: "chinese", label: "简体中文" },
- { value: "thai", label: "ไทย" },
- ];
return (
diff --git a/frontend/src/components/tools/addWatermark/WatermarkWording.tsx b/frontend/src/components/tools/addWatermark/WatermarkWording.tsx
index 7322f2781..aad046130 100644
--- a/frontend/src/components/tools/addWatermark/WatermarkWording.tsx
+++ b/frontend/src/components/tools/addWatermark/WatermarkWording.tsx
@@ -1,7 +1,7 @@
import React from "react";
import { Stack, Text, TextInput } from "@mantine/core";
import { useTranslation } from "react-i18next";
-import { AddWatermarkParameters } from "./types";
+import { AddWatermarkParameters } from "../../../hooks/tools/addWatermark/useAddWatermarkParameters";
interface WatermarkWordingProps {
parameters: AddWatermarkParameters;
diff --git a/frontend/src/components/tools/addWatermark/types.ts b/frontend/src/components/tools/addWatermark/types.ts
deleted file mode 100644
index 610212fea..000000000
--- a/frontend/src/components/tools/addWatermark/types.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export interface AddWatermarkParameters {
- watermarkType?: 'text' | 'image';
- watermarkText: string;
- watermarkImage?: File;
- fontSize: number;
- rotation: number;
- opacity: number;
- widthSpacer: number;
- heightSpacer: number;
- alphabet: string;
- customColor: string;
- convertPDFToImage: boolean;
-}
\ No newline at end of file
diff --git a/frontend/src/components/tooltips/useWatermarkTips.ts b/frontend/src/components/tooltips/useWatermarkTips.ts
index 675d56d52..dd14a31cc 100644
--- a/frontend/src/components/tooltips/useWatermarkTips.ts
+++ b/frontend/src/components/tooltips/useWatermarkTips.ts
@@ -1,5 +1,43 @@
import { useTranslation } from 'react-i18next';
-import { TooltipContent } from '../../types/tips';
+import { TooltipContent, TooltipTip } from '../../types/tips';
+
+// Shared tooltip content to reduce duplication
+const useSharedWatermarkContent = () => {
+ const { t } = useTranslation();
+
+ const languageSupportTip: TooltipTip = {
+ title: t("watermark.tooltip.language.title", "Language Support"),
+ description: t("watermark.tooltip.language.text", "Choose the appropriate language setting to ensure proper font rendering for your text."),
+ bullets: [
+ t("watermark.tooltip.language.bullet1", "Roman/Latin for Western languages"),
+ t("watermark.tooltip.language.bullet2", "Arabic for Arabic script"),
+ t("watermark.tooltip.language.bullet3", "Japanese, Korean, Chinese for Asian languages"),
+ t("watermark.tooltip.language.bullet4", "Thai for Thai script")
+ ]
+ };
+
+ const appearanceTip: TooltipTip = {
+ title: t("watermark.tooltip.appearance.title", "Appearance Settings"),
+ description: t("watermark.tooltip.appearance.text", "Control how your watermark looks and blends with the document."),
+ bullets: [
+ t("watermark.tooltip.appearance.bullet1", "Rotation: -360° to 360° for angled watermarks"),
+ t("watermark.tooltip.appearance.bullet2", "Opacity: 0-100% for transparency control"),
+ t("watermark.tooltip.appearance.bullet3", "Lower opacity creates subtle watermarks")
+ ]
+ };
+
+ const spacingTip: TooltipTip = {
+ title: t("watermark.tooltip.spacing.title", "Spacing Control"),
+ description: t("watermark.tooltip.spacing.text", "Adjust the spacing between repeated watermarks across the page."),
+ bullets: [
+ t("watermark.tooltip.spacing.bullet1", "Width spacing: Horizontal distance between watermarks"),
+ t("watermark.tooltip.spacing.bullet2", "Height spacing: Vertical distance between watermarks"),
+ t("watermark.tooltip.spacing.bullet3", "Higher values create more spread out patterns")
+ ]
+ };
+
+ return { languageSupportTip, appearanceTip, spacingTip };
+};
export const useWatermarkTypeTips = (): TooltipContent => {
const { t } = useTranslation();
@@ -35,67 +73,7 @@ export const useWatermarkTypeTips = (): TooltipContent => {
};
};
-export const useWatermarkContentTips = (): TooltipContent => {
- const { t } = useTranslation();
- return {
- header: {
- title: t("watermark.tooltip.content.header.title", "Content Configuration")
- },
- tips: [
- {
- title: t("watermark.tooltip.content.text.title", "Text Settings"),
- description: t("watermark.tooltip.content.text.text", "Configure your text watermark appearance and language support."),
- bullets: [
- t("watermark.tooltip.content.text.bullet1", "Enter your watermark text"),
- t("watermark.tooltip.content.text.bullet2", "Adjust font size (8-72pt)"),
- t("watermark.tooltip.content.text.bullet3", "Select language/script support"),
- t("watermark.tooltip.content.text.bullet4", "Choose custom colors")
- ]
- },
- {
- title: t("watermark.tooltip.content.language.title", "Language Support"),
- description: t("watermark.tooltip.content.language.text", "Choose the appropriate language setting to ensure proper font rendering for your text."),
- bullets: [
- t("watermark.tooltip.content.language.bullet1", "Roman/Latin for Western languages"),
- t("watermark.tooltip.content.language.bullet2", "Arabic for Arabic script"),
- t("watermark.tooltip.content.language.bullet3", "Japanese, Korean, Chinese for Asian languages"),
- t("watermark.tooltip.content.language.bullet4", "Thai for Thai script")
- ]
- }
- ]
- };
-};
-
-export const useWatermarkStyleTips = (): TooltipContent => {
- const { t } = useTranslation();
-
- return {
- header: {
- title: t("watermark.tooltip.style.header.title", "Style & Positioning")
- },
- tips: [
- {
- title: t("watermark.tooltip.style.appearance.title", "Appearance Settings"),
- description: t("watermark.tooltip.style.appearance.text", "Control how your watermark looks and blends with the document."),
- bullets: [
- t("watermark.tooltip.style.appearance.bullet1", "Rotation: -360° to 360° for angled watermarks"),
- t("watermark.tooltip.style.appearance.bullet2", "Opacity: 0-100% for transparency control"),
- t("watermark.tooltip.style.appearance.bullet3", "Lower opacity creates subtle watermarks")
- ]
- },
- {
- title: t("watermark.tooltip.style.spacing.title", "Spacing Control"),
- description: t("watermark.tooltip.style.spacing.text", "Adjust the spacing between repeated watermarks across the page."),
- bullets: [
- t("watermark.tooltip.style.spacing.bullet1", "Width spacing: Horizontal distance between watermarks"),
- t("watermark.tooltip.style.spacing.bullet2", "Height spacing: Vertical distance between watermarks"),
- t("watermark.tooltip.style.spacing.bullet3", "Higher values create more spread out patterns")
- ]
- }
- ]
- };
-};
export const useWatermarkWordingTips = (): TooltipContent => {
const { t } = useTranslation();
@@ -129,22 +107,14 @@ export const useWatermarkWordingTips = (): TooltipContent => {
export const useWatermarkTextStyleTips = (): TooltipContent => {
const { t } = useTranslation();
+ const { languageSupportTip } = useSharedWatermarkContent();
return {
header: {
title: t("watermark.tooltip.textStyle.header.title", "Text Style")
},
tips: [
- {
- title: t("watermark.tooltip.textStyle.language.title", "Language Support"),
- description: t("watermark.tooltip.textStyle.language.text", "Choose the appropriate language setting to ensure proper font rendering."),
- bullets: [
- t("watermark.tooltip.textStyle.language.bullet1", "Roman/Latin for Western languages"),
- t("watermark.tooltip.textStyle.language.bullet2", "Arabic for Arabic script"),
- t("watermark.tooltip.textStyle.language.bullet3", "Japanese, Korean, Chinese for Asian languages"),
- t("watermark.tooltip.textStyle.language.bullet4", "Thai for Thai script")
- ]
- },
+ languageSupportTip,
{
title: t("watermark.tooltip.textStyle.color.title", "Color Selection"),
description: t("watermark.tooltip.textStyle.color.text", "Choose a color that provides good contrast with your document content."),
@@ -190,30 +160,15 @@ export const useWatermarkFileTips = (): TooltipContent => {
export const useWatermarkFormattingTips = (): TooltipContent => {
const { t } = useTranslation();
+ const { appearanceTip, spacingTip } = useSharedWatermarkContent();
return {
header: {
title: t("watermark.tooltip.formatting.header.title", "Formatting & Layout")
},
tips: [
- {
- title: t("watermark.tooltip.formatting.appearance.title", "Appearance Settings"),
- description: t("watermark.tooltip.formatting.appearance.text", "Control how your watermark looks and blends with the document."),
- bullets: [
- t("watermark.tooltip.formatting.appearance.bullet1", "Rotation: -360° to 360° for angled watermarks"),
- t("watermark.tooltip.formatting.appearance.bullet2", "Opacity: 0-100% for transparency control"),
- t("watermark.tooltip.formatting.appearance.bullet3", "Lower opacity creates subtle watermarks")
- ]
- },
- {
- title: t("watermark.tooltip.formatting.spacing.title", "Spacing Control"),
- description: t("watermark.tooltip.formatting.spacing.text", "Adjust the spacing between repeated watermarks across the page."),
- bullets: [
- t("watermark.tooltip.formatting.spacing.bullet1", "Width spacing: Horizontal distance between watermarks"),
- t("watermark.tooltip.formatting.spacing.bullet2", "Height spacing: Vertical distance between watermarks"),
- t("watermark.tooltip.formatting.spacing.bullet3", "Higher values create more spread out patterns")
- ]
- },
+ appearanceTip,
+ spacingTip,
{
title: t("watermark.tooltip.formatting.security.title", "Security Option"),
description: t("watermark.tooltip.formatting.security.text", "Convert the final PDF to an image-based format for enhanced security."),
diff --git a/frontend/src/constants/addWatermarkConstants.ts b/frontend/src/constants/addWatermarkConstants.ts
new file mode 100644
index 000000000..65d26e5ca
--- /dev/null
+++ b/frontend/src/constants/addWatermarkConstants.ts
@@ -0,0 +1,28 @@
+import { AddWatermarkParameters } from "../hooks/tools/addWatermark/useAddWatermarkParameters";
+
+export interface AlphabetOption {
+ value: string;
+ label: string;
+}
+
+export const alphabetOptions: AlphabetOption[] = [
+ { value: "roman", label: "Roman" },
+ { value: "arabic", label: "العربية" },
+ { value: "japanese", label: "日本語" },
+ { value: "korean", label: "한국어" },
+ { value: "chinese", label: "简体中文" },
+ { value: "thai", label: "ไทย" },
+];
+
+export const defaultWatermarkParameters: AddWatermarkParameters = {
+ watermarkType: undefined,
+ watermarkText: '',
+ fontSize: 12,
+ rotation: 0,
+ opacity: 50,
+ widthSpacer: 50,
+ heightSpacer: 50,
+ alphabet: 'roman',
+ customColor: '#d3d3d3',
+ convertPDFToImage: false
+};
\ No newline at end of file
diff --git a/frontend/src/hooks/tools/addWatermark/useAddWatermarkParameters.ts b/frontend/src/hooks/tools/addWatermark/useAddWatermarkParameters.ts
index 68f31ff8a..f9bab0a7c 100644
--- a/frontend/src/hooks/tools/addWatermark/useAddWatermarkParameters.ts
+++ b/frontend/src/hooks/tools/addWatermark/useAddWatermarkParameters.ts
@@ -1,4 +1,5 @@
import { useState, useCallback } from 'react';
+import { defaultWatermarkParameters } from '../../../constants/addWatermarkConstants';
export interface AddWatermarkParameters {
watermarkType?: 'text' | 'image';
@@ -14,21 +15,9 @@ export interface AddWatermarkParameters {
convertPDFToImage: boolean;
}
-const defaultParameters: AddWatermarkParameters = {
- watermarkType: undefined,
- watermarkText: '',
- fontSize: 12,
- rotation: 0,
- opacity: 50,
- widthSpacer: 50,
- heightSpacer: 50,
- alphabet: 'roman',
- customColor: '#d3d3d3',
- convertPDFToImage: false
-};
export const useAddWatermarkParameters = () => {
- const [parameters, setParameters] = useState(defaultParameters);
+ const [parameters, setParameters] = useState(defaultWatermarkParameters);
const updateParameter = useCallback((
key: K,
@@ -38,7 +27,7 @@ export const useAddWatermarkParameters = () => {
}, []);
const resetParameters = useCallback(() => {
- setParameters(defaultParameters);
+ setParameters(defaultWatermarkParameters);
}, []);
const validateParameters = useCallback((): boolean => {
diff --git a/frontend/src/tools/AddWatermark.tsx b/frontend/src/tools/AddWatermark.tsx
index ad0b55a37..b43605c82 100644
--- a/frontend/src/tools/AddWatermark.tsx
+++ b/frontend/src/tools/AddWatermark.tsx
@@ -22,7 +22,6 @@ import {
useWatermarkFormattingTips,
} from "../components/tooltips/useWatermarkTips";
import { BaseToolProps } from "../types/tool";
-import { isVisible } from "@testing-library/user-event/dist/utils";
const AddWatermark = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const { t } = useTranslation();