Update version to 1.6.2 and enhance navigation links across HTML pages

- Updated version number in package-lock.json and relevant HTML files.
- Changed navigation links to point to the root path for consistency.
- Improved code formatting and structure in various JavaScript and HTML files for better readability.
This commit is contained in:
abdullahalam123
2025-11-13 11:26:40 +05:30
parent 18ecaf4228
commit cb53370a26
13 changed files with 784 additions and 1012 deletions

View File

@@ -594,7 +594,7 @@
© 2025 BentoPDF. All rights reserved.
</p>
<p class="text-gray-500 text-xs mt-2">
Version <span id="app-version">1.5.0</span>
Version <span id="app-version">1.6.2</span>
</p>
</div>

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "bento-pdf",
"version": "1.2.0",
"version": "1.6.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "bento-pdf",
"version": "1.2.0",
"version": "1.6.1",
"license": "Apache-2.0",
"dependencies": {
"@fontsource/cedarville-cursive": "^5.2.7",

View File

@@ -50,14 +50,14 @@ function showInputModal(title, fields = [], defaultValues = {}) {
<label class="block text-sm font-medium text-gray-700 mb-2">${field.label}</label>
<select id="modal-${field.name}" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
${field.options
.map(
(opt) => `
.map(
(opt) => `
<option value="${opt.value}" ${defaultValues[field.name] === opt.value ? 'selected' : ''}>
${opt.label}
</option>
`
)
.join('')}
)
.join('')}
</select>
${field.name === 'color' ? '<input type="color" id="modal-color-picker" class="hidden w-full h-10 mt-2 rounded cursor-pointer border border-gray-300" value="#000000" />' : ''}
</div>
@@ -654,6 +654,9 @@ const fileDisplayArea = document.getElementById(
const backToToolsBtn = document.getElementById(
'back-to-tools'
) as HTMLButtonElement;
const closeBtn = document.getElementById(
'back-btn'
) as HTMLButtonElement;
const canvas = document.getElementById('pdf-canvas');
const ctx = canvas.getContext('2d');
const pageIndicator = document.getElementById('page-indicator');
@@ -2078,7 +2081,13 @@ async function extractExistingBookmarks(doc) {
// Back to tools button
if (backToToolsBtn) {
backToToolsBtn.addEventListener('click', () => {
window.location.href = '../../index.html#tools-header';
window.location.href = '/';
});
}
if (closeBtn) {
closeBtn.addEventListener('click', () => {
window.location.href = '/';
});
}

View File

@@ -16,13 +16,12 @@ function showStatus(
type: 'success' | 'error' | 'info' = 'info'
) {
statusMessage.textContent = message
statusMessage.className = `mt-4 p-3 rounded-lg text-sm ${
type === 'success'
statusMessage.className = `mt-4 p-3 rounded-lg text-sm ${type === 'success'
? 'bg-green-900 text-green-200'
: type === 'error'
? 'bg-red-900 text-red-200'
: 'bg-blue-900 text-blue-200'
}`
}`
statusMessage.classList.remove('hidden')
}
@@ -87,9 +86,9 @@ async function convertJSONsToPDF() {
showStatus('Converting JSONs to PDFs...', 'info')
worker.postMessage({
command: 'convert',
fileBuffers: fileBuffers,
fileNames: selectedFiles.map(f => f.name)
command: 'convert',
fileBuffers: fileBuffers,
fileNames: selectedFiles.map(f => f.name)
}, fileBuffers);
} catch (error) {
@@ -100,55 +99,55 @@ async function convertJSONsToPDF() {
}
worker.onmessage = async (e: MessageEvent) => {
convertBtn.disabled = false;
convertBtn.disabled = false;
if (e.data.status === 'success') {
const pdfFiles = e.data.pdfFiles as Array<{ name: string, data: ArrayBuffer }>;
if (e.data.status === 'success') {
const pdfFiles = e.data.pdfFiles as Array<{ name: string, data: ArrayBuffer }>;
try {
showStatus('Creating ZIP file...', 'info')
try {
showStatus('Creating ZIP file...', 'info')
const zip = new JSZip()
pdfFiles.forEach(({ name, data }) => {
const pdfName = name.replace(/\.json$/i, '.pdf')
const uint8Array = new Uint8Array(data)
zip.file(pdfName, uint8Array)
})
const zip = new JSZip()
pdfFiles.forEach(({ name, data }) => {
const pdfName = name.replace(/\.json$/i, '.pdf')
const uint8Array = new Uint8Array(data)
zip.file(pdfName, uint8Array)
})
const zipBlob = await zip.generateAsync({ type: 'blob' })
const url = URL.createObjectURL(zipBlob)
const a = document.createElement('a')
a.href = url
a.download = 'jsons-to-pdf.zip'
downloadFile(zipBlob, 'jsons-to-pdf.zip')
const zipBlob = await zip.generateAsync({ type: 'blob' })
const url = URL.createObjectURL(zipBlob)
const a = document.createElement('a')
a.href = url
a.download = 'jsons-to-pdf.zip'
downloadFile(zipBlob, 'jsons-to-pdf.zip')
showStatus('✅ JSONs converted to PDF successfully! ZIP download started.', 'success')
showStatus('✅ JSONs converted to PDF successfully! ZIP download started.', 'success')
selectedFiles = []
jsonFilesInput.value = ''
fileListDiv.innerHTML = ''
fileListDiv.classList.add('hidden')
convertBtn.disabled = true
selectedFiles = []
jsonFilesInput.value = ''
fileListDiv.innerHTML = ''
fileListDiv.classList.add('hidden')
convertBtn.disabled = true
setTimeout(() => {
hideStatus()
}, 3000)
setTimeout(() => {
hideStatus()
}, 3000)
} catch (error) {
console.error('Error creating ZIP:', error)
showStatus(`❌ Error creating ZIP: ${error instanceof Error ? error.message : 'Unknown error'}`, 'error')
}
} else if (e.data.status === 'error') {
const errorMessage = e.data.message || 'Unknown error occurred in worker.';
console.error('Worker Error:', errorMessage);
showStatus(`❌ Worker Error: ${errorMessage}`, 'error');
} catch (error) {
console.error('Error creating ZIP:', error)
showStatus(`❌ Error creating ZIP: ${error instanceof Error ? error.message : 'Unknown error'}`, 'error')
}
} else if (e.data.status === 'error') {
const errorMessage = e.data.message || 'Unknown error occurred in worker.';
console.error('Worker Error:', errorMessage);
showStatus(`❌ Worker Error: ${errorMessage}`, 'error');
}
};
if (backToToolsBtn) {
backToToolsBtn.addEventListener('click', () => {
window.location.href = '../../index.html#tools-header'
window.location.href = '/'
})
}

View File

@@ -29,6 +29,7 @@ let currentPdfDocs: PDFLibDocument[] = [];
let splitMarkers: Set<number> = new Set();
let isRendering = false;
let renderCancelled = false;
let sortableInstance: Sortable | null = null;
const pageCanvasCache = new Map<string, HTMLCanvasElement>();
@@ -114,7 +115,7 @@ function initializeTool() {
createIcons({ icons });
document.getElementById('close-tool-btn')?.addEventListener('click', () => {
window.location.href = '../../index.html';
window.location.href = '/';
});
document.getElementById('upload-pdfs-btn')?.addEventListener('click', () => {
@@ -247,6 +248,13 @@ function resetAll() {
pageCanvasCache.clear();
renderCancelled = false;
isRendering = false;
// Destroy sortable instance
if (sortableInstance) {
sortableInstance.destroy();
sortableInstance = null;
}
updatePageDisplay();
document.getElementById('upload-area')?.classList.remove('hidden');
}
@@ -492,9 +500,18 @@ function setupSortable() {
const pagesContainer = document.getElementById('pages-container');
if (!pagesContainer) return;
Sortable.create(pagesContainer, {
// Destroy existing instance before creating new one
if (sortableInstance) {
sortableInstance.destroy();
}
sortableInstance = Sortable.create(pagesContainer, {
animation: 150,
handle: '.cursor-move',
forceFallback: true,
touchStartThreshold: 3,
fallbackTolerance: 3,
delay: 200,
delayOnTouchOnly: true,
onEnd: (evt) => {
const oldIndex = evt.oldIndex!;
const newIndex = evt.newIndex!;

View File

@@ -16,13 +16,12 @@ function showStatus(
type: 'success' | 'error' | 'info' = 'info'
) {
statusMessage.textContent = message
statusMessage.className = `mt-4 p-3 rounded-lg text-sm ${
type === 'success'
statusMessage.className = `mt-4 p-3 rounded-lg text-sm ${type === 'success'
? 'bg-green-900 text-green-200'
: type === 'error'
? 'bg-red-900 text-red-200'
: 'bg-blue-900 text-blue-200'
}`
}`
statusMessage.classList.remove('hidden')
}
@@ -87,9 +86,9 @@ async function convertPDFsToJSON() {
showStatus('Converting PDFs to JSON..', 'info')
worker.postMessage({
command: 'convert',
fileBuffers: fileBuffers,
fileNames: selectedFiles.map(f => f.name)
command: 'convert',
fileBuffers: fileBuffers,
fileNames: selectedFiles.map(f => f.name)
}, fileBuffers);
} catch (error) {
@@ -100,51 +99,51 @@ async function convertPDFsToJSON() {
}
worker.onmessage = async (e: MessageEvent) => {
convertBtn.disabled = false;
convertBtn.disabled = false;
if (e.data.status === 'success') {
const jsonFiles = e.data.jsonFiles as Array<{ name: string, data: ArrayBuffer }>;
if (e.data.status === 'success') {
const jsonFiles = e.data.jsonFiles as Array<{ name: string, data: ArrayBuffer }>;
try {
showStatus('Creating ZIP file...', 'info')
try {
showStatus('Creating ZIP file...', 'info')
const zip = new JSZip()
jsonFiles.forEach(({ name, data }) => {
const jsonName = name.replace(/\.pdf$/i, '.json')
const uint8Array = new Uint8Array(data)
zip.file(jsonName, uint8Array)
})
const zip = new JSZip()
jsonFiles.forEach(({ name, data }) => {
const jsonName = name.replace(/\.pdf$/i, '.json')
const uint8Array = new Uint8Array(data)
zip.file(jsonName, uint8Array)
})
const zipBlob = await zip.generateAsync({ type: 'blob' })
downloadFile(zipBlob, 'pdfs-to-json.zip')
const zipBlob = await zip.generateAsync({ type: 'blob' })
downloadFile(zipBlob, 'pdfs-to-json.zip')
showStatus('✅ PDFs converted to JSON successfully! ZIP download started.', 'success')
showStatus('✅ PDFs converted to JSON successfully! ZIP download started.', 'success')
selectedFiles = []
pdfFilesInput.value = ''
fileListDiv.innerHTML = ''
fileListDiv.classList.add('hidden')
convertBtn.disabled = true
selectedFiles = []
pdfFilesInput.value = ''
fileListDiv.innerHTML = ''
fileListDiv.classList.add('hidden')
convertBtn.disabled = true
setTimeout(() => {
hideStatus()
}, 3000)
setTimeout(() => {
hideStatus()
}, 3000)
} catch (error) {
console.error('Error creating ZIP:', error)
showStatus(`❌ Error creating ZIP: ${error instanceof Error ? error.message : 'Unknown error'}`, 'error')
}
} else if (e.data.status === 'error') {
const errorMessage = e.data.message || 'Unknown error occurred in worker.';
console.error('Worker Error:', errorMessage);
showStatus(`❌ Worker Error: ${errorMessage}`, 'error');
} catch (error) {
console.error('Error creating ZIP:', error)
showStatus(`❌ Error creating ZIP: ${error instanceof Error ? error.message : 'Unknown error'}`, 'error')
}
} else if (e.data.status === 'error') {
const errorMessage = e.data.message || 'Unknown error occurred in worker.';
console.error('Worker Error:', errorMessage);
showStatus(`❌ Worker Error: ${errorMessage}`, 'error');
}
};
if (backToToolsBtn) {
backToToolsBtn.addEventListener('click', () => {
window.location.href = '../../index.html#tools-header'
window.location.href = '/'
})
}

View File

@@ -53,13 +53,12 @@ function showStatus(
type: 'success' | 'error' | 'info' = 'info'
) {
statusMessage.textContent = message;
statusMessage.className = `mt-4 p-3 rounded-lg text-sm ${
type === 'success'
statusMessage.className = `mt-4 p-3 rounded-lg text-sm ${type === 'success'
? 'bg-green-900 text-green-200'
: type === 'error'
? 'bg-red-900 text-red-200'
: 'bg-blue-900 text-blue-200'
}`;
}`;
statusMessage.classList.remove('hidden');
}
@@ -198,7 +197,7 @@ worker.onerror = (error) => {
if (backToToolsBtn) {
backToToolsBtn.addEventListener('click', () => {
window.location.href = '../../index.html#tools-header';
window.location.href = '/';
});
}

View File

@@ -94,7 +94,7 @@ const init = () => {
&copy; 2025 BentoPDF. All rights reserved.
</p>
<p class="text-gray-500 text-xs mt-2">
Version <span id="app-version-simple">1.6.0</span>
Version <span id="app-version-simple">1.6.2</span>
</p>
</div>
`;

File diff suppressed because it is too large Load Diff

View File

@@ -1,113 +1,112 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JSON to PDF Converter - BentoPDF</title>
<link rel="icon" type="image/png" href="../../images/favicon.svg" />
<link href="../../src/css/styles.css" rel="stylesheet" />
</head>
<body class="antialiased bg-gray-900">
<nav class="bg-gray-800 border-b border-gray-700 sticky top-0 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 cursor-pointer" id="home-logo">
<img src="../../public/images/favicon.svg" alt="Bento PDF Logo" class="h-8 w-8" />
<span class="text-white font-bold text-xl ml-2">
<a href="../../index.html">BentoPDF</a>
</span>
</div>
<!-- Desktop Navigation -->
<div class="hidden md:flex items-center space-x-8 text-white">
<a href="../../index.html" class="nav-link">Home</a>
<a href="../../about.html" class="nav-link">About</a>
<a href="../../contact.html" class="nav-link">Contact</a>
<a href="../../index.html#tools-header" class="nav-link">All Tools</a>
</div>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JSON to PDF Converter - BentoPDF</title>
<link rel="icon" type="image/png" href="../../images/favicon.svg" />
<link href="../../src/css/styles.css" rel="stylesheet" />
</head>
<!-- Mobile Hamburger Button -->
<div class="md:hidden flex items-center">
<button id="mobile-menu-button" type="button"
class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500 transition-colors"
aria-controls="mobile-menu" aria-expanded="false">
<span class="sr-only">Open main menu</span>
<svg id="menu-icon" class="block h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
<svg id="close-icon" class="hidden h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
</div>
<!-- Mobile Menu Dropdown -->
<div id="mobile-menu" class="hidden md:hidden bg-gray-800 border-t border-gray-700">
<div class="px-2 pt-2 pb-3 space-y-1 text-center">
<a href="../../index.html" class="mobile-nav-link">Home</a>
<a href="../../about.html" class="mobile-nav-link">About</a>
<a href="../../contact.html" class="mobile-nav-link">Contact</a>
<a href="../../index.html#tools-header" class="mobile-nav-link">All Tools</a>
</div>
</div>
</nav>
<div class="min-h-screen flex items-center justify-center p-4 bg-gray-900">
<div class="bg-gray-800 rounded-xl shadow-xl p-8 max-w-2xl w-full text-gray-200 border border-gray-700">
<button id="back-to-tools"
class="flex items-center gap-2 text-indigo-400 hover:text-indigo-300 mb-6 font-semibold">
<i data-lucide="arrow-left" class="cursor-pointer"></i>
<span class="cursor-pointer"> Back to Tools </span>
</button>
<h1 class="text-2xl font-bold text-white mb-2">JSON to PDF Converter</h1>
<p class="text-gray-400 mb-6">
Upload multiple JSON files to convert them all to PDF format. Files will be downloaded as a ZIP archive.
</p>
<div class="bg-yellow-900/30 border border-yellow-700 rounded-lg p-3 mb-6">
<p class="text-yellow-200 text-sm">
<strong>Note:</strong> Only JSON files created by the PDF-to-JSON converter tool are supported. Standard JSON files from other tools will not work.
</p>
<body class="antialiased bg-gray-900">
<nav class="bg-gray-800 border-b border-gray-700 sticky top-0 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 cursor-pointer" id="home-logo">
<img src="../../public/images/favicon.svg" alt="Bento PDF Logo" class="h-8 w-8" />
<span class="text-white font-bold text-xl ml-2">
<a href="/">BentoPDF</a>
</span>
</div>
<div class="upload-section mb-6">
<div 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-700 hover:bg-gray-600 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 files</span> or drag and drop
</p>
<p class="text-xs text-gray-500">Multiple JSON files</p>
<p class="text-xs text-gray-500">Your files never leave your device.</p>
</div>
<input
type="file"
id="jsonFiles"
accept="application/json"
multiple
class="absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer"
/>
</div>
<!-- Desktop Navigation -->
<div class="hidden md:flex items-center space-x-8 text-white">
<a href="/" class="nav-link">Home</a>
<a href="/about.html" class="nav-link">About</a>
<a href="/contact.html" class="nav-link">Contact</a>
<a href="/" class="nav-link">All Tools</a>
</div>
<!-- File Display Area -->
<div id="fileList" class="mt-4 hidden"></div>
<button id="convertBtn" disabled class="btn-gradient w-full mt-6">
Convert to PDF
<!-- Mobile Hamburger Button -->
<div class="md:hidden flex items-center">
<button id="mobile-menu-button" type="button"
class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500 transition-colors"
aria-controls="mobile-menu" aria-expanded="false">
<span class="sr-only">Open main menu</span>
<svg id="menu-icon" class="block h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
<svg id="close-icon" class="hidden h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<!-- Status Message -->
<div id="status-message" class="mt-4 hidden p-3 rounded-lg text-sm"></div>
</div>
</div>
<script type="module" src="../js/logic/json-to-pdf.ts"></script>
<script type="module" src="../js/utils/lucide-init.ts"></script>
<script type="module" src="../js/mobileMenu.ts"></script>
</body>
</html>
<!-- Mobile Menu Dropdown -->
<div id="mobile-menu" class="hidden md:hidden bg-gray-800 border-t border-gray-700">
<div class="px-2 pt-2 pb-3 space-y-1 text-center">
<a href="/" class="mobile-nav-link">Home</a>
<a href="/about.html" class="mobile-nav-link">About</a>
<a href="/contact.html" class="mobile-nav-link">Contact</a>
<a href="/" class="mobile-nav-link">All Tools</a>
</div>
</div>
</nav>
<div class="min-h-screen flex items-center justify-center p-4 bg-gray-900">
<div class="bg-gray-800 rounded-xl shadow-xl p-8 max-w-2xl w-full text-gray-200 border border-gray-700">
<button id="back-to-tools"
class="flex items-center gap-2 text-indigo-400 hover:text-indigo-300 mb-6 font-semibold">
<i data-lucide="arrow-left" class="cursor-pointer"></i>
<span class="cursor-pointer"> Back to Tools </span>
</button>
<h1 class="text-2xl font-bold text-white mb-2">JSON to PDF Converter</h1>
<p class="text-gray-400 mb-6">
Upload multiple JSON files to convert them all to PDF format. Files will be downloaded as a ZIP archive.
</p>
<div class="bg-yellow-900/30 border border-yellow-700 rounded-lg p-3 mb-6">
<p class="text-yellow-200 text-sm">
<strong>Note:</strong> Only JSON files created by the PDF-to-JSON converter tool are supported. Standard JSON
files from other tools will not work.
</p>
</div>
<div class="upload-section mb-6">
<div
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-700 hover:bg-gray-600 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 files</span> or drag and drop
</p>
<p class="text-xs text-gray-500">Multiple JSON files</p>
<p class="text-xs text-gray-500">Your files never leave your device.</p>
</div>
<input type="file" id="jsonFiles" accept="application/json" multiple
class="absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer" />
</div>
<!-- File Display Area -->
<div id="fileList" class="mt-4 hidden"></div>
<button id="convertBtn" disabled class="btn-gradient w-full mt-6">
Convert to PDF
</button>
</div>
<!-- Status Message -->
<div id="status-message" class="mt-4 hidden p-3 rounded-lg text-sm"></div>
</div>
</div>
<script type="module" src="../js/logic/json-to-pdf.ts"></script>
<script type="module" src="../js/utils/lucide-init.ts"></script>
<script type="module" src="../js/mobileMenu.ts"></script>
</body>
</html>

View File

@@ -30,7 +30,7 @@
<div class="flex-shrink-0 flex items-center">
<img src="../../public/images/favicon.svg" alt="Bento PDF Logo" class="h-8 w-8" />
<span class="text-white font-bold text-xl ml-2">
<a href="../../index.html">BentoPDF</a>
<a href="/">BentoPDF</a>
</span>
<span class="text-gray-400 ml-3 text-sm sm:text-base">PDF Multi Tool</span>
</div>
@@ -60,6 +60,7 @@
<div class="border-l border-gray-600 h-5 sm:h-6 mx-1"></div>
<!-- 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">
@@ -68,19 +69,19 @@
</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 hidden md:inline">Edit:</span>
<span class="text-gray-400 text-xs sm:text-sm md:inline">Edit:</span>
<!-- 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="rotate-ccw" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<i data-lucide="undo-2" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden lg:inline">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="rotate-cw" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<i data-lucide="redo-2" class="w-3 h-3 sm:w-4 sm:h-4"></i>
<span class="hidden lg:inline">Redo</span>
</button>
@@ -93,7 +94,7 @@
<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 hidden md:inline">Selection:</span>
<span class="text-gray-400 text-xs sm:text-sm md:inline">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">
@@ -110,7 +111,7 @@
<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 hidden md:inline">Rotate:</span>
<span class="text-gray-400 text-xs sm:text-sm md:inline">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>
@@ -124,6 +125,8 @@
</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">Transform:</span>
<!-- Duplicate / Split -->
<button id="bulk-duplicate-btn"
@@ -139,7 +142,7 @@
</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 hidden md:inline">Clear:</span>
<span class="text-gray-400 text-xs sm:text-sm md:inline">Clear:</span>
<!-- Delete -->
@@ -152,7 +155,7 @@
<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 hidden md:inline">Download:</span>
<span class="text-gray-400 text-xs sm:text-sm md:inline">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>

View File

@@ -1,108 +1,106 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PDF to JSON Converter - BentoPDF</title>
<link rel="icon" type="image/png" href="../../images/favicon.svg" />
<link href="../../src/css/styles.css" rel="stylesheet" />
</head>
<body class="antialiased bg-gray-900">
<nav class="bg-gray-800 border-b border-gray-700 sticky top-0 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 cursor-pointer" id="home-logo">
<img src="../../public/images/favicon.svg" alt="Bento PDF Logo" class="h-8 w-8" />
<span class="text-white font-bold text-xl ml-2">
<a href="../../index.html">BentoPDF</a>
</span>
</div>
<!-- Desktop Navigation -->
<div class="hidden md:flex items-center space-x-8 text-white">
<a href="../../index.html" class="nav-link">Home</a>
<a href="../../about.html" class="nav-link">About</a>
<a href="../../contact.html" class="nav-link">Contact</a>
<a href="../../index.html#tools-header" class="nav-link">All Tools</a>
</div>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PDF to JSON Converter - BentoPDF</title>
<link rel="icon" type="image/png" href="../../images/favicon.svg" />
<link href="../../src/css/styles.css" rel="stylesheet" />
</head>
<!-- Mobile Hamburger Button -->
<div class="md:hidden flex items-center">
<button id="mobile-menu-button" type="button"
class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500 transition-colors"
aria-controls="mobile-menu" aria-expanded="false">
<span class="sr-only">Open main menu</span>
<svg id="menu-icon" class="block h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
<svg id="close-icon" class="hidden h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<body class="antialiased bg-gray-900">
<nav class="bg-gray-800 border-b border-gray-700 sticky top-0 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 cursor-pointer" id="home-logo">
<img src="../../public/images/favicon.svg" alt="Bento PDF Logo" class="h-8 w-8" />
<span class="text-white font-bold text-xl ml-2">
<a href="/">BentoPDF</a>
</span>
</div>
</div>
<!-- Mobile Menu Dropdown -->
<div id="mobile-menu" class="hidden md:hidden bg-gray-800 border-t border-gray-700">
<div class="px-2 pt-2 pb-3 space-y-1 text-center">
<a href="../../index.html" class="mobile-nav-link">Home</a>
<a href="../../about.html" class="mobile-nav-link">About</a>
<a href="../../contact.html" class="mobile-nav-link">Contact</a>
<a href="../../index.html#tools-header" class="mobile-nav-link">All Tools</a>
<!-- Desktop Navigation -->
<div class="hidden md:flex items-center space-x-8 text-white">
<a href="/" class="nav-link">Home</a>
<a href="/about.html" class="nav-link">About</a>
<a href="/contact.html" class="nav-link">Contact</a>
<a href="/" class="nav-link">All Tools</a>
</div>
</div>
</nav>
<div class="min-h-screen flex items-center justify-center p-4 bg-gray-900">
<div class="bg-gray-800 rounded-xl shadow-xl p-8 max-w-2xl w-full text-gray-200 border border-gray-700">
<button id="back-to-tools"
class="flex items-center gap-2 text-indigo-400 hover:text-indigo-300 mb-6 font-semibold">
<i data-lucide="arrow-left" class="cursor-pointer"></i>
<span class="cursor-pointer"> Back to Tools </span>
</button>
<h1 class="text-2xl font-bold text-white mb-2">PDF to JSON Converter</h1>
<p class="text-gray-400 mb-6">
Upload multiple PDF files to convert them all to JSON format. Files will be downloaded as a ZIP archive.
</p>
<div class="upload-section mb-6">
<div 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-700 hover:bg-gray-600 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 files</span> or drag and drop
</p>
<p class="text-xs text-gray-500">Multiple PDF files</p>
<p class="text-xs text-gray-500">Your files never leave your device.</p>
</div>
<input
type="file"
id="pdfFiles"
accept="application/pdf"
multiple
class="absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer"
/>
</div>
<!-- File Display Area -->
<div id="fileList" class="mt-4 hidden"></div>
<button id="convertBtn" disabled class="btn-gradient w-full mt-6">
Convert to JSON
<!-- Mobile Hamburger Button -->
<div class="md:hidden flex items-center">
<button id="mobile-menu-button" type="button"
class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500 transition-colors"
aria-controls="mobile-menu" aria-expanded="false">
<span class="sr-only">Open main menu</span>
<svg id="menu-icon" class="block h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
<svg id="close-icon" class="hidden h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<!-- Status Message -->
<div id="status-message" class="mt-4 hidden p-3 rounded-lg text-sm"></div>
</div>
</div>
<script type="module" src="../js/logic/pdf-to-json.ts"></script>
<script type="module" src="../js/utils/lucide-init.ts"></script>
<script type="module" src="../js/mobileMenu.ts"></script>
</body>
</html>
<!-- Mobile Menu Dropdown -->
<div id="mobile-menu" class="hidden md:hidden bg-gray-800 border-t border-gray-700">
<div class="px-2 pt-2 pb-3 space-y-1 text-center">
<a href="/" class="mobile-nav-link">Home</a>
<a href="/about.html" class="mobile-nav-link">About</a>
<a href="/contact.html" class="mobile-nav-link">Contact</a>
<a href="/" class="mobile-nav-link">All Tools</a>
</div>
</div>
</nav>
<div class="min-h-screen flex items-center justify-center p-4 bg-gray-900">
<div class="bg-gray-800 rounded-xl shadow-xl p-8 max-w-2xl w-full text-gray-200 border border-gray-700">
<button id="back-to-tools"
class="flex items-center gap-2 text-indigo-400 hover:text-indigo-300 mb-6 font-semibold">
<i data-lucide="arrow-left" class="cursor-pointer"></i>
<span class="cursor-pointer"> Back to Tools </span>
</button>
<h1 class="text-2xl font-bold text-white mb-2">PDF to JSON Converter</h1>
<p class="text-gray-400 mb-6">
Upload multiple PDF files to convert them all to JSON format. Files will be downloaded as a ZIP archive.
</p>
<div class="upload-section mb-6">
<div
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-700 hover:bg-gray-600 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 files</span> or drag and drop
</p>
<p class="text-xs text-gray-500">Multiple PDF files</p>
<p class="text-xs text-gray-500">Your files never leave your device.</p>
</div>
<input type="file" id="pdfFiles" accept="application/pdf" multiple
class="absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer" />
</div>
<!-- File Display Area -->
<div id="fileList" class="mt-4 hidden"></div>
<button id="convertBtn" disabled class="btn-gradient w-full mt-6">
Convert to JSON
</button>
</div>
<!-- Status Message -->
<div id="status-message" class="mt-4 hidden p-3 rounded-lg text-sm"></div>
</div>
</div>
<script type="module" src="../js/logic/pdf-to-json.ts"></script>
<script type="module" src="../js/utils/lucide-init.ts"></script>
<script type="module" src="../js/mobileMenu.ts"></script>
</body>
</html>

View File

@@ -16,16 +16,16 @@
<div class="flex-shrink-0 flex items-center cursor-pointer" id="home-logo">
<img src="../../public/images/favicon.svg" alt="Bento PDF Logo" class="h-8 w-8" />
<span class="text-white font-bold text-xl ml-2">
<a href="../../index.html">BentoPDF</a>
<a href="/">BentoPDF</a>
</span>
</div>
<!-- Desktop Navigation -->
<div class="hidden md:flex items-center space-x-8 text-white">
<a href="../../index.html" class="nav-link">Home</a>
<a href="../../about.html" class="nav-link">About</a>
<a href="../../contact.html" class="nav-link">Contact</a>
<a href="../../index.html#tools-header" class="nav-link">All Tools</a>
<a href="/" class="nav-link">Home</a>
<a href="/about.html" class="nav-link">About</a>
<a href="/contact.html" class="nav-link">Contact</a>
<a href="/" class="nav-link">All Tools</a>
</div>
<!-- Mobile Hamburger Button -->
@@ -52,10 +52,10 @@
<!-- Mobile Menu Dropdown -->
<div id="mobile-menu" class="hidden md:hidden bg-gray-800 border-t border-gray-700">
<div class="px-2 pt-2 pb-3 space-y-1 text-center">
<a href="../../index.html" class="mobile-nav-link">Home</a>
<a href="../../about.html" class="mobile-nav-link">About</a>
<a href="../../contact.html" class="mobile-nav-link">Contact</a>
<a href="../../index.html#tools-header" class="mobile-nav-link">All Tools</a>
<a href="/" class="mobile-nav-link">Home</a>
<a href="/about.html" class="mobile-nav-link">About</a>
<a href="/contact.html" class="mobile-nav-link">Contact</a>
<a href="/" class="mobile-nav-link">All Tools</a>
</div>
</div>
</nav>