diff --git a/frontend/src/components/tools/adjustContrast/AdjustContrastBasicSettings.tsx b/frontend/src/components/tools/adjustContrast/AdjustContrastBasicSettings.tsx new file mode 100644 index 000000000..8a376c8de --- /dev/null +++ b/frontend/src/components/tools/adjustContrast/AdjustContrastBasicSettings.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { Stack, Slider, Text, Group, NumberInput } from '@mantine/core'; +import { useTranslation } from 'react-i18next'; +import { AdjustContrastParameters } from '../../../hooks/tools/adjustContrast/useAdjustContrastParameters'; + +interface Props { + parameters: AdjustContrastParameters; + onParameterChange: (key: K, value: AdjustContrastParameters[K]) => void; + disabled?: boolean; +} + +export default function AdjustContrastBasicSettings({ parameters, onParameterChange, disabled }: Props) { + const { t } = useTranslation(); + + const renderSlider = (label: string, value: number, onChange: (v: number) => void) => ( +
+ {label}: {Math.round(value)}% + +
+ +
+ onChange(Number(v) || 0)} + min={0} + max={200} + step={1} + disabled={disabled} + style={{ width: 90 }} + /> +
+
+ ); + + return ( + + {renderSlider(t('adjustContrast.contrast', 'Contrast'), parameters.contrast, (v) => onParameterChange('contrast', v as any))} + {renderSlider(t('adjustContrast.brightness', 'Brightness'), parameters.brightness, (v) => onParameterChange('brightness', v as any))} + {renderSlider(t('adjustContrast.saturation', 'Saturation'), parameters.saturation, (v) => onParameterChange('saturation', v as any))} + + ); +} + + diff --git a/frontend/src/components/tools/adjustContrast/AdjustContrastColorSettings.tsx b/frontend/src/components/tools/adjustContrast/AdjustContrastColorSettings.tsx new file mode 100644 index 000000000..3d255ed41 --- /dev/null +++ b/frontend/src/components/tools/adjustContrast/AdjustContrastColorSettings.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { Stack, Slider, Text, Group, NumberInput } from '@mantine/core'; +import { useTranslation } from 'react-i18next'; +import { AdjustContrastParameters } from '../../../hooks/tools/adjustContrast/useAdjustContrastParameters'; + +interface Props { + parameters: AdjustContrastParameters; + onParameterChange: (key: K, value: AdjustContrastParameters[K]) => void; + disabled?: boolean; +} + +export default function AdjustContrastColorSettings({ parameters, onParameterChange, disabled }: Props) { + const { t } = useTranslation(); + + const renderSlider = (label: string, value: number, onChange: (v: number) => void) => ( +
+ {label}: {Math.round(value)}% + +
+ +
+ onChange(Number(v) || 0)} + min={0} + max={200} + step={1} + disabled={disabled} + style={{ width: 90 }} + /> +
+
+ ); + + return ( + + {renderSlider(t('adjustContrast.red', 'Red'), parameters.red, (v) => onParameterChange('red', v as any))} + {renderSlider(t('adjustContrast.green', 'Green'), parameters.green, (v) => onParameterChange('green', v as any))} + {renderSlider(t('adjustContrast.blue', 'Blue'), parameters.blue, (v) => onParameterChange('blue', v as any))} + + ); +} + + diff --git a/frontend/src/components/tools/adjustContrast/AdjustContrastSettings.tsx b/frontend/src/components/tools/adjustContrast/AdjustContrastSettings.tsx index 1dfbc7c4b..cd350b0fb 100644 --- a/frontend/src/components/tools/adjustContrast/AdjustContrastSettings.tsx +++ b/frontend/src/components/tools/adjustContrast/AdjustContrastSettings.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { Stack, Slider, Text, Group, NumberInput, Divider } from '@mantine/core'; -import AdjustContrastPreview from './AdjustContrastPreview'; import { useTranslation } from 'react-i18next'; import { AdjustContrastParameters } from '../../../hooks/tools/adjustContrast/useAdjustContrastParameters'; @@ -11,7 +10,7 @@ interface Props { file?: File | null; } -export default function AdjustContrastSettings({ parameters, onParameterChange, disabled, file }: Props) { +export default function AdjustContrastSettings({ parameters, onParameterChange, disabled }: Props) { const { t } = useTranslation(); const renderSlider = (label: string, value: number, onChange: (v: number) => void) => ( @@ -45,8 +44,6 @@ export default function AdjustContrastSettings({ parameters, onParameterChange, {renderSlider(t('adjustContrast.red', 'Red'), parameters.red, (v) => onParameterChange('red', v as any))} {renderSlider(t('adjustContrast.green', 'Green'), parameters.green, (v) => onParameterChange('green', v as any))} {renderSlider(t('adjustContrast.blue', 'Blue'), parameters.blue, (v) => onParameterChange('blue', v as any))} - {/* Inline accurate preview */} - ); } diff --git a/frontend/src/components/tools/shared/createToolFlow.tsx b/frontend/src/components/tools/shared/createToolFlow.tsx index 4724648c8..2f7835c15 100644 --- a/frontend/src/components/tools/shared/createToolFlow.tsx +++ b/frontend/src/components/tools/shared/createToolFlow.tsx @@ -54,6 +54,8 @@ export interface ToolFlowConfig { title?: TitleConfig; files: FilesStepConfig; steps: MiddleStepConfig[]; + // Optional preview content rendered between steps and the execute button + preview?: React.ReactNode; executeButton?: ExecuteButtonConfig; review: ReviewStepConfig; forceStepNumbers?: boolean; @@ -90,6 +92,9 @@ export function createToolFlow(config: ToolFlowConfig) { }, stepConfig.content) )} + {/* Preview (outside steps, above execute button). Hide when review is visible. */} + {!config.review.isVisible && config.preview} + {/* Execute Button */} {config.executeButton && config.executeButton.isVisible !== false && ( { @@ -17,10 +20,10 @@ const AdjustContrast = (props: BaseToolProps) => { props ); - enum Step { NONE='none', SETTINGS='settings' } + enum Step { NONE='none', BASIC='basic', COLORS='colors' } const accordion = useAccordionSteps({ noneValue: Step.NONE, - initialStep: Step.SETTINGS, + initialStep: Step.BASIC, stateConditions: { hasFiles: base.hasFiles, hasResults: base.hasResults }, afterResults: base.handleSettingsReset }); @@ -32,19 +35,36 @@ const AdjustContrast = (props: BaseToolProps) => { }, steps: [ { - title: t('adjustContrast.title', 'Adjust Colors/Contrast'), - isCollapsed: accordion.getCollapsedState(Step.SETTINGS), - onCollapsedClick: () => accordion.handleStepToggle(Step.SETTINGS), + title: t('adjustContrast.basic', 'Basic Adjustments'), + isCollapsed: accordion.getCollapsedState(Step.BASIC), + onCollapsedClick: () => accordion.handleStepToggle(Step.BASIC), content: ( - + ), + }, + { + title: t('adjustContrast.adjustColors', 'Adjust Colors'), + isCollapsed: accordion.getCollapsedState(Step.COLORS), + onCollapsedClick: () => accordion.handleStepToggle(Step.COLORS), + content: ( + ), }, ], + preview: ( + + ), executeButton: { text: t('adjustContrast.confirm', 'Confirm'), isVisible: !base.hasResults,