@aglyn/plugins-ai 1.0.0-beta.236 → 1.0.0-beta.238
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/package.json +17 -17
- package/src/lib/components/ai-credits-prompt.component.d.ts +44 -0
- package/src/lib/components/ai-credits-prompt.component.js +117 -0
- package/src/lib/components/ai-credits-prompt.component.js.map +1 -0
- package/src/lib/components/ai-job-cancel.component.d.ts +38 -0
- package/src/lib/components/ai-job-cancel.component.js +156 -0
- package/src/lib/components/ai-job-cancel.component.js.map +1 -0
- package/src/lib/components/ai-job-plan.component.d.ts +5 -4
- package/src/lib/components/ai-job-plan.component.js +48 -12
- package/src/lib/components/ai-job-plan.component.js.map +1 -1
- package/src/lib/components/ai-job-requests.d.ts +10 -0
- package/src/lib/components/ai-job-requests.js +12 -4
- package/src/lib/components/ai-job-requests.js.map +1 -1
- package/src/lib/components/ai-jobs-list-page.component.js +141 -72
- package/src/lib/components/ai-jobs-list-page.component.js.map +1 -1
- package/src/lib/components/ai-site-build-page.component.js +48 -9
- package/src/lib/components/ai-site-build-page.component.js.map +1 -1
- package/src/lib/components/ai-site-start-card.component.js +68 -22
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/components/ai-usage-strip.component.d.ts +19 -2
- package/src/lib/components/ai-usage-strip.component.js +40 -9
- package/src/lib/components/ai-usage-strip.component.js.map +1 -1
- package/src/lib/components/assist-build-card.component.d.ts +3 -1
- package/src/lib/components/assist-build-card.component.js +58 -7
- package/src/lib/components/assist-build-card.component.js.map +1 -1
- package/src/lib/components/assist-jobs-drawer.component.js +66 -22
- package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
- package/src/lib/components/assist-panel.component.js +89 -52
- package/src/lib/components/assist-panel.component.js.map +1 -1
- package/src/lib/jobs/ai-job-admission.d.ts +22 -2
- package/src/lib/jobs/ai-job-admission.js.map +1 -1
- package/src/lib/jobs/ai-job-build-step.d.ts +24 -11
- package/src/lib/jobs/ai-job-build-step.js +54 -35
- package/src/lib/jobs/ai-job-build-step.js.map +1 -1
- package/src/lib/jobs/ai-job-cancel.d.ts +71 -0
- package/src/lib/jobs/ai-job-cancel.js +102 -0
- package/src/lib/jobs/ai-job-cancel.js.map +1 -0
- package/src/lib/jobs/ai-job-component-step.js +4 -1
- package/src/lib/jobs/ai-job-component-step.js.map +1 -1
- package/src/lib/jobs/ai-job-drafts.js +2 -0
- package/src/lib/jobs/ai-job-drafts.js.map +1 -1
- package/src/lib/jobs/ai-job-form-step.js +4 -1
- package/src/lib/jobs/ai-job-form-step.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.d.ts +2 -0
- package/src/lib/jobs/ai-job-layout-language.js +13 -1
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-step.js +6 -1
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.js +12 -0
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.d.ts +13 -0
- package/src/lib/jobs/ai-job-page-step.js +46 -4
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +42 -0
- package/src/lib/jobs/ai-job-plan-step.js +118 -18
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-content.d.ts +49 -3
- package/src/lib/jobs/ai-job-site-content.js +196 -37
- package/src/lib/jobs/ai-job-site-content.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.js +49 -16
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-job-template-step.js +4 -1
- package/src/lib/jobs/ai-job-template-step.js.map +1 -1
- package/src/lib/jobs/ai-job-text-step.d.ts +8 -0
- package/src/lib/jobs/ai-job-text-step.js.map +1 -1
- package/src/lib/jobs/ai-jobs.d.ts +55 -13
- package/src/lib/jobs/ai-jobs.js +213 -41
- package/src/lib/jobs/ai-jobs.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +194 -34
- package/src/lib/jobs/ai-layout-stock-photos.js +861 -146
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-ceramics-portfolio-site-plan.d.ts +30 -0
- package/src/lib/jobs/fixtures/ai-ceramics-portfolio-site-plan.js +220 -0
- package/src/lib/jobs/fixtures/ai-ceramics-portfolio-site-plan.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-pixabay-recordings.d.ts +27 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-pixabay-recordings.js +151 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-pixabay-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.d.ts +33 -0
- package/src/lib/layout-language/ai-layout-compiler.js +381 -18
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-design.d.ts +6 -3
- package/src/lib/layout-language/ai-layout-design.js +5 -3
- package/src/lib/layout-language/ai-layout-design.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame.d.ts +12 -0
- package/src/lib/layout-language/ai-layout-frame.js +58 -3
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-gaps.js +3 -1
- package/src/lib/layout-language/ai-layout-gaps.js.map +1 -1
- package/src/lib/layout-language/ai-layout-language.js +1 -1
- package/src/lib/layout-language/ai-layout-language.js.map +1 -1
- package/src/lib/layout-language/ai-layout-listings.d.ts +49 -1
- package/src/lib/layout-language/ai-layout-listings.js +117 -47
- package/src/lib/layout-language/ai-layout-listings.js.map +1 -1
- package/src/lib/layout-language/ai-layout-pictures.d.ts +10 -1
- package/src/lib/layout-language/ai-layout-pictures.js +5 -2
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
- package/src/lib/layout-language/ai-layout-storefront.d.ts +82 -0
- package/src/lib/layout-language/ai-layout-storefront.js +223 -0
- package/src/lib/layout-language/ai-layout-storefront.js.map +1 -0
- package/src/lib/model/ai-build-job.d.ts +39 -0
- package/src/lib/model/ai-build-job.js +100 -1
- package/src/lib/model/ai-build-job.js.map +1 -1
- package/src/lib/model/ai-build-progress.d.ts +8 -0
- package/src/lib/model/ai-build-progress.js +35 -0
- package/src/lib/model/ai-build-progress.js.map +1 -1
- package/src/lib/model/ai-credit-estimate.d.ts +249 -0
- package/src/lib/model/ai-credit-estimate.js +278 -0
- package/src/lib/model/ai-credit-estimate.js.map +1 -0
- package/src/lib/model/ai-job-cancel-copy.d.ts +44 -0
- package/src/lib/model/ai-job-cancel-copy.js +53 -0
- package/src/lib/model/ai-job-cancel-copy.js.map +1 -0
- package/src/lib/model/ai-job-failure-copy.d.ts +4 -1
- package/src/lib/model/ai-job-failure-copy.js +8 -3
- package/src/lib/model/ai-job-failure-copy.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +35 -0
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-site-build-progress.js +7 -4
- package/src/lib/model/ai-site-build-progress.js.map +1 -1
- package/src/lib/model/ai-site-job.d.ts +76 -22
- package/src/lib/model/ai-site-job.js +125 -23
- package/src/lib/model/ai-site-job.js.map +1 -1
- package/src/lib/model/ai-site-kinds.d.ts +4 -1
- package/src/lib/model/ai-site-kinds.js +35 -7
- package/src/lib/model/ai-site-kinds.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +37 -1
- package/src/lib/runtime/ai-doctrine-validators.js +161 -7
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +4 -3
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-node-tree.d.ts +11 -0
- package/src/lib/runtime/ai-node-tree.js +26 -0
- package/src/lib/runtime/ai-node-tree.js.map +1 -1
- package/src/lib/runtime/ai-palette.generated.js +592 -14
- package/src/lib/runtime/ai-palette.generated.js.map +1 -1
- package/src/lib/server/ai-jobs-cancel.d.ts +13 -5
- package/src/lib/server/ai-jobs-cancel.js +27 -9
- package/src/lib/server/ai-jobs-cancel.js.map +1 -1
- package/src/lib/server/ai-jobs-gate.d.ts +12 -2
- package/src/lib/server/ai-jobs-gate.js +20 -9
- package/src/lib/server/ai-jobs-gate.js.map +1 -1
- package/src/lib/server/ai-jobs-resume.js +93 -35
- package/src/lib/server/ai-jobs-resume.js.map +1 -1
- package/src/lib/server/ai-jobs-route.js +45 -4
- package/src/lib/server/ai-jobs-route.js.map +1 -1
- package/src/lib/server/assist-chat.js +4 -1
- package/src/lib/server/assist-chat.js.map +1 -1
- package/src/lib/server/assist-edit.js +3 -1
- package/src/lib/server/assist-edit.js.map +1 -1
- package/src/lib/server/assist-music.d.ts +36 -0
- package/src/lib/server/assist-music.js +36 -0
- package/src/lib/server/assist-music.js.map +1 -0
- package/src/lib/server.js +6 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/usage/ai-usage-meter.d.ts +2 -1
- package/src/lib/usage/ai-usage-meter.js +17 -1
- package/src/lib/usage/ai-usage-meter.js.map +1 -1
- package/src/lib/usage/ai-usage-wire.d.ts +6 -0
- package/src/lib/usage/ai-usage-wire.js.map +1 -1
- package/src/lib/usage/assist-usage.d.ts +7 -0
- package/src/lib/usage/assist-usage.js +14 -4
- package/src/lib/usage/assist-usage.js.map +1 -1
- package/src/lib/usage/free-ai-credits-left.d.ts +7 -0
- package/src/lib/usage/free-ai-credits-left.js +4 -2
- package/src/lib/usage/free-ai-credits-left.js.map +1 -1
|
@@ -22,8 +22,9 @@ import { AI_INSTANCE_REF_PROP } from "../runtime/ai-node-tree.js";
|
|
|
22
22
|
import { aiPageScrollInteraction } from "../runtime/ai-page-links.js";
|
|
23
23
|
import { aiLayoutFitText, aiLayoutQuoteGap, aiLayoutWords } from "./ai-layout-copy.js";
|
|
24
24
|
import { AI_LAYOUT_GROUP_KINDS, AI_LAYOUT_MAX_ITEMS } from "./ai-layout-language.js";
|
|
25
|
-
import { aiLayoutDesignChoices, aiLayoutGroupVariant } from "./ai-layout-design.js";
|
|
25
|
+
import { aiLayoutDesignChoices, aiLayoutFamily, aiLayoutGroupVariant } from "./ai-layout-design.js";
|
|
26
26
|
import { AI_LAYOUT_FEATURED_RECORDS, AI_LAYOUT_LISTING_ELEMENTS, aiLayoutListingAt } from "./ai-layout-listings.js";
|
|
27
|
+
import { aiStorefrontItemIcons } from "./ai-layout-storefront.js";
|
|
27
28
|
import { aiLayoutRenamedLabel, aiLayoutResolveLink } from "./ai-layout-links.js";
|
|
28
29
|
import { AI_LAYOUT_FRAMES, AiLayoutTreeBuilder } from "./ai-layout-tree.js";
|
|
29
30
|
/**
|
|
@@ -166,6 +167,9 @@ function compileSection(page, raw, index) {
|
|
|
166
167
|
if (raw.blocks.some((block)=>block.kind === 'quotes') && !blocks.some((block)=>AI_LAYOUT_GROUP_KINDS.has(block.kind) || block.kind === 'component')) {
|
|
167
168
|
page.quotesOnly.push(index);
|
|
168
169
|
}
|
|
170
|
+
// A store's Shop page opens on its grid (AGL-3676): its first section is a
|
|
171
|
+
// short title bar, never a hero, so the products start above the fold.
|
|
172
|
+
if (index === 0 && shopGridAt(page) > 0) return shopTitle(scope, blocks);
|
|
169
173
|
// A section the site's records fill — its catalog, its blog — shows them
|
|
170
174
|
// through the element that keeps them, around the words the design gave it (AGL-3676).
|
|
171
175
|
const listed = aiLayoutListingAt((_page_targets_listings = page.targets.listings) != null ? _page_targets_listings : [], page.targets.pageId, index);
|
|
@@ -385,7 +389,11 @@ function compileSection(page, raw, index) {
|
|
|
385
389
|
}
|
|
386
390
|
/** A band the page has room for: past two brand or two dark bands, a soft one instead. */ function settleBand(page, band, at) {
|
|
387
391
|
if (band !== 'brand' && band !== 'dark') return band;
|
|
388
|
-
|
|
392
|
+
// A storefront keeps one dark band at most (AGL-3676): the beta.237 Willow
|
|
393
|
+
// Wick home ran its text bands dark, and read as big empty dark slabs
|
|
394
|
+
// between the products.
|
|
395
|
+
const most = band === 'dark' && page.design && aiLayoutFamily(page.design.input.kind) === 'retail' ? 1 : AI_LAYOUT_MAX_STRONG_BANDS;
|
|
396
|
+
if (page.strong[band] >= most) {
|
|
389
397
|
page.settled.push({
|
|
390
398
|
at: `${at}.band`,
|
|
391
399
|
what: `a third ${band} band drawn soft`
|
|
@@ -819,8 +827,39 @@ export function destinationProps(destination) {
|
|
|
819
827
|
* text (rule 9), and no source is set here: the compiler stays pure, and
|
|
820
828
|
* `ai-layout-pictures.ts` fills the slot with a photo the site serves itself
|
|
821
829
|
* once the page is checked.
|
|
822
|
-
*/
|
|
830
|
+
*/ /**
|
|
831
|
+
* The site kinds whose galleries open in a lightbox by default (AGL-3717): a
|
|
832
|
+
* portfolio's or a photographer's work is looked at, not skimmed, and a
|
|
833
|
+
* visitor who presses a picture expects to see it large and step through the
|
|
834
|
+
* rest. Every other kind opens a picture only where the design says so.
|
|
835
|
+
*/ export const AI_LIGHTBOX_GALLERY_KINDS = new Set([
|
|
836
|
+
'portfolio',
|
|
837
|
+
'photography'
|
|
838
|
+
]);
|
|
839
|
+
/** The `to` that opens an image block's picture in a lightbox (AGL-3717). */ export const AI_LAYOUT_LIGHTBOX_TO = 'lightbox';
|
|
840
|
+
/** Whether this page's galleries open in a lightbox by default. */ export function aiOpensGalleriesInLightbox(page) {
|
|
841
|
+
var _page_design;
|
|
842
|
+
const kind = (_page_design = page.design) == null ? void 0 : _page_design.input.kind;
|
|
843
|
+
return Boolean(kind && AI_LIGHTBOX_GALLERY_KINDS.has(kind));
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* The Image props that make a picture open in a lightbox: as one gallery
|
|
847
|
+
* with the section's other pictures, named for the section, and with the
|
|
848
|
+
* item's title as its caption. The Image element reads exactly these.
|
|
849
|
+
*/ function lightboxProps(scope, caption) {
|
|
850
|
+
var _scope_page_plan_sections_scope_index;
|
|
851
|
+
const name = aiLayoutFitText(scope.heading, 'alt') || aiLayoutFitText((_scope_page_plan_sections_scope_index = scope.page.plan.sections[scope.index]) == null ? void 0 : _scope_page_plan_sections_scope_index.name, 'alt') || `Gallery ${scope.index + 1}`;
|
|
852
|
+
const words = aiLayoutFitText(caption, 'alt');
|
|
853
|
+
return _extends({
|
|
854
|
+
lightbox: true,
|
|
855
|
+
lightboxGallery: name
|
|
856
|
+
}, words ? {
|
|
857
|
+
lightboxCaption: words
|
|
858
|
+
} : {});
|
|
859
|
+
}
|
|
860
|
+
function image(scope, block, room) {
|
|
823
861
|
var _aiIconOfWord;
|
|
862
|
+
var _block_to;
|
|
824
863
|
const { page } = scope;
|
|
825
864
|
const alt = aiLayoutFitText(block.text, 'alt');
|
|
826
865
|
if (!alt) return null;
|
|
@@ -840,10 +879,13 @@ export function destinationProps(destination) {
|
|
|
840
879
|
}, {
|
|
841
880
|
color: 'primary.main'
|
|
842
881
|
}, null, 'imageIcon');
|
|
843
|
-
|
|
882
|
+
// `to: lightbox` opens the picture large (AGL-3717); one picture is its
|
|
883
|
+
// own gallery, so it opens alone unless the section has more.
|
|
884
|
+
const opensLarge = ((_block_to = block.to) == null ? void 0 : _block_to.trim().toLowerCase()) === AI_LAYOUT_LIGHTBOX_TO;
|
|
885
|
+
const picture = tree.add('image', _extends({
|
|
844
886
|
alt,
|
|
845
887
|
objectFit: 'cover'
|
|
846
|
-
}, {
|
|
888
|
+
}, opensLarge ? lightboxProps(scope) : {}), {
|
|
847
889
|
position: 'absolute',
|
|
848
890
|
top: 0,
|
|
849
891
|
left: 0,
|
|
@@ -1020,11 +1062,21 @@ function group(scope, block, room) {
|
|
|
1020
1062
|
const placed = componentOf(scope.page.targets, block.to);
|
|
1021
1063
|
if (placed) return instances(scope, placed, items, perRow);
|
|
1022
1064
|
const design = scope.page.design;
|
|
1065
|
+
const retail = !!design && aiLayoutFamily(design.input.kind) === 'retail';
|
|
1066
|
+
// A store's making, shown: its steps as pictures over their words (AGL-3676),
|
|
1067
|
+
// where the page has the pictures for them.
|
|
1068
|
+
if (retail && block.kind === 'steps' && room === 'full' && items.length >= 2 && items.length <= 4 && picturesLeft(scope.page) >= items.length) {
|
|
1069
|
+
const drawn = designedGroup(scope, 'articles', items, room);
|
|
1070
|
+
if (drawn) return drawn;
|
|
1071
|
+
}
|
|
1023
1072
|
if (rule1(scope)) {
|
|
1024
1073
|
var _scope_words;
|
|
1025
1074
|
// Picture cards the design draws are the compiler's, not a block typed out
|
|
1026
|
-
// by hand (`repeatsCompiled`, AGL-3660)
|
|
1075
|
+
// by hand (`repeatsCompiled`, AGL-3660), and so are a storefront's icon
|
|
1076
|
+
// columns (AGL-3676): the beta.237 Willow Wick home, on a paid plan, drew
|
|
1077
|
+
// every other group compact — four bands of a title and a sentence.
|
|
1027
1078
|
const variant = design && block.kind === 'cards' && block.style !== 'quiet' ? aiLayoutGroupVariant(design.input, design.choices, (_scope_words = scope.words) != null ? _scope_words : '') : null;
|
|
1079
|
+
if (variant === 'icons') return iconColumns(scope, items, room);
|
|
1028
1080
|
const pictured = (variant === 'pictures' || variant === 'articles') && room === 'full' && picturesLeft(scope.page) >= items.length;
|
|
1029
1081
|
return pictured && designedGroup(scope, variant, items, room) || compactGroup(scope, block, items, perRow);
|
|
1030
1082
|
}
|
|
@@ -1423,6 +1475,7 @@ function instances(scope, placed, items, perRow) {
|
|
|
1423
1475
|
flow[lead] = design.choices.hero === 'split' ? title : _extends({}, title, {
|
|
1424
1476
|
style: 'large'
|
|
1425
1477
|
});
|
|
1478
|
+
sellingHero(scope, flow);
|
|
1426
1479
|
const given = images[0] ? aiLayoutFitText(images[0].text, 'alt') : '';
|
|
1427
1480
|
return hero(scope, raw, flow, given ? {
|
|
1428
1481
|
alt: given,
|
|
@@ -1825,6 +1878,7 @@ function instances(scope, placed, items, perRow) {
|
|
|
1825
1878
|
variant: type
|
|
1826
1879
|
}, muted(scope), null, 'text') : null;
|
|
1827
1880
|
if (variant === 'cards') return null;
|
|
1881
|
+
if (variant === 'icons') return iconColumns(scope, items, room);
|
|
1828
1882
|
const pictured = variant === 'pictures' || variant === 'articles';
|
|
1829
1883
|
if (variant === 'ruled' || pictured && (room !== 'full' || picturesLeft(page) < items.length)) {
|
|
1830
1884
|
const perRow = across(items.length, room, 'cards');
|
|
@@ -1907,12 +1961,19 @@ function instances(scope, placed, items, perRow) {
|
|
|
1907
1961
|
const span = !mosaic ? 12 / perRow : lone ? 12 : wide ? 7 : 5;
|
|
1908
1962
|
const aspect = !mosaic ? variant === 'articles' ? '3 / 2' : portrait ? '4 / 5' : '4 / 3' : lone ? '21 / 9' : wide ? '4 / 3' : '4 / 5';
|
|
1909
1963
|
// The picture is its own frame: its shape its one style, so a grid of them repeats no inline style.
|
|
1964
|
+
// A portfolio's or a photographer's gallery opens in a lightbox, its
|
|
1965
|
+
// pictures one gallery with the item's title as each caption (AGL-3717).
|
|
1966
|
+
const opens = variant === 'pictures' && aiOpensGalleriesInLightbox(page);
|
|
1967
|
+
// A store's collection tiles open its Shop page (AGL-3676).
|
|
1968
|
+
const shop = variant === 'pictures' && !opens && aiLayoutFamily(design.input.kind) === 'retail' ? shopPageOf(page) : null;
|
|
1910
1969
|
const photo = designImage(scope, {
|
|
1911
1970
|
alt: standInAlt(scope, item.title || item.text),
|
|
1912
1971
|
given: false
|
|
1913
|
-
}, {
|
|
1972
|
+
}, _extends({
|
|
1914
1973
|
width: '100%'
|
|
1915
|
-
}, {
|
|
1974
|
+
}, opens ? lightboxProps(scope, item.title) : {}, shop ? {
|
|
1975
|
+
screenId: shop
|
|
1976
|
+
} : {}), {
|
|
1916
1977
|
aspectRatio: {
|
|
1917
1978
|
xs: '4 / 3',
|
|
1918
1979
|
md: aspect
|
|
@@ -1978,18 +2039,24 @@ function instances(scope, placed, items, perRow) {
|
|
|
1978
2039
|
style: 'secondary'
|
|
1979
2040
|
} : null;
|
|
1980
2041
|
const index = listing.placements.find((placement)=>placement.role === 'index' && placement.screenId !== page.targets.pageId);
|
|
1981
|
-
|
|
2042
|
+
if (!index) return null;
|
|
2043
|
+
return {
|
|
1982
2044
|
kind: 'button',
|
|
1983
|
-
text: 'Shop all',
|
|
2045
|
+
text: listing.kind === 'tracks' ? 'All music' : 'Shop all',
|
|
1984
2046
|
to: `page:${index.screenId}`,
|
|
1985
2047
|
style: 'secondary'
|
|
1986
|
-
}
|
|
2048
|
+
};
|
|
1987
2049
|
}
|
|
1988
2050
|
function listingSection(scope, blocks, placed) {
|
|
1989
2051
|
var _ref;
|
|
1990
2052
|
var _page_plan_sections_index_name, _page_plan_sections_index, _page_options_sectionIds;
|
|
1991
2053
|
const { page, index, at } = scope;
|
|
1992
2054
|
const { listing, role } = placed;
|
|
2055
|
+
if (listing.kind === 'reviews') return reviewsSection(scope, blocks);
|
|
2056
|
+
if (listing.kind === 'signup') return signupSection(scope, blocks);
|
|
2057
|
+
// The grid straight under a Shop page's title bar opens on the products:
|
|
2058
|
+
// the title bar already heads the page (AGL-3676).
|
|
2059
|
+
const underTitle = listing.kind === 'products' && role === 'index' && index === 1 && shopGridAt(page) === 1;
|
|
1993
2060
|
const left = blocks.filter((block)=>LISTING_REPLACES.has(block.kind));
|
|
1994
2061
|
if (left.length) {
|
|
1995
2062
|
page.settled.push({
|
|
@@ -1997,7 +2064,7 @@ function listingSection(scope, blocks, placed) {
|
|
|
1997
2064
|
what: `${left.map((block)=>block.kind).join(', ')} left out: the section lists the site's own ${listing.kind}`
|
|
1998
2065
|
});
|
|
1999
2066
|
}
|
|
2000
|
-
const kept = blocks.filter((block)=>!LISTING_REPLACES.has(block.kind)).map((_0)=>{
|
|
2067
|
+
const kept = underTitle ? [] : blocks.filter((block)=>!LISTING_REPLACES.has(block.kind)).map((_0)=>{
|
|
2001
2068
|
let { col: _col } = _0, block = _object_without_properties_loose(_0, [
|
|
2002
2069
|
"col"
|
|
2003
2070
|
]);
|
|
@@ -2011,7 +2078,7 @@ function listingSection(scope, blocks, placed) {
|
|
|
2011
2078
|
all
|
|
2012
2079
|
];
|
|
2013
2080
|
}
|
|
2014
|
-
if (!words.some((block)=>speaksHeading(scope, block))) {
|
|
2081
|
+
if (!underTitle && !words.some((block)=>speaksHeading(scope, block))) {
|
|
2015
2082
|
var _page_plan_sections_index1;
|
|
2016
2083
|
// Every band of records is headed: the plan's name for it, or on a first section the page's title.
|
|
2017
2084
|
words.unshift({
|
|
@@ -2064,7 +2131,13 @@ function listingSection(scope, blocks, placed) {
|
|
|
2064
2131
|
} : {}), null, parts, 'content');
|
|
2065
2132
|
const container = tree.add('muiContainer', {
|
|
2066
2133
|
maxWidth: 'lg'
|
|
2067
|
-
}, {
|
|
2134
|
+
}, underTitle ? {
|
|
2135
|
+
pt: {
|
|
2136
|
+
xs: 2,
|
|
2137
|
+
md: 3
|
|
2138
|
+
},
|
|
2139
|
+
pb: _extends({}, SECTION_PADDING)
|
|
2140
|
+
} : {
|
|
2068
2141
|
py: index === 0 ? _extends({}, HERO_PADDING) : _extends({}, SECTION_PADDING)
|
|
2069
2142
|
}, [
|
|
2070
2143
|
content
|
|
@@ -2075,10 +2148,268 @@ function listingSection(scope, blocks, placed) {
|
|
|
2075
2148
|
ariaLabel: sectionLabel(name, index)
|
|
2076
2149
|
}, scope.band === 'dark' ? {
|
|
2077
2150
|
colorScheme: 'dark'
|
|
2078
|
-
} : {}), bandSx(scope.band), [
|
|
2151
|
+
} : {}), underTitle ? null : bandSx(scope.band), [
|
|
2079
2152
|
container
|
|
2080
2153
|
], 'section', (_ref = (_page_options_sectionIds = page.options.sectionIds) == null ? void 0 : _page_options_sectionIds[index]) != null ? _ref : sectionIdOf(index));
|
|
2081
2154
|
}
|
|
2155
|
+
/** What a store's reviews are headed with where neither the design nor the plan says. */ export const AI_LAYOUT_REVIEWS_HEADING = 'What our customers say';
|
|
2156
|
+
/**
|
|
2157
|
+
* A store's own customer reviews (AGL-3676): the commerce plugin's Product
|
|
2158
|
+
* reviews in its store-wide scope, carrying the section's heading itself.
|
|
2159
|
+
* It lists approved reviews with their star ratings, and on a published page
|
|
2160
|
+
* with none — every store that just opened — it shows nothing, heading and
|
|
2161
|
+
* all, so the band takes no room until a shopper has written one. No review
|
|
2162
|
+
* is ever written here: the design's quotes, if it gave any, were left out.
|
|
2163
|
+
*/ function reviewsSection(scope, blocks) {
|
|
2164
|
+
var _page_plan_sections_index;
|
|
2165
|
+
const { page, index, at } = scope;
|
|
2166
|
+
const tree = page.tree;
|
|
2167
|
+
const given = blocks.find((block)=>speaksHeading(scope, block));
|
|
2168
|
+
const heading = aiLayoutWords(given == null ? void 0 : given.text, 'heading', page.targets.facts) || aiLayoutFitText((_page_plan_sections_index = page.plan.sections[index]) == null ? void 0 : _page_plan_sections_index.name, 'heading') || AI_LAYOUT_REVIEWS_HEADING;
|
|
2169
|
+
page.settled.push({
|
|
2170
|
+
at,
|
|
2171
|
+
what: "the store's own reviews placed: shown once shoppers leave them, never written for them"
|
|
2172
|
+
});
|
|
2173
|
+
const id = tree.add(AI_LAYOUT_LISTING_ELEMENTS.reviews, {
|
|
2174
|
+
scope: 'store',
|
|
2175
|
+
heading,
|
|
2176
|
+
maxItems: String(AI_LAYOUT_FEATURED_RECORDS.reviews)
|
|
2177
|
+
}, // The padding is the element's, so a store with no reviews yet keeps no empty band.
|
|
2178
|
+
{
|
|
2179
|
+
py: _extends({}, SECTION_PADDING)
|
|
2180
|
+
}, null, 'reviews');
|
|
2181
|
+
// The reviews are what the section shows: its shoppers' to write.
|
|
2182
|
+
noted(scope, [
|
|
2183
|
+
id,
|
|
2184
|
+
id
|
|
2185
|
+
]);
|
|
2186
|
+
const container = tree.add('muiContainer', {
|
|
2187
|
+
maxWidth: 'lg'
|
|
2188
|
+
}, null, [
|
|
2189
|
+
id
|
|
2190
|
+
], 'container');
|
|
2191
|
+
return designedRoot(scope, [
|
|
2192
|
+
container
|
|
2193
|
+
], bandSx(scope.band), scope.band === 'dark');
|
|
2194
|
+
}
|
|
2195
|
+
/** What a store's sign-up is headed with where neither the design nor the plan says. */ export const AI_LAYOUT_SIGNUP_HEADING = 'Join our newsletter';
|
|
2196
|
+
/**
|
|
2197
|
+
* A store's newsletter sign-up (AGL-3676): the design's heading and words
|
|
2198
|
+
* beside the commerce plugin's Newsletter signup field, or over it on a
|
|
2199
|
+
* centered band. Any form or button the design drew for it is the field's.
|
|
2200
|
+
*/ function signupSection(scope, blocks) {
|
|
2201
|
+
const { page, index, at } = scope;
|
|
2202
|
+
const tree = page.tree;
|
|
2203
|
+
const flow = blocks.filter((block)=>WORD_KINDS.has(block.kind) && block.kind !== 'button').map((_0)=>{
|
|
2204
|
+
let { col: _col } = _0, block = _object_without_properties_loose(_0, [
|
|
2205
|
+
"col"
|
|
2206
|
+
]);
|
|
2207
|
+
return block;
|
|
2208
|
+
});
|
|
2209
|
+
if (!flow.some((block)=>speaksHeading(scope, block))) {
|
|
2210
|
+
var _page_plan_sections_index;
|
|
2211
|
+
flow.unshift({
|
|
2212
|
+
kind: 'heading',
|
|
2213
|
+
text: ((_page_plan_sections_index = page.plan.sections[index]) == null ? void 0 : _page_plan_sections_index.name) || AI_LAYOUT_SIGNUP_HEADING
|
|
2214
|
+
});
|
|
2215
|
+
}
|
|
2216
|
+
page.settled.push({
|
|
2217
|
+
at,
|
|
2218
|
+
what: "the store's newsletter sign-up placed"
|
|
2219
|
+
});
|
|
2220
|
+
const field = tree.add(AI_LAYOUT_LISTING_ELEMENTS.signup, {
|
|
2221
|
+
buttonLabel: 'Subscribe'
|
|
2222
|
+
}, null, null, 'signup');
|
|
2223
|
+
noted(scope, [
|
|
2224
|
+
field,
|
|
2225
|
+
field
|
|
2226
|
+
]);
|
|
2227
|
+
const words = compileFlow(scope, flow, scope.centered ? 'full' : 'half');
|
|
2228
|
+
const body = scope.centered ? tree.add('muiStack', {
|
|
2229
|
+
spacing: '4',
|
|
2230
|
+
alignItems: 'center'
|
|
2231
|
+
}, null, [
|
|
2232
|
+
words,
|
|
2233
|
+
tree.add('muiContainer', {
|
|
2234
|
+
maxWidth: 'sm',
|
|
2235
|
+
disableGutters: true
|
|
2236
|
+
}, null, [
|
|
2237
|
+
field
|
|
2238
|
+
], 'measure')
|
|
2239
|
+
], 'content') : designRow(scope, [
|
|
2240
|
+
...words ? [
|
|
2241
|
+
{
|
|
2242
|
+
id: words,
|
|
2243
|
+
size: 'xs:12 md:6'
|
|
2244
|
+
}
|
|
2245
|
+
] : [],
|
|
2246
|
+
{
|
|
2247
|
+
id: field,
|
|
2248
|
+
size: 'xs:12 md:6'
|
|
2249
|
+
}
|
|
2250
|
+
], '6');
|
|
2251
|
+
const container = tree.add('muiContainer', {
|
|
2252
|
+
maxWidth: 'lg'
|
|
2253
|
+
}, {
|
|
2254
|
+
py: _extends({}, SECTION_PADDING)
|
|
2255
|
+
}, [
|
|
2256
|
+
body
|
|
2257
|
+
], 'container');
|
|
2258
|
+
return designedRoot(scope, [
|
|
2259
|
+
container
|
|
2260
|
+
], bandSx(scope.band), scope.band === 'dark');
|
|
2261
|
+
}
|
|
2262
|
+
/** A store's Shop page's grid section on this page, by plan index; -1 where this page is not its Shop page. */ function shopGridAt(page) {
|
|
2263
|
+
var _page_targets_listings, _ref;
|
|
2264
|
+
var _products_placements_find;
|
|
2265
|
+
const products = ((_page_targets_listings = page.targets.listings) != null ? _page_targets_listings : []).find((listing)=>listing.kind === 'products');
|
|
2266
|
+
return (_ref = products == null ? void 0 : (_products_placements_find = products.placements.find((placement)=>placement.role === 'index' && placement.screenId === page.targets.pageId)) == null ? void 0 : _products_placements_find.section) != null ? _ref : -1;
|
|
2267
|
+
}
|
|
2268
|
+
/** A store's Shop page, by its id, where this page is another page of the store; `null` otherwise. */ function shopPageOf(page) {
|
|
2269
|
+
var _page_targets_listings;
|
|
2270
|
+
var _products_placements_find;
|
|
2271
|
+
const products = ((_page_targets_listings = page.targets.listings) != null ? _page_targets_listings : []).find((listing)=>listing.kind === 'products');
|
|
2272
|
+
const shop = products == null ? void 0 : (_products_placements_find = products.placements.find((placement)=>placement.role === 'index')) == null ? void 0 : _products_placements_find.screenId;
|
|
2273
|
+
return shop && shop !== page.targets.pageId && page.targets.pages.some((entry)=>entry.id === shop) ? shop : null;
|
|
2274
|
+
}
|
|
2275
|
+
/**
|
|
2276
|
+
* A Shop page's opening, as a storefront's collection page opens (AGL-3676):
|
|
2277
|
+
* the page's title and one line under it, on the page's own ground, with
|
|
2278
|
+
* little room around them — no photo and no buttons — so the grid that
|
|
2279
|
+
* follows starts above the fold. The beta.237 Willow Wick /shop opened on a
|
|
2280
|
+
* tall candle photo and its words, the products below the fold.
|
|
2281
|
+
*/ function shopTitle(scope, blocks) {
|
|
2282
|
+
var _ref;
|
|
2283
|
+
const { page, at } = scope;
|
|
2284
|
+
const left = blocks.filter((block)=>![
|
|
2285
|
+
'eyebrow',
|
|
2286
|
+
'heading',
|
|
2287
|
+
'lede',
|
|
2288
|
+
'text'
|
|
2289
|
+
].includes(block.kind));
|
|
2290
|
+
if (left.length) {
|
|
2291
|
+
page.settled.push({
|
|
2292
|
+
at,
|
|
2293
|
+
what: `${left.map((block)=>block.kind).join(', ')} left out: a Shop page opens on its title and its grid`
|
|
2294
|
+
});
|
|
2295
|
+
}
|
|
2296
|
+
const heading = blocks.find((block)=>speaksHeading(scope, block));
|
|
2297
|
+
const line = blocks.find((block)=>block.kind === 'lede' || block.kind === 'text');
|
|
2298
|
+
const eyebrow = blocks.find((block)=>block.kind === 'eyebrow');
|
|
2299
|
+
const flow = [
|
|
2300
|
+
...eyebrow ? [
|
|
2301
|
+
eyebrow
|
|
2302
|
+
] : [],
|
|
2303
|
+
{
|
|
2304
|
+
kind: 'heading',
|
|
2305
|
+
text: (_ref = heading == null ? void 0 : heading.text) != null ? _ref : page.plan.title
|
|
2306
|
+
},
|
|
2307
|
+
...line ? [
|
|
2308
|
+
{
|
|
2309
|
+
kind: 'lede',
|
|
2310
|
+
text: line.text
|
|
2311
|
+
}
|
|
2312
|
+
] : []
|
|
2313
|
+
];
|
|
2314
|
+
scope.band = 'plain';
|
|
2315
|
+
scope.centered = false;
|
|
2316
|
+
page.settled.push({
|
|
2317
|
+
at,
|
|
2318
|
+
what: "drawn as the Shop page's title bar, the grid under it"
|
|
2319
|
+
});
|
|
2320
|
+
const words = compileFlow(scope, flow, 'half');
|
|
2321
|
+
const container = page.tree.add('muiContainer', {
|
|
2322
|
+
maxWidth: 'lg'
|
|
2323
|
+
}, {
|
|
2324
|
+
pt: {
|
|
2325
|
+
xs: 5,
|
|
2326
|
+
md: 7
|
|
2327
|
+
},
|
|
2328
|
+
pb: {
|
|
2329
|
+
xs: 1,
|
|
2330
|
+
md: 2
|
|
2331
|
+
}
|
|
2332
|
+
}, [
|
|
2333
|
+
words
|
|
2334
|
+
], 'container');
|
|
2335
|
+
return designedRoot(scope, [
|
|
2336
|
+
container
|
|
2337
|
+
], null, false);
|
|
2338
|
+
}
|
|
2339
|
+
/**
|
|
2340
|
+
* A storefront's home hero sells (AGL-3676): it opens the shop. Where the
|
|
2341
|
+
* design gave it no button to the Shop page, "Shop all" leads its buttons,
|
|
2342
|
+
* and any other primary button steps back to secondary beside it.
|
|
2343
|
+
*/ function sellingHero(scope, flow) {
|
|
2344
|
+
const design = scope.page.design;
|
|
2345
|
+
if (!(design == null ? void 0 : design.input.home) || aiLayoutFamily(design.input.kind) !== 'retail') return;
|
|
2346
|
+
const shop = shopPageOf(scope.page);
|
|
2347
|
+
if (!shop || flow.some((block)=>block.kind === 'button' && block.to === `page:${shop}`)) return;
|
|
2348
|
+
const firstButton = flow.findIndex((block)=>block.kind === 'button');
|
|
2349
|
+
for (const [at, block] of flow.entries()){
|
|
2350
|
+
var _block_style;
|
|
2351
|
+
if (block.kind === 'button' && ((_block_style = block.style) != null ? _block_style : 'primary') === 'primary') flow[at] = _extends({}, block, {
|
|
2352
|
+
style: 'secondary'
|
|
2353
|
+
});
|
|
2354
|
+
}
|
|
2355
|
+
const shopAll = {
|
|
2356
|
+
kind: 'button',
|
|
2357
|
+
text: AI_LAYOUT_SHOP_ALL,
|
|
2358
|
+
to: `page:${shop}`,
|
|
2359
|
+
style: 'primary'
|
|
2360
|
+
};
|
|
2361
|
+
if (firstButton === -1) flow.push(shopAll);
|
|
2362
|
+
else flow.splice(firstButton, 0, shopAll);
|
|
2363
|
+
scope.page.settled.push({
|
|
2364
|
+
at: scope.at,
|
|
2365
|
+
what: `the hero opens the shop: "${AI_LAYOUT_SHOP_ALL}" leads its buttons`
|
|
2366
|
+
});
|
|
2367
|
+
}
|
|
2368
|
+
/** The button a storefront's hero opens its shop with. */ export const AI_LAYOUT_SHOP_ALL = 'Shop all';
|
|
2369
|
+
/**
|
|
2370
|
+
* A storefront's reasons to buy as open columns, each led by an icon over its
|
|
2371
|
+
* title and words (AGL-3676): the icon the design named for it, else one its
|
|
2372
|
+
* words suggest (shipping a truck, returns the arrows, small batch the hand),
|
|
2373
|
+
* never the same twice in a row. One style key an element, so a row repeats
|
|
2374
|
+
* no multi-key inline style (rule 16).
|
|
2375
|
+
*/ function iconColumns(scope, items, room) {
|
|
2376
|
+
const { page } = scope;
|
|
2377
|
+
const tree = page.tree;
|
|
2378
|
+
const facts = page.targets.facts;
|
|
2379
|
+
const iconWords = aiStorefrontItemIcons(items, (word)=>!!aiIconOfWord(word));
|
|
2380
|
+
const perRow = across(items.length, room, 'cards');
|
|
2381
|
+
const textAlign = scope.centered ? {
|
|
2382
|
+
align: 'center'
|
|
2383
|
+
} : {};
|
|
2384
|
+
page.settled.push({
|
|
2385
|
+
at: scope.at,
|
|
2386
|
+
what: `${items.length} items drawn as icon columns`
|
|
2387
|
+
});
|
|
2388
|
+
const ids = items.map((item, position)=>{
|
|
2389
|
+
var _aiIconOfWord;
|
|
2390
|
+
const icon = (_aiIconOfWord = aiIconOfWord(iconWords[position])) != null ? _aiIconOfWord : AI_ICON_LIBRARY.star;
|
|
2391
|
+
return tree.add('muiStack', _extends({
|
|
2392
|
+
spacing: '1.5'
|
|
2393
|
+
}, scope.centered ? {
|
|
2394
|
+
alignItems: 'center'
|
|
2395
|
+
} : {}), null, [
|
|
2396
|
+
tree.add(AI_ICON_COMPONENT_ID, {
|
|
2397
|
+
iconId: icon.id,
|
|
2398
|
+
size: '32'
|
|
2399
|
+
}, accent(scope), null, 'icon'),
|
|
2400
|
+
item.title.trim() ? tree.add('muiTypography', _extends({
|
|
2401
|
+
children: aiLayoutWords(item.title, 'itemTitle', facts),
|
|
2402
|
+
variant: 'h6',
|
|
2403
|
+
component: itemElement(scope)
|
|
2404
|
+
}, textAlign), null, null, 'title') : null,
|
|
2405
|
+
item.text.trim() ? tree.add('muiTypography', _extends({
|
|
2406
|
+
children: aiLayoutWords(item.text, 'itemText', facts),
|
|
2407
|
+
variant: 'body2'
|
|
2408
|
+
}, textAlign), muted(scope), null, 'text') : null
|
|
2409
|
+
], 'iconItem');
|
|
2410
|
+
});
|
|
2411
|
+
return layOut(scope, noted(scope, ids), perRow, '5', 'icons');
|
|
2412
|
+
}
|
|
2082
2413
|
/**
|
|
2083
2414
|
* The element that lists the records, bound to them: the Product grid over
|
|
2084
2415
|
* the site's catalog, or Collection Entries over its blog with one post's
|
|
@@ -2090,6 +2421,22 @@ function listingSection(scope, blocks, placed) {
|
|
|
2090
2421
|
const shown = featured ? AI_LAYOUT_FEATURED_RECORDS[listing.kind] : 12;
|
|
2091
2422
|
const element = AI_LAYOUT_LISTING_ELEMENTS[listing.kind];
|
|
2092
2423
|
let id;
|
|
2424
|
+
if (listing.kind === 'tracks') {
|
|
2425
|
+
// An empty player (AGL-3716): its "add your tracks" state, which the owner
|
|
2426
|
+
// fills from their own media library. No source, ever — the section's
|
|
2427
|
+
// heading and words are the model's, the recordings the owner's.
|
|
2428
|
+
id = tree.add(element, null, null, null, 'player');
|
|
2429
|
+
page.settled.push({
|
|
2430
|
+
at: scope.at,
|
|
2431
|
+
what: 'an empty music player placed for the owner’s own tracks'
|
|
2432
|
+
});
|
|
2433
|
+
// The player is what the section shows: its tracks are the owner's to add.
|
|
2434
|
+
noted(scope, [
|
|
2435
|
+
id,
|
|
2436
|
+
id
|
|
2437
|
+
]);
|
|
2438
|
+
return id;
|
|
2439
|
+
}
|
|
2093
2440
|
if (listing.kind === 'products') {
|
|
2094
2441
|
id = tree.add(element, _extends({
|
|
2095
2442
|
source: 'all',
|
|
@@ -2098,11 +2445,22 @@ function listingSection(scope, blocks, placed) {
|
|
|
2098
2445
|
}, featured ? {
|
|
2099
2446
|
maxItems: String(shown)
|
|
2100
2447
|
} : {
|
|
2101
|
-
pageSize: String(shown)
|
|
2448
|
+
pageSize: String(shown),
|
|
2449
|
+
showSort: true,
|
|
2450
|
+
showCategories: true
|
|
2102
2451
|
}, {
|
|
2103
2452
|
cardStyle: 'photo',
|
|
2104
|
-
|
|
2105
|
-
|
|
2453
|
+
// A storefront's cards sell from the grid (AGL-3676): Add to cart on a
|
|
2454
|
+
// product with one variant, Choose options on one with several.
|
|
2455
|
+
quickAdd: true,
|
|
2456
|
+
// A store that opens before its first products are in says so, with a
|
|
2457
|
+
// way to hear when they land (AGL-3676): never placeholder products.
|
|
2458
|
+
emptyTitle: AI_LAYOUT_STORE_EMPTY.title,
|
|
2459
|
+
emptyText: listing.emptyAction ? AI_LAYOUT_STORE_EMPTY.text : AI_LAYOUT_STORE_EMPTY.textAlone
|
|
2460
|
+
}, listing.emptyAction ? {
|
|
2461
|
+
emptyActionLabel: listing.emptyAction.label,
|
|
2462
|
+
emptyActionHref: listing.emptyAction.href
|
|
2463
|
+
} : {}), null, null, 'products');
|
|
2106
2464
|
} else {
|
|
2107
2465
|
id = postsElement(scope, listing, featured ? shown : COLLECTION_INDEX_POSTS);
|
|
2108
2466
|
}
|
|
@@ -2113,6 +2471,11 @@ function listingSection(scope, blocks, placed) {
|
|
|
2113
2471
|
}, ()=>id));
|
|
2114
2472
|
return id;
|
|
2115
2473
|
}
|
|
2474
|
+
/** What a store's Product grid says while the store lists nothing yet (AGL-3676). */ export const AI_LAYOUT_STORE_EMPTY = {
|
|
2475
|
+
title: 'New pieces are on the way',
|
|
2476
|
+
text: 'Our first pieces are being finished now. Get in touch and we will let you know the moment they land.',
|
|
2477
|
+
/** Said where the site has no page to get in touch on. */ textAlone: 'Our first pieces are being finished now. Check back soon.'
|
|
2478
|
+
};
|
|
2116
2479
|
/** The most posts a page of the site lists where it is the writing's own page. */ const COLLECTION_INDEX_POSTS = 9;
|
|
2117
2480
|
/** The blog's posts as the site's design lists them: a grid of covers, or a ruled list with the dates. */ function postsElement(scope, listing, limit) {
|
|
2118
2481
|
var _page_design;
|