KEXEL commited on
Commit
1746d61
·
verified ·
1 Parent(s): f59f14b
Files changed (1) hide show
  1. excel-file-reader.html +751 -0
excel-file-reader.html ADDED
@@ -0,0 +1,751 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Excel File Reader - Show All Text</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
+ <style>
11
+ .file-input-wrapper {
12
+ position: relative;
13
+ overflow: hidden;
14
+ display: inline-block;
15
+ }
16
+ .file-input-wrapper input[type=file] {
17
+ font-size: 100px;
18
+ position: absolute;
19
+ left: 0;
20
+ top: 0;
21
+ opacity: 0;
22
+ cursor: pointer;
23
+ }
24
+ .excel-grid-container {
25
+ position: relative;
26
+ overflow: auto;
27
+ border: 1px solid #e2e8f0;
28
+ border-radius: 0.5rem;
29
+ max-height: none !important;
30
+ }
31
+ .excel-sheet {
32
+ position: relative;
33
+ min-width: 100%;
34
+ }
35
+ .excel-cell {
36
+ position: absolute;
37
+ box-sizing: border-box;
38
+ border: 1px solid #e2e8f0;
39
+ padding: 4px 8px;
40
+ font-size: 14px;
41
+ overflow: visible;
42
+ white-space: normal;
43
+ word-wrap: break-word;
44
+ background-color: white;
45
+ min-height: 30px;
46
+ }
47
+ .excel-header {
48
+ background-color: #f8fafc;
49
+ font-weight: 600;
50
+ }
51
+ .excel-col-header {
52
+ position: absolute;
53
+ top: 0;
54
+ z-index: 10;
55
+ background-color: #f8fafc;
56
+ font-weight: 600;
57
+ text-align: center;
58
+ border: 1px solid #e2e8f0;
59
+ }
60
+ .excel-row-header {
61
+ position: sticky;
62
+ left: 0;
63
+ z-index: 10;
64
+ background-color: #f8fafc;
65
+ font-weight: 600;
66
+ text-align: center;
67
+ border: 1px solid #e2e8f0;
68
+ }
69
+ .excel-corner {
70
+ position: sticky;
71
+ top: 0;
72
+ left: 0;
73
+ z-index: 20;
74
+ background-color: #f8fafc;
75
+ border: 1px solid #e2e8f0;
76
+ }
77
+ .merged-cell {
78
+ background-color: #f0f9ff;
79
+ }
80
+ .text-bold {
81
+ font-weight: bold;
82
+ }
83
+ .text-italic {
84
+ font-style: italic;
85
+ }
86
+ .text-underline {
87
+ text-decoration: underline;
88
+ }
89
+ .text-center {
90
+ text-align: center;
91
+ }
92
+ .text-right {
93
+ text-align: right;
94
+ }
95
+ .text-left {
96
+ text-align: left;
97
+ }
98
+ .bg-yellow {
99
+ background-color: #fef9c3;
100
+ }
101
+ .bg-green {
102
+ background-color: #dcfce7;
103
+ }
104
+ .bg-red {
105
+ background-color: #fee2e2;
106
+ }
107
+ .bg-blue {
108
+ background-color: #dbeafe;
109
+ }
110
+ .pulse {
111
+ animation: pulse 2s infinite;
112
+ }
113
+ @keyframes pulse {
114
+ 0% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4); }
115
+ 70% { box-shadow: 0 0 0 10px rgba(59, 130, 246, 0); }
116
+ 100% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0); }
117
+ }
118
+ .sheet-tab {
119
+ transition: all 0.2s ease;
120
+ }
121
+ .sheet-tab:hover {
122
+ transform: translateY(-2px);
123
+ }
124
+ .sheet-tab.active {
125
+ border-bottom: 3px solid #3b82f6;
126
+ font-weight: 600;
127
+ }
128
+ /* New styles to ensure all text is visible */
129
+ .auto-height {
130
+ height: auto !important;
131
+ min-height: 30px;
132
+ }
133
+ .text-preserve {
134
+ white-space: pre-wrap !important;
135
+ overflow: visible !important;
136
+ }
137
+ </style>
138
+ </head>
139
+ <body class="bg-gray-50 min-h-screen">
140
+ <div class="container mx-auto px-4 py-8">
141
+ <div class="max-w-6xl mx-auto">
142
+ <!-- Header -->
143
+ <div class="text-center mb-10">
144
+ <h1 class="text-4xl font-bold text-blue-600 mb-2">Excel File Reader</h1>
145
+ <p class="text-gray-600">View your Excel files with all text preserved</p>
146
+ </div>
147
+
148
+ <!-- Upload Card -->
149
+ <div class="bg-white rounded-xl shadow-md overflow-hidden mb-8 transition-all duration-300 hover:shadow-lg">
150
+ <div class="p-6">
151
+ <div class="flex flex-col items-center justify-center py-12 px-4 border-2 border-dashed border-gray-300 rounded-lg bg-gray-50">
152
+ <div class="file-input-wrapper">
153
+ <button id="uploadBtn" class="flex items-center px-6 py-3 bg-blue-600 text-white rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 pulse">
154
+ <i class="fas fa-file-excel mr-2"></i>
155
+ Choose Excel File
156
+ </button>
157
+ <input id="fileInput" type="file" accept=".xlsx, .xls" class="hidden">
158
+ </div>
159
+ <p class="mt-4 text-gray-500">or drag and drop your file here</p>
160
+ <p class="text-sm text-gray-400 mt-2">Supports .xlsx and .xls files</p>
161
+ </div>
162
+ <div id="fileInfo" class="mt-4 hidden">
163
+ <div class="flex items-center justify-between bg-blue-50 p-3 rounded-lg">
164
+ <div class="flex items-center">
165
+ <i class="fas fa-file-excel text-blue-600 text-xl mr-3"></i>
166
+ <div>
167
+ <p id="fileName" class="font-medium text-gray-800"></p>
168
+ <p id="fileSize" class="text-sm text-gray-500"></p>
169
+ </div>
170
+ </div>
171
+ <button id="clearBtn" class="text-red-500 hover:text-red-700">
172
+ <i class="fas fa-times"></i>
173
+ </button>
174
+ </div>
175
+ </div>
176
+ </div>
177
+ </div>
178
+
179
+ <!-- Sheets Navigation -->
180
+ <div id="sheetsNav" class="hidden mb-6">
181
+ <div class="flex space-x-1 overflow-x-auto pb-2">
182
+ <!-- Sheets tabs will be added here dynamically -->
183
+ </div>
184
+ </div>
185
+
186
+ <!-- Data Preview -->
187
+ <div id="dataPreview" class="hidden">
188
+ <div class="bg-white rounded-xl shadow-md overflow-hidden mb-8">
189
+ <div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
190
+ <h3 class="text-lg font-medium text-gray-900">Sheet Preview</h3>
191
+ <div class="flex space-x-2">
192
+ <button id="downloadJsonBtn" class="flex items-center px-3 py-1.5 bg-green-100 text-green-800 rounded-md text-sm hover:bg-green-200">
193
+ <i class="fas fa-file-code mr-1"></i> JSON
194
+ </button>
195
+ <button id="downloadCsvBtn" class="flex items-center px-3 py-1.5 bg-blue-100 text-blue-800 rounded-md text-sm hover:bg-blue-200">
196
+ <i class="fas fa-file-csv mr-1"></i> CSV
197
+ </button>
198
+ <button id="toggleAutoHeight" class="flex items-center px-3 py-1.5 bg-purple-100 text-purple-800 rounded-md text-sm hover:bg-purple-200">
199
+ <i class="fas fa-arrows-alt-v mr-1"></i> Auto Height
200
+ </button>
201
+ </div>
202
+ </div>
203
+ <div class="p-6">
204
+ <div class="excel-grid-container" style="max-height: 70vh;">
205
+ <div id="excelContainer"></div>
206
+ </div>
207
+ </div>
208
+ </div>
209
+ </div>
210
+
211
+ <!-- Statistics -->
212
+ <div id="statsSection" class="hidden">
213
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8">
214
+ <div class="bg-white rounded-xl shadow-md p-6">
215
+ <div class="flex items-center">
216
+ <div class="p-3 rounded-full bg-blue-100 text-blue-600 mr-4">
217
+ <i class="fas fa-table text-lg"></i>
218
+ </div>
219
+ <div>
220
+ <p class="text-sm text-gray-500">Sheets</p>
221
+ <p id="sheetsCount" class="text-2xl font-semibold">0</p>
222
+ </div>
223
+ </div>
224
+ </div>
225
+ <div class="bg-white rounded-xl shadow-md p-6">
226
+ <div class="flex items-center">
227
+ <div class="p-3 rounded-full bg-green-100 text-green-600 mr-4">
228
+ <i class="fas fa-columns text-lg"></i>
229
+ </div>
230
+ <div>
231
+ <p class="text-sm text-gray-500">Columns</p>
232
+ <p id="columnsCount" class="text-2xl font-semibold">0</p>
233
+ </div>
234
+ </div>
235
+ </div>
236
+ <div class="bg-white rounded-xl shadow-md p-6">
237
+ <div class="flex items-center">
238
+ <div class="p-3 rounded-full bg-purple-100 text-purple-600 mr-4">
239
+ <i class="fas fa-list text-lg"></i>
240
+ </div>
241
+ <div>
242
+ <p class="text-sm text-gray-500">Rows</p>
243
+ <p id="rowsCount" class="text-2xl font-semibold">0</p>
244
+ </div>
245
+ </div>
246
+ </div>
247
+ </div>
248
+ </div>
249
+ </div>
250
+ </div>
251
+
252
+ <script>
253
+ document.addEventListener('DOMContentLoaded', function() {
254
+ const fileInput = document.getElementById('fileInput');
255
+ const uploadBtn = document.getElementById('uploadBtn');
256
+ const fileInfo = document.getElementById('fileInfo');
257
+ const fileName = document.getElementById('fileName');
258
+ const fileSize = document.getElementById('fileSize');
259
+ const clearBtn = document.getElementById('clearBtn');
260
+ const sheetsNav = document.getElementById('sheetsNav');
261
+ const dataPreview = document.getElementById('dataPreview');
262
+ const excelContainer = document.getElementById('excelContainer');
263
+ const downloadJsonBtn = document.getElementById('downloadJsonBtn');
264
+ const downloadCsvBtn = document.getElementById('downloadCsvBtn');
265
+ const toggleAutoHeight = document.getElementById('toggleAutoHeight');
266
+ const statsSection = document.getElementById('statsSection');
267
+ const sheetsCount = document.getElementById('sheetsCount');
268
+ const columnsCount = document.getElementById('columnsCount');
269
+ const rowsCount = document.getElementById('rowsCount');
270
+ let workbook = null;
271
+ let currentSheet = null;
272
+ let jsonData = null;
273
+ let autoHeightEnabled = false;
274
+ const cellWidth = 120;
275
+ const defaultCellHeight = 30;
276
+ const headerSize = 25;
277
+ // Handle file selection
278
+ uploadBtn.addEventListener('click', function() {
279
+ fileInput.click();
280
+ });
281
+ fileInput.addEventListener('change', function(e) {
282
+ if (e.target.files.length) {
283
+ const file = e.target.files[0];
284
+ processFile(file);
285
+ }
286
+ });
287
+ // Handle drag and drop
288
+ const dropArea = document.querySelector('.bg-gray-50');
289
+
290
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
291
+ dropArea.addEventListener(eventName, preventDefaults, false);
292
+ });
293
+ function preventDefaults(e) {
294
+ e.preventDefault();
295
+ e.stopPropagation();
296
+ }
297
+ ['dragenter', 'dragover'].forEach(eventName => {
298
+ dropArea.addEventListener(eventName, highlight, false);
299
+ });
300
+ ['dragleave', 'drop'].forEach(eventName => {
301
+ dropArea.addEventListener(eventName, unhighlight, false);
302
+ });
303
+ function highlight() {
304
+ dropArea.classList.add('bg-blue-50', 'border-blue-300');
305
+ }
306
+ function unhighlight() {
307
+ dropArea.classList.remove('bg-blue-50', 'border-blue-300');
308
+ }
309
+ dropArea.addEventListener('drop', function(e) {
310
+ const dt = e.dataTransfer;
311
+ const file = dt.files[0];
312
+
313
+ if (file && (file.name.endsWith('.xlsx') || file.name.endsWith('.xls'))) {
314
+ fileInput.files = dt.files;
315
+ processFile(file);
316
+ } else {
317
+ alert('Please upload an Excel file (.xlsx or .xls)');
318
+ }
319
+ });
320
+ // Clear file
321
+ clearBtn.addEventListener('click', function() {
322
+ resetUI();
323
+ });
324
+ // Toggle auto height
325
+ toggleAutoHeight.addEventListener('click', function() {
326
+ autoHeightEnabled = !autoHeightEnabled;
327
+ if (autoHeightEnabled) {
328
+ this.classList.add('bg-purple-200');
329
+ this.classList.remove('bg-purple-100');
330
+ document.querySelectorAll('.excel-cell').forEach(cell => {
331
+ cell.classList.add('auto-height');
332
+ cell.style.height = 'auto';
333
+ });
334
+ } else {
335
+ this.classList.remove('bg-purple-200');
336
+ this.classList.add('bg-purple-100');
337
+ document.querySelectorAll('.excel-cell').forEach(cell => {
338
+ cell.classList.remove('auto-height');
339
+ cell.style.height = defaultCellHeight + 'px';
340
+ });
341
+ }
342
+
343
+ if (workbook && currentSheet) {
344
+ loadSheet(currentSheet);
345
+ }
346
+ });
347
+ // Process the uploaded file
348
+ function processFile(file) {
349
+ fileName.textContent = file.name;
350
+ fileSize.textContent = formatFileSize(file.size);
351
+ fileInfo.classList.remove('hidden');
352
+ uploadBtn.classList.remove('pulse');
353
+ const reader = new FileReader();
354
+ reader.onload = function(e) {
355
+ const data = new Uint8Array(e.target.result);
356
+ workbook = XLSX.read(data, { type: 'array', cellStyles: true, cellText: true });
357
+
358
+ // Update stats
359
+ sheetsCount.textContent = workbook.SheetNames.length;
360
+
361
+ // Show sheets navigation
362
+ renderSheetsNav(workbook.SheetNames);
363
+
364
+ // Load first sheet by default
365
+ loadSheet(workbook.SheetNames[0]);
366
+
367
+ // Show preview and stats sections
368
+ dataPreview.classList.remove('hidden');
369
+ statsSection.classList.remove('hidden');
370
+ };
371
+ reader.readAsArrayBuffer(file);
372
+ }
373
+ // Format file size
374
+ function formatFileSize(bytes) {
375
+ if (bytes === 0) return '0 Bytes';
376
+ const k = 1024;
377
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
378
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
379
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
380
+ }
381
+ // Render sheets navigation
382
+ function renderSheetsNav(sheetNames) {
383
+ sheetsNav.classList.remove('hidden');
384
+ const sheetsContainer = sheetsNav.querySelector('.flex');
385
+ sheetsContainer.innerHTML = '';
386
+
387
+ sheetNames.forEach((name, index) => {
388
+ const tab = document.createElement('button');
389
+ tab.className = `sheet-tab px-4 py-2 text-sm font-medium text-gray-600 hover:text-blue-600 ${index === 0 ? 'active' : ''}`;
390
+ tab.textContent = name;
391
+ tab.dataset.sheetName = name;
392
+ tab.addEventListener('click', function() {
393
+ document.querySelectorAll('.sheet-tab').forEach(t => t.classList.remove('active'));
394
+ this.classList.add('active');
395
+ loadSheet(this.dataset.sheetName);
396
+ });
397
+ sheetsContainer.appendChild(tab);
398
+ });
399
+ }
400
+ // Load sheet data
401
+ function loadSheet(sheetName) {
402
+ currentSheet = sheetName;
403
+ const worksheet = workbook.Sheets[sheetName];
404
+
405
+ // Get the range of the sheet
406
+ const range = worksheet['!ref'] ? XLSX.utils.decode_range(worksheet['!ref']) : {s: {c:0, r:0}, e: {c:0, r:0}};
407
+
408
+ // Update stats
409
+ columnsCount.textContent = range.e.c - range.s.c + 1;
410
+ rowsCount.textContent = range.e.r - range.s.r + 1;
411
+
412
+ // Render the sheet with original layout
413
+ renderExcelSheet(worksheet, range);
414
+ }
415
+ // Render Excel sheet with original layout
416
+ function renderExcelSheet(worksheet, range) {
417
+ excelContainer.innerHTML = '';
418
+
419
+ // Create sheet container
420
+ const sheetContainer = document.createElement('div');
421
+ sheetContainer.className = 'excel-sheet';
422
+
423
+ // Calculate sheet dimensions
424
+ const width = (range.e.c - range.s.c + 1) * cellWidth + headerSize;
425
+ const height = (range.e.r - range.s.r + 1) * defaultCellHeight + headerSize;
426
+
427
+ sheetContainer.style.width = `${width}px`;
428
+ sheetContainer.style.height = `${height}px`;
429
+
430
+ // Create corner header
431
+ const cornerHeader = document.createElement('div');
432
+ cornerHeader.className = 'excel-corner';
433
+ cornerHeader.style.width = `${headerSize}px`;
434
+ cornerHeader.style.height = `${headerSize}px`;
435
+ cornerHeader.style.top = '0';
436
+ cornerHeader.style.left = '0';
437
+ sheetContainer.appendChild(cornerHeader);
438
+
439
+ // Create column headers
440
+ for (let C = range.s.c; C <= range.e.c; ++C) {
441
+ const colHeader = document.createElement('div');
442
+ colHeader.className = 'excel-col-header';
443
+ colHeader.style.width = `${cellWidth}px`;
444
+ colHeader.style.height = `${headerSize}px`;
445
+ colHeader.style.left = `${headerSize + (C - range.s.c) * cellWidth}px`;
446
+ colHeader.style.top = '0';
447
+ colHeader.textContent = XLSX.utils.encode_col(C);
448
+ sheetContainer.appendChild(colHeader);
449
+ }
450
+
451
+ // Create row headers
452
+ for (let R = range.s.r; R <= range.e.r; ++R) {
453
+ const rowHeader = document.createElement('div');
454
+ rowHeader.className = 'excel-row-header';
455
+ rowHeader.style.width = `${headerSize}px`;
456
+ rowHeader.style.height = `${defaultCellHeight}px`;
457
+ rowHeader.style.left = '0';
458
+ rowHeader.style.top = `${headerSize + (R - range.s.r) * defaultCellHeight}px`;
459
+ rowHeader.textContent = (R + 1).toString();
460
+ sheetContainer.appendChild(rowHeader);
461
+ }
462
+
463
+ // Process each cell
464
+ for (let R = range.s.r; R <= range.e.r; ++R) {
465
+ for (let C = range.s.c; C <= range.e.c; ++C) {
466
+ const cell_address = {c: C, r: R};
467
+ const cell_ref = XLSX.utils.encode_cell(cell_address);
468
+
469
+ // Create cell
470
+ const cell = document.createElement('div');
471
+ cell.className = 'excel-cell text-preserve';
472
+ cell.style.width = `${cellWidth}px`;
473
+ cell.style.left = `${headerSize + (C - range.s.c) * cellWidth}px`;
474
+ cell.style.top = `${headerSize + (R - range.s.r) * defaultCellHeight}px`;
475
+
476
+ // Check if cell exists in worksheet
477
+ if (worksheet[cell_ref]) {
478
+ const excelCell = worksheet[cell_ref];
479
+
480
+ // Set cell content - preserve all text
481
+ if (excelCell.w) {
482
+ // Use formatted text if available
483
+ cell.innerHTML = excelCell.w.replace(/\n/g, '<br>');
484
+ } else if (excelCell.v !== undefined && excelCell.v !== null) {
485
+ // Use raw value otherwise
486
+ if (typeof excelCell.v === 'string') {
487
+ cell.innerHTML = excelCell.v.replace(/\n/g, '<br>');
488
+ } else {
489
+ cell.textContent = excelCell.v.toString();
490
+ }
491
+ }
492
+
493
+ // Apply cell styles with more precision
494
+ applyCellStyles(cell, excelCell);
495
+
496
+ // Handle merged cells
497
+ if (worksheet['!merges']) {
498
+ const merge = worksheet['!merges'].find(m => {
499
+ return R >= m.s.r && R <= m.e.r &&
500
+ C >= m.s.c && C <= m.e.c;
501
+ });
502
+
503
+ if (merge) {
504
+ cell.classList.add('merged-cell');
505
+ cell.style.width = `${(merge.e.c - merge.s.c + 1) * cellWidth}px`;
506
+
507
+ // For merged cells, we need to calculate the height based on content
508
+ if (autoHeightEnabled) {
509
+ cell.style.height = 'auto';
510
+ cell.classList.add('auto-height');
511
+ } else {
512
+ cell.style.height = `${(merge.e.r - merge.s.r + 1) * defaultCellHeight}px`;
513
+ }
514
+
515
+ // Center content in merged cells by default
516
+ if (!cell.style.textAlign) {
517
+ cell.style.textAlign = 'center';
518
+ cell.style.display = 'flex';
519
+ cell.style.alignItems = 'center';
520
+ cell.style.justifyContent = 'center';
521
+ }
522
+ }
523
+ }
524
+
525
+ // Auto height for regular cells
526
+ if (autoHeightEnabled && !cell.classList.contains('merged-cell')) {
527
+ cell.style.height = 'auto';
528
+ cell.classList.add('auto-height');
529
+ } else if (!cell.classList.contains('merged-cell')) {
530
+ cell.style.height = defaultCellHeight + 'px';
531
+ }
532
+ } else {
533
+ // Empty cell
534
+ cell.style.height = defaultCellHeight + 'px';
535
+ if (autoHeightEnabled) {
536
+ cell.style.height = 'auto';
537
+ cell.classList.add('auto-height');
538
+ }
539
+ }
540
+
541
+ sheetContainer.appendChild(cell);
542
+ }
543
+ }
544
+
545
+ excelContainer.appendChild(sheetContainer);
546
+
547
+ // After rendering, adjust heights for cells with lots of text
548
+ if (autoHeightEnabled) {
549
+ adjustCellHeights();
550
+ }
551
+ }
552
+ // Adjust cell heights based on content
553
+ function adjustCellHeights() {
554
+ document.querySelectorAll('.excel-cell').forEach(cell => {
555
+ // Create a clone to measure the height
556
+ const clone = document.createElement('div');
557
+ clone.style.position = 'absolute';
558
+ clone.style.visibility = 'hidden';
559
+ clone.style.width = cell.offsetWidth + 'px';
560
+ clone.style.padding = window.getComputedStyle(cell).padding;
561
+ clone.style.whiteSpace = 'pre-wrap';
562
+ clone.style.wordWrap = 'break-word';
563
+ clone.innerHTML = cell.innerHTML;
564
+
565
+ document.body.appendChild(clone);
566
+ const height = clone.offsetHeight + 8; // Add some padding
567
+ document.body.removeChild(clone);
568
+
569
+ // Set the minimum height to show all content
570
+ cell.style.height = Math.max(height, defaultCellHeight) + 'px';
571
+ });
572
+ }
573
+ // Apply Excel cell styles to HTML cell with more precision
574
+ function applyCellStyles(cell, excelCell) {
575
+ if (!excelCell.s) return;
576
+
577
+ const style = excelCell.s;
578
+ let cellStyle = '';
579
+
580
+ // Font styles
581
+ if (style.font) {
582
+ const font = style.font;
583
+
584
+ if (font.bold) cell.classList.add('text-bold');
585
+ if (font.italic) cell.classList.add('text-italic');
586
+ if (font.underline) cell.classList.add('text-underline');
587
+
588
+ // Font family
589
+ if (font.name) {
590
+ cellStyle += `font-family: ${font.name}, sans-serif;`;
591
+ }
592
+
593
+ // Font color
594
+ if (font.color && font.color.rgb) {
595
+ cellStyle += `color: #${font.color.rgb.slice(2)};`;
596
+ }
597
+
598
+ // Font size
599
+ if (font.sz) {
600
+ cellStyle += `font-size: ${font.sz}pt;`;
601
+ }
602
+ }
603
+
604
+ // Alignment
605
+ if (style.alignment) {
606
+ const align = style.alignment.horizontal;
607
+ if (align === 'center') {
608
+ cell.classList.add('text-center');
609
+ } else if (align === 'right') {
610
+ cell.classList.add('text-right');
611
+ } else if (align === 'left') {
612
+ cell.classList.add('text-left');
613
+ }
614
+
615
+ // Vertical alignment
616
+ if (style.alignment.vertical) {
617
+ const vertical = style.alignment.vertical;
618
+ if (vertical === 'top') {
619
+ cellStyle += 'vertical-align: top;';
620
+ } else if (vertical === 'center') {
621
+ cellStyle += 'vertical-align: middle;';
622
+ } else if (vertical === 'bottom') {
623
+ cellStyle += 'vertical-align: bottom;';
624
+ }
625
+
626
+ // For vertical alignment to work properly
627
+ cellStyle += 'display: flex; align-items: center;';
628
+ }
629
+
630
+ // Wrap text - always enabled to prevent text loss
631
+ cellStyle += 'white-space: pre-wrap; word-wrap: break-word; overflow: visible;';
632
+
633
+ // Indent
634
+ if (style.alignment.indent) {
635
+ cellStyle += `padding-left: ${style.alignment.indent * 10}px;`;
636
+ }
637
+ }
638
+
639
+ // Fill (background color)
640
+ if (style.fill && style.fill.fgColor && style.fill.fgColor.rgb) {
641
+ const bgColor = `#${style.fill.fgColor.rgb.slice(2)}`;
642
+ cellStyle += `background-color: ${bgColor};`;
643
+ } else if (style.fill && style.fill.patternType === 'solid' && style.fill.bgColor && style.fill.bgColor.rgb) {
644
+ const bgColor = `#${style.fill.bgColor.rgb.slice(2)}`;
645
+ cellStyle += `background-color: ${bgColor};`;
646
+ }
647
+
648
+ // Borders
649
+ if (style.border) {
650
+ const border = style.border;
651
+
652
+ if (border.top && border.top.style) {
653
+ const color = border.top.color?.rgb ? `#${border.top.color.rgb.slice(2)}` : '#94a3b8';
654
+ const width = border.top.style === 'thin' ? '1px' :
655
+ border.top.style === 'medium' ? '2px' :
656
+ border.top.style === 'thick' ? '3px' : '1px';
657
+ cellStyle += `border-top: ${width} solid ${color};`;
658
+ }
659
+ if (border.bottom && border.bottom.style) {
660
+ const color = border.bottom.color?.rgb ? `#${border.bottom.color.rgb.slice(2)}` : '#94a3b8';
661
+ const width = border.bottom.style === 'thin' ? '1px' :
662
+ border.bottom.style === 'medium' ? '2px' :
663
+ border.bottom.style === 'thick' ? '3px' : '1px';
664
+ cellStyle += `border-bottom: ${width} solid ${color};`;
665
+ }
666
+ if (border.left && border.left.style) {
667
+ const color = border.left.color?.rgb ? `#${border.left.color.rgb.slice(2)}` : '#94a3b8';
668
+ const width = border.left.style === 'thin' ? '1px' :
669
+ border.left.style === 'medium' ? '2px' :
670
+ border.left.style === 'thick' ? '3px' : '1px';
671
+ cellStyle += `border-left: ${width} solid ${color};`;
672
+ }
673
+ if (border.right && border.right.style) {
674
+ const color = border.right.color?.rgb ? `#${border.right.color.rgb.slice(2)}` : '#94a3b8';
675
+ const width = border.right.style === 'thin' ? '1px' :
676
+ border.right.style === 'medium' ? '2px' :
677
+ border.right.style === 'thick' ? '3px' : '1px';
678
+ cellStyle += `border-right: ${width} solid ${color};`;
679
+ }
680
+ }
681
+
682
+ // Number formatting
683
+ if (excelCell.z) {
684
+ // You could add specific formatting for numbers, dates, etc.
685
+ // For example, format dates, currency, percentages, etc.
686
+ }
687
+
688
+ // Apply all styles at once
689
+ if (cellStyle) {
690
+ cell.style.cssText += cellStyle;
691
+ }
692
+
693
+ // Padding - Excel default is different from our default
694
+ cell.style.padding = '4px 8px';
695
+ }
696
+ // Download as JSON
697
+ downloadJsonBtn.addEventListener('click', function() {
698
+ if (!workbook || !currentSheet) return;
699
+
700
+ const worksheet = workbook.Sheets[currentSheet];
701
+ const json = XLSX.utils.sheet_to_json(worksheet);
702
+
703
+ const blob = new Blob([JSON.stringify(json, null, 2)], { type: 'application/json' });
704
+ const url = URL.createObjectURL(blob);
705
+
706
+ const a = document.createElement('a');
707
+ a.href = url;
708
+ a.download = `${currentSheet}.json`;
709
+ document.body.appendChild(a);
710
+ a.click();
711
+ document.body.removeChild(a);
712
+ URL.revokeObjectURL(url);
713
+ });
714
+ // Download as CSV
715
+ downloadCsvBtn.addEventListener('click', function() {
716
+ if (!workbook || !currentSheet) return;
717
+
718
+ const worksheet = workbook.Sheets[currentSheet];
719
+ const csv = XLSX.utils.sheet_to_csv(worksheet);
720
+
721
+ const blob = new Blob([csv], { type: 'text/csv' });
722
+ const url = URL.createObjectURL(blob);
723
+
724
+ const a = document.createElement('a');
725
+ a.href = url;
726
+ a.download = `${currentSheet}.csv`;
727
+ document.body.appendChild(a);
728
+ a.click();
729
+ document.body.removeChild(a);
730
+ URL.revokeObjectURL(url);
731
+ });
732
+ // Reset UI
733
+ function resetUI() {
734
+ fileInput.value = '';
735
+ fileInfo.classList.add('hidden');
736
+ sheetsNav.classList.add('hidden');
737
+ dataPreview.classList.add('hidden');
738
+ statsSection.classList.add('hidden');
739
+ uploadBtn.classList.add('pulse');
740
+ workbook = null;
741
+ currentSheet = null;
742
+ jsonData = null;
743
+ excelContainer.innerHTML = '';
744
+ autoHeightEnabled = false;
745
+ toggleAutoHeight.classList.remove('bg-purple-200');
746
+ toggleAutoHeight.classList.add('bg-purple-100');
747
+ }
748
+ });
749
+ </script>
750
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=KEXEL/excel-file-reader" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
751
+ </html>