feature: v1

This commit is contained in:
Alexander Nicholson 4584443+DragonStuff@users.noreply.github.com
2024-11-19 00:48:26 +09:00
parent 6b1e6c945f
commit 6d8acb2752
17 changed files with 794 additions and 2 deletions

52
src/templates/browser.ts Normal file
View File

@@ -0,0 +1,52 @@
import { ListObjectsResult } from "../types/mod.ts";
import { objectList } from "./components/object_list.ts";
import { pagination } from "./components/pagination.ts";
import { search } from "./components/search.ts";
export function browser(
result: ListObjectsResult,
prefix = "",
query = "",
) {
return `
<div class="browser">
<h1>Object Browser</h1>
${search(query)}
<div id="browser-navigation">
${renderBreadcrumbs(prefix)}
</div>
<div id="browser-content">
${objectList(result)}
${pagination(result)}
</div>
</div>
`;
}
export function renderBreadcrumbs(prefix: string) {
const parts = prefix.split("/").filter(Boolean);
const links = parts.map((part, i) => {
const path = parts.slice(0, i + 1).join("/");
return `
<a href="/?prefix=${path}"
hx-get="/?prefix=${path}"
hx-target="#browser-navigation, #browser-content"
hx-swap="innerHTML"
hx-push-url="true">${part}</a>
`;
});
return `
<div class="breadcrumbs">
<a href="/"
hx-get="/"
hx-target="#browser-navigation, #browser-content"
hx-swap="innerHTML"
hx-push-url="true">Home</a>
${links.length ? " / " + links.join(" / ") : ""}
</div>
`;
}

View File

@@ -0,0 +1,48 @@
import { ListObjectsResult } from "../../types/mod.ts";
export function objectList(result: ListObjectsResult) {
return `
<div class="object-list">
${result.prefixes.map(prefix => `
<div class="folder">
<a href="/?prefix=${prefix}"
hx-get="/?prefix=${prefix}"
hx-target="#browser-navigation, #browser-content"
hx-swap="innerHTML"
hx-push-url="true">
📁 ${prefix}
</a>
</div>
`).join("")}
${result.objects.map(obj => `
<div class="object">
<span class="name">📄 ${obj.key}</span>
<span class="size">${formatSize(obj.size)}</span>
<span class="modified">${formatDate(obj.lastModified)}</span>
<a href="/api/download/${encodeURIComponent(obj.key)}"
class="download">
⬇️ Download
</a>
</div>
`).join("")}
</div>
`;
}
function formatSize(bytes: number): string {
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
let size = bytes;
let unit = 0;
while (size >= 1024 && unit < units.length - 1) {
size /= 1024;
unit++;
}
return `${size.toFixed(1)} ${units[unit]}`;
}
function formatDate(date: Date): string {
return date.toLocaleDateString();
}

View File

@@ -0,0 +1,15 @@
import { ListObjectsResult } from "../../types/mod.ts";
export function pagination(result: ListObjectsResult) {
if (!result.truncated) return '';
return `
<div class="pagination">
<button hx-get="/?continuation=${result.nextContinuationToken}"
hx-target="#browser-content"
hx-swap="innerHTML">
Load More
</button>
</div>
`;
}

View File

@@ -0,0 +1,13 @@
export function search(query = "") {
return `
<div class="search">
<input type="search"
name="q"
placeholder="Search objects..."
value="${query}"
hx-get="/api/search"
hx-trigger="keyup changed delay:500ms"
hx-target="#browser-content">
</div>
`;
}

20
src/templates/layout.ts Normal file
View File

@@ -0,0 +1,20 @@
export function layout(content: string) {
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Object Storage Browser</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css">
<link rel="stylesheet" href="/static/styles.css">
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
</head>
<body>
<main class="container">
${content}
</main>
</body>
</html>
`;
}