{% extends "base.html" %} {% block title %}{{ topic.title }} - Forum - Norda Biznes Partner{% endblock %} {% block extra_css %} {% endblock %} {% block content %}

{% if topic.is_pinned %} Przypięty {% endif %} {% if topic.is_locked %} Zamknięty {% endif %} {{ category_labels.get(topic.category, 'Pytanie') }} {{ status_labels.get(topic.status, 'Nowy') }} {{ topic.title }}

{{ topic.author.name or topic.author.email.split('@')[0] }} {% if topic.is_ai_generated %} AI {% endif %} {{ topic.created_at.strftime('%d.%m.%Y %H:%M') }} {{ topic.views_count }} wyświetleń
{{ topic.content }}
{% if topic.attachments %} {% for attachment in topic.attachments %}
{{ attachment.original_filename }}
{{ attachment.original_filename }} ({{ (attachment.file_size / 1024)|int }} KB)
{% endfor %} {% endif %}

Odpowiedzi ({{ topic.replies|length }})

{% if topic.replies %}
{% for reply in topic.replies %}
{{ (reply.author.name or reply.author.email)[0].upper() }}
{{ reply.author.name or reply.author.email.split('@')[0] }} {% if reply.is_ai_generated %} AI {% endif %}
{{ reply.created_at.strftime('%d.%m.%Y %H:%M') }}
{{ reply.content }}
{% if reply.attachments %}
{% for attachment in reply.attachments %}
{{ attachment.original_filename }}
{{ attachment.original_filename|truncate(20) }} ({{ (attachment.file_size / 1024)|int }} KB)
{% endfor %}
{% endif %}
{% endfor %}
{% else %}
Brak odpowiedzi. Bądź pierwszy!
{% endif %}
{% if topic.is_locked %}
Ten temat jest zamknięty. Nie można dodawać nowych odpowiedzi.
{% else %}

Dodaj odpowiedź

Przeciągnij obrazy lub kliknij tutaj (max 10 plików, możesz też wkleić Ctrl+V)

{% endif %}
{% endblock %} {% block extra_js %} function showToast(message, type = 'info', duration = 4000) { const container = document.getElementById('toastContainer'); const icons = { success: '✓', error: '✕', warning: '⚠', info: 'ℹ' }; const toast = document.createElement('div'); toast.className = `toast ${type}`; toast.innerHTML = `${icons[type]||'ℹ'}${message}`; container.appendChild(toast); setTimeout(() => { toast.style.animation = 'toastOut 0.3s ease forwards'; setTimeout(() => toast.remove(), 300); }, duration); } // Lightbox functions function openLightbox(src) { document.getElementById('lightboxImage').src = src; document.getElementById('lightbox').classList.add('active'); } function closeLightbox() { document.getElementById('lightbox').classList.remove('active'); } // Close lightbox with Escape key document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { closeLightbox(); } }); // Multi-file upload handling (only if form exists) const dropzone = document.getElementById('dropzone'); if (dropzone) { const fileInput = document.getElementById('attachmentInput'); const previewsContainer = document.getElementById('previewsContainer'); const uploadCounter = document.getElementById('uploadCounter'); const replyContent = document.getElementById('replyContent'); const MAX_FILES = 10; const MAX_SIZE = 5 * 1024 * 1024; // 5MB const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/gif']; // Store files in a Map for easy removal let filesMap = new Map(); let fileIdCounter = 0; // Click to upload dropzone.addEventListener('click', () => fileInput.click()); // Drag and drop dropzone.addEventListener('dragover', (e) => { e.preventDefault(); dropzone.classList.add('drag-over'); }); dropzone.addEventListener('dragleave', () => { dropzone.classList.remove('drag-over'); }); dropzone.addEventListener('drop', (e) => { e.preventDefault(); dropzone.classList.remove('drag-over'); const droppedFiles = Array.from(e.dataTransfer.files).filter(f => f.type.startsWith('image/')); addFiles(droppedFiles); }); // File input change fileInput.addEventListener('change', (e) => { const selectedFiles = Array.from(e.target.files); addFiles(selectedFiles); // Reset input to allow selecting same files again fileInput.value = ''; }); // Paste from clipboard (Ctrl+V) document.addEventListener('paste', (e) => { // Only handle paste if reply textarea is focused if (document.activeElement !== replyContent && !replyContent.contains(document.activeElement)) { return; } const items = e.clipboardData?.items; if (!items) return; const pastedFiles = []; for (let i = 0; i < items.length; i++) { if (items[i].type.startsWith('image/')) { e.preventDefault(); const file = items[i].getAsFile(); if (file) { pastedFiles.push(file); } } } if (pastedFiles.length > 0) { addFiles(pastedFiles); } }); function addFiles(newFiles) { const currentCount = filesMap.size; const availableSlots = MAX_FILES - currentCount; if (availableSlots <= 0) { showToast('Osiągnięto limit ' + MAX_FILES + ' plików', 'warning'); return; } const filesToAdd = newFiles.slice(0, availableSlots); const errors = []; filesToAdd.forEach(file => { // Validate size if (file.size > MAX_SIZE) { errors.push(file.name + ': za duży (max 5MB)'); return; } // Validate type if (!ALLOWED_TYPES.includes(file.type)) { errors.push(file.name + ': niedozwolony format'); return; } const fileId = 'file_' + (fileIdCounter++); filesMap.set(fileId, file); createPreview(fileId, file); }); if (errors.length > 0) { showToast('Błędy: ' + errors.join(', '), 'error'); } updateCounter(); syncFilesToInput(); } function createPreview(fileId, file) { const preview = document.createElement('div'); preview.className = 'upload-preview-item'; preview.dataset.fileId = fileId; const img = document.createElement('img'); const info = document.createElement('div'); info.className = 'preview-info'; info.textContent = file.name.substring(0, 15) + (file.name.length > 15 ? '...' : '') + ' (' + formatFileSize(file.size) + ')'; const removeBtn = document.createElement('button'); removeBtn.type = 'button'; removeBtn.className = 'remove-preview'; removeBtn.innerHTML = '×'; removeBtn.title = 'Usuń'; removeBtn.onclick = () => removeFile(fileId); preview.appendChild(img); preview.appendChild(info); preview.appendChild(removeBtn); previewsContainer.appendChild(preview); // Load image preview const reader = new FileReader(); reader.onload = (e) => { img.src = e.target.result; }; reader.readAsDataURL(file); } function removeFile(fileId) { filesMap.delete(fileId); const preview = previewsContainer.querySelector('[data-file-id="' + fileId + '"]'); if (preview) { preview.remove(); } updateCounter(); syncFilesToInput(); } function updateCounter() { const count = filesMap.size; if (count === 0) { uploadCounter.textContent = ''; uploadCounter.classList.remove('limit-reached'); dropzone.style.display = 'block'; } else { uploadCounter.textContent = 'Wybrano: ' + count + '/' + MAX_FILES + ' plikow'; uploadCounter.classList.toggle('limit-reached', count >= MAX_FILES); dropzone.style.display = count >= MAX_FILES ? 'none' : 'block'; } } function syncFilesToInput() { // Create DataTransfer and add all files from Map const dataTransfer = new DataTransfer(); filesMap.forEach(file => { dataTransfer.items.add(file); }); fileInput.files = dataTransfer.files; } function formatFileSize(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / (1024 * 1024)).toFixed(1) + ' MB'; } } {% endblock %}