diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3b5d1e1..e106dec 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -82,6 +82,7 @@ When submitting code contributions, please use our [pull request template](.gith ``` 6. **Push and Submit a Pull Request** + ```bash git push origin feature/my-new-feature ``` diff --git a/index.html b/index.html index 86ca77a..39f2da5 100644 --- a/index.html +++ b/index.html @@ -1,590 +1,892 @@ - + - - - - + + + BentoPDF - The Privacy First PDF Toolkit - - - - + - - - - + rel="stylesheet" + href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.6.1/cropper.min.css" + /> + + + + + + + + - - - +
+
+

+ The PDF Toolkit built for + privacy. +

+

Fast, Secure and Forever Free.

+
+ + + No Signups + + + + Unlimited Use + + + + Works Offline + +
-
-

- The - PDF Toolkit - built for privacy. -

-

- Fast, Secure and Forever Free. +

+
+ +
+ +
+

+ Why BentoPDF? +

+
+
+
+ +

No Signup

+
+

+ Start instantly, no accounts or emails.

-
- - - No Signups - - - - Unlimited Use - - - - Works Offline - -
- - - -
- -
- -
-

- Why BentoPDF? -

-
-
-
- -

No Signup

-
-

Start instantly, no accounts or emails.

-
-
-
- -

No Uploads

-
-

100% client-side, your files never leave your device.

-
-
-
- -

Forever Free

-
-

All tools, no trials, no paywalls.

-
-
-
- -

No Limits

-
-

Use as much as you want, no hidden caps.

-
-
-
- -

Batch Processing

-
-

Handle unlimited PDFs in one go.

-
-
-
- -

Lightning Fast

-
-

Process PDFs instantly, without waiting or delays.

-
+
+
+
+ +

No Uploads

-
+

+ 100% client-side, your files never leave your device. +

+
+
+
+ +

Forever Free

+
+

+ All tools, no trials, no paywalls. +

+
+
+
+ +

No Limits

+
+

+ Use as much as you want, no hidden caps. +

+
+
+
+ +

Batch Processing

+
+

Handle unlimited PDFs in one go.

+
+
+
+ +

Lightning Fast

+
+

+ Process PDFs instantly, without waiting or delays. +

+
+ + -
+
-
-

- Get Started with Tools -

-

Click a tool to open the file uploader

+
+

+ Get Started with Tools +

+

Click a tool to open the file uploader

+
+ +
+
+
+ + + + +
-
-
-
- - - - -
-
+
+
-
+ + + + + + + + +
+ + +
+
+

+ Your data never leaves your device + + + We keep + + + + your information safe + + by following global security standards. +

+
+
+ + All the processing happens locally on your device. +
- - - - - - - - -
- - -
-
-

- Your data never leaves your device - - - We keep - - - - your information safe - - by following global security standards. -

-
-
- - All the processing happens locally on your device. - -
- -
- -
-
- GDPR compliance -
-

GDPR compliance

-

Protects the personal data - and privacy of individuals within the European Union.

-
- -
-
- CCPA compliance -
-

CCPA compliance

-

Gives California residents - rights over how their personal information is collected, used, and shared.

-
- -
-
- HIPAA compliance -
-

HIPAA compliance

-

Sets safeguards for handling - sensitive health information in the United States healthcare system.

-
- -
-
- - - -
- -
-

- Frequently Asked Questions -

- -
- -
-

- Yes, absolutely. All tools on BentoPDF are 100% free to use, with no file limits, no sign-ups, - and no - watermarks. We believe everyone deserves access to simple, powerful PDF tools without a paywall. -

-
-
- -
- -
-

- Your files are as secure as possible because they **never leave your computer**. All processing - happens - directly in your web browser (client-side). We never upload your files to a server, so you - maintain - complete privacy and control over your documents. -

-
-
- -
- -
-

- Yes! Since BentoPDF runs entirely in your browser, it works on any operating system with a - modern web - browser, including Windows, macOS, Linux, iOS, and Android. -

-
-
- - -
- -
-

- Yes. BentoPDF is fully GDPR compliant. Since all file processing happens locally in your browser - and we - never collect or transmit your files to any server, we have no access to your data. This ensures - you are - always in control of your documents. -

-
-
- - -
- -
-

- No. We never store, track, or log your files. Everything you do on BentoPDF happens in your - browser - memory and disappears once you close the page. There are no uploads, no history logs, and no - servers - involved. -

-
-
- - -
- -
-

- Most PDF tools upload your files to a server for processing. BentoPDF never does that. We use - secure, - modern web technology to process your files directly in your browser. This means faster - performance, - stronger privacy, and complete peace of mind. -

-
-
- - -
- -
-

- By running entirely inside your browser, BentoPDF ensures that your files never leave your - device. This - eliminates the risks of server hacks, data breaches, or unauthorized access. Your files remain - yours—always. -

-
-
- - -
- -
-

- We care about your privacy. BentoPDF does not track personal information. We use Simple Analytics solely to see anonymous visit counts. This - means we can know how many users visit our site, but we never know who you are. - Simple Analytics is fully GDPR-compliant and respects your privacy. -

-
-
-
- - -
- -
-

- What Our Users Say -

-
-
-
-
-

Sarah L.

-
★★★★★
-
-
-

"This is the tool I've been searching for! It's fast, free, and I love that - my confidential documents never get uploaded to some random server. A lifesaver for my freelance - work."

-
-
-
-
-

Mark Chen

-
★★★★★
-
-
-

"Finally, a PDF editor that just works. No ads, no sign-ups, no nonsense. - The merge tool is surprisingly powerful. I've already bookmarked it on all my devices."

-
-
-
-
-

Anonymous User A-35Z

-
★☆☆☆☆
-
-
-

"Terrible. It won't let me upload my files to the cloud. How is my Big Data - Tech Overlord supposed to know I signed a permission slip for my kid's field trip? Useless for - my data profile."

-
-
-
-
-

Dr. Brickson

-
★★★★★
-
-
-

"As a researcher, data privacy is paramount. BentoPDF's client-side - processing model is exactly what my institution recommends. It's robust, reliable, and secure. A - fantastic resource."

-
-
-
-
-

AdTracker Pro

-
★☆☆☆☆
-
-
-

"This website is broken. My ad blocker says it hasn't blocked a single - tracker. How am I supposed to know if a product is good if it's not following me around the - internet for a week? 1 star."

-
-
-
-
-

Raj P.

-
★★★★★
-
-
-

"Simple, elegant, and powerful. I needed to merge 50 reports, and it - handled it instantly without crashing my browser. This is what a web tool should be. Highly - recommended."

-
-
-
- -
-
+
+ +
-

- Like My Work? -

-

- BentoPDF is a passion project, built to provide a free, private, and powerful PDF toolkit for - everyone. If you find it useful, consider supporting its development. Every coffee helps! -

- - - - Buy Me a Coffee - - + class="w-20 h-20 md:w-24 md:h-24 rounded-full bg-blue-600 flex items-center justify-center mb-4" + > + GDPR compliance
-
+

+ GDPR compliance +

+

+ Protects the personal data and privacy of individuals within the + European Union. +

+
+
+
+ CCPA compliance +
+

+ CCPA compliance +

+

+ Gives California residents rights over how their personal + information is collected, used, and shared. +

+
- +
+
+ HIPAA compliance +
+

+ HIPAA compliance +

+

+ Sets safeguards for handling sensitive health information in the + United States healthcare system. +

+
+
+ + + + +
+ +
+

+ Frequently Asked Questions +

+ +
+ +
+

+ Yes, absolutely. All tools on BentoPDF are 100% free to use, with + no file limits, no sign-ups, and no watermarks. We believe + everyone deserves access to simple, powerful PDF tools without a + paywall. +

+
+
+ +
+ +
+

+ Your files are as secure as possible because they **never leave + your computer**. All processing happens directly in your web + browser (client-side). We never upload your files to a server, so + you maintain complete privacy and control over your documents. +

+
+
+ +
+ +
+

+ Yes! Since BentoPDF runs entirely in your browser, it works on any + operating system with a modern web browser, including Windows, + macOS, Linux, iOS, and Android. +

+
+
+ + +
+ +
+

+ Yes. BentoPDF is fully GDPR compliant. Since all file processing + happens locally in your browser and we never collect or transmit + your files to any server, we have no access to your data. This + ensures you are always in control of your documents. +

+
+
+ + +
+ +
+

+ No. We never store, track, or log your files. Everything you do on + BentoPDF happens in your browser memory and disappears once you + close the page. There are no uploads, no history logs, and no + servers involved. +

+
+
+ + +
+ +
+

+ Most PDF tools upload your files to a server for processing. + BentoPDF never does that. We use secure, modern web technology to + process your files directly in your browser. This means faster + performance, stronger privacy, and complete peace of mind. +

+
+
+ + +
+ +
+

+ By running entirely inside your browser, BentoPDF ensures that + your files never leave your device. This eliminates the risks of + server hacks, data breaches, or unauthorized access. Your files + remain yours—always. +

+
+
+ + +
+ +
+

+ We care about your privacy. BentoPDF does not track personal + information. We use + Simple Analytics + solely to see anonymous visit counts. This means we can know how + many users visit our site, but + we never know who you are. Simple Analytics is + fully GDPR-compliant and respects your privacy. +

+
+
+
+ +
+ +
+

+ What Our Users Say +

+
+
+
+
+

Sarah L.

+
+ ★★★★★ +
+
+
+

+ "This is the tool I've been searching for! It's fast, free, and I + love that my confidential documents never get uploaded to some + random server. A lifesaver for my freelance work." +

+
+
+
+
+

Mark Chen

+
+ ★★★★★ +
+
+
+

+ "Finally, a PDF editor that just works. No ads, no sign-ups, no + nonsense. The merge tool is surprisingly powerful. I've already + bookmarked it on all my devices." +

+
+
+
+
+

Anonymous User A-35Z

+
+ ★☆☆☆☆ +
+
+
+

+ "Terrible. It won't let me upload my files to the cloud. How is my + Big Data Tech Overlord supposed to know I signed a permission slip + for my kid's field trip? Useless for my data profile." +

+
+
+
+
+

Dr. Brickson

+
+ ★★★★★ +
+
+
+

+ "As a researcher, data privacy is paramount. BentoPDF's + client-side processing model is exactly what my institution + recommends. It's robust, reliable, and secure. A fantastic + resource." +

+
+
+
+
+

AdTracker Pro

+
+ ★☆☆☆☆ +
+
+
+

+ "This website is broken. My ad blocker says it hasn't blocked a + single tracker. How am I supposed to know if a product is good if + it's not following me around the internet for a week? 1 star." +

+
+
+
+
+

Raj P.

+
+ ★★★★★ +
+
+
+

+ "Simple, elegant, and powerful. I needed to merge 50 reports, and + it handled it instantly without crashing my browser. This is what + a web tool should be. Highly recommended." +

+
+
+
+ +
+
+
+

+ Like My Work? +

+

+ BentoPDF is a passion project, built to provide a free, private, and + powerful PDF toolkit for everyone. If you find it useful, consider + supporting its development. Every coffee helps! +

+ + + + Buy Me a Coffee + +
+
+ +
- - - \ No newline at end of file + + diff --git a/src/js/logic/add-watermark.ts b/src/js/logic/add-watermark.ts index 6afe884..537e368 100644 --- a/src/js/logic/add-watermark.ts +++ b/src/js/logic/add-watermark.ts @@ -38,15 +38,18 @@ export function setupWatermarkUI() { const angleSliderText = document.getElementById('angle-text'); const angleValueText = document.getElementById('angle-value-text'); - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message opacitySliderText.addEventListener( 'input', - () => (opacityValueText.textContent = opacitySliderText.value) + () => + (opacityValueText.textContent = ( + opacitySliderText as HTMLInputElement + ).value) ); - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + angleSliderText.addEventListener( 'input', - () => (angleValueText.textContent = angleSliderText.value) + () => + (angleValueText.textContent = (angleSliderText as HTMLInputElement).value) ); const opacitySliderImage = document.getElementById('opacity-image'); @@ -54,22 +57,28 @@ export function setupWatermarkUI() { const angleSliderImage = document.getElementById('angle-image'); const angleValueImage = document.getElementById('angle-value-image'); - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message opacitySliderImage.addEventListener( 'input', - () => (opacityValueImage.textContent = opacitySliderImage.value) + () => + (opacityValueImage.textContent = ( + opacitySliderImage as HTMLInputElement + ).value) ); - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + angleSliderImage.addEventListener( 'input', - () => (angleValueImage.textContent = angleSliderImage.value) + () => + (angleValueImage.textContent = ( + angleSliderImage as HTMLInputElement + ).value) ); } export async function addWatermark() { - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'Element'. - const watermarkType = document.querySelector( - 'input[name="watermark-type"]:checked' + const watermarkType = ( + document.querySelector( + 'input[name="watermark-type"]:checked' + ) as HTMLInputElement ).value; showLoader('Adding watermark...'); @@ -82,9 +91,9 @@ export async function addWatermark() { watermarkAsset = await state.pdfDoc.embedFont(StandardFonts.Helvetica); } else { // 'image' - // @ts-expect-error TS(2339) FIXME: Property 'files' does not exist on type 'HTMLEleme... Remove this comment to see the full error message - const imageFile = document.getElementById('image-watermark-input') - .files[0]; + const imageFile = ( + document.getElementById('image-watermark-input') as HTMLInputElement + ).files?.[0]; if (!imageFile) throw new Error('Please select an image file for the watermark.'); @@ -109,17 +118,21 @@ export async function addWatermark() { if (!text.trim()) throw new Error('Please enter text for the watermark.'); - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message const fontSize = - parseInt(document.getElementById('font-size').value) || 72; - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + parseInt( + (document.getElementById('font-size') as HTMLInputElement).value + ) || 72; const angle = - parseInt(document.getElementById('angle-text').value) || 0; - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + parseInt( + (document.getElementById('angle-text') as HTMLInputElement).value + ) || 0; const opacity = - parseFloat(document.getElementById('opacity-text').value) || 0.3; - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message - const colorHex = document.getElementById('text-color').value; + parseFloat( + (document.getElementById('opacity-text') as HTMLInputElement).value + ) || 0.3; + const colorHex = ( + document.getElementById('text-color') as HTMLInputElement + ).value; const textColor = hexToRgb(colorHex); const textWidth = watermarkAsset.widthOfTextAtSize(text, fontSize); @@ -133,12 +146,14 @@ export async function addWatermark() { rotate: degrees(angle), }); } else { - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message const angle = - parseInt(document.getElementById('angle-image').value) || 0; - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + parseInt( + (document.getElementById('angle-image') as HTMLInputElement).value + ) || 0; const opacity = - parseFloat(document.getElementById('opacity-image').value) || 0.3; + parseFloat( + (document.getElementById('opacity-image') as HTMLInputElement).value + ) || 0.3; const scale = 0.5; const imgWidth = watermarkAsset.width * scale; diff --git a/src/js/logic/change-text-color.ts b/src/js/logic/change-text-color.ts index d9d565a..42c3e08 100644 --- a/src/js/logic/change-text-color.ts +++ b/src/js/logic/change-text-color.ts @@ -34,17 +34,16 @@ async function updateTextColorPreview() { textColorCanvas.height = viewport.height; await page.render({ canvasContext: context, viewport }).promise; - - // @ts-expect-error TS(2339) FIXME: Property 'width' does not exist on type 'HTMLEleme... Remove this comment to see the full error message const imageData = context.getImageData( 0, 0, - textColorCanvas.width, - textColorCanvas.height + (textColorCanvas as HTMLCanvasElement).width, + (textColorCanvas as HTMLCanvasElement).height ); const data = imageData.data; - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message - const colorHex = document.getElementById('text-color-input').value; + const colorHex = ( + document.getElementById('text-color-input') as HTMLInputElement + ).value; const { r, g, b } = hexToRgb(colorHex); const darknessThreshold = 120; @@ -91,9 +90,8 @@ export async function setupTextColorTool() { // @ts-expect-error TS(2339) FIXME: Property 'height' does not exist on type 'HTMLElem... Remove this comment to see the full error message originalCanvas.height = viewport.height; - // @ts-expect-error TS(2339) FIXME: Property 'getContext' does not exist on type 'HTML... Remove this comment to see the full error message await page.render({ - canvasContext: originalCanvas.getContext('2d'), + canvasContext: (originalCanvas as HTMLCanvasElement).getContext('2d'), viewport, }).promise; await updateTextColorPreview(); diff --git a/src/js/logic/compare-pdfs.ts b/src/js/logic/compare-pdfs.ts index f9dd867..0f283b8 100644 --- a/src/js/logic/compare-pdfs.ts +++ b/src/js/logic/compare-pdfs.ts @@ -223,9 +223,8 @@ export function setupCompareTool() { const panel1 = document.getElementById('panel-1'); const panel2 = document.getElementById('panel-2'); const syncToggle = document.getElementById('sync-scroll-toggle'); - // @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'HTMLEle... Remove this comment to see the full error message - syncToggle.addEventListener('change', () => { - state.isSyncScroll = syncToggle.checked; + (syncToggle as HTMLInputElement).addEventListener('change', () => { + state.isSyncScroll = (syncToggle as HTMLInputElement).checked; }); let scrollingPanel: any = null; diff --git a/src/js/logic/compress.ts b/src/js/logic/compress.ts index 17c310f..7db64b9 100644 --- a/src/js/logic/compress.ts +++ b/src/js/logic/compress.ts @@ -297,12 +297,7 @@ export async function compress() { resultBytes = vectorResultBytes; usedMethod = 'Vector (Automatic)'; } else { - // @ts-expect-error TS(2554) FIXME: Expected 2 arguments, but got 3. - showAlert( - 'Vector failed to reduce size. Trying Photon...', - 'info', - 3000 - ); + showAlert('Vector failed to reduce size. Trying Photon...', 'info'); showLoader('Running Automatic (Photon fallback)...'); resultBytes = await performLegacyCompression( arrayBuffer, @@ -339,12 +334,9 @@ export async function compress() { 'compressed-final.pdf' ); } catch (e) { - console.error(e); - // @ts-expect-error TS(2554) FIXME: Expected 2 arguments, but got 3. showAlert( 'Error', - `An error occurred during compression. Error: ${e.message}`, - 'error' + `An error occurred during compression. Error: ${e.message}` ); } finally { hideLoader(); diff --git a/src/js/logic/cropper.ts b/src/js/logic/cropper.ts index 3dbdfd4..32047f3 100644 --- a/src/js/logic/cropper.ts +++ b/src/js/logic/cropper.ts @@ -273,13 +273,11 @@ export async function setupCropperTool() { // Get the last known crop from the active page before processing saveCurrentCrop(); - // @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'HTMLEle... Remove this comment to see the full error message - const isDestructive = document.getElementById( - 'destructive-crop-toggle' + const isDestructive = ( + document.getElementById('destructive-crop-toggle') as HTMLInputElement ).checked; - // @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'HTMLEle... Remove this comment to see the full error message - const isApplyToAll = document.getElementById( - 'apply-to-all-toggle' + const isApplyToAll = ( + document.getElementById('apply-to-all-toggle') as HTMLInputElement ).checked; let finalCropData = {}; diff --git a/src/js/logic/decrypt.ts b/src/js/logic/decrypt.ts index 4287561..758ad09 100644 --- a/src/js/logic/decrypt.ts +++ b/src/js/logic/decrypt.ts @@ -16,8 +16,7 @@ export async function decrypt() { try { showLoader('Preparing to process...'); - const pdfData = await readFileAsArrayBuffer(file); - // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdfData = (await readFileAsArrayBuffer(file)) as ArrayBuffer; const pdf = await pdfjsLib.getDocument({ data: pdfData, password: password, diff --git a/src/js/logic/duplicate-organize.ts b/src/js/logic/duplicate-organize.ts index 40cc20c..aa828e3 100644 --- a/src/js/logic/duplicate-organize.ts +++ b/src/js/logic/duplicate-organize.ts @@ -156,9 +156,8 @@ export async function processAndSave() { const grid = document.getElementById('page-grid'); const finalPageElements = grid.querySelectorAll('.page-thumbnail'); - // @ts-expect-error TS(2339) FIXME: Property 'dataset' does not exist on type 'Element... Remove this comment to see the full error message const finalIndices = Array.from(finalPageElements).map((el) => - parseInt(el.dataset.originalPageIndex) + parseInt((el as HTMLElement).dataset.originalPageIndex) ); const newPdfDoc = await PDFLibDocument.create(); diff --git a/src/js/logic/fix-dimensions.ts b/src/js/logic/fix-dimensions.ts index 186ae81..25b56e1 100644 --- a/src/js/logic/fix-dimensions.ts +++ b/src/js/logic/fix-dimensions.ts @@ -9,27 +9,29 @@ export function setupFixDimensionsUI() { const customSizeWrapper = document.getElementById('custom-size-wrapper'); if (targetSizeSelect && customSizeWrapper) { targetSizeSelect.addEventListener('change', () => { - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message customSizeWrapper.classList.toggle( 'hidden', - targetSizeSelect.value !== 'Custom' + (targetSizeSelect as HTMLSelectElement).value !== 'Custom' ); }); } } export async function fixDimensions() { - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message - const targetSizeKey = document.getElementById('target-size').value; - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message - const orientation = document.getElementById('orientation').value; - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'Element'. - const scalingMode = document.querySelector( - 'input[name="scaling-mode"]:checked' + const targetSizeKey = ( + document.getElementById('target-size') as HTMLSelectElement + ).value; + const orientation = ( + document.getElementById('orientation') as HTMLSelectElement + ).value; + + const scalingMode = ( + document.querySelector( + 'input[name="scaling-mode"]:checked' + ) as HTMLInputElement ).value; - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message const backgroundColor = hexToRgb( - document.getElementById('background-color').value + (document.getElementById('background-color') as HTMLInputElement).value ); showLoader('Standardizing pages...'); diff --git a/src/js/logic/index.ts b/src/js/logic/index.ts index 7cf4f10..fe22f4c 100644 --- a/src/js/logic/index.ts +++ b/src/js/logic/index.ts @@ -30,7 +30,7 @@ import { txtToPdf } from './txt-to-pdf.js'; import { invertColors } from './invert-colors.js'; // import { viewMetadata } from './view-metadata.js'; import { reversePages } from './reverse-pages.js'; -import { mdToPdf } from './md-to-pdf.js'; +// import { mdToPdf } from './md-to-pdf.js'; import { svgToPdf } from './svg-to-pdf.js'; import { bmpToPdf } from './bmp-to-pdf.js'; import { heicToPdf } from './heic-to-pdf.js'; @@ -94,7 +94,7 @@ export const toolLogic = { 'txt-to-pdf': txtToPdf, 'invert-colors': invertColors, 'reverse-pages': reversePages, - 'md-to-pdf': mdToPdf, + // 'md-to-pdf': mdToPdf, 'svg-to-pdf': svgToPdf, 'bmp-to-pdf': bmpToPdf, 'heic-to-pdf': heicToPdf, diff --git a/src/js/logic/md-to-pdf.ts b/src/js/logic/md-to-pdf.ts index 02bf588..11dae08 100644 --- a/src/js/logic/md-to-pdf.ts +++ b/src/js/logic/md-to-pdf.ts @@ -1,95 +1,95 @@ -// note: this is a work in progress -import { showLoader, hideLoader, showAlert } from '../ui.js'; -import { downloadFile } from '../utils/helpers.js'; -import html2canvas from 'html2canvas'; +// // note: this is a work in progress +// import { showLoader, hideLoader, showAlert } from '../ui.js'; +// import { downloadFile } from '../utils/helpers.js'; +// import html2canvas from 'html2canvas'; -export async function mdToPdf() { - // @ts-expect-error TS(2339) FIXME: Property 'jspdf' does not exist on type 'Window & ... Remove this comment to see the full error message - if ( - typeof window.jspdf === 'undefined' || - typeof window.html2canvas === 'undefined' - ) { - showAlert( - 'Libraries Not Ready', - 'PDF generation libraries are loading. Please try again.' - ); - return; - } - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message - const markdownContent = document.getElementById('md-input').value.trim(); - if (!markdownContent) { - showAlert('Input Required', 'Please enter some Markdown text.'); - return; - } - showLoader('Generating High-Quality PDF...'); +// export async function mdToPdf() { +// // @ts-expect-error TS(2339) FIXME: Property 'jspdf' does not exist on type 'Window & ... Remove this comment to see the full error message +// if ( +// typeof window.jspdf === 'undefined' || +// typeof window.html2canvas === 'undefined' +// ) { +// showAlert( +// 'Libraries Not Ready', +// 'PDF generation libraries are loading. Please try again.' +// ); +// return; +// } +// // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message +// const markdownContent = document.getElementById('md-input').value.trim(); +// if (!markdownContent) { +// showAlert('Input Required', 'Please enter some Markdown text.'); +// return; +// } +// showLoader('Generating High-Quality PDF...'); - try { - // @ts-expect-error TS(2304) FIXME: Cannot find name 'marked'. - const htmlContent = marked.parse(markdownContent); - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message - const pageFormat = document.getElementById('page-format').value; - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message - const orientation = document.getElementById('orientation').value; - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message - const marginSize = document.getElementById('margin-size').value; +// try { +// // @ts-expect-error TS(2304) FIXME: Cannot find name 'marked'. +// const htmlContent = marked.parse(markdownContent); +// // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message +// const pageFormat = document.getElementById('page-format').value; +// // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message +// const orientation = document.getElementById('orientation').value; +// // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message +// const marginSize = document.getElementById('margin-size').value; - const tempContainer = document.createElement('div'); - tempContainer.style.cssText = - 'position: absolute; top: -9999px; left: -9999px; width: 800px; padding: 40px; background: white; color: black;'; - const styleSheet = document.createElement('style'); - styleSheet.textContent = ` - body { font-family: Helvetica, Arial, sans-serif; line-height: 1.6; font-size: 12px; } - h1, h2, h3 { margin: 20px 0 10px 0; font-weight: 600; border-bottom: 1px solid #eaecef; padding-bottom: .3em; } - h1 { font-size: 2em; } h2 { font-size: 1.5em; } - p, blockquote, ul, ol, pre, table { margin: 0 0 16px 0; } - blockquote { padding: 0 1em; color: #6a737d; border-left: .25em solid #dfe2e5; } - pre { padding: 16px; overflow: auto; font-size: 85%; line-height: 1.45; background-color: #f6f8fa; border-radius: 6px; } - code { font-family: 'Courier New', monospace; background-color: rgba(27,31,35,.05); border-radius: 3px; padding: .2em .4em; } - table { width: 100%; border-collapse: collapse; } th, td { padding: 6px 13px; border: 1px solid #dfe2e5; } - img { max-width: 100%; } - `; - tempContainer.appendChild(styleSheet); - tempContainer.innerHTML += htmlContent; - document.body.appendChild(tempContainer); +// const tempContainer = document.createElement('div'); +// tempContainer.style.cssText = +// 'position: absolute; top: -9999px; left: -9999px; width: 800px; padding: 40px; background: white; color: black;'; +// const styleSheet = document.createElement('style'); +// styleSheet.textContent = ` +// body { font-family: Helvetica, Arial, sans-serif; line-height: 1.6; font-size: 12px; } +// h1, h2, h3 { margin: 20px 0 10px 0; font-weight: 600; border-bottom: 1px solid #eaecef; padding-bottom: .3em; } +// h1 { font-size: 2em; } h2 { font-size: 1.5em; } +// p, blockquote, ul, ol, pre, table { margin: 0 0 16px 0; } +// blockquote { padding: 0 1em; color: #6a737d; border-left: .25em solid #dfe2e5; } +// pre { padding: 16px; overflow: auto; font-size: 85%; line-height: 1.45; background-color: #f6f8fa; border-radius: 6px; } +// code { font-family: 'Courier New', monospace; background-color: rgba(27,31,35,.05); border-radius: 3px; padding: .2em .4em; } +// table { width: 100%; border-collapse: collapse; } th, td { padding: 6px 13px; border: 1px solid #dfe2e5; } +// img { max-width: 100%; } +// `; +// tempContainer.appendChild(styleSheet); +// tempContainer.innerHTML += htmlContent; +// document.body.appendChild(tempContainer); - const canvas = await html2canvas(tempContainer, { - scale: 2, - useCORS: true, - }); - document.body.removeChild(tempContainer); +// const canvas = await html2canvas(tempContainer, { +// scale: 2, +// useCORS: true, +// }); +// document.body.removeChild(tempContainer); - // @ts-expect-error TS(2339) FIXME: Property 'jspdf' does not exist on type 'Window & ... Remove this comment to see the full error message - const { jsPDF } = window.jspdf; - const pdf = new jsPDF({ orientation, unit: 'mm', format: pageFormat }); - const pageFormats = { a4: [210, 297], letter: [216, 279] }; - const format = pageFormats[pageFormat]; - const [pageWidth, pageHeight] = - orientation === 'landscape' ? [format[1], format[0]] : format; - const margins = { narrow: 10, normal: 20, wide: 30 }; - const margin = margins[marginSize]; - const contentWidth = pageWidth - margin * 2; - const contentHeight = pageHeight - margin * 2; - const imgData = canvas.toDataURL('image/png'); - const imgHeight = (canvas.height * contentWidth) / canvas.width; +// // @ts-expect-error TS(2339) FIXME: Property 'jspdf' does not exist on type 'Window & ... Remove this comment to see the full error message +// const { jsPDF } = window.jspdf; +// const pdf = new jsPDF({ orientation, unit: 'mm', format: pageFormat }); +// const pageFormats = { a4: [210, 297], letter: [216, 279] }; +// const format = pageFormats[pageFormat]; +// const [pageWidth, pageHeight] = +// orientation === 'landscape' ? [format[1], format[0]] : format; +// const margins = { narrow: 10, normal: 20, wide: 30 }; +// const margin = margins[marginSize]; +// const contentWidth = pageWidth - margin * 2; +// const contentHeight = pageHeight - margin * 2; +// const imgData = canvas.toDataURL('image/png'); +// const imgHeight = (canvas.height * contentWidth) / canvas.width; - let heightLeft = imgHeight; - let position = margin; - pdf.addImage(imgData, 'PNG', margin, position, contentWidth, imgHeight); - heightLeft -= contentHeight; +// let heightLeft = imgHeight; +// let position = margin; +// pdf.addImage(imgData, 'PNG', margin, position, contentWidth, imgHeight); +// heightLeft -= contentHeight; - while (heightLeft > 0) { - position = position - pageHeight; - pdf.addPage(); - pdf.addImage(imgData, 'PNG', margin, position, contentWidth, imgHeight); - heightLeft -= contentHeight; - } +// while (heightLeft > 0) { +// position = position - pageHeight; +// pdf.addPage(); +// pdf.addImage(imgData, 'PNG', margin, position, contentWidth, imgHeight); +// heightLeft -= contentHeight; +// } - const pdfBlob = pdf.output('blob'); - downloadFile(pdfBlob, 'markdown-document.pdf'); - } catch (error) { - console.error('MD to PDF conversion error:', error); - showAlert('Conversion Error', 'Failed to generate PDF.'); - } finally { - hideLoader(); - } -} +// const pdfBlob = pdf.output('blob'); +// downloadFile(pdfBlob, 'markdown-document.pdf'); +// } catch (error) { +// console.error('MD to PDF conversion error:', error); +// showAlert('Conversion Error', 'Failed to generate PDF.'); +// } finally { +// hideLoader(); +// } +// } diff --git a/src/js/logic/ocr-pdf.ts b/src/js/logic/ocr-pdf.ts index fc4c329..2cf5aec 100644 --- a/src/js/logic/ocr-pdf.ts +++ b/src/js/logic/ocr-pdf.ts @@ -81,10 +81,9 @@ function updateProgress(status: any, progress: any) { } async function runOCR() { - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'Element'. const selectedLangs = Array.from( document.querySelectorAll('.lang-checkbox:checked') - ).map((cb) => cb.value); + ).map((cb) => (cb as HTMLInputElement).value); // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message const scale = parseFloat(document.getElementById('ocr-resolution').value); // @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'HTMLEle... Remove this comment to see the full error message diff --git a/src/js/logic/organize.ts b/src/js/logic/organize.ts index 04ca094..9bc1a1e 100644 --- a/src/js/logic/organize.ts +++ b/src/js/logic/organize.ts @@ -9,9 +9,8 @@ export async function organize() { try { const newPdf = await PDFLibDocument.create(); const pageContainer = document.getElementById('page-organizer'); - // @ts-expect-error TS(2339) FIXME: Property 'dataset' does not exist on type 'Element... Remove this comment to see the full error message const pageIndices = Array.from(pageContainer.children).map((child) => - parseInt(child.dataset.pageIndex) + parseInt((child as HTMLElement).dataset.pageIndex) ); const copiedPages = await newPdf.copyPages(state.pdfDoc, pageIndices); diff --git a/src/js/logic/remove-annotations.ts b/src/js/logic/remove-annotations.ts index 54bb7c1..5aa425e 100644 --- a/src/js/logic/remove-annotations.ts +++ b/src/js/logic/remove-annotations.ts @@ -34,9 +34,10 @@ export async function removeAnnotations() { const totalPages = state.pdfDoc.getPageCount(); let targetPageIndices = []; - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'Element'. - const pageScope = document.querySelector( - 'input[name="page-scope"]:checked' + const pageScope = ( + document.querySelector( + 'input[name="page-scope"]:checked' + ) as HTMLInputElement ).value; if (pageScope === 'all') { targetPageIndices = Array.from({ length: totalPages }, (_, i) => i); @@ -71,9 +72,8 @@ export async function removeAnnotations() { throw new Error('No valid pages were selected.'); const typesToRemove = new Set( - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'Element'. Array.from(document.querySelectorAll('.annot-checkbox:checked')).map( - (cb) => cb.value + (cb) => (cb as HTMLInputElement).value ) ); diff --git a/src/js/logic/sign-pdf.ts b/src/js/logic/sign-pdf.ts index cc6632e..4305078 100644 --- a/src/js/logic/sign-pdf.ts +++ b/src/js/logic/sign-pdf.ts @@ -110,11 +110,12 @@ function setupDrawingCanvas() { signState.drawContext.lineWidth = 2; const colorPicker = document.getElementById('signature-color'); - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + colorPicker.oninput = () => - (signState.drawContext.strokeStyle = colorPicker.value); - // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message - signState.drawContext.strokeStyle = colorPicker.value; + (signState.drawContext.strokeStyle = ( + colorPicker as HTMLInputElement + ).value); + signState.drawContext.strokeStyle = (colorPicker as HTMLInputElement).value; const start = (e: any) => { signState.isDrawing = true; diff --git a/src/js/logic/split.ts b/src/js/logic/split.ts index 9c7797e..b0d19db 100644 --- a/src/js/logic/split.ts +++ b/src/js/logic/split.ts @@ -126,9 +126,9 @@ export function setupSplitTool() { export async function split() { // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message const splitMode = document.getElementById('split-mode').value; - // @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'HTMLEle... Remove this comment to see the full error message const downloadAsZip = - document.getElementById('download-as-zip')?.checked || false; + (document.getElementById('download-as-zip') as HTMLInputElement)?.checked || + false; showLoader('Splitting PDF...'); diff --git a/vite.config.ts b/vite.config.ts index 3a0e7f1..f5b2873 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'vite'; +import { defineConfig } from 'vitest/config'; import tailwindcss from '@tailwindcss/vite'; import { nodePolyfills } from 'vite-plugin-node-polyfills'; import { resolve } from 'path';