From c159ad4f376c6b089008694d2de6ef7cfd6676b3 Mon Sep 17 00:00:00 2001 From: Elijah Date: Wed, 10 Jun 2026 19:28:53 -0700 Subject: [PATCH] Update UI design to premium violet palette, tweak hero section, and make search bar outline visible --- frontend/package-lock.json | 20 ++++ frontend/package.json | 2 + frontend/src/features/auth/LoginForm.tsx | 19 ++-- frontend/src/features/auth/SetupForm.tsx | 26 ++--- frontend/src/features/library/ContextMenu.tsx | 16 +-- .../src/features/library/DocumentGrid.tsx | 53 ++++----- .../src/features/library/LibraryHeader.tsx | 103 +++++++++--------- frontend/src/features/library/UploadArea.tsx | 16 +-- frontend/src/index.css | 84 ++++++++------ frontend/src/pages/HomePage.tsx | 55 +++++++++- frontend/src/pages/LoginPage.tsx | 5 +- 11 files changed, 247 insertions(+), 152 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9850eac..2f3f411 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,6 +8,8 @@ "name": "paperjet", "version": "0.1.0", "dependencies": { + "@fontsource/outfit": "^5.2.8", + "@fontsource/plus-jakarta-sans": "^5.2.8", "@tailwindcss/vite": "^4.3.0", "date-fns": "^4.4.0", "fabric": "^7.4.0", @@ -658,6 +660,24 @@ } } }, + "node_modules/@fontsource/outfit": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource/outfit/-/outfit-5.2.8.tgz", + "integrity": "sha512-rXC6g0MqD7cOBjht0bMqc43qM6lRqDLML9KXsmg9uykz0wLQhy8Z/ajrMG6iyoT3NJR+MYgU+OEHp7uHoTb+Yw==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource/plus-jakarta-sans": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource/plus-jakarta-sans/-/plus-jakarta-sans-5.2.8.tgz", + "integrity": "sha512-P5qE49fqdeD+7DXH1KBxmMPlB17LTz1zvBhFH0tFzfnYTKVJVyb0pR6plh0ZGXxcB+Oayb54FZZw3V42/DawTw==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, "node_modules/@humanfs/core": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 7149971..f091777 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,6 +13,8 @@ "preview": "vite preview" }, "dependencies": { + "@fontsource/outfit": "^5.2.8", + "@fontsource/plus-jakarta-sans": "^5.2.8", "@tailwindcss/vite": "^4.3.0", "date-fns": "^4.4.0", "fabric": "^7.4.0", diff --git a/frontend/src/features/auth/LoginForm.tsx b/frontend/src/features/auth/LoginForm.tsx index 5949c2e..69665ce 100644 --- a/frontend/src/features/auth/LoginForm.tsx +++ b/frontend/src/features/auth/LoginForm.tsx @@ -20,25 +20,28 @@ export const LoginForm = () => { } return ( -
+
-

+
+ P +
+

Welcome back

-

+

Enter your master password to unlock your library

