diff --git a/admin-dashboard.html b/admin-dashboard.html index b0ee6d3..66d281b 100644 --- a/admin-dashboard.html +++ b/admin-dashboard.html @@ -603,6 +603,121 @@ text-align: center; z-index: 2; } + + /* Upload Box Styles */ + .upload-box { + border: 2px dashed #dee2e6; + border-radius: 8px; + background-color: #f8f9fa; + transition: all 0.3s ease; + overflow: hidden; + min-height: 200px; + display: flex; + align-items: center; + justify-content: center; + } + + .upload-box.dragover { + border-color: #0d6efd; + background-color: rgba(13, 110, 253, 0.05); + } + + .upload-prompt { + padding: 2rem; + max-width: 320px; + margin: 0 auto; + } + + .upload-icon { + color: #adb5bd; + transition: color 0.2s; + } + + .upload-box:hover .upload-icon { + color: #6c757d; + } + + /* Image Preview Styles */ + .image-preview { + width: 100%; + height: 100%; + padding: 1rem; + } + + .preview-container { + position: relative; + width: 100%; + height: 100%; + border-radius: 6px; + overflow: hidden; + background-color: #f1f3f5; + display: flex; + align-items: center; + justify-content: center; + min-height: 180px; + } + + .preview-container img { + max-width: 100%; + max-height: 100%; + object-fit: contain; + } + + .preview-overlay { + position: absolute; + bottom: 1rem; + left: 50%; + transform: translateX(-50%); + opacity: 0; + transition: opacity 0.2s; + display: flex; + gap: 0.5rem; + } + + .preview-container:hover .preview-overlay { + opacity: 1; + } + + .preview-overlay .btn { + width: 36px; + height: 36px; + display: inline-flex; + align-items: center; + justify-content: center; + box-shadow: 0 2px 8px rgba(0,0,0,0.1); + } + + /* Position Controls */ + .position-controls .btn-group { + box-shadow: 0 1px 3px rgba(0,0,0,0.1); + } + + .position-controls .btn { + transition: all 0.2s; + font-weight: 500; + } + + .position-controls .btn.active { + background-color: #0d6efd; + color: white; + border-color: #0d6efd; + } + + /* Responsive Adjustments */ + @media (max-width: 768px) { + .upload-box { + min-height: 160px; + } + + .upload-prompt { + padding: 1.5rem; + } + + .preview-overlay { + opacity: 1; + bottom: 0.5rem; + } + } @@ -644,34 +759,53 @@
- -
+ + + +
- Náhled obrázku -
- -

Přetáhněte obrázek sem nebo klikněte pro nahrání

- + + +
+
+ +
+
Přetáhněte obrázek sem
+

Nebo

+ +

Podporované formáty: JPG, PNG, GIF (max. 5MB)

+
+ + +
-
- -
- -
- + +
+
- - -
@@ -918,17 +1052,115 @@ document.addEventListener('DOMContentLoaded', () => { } }); - // Set up image position buttons - document.querySelectorAll('.image-pos-btn').forEach(btn => { + // Initialize upload functionality + const uploadPrompt = document.getElementById('uploadPrompt'); + const imagePreview = document.getElementById('imagePreview'); + const bannerImagePreview = document.getElementById('bannerImagePreview'); + const fileInput = document.getElementById('fileElem'); + const uploadBtn = document.getElementById('uploadBtn'); + const changeImageBtn = document.getElementById('changeImageBtn'); + const removeImageBtn = document.getElementById('removeImageBtn'); + const dropArea = document.getElementById('dropArea'); + + // Initialize image position buttons + document.querySelectorAll('.position-btn').forEach(btn => { btn.addEventListener('click', function() { - document.querySelectorAll('.image-pos-btn').forEach(b => b.classList.remove('active')); - this.classList.add('active'); + document.querySelectorAll('.position-btn').forEach(b => { + b.classList.remove('active', 'btn-primary'); + b.classList.add('btn-outline-secondary'); + }); + this.classList.add('active', 'btn-primary'); + this.classList.remove('btn-outline-secondary'); updateBannerPreview(); }); }); - // Initialize save button - saveBannerBtn = document.getElementById('saveBannerBtn'); + // Handle file selection + function handleFileSelect(file) { + if (!file) return; + + // Check file type + const validTypes = ['image/jpeg', 'image/png', 'image/gif']; + if (!validTypes.includes(file.type)) { + showNotification('Nepodporovaný formát souboru. Povolené formáty: JPG, PNG, GIF', 'error'); + return; + } + + // Check file size (5MB max) + if (file.size > 5 * 1024 * 1024) { + showNotification('Soubor je příliš velký. Maximální velikost je 5MB.', 'error'); + return; + } + + // Show preview + const reader = new FileReader(); + reader.onload = function(e) { + currentImage = e.target.result; + bannerImagePreview.src = currentImage; + uploadPrompt.style.display = 'none'; + imagePreview.style.display = 'block'; + updateBannerPreview(); + }; + reader.readAsDataURL(file); + } + + // Handle file input change + fileInput.addEventListener('change', function() { + if (this.files && this.files[0]) { + handleFileSelect(this.files[0]); + } + }); + + // Handle upload button click + uploadBtn.addEventListener('click', () => fileInput.click()); + + // Handle change image button + if (changeImageBtn) { + changeImageBtn.addEventListener('click', () => fileInput.click()); + } + + // Handle remove image button + if (removeImageBtn) { + removeImageBtn.addEventListener('click', function() { + currentImage = null; + fileInput.value = ''; + if (uploadPrompt) uploadPrompt.style.display = 'flex'; + if (imagePreview) imagePreview.style.display = 'none'; + updateBannerPreview(); + }); + } + + // Handle drag and drop + ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { + dropArea.addEventListener(eventName, preventDefaults, false); + }); + + function highlight() { + dropArea.classList.add('dragover'); + } + + function unhighlight() { + dropArea.classList.remove('dragover'); + } + + ['dragenter', 'dragover'].forEach(eventName => { + dropArea.addEventListener(eventName, highlight, false); + }); + + ['dragleave', 'drop'].forEach(eventName => { + dropArea.addEventListener(eventName, unhighlight, false); + }); + + dropArea.addEventListener('drop', function(e) { + const dt = e.dataTransfer; + const file = dt.files[0]; + if (file) { + handleFileSelect(file); + } + }); + + // Set up save button + const saveBannerBtn = document.getElementById('saveBannerBtn'); if (saveBannerBtn) { saveBannerBtn.addEventListener('click', saveBanner); } @@ -936,12 +1168,6 @@ document.addEventListener('DOMContentLoaded', () => { // Set up color input listeners setupColorInputListeners(); - // Set up remove image button - const removeImageBtn = document.getElementById('removeImageBtn'); - if (removeImageBtn) { - removeImageBtn.addEventListener('click', removeImage); - } - // Initial preview update updateBannerPreview(); @@ -949,17 +1175,10 @@ document.addEventListener('DOMContentLoaded', () => { loadBanner(); }); -// Handle dropped files - -function handleDrop(e) { - const dt = e.dataTransfer; - const files = dt.files; - - if (files.length) { - bannerImage.files = files; - const event = new Event('change'); - bannerImage.dispatchEvent(event); - } +// Prevent default drag behaviors +function preventDefaults(e) { + e.preventDefault(); + e.stopPropagation(); } // Handle image upload @@ -1070,9 +1289,7 @@ document.getElementById('logoutBtn').addEventListener('click', function() { }); // DOM Elements -const bannerText = document.getElementById('bannerText'); -// These will be initialized in DOMContentLoaded -let bannerVisible, bannerBgColor, bannerTextColor, bannerTextAlign, bannerFontSize, +let bannerText, bannerVisible, bannerBgColor, bannerTextColor, bannerTextAlign, bannerFontSize, bannerPadding, bannerMargin, bannerBorderRadius, bannerPreview, bannerPreviewContent, bannerPreviewText, bannerPreviewBg, bgColorPreview, textColorPreview, saveBannerBtn, stylePresets, currentImage = null, currentTemplate = 'modern-minimal'; @@ -1323,12 +1540,20 @@ async function saveBanner(event) { // Handle image upload if a new image was selected const fileInput = document.getElementById('bannerImage'); - if (fileInput.files.length > 0) { + if (fileInput && fileInput.files && fileInput.files.length > 0) { formData.append('image', fileInput.files[0]); } else if (currentImage && currentImage.startsWith('data:image')) { - // If we have a data URL but no file input, convert it to a blob - const blob = await fetch(currentImage).then(r => r.blob()); - formData.append('image', blob, 'banner-image.jpg'); + try { + // If we have a data URL but no file input, convert it to a blob + const response = await fetch(currentImage); + if (!response.ok) throw new Error('Failed to fetch image'); + const blob = await response.blob(); + formData.append('image', blob, 'banner-image.jpg'); + } catch (error) { + console.error('Error processing image:', error); + showNotification('Chyba při zpracování obrázku', 'error'); + throw error; + } } // Log form data for debugging (without the actual file data) @@ -1502,7 +1727,8 @@ function updateBannerPreview() { // Get the current template config or use default const template = currentTemplate ? templateConfigs[currentTemplate] : templateConfigs['modern-minimal']; - const hasImage = currentImage || (bannerImage && bannerImage.files.length > 0); + const fileInput = document.getElementById('bannerImage'); + const hasImage = currentImage || (fileInput && fileInput.files && fileInput.files.length > 0); // Show/hide templates and size controls based on image presence if (bannerTemplates) {