Add url for editing page
This commit is contained in:
parent
ea651d37f4
commit
5ac1f1be96
31
src/back/routes/admin/pages/[id]/content.jdd-editor.tsx
Normal file
31
src/back/routes/admin/pages/[id]/content.jdd-editor.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import type { Context } from "koa";
|
||||||
|
import type { FieldNames } from "sealious";
|
||||||
|
import { TempstreamJSX } from "tempstream";
|
||||||
|
import type Pages from "src/back/collections/pages.js";
|
||||||
|
import { EditJDDField } from "@sealcode/jdd-editor";
|
||||||
|
import html from "src/back/html.js";
|
||||||
|
import { registry } from "src/back/jdd-components/registry.js";
|
||||||
|
import { makeJDDContext } from "src/back/jdd-context.js";
|
||||||
|
import { defaultHead } from "src/back/defaultHead.js";
|
||||||
|
|
||||||
|
export const actionName = "EditPageContent";
|
||||||
|
|
||||||
|
export default new (class JDDCreatePreviewPage extends EditJDDField<Pages> {
|
||||||
|
getCollection(ctx: Context) {
|
||||||
|
return ctx.$app.collections["pages"];
|
||||||
|
}
|
||||||
|
|
||||||
|
getJDDFieldName(): FieldNames<Pages["fields"]> {
|
||||||
|
return "content";
|
||||||
|
}
|
||||||
|
|
||||||
|
async renderPreParameterButtons(ctx: Context) {
|
||||||
|
const item = await this.getItem(ctx);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Edit pages: {item.id}</h1>{" "}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})({ html, registry, makeJDDContext, defaultHead });
|
||||||
|
|
25
src/back/routes/admin/pages/[id]/delete.page.tsx
Normal file
25
src/back/routes/admin/pages/[id]/delete.page.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import type { Context } from "koa";
|
||||||
|
import { Mountable } from "@sealcode/sealgen";
|
||||||
|
import type Router from "@koa/router";
|
||||||
|
|
||||||
|
import { Pages } from "../../../../collections/collections.js";
|
||||||
|
|
||||||
|
import { PagesCRUDListURL } from "../../../urls.js";
|
||||||
|
|
||||||
|
export const actionName = "PagesCRUDDelete";
|
||||||
|
|
||||||
|
export default new (class PagesCRUDDeleteRedirect extends Mountable {
|
||||||
|
canAccess = async (ctx: Context) => {
|
||||||
|
const policy = Pages.getPolicy("edit");
|
||||||
|
const response = await policy.check(ctx.$context);
|
||||||
|
return { canAccess: response?.allowed || false, message: response?.reason || "" };
|
||||||
|
};
|
||||||
|
|
||||||
|
mount(router: Router, path: string) {
|
||||||
|
router.post(path, async (ctx) => {
|
||||||
|
await ctx.$app.collections["pages"].removeByID(ctx.$context, ctx.params.id!);
|
||||||
|
ctx.status = 302;
|
||||||
|
ctx.redirect(PagesCRUDListURL);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
117
src/back/routes/admin/pages/[id]/edit.form.ts
Normal file
117
src/back/routes/admin/pages/[id]/edit.form.ts
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import type { Context } from "koa";
|
||||||
|
import type { FormData } from "@sealcode/sealgen";
|
||||||
|
import { Form, Controls, fieldsToShape } from "@sealcode/sealgen";
|
||||||
|
import html from "../../../../html.js";
|
||||||
|
|
||||||
|
import { PagesFormFields, PagesFormControls } from "../shared.js";
|
||||||
|
import { Pages } from "../../../../collections/collections.js";
|
||||||
|
import { PagesCRUDListURL } from "../../../urls.js";
|
||||||
|
import { tempstream } from "tempstream";
|
||||||
|
|
||||||
|
import { withFallback } from "@sealcode/sealgen";
|
||||||
|
|
||||||
|
export const actionName = "PagesCRUDEdit";
|
||||||
|
|
||||||
|
const fields = {
|
||||||
|
...PagesFormFields,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PagesCRUDEditShape = fieldsToShape(fields);
|
||||||
|
|
||||||
|
export default new (class PagesCRUDEditForm extends Form<typeof fields, void> {
|
||||||
|
defaultSuccessMessage = "Formularz wypełniony poprawnie";
|
||||||
|
fields = fields;
|
||||||
|
|
||||||
|
controls = [new Controls.FormHeader("Edit Pages"), ...PagesFormControls];
|
||||||
|
|
||||||
|
async getID(ctx: Context): Promise<string> {
|
||||||
|
const param_name = "id";
|
||||||
|
const id = ctx.params[param_name];
|
||||||
|
if (!id) {
|
||||||
|
throw new Error("Missing URL parameter: " + param_name);
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getInitialValues(ctx: Context) {
|
||||||
|
const id = await this.getID(ctx);
|
||||||
|
|
||||||
|
const {
|
||||||
|
items: [item],
|
||||||
|
} = await ctx.$app.collections["pages"]
|
||||||
|
.list(ctx.$context)
|
||||||
|
.ids([id])
|
||||||
|
.attach({})
|
||||||
|
.fetch();
|
||||||
|
|
||||||
|
if (!item) {
|
||||||
|
throw new Error("Item with given id not found: " + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: item.get("url"),
|
||||||
|
domain: withFallback(item.get("domain"), ""),
|
||||||
|
title: withFallback(item.get("title"), ""),
|
||||||
|
heading: withFallback(item.get("heading"), ""),
|
||||||
|
description: withFallback(item.get("description"), ""),
|
||||||
|
imageForMetadata: { old: item.get("imageForMetadata") },
|
||||||
|
hideNavigation: withFallback(
|
||||||
|
item.get("hideNavigation"),
|
||||||
|
String(item.get("hideNavigation")),
|
||||||
|
"false"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async onSubmit(ctx: Context) {
|
||||||
|
const data = await this.getParsedValues(ctx);
|
||||||
|
const id = await this.getID(ctx);
|
||||||
|
const {
|
||||||
|
items: [item],
|
||||||
|
} = await ctx.$app.collections["pages"].list(ctx.$context).ids([id]).fetch();
|
||||||
|
|
||||||
|
if (!item) {
|
||||||
|
throw new Error("Unknown id: " + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
throw new Error("Error when parsing the form values");
|
||||||
|
}
|
||||||
|
|
||||||
|
const preparedImageForMetadata =
|
||||||
|
data.imageForMetadata.new || data.imageForMetadata.old;
|
||||||
|
if (!preparedImageForMetadata) {
|
||||||
|
throw new Error("Missing field: imageForMetadata");
|
||||||
|
}
|
||||||
|
|
||||||
|
item.setMultiple({
|
||||||
|
url: data["url"],
|
||||||
|
content: [],
|
||||||
|
domain: data["domain"] != null ? data["domain"] : "",
|
||||||
|
title: data["title"] != null ? data["title"] : "",
|
||||||
|
heading: data["heading"] != null ? data["heading"] : "",
|
||||||
|
description: data["description"] != null ? data["description"] : "",
|
||||||
|
imageForMetadata: preparedImageForMetadata,
|
||||||
|
hideNavigation: !!data.hideNavigation != null ? !!data.hideNavigation : false,
|
||||||
|
});
|
||||||
|
await item.save(ctx.$context);
|
||||||
|
}
|
||||||
|
|
||||||
|
canAccess = async (ctx: Context) => {
|
||||||
|
const policy = Pages.getPolicy("edit");
|
||||||
|
const response = await policy.check(ctx.$context);
|
||||||
|
return { canAccess: response?.allowed || false, message: response?.reason || "" };
|
||||||
|
};
|
||||||
|
|
||||||
|
async render(ctx: Context, data: FormData, show_field_errors: boolean) {
|
||||||
|
return html({
|
||||||
|
ctx,
|
||||||
|
title: "Edit Pages",
|
||||||
|
body: tempstream/* HTML */ ` <div class="sealgen-crud-form">
|
||||||
|
<a class="" href="${PagesCRUDListURL}">← Back to pages list</a>
|
||||||
|
${await super.render(ctx, data, show_field_errors)}
|
||||||
|
</div>`,
|
||||||
|
description: "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
69
src/back/routes/admin/pages/create.form.ts
Normal file
69
src/back/routes/admin/pages/create.form.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import type { Context } from "koa";
|
||||||
|
import type { FormData } from "@sealcode/sealgen";
|
||||||
|
import { Form, Controls, fieldsToShape } from "@sealcode/sealgen";
|
||||||
|
import html from "../../../html.js";
|
||||||
|
|
||||||
|
import { PagesFormFields, PagesFormControls } from "./shared.js";
|
||||||
|
|
||||||
|
import { Pages } from "../../../collections/collections.js";
|
||||||
|
|
||||||
|
import { PagesCRUDListURL } from "../../urls.js";
|
||||||
|
|
||||||
|
import { tempstream } from "tempstream";
|
||||||
|
|
||||||
|
export const actionName = "PagesCRUDCreate";
|
||||||
|
|
||||||
|
const fields = {
|
||||||
|
...PagesFormFields,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PagesCRUDCreateShape = fieldsToShape(fields);
|
||||||
|
|
||||||
|
export default new (class PagesCRUDCreateForm extends Form<typeof fields, void> {
|
||||||
|
defaultSuccessMessage = "Formularz wypełniony poprawnie";
|
||||||
|
fields = fields;
|
||||||
|
|
||||||
|
controls = [new Controls.FormHeader("Create Pages"), ...PagesFormControls];
|
||||||
|
|
||||||
|
async onSubmit(ctx: Context) {
|
||||||
|
const data = await this.getParsedValues(ctx);
|
||||||
|
if (!data) {
|
||||||
|
throw new Error("Error when parsing the form values");
|
||||||
|
}
|
||||||
|
|
||||||
|
const preparedImageForMetadata =
|
||||||
|
data.imageForMetadata.new || data.imageForMetadata.old;
|
||||||
|
if (!preparedImageForMetadata) {
|
||||||
|
throw new Error("Missing field: imageForMetadata");
|
||||||
|
}
|
||||||
|
|
||||||
|
await ctx.$app.collections["pages"].create(ctx.$context, {
|
||||||
|
url: data["url"],
|
||||||
|
content: [],
|
||||||
|
domain: data["domain"] != null ? data["domain"] : "",
|
||||||
|
title: data["title"] != null ? data["title"] : "",
|
||||||
|
heading: data["heading"] != null ? data["heading"] : "",
|
||||||
|
description: data["description"] != null ? data["description"] : "",
|
||||||
|
imageForMetadata: preparedImageForMetadata,
|
||||||
|
hideNavigation: !!data.hideNavigation != null ? !!data.hideNavigation : false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
canAccess = async (ctx: Context) => {
|
||||||
|
const policy = Pages.getPolicy("create");
|
||||||
|
const response = await policy.check(ctx.$context);
|
||||||
|
return { canAccess: response?.allowed || false, message: response?.reason || "" };
|
||||||
|
};
|
||||||
|
|
||||||
|
async render(ctx: Context, data: FormData, show_field_errors: boolean) {
|
||||||
|
return html({
|
||||||
|
ctx,
|
||||||
|
title: "Create pages",
|
||||||
|
body: tempstream/* HTML */ ` <div class="sealgen-crud-form">
|
||||||
|
<a class="" href="${PagesCRUDListURL}">← Back to pages list</a>
|
||||||
|
${await super.render(ctx, data, show_field_errors)}
|
||||||
|
</div>`,
|
||||||
|
description: "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
185
src/back/routes/admin/pages/index.list.tsx
Normal file
185
src/back/routes/admin/pages/index.list.tsx
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
import type { Context } from "koa";
|
||||||
|
import type { CollectionItem } from "sealious";
|
||||||
|
import type { FlatTemplatable, Templatable } from "tempstream";
|
||||||
|
import { TempstreamJSX, tempstream } from "tempstream";
|
||||||
|
import { Pages } from "src/back/collections/collections.js";
|
||||||
|
import html from "src/back/html.js";
|
||||||
|
import type { ListFilterRender } from "@sealcode/sealgen";
|
||||||
|
import {
|
||||||
|
SealiousItemListPage,
|
||||||
|
BaseListPageFields,
|
||||||
|
DefaultListFilters,
|
||||||
|
} from "@sealcode/sealgen";
|
||||||
|
import qs from "qs";
|
||||||
|
|
||||||
|
import {
|
||||||
|
PagesCRUDCreateURL,
|
||||||
|
PagesCRUDEditURL,
|
||||||
|
PagesCRUDDeleteURL,
|
||||||
|
EditPageContentURL,
|
||||||
|
} from "../../urls.js";
|
||||||
|
|
||||||
|
import type { FilePointer } from "@sealcode/file-manager";
|
||||||
|
import { imageRouter } from "src/back/image-router.js";
|
||||||
|
|
||||||
|
export const actionName = "PagesCRUDList";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
|
const filterFields = [
|
||||||
|
{ field: "url", ...DefaultListFilters["text"] },
|
||||||
|
{ field: "content", ...DefaultListFilters.fallback },
|
||||||
|
{ field: "domain", ...DefaultListFilters["text"] },
|
||||||
|
{ field: "title", ...DefaultListFilters["text"] },
|
||||||
|
{ field: "heading", ...DefaultListFilters["text"] },
|
||||||
|
{ field: "description", ...DefaultListFilters["text"] },
|
||||||
|
{ field: "imageForMetadata", ...DefaultListFilters.fallback },
|
||||||
|
{ field: "hideNavigation", ...DefaultListFilters["boolean"] },
|
||||||
|
] as {
|
||||||
|
field: keyof (typeof Pages)["fields"];
|
||||||
|
render?: ListFilterRender;
|
||||||
|
prepareValue?: (filter_value: unknown) => unknown; // set this function to change what filter value is passed to Sealious
|
||||||
|
}[];
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
|
const displayFields = [
|
||||||
|
{ field: "url", label: "url" },
|
||||||
|
{ field: "content", label: "content" },
|
||||||
|
{ field: "domain", label: "domain" },
|
||||||
|
{ field: "title", label: "title" },
|
||||||
|
{ field: "heading", label: "heading" },
|
||||||
|
{ field: "description", label: "description" },
|
||||||
|
{
|
||||||
|
field: "imageForMetadata",
|
||||||
|
label: "imageForMetadata",
|
||||||
|
format: async (value: FilePointer) => {
|
||||||
|
return imageRouter.image(await value.getPath(), {
|
||||||
|
container: { width: 45, height: 45 },
|
||||||
|
crop: { width: 45, height: 45 },
|
||||||
|
alt: "",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "hideNavigation",
|
||||||
|
label: "hideNavigation",
|
||||||
|
format: (v: boolean) => (v ? "YES" : "NO"),
|
||||||
|
},
|
||||||
|
] as {
|
||||||
|
field: string;
|
||||||
|
label: string;
|
||||||
|
format?: (value: unknown, item: CollectionItem<typeof Pages>) => FlatTemplatable;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
export default new (class PagesCRUDListPage extends SealiousItemListPage<
|
||||||
|
typeof Pages,
|
||||||
|
typeof BaseListPageFields
|
||||||
|
> {
|
||||||
|
fields = BaseListPageFields;
|
||||||
|
|
||||||
|
async renderFilters(ctx: Context): Promise<FlatTemplatable> {
|
||||||
|
const query_params = qs.parse(ctx.search.slice(1));
|
||||||
|
query_params.page = "1";
|
||||||
|
const filter_values = await super.getFilterValues(ctx);
|
||||||
|
return (
|
||||||
|
<form>
|
||||||
|
{Object.entries(query_params).map(([key, value]) => {
|
||||||
|
if (key == "filter") {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
// this is necessary to not lose any query params when the user changes the filter values
|
||||||
|
return <input type="hidden" name={key} value={value} />;
|
||||||
|
})}
|
||||||
|
{filterFields.map(({ field, render }) => {
|
||||||
|
if (!render) {
|
||||||
|
render = DefaultListFilters.fallback.render;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
render(
|
||||||
|
filter_values[field] || "",
|
||||||
|
this.collection.fields[field]
|
||||||
|
) || ""
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<input type="submit" />
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getFilterValues(ctx: Context) {
|
||||||
|
// adding opportunity to adjust the values for a given field filter before it's sent to Sealious
|
||||||
|
const values = await super.getFilterValues(ctx);
|
||||||
|
for (const filterField of filterFields) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
|
const key = filterField.field as keyof typeof values;
|
||||||
|
if (key in values) {
|
||||||
|
const prepare_fn = filterField.prepareValue;
|
||||||
|
if (prepare_fn) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
|
||||||
|
values[key] = prepare_fn(values[key]) as any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
async renderItem(ctx: Context, item: CollectionItem<typeof Pages>) {
|
||||||
|
return (
|
||||||
|
<tr>
|
||||||
|
{displayFields.map(({ field, format }) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
|
||||||
|
const value = item.get(field as any);
|
||||||
|
return <td>{format ? format(value, item) : value}</td>;
|
||||||
|
})}
|
||||||
|
<td>
|
||||||
|
<div class="sealious-list__actions">
|
||||||
|
<a href={PagesCRUDEditURL(item.id)}>Edit Metadata</a>
|
||||||
|
<a
|
||||||
|
data-turbo-method="POST"
|
||||||
|
data-turbo-confirm="Delete item?"
|
||||||
|
href={PagesCRUDDeleteURL(item.id)}
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</a>
|
||||||
|
<a href={EditPageContentURL(item.id)}>Edit Content</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderListContainer(ctx: Context, content: Templatable): FlatTemplatable {
|
||||||
|
return (
|
||||||
|
<table class="sealious-list pages-crudlist-table">
|
||||||
|
{this.renderTableHead(ctx, displayFields)}
|
||||||
|
<tbody>{content}</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTableHead(
|
||||||
|
ctx: Context,
|
||||||
|
fields: { field: string; label?: string }[]
|
||||||
|
): FlatTemplatable {
|
||||||
|
return tempstream/* HTML */ `<thead>
|
||||||
|
<tr>
|
||||||
|
${fields.map(({ label, field }) => this.renderHeading(ctx, field, label))}
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async render(ctx: Context) {
|
||||||
|
return html({
|
||||||
|
ctx,
|
||||||
|
title: "PagesCRUDList",
|
||||||
|
description: "",
|
||||||
|
body: (
|
||||||
|
<div class="sealious-list-wrapper pages-crudlist--wrapper">
|
||||||
|
<h2>PagesCRUDList List</h2>
|
||||||
|
<a href={PagesCRUDCreateURL}> Create </a>
|
||||||
|
{super.render(ctx)}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})(Pages);
|
36
src/back/routes/admin/pages/shared.ts
Normal file
36
src/back/routes/admin/pages/shared.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { Controls, Fields } from "@sealcode/sealgen";
|
||||||
|
import { Pages } from "../../../collections/collections.js";
|
||||||
|
|
||||||
|
import { imageRouter } from "../../../image-router.js";
|
||||||
|
import { TheFileManager } from "../../../file-manager.js";
|
||||||
|
|
||||||
|
export const PagesFormFields = <const>{
|
||||||
|
url: new Fields.CollectionField(Pages.fields.url.required, Pages.fields.url),
|
||||||
|
domain: new Fields.CollectionField(Pages.fields.domain.required, Pages.fields.domain),
|
||||||
|
title: new Fields.CollectionField(Pages.fields.title.required, Pages.fields.title),
|
||||||
|
heading: new Fields.CollectionField(
|
||||||
|
Pages.fields.heading.required,
|
||||||
|
Pages.fields.heading
|
||||||
|
),
|
||||||
|
description: new Fields.CollectionField(
|
||||||
|
Pages.fields.description.required,
|
||||||
|
Pages.fields.description
|
||||||
|
),
|
||||||
|
imageForMetadata: new Fields.File(
|
||||||
|
Pages.fields.imageForMetadata.required,
|
||||||
|
TheFileManager
|
||||||
|
),
|
||||||
|
hideNavigation: new Fields.Boolean(Pages.fields.hideNavigation.required),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PagesFormControls = [
|
||||||
|
new Controls.SimpleInput(PagesFormFields.url, { label: "url" }),
|
||||||
|
new Controls.SimpleInput(PagesFormFields.domain, { label: "domain" }),
|
||||||
|
new Controls.SimpleInput(PagesFormFields.title, { label: "title" }),
|
||||||
|
new Controls.SimpleInput(PagesFormFields.heading, { label: "heading" }),
|
||||||
|
new Controls.SimpleInput(PagesFormFields.description, { label: "description" }),
|
||||||
|
new Controls.Photo(PagesFormFields.imageForMetadata, imageRouter, {
|
||||||
|
label: "imageForMetadata",
|
||||||
|
}),
|
||||||
|
new Controls.Checkbox(PagesFormFields.hideNavigation, { label: "hideNavigation" }),
|
||||||
|
];
|
@ -1,17 +1,20 @@
|
|||||||
import type { BaseContext } from "koa";
|
import type { BaseContext } from "koa";
|
||||||
import type { FlatTemplatable } from "tempstream";
|
import type { FlatTemplatable } from "tempstream";
|
||||||
import { SignInURL, LogoutURL } from "../urls.js";
|
import { SignInURL, LogoutURL, PagesCRUDListURL } from "../urls.js";
|
||||||
|
|
||||||
export async function default_navbar(ctx: BaseContext): Promise<FlatTemplatable> {
|
export async function default_navbar(ctx: BaseContext): Promise<FlatTemplatable> {
|
||||||
const isLoggedIn = !!ctx.$context.session_id;
|
const isLoggedIn = !!ctx.$context.session_id;
|
||||||
|
|
||||||
const linkData = isLoggedIn
|
const linkData = isLoggedIn
|
||||||
? [{ text: "Logout", url: LogoutURL }]
|
? [
|
||||||
|
{ text: "Pages", url: PagesCRUDListURL },
|
||||||
|
{ text: "Logout", url: LogoutURL },
|
||||||
|
]
|
||||||
: [{ text: "Sign in", url: SignInURL }];
|
: [{ text: "Sign in", url: SignInURL }];
|
||||||
|
|
||||||
const linksHTML = linkData
|
const linksHTML = linkData
|
||||||
.map((link) =>
|
.map((link) =>
|
||||||
link.url === new URL(ctx.url, "https://a.com").pathname
|
link.url === new URL(ctx.url, "https://a.com").pathname // checking if it's the current path we're looking at
|
||||||
? `<li class="active"><span>${link.text}</span></li>`
|
? `<li class="active"><span>${link.text}</span></li>`
|
||||||
: /* HTML */ `<li><a href="${link.url}">${link.text}</a></li>`
|
: /* HTML */ `<li><a href="${link.url}">${link.text}</a></li>`
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user