pvanand commited on
Commit
0dfafe3
·
verified ·
1 Parent(s): 708499f

Rename static/ui to static/ui/index.html

Browse files
Files changed (2) hide show
  1. static/ui +0 -1
  2. static/ui/index.html +227 -0
static/ui DELETED
@@ -1 +0,0 @@
1
- hi
 
 
static/ui/index.html ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
120
+ createApp({
121
+ data() {
122
+ return {
123
+ selectedFile: null,
124
+ outputFormat: 'pdf',
125
+ filterOptions: '',
126
+ isDragging: false,
127
+ converting: false,
128
+ status: '',
129
+ statusType: 'info'
130
+ }
131
+ },
132
+ computed: {
133
+ showFilterOptions() {
134
+ return ['png', 'jpg', 'csv'].includes(this.outputFormat)
135
+ },
136
+ filterOptionsHint() {
137
+ if (this.outputFormat === 'png' || this.outputFormat === 'jpg') {
138
+ return 'Example: PixelWidth=640,PixelHeight=480'
139
+ } else if (this.outputFormat === 'csv') {
140
+ return 'Example: 59,34,76,1 for CSV specific options'
141
+ }
142
+ return ''
143
+ },
144
+ statusClass() {
145
+ const baseClasses = 'text-sm p-4 rounded-md'
146
+ switch (this.statusType) {
147
+ case 'success':
148
+ return `${baseClasses} bg-green-50 text-green-700`
149
+ case 'error':
150
+ return `${baseClasses} bg-red-50 text-red-700`
151
+ default:
152
+ return `${baseClasses} bg-blue-50 text-blue-700`
153
+ }
154
+ }
155
+ },
156
+ methods: {
157
+ triggerFileInput() {
158
+ this.$refs.fileInput.click()
159
+ },
160
+ handleFileSelect(event) {
161
+ const file = event.target.files[0]
162
+ if (file) {
163
+ this.selectedFile = file
164
+ this.status = ''
165
+ }
166
+ },
167
+ handleDrop(event) {
168
+ this.isDragging = false
169
+ const file = event.dataTransfer.files[0]
170
+ if (file) {
171
+ this.selectedFile = file
172
+ this.status = ''
173
+ }
174
+ },
175
+ async convertFile() {
176
+ if (!this.selectedFile) return
177
+
178
+ this.converting = true
179
+ this.status = 'Converting document...'
180
+ this.statusType = 'info'
181
+
182
+ const formData = new FormData()
183
+ formData.append('file', this.selectedFile)
184
+
185
+ try {
186
+ const queryParams = new URLSearchParams({
187
+ output_format: this.outputFormat
188
+ })
189
+
190
+ if (this.filterOptions) {
191
+ queryParams.append('filter_options', this.filterOptions)
192
+ }
193
+
194
+ const response = await fetch(`/convert/?${queryParams}`, {
195
+ method: 'POST',
196
+ body: formData
197
+ })
198
+
199
+ if (!response.ok) {
200
+ throw new Error(`Conversion failed: ${response.statusText}`)
201
+ }
202
+
203
+ // Handle successful conversion
204
+ const blob = await response.blob()
205
+ const url = window.URL.createObjectURL(blob)
206
+ const a = document.createElement('a')
207
+ a.href = url
208
+ a.download = `converted.${this.outputFormat}`
209
+ document.body.appendChild(a)
210
+ a.click()
211
+ window.URL.revokeObjectURL(url)
212
+ document.body.removeChild(a)
213
+
214
+ this.status = 'Document converted successfully!'
215
+ this.statusType = 'success'
216
+ } catch (error) {
217
+ this.status = `Error: ${error.message}`
218
+ this.statusType = 'error'
219
+ } finally {
220
+ this.converting = false
221
+ }
222
+ }
223
+ }
224
+ }).mount('#app')
225
+ </script>
226
+ </body>
227
+ </html>