|
|
@@ -12,6 +12,16 @@
|
|
|
<!-- Fancybox CSS and JS -->
|
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0/dist/fancybox/fancybox.css">
|
|
|
<script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0/dist/fancybox/fancybox.umd.js"></script>
|
|
|
+
|
|
|
+ <!-- GLightbox for videos -->
|
|
|
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/glightbox/dist/css/glightbox.min.css">
|
|
|
+ <script src="https://cdn.jsdelivr.net/npm/glightbox/dist/js/glightbox.min.js"></script>
|
|
|
+
|
|
|
+ <!-- PDF.js -->
|
|
|
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
|
|
|
+
|
|
|
+ <!-- HEIC2ANY for iPhone images -->
|
|
|
+ <script src="https://cdn.jsdelivr.net/npm/heic2any@0.0.4/dist/heic2any.min.js"></script>
|
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
|
<script>
|
|
|
(function() {
|
|
|
@@ -142,11 +152,11 @@
|
|
|
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 flex justify-center">
|
|
|
{% if media_type == 'image' %}
|
|
|
<div class="relative group">
|
|
|
- <a href="/preview/{{ file_id }}" data-fancybox="gallery" data-caption="{{ filename }}">
|
|
|
- <img src="/preview/{{ file_id }}" alt="{{ filename }}" class="max-w-full max-h-96 rounded-lg shadow-sm cursor-pointer transition-transform duration-200 hover:scale-105" loading="lazy">
|
|
|
+ <a href="/preview/{{ file_id }}" data-fancybox="gallery" data-caption="{{ filename }}" id="image-link-{{ file_id }}">
|
|
|
+ <img src="/preview/{{ file_id }}" alt="{{ filename }}" class="max-w-full max-h-96 rounded-lg shadow-sm cursor-pointer transition-transform duration-200 hover:scale-105" loading="lazy" id="preview-image-{{ file_id }}">
|
|
|
</a>
|
|
|
<div class="mt-3 flex flex-col items-center space-y-2">
|
|
|
- <p class="text-xs text-gray-500 dark:text-gray-400">Click to view with zoom, fullscreen & advanced controls</p>
|
|
|
+ <p class="text-xs text-gray-500 dark:text-gray-400">Click to view with zoom, fullscreen & advanced controls (supports HEIC/HEIF)</p>
|
|
|
<div class="flex space-x-2">
|
|
|
<button onclick="downloadImage('{{ file_id }}', '{{ filename }}')" class="inline-flex items-center px-2 py-1 text-xs font-medium text-white bg-green-600 hover:bg-green-700 rounded transition-colors duration-200">
|
|
|
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
@@ -164,10 +174,16 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
{% elif media_type == 'video' %}
|
|
|
- <video controls class="max-w-full max-h-96 rounded-lg shadow-sm">
|
|
|
- <source src="/preview/{{ file_id }}" type="{{ mime_type }}">
|
|
|
- Your browser does not support the video tag.
|
|
|
- </video>
|
|
|
+ <div class="w-full max-w-2xl mx-auto">
|
|
|
+ <video controls class="w-full rounded-lg shadow-lg" preload="metadata">
|
|
|
+ <source src="/preview/{{ file_id }}" type="{{ mime_type }}">
|
|
|
+ Your browser does not support the video tag.
|
|
|
+ </video>
|
|
|
+ <div class="mt-3 text-center">
|
|
|
+ <p class="text-sm font-medium text-gray-900 dark:text-white">{{ filename }}</p>
|
|
|
+ <p class="text-xs text-gray-500 dark:text-gray-400">{{ mime_type }}</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
{% elif media_type == 'audio' %}
|
|
|
<div class="w-full max-w-md">
|
|
|
<div class="flex items-center space-x-4 mb-4">
|
|
|
@@ -184,6 +200,42 @@
|
|
|
Your browser does not support the audio tag.
|
|
|
</audio>
|
|
|
</div>
|
|
|
+ {% elif media_type == 'pdf' %}
|
|
|
+ <div class="relative group w-full">
|
|
|
+ <div class="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden">
|
|
|
+ <div class="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700">
|
|
|
+ <div class="flex items-center space-x-3">
|
|
|
+ <svg class="w-8 h-8 text-red-500" fill="currentColor" viewBox="0 0 20 20">
|
|
|
+ <path fill-rule="evenodd" d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4z" clip-rule="evenodd"></path>
|
|
|
+ </svg>
|
|
|
+ <div>
|
|
|
+ <h4 class="font-medium text-gray-900 dark:text-white">{{ filename }}</h4>
|
|
|
+ <p class="text-sm text-gray-500 dark:text-gray-400">PDF Document</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <button onclick="openPDFViewer('/preview/{{ file_id }}', '{{ filename }}')" class="inline-flex items-center px-3 py-2 text-sm font-medium text-white bg-red-600 hover:bg-red-700 rounded-lg transition-colors duration-200">
|
|
|
+ <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
|
|
|
+ </svg>
|
|
|
+ View PDF
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <div id="pdf-preview-{{ file_id }}" class="p-4 bg-gray-50 dark:bg-gray-900">
|
|
|
+ <div class="flex items-center justify-center h-48 text-gray-500 dark:text-gray-400">
|
|
|
+ <div class="text-center">
|
|
|
+ <svg class="w-12 h-12 mx-auto mb-2 text-red-500" fill="currentColor" viewBox="0 0 20 20">
|
|
|
+ <path fill-rule="evenodd" d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4z" clip-rule="evenodd"></path>
|
|
|
+ </svg>
|
|
|
+ <p class="text-sm">Click "View PDF" to open with full viewer controls</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="mt-3 flex flex-col items-center space-y-2">
|
|
|
+ <p class="text-xs text-gray-500 dark:text-gray-400">PDF viewer with zoom, search, navigation & print support</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
{% endif %}
|
|
|
</div>
|
|
|
|
|
|
@@ -471,5 +523,112 @@
|
|
|
}
|
|
|
});
|
|
|
</script>
|
|
|
+
|
|
|
+ <!-- HEIC/HEIF Support -->
|
|
|
+ <script>
|
|
|
+ // Function to handle HEIC/HEIF images
|
|
|
+ async function handleHEICImage(imgElement, fileId) {
|
|
|
+ try {
|
|
|
+ const response = await fetch(`/preview/${fileId}`);
|
|
|
+ const blob = await response.blob();
|
|
|
+
|
|
|
+ if (blob.type === 'image/heic' || blob.type === 'image/heif') {
|
|
|
+ // Convert HEIC to JPEG using heic2any
|
|
|
+ const convertedBlob = await heic2any({
|
|
|
+ blob: blob,
|
|
|
+ toType: 'image/jpeg',
|
|
|
+ quality: 0.8
|
|
|
+ });
|
|
|
+
|
|
|
+ const convertedUrl = URL.createObjectURL(convertedBlob);
|
|
|
+ imgElement.src = convertedUrl;
|
|
|
+
|
|
|
+ // Update the Fancybox link as well
|
|
|
+ const linkElement = imgElement.closest('a[data-fancybox]');
|
|
|
+ if (linkElement) {
|
|
|
+ linkElement.href = convertedUrl;
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('HEIC image converted successfully');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Error converting HEIC image:', error);
|
|
|
+ // Fallback: show error message
|
|
|
+ imgElement.alt = 'HEIC image conversion failed';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check for HEIC images on page load
|
|
|
+ document.addEventListener('DOMContentLoaded', function() {
|
|
|
+ const images = document.querySelectorAll('img[id^="preview-image-"]');
|
|
|
+ images.forEach(img => {
|
|
|
+ img.addEventListener('error', function() {
|
|
|
+ // If image fails to load, it might be HEIC
|
|
|
+ const fileId = this.id.replace('preview-image-', '');
|
|
|
+ handleHEICImage(this, fileId);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ </script>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ <!-- PDF.js Support -->
|
|
|
+ <script>
|
|
|
+ // PDF viewer function
|
|
|
+ function openPDFViewer(pdfUrl, filename) {
|
|
|
+ // Create a modal for PDF viewing
|
|
|
+ const modal = document.createElement('div');
|
|
|
+ modal.className = 'fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50';
|
|
|
+ modal.innerHTML = `
|
|
|
+ <div class="bg-white dark:bg-gray-800 rounded-lg w-11/12 h-5/6 max-w-6xl flex flex-col">
|
|
|
+ <div class="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700">
|
|
|
+ <h3 class="text-lg font-semibold text-gray-900 dark:text-white">${filename}</h3>
|
|
|
+ <div class="flex items-center space-x-2">
|
|
|
+ <button id="pdf-download" class="px-3 py-1 text-sm bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors duration-200">
|
|
|
+ Download
|
|
|
+ </button>
|
|
|
+ <button onclick="this.closest('.fixed').remove()" class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300">
|
|
|
+ <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
|
|
+ </svg>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="flex-1 p-4">
|
|
|
+ <iframe src="${pdfUrl}" class="w-full h-full border-0 rounded" title="${filename}"></iframe>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ `;
|
|
|
+
|
|
|
+ document.body.appendChild(modal);
|
|
|
+
|
|
|
+ // Add download functionality
|
|
|
+ modal.querySelector('#pdf-download').addEventListener('click', function() {
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = pdfUrl;
|
|
|
+ link.download = filename;
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ document.body.removeChild(link);
|
|
|
+ });
|
|
|
+
|
|
|
+ // Close modal when clicking outside
|
|
|
+ modal.addEventListener('click', function(e) {
|
|
|
+ if (e.target === modal) {
|
|
|
+ modal.remove();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // Close modal with Escape key
|
|
|
+ const handleEscape = function(e) {
|
|
|
+ if (e.key === 'Escape') {
|
|
|
+ modal.remove();
|
|
|
+ document.removeEventListener('keydown', handleEscape);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ document.addEventListener('keydown', handleEscape);
|
|
|
+ }
|
|
|
+ </script>
|
|
|
</body>
|
|
|
</html>
|