bep40 commited on
Commit
222671a
·
verified ·
1 Parent(s): 2fc78d3

Add 3 files

Browse files
Files changed (3) hide show
  1. README.md +7 -5
  2. index.html +432 -19
  3. prompts.txt +1 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Pdf List
3
- emoji:
4
- colorFrom: red
5
- colorTo: yellow
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: pdf-list
3
+ emoji: 🐳
4
+ colorFrom: blue
5
+ colorTo: red
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,432 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>PDF Viewer Hub</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.min.js"></script>
10
+ <style>
11
+ .pdf-thumbnail:hover .pdf-overlay {
12
+ opacity: 1;
13
+ }
14
+ .pdf-overlay {
15
+ transition: opacity 0.3s ease;
16
+ }
17
+ .pdf-container {
18
+ height: 600px;
19
+ overflow: auto;
20
+ position: relative;
21
+ }
22
+ .pdf-fullscreen {
23
+ position: fixed;
24
+ top: 0;
25
+ left: 0;
26
+ right: 0;
27
+ bottom: 0;
28
+ z-index: 9999;
29
+ background: white;
30
+ overflow: auto;
31
+ }
32
+ .search-highlight {
33
+ background-color: rgba(255, 255, 0, 0.5);
34
+ }
35
+ </style>
36
+ </head>
37
+ <body class="bg-gray-100">
38
+ <div class="container mx-auto px-4 py-8">
39
+ <header class="mb-10 text-center">
40
+ <h1 class="text-4xl font-bold text-indigo-700 mb-2">PDF Viewer Hub</h1>
41
+ <p class="text-gray-600 text-lg">View, search and download PDF documents</p>
42
+ </header>
43
+
44
+ <div class="flex flex-wrap -mx-2">
45
+ <!-- PDF Thumbnails -->
46
+ <div class="w-full sm:w-1/2 md:w-1/3 lg:w-1/4 px-2 mb-4">
47
+ <div class="pdf-thumbnail bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300 relative">
48
+ <img src="https://via.placeholder.com/300x400/4F46E5/FFFFFF?text=Sample+PDF+1" alt="Sample PDF 1" class="w-full h-64 object-cover">
49
+ <div class="pdf-overlay absolute inset-0 bg-black bg-opacity-50 opacity-0 flex items-center justify-center">
50
+ <button onclick="openPdfModal('sample1.pdf', 'Sample Document 1')" class="bg-white text-indigo-600 px-4 py-2 rounded-lg font-medium mx-1 hover:bg-indigo-100 transition">
51
+ <i class="fas fa-eye mr-1"></i> View
52
+ </button>
53
+ <a href="sample1.pdf" download class="bg-white text-indigo-600 px-4 py-2 rounded-lg font-medium mx-1 hover:bg-indigo-100 transition">
54
+ <i class="fas fa-download mr-1"></i> Download
55
+ </a>
56
+ </div>
57
+ <div class="p-4">
58
+ <h3 class="font-semibold text-lg mb-1">Sample Document 1</h3>
59
+ <p class="text-gray-500 text-sm">2.4 MB • 12 pages</p>
60
+ </div>
61
+ </div>
62
+ </div>
63
+
64
+ <div class="w-full sm:w-1/2 md:w-1/3 lg:w-1/4 px-2 mb-4">
65
+ <div class="pdf-thumbnail bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300 relative">
66
+ <img src="https://via.placeholder.com/300x400/4F46E5/FFFFFF?text=Sample+PDF+2" alt="Sample PDF 2" class="w-full h-64 object-cover">
67
+ <div class="pdf-overlay absolute inset-0 bg-black bg-opacity-50 opacity-0 flex items-center justify-center">
68
+ <button onclick="openPdfModal('sample2.pdf', 'Sample Document 2')" class="bg-white text-indigo-600 px-4 py-2 rounded-lg font-medium mx-1 hover:bg-indigo-100 transition">
69
+ <i class="fas fa-eye mr-1"></i> View
70
+ </button>
71
+ <a href="sample2.pdf" download class="bg-white text-indigo-600 px-4 py-2 rounded-lg font-medium mx-1 hover:bg-indigo-100 transition">
72
+ <i class="fas fa-download mr-1"></i> Download
73
+ </a>
74
+ </div>
75
+ <div class="p-4">
76
+ <h3 class="font-semibold text-lg mb-1">Sample Document 2</h3>
77
+ <p class="text-gray-500 text-sm">3.1 MB • 18 pages</p>
78
+ </div>
79
+ </div>
80
+ </div>
81
+
82
+ <div class="w-full sm:w-1/2 md:w-1/3 lg:w-1/4 px-2 mb-4">
83
+ <div class="pdf-thumbnail bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300 relative">
84
+ <img src="https://via.placeholder.com/300x400/4F46E5/FFFFFF?text=Sample+PDF+3" alt="Sample PDF 3" class="w-full h-64 object-cover">
85
+ <div class="pdf-overlay absolute inset-0 bg-black bg-opacity-50 opacity-0 flex items-center justify-center">
86
+ <button onclick="openPdfModal('sample3.pdf', 'Sample Document 3')" class="bg-white text-indigo-600 px-4 py-2 rounded-lg font-medium mx-1 hover:bg-indigo-100 transition">
87
+ <i class="fas fa-eye mr-1"></i> View
88
+ </button>
89
+ <a href="sample3.pdf" download class="bg-white text-indigo-600 px-4 py-2 rounded-lg font-medium mx-1 hover:bg-indigo-100 transition">
90
+ <i class="fas fa-download mr-1"></i> Download
91
+ </a>
92
+ </div>
93
+ <div class="p-4">
94
+ <h3 class="font-semibold text-lg mb-1">Sample Document 3</h3>
95
+ <p class="text-gray-500 text-sm">1.8 MB • 8 pages</p>
96
+ </div>
97
+ </div>
98
+ </div>
99
+
100
+ <div class="w-full sm:w-1/2 md:w-1/3 lg:w-1/4 px-2 mb-4">
101
+ <div class="pdf-thumbnail bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300 relative">
102
+ <img src="https://via.placeholder.com/300x400/4F46E5/FFFFFF?text=Sample+PDF+4" alt="Sample PDF 4" class="w-full h-64 object-cover">
103
+ <div class="pdf-overlay absolute inset-0 bg-black bg-opacity-50 opacity-0 flex items-center justify-center">
104
+ <button onclick="openPdfModal('sample4.pdf', 'Sample Document 4')" class="bg-white text-indigo-600 px-4 py-2 rounded-lg font-medium mx-1 hover:bg-indigo-100 transition">
105
+ <i class="fas fa-eye mr-1"></i> View
106
+ </button>
107
+ <a href="sample4.pdf" download class="bg-white text-indigo-600 px-4 py-2 rounded-lg font-medium mx-1 hover:bg-indigo-100 transition">
108
+ <i class="fas fa-download mr-1"></i> Download
109
+ </a>
110
+ </div>
111
+ <div class="p-4">
112
+ <h3 class="font-semibold text-lg mb-1">Sample Document 4</h3>
113
+ <p class="text-gray-500 text-sm">5.2 MB • 24 pages</p>
114
+ </div>
115
+ </div>
116
+ </div>
117
+ </div>
118
+ </div>
119
+
120
+ <!-- PDF Viewer Modal -->
121
+ <div id="pdfModal" class="fixed inset-0 z-50 overflow-y-auto hidden">
122
+ <div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
123
+ <div class="fixed inset-0 transition-opacity" aria-hidden="true">
124
+ <div class="absolute inset-0 bg-gray-500 opacity-75"></div>
125
+ </div>
126
+ <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
127
+ <div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-4xl sm:w-full">
128
+ <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
129
+ <div class="sm:flex sm:items-start justify-between">
130
+ <h3 id="pdfTitle" class="text-lg leading-6 font-medium text-gray-900"></h3>
131
+ <button type="button" onclick="closePdfModal()" class="rounded-md text-gray-400 hover:text-gray-500 focus:outline-none">
132
+ <span class="sr-only">Close</span>
133
+ <i class="fas fa-times"></i>
134
+ </button>
135
+ </div>
136
+ <div class="mt-4">
137
+ <div class="flex justify-between items-center mb-4">
138
+ <div class="flex space-x-2">
139
+ <button id="zoomIn" class="bg-gray-100 hover:bg-gray-200 text-gray-800 py-1 px-3 rounded">
140
+ <i class="fas fa-search-plus"></i>
141
+ </button>
142
+ <button id="zoomOut" class="bg-gray-100 hover:bg-gray-200 text-gray-800 py-1 px-3 rounded">
143
+ <i class="fas fa-search-minus"></i>
144
+ </button>
145
+ <button id="fullscreen" class="bg-gray-100 hover:bg-gray-200 text-gray-800 py-1 px-3 rounded">
146
+ <i class="fas fa-expand"></i>
147
+ </button>
148
+ <a id="downloadBtn" download class="bg-gray-100 hover:bg-gray-200 text-gray-800 py-1 px-3 rounded inline-flex items-center">
149
+ <i class="fas fa-download mr-1"></i> Download
150
+ </a>
151
+ </div>
152
+ <div class="relative">
153
+ <div class="flex">
154
+ <input type="text" id="searchText" placeholder="Search in document..." class="border rounded-l py-1 px-3 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
155
+ <button id="searchBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white py-1 px-3 rounded-r">
156
+ <i class="fas fa-search"></i>
157
+ </button>
158
+ </div>
159
+ </div>
160
+ </div>
161
+ <div id="pdfContainer" class="pdf-container border">
162
+ <canvas id="pdfCanvas"></canvas>
163
+ </div>
164
+ <div class="flex justify-between items-center mt-4">
165
+ <div>
166
+ <button id="prevPage" class="bg-indigo-600 hover:bg-indigo-700 text-white py-1 px-4 rounded mr-2">
167
+ <i class="fas fa-chevron-left"></i> Prev
168
+ </button>
169
+ <button id="nextPage" class="bg-indigo-600 hover:bg-indigo-700 text-white py-1 px-4 rounded">
170
+ Next <i class="fas fa-chevron-right"></i>
171
+ </button>
172
+ </div>
173
+ <div class="text-gray-600 text-sm">
174
+ Page <span id="currentPage">1</span> of <span id="totalPages">1</span>
175
+ </div>
176
+ </div>
177
+ </div>
178
+ </div>
179
+ </div>
180
+ </div>
181
+ </div>
182
+
183
+ <script>
184
+ // Initialize PDF.js
185
+ pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.worker.min.js';
186
+
187
+ // Modal variables
188
+ let pdfModal = document.getElementById('pdfModal');
189
+ let currentPdf = null;
190
+ let currentPage = 1;
191
+ let scale = 1;
192
+ let fullscreen = false;
193
+ let searchText = '';
194
+ let searchResults = [];
195
+ let currentSearchResult = 0;
196
+
197
+ // Open PDF modal
198
+ function openPdfModal(pdfUrl, pdfTitle) {
199
+ document.getElementById('pdfTitle').textContent = pdfTitle;
200
+ document.getElementById('downloadBtn').href = pdfUrl;
201
+
202
+ // Show modal
203
+ pdfModal.classList.remove('hidden');
204
+
205
+ // Load PDF
206
+ loadPdf(pdfUrl);
207
+
208
+ // Reset search
209
+ document.getElementById('searchText').value = '';
210
+ searchText = '';
211
+ searchResults = [];
212
+ currentSearchResult = 0;
213
+ }
214
+
215
+ // Close PDF modal
216
+ function closePdfModal() {
217
+ if (fullscreen) {
218
+ toggleFullscreen();
219
+ }
220
+ pdfModal.classList.add('hidden');
221
+ currentPdf = null;
222
+ }
223
+
224
+ // Load PDF
225
+ function loadPdf(pdfUrl) {
226
+ // Reset variables
227
+ currentPage = 1;
228
+ scale = 1;
229
+
230
+ // Loading PDF document
231
+ pdfjsLib.getDocument(pdfUrl).promise.then(function(pdf) {
232
+ currentPdf = pdf;
233
+
234
+ // Update total pages
235
+ document.getElementById('totalPages').textContent = pdf.numPages;
236
+
237
+ // Render first page
238
+ renderPage(currentPage);
239
+ }).catch(function(error) {
240
+ alert('Error loading PDF: ' + error.message);
241
+ });
242
+ }
243
+
244
+ // Render PDF page
245
+ function renderPage(pageNum) {
246
+ if (!currentPdf) return;
247
+
248
+ currentPdf.getPage(pageNum).then(function(page) {
249
+ let viewport = page.getViewport({ scale: scale });
250
+ let canvas = document.getElementById('pdfCanvas');
251
+ let context = canvas.getContext('2d');
252
+
253
+ // Adjust canvas size
254
+ canvas.height = viewport.height;
255
+ canvas.width = viewport.width;
256
+
257
+ // Clear previous highlights
258
+ document.querySelectorAll('.search-highlight').forEach(el => el.remove());
259
+
260
+ // Update current page number
261
+ document.getElementById('currentPage').textContent = pageNum;
262
+
263
+ // Disable prev/next buttons on first/last page
264
+ document.getElementById('prevPage').disabled = (pageNum <= 1);
265
+ document.getElementById('nextPage').disabled = (pageNum >= currentPdf.numPages);
266
+
267
+ // Render PDF page
268
+ let renderContext = {
269
+ canvasContext: context,
270
+ viewport: viewport
271
+ };
272
+
273
+ page.render(renderContext);
274
+
275
+ // Highlight search terms if any
276
+ if (searchText) {
277
+ searchInPage(page, viewport);
278
+ }
279
+ });
280
+ }
281
+
282
+ // Search in PDF page
283
+ function searchInPage(page, viewport) {
284
+ page.getTextContent().then(function(textContent) {
285
+ // Search for text
286
+ searchResults = [];
287
+ let text = textContent.items.map(item => item.str).join(' ');
288
+
289
+ let regex = new RegExp(searchText, 'gi');
290
+ let match;
291
+ while ((match = regex.exec(text)) !== null) {
292
+ searchResults.push(match.index);
293
+ }
294
+
295
+ // Highlight matches
296
+ if (searchResults.length > 0) {
297
+ highlightMatches(page, textContent, viewport);
298
+ document.getElementById('searchText').classList.remove('border-gray-300');
299
+ document.getElementById('searchText').classList.add('border-green-500');
300
+ } else {
301
+ document.getElementById('searchText').classList.remove('border-green-500');
302
+ document.getElementById('searchText').classList.add('border-gray-300');
303
+ }
304
+ });
305
+ }
306
+
307
+ // Highlight search matches
308
+ function highlightMatches(page, textContent, viewport) {
309
+ let textItems = textContent.items;
310
+ let canvas = document.getElementById('pdfCanvas');
311
+ let searchTermLength = searchText.length;
312
+
313
+ // Clear previous highlights
314
+ document.querySelectorAll('.search-highlight').forEach(el => el.remove());
315
+
316
+ let foundChars = 0;
317
+ let currentResult = 0;
318
+
319
+ for (let i = 0; i < textItems.length; i++) {
320
+ let item = textItems[i];
321
+ let itemText = item.str;
322
+
323
+ // Check if this item contains any part of our search results
324
+ while (currentResult < searchResults.length &&
325
+ foundChars + itemText.length >= searchResults[currentResult]) {
326
+
327
+ let position = searchResults[currentResult] - foundChars;
328
+ if (position < 0) position = 0;
329
+
330
+ // Get text up to the search term
331
+ let textBefore = itemText.substr(0, position);
332
+ let measureBefore = page.getTextWidth(textBefore);
333
+
334
+ // Get the search term text
335
+ let searchTermText = itemText.substr(position, searchTermLength);
336
+ let searchMeasure = page.getTextWidth(searchTermText);
337
+
338
+ // Create highlight div
339
+ let highlightDiv = document.createElement('div');
340
+ highlightDiv.className = 'search-highlight absolute';
341
+ highlightDiv.style.top = (item.transform[5] - (item.height * (scale * 0.9))) + 'px';
342
+ highlightDiv.style.left = (item.transform[4] + measureBefore) + 'px';
343
+ highlightDiv.style.width = searchMeasure + 'px';
344
+ highlightDiv.style.height = (item.height * scale) + 'px';
345
+
346
+ if (currentSearchResult === currentResult) {
347
+ highlightDiv.style.border = '2px solid red';
348
+ highlightDiv.style.boxSizing = 'border-box';
349
+ }
350
+
351
+ document.querySelector('#pdfContainer').appendChild(highlightDiv);
352
+
353
+ currentResult++;
354
+
355
+ // If we've reached the end of this item's text, break
356
+ if (position + searchTermLength >= itemText.length) {
357
+ break;
358
+ }
359
+ }
360
+
361
+ foundChars += itemText.length;
362
+ }
363
+ }
364
+
365
+ // Toggle fullscreen mode
366
+ function toggleFullscreen() {
367
+ let container = document.getElementById('pdfContainer');
368
+ if (!fullscreen) {
369
+ container.classList.add('pdf-fullscreen');
370
+ fullscreen = true;
371
+ document.getElementById('fullscreen').innerHTML = '<i class="fas fa-compress"></i>';
372
+ } else {
373
+ container.classList.remove('pdf-fullscreen');
374
+ fullscreen = false;
375
+ document.getElementById('fullscreen').innerHTML = '<i class="fas fa-expand"></i>';
376
+ }
377
+ renderPage(currentPage);
378
+ }
379
+
380
+ // Event listeners
381
+ document.getElementById('prevPage').addEventListener('click', function() {
382
+ if (currentPage > 1) {
383
+ currentPage--;
384
+ renderPage(currentPage);
385
+ }
386
+ });
387
+
388
+ document.getElementById('nextPage').addEventListener('click', function() {
389
+ if (currentPdf && currentPage < currentPdf.numPages) {
390
+ currentPage++;
391
+ renderPage(currentPage);
392
+ }
393
+ });
394
+
395
+ document.getElementById('zoomIn').addEventListener('click', function() {
396
+ scale += 0.25;
397
+ renderPage(currentPage);
398
+ });
399
+
400
+ document.getElementById('zoomOut').addEventListener('click', function() {
401
+ if (scale > 0.5) {
402
+ scale -= 0.25;
403
+ renderPage(currentPage);
404
+ }
405
+ });
406
+
407
+ document.getElementById('fullscreen').addEventListener('click', toggleFullscreen);
408
+
409
+ document.getElementById('searchBtn').addEventListener('click', function() {
410
+ searchText = document.getElementById('searchText').value.trim();
411
+ if (searchText && currentPdf) {
412
+ currentSearchResult = 0;
413
+ renderPage(currentPage);
414
+ }
415
+ });
416
+
417
+ // Handle search text input (trigger search on Enter)
418
+ document.getElementById('searchText').addEventListener('keypress', function(e) {
419
+ if (e.key === 'Enter') {
420
+ document.getElementById('searchBtn').click();
421
+ }
422
+ });
423
+
424
+ // Close modal when clicking outside
425
+ document.querySelector('#pdfModal > div > div').addEventListener('click', function(e) {
426
+ if (e.target === this) {
427
+ closePdfModal();
428
+ }
429
+ });
430
+ </script>
431
+ <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=bep40/pdf-list" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
432
+ </html>
prompts.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ Tạo 1 website trình bày danh sách file PDF có sẵn dưới dạng thumbnail xem file qua popup, có thể tải xuống, có các chức năng phóng to, thu nhỏ, zoom full màn hình, tìm văn bản ngay trên file