feat(multi-tool): replace the page grid with the pdfium organizer

This commit is contained in:
alam00000
2026-10-30 16:11:50 +05:30
parent 3ce02c9ef7
commit 6ac0599ce3
4 changed files with 277 additions and 1753 deletions
File diff suppressed because it is too large Load Diff
+46 -236
View File
@@ -132,231 +132,51 @@
<div class="flex flex-col flex-1 overflow-hidden relative">
<!-- Toolbar -->
<div
class="bg-gray-800 border-b border-gray-700 p-2 sm:p-3 toolbar-container flex-none z-20"
class="bg-gray-800 border-b border-gray-700 flex items-center gap-2 px-2 sm:px-4 py-2 toolbar-container flex-none z-20"
>
<div
class="flex flex-wrap items-center justify-center sm:justify-start gap-2 bg-gray-900 p-2 sm:p-4 rounded-lg w-full"
<button
id="reset-btn"
style="display: none"
class="flex items-center gap-1.5 bg-gray-700 hover:bg-gray-600 text-white px-2.5 sm:px-3 py-1.5 rounded-lg text-sm transition-colors"
>
<!-- Upload -->
<button
id="upload-pdfs-btn"
class="flex items-center gap-1 sm:gap-2 bg-indigo-600 hover:bg-indigo-700 text-white px-2 sm:px-3 md:px-4 py-1 sm:py-1.5 md:py-2 rounded text-xs sm:text-sm md:text-base"
<i data-lucide="refresh-ccw" class="w-4 h-4"></i>
<span class="hidden min-[390px]:inline" data-i18n="multiTool.reset"
>Reset</span
>
<i data-lucide="upload" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden sm:inline" data-i18n="multiTool.uploadPdfs"
>Upload PDFs</span
>
<span class="sm:hidden" data-i18n="multiTool.upload">Upload</span>
</button>
</button>
<div class="border-l border-gray-600 h-5 sm:h-6 mx-1"></div>
<button
id="export-pdf-btn"
style="display: none"
class="flex items-center gap-1.5 bg-indigo-600 hover:bg-indigo-700 text-white px-2.5 sm:px-3 py-1.5 rounded-lg text-sm transition-colors"
>
<i data-lucide="download" class="w-4 h-4"></i>
<span data-i18n="multiTool.exportPdf">Export PDF</span>
</button>
<!-- Add Blank -->
<button
id="add-blank-page-btn"
class="flex items-center gap-1 sm:gap-2 bg-gray-700 hover:bg-gray-600 text-white px-2 sm:px-3 md:px-4 py-1 sm:py-1.5 md:py-2 rounded text-xs sm:text-sm md:text-base"
>
<i data-lucide="file-plus" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden sm:inline" data-i18n="multiTool.addBlankPage"
>Add Blank Page</span
>
</button>
<div class="flex-1"></div>
<div class="border-l border-gray-600 h-5 sm:h-6 mx-1"></div>
<span
class="text-gray-400 text-xs sm:text-sm md:inline"
data-i18n="multiTool.edit"
>Edit:</span
>
<button
id="faq-open-btn"
type="button"
class="flex items-center gap-1.5 bg-gray-700 hover:bg-gray-600 text-white px-2.5 sm:px-3 py-1.5 rounded-lg text-sm transition-colors"
aria-label="FAQ"
aria-haspopup="dialog"
aria-controls="faq-modal"
aria-expanded="false"
>
<i data-lucide="circle-help" class="w-4 h-4"></i>
<span class="hidden sm:inline">FAQ</span>
</button>
<!-- Undo / Redo / Reset -->
<button
id="undo-btn"
class="flex items-center gap-1 sm:gap-2 bg-gray-700 hover:bg-gray-600 text-white px-2 sm:px-3 md:px-4 py-1 sm:py-1.5 md:py-2 rounded text-xs sm:text-sm md:text-base"
>
<i data-lucide="undo-2" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden lg:inline" data-i18n="multiTool.undo"
>Undo</span
>
</button>
<button
id="redo-btn"
class="flex items-center gap-1 sm:gap-2 bg-gray-700 hover:bg-gray-600 text-white px-2 sm:px-3 md:px-4 py-1 sm:py-1.5 md:py-2 rounded text-xs sm:text-sm md:text-base"
>
<i data-lucide="redo-2" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden lg:inline" data-i18n="multiTool.redo"
>Redo</span
>
</button>
<button
id="reset-btn"
class="flex items-center gap-1 sm:gap-2 bg-gray-700 hover:bg-gray-600 text-white px-2 sm:px-3 md:px-4 py-1 sm:py-1.5 md:py-2 rounded text-xs sm:text-sm md:text-base"
>
<i data-lucide="refresh-ccw" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden lg:inline" data-i18n="multiTool.reset"
>Reset</span
>
</button>
<div class="border-l border-gray-600 h-5 sm:h-6 mx-1"></div>
<!-- Selection -->
<span
class="text-gray-400 text-xs sm:text-sm md:inline"
data-i18n="multiTool.selection"
>Selection:</span
>
<button
id="select-all-btn"
class="flex items-center gap-1 sm:gap-2 bg-gray-700 hover:bg-gray-600 text-white px-2 sm:px-3 md:px-4 py-1 sm:py-1.5 md:py-2 rounded text-xs sm:text-sm md:text-base"
>
<i data-lucide="check-square" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden lg:inline" data-i18n="multiTool.selectAll"
>Select All</span
>
</button>
<button
id="deselect-all-btn"
class="flex items-center gap-1 sm:gap-2 bg-gray-700 hover:bg-gray-600 text-white px-2 sm:px-3 md:px-4 py-1 sm:py-1.5 md:py-2 rounded text-xs sm:text-sm md:text-base"
>
<i data-lucide="square" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden lg:inline" data-i18n="multiTool.deselectAll"
>Deselect All</span
>
</button>
<div class="border-l border-gray-600 h-5 sm:h-6 mx-1"></div>
<!-- Rotate -->
<span
class="text-gray-400 text-xs sm:text-sm md:inline"
data-i18n="multiTool.rotate"
>Rotate:</span
>
<button
id="bulk-rotate-left-btn"
class="flex items-center gap-1 sm:gap-2 bg-gray-700 hover:bg-gray-600 text-white px-2 sm:px-3 md:px-4 py-1 sm:py-1.5 md:py-2 rounded text-xs sm:text-sm md:text-base"
>
<i data-lucide="rotate-ccw" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden xl:inline" data-i18n="multiTool.rotateLeft"
>Left</span
>
</button>
<button
id="bulk-rotate-btn"
class="flex items-center gap-1 sm:gap-2 bg-gray-700 hover:bg-gray-600 text-white px-2 sm:px-3 md:px-4 py-1 sm:py-1.5 md:py-2 rounded text-xs sm:text-sm md:text-base"
>
<i data-lucide="rotate-cw" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden xl:inline" data-i18n="multiTool.rotateRight"
>Right</span
>
</button>
<div class="border-l border-gray-600 h-5 sm:h-6 mx-1"></div>
<span
class="text-gray-400 text-xs sm:text-sm md:inline"
data-i18n="multiTool.transform"
>Transform:</span
>
<!-- Duplicate / Split -->
<button
id="bulk-duplicate-btn"
class="flex items-center gap-1 sm:gap-2 bg-gray-700 hover:bg-gray-600 text-white px-2 sm:px-3 md:px-4 py-1 sm:py-1.5 md:py-2 rounded text-xs sm:text-sm md:text-base"
>
<i data-lucide="copy" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden xl:inline" data-i18n="multiTool.duplicate"
>Duplicate</span
>
</button>
<button
id="bulk-split-btn"
class="flex items-center gap-1 sm:gap-2 bg-gray-700 hover:bg-gray-600 text-white px-2 sm:px-3 md:px-4 py-1 sm:py-1.5 md:py-2 rounded text-xs sm:text-sm md:text-base"
>
<i data-lucide="scissors" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden xl:inline" data-i18n="multiTool.split"
>Split</span
>
</button>
<div class="border-l border-gray-600 h-5 sm:h-6 mx-1"></div>
<span
class="text-gray-400 text-xs sm:text-sm md:inline"
data-i18n="multiTool.clear"
>Clear:</span
>
<!-- Delete -->
<button
id="bulk-delete-btn"
class="flex items-center gap-1 sm:gap-2 bg-red-500 hover:bg-red-700 text-white px-2 sm:px-3 md:px-4 py-1 sm:py-1.5 md:py-2 rounded text-xs sm:text-sm md:text-base"
>
<i data-lucide="trash-2" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden xl:inline" data-i18n="multiTool.delete"
>Delete</span
>
</button>
<div class="border-l border-gray-600 h-5 sm:h-6 mx-1"></div>
<!-- Download -->
<span
class="text-gray-400 text-xs sm:text-sm md:inline"
data-i18n="multiTool.download"
>Download:</span
>
<button
id="bulk-download-btn"
class="flex items-center gap-1 sm:gap-2 bg-green-600 hover:bg-green-700 text-white px-2 sm:px-3 md:px-4 py-1 sm:py-1.5 md:py-2 rounded text-xs sm:text-sm md:text-base"
>
<i data-lucide="download" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span
class="hidden xl:inline"
data-i18n="multiTool.downloadSelected"
>Download Selected</span
>
</button>
<button
id="export-pdf-btn"
class="flex items-center gap-1 sm:gap-2 bg-indigo-600 hover:bg-indigo-700 text-white px-2 sm:px-3 md:px-4 py-1 sm:py-1.5 md:py-2 rounded text-xs sm:text-sm md:text-base"
>
<i data-lucide="download" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden xl:inline" data-i18n="multiTool.exportPdf"
>Export PDF</span
>
</button>
<div class="border-l border-gray-600 h-5 sm:h-6 mx-1"></div>
<button
id="faq-open-btn"
type="button"
class="flex items-center gap-1 sm:gap-2 bg-gray-700 hover:bg-gray-600 text-white px-2 sm:px-3 md:px-4 py-1 sm:py-1.5 md:py-2 rounded text-xs sm:text-sm md:text-base"
aria-label="FAQ"
aria-haspopup="dialog"
aria-controls="faq-modal"
aria-expanded="false"
>
<i data-lucide="circle-help" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden sm:inline">FAQ</span>
</button>
<button
id="close-tool-btn"
class="flex items-center gap-1 sm:gap-2 bg-gray-700 hover:bg-gray-600 text-white px-2 sm:px-3 md:px-4 py-1 sm:py-1.5 md:py-2 rounded text-xs sm:text-sm md:text-base"
aria-label="Close"
>
<i data-lucide="x" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden sm:inline" data-i18n="common.close">Close</span>
</button>
</div>
<button
id="close-tool-btn"
class="flex items-center gap-1.5 bg-gray-700 hover:bg-gray-600 text-white px-2.5 sm:px-3 py-1.5 rounded-lg text-sm transition-colors"
aria-label="Close"
>
<i data-lucide="x" class="w-4 h-4"></i>
<span class="hidden sm:inline" data-i18n="common.close">Close</span>
</button>
</div>
<!-- Content Area -->
@@ -398,12 +218,9 @@
Select Files
</button>
</div>
<div
id="pages-container"
class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-3 sm:gap-4"
></div>
</div>
<div id="organize-viewer" class="hidden flex-1 min-h-0"></div>
</div>
{{> footer-compact }}
@@ -463,13 +280,6 @@
</div>
<!-- Hidden File Input -->
<input
type="file"
id="insert-pdf-input"
accept="application/pdf"
class="hidden"
/>
<!-- Scripts -->
<!-- FAQ Modal -->
<div
@@ -534,8 +344,8 @@
<p class="faq-d-a">
Drop JPG, PNG, WebP, HEIC, TIFF, BMP, GIF, or SVG files
alongside your PDFs and each image becomes a page you can move,
rotate, or delete like any other. Blank A4 pages can also be
appended with the Add Blank Page button.
rotate, or delete like any other. Blank pages can also be added
from the Insert menu.
</p>
</details>
<details class="faq-d">
@@ -544,10 +354,10 @@
<i data-lucide="plus" class="faq-d-icon"></i>
</summary>
<p class="faq-d-a">
Click the scissors icon on a page to place a split marker after
it; a dashed line shows where the document will be divided.
Export then produces split-documents.zip containing document -
1.pdf, document - 2.pdf, and so on.
Click Split and choose how to divide the document: by page
ranges, odd and even pages, every page, bookmarks, every N
pages, or file size. One part downloads as a PDF; several parts
download together as a ZIP.
</p>
</details>
<details class="faq-d">