unoconvert / static /ui /index.html
pvanand's picture
Upload index.html
ffc414e verified
raw
history blame
10.1 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document Converter</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@tailwindcss/typography/dist/typography.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Inter', sans-serif;
}
.drop-zone {
border: 2px dashed #cbd5e0;
transition: all 0.3s ease;
}
.drop-zone:hover, .drop-zone.dragging {
border-color: #4a5568;
background-color: #f7fafc;
}
.loading-spinner {
border: 3px solid #f3f3f3;
border-top: 3px solid #3498db;
border-radius: 50%;
width: 24px;
height: 24px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body class="bg-gray-50">
<div id="app" class="min-h-screen py-12 px-4 sm:px-6 lg:px-8">
<div class="max-w-3xl mx-auto">
<!-- Header -->
<div class="text-center mb-12">
<h1 class="text-3xl font-bold text-gray-900 mb-2">Document Converter</h1>
<p class="text-gray-600">Convert your documents to various formats quickly and easily</p>
</div>
<!-- Main Content -->
<div class="bg-white rounded-lg shadow p-6">
<!-- File Upload Zone -->
<div
class="drop-zone rounded-lg p-8 text-center cursor-pointer mb-6"
:class="{ 'dragging': isDragging }"
@dragenter.prevent="isDragging = true"
@dragleave.prevent="isDragging = false"
@dragover.prevent
@drop.prevent="handleDrop"
@click="triggerFileInput">
<input
type="file"
ref="fileInput"
@change="handleFileSelect"
class="hidden">
<div v-if="!selectedFile">
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"/>
</svg>
<p class="mt-2 text-gray-600">Drag and drop your file here or click to browse</p>
</div>
<div v-else class="text-gray-700">
<p class="font-medium">Selected file:</p>
<p class="text-sm">{{ selectedFile.name }}</p>
</div>
</div>
<!-- Conversion Options -->
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2">Output Format</label>
<select
v-model="outputFormat"
class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
<option value="pdf">PDF</option>
<option value="docx">DOCX</option>
<option value="xlsx">XLSX</option>
<option value="png">PNG</option>
<option value="jpg">JPG</option>
<option value="csv">CSV</option>
</select>
</div>
<!-- Filter Options -->
<div class="mb-6" v-if="showFilterOptions">
<label class="block text-sm font-medium text-gray-700 mb-2">Filter Options</label>
<input
type="text"
v-model="filterOptions"
placeholder="e.g., PixelWidth=640,PixelHeight=480"
class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
<p class="mt-1 text-sm text-gray-500">{{ filterOptionsHint }}</p>
</div>
<!-- Convert Button -->
<button
@click="convertFile"
:disabled="!selectedFile || converting"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50 disabled:cursor-not-allowed">
<span v-if="!converting">Convert Document</span>
<div v-else class="loading-spinner"></div>
</button>
<!-- Status Messages -->
<div v-if="status" :class="statusClass" class="mt-4 p-4 rounded-md">
{{ status }}
</div>
</div>
</div>
</div>
<script>
const { createApp } = Vue
createApp({
data() {
return {
selectedFile: null,
outputFormat: 'pdf',
filterOptions: '',
isDragging: false,
converting: false,
status: '',
statusType: 'info'
}
},
computed: {
showFilterOptions() {
return ['png', 'jpg', 'csv'].includes(this.outputFormat)
},
filterOptionsHint() {
if (this.outputFormat === 'png' || this.outputFormat === 'jpg') {
return 'Example: PixelWidth=640,PixelHeight=480'
} else if (this.outputFormat === 'csv') {
return 'Example: 59,34,76,1 for CSV specific options'
}
return ''
},
statusClass() {
const baseClasses = 'text-sm p-4 rounded-md'
switch (this.statusType) {
case 'success':
return `${baseClasses} bg-green-50 text-green-700`
case 'error':
return `${baseClasses} bg-red-50 text-red-700`
default:
return `${baseClasses} bg-blue-50 text-blue-700`
}
}
},
methods: {
triggerFileInput() {
this.$refs.fileInput.click()
},
handleFileSelect(event) {
const file = event.target.files[0]
if (file) {
this.selectedFile = file
this.status = ''
}
},
handleDrop(event) {
this.isDragging = false
const file = event.dataTransfer.files[0]
if (file) {
this.selectedFile = file
this.status = ''
}
},
async convertFile() {
if (!this.selectedFile) return
this.converting = true
this.status = 'Converting document...'
this.statusType = 'info'
const formData = new FormData()
formData.append('file', this.selectedFile)
try {
const queryParams = new URLSearchParams({
output_format: this.outputFormat
})
if (this.filterOptions) {
queryParams.append('filter_options', this.filterOptions)
}
const response = await fetch(`/convert/?${queryParams}`, {
method: 'POST',
body: formData
})
if (!response.ok) {
throw new Error(`Conversion failed: ${response.statusText}`)
}
// Handle successful conversion
const blob = await response.blob()
const url = window.URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `converted.${this.outputFormat}`
document.body.appendChild(a)
a.click()
window.URL.revokeObjectURL(url)
document.body.removeChild(a)
this.status = 'Document converted successfully!'
this.statusType = 'success'
} catch (error) {
this.status = `Error: ${error.message}`
this.statusType = 'error'
} finally {
this.converting = false
}
}
}
}).mount('#app')
</script>
</body>
</html>