Skip to content

Commit

Permalink
Simple dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
xirreal committed Jan 1, 2025
1 parent 963bb90 commit 38eba0c
Show file tree
Hide file tree
Showing 3 changed files with 256 additions and 91 deletions.
265 changes: 176 additions & 89 deletions plugins/externalUpload/modal.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import styles from "./modal.jsx.scss";

import { formatFileSize, getFilePreview, uploadFiles } from "./utils";
import { formatFileSize, getAllFiles, getFilePreview, uploadFiles, formatDate, getUrl } from "./utils";

const {
ui: { ModalRoot, ModalHeader, ModalBody, ModalConfirmFooter, ModalSizes, showToast },
solid: { createSignal, createEffect, Show },
ui: {
ModalRoot,
ModalHeader,
ModalBody,
ModalFooter,
ModalSizes,
showToast,
Button,
ButtonColors,
ButtonSizes,
LinkButton,
},
solid: { createSignal, createEffect, Show, For },
util: { log, getFiber },
plugin: { store },
} = shelter;
Expand All @@ -15,6 +25,8 @@ export function UploadModal(closeModal) {
const [previews, setPreviews] = createSignal([]);
const [isUploading, setIsUploading] = createSignal(false);
const [uploadProgress, setUploadProgress] = createSignal(0);
const [dashOpen, setDashOpen] = createSignal(false);
const [dashboardFiles, setDashboardFiles] = createSignal([]);

let fileInputRef;

Expand Down Expand Up @@ -102,11 +114,8 @@ export function UploadModal(closeModal) {

for (let i = 0; i < uploadedUrls.length; i++) {
const result = uploadedUrls[i];
if (store.publicUrl) {
editor.insertText(`${store.publicUrl}/${result.Key}`);
} else {
editor.insertText(result.Location);
}
const url = getUrl(result, store.publicUrl);
editor.insertText(url);
if (i < uploadedUrls.length - 1) {
editor.insertText(" ");
}
Expand All @@ -117,99 +126,177 @@ export function UploadModal(closeModal) {
setIsUploading(false);
};

const fetchDashboardFiles = async () => {
const files = await getAllFiles();
setDashboardFiles(files);
};

const handleDeleteFile = async (file) => {
console.log("Deleting file:", file);
await fetchDashboardFiles();
};

createEffect(() => {
const newFiles = files();
Promise.all(newFiles.map((file) => getFilePreview(file))).then((newPreviews) => {
setPreviews(newPreviews);
});
});

createEffect(() => {
if (dashOpen()) {
fetchDashboardFiles();
}
});

return (
<ModalRoot size={ModalSizes.MEDIUM} class={styles.uploadModal}>
<ModalHeader close={closeModal}>Upload Files</ModalHeader>
<ModalBody>
<div
class={`${styles.uploadArea} ${isDragOver() ? styles.dragOver : ""} ${isUploading() ? styles.uploading : ""}`}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
onClick={handleUploadClick}
>
<Show when={!isUploading()} fallback={<p>Uploading... Please wait</p>}>
<p>Drag & drop files here or click to select</p>
<ModalHeader close={closeModal}>{dashOpen() ? "File Dashboard" : "Upload Files"}</ModalHeader>
<Show when={!dashOpen()}>
<ModalBody>
<div
class={`${styles.uploadArea} ${isDragOver() ? styles.dragOver : ""} ${isUploading() ? styles.uploading : ""}`}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
onClick={handleUploadClick}
>
<Show when={!isUploading()} fallback={<p>Uploading... Please wait</p>}>
<p>Drag & drop files here or click to select</p>
</Show>
<input
type="file"
ref={fileInputRef}
onChange={handleFileChange}
multiple
hidden
disabled={isUploading()}
/>
</div>
<Show when={isUploading()}>
<div class={styles.progressBar}>
<div class={styles.progressFill} style={{ width: `${uploadProgress()}%` }}></div>
</div>
<p>Uploading: {uploadProgress().toFixed(2)}%</p>
</Show>
<input
type="file"
ref={fileInputRef}
onChange={handleFileChange}
multiple
hidden
disabled={isUploading()}
/>
</div>
<Show when={isUploading()}>
<div class={styles.progressBar}>
<div class={styles.progressFill} style={{ width: `${uploadProgress()}%` }}></div>
<div class={styles.previewArea}>
<For each={files()}>
{(file, index) => (
<div class={styles.previewItem}>
{file.type.startsWith("image/") && (
<img src={previews()[index()]} alt={file.name} class={styles.previewImage} />
)}
{file.type.startsWith("video/") && (
<img src={previews()[index()]} alt={file.name} class={styles.previewVideo} />
)}
{!file.type.startsWith("image/") && !file.type.startsWith("video/") && (
<div class={styles.previewIcon}>📄</div>
)}
<div class={styles.previewItemInfo}>
<p>{file.name}</p>
<p>{formatFileSize(file.size)}</p>
</div>
<button
class={styles.removeButton}
onClick={() => handleRemoveFile(index())}
disabled={isUploading()}
>
<svg
aria-hidden="true"
role="img"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
fill="none"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M14.25 1c.41 0 .75.34.75.75V3h5.25c.41 0 .75.34.75.75v.5c0 .41-.34.75-.75.75H3.75A.75.75 0 0 1 3 4.25v-.5c0-.41.34-.75.75-.75H9V1.75c0-.41.34-.75.75-.75h4.5Z"
class=""
></path>
<path
fill="currentColor"
fill-rule="evenodd"
d="M5.06 7a1 1 0 0 0-1 1.06l.76 12.13a3 3 0 0 0 3 2.81h8.36a3 3 0 0 0 3-2.81l.75-12.13a1 1 0 0 0-1-1.06H5.07ZM11 12a1 1 0 1 0-2 0v6a1 1 0 1 0 2 0v-6Zm3-1a1 1 0 0 1 1 1v6a1 1 0 1 1-2 0v-6a1 1 0 0 1 1-1Z"
clip-rule="evenodd"
class=""
></path>
</svg>
</button>
</div>
)}
</For>
</div>
<p>Uploading: {uploadProgress().toFixed(2)}%</p>
</Show>
<div class={styles.previewArea}>
<For each={files()}>
{(file, index) => (
<div class={styles.previewItem}>
{file.type.startsWith("image/") && (
<img src={previews()[index()]} alt={file.name} class={styles.previewImage} />
)}
{file.type.startsWith("video/") && (
<img src={previews()[index()]} alt={file.name} class={styles.previewVideo} />
</ModalBody>
</Show>
<Show when={dashOpen()}>
<ModalBody>
<p>Total bucket usage: {formatFileSize(dashboardFiles().reduce((acc, file) => acc + file.Size, 0))}</p>
<table class={styles.dashboardTable}>
<thead>
<tr>
<th>File Name</th>
<th>Size</th>
<th>Uploaded</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<For each={dashboardFiles()}>
{(file) => (
<tr>
<td>
<LinkButton href={getUrl(file, store.publicUrl)}>{file.Key}</LinkButton>
</td>
<td>{formatFileSize(file.Size)}</td>
<td>{formatDate(file.LastModified)}</td>
<td>
<Button
size={ButtonSizes.SMALL}
color={ButtonColors.RED}
onClick={() => handleDeleteFile(file)}
>
Delete
</Button>
</td>
</tr>
)}
{!file.type.startsWith("image/") && !file.type.startsWith("video/") && (
<div class={styles.previewIcon}>📄</div>
)}
<div class={styles.previewItemInfo}>
<p>{file.name}</p>
<p>{formatFileSize(file.size)}</p>
</div>
<button
class={styles.removeButton}
onClick={() => handleRemoveFile(index())}
disabled={isUploading()}
>
<svg
aria-hidden="true"
role="img"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
fill="none"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M14.25 1c.41 0 .75.34.75.75V3h5.25c.41 0 .75.34.75.75v.5c0 .41-.34.75-.75.75H3.75A.75.75 0 0 1 3 4.25v-.5c0-.41.34-.75.75-.75H9V1.75c0-.41.34-.75.75-.75h4.5Z"
class=""
></path>
<path
fill="currentColor"
fill-rule="evenodd"
d="M5.06 7a1 1 0 0 0-1 1.06l.76 12.13a3 3 0 0 0 3 2.81h8.36a3 3 0 0 0 3-2.81l.75-12.13a1 1 0 0 0-1-1.06H5.07ZM11 12a1 1 0 1 0-2 0v6a1 1 0 1 0 2 0v-6Zm3-1a1 1 0 0 1 1 1v6a1 1 0 1 1-2 0v-6a1 1 0 0 1 1-1Z"
clip-rule="evenodd"
class=""
></path>
</svg>
</button>
</div>
)}
</For>
</For>
</tbody>
</table>
</ModalBody>
</Show>
<ModalFooter>
<div class={styles.footer}>
<Button
class={styles.dashboardButton}
size={ButtonSizes.MEDIUM}
color={ButtonColors.SECONDARY}
onClick={() => setDashOpen(!dashOpen())}
>
{dashOpen() ? "Upload Files" : "Dashboard"}
</Button>
<Button
disabled={isUploading()}
size={ButtonSizes.MEDIUM}
color={ButtonColors.SECONDARY}
onClick={() => (isUploading() ? null : closeModal())}
>
Cancel
</Button>
<Show when={!dashOpen()}>
<Button
disabled={isUploading() || files().length === 0}
size={ButtonSizes.MEDIUM}
color={ButtonColors.BRANDED}
onClick={handleConfirm}
>
{isUploading() ? "Uploading..." : "Upload"}
</Button>
</Show>
</div>
</ModalBody>
<ModalConfirmFooter
close={() => (isUploading() ? null : closeModal())}
confirmText={isUploading() ? "Uploading..." : "Upload"}
onConfirm={handleConfirm}
disabled={isUploading() || files().length === 0}
cancelDisabled={isUploading()}
/>
</ModalFooter>
</ModalRoot>
);
}
56 changes: 56 additions & 0 deletions plugins/externalUpload/modal.jsx.scss
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,60 @@
.uploadModal {
width: 645px;
user-select: none;
}

.footer {
display: flex;
justify-content: flex-end;
gap: .5rem;
}

.dashboardButton {
margin-right: auto;
}

.dashboardTable {
width: 100%;
border-collapse: collapse;
background-color: var(--background-primary);
border-radius: 8px;
overflow: hidden;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
}

.dashboardTable thead {
background-color: var(--background-tertiary);
color: var(--text-normal);
}

.dashboardTable th {
padding: 12px 16px;
text-align: left;
font-weight: 600;
font-size: 14px;
text-transform: uppercase;
border-bottom: 2px solid var(--background-modifier-border);
}

.dashboardTable tbody tr {
transition: background-color 0.3s ease;
}

.dashboardTable tbody tr:nth-child(even) {
background-color: var(--background-secondary);
}

.dashboardTable tbody tr:hover {
background-color: var(--brand-15a);
color: var(--text-bright);
}

.dashboardTable td {
padding: 12px 16px;
font-size: 14px;
border-bottom: 1px solid var(--background-modifier-border);
}

.dashboardTable td:last-child {
text-align: center;
}
Loading

0 comments on commit 38eba0c

Please sign in to comment.