mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-11-16 01:21:16 +01:00
Frontend V2 Ui Tweaks (#4590)
* Top Controls only show when files > 0 * Moved content down so top controls don't obscure * Viewer background set to match workbench and shadow around pages added so that page boundaries are visible * unsaved-changes modal rework --------- Co-authored-by: Connor Yoh <connor@stirlingpdf.com>
This commit is contained in:
parent
03e81a0f16
commit
eba93a3b6c
@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"unsavedChanges": "You have unsaved changes to your PDF. What would you like to do?",
|
"unsavedChanges": "You have unsaved changes to your PDF.",
|
||||||
|
"areYouSure": "Are you sure you want to leave?",
|
||||||
"unsavedChangesTitle": "Unsaved Changes",
|
"unsavedChangesTitle": "Unsaved Changes",
|
||||||
"keepWorking": "Keep Working",
|
"keepWorking": "Keep Working",
|
||||||
"discardChanges": "Discard Changes",
|
"discardChanges": "Discard & Leave",
|
||||||
"applyAndContinue": "Apply & Continue",
|
"applyAndContinue": "Save & Leave",
|
||||||
"exportAndContinue": "Export & Continue",
|
"exportAndContinue": "Export & Continue",
|
||||||
"language": {
|
"language": {
|
||||||
"direction": "ltr"
|
"direction": "ltr"
|
||||||
|
|||||||
@ -348,7 +348,7 @@ const FileEditor = ({
|
|||||||
<Box pos="relative" style={{ overflow: 'auto' }}>
|
<Box pos="relative" style={{ overflow: 'auto' }}>
|
||||||
<LoadingOverlay visible={false} />
|
<LoadingOverlay visible={false} />
|
||||||
|
|
||||||
<Box p="md" pt="xl">
|
<Box p="md">
|
||||||
|
|
||||||
|
|
||||||
{activeStirlingFileStubs.length === 0 && !zipExtractionProgress.isExtracting ? (
|
{activeStirlingFileStubs.length === 0 && !zipExtractionProgress.isExtracting ? (
|
||||||
@ -446,7 +446,7 @@ const FileEditor = ({
|
|||||||
onSelectFiles={handleLoadFromStorage}
|
onSelectFiles={handleLoadFromStorage}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
</Box>
|
</Box>
|
||||||
</Dropzone>
|
</Dropzone>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -146,10 +146,12 @@ export default function Workbench() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
{/* Top Controls */}
|
{/* Top Controls */}
|
||||||
<TopControls
|
{activeFiles.length > 0 && (
|
||||||
currentView={currentView}
|
<TopControls
|
||||||
setCurrentView={setCurrentView}
|
currentView={currentView}
|
||||||
/>
|
setCurrentView={setCurrentView}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Dismiss All Errors Button */}
|
{/* Dismiss All Errors Button */}
|
||||||
<DismissAllErrorsButton />
|
<DismissAllErrorsButton />
|
||||||
@ -159,6 +161,7 @@ export default function Workbench() {
|
|||||||
className="flex-1 min-h-0 relative z-10 workbench-scrollable "
|
className="flex-1 min-h-0 relative z-10 workbench-scrollable "
|
||||||
style={{
|
style={{
|
||||||
transition: 'opacity 0.15s ease-in-out',
|
transition: 'opacity 0.15s ease-in-out',
|
||||||
|
paddingTop: activeFiles.length > 0 ? '3.5rem' : '0',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{renderMainContent()}
|
{renderMainContent()}
|
||||||
|
|||||||
@ -662,7 +662,7 @@ const PageEditor = ({
|
|||||||
const displayedPages = displayDocument?.pages || [];
|
const displayedPages = displayDocument?.pages || [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box pos="relative" h='100%' pt={40} style={{ overflow: 'auto' }} data-scrolling-container="true">
|
<Box pos="relative" h='100%' style={{ overflow: 'auto' }} data-scrolling-container="true">
|
||||||
<LoadingOverlay visible={globalProcessing && !mergedPdfDocument} />
|
<LoadingOverlay visible={globalProcessing && !mergedPdfDocument} />
|
||||||
|
|
||||||
{!mergedPdfDocument && !globalProcessing && activeFileIds.length === 0 && (
|
{!mergedPdfDocument && !globalProcessing && activeFileIds.length === 0 && (
|
||||||
|
|||||||
@ -1,25 +1,19 @@
|
|||||||
import { Modal, Text, Button, Group, Stack } from '@mantine/core';
|
import { Modal, Text, Button, Group, Stack } from "@mantine/core";
|
||||||
import { useNavigationGuard } from '../../contexts/NavigationContext';
|
import { useNavigationGuard } from "../../contexts/NavigationContext";
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from "react-i18next";
|
||||||
|
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
||||||
|
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
|
||||||
|
import CheckCircleOutlineIcon from "@mui/icons-material/CheckCircleOutline";
|
||||||
|
|
||||||
interface NavigationWarningModalProps {
|
interface NavigationWarningModalProps {
|
||||||
onApplyAndContinue?: () => Promise<void>;
|
onApplyAndContinue?: () => Promise<void>;
|
||||||
onExportAndContinue?: () => Promise<void>;
|
onExportAndContinue?: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NavigationWarningModal = ({
|
const NavigationWarningModal = ({ onApplyAndContinue, onExportAndContinue }: NavigationWarningModalProps) => {
|
||||||
onApplyAndContinue,
|
|
||||||
onExportAndContinue
|
|
||||||
}: NavigationWarningModalProps) => {
|
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const {
|
const { showNavigationWarning, hasUnsavedChanges, cancelNavigation, confirmNavigation, setHasUnsavedChanges } =
|
||||||
showNavigationWarning,
|
useNavigationGuard();
|
||||||
hasUnsavedChanges,
|
|
||||||
cancelNavigation,
|
|
||||||
confirmNavigation,
|
|
||||||
setHasUnsavedChanges
|
|
||||||
} = useNavigationGuard();
|
|
||||||
|
|
||||||
const handleKeepWorking = () => {
|
const handleKeepWorking = () => {
|
||||||
cancelNavigation();
|
cancelNavigation();
|
||||||
@ -38,13 +32,14 @@ const NavigationWarningModal = ({
|
|||||||
confirmNavigation();
|
confirmNavigation();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleExportAndContinue = async () => {
|
const _handleExportAndContinue = async () => {
|
||||||
if (onExportAndContinue) {
|
if (onExportAndContinue) {
|
||||||
await onExportAndContinue();
|
await onExportAndContinue();
|
||||||
}
|
}
|
||||||
setHasUnsavedChanges(false);
|
setHasUnsavedChanges(false);
|
||||||
confirmNavigation();
|
confirmNavigation();
|
||||||
};
|
};
|
||||||
|
const BUTTON_WIDTH = "10rem";
|
||||||
|
|
||||||
if (!hasUnsavedChanges) {
|
if (!hasUnsavedChanges) {
|
||||||
return null;
|
return null;
|
||||||
@ -56,55 +51,53 @@ const NavigationWarningModal = ({
|
|||||||
onClose={handleKeepWorking}
|
onClose={handleKeepWorking}
|
||||||
title={t("unsavedChangesTitle", "Unsaved Changes")}
|
title={t("unsavedChangesTitle", "Unsaved Changes")}
|
||||||
centered
|
centered
|
||||||
size="xl"
|
size="auto"
|
||||||
closeOnClickOutside={false}
|
closeOnClickOutside={true}
|
||||||
closeOnEscape={false}
|
closeOnEscape={true}
|
||||||
>
|
>
|
||||||
<Stack gap="xl">
|
<Stack>
|
||||||
<Text size="md">
|
<Stack ta="center" p="md">
|
||||||
{t("unsavedChanges", "You have unsaved changes to your PDF. What would you like to do?")}
|
<Text size="md" fw="300">
|
||||||
|
{t("unsavedChanges", "You have unsaved changes to your PDF.")}
|
||||||
</Text>
|
</Text>
|
||||||
|
<Text size="lg" fw="500" >
|
||||||
|
{t("areYouSure", "Are you sure you want to leave?")}
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
<Group justify="space-between" gap="xl" mt="xl">
|
{/* Desktop layout: 2 groups side by side */}
|
||||||
<Group gap="xl">
|
<Group justify="space-between" gap="xl" visibleFrom="md">
|
||||||
<Button
|
<Group gap="sm">
|
||||||
variant="light"
|
<Button variant="light" color="var(--mantine-color-gray-8)" onClick={handleKeepWorking} w={BUTTON_WIDTH} leftSection={<ArrowBackIcon fontSize="small" />}>
|
||||||
color="red"
|
|
||||||
onClick={handleDiscardChanges}
|
|
||||||
>
|
|
||||||
{t("discardChanges", "Discard Changes")}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
variant="light"
|
|
||||||
color="var(--mantine-color-gray-8)"
|
|
||||||
onClick={handleKeepWorking}
|
|
||||||
>
|
|
||||||
{t("keepWorking", "Keep Working")}
|
{t("keepWorking", "Keep Working")}
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
<Group gap="sm">
|
||||||
<Group gap="xl">
|
<Button variant="filled" color="var(--mantine-color-red-9)" onClick={handleDiscardChanges} w={BUTTON_WIDTH} leftSection={<DeleteOutlineIcon fontSize="small" />}>
|
||||||
{onExportAndContinue && (
|
{t("discardChanges", "Discard Changes")}
|
||||||
<Button
|
</Button>
|
||||||
variant="light"
|
|
||||||
onClick={handleExportAndContinue}
|
|
||||||
>
|
|
||||||
{t("exportAndContinue", "Export & Continue")}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{onApplyAndContinue && (
|
{onApplyAndContinue && (
|
||||||
<Button
|
<Button variant="filled" onClick={handleApplyAndContinue} w={BUTTON_WIDTH} leftSection={<CheckCircleOutlineIcon fontSize="small" />}>
|
||||||
variant="light"
|
{t("applyAndContinue", "Apply & Leave")}
|
||||||
color="blue"
|
|
||||||
onClick={handleApplyAndContinue}
|
|
||||||
>
|
|
||||||
{t("applyAndContinue", "Apply & Continue")}
|
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
|
{/* Mobile layout: centered stack of 4 buttons */}
|
||||||
|
<Stack align="center" gap="sm" hiddenFrom="md">
|
||||||
|
<Button variant="light" color="var(--mantine-color-gray-8)" onClick={handleKeepWorking} w={BUTTON_WIDTH} leftSection={<ArrowBackIcon fontSize="small" />}>
|
||||||
|
{t("keepWorking", "Keep Working")}
|
||||||
|
</Button>
|
||||||
|
<Button variant="filled" color="var(--mantine-color-red-9)" onClick={handleDiscardChanges} w={BUTTON_WIDTH} leftSection={<DeleteOutlineIcon fontSize="small" />}>
|
||||||
|
{t("discardChanges", "Discard Changes")}
|
||||||
|
</Button>
|
||||||
|
{onApplyAndContinue && (
|
||||||
|
<Button variant="filled" onClick={handleApplyAndContinue} w={BUTTON_WIDTH} leftSection={<CheckCircleOutlineIcon fontSize="small" />}>
|
||||||
|
{t("applyAndContinue", "Apply & Leave")}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -274,7 +274,7 @@ export function LocalEmbedPDF({ file, url, enableAnnotations = false, onSignatur
|
|||||||
<GlobalPointerProvider>
|
<GlobalPointerProvider>
|
||||||
<Viewport
|
<Viewport
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: 'var(--bg-surface)',
|
backgroundColor: 'var(--bg-background)',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
maxHeight: '100%',
|
maxHeight: '100%',
|
||||||
@ -299,7 +299,8 @@ export function LocalEmbedPDF({ file, url, enableAnnotations = false, onSignatur
|
|||||||
userSelect: 'none',
|
userSelect: 'none',
|
||||||
WebkitUserSelect: 'none',
|
WebkitUserSelect: 'none',
|
||||||
MozUserSelect: 'none',
|
MozUserSelect: 'none',
|
||||||
msUserSelect: 'none'
|
msUserSelect: 'none',
|
||||||
|
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)'
|
||||||
}}
|
}}
|
||||||
draggable={false}
|
draggable={false}
|
||||||
onDragStart={(e) => e.preventDefault()}
|
onDragStart={(e) => e.preventDefault()}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user