forked from UKSOURCE/cms.lams
Improve the CMS administration interface across multiple pages (Accreditation, Admissions, History, Partnerships, and Policies) with a focus on usability and data integrity. Key changes include: - Implement `ensureUniqueIds` utility to automatically generate and maintain unique slugs for content items, removing the need for manual ID entry in the UI. - Refactor the Admissions calculator to support detailed per-option editing via a new dedicated view and routes. - Replace basic datalists with a custom, searchable icon combobox component for better visual selection. - Update `_renderSingletonPageView` to handle active tab persistence via query parameters. - Streamline editor configurations by removing redundant fields and improving help text. - Enhance the Admissions "Key Dates" editor with a dynamic table interface for managing columns and rows. - Normalize data payloads in controllers to ensure consistent API responses and internal linking.
148 lines
4.6 KiB
JavaScript
148 lines
4.6 KiB
JavaScript
const {
|
|
text,
|
|
textarea,
|
|
image,
|
|
checkbox,
|
|
select,
|
|
combobox,
|
|
object,
|
|
stringList,
|
|
objectList,
|
|
} = require("./sharedFields");
|
|
|
|
const inquiryFieldOptions = [
|
|
{ value: "text", label: "Single line text" },
|
|
{ value: "textarea", label: "Paragraph" },
|
|
{ value: "select", label: "Dropdown" },
|
|
];
|
|
|
|
const widthOptions = [
|
|
{ value: "half", label: "Half width" },
|
|
{ value: "full", label: "Full width" },
|
|
];
|
|
|
|
module.exports = {
|
|
key: "partnerships",
|
|
title: "Partnerships Management",
|
|
subtitle: "Manage the content for the partnerships page",
|
|
routeBase: "/admin/partnerships",
|
|
apiPath: "/api/partnerships",
|
|
previewPath: "/about/partnerships",
|
|
dataFile: "partnerships",
|
|
imageType: "partnerships",
|
|
tabs: [
|
|
{
|
|
key: "hero",
|
|
label: "Hero",
|
|
icon: "fas fa-image",
|
|
schema: object("hero", "Hero", [
|
|
text("badge", "Eyebrow label", { maxLength: 40 }),
|
|
text("title", "Headline", { maxLength: 90 }),
|
|
textarea("description", "Supporting text", { maxLength: 220, rows: 4 }),
|
|
text("linkLabel", "Scroll link label", { maxLength: 40 }),
|
|
image("image", "Hero image", {
|
|
imageHint: "Recommended 720x630 px",
|
|
helpText: "Upload the image shown in the right hero panel.",
|
|
}),
|
|
text("imageAlt", "Hero image alt text", { maxLength: 120 }),
|
|
]),
|
|
},
|
|
{
|
|
key: "directory",
|
|
label: "Partner Directory",
|
|
icon: "fas fa-handshake",
|
|
schema: object("directory", "Partner directory", [
|
|
text("heading", "Section heading", { maxLength: 70 }),
|
|
textarea("description", "Section description", {
|
|
maxLength: 180,
|
|
rows: 3,
|
|
}),
|
|
stringList("tabs", "Category tabs", {
|
|
itemLabel: "Category tab",
|
|
maxLength: 30,
|
|
placeholder: "Industry",
|
|
sortable: true,
|
|
helpText: "Add and reorder the category tabs shown on the page.",
|
|
}),
|
|
objectList(
|
|
"partners",
|
|
"Partners",
|
|
[
|
|
text("name", "Partner name", { maxLength: 90 }),
|
|
combobox("category", "Category", {
|
|
maxLength: 30,
|
|
optionsPath: "directory.tabs",
|
|
}),
|
|
textarea("summary", "Card summary", {
|
|
maxLength: 130,
|
|
rows: 3,
|
|
helpText: "Keep this short. Around 130 characters works best in the card layout.",
|
|
}),
|
|
image("logo", "Partner logo", {
|
|
imageHint: "Recommended 105x80 px minimum visible ratio",
|
|
helpText: "Use a clean logo with transparent or simple background.",
|
|
}),
|
|
text("logoAlt", "Logo alt text", { maxLength: 120 }),
|
|
textarea("about", "About text", { maxLength: 600, rows: 5 }),
|
|
text("collabType", "Collaboration type", { maxLength: 40 }),
|
|
textarea("benefits", "Benefits", { maxLength: 240, rows: 4 }),
|
|
],
|
|
{
|
|
itemLabel: "Partner",
|
|
sortable: true,
|
|
itemTitleKey: "name",
|
|
itemSubtitleKey: "category",
|
|
emptyText: "No partners yet.",
|
|
},
|
|
),
|
|
]),
|
|
},
|
|
{
|
|
key: "cta",
|
|
label: "Call To Action",
|
|
icon: "fas fa-bullhorn",
|
|
schema: object("cta", "Call to action", [
|
|
text("heading", "Headline", { maxLength: 80 }),
|
|
textarea("description", "Supporting text", {
|
|
maxLength: 220,
|
|
rows: 4,
|
|
}),
|
|
text("buttonLabel", "Button label", { maxLength: 40 }),
|
|
]),
|
|
},
|
|
{
|
|
key: "inquiryForm",
|
|
label: "Inquiry Form",
|
|
icon: "fas fa-envelope",
|
|
schema: object("inquiryForm", "Inquiry form", [
|
|
text("title", "Modal title", { maxLength: 60 }),
|
|
objectList(
|
|
"fields",
|
|
"Form fields",
|
|
[
|
|
text("label", "Field label", { maxLength: 40 }),
|
|
text("placeholder", "Placeholder text", { maxLength: 80 }),
|
|
select("type", "Field type", inquiryFieldOptions),
|
|
select("width", "Field width", widthOptions),
|
|
stringList("options", "Dropdown options", {
|
|
itemLabel: "Option",
|
|
maxLength: 50,
|
|
sortable: true,
|
|
helpText: "Only used when the field type is Dropdown.",
|
|
visibleWhen: { path: "type", equals: "select" },
|
|
}),
|
|
checkbox("required", "Required field"),
|
|
],
|
|
{
|
|
itemLabel: "Field",
|
|
sortable: true,
|
|
itemTitleKey: "label",
|
|
itemSubtitleKey: "type",
|
|
emptyText: "No inquiry fields yet.",
|
|
},
|
|
),
|
|
]),
|
|
},
|
|
],
|
|
};
|