@paroicms/site-generator-plugin 0.1.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/README.md +9 -0
- package/gen-backend/dist/context.js +2 -0
- package/gen-backend/dist/data-format.js +37 -0
- package/gen-backend/dist/generator/actions.js +35 -0
- package/gen-backend/dist/generator/fake-content-generator.ts/create-database-with-fake-content.js +227 -0
- package/gen-backend/dist/generator/fake-content-generator.ts/create-node-contents.js +156 -0
- package/gen-backend/dist/generator/fake-content-generator.ts/fake-content-types.js +1 -0
- package/gen-backend/dist/generator/fake-content-generator.ts/generate-fake-content.js +127 -0
- package/gen-backend/dist/generator/fake-content-generator.ts/invoke-generate-fake-content.js +49 -0
- package/gen-backend/dist/generator/generator-types.js +1 -0
- package/gen-backend/dist/generator/helpers/esm-module.helper.js +6 -0
- package/gen-backend/dist/generator/helpers/js-utils.js +14 -0
- package/gen-backend/dist/generator/lib/common-types.js +1 -0
- package/gen-backend/dist/generator/lib/create-prompt.js +44 -0
- package/gen-backend/dist/generator/lib/debug-utils.js +118 -0
- package/gen-backend/dist/generator/lib/images-lib.js +16 -0
- package/gen-backend/dist/generator/lib/llm-invoke-types.js +1 -0
- package/gen-backend/dist/generator/lib/llm-tokens.js +10 -0
- package/gen-backend/dist/generator/lib/markdown-bulleted-list-parser.js +147 -0
- package/gen-backend/dist/generator/lib/parse-llm-response.js +160 -0
- package/gen-backend/dist/generator/lib/tasks.js +112 -0
- package/gen-backend/dist/generator/lib/utils.js +13 -0
- package/gen-backend/dist/generator/llm-queries/invoke-message-guard.js +86 -0
- package/gen-backend/dist/generator/llm-queries/invoke-new-site-analysis.js +169 -0
- package/gen-backend/dist/generator/llm-queries/invoke-update-site-schema.js +94 -0
- package/gen-backend/dist/generator/site-generator/common-template-creator.js +108 -0
- package/gen-backend/dist/generator/site-generator/document-template-creator.js +329 -0
- package/gen-backend/dist/generator/site-generator/id-key-provider.js +14 -0
- package/gen-backend/dist/generator/site-generator/jt-site-schema-helpers.js +55 -0
- package/gen-backend/dist/generator/site-generator/site-generator.js +75 -0
- package/gen-backend/dist/generator/site-generator/template-creator-types.js +1 -0
- package/gen-backend/dist/generator/site-generator/template-helpers.js +26 -0
- package/gen-backend/dist/generator/site-generator/theme-creator.js +180 -0
- package/gen-backend/dist/generator/site-generator/theme-css.js +323 -0
- package/gen-backend/dist/generator/site-schema-generator/analysis-types.js +1 -0
- package/gen-backend/dist/generator/site-schema-generator/create-l10n.js +42 -0
- package/gen-backend/dist/generator/site-schema-generator/create-site-schema.js +240 -0
- package/gen-backend/dist/generator/site-schema-generator/default-pages.js +38 -0
- package/gen-backend/dist/plugin.js +86 -0
- package/gen-backend/prompts/0-context.md +9 -0
- package/gen-backend/prompts/generate-fake-content-multiple.md +22 -0
- package/gen-backend/prompts/generate-fake-content-single.md +16 -0
- package/gen-backend/prompts/message-guard.md +89 -0
- package/gen-backend/prompts/new-site-1-analysis.md +214 -0
- package/gen-backend/prompts/new-site-2-fields.md +50 -0
- package/gen-backend/prompts/predefined-fields.json +110 -0
- package/gen-backend/prompts/test-message1.txt +1 -0
- package/gen-backend/prompts/update-site-schema-1-write-details.md +57 -0
- package/gen-backend/prompts/update-site-schema-2-execute.md +77 -0
- package/gen-front/dist/gen-front.css +1 -0
- package/gen-front/dist/gen-front.eot +0 -0
- package/gen-front/dist/gen-front.mjs +998 -0
- package/gen-front/dist/gen-front.svg +345 -0
- package/gen-front/dist/gen-front.ttf +0 -0
- package/gen-front/dist/gen-front.woff +0 -0
- package/gen-front/dist/gen-front.woff2 +0 -0
- package/gen-front/dist/gen-front2.woff2 +0 -0
- package/gen-front/dist/gen-front3.woff2 +0 -0
- package/package.json +79 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { boolVal, listValOrUndef, strVal, strValOrUndef, } from "@paroi/data-formatters-lib";
|
|
2
|
+
import { createPromptTemplate } from "../lib/create-prompt.js";
|
|
3
|
+
import { debugLlmOutput } from "../lib/debug-utils.js";
|
|
4
|
+
import { parseLlmResponseAsProperties } from "../lib/parse-llm-response.js";
|
|
5
|
+
const guardPrompt = await createPromptTemplate({
|
|
6
|
+
fileName: "message-guard.md",
|
|
7
|
+
});
|
|
8
|
+
const invalidCauses = new Set(["rude", "malicious", "outOfScope", "technicalLimits", "noSense"]);
|
|
9
|
+
export async function invokeMessageGuard(ctx, input) {
|
|
10
|
+
const debugName = "guard";
|
|
11
|
+
const llmInput = {
|
|
12
|
+
message: input.prompt,
|
|
13
|
+
};
|
|
14
|
+
const debug = await debugLlmOutput(ctx, debugName, ctx.goodModelName, {
|
|
15
|
+
message: llmInput.message,
|
|
16
|
+
});
|
|
17
|
+
let llmMessageContent = debug.storedContent;
|
|
18
|
+
if (!llmMessageContent) {
|
|
19
|
+
const llmMessage = await guardPrompt.pipe(ctx.goodModel).invoke(llmInput);
|
|
20
|
+
llmMessageContent = await debug.getMessageContent(llmMessage);
|
|
21
|
+
}
|
|
22
|
+
const rawReport = parseLlmResponseAsProperties(llmMessageContent, [
|
|
23
|
+
{
|
|
24
|
+
tagName: "guard_yaml",
|
|
25
|
+
key: "guard",
|
|
26
|
+
format: "yaml",
|
|
27
|
+
},
|
|
28
|
+
]);
|
|
29
|
+
const report = formatMessageGuardReport(rawReport.guard);
|
|
30
|
+
if (report.valid)
|
|
31
|
+
return;
|
|
32
|
+
return {
|
|
33
|
+
success: false,
|
|
34
|
+
language: report.language,
|
|
35
|
+
userMessage: report.explanation ?? toUserMessage(report.causes, report.language),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function toUserMessage(causes, language) {
|
|
39
|
+
if (!causes || causes.length === 0)
|
|
40
|
+
return "Invalid message";
|
|
41
|
+
return causes.map((cause) => getCauseLabel(cause, language)).join(", ");
|
|
42
|
+
}
|
|
43
|
+
function getCauseLabel(cause, language) {
|
|
44
|
+
if (language === "fr") {
|
|
45
|
+
switch (cause) {
|
|
46
|
+
case "rude":
|
|
47
|
+
case "malicious":
|
|
48
|
+
return "Nous ne pouvons pas répondre à cette demande";
|
|
49
|
+
case "outOfScope":
|
|
50
|
+
return "Hors sujet";
|
|
51
|
+
case "technicalLimits":
|
|
52
|
+
return "Limites techniques";
|
|
53
|
+
case "noSense":
|
|
54
|
+
return "Nous ne comprenons pas la demande";
|
|
55
|
+
default:
|
|
56
|
+
return cause;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
switch (cause) {
|
|
60
|
+
case "rude":
|
|
61
|
+
case "malicious":
|
|
62
|
+
return "We cannot answer to this request";
|
|
63
|
+
case "outOfScope":
|
|
64
|
+
return "Out of scope";
|
|
65
|
+
case "technicalLimits":
|
|
66
|
+
return "Technical limits";
|
|
67
|
+
case "noSense":
|
|
68
|
+
return "We do not understand the request";
|
|
69
|
+
default:
|
|
70
|
+
return cause;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function formatMessageGuardReport(rawReport) {
|
|
74
|
+
return {
|
|
75
|
+
language: strValOrUndef(rawReport.language, { varName: "language" }),
|
|
76
|
+
valid: boolVal(rawReport.valid, { varName: "valid" }),
|
|
77
|
+
causes: listValOrUndef(rawReport.causes, formatGuardInvalidCause),
|
|
78
|
+
explanation: strValOrUndef(rawReport.explanation, { varName: "explanation" }),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function formatGuardInvalidCause(cause) {
|
|
82
|
+
const v = strVal(cause, { varName: "cause" });
|
|
83
|
+
if (!invalidCauses.has(v))
|
|
84
|
+
throw new Error(`Invalid cause: "${v}"`);
|
|
85
|
+
return v;
|
|
86
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { reorderObjectKeys } from "../helpers/js-utils.js";
|
|
2
|
+
import { createPromptTemplate, getPredefinedFields, getSiteSchemaTsDefs, } from "../lib/create-prompt.js";
|
|
3
|
+
import { debugLlmOutput } from "../lib/debug-utils.js";
|
|
4
|
+
import { parseMarkdownBulletedList } from "../lib/markdown-bulleted-list-parser.js";
|
|
5
|
+
import { parseLlmResponseAsProperties } from "../lib/parse-llm-response.js";
|
|
6
|
+
import { createL10n } from "../site-schema-generator/create-l10n.js";
|
|
7
|
+
import { createSiteSchemaFromAnalysis } from "../site-schema-generator/create-site-schema.js";
|
|
8
|
+
import { invokeUpdateSiteSchema } from "./invoke-update-site-schema.js";
|
|
9
|
+
export const analyzePrompt = await createPromptTemplate({
|
|
10
|
+
fileName: "new-site-1-analysis.md",
|
|
11
|
+
withSiteSchemaTsDefs: true,
|
|
12
|
+
});
|
|
13
|
+
const fieldsPrompt = await createPromptTemplate({
|
|
14
|
+
fileName: "new-site-2-fields.md",
|
|
15
|
+
withSiteSchemaTsDefs: true,
|
|
16
|
+
});
|
|
17
|
+
export async function invokeNewSiteAnalysis(ctx, input) {
|
|
18
|
+
const { analysis, explanation, unusedInformation } = await invokeAnalysisStep1(ctx, input);
|
|
19
|
+
const siteSchema = createSiteSchemaFromAnalysis(analysis);
|
|
20
|
+
await invokeAnalysisStep2(ctx, { prompt: unusedInformation ?? "" }, siteSchema);
|
|
21
|
+
reorderSiteSchemaNodeTypes(siteSchema);
|
|
22
|
+
const l10n = createL10n(analysis, siteSchema);
|
|
23
|
+
const siteTitle = {
|
|
24
|
+
[analysis.siteProperties.language]: analysis.siteProperties.title,
|
|
25
|
+
};
|
|
26
|
+
if (!unusedInformation) {
|
|
27
|
+
return {
|
|
28
|
+
siteTitle,
|
|
29
|
+
siteSchema,
|
|
30
|
+
l10n,
|
|
31
|
+
explanation,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
ctx.logger.debug("Unused information:", unusedInformation);
|
|
35
|
+
const updated = await invokeUpdateSiteSchema(ctx, {
|
|
36
|
+
prompt: unusedInformation,
|
|
37
|
+
generatedSchema: {
|
|
38
|
+
siteTitle,
|
|
39
|
+
siteSchema,
|
|
40
|
+
l10n,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
return {
|
|
44
|
+
siteTitle,
|
|
45
|
+
siteSchema: updated.siteSchema,
|
|
46
|
+
l10n: updated.l10n,
|
|
47
|
+
explanation: `${explanation}\n\n${updated.explanation}`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
async function invokeAnalysisStep1(ctx, input) {
|
|
51
|
+
const debugName = "analysis";
|
|
52
|
+
const llmInput = {
|
|
53
|
+
message: input.prompt,
|
|
54
|
+
siteSchemaTsDefs: getSiteSchemaTsDefs(),
|
|
55
|
+
};
|
|
56
|
+
const debug = await debugLlmOutput(ctx, debugName, ctx.goodModelName, {
|
|
57
|
+
message: llmInput.message,
|
|
58
|
+
});
|
|
59
|
+
let llmMessageContent = debug.storedContent;
|
|
60
|
+
if (!llmMessageContent) {
|
|
61
|
+
const llmMessage = await analyzePrompt.pipe(ctx.goodModel).invoke(llmInput);
|
|
62
|
+
llmMessageContent = await debug.getMessageContent(llmMessage);
|
|
63
|
+
}
|
|
64
|
+
const rawAnalysis = parseLlmResponseAsProperties(llmMessageContent, [
|
|
65
|
+
{
|
|
66
|
+
tagName: "website_properties_yaml",
|
|
67
|
+
key: "siteProperties",
|
|
68
|
+
format: "yaml",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
tagName: "hierarchical_md",
|
|
72
|
+
key: "tree",
|
|
73
|
+
format: "markdown",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
tagName: "dictionary_yaml",
|
|
77
|
+
key: "dictionary",
|
|
78
|
+
format: "yaml",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
tagName: "explanation_md",
|
|
82
|
+
key: "explanation",
|
|
83
|
+
format: "markdown",
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
tagName: "unused_information_md",
|
|
87
|
+
key: "unusedInformation",
|
|
88
|
+
format: "markdown",
|
|
89
|
+
optional: true,
|
|
90
|
+
},
|
|
91
|
+
]);
|
|
92
|
+
const tree = parseMarkdownBulletedList(rawAnalysis.tree);
|
|
93
|
+
const analysis = {
|
|
94
|
+
dictionary: rawAnalysis.dictionary,
|
|
95
|
+
siteProperties: rawAnalysis.siteProperties,
|
|
96
|
+
tree,
|
|
97
|
+
};
|
|
98
|
+
return {
|
|
99
|
+
analysis,
|
|
100
|
+
explanation: rawAnalysis.explanation,
|
|
101
|
+
unusedInformation: rawAnalysis.unusedInformation,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
async function invokeAnalysisStep2(ctx, input,
|
|
105
|
+
/** Will be mutated. */
|
|
106
|
+
siteSchema) {
|
|
107
|
+
const debugName = "assign-fields";
|
|
108
|
+
const llmInput = {
|
|
109
|
+
siteSchemaTsDefs: getSiteSchemaTsDefs(),
|
|
110
|
+
predefinedFields: JSON.stringify(getPredefinedFields(), undefined, 2),
|
|
111
|
+
siteSchemaJson: JSON.stringify(siteSchema, undefined, 2),
|
|
112
|
+
message: input.prompt,
|
|
113
|
+
};
|
|
114
|
+
const debug = await debugLlmOutput(ctx, debugName, ctx.goodModelName, {
|
|
115
|
+
message: llmInput.message,
|
|
116
|
+
siteSchemaJson: llmInput.siteSchemaJson,
|
|
117
|
+
});
|
|
118
|
+
let llmMessageContent = debug.storedContent;
|
|
119
|
+
if (!llmMessageContent) {
|
|
120
|
+
const llmMessage = await fieldsPrompt.pipe(ctx.goodModel).invoke(llmInput);
|
|
121
|
+
llmMessageContent = await debug.getMessageContent(llmMessage);
|
|
122
|
+
}
|
|
123
|
+
const { assignedFields } = parseLlmResponseAsProperties(llmMessageContent, [
|
|
124
|
+
{
|
|
125
|
+
tagName: "yaml_result",
|
|
126
|
+
key: "assignedFields",
|
|
127
|
+
format: "yaml",
|
|
128
|
+
},
|
|
129
|
+
]);
|
|
130
|
+
if (siteSchema.nodeTypes) {
|
|
131
|
+
assignFieldsToNodeTypes(ctx, assignedFields, siteSchema.nodeTypes);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function assignFieldsToNodeTypes(ctx, assignedFields, nodeTypes) {
|
|
135
|
+
const remainingTypeNames = new Set(Object.keys(assignedFields));
|
|
136
|
+
for (const nodeType of nodeTypes) {
|
|
137
|
+
const typeName = nodeType.kind === "site" ? "_site" : nodeType.typeName;
|
|
138
|
+
const fieldNames = assignedFields[typeName];
|
|
139
|
+
if (!fieldNames) {
|
|
140
|
+
ctx.logger.warn(`Missing assigned fields for node type "${typeName}"`);
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (fieldNames.length > 0) {
|
|
144
|
+
nodeType.fields = fieldNames;
|
|
145
|
+
}
|
|
146
|
+
remainingTypeNames.delete(typeName);
|
|
147
|
+
}
|
|
148
|
+
if (remainingTypeNames.size > 0) {
|
|
149
|
+
ctx.logger.warn(`Field names were produced for unknown node types: ${[...remainingTypeNames].join(", ")}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function reorderSiteSchemaNodeTypes(siteSchema) {
|
|
153
|
+
if (!siteSchema.nodeTypes)
|
|
154
|
+
return;
|
|
155
|
+
siteSchema.nodeTypes = siteSchema.nodeTypes.map((nodeType) => reorderObjectKeys(nodeType, [
|
|
156
|
+
"typeName",
|
|
157
|
+
"kind",
|
|
158
|
+
"documentKind",
|
|
159
|
+
"route",
|
|
160
|
+
"redirectTo",
|
|
161
|
+
"ogType",
|
|
162
|
+
"withFeaturedImage",
|
|
163
|
+
"fields",
|
|
164
|
+
"lists",
|
|
165
|
+
"routingChildren",
|
|
166
|
+
"children",
|
|
167
|
+
"orderChildrenBy",
|
|
168
|
+
]));
|
|
169
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { createPromptTemplate, getPredefinedFields, getSiteSchemaTsDefs, } from "../lib/create-prompt.js";
|
|
2
|
+
import { debugLlmOutput } from "../lib/debug-utils.js";
|
|
3
|
+
import { parseLlmResponseAsProperties } from "../lib/parse-llm-response.js";
|
|
4
|
+
const prompt1Tpl = await createPromptTemplate({
|
|
5
|
+
fileName: "update-site-schema-1-write-details.md",
|
|
6
|
+
});
|
|
7
|
+
const prompt2Tpl = await createPromptTemplate({
|
|
8
|
+
fileName: "update-site-schema-2-execute.md",
|
|
9
|
+
});
|
|
10
|
+
export async function invokeUpdateSiteSchema(ctx, input) {
|
|
11
|
+
const task = await invokeUpdateSiteSchemaStep1(ctx, input);
|
|
12
|
+
if (!task.taskDetailsMd) {
|
|
13
|
+
// no changes
|
|
14
|
+
return {
|
|
15
|
+
...input.generatedSchema,
|
|
16
|
+
explanation: task.explanation,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const genSchema = await invokeUpdateSiteSchemaStep2(ctx, {
|
|
20
|
+
taskDetailsMd: task.taskDetailsMd,
|
|
21
|
+
generatedSchema: input.generatedSchema,
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
...genSchema,
|
|
25
|
+
explanation: task.explanation,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
async function invokeUpdateSiteSchemaStep1(ctx, input) {
|
|
29
|
+
const debugName = "update-step1";
|
|
30
|
+
const llmInput = {
|
|
31
|
+
siteSchemaTsDefs: getSiteSchemaTsDefs(),
|
|
32
|
+
siteSchemaJson: JSON.stringify(input.generatedSchema.siteSchema, undefined, 2),
|
|
33
|
+
l10nJson: JSON.stringify(input.generatedSchema.l10n, undefined, 2),
|
|
34
|
+
updateMessage: input.prompt,
|
|
35
|
+
};
|
|
36
|
+
const debug = await debugLlmOutput(ctx, debugName, ctx.goodModelName, {
|
|
37
|
+
updateMessage: llmInput.updateMessage,
|
|
38
|
+
siteSchemaJson: llmInput.siteSchemaJson,
|
|
39
|
+
l10nJson: llmInput.l10nJson,
|
|
40
|
+
});
|
|
41
|
+
let llmMessageContent = debug.storedContent;
|
|
42
|
+
if (!llmMessageContent) {
|
|
43
|
+
const llmMessage = await prompt1Tpl.pipe(ctx.goodModel).invoke(llmInput);
|
|
44
|
+
llmMessageContent = await debug.getMessageContent(llmMessage);
|
|
45
|
+
}
|
|
46
|
+
return parseLlmResponseAsProperties(llmMessageContent, [
|
|
47
|
+
{
|
|
48
|
+
tagName: "task_details_md",
|
|
49
|
+
key: "taskDetailsMd",
|
|
50
|
+
format: "markdown",
|
|
51
|
+
optional: true,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
tagName: "explanation_md",
|
|
55
|
+
key: "explanation",
|
|
56
|
+
format: "markdown",
|
|
57
|
+
},
|
|
58
|
+
]);
|
|
59
|
+
}
|
|
60
|
+
async function invokeUpdateSiteSchemaStep2(ctx, input) {
|
|
61
|
+
const debugName = "update-step2";
|
|
62
|
+
const llmInput = {
|
|
63
|
+
siteSchemaTsDefs: getSiteSchemaTsDefs(),
|
|
64
|
+
predefinedFields: JSON.stringify(getPredefinedFields(), undefined, 2),
|
|
65
|
+
siteSchemaJson: JSON.stringify(input.generatedSchema.siteSchema, undefined, 2),
|
|
66
|
+
l10nJson: JSON.stringify(input.generatedSchema.l10n, undefined, 2),
|
|
67
|
+
taskDetailsMd: input.taskDetailsMd,
|
|
68
|
+
};
|
|
69
|
+
const debug = await debugLlmOutput(ctx, debugName, ctx.goodModelName, {
|
|
70
|
+
taskDetailsMd: llmInput.taskDetailsMd,
|
|
71
|
+
siteSchemaJson: llmInput.siteSchemaJson,
|
|
72
|
+
l10nJson: llmInput.l10nJson,
|
|
73
|
+
});
|
|
74
|
+
let llmMessageContent = debug.storedContent;
|
|
75
|
+
if (!llmMessageContent) {
|
|
76
|
+
const llmMessage = await prompt2Tpl.pipe(ctx.goodModel).invoke(llmInput);
|
|
77
|
+
llmMessageContent = await debug.getMessageContent(llmMessage);
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
...input.generatedSchema,
|
|
81
|
+
...parseLlmResponseAsProperties(llmMessageContent, [
|
|
82
|
+
{
|
|
83
|
+
tagName: "updated_site_schema_json",
|
|
84
|
+
key: "siteSchema",
|
|
85
|
+
format: "json",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
tagName: "updated_labels_json",
|
|
89
|
+
key: "l10n",
|
|
90
|
+
format: "json",
|
|
91
|
+
},
|
|
92
|
+
]),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { getJtHomeType, getJtSiteType, isMultilingual } from "./jt-site-schema-helpers.js";
|
|
2
|
+
import { indent } from "./template-helpers.js";
|
|
3
|
+
export function templateOfDocumentBreadcrumb() {
|
|
4
|
+
return `{% if doc.breadcrumb %}
|
|
5
|
+
<div class="Container">
|
|
6
|
+
{% for crumb in doc.breadcrumb %}
|
|
7
|
+
<a class="TextLink" href="{{ crumb.url }}">{{ crumb.title }}</a>
|
|
8
|
+
/
|
|
9
|
+
{% endfor %}
|
|
10
|
+
{{ doc.title }}
|
|
11
|
+
</div>
|
|
12
|
+
{% endif %}`;
|
|
13
|
+
}
|
|
14
|
+
export function templateOfSiteHeader(ctx) {
|
|
15
|
+
const content = [
|
|
16
|
+
templateOfSiteLogoTitle(ctx),
|
|
17
|
+
templateOfMainMenu(ctx),
|
|
18
|
+
templateOfSearchOpener(ctx),
|
|
19
|
+
];
|
|
20
|
+
return `<div class="_bg2">
|
|
21
|
+
<header class="Container Header">
|
|
22
|
+
${indent(content.filter(Boolean).join("\n"), 2, { skipFirst: true })}
|
|
23
|
+
</header>
|
|
24
|
+
</div>`;
|
|
25
|
+
}
|
|
26
|
+
function templateOfSiteLogoTitle(ctx) {
|
|
27
|
+
const { siteSchema } = ctx;
|
|
28
|
+
const siteType = getJtSiteType(siteSchema);
|
|
29
|
+
const content = [
|
|
30
|
+
siteType.fields?.includes("logo")
|
|
31
|
+
? `{% if site.field.logo %}
|
|
32
|
+
{% useImage logo uid: site.field.logo.uid size: "x50" %}
|
|
33
|
+
<img
|
|
34
|
+
src="{{ logo.url }}"
|
|
35
|
+
width="{{ logo.width }}"
|
|
36
|
+
height="{{ logo.height }}"
|
|
37
|
+
loading="lazy"
|
|
38
|
+
alt="">
|
|
39
|
+
{% endif %}`
|
|
40
|
+
: undefined,
|
|
41
|
+
`<span class="Header-title">{{ site.field.title }}</span>`,
|
|
42
|
+
];
|
|
43
|
+
return `<a
|
|
44
|
+
class="Header-logo"
|
|
45
|
+
href="{{ site.home.url }}"
|
|
46
|
+
data-menu-item-id="{{ site.home.id }}">
|
|
47
|
+
${indent(content.filter(Boolean).join("\n"), 1, { skipFirst: true })}
|
|
48
|
+
</a>`;
|
|
49
|
+
}
|
|
50
|
+
function templateOfMainMenu(ctx) {
|
|
51
|
+
const { siteSchema } = ctx;
|
|
52
|
+
const homeType = getJtHomeType(siteSchema);
|
|
53
|
+
const menuItems = homeType.routingChildren?.filter((typeName) => typeName !== "search" && typeName !== "searchPage");
|
|
54
|
+
if (!menuItems || menuItems.length === 0)
|
|
55
|
+
return;
|
|
56
|
+
const variableTemplates = menuItems.map((typeName) => `{% getDoc ${typeName} id: site.home.${typeName}.id %}`);
|
|
57
|
+
const itemTemplates = menuItems.map((typeName) => `<a
|
|
58
|
+
data-menu-item-id="{{ ${typeName}.id }}"
|
|
59
|
+
href="{{ ${typeName}.url }}">
|
|
60
|
+
{{ ${typeName}.title }}
|
|
61
|
+
</a>`);
|
|
62
|
+
return `${variableTemplates.join("\n")}
|
|
63
|
+
<nav data-activate-menu-items="{{ doc.id | activateMenuItemsData }}">
|
|
64
|
+
${indent(itemTemplates.join("\n"), 1, { skipFirst: true })}
|
|
65
|
+
</nav>`;
|
|
66
|
+
}
|
|
67
|
+
function templateOfSearchOpener(ctx) {
|
|
68
|
+
const { siteSchema } = ctx;
|
|
69
|
+
const homeType = getJtHomeType(siteSchema);
|
|
70
|
+
const typeName = homeType.routingChildren?.find((typeName) => typeName === "search" || typeName === "searchPage");
|
|
71
|
+
if (!typeName)
|
|
72
|
+
return;
|
|
73
|
+
return `{% getDoc ${typeName} id: site.home.${typeName}.id %}
|
|
74
|
+
<span
|
|
75
|
+
data-effect="searchOpener"
|
|
76
|
+
data-search-url="{{ ${typeName}.url }}"
|
|
77
|
+
data-icon-color="#fff"></span>`;
|
|
78
|
+
}
|
|
79
|
+
export function templateOfSiteFooter(ctx) {
|
|
80
|
+
const content = [templateOfSiteFooterMention(ctx), templateOfLanguageSelector(ctx)];
|
|
81
|
+
return `<div class="_bg2">
|
|
82
|
+
<footer class="Container">
|
|
83
|
+
${indent(content.filter(Boolean).join("\n"), 2, { skipFirst: true })}
|
|
84
|
+
</footer>
|
|
85
|
+
</div>`;
|
|
86
|
+
}
|
|
87
|
+
function templateOfSiteFooterMention(ctx) {
|
|
88
|
+
const { siteSchema } = ctx;
|
|
89
|
+
const siteType = getJtSiteType(siteSchema);
|
|
90
|
+
if (!siteType.fields?.includes("footerMention"))
|
|
91
|
+
return;
|
|
92
|
+
return `<div class="Text">{{ site.field.footerMention | raw }}</div>`;
|
|
93
|
+
}
|
|
94
|
+
function templateOfLanguageSelector(ctx) {
|
|
95
|
+
const { siteSchema } = ctx;
|
|
96
|
+
if (!isMultilingual(siteSchema))
|
|
97
|
+
return;
|
|
98
|
+
return `<ul class="LanguageSelector">
|
|
99
|
+
{% for translation in doc.translations %}
|
|
100
|
+
<li>
|
|
101
|
+
<a
|
|
102
|
+
class="{% if translation.active %}active{% endif %}"
|
|
103
|
+
href="{{ translation.url }}"
|
|
104
|
+
title="{{ translation.languageLabel }}">{{ translation.language }}</a>
|
|
105
|
+
</li>
|
|
106
|
+
{% endfor %}
|
|
107
|
+
</ul>`;
|
|
108
|
+
}
|