Add authentication #17
2 changed files with 300 additions and 171 deletions
|
@ -138,11 +138,45 @@ const {
|
||||||
|
|
||||||
getFileType(fileName) {
|
getFileType(fileName) {
|
||||||
const ext = fileName.split(".").pop()?.toLowerCase() || "";
|
const ext = fileName.split(".").pop()?.toLowerCase() || "";
|
||||||
if (["jpg", "jpeg", "png", "gif", "webp"].includes(ext))
|
// Images
|
||||||
|
if (
|
||||||
|
["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp"].includes(
|
||||||
|
ext
|
||||||
|
)
|
||||||
|
)
|
||||||
return "image";
|
return "image";
|
||||||
if (["mp4", "webm", "ogg"].includes(ext)) return "video";
|
// Videos
|
||||||
if (["mp3", "wav", "ogg"].includes(ext)) return "audio";
|
if (["mp4", "webm", "ogg", "mov", "avi"].includes(ext))
|
||||||
|
return "video";
|
||||||
|
// Audio
|
||||||
|
if (["mp3", "wav", "ogg", "m4a", "aac"].includes(ext))
|
||||||
|
return "audio";
|
||||||
|
// Documents
|
||||||
if (["pdf"].includes(ext)) return "pdf";
|
if (["pdf"].includes(ext)) return "pdf";
|
||||||
|
if (["doc", "docx"].includes(ext)) return "word";
|
||||||
|
if (["xls", "xlsx"].includes(ext)) return "excel";
|
||||||
|
if (["ppt", "pptx"].includes(ext)) return "powerpoint";
|
||||||
|
if (["txt", "rtf", "md"].includes(ext)) return "text";
|
||||||
|
// Archives
|
||||||
|
if (["zip", "rar", "7z", "tar", "gz"].includes(ext))
|
||||||
|
return "archive";
|
||||||
|
// Code
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
"js",
|
||||||
|
"ts",
|
||||||
|
"py",
|
||||||
|
"java",
|
||||||
|
"cpp",
|
||||||
|
"c",
|
||||||
|
"cs",
|
||||||
|
"html",
|
||||||
|
"css",
|
||||||
|
"php",
|
||||||
|
"rb",
|
||||||
|
].includes(ext)
|
||||||
|
)
|
||||||
|
return "code";
|
||||||
return "other";
|
return "other";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,16 +196,24 @@ const {
|
||||||
element = document.createElement("video");
|
element = document.createElement("video");
|
||||||
element.className = "w-full h-full";
|
element.className = "w-full h-full";
|
||||||
element.setAttribute("controls", "");
|
element.setAttribute("controls", "");
|
||||||
|
element.setAttribute("controlsList", "nodownload");
|
||||||
|
element.setAttribute("preload", "metadata");
|
||||||
element.src = file.url;
|
element.src = file.url;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "audio":
|
case "audio":
|
||||||
element = document.createElement("div");
|
element = document.createElement("div");
|
||||||
element.className =
|
element.className =
|
||||||
"w-full h-full flex items-center justify-center p-4";
|
"w-full h-full flex flex-col items-center justify-center p-8 gap-4";
|
||||||
|
// Add audio icon
|
||||||
|
element.innerHTML = `
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-24 w-24 text-base-content/50" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path fill-rule="evenodd" d="M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM14.657 2.929a1 1 0 011.414 0A9.972 9.972 0 0119 10a9.972 9.972 0 01-2.929 7.071 1 1 0 01-1.414-1.414A7.971 7.971 0 0017 10c0-2.21-.894-4.208-2.343-5.657a1 1 0 010-1.414zm-2.829 2.828a1 1 0 011.415 0A5.983 5.983 0 0115 10a5.984 5.984 0 01-1.757 4.243 1 1 0 01-1.415-1.415A3.984 3.984 0 0013 10a3.983 3.983 0 00-1.172-2.828 1 1 0 010-1.415z" clip-rule="evenodd" />
|
||||||
|
</svg>`;
|
||||||
const audio = document.createElement("audio");
|
const audio = document.createElement("audio");
|
||||||
audio.className = "w-full";
|
audio.className = "w-full max-w-md";
|
||||||
audio.setAttribute("controls", "");
|
audio.setAttribute("controls", "");
|
||||||
|
audio.setAttribute("controlsList", "nodownload");
|
||||||
audio.src = file.url;
|
audio.src = file.url;
|
||||||
element.appendChild(audio);
|
element.appendChild(audio);
|
||||||
break;
|
break;
|
||||||
|
@ -183,7 +225,41 @@ const {
|
||||||
element.src = file.url + "#toolbar=0&navpanes=0";
|
element.src = file.url + "#toolbar=0&navpanes=0";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "word":
|
||||||
|
case "excel":
|
||||||
|
case "powerpoint":
|
||||||
|
case "text":
|
||||||
|
case "code":
|
||||||
|
// For documents that might be previewable, offer both preview and download
|
||||||
|
element = document.createElement("div");
|
||||||
|
element.className =
|
||||||
|
"w-full h-full flex flex-col items-center justify-center p-8 gap-4";
|
||||||
|
const icon = this.getFileTypeIcon(fileType);
|
||||||
|
element.innerHTML = `
|
||||||
|
<div class="text-center">
|
||||||
|
${icon}
|
||||||
|
<p class="mt-4 font-medium">${file.name}</p>
|
||||||
|
<p class="text-base-content/70 mb-4">This file type may not be previewable in the browser</p>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<a href="${file.url}" target="_blank" class="btn btn-primary btn-sm">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path d="M11 3a1 1 0 100 2h2.586l-6.293 6.293a1 1 0 101.414 1.414L15 6.414V9a1 1 0 102 0V4a1 1 0 00-1-1h-5z" />
|
||||||
|
</svg>
|
||||||
|
Open in New Tab
|
||||||
|
</a>
|
||||||
|
<a href="${file.url}" download class="btn btn-ghost btn-sm">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path fill-rule="evenodd" d="M3 17a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm3.293-7.707a1 1 0 011.414 0L9 10.586V3a1 1 0 112 0v7.586l1.293-1.293a1 1 0 111.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
Download
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
// For other file types, show a download option
|
||||||
element = document.createElement("div");
|
element = document.createElement("div");
|
||||||
element.className =
|
element.className =
|
||||||
"w-full h-full flex items-center justify-center";
|
"w-full h-full flex items-center justify-center";
|
||||||
|
@ -192,8 +268,13 @@ const {
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 mx-auto mb-4 text-base-content/50" viewBox="0 0 20 20" fill="currentColor">
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 mx-auto mb-4 text-base-content/50" viewBox="0 0 20 20" fill="currentColor">
|
||||||
<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 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" />
|
||||||
</svg>
|
</svg>
|
||||||
<p>This file type cannot be previewed</p>
|
<p class="mb-4">${file.name}</p>
|
||||||
<a href="${file.url}" target="_blank" class="btn btn-primary btn-sm mt-4">Download File</a>
|
<a href="${file.url}" download class="btn btn-primary btn-sm">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path fill-rule="evenodd" d="M3 17a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm3.293-7.707a1 1 0 011.414 0L9 10.586V3a1 1 0 112 0v7.586l1.293-1.293a1 1 0 111.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
Download File
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -201,6 +282,33 @@ const {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getFileTypeIcon(fileType) {
|
||||||
|
const iconClasses = "h-24 w-24 mx-auto text-base-content/50";
|
||||||
|
switch (fileType) {
|
||||||
|
case "word":
|
||||||
|
return `<svg xmlns="http://www.w3.org/2000/svg" class="${iconClasses}" viewBox="0 0 384 512">
|
||||||
|
<path fill="currentColor" d="M48 448V64c0-8.8 7.2-16 16-16h256c8.8 0 16 7.2 16 16v384c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16zm16-64h256V80H64v304zm48-208h160c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16zm0 64h160c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16zm0 64h160c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16z"/>
|
||||||
|
</svg>`;
|
||||||
|
case "excel":
|
||||||
|
return `<svg xmlns="http://www.w3.org/2000/svg" class="${iconClasses}" viewBox="0 0 384 512">
|
||||||
|
<path fill="currentColor" d="M48 448V64c0-8.8 7.2-16 16-16h256c8.8 0 16 7.2 16 16v384c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16zm16-64h256V80H64v304zm48-208h160c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16zm0 128h160c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16z"/>
|
||||||
|
</svg>`;
|
||||||
|
case "powerpoint":
|
||||||
|
return `<svg xmlns="http://www.w3.org/2000/svg" class="${iconClasses}" viewBox="0 0 384 512">
|
||||||
|
<path fill="currentColor" d="M48 448V64c0-8.8 7.2-16 16-16h256c8.8 0 16 7.2 16 16v384c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16zm16-64h256V80H64v304zm144-208c35.3 0 64 28.7 64 64s-28.7 64-64 64h-48v48c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16h64zm0 96c17.7 0 32-14.3 32-32s-14.3-32-32-32h-48v64h48z"/>
|
||||||
|
</svg>`;
|
||||||
|
case "text":
|
||||||
|
case "code":
|
||||||
|
return `<svg xmlns="http://www.w3.org/2000/svg" class="${iconClasses}" viewBox="0 0 384 512">
|
||||||
|
<path fill="currentColor" d="M48 448V64c0-8.8 7.2-16 16-16h256c8.8 0 16 7.2 16 16v384c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16zm16-64h256V80H64v304zm48-208h160c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16zm0 64h160c8.8 0 16 7.2 16 16s-7.2 16-16 16H112c-8.8 0-16-7.2-16-16s7.2-16 16-16z"/>
|
||||||
|
</svg>`;
|
||||||
|
default:
|
||||||
|
return `<svg xmlns="http://www.w3.org/2000/svg" class="${iconClasses}" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<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" />
|
||||||
|
</svg>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
showLoading(isMultiple = false) {
|
showLoading(isMultiple = false) {
|
||||||
if (isMultiple) {
|
if (isMultiple) {
|
||||||
if (this.multipleLoadingElement) {
|
if (this.multipleLoadingElement) {
|
||||||
|
|
|
@ -1,3 +1,12 @@
|
||||||
|
---
|
||||||
|
// Import the FilePreviewModal component
|
||||||
|
import FilePreviewModal from "../modals/FilePreviewModal.astro";
|
||||||
|
|
||||||
|
// Define the component's props and setup
|
||||||
|
interface Props {}
|
||||||
|
const {} = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 h-full">
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 h-full">
|
||||||
<!-- Left Column - Events List -->
|
<!-- Left Column - Events List -->
|
||||||
<div class="card bg-base-200 shadow-xl h-full">
|
<div class="card bg-base-200 shadow-xl h-full">
|
||||||
|
@ -115,72 +124,24 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- PDF Viewer Modal -->
|
<!-- Add the FilePreviewModal component -->
|
||||||
<dialog id="pdfViewer" class="modal">
|
<FilePreviewModal id="eventFileViewer" title="Event Files" />
|
||||||
<div class="modal-box w-11/12 max-w-5xl h-[80vh]">
|
|
||||||
<div class="flex justify-between items-center mb-4">
|
|
||||||
<h3 class="font-bold text-lg" id="pdfTitle">Resume</h3>
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<a
|
|
||||||
id="pdfExternalLink"
|
|
||||||
href="#"
|
|
||||||
target="_blank"
|
|
||||||
class="btn btn-sm btn-ghost"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
class="h-4 w-4 mr-1"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M11 3a1 1 0 100 2h2.586l-6.293 6.293a1 1 0 101.414 1.414L15 6.414V9a1 1 0 102 0V4a1 1 0 00-1-1h-5z"
|
|
||||||
></path>
|
|
||||||
<path
|
|
||||||
d="M5 5a2 2 0 00-2 2v8a2 2 0 002 2h8a2 2 0 002-2v-3a1 1 0 10-2 0v3H5z"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
Open in New Tab
|
|
||||||
</a>
|
|
||||||
<form method="dialog">
|
|
||||||
<button class="btn btn-sm btn-circle btn-ghost">✕</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="h-[calc(100%-4rem)]">
|
|
||||||
<iframe
|
|
||||||
id="pdfFrame"
|
|
||||||
class="w-full h-full rounded-lg border-2 border-base-300"
|
|
||||||
src=""></iframe>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<form method="dialog" class="modal-backdrop">
|
|
||||||
<button>close</button>
|
|
||||||
</form>
|
|
||||||
</dialog>
|
|
||||||
|
|
||||||
<!-- File Viewer Modal -->
|
|
||||||
<dialog id="fileViewer" class="modal">
|
|
||||||
<div class="modal-box w-11/12 max-w-5xl">
|
|
||||||
<div class="flex justify-between items-center mb-4">
|
|
||||||
<h3 class="font-bold text-lg" id="fileViewerTitle">Event Files</h3>
|
|
||||||
<form method="dialog">
|
|
||||||
<button class="btn btn-sm btn-circle btn-ghost">✕</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
id="fileViewerContent"
|
|
||||||
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"
|
|
||||||
>
|
|
||||||
<!-- Files will be dynamically inserted here -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<form method="dialog" class="modal-backdrop">
|
|
||||||
<button>close</button>
|
|
||||||
</form>
|
|
||||||
</dialog>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// TypeScript declarations
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
showEventFiles: (eventId: string) => Promise<void>;
|
||||||
|
filePreviewModal: {
|
||||||
|
show: (
|
||||||
|
file:
|
||||||
|
| { url: string; name: string }
|
||||||
|
| Array<{ url: string; name: string }>
|
||||||
|
) => void;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
import { Authentication } from "../pocketbase/Authentication";
|
import { Authentication } from "../pocketbase/Authentication";
|
||||||
import { Get } from "../pocketbase/Get";
|
import { Get } from "../pocketbase/Get";
|
||||||
import { SendLog } from "../pocketbase/SendLog";
|
import { SendLog } from "../pocketbase/SendLog";
|
||||||
|
@ -341,7 +302,7 @@
|
||||||
? `
|
? `
|
||||||
<button
|
<button
|
||||||
class="btn btn-ghost btn-xs gap-2"
|
class="btn btn-ghost btn-xs gap-2"
|
||||||
onclick="document.getElementById('fileViewer').showModal(); document.dispatchEvent(new CustomEvent('viewEventFiles', { detail: { eventId: '${event.id}' } }))"
|
onclick="window.showEventFiles('${event.id}')"
|
||||||
>
|
>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
|
||||||
<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 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" />
|
||||||
|
@ -560,112 +521,172 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add event listener for viewing files
|
// Add global function to handle showing event files
|
||||||
interface ViewEventFilesEvent extends CustomEvent {
|
window.showEventFiles = async (eventId: string) => {
|
||||||
detail: {
|
try {
|
||||||
eventId: string;
|
const modal = document.getElementById(
|
||||||
};
|
"eventFileViewer"
|
||||||
}
|
) as HTMLDialogElement;
|
||||||
|
if (!modal) {
|
||||||
|
console.error("Modal element not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener("viewEventFiles", ((e: Event) => {
|
// Show the modal first
|
||||||
if (e instanceof CustomEvent && "eventId" in e.detail) {
|
modal.showModal();
|
||||||
(async () => {
|
|
||||||
try {
|
|
||||||
const event = await get.getOne<Event>(
|
|
||||||
"events",
|
|
||||||
e.detail.eventId
|
|
||||||
);
|
|
||||||
const fileViewerContent =
|
|
||||||
document.getElementById("fileViewerContent");
|
|
||||||
const fileViewerTitle =
|
|
||||||
document.getElementById("fileViewerTitle");
|
|
||||||
|
|
||||||
if (fileViewerContent && fileViewerTitle) {
|
// Fetch the event data
|
||||||
fileViewerTitle.textContent = `Files - ${event.event_name}`;
|
const event = await get.getOne("events", eventId);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!event.files ||
|
!event.files ||
|
||||||
!Array.isArray(event.files) ||
|
!Array.isArray(event.files) ||
|
||||||
event.files.length === 0
|
event.files.length === 0
|
||||||
) {
|
) {
|
||||||
fileViewerContent.innerHTML = `
|
const previewContainer = document.getElementById(
|
||||||
<div class="col-span-full text-center py-4 opacity-70">
|
"eventFileViewer-preview-container"
|
||||||
No files available
|
);
|
||||||
|
if (previewContainer) {
|
||||||
|
previewContainer.innerHTML = `
|
||||||
|
<div class="flex items-center justify-center h-full">
|
||||||
|
<div class="text-center text-base-content/70">
|
||||||
|
<p>No files available</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert files to the format expected by FilePreviewModal
|
||||||
|
const files = event.files.map((file) => {
|
||||||
|
const fileName = file.split("/").pop() || "File";
|
||||||
|
return {
|
||||||
|
url: fileManager.getFileUrl("events", event.id, file),
|
||||||
|
name: fileName,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// If it's a single file, show it directly
|
||||||
|
if (files.length === 1) {
|
||||||
|
const previewContainer = document.getElementById(
|
||||||
|
"eventFileViewer-preview-container"
|
||||||
|
);
|
||||||
|
const loadingElement = document.getElementById(
|
||||||
|
"eventFileViewer-loading"
|
||||||
|
);
|
||||||
|
const titleElement = document.getElementById(
|
||||||
|
"eventFileViewer-title"
|
||||||
|
);
|
||||||
|
const externalLink = document.getElementById(
|
||||||
|
"eventFileViewer-external-link"
|
||||||
|
) as HTMLAnchorElement;
|
||||||
|
|
||||||
|
if (
|
||||||
|
previewContainer &&
|
||||||
|
loadingElement &&
|
||||||
|
titleElement &&
|
||||||
|
externalLink
|
||||||
|
) {
|
||||||
|
// Show loading
|
||||||
|
loadingElement.classList.remove("hidden");
|
||||||
|
previewContainer.classList.add("hidden");
|
||||||
|
|
||||||
|
// Update title and external link
|
||||||
|
titleElement.textContent = files[0].name;
|
||||||
|
externalLink.href = files[0].url;
|
||||||
|
|
||||||
|
// Create preview element
|
||||||
|
const filePreview = document.createElement("div");
|
||||||
|
filePreview.className = "w-full h-full";
|
||||||
|
|
||||||
|
// Handle PDF files
|
||||||
|
if (files[0].name.toLowerCase().endsWith(".pdf")) {
|
||||||
|
filePreview.innerHTML = `
|
||||||
|
<embed
|
||||||
|
src="${files[0].url}#toolbar=0&navpanes=0"
|
||||||
|
type="application/pdf"
|
||||||
|
class="w-full h-full"
|
||||||
|
/>
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
// For other files, show download option
|
||||||
|
filePreview.innerHTML = `
|
||||||
|
<div class="flex items-center justify-center h-full">
|
||||||
|
<div class="text-center">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 mx-auto mb-4 text-base-content/50" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<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" />
|
||||||
|
</svg>
|
||||||
|
<p class="mb-4">${files[0].name}</p>
|
||||||
|
<a href="${files[0].url}" download class="btn btn-primary btn-sm">
|
||||||
|
Download File
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
`;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fileViewerContent.innerHTML = event.files
|
|
||||||
.map((file) => {
|
|
||||||
const fileUrl = fileManager.getFileUrl(
|
|
||||||
"events",
|
|
||||||
event.id,
|
|
||||||
file
|
|
||||||
);
|
|
||||||
const fileName =
|
|
||||||
file.split("/").pop() || "File";
|
|
||||||
const fileExt =
|
|
||||||
fileName.split(".").pop()?.toLowerCase() ||
|
|
||||||
"";
|
|
||||||
|
|
||||||
let preview = "";
|
|
||||||
if (
|
|
||||||
["jpg", "jpeg", "png", "gif"].includes(
|
|
||||||
fileExt
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
preview = `
|
|
||||||
<div class="aspect-video bg-base-300 rounded-t-lg overflow-hidden">
|
|
||||||
<img src="${fileUrl}" alt="${fileName}" class="w-full h-full object-contain">
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
} else {
|
|
||||||
preview = `
|
|
||||||
<div class="aspect-video bg-base-300 rounded-t-lg flex items-center justify-center">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 opacity-50" viewBox="0 0 20 20" fill="currentColor">
|
|
||||||
<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" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `
|
|
||||||
<div class="card bg-base-200">
|
|
||||||
${preview}
|
|
||||||
<div class="card-body p-4">
|
|
||||||
<h3 class="card-title text-sm flex items-center justify-between gap-2" title="${fileName}">
|
|
||||||
<span class="truncate min-w-0">${fileName.substring(0, fileName.lastIndexOf("."))}</span>
|
|
||||||
<span class="text-base-content/50 text-xs uppercase font-mono shrink-0">${fileExt}</span>
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<div class="border-t border-base-300">
|
|
||||||
<a href="${fileUrl}" target="_blank" class="btn btn-ghost btn-sm w-full rounded-none rounded-b-lg gap-2 h-12">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
|
|
||||||
<path d="M11 3a1 1 0 100 2h2.586l-6.293 6.293a1 1 0 101.414 1.414L15 6.414V9a1 1 0 102 0V4a1 1 0 00-1-1h-5z" />
|
|
||||||
<path d="M5 5a2 2 0 00-2 2v8a2 2 0 002 2h8a2 2 0 002-2v-3a1 1 0 10-2 0v3H5V7h3a1 1 0 000-2H5z" />
|
|
||||||
</svg>
|
|
||||||
Open in New Tab
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
})
|
|
||||||
.join("");
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Failed to load event files:", err);
|
|
||||||
const fileViewerContent =
|
|
||||||
document.getElementById("fileViewerContent");
|
|
||||||
if (fileViewerContent) {
|
|
||||||
fileViewerContent.innerHTML = `
|
|
||||||
<div class="col-span-full text-center py-4 text-error">
|
|
||||||
Failed to load files. Please try again.
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear previous content and add new preview
|
||||||
|
previewContainer.innerHTML = "";
|
||||||
|
previewContainer.appendChild(filePreview);
|
||||||
|
|
||||||
|
// Hide loading after a short delay
|
||||||
|
setTimeout(() => {
|
||||||
|
loadingElement.classList.add("hidden");
|
||||||
|
previewContainer.classList.remove("hidden");
|
||||||
|
}, 500);
|
||||||
}
|
}
|
||||||
})();
|
} else {
|
||||||
|
// For multiple files, show the grid view
|
||||||
|
const fileGrid = document.getElementById(
|
||||||
|
"eventFileViewer-file-grid"
|
||||||
|
);
|
||||||
|
const multipleView = document.getElementById(
|
||||||
|
"eventFileViewer-multiple"
|
||||||
|
);
|
||||||
|
const singleView = document.getElementById(
|
||||||
|
"eventFileViewer-single"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (fileGrid && multipleView && singleView) {
|
||||||
|
singleView.classList.add("hidden");
|
||||||
|
multipleView.classList.remove("hidden");
|
||||||
|
|
||||||
|
fileGrid.innerHTML = files
|
||||||
|
.map(
|
||||||
|
(file) => `
|
||||||
|
<div class="card bg-base-200 hover:bg-base-300 cursor-pointer transition-colors">
|
||||||
|
<div class="aspect-video bg-base-300 rounded-t-lg flex items-center justify-center">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 opacity-50" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<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" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-4">
|
||||||
|
<h3 class="card-title text-sm" title="${file.name}">
|
||||||
|
<span class="truncate">${file.name}</span>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
)
|
||||||
|
.join("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to load event files:", err);
|
||||||
|
const previewContainer = document.getElementById(
|
||||||
|
"eventFileViewer-preview-container"
|
||||||
|
);
|
||||||
|
if (previewContainer) {
|
||||||
|
previewContainer.innerHTML = `
|
||||||
|
<div class="flex items-center justify-center h-full">
|
||||||
|
<div class="text-center text-error">
|
||||||
|
<p>Failed to load files</p>
|
||||||
|
<p class="text-sm mt-2 opacity-70">${err instanceof Error ? err.message : "Unknown error"}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}) as unknown as EventListener);
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in a new issue