@paroicms/site-generator-plugin 0.24.2 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/backend/dist/generator/fake-content-generator/create-node-contents.js +13 -2
- package/backend/dist/generator/fake-content-generator/generate-fake-content.js +2 -1
- package/backend/dist/generator/lib/calling-llm-mistral.js +2 -2
- package/backend/dist/generator/lib/debug-utils.js +2 -2
- package/backend/dist/generator/llm-queries/invoke-new-site-analysis.js +2 -1
- package/backend/dist/generator/site-generator/common-template-creator.js +15 -16
- package/backend/dist/generator/site-generator/document-card-template-creator.js +40 -0
- package/backend/dist/generator/site-generator/document-template-creator.js +69 -90
- package/backend/dist/generator/site-generator/id-key-provider.js +1 -1
- package/backend/dist/generator/site-generator/jt-site-schema-helpers.js +16 -0
- package/backend/dist/generator/site-generator/labeled-list-template-creator.js +56 -0
- package/backend/dist/generator/site-generator/theme-creator-context.js +109 -0
- package/backend/dist/generator/site-generator/theme-creator.js +3 -67
- package/backend/dist/generator/site-generator/theme-css.js +58 -1
- package/backend/dist/index.js +4 -4
- package/backend/prompts/message-guard.md +0 -1
- package/frontend/dist/frontend.mjs +61 -57
- package/package.json +10 -10
|
@@ -150,13 +150,24 @@ function getDefaultStringValueForField(fieldName) {
|
|
|
150
150
|
return undefined;
|
|
151
151
|
}
|
|
152
152
|
export function generateLocalizedFooterMention(siteSchema) {
|
|
153
|
-
const { languages
|
|
153
|
+
const { languages } = siteSchema;
|
|
154
154
|
return Object.fromEntries(languages.map((language) => [
|
|
155
155
|
language,
|
|
156
156
|
{
|
|
157
157
|
j: {
|
|
158
|
-
ops: markdownToDelta(
|
|
158
|
+
ops: markdownToDelta(getPoweredByLabel(language)),
|
|
159
159
|
},
|
|
160
160
|
},
|
|
161
161
|
]));
|
|
162
162
|
}
|
|
163
|
+
function getPoweredByLabel(language) {
|
|
164
|
+
const translations = {
|
|
165
|
+
en: "Powered by ParoiCMS",
|
|
166
|
+
fr: "Propulsé par ParoiCMS",
|
|
167
|
+
es: "Desarrollado por ParoiCMS",
|
|
168
|
+
de: "Betrieben von ParoiCMS",
|
|
169
|
+
it: "Alimentato da ParoiCMS",
|
|
170
|
+
pt: "Desenvolvido por ParoiCMS",
|
|
171
|
+
};
|
|
172
|
+
return translations[language] ?? translations.en;
|
|
173
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isDef, } from "@paroicms/public-anywhere-lib";
|
|
1
2
|
import { camelToKebabCase, camelToTitleCase } from "../lib/utils.js";
|
|
2
3
|
import { createNodeContents } from "./create-node-contents.js";
|
|
3
4
|
import { invokeGenerateFakeContent, } from "./invoke-generate-fake-content.js";
|
|
@@ -20,7 +21,7 @@ export async function generateMultipleFieldSetContents(ctx, options, report) {
|
|
|
20
21
|
? [{ tagName: "title", key: "title", format: "text", tagDescription: "Write the title here" }]
|
|
21
22
|
: [];
|
|
22
23
|
if (nodeType.fields) {
|
|
23
|
-
outputTags.push(...nodeType.fields.map(toFakeContentOutputTag).filter(
|
|
24
|
+
outputTags.push(...nodeType.fields.map(toFakeContentOutputTag).filter(isDef));
|
|
24
25
|
}
|
|
25
26
|
const defaultLanguage = siteSchema.languages?.[0];
|
|
26
27
|
const typeLabel = translateText(schemaI18n, `nodeTypes.${nodeType.typeName}.label`, {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { messageOf } from "@paroicms/public-anywhere-lib";
|
|
1
|
+
import { isDef, messageOf } from "@paroicms/public-anywhere-lib";
|
|
2
2
|
let seq = 0;
|
|
3
3
|
export async function batchInvokeMinistral(ctx, prompts, options) {
|
|
4
4
|
const startTime = Date.now();
|
|
5
5
|
const responses = await execBatchInvokeMinistral(ctx, prompts, options);
|
|
6
6
|
const llmMessages = responses
|
|
7
7
|
.map((msg) => msg.response.body.choices[0]?.message.content)
|
|
8
|
-
.filter(
|
|
8
|
+
.filter(isDef);
|
|
9
9
|
const llmReport = {
|
|
10
10
|
llmTaskName: options.llmTaskName,
|
|
11
11
|
modelName: ctx.mistralModelName,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ensureDirectory } from "@paroicms/internal-server-lib";
|
|
2
|
-
import { isObj, messageOf } from "@paroicms/public-anywhere-lib";
|
|
2
|
+
import { isDef, isObj, messageOf } from "@paroicms/public-anywhere-lib";
|
|
3
3
|
import { readFile, writeFile } from "node:fs/promises";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { estimateTokenCount } from "./llm-tokens.js";
|
|
@@ -112,7 +112,7 @@ async function writeDebugLlmInputOutputs(ctx, stepHandle, list, llmReport, start
|
|
|
112
112
|
stepHandle?.stepNumber,
|
|
113
113
|
llmReport.llmTaskName,
|
|
114
114
|
llmReport.errorMessage ? "ERROR" : undefined,
|
|
115
|
-
].filter(
|
|
115
|
+
].filter(isDef);
|
|
116
116
|
const baseName = nameParts.join("-");
|
|
117
117
|
const header = [
|
|
118
118
|
`Model: ${llmReport.modelName}`,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isDef } from "@paroicms/public-anywhere-lib";
|
|
1
2
|
import { loadStep } from "../../db/db-read.queries.js";
|
|
2
3
|
import { insertStep, saveCompletedSchemaStep, updateStep, } from "../../db/db-write.queries.js";
|
|
3
4
|
import { reorderObjectKeys } from "../helpers/js-utils.js";
|
|
@@ -210,7 +211,7 @@ function createUnusedInformationPrompt(unusedInformation, analysis) {
|
|
|
210
211
|
.map(([typeName, entry]) => {
|
|
211
212
|
return entry.prompt ? `${typeName}: ${entry.prompt}` : undefined;
|
|
212
213
|
})
|
|
213
|
-
.filter(
|
|
214
|
+
.filter(isDef);
|
|
214
215
|
if (prompts.length > 0) {
|
|
215
216
|
const nodeTypePrompts = `To do:\n\n- ${prompts.join("- \n")}`;
|
|
216
217
|
return unusedInformation ? `${nodeTypePrompts}\n\n${unusedInformation}` : nodeTypePrompts;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isDef } from "@paroicms/public-anywhere-lib";
|
|
1
2
|
import { getJtHomeType, getJtSiteType, isMultilingual } from "./jt-site-schema-helpers.js";
|
|
2
3
|
import { indent } from "./template-helpers.js";
|
|
3
4
|
export function templateOfDocumentBreadcrumb() {
|
|
@@ -24,7 +25,7 @@ export function templateOfSiteHeader(ctx) {
|
|
|
24
25
|
];
|
|
25
26
|
return `<div class="_bg2">
|
|
26
27
|
<header class="Container Header">
|
|
27
|
-
${indent(content.filter(
|
|
28
|
+
${indent(content.filter(isDef).join("\n"), 2, { skipFirst: true })}
|
|
28
29
|
</header>
|
|
29
30
|
</div>
|
|
30
31
|
<div
|
|
@@ -42,7 +43,7 @@ function templateOfSiteLogoTitle(ctx) {
|
|
|
42
43
|
const content = [
|
|
43
44
|
siteType.fields?.includes("logo")
|
|
44
45
|
? `{% if site.field.logo %}
|
|
45
|
-
{%
|
|
46
|
+
{% set logo = image(site.field.logo, resize: "50x50") %}
|
|
46
47
|
<img
|
|
47
48
|
src="{{ logo.url }}"
|
|
48
49
|
width="{{ logo.width }}"
|
|
@@ -57,7 +58,7 @@ function templateOfSiteLogoTitle(ctx) {
|
|
|
57
58
|
class="Header-logo"
|
|
58
59
|
href="{{ site.home.url }}"
|
|
59
60
|
data-mobile-menu-part="logo">
|
|
60
|
-
${indent(content.filter(
|
|
61
|
+
${indent(content.filter(isDef).join("\n"), 1, { skipFirst: true })}
|
|
61
62
|
</a>`;
|
|
62
63
|
}
|
|
63
64
|
function templateOfMainMenu(ctx) {
|
|
@@ -66,8 +67,8 @@ function templateOfMainMenu(ctx) {
|
|
|
66
67
|
const menuItems = homeType.routingChildren?.filter((typeName) => typeName !== "search" && typeName !== "searchPage");
|
|
67
68
|
if (!menuItems || menuItems.length === 0)
|
|
68
69
|
return;
|
|
69
|
-
const itemTemplates = menuItems.map((typeName) => `{%
|
|
70
|
-
|
|
70
|
+
const itemTemplates = menuItems.map((typeName) => `{% set ${typeName} = doc(site.home.${typeName}) %}
|
|
71
|
+
{% if ${typeName} %}
|
|
71
72
|
<a
|
|
72
73
|
data-menu-item-id="{{ ${typeName}.id }}"
|
|
73
74
|
href="{{ ${typeName}.url }}">
|
|
@@ -88,12 +89,9 @@ function templateOfSearchOpener(ctx) {
|
|
|
88
89
|
if (!typeName)
|
|
89
90
|
return;
|
|
90
91
|
return `<div class="Row center">
|
|
91
|
-
{%
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
data-effect="paSearchOpener"
|
|
95
|
-
data-search-url="{{ ${typeName}.url }}"
|
|
96
|
-
data-icon-color="#fff"></span>
|
|
92
|
+
{% set ${typeName} = doc(site.home.${typeName}) %}
|
|
93
|
+
{% if ${typeName} %}
|
|
94
|
+
{% out searchOpener(url: ${typeName}.url, iconColor: "#fff") %}
|
|
97
95
|
{% endif %}
|
|
98
96
|
<div data-mobile-menu="button"></div>
|
|
99
97
|
</div>`;
|
|
@@ -102,7 +100,7 @@ export function templateOfSiteFooter(ctx) {
|
|
|
102
100
|
const content = [templateOfSiteFooterMention(ctx), templateOfLanguageSelector(ctx)];
|
|
103
101
|
return `<div class="_bg2">
|
|
104
102
|
<footer class="Container">
|
|
105
|
-
${indent(content.filter(
|
|
103
|
+
${indent(content.filter(isDef).join("\n"), 2, { skipFirst: true })}
|
|
106
104
|
</footer>
|
|
107
105
|
</div>`;
|
|
108
106
|
}
|
|
@@ -120,10 +118,11 @@ function templateOfLanguageSelector(ctx) {
|
|
|
120
118
|
return `<ul class="LanguageSelector">
|
|
121
119
|
{% for translation in doc.translations %}
|
|
122
120
|
<li>
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
121
|
+
{% if translation.active %}
|
|
122
|
+
<span>{{ translation.languageLabel }}</span>
|
|
123
|
+
{% else %}
|
|
124
|
+
<a href="{{ translation.url }}">{{ translation.languageLabel }}</a>
|
|
125
|
+
{% endif %}
|
|
127
126
|
</li>
|
|
128
127
|
{% endfor %}
|
|
129
128
|
</ul>`;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { getJtRegularDocumentType, getPossibleJtLabelingFieldTypes, } from "./jt-site-schema-helpers.js";
|
|
2
|
+
import { indent } from "./template-helpers.js";
|
|
3
|
+
export function templateOfDocumentCard(ctx, docVariableName, { parentType } = {}) {
|
|
4
|
+
const { siteSchema } = ctx;
|
|
5
|
+
const possibleTypes = parentType
|
|
6
|
+
? (parentType.regularChildren ?? []).map((childName) => getJtRegularDocumentType(siteSchema, childName))
|
|
7
|
+
: undefined;
|
|
8
|
+
const labelingFields = getPossibleJtLabelingFieldTypes(siteSchema, possibleTypes);
|
|
9
|
+
const labelingTemplates = labelingFields.map((field) => {
|
|
10
|
+
const fieldName = ` ${docVariableName}.field.${field.name}`;
|
|
11
|
+
return `{% if ${fieldName} %}
|
|
12
|
+
<ul class="FlexWrap">
|
|
13
|
+
{% for labelDoc in ${fieldName} %}
|
|
14
|
+
<li class="Label">{{ labelDoc.title }}</li>
|
|
15
|
+
{% endfor %}
|
|
16
|
+
</ul>
|
|
17
|
+
{% endif %}`;
|
|
18
|
+
});
|
|
19
|
+
return `<a href="{{ ${docVariableName}.url }}">
|
|
20
|
+
<article>
|
|
21
|
+
{% if ${docVariableName}.defaultImage %}
|
|
22
|
+
<div>
|
|
23
|
+
{% set im = image(${docVariableName}.defaultImage, resize: "120x120") %}
|
|
24
|
+
<img
|
|
25
|
+
src="{{ im.url }}"
|
|
26
|
+
width="{{ im.width }}"
|
|
27
|
+
height="{{ im.height }}"
|
|
28
|
+
loading="lazy"
|
|
29
|
+
alt=""
|
|
30
|
+
>
|
|
31
|
+
</div>
|
|
32
|
+
{% endif %}
|
|
33
|
+
<div>
|
|
34
|
+
<h3>{{ ${docVariableName}.title }}</h3>
|
|
35
|
+
<p>{{ ${docVariableName}.excerpt | makeExcerpt: 40 }}</p>
|
|
36
|
+
${indent(labelingTemplates.join("\n"), 3, { skipFirst: true })}
|
|
37
|
+
</div>
|
|
38
|
+
</article>
|
|
39
|
+
</a>`;
|
|
40
|
+
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { isDef } from "@paroicms/public-anywhere-lib";
|
|
1
2
|
import { camelToKebabCase } from "../lib/utils.js";
|
|
2
3
|
import { templateOfDocumentBreadcrumb } from "./common-template-creator.js";
|
|
4
|
+
import { templateOfDocumentCard } from "./document-card-template-creator.js";
|
|
3
5
|
import { createIdKeyProvider } from "./id-key-provider.js";
|
|
4
6
|
import { getJtPartType, getJtRoutingDocumentType, hasTemporalChildren, } from "./jt-site-schema-helpers.js";
|
|
7
|
+
import { templatesOfLabeledList } from "./labeled-list-template-creator.js";
|
|
5
8
|
import { getPredefinedDataType, indent, localizedLabelTemplate } from "./template-helpers.js";
|
|
6
9
|
export function templateOfDocumentType(ctx, documentType) {
|
|
7
10
|
const childrenTemplate = templateOfDocumentChildren(ctx, documentType, createIdKeyProvider());
|
|
@@ -11,20 +14,24 @@ export function templateOfDocumentType(ctx, documentType) {
|
|
|
11
14
|
})
|
|
12
15
|
: undefined;
|
|
13
16
|
const titleFieldsTemplate = templateOfTitleAndFields(ctx, documentType);
|
|
14
|
-
const listTemplates = documentType.lists
|
|
17
|
+
const listTemplates = documentType.lists
|
|
18
|
+
?.map((list) => templateOfList(ctx, list, { listKey: `doc.list.${list.listName}`, nested: false }))
|
|
19
|
+
.filter(isDef) ?? [];
|
|
15
20
|
const specialTemplate = templateOfSpecialDocument(ctx, documentType);
|
|
21
|
+
const labeledListTemplates = templatesOfLabeledList(ctx, documentType);
|
|
16
22
|
ctx.addLiquidFile("partials", "breadcrumb.liquid", templateOfDocumentBreadcrumb(), {
|
|
17
23
|
skipIfExists: true,
|
|
18
24
|
});
|
|
19
25
|
const blocks = [
|
|
20
|
-
`{% render "partials/breadcrumb" doc: doc
|
|
26
|
+
`{% render "partials/breadcrumb" doc: doc %}`,
|
|
21
27
|
featuredImageTemplate,
|
|
22
28
|
titleFieldsTemplate,
|
|
23
|
-
childrenTemplate,
|
|
24
29
|
specialTemplate,
|
|
25
30
|
...listTemplates,
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
...labeledListTemplates,
|
|
32
|
+
childrenTemplate,
|
|
33
|
+
].filter(isDef);
|
|
34
|
+
return `{% layout "layouts/main-layout.liquid" %}
|
|
28
35
|
{% block %}
|
|
29
36
|
${blocks.join("\n\n")}
|
|
30
37
|
{% endblock %}`;
|
|
@@ -38,8 +45,8 @@ function templateOfTitleAndFields(ctx, documentType) {
|
|
|
38
45
|
const textBlock = `<div class="TextWidth">
|
|
39
46
|
${indent(blocks1.join("\n"), 1, { skipFirst: true })}
|
|
40
47
|
</div>`;
|
|
41
|
-
const siblingsTemplate = documentType.documentKind === "regular"
|
|
42
|
-
const blocks2 = [textBlock, siblingsTemplate].filter(
|
|
48
|
+
const siblingsTemplate = documentType.documentKind === "regular" ? templateOfSiblingLinks(ctx) : undefined;
|
|
49
|
+
const blocks2 = [textBlock, siblingsTemplate].filter(isDef);
|
|
43
50
|
return `<div class="_bg2">
|
|
44
51
|
<div class="Container">
|
|
45
52
|
<div class="Page">
|
|
@@ -51,31 +58,31 @@ function templateOfTitleAndFields(ctx, documentType) {
|
|
|
51
58
|
function templateOfSpecialDocument(ctx, documentType) {
|
|
52
59
|
const { addLiquidFile } = ctx;
|
|
53
60
|
if (documentType.typeName === "search" || documentType.typeName === "searchPage") {
|
|
54
|
-
addLiquidFile("partials", "result-item.public.liquid",
|
|
55
|
-
return `<div
|
|
56
|
-
class="
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
addLiquidFile("partials", "result-item.public.liquid", templateOfDocumentCard(ctx, "doc"));
|
|
62
|
+
return `<div class="Container">
|
|
63
|
+
<div class="Page">
|
|
64
|
+
{% out searchApp(class: "Container", template: "partials/result-item.public", by: 10) %}
|
|
65
|
+
</div>
|
|
66
|
+
</div>`;
|
|
60
67
|
}
|
|
61
68
|
if (documentType.typeName === "contact" || documentType.typeName === "contactPage") {
|
|
62
69
|
return `<div class="Container">
|
|
63
|
-
<div class="
|
|
64
|
-
<div
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
<div class="Page">
|
|
71
|
+
<div class="TextWidth Pt">
|
|
72
|
+
{% out contactForm %}
|
|
73
|
+
</div>
|
|
67
74
|
</div>
|
|
68
75
|
</div>`;
|
|
69
76
|
}
|
|
70
77
|
}
|
|
71
78
|
function templateOfDocumentChildren(ctx, parentType, parentIdKeyProvider) {
|
|
72
79
|
const routingBlocks = templateOfRoutingChildren(ctx, parentType, parentIdKeyProvider);
|
|
73
|
-
const regularBlocks = parentType.documentKind === "routing" &&
|
|
74
|
-
parentType
|
|
75
|
-
templateOfRegularDocumentTiles(ctx, parentType, parentIdKeyProvider, {
|
|
80
|
+
const regularBlocks = parentType.documentKind === "routing" && parentType.regularChildren
|
|
81
|
+
? templateOfRegularDocumentCards(ctx, parentType, parentIdKeyProvider, {
|
|
76
82
|
mode: "all",
|
|
77
|
-
})
|
|
78
|
-
|
|
83
|
+
})
|
|
84
|
+
: undefined;
|
|
85
|
+
return [routingBlocks, regularBlocks].filter(isDef).join("\n\n") || undefined;
|
|
79
86
|
}
|
|
80
87
|
function templateOfRoutingChildren(ctx, parentType, parentIdKeyProvider) {
|
|
81
88
|
const { siteSchema } = ctx;
|
|
@@ -87,7 +94,7 @@ function templateOfRoutingChildren(ctx, parentType, parentIdKeyProvider) {
|
|
|
87
94
|
}
|
|
88
95
|
return templateOfRoutingChild(ctx, child, parentIdKeyProvider);
|
|
89
96
|
})
|
|
90
|
-
.filter(
|
|
97
|
+
.filter(isDef);
|
|
91
98
|
if (routingBlocks.length === 0)
|
|
92
99
|
return;
|
|
93
100
|
return `<div class="Container">
|
|
@@ -101,63 +108,52 @@ function templateOfRoutingChild(ctx, child, parentIdKeyProvider) {
|
|
|
101
108
|
const idKeyProvider = parentIdKeyProvider.createForRoutingChild(typeName);
|
|
102
109
|
const key = idKeyProvider.key;
|
|
103
110
|
if (!hasTemporalChildren(siteSchema, child) || regularChildrenSorting !== "publishDate desc") {
|
|
104
|
-
const buttonTemplate = `{%
|
|
105
|
-
|
|
111
|
+
const buttonTemplate = `{% set ${variableName} = doc(${key}) %}
|
|
112
|
+
{% if ${variableName} %}
|
|
106
113
|
<a class="Button" href="{{ ${variableName}.url }}">{{ ${variableName}.title }}</a>
|
|
107
114
|
{% endif %}`;
|
|
108
115
|
return buttonTemplate;
|
|
109
116
|
}
|
|
110
|
-
const
|
|
117
|
+
const cardsTemplate = templateOfRegularDocumentCards(ctx, child, idKeyProvider, {
|
|
111
118
|
mode: "sampleOnly",
|
|
112
119
|
});
|
|
113
|
-
return `{%
|
|
114
|
-
{%
|
|
115
|
-
<div class="Pt">
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
</div>
|
|
120
|
+
return `{% set ${variableName} = doc(${key}) %}
|
|
121
|
+
{% if ${variableName} %}
|
|
122
|
+
<div class="Pt">
|
|
123
|
+
<h2>
|
|
124
|
+
<a class="TextLink" href="{{ ${variableName}.url }}">{{ ${variableName}.title }}</a>
|
|
125
|
+
</h2>
|
|
126
|
+
${indent(cardsTemplate, 2, { skipFirst: true })}
|
|
127
|
+
</div>
|
|
121
128
|
{% endif %}`;
|
|
122
129
|
}
|
|
123
|
-
function
|
|
130
|
+
function templateOfRegularDocumentCards(ctx, parentType, parentIdKeyProvider, { mode }) {
|
|
124
131
|
const { siteSchema, addLiquidFile } = ctx;
|
|
125
132
|
const { typeName: parentTypeName } = parentType;
|
|
126
133
|
const childrenVariableName = `${parentTypeName}Children`;
|
|
127
134
|
const childVariableName = `${parentTypeName}Child`;
|
|
128
|
-
const
|
|
135
|
+
const key = parentIdKeyProvider.key;
|
|
129
136
|
if (mode === "sampleOnly") {
|
|
130
|
-
return `{%
|
|
137
|
+
return `{% set ${childrenVariableName} = docs(${key}.children, limit: 4) %}
|
|
131
138
|
<div class="List">
|
|
132
139
|
{% for ${childVariableName} in ${childrenVariableName} %}
|
|
133
|
-
${indent(
|
|
140
|
+
${indent(templateOfDocumentCard(ctx, childVariableName, { parentType }), 2, { skipFirst: true })}
|
|
134
141
|
{% endfor %}
|
|
135
142
|
</div>`;
|
|
136
143
|
}
|
|
137
144
|
if (!hasTemporalChildren(siteSchema, parentType)) {
|
|
138
|
-
return `{%
|
|
145
|
+
return `{% set ${childrenVariableName} = docs(${key}.children) %}
|
|
139
146
|
<div class="Container List Pt Pb">
|
|
140
147
|
{% for ${childVariableName} in ${childrenVariableName} %}
|
|
141
|
-
${indent(
|
|
148
|
+
${indent(templateOfDocumentCard(ctx, childVariableName, { parentType }), 2, { skipFirst: true })}
|
|
142
149
|
{% endfor %}
|
|
143
150
|
</div>`;
|
|
144
151
|
}
|
|
145
|
-
const
|
|
146
|
-
addLiquidFile("partials", `${
|
|
147
|
-
return `{%
|
|
152
|
+
const cardTemplateName = `${camelToKebabCase(parentTypeName)}-card.public`;
|
|
153
|
+
addLiquidFile("partials", `${cardTemplateName}.liquid`, templateOfDocumentCard(ctx, "doc", { parentType }), { skipIfExists: true });
|
|
154
|
+
return `{% set ${childrenVariableName} = paginatedDocs(${key}.children, by: 10) %}
|
|
148
155
|
<div class="Container">
|
|
149
|
-
|
|
150
|
-
class="Page List"
|
|
151
|
-
data-effect="paInfiniteLoading"
|
|
152
|
-
data-parent-id="{{ ${idKey} }}"
|
|
153
|
-
data-start="{{ ${childrenVariableName}.pageSize }}"
|
|
154
|
-
data-limit="{{ ${childrenVariableName}.pageSize }}"
|
|
155
|
-
data-total="{{ ${childrenVariableName}.total }}"
|
|
156
|
-
data-template="${tileTemplateName}">
|
|
157
|
-
{% for ${childrenVariableName} in ${childrenVariableName}.items %}
|
|
158
|
-
{% render "partials/${tileTemplateName}.public.liquid" doc: ${childrenVariableName} %}
|
|
159
|
-
{% endfor %}
|
|
160
|
-
</div>
|
|
156
|
+
{% out infiniteLoading(class: "Page List", paginatedDocs: ${childrenVariableName}, template: "partials/${cardTemplateName}") %}
|
|
161
157
|
</div>`;
|
|
162
158
|
}
|
|
163
159
|
function templateOfFields(ctx, fields, { parentKey }) {
|
|
@@ -178,9 +174,9 @@ function templateOfField(ctx, fieldOrName, parentKey) {
|
|
|
178
174
|
<div class="Field">
|
|
179
175
|
{% for tag in ${parentKey}.${fieldName} %}
|
|
180
176
|
{% if tag.inRightLanguage %}
|
|
181
|
-
<a href="{{ tag.url }}">{{ tag.title }}</a>
|
|
177
|
+
<a class="Label" href="{{ tag.url }}">{{ tag.title }}</a>
|
|
182
178
|
{% else %}
|
|
183
|
-
<span>{{ tag.title }}</span>
|
|
179
|
+
<span class="Label">{{ tag.title }}</span>
|
|
184
180
|
{% endif %}
|
|
185
181
|
{% endfor %}
|
|
186
182
|
</div>
|
|
@@ -201,7 +197,7 @@ function templateOfField(ctx, fieldOrName, parentKey) {
|
|
|
201
197
|
if (dataType === "gallery") {
|
|
202
198
|
return `<div class="Field">
|
|
203
199
|
{% for media in ${parentKey}.${fieldName} %}
|
|
204
|
-
{%
|
|
200
|
+
{% set im = image(media, resize: "150x150") %}
|
|
205
201
|
<img
|
|
206
202
|
class="Field-img"
|
|
207
203
|
src="{{ im.url }}"
|
|
@@ -216,7 +212,7 @@ function templateOfField(ctx, fieldOrName, parentKey) {
|
|
|
216
212
|
}
|
|
217
213
|
if (dataType === "media") {
|
|
218
214
|
const mediaKey = `${parentKey}.${fieldName}`;
|
|
219
|
-
return `{%
|
|
215
|
+
return `{% set im = image(${mediaKey}, resize: "x250x") %}
|
|
220
216
|
<div class="Field">
|
|
221
217
|
<img
|
|
222
218
|
class="Field-img"
|
|
@@ -236,21 +232,23 @@ function templateOfField(ctx, fieldOrName, parentKey) {
|
|
|
236
232
|
}
|
|
237
233
|
function templateOfPicture({ imageKey }) {
|
|
238
234
|
return `{% if ${imageKey} %}
|
|
239
|
-
{%
|
|
240
|
-
{%
|
|
235
|
+
{% set smallIm = image(${imageKey}, resize: "360x48") %}
|
|
236
|
+
{% set largeIm = image(${imageKey}, resize: "1200x160") %}
|
|
241
237
|
<div class="Container">
|
|
242
238
|
<picture class="Hero">
|
|
243
239
|
<source
|
|
244
240
|
srcset="{{ largeIm.url }}"
|
|
245
241
|
width="{{ largeIm.width }}"
|
|
246
242
|
height="{{ largeIm.height }}"
|
|
247
|
-
media="(min-width: 361px)"
|
|
243
|
+
media="(min-width: 361px)"
|
|
244
|
+
>
|
|
248
245
|
<img
|
|
249
246
|
src="{{ smallIm.url }}"
|
|
250
247
|
width="{{ smallIm.width }}"
|
|
251
248
|
height="{{ smallIm.height }}"
|
|
252
249
|
loading="lazy"
|
|
253
|
-
alt=""
|
|
250
|
+
alt=""
|
|
251
|
+
>
|
|
254
252
|
</picture>
|
|
255
253
|
</div>
|
|
256
254
|
{% endif %}`;
|
|
@@ -273,7 +271,7 @@ function templateOfList(ctx, list, { listKey, nested }) {
|
|
|
273
271
|
return `{% ${ifOrElsif} part.type == "${partType.typeName}" %}
|
|
274
272
|
{% render "partials/${partTemplateName}.liquid" part: part %}`;
|
|
275
273
|
})
|
|
276
|
-
.filter(
|
|
274
|
+
.filter(isDef);
|
|
277
275
|
partTemplates.push("{% endif %}");
|
|
278
276
|
if (nested) {
|
|
279
277
|
return `{% if ${listKey} %}
|
|
@@ -303,7 +301,7 @@ function templateOfPart(ctx, part, partKey) {
|
|
|
303
301
|
nested: true,
|
|
304
302
|
})
|
|
305
303
|
: undefined,
|
|
306
|
-
].filter(
|
|
304
|
+
].filter(isDef);
|
|
307
305
|
return `<section class="TextWidth">
|
|
308
306
|
${indent(templates.join("\n\n"), 1, { skipFirst: true })}
|
|
309
307
|
</section>`;
|
|
@@ -318,34 +316,15 @@ function templateOfSiblingLinks(ctx) {
|
|
|
318
316
|
fr: "Suivant",
|
|
319
317
|
});
|
|
320
318
|
return `<div class="Row spaceBetween">
|
|
321
|
-
{%
|
|
322
|
-
|
|
319
|
+
{% set previous = doc(doc.siblings.previous) %}
|
|
320
|
+
{% if previous %}
|
|
321
|
+
<a href="{{ previous.url }}" title="{{ previous.title }}">← ${previousLabelTemplate}</a>
|
|
323
322
|
{% else %}
|
|
324
323
|
<span></span>
|
|
325
324
|
{% endif %}
|
|
326
|
-
{%
|
|
327
|
-
|
|
325
|
+
{% set next = doc(doc.siblings.next) %}
|
|
326
|
+
{% if next %}
|
|
327
|
+
<a href="{{ next.url }}" title="{{ next.title }}">${nextLabelTemplate} →</a>
|
|
328
328
|
{% endif %}
|
|
329
329
|
</div>`;
|
|
330
330
|
}
|
|
331
|
-
function templateOfDocumentTile(docVariableName) {
|
|
332
|
-
return `<a href="{{ ${docVariableName}.url }}">
|
|
333
|
-
<article>
|
|
334
|
-
{% if ${docVariableName}.defaultImage %}
|
|
335
|
-
<div>
|
|
336
|
-
{% useImage im image: ${docVariableName}.defaultImage resize: "120x120" %}
|
|
337
|
-
<img
|
|
338
|
-
src="{{ im.url }}"
|
|
339
|
-
width="{{ im.width }}"
|
|
340
|
-
height="{{ im.height }}"
|
|
341
|
-
loading="lazy"
|
|
342
|
-
alt="">
|
|
343
|
-
</div>
|
|
344
|
-
{% endif %}
|
|
345
|
-
<div>
|
|
346
|
-
<h3>{{ ${docVariableName}.title }}</h3>
|
|
347
|
-
<p>{{ ${docVariableName}.excerpt | makeExcerpt: 40 }}</p>
|
|
348
|
-
</div>
|
|
349
|
-
</article>
|
|
350
|
-
</a>`;
|
|
351
|
-
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export function createIdKeyProvider() {
|
|
2
2
|
return {
|
|
3
|
-
key: "doc",
|
|
3
|
+
key: "doc.routing",
|
|
4
4
|
idKey: "doc.id",
|
|
5
5
|
getChildRoutingKey: (typeName) => `doc.routing.${typeName}`,
|
|
6
6
|
createForRoutingChild: (routingTypeName) => createChildIdKeyProvider(`doc.routing.${routingTypeName}`),
|
|
@@ -53,3 +53,19 @@ export function getFirstSiteLanguage(siteSchema) {
|
|
|
53
53
|
throw new Error("Missing language in site schema");
|
|
54
54
|
return siteSchema.languages[0];
|
|
55
55
|
}
|
|
56
|
+
export function getPossibleJtLabelingFieldTypes(siteSchema, possibleTypes) {
|
|
57
|
+
const searchInTypes = possibleTypes ??
|
|
58
|
+
siteSchema.nodeTypes?.filter((type) => type.kind === "document" && type.documentKind === "regular") ??
|
|
59
|
+
[];
|
|
60
|
+
const result = [];
|
|
61
|
+
for (const documentType of searchInTypes) {
|
|
62
|
+
for (const fieldType of documentType.fields ?? []) {
|
|
63
|
+
if (typeof fieldType !== "string" &&
|
|
64
|
+
fieldType.storedAs === "labeling" &&
|
|
65
|
+
!result.find((alreadyThere) => alreadyThere.name === fieldType.name)) {
|
|
66
|
+
result.push(fieldType);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { isDef } from "@paroicms/public-anywhere-lib";
|
|
2
|
+
import { camelToKebabCase } from "../lib/utils.js";
|
|
3
|
+
import { templateOfDocumentCard } from "./document-card-template-creator.js";
|
|
4
|
+
export function templatesOfLabeledList(ctx, documentType) {
|
|
5
|
+
const { addLiquidFile } = ctx;
|
|
6
|
+
const labeledByUs = ctx.labeledDocuments.filter((doc) => {
|
|
7
|
+
const parentTypes = ctx.getParentTypes(documentType);
|
|
8
|
+
return parentTypes.some((parentType) => parentType.typeName === doc.taxonomyType.typeName);
|
|
9
|
+
});
|
|
10
|
+
return labeledByUs
|
|
11
|
+
.map((labeledDocument) => {
|
|
12
|
+
const parentRoutingKey = getRoutingKeyInCluster(ctx, labeledDocument.parentDocumentType, {
|
|
13
|
+
sameClusterAs: labeledDocument.taxonomyType,
|
|
14
|
+
});
|
|
15
|
+
if (!parentRoutingKey)
|
|
16
|
+
return;
|
|
17
|
+
const labeledListKey = `labeled${upperCaseFirstLetter(labeledDocument.parentDocumentType.typeName)}`;
|
|
18
|
+
const cardTemplateName = `${camelToKebabCase(labeledDocument.documentType.typeName)}-card.public`;
|
|
19
|
+
addLiquidFile("partials", `${cardTemplateName}.liquid`, templateOfDocumentCard(ctx, "doc", { parentType: labeledDocument.parentDocumentType }), { skipIfExists: true });
|
|
20
|
+
return `{% set ${labeledListKey} = paginatedDocs(${parentRoutingKey}.children, by: 10, term: doc, labeledWith: "${labeledDocument.field.name}") %}
|
|
21
|
+
<div class="Container">
|
|
22
|
+
{% out infiniteLoading(class: "Page List", paginatedDocs: ${labeledListKey}, template: "partials/${cardTemplateName}") %}
|
|
23
|
+
</div>`;
|
|
24
|
+
})
|
|
25
|
+
.filter(isDef);
|
|
26
|
+
}
|
|
27
|
+
function upperCaseFirstLetter(str) {
|
|
28
|
+
return `${str.charAt(0).toUpperCase()}${str.slice(1)}`;
|
|
29
|
+
}
|
|
30
|
+
function getRoutingKeyInCluster(ctx, documentType, options) {
|
|
31
|
+
const { siteSchema } = ctx;
|
|
32
|
+
const { nodeTypes } = siteSchema;
|
|
33
|
+
if (!nodeTypes)
|
|
34
|
+
return;
|
|
35
|
+
const getNodeType = (typeName) => nodeTypes.find((nt) => nt.typeName === typeName);
|
|
36
|
+
function findPath(target, current, parentPath) {
|
|
37
|
+
const currentPath = [...parentPath, current];
|
|
38
|
+
if (current === target)
|
|
39
|
+
return currentPath;
|
|
40
|
+
const node = getNodeType(current);
|
|
41
|
+
if (!node || node.kind !== "document" || !node.routingChildren)
|
|
42
|
+
return;
|
|
43
|
+
for (const childName of node.routingChildren) {
|
|
44
|
+
const found = findPath(target, childName, currentPath);
|
|
45
|
+
if (found)
|
|
46
|
+
return found;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const clusterRootTypeName = "home"; // limitation here: only works for the "home" cluster
|
|
50
|
+
const targetPath = findPath(documentType.typeName, clusterRootTypeName, []);
|
|
51
|
+
const sameClusterPath = findPath(options.sameClusterAs.typeName, clusterRootTypeName, []);
|
|
52
|
+
if (!targetPath || !sameClusterPath)
|
|
53
|
+
return;
|
|
54
|
+
targetPath.shift(); // remove leading 'home'
|
|
55
|
+
return `doc.cluster.routing.${targetPath.join(".")}`;
|
|
56
|
+
}
|