feat: Add licensing page and FAQ script, update site content and navigation, and refine PDF tool logic for multi tool

This commit is contained in:
abdullahalam123
2025-11-20 19:58:41 +05:30
parent 092f84be23
commit 8a8ae3f0c5
13 changed files with 1996 additions and 1517 deletions

23
src/js/faq.ts Normal file
View File

@@ -0,0 +1,23 @@
// Simple FAQ accordion handler for standalone pages
document.addEventListener('DOMContentLoaded', () => {
const faqAccordion = document.getElementById('faq-accordion');
if (faqAccordion) {
faqAccordion.addEventListener('click', (e) => {
const questionButton = (e.target as HTMLElement).closest('.faq-question');
if (!questionButton) return;
const faqItem = questionButton.parentElement;
const answer = faqItem?.querySelector('.faq-answer') as HTMLElement;
if (!faqItem || !answer) return;
faqItem.classList.toggle('open');
if (faqItem.classList.contains('open')) {
answer.style.maxHeight = answer.scrollHeight + 'px';
} else {
answer.style.maxHeight = '0px';
}
});
}
});

View File

@@ -1,7 +1,7 @@
import { showLoader, hideLoader, showAlert } from '../ui.ts';
import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.ts';
import { state } from '../state.ts';
import { renderPagesProgressively, cleanupLazyRendering } from '../utils/render-utils.ts';
import { renderPagesProgressively, cleanupLazyRendering, createPlaceholder } from '../utils/render-utils.ts';
import { createIcons, icons } from 'lucide';
import { PDFDocument as PDFLibDocument } from 'pdf-lib';
@@ -202,7 +202,7 @@ async function renderPageMergeThumbnails() {
onProgress: (current, total) => {
currentPageNumber++;
showLoader(
`Rendering page previews: ${currentPageNumber}/${totalPages}`
`Rendering page previews...`
);
},
onBatchComplete: () => {

View File

@@ -17,9 +17,10 @@ interface PageData {
pageIndex: number;
rotation: number;
visualRotation: number;
canvas: HTMLCanvasElement | null;
canvas: HTMLCanvasElement | null;
pdfDoc: PDFLibDocument;
originalPageIndex: number;
fileName: string; // Added for lazy loading identification
}
function generateId(): string {
@@ -104,7 +105,7 @@ function showLoading(current: number, total: number) {
loader.classList.remove('hidden');
const percentage = Math.round((current / total) * 100);
progress.style.width = `${percentage}%`;
text.textContent = `Rendering pages... ${current} of ${total}`;
text.textContent = `Rendering pages...`;
}
async function withButtonLoading(buttonId: string, action: () => Promise<void>) {
@@ -198,6 +199,18 @@ function initializeTool() {
});
});
document.getElementById('select-all-btn')?.addEventListener('click', () => {
if (isRendering) return;
snapshot();
selectAll();
});
document.getElementById('deselect-all-btn')?.addEventListener('click', () => {
if (isRendering) return;
snapshot();
deselectAll();
});
document.getElementById('export-pdf-btn')?.addEventListener('click', () => {
if (isRendering) return;
if (allPages.length === 0) {
@@ -278,7 +291,7 @@ function initializeTool() {
}
function resetAll() {
renderCancelled = true;
renderCancelled = true;
isRendering = false;
snapshot();
allPages = [];
@@ -286,7 +299,7 @@ function resetAll() {
splitMarkers.clear();
currentPdfDocs = [];
pageCanvasCache.clear();
cleanupLazyRendering();
cleanupLazyRendering();
if (sortableInstance) {
sortableInstance.destroy();
@@ -356,6 +369,7 @@ async function loadPdfs(files: File[]) {
canvas: null, // Will be filled when rendered
pdfDoc,
originalPageIndex: i,
fileName: file.name,
});
}
@@ -402,6 +416,9 @@ async function loadPdfs(files: File[]) {
if (renderCancelled) {
renderCancelled = false;
}
if (allPages.length === 0) {
resetAll();
}
}
}
@@ -431,14 +448,22 @@ function createPageElement(canvas: HTMLCanvasElement | null, index: number): HTM
card.className = 'bg-gray-800 rounded-lg border-2 border-gray-700 p-2 relative group cursor-move';
card.dataset.pageIndex = index.toString();
card.dataset.pageId = pageData.id; // Set ID for reconciliation
// Add attributes for lazy loading identification
card.dataset.pageNumber = (pageData.pageIndex + 1).toString();
if (pageData.fileName) {
card.dataset.fileName = pageData.fileName;
}
if (!pageData.canvas) {
card.dataset.lazyLoad = 'true';
}
if (selectedPages.has(index)) {
card.classList.add('border-indigo-500', 'ring-2', 'ring-indigo-500');
}
const preview = document.createElement('div');
preview.className = 'bg-white rounded mb-2 overflow-hidden w-full flex items-center justify-center relative';
preview.style.minHeight = '160px';
preview.style.height = '250px';
preview.className = 'bg-white rounded mb-2 overflow-hidden w-full flex items-center justify-center relative h-36 sm:h-64';
if (canvas) {
const previewCanvas = canvas;
@@ -574,6 +599,9 @@ function setupSortable() {
fallbackTolerance: 3,
delay: 200,
delayOnTouchOnly: true,
scroll: document.getElementById('main-scroll-container'),
scrollSensitivity: 100, // Increase sensitivity for smoother scrolling
bubbleScroll: false, // Prevent bubbling scroll to parent
onEnd: (evt) => {
const oldIndex = evt.oldIndex!;
const newIndex = evt.newIndex!;
@@ -724,6 +752,7 @@ async function handleInsertPdf(e: Event) {
canvas: null, // Placeholder
pdfDoc,
originalPageIndex: i,
fileName: file.name,
});
}
@@ -752,9 +781,7 @@ async function handleInsertPdf(e: Event) {
if (preview) {
// Re-create the preview content
preview.innerHTML = '';
preview.className = 'bg-white rounded mb-2 overflow-hidden w-full flex items-center justify-center relative';
(preview as HTMLElement).style.minHeight = '160px';
(preview as HTMLElement).style.height = '250px';
preview.className = 'bg-white rounded mb-2 overflow-hidden w-full flex items-center justify-center relative h-36 sm:h-64';
const previewCanvas = canvas;
previewCanvas.className = 'max-w-full max-h-full object-contain';
@@ -814,6 +841,7 @@ function addBlankPage() {
canvas,
pdfDoc: null as any,
originalPageIndex: -1,
fileName: '', // Blank page has no file
};
allPages.push(blankPageData);
@@ -1066,6 +1094,12 @@ function updatePageDisplay() {
};
}
// Update visual rotation
const canvas = card.querySelector('canvas');
if (canvas) {
canvas.style.transform = `rotate(${pageData.visualRotation}deg)`;
}
// Update action buttons
const actionsInner = card.querySelector('.flex.items-center.gap-1.bg-gray-900\\/90');
if (actionsInner) {

View File

@@ -1,5 +1,5 @@
<!doctype html>
<html lang="en">
<html lang="en" class="overflow-hidden">
<head>
<meta charset="UTF-8" />
@@ -18,7 +18,7 @@
-ms-overflow-style: none;
scrollbar-width: none;
}
/* Fix for mobile toolbar to prevent movement during drag operations */
.toolbar-container {
-webkit-user-select: none;
@@ -28,7 +28,7 @@
transform: translateZ(0);
will-change: transform;
}
/* Prevent layout shifts during dragging */
body.dragging {
overflow: hidden;
@@ -36,10 +36,10 @@
</style>
</head>
<body class="antialiased bg-gray-900 h-screen overflow-hidden">
<body class="antialiased bg-gray-900 h-[100dvh] overflow-hidden flex flex-col">
<!-- Navigation -->
<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 flex-none z-30">
<div class="container mx-auto px-4">
<div class="flex justify-between items-center h-16">
<div class="flex-shrink-0 flex items-center">
@@ -58,10 +58,10 @@
</nav>
<!-- Main Container -->
<div class="flex flex-col h-[calc(100vh-4rem)]">
<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 overflow-x-auto scrollbar-hide toolbar-container sm:sticky sm:top-16 sm:z-20">
<div class="bg-gray-800 border-b border-gray-700 p-2 sm:p-3 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">
@@ -186,7 +186,7 @@
</div>
<!-- Content Area -->
<div class="flex-1 overflow-auto p-3 sm:p-4 sm:pt-20 sm:pb-8 md:pt-4 md:pb-4">
<div id="main-scroll-container" class="flex-1 overflow-auto p-3 pb-24 sm:p-4 sm:pb-8 md:pt-4 md:pb-4">
<div id="upload-area"
class="hidden border-2 border-dashed border-gray-600 rounded-lg p-6 sm:p-12 text-center max-w-full cursor-pointer"
onclick="document.getElementById('pdf-file-input').click()">