feat(housekeeping): deliver content vertical

This commit is contained in:
Simo committed 2026-08-30 01:54:43 +02:00
1 parent bdab924bdf
commit fd68819d9b
67 files changed
+5742 -1916

No files matched your search

@@ -0,0 +1,77 @@
import type { ReactNode } from "react";
import type {
HousekeepingResult,
} from "../../../foundation/contracts";
import type { ContentQueryData } from "../queries/content-queries";
export interface ContentPageProps {
readonly context: import("../../../foundation/contracts").HousekeepingCapabilityContext;
readonly result?: HousekeepingResult<ContentQueryData>;
readonly routeId: import("../routes").ContentRouteId | null;
}
export function ContentPageFrame({
title,
description,
result,
forms,
}: {
readonly title: string;
readonly description: string;
readonly result?: HousekeepingResult<ContentQueryData>;
readonly forms?: ReactNode;
}) {
if (!result) {
return (
<section data-housekeeping-state="loading">
<h1>{title}</h1>
<p>{description}</p>
<p>Loading content…</p>
</section>
);
}
if (!result.ok) {
const state = result.error.code === "FORBIDDEN" ? "forbidden" : "error";
return (
<section data-housekeeping-state={state} role="alert">
<h1>{title}</h1>
<p>{result.error.messageKey}</p>
</section>
);
}
const state = result.data.items.length === 0 ? "empty" : "ready";
return (
<section data-housekeeping-state={state} className="space-y-4">
<header>
<h1>{title}</h1>
<p>{description}</p>
</header>
{forms}
{result.data.items.length === 0 ? (
<p>No matching content.</p>
) : (
<ul className="divide-y divide-[var(--admin-border)]">
{result.data.items.map((item) => (
<li key={item.id} className="py-2">
{item.href ? <a href={item.href}>{item.title}</a> : item.title}
{item.status ? <span> — {item.status}</span> : null}
{item.description ? <p>{item.description}</p> : null}
</li>
))}
</ul>
)}
</section>
);
}
export function parseContentListInput(
searchParams: Readonly<Record<string, string | readonly string[] | undefined>>,
) {
const first = (value: string | readonly string[] | undefined) =>
Array.isArray(value) ? value[0] : value;
return {
search: first(searchParams.search),
pageSize: Number(first(searchParams.pageSize) ?? 25),
offset: Number(first(searchParams.offset) ?? 0),
};
}