allow custom breadcrumbs label

Summary: Ref T3092

Reviewers: kuba-orlik

Reviewed By: kuba-orlik

Maniphest Tasks: T3092

Differential Revision: https://hub.sealcode.org/D1681
This commit is contained in:
PrzZiomek2 2026-04-02 17:13:31 +02:00
parent ee2368c686
commit c62adb4752
3 changed files with 56 additions and 28 deletions

View File

@ -43,29 +43,29 @@ function arrow_head() {
); );
} }
export function breadcrumbs(ctx: Context) { export async function breadcrumbs(ctx: Context) {
return ( const breadcrumbs = await Promise.all(
<div class="breadcrumbs"> get_breadcrumbs_from_path(ctx.path).map(async (e, i, all) => {
{get_breadcrumbs_from_path(ctx.path)
.map((e, i, all) => {
if (!e.actionName) { if (!e.actionName) {
return ""; return "";
} }
const breadcrumbLabel = e.breadcrumbLabel?.({ ...ctx });
const breadcrumbLabelResult = await breadcrumbLabel;
if (i == all.length - 1) { if (i == all.length - 1) {
return <span>{e.actionName}</span>; return <span>{breadcrumbLabelResult || e.actionName}</span>;
} }
return ( return (
<> <>
<a href={e.url}> <a href={e.url}>
{i !== 0 ? arrow_tail() : ""} {i !== 0 ? arrow_tail() : ""}
<span>{e.actionName}</span> <span>{breadcrumbLabelResult || e.actionName}</span>
{arrow_head()} {arrow_head()}
</a> </a>
</> </>
); );
}) })
.filter((e) => e !== "")
.join("")}
</div>
); );
return <div class="breadcrumbs">{breadcrumbs.filter((e) => e !== "").join("")}</div>;
} }

View File

@ -2,9 +2,12 @@ import type { Context } from "koa";
import { TempstreamJSX } from "tempstream"; import { TempstreamJSX } from "tempstream";
import { Page } from "@sealcode/sealgen"; import { Page } from "@sealcode/sealgen";
import type { BreadcrumbLabel } from "@sealcode/sealgen";
import html from "src/back/html.js"; import html from "src/back/html.js";
export const actionName = "HelloPage"; export const actionName = "HelloPage";
export const breadcrumbLabel: BreadcrumbLabel = "Witaj";
export default new (class HelloPagePage extends Page { export default new (class HelloPagePage extends Page {
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars

View File

@ -1,12 +1,17 @@
import * as path from "path";
import type { Context } from "koa";
import { url_tree } from "./routes.js"; import { url_tree } from "./routes.js";
import type { URLTree } from "./routes.js"; import type { URLTree } from "./routes.js";
import type { BreadcrumbLabel } from "@sealcode/sealgen";
export function get_breadcrumbs_from_path(url: string) { export function get_breadcrumbs_from_path(url: string) {
let position: URLTree = url_tree; let position: URLTree = url_tree;
const elements = url.split("/").filter((e) => e != ""); const elements = url.split("/").filter((e) => e != "");
const breadcrumbs: { actionName?: string; url?: string }[] = [ const breadcrumbs: {
{ actionName: "Home", url: "/" }, actionName?: string;
]; url?: string;
breadcrumbLabel?: (ctx: Context) => Promise<string>;
}[] = [{ actionName: "Home", url: "/" }];
let path_so_far = ""; let path_so_far = "";
for (const element of elements) { for (const element of elements) {
if (position.children[element]) { if (position.children[element]) {
@ -18,7 +23,27 @@ export function get_breadcrumbs_from_path(url: string) {
break; break;
} }
path_so_far += "/" + element; path_so_far += "/" + element;
breadcrumbs.push({ actionName: position.actionName, url: path_so_far }); const actionName = position.actionName;
const modulePath = position.module_path;
breadcrumbs.push({
actionName: actionName,
url: path_so_far,
breadcrumbLabel: async (ctx: Context) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/consistent-type-assertions
const module = (await import(path.resolve(modulePath || "") || "")) as {
breadcrumbLabel: BreadcrumbLabel;
};
if (!module.breadcrumbLabel) return actionName || "";
if (typeof module.breadcrumbLabel === "function") {
return module.breadcrumbLabel(ctx);
} else {
return module.breadcrumbLabel;
}
},
});
} }
return breadcrumbs; return breadcrumbs;
} }