diff --git a/frontend/editor/public/locales/en-GB/translation.toml b/frontend/editor/public/locales/en-GB/translation.toml index 4c085512f..ddc117e01 100644 --- a/frontend/editor/public/locales/en-GB/translation.toml +++ b/frontend/editor/public/locales/en-GB/translation.toml @@ -8643,12 +8643,16 @@ enableDarkFilter = "Enable Dark Filter" enableSepiaFilter = "Enable Sepia Filter" firstPage = "First Page" lastPage = "Last Page" +moreOptions = "More" nextPage = "Next Page" onlyPdfSupported = "This file format is not supported for preview." +pageNavigation = "Page navigation" previousPage = "Previous Page" resetZoom = "Reset zoom" singlePageView = "Single Page View" unknownFile = "Unknown file" +view = "View" +zoom = "Zoom" zoomIn = "Zoom In" zoomOut = "Zoom Out" diff --git a/frontend/editor/src/core/components/fileEditor/AddFileCard.tsx b/frontend/editor/src/core/components/fileEditor/AddFileCard.tsx index a7aae35f2..00c9e4b39 100644 --- a/frontend/editor/src/core/components/fileEditor/AddFileCard.tsx +++ b/frontend/editor/src/core/components/fileEditor/AddFileCard.tsx @@ -104,44 +104,44 @@ const AddFileCard = ({ }} onMouseLeave={() => setIsUploadHover(false)} > - + + )} + {!isPhone && ( + + )} {/* Previous Page Button */} {/* Last Page Button */} - + {!isPhone && ( + + )} {/* Dual Page Toggle */} - - - + + + )} {/* PDF Render Mode Toggle */} - - - + + + )} - {/* Zoom Controls */} - - - - - zoomActions.setZoomLevel?.(val / 100)} - size="xs" - styles={{ - root: { width: "6rem" }, - thumb: { width: 14, height: 14 }, - track: { height: 3 }, - }} - label={null} - /> - + + + zoomActions.setZoomLevel?.(val / 100)} + size="xs" + styles={{ + root: { minWidth: "6rem", width: "6rem", flexShrink: 0 }, + thumb: { width: 14, height: 14 }, + track: { height: 3 }, + }} + label={null} + /> + + + + + {displayZoomPercent}% + + + )} + + {isPhone && ( + - - - - {displayZoomPercent}% - - + + + + + + + + {t("viewer.pageNavigation", "Page navigation")} + + } + disabled={scrollState.currentPage === 1} + onClick={handleFirstPage} + > + {t("viewer.firstPage", "First page")} + + } + disabled={scrollState.currentPage === scrollState.totalPages} + onClick={handleLastPage} + > + {t("viewer.lastPage", "Last page")} + + + + {t("viewer.zoom", "Zoom")} + } + onClick={handleZoomOut} + > + {t("viewer.zoomOut", "Zoom out")} + + } + onClick={handleZoomIn} + > + {t("viewer.zoomIn", "Zoom in")} ({displayZoomPercent}%) + + + + {t("viewer.view", "View")} + + ) : ( + + ) + } + disabled={scrollState.totalPages <= 1} + onClick={handleDualPageToggle} + > + {isDualPageActive + ? t("viewer.singlePageView", "Single Page View") + : t("viewer.dualPageView", "Dual Page View")} + + + ) : pdfRenderMode === "dark" ? ( + + ) : ( + + ) + } + onClick={cyclePdfRenderMode} + > + {pdfRenderMode === "normal" + ? t("viewer.enableDarkFilter", "Enable Dark Filter") + : pdfRenderMode === "dark" + ? t("viewer.enableSepiaFilter", "Enable Sepia Filter") + : t("viewer.disableColorFilter", "Disable Color Filter")} + + + + )} ); } diff --git a/frontend/editor/src/core/hooks/useIsMobile.ts b/frontend/editor/src/core/hooks/useIsMobile.ts index 23d461041..a75ef7924 100644 --- a/frontend/editor/src/core/hooks/useIsMobile.ts +++ b/frontend/editor/src/core/hooks/useIsMobile.ts @@ -15,3 +15,11 @@ export const useIsMobile = (): boolean => { export const useIsPhone = (): boolean => { return useMediaQuery("(max-width: 768px)") ?? false; }; + +/** + * Custom hook to detect a coarse pointer (touch device) + * Use to gate touch-only UI hints when combined with useIsMobile + */ +export const useIsTouch = (): boolean => { + return useMediaQuery("(pointer: coarse)") ?? false; +}; diff --git a/frontend/editor/src/core/pages/HomePage.tsx b/frontend/editor/src/core/pages/HomePage.tsx index a589ed43b..f1e5158da 100644 --- a/frontend/editor/src/core/pages/HomePage.tsx +++ b/frontend/editor/src/core/pages/HomePage.tsx @@ -5,7 +5,7 @@ import { Group } from "@mantine/core"; import { useSidebarContext } from "@app/contexts/SidebarContext"; import { useDocumentMeta } from "@app/hooks/useDocumentMeta"; import { useBaseUrl } from "@app/hooks/useBaseUrl"; -import { useIsMobile } from "@app/hooks/useIsMobile"; +import { useIsMobile, useIsTouch } from "@app/hooks/useIsMobile"; import { useAppConfig } from "@app/contexts/AppConfigContext"; import { LogoIcon } from "@app/components/shared/LogoIcon"; import { Wordmark } from "@app/components/shared/Wordmark"; @@ -84,6 +84,7 @@ export default function HomePage() { const navigate = useNavigate(); const { config } = useAppConfig(); const isMobile = useIsMobile(); + const isTouch = useIsTouch(); const sliderRef = useRef(null); const [activeMobileView, setActiveMobileView] = useState("tools"); const isProgrammaticScroll = useRef(false); @@ -352,12 +353,14 @@ export default function HomePage() { {t("home.mobile.workspace", "Workspace")} - - {t( - "home.mobile.swipeHint", - "Swipe left or right to switch views", - )} - + {isTouch && ( + + {t( + "home.mobile.swipeHint", + "Swipe left or right to switch views", + )} + + )} )} {navigationState.workbench === "myFiles" ? ( diff --git a/frontend/editor/src/proprietary/components/shared/config/OverviewHeader.tsx b/frontend/editor/src/proprietary/components/shared/config/OverviewHeader.tsx index 9f0de01f9..2307ed78b 100644 --- a/frontend/editor/src/proprietary/components/shared/config/OverviewHeader.tsx +++ b/frontend/editor/src/proprietary/components/shared/config/OverviewHeader.tsx @@ -1,19 +1,18 @@ import { Text, Button } from "@mantine/core"; import { useTranslation } from "react-i18next"; import { useAuth } from "@app/auth/UseSession"; -import { useNavigate } from "react-router-dom"; export function OverviewHeader() { const { t } = useTranslation(); const { signOut, user } = useAuth(); - const navigate = useNavigate(); const handleLogout = async () => { try { await signOut(); - navigate("/login"); } catch (error) { console.error("Logout error:", error); + } finally { + window.location.assign("/login"); } }; diff --git a/frontend/editor/src/proprietary/components/shared/config/configSections/AdminAdvancedSection.tsx b/frontend/editor/src/proprietary/components/shared/config/configSections/AdminAdvancedSection.tsx index 4450f9c18..e0b6a75e7 100644 --- a/frontend/editor/src/proprietary/components/shared/config/configSections/AdminAdvancedSection.tsx +++ b/frontend/editor/src/proprietary/components/shared/config/configSections/AdminAdvancedSection.tsx @@ -503,7 +503,7 @@ export default function AdminAdvancedSection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.advanced.enableAlphaFunctionality.label", @@ -543,7 +543,7 @@ export default function AdminAdvancedSection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.advanced.enableUrlToPDF.label", @@ -581,7 +581,7 @@ export default function AdminAdvancedSection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.advanced.disableSanitize.label", @@ -959,7 +959,7 @@ export default function AdminAdvancedSection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.advanced.tempFileManagement.startupCleanup.label", @@ -1002,7 +1002,7 @@ export default function AdminAdvancedSection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.advanced.tempFileManagement.cleanupSystemTemp.label", diff --git a/frontend/editor/src/proprietary/components/shared/config/configSections/AdminConnectionsSection.tsx b/frontend/editor/src/proprietary/components/shared/config/configSections/AdminConnectionsSection.tsx index 671a7c0a8..168ae6ca6 100644 --- a/frontend/editor/src/proprietary/components/shared/config/configSections/AdminConnectionsSection.tsx +++ b/frontend/editor/src/proprietary/components/shared/config/configSections/AdminConnectionsSection.tsx @@ -603,7 +603,7 @@ export default function AdminConnectionsSection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.connections.ssoAutoLogin.enable", @@ -674,7 +674,7 @@ export default function AdminConnectionsSection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.connections.mobileScanner.enable", diff --git a/frontend/editor/src/proprietary/components/shared/config/configSections/AdminDatabaseSection.tsx b/frontend/editor/src/proprietary/components/shared/config/configSections/AdminDatabaseSection.tsx index 7fd272fb5..05ad76bf7 100644 --- a/frontend/editor/src/proprietary/components/shared/config/configSections/AdminDatabaseSection.tsx +++ b/frontend/editor/src/proprietary/components/shared/config/configSections/AdminDatabaseSection.tsx @@ -496,7 +496,7 @@ export default function AdminDatabaseSection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.database.enableCustom.label", diff --git a/frontend/editor/src/proprietary/components/shared/config/configSections/AdminFeaturesSection.tsx b/frontend/editor/src/proprietary/components/shared/config/configSections/AdminFeaturesSection.tsx index 0e85990c6..86edd7444 100644 --- a/frontend/editor/src/proprietary/components/shared/config/configSections/AdminFeaturesSection.tsx +++ b/frontend/editor/src/proprietary/components/shared/config/configSections/AdminFeaturesSection.tsx @@ -200,7 +200,7 @@ export default function AdminFeaturesSection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.features.serverCertificate.enabled.label", @@ -316,7 +316,7 @@ export default function AdminFeaturesSection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.features.serverCertificate.regenerateOnStartup.label", diff --git a/frontend/editor/src/proprietary/components/shared/config/configSections/AdminGeneralSection.tsx b/frontend/editor/src/proprietary/components/shared/config/configSections/AdminGeneralSection.tsx index 709c3565f..a58e47823 100644 --- a/frontend/editor/src/proprietary/components/shared/config/configSections/AdminGeneralSection.tsx +++ b/frontend/editor/src/proprietary/components/shared/config/configSections/AdminGeneralSection.tsx @@ -703,7 +703,7 @@ export default function AdminGeneralSection() { marginBottom: "1rem", }} > -
+
{t( "admin.settings.general.hideDisabledTools.googleDrive.label", @@ -747,7 +747,7 @@ export default function AdminGeneralSection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.general.hideDisabledTools.mobileScanner.label", @@ -793,7 +793,7 @@ export default function AdminGeneralSection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.general.showUpdate.label", @@ -832,7 +832,7 @@ export default function AdminGeneralSection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.general.showUpdateOnlyAdmin.label", @@ -873,7 +873,7 @@ export default function AdminGeneralSection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.general.customHTMLFiles.label", @@ -938,7 +938,7 @@ export default function AdminGeneralSection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.general.customMetadata.autoUpdate.label", diff --git a/frontend/editor/src/proprietary/components/shared/config/configSections/AdminPremiumSection.tsx b/frontend/editor/src/proprietary/components/shared/config/configSections/AdminPremiumSection.tsx index 66c7fc911..d65abbf6f 100644 --- a/frontend/editor/src/proprietary/components/shared/config/configSections/AdminPremiumSection.tsx +++ b/frontend/editor/src/proprietary/components/shared/config/configSections/AdminPremiumSection.tsx @@ -197,7 +197,7 @@ export default function AdminPremiumSection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.premium.enabled.label", diff --git a/frontend/editor/src/proprietary/components/shared/config/configSections/AdminPrivacySection.tsx b/frontend/editor/src/proprietary/components/shared/config/configSections/AdminPrivacySection.tsx index 7a2b8b5de..37d6b7da1 100644 --- a/frontend/editor/src/proprietary/components/shared/config/configSections/AdminPrivacySection.tsx +++ b/frontend/editor/src/proprietary/components/shared/config/configSections/AdminPrivacySection.tsx @@ -165,7 +165,7 @@ export default function AdminPrivacySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.privacy.enableAnalytics.label", @@ -203,7 +203,7 @@ export default function AdminPrivacySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.privacy.metricsEnabled.label", @@ -253,7 +253,7 @@ export default function AdminPrivacySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.privacy.googleVisibility.label", diff --git a/frontend/editor/src/proprietary/components/shared/config/configSections/AdminSecuritySection.tsx b/frontend/editor/src/proprietary/components/shared/config/configSections/AdminSecuritySection.tsx index 20e559d9e..02d1f2701 100644 --- a/frontend/editor/src/proprietary/components/shared/config/configSections/AdminSecuritySection.tsx +++ b/frontend/editor/src/proprietary/components/shared/config/configSections/AdminSecuritySection.tsx @@ -292,7 +292,7 @@ export default function AdminSecuritySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.security.enableLogin.label", @@ -519,7 +519,7 @@ export default function AdminSecuritySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.security.jwt.persistence.label", @@ -556,7 +556,7 @@ export default function AdminSecuritySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.security.jwt.enableKeyRotation.label", @@ -596,7 +596,7 @@ export default function AdminSecuritySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.security.jwt.enableKeyCleanup.label", @@ -780,7 +780,7 @@ export default function AdminSecuritySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.security.jwt.secureCookie.label", @@ -840,7 +840,7 @@ export default function AdminSecuritySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.security.audit.enabled.label", @@ -955,7 +955,7 @@ export default function AdminSecuritySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.security.audit.captureFileHash.label", @@ -995,7 +995,7 @@ export default function AdminSecuritySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.security.audit.capturePdfAuthor.label", @@ -1035,7 +1035,7 @@ export default function AdminSecuritySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.security.audit.captureOperationResults.label", @@ -1097,7 +1097,7 @@ export default function AdminSecuritySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.security.htmlUrlSecurity.enabled.label", @@ -1374,7 +1374,7 @@ export default function AdminSecuritySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.security.htmlUrlSecurity.blockPrivateNetworks.label", @@ -1424,7 +1424,7 @@ export default function AdminSecuritySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.security.htmlUrlSecurity.blockLocalhost.label", @@ -1473,7 +1473,7 @@ export default function AdminSecuritySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.security.htmlUrlSecurity.blockLinkLocal.label", @@ -1522,7 +1522,7 @@ export default function AdminSecuritySection() { justifyContent: "space-between", }} > -
+
{t( "admin.settings.security.htmlUrlSecurity.blockCloudMetadata.label", diff --git a/frontend/editor/src/proprietary/components/shared/config/configSections/PeopleSection.tsx b/frontend/editor/src/proprietary/components/shared/config/configSections/PeopleSection.tsx index f9ca9eab4..9a0a76014 100644 --- a/frontend/editor/src/proprietary/components/shared/config/configSections/PeopleSection.tsx +++ b/frontend/editor/src/proprietary/components/shared/config/configSections/PeopleSection.tsx @@ -585,9 +585,12 @@ export default function PeopleSection() { {t("workspace.people.user")} {t("workspace.people.role")} @@ -690,7 +693,7 @@ export default function PeopleSection() { - + {(user.rolesAsString || "").includes("ROLE_ADMIN") ? t("workspace.people.admin", "Admin")