This commit is contained in:
@@ -282,4 +282,15 @@ kbd {
|
||||
.attachment-item a:hover {
|
||||
color: #60a5fa;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
/* File Viewer */
|
||||
#fileViewerModal .modal-content {
|
||||
border-color: var(--neptune-border);
|
||||
}
|
||||
|
||||
#fileViewerBody pre {
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
@@ -588,13 +588,20 @@ async function renderAttachments(eventId, container) {
|
||||
container.innerHTML = attachments.map(a => {
|
||||
const icon = getFileIcon(a.mime_type, a.original_name);
|
||||
const size = formatFileSize(a.file_size);
|
||||
const ext = a.original_name.split('.').pop().toLowerCase();
|
||||
const viewable = ['txt', 'md', 'csv'].includes(ext);
|
||||
const href = viewable ? '#' : '/download/?file=' + encodeURIComponent(a.stored_name) + '&mode=download';
|
||||
const onclick = viewable ? ` onclick="event.preventDefault();openFileViewer('${esc(a.stored_name)}','${esc(a.original_name)}')"` : '';
|
||||
return `<div class="attachment-item d-flex align-items-center justify-content-between py-1">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="fas ${icon} me-2" style="font-size:.85rem;"></i>
|
||||
<a href="/uploads/${a.stored_name}" target="_blank" class="small text-decoration-none" style="word-break:break-all;">${esc(a.original_name)}</a>
|
||||
<small class="text-secondary ms-2">(${size})</small>
|
||||
<div class="d-flex align-items-center" style="min-width:0;">
|
||||
<i class="fas ${icon} me-2" style="font-size:.85rem;flex-shrink:0;"></i>
|
||||
<a href="${href}"${onclick} target="_blank" class="small text-decoration-none text-truncate" style="color:var(--neptune-accent);">${esc(a.original_name)}</a>
|
||||
<small class="text-secondary ms-2 flex-shrink-0">(${size})</small>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-1 flex-shrink-0">
|
||||
<a href="/download/?file=${encodeURIComponent(a.stored_name)}&mode=download" class="btn btn-outline-primary btn-sm py-0 px-1" title="Download" style="font-size:.6rem;"><i class="fas fa-download"></i></a>
|
||||
<button class="btn btn-outline-danger btn-sm py-0 px-1" onclick="deleteAttachment(${a.id}, this)" title="Delete file" style="font-size:.6rem;"><i class="fas fa-times"></i></button>
|
||||
</div>
|
||||
<button class="btn btn-outline-danger btn-sm py-0 px-1 ms-2" onclick="deleteAttachment(${a.id}, this)" title="Delete file" style="font-size:.65rem;"><i class="fas fa-times"></i></button>
|
||||
</div>`;
|
||||
}).join('');
|
||||
}
|
||||
@@ -618,6 +625,41 @@ function getFileIcon(mime, name) {
|
||||
return 'fa-file';
|
||||
}
|
||||
|
||||
function openFileViewer(storedName, originalName) {
|
||||
const modalEl = document.getElementById('fileViewerModal');
|
||||
document.getElementById('fileViewerName').textContent = originalName;
|
||||
document.getElementById('fileViewerDownloadBtn').onclick = () => {
|
||||
window.open('/download/?file=' + encodeURIComponent(storedName) + '&mode=download', '_blank');
|
||||
};
|
||||
const body = document.getElementById('fileViewerBody');
|
||||
body.innerHTML = '<div class="text-center text-secondary py-5"><div class="spinner-border" role="status"></div><p class="mt-2 small">Loading file...</p></div>';
|
||||
|
||||
const modal = new bootstrap.Modal(modalEl);
|
||||
modal.show();
|
||||
|
||||
const ext = originalName.split('.').pop().toLowerCase();
|
||||
if (ext === 'pdf') {
|
||||
body.innerHTML = `<iframe src="/download/?file=${encodeURIComponent(storedName)}&mode=view" style="width:100%;min-height:80vh;border:none;"></iframe>`;
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('/download/?file=' + encodeURIComponent(storedName) + '&mode=view')
|
||||
.then(r => {
|
||||
if (!r.ok) throw new Error('Failed to load');
|
||||
return r.text();
|
||||
})
|
||||
.then(text => {
|
||||
if (ext === 'md') {
|
||||
body.innerHTML = '<div class="p-3" style="white-space:pre-wrap;font-family:var(--bs-font-monospace);font-size:.85rem;line-height:1.6;color:#e2e8f0;">' + esc(text) + '</div>';
|
||||
} else {
|
||||
body.innerHTML = '<div class="p-3" style="white-space:pre-wrap;font-family:var(--bs-font-monospace);font-size:.85rem;line-height:1.6;color:#e2e8f0;">' + esc(text) + '</div>';
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
body.innerHTML = '<div class="text-center text-danger py-5"><i class="fas fa-exclamation-circle fs-2 mb-2"></i><p class="small">Failed to load file</p></div>';
|
||||
});
|
||||
}
|
||||
|
||||
async function saveEvent() {
|
||||
const tags = parseEventTags();
|
||||
const data = {
|
||||
|
||||
Reference in New Issue
Block a user