mirror of
https://github.com/alexandernicholson/s3panoramic.git
synced 2026-05-06 15:00:41 +09:00
feature: v1
This commit is contained in:
parent
6b1e6c945f
commit
6d8acb2752
52
src/templates/browser.ts
Normal file
52
src/templates/browser.ts
Normal 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>
|
||||
`;
|
||||
}
|
||||
48
src/templates/components/object_list.ts
Normal file
48
src/templates/components/object_list.ts
Normal 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();
|
||||
}
|
||||
15
src/templates/components/pagination.ts
Normal file
15
src/templates/components/pagination.ts
Normal 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>
|
||||
`;
|
||||
}
|
||||
13
src/templates/components/search.ts
Normal file
13
src/templates/components/search.ts
Normal 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
20
src/templates/layout.ts
Normal 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>
|
||||
`;
|
||||
}
|
||||
Reference in New Issue
Block a user