feat: dashboard

This commit is contained in:
eric
2026-02-26 14:45:57 +01:00
parent 94ad2896cc
commit 3756830ec2
43 changed files with 7043 additions and 2060 deletions

55
src/web/http.ts Normal file
View File

@@ -0,0 +1,55 @@
export function jsonResponse(data: unknown, status = 200, headers?: HeadersInit): Response {
return Response.json(data, { status, headers });
}
export function htmlResponse(html: string, status = 200, headers?: HeadersInit): Response {
const responseHeaders = new Headers(headers);
if (!responseHeaders.has("Content-Type")) {
responseHeaders.set("Content-Type", "text/html; charset=utf-8");
}
return new Response(html, {
status,
headers: responseHeaders,
});
}
export function textResponse(content: string, status = 200, headers?: HeadersInit): Response {
const responseHeaders = new Headers(headers);
if (!responseHeaders.has("Content-Type")) {
responseHeaders.set("Content-Type", "text/plain; charset=utf-8");
}
return new Response(content, {
status,
headers: responseHeaders,
});
}
export function isHtmxRequest(request: Request): boolean {
return request.headers.has("hx-request");
}
export async function parseBody(request: Request): Promise<Record<string, unknown>> {
const contentType = request.headers.get("content-type") ?? "";
if (
contentType.includes("application/x-www-form-urlencoded") ||
contentType.includes("multipart/form-data")
) {
const form = await request.formData();
const result: Record<string, unknown> = {};
form.forEach((value, key) => {
result[key] = typeof value === "string" ? value : value.name;
});
return result;
}
if (contentType.includes("application/json")) {
return (await request.json()) as Record<string, unknown>;
}
return {};
}