@paroicms/site-generator-plugin 0.24.3 → 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.
@@ -43,7 +43,7 @@ function templateOfSiteLogoTitle(ctx) {
43
43
  const content = [
44
44
  siteType.fields?.includes("logo")
45
45
  ? `{% if site.field.logo %}
46
- {% useImage logo image: site.field.logo resize: "50x50" %}
46
+ {% set logo = image(site.field.logo, resize: "50x50") %}
47
47
  <img
48
48
  src="{{ logo.url }}"
49
49
  width="{{ logo.width }}"
@@ -67,8 +67,8 @@ function templateOfMainMenu(ctx) {
67
67
  const menuItems = homeType.routingChildren?.filter((typeName) => typeName !== "search" && typeName !== "searchPage");
68
68
  if (!menuItems || menuItems.length === 0)
69
69
  return;
70
- const itemTemplates = menuItems.map((typeName) => `{% if site.home.${typeName} %}
71
- {% assign ${typeName} = site.home.${typeName}.doc %}
70
+ const itemTemplates = menuItems.map((typeName) => `{% set ${typeName} = doc(site.home.${typeName}) %}
71
+ {% if ${typeName} %}
72
72
  <a
73
73
  data-menu-item-id="{{ ${typeName}.id }}"
74
74
  href="{{ ${typeName}.url }}">
@@ -89,12 +89,9 @@ function templateOfSearchOpener(ctx) {
89
89
  if (!typeName)
90
90
  return;
91
91
  return `<div class="Row center">
92
- {% if site.home.${typeName} %}
93
- {% assign ${typeName} = site.home.${typeName}.doc %}
94
- <span
95
- data-effect="paSearchOpener"
96
- data-search-url="{{ ${typeName}.url }}"
97
- data-icon-color="#fff"></span>
92
+ {% set ${typeName} = doc(site.home.${typeName}) %}
93
+ {% if ${typeName} %}
94
+ {% out searchOpener(url: ${typeName}.url, iconColor: "#fff") %}
98
95
  {% endif %}
99
96
  <div data-mobile-menu="button"></div>
100
97
  </div>`;
@@ -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,8 +1,10 @@
1
1
  import { isDef } from "@paroicms/public-anywhere-lib";
2
2
  import { camelToKebabCase } from "../lib/utils.js";
3
3
  import { templateOfDocumentBreadcrumb } from "./common-template-creator.js";
4
+ import { templateOfDocumentCard } from "./document-card-template-creator.js";
4
5
  import { createIdKeyProvider } from "./id-key-provider.js";
5
- import { getJtPartType, getJtRegularDocumentType, getJtRoutingDocumentType, getPossibleJtLabelingFieldTypes, hasTemporalChildren, } from "./jt-site-schema-helpers.js";
6
+ import { getJtPartType, getJtRoutingDocumentType, hasTemporalChildren, } from "./jt-site-schema-helpers.js";
7
+ import { templatesOfLabeledList } from "./labeled-list-template-creator.js";
6
8
  import { getPredefinedDataType, indent, localizedLabelTemplate } from "./template-helpers.js";
7
9
  export function templateOfDocumentType(ctx, documentType) {
8
10
  const childrenTemplate = templateOfDocumentChildren(ctx, documentType, createIdKeyProvider());
@@ -16,26 +18,20 @@ export function templateOfDocumentType(ctx, documentType) {
16
18
  ?.map((list) => templateOfList(ctx, list, { listKey: `doc.list.${list.listName}`, nested: false }))
17
19
  .filter(isDef) ?? [];
18
20
  const specialTemplate = templateOfSpecialDocument(ctx, documentType);
21
+ const labeledListTemplates = templatesOfLabeledList(ctx, documentType);
19
22
  ctx.addLiquidFile("partials", "breadcrumb.liquid", templateOfDocumentBreadcrumb(), {
20
23
  skipIfExists: true,
21
24
  });
22
25
  const blocks = [
23
- `{% render "partials/breadcrumb" doc: doc site: site %}`,
26
+ `{% render "partials/breadcrumb" doc: doc %}`,
24
27
  featuredImageTemplate,
25
28
  titleFieldsTemplate,
26
- childrenTemplate,
27
29
  specialTemplate,
28
30
  ...listTemplates,
31
+ ...labeledListTemplates,
32
+ childrenTemplate,
29
33
  ].filter(isDef);
30
- const notOK = blocks.filter((f) => typeof f !== "string" || f === "false");
31
- if (notOK.length > 0) {
32
- console.log("......................BUG", notOK);
33
- console.log("......................titleFieldsTemplate", titleFieldsTemplate);
34
- console.log("......................childrenTemplate", childrenTemplate);
35
- console.log("......................specialTemplate", specialTemplate);
36
- console.log("......................listTemplates", listTemplates);
37
- }
38
- return `{% layout "layouts/main-layout.liquid" doc: doc site: site %}
34
+ return `{% layout "layouts/main-layout.liquid" %}
39
35
  {% block %}
40
36
  ${blocks.join("\n\n")}
41
37
  {% endblock %}`;
@@ -49,7 +45,7 @@ function templateOfTitleAndFields(ctx, documentType) {
49
45
  const textBlock = `<div class="TextWidth">
50
46
  ${indent(blocks1.join("\n"), 1, { skipFirst: true })}
51
47
  </div>`;
52
- const siblingsTemplate = documentType.documentKind === "regular" && templateOfSiblingLinks(ctx);
48
+ const siblingsTemplate = documentType.documentKind === "regular" ? templateOfSiblingLinks(ctx) : undefined;
53
49
  const blocks2 = [textBlock, siblingsTemplate].filter(isDef);
54
50
  return `<div class="_bg2">
55
51
  <div class="Container">
@@ -63,19 +59,18 @@ function templateOfSpecialDocument(ctx, documentType) {
63
59
  const { addLiquidFile } = ctx;
64
60
  if (documentType.typeName === "search" || documentType.typeName === "searchPage") {
65
61
  addLiquidFile("partials", "result-item.public.liquid", templateOfDocumentCard(ctx, "doc"));
66
- return `<div
67
- class="Container"
68
- data-effect="paSearchApp"
69
- data-template="result-item"
70
- data-limit="10"></div>`;
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>`;
71
67
  }
72
68
  if (documentType.typeName === "contact" || documentType.typeName === "contactPage") {
73
69
  return `<div class="Container">
74
- <div class="TextWidth Pt">
75
- <div
76
- data-effect="paContactForm"
77
- data-home-url="{{ site.home.url }}"
78
- ></div>
70
+ <div class="Page">
71
+ <div class="TextWidth Pt">
72
+ {% out contactForm %}
73
+ </div>
79
74
  </div>
80
75
  </div>`;
81
76
  }
@@ -113,8 +108,8 @@ function templateOfRoutingChild(ctx, child, parentIdKeyProvider) {
113
108
  const idKeyProvider = parentIdKeyProvider.createForRoutingChild(typeName);
114
109
  const key = idKeyProvider.key;
115
110
  if (!hasTemporalChildren(siteSchema, child) || regularChildrenSorting !== "publishDate desc") {
116
- const buttonTemplate = `{% if ${key} %}
117
- {% assign ${variableName} = ${key}.doc %}
111
+ const buttonTemplate = `{% set ${variableName} = doc(${key}) %}
112
+ {% if ${variableName} %}
118
113
  <a class="Button" href="{{ ${variableName}.url }}">{{ ${variableName}.title }}</a>
119
114
  {% endif %}`;
120
115
  return buttonTemplate;
@@ -122,8 +117,8 @@ function templateOfRoutingChild(ctx, child, parentIdKeyProvider) {
122
117
  const cardsTemplate = templateOfRegularDocumentCards(ctx, child, idKeyProvider, {
123
118
  mode: "sampleOnly",
124
119
  });
125
- return `{% if ${key} %}
126
- {% assign ${variableName} = ${key}.doc %}
120
+ return `{% set ${variableName} = doc(${key}) %}
121
+ {% if ${variableName} %}
127
122
  <div class="Pt">
128
123
  <h2>
129
124
  <a class="TextLink" href="{{ ${variableName}.url }}">{{ ${variableName}.title }}</a>
@@ -137,9 +132,9 @@ function templateOfRegularDocumentCards(ctx, parentType, parentIdKeyProvider, {
137
132
  const { typeName: parentTypeName } = parentType;
138
133
  const childrenVariableName = `${parentTypeName}Children`;
139
134
  const childVariableName = `${parentTypeName}Child`;
140
- const idKey = parentIdKeyProvider.idKey;
135
+ const key = parentIdKeyProvider.key;
141
136
  if (mode === "sampleOnly") {
142
- return `{% getDocs ${childrenVariableName} parentId: ${idKey} limit: 4 %}
137
+ return `{% set ${childrenVariableName} = docs(${key}.children, limit: 4) %}
143
138
  <div class="List">
144
139
  {% for ${childVariableName} in ${childrenVariableName} %}
145
140
  ${indent(templateOfDocumentCard(ctx, childVariableName, { parentType }), 2, { skipFirst: true })}
@@ -147,30 +142,18 @@ function templateOfRegularDocumentCards(ctx, parentType, parentIdKeyProvider, {
147
142
  </div>`;
148
143
  }
149
144
  if (!hasTemporalChildren(siteSchema, parentType)) {
150
- return `{% getDocs ${childrenVariableName} parentId: ${idKey} %}
145
+ return `{% set ${childrenVariableName} = docs(${key}.children) %}
151
146
  <div class="Container List Pt Pb">
152
147
  {% for ${childVariableName} in ${childrenVariableName} %}
153
148
  ${indent(templateOfDocumentCard(ctx, childVariableName, { parentType }), 2, { skipFirst: true })}
154
149
  {% endfor %}
155
150
  </div>`;
156
151
  }
157
- const cardTemplateName = `${camelToKebabCase(parentTypeName)}-card`;
158
- addLiquidFile("partials", `${cardTemplateName}.public.liquid`, templateOfDocumentCard(ctx, "doc", { parentType }));
159
- return `{% getPaginatedDocs ${childrenVariableName} parentId: ${idKey} pageSize: 10 %}
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) %}
160
155
  <div class="Container">
161
- <div
162
- class="Page List"
163
- data-effect="paInfiniteLoading"
164
- data-parent-id="{{ ${idKey} }}"
165
- data-start="{{ ${childrenVariableName}.pageSize }}"
166
- data-limit="{{ ${childrenVariableName}.pageSize }}"
167
- data-total="{{ ${childrenVariableName}.total }}"
168
- data-template="${cardTemplateName}"
169
- >
170
- {% for ${childrenVariableName} in ${childrenVariableName}.items %}
171
- {% render "partials/${cardTemplateName}.public.liquid" doc: ${childrenVariableName} %}
172
- {% endfor %}
173
- </div>
156
+ {% out infiniteLoading(class: "Page List", paginatedDocs: ${childrenVariableName}, template: "partials/${cardTemplateName}") %}
174
157
  </div>`;
175
158
  }
176
159
  function templateOfFields(ctx, fields, { parentKey }) {
@@ -214,7 +197,7 @@ function templateOfField(ctx, fieldOrName, parentKey) {
214
197
  if (dataType === "gallery") {
215
198
  return `<div class="Field">
216
199
  {% for media in ${parentKey}.${fieldName} %}
217
- {% useImage im image: media resize: "150x150" %}
200
+ {% set im = image(media, resize: "150x150") %}
218
201
  <img
219
202
  class="Field-img"
220
203
  src="{{ im.url }}"
@@ -229,7 +212,7 @@ function templateOfField(ctx, fieldOrName, parentKey) {
229
212
  }
230
213
  if (dataType === "media") {
231
214
  const mediaKey = `${parentKey}.${fieldName}`;
232
- return `{% useImage im image: ${mediaKey} resize: "x250x" %}
215
+ return `{% set im = image(${mediaKey}, resize: "x250x") %}
233
216
  <div class="Field">
234
217
  <img
235
218
  class="Field-img"
@@ -249,8 +232,8 @@ function templateOfField(ctx, fieldOrName, parentKey) {
249
232
  }
250
233
  function templateOfPicture({ imageKey }) {
251
234
  return `{% if ${imageKey} %}
252
- {% useImage smallIm image: ${imageKey} resize: "360x48" %}
253
- {% useImage largeIm image: ${imageKey} resize: "1200x160" %}
235
+ {% set smallIm = image(${imageKey}, resize: "360x48") %}
236
+ {% set largeIm = image(${imageKey}, resize: "1200x160") %}
254
237
  <div class="Container">
255
238
  <picture class="Hero">
256
239
  <source
@@ -333,51 +316,15 @@ function templateOfSiblingLinks(ctx) {
333
316
  fr: "Suivant",
334
317
  });
335
318
  return `<div class="Row spaceBetween">
336
- {% if doc.siblings.previous %}
337
- <a href="{{ doc.siblings.previous.url }}" title="{{ doc.siblings.previous.title }}">← ${previousLabelTemplate}</a>
319
+ {% set previous = doc(doc.siblings.previous) %}
320
+ {% if previous %}
321
+ <a href="{{ previous.url }}" title="{{ previous.title }}">← ${previousLabelTemplate}</a>
338
322
  {% else %}
339
323
  <span></span>
340
324
  {% endif %}
341
- {% if doc.siblings.next %}
342
- <a href="{{ doc.siblings.next.url }}" title="{{ doc.siblings.next.title }}">${nextLabelTemplate} →</a>
325
+ {% set next = doc(doc.siblings.next) %}
326
+ {% if next %}
327
+ <a href="{{ next.url }}" title="{{ next.title }}">${nextLabelTemplate} →</a>
343
328
  {% endif %}
344
329
  </div>`;
345
330
  }
346
- function templateOfDocumentCard(ctx, docVariableName, { parentType } = {}) {
347
- const { siteSchema } = ctx;
348
- const possibleTypes = parentType
349
- ? (parentType.regularChildren ?? []).map((childName) => getJtRegularDocumentType(siteSchema, childName))
350
- : undefined;
351
- const labelingFields = getPossibleJtLabelingFieldTypes(siteSchema, possibleTypes);
352
- const labelingTemplates = labelingFields.map((field) => {
353
- const fieldName = ` ${docVariableName}.field.${field.name}`;
354
- return `{% if ${fieldName} %}
355
- <ul class="FlexWrap">
356
- {% for labelDoc in ${fieldName} %}
357
- <li class="Label">{{ labelDoc.title }}</li>
358
- {% endfor %}
359
- </ul>
360
- {% endif %}`;
361
- });
362
- return `<a href="{{ ${docVariableName}.url }}">
363
- <article>
364
- {% if ${docVariableName}.defaultImage %}
365
- <div>
366
- {% useImage im image: ${docVariableName}.defaultImage resize: "120x120" %}
367
- <img
368
- src="{{ im.url }}"
369
- width="{{ im.width }}"
370
- height="{{ im.height }}"
371
- loading="lazy"
372
- alt=""
373
- >
374
- </div>
375
- {% endif %}
376
- <div>
377
- <h3>{{ ${docVariableName}.title }}</h3>
378
- <p>{{ ${docVariableName}.excerpt | makeExcerpt: 40 }}</p>
379
- ${indent(labelingTemplates.join("\n"), 3, { skipFirst: true })}
380
- </div>
381
- </article>
382
- </a>`;
383
- }
@@ -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}`),
@@ -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
+ }
@@ -0,0 +1,109 @@
1
+ import { getPredefinedFields } from "../lib/create-prompt.js";
2
+ export function createThemeCreatorContext(siteSchema) {
3
+ const languages = siteSchema.languages ?? [];
4
+ const liquidFiles = new Map();
5
+ const localeFiles = new Map();
6
+ const otherFiles = new Map();
7
+ const issues = [];
8
+ const getParentTypes = makeGetParentTypes(siteSchema);
9
+ return {
10
+ siteSchema,
11
+ labeledDocuments: getLabeledDocuments(siteSchema, getParentTypes),
12
+ getParentTypes,
13
+ predefinedFields: new Map(getPredefinedFields().map((f) => [f.fieldName, f])),
14
+ setLocalizedLabel(label) {
15
+ for (const language of languages) {
16
+ const value = label[language];
17
+ if (!value)
18
+ continue;
19
+ let f = localeFiles.get(language);
20
+ if (!f) {
21
+ f = {};
22
+ localeFiles.set(language, f);
23
+ }
24
+ f[language] = value;
25
+ }
26
+ },
27
+ hasLiquidFile(directory, filename) {
28
+ const path = directory === "root" ? `templates/${filename}` : `templates/${directory}/${filename}`;
29
+ return liquidFiles.has(path);
30
+ },
31
+ addLiquidFile(directory, filename, content, { skipIfExists = false } = {}) {
32
+ const path = directory === "root" ? `templates/${filename}` : `templates/${directory}/${filename}`;
33
+ if (liquidFiles.has(path)) {
34
+ if (skipIfExists)
35
+ return;
36
+ issues.push(`Liquid file already exists, overwrite: "${path}"`);
37
+ }
38
+ liquidFiles.set(path, content);
39
+ },
40
+ addFile(path, content) {
41
+ if (otherFiles.has(path))
42
+ throw new Error(`File already exists: "${path}"`);
43
+ otherFiles.set(path, content);
44
+ },
45
+ toFiles() {
46
+ const files = [
47
+ ...Array.from(liquidFiles.entries()).map(([path, content]) => ({ path, content })),
48
+ ...Array.from(localeFiles.entries()).map(([language, content]) => ({
49
+ path: `locales/${language}.json`,
50
+ content: JSON.stringify(content, null, 2),
51
+ })),
52
+ ...Array.from(otherFiles.entries()).map(([path, content]) => ({ path, content })),
53
+ ];
54
+ files.sort((a, b) => a.path.localeCompare(b.path));
55
+ return { files, issues: issues.length > 0 ? issues : undefined };
56
+ },
57
+ };
58
+ }
59
+ function makeGetParentTypes(siteSchema) {
60
+ const parentsByChild = new Map();
61
+ const nodeTypes = siteSchema.nodeTypes ?? [];
62
+ for (const type of nodeTypes) {
63
+ if (type.kind !== "document")
64
+ continue;
65
+ if (type.documentKind === "routing") {
66
+ for (const childName of type.routingChildren ?? []) {
67
+ const list = parentsByChild.get(childName) ?? [];
68
+ list.push(type);
69
+ parentsByChild.set(childName, list);
70
+ }
71
+ }
72
+ for (const childName of type.regularChildren ?? []) {
73
+ const list = parentsByChild.get(childName) ?? [];
74
+ list.push(type);
75
+ parentsByChild.set(childName, list);
76
+ }
77
+ }
78
+ return (documentType) => parentsByChild.get(documentType.typeName) ?? [];
79
+ }
80
+ function getLabeledDocuments(siteSchema, getParentTypes) {
81
+ const result = [];
82
+ for (const documentType of siteSchema.nodeTypes ?? []) {
83
+ if (documentType.kind !== "document" || documentType.documentKind !== "regular")
84
+ continue;
85
+ for (const field of documentType.fields ?? []) {
86
+ if (typeof field === "string" || field.storedAs !== "labeling")
87
+ continue;
88
+ const taxonomyType = siteSchema.nodeTypes?.find((nt) => nt.typeName === field.taxonomy);
89
+ if (!taxonomyType ||
90
+ taxonomyType.kind !== "document" ||
91
+ taxonomyType.documentKind !== "routing") {
92
+ continue;
93
+ }
94
+ for (const parentDocumentType of getParentTypes(documentType)) {
95
+ if (parentDocumentType.kind !== "document" ||
96
+ parentDocumentType.documentKind !== "routing") {
97
+ continue;
98
+ }
99
+ result.push({
100
+ documentType,
101
+ parentDocumentType,
102
+ field,
103
+ taxonomyType,
104
+ });
105
+ }
106
+ }
107
+ }
108
+ return result;
109
+ }
@@ -1,11 +1,11 @@
1
1
  import { isObj } from "@paroicms/public-anywhere-lib";
2
2
  import { mkdir, writeFile } from "node:fs/promises";
3
3
  import { dirname, join } from "node:path";
4
- import { getPredefinedFields } from "../lib/create-prompt.js";
5
4
  import { camelToKebabCase } from "../lib/utils.js";
6
5
  import { templateOfSiteFooter, templateOfSiteHeader } from "./common-template-creator.js";
7
6
  import { templateOfDocumentType } from "./document-template-creator.js";
8
7
  import { isMultilingual } from "./jt-site-schema-helpers.js";
8
+ import { createThemeCreatorContext } from "./theme-creator-context.js";
9
9
  import { getThemeCssContent } from "./theme-css.js";
10
10
  export async function createTheme(ctx, siteDir, siteSchema) {
11
11
  const themeContext = createThemeCreatorContext(siteSchema);
@@ -38,70 +38,6 @@ export async function createTheme(ctx, siteDir, siteSchema) {
38
38
  ctx.logger.warn(`Issues in "${siteDir}":`, issues);
39
39
  }
40
40
  }
41
- function createThemeCreatorContext(siteSchema) {
42
- const languages = siteSchema.languages ?? [];
43
- const liquidFiles = new Map();
44
- const localeFiles = new Map();
45
- const otherFiles = new Map();
46
- const issues = [];
47
- return {
48
- siteSchema,
49
- predefinedFields: new Map(getPredefinedFields().map((f) => [f.fieldName, f])),
50
- setLocalizedLabel(label) {
51
- for (const language of languages) {
52
- const value = label[language];
53
- if (!value)
54
- continue;
55
- let f = localeFiles.get(language);
56
- if (!f) {
57
- f = {};
58
- localeFiles.set(language, f);
59
- }
60
- f[language] = value;
61
- }
62
- },
63
- hasLiquidFile(directory, filename) {
64
- const path = directory === "root" ? `templates/${filename}` : `templates/${directory}/${filename}`;
65
- return liquidFiles.has(path);
66
- },
67
- addLiquidFile(directory, filename, content, { skipIfExists = false } = {}) {
68
- const path = directory === "root" ? `templates/${filename}` : `templates/${directory}/${filename}`;
69
- if (liquidFiles.has(path)) {
70
- if (skipIfExists)
71
- return;
72
- issues.push(`Liquid file already exists, overwrite: "${path}"`);
73
- }
74
- liquidFiles.set(path, content);
75
- },
76
- addFile(path, content) {
77
- if (otherFiles.has(path))
78
- throw new Error(`File already exists: "${path}"`);
79
- otherFiles.set(path, content);
80
- },
81
- toFiles() {
82
- const files = [
83
- ...Array.from(liquidFiles.entries()).map(([path, content]) => ({ path, content })),
84
- ...Array.from(localeFiles.entries()).map(([language, content]) => ({
85
- path: `locales/${language}.json`,
86
- content: JSON.stringify(content, null, 2),
87
- })),
88
- ...Array.from(otherFiles.entries()).map(([path, content]) => ({ path, content })),
89
- ];
90
- files.sort((a, b) => a.path.localeCompare(b.path));
91
- return { files, issues: issues.length > 0 ? issues : undefined };
92
- },
93
- };
94
- }
95
- // function getDefaultLiquidContent() {
96
- // return `{% layout "layouts/main-layout.liquid" doc: doc site: site %}
97
- // {% block %}
98
- // <div class="Container">
99
- // <div class="Page">
100
- // {{ doc | info }}
101
- // </div>
102
- // </div>
103
- // {% endblock %}`;
104
- // }
105
41
  function templateOf404(ctx) {
106
42
  const { siteSchema } = ctx;
107
43
  const rawParam = isMultilingual(siteSchema) ? " raw: true" : "";
@@ -132,13 +68,13 @@ function templateOfLayout(ctx) {
132
68
  const multilingual = isMultilingual(siteSchema);
133
69
  ctx.addLiquidFile("partials", "site-header.liquid", templateOfSiteHeader(ctx));
134
70
  ctx.addLiquidFile("partials", "site-footer.liquid", templateOfSiteFooter(ctx));
135
- const renderHeader = `{% render "partials/site-header" doc: doc site: site %}`;
71
+ const renderHeader = `{% render "partials/site-header" doc: doc %}`;
136
72
  const headerTemplate = multilingual
137
73
  ? `{% unless raw %}
138
74
  ${renderHeader}
139
75
  {% endunless %}`
140
76
  : renderHeader;
141
- const renderFooter = `{% render "partials/site-footer" doc: doc site: site %}`;
77
+ const renderFooter = `{% render "partials/site-footer" doc: doc %}`;
142
78
  const footerTemplate = multilingual
143
79
  ? `{% unless raw %}
144
80
  ${renderFooter}
@@ -43,12 +43,12 @@ const plugin = {
43
43
  startSiteRemover(rawContext);
44
44
  });
45
45
  service.setPublicAssetsDirectory(join(packageDir, "frontend", "dist"));
46
- service.registerLiquidTag("siteGeneratorApp", "injectHtml", (service) => {
47
- service.setRenderState("paSiteGeneratorApp", true);
46
+ service.registerOutLiquidTagFunction("siteGeneratorApp", (service) => {
47
+ service.setRenderState("siteGeneratorApp", true);
48
48
  return `<div id="site-generator-app"></div>`;
49
- });
49
+ }, { raw: true });
50
50
  service.registerHeadTags(({ state }) => {
51
- if (!state.get("paSiteGeneratorApp"))
51
+ if (!state.get("siteGeneratorApp"))
52
52
  return;
53
53
  return [
54
54
  makeStylesheetLinkAsyncTag(`${service.pluginAssetsUrl}/frontend.css`),