diff --git a/README.md b/README.md
index ebb5136..6ce0f9f 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,12 @@
# Convert UI
-A modern, browser-based file conversion application built with Next.js 16, Tailwind CSS 4, and WebAssembly. Convert videos, images, and documents directly in your browser without uploading files to any server.
+A modern, browser-based file conversion application built with Next.js 16, Tailwind CSS 4, and WebAssembly. Convert videos, audio, and images directly in your browser without uploading files to any server.
## Features
- **🎬 Video Conversion** - Convert between MP4, WebM, AVI, MOV, MKV, and GIF
- **🎵 Audio Conversion** - Convert between MP3, WAV, OGG, AAC, and FLAC
- **🖼️ Image Conversion** - Convert between PNG, JPG, WebP, GIF, BMP, TIFF, and SVG
-- **📄 Document Conversion** - Convert between PDF, Markdown, HTML, and Plain Text
- **🔒 Privacy First** - All conversions happen locally in your browser, no server uploads
- **⚡ Fast & Efficient** - Powered by WebAssembly for near-native performance
- **🎨 Beautiful UI** - Modern, responsive design with dark/light theme support
@@ -23,13 +22,6 @@ A modern, browser-based file conversion application built with Next.js 16, Tailw
- **Tailwind CSS 4** - Utility-first CSS with OKLCH color system
- **FFmpeg.wasm** - Video and audio conversion
- **ImageMagick WASM** - Image processing and conversion
-- **Marked** - Markdown to HTML conversion
-- **Turndown** - HTML to Markdown conversion
-- **DOMPurify** - HTML sanitization
-- **jsPDF** - PDF generation
-- **PDF.js** - PDF text extraction
-- **docx** - DOCX document generation
-- **mammoth** - DOCX document reading
- **Fuse.js** - Fuzzy search for format selection
- **Lucide React** - Beautiful icon library
@@ -92,8 +84,7 @@ convert-ui/
├── lib/
│ ├── converters/ # Conversion services
│ │ ├── ffmpegService.ts # Video/audio conversion
-│ │ ├── imagemagickService.ts # Image conversion
-│ │ └── pandocService.ts # Document conversion (placeholder)
+│ │ └── imagemagickService.ts # Image conversion
│ ├── wasm/
│ │ └── wasmLoader.ts # WASM module lazy loading
│ ├── storage/
@@ -118,31 +109,6 @@ convert-ui/
### Images (ImageMagick)
- **Input/Output:** PNG, JPG, WebP, GIF, BMP, TIFF, SVG
-### Documents
-- **PDF → Text/Markdown** - Extract text from PDF files with page-by-page processing
-- **Markdown/HTML/Text → PDF** - Generate formatted PDF documents
-- **DOCX → Text/HTML/Markdown** - Extract content from Word documents
-- **Markdown/HTML/Text → DOCX** - Create formatted Word documents with headings
-- **Markdown → HTML** - Full GitHub Flavored Markdown support with styling
-- **HTML → Markdown** - Clean conversion with formatting preservation
-- **Markdown ↔ Plain Text** - Strip or add basic formatting
-- **HTML → Plain Text** - Extract text content
-- **Plain Text → HTML** - Convert to formatted HTML document
-
-**Supported PDF Operations:**
-- Read PDFs and extract all text content
-- Convert extracted text to Markdown or plain text
-- Create PDFs from Markdown, HTML, or plain text
-- Automatic pagination and formatting
-
-**Supported DOCX Operations:**
-- Read DOCX files and extract text, HTML, or Markdown
-- Create DOCX files from Markdown with proper heading levels (H1-H3)
-- Create DOCX files from HTML or plain text
-- Automatic paragraph formatting and spacing
-
-**Note:** Uses PDF.js for reading and jsPDF for generation. Uses mammoth for DOCX reading and docx library for generation. Lightweight JavaScript libraries (marked, turndown) used instead of Pandoc WASM for fast, reliable conversions.
-
## How It Works
1. **File Upload** - Users can drag-and-drop or click to select a file
diff --git a/components/converter/FileConverter.tsx b/components/converter/FileConverter.tsx
index b189a4b..c212ed6 100644
--- a/components/converter/FileConverter.tsx
+++ b/components/converter/FileConverter.tsx
@@ -16,7 +16,6 @@ import {
} from '@/lib/utils/formatMappings';
import { convertWithFFmpeg } from '@/lib/converters/ffmpegService';
import { convertWithImageMagick } from '@/lib/converters/imagemagickService';
-import { convertWithPandoc } from '@/lib/converters/pandocService';
import { addToHistory } from '@/lib/storage/history';
import type { ConversionJob, ConversionFormat } from '@/types/conversion';
@@ -111,12 +110,6 @@ export function FileConverter() {
);
break;
- case 'pandoc':
- result = await convertWithPandoc(selectedFile, outputFormat.extension, {}, (progress) => {
- setConversionJob((prev) => prev && { ...prev, progress });
- });
- break;
-
default:
throw new Error(`Unknown converter: ${outputFormat.converter}`);
}
@@ -184,7 +177,7 @@ export function FileConverter() {
File Converter
- Convert videos, images, and documents directly in your browser using WebAssembly
+ Convert videos, audio, and images directly in your browser using WebAssembly
diff --git a/lib/converters/docxService.ts b/lib/converters/docxService.ts
deleted file mode 100644
index b8f949d..0000000
--- a/lib/converters/docxService.ts
+++ /dev/null
@@ -1,443 +0,0 @@
-import { Document, Packer, Paragraph, TextRun, HeadingLevel } from 'docx';
-import type { ConversionOptions, ProgressCallback, ConversionResult } from '@/types/conversion';
-
-/**
- * Extract text from DOCX file using mammoth
- */
-export async function extractTextFromDOCX(file: File, onProgress?: ProgressCallback): Promise {
- if (onProgress) onProgress(10);
-
- // Dynamically import mammoth (client-side only)
- const mammoth = await import('mammoth');
-
- if (onProgress) onProgress(30);
-
- // Read file as ArrayBuffer
- const arrayBuffer = await file.arrayBuffer();
-
- if (onProgress) onProgress(50);
-
- // Extract text from DOCX
- const result = await mammoth.extractRawText({ arrayBuffer });
-
- if (onProgress) onProgress(100);
-
- return result.value;
-}
-
-/**
- * Extract HTML from DOCX file using mammoth
- */
-export async function extractHTMLFromDOCX(file: File, onProgress?: ProgressCallback): Promise {
- if (onProgress) onProgress(10);
-
- // Dynamically import mammoth (client-side only)
- const mammoth = await import('mammoth');
-
- if (onProgress) onProgress(30);
-
- // Read file as ArrayBuffer
- const arrayBuffer = await file.arrayBuffer();
-
- if (onProgress) onProgress(50);
-
- // Convert DOCX to HTML
- const result = await mammoth.convertToHtml({ arrayBuffer });
-
- if (onProgress) onProgress(100);
-
- return result.value;
-}
-
-/**
- * Convert DOCX to plain text
- */
-export async function docxToText(
- file: File,
- onProgress?: ProgressCallback
-): Promise {
- const startTime = Date.now();
-
- try {
- const text = await extractTextFromDOCX(file, onProgress);
- const blob = new Blob([text], { type: 'text/plain' });
-
- return {
- success: true,
- blob,
- duration: Date.now() - startTime,
- };
- } catch (error) {
- console.error('[DOCX Converter] DOCX to text error:', error);
-
- return {
- success: false,
- error: error instanceof Error ? error.message : 'Failed to extract text from DOCX',
- duration: Date.now() - startTime,
- };
- }
-}
-
-/**
- * Convert DOCX to HTML
- */
-export async function docxToHTML(
- file: File,
- onProgress?: ProgressCallback
-): Promise {
- const startTime = Date.now();
-
- try {
- const html = await extractHTMLFromDOCX(file, (progress) => {
- if (onProgress) onProgress(progress * 0.9);
- });
-
- // Wrap in full HTML document
- const fullHTML = `
-
-
-
-
- Converted Document
-
-
-
-${html}
-
-`;
-
- if (onProgress) onProgress(100);
-
- const blob = new Blob([fullHTML], { type: 'text/html' });
-
- return {
- success: true,
- blob,
- duration: Date.now() - startTime,
- };
- } catch (error) {
- console.error('[DOCX Converter] DOCX to HTML error:', error);
-
- return {
- success: false,
- error: error instanceof Error ? error.message : 'Failed to convert DOCX to HTML',
- duration: Date.now() - startTime,
- };
- }
-}
-
-/**
- * Convert DOCX to Markdown
- */
-export async function docxToMarkdown(
- file: File,
- onProgress?: ProgressCallback
-): Promise {
- const startTime = Date.now();
-
- try {
- // First convert to HTML
- const html = await extractHTMLFromDOCX(file, (progress) => {
- if (onProgress) onProgress(progress * 0.7);
- });
-
- if (onProgress) onProgress(80);
-
- // Import turndown for HTML to Markdown
- const TurndownService = (await import('turndown')).default;
- const turndownService = new TurndownService({
- headingStyle: 'atx',
- codeBlockStyle: 'fenced',
- bulletListMarker: '-',
- });
-
- const markdown = turndownService.turndown(html);
-
- if (onProgress) onProgress(100);
-
- const blob = new Blob([markdown], { type: 'text/markdown' });
-
- return {
- success: true,
- blob,
- duration: Date.now() - startTime,
- };
- } catch (error) {
- console.error('[DOCX Converter] DOCX to Markdown error:', error);
-
- return {
- success: false,
- error: error instanceof Error ? error.message : 'Failed to convert DOCX to Markdown',
- duration: Date.now() - startTime,
- };
- }
-}
-
-/**
- * Create DOCX from text content
- */
-async function createDOCXFromText(text: string, onProgress?: ProgressCallback): Promise {
- if (onProgress) onProgress(20);
-
- // Split text into paragraphs
- const paragraphs = text.split('\n\n').filter(p => p.trim());
-
- if (onProgress) onProgress(40);
-
- // Create document with paragraphs
- const doc = new Document({
- sections: [
- {
- properties: {},
- children: paragraphs.map((para) => {
- return new Paragraph({
- children: [new TextRun(para.trim())],
- spacing: {
- after: 200,
- },
- });
- }),
- },
- ],
- });
-
- if (onProgress) onProgress(70);
-
- // Generate DOCX blob
- const blob = await Packer.toBlob(doc);
-
- if (onProgress) onProgress(100);
-
- return blob;
-}
-
-/**
- * Create DOCX from Markdown
- */
-async function createDOCXFromMarkdown(markdown: string, onProgress?: ProgressCallback): Promise {
- if (onProgress) onProgress(10);
-
- // Parse markdown and create structured document
- const lines = markdown.split('\n');
- const children: Paragraph[] = [];
-
- let currentParagraph: string[] = [];
-
- for (const line of lines) {
- if (line.startsWith('# ')) {
- // Heading 1
- if (currentParagraph.length > 0) {
- children.push(new Paragraph({
- children: [new TextRun(currentParagraph.join(' '))],
- spacing: { after: 200 },
- }));
- currentParagraph = [];
- }
- children.push(new Paragraph({
- text: line.substring(2),
- heading: HeadingLevel.HEADING_1,
- spacing: { before: 240, after: 120 },
- }));
- } else if (line.startsWith('## ')) {
- // Heading 2
- if (currentParagraph.length > 0) {
- children.push(new Paragraph({
- children: [new TextRun(currentParagraph.join(' '))],
- spacing: { after: 200 },
- }));
- currentParagraph = [];
- }
- children.push(new Paragraph({
- text: line.substring(3),
- heading: HeadingLevel.HEADING_2,
- spacing: { before: 200, after: 100 },
- }));
- } else if (line.startsWith('### ')) {
- // Heading 3
- if (currentParagraph.length > 0) {
- children.push(new Paragraph({
- children: [new TextRun(currentParagraph.join(' '))],
- spacing: { after: 200 },
- }));
- currentParagraph = [];
- }
- children.push(new Paragraph({
- text: line.substring(4),
- heading: HeadingLevel.HEADING_3,
- spacing: { before: 160, after: 80 },
- }));
- } else if (line.trim() === '') {
- // Empty line - paragraph break
- if (currentParagraph.length > 0) {
- children.push(new Paragraph({
- children: [new TextRun(currentParagraph.join(' '))],
- spacing: { after: 200 },
- }));
- currentParagraph = [];
- }
- } else {
- // Regular text
- currentParagraph.push(line);
- }
- }
-
- // Add remaining paragraph
- if (currentParagraph.length > 0) {
- children.push(new Paragraph({
- children: [new TextRun(currentParagraph.join(' '))],
- spacing: { after: 200 },
- }));
- }
-
- if (onProgress) onProgress(60);
-
- const doc = new Document({
- sections: [
- {
- properties: {},
- children,
- },
- ],
- });
-
- if (onProgress) onProgress(80);
-
- const blob = await Packer.toBlob(doc);
-
- if (onProgress) onProgress(100);
-
- return blob;
-}
-
-/**
- * Convert plain text to DOCX
- */
-export async function textToDOCX(
- file: File,
- onProgress?: ProgressCallback
-): Promise {
- const startTime = Date.now();
-
- try {
- if (onProgress) onProgress(10);
-
- const text = await file.text();
-
- if (onProgress) onProgress(20);
-
- const blob = await createDOCXFromText(text, (progress) => {
- if (onProgress) onProgress(20 + progress * 0.8);
- });
-
- return {
- success: true,
- blob,
- duration: Date.now() - startTime,
- };
- } catch (error) {
- console.error('[DOCX Converter] Text to DOCX error:', error);
-
- return {
- success: false,
- error: error instanceof Error ? error.message : 'Failed to convert text to DOCX',
- duration: Date.now() - startTime,
- };
- }
-}
-
-/**
- * Convert Markdown to DOCX
- */
-export async function markdownToDOCX(
- file: File,
- onProgress?: ProgressCallback
-): Promise {
- const startTime = Date.now();
-
- try {
- if (onProgress) onProgress(10);
-
- const markdown = await file.text();
-
- if (onProgress) onProgress(20);
-
- const blob = await createDOCXFromMarkdown(markdown, (progress) => {
- if (onProgress) onProgress(20 + progress * 0.8);
- });
-
- return {
- success: true,
- blob,
- duration: Date.now() - startTime,
- };
- } catch (error) {
- console.error('[DOCX Converter] Markdown to DOCX error:', error);
-
- return {
- success: false,
- error: error instanceof Error ? error.message : 'Failed to convert Markdown to DOCX',
- duration: Date.now() - startTime,
- };
- }
-}
-
-/**
- * Convert HTML to DOCX
- */
-export async function htmlToDOCX(
- file: File,
- onProgress?: ProgressCallback
-): Promise {
- const startTime = Date.now();
-
- try {
- if (onProgress) onProgress(10);
-
- const html = await file.text();
-
- if (onProgress) onProgress(20);
-
- // Strip HTML tags to get plain text
- const text = html
- .replace(/