feat(bookmark): improve pdf bookmark tool ui with dark mode and drag-drop

- Add dark mode styling to the bookmark tool page
- Implement drag-and-drop file upload zones for PDF, CSV and JSON
- Enhance file input UI with icons and better visual feedback
- Fix formatting and whitespace issues in multiple files
This commit is contained in:
abdullahalam123
2025-10-27 22:35:49 +05:30
parent 72e74d2a62
commit 090146c600
7 changed files with 95 additions and 43 deletions

View File

@@ -339,7 +339,6 @@
</div> </div>
</footer> </footer>
<script type="module" src="src/js/utils/lucide-init.ts"></script> <script type="module" src="src/js/utils/lucide-init.ts"></script>
<script type="module" src="src/js/mobileMenu.ts"></script> <script type="module" src="src/js/mobileMenu.ts"></script>

View File

@@ -78,11 +78,10 @@ export const categories = [
}, },
{ {
// id: 'bookmark-pdf', // id: 'bookmark-pdf',
href: '/src/pages/bookmark.html', href: '/src/pages/bookmark.html',
name: 'Edit Bookmarks', name: 'Edit Bookmarks',
icon: 'bookmark', icon: 'bookmark',
subtitle: subtitle: 'Add, edit, import, delete and extract PDF bookmarks.',
'Add, edit, import, delete and extract PDF bookmarks.',
}, },
{ {
id: 'add-page-numbers', id: 'add-page-numbers',

View File

@@ -1,4 +1,6 @@
// @ts-nocheck // @ts-nocheck
// TODO: @ALAM - remove ts-nocheck and fix types later, possibly convert this into an npm package
import { PDFDocument, PDFName, PDFString, PDFNumber, PDFArray } from 'pdf-lib'; import { PDFDocument, PDFName, PDFString, PDFNumber, PDFArray } from 'pdf-lib';
import * as pdfjsLib from 'pdfjs-dist'; import * as pdfjsLib from 'pdfjs-dist';
import Sortable from 'sortablejs'; import Sortable from 'sortablejs';

View File

@@ -137,7 +137,7 @@ const init = () => {
'grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4 md:gap-6'; 'grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4 md:gap-6';
category.tools.forEach((tool) => { category.tools.forEach((tool) => {
let toolCard: HTMLDivElement | HTMLAnchorElement; let toolCard: HTMLDivElement | HTMLAnchorElement;
if (tool.href) { if (tool.href) {
toolCard = document.createElement('a'); toolCard = document.createElement('a');
@@ -262,5 +262,3 @@ const init = () => {
}; };
document.addEventListener('DOMContentLoaded', init); document.addEventListener('DOMContentLoaded', init);

View File

@@ -179,12 +179,11 @@ export async function initializeQpdf() {
return qpdfInstance; return qpdfInstance;
} }
export function initializeIcons(): void { export function initializeIcons(): void {
createIcons({ createIcons({
attrs: { attrs: {
class: 'bento-icon', class: 'bento-icon',
'stroke-width': '1.5', 'stroke-width': '1.5',
}, },
}); });
} }

View File

@@ -2,4 +2,4 @@ import { createIcons, icons } from 'lucide';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
createIcons({ icons }); createIcons({ icons });
}); });

View File

@@ -10,7 +10,7 @@
<style> <style>
.sortable-ghost { .sortable-ghost {
opacity: 0.4; opacity: 0.4;
border: 2px dashed #2b7fff; border: 2px dashed #2b7fff;
} }
.sortable-drag { .sortable-drag {
cursor: move; cursor: move;
@@ -137,7 +137,7 @@
} }
</style> </style>
</head> </head>
<body class="bg-gray-50"> <body class="bg-gray-900">
<nav class="bg-gray-800 border-b border-gray-700 sticky top-0 z-30"> <nav class="bg-gray-800 border-b border-gray-700 sticky top-0 z-30">
<div class="container mx-auto px-4"> <div class="container mx-auto px-4">
<div class="flex justify-between items-center h-16"> <div class="flex justify-between items-center h-16">
@@ -231,51 +231,106 @@
id="uploader" id="uploader"
class="min-h-screen flex items-center justify-center p-4" class="min-h-screen flex items-center justify-center p-4"
> >
<div class="bg-white rounded-lg shadow-lg p-8 max-w-md w-full"> <div
<h2 class="text-2xl font-bold text-gray-800 mb-4">PDF Bookmark Tool</h2> class="bg-gray-900 rounded-xl shadow-xl p-8 max-w-md w-full text-gray-200"
<p class="text-gray-600 mb-6"> >
<p class="text-gray-400 mb-6">
Upload a PDF to begin editing bookmarks Upload a PDF to begin editing bookmarks
</p> </p>
<input
type="file"
id="file-input"
accept=".pdf"
class="w-full px-4 py-2 border border-gray-300 rounded-lg cursor-pointer hover:bg-gray-50"
/>
<!-- Drop Zone for Main PDF Upload -->
<div
id="drop-zone"
class="relative flex flex-col items-center justify-center w-full h-48 border-2 border-dashed border-gray-600 rounded-xl cursor-pointer bg-gray-800 hover:bg-gray-700 transition-colors duration-300"
>
<div class="flex flex-col items-center justify-center pt-5 pb-6">
<i
data-lucide="upload-cloud"
class="w-10 h-10 mb-3 text-gray-400"
></i>
<p class="mb-2 text-sm text-gray-300">
<span class="font-semibold">Click to select a file</span> or drag
and drop
</p>
<p class="text-xs text-gray-500">A single PDF file</p>
<p class="text-xs text-gray-500">
Your files never leave your device.
</p>
</div>
<input
type="file"
id="file-input"
accept=".pdf"
class="absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer"
/>
</div>
<!-- Auto Extract Checkbox -->
<div class="mt-4"> <div class="mt-4">
<label class="flex items-center gap-2 text-sm text-gray-700"> <label class="flex items-center gap-2 text-sm text-gray-300">
<input type="checkbox" id="auto-extract-checkbox" class="w-4 h-4" /> <input
type="checkbox"
id="auto-extract-checkbox"
class="w-4 h-4 accent-blue-500"
/>
<span>Auto-extract existing bookmarks</span> <span>Auto-extract existing bookmarks</span>
</label> </label>
</div> </div>
<div class="mt-6 pt-6 border-t border-gray-200"> <!-- Import Bookmarks Section -->
<h3 class="text-sm font-semibold text-gray-700 mb-3"> <div class="mt-8 pt-6 border-t border-gray-700">
<h3 class="text-sm font-semibold text-gray-300 mb-4">
Or Import Bookmarks Or Import Bookmarks
</h3> </h3>
<div class="space-y-2">
<label class="block"> <!-- CSV Upload -->
<span class="text-xs text-gray-500" <label class="block mb-4">
>CSV format: title,page,level</span <span class="text-xs text-gray-500"
> >CSV format: title,page,level</span
>
<div
class="relative flex flex-col items-center justify-center w-full h-32 mt-2 border-2 border-dashed border-gray-600 rounded-xl cursor-pointer bg-gray-800 hover:bg-gray-700 transition-colors duration-300"
>
<div class="flex flex-col items-center justify-center pt-4 pb-4">
<i
data-lucide="file-text"
class="w-8 h-8 mb-2 text-gray-400"
></i>
<p class="text-xs text-gray-400">
<span class="font-semibold">Click to upload CSV</span> or drag
here
</p>
</div>
<input <input
type="file" type="file"
id="csv-input" id="csv-input"
accept=".csv" accept=".csv"
class="w-full px-4 py-2 border border-gray-300 rounded-lg cursor-pointer hover:bg-gray-50 text-sm mt-1" class="absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer"
/> />
</label> </div>
<label class="block"> </label>
<span class="text-xs text-gray-500">JSON format</span>
<!-- JSON Upload -->
<label class="block">
<span class="text-xs text-gray-500">JSON format</span>
<div
class="relative flex flex-col items-center justify-center w-full h-32 mt-2 border-2 border-dashed border-gray-600 rounded-xl cursor-pointer bg-gray-800 hover:bg-gray-700 transition-colors duration-300"
>
<div class="flex flex-col items-center justify-center pt-4 pb-4">
<i data-lucide="braces" class="w-8 h-8 mb-2 text-gray-400"></i>
<p class="text-xs text-gray-400">
<span class="font-semibold">Click to upload JSON</span> or
drag here
</p>
</div>
<input <input
type="file" type="file"
id="json-input" id="json-input"
accept=".json" accept=".json"
class="w-full px-4 py-2 border border-gray-300 rounded-lg cursor-pointer hover:bg-gray-50 text-sm mt-1" class="absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer"
/> />
</label> </div>
</div> </label>
</div> </div>
</div> </div>
</div> </div>