pvanand commited on
Commit
ffc414e
·
verified ·
1 Parent(s): 431645c

Upload index.html

Browse files
Files changed (1) hide show
  1. static/ui/index.html +219 -0
static/ui/index.html ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Document Converter</title>
7
+ <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
8
+ <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
9
+ <link href="https://cdn.jsdelivr.net/npm/@tailwindcss/typography/dist/typography.min.css" rel="stylesheet">
10
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
11
+ <style>
12
+ body {
13
+ font-family: 'Inter', sans-serif;
14
+ }
15
+ .drop-zone {
16
+ border: 2px dashed #cbd5e0;
17
+ transition: all 0.3s ease;
18
+ }
19
+ .drop-zone:hover, .drop-zone.dragging {
20
+ border-color: #4a5568;
21
+ background-color: #f7fafc;
22
+ }
23
+ .loading-spinner {
24
+ border: 3px solid #f3f3f3;
25
+ border-top: 3px solid #3498db;
26
+ border-radius: 50%;
27
+ width: 24px;
28
+ height: 24px;
29
+ animation: spin 1s linear infinite;
30
+ }
31
+ @keyframes spin {
32
+ 0% { transform: rotate(0deg); }
33
+ 100% { transform: rotate(360deg); }
34
+ }
35
+ </style>
36
+ </head>
37
+ <body class="bg-gray-50">
38
+ <div id="app" class="min-h-screen py-12 px-4 sm:px-6 lg:px-8">
39
+ <div class="max-w-3xl mx-auto">
40
+ <!-- Header -->
41
+ <div class="text-center mb-12">
42
+ <h1 class="text-3xl font-bold text-gray-900 mb-2">Document Converter</h1>
43
+ <p class="text-gray-600">Convert your documents to various formats quickly and easily</p>
44
+ </div>
45
+
46
+ <!-- Main Content -->
47
+ <div class="bg-white rounded-lg shadow p-6">
48
+ <!-- File Upload Zone -->
49
+ <div
50
+ class="drop-zone rounded-lg p-8 text-center cursor-pointer mb-6"
51
+ :class="{ 'dragging': isDragging }"
52
+ @dragenter.prevent="isDragging = true"
53
+ @dragleave.prevent="isDragging = false"
54
+ @dragover.prevent
55
+ @drop.prevent="handleDrop"
56
+ @click="triggerFileInput">
57
+ <input
58
+ type="file"
59
+ ref="fileInput"
60
+ @change="handleFileSelect"
61
+ class="hidden">
62
+ <div v-if="!selectedFile">
63
+ <svg class="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
64
+ <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"/>
65
+ </svg>
66
+ <p class="mt-2 text-gray-600">Drag and drop your file here or click to browse</p>
67
+ </div>
68
+ <div v-else class="text-gray-700">
69
+ <p class="font-medium">Selected file:</p>
70
+ <p class="text-sm">{{ selectedFile.name }}</p>
71
+ </div>
72
+ </div>
73
+
74
+ <!-- Conversion Options -->
75
+ <div class="mb-6">
76
+ <label class="block text-sm font-medium text-gray-700 mb-2">Output Format</label>
77
+ <select
78
+ v-model="outputFormat"
79
+ 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">
80
+ <option value="pdf">PDF</option>
81
+ <option value="docx">DOCX</option>
82
+ <option value="xlsx">XLSX</option>
83
+ <option value="png">PNG</option>
84
+ <option value="jpg">JPG</option>
85
+ <option value="csv">CSV</option>
86
+ </select>
87
+ </div>
88
+
89
+ <!-- Filter Options -->
90
+ <div class="mb-6" v-if="showFilterOptions">
91
+ <label class="block text-sm font-medium text-gray-700 mb-2">Filter Options</label>
92
+ <input
93
+ type="text"
94
+ v-model="filterOptions"
95
+ placeholder="e.g., PixelWidth=640,PixelHeight=480"
96
+ 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">
97
+ <p class="mt-1 text-sm text-gray-500">{{ filterOptionsHint }}</p>
98
+ </div>
99
+
100
+ <!-- Convert Button -->
101
+ <button
102
+ @click="convertFile"
103
+ :disabled="!selectedFile || converting"
104
+ 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">
105
+ <span v-if="!converting">Convert Document</span>
106
+ <div v-else class="loading-spinner"></div>
107
+ </button>
108
+
109
+ <!-- Status Messages -->
110
+ <div v-if="status" :class="statusClass" class="mt-4 p-4 rounded-md">
111
+ {{ status }}
112
+ </div>
113
+ </div>
114
+ </div>
115
+ </div>
116
+
117
+ <script>
118
+ const { createApp } = Vue
119
+ createApp({
120
+ data() {
121
+ return {
122
+ selectedFile: null,
123
+ outputFormat: 'pdf',
124
+ filterOptions: '',
125
+ isDragging: false,
126
+ converting: false,
127
+ status: '',
128
+ statusType: 'info'
129
+ }
130
+ },
131
+ computed: {
132
+ showFilterOptions() {
133
+ return ['png', 'jpg', 'csv'].includes(this.outputFormat)
134
+ },
135
+ filterOptionsHint() {
136
+ if (this.outputFormat === 'png' || this.outputFormat === 'jpg') {
137
+ return 'Example: PixelWidth=640,PixelHeight=480'
138
+ } else if (this.outputFormat === 'csv') {
139
+ return 'Example: 59,34,76,1 for CSV specific options'
140
+ }
141
+ return ''
142
+ },
143
+ statusClass() {
144
+ const baseClasses = 'text-sm p-4 rounded-md'
145
+ switch (this.statusType) {
146
+ case 'success':
147
+ return `${baseClasses} bg-green-50 text-green-700`
148
+ case 'error':
149
+ return `${baseClasses} bg-red-50 text-red-700`
150
+ default:
151
+ return `${baseClasses} bg-blue-50 text-blue-700`
152
+ }
153
+ }
154
+ },
155
+ methods: {
156
+ triggerFileInput() {
157
+ this.$refs.fileInput.click()
158
+ },
159
+ handleFileSelect(event) {
160
+ const file = event.target.files[0]
161
+ if (file) {
162
+ this.selectedFile = file
163
+ this.status = ''
164
+ }
165
+ },
166
+ handleDrop(event) {
167
+ this.isDragging = false
168
+ const file = event.dataTransfer.files[0]
169
+ if (file) {
170
+ this.selectedFile = file
171
+ this.status = ''
172
+ }
173
+ },
174
+ async convertFile() {
175
+ if (!this.selectedFile) return
176
+ this.converting = true
177
+ this.status = 'Converting document...'
178
+ this.statusType = 'info'
179
+ const formData = new FormData()
180
+ formData.append('file', this.selectedFile)
181
+ try {
182
+ const queryParams = new URLSearchParams({
183
+ output_format: this.outputFormat
184
+ })
185
+
186
+ if (this.filterOptions) {
187
+ queryParams.append('filter_options', this.filterOptions)
188
+ }
189
+ const response = await fetch(`/convert/?${queryParams}`, {
190
+ method: 'POST',
191
+ body: formData
192
+ })
193
+ if (!response.ok) {
194
+ throw new Error(`Conversion failed: ${response.statusText}`)
195
+ }
196
+ // Handle successful conversion
197
+ const blob = await response.blob()
198
+ const url = window.URL.createObjectURL(blob)
199
+ const a = document.createElement('a')
200
+ a.href = url
201
+ a.download = `converted.${this.outputFormat}`
202
+ document.body.appendChild(a)
203
+ a.click()
204
+ window.URL.revokeObjectURL(url)
205
+ document.body.removeChild(a)
206
+ this.status = 'Document converted successfully!'
207
+ this.statusType = 'success'
208
+ } catch (error) {
209
+ this.status = `Error: ${error.message}`
210
+ this.statusType = 'error'
211
+ } finally {
212
+ this.converting = false
213
+ }
214
+ }
215
+ }
216
+ }).mount('#app')
217
+ </script>
218
+ </body>
219
+ </html>