+
-
);
diff --git a/frontend/src/pages/HomePage.tsx b/frontend/src/pages/HomePage.tsx
index 9ceec9948..e6d761cd5 100644
--- a/frontend/src/pages/HomePage.tsx
+++ b/frontend/src/pages/HomePage.tsx
@@ -78,14 +78,12 @@ export default function HomePage() {
{/* Left: Tool Picker */}
{sidebarsVisible && (
+
{/* Top Controls */}
-
+
{(currentView === "viewer" || currentView === "pageEditor") && !pdfFile ? (
setSidebarsVisible((v) => !v)}
>
{t("sidebar.toggle", sidebarsVisible ? "Hide Sidebars" : "Show Sidebars")}
diff --git a/frontend/src/styles/HomePage.module.css b/frontend/src/styles/HomePage.module.css
index 5ffd91e12..51c69670c 100644
--- a/frontend/src/styles/HomePage.module.css
+++ b/frontend/src/styles/HomePage.module.css
@@ -1,95 +1,13 @@
-/* Main container */
-.container {
- min-height: 100vh;
- width: 100vw;
- overflow: hidden;
- flex-wrap: nowrap;
- display: flex;
-}
+/* Use Tailwind for most styles, keep only complex layouts in CSS modules */
-/* Left sidebar */
.leftSidebar {
- min-width: 180px;
- max-width: 240px;
- width: 16vw;
- height: 100vh;
- z-index: 101;
- display: flex;
- flex-direction: column;
+ min-width: var(--sidebar-width-min);
+ max-width: var(--sidebar-width-max);
+ width: var(--sidebar-width);
}
-.leftSidebarLight {
- border-right: 1px solid #e9ecef;
- background: #fff;
-}
-
-.leftSidebarDark {
- border-right: 1px solid var(--mantine-color-dark-4);
- background: var(--mantine-color-dark-7);
-}
-
-/* Main content area */
-.mainContent {
- flex: 1;
- height: 100vh;
- min-width: 20rem;
- position: relative;
- display: flex;
- flex-direction: column;
- transition: all 0.3s;
-}
-
-.mainContentLight {
- background: #f8f9fa;
-}
-
-.mainContentDark {
- background: var(--mantine-color-dark-6);
-}
-
-/* Main paper container */
-.mainPaper {
- flex: 1;
- min-height: 0;
- margin-top: 0;
- box-sizing: border-box;
- overflow: hidden;
- display: flex;
- flex-direction: column;
-}
-
-.mainPaperInner {
- flex: 1;
- min-height: 0;
-}
-
-/* Right sidebar */
.rightSidebar {
min-width: 260px;
max-width: 400px;
width: 22vw;
- height: 100vh;
- padding: 24px;
- gap: 16px;
- z-index: 100;
- display: flex;
- flex-direction: column;
}
-
-.rightSidebarLight {
- border-left: 1px solid #e9ecef;
- background: #fff;
-}
-
-.rightSidebarDark {
- border-left: 1px solid var(--mantine-color-dark-4);
- background: var(--mantine-color-dark-7);
-}
-
-/* Sidebar toggle button */
-.sidebarToggle {
- position: fixed;
- top: 16px;
- right: 16px;
- z-index: 200;
-}
\ No newline at end of file
diff --git a/frontend/src/styles/components.css b/frontend/src/styles/components.css
new file mode 100644
index 000000000..4eb82cb55
--- /dev/null
+++ b/frontend/src/styles/components.css
@@ -0,0 +1,123 @@
+/* Custom component styles that don't fit Tailwind patterns */
+
+/* Mantine component overrides */
+.mantine-override {
+ /* Custom overrides for Mantine components when needed */
+}
+
+/* PDF-specific custom components */
+.pdf-page-thumbnail {
+ aspect-ratio: 3/4;
+ background: var(--bg-surface);
+ border: 1px solid var(--border-subtle);
+ border-radius: var(--radius-sm);
+ overflow: hidden;
+ position: relative;
+}
+
+.pdf-page-thumbnail:hover {
+ border-color: var(--color-primary-500);
+ box-shadow: var(--shadow-md);
+}
+
+.pdf-page-thumbnail img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+
+/* Loading spinner for PDF operations */
+.pdf-loading {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-height: 200px;
+ background: var(--bg-surface);
+ border-radius: var(--radius-md);
+}
+
+/* Custom scrollbar for PDF viewer */
+.pdf-viewer-container {
+ scrollbar-width: thin;
+ scrollbar-color: var(--border-strong) var(--bg-muted);
+}
+
+.pdf-viewer-container::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+}
+
+.pdf-viewer-container::-webkit-scrollbar-track {
+ background: var(--bg-muted);
+ border-radius: var(--radius-md);
+}
+
+.pdf-viewer-container::-webkit-scrollbar-thumb {
+ background: var(--border-strong);
+ border-radius: var(--radius-md);
+}
+
+.pdf-viewer-container::-webkit-scrollbar-thumb:hover {
+ background: var(--color-primary-500);
+}
+
+/* File upload drag and drop animations */
+.file-drop-zone.drag-over {
+ animation: pulse 1s infinite;
+}
+
+@keyframes pulse {
+ 0%, 100% {
+ transform: scale(1);
+ }
+ 50% {
+ transform: scale(1.02);
+ }
+}
+
+/* Progress bar for operations */
+.progress-bar {
+ width: 100%;
+ height: 4px;
+ background: var(--bg-muted);
+ border-radius: var(--radius-full);
+ overflow: hidden;
+}
+
+.progress-bar-fill {
+ height: 100%;
+ background: var(--color-primary-500);
+ border-radius: var(--radius-full);
+ transition: width 0.3s ease;
+}
+
+/* Tool-specific layouts that need custom CSS */
+.split-preview-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
+ gap: var(--space-md);
+ padding: var(--space-md);
+ background: var(--bg-surface);
+ border-radius: var(--radius-lg);
+ border: 1px solid var(--border-subtle);
+}
+
+/* Error states */
+.error-state {
+ padding: var(--space-lg);
+ text-align: center;
+ background: var(--bg-surface);
+ border: 1px solid var(--color-error);
+ border-radius: var(--radius-md);
+ color: var(--color-error);
+}
+
+/* Success states */
+.success-state {
+ padding: var(--space-lg);
+ text-align: center;
+ background: var(--bg-surface);
+ border: 1px solid var(--color-success);
+ border-radius: var(--radius-md);
+ color: var(--color-success);
+}
\ No newline at end of file
diff --git a/frontend/src/styles/tailwind.css b/frontend/src/styles/tailwind.css
new file mode 100644
index 000000000..3a32f3d32
--- /dev/null
+++ b/frontend/src/styles/tailwind.css
@@ -0,0 +1,66 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+/* Custom component classes using Tailwind (with app- prefix to avoid Mantine conflicts) */
+@layer components {
+ .app-card {
+ @apply bg-bg-surface border border-border-subtle rounded-app-lg p-app-lg shadow-app-md;
+ }
+
+ .app-surface {
+ @apply bg-bg-surface border border-border-subtle rounded-app-md shadow-app-sm;
+ }
+
+ .app-raised {
+ @apply bg-bg-raised shadow-app-sm rounded-app-md;
+ }
+
+ .app-interactive {
+ @apply cursor-pointer transition-all duration-200 hover:bg-hover-bg active:bg-active-bg;
+ }
+
+ .app-file-drop-zone {
+ @apply border-2 border-dashed border-file-drop rounded-app-lg bg-bg-surface transition-all duration-200;
+ }
+
+ .app-file-drop-zone:hover,
+ .app-file-drop-zone.drag-over {
+ @apply border-app-primary-500 bg-file-drop-hover;
+ }
+
+ /* PDF-specific component classes */
+ .app-pdf-viewer-bg {
+ @apply bg-pdf-viewer;
+ }
+
+ .app-pdf-toolbar {
+ @apply bg-pdf-toolbar border-b border-border-subtle;
+ }
+
+ /* Button variants */
+ .app-btn-pdf-tool {
+ @apply bg-bg-surface border border-border-default text-text-primary px-app-md py-app-sm rounded-app-md font-medium transition-all duration-200 hover:bg-hover-bg hover:border-app-primary-500;
+ }
+
+ /* Focus styles */
+ .app-focus-ring {
+ @apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2;
+ }
+}
+
+/* Custom utilities */
+@layer utilities {
+ .text-balance {
+ text-wrap: balance;
+ }
+
+ .scrollbar-hide {
+ -ms-overflow-style: none;
+ scrollbar-width: none;
+ }
+
+ .scrollbar-hide::-webkit-scrollbar {
+ display: none;
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/styles/theme.css b/frontend/src/styles/theme.css
new file mode 100644
index 000000000..42345f479
--- /dev/null
+++ b/frontend/src/styles/theme.css
@@ -0,0 +1,160 @@
+/* Design System CSS Variables - Single Source of Truth */
+
+:root {
+ /* Color System */
+ --color-primary-50: #eff6ff;
+ --color-primary-100: #dbeafe;
+ --color-primary-200: #bfdbfe;
+ --color-primary-300: #93c5fd;
+ --color-primary-400: #60a5fa;
+ --color-primary-500: #3b82f6;
+ --color-primary-600: #2563eb;
+ --color-primary-700: #1d4ed8;
+ --color-primary-800: #1e40af;
+ --color-primary-900: #1e3a8a;
+
+ --color-gray-50: #f9fafb;
+ --color-gray-100: #f3f4f6;
+ --color-gray-200: #e5e7eb;
+ --color-gray-300: #d1d5db;
+ --color-gray-400: #9ca3af;
+ --color-gray-500: #6b7280;
+ --color-gray-600: #4b5563;
+ --color-gray-700: #374151;
+ --color-gray-800: #1f2937;
+ --color-gray-900: #111827;
+
+ /* Semantic Colors */
+ --color-success: #10b981;
+ --color-warning: #f59e0b;
+ --color-error: #ef4444;
+ --color-info: #3b82f6;
+
+ /* Spacing System */
+ --space-xs: 4px;
+ --space-sm: 8px;
+ --space-md: 16px;
+ --space-lg: 24px;
+ --space-xl: 32px;
+ --space-2xl: 48px;
+
+ /* Radius System */
+ --radius-xs: 2px;
+ --radius-sm: 4px;
+ --radius-md: 8px;
+ --radius-lg: 12px;
+ --radius-xl: 16px;
+ --radius-2xl: 24px;
+ --radius-full: 9999px;
+
+ /* Shadow System */
+ --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
+ --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
+ --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
+ --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.1);
+
+ /* Layout */
+ --sidebar-width-min: 180px;
+ --sidebar-width-max: 240px;
+ --sidebar-width: 16vw;
+ --header-height: 60px;
+ --border-width: 1px;
+
+ /* Typography */
+ --font-weight-normal: 400;
+ --font-weight-medium: 500;
+ --font-weight-semibold: 600;
+ --font-weight-bold: 700;
+
+ /* Z-Index Scale */
+ --z-dropdown: 1000;
+ --z-sticky: 1020;
+ --z-fixed: 1030;
+ --z-modal-backdrop: 1040;
+ --z-modal: 1050;
+ --z-popover: 1060;
+ --z-tooltip: 1070;
+}
+
+/* Light Theme */
+:root, [data-mantine-color-scheme="light"] {
+ /* Background Colors */
+ --bg-app: var(--color-gray-50);
+ --bg-surface: #ffffff;
+ --bg-raised: var(--color-gray-50);
+ --bg-overlay: rgba(255, 255, 255, 0.8);
+ --bg-muted: var(--color-gray-100);
+
+ /* Text Colors */
+ --text-primary: var(--color-gray-900);
+ --text-secondary: var(--color-gray-600);
+ --text-muted: var(--color-gray-500);
+ --text-inverse: #ffffff;
+
+ /* Border Colors */
+ --border-subtle: var(--color-gray-200);
+ --border-default: var(--color-gray-300);
+ --border-strong: var(--color-gray-400);
+
+ /* Interactive States */
+ --hover-bg: var(--color-gray-50);
+ --active-bg: var(--color-gray-100);
+ --focus-ring: var(--color-primary-500);
+
+ /* PDF Tool Specific */
+ --pdf-viewer-bg: #f8fafc;
+ --pdf-toolbar-bg: var(--bg-surface);
+ --file-drop-border: var(--color-gray-300);
+ --file-drop-hover: var(--color-primary-100);
+}
+
+/* Dark Theme */
+[data-mantine-color-scheme="dark"] {
+ /* Background Colors */
+ --bg-app: var(--color-gray-900);
+ --bg-surface: var(--color-gray-800);
+ --bg-raised: var(--color-gray-700);
+ --bg-overlay: rgba(17, 24, 39, 0.8);
+ --bg-muted: var(--color-gray-700);
+
+ /* Text Colors */
+ --text-primary: var(--color-gray-50);
+ --text-secondary: var(--color-gray-300);
+ --text-muted: var(--color-gray-400);
+ --text-inverse: var(--color-gray-900);
+
+ /* Border Colors */
+ --border-subtle: var(--color-gray-700);
+ --border-default: var(--color-gray-600);
+ --border-strong: var(--color-gray-500);
+
+ /* Interactive States */
+ --hover-bg: var(--color-gray-700);
+ --active-bg: var(--color-gray-600);
+ --focus-ring: var(--color-primary-400);
+
+ /* PDF Tool Specific */
+ --pdf-viewer-bg: var(--color-gray-800);
+ --pdf-toolbar-bg: var(--bg-surface);
+ --file-drop-border: var(--color-gray-600);
+ --file-drop-hover: var(--color-primary-900);
+
+ /* Shadow adjustments for dark mode */
+ --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.3);
+ --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4);
+ --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
+ --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.4);
+ --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.4);
+}
+
+/* Smooth transitions for theme switching */
+* {
+ transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
+}
+
+/* Focus styles */
+*:focus-visible {
+ outline: 2px solid var(--focus-ring);
+ outline-offset: 2px;
+}
\ No newline at end of file
diff --git a/frontend/src/theme/mantineTheme.ts b/frontend/src/theme/mantineTheme.ts
new file mode 100644
index 000000000..017b7d737
--- /dev/null
+++ b/frontend/src/theme/mantineTheme.ts
@@ -0,0 +1,281 @@
+import { createTheme, MantineColorsTuple } from '@mantine/core';
+
+// Define color tuples using CSS variables
+const primary: MantineColorsTuple = [
+ 'var(--color-primary-50)',
+ 'var(--color-primary-100)',
+ 'var(--color-primary-200)',
+ 'var(--color-primary-300)',
+ 'var(--color-primary-400)',
+ 'var(--color-primary-500)',
+ 'var(--color-primary-600)',
+ 'var(--color-primary-700)',
+ 'var(--color-primary-800)',
+ 'var(--color-primary-900)',
+];
+
+const gray: MantineColorsTuple = [
+ 'var(--color-gray-50)',
+ 'var(--color-gray-100)',
+ 'var(--color-gray-200)',
+ 'var(--color-gray-300)',
+ 'var(--color-gray-400)',
+ 'var(--color-gray-500)',
+ 'var(--color-gray-600)',
+ 'var(--color-gray-700)',
+ 'var(--color-gray-800)',
+ 'var(--color-gray-900)',
+];
+
+export const mantineTheme = createTheme({
+ // Primary color
+ primaryColor: 'primary',
+
+ // Color palette
+ colors: {
+ primary,
+ gray,
+ },
+
+ // Spacing system - uses CSS variables
+ spacing: {
+ xs: 'var(--space-xs)',
+ sm: 'var(--space-sm)',
+ md: 'var(--space-md)',
+ lg: 'var(--space-lg)',
+ xl: 'var(--space-xl)',
+ },
+
+ // Border radius system
+ radius: {
+ xs: 'var(--radius-xs)',
+ sm: 'var(--radius-sm)',
+ md: 'var(--radius-md)',
+ lg: 'var(--radius-lg)',
+ xl: 'var(--radius-xl)',
+ },
+
+ // Shadow system
+ shadows: {
+ xs: 'var(--shadow-xs)',
+ sm: 'var(--shadow-sm)',
+ md: 'var(--shadow-md)',
+ lg: 'var(--shadow-lg)',
+ xl: 'var(--shadow-xl)',
+ },
+
+ // Font weights
+ fontWeights: {
+ normal: 'var(--font-weight-normal)',
+ medium: 'var(--font-weight-medium)',
+ semibold: 'var(--font-weight-semibold)',
+ bold: 'var(--font-weight-bold)',
+ },
+
+ // Component customizations
+ components: {
+ Button: {
+ styles: {
+ root: {
+ fontWeight: 'var(--font-weight-medium)',
+ transition: 'all 0.2s ease',
+ },
+ },
+ variants: {
+ // Custom button variant for PDF tools
+ pdfTool: (theme) => ({
+ root: {
+ backgroundColor: 'var(--bg-surface)',
+ border: '1px solid var(--border-default)',
+ color: 'var(--text-primary)',
+ '&:hover': {
+ backgroundColor: 'var(--hover-bg)',
+ borderColor: 'var(--color-primary-500)',
+ },
+ },
+ }),
+ },
+ },
+
+ Paper: {
+ styles: {
+ root: {
+ backgroundColor: 'var(--bg-surface)',
+ border: '1px solid var(--border-subtle)',
+ },
+ },
+ },
+
+ Card: {
+ styles: {
+ root: {
+ backgroundColor: 'var(--bg-surface)',
+ border: '1px solid var(--border-subtle)',
+ boxShadow: 'var(--shadow-sm)',
+ },
+ },
+ },
+
+ TextInput: {
+ styles: {
+ input: {
+ backgroundColor: 'var(--bg-surface)',
+ borderColor: 'var(--border-default)',
+ color: 'var(--text-primary)',
+ '&:focus': {
+ borderColor: 'var(--color-primary-500)',
+ boxShadow: '0 0 0 1px var(--color-primary-500)',
+ },
+ },
+ label: {
+ color: 'var(--text-secondary)',
+ fontWeight: 'var(--font-weight-medium)',
+ },
+ },
+ },
+
+ Select: {
+ styles: {
+ input: {
+ backgroundColor: 'var(--bg-surface)',
+ borderColor: 'var(--border-default)',
+ color: 'var(--text-primary)',
+ '&:focus': {
+ borderColor: 'var(--color-primary-500)',
+ boxShadow: '0 0 0 1px var(--color-primary-500)',
+ },
+ },
+ label: {
+ color: 'var(--text-secondary)',
+ fontWeight: 'var(--font-weight-medium)',
+ },
+ dropdown: {
+ backgroundColor: 'var(--bg-surface)',
+ borderColor: 'var(--border-subtle)',
+ boxShadow: 'var(--shadow-lg)',
+ },
+ option: {
+ color: 'var(--text-primary)',
+ '&[data-hovered]': {
+ backgroundColor: 'var(--hover-bg)',
+ },
+ '&[data-selected]': {
+ backgroundColor: 'var(--color-primary-100)',
+ color: 'var(--color-primary-900)',
+ },
+ },
+ },
+ },
+
+ Checkbox: {
+ styles: {
+ input: {
+ borderColor: 'var(--border-default)',
+ '&:checked': {
+ backgroundColor: 'var(--color-primary-500)',
+ borderColor: 'var(--color-primary-500)',
+ },
+ },
+ label: {
+ color: 'var(--text-primary)',
+ },
+ },
+ },
+
+ Slider: {
+ styles: {
+ track: {
+ backgroundColor: 'var(--bg-muted)',
+ },
+ bar: {
+ backgroundColor: 'var(--color-primary-500)',
+ },
+ thumb: {
+ backgroundColor: 'var(--color-primary-500)',
+ borderColor: 'var(--color-primary-500)',
+ },
+ mark: {
+ borderColor: 'var(--border-default)',
+ },
+ markLabel: {
+ color: 'var(--text-muted)',
+ },
+ },
+ },
+
+ Modal: {
+ styles: {
+ content: {
+ backgroundColor: 'var(--bg-surface)',
+ border: '1px solid var(--border-subtle)',
+ boxShadow: 'var(--shadow-xl)',
+ },
+ header: {
+ backgroundColor: 'var(--bg-surface)',
+ borderBottom: '1px solid var(--border-subtle)',
+ },
+ title: {
+ color: 'var(--text-primary)',
+ fontWeight: 'var(--font-weight-semibold)',
+ },
+ },
+ },
+
+ Notification: {
+ styles: {
+ root: {
+ backgroundColor: 'var(--bg-surface)',
+ border: '1px solid var(--border-subtle)',
+ boxShadow: 'var(--shadow-lg)',
+ },
+ title: {
+ color: 'var(--text-primary)',
+ },
+ description: {
+ color: 'var(--text-secondary)',
+ },
+ },
+ },
+
+ SegmentedControl: {
+ styles: {
+ root: {
+ backgroundColor: 'var(--bg-muted)',
+ border: '1px solid var(--border-subtle)',
+ },
+ control: {
+ color: 'var(--text-secondary)',
+ '&[data-active]': {
+ backgroundColor: 'var(--bg-surface)',
+ color: 'var(--text-primary)',
+ boxShadow: 'var(--shadow-sm)',
+ },
+ },
+ },
+ },
+ },
+
+ // Global styles
+ globalStyles: () => ({
+ // Ensure smooth color transitions
+ '*': {
+ transition: 'background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease',
+ },
+
+ // Custom scrollbar styling
+ '*::-webkit-scrollbar': {
+ width: '8px',
+ height: '8px',
+ },
+ '*::-webkit-scrollbar-track': {
+ backgroundColor: 'var(--bg-muted)',
+ },
+ '*::-webkit-scrollbar-thumb': {
+ backgroundColor: 'var(--border-strong)',
+ borderRadius: 'var(--radius-md)',
+ },
+ '*::-webkit-scrollbar-thumb:hover': {
+ backgroundColor: 'var(--color-primary-500)',
+ },
+ }),
+});
\ No newline at end of file
diff --git a/frontend/src/tools/Split.tsx b/frontend/src/tools/Split.tsx
index 37b4efe8c..2e3dbbe24 100644
--- a/frontend/src/tools/Split.tsx
+++ b/frontend/src/tools/Split.tsx
@@ -143,7 +143,7 @@ const SplitPdfPanel: React.FC = ({
};
return (
-