diff --git a/frontend/public/locales/en-US/translation.json b/frontend/public/locales/en-US/translation.json
index c3bf98080..4f79f9d4d 100644
--- a/frontend/public/locales/en-US/translation.json
+++ b/frontend/public/locales/en-US/translation.json
@@ -1780,6 +1780,98 @@
"chinese": "Chinese",
"thai": "Thai"
},
+ "steps": {
+ "type": "Watermark Type",
+ "textContent": "Text Content",
+ "imageContent": "Image Content",
+ "style": "Style & Position",
+ "advanced": "Advanced Options"
+ },
+ "results": {
+ "title": "Watermark Results"
+ },
+ "tooltip": {
+ "type": {
+ "header": {
+ "title": "Watermark Type Selection"
+ },
+ "description": {
+ "title": "Choose Your Watermark",
+ "text": "Select between text or image watermarks based on your needs."
+ },
+ "text": {
+ "title": "Text Watermarks",
+ "text": "Perfect for adding copyright notices, company names, or confidentiality labels. Supports multiple languages and custom colors.",
+ "bullet1": "Customizable fonts and languages",
+ "bullet2": "Adjustable colors and transparency",
+ "bullet3": "Ideal for legal or branding text"
+ },
+ "image": {
+ "title": "Image Watermarks",
+ "text": "Use logos, stamps, or any image as a watermark. Great for branding and visual identification.",
+ "bullet1": "Upload any image format",
+ "bullet2": "Maintains image quality",
+ "bullet3": "Perfect for logos and stamps"
+ }
+ },
+ "content": {
+ "header": {
+ "title": "Content Configuration"
+ },
+ "text": {
+ "title": "Text Settings",
+ "text": "Configure your text watermark appearance and language support.",
+ "bullet1": "Enter your watermark text",
+ "bullet2": "Adjust font size (8-72pt)",
+ "bullet3": "Select language/script support",
+ "bullet4": "Choose custom colors"
+ },
+ "language": {
+ "title": "Language Support",
+ "text": "Choose the appropriate language setting to ensure proper font rendering for your text.",
+ "bullet1": "Roman/Latin for Western languages",
+ "bullet2": "Arabic for Arabic script",
+ "bullet3": "Japanese, Korean, Chinese for Asian languages",
+ "bullet4": "Thai for Thai script"
+ }
+ },
+ "style": {
+ "header": {
+ "title": "Style & Positioning"
+ },
+ "appearance": {
+ "title": "Appearance Settings",
+ "text": "Control how your watermark looks and blends with the document.",
+ "bullet1": "Rotation: -360° to 360° for angled watermarks",
+ "bullet2": "Opacity: 0-100% for transparency control",
+ "bullet3": "Lower opacity creates subtle watermarks"
+ },
+ "spacing": {
+ "title": "Spacing Control",
+ "text": "Adjust the spacing between repeated watermarks across the page.",
+ "bullet1": "Width spacing: Horizontal distance between watermarks",
+ "bullet2": "Height spacing: Vertical distance between watermarks",
+ "bullet3": "Higher values create more spread out patterns"
+ }
+ },
+ "advanced": {
+ "header": {
+ "title": "Advanced Options"
+ },
+ "conversion": {
+ "title": "PDF to Image Conversion",
+ "text": "Convert the final PDF to an image-based format for enhanced security.",
+ "bullet1": "Prevents text selection and copying",
+ "bullet2": "Makes watermarks harder to remove",
+ "bullet3": "Results in larger file sizes",
+ "bullet4": "Best for sensitive or copyrighted content"
+ },
+ "security": {
+ "title": "Security Considerations",
+ "text": "Image-based PDFs provide additional protection against unauthorized editing and content extraction."
+ }
+ }
+ },
"positions": {
"topLeft": "Top Left",
"topCenter": "Top Center",
diff --git a/frontend/src/components/tools/addWatermark/WatermarkAdvancedSettings.tsx b/frontend/src/components/tools/addWatermark/WatermarkAdvancedSettings.tsx
new file mode 100644
index 000000000..a691471a0
--- /dev/null
+++ b/frontend/src/components/tools/addWatermark/WatermarkAdvancedSettings.tsx
@@ -0,0 +1,29 @@
+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/WatermarkContentSettings.tsx b/frontend/src/components/tools/addWatermark/WatermarkContentSettings.tsx
index 872bc1d23..5bab1ab83 100644
--- a/frontend/src/components/tools/addWatermark/WatermarkContentSettings.tsx
+++ b/frontend/src/components/tools/addWatermark/WatermarkContentSettings.tsx
@@ -1,20 +1,7 @@
import React, { useRef } from "react";
-import { Stack, Text, TextInput, FileButton, Button, NumberInput } from "@mantine/core";
+import { Stack, Text, TextInput, FileButton, Button, NumberInput, Select, ColorInput } 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;
-}
+import { AddWatermarkParameters } from "./types";
interface WatermarkContentSettingsProps {
parameters: AddWatermarkParameters;
@@ -26,6 +13,15 @@ const WatermarkContentSettings = ({ parameters, onParameterChange, disabled = fa
const { t } = useTranslation();
const resetRef = useRef<() => void>(null);
+ const alphabetOptions = [
+ { value: 'roman', label: t('watermark.alphabet.roman', 'Roman/Latin') },
+ { value: 'arabic', label: t('watermark.alphabet.arabic', 'Arabic') },
+ { value: 'japanese', label: t('watermark.alphabet.japanese', 'Japanese') },
+ { value: 'korean', label: t('watermark.alphabet.korean', 'Korean') },
+ { value: 'chinese', label: t('watermark.alphabet.chinese', 'Chinese') },
+ { value: 'thai', label: t('watermark.alphabet.thai', 'Thai') }
+ ];
+
return (
{/* Text Watermark Settings */}
@@ -47,6 +43,23 @@ const WatermarkContentSettings = ({ parameters, onParameterChange, disabled = fa
max={72}
disabled={disabled}
/>
+
+ {t('watermark.settings.alphabet', 'Font/Language')}
+
)}
diff --git a/frontend/src/components/tools/addWatermark/WatermarkStyleSettings.tsx b/frontend/src/components/tools/addWatermark/WatermarkStyleSettings.tsx
index 95aa7e4a3..3da084d02 100644
--- a/frontend/src/components/tools/addWatermark/WatermarkStyleSettings.tsx
+++ b/frontend/src/components/tools/addWatermark/WatermarkStyleSettings.tsx
@@ -1,20 +1,7 @@
import React from "react";
-import { Stack, Text, NumberInput, Select, ColorInput, Checkbox } from "@mantine/core";
+import { Stack, Text, NumberInput } 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;
- alphabet: string;
- customColor: string;
- convertPDFToImage: boolean;
-}
+import { AddWatermarkParameters } from "./types";
interface WatermarkStyleSettingsProps {
parameters: AddWatermarkParameters;
@@ -25,39 +12,8 @@ interface WatermarkStyleSettingsProps {
const WatermarkStyleSettings = ({ parameters, onParameterChange, disabled = false }: WatermarkStyleSettingsProps) => {
const { t } = useTranslation();
- const alphabetOptions = [
- { value: 'roman', label: t('watermark.alphabet.roman', 'Roman/Latin') },
- { value: 'arabic', label: t('watermark.alphabet.arabic', 'Arabic') },
- { value: 'japanese', label: t('watermark.alphabet.japanese', 'Japanese') },
- { value: 'korean', label: t('watermark.alphabet.korean', 'Korean') },
- { value: 'chinese', label: t('watermark.alphabet.chinese', 'Chinese') },
- { value: 'thai', label: t('watermark.alphabet.thai', 'Thai') }
- ];
-
return (
- {/* Text-specific settings */}
- {parameters.watermarkType === 'text' && (
-
- {t('watermark.settings.alphabet', 'Font/Language')}
-
- )}
-
{/* Appearance Settings */}
{t('watermark.settings.rotation', 'Rotation (degrees)')}
@@ -100,16 +56,6 @@ const WatermarkStyleSettings = ({ parameters, onParameterChange, disabled = fals
/>
- {/* Output Options */}
-
- onParameterChange('convertPDFToImage', event.currentTarget.checked)}
- disabled={disabled}
- />
-
);
};
diff --git a/frontend/src/components/tools/addWatermark/types.ts b/frontend/src/components/tools/addWatermark/types.ts
new file mode 100644
index 000000000..610212fea
--- /dev/null
+++ b/frontend/src/components/tools/addWatermark/types.ts
@@ -0,0 +1,13 @@
+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
new file mode 100644
index 000000000..408d5de2f
--- /dev/null
+++ b/frontend/src/components/tooltips/useWatermarkTips.ts
@@ -0,0 +1,124 @@
+import { useTranslation } from 'react-i18next';
+import { TooltipContent } from '../../types/tips';
+
+export const useWatermarkTypeTips = (): TooltipContent => {
+ const { t } = useTranslation();
+
+ return {
+ header: {
+ title: t("watermark.tooltip.type.header.title", "Watermark Type Selection")
+ },
+ tips: [
+ {
+ title: t("watermark.tooltip.type.description.title", "Choose Your Watermark"),
+ description: t("watermark.tooltip.type.description.text", "Select between text or image watermarks based on your needs.")
+ },
+ {
+ title: t("watermark.tooltip.type.text.title", "Text Watermarks"),
+ description: t("watermark.tooltip.type.text.text", "Perfect for adding copyright notices, company names, or confidentiality labels. Supports multiple languages and custom colors."),
+ bullets: [
+ t("watermark.tooltip.type.text.bullet1", "Customizable fonts and languages"),
+ t("watermark.tooltip.type.text.bullet2", "Adjustable colors and transparency"),
+ t("watermark.tooltip.type.text.bullet3", "Ideal for legal or branding text")
+ ]
+ },
+ {
+ title: t("watermark.tooltip.type.image.title", "Image Watermarks"),
+ description: t("watermark.tooltip.type.image.text", "Use logos, stamps, or any image as a watermark. Great for branding and visual identification."),
+ bullets: [
+ t("watermark.tooltip.type.image.bullet1", "Upload any image format"),
+ t("watermark.tooltip.type.image.bullet2", "Maintains image quality"),
+ t("watermark.tooltip.type.image.bullet3", "Perfect for logos and stamps")
+ ]
+ }
+ ]
+ };
+};
+
+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 useWatermarkAdvancedTips = (): TooltipContent => {
+ const { t } = useTranslation();
+
+ return {
+ header: {
+ title: t("watermark.tooltip.advanced.header.title", "Advanced Options")
+ },
+ tips: [
+ {
+ title: t("watermark.tooltip.advanced.conversion.title", "PDF to Image Conversion"),
+ description: t("watermark.tooltip.advanced.conversion.text", "Convert the final PDF to an image-based format for enhanced security."),
+ bullets: [
+ t("watermark.tooltip.advanced.conversion.bullet1", "Prevents text selection and copying"),
+ t("watermark.tooltip.advanced.conversion.bullet2", "Makes watermarks harder to remove"),
+ t("watermark.tooltip.advanced.conversion.bullet3", "Results in larger file sizes"),
+ t("watermark.tooltip.advanced.conversion.bullet4", "Best for sensitive or copyrighted content")
+ ]
+ },
+ {
+ title: t("watermark.tooltip.advanced.security.title", "Security Considerations"),
+ description: t("watermark.tooltip.advanced.security.text", "Image-based PDFs provide additional protection against unauthorized editing and content extraction.")
+ }
+ ]
+ };
+};
\ No newline at end of file
diff --git a/frontend/src/tools/AddWatermark.tsx b/frontend/src/tools/AddWatermark.tsx
index 4ef37625d..1e30f948e 100644
--- a/frontend/src/tools/AddWatermark.tsx
+++ b/frontend/src/tools/AddWatermark.tsx
@@ -1,23 +1,19 @@
-import React, { useEffect, useMemo, useState } from "react";
-import { Button, Stack, Text } from "@mantine/core";
+import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
-import DownloadIcon from "@mui/icons-material/Download";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
-import ToolStep, { ToolStepContainer } from "../components/tools/shared/ToolStep";
-import OperationButton from "../components/tools/shared/OperationButton";
-import ErrorNotification from "../components/tools/shared/ErrorNotification";
-import FileStatusIndicator from "../components/tools/shared/FileStatusIndicator";
-import ResultsPreview from "../components/tools/shared/ResultsPreview";
+import { createToolFlow } from "../components/tools/shared/createToolFlow";
import WatermarkTypeSettings from "../components/tools/addWatermark/WatermarkTypeSettings";
import WatermarkContentSettings from "../components/tools/addWatermark/WatermarkContentSettings";
import WatermarkStyleSettings from "../components/tools/addWatermark/WatermarkStyleSettings";
+import WatermarkAdvancedSettings from "../components/tools/addWatermark/WatermarkAdvancedSettings";
import { useAddWatermarkParameters } from "../hooks/tools/addWatermark/useAddWatermarkParameters";
import { useAddWatermarkOperation } from "../hooks/tools/addWatermark/useAddWatermarkOperation";
+import { useWatermarkTypeTips, useWatermarkContentTips, useWatermarkStyleTips, useWatermarkAdvancedTips } from "../components/tooltips/useWatermarkTips";
import { BaseToolProps } from "../types/tool";
const AddWatermark = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
@@ -25,8 +21,16 @@ const AddWatermark = ({ onPreviewFile, onComplete, onError }: BaseToolProps) =>
const { setCurrentMode } = useFileContext();
const { selectedFiles } = useToolFileSelection();
+ const [collapsedType, setCollapsedType] = useState(false);
+ const [collapsedStyle, setCollapsedStyle] = useState(true);
+ const [collapsedAdvanced, setCollapsedAdvanced] = useState(true);
+
const watermarkParams = useAddWatermarkParameters();
const watermarkOperation = useAddWatermarkOperation();
+ const watermarkTypeTips = useWatermarkTypeTips();
+ const watermarkContentTips = useWatermarkContentTips();
+ const watermarkStyleTips = useWatermarkStyleTips();
+ const watermarkAdvancedTips = useWatermarkAdvancedTips();
// Endpoint validation
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled("add-watermark");
@@ -34,234 +38,129 @@ const AddWatermark = ({ onPreviewFile, onComplete, onError }: BaseToolProps) =>
useEffect(() => {
watermarkOperation.resetResults();
onPreviewFile?.(null);
- }, [watermarkParams.parameters, selectedFiles]);
+ }, [watermarkParams.parameters]);
+
+ // Auto-collapse type step after selection
+ useEffect(() => {
+ if (watermarkParams.parameters.watermarkType && !collapsedType) {
+ setCollapsedType(true);
+ }
+ }, [watermarkParams.parameters.watermarkType]);
const handleAddWatermark = async () => {
try {
- await watermarkOperation.executeOperation(
- watermarkParams.parameters,
- selectedFiles
- );
+ await watermarkOperation.executeOperation(watermarkParams.parameters, selectedFiles);
if (watermarkOperation.files && onComplete) {
onComplete(watermarkOperation.files);
}
} catch (error) {
if (onError) {
- onError(error instanceof Error ? error.message : 'Add watermark operation failed');
+ onError(error instanceof Error ? error.message : t("watermark.error.failed", "Add watermark operation failed"));
}
}
};
const handleThumbnailClick = (file: File) => {
onPreviewFile?.(file);
- sessionStorage.setItem('previousMode', 'watermark');
- setCurrentMode('viewer');
+ sessionStorage.setItem("previousMode", "watermark");
+ setCurrentMode("viewer");
};
const handleSettingsReset = () => {
watermarkOperation.resetResults();
onPreviewFile?.(null);
- setCurrentMode('watermark');
+ setCurrentMode("watermark");
};
const hasFiles = selectedFiles.length > 0;
const hasResults = watermarkOperation.files.length > 0 || watermarkOperation.downloadUrl !== null;
- const filesCollapsed = hasFiles;
-
- // Step completion logic
+ const settingsCollapsed = !hasFiles || hasResults;
+
+ // Step completion logic
const typeStepCompleted = hasFiles && !!watermarkParams.parameters.watermarkType;
const contentStepCompleted = typeStepCompleted && (
(watermarkParams.parameters.watermarkType === 'text' && watermarkParams.parameters.watermarkText.trim().length > 0) ||
(watermarkParams.parameters.watermarkType === 'image' && watermarkParams.parameters.watermarkImage !== undefined)
);
- const styleStepCompleted = contentStepCompleted; // Style step has defaults, so completed when content is done
-
- // Track which steps have been manually opened
- const [manuallyOpenedSteps, setManuallyOpenedSteps] = useState>(new Set());
-
- // Auto-collapse logic with manual override
- const typeStepCollapsed = typeStepCompleted && !hasResults && !manuallyOpenedSteps.has('type');
- const contentStepCollapsed = contentStepCompleted && !hasResults && !manuallyOpenedSteps.has('content');
- const styleStepCollapsed = !manuallyOpenedSteps.has('style'); // Style starts collapsed, only opens when clicked
-
- // Click handlers to manage step visibility and reset results
- const handleTypeStepClick = () => {
- setManuallyOpenedSteps(prev => {
- const newSet = new Set(prev);
- if (newSet.has('type')) {
- newSet.delete('type'); // Close if already open
- } else {
- newSet.add('type'); // Open if closed
- }
- return newSet;
- });
- watermarkOperation.resetResults();
- onPreviewFile?.(null);
- };
-
- const handleContentStepClick = () => {
- setManuallyOpenedSteps(prev => {
- const newSet = new Set(prev);
- if (newSet.has('content')) {
- newSet.delete('content'); // Close if already open
- } else {
- newSet.add('content'); // Open if closed
- }
- return newSet;
- });
- watermarkOperation.resetResults();
- onPreviewFile?.(null);
- };
-
- const handleStyleStepClick = () => {
- setManuallyOpenedSteps(prev => {
- const newSet = new Set(prev);
- if (newSet.has('style')) {
- newSet.delete('style'); // Close if already open
- } else {
- newSet.add('style'); // Open if closed
- }
- return newSet;
- });
- watermarkOperation.resetResults();
- onPreviewFile?.(null);
- };
- const previewResults = useMemo(() =>
- watermarkOperation.files?.map((file, index) => ({
- file,
- thumbnail: watermarkOperation.thumbnails[index]
- })) || [],
- [watermarkOperation.files, watermarkOperation.thumbnails]
- );
+ // Step visibility logic - all steps always visible once files are selected
+ const styleCollapsed = collapsedStyle || hasResults;
+ const advancedCollapsed = collapsedAdvanced || hasResults;
- return (
-
-
- {/* Files Step */}
-
-
-
-
- {/* Watermark Type Step */}
-
+ return createToolFlow({
+ files: {
+ selectedFiles,
+ isCollapsed: hasFiles || hasResults,
+ },
+ steps: [
+ {
+ title: t("watermark.steps.type", "Watermark Type"),
+ isCollapsed: settingsCollapsed? true : collapsedType,
+ onCollapsedClick: hasResults ? handleSettingsReset : () => setCollapsedType(!collapsedType),
+ tooltip: watermarkTypeTips,
+ content: (
watermarkParams.updateParameter('watermarkType', type)}
disabled={endpointLoading}
/>
-
-
- {/* Content Step */}
-
+ ),
+ },
+ {
+ title: watermarkParams.parameters.watermarkType === 'text'
+ ? t("watermark.steps.textContent", "Text Content")
+ : t("watermark.steps.imageContent", "Image Content"),
+ isCollapsed: settingsCollapsed? true : contentStepCompleted,
+ tooltip: watermarkContentTips,
+ content: (
-
-
- {/* Style Step */}
-
+ ),
+ },
+ {
+ title: t("watermark.steps.style", "Style & Position"),
+ isCollapsed: settingsCollapsed? true : styleCollapsed,
+ onCollapsedClick: hasResults ? handleSettingsReset : () => setCollapsedStyle(!collapsedStyle),
+ tooltip: watermarkStyleTips,
+ content: (
-
-
- {/* Apply Button - Outside of settings steps */}
- {styleStepCompleted && !hasResults && (
-
-
-
- )}
-
- {/* Results Step */}
-
-
- {watermarkOperation.status && (
- {watermarkOperation.status}
- )}
-
-
-
- {watermarkOperation.downloadUrl && (
- }
- color="green"
- fullWidth
- mb="md"
- >
- {t("download", "Download")}
-
- )}
-
-
-
-
-
-
- );
+ ),
+ },
+ {
+ title: t("watermark.steps.advanced", "Advanced Options"),
+ isCollapsed: settingsCollapsed? true : advancedCollapsed,
+ onCollapsedClick: hasResults ? handleSettingsReset : () => setCollapsedAdvanced(!collapsedAdvanced),
+ tooltip: watermarkAdvancedTips,
+ content: (
+
+ ),
+ },
+ ],
+ executeButton: {
+ text: t("watermark.submit", "Add Watermark"),
+ isVisible: !hasResults,
+ loadingText: t("loading"),
+ onClick: handleAddWatermark,
+ disabled: !watermarkParams.validateParameters() || !hasFiles || !endpointEnabled,
+ },
+ review: {
+ isVisible: hasResults,
+ operation: watermarkOperation,
+ title: t("watermark.results.title", "Watermark Results"),
+ onFileClick: handleThumbnailClick,
+ },
+ });
}
-export default AddWatermark;
\ No newline at end of file
+export default AddWatermark;