-
{error && ( -
+
{error}
)} @@ -55,10 +58,10 @@ export const LoginForm = () => { -
+
@@ -80,14 +80,14 @@ export const ContextMenu = ({ <> -
+
diff --git a/frontend/src/features/library/DocumentGrid.tsx b/frontend/src/features/library/DocumentGrid.tsx index c5a454c..efa7e6a 100644 --- a/frontend/src/features/library/DocumentGrid.tsx +++ b/frontend/src/features/library/DocumentGrid.tsx @@ -57,25 +57,21 @@ export const DocumentGrid = ({ isTrash }: { isTrash: boolean }) => {
handleContextMenu(e, doc.id)} - className={`group relative flex flex-col bg-white dark:bg-gray-800 rounded-2xl overflow-hidden shadow-sm hover:shadow-xl transition-all duration-300 border-2 ${ - isSelected ? 'border-indigo-500 shadow-md ring-2 ring-indigo-500/20' : 'border-transparent hover:border-indigo-200 dark:hover:border-indigo-800' + className={`group relative flex flex-col bg-white dark:bg-gray-800 rounded-3xl overflow-hidden shadow-sm hover:shadow-xl hover:shadow-accent-500/10 transition-all duration-300 border border-gray-200 dark:border-gray-700 hover:-translate-y-1 ${ + isSelected ? 'border-accent-500 shadow-md ring-2 ring-accent-500/50 scale-[1.02]' : 'hover:border-accent-300 dark:hover:border-accent-700' }`} > -
- toggleSelection(doc.id)} - className="w-5 h-5 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 cursor-pointer shadow-sm" - /> -
+ {isSelected && ( +
+ + + +
+ )} { if (isTrash) e.preventDefault() // disable link in trash }} @@ -83,27 +79,32 @@ export const DocumentGrid = ({ isTrash }: { isTrash: boolean }) => { {doc.title} { // Fallback if no thumbnail - (e.target as HTMLImageElement).src = 'data:image/svg+xml;utf8,' - ;(e.target as HTMLImageElement).className = 'w-1/2 h-1/2 absolute top-1/4 left-1/4 opacity-30 object-contain' + const target = e.target as HTMLImageElement; + target.onerror = null; + target.src = 'data:image/svg+xml;utf8,'; }} /> -
+ + {/* Hover overlay */} +
-
-

+
+

{doc.title}

-

- {formatDistanceToNow(new Date(doc.updated_at), { addSuffix: true })} -

-

- {(doc.size_bytes / 1024 / 1024).toFixed(1)} MB -

+
+

+ {formatDistanceToNow(new Date(doc.updated_at), { addSuffix: true })} +

+

+ {(doc.size_bytes / 1024 / 1024).toFixed(1)} MB +

+

) diff --git a/frontend/src/features/library/LibraryHeader.tsx b/frontend/src/features/library/LibraryHeader.tsx index dfe6460..047fd35 100644 --- a/frontend/src/features/library/LibraryHeader.tsx +++ b/frontend/src/features/library/LibraryHeader.tsx @@ -28,59 +28,60 @@ export const LibraryHeader = ({ currentTab, onTabChange }: { currentTab: 'librar const allSelected = documents.length > 0 && selectedIds.size === documents.length return ( -
-
+
+
- {/* Left: Branding & Tabs */} -
-
-
- P -
-

PaperJet

+ {/* Left: Logo Area */} +
+
+ P
- - +

+ PaperJet +

- {/* Right: Search & Actions */} + {/* Center: Navigation */} + + + {/* Right: Actions */}
{isSelectionMode ? ( -
- +
+ {selectedIds.size} selected -
+
- {currentTab === 'library' ? ( @@ -88,13 +89,13 @@ export const LibraryHeader = ({ currentTab, onTabChange }: { currentTab: 'librar <> @@ -104,10 +105,10 @@ export const LibraryHeader = ({ currentTab, onTabChange }: { currentTab: 'librar ) : ( <> {currentTab === 'library' && ( - -
- - +
+
+ +
setSearchQuery(e.target.value)} placeholder="Search documents..." - className="block w-full pl-10 pr-3 py-2 border border-gray-200 dark:border-gray-700 rounded-xl leading-5 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent sm:text-sm transition-all" + className="block w-full pl-11 pr-4 py-2 border border-gray-300 dark:border-gray-600 bg-white/80 dark:bg-gray-800/80 rounded-full leading-5 text-gray-900 dark:text-gray-100 placeholder-gray-500 focus:outline-none focus:bg-white focus:border-accent-400 focus:ring-4 focus:ring-accent-500/20 sm:text-sm transition-all shadow-inner font-medium" /> )} @@ -123,14 +124,14 @@ export const LibraryHeader = ({ currentTab, onTabChange }: { currentTab: 'librar {currentTab === 'trash' && ( )} {currentTab === 'library' && ( -
-
+
) } diff --git a/frontend/src/features/library/UploadArea.tsx b/frontend/src/features/library/UploadArea.tsx index 732e7ad..6f8ae8c 100644 --- a/frontend/src/features/library/UploadArea.tsx +++ b/frontend/src/features/library/UploadArea.tsx @@ -69,13 +69,15 @@ export const UploadArea = ({ children }: { children: React.ReactNode }) => { {/* Invisible overlay that appears when dragging to prevent flickering */} {isDragging && ( -
-
- - - -

Drop PDFs here

-

Release to upload to your library

+
+
+
+ + + +
+

Drop PDFs here

+

Release to upload to your library

)} diff --git a/frontend/src/index.css b/frontend/src/index.css index 1fda1df..2848b5d 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1,3 +1,12 @@ +@import "@fontsource/outfit/400.css"; +@import "@fontsource/outfit/500.css"; +@import "@fontsource/outfit/600.css"; +@import "@fontsource/outfit/700.css"; +@import "@fontsource/plus-jakarta-sans/400.css"; +@import "@fontsource/plus-jakarta-sans/500.css"; +@import "@fontsource/plus-jakarta-sans/600.css"; +@import "@fontsource/plus-jakarta-sans/700.css"; + @import "tailwindcss"; /* Force light mode by requiring a .dark class that we never add */ @@ -6,44 +15,44 @@ /* * PaperJet Design Tokens * - * Sejda-inspired: bright, airy, light mode with generous whitespace, - * a restrained palette (one accent), soft shadows, rounded corners. + * Canva-inspired: Playful but professional. Violet/Indigo accents, dot-grid background. */ @theme { - /* Accent color — refined blue */ - --color-accent-50: oklch(0.97 0.02 250); - --color-accent-100: oklch(0.93 0.04 250); - --color-accent-200: oklch(0.87 0.08 250); - --color-accent-300: oklch(0.78 0.12 250); - --color-accent-400: oklch(0.68 0.16 250); - --color-accent-500: oklch(0.58 0.19 250); - --color-accent-600: oklch(0.50 0.19 250); - --color-accent-700: oklch(0.43 0.17 250); - --color-accent-800: oklch(0.37 0.14 250); - --color-accent-900: oklch(0.30 0.10 250); + /* Premium Violet/Indigo Accent */ + --color-accent-50: #f5f3ff; + --color-accent-100: #ede9fe; + --color-accent-200: #ddd6fe; + --color-accent-300: #c4b5fd; + --color-accent-400: #a855f7; /* Purple */ + --color-accent-500: #8b5cf6; /* Violet */ + --color-accent-600: #7c3aed; + --color-accent-700: #6d28d9; + --color-accent-800: #5b21b6; + --color-accent-900: #4c1d95; - /* Neutrals — warm gray */ - --color-neutral-50: oklch(0.985 0.002 250); - --color-neutral-100: oklch(0.965 0.004 250); - --color-neutral-200: oklch(0.925 0.006 250); - --color-neutral-300: oklch(0.870 0.008 250); - --color-neutral-400: oklch(0.700 0.010 250); - --color-neutral-500: oklch(0.550 0.012 250); - --color-neutral-600: oklch(0.440 0.012 250); - --color-neutral-700: oklch(0.370 0.012 250); - --color-neutral-800: oklch(0.270 0.010 250); - --color-neutral-900: oklch(0.180 0.008 250); + /* Neutrals — clean cool gray */ + --color-neutral-50: #f8fafc; + --color-neutral-100: #f1f5f9; + --color-neutral-200: #e2e8f0; + --color-neutral-300: #cbd5e1; + --color-neutral-400: #94a3b8; + --color-neutral-500: #64748b; + --color-neutral-600: #475569; + --color-neutral-700: #334155; + --color-neutral-800: #1e293b; + --color-neutral-900: #0f172a; /* Semantic */ - --color-success: oklch(0.60 0.16 145); - --color-warning: oklch(0.75 0.16 65); - --color-error: oklch(0.58 0.20 25); + --color-success: #10b981; + --color-warning: #f59e0b; + --color-error: #ef4444; /* Typography */ - --font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif; - --font-mono: 'JetBrains Mono', ui-monospace, monospace; + --font-sans: 'Plus Jakarta Sans', ui-sans-serif, system-ui, -apple-system, sans-serif; + --font-heading: 'Outfit', ui-sans-serif, system-ui, -apple-system, sans-serif; /* Transitions */ + --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1); --ease-out: cubic-bezier(0.16, 1, 0.3, 1); --duration-fast: 150ms; --duration-normal: 250ms; @@ -61,18 +70,27 @@ html { font-family: var(--font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + scroll-behavior: smooth; } +/* + Modern Dot Grid Background + Very clean, provides texture without overwhelming the content. +*/ body { margin: 0; - background-color: var(--color-neutral-50); color: var(--color-neutral-800); line-height: 1.6; + background-color: #f8fafc; + background-image: radial-gradient(#cbd5e1 1px, transparent 1px); + background-size: 24px 24px; + min-height: 100vh; } -/* Smooth scrolling */ -html { - scroll-behavior: smooth; +/* Headings use the geometric font */ +h1, h2, h3, h4, h5, h6 { + font-family: var(--font-heading); + letter-spacing: -0.02em; } /* Focus ring utility */ diff --git a/frontend/src/pages/HomePage.tsx b/frontend/src/pages/HomePage.tsx index 1d83f64..11d9149 100644 --- a/frontend/src/pages/HomePage.tsx +++ b/frontend/src/pages/HomePage.tsx @@ -18,12 +18,64 @@ export function HomePage() { }, [currentTab, fetchDocuments, fetchTrash]) return ( -
+
{currentTab === 'library' ? ( + {/* Hero Section */} +
+ {/* Decorative background shapes */} +
+
+ +
+
+

+ What will you edit today? +

+

+ Upload any PDF to instantly annotate, sign, and modify it. Drop your files right here to get started. +

+ +
+ + {/* Visual Graphic */} +
+
+
+ + + +
+
+
+
+ +
+

Recent Documents

+
+
) : ( @@ -33,4 +85,3 @@ export function HomePage() {
) } - diff --git a/frontend/src/pages/LoginPage.tsx b/frontend/src/pages/LoginPage.tsx index 91d00a1..0e17442 100644 --- a/frontend/src/pages/LoginPage.tsx +++ b/frontend/src/pages/LoginPage.tsx @@ -2,9 +2,8 @@ import { LoginForm } from '@/features/auth/LoginForm' export function LoginPage() { return ( -
-
-
+
+