## 1. UI/UX Enhancements

#21
Files changed (3) hide show
  1. index.html +245 -0
  2. script.js +440 -0
  3. styles.css +168 -0
index.html ADDED
@@ -0,0 +1,245 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Virtual Data Analyst</title>
7
+ <!-- Tailwind CSS -->
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <!-- Google Fonts -->
10
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
11
+ <!-- Font Awesome -->
12
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
13
+ <!-- Custom Styles -->
14
+ <link rel="stylesheet" href="styles.css">
15
+ <script>
16
+ tailwind.config = {
17
+ theme: {
18
+ extend: {
19
+ fontFamily: {
20
+ 'sans': ['Inter', 'sans-serif'],
21
+ },
22
+ colors: {
23
+ primary: '#3B82F6',
24
+ secondary: '#6B7280',
25
+ },
26
+ }
27
+ }
28
+ }
29
+ </script>
30
+ </head>
31
+ <body class="bg-gray-50 font-sans">
32
+ <div class="min-h-screen p-6">
33
+ <!-- Header -->
34
+ <header class="max-w-4xl mx-auto mb-12 text-center">
35
+ <h1 class="text-4xl font-bold text-gray-900 mb-4">Virtual Data Analyst</h1>
36
+ <p class="text-lg text-gray-600 mb-6">
37
+ A powerful tool for data analysis, visualizations, and insights
38
+ </p>
39
+ <div class="bg-blue-50 border border-blue-200 rounded-lg p-4 max-w-2xl mx-auto">
40
+ <h2 class="font-semibold text-blue-800 mb-2">
41
+ <i class="fas fa-info-circle mr-2"></i>Supported Files
42
+ </h2>
43
+ <div class="flex flex-wrap justify-center gap-3 text-blue-700">
44
+ <span class="tooltip">
45
+ <i class="fas fa-file-csv mr-1"></i>CSV
46
+ <span class="tooltip-text">Comma-separated values</span>
47
+ </span>
48
+ <span class="tooltip">
49
+ <i class="fas fa-file-alt mr-1"></i>TSV
50
+ <span class="tooltip-text">Tab-separated values</span>
51
+ </span>
52
+ <span class="tooltip">
53
+ <i class="fas fa-file-alt mr-1"></i>TXT
54
+ <span class="tooltip-text">Text files</span>
55
+ </span>
56
+ <span class="tooltip">
57
+ <i class="fas fa-file-excel mr-1"></i>XLS/XLSX
58
+ <span class="tooltip-text">Excel spreadsheets</span>
59
+ </span>
60
+ <span class="tooltip">
61
+ <i class="fas fa-file-code mr-1"></i>XML
62
+ <span class="tooltip-text">XML documents</span>
63
+ </span>
64
+ <span class="tooltip">
65
+ <i class="fas fa-file-code mr-1"></i>JSON
66
+ <span class="tooltip-text">JSON data files</span>
67
+ </span>
68
+ </div>
69
+ </div>
70
+ </header>
71
+
72
+ <!-- Main Content -->
73
+ <main class="max-w-4xl mx-auto">
74
+ <!-- File Upload Section -->
75
+ <div class="bg-white rounded-xl shadow-lg p-8 mb-8">
76
+ <div class="drop-zone border-2 border-dashed border-gray-300 rounded-lg p-12 text-center hover:border-primary cursor-pointer bg-gray-50 hover:bg-blue-50 transition-colors duration-300">
77
+ <input type="file" id="fileInput" class="hidden" accept=".csv,.tsv,.txt,.xls,.xlsx,.xml,.json">
78
+
79
+ <!-- Upload Icon & Success Checkmark -->
80
+ <div class="relative inline-block">
81
+ <i class="fas fa-cloud-upload-alt text-5xl text-gray-400 mb-4 upload-icon"></i>
82
+ <i class="fas fa-check-circle text-5xl success-checkmark absolute top-0 left-0"></i>
83
+ </div>
84
+
85
+ <!-- Loading Spinner -->
86
+ <div class="loading-spinner mx-auto mb-4"></div>
87
+
88
+ <h3 class="text-xl font-semibold text-gray-700 mb-2">Drop your data file here</h3>
89
+ <p class="text-gray-500 mb-4">or</p>
90
+ <button onclick="document.getElementById('fileInput').click()" class="bg-primary text-white px-6 py-3 rounded-lg hover:bg-blue-600 transition-colors duration-300">
91
+ <i class="fas fa-folder-open mr-2"></i>Browse Files
92
+ </button>
93
+
94
+ <!-- Progress Bar -->
95
+ <div class="progress-bar mt-4">
96
+ <div class="progress-bar-fill"></div>
97
+ </div>
98
+
99
+ <!-- File Info -->
100
+ <div id="fileInfo" class="hidden mt-4 p-4 bg-gray-100 rounded-lg">
101
+ <div class="flex items-center justify-center">
102
+ <i class="file-type-icon fas"></i>
103
+ <span class="file-name font-medium"></span>
104
+ </div>
105
+ <div class="text-sm text-gray-500 mt-2">
106
+ <span class="file-size"></span>
107
+ </div>
108
+ </div>
109
+
110
+ <p class="text-sm text-gray-500 mt-4">Maximum file size: 100MB</p>
111
+ </div>
112
+ </div>
113
+
114
+ <!-- Sample Data Section -->
115
+ <div class="bg-white rounded-xl shadow-lg p-8">
116
+ <h2 class="text-2xl font-semibold text-gray-800 mb-6">
117
+ <i class="fas fa-flask mr-2"></i>Try Sample Datasets
118
+ </h2>
119
+ <div class="grid md:grid-cols-2 gap-4">
120
+ <!-- Marketing Campaign Sample -->
121
+ <button class="sample-btn bg-gradient-to-r from-purple-500 to-indigo-600 text-white p-6 rounded-lg text-left hover:shadow-lg">
122
+ <div class="flex items-center mb-3">
123
+ <i class="fas fa-bullhorn text-2xl mr-3"></i>
124
+ <div>
125
+ <h3 class="text-lg font-semibold">Marketing Campaign Data</h3>
126
+ <p class="text-sm opacity-90">10,000 records</p>
127
+ </div>
128
+ </div>
129
+ <p class="text-sm opacity-90">Analyze customer responses to marketing campaigns and identify key success factors</p>
130
+ <div class="mt-4 text-xs opacity-75">
131
+ <i class="fas fa-table mr-1"></i> CSV format
132
+ </div>
133
+ </button>
134
+
135
+ <!-- Retail Data Sample -->
136
+ <button class="sample-btn bg-gradient-to-r from-green-500 to-teal-600 text-white p-6 rounded-lg text-left hover:shadow-lg">
137
+ <div class="flex items-center mb-3">
138
+ <i class="fas fa-shopping-cart text-2xl mr-3"></i>
139
+ <div>
140
+ <h3 class="text-lg font-semibold">Online Retail Data</h3>
141
+ <p class="text-sm opacity-90">50,000 records</p>
142
+ </div>
143
+ </div>
144
+ <p class="text-sm opacity-90">Explore sales patterns, customer behavior, and product performance</p>
145
+ <div class="mt-4 text-xs opacity-75">
146
+ <i class="fas fa-file-excel mr-1"></i> XLSX format
147
+ </div>
148
+ </button>
149
+ </div>
150
+ </div>
151
+
152
+ <!-- Features Preview -->
153
+ <div class="mt-12 grid md:grid-cols-3 gap-6">
154
+ <div class="feature-card bg-white p-6 rounded-lg shadow-md">
155
+ <i class="feature-icon fas fa-chart-line text-primary text-2xl mb-4"></i>
156
+ <h3 class="font-semibold text-gray-800 mb-2">Advanced Analytics</h3>
157
+ <p class="text-gray-600 text-sm">Run SQL queries, perform regressions, and analyze results with ease</p>
158
+ </div>
159
+ <div class="feature-card bg-white p-6 rounded-lg shadow-md">
160
+ <i class="feature-icon fas fa-chart-pie text-primary text-2xl mb-4"></i>
161
+ <h3 class="font-semibold text-gray-800 mb-2">Rich Visualizations</h3>
162
+ <p class="text-gray-600 text-sm">Create scatter plots, line charts, pie charts, and more</p>
163
+ </div>
164
+ <div class="feature-card bg-white p-6 rounded-lg shadow-md">
165
+ <i class="feature-icon fas fa-magic text-primary text-2xl mb-4"></i>
166
+ <h3 class="font-semibold text-gray-800 mb-2">Automated Insights</h3>
167
+ <p class="text-gray-600 text-sm">Get instant insights and recommendations for your data</p>
168
+ </div>
169
+ </div>
170
+ </main>
171
+
172
+ <!-- Footer -->
173
+ <footer class="max-w-4xl mx-auto mt-12 text-center text-gray-500 text-sm">
174
+ <p>This application is under active development. For bugs or feedback, please open a discussion in the community tab.</p>
175
+ </footer>
176
+ </div>
177
+
178
+ <!-- Results Section -->
179
+ <div id="results" class="max-w-4xl mx-auto mt-12 hidden">
180
+ <div class="bg-white rounded-xl shadow-lg p-8">
181
+ <div class="flex items-center justify-between mb-6">
182
+ <h2 class="text-2xl font-semibold text-gray-800">
183
+ <i class="fas fa-chart-bar mr-2"></i>Analysis Results
184
+ </h2>
185
+ <button onclick="closeResults()" class="text-gray-500 hover:text-gray-700">
186
+ <i class="fas fa-times"></i>
187
+ </button>
188
+ </div>
189
+
190
+ <!-- Loading State -->
191
+ <div id="resultsLoading" class="text-center py-12">
192
+ <div class="loading-spinner mx-auto mb-4"></div>
193
+ <p class="text-gray-600">Analyzing your data...</p>
194
+ </div>
195
+
196
+ <!-- Error State -->
197
+ <div id="resultsError" class="hidden">
198
+ <div class="bg-red-50 border border-red-200 rounded-lg p-4 text-red-700">
199
+ <i class="fas fa-exclamation-circle mr-2"></i>
200
+ <span id="errorMessage">An error occurred</span>
201
+ </div>
202
+ </div>
203
+
204
+ <!-- Results Content -->
205
+ <div id="resultsContent" class="hidden">
206
+ <!-- Basic Statistics -->
207
+ <div class="mb-8">
208
+ <h3 class="text-lg font-semibold text-gray-700 mb-4">Basic Statistics</h3>
209
+ <div id="basicStats" class="grid grid-cols-2 md:grid-cols-4 gap-4">
210
+ <!-- Stats will be inserted here -->
211
+ </div>
212
+ </div>
213
+
214
+ <!-- Data Preview -->
215
+ <div class="mb-8">
216
+ <h3 class="text-lg font-semibold text-gray-700 mb-4">Data Preview</h3>
217
+ <div class="overflow-x-auto">
218
+ <table id="dataPreview" class="min-w-full divide-y divide-gray-200">
219
+ <!-- Table content will be inserted here -->
220
+ </table>
221
+ </div>
222
+ </div>
223
+
224
+ <!-- Visualizations -->
225
+ <div class="mb-8">
226
+ <h3 class="text-lg font-semibold text-gray-700 mb-4">Visualizations</h3>
227
+ <div id="visualizations" class="grid grid-cols-1 md:grid-cols-2 gap-6">
228
+ <!-- Visualization charts will be inserted here -->
229
+ </div>
230
+ </div>
231
+
232
+ <!-- Insights -->
233
+ <div>
234
+ <h3 class="text-lg font-semibold text-gray-700 mb-4">Key Insights</h3>
235
+ <ul id="insights" class="space-y-3">
236
+ <!-- Insights will be inserted here -->
237
+ </ul>
238
+ </div>
239
+ </div>
240
+ </div>
241
+ </div>
242
+
243
+ <script src="script.js"></script>
244
+ </body>
245
+ </html>
script.js ADDED
@@ -0,0 +1,440 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // API Configuration
2
+ const API_URL = 'https://nolanzandi-virtual-data-analyst.hf.space';
3
+ const PREDICT_ENDPOINT = `${API_URL}/api/predict`;
4
+ const SAMPLE_ENDPOINT = `${API_URL}/api/sample`;
5
+
6
+ // File Upload and API Integration
7
+ async function handleFileUpload(file) {
8
+ try {
9
+ // Show loading state
10
+ document.querySelector('.upload-icon').style.display = 'none';
11
+ document.querySelector('.loading-spinner').style.display = 'block';
12
+ document.querySelector('.progress-bar').style.display = 'block';
13
+
14
+ // Create FormData
15
+ const formData = new FormData();
16
+ formData.append('file', file);
17
+
18
+ // Update file info
19
+ updateFileInfo(file);
20
+
21
+ // Simulate progress while actually uploading
22
+ const progressInterval = simulateProgress();
23
+
24
+ // Make API request
25
+ const response = await fetch(API_URL, {
26
+ method: 'POST',
27
+ body: formData
28
+ });
29
+
30
+ if (!response.ok) {
31
+ throw new Error('API request failed');
32
+ }
33
+
34
+ const data = await response.json();
35
+
36
+ // Clear progress simulation
37
+ clearInterval(progressInterval);
38
+
39
+ // Show success state
40
+ showSuccessState();
41
+
42
+ // Handle API response
43
+ handleApiResponse(data);
44
+
45
+ } catch (error) {
46
+ console.error('Error:', error);
47
+ showErrorState(error.message);
48
+ }
49
+ }
50
+
51
+ function updateFileInfo(file) {
52
+ const fileInfo = document.getElementById('fileInfo');
53
+ const fileName = fileInfo.querySelector('.file-name');
54
+ const fileSize = fileInfo.querySelector('.file-size');
55
+ const fileIcon = fileInfo.querySelector('.file-type-icon');
56
+
57
+ const fileType = file.name.split('.').pop().toLowerCase();
58
+ const iconClass = getFileTypeIcon(fileType);
59
+
60
+ fileIcon.className = `file-type-icon fas ${iconClass}`;
61
+ fileName.textContent = file.name;
62
+ fileSize.textContent = formatFileSize(file.size);
63
+ fileInfo.classList.remove('hidden');
64
+ }
65
+
66
+ function simulateProgress() {
67
+ const progressBar = document.querySelector('.progress-bar-fill');
68
+ let progress = 0;
69
+
70
+ return setInterval(() => {
71
+ if (progress < 90) { // Only go up to 90% until we get actual completion
72
+ progress += 5;
73
+ progressBar.style.width = `${progress}%`;
74
+ }
75
+ }, 100);
76
+ }
77
+
78
+ function showSuccessState() {
79
+ document.querySelector('.loading-spinner').style.display = 'none';
80
+ document.querySelector('.success-checkmark').style.display = 'block';
81
+ document.querySelector('.progress-bar-fill').style.width = '100%';
82
+
83
+ setTimeout(() => {
84
+ resetUploadState();
85
+ }, 2000);
86
+ }
87
+
88
+ function showErrorState(message) {
89
+ // Reset upload UI
90
+ resetUploadState();
91
+
92
+ // Show error message
93
+ const errorDiv = document.createElement('div');
94
+ errorDiv.className = 'text-red-500 mt-4';
95
+ errorDiv.innerHTML = `<i class="fas fa-exclamation-circle mr-2"></i>${message}`;
96
+ document.querySelector('.drop-zone').appendChild(errorDiv);
97
+
98
+ setTimeout(() => {
99
+ errorDiv.remove();
100
+ }, 5000);
101
+ }
102
+
103
+ function resetUploadState() {
104
+ document.querySelector('.success-checkmark').style.display = 'none';
105
+ document.querySelector('.upload-icon').style.display = 'block';
106
+ document.querySelector('.progress-bar').style.display = 'none';
107
+ document.querySelector('.progress-bar-fill').style.width = '0%';
108
+ document.getElementById('fileInfo').classList.add('hidden');
109
+ }
110
+
111
+ function handleSampleDataClick(datasetName) {
112
+ // Show loading state in results section
113
+ const resultsSection = document.getElementById('results');
114
+ const resultsLoading = document.getElementById('resultsLoading');
115
+ const resultsContent = document.getElementById('resultsContent');
116
+ const resultsError = document.getElementById('resultsError');
117
+
118
+ resultsSection.classList.remove('hidden');
119
+ resultsLoading.classList.remove('hidden');
120
+ resultsContent.classList.add('hidden');
121
+ resultsError.classList.add('hidden');
122
+
123
+ // Simulate API delay
124
+ setTimeout(() => {
125
+ try {
126
+ // Mock data based on dataset type
127
+ const mockData = datasetName === 'marketing_campaign' ? {
128
+ statistics: {
129
+ rows: 10000,
130
+ columns: 15,
131
+ missing_values: 120,
132
+ data_types: ['numeric', 'categorical', 'datetime']
133
+ },
134
+ preview: {
135
+ columns: ['Campaign ID', 'Customer ID', 'Response', 'Channel'],
136
+ data: [
137
+ ['CAM001', 'C001', 'Converted', 'Email'],
138
+ ['CAM001', 'C002', 'No Response', 'SMS'],
139
+ ['CAM002', 'C003', 'Converted', 'Social Media']
140
+ ]
141
+ },
142
+ visualizations: [
143
+ {
144
+ title: 'Response Rate by Channel',
145
+ description: 'Conversion rates across different marketing channels',
146
+ image_url: 'https://via.placeholder.com/400x300'
147
+ },
148
+ {
149
+ title: 'Campaign Performance',
150
+ description: 'Success metrics for each campaign',
151
+ image_url: 'https://via.placeholder.com/400x300'
152
+ }
153
+ ],
154
+ insights: [
155
+ {
156
+ title: 'Best Performing Channel',
157
+ description: 'Email campaigns show highest conversion rate at 28%'
158
+ },
159
+ {
160
+ title: 'Optimal Send Time',
161
+ description: 'Campaigns sent between 2 PM - 4 PM have better engagement'
162
+ }
163
+ ]
164
+ } : {
165
+ statistics: {
166
+ rows: 50000,
167
+ columns: 12,
168
+ missing_values: 85,
169
+ data_types: ['numeric', 'categorical', 'datetime']
170
+ },
171
+ preview: {
172
+ columns: ['Order ID', 'Product', 'Quantity', 'Price'],
173
+ data: [
174
+ ['ORD001', 'Laptop', '1', '$999.99'],
175
+ ['ORD002', 'Mouse', '2', '$29.99'],
176
+ ['ORD003', 'Monitor', '1', '$299.99']
177
+ ]
178
+ },
179
+ visualizations: [
180
+ {
181
+ title: 'Sales by Category',
182
+ description: 'Distribution of sales across product categories',
183
+ image_url: 'https://via.placeholder.com/400x300'
184
+ },
185
+ {
186
+ title: 'Monthly Revenue',
187
+ description: 'Revenue trends over the past 12 months',
188
+ image_url: 'https://via.placeholder.com/400x300'
189
+ }
190
+ ],
191
+ insights: [
192
+ {
193
+ title: 'Top Products',
194
+ description: 'Electronics category generates 45% of total revenue'
195
+ },
196
+ {
197
+ title: 'Customer Behavior',
198
+ description: 'Average order value increased by 15% in Q4'
199
+ }
200
+ ]
201
+ };
202
+
203
+ handleApiResponse(mockData);
204
+ } catch (error) {
205
+ console.error('Error:', error);
206
+ showErrorState('Failed to process sample dataset');
207
+ }
208
+ }, 1000); // 1 second delay to show loading state
209
+ }
210
+
211
+ function handleApiResponse(data) {
212
+ const resultsSection = document.getElementById('results');
213
+ const resultsLoading = document.getElementById('resultsLoading');
214
+ const resultsContent = document.getElementById('resultsContent');
215
+ const resultsError = document.getElementById('resultsError');
216
+
217
+ // Show results section
218
+ resultsSection.classList.remove('hidden');
219
+ resultsLoading.classList.add('hidden');
220
+ resultsError.classList.add('hidden');
221
+ resultsContent.classList.remove('hidden');
222
+
223
+ // Update Basic Statistics
224
+ updateBasicStats(data.statistics);
225
+
226
+ // Update Data Preview
227
+ updateDataPreview(data.preview);
228
+
229
+ // Update Visualizations
230
+ updateVisualizations(data.visualizations);
231
+
232
+ // Update Insights
233
+ updateInsights(data.insights);
234
+ }
235
+
236
+ function updateBasicStats(statistics) {
237
+ const statsContainer = document.getElementById('basicStats');
238
+ statsContainer.innerHTML = '';
239
+
240
+ const stats = [
241
+ { label: 'Rows', value: statistics.rows, icon: 'fa-list' },
242
+ { label: 'Columns', value: statistics.columns, icon: 'fa-columns' },
243
+ { label: 'Missing Values', value: statistics.missing_values, icon: 'fa-exclamation-triangle' },
244
+ { label: 'Data Types', value: statistics.data_types.length, icon: 'fa-code' }
245
+ ];
246
+
247
+ stats.forEach(stat => {
248
+ const statDiv = document.createElement('div');
249
+ statDiv.className = 'bg-gray-50 rounded-lg p-4';
250
+ statDiv.innerHTML = `
251
+ <div class="flex items-center">
252
+ <i class="fas ${stat.icon} text-primary text-xl mr-3"></i>
253
+ <div>
254
+ <div class="text-sm text-gray-500">${stat.label}</div>
255
+ <div class="text-lg font-semibold">${stat.value}</div>
256
+ </div>
257
+ </div>
258
+ `;
259
+ statsContainer.appendChild(statDiv);
260
+ });
261
+ }
262
+
263
+ function updateDataPreview(preview) {
264
+ const table = document.getElementById('dataPreview');
265
+ table.innerHTML = '';
266
+
267
+ // Add header
268
+ const thead = document.createElement('thead');
269
+ thead.className = 'bg-gray-50';
270
+ const headerRow = document.createElement('tr');
271
+ preview.columns.forEach(column => {
272
+ const th = document.createElement('th');
273
+ th.className = 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider';
274
+ th.textContent = column;
275
+ headerRow.appendChild(th);
276
+ });
277
+ thead.appendChild(headerRow);
278
+ table.appendChild(thead);
279
+
280
+ // Add body
281
+ const tbody = document.createElement('tbody');
282
+ tbody.className = 'bg-white divide-y divide-gray-200';
283
+ preview.data.forEach(row => {
284
+ const tr = document.createElement('tr');
285
+ row.forEach(cell => {
286
+ const td = document.createElement('td');
287
+ td.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500';
288
+ td.textContent = cell;
289
+ tr.appendChild(td);
290
+ });
291
+ tbody.appendChild(tr);
292
+ });
293
+ table.appendChild(tbody);
294
+ }
295
+
296
+ function updateVisualizations(visualizations) {
297
+ const container = document.getElementById('visualizations');
298
+ container.innerHTML = '';
299
+
300
+ visualizations.forEach(viz => {
301
+ const vizDiv = document.createElement('div');
302
+ vizDiv.className = 'bg-white rounded-lg p-4 shadow';
303
+ vizDiv.innerHTML = `
304
+ <h4 class="text-lg font-medium text-gray-800 mb-4">${viz.title}</h4>
305
+ <div class="aspect-w-16 aspect-h-9">
306
+ <img src="${viz.image_url}" alt="${viz.title}" class="rounded-lg">
307
+ </div>
308
+ <p class="mt-2 text-sm text-gray-600">${viz.description}</p>
309
+ `;
310
+ container.appendChild(vizDiv);
311
+ });
312
+ }
313
+
314
+ function updateInsights(insights) {
315
+ const insightsList = document.getElementById('insights');
316
+ insightsList.innerHTML = '';
317
+
318
+ insights.forEach(insight => {
319
+ const li = document.createElement('li');
320
+ li.className = 'bg-blue-50 rounded-lg p-4';
321
+ li.innerHTML = `
322
+ <div class="flex items-start">
323
+ <i class="fas fa-lightbulb text-yellow-500 mt-1 mr-3"></i>
324
+ <div>
325
+ <div class="font-medium text-blue-900">${insight.title}</div>
326
+ <p class="mt-1 text-sm text-blue-700">${insight.description}</p>
327
+ </div>
328
+ </div>
329
+ `;
330
+ insightsList.appendChild(li);
331
+ });
332
+ }
333
+
334
+ function closeResults() {
335
+ document.getElementById('results').classList.add('hidden');
336
+ }
337
+
338
+ function showErrorState(message) {
339
+ const resultsSection = document.getElementById('results');
340
+ const resultsLoading = document.getElementById('resultsLoading');
341
+ const resultsContent = document.getElementById('resultsContent');
342
+ const resultsError = document.getElementById('resultsError');
343
+ const errorMessage = document.getElementById('errorMessage');
344
+
345
+ resultsSection.classList.remove('hidden');
346
+ resultsLoading.classList.add('hidden');
347
+ resultsContent.classList.add('hidden');
348
+ resultsError.classList.remove('hidden');
349
+ errorMessage.textContent = message;
350
+ }
351
+
352
+ // Event Listeners
353
+ document.addEventListener('DOMContentLoaded', () => {
354
+ // File Upload Handling
355
+ const dropZone = document.querySelector('.drop-zone');
356
+ const fileInput = document.getElementById('fileInput');
357
+
358
+ // Prevent default drag behaviors
359
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
360
+ dropZone.addEventListener(eventName, preventDefaults, false);
361
+ document.body.addEventListener(eventName, preventDefaults, false);
362
+ });
363
+
364
+ // Highlight drop zone when dragging over it
365
+ ['dragenter', 'dragover'].forEach(eventName => {
366
+ dropZone.addEventListener(eventName, highlight, false);
367
+ });
368
+
369
+ ['dragleave', 'drop'].forEach(eventName => {
370
+ dropZone.addEventListener(eventName, unhighlight, false);
371
+ });
372
+
373
+ // Handle dropped files
374
+ dropZone.addEventListener('drop', (e) => {
375
+ const dt = e.dataTransfer;
376
+ const files = dt.files;
377
+ if (files.length > 0) {
378
+ handleFileUpload(files[0]);
379
+ }
380
+ });
381
+
382
+ fileInput.addEventListener('change', (e) => {
383
+ if (e.target.files.length > 0) {
384
+ handleFileUpload(e.target.files[0]);
385
+ }
386
+ });
387
+
388
+ // Sample Data Button Handlers
389
+ const marketingBtn = document.querySelector('.sample-btn:nth-child(1)');
390
+ const retailBtn = document.querySelector('.sample-btn:nth-child(2)');
391
+
392
+ if (marketingBtn) {
393
+ marketingBtn.addEventListener('click', () => {
394
+ console.log('Marketing campaign button clicked');
395
+ handleSampleDataClick('marketing_campaign');
396
+ });
397
+ }
398
+
399
+ if (retailBtn) {
400
+ retailBtn.addEventListener('click', () => {
401
+ console.log('Online retail button clicked');
402
+ handleSampleDataClick('online_retail');
403
+ });
404
+ }
405
+ });
406
+
407
+ // Utility Functions
408
+ function preventDefaults(e) {
409
+ e.preventDefault();
410
+ e.stopPropagation();
411
+ }
412
+
413
+ function highlight(e) {
414
+ document.querySelector('.drop-zone').classList.add('border-primary', 'bg-blue-50');
415
+ }
416
+
417
+ function unhighlight(e) {
418
+ document.querySelector('.drop-zone').classList.remove('border-primary', 'bg-blue-50');
419
+ }
420
+
421
+ function getFileTypeIcon(fileType) {
422
+ const icons = {
423
+ 'csv': 'fa-file-csv',
424
+ 'tsv': 'fa-file-alt',
425
+ 'txt': 'fa-file-alt',
426
+ 'xls': 'fa-file-excel',
427
+ 'xlsx': 'fa-file-excel',
428
+ 'xml': 'fa-file-code',
429
+ 'json': 'fa-file-code'
430
+ };
431
+ return icons[fileType] || 'fa-file';
432
+ }
433
+
434
+ function formatFileSize(bytes) {
435
+ if (bytes === 0) return '0 Bytes';
436
+ const k = 1024;
437
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
438
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
439
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
440
+ }
styles.css ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Loading Animation */
2
+ .loading-spinner {
3
+ display: none;
4
+ width: 50px;
5
+ height: 50px;
6
+ border: 5px solid #f3f3f3;
7
+ border-top: 5px solid #3B82F6;
8
+ border-radius: 50%;
9
+ animation: spin 1s linear infinite;
10
+ margin: 0 auto;
11
+ }
12
+
13
+ @keyframes spin {
14
+ 0% { transform: rotate(0deg); }
15
+ 100% { transform: rotate(360deg); }
16
+ }
17
+
18
+ /* File Upload Progress */
19
+ .progress-bar {
20
+ width: 100%;
21
+ height: 6px;
22
+ background-color: #e5e7eb;
23
+ border-radius: 3px;
24
+ overflow: hidden;
25
+ display: none;
26
+ margin: 1rem auto;
27
+ max-width: 300px;
28
+ }
29
+
30
+ .progress-bar-fill {
31
+ height: 100%;
32
+ background-color: #3B82F6;
33
+ width: 0%;
34
+ transition: width 0.3s ease;
35
+ }
36
+
37
+ /* Tooltip */
38
+ .tooltip {
39
+ position: relative;
40
+ display: inline-block;
41
+ }
42
+
43
+ .tooltip .tooltip-text {
44
+ visibility: hidden;
45
+ background-color: #1f2937;
46
+ color: white;
47
+ text-align: center;
48
+ padding: 8px 12px;
49
+ border-radius: 6px;
50
+ position: absolute;
51
+ z-index: 1;
52
+ bottom: 125%;
53
+ left: 50%;
54
+ transform: translateX(-50%);
55
+ opacity: 0;
56
+ transition: opacity 0.3s;
57
+ font-size: 0.875rem;
58
+ white-space: nowrap;
59
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
60
+ }
61
+
62
+ .tooltip:hover .tooltip-text {
63
+ visibility: visible;
64
+ opacity: 1;
65
+ }
66
+
67
+ /* File Type Icons */
68
+ .file-type-icon {
69
+ font-size: 1.5rem;
70
+ margin-right: 0.5rem;
71
+ color: #3B82F6;
72
+ }
73
+
74
+ /* Success Animation */
75
+ @keyframes checkmark {
76
+ 0% { transform: scale(0); opacity: 0; }
77
+ 50% { transform: scale(1.2); opacity: 0.8; }
78
+ 100% { transform: scale(1); opacity: 1; }
79
+ }
80
+
81
+ .success-checkmark {
82
+ display: none;
83
+ color: #10B981;
84
+ animation: checkmark 0.5s ease-in-out forwards;
85
+ }
86
+
87
+ /* Sample Data Cards */
88
+ .sample-btn {
89
+ transition: all 0.3s ease;
90
+ position: relative;
91
+ overflow: hidden;
92
+ }
93
+
94
+ .sample-btn::after {
95
+ content: '';
96
+ position: absolute;
97
+ top: 0;
98
+ left: 0;
99
+ width: 100%;
100
+ height: 100%;
101
+ background: linear-gradient(rgba(255,255,255,0.1), rgba(255,255,255,0));
102
+ transform: translateY(-100%);
103
+ transition: transform 0.3s ease;
104
+ }
105
+
106
+ .sample-btn:hover::after {
107
+ transform: translateY(0);
108
+ }
109
+
110
+ .sample-btn:hover {
111
+ transform: translateY(-2px);
112
+ box-shadow: 0 8px 15px rgba(0,0,0,0.1);
113
+ }
114
+
115
+ /* Drop Zone Enhancements */
116
+ .drop-zone {
117
+ transition: all 0.3s ease;
118
+ position: relative;
119
+ overflow: hidden;
120
+ }
121
+
122
+ .drop-zone::before {
123
+ content: '';
124
+ position: absolute;
125
+ top: 0;
126
+ left: 0;
127
+ right: 0;
128
+ bottom: 0;
129
+ border-radius: 8px;
130
+ border: 2px dashed #3B82F6;
131
+ opacity: 0;
132
+ transition: opacity 0.3s ease;
133
+ }
134
+
135
+ .drop-zone:hover::before {
136
+ opacity: 1;
137
+ }
138
+
139
+ /* File Info Card */
140
+ #fileInfo {
141
+ background: linear-gradient(to right, #f8fafc, #f1f5f9);
142
+ border: 1px solid #e2e8f0;
143
+ transition: all 0.3s ease;
144
+ }
145
+
146
+ #fileInfo:hover {
147
+ transform: translateY(-2px);
148
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
149
+ }
150
+
151
+ /* Features Section */
152
+ .feature-card {
153
+ transition: all 0.3s ease;
154
+ }
155
+
156
+ .feature-card:hover {
157
+ transform: translateY(-2px);
158
+ box-shadow: 0 8px 15px rgba(0,0,0,0.1);
159
+ }
160
+
161
+ .feature-icon {
162
+ transition: all 0.3s ease;
163
+ }
164
+
165
+ .feature-card:hover .feature-icon {
166
+ transform: scale(1.1);
167
+ color: #2563eb;
168
+ }