@seamlet/astro 1.1.0 → 1.2.1
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/CHANGELOG.md +9 -0
- package/README.md +30 -1
- package/dist/bridge.d.ts +2 -2
- package/dist/bridge.js +2 -2
- package/dist/{chunk-G6Z44LGA.js → chunk-HFPZVDST.js} +24 -13
- package/dist/{chunk-QXPXIMIM.js → chunk-OCA2WYK3.js} +2 -2
- package/dist/{chunk-I3HOJE3S.js → chunk-UL2C2IB2.js} +32 -5
- package/dist/{chunk-PLNPM2D3.js → chunk-Y4R4YV5O.js} +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.js +3 -3
- package/dist/{messages-Bqgs_mic.d.ts → messages-C2OjqFmy.d.ts} +1 -1
- package/dist/{parse-content-IOJxgKLB.d.ts → parse-content-Bnn6Wa-l.d.ts} +1 -1
- package/dist/preview-requests.d.ts +2 -2
- package/dist/preview-requests.js +3 -3
- package/dist/protocol.d.ts +3 -3
- package/dist/protocol.js +2 -2
- package/dist/routes/media.js +3 -3
- package/dist/schema.d.ts +33 -4
- package/dist/schema.js +3 -1
- package/dist/{site-description-BuEpga8p.d.ts → site-description-BnHrODQX.d.ts} +18 -5
- package/dist/site.d.ts +13 -8
- package/dist/site.js +4 -2
- package/package.json +1 -1
- package/routes/preview.astro +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.1
|
|
4
|
+
|
|
5
|
+
- `site.staticPaths(content)` is what Astro's `GetStaticPaths` takes: a static site's `[...page]` route may write `satisfies GetStaticPaths` and read its props with `InferGetStaticPropsType`. `StaticPage` and `RenderedPage` became type aliases, and `staticPaths` returns a mutable array.
|
|
6
|
+
|
|
7
|
+
## 1.2.0
|
|
8
|
+
|
|
9
|
+
- `productFields()`: the fields of a product of a catalog, for the record of a collection, with its address, photos, a short and a whole description, the price with a word about it, characteristics as pairs of a name and a value, the switch that hides it and what search engines show.
|
|
10
|
+
- `recordPages(…, { shows })` leaves the pages of some records off the site: `site.pageOf` and `site.staticPaths` leave them out, `pathOf` gives them no address, and the preview shows them (`site.previewPageOf`), so the owner prepares a hidden record in the editor.
|
|
11
|
+
|
|
3
12
|
## 1.1.0
|
|
4
13
|
|
|
5
14
|
- Pages of records: `recordPages(schema, { collection, path: "/menu/[record]" })` gives every record of a collection a page, rendered by one component with `content`, `record` and `index`; `defineSeamletSite` takes them as `recordPages`, the site's description tells the CMS about them, and the preview shows them, a record the editor has just added too.
|
package/README.md
CHANGED
|
@@ -230,6 +230,33 @@ Sets of fields almost every site has, edited the same way everywhere; they are p
|
|
|
230
230
|
|
|
231
231
|
Each takes `{ label }` to name it otherwise.
|
|
232
232
|
|
|
233
|
+
`productFields()` is the fields of a product of a catalog, for the record of a collection: `name`, `slug` (the address of its page), `photos` (records of one `photo`, the first is the main one), `summary` (one line for a card), `description`, `price` with `priceNote` («от», «за м²»), `characteristics` (records of a `name` and a `value`, so the owner adds a property without code: «Площадь» — «36 м²»), `isHidden` and `seo`. A site adds its own fields beside them, a category for one:
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
export const schema = defineSchema({
|
|
237
|
+
categories: collection({
|
|
238
|
+
label: "Категории",
|
|
239
|
+
itemTitle: "name",
|
|
240
|
+
item: { name: text({ label: "Название" }) },
|
|
241
|
+
}),
|
|
242
|
+
products: collection({
|
|
243
|
+
label: "Товары",
|
|
244
|
+
itemTitle: "name",
|
|
245
|
+
item: {
|
|
246
|
+
...productFields(),
|
|
247
|
+
category: reference({ label: "Категория", collection: "categories" }),
|
|
248
|
+
},
|
|
249
|
+
}),
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
export const productPages = recordPages(schema, {
|
|
253
|
+
collection: "products",
|
|
254
|
+
path: "/catalog/[record]",
|
|
255
|
+
searchTexts: "seo",
|
|
256
|
+
shows: (product) => !product.isHidden,
|
|
257
|
+
});
|
|
258
|
+
```
|
|
259
|
+
|
|
233
260
|
## Records and references
|
|
234
261
|
|
|
235
262
|
Every record of a collection has an `id` of its own, which never changes when records move, so a record has no field named `id`. The CMS gives ids to records that have none (`withRecordIds`), so a site's initial content may leave them out, unless something refers to those records.
|
|
@@ -317,6 +344,8 @@ const edit = editable<Content>();
|
|
|
317
344
|
<h1 {...edit("menu", index, "name")}>{record.name}</h1>
|
|
318
345
|
```
|
|
319
346
|
|
|
347
|
+
`shows` leaves the pages of some records off the site, a hidden product's for one: `site.pageOf` and `site.staticPaths` leave them out and `pathOf` gives them no address, while the preview shows them, so the owner prepares a product before showing it.
|
|
348
|
+
|
|
320
349
|
`drinkPages.pathOf(drink)` gives the address of a record's page for a link to it: `/menu/latte`. The address is the record's `slug` when it has one, a field the owner fills in (lower-case Latin letters, digits and hyphens; the CMS spells it from the record's name), and its id otherwise, so a record has its page from the moment it is added, and keeps it when it is renamed or moved. A slug another record of the collection has, as its slug or as its id, is the issue `taken-slug`; a slug with other characters, `invalid-slug`. A collection is `catalog.products` through groups, its pages have one segment more than a page of the site (`/catalog/[record]`, never `/[record]`), a record has one page, and no page of the site may stand among the pages of records (`/menu/specials` beside `/menu/[record]`). `searchTexts` names a group of the record with a `title` and a `description` text for its page.
|
|
321
350
|
|
|
322
351
|
Every record of the initial content needs an address of its own, a slug or an id, since its page is built before the CMS saves anything. The preview shows a page of a record the owner has just added, so the editor opens it before it is saved or published: under the pages of records, an address that could be an id and names no record shows a blank record, which the editor's draft replaces at once.
|
|
@@ -335,7 +364,7 @@ What was opened stays open while the page is rendered anew after every edit: a p
|
|
|
335
364
|
|
|
336
365
|
## What the integration adds
|
|
337
366
|
|
|
338
|
-
- `/preview` and `/preview/<page>`: the preview the CMS's editor frames, the pages of records too (at their address or at the record's id). `GET` shows the published content; `POST` with the content as JSON shows that content without saving it, which is how the editor shows every edit at once. Only the CMS may frame it (`Content-Security-Policy: frame-ancestors`), and it is never indexed or cached; its refusals (an address of no page, a record a draft does not have, a draft that is not JSON or is over 1 MB) say the same.
|
|
367
|
+
- `/preview` and `/preview/<page>`: the preview the CMS's editor frames, the pages of records too (at their address or at the record's id, a page the site does not show too). `GET` shows the published content; `POST` with the content as JSON shows that content without saving it, which is how the editor shows every edit at once. Only the CMS may frame it (`Content-Security-Policy: frame-ancestors`), and it is never indexed or cached; its refusals (an address of no page, a record a draft does not have, a draft that is not JSON or is over 1 MB) say the same.
|
|
339
368
|
- The bridge on the preview: it tells the editor where the marked elements are and what a person does on the page, and types texts in place, formatted ones too.
|
|
340
369
|
- `/seamlet/site.json`: what the site tells the CMS about itself (`SITE_DESCRIPTION_PATH`): its id and name from `seamlet.json`, its schema, the content it starts with and its pages. The CMS reads it with `readSiteDescription` whenever the site is opened in its editor.
|
|
341
370
|
- `/seamlet-photos/<address>`: the site's own photo at an address its content gives it, found by `photos` of `defineSeamletSite`, for the CMS's editor.
|
package/dist/bridge.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { F as Fields } from './parse-content-
|
|
2
|
-
import { P as PageMessage, E as EditorMessage } from './messages-
|
|
1
|
+
import { F as Fields } from './parse-content-Bnn6Wa-l.js';
|
|
2
|
+
import { P as PageMessage, E as EditorMessage } from './messages-C2OjqFmy.js';
|
|
3
3
|
|
|
4
4
|
interface BridgeOptions {
|
|
5
5
|
/** The origin of the CMS whose editor may frame the page, such as `https://cms.example.com`. */
|
package/dist/bridge.js
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
shortcutOf,
|
|
19
19
|
toggleList,
|
|
20
20
|
toggleMark
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-Y4R4YV5O.js";
|
|
22
22
|
import {
|
|
23
23
|
FIELD_PATH_ATTRIBUTE,
|
|
24
24
|
REVEALED_ATTRIBUTE,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
readRichText,
|
|
29
29
|
resolveFieldPath,
|
|
30
30
|
safeHref
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-UL2C2IB2.js";
|
|
32
32
|
|
|
33
33
|
// src/bridge/typed-fields.ts
|
|
34
34
|
function typedKindAt(schema, path) {
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
recordAt,
|
|
7
7
|
recordPageAt,
|
|
8
8
|
recordPagePath
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-UL2C2IB2.js";
|
|
10
10
|
|
|
11
11
|
// src/site-pages.ts
|
|
12
12
|
function pagePathOf(rest) {
|
|
@@ -15,12 +15,13 @@ function pagePathOf(rest) {
|
|
|
15
15
|
function pageParameterOf(path) {
|
|
16
16
|
return path === HOME_PAGE_PATH ? void 0 : path.slice(PAGE_PATH_SEPARATOR.length);
|
|
17
17
|
}
|
|
18
|
+
var SHOWN_ON_SITE = (recordPage, record) => recordPage.pages.isShown?.(record) ?? true;
|
|
19
|
+
var EVERY_RECORD = () => true;
|
|
18
20
|
function renderedPageAt(site, path, content) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
return renderedRecordPageAt(site, path, content);
|
|
21
|
+
return ownPageAt(site, path, content) ?? renderedRecordPageAt(site, { path, content, isShown: SHOWN_ON_SITE });
|
|
22
|
+
}
|
|
23
|
+
function previewedPageAt(site, path, content) {
|
|
24
|
+
return ownPageAt(site, path, content) ?? renderedRecordPageAt(site, { path, content, isShown: EVERY_RECORD });
|
|
24
25
|
}
|
|
25
26
|
function staticPagesOf(site, content) {
|
|
26
27
|
const ownPages = Object.entries(site.pages).map(
|
|
@@ -31,26 +32,35 @@ function staticPagesOf(site, content) {
|
|
|
31
32
|
);
|
|
32
33
|
return [...ownPages, ...recordPages];
|
|
33
34
|
}
|
|
34
|
-
function
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
function ownPageAt(site, path, content) {
|
|
36
|
+
const page = Object.hasOwn(site.pages, path) ? site.pages[path] : void 0;
|
|
37
|
+
return page === void 0 ? void 0 : { component: page.component, props: { content } };
|
|
38
|
+
}
|
|
39
|
+
function renderedRecordPageAt(site, request) {
|
|
40
|
+
const { path, content, isShown } = request;
|
|
41
|
+
const described = site.recordPages.map((recordPage2) => ({
|
|
42
|
+
...recordPage2.pages,
|
|
43
|
+
recordPage: recordPage2
|
|
38
44
|
}));
|
|
39
45
|
const found = recordPageAt(described, path);
|
|
40
46
|
if (found === void 0) return void 0;
|
|
41
47
|
const records = collectionAt(site.schema, content, found.page.collection);
|
|
42
48
|
if (records === void 0) return void 0;
|
|
43
49
|
const placed = recordAt(records.collection, records.records, found.address);
|
|
44
|
-
|
|
50
|
+
const { recordPage } = found.page;
|
|
51
|
+
if (placed === void 0 || !isShown(recordPage, placed.record)) {
|
|
52
|
+
return void 0;
|
|
53
|
+
}
|
|
45
54
|
const props = { content, record: placed.record, index: placed.index };
|
|
46
|
-
return { component:
|
|
55
|
+
return { component: recordPage.component, props };
|
|
47
56
|
}
|
|
48
57
|
function staticRecordPagesOf(schema, recordPage, content) {
|
|
49
58
|
const found = collectionAt(schema, content, recordPage.pages.collection);
|
|
50
59
|
if (found === void 0) return [];
|
|
51
60
|
return found.records.flatMap((record, index) => {
|
|
52
61
|
const address = recordAddressOf(found.collection, record);
|
|
53
|
-
|
|
62
|
+
const hasPage = address !== void 0 && SHOWN_ON_SITE(recordPage, record);
|
|
63
|
+
if (!hasPage) return [];
|
|
54
64
|
const path = recordPagePath(recordPage.pages.path, address);
|
|
55
65
|
const props = { content, record, index };
|
|
56
66
|
return [staticPage(path, { component: recordPage.component, props })];
|
|
@@ -63,5 +73,6 @@ function staticPage(path, page) {
|
|
|
63
73
|
export {
|
|
64
74
|
pagePathOf,
|
|
65
75
|
renderedPageAt,
|
|
76
|
+
previewedPageAt,
|
|
66
77
|
staticPagesOf
|
|
67
78
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
pagePathOf
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-HFPZVDST.js";
|
|
4
4
|
import {
|
|
5
5
|
FIELD_PATH_SEPARATOR,
|
|
6
6
|
collectionAt,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
newRecord,
|
|
10
10
|
recordAt,
|
|
11
11
|
recordPageAt
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-UL2C2IB2.js";
|
|
13
13
|
|
|
14
14
|
// src/preview-requests.ts
|
|
15
15
|
var MAX_DRAFT_BYTES = 1024 * 1024;
|
|
@@ -1026,6 +1026,30 @@ function openingHoursField(options = {}) {
|
|
|
1026
1026
|
}
|
|
1027
1027
|
});
|
|
1028
1028
|
}
|
|
1029
|
+
function productFields() {
|
|
1030
|
+
return {
|
|
1031
|
+
name: text({ label: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435", maxLength: 120 }),
|
|
1032
|
+
slug: slug({ label: "\u0410\u0434\u0440\u0435\u0441 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B" }),
|
|
1033
|
+
photos: collection({
|
|
1034
|
+
label: "\u0424\u043E\u0442\u043E",
|
|
1035
|
+
item: { photo: image({ label: "\u0424\u043E\u0442\u043E" }) }
|
|
1036
|
+
}),
|
|
1037
|
+
summary: richText({ label: "\u041A\u0440\u0430\u0442\u043A\u043E", inline: true, maxLength: 200 }),
|
|
1038
|
+
description: richText({ label: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435" }),
|
|
1039
|
+
price: number({ label: "\u0426\u0435\u043D\u0430, \u20BD", min: 0 }),
|
|
1040
|
+
priceNote: text({ label: "\u0423\u0442\u043E\u0447\u043D\u0435\u043D\u0438\u0435 \u0446\u0435\u043D\u044B", maxLength: 40 }),
|
|
1041
|
+
characteristics: collection({
|
|
1042
|
+
label: "\u0425\u0430\u0440\u0430\u043A\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043A\u0438",
|
|
1043
|
+
itemTitle: "name",
|
|
1044
|
+
item: {
|
|
1045
|
+
name: text({ label: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435", maxLength: 60 }),
|
|
1046
|
+
value: text({ label: "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435", maxLength: 120 })
|
|
1047
|
+
}
|
|
1048
|
+
}),
|
|
1049
|
+
isHidden: toggle({ label: "\u0421\u043A\u0440\u044B\u0442\u044C \u0441 \u0441\u0430\u0439\u0442\u0430" }),
|
|
1050
|
+
seo: seoFields()
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1029
1053
|
|
|
1030
1054
|
// src/schema/read-fields.ts
|
|
1031
1055
|
var TITLE_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -1310,17 +1334,19 @@ var RECORD_PAGE_PATH = new RegExp(
|
|
|
1310
1334
|
var PAGE_PATH_SEPARATOR = "/";
|
|
1311
1335
|
var NOT_FOUND = -1;
|
|
1312
1336
|
function recordPages(schema, options) {
|
|
1313
|
-
const
|
|
1337
|
+
const { shows, ...described } = options;
|
|
1338
|
+
const collection2 = collectionFieldAt(schema, described.collection);
|
|
1314
1339
|
if (collection2 === void 0) {
|
|
1315
1340
|
throw new Error(
|
|
1316
|
-
`@seamlet/astro: the schema has no collection "${
|
|
1341
|
+
`@seamlet/astro: the schema has no collection "${described.collection}" for the pages at "${described.path}"`
|
|
1317
1342
|
);
|
|
1318
1343
|
}
|
|
1344
|
+
const isShown = (record) => shows === void 0 || shows(record);
|
|
1319
1345
|
const pathOf = (record) => {
|
|
1320
|
-
const address = recordAddressOf(collection2, record);
|
|
1321
|
-
return address === void 0 ? void 0 : recordPagePath(
|
|
1346
|
+
const address = isShown(record) ? recordAddressOf(collection2, record) : void 0;
|
|
1347
|
+
return address === void 0 ? void 0 : recordPagePath(described.path, address);
|
|
1322
1348
|
};
|
|
1323
|
-
return { ...
|
|
1349
|
+
return { ...described, isShown, pathOf };
|
|
1324
1350
|
}
|
|
1325
1351
|
function isRecordPagePath(path) {
|
|
1326
1352
|
return typeof path === "string" && RECORD_PAGE_PATH.test(path);
|
|
@@ -1586,6 +1612,7 @@ export {
|
|
|
1586
1612
|
contactsFields,
|
|
1587
1613
|
WEEKDAYS,
|
|
1588
1614
|
openingHoursField,
|
|
1615
|
+
productFields,
|
|
1589
1616
|
readFields,
|
|
1590
1617
|
checkFields,
|
|
1591
1618
|
SITE_CONFIG_FILE,
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -8,14 +8,14 @@ import {
|
|
|
8
8
|
} from "./chunk-QCVWHHJC.js";
|
|
9
9
|
import {
|
|
10
10
|
isUploadedPhoto
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-OCA2WYK3.js";
|
|
12
|
+
import "./chunk-HFPZVDST.js";
|
|
13
13
|
import {
|
|
14
14
|
SITE_CONFIG_FILE,
|
|
15
15
|
SITE_DESCRIPTION_PATH,
|
|
16
16
|
isJsonObject,
|
|
17
17
|
readSiteConfig
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-UL2C2IB2.js";
|
|
19
19
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
import process from "process";
|
|
@@ -300,4 +300,4 @@ declare function countCharacters(text: string): number;
|
|
|
300
300
|
*/
|
|
301
301
|
declare function parseContent<F extends Fields>(schema: F, input: unknown): ParsedContent<ContentOf<F>>;
|
|
302
302
|
|
|
303
|
-
export { parseContent as $, collection as A, countCharacters as B, type Content as C, type DateField as D, date as E, type Fields as F, type GroupField as G, defaultContent as H, type ImageField as I, defaultValue as J, defineSchema as K, type LinkValue as L, formatFieldPath as M, type NumberField as N, type OptionValue as O, type ParsedContent as P, group as Q, type RichText as R, type SlugField as S, type TextField as T, type UrlField as U, type ValueOf as V, image as W, linesOf as X, link as Y, normalizedLine as Z, number as _, type FieldPath as a, plainTextOf as a0, readRichText as a1, reference as a2, references as a3, richText as a4, richTextOf as a5, slug as a6, text as a7, time as a8, toggle as a9, url as aa, type ContentOf as b, type Field as c, type CollectionField as d, type RecordFields as e, type RecordOf as f, type ContentIssue as g, type ImageValue as h, type LinkField as i, type ChoicesField as j, type TimeField as k, type
|
|
303
|
+
export { parseContent as $, collection as A, countCharacters as B, type Content as C, type DateField as D, date as E, type Fields as F, type GroupField as G, defaultContent as H, type ImageField as I, defaultValue as J, defineSchema as K, type LinkValue as L, formatFieldPath as M, type NumberField as N, type OptionValue as O, type ParsedContent as P, group as Q, type RichText as R, type SlugField as S, type TextField as T, type UrlField as U, type ValueOf as V, image as W, linesOf as X, link as Y, normalizedLine as Z, number as _, type FieldPath as a, plainTextOf as a0, readRichText as a1, reference as a2, references as a3, richText as a4, richTextOf as a5, slug as a6, text as a7, time as a8, toggle as a9, url as aa, type ContentOf as b, type Field as c, type CollectionField as d, type RecordFields as e, type RecordOf as f, type ContentIssue as g, type ImageValue as h, type LinkField as i, type ChoicesField as j, type TimeField as k, type RichTextField as l, type ToggleField as m, type ChoiceField as n, type ChoiceOption as o, type FieldKind as p, type FieldValue as q, type ImageFocus as r, type ReferenceField as s, type ReferencesField as t, type RichBlock as u, type RichLine as v, type RichSpan as w, asOneParagraph as x, choice as y, choices as z };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as Content } from './parse-content-
|
|
2
|
-
import { S as SiteDescription } from './site-description-
|
|
1
|
+
import { C as Content } from './parse-content-Bnn6Wa-l.js';
|
|
2
|
+
import { S as SiteDescription } from './site-description-BnHrODQX.js';
|
|
3
3
|
|
|
4
4
|
/** Far more than the content of a site ever takes; a bigger body is not a draft. */
|
|
5
5
|
declare const MAX_DRAFT_BYTES: number;
|
package/dist/preview-requests.js
CHANGED
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
previewContentAt,
|
|
6
6
|
previewHeadersOf,
|
|
7
7
|
readDraft
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-OCA2WYK3.js";
|
|
9
|
+
import "./chunk-HFPZVDST.js";
|
|
10
|
+
import "./chunk-UL2C2IB2.js";
|
|
11
11
|
export {
|
|
12
12
|
MAX_DRAFT_BYTES,
|
|
13
13
|
isPageAddress,
|
package/dist/protocol.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { S as Shortcut, T as TextFormats } from './messages-
|
|
2
|
-
export { B as Box, a as EditorKey, E as EditorMessage, I as InlineEditingOutcome, L as LinkBox, M as MarkerBox, b as PROTOCOL_VERSION, c as PageLayout, P as PageMessage, d as Point, e as TextFormat, f as TypedSelection, V as Viewport, r as readEditorMessage, g as readPageMessage } from './messages-
|
|
3
|
-
import { F as Fields, a as FieldPath, I as ImageField, R as RichText } from './parse-content-
|
|
1
|
+
import { S as Shortcut, T as TextFormats } from './messages-C2OjqFmy.js';
|
|
2
|
+
export { B as Box, a as EditorKey, E as EditorMessage, I as InlineEditingOutcome, L as LinkBox, M as MarkerBox, b as PROTOCOL_VERSION, c as PageLayout, P as PageMessage, d as Point, e as TextFormat, f as TypedSelection, V as Viewport, r as readEditorMessage, g as readPageMessage } from './messages-C2OjqFmy.js';
|
|
3
|
+
import { F as Fields, a as FieldPath, I as ImageField, R as RichText } from './parse-content-Bnn6Wa-l.js';
|
|
4
4
|
|
|
5
5
|
declare function shortcutOf(event: KeyboardEvent): Shortcut | undefined;
|
|
6
6
|
|
package/dist/protocol.js
CHANGED
|
@@ -22,9 +22,9 @@ import {
|
|
|
22
22
|
shortcutOf,
|
|
23
23
|
toggleList,
|
|
24
24
|
toggleMark
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-Y4R4YV5O.js";
|
|
26
26
|
import "./chunk-QCVWHHJC.js";
|
|
27
|
-
import "./chunk-
|
|
27
|
+
import "./chunk-UL2C2IB2.js";
|
|
28
28
|
export {
|
|
29
29
|
OWN_PHOTOS_PATH,
|
|
30
30
|
PROTOCOL_VERSION,
|
package/dist/routes/media.js
CHANGED
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
} from "../chunk-QCVWHHJC.js";
|
|
4
4
|
import {
|
|
5
5
|
isUploadedPhoto
|
|
6
|
-
} from "../chunk-
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
6
|
+
} from "../chunk-OCA2WYK3.js";
|
|
7
|
+
import "../chunk-HFPZVDST.js";
|
|
8
|
+
import "../chunk-UL2C2IB2.js";
|
|
9
9
|
|
|
10
10
|
// src/routes/media.ts
|
|
11
11
|
import { cmsOrigin } from "virtual:seamlet/config";
|
package/dist/schema.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { h as ImageValue, L as LinkValue, d as CollectionField, C as Content, F as Fields, e as RecordFields, b as ContentOf, G as GroupField, i as LinkField, T as TextField, U as UrlField, j as ChoicesField, k as TimeField, I as ImageField } from './parse-content-
|
|
2
|
-
export {
|
|
3
|
-
export { C as CollectionPath, F as FIELD_PATH_SEPARATOR, b as FieldTarget, c as FieldsReading, H as HOME_PAGE_PATH, P as PAGE_PATH_SEPARATOR, d as PageProblemReason, e as PlacedRecord, R as RECORD_PLACEHOLDER, f as RecordFieldsAt, g as RecordPagePath, h as RecordPageProblemReason, i as RecordPages, j as SITE_DESCRIPTION_PATH, k as SchemaProblem, l as SchemaProblemReason, S as SiteDescription, m as SiteDescriptionProblem, n as SiteDescriptionReading, o as SitePageDescription,
|
|
1
|
+
import { h as ImageValue, L as LinkValue, d as CollectionField, C as Content, F as Fields, e as RecordFields, b as ContentOf, G as GroupField, i as LinkField, T as TextField, U as UrlField, j as ChoicesField, k as TimeField, S as SlugField, I as ImageField, l as RichTextField, N as NumberField, m as ToggleField } from './parse-content-Bnn6Wa-l.js';
|
|
2
|
+
export { n as ChoiceField, o as ChoiceOption, g as ContentIssue, D as DateField, c as Field, p as FieldKind, a as FieldPath, q as FieldValue, r as ImageFocus, O as OptionValue, P as ParsedContent, f as RecordOf, s as ReferenceField, t as ReferencesField, u as RichBlock, v as RichLine, w as RichSpan, R as RichText, V as ValueOf, x as asOneParagraph, y as choice, z as choices, A as collection, B as countCharacters, E as date, H as defaultContent, J as defaultValue, K as defineSchema, M as formatFieldPath, Q as group, W as image, X as linesOf, Y as link, Z as normalizedLine, _ as number, $ as parseContent, a0 as plainTextOf, a1 as readRichText, a2 as reference, a3 as references, a4 as richText, a5 as richTextOf, a6 as slug, a7 as text, a8 as time, a9 as toggle, aa as url } from './parse-content-Bnn6Wa-l.js';
|
|
3
|
+
export { C as CollectionPath, F as FIELD_PATH_SEPARATOR, b as FieldTarget, c as FieldsReading, H as HOME_PAGE_PATH, P as PAGE_PATH_SEPARATOR, d as PageProblemReason, e as PlacedRecord, R as RECORD_PLACEHOLDER, f as RecordFieldsAt, g as RecordPagePath, h as RecordPageProblemReason, i as RecordPages, j as SITE_DESCRIPTION_PATH, k as SchemaProblem, l as SchemaProblemReason, S as SiteDescription, m as SiteDescriptionProblem, n as SiteDescriptionReading, o as SitePageDescription, p as SiteRecordPageDescription, a as SiteRecordPages, q as checkFields, r as checkSiteDescription, s as isRecordPagePath, t as isSearchTextsGroup, u as readFields, v as readSiteDescription, w as recordAddressOf, x as recordAt, y as recordPageAt, z as recordPagePath, A as recordPages, B as resolveFieldPath } from './site-description-BnHrODQX.js';
|
|
4
4
|
|
|
5
5
|
declare const FIELD_PATH_ATTRIBUTE = "data-cms-path";
|
|
6
6
|
interface FieldMarker {
|
|
@@ -159,6 +159,35 @@ declare function openingHoursField(options?: {
|
|
|
159
159
|
closes: TimeField;
|
|
160
160
|
note: TextField;
|
|
161
161
|
}>;
|
|
162
|
+
/**
|
|
163
|
+
* The fields of a product of a catalog: its name and the address of its page, its photos (the first
|
|
164
|
+
* is the main one), a short line for a card and a whole description for its page, the price and a
|
|
165
|
+
* word about it («от», «за м²»), characteristics as pairs of a name and a value, so the owner adds a
|
|
166
|
+
* property without code, the switch that hides it, and what search engines show for its page. A
|
|
167
|
+
* site puts them into its collection and adds its own fields beside them:
|
|
168
|
+
* `item: { ...productFields(), category: reference({ label: "Категория", collection: "categories" }) }`.
|
|
169
|
+
*/
|
|
170
|
+
declare function productFields(): {
|
|
171
|
+
name: TextField;
|
|
172
|
+
slug: SlugField;
|
|
173
|
+
photos: CollectionField<{
|
|
174
|
+
photo: ImageField;
|
|
175
|
+
}>;
|
|
176
|
+
summary: RichTextField;
|
|
177
|
+
description: RichTextField;
|
|
178
|
+
price: NumberField;
|
|
179
|
+
priceNote: TextField;
|
|
180
|
+
characteristics: CollectionField<{
|
|
181
|
+
name: TextField;
|
|
182
|
+
value: TextField;
|
|
183
|
+
}>;
|
|
184
|
+
isHidden: ToggleField;
|
|
185
|
+
seo: GroupField<{
|
|
186
|
+
title: TextField;
|
|
187
|
+
description: TextField;
|
|
188
|
+
image: ImageField;
|
|
189
|
+
}>;
|
|
190
|
+
};
|
|
162
191
|
|
|
163
192
|
/** An object of named values: not null, not a list. */
|
|
164
193
|
type JsonObject = Readonly<Record<string, unknown>>;
|
|
@@ -205,4 +234,4 @@ declare function slugOf(words: string): string;
|
|
|
205
234
|
/** The name of the slug of a record of the collection, if its records have one. */
|
|
206
235
|
declare function slugFieldOf(item: RecordFields): string | undefined;
|
|
207
236
|
|
|
208
|
-
export { ChoicesField, CollectionField, type CollectionRecords, Content, ContentOf, type ContentPath, FIELD_PATH_ATTRIBUTE, type FieldMarker, Fields, GroupField, ImageField, ImageValue, type JsonObject, LinkField, type LinkKind, type LinkTarget, LinkValue, MAX_SLUG_LENGTH, RECORD_ID_KEY, REVEALED_ATTRIBUTE, REVEAL_ATTRIBUTE, REVEAL_EVENT, RecordFields, SITE_CONFIG_FILE, type SiteConfig, type SiteConfigField, type SiteConfigReading, TextField, TimeField, UrlField, WEEKDAYS, collectionAt, collectionFieldAt, contactsFields, editable, findRecord, hrefOf, imagePosition, isContentObject, isJsonObject, isRecordId, isSiteId, isSlug, linkTargetOf, newRecord, openingHoursField, readSiteConfig, safeHref, seoFields, slugFieldOf, slugOf, withRecordIds };
|
|
237
|
+
export { ChoicesField, CollectionField, type CollectionRecords, Content, ContentOf, type ContentPath, FIELD_PATH_ATTRIBUTE, type FieldMarker, Fields, GroupField, ImageField, ImageValue, type JsonObject, LinkField, type LinkKind, type LinkTarget, LinkValue, MAX_SLUG_LENGTH, NumberField, RECORD_ID_KEY, REVEALED_ATTRIBUTE, REVEAL_ATTRIBUTE, REVEAL_EVENT, RecordFields, RichTextField, SITE_CONFIG_FILE, type SiteConfig, type SiteConfigField, type SiteConfigReading, SlugField, TextField, TimeField, ToggleField, UrlField, WEEKDAYS, collectionAt, collectionFieldAt, contactsFields, editable, findRecord, hrefOf, imagePosition, isContentObject, isJsonObject, isRecordId, isSiteId, isSlug, linkTargetOf, newRecord, openingHoursField, productFields, readSiteConfig, safeHref, seoFields, slugFieldOf, slugOf, withRecordIds };
|
package/dist/schema.js
CHANGED
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
openingHoursField,
|
|
50
50
|
parseContent,
|
|
51
51
|
plainTextOf,
|
|
52
|
+
productFields,
|
|
52
53
|
readFields,
|
|
53
54
|
readRichText,
|
|
54
55
|
readSiteConfig,
|
|
@@ -73,7 +74,7 @@ import {
|
|
|
73
74
|
toggle,
|
|
74
75
|
url,
|
|
75
76
|
withRecordIds
|
|
76
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-UL2C2IB2.js";
|
|
77
78
|
export {
|
|
78
79
|
FIELD_PATH_ATTRIBUTE,
|
|
79
80
|
FIELD_PATH_SEPARATOR,
|
|
@@ -125,6 +126,7 @@ export {
|
|
|
125
126
|
openingHoursField,
|
|
126
127
|
parseContent,
|
|
127
128
|
plainTextOf,
|
|
129
|
+
productFields,
|
|
128
130
|
readFields,
|
|
129
131
|
readRichText,
|
|
130
132
|
readSiteConfig,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as FieldPath, c as Field, d as CollectionField, F as Fields, G as GroupField, C as Content, e as RecordFields, f as RecordOf, g as ContentIssue } from './parse-content-
|
|
1
|
+
import { a as FieldPath, c as Field, d as CollectionField, F as Fields, G as GroupField, C as Content, e as RecordFields, f as RecordOf, g as ContentIssue } from './parse-content-Bnn6Wa-l.js';
|
|
2
2
|
|
|
3
3
|
/** What a path written on a page points at: a field, or a whole record of a collection. */
|
|
4
4
|
type FieldTarget = {
|
|
@@ -75,9 +75,20 @@ interface PlacedRecord {
|
|
|
75
75
|
readonly record: Content;
|
|
76
76
|
readonly index: number;
|
|
77
77
|
}
|
|
78
|
+
/** The pages of the records of a collection as the site renders them. */
|
|
79
|
+
interface SiteRecordPages extends SiteRecordPageDescription {
|
|
80
|
+
/**
|
|
81
|
+
* Whether the site shows the record's page; every record's when left out. The preview shows the
|
|
82
|
+
* page of every record, a hidden one too, so the owner prepares it before showing it.
|
|
83
|
+
*/
|
|
84
|
+
readonly isShown?: (record: Content) => boolean;
|
|
85
|
+
}
|
|
78
86
|
/** The pages of the records of a collection, with the address of each record's page. */
|
|
79
|
-
interface RecordPages<R> extends
|
|
80
|
-
/**
|
|
87
|
+
interface RecordPages<R> extends SiteRecordPages {
|
|
88
|
+
/**
|
|
89
|
+
* The address of the record's page: `/menu/latte`; none for a record whose page the site does
|
|
90
|
+
* not show, or with neither slug nor id.
|
|
91
|
+
*/
|
|
81
92
|
readonly pathOf: (record: R) => string | undefined;
|
|
82
93
|
}
|
|
83
94
|
/** The address of a record's page with `[record]` in place of the record. */
|
|
@@ -96,12 +107,14 @@ declare const PAGE_PATH_SEPARATOR = "/";
|
|
|
96
107
|
* A page of every record of a collection of the schema at the address with `[record]`:
|
|
97
108
|
* `recordPages(schema, { collection: "menu", path: "/menu/[record]" })`. A site gives it to
|
|
98
109
|
* `defineSeamletSite` with the component that renders a record, and links to a record's page with
|
|
99
|
-
* its `pathOf`.
|
|
110
|
+
* its `pathOf`. `shows` leaves the pages of some records off the site, such as hidden ones:
|
|
111
|
+
* `shows: (product) => !product.isHidden`.
|
|
100
112
|
*/
|
|
101
113
|
declare function recordPages<F extends Fields, const P extends CollectionPath<F>>(schema: F, options: {
|
|
102
114
|
readonly collection: P;
|
|
103
115
|
readonly path: RecordPagePath;
|
|
104
116
|
readonly searchTexts?: string;
|
|
117
|
+
readonly shows?: (record: RecordOf<RecordFieldsAt<F, P>>) => boolean;
|
|
105
118
|
}): RecordPages<RecordOf<RecordFieldsAt<F, P>>>;
|
|
106
119
|
/** Whether the path can be the address of the pages of records: `/menu/[record]`. */
|
|
107
120
|
declare function isRecordPagePath(path: unknown): path is string;
|
|
@@ -242,4 +255,4 @@ declare function checkSiteDescription(input: unknown): SiteDescriptionReading;
|
|
|
242
255
|
/** Whether the path names a group of a `title` and a `description` text. */
|
|
243
256
|
declare function isSearchTextsGroup(schema: Fields, path: string): boolean;
|
|
244
257
|
|
|
245
|
-
export {
|
|
258
|
+
export { recordPages as A, resolveFieldPath as B, type CollectionPath as C, FIELD_PATH_SEPARATOR as F, HOME_PAGE_PATH as H, PAGE_PATH_SEPARATOR as P, RECORD_PLACEHOLDER as R, type SiteDescription as S, type SiteRecordPages as a, type FieldTarget as b, type FieldsReading as c, type PageProblemReason as d, type PlacedRecord as e, type RecordFieldsAt as f, type RecordPagePath as g, type RecordPageProblemReason as h, type RecordPages as i, SITE_DESCRIPTION_PATH as j, type SchemaProblem as k, type SchemaProblemReason as l, type SiteDescriptionProblem as m, type SiteDescriptionReading as n, type SitePageDescription as o, type SiteRecordPageDescription as p, checkFields as q, checkSiteDescription as r, isRecordPagePath as s, isSearchTextsGroup as t, readFields as u, readSiteDescription as v, recordAddressOf as w, recordAt as x, recordPageAt as y, recordPagePath as z };
|
package/dist/site.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ImageMetadata } from 'astro';
|
|
2
2
|
import { AstroComponentFactory } from 'astro/runtime/server/index.js';
|
|
3
|
-
import { C as Content, F as Fields, b as ContentOf } from './parse-content-
|
|
4
|
-
import { a as
|
|
3
|
+
import { C as Content, F as Fields, b as ContentOf } from './parse-content-Bnn6Wa-l.js';
|
|
4
|
+
import { a as SiteRecordPages, S as SiteDescription } from './site-description-BnHrODQX.js';
|
|
5
5
|
|
|
6
6
|
/** A page of the site: how the editor names it, and the component that renders it. */
|
|
7
7
|
interface SeamletPage {
|
|
@@ -14,7 +14,7 @@ interface SeamletPage {
|
|
|
14
14
|
/** The pages of the records of a collection, and the component that renders each of them. */
|
|
15
15
|
interface SeamletRecordPage {
|
|
16
16
|
/** Which records have pages and where: `recordPages(schema, { collection, path })`. */
|
|
17
|
-
readonly pages:
|
|
17
|
+
readonly pages: SiteRecordPages;
|
|
18
18
|
/**
|
|
19
19
|
* A component that takes the site's content, the record and its place in its collection as its
|
|
20
20
|
* `content`, `record` and `index` props.
|
|
@@ -22,10 +22,10 @@ interface SeamletRecordPage {
|
|
|
22
22
|
readonly component: AstroComponentFactory;
|
|
23
23
|
}
|
|
24
24
|
/** What renders a page: its component, and the props to give it. */
|
|
25
|
-
|
|
25
|
+
type RenderedPage = {
|
|
26
26
|
readonly component: AstroComponentFactory;
|
|
27
27
|
readonly props: PageProps;
|
|
28
|
-
}
|
|
28
|
+
};
|
|
29
29
|
type PageProps = {
|
|
30
30
|
readonly content: Content;
|
|
31
31
|
} | {
|
|
@@ -34,12 +34,12 @@ type PageProps = {
|
|
|
34
34
|
readonly index: number;
|
|
35
35
|
};
|
|
36
36
|
/** A page that `getStaticPaths` of a site's `[...page]` route builds. */
|
|
37
|
-
|
|
37
|
+
type StaticPage = {
|
|
38
38
|
readonly params: {
|
|
39
39
|
readonly page: string | undefined;
|
|
40
40
|
};
|
|
41
41
|
readonly props: RenderedPage;
|
|
42
|
-
}
|
|
42
|
+
};
|
|
43
43
|
|
|
44
44
|
/** The site's content and pages; its id and title come from `seamlet.json`. */
|
|
45
45
|
interface SeamletSiteDefinition<F extends Fields> {
|
|
@@ -72,8 +72,13 @@ interface SeamletSite<F extends Fields = Fields> {
|
|
|
72
72
|
* first page, `menu/latte` the page of the record at /menu/latte. Undefined when there is none.
|
|
73
73
|
*/
|
|
74
74
|
readonly pageOf: (rest: string | undefined, content: ContentOf<F>) => RenderedPage | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* What the preview renders at the rest of an address with the content: as `pageOf`, and the page
|
|
77
|
+
* of a record the site does not show, so the owner prepares it in the editor.
|
|
78
|
+
*/
|
|
79
|
+
readonly previewPageOf: (rest: string | undefined, content: ContentOf<F>) => RenderedPage | undefined;
|
|
75
80
|
/** Every page of the site with the content, for `getStaticPaths` of a `[...page]` route. */
|
|
76
|
-
readonly staticPaths: (content: ContentOf<F>) =>
|
|
81
|
+
readonly staticPaths: (content: ContentOf<F>) => StaticPage[];
|
|
77
82
|
/** What the CMS published: the site's initial content until the first publication. */
|
|
78
83
|
readonly loadPublishedContent: () => Promise<ContentOf<F>>;
|
|
79
84
|
/** The site's own photo at an address its content gives it, if it has one there. */
|
package/dist/site.js
CHANGED
|
@@ -3,14 +3,15 @@ import {
|
|
|
3
3
|
} from "./chunk-QCVWHHJC.js";
|
|
4
4
|
import {
|
|
5
5
|
pagePathOf,
|
|
6
|
+
previewedPageAt,
|
|
6
7
|
renderedPageAt,
|
|
7
8
|
staticPagesOf
|
|
8
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-HFPZVDST.js";
|
|
9
10
|
import {
|
|
10
11
|
checkSiteDescription,
|
|
11
12
|
formatFieldPath,
|
|
12
13
|
parseContent
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-UL2C2IB2.js";
|
|
14
15
|
|
|
15
16
|
// src/site.ts
|
|
16
17
|
import { cmsOrigin, siteId, siteTitle } from "virtual:seamlet/config";
|
|
@@ -173,6 +174,7 @@ function defineSeamletSite(definition) {
|
|
|
173
174
|
return page?.component;
|
|
174
175
|
},
|
|
175
176
|
pageOf: (rest, content) => renderedPageAt(sitePages, pagePathOf(rest), contentOf(content)),
|
|
177
|
+
previewPageOf: (rest, content) => previewedPageAt(sitePages, pagePathOf(rest), contentOf(content)),
|
|
176
178
|
staticPaths: (content) => staticPagesOf(sitePages, contentOf(content)),
|
|
177
179
|
loadPublishedContent: () => loadPublishedContent(definition.schema),
|
|
178
180
|
ownPhotoAt: (src) => definition.photos?.(src),
|
package/package.json
CHANGED
package/routes/preview.astro
CHANGED
|
@@ -38,7 +38,7 @@ const content =
|
|
|
38
38
|
)
|
|
39
39
|
: parseContent(site.schema, reading.draft).content;
|
|
40
40
|
|
|
41
|
-
const page = site.
|
|
41
|
+
const page = site.previewPageOf(rest, content);
|
|
42
42
|
if (page === undefined) {
|
|
43
43
|
return new Response(null, { status: NOT_FOUND, headers });
|
|
44
44
|
}
|