caracms 0.4.0 → 0.5.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/README.md +14 -0
- package/package.json +1 -1
- package/src/cli/validate.ts +53 -3
- package/src/content-schema.ts +1 -0
- package/src/content.ts +41 -20
- package/src/document.ts +5 -2
- package/src/editor/README.md +3 -0
- package/src/editor/addresses.ts +6 -1
- package/src/editor/client/arrange/ArrangeStage.tsx +629 -0
- package/src/editor/client/arrange/model.ts +659 -0
- package/src/editor/client/arrange/store.ts +335 -0
- package/src/editor/client/documents/actions.ts +14 -3
- package/src/editor/client/documents/dialogs.tsx +33 -3
- package/src/editor/client/editor.ts +56 -5
- package/src/editor/client/pane/Pane.tsx +3 -0
- package/src/editor/client/pane/levels/ArrangeLevel.tsx +342 -0
- package/src/editor/client/pane/levels/DocumentsLevel.tsx +10 -0
- package/src/editor/client/shell/Stage.tsx +8 -4
- package/src/editor/routes/admin.astro +1 -1
- package/src/editor/routes/arrange.ts +17 -0
- package/src/editor/server/admin-props.ts +5 -3
- package/src/editor/server/arrange.ts +245 -0
- package/src/editor/server/drafts-store.ts +34 -4
- package/src/editor/server/move.ts +41 -7
- package/src/editor/styles/levels/arrange.css +152 -0
- package/src/editor/types.ts +52 -2
- package/src/index.ts +45 -3
- package/src/live/drafts-store.ts +62 -4
- package/src/live/editor.ts +4 -0
- package/src/page-order.ts +253 -0
- package/src/redirects.ts +39 -7
- package/src/reserved.ts +3 -2
- package/src/serialize.ts +17 -0
package/src/serialize.ts
CHANGED
|
@@ -57,6 +57,7 @@ import {
|
|
|
57
57
|
import { fieldToJson, isEmptyValue, parseField, type Field, type Fields } from './fields.ts';
|
|
58
58
|
import { mediaLine } from './media-value.ts';
|
|
59
59
|
import { parseRedirects } from './redirects.ts';
|
|
60
|
+
import { parsePageOrder } from './page-order.ts';
|
|
60
61
|
import { member, parseSource, slice, type ArrayNode, type JsonNode, type MemberNode, type ObjectNode, type ParsedSource } from './json-source.ts';
|
|
61
62
|
import { isEmptySeo, parseFormRecipients, parseGoogleTag, parseSeo, seoText, type Seo } from './seo.ts';
|
|
62
63
|
import { SCHEMA_KEY } from './schema-key.ts';
|
|
@@ -384,6 +385,18 @@ const redirectsCodec: KeyCodec = {
|
|
|
384
385
|
removeWhenEmpty: true,
|
|
385
386
|
};
|
|
386
387
|
|
|
388
|
+
/** Arrange pages (Decision 6): the saved order, one parent's list per line. */
|
|
389
|
+
const pageOrderCodec: KeyCodec = {
|
|
390
|
+
parse: parsePageOrder,
|
|
391
|
+
text: (v, depth) => {
|
|
392
|
+
const entries = Object.entries(parsePageOrder(v));
|
|
393
|
+
if (entries.length === 0) return '{}';
|
|
394
|
+
return `{\n${entries.map(([k, list]) => `${pad(depth + 1)}${JSON.stringify(k)}: [${list.map((s) => JSON.stringify(s)).join(', ')}]`).join(',\n')}\n${pad(depth)}}`;
|
|
395
|
+
},
|
|
396
|
+
empty: (v) => Object.keys(parsePageOrder(v)).length === 0,
|
|
397
|
+
removeWhenEmpty: true,
|
|
398
|
+
};
|
|
399
|
+
|
|
387
400
|
const fieldCodec = (field: Field): KeyCodec => ({
|
|
388
401
|
parse: (raw) => parseField(field, raw),
|
|
389
402
|
text: (value, depth) => fieldText(field, value, depth),
|
|
@@ -419,6 +432,7 @@ function codecsFor(collection: Pick<ResolvedCollection, 'kind' | 'fields'>): Map
|
|
|
419
432
|
codecs.set('googleTag', googleTagCodec);
|
|
420
433
|
codecs.set('formRecipients', recipientsCodec);
|
|
421
434
|
codecs.set('redirects', redirectsCodec);
|
|
435
|
+
codecs.set('pageOrder', pageOrderCodec);
|
|
422
436
|
}
|
|
423
437
|
for (const [key, field] of Object.entries(collection.fields ?? ({} as Fields))) codecs.set(key, fieldCodec(field));
|
|
424
438
|
return codecs;
|
|
@@ -692,6 +706,9 @@ export function savedForm(text: string, collection: Pick<ResolvedCollection, 'ki
|
|
|
692
706
|
// brandCodec: logo and icon on one line each; redirectsCodec: one redirect per line.
|
|
693
707
|
keys.set('brand', { kind: 'object', keys: new Map([['logo', INLINE], ['icon', INLINE]]) });
|
|
694
708
|
keys.set('redirects', { kind: 'list', item: INLINE });
|
|
709
|
+
// pageOrderCodec: one parent's list per line.
|
|
710
|
+
const order = (raw as Record<string, unknown>).pageOrder;
|
|
711
|
+
if (order && typeof order === 'object' && !Array.isArray(order)) keys.set('pageOrder', { kind: 'object', keys: new Map(Object.keys(order).map((k) => [k, INLINE])) });
|
|
695
712
|
}
|
|
696
713
|
return `${layout(raw, { kind: 'object', keys }, 0)}\n`;
|
|
697
714
|
}
|