diff --git a/frontend/public/locales/en-GB/translation.toml b/frontend/public/locales/en-GB/translation.toml index 6d27d6f84..a69ed9cdf 100644 --- a/frontend/public/locales/en-GB/translation.toml +++ b/frontend/public/locales/en-GB/translation.toml @@ -3800,6 +3800,11 @@ failed = "An error occurred while compressing the PDF." _value = "Compression Settings" 1 = "1-3 PDF compression,
4-6 lite image compression,
7-9 intense image compression Will dramatically reduce image quality" +[compress.compressionLevel] +range1to3 = "Lower values preserve quality but result in larger files" +range4to6 = "Medium compression with moderate quality reduction" +range7to9 = "Higher values reduce file size significantly but may reduce image clarity" + [decrypt] passwordPrompt = "This file is password-protected. Please enter the password:" cancelled = "Operation cancelled for PDF: {0}" diff --git a/frontend/src/core/components/shared/sliderWithInput/SliderWithInput.tsx b/frontend/src/core/components/shared/sliderWithInput/SliderWithInput.tsx index 7a91cdbe3..85e7039e2 100644 --- a/frontend/src/core/components/shared/sliderWithInput/SliderWithInput.tsx +++ b/frontend/src/core/components/shared/sliderWithInput/SliderWithInput.tsx @@ -8,6 +8,7 @@ interface Props { min?: number; max?: number; step?: number; + suffix?: string; } export default function SliderWithInput({ @@ -18,11 +19,12 @@ export default function SliderWithInput({ min = 0, max = 200, step = 1, + suffix = '%', }: Props) { return (
- {label}: {Math.round(value)}% - + {label} +
@@ -33,6 +35,7 @@ export default function SliderWithInput({ max={max} step={step} disabled={disabled} + suffix={suffix} style={{ width: 90 }} />
diff --git a/frontend/src/core/components/tools/compress/CompressSettings.tsx b/frontend/src/core/components/tools/compress/CompressSettings.tsx index 9dc6d2ca5..7d5941f3b 100644 --- a/frontend/src/core/components/tools/compress/CompressSettings.tsx +++ b/frontend/src/core/components/tools/compress/CompressSettings.tsx @@ -1,5 +1,6 @@ import { useState, useEffect } from "react"; import { Stack, Text, NumberInput, Select, Divider, Checkbox, Slider, SegmentedControl } from "@mantine/core"; +import SliderWithInput from '@app/components/shared/sliderWithInput/SliderWithInput'; import { useTranslation } from "react-i18next"; import { CompressParameters } from "@app/hooks/tools/compress/useCompressParameters"; import ButtonSelector from "@app/components/shared/ButtonSelector"; @@ -13,7 +14,6 @@ interface CompressSettingsProps { const CompressSettings = ({ parameters, onParameterChange, disabled = false }: CompressSettingsProps) => { const { t } = useTranslation(); - const [isSliding, setIsSliding] = useState(false); const [imageMagickAvailable, setImageMagickAvailable] = useState(null); useEffect(() => { @@ -47,57 +47,22 @@ const CompressSettings = ({ parameters, onParameterChange, disabled = false }: C {/* Quality Adjustment */} {parameters.compressionMethod === 'quality' && ( - + - Compression Level -
- onParameterChange('compressionLevel', parseInt(e.target.value))} - onMouseDown={() => setIsSliding(true)} - onMouseUp={() => setIsSliding(false)} - onTouchStart={() => setIsSliding(true)} - onTouchEnd={() => setIsSliding(false)} - disabled={disabled} - style={{ - width: '100%', - height: '6px', - borderRadius: '3px', - background: `linear-gradient(to right, #228be6 0%, #228be6 ${(parameters.compressionLevel - 1) / 8 * 100}%, #e9ecef ${(parameters.compressionLevel - 1) / 8 * 100}%, #e9ecef 100%)`, - outline: 'none', - WebkitAppearance: 'none' - }} - /> - {isSliding && ( -
- {parameters.compressionLevel} -
- )} -
-
- Min 1 - Max 9 -
- - {parameters.compressionLevel <= 3 && "1-3 PDF compression"} - {parameters.compressionLevel >= 4 && parameters.compressionLevel <= 6 && "4-6 lite image compression"} - {parameters.compressionLevel >= 7 && "7-9 intense image compression Will dramatically reduce image quality"} + onParameterChange('compressionLevel', value)} + disabled={disabled} + min={1} + max={9} + step={1} + suffix="" + /> + + {parameters.compressionLevel <= 3 && t('compress.compressionLevel.range1to3', 'Lower values preserve quality but result in larger files')} + {parameters.compressionLevel >= 4 && parameters.compressionLevel <= 6 && t('compress.compressionLevel.range4to6', 'Medium compression with moderate quality reduction')} + {parameters.compressionLevel >= 7 && t('compress.compressionLevel.range7to9', 'Higher values reduce file size significantly but may reduce image clarity')}
)} diff --git a/frontend/src/proprietary/routes/authShared/auth.css b/frontend/src/proprietary/routes/authShared/auth.css index 996655835..05cb815f6 100644 --- a/frontend/src/proprietary/routes/authShared/auth.css +++ b/frontend/src/proprietary/routes/authShared/auth.css @@ -185,8 +185,8 @@ width: 100%; display: flex; align-items: center; - justify-content: center; - padding: 1rem 1rem; /* 16px 16px */ + justify-content: flex-start; + padding: 0.75rem 1rem; /* 12px 16px */ border: 1px solid #d1d5db; border-radius: 0.75rem; /* 12px */ background-color: var(--auth-card-bg-light-only); @@ -195,6 +195,12 @@ color: var(--auth-text-primary-light-only); cursor: pointer; gap: 0.75rem; /* 12px */ + font-family: inherit; + transition: background-color 0.2s ease; +} + +.oauth-button-vertical:hover:not(:disabled) { + background-color: #f3f4f6; } .oauth-button-vertical:disabled { @@ -202,6 +208,11 @@ opacity: 0.6; } +.oauth-button-vertical:focus-visible { + outline: 2px solid var(--auth-border-focus-light-only); + outline-offset: 2px; +} + .oauth-icon-small { width: 1.75rem; /* 28px */ height: 1.75rem; /* 28px */ @@ -217,6 +228,8 @@ .oauth-icon-tiny { width: 1.25rem; /* 20px */ height: 1.25rem; /* 20px */ + display: block; + flex-shrink: 0; } /* Login Header Styles */ diff --git a/frontend/src/proprietary/routes/login/EmailPasswordForm.tsx b/frontend/src/proprietary/routes/login/EmailPasswordForm.tsx index 65dd6c588..12777d1c6 100644 --- a/frontend/src/proprietary/routes/login/EmailPasswordForm.tsx +++ b/frontend/src/proprietary/routes/login/EmailPasswordForm.tsx @@ -1,5 +1,6 @@ import { useTranslation } from 'react-i18next'; import '@app/routes/authShared/auth.css'; +import { TextInput, PasswordInput, Button } from '@mantine/core'; interface EmailPasswordFormProps { email: string @@ -38,49 +39,46 @@ export default function EmailPasswordForm({
- - setEmail(e.target.value)} - className={`auth-input ${fieldErrors.email ? 'auth-input-error' : ''}`} + error={fieldErrors.email} + classNames={{ label: 'auth-label' }} /> - {fieldErrors.email && ( -
{fieldErrors.email}
- )}
{showPasswordField && (
- - setPassword(e.target.value)} - className={`auth-input ${fieldErrors.password ? 'auth-input-error' : ''}`} + error={fieldErrors.password} + classNames={{ label: 'auth-label' }} /> - {fieldErrors.password && ( -
{fieldErrors.password}
- )}
)}
- +
); } diff --git a/frontend/src/proprietary/routes/login/NavigationLink.tsx b/frontend/src/proprietary/routes/login/NavigationLink.tsx index 935654381..af08094ce 100644 --- a/frontend/src/proprietary/routes/login/NavigationLink.tsx +++ b/frontend/src/proprietary/routes/login/NavigationLink.tsx @@ -1,3 +1,5 @@ +import { Button } from '@mantine/core'; + interface NavigationLinkProps { onClick: () => void text: string @@ -7,13 +9,14 @@ interface NavigationLinkProps { export default function NavigationLink({ onClick, text, isDisabled = false }: NavigationLinkProps) { return (
- +
); } diff --git a/frontend/src/proprietary/routes/login/OAuthButtons.tsx b/frontend/src/proprietary/routes/login/OAuthButtons.tsx index 4a9cc3cc3..a6e0679d7 100644 --- a/frontend/src/proprietary/routes/login/OAuthButtons.tsx +++ b/frontend/src/proprietary/routes/login/OAuthButtons.tsx @@ -1,6 +1,7 @@ import { useTranslation } from 'react-i18next'; import { BASE_PATH } from '@app/constants/app'; import { type OAuthProvider } from '@app/auth/oauthTypes'; +import { Button } from '@mantine/core'; // Debug flag to show all providers for UI testing // Set to true to see all SSO options regardless of backend configuration @@ -69,14 +70,15 @@ export default function OAuthButtons({ onProviderClick, isSubmitting, layout = '
{providers.map((p) => (
- +
))}
@@ -88,14 +90,15 @@ export default function OAuthButtons({ onProviderClick, isSubmitting, layout = '
{providers.map((p) => (
- +
))}
@@ -105,16 +108,18 @@ export default function OAuthButtons({ onProviderClick, isSubmitting, layout = ' return (
{providers.map((p) => ( - +
+ +
))}
); diff --git a/frontend/src/proprietary/routes/signup/SignupForm.tsx b/frontend/src/proprietary/routes/signup/SignupForm.tsx index 9e6ac9dc0..92c06c319 100644 --- a/frontend/src/proprietary/routes/signup/SignupForm.tsx +++ b/frontend/src/proprietary/routes/signup/SignupForm.tsx @@ -1,7 +1,7 @@ import { useEffect } from 'react'; import '@app/routes/authShared/auth.css'; import { useTranslation } from 'react-i18next'; -import { Checkbox } from '@mantine/core'; +import { Checkbox, TextInput, PasswordInput, Button } from '@mantine/core'; import { SignupFieldErrors } from '@app/routes/signup/SignupFormValidation'; interface SignupFormProps { @@ -53,57 +53,49 @@ export default function SignupForm({
{showName && (
- - setName?.(e.target.value)} - className={`auth-input ${fieldErrors.name ? 'auth-input-error' : ''}`} + error={fieldErrors.name} + classNames={{ label: 'auth-label' }} /> - {fieldErrors.name && ( -
{fieldErrors.name}
- )}
)}
- - setEmail(e.target.value)} - onKeyPress={(e) => e.key === 'Enter' && !isSubmitting && onSubmit()} - className={`auth-input ${fieldErrors.email ? 'auth-input-error' : ''}`} + onKeyDown={(e) => e.key === 'Enter' && !isSubmitting && onSubmit()} + error={fieldErrors.email} + classNames={{ label: 'auth-label' }} /> - {fieldErrors.email && ( -
{fieldErrors.email}
- )}
- - setPassword(e.target.value)} - onKeyPress={(e) => e.key === 'Enter' && !isSubmitting && onSubmit()} - className={`auth-input ${fieldErrors.password ? 'auth-input-error' : ''}`} + onKeyDown={(e) => e.key === 'Enter' && !isSubmitting && onSubmit()} + error={fieldErrors.password} + classNames={{ label: 'auth-label' }} /> - {fieldErrors.password && ( -
{fieldErrors.password}
- )}
- - setConfirmPassword(e.target.value)} - onKeyPress={(e) => e.key === 'Enter' && !isSubmitting && onSubmit()} - className={`auth-input ${fieldErrors.confirmPassword ? 'auth-input-error' : ''}`} + onKeyDown={(e) => e.key === 'Enter' && !isSubmitting && onSubmit()} + error={fieldErrors.confirmPassword} + classNames={{ label: 'auth-label' }} /> - {fieldErrors.confirmPassword && ( -
{fieldErrors.confirmPassword}
- )}
@@ -152,13 +141,15 @@ export default function SignupForm({ )} {/* Sign Up Button */} - + ); }