create-cogenta 0.5.2 → 0.6.7
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/dist/blueprint-defaults.js +1 -1
- package/dist/blueprint-defaults.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/playground-reset.js +1 -1
- package/dist/playground-reset.js.map +1 -1
- package/dist/recap.js +1 -1
- package/dist/recap.js.map +1 -1
- package/dist/scaffold.d.ts +4 -2
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +10 -6
- package/dist/scaffold.js.map +1 -1
- package/dist/wizard.js +1 -1
- package/dist/wizard.js.map +1 -1
- package/package.json +14 -13
- package/dist/blueprints/assets/photos/association/community-cleanup.jpg +0 -0
- package/dist/blueprints/assets/photos/association/fundraising-dinner.jpg +0 -0
- package/dist/blueprints/assets/photos/association/garden-planting.jpg +0 -0
- package/dist/blueprints/assets/photos/association/harvest-food-drive.jpg +0 -0
- package/dist/blueprints/assets/photos/association/hero.jpg +0 -0
- package/dist/blueprints/assets/photos/association/volunteer-orientation.jpg +0 -0
- package/dist/blueprints/assets/photos/association/winter-coat-collection.jpg +0 -0
- package/dist/blueprints/assets/photos/blog/blog-runs-itself.jpg +0 -0
- package/dist/blueprints/assets/photos/blog/desk-setup.jpg +0 -0
- package/dist/blueprints/assets/photos/blog/editing.jpg +0 -0
- package/dist/blueprints/assets/photos/blog/hero.jpg +0 -0
- package/dist/blueprints/assets/photos/blog/notebooks.jpg +0 -0
- package/dist/blueprints/assets/photos/blog/plain-text-editor.jpg +0 -0
- package/dist/blueprints/assets/photos/blog/reading-nonfiction.jpg +0 -0
- package/dist/blueprints/assets/photos/blog/small-tool.jpg +0 -0
- package/dist/blueprints/assets/photos/blog/writing-schedule.jpg +0 -0
- package/dist/blueprints/assets/photos/magazine/business-2.jpg +0 -0
- package/dist/blueprints/assets/photos/magazine/business-3.jpg +0 -0
- package/dist/blueprints/assets/photos/magazine/business.jpg +0 -0
- package/dist/blueprints/assets/photos/magazine/culture-2.jpg +0 -0
- package/dist/blueprints/assets/photos/magazine/culture-3.jpg +0 -0
- package/dist/blueprints/assets/photos/magazine/culture.jpg +0 -0
- package/dist/blueprints/assets/photos/magazine/news-2.jpg +0 -0
- package/dist/blueprints/assets/photos/magazine/news-3.jpg +0 -0
- package/dist/blueprints/assets/photos/magazine/news.jpg +0 -0
- package/dist/blueprints/assets/photos/magazine/opinion-2.jpg +0 -0
- package/dist/blueprints/assets/photos/magazine/opinion-3.jpg +0 -0
- package/dist/blueprints/assets/photos/magazine/opinion.jpg +0 -0
- package/dist/blueprints/assets/photos/portfolio/adatum-publishing.jpg +0 -0
- package/dist/blueprints/assets/photos/portfolio/contoso-mobile-app.jpg +0 -0
- package/dist/blueprints/assets/photos/portfolio/fabrikam-annual-report.jpg +0 -0
- package/dist/blueprints/assets/photos/portfolio/hero.jpg +0 -0
- package/dist/blueprints/assets/photos/portfolio/litware-signage.jpg +0 -0
- package/dist/blueprints/assets/photos/portfolio/northwind-rebrand.jpg +0 -0
- package/dist/blueprints/assets/photos/portfolio/proseware-launch.jpg +0 -0
- package/dist/blueprints/assets/photos/portfolio/tailspin-streaming.jpg +0 -0
- package/dist/blueprints/assets/photos/portfolio/wingtip-wayfinding.jpg +0 -0
- package/dist/blueprints/assets/photos/restaurant/charred-octopus.jpg +0 -0
- package/dist/blueprints/assets/photos/restaurant/chocolate-tart.jpg +0 -0
- package/dist/blueprints/assets/photos/restaurant/creme-brulee.jpg +0 -0
- package/dist/blueprints/assets/photos/restaurant/hero.jpg +0 -0
- package/dist/blueprints/assets/photos/restaurant/house-red.jpg +0 -0
- package/dist/blueprints/assets/photos/restaurant/house-white.jpg +0 -0
- package/dist/blueprints/assets/photos/restaurant/pan-seared-trout.jpg +0 -0
- package/dist/blueprints/assets/photos/restaurant/poached-pear.jpg +0 -0
- package/dist/blueprints/assets/photos/restaurant/roasted-beet-salad.jpg +0 -0
- package/dist/blueprints/assets/photos/restaurant/slow-roast-duck-leg.jpg +0 -0
- package/dist/blueprints/assets/photos/restaurant/soup-of-the-day.jpg +0 -0
- package/dist/blueprints/assets/photos/restaurant/sparkling-water.jpg +0 -0
- package/dist/blueprints/assets/photos/restaurant/wild-mushroom-risotto.jpg +0 -0
- package/dist/blueprints/assets/photos/saas/avatar-1.jpg +0 -0
- package/dist/blueprints/assets/photos/saas/hero.jpg +0 -0
- package/dist/blueprints/assets/photos/store/camp-blanket.jpg +0 -0
- package/dist/blueprints/assets/photos/store/canvas-tote.jpg +0 -0
- package/dist/blueprints/assets/photos/store/cast-iron-skillet.jpg +0 -0
- package/dist/blueprints/assets/photos/store/ceramic-pour-over-set.jpg +0 -0
- package/dist/blueprints/assets/photos/store/enamel-mug.jpg +0 -0
- package/dist/blueprints/assets/photos/store/everyday-tee.jpg +0 -0
- package/dist/blueprints/assets/photos/store/field-jacket.jpg +0 -0
- package/dist/blueprints/assets/photos/store/hero.jpg +0 -0
- package/dist/blueprints/assets/photos/store/leather-card-holder.jpg +0 -0
- package/dist/blueprints/assets/photos/store/linen-table-runner.jpg +0 -0
- package/dist/blueprints/assets/photos/store/trail-tote.jpg +0 -0
- package/dist/blueprints/assets/photos/store/wool-beanie.jpg +0 -0
- package/dist/blueprints/assets/photos/store/wool-overshirt.jpg +0 -0
- package/dist/blueprints/assets/photos/vitrine/avatar-1.jpg +0 -0
- package/dist/blueprints/assets/photos/vitrine/avatar-2.jpg +0 -0
- package/dist/blueprints/assets/photos/vitrine/avatar-3.jpg +0 -0
- package/dist/blueprints/assets/photos/vitrine/dashboard.jpg +0 -0
- package/dist/blueprints/assets/photos/vitrine/hero.jpg +0 -0
- package/dist/blueprints/association.d.ts +0 -151
- package/dist/blueprints/association.d.ts.map +0 -1
- package/dist/blueprints/association.js +0 -732
- package/dist/blueprints/association.js.map +0 -1
- package/dist/blueprints/blog.d.ts +0 -198
- package/dist/blueprints/blog.d.ts.map +0 -1
- package/dist/blueprints/blog.js +0 -665
- package/dist/blueprints/blog.js.map +0 -1
- package/dist/blueprints/content-pack.d.ts +0 -143
- package/dist/blueprints/content-pack.d.ts.map +0 -1
- package/dist/blueprints/content-pack.js +0 -111
- package/dist/blueprints/content-pack.js.map +0 -1
- package/dist/blueprints/content-packs.d.ts +0 -11
- package/dist/blueprints/content-packs.d.ts.map +0 -1
- package/dist/blueprints/content-packs.js +0 -29
- package/dist/blueprints/content-packs.js.map +0 -1
- package/dist/blueprints/demo-media.d.ts +0 -39
- package/dist/blueprints/demo-media.d.ts.map +0 -1
- package/dist/blueprints/demo-media.js +0 -30
- package/dist/blueprints/demo-media.js.map +0 -1
- package/dist/blueprints/documentation.d.ts +0 -134
- package/dist/blueprints/documentation.d.ts.map +0 -1
- package/dist/blueprints/documentation.js +0 -678
- package/dist/blueprints/documentation.js.map +0 -1
- package/dist/blueprints/magazine.d.ts +0 -145
- package/dist/blueprints/magazine.d.ts.map +0 -1
- package/dist/blueprints/magazine.js +0 -543
- package/dist/blueprints/magazine.js.map +0 -1
- package/dist/blueprints/menus.d.ts +0 -25
- package/dist/blueprints/menus.d.ts.map +0 -1
- package/dist/blueprints/menus.js +0 -33
- package/dist/blueprints/menus.js.map +0 -1
- package/dist/blueprints/photo-assets.d.ts +0 -3
- package/dist/blueprints/photo-assets.d.ts.map +0 -1
- package/dist/blueprints/photo-assets.js +0 -33
- package/dist/blueprints/photo-assets.js.map +0 -1
- package/dist/blueprints/portfolio.d.ts +0 -141
- package/dist/blueprints/portfolio.d.ts.map +0 -1
- package/dist/blueprints/portfolio.js +0 -700
- package/dist/blueprints/portfolio.js.map +0 -1
- package/dist/blueprints/restaurant.d.ts +0 -124
- package/dist/blueprints/restaurant.d.ts.map +0 -1
- package/dist/blueprints/restaurant.js +0 -457
- package/dist/blueprints/restaurant.js.map +0 -1
- package/dist/blueprints/saas.d.ts +0 -133
- package/dist/blueprints/saas.d.ts.map +0 -1
- package/dist/blueprints/saas.js +0 -551
- package/dist/blueprints/saas.js.map +0 -1
- package/dist/blueprints/site-settings-seed.d.ts +0 -17
- package/dist/blueprints/site-settings-seed.d.ts.map +0 -1
- package/dist/blueprints/site-settings-seed.js +0 -45
- package/dist/blueprints/site-settings-seed.js.map +0 -1
- package/dist/blueprints/starting-skins.d.ts +0 -19
- package/dist/blueprints/starting-skins.d.ts.map +0 -1
- package/dist/blueprints/starting-skins.js +0 -301
- package/dist/blueprints/starting-skins.js.map +0 -1
- package/dist/blueprints/store.d.ts +0 -173
- package/dist/blueprints/store.d.ts.map +0 -1
- package/dist/blueprints/store.js +0 -643
- package/dist/blueprints/store.js.map +0 -1
- package/dist/blueprints/vitrine.d.ts +0 -178
- package/dist/blueprints/vitrine.d.ts.map +0 -1
- package/dist/blueprints/vitrine.js +0 -529
- package/dist/blueprints/vitrine.js.map +0 -1
- package/dist/demo-art/compositions.d.ts +0 -48
- package/dist/demo-art/compositions.d.ts.map +0 -1
- package/dist/demo-art/compositions.js +0 -690
- package/dist/demo-art/compositions.js.map +0 -1
- package/dist/demo-art/index.d.ts +0 -8
- package/dist/demo-art/index.d.ts.map +0 -1
- package/dist/demo-art/index.js +0 -5
- package/dist/demo-art/index.js.map +0 -1
- package/dist/demo-art/oklch.d.ts +0 -39
- package/dist/demo-art/oklch.d.ts.map +0 -1
- package/dist/demo-art/oklch.js +0 -79
- package/dist/demo-art/oklch.js.map +0 -1
- package/dist/demo-art/png.d.ts +0 -24
- package/dist/demo-art/png.d.ts.map +0 -1
- package/dist/demo-art/png.js +0 -110
- package/dist/demo-art/png.js.map +0 -1
- package/dist/demo-art/render.d.ts +0 -228
- package/dist/demo-art/render.d.ts.map +0 -1
- package/dist/demo-art/render.js +0 -478
- package/dist/demo-art/render.js.map +0 -1
|
@@ -1,678 +0,0 @@
|
|
|
1
|
-
import { CogentaError } from '@cogenta/core';
|
|
2
|
-
import { createContentStore, defineCollection, f, validateCollectionSet, } from '@cogenta/schema';
|
|
3
|
-
import { coverArt } from '../demo-art/compositions.js';
|
|
4
|
-
import { definePageCollection, richTextParagraph, SEO_FIELDS, toBlockZoneEntry, } from './content-pack.js';
|
|
5
|
-
import { STARTING_SKINS } from './starting-skins.js';
|
|
6
|
-
/**
|
|
7
|
-
* The `documentation` blueprint's content model (L9 task 8, batch A;
|
|
8
|
-
* rebuilt for L25 task Phase 1 — `theme-docs`): reference material, not
|
|
9
|
-
* marketing — the "page types" are `doc_page` entries themselves (ordered,
|
|
10
|
-
* grouped into sections), rather than a generic block-composed page for
|
|
11
|
-
* each one. A single `page` entry (`home`) still exists so the site root
|
|
12
|
-
* works and links into the docs, exactly like every other blueprint's
|
|
13
|
-
* landing page.
|
|
14
|
-
*
|
|
15
|
-
* `body: f.blocks()`, not `f.richText()`: a doc page's own content is a
|
|
16
|
-
* block zone like `page.blocks`, whose *first* block is always the
|
|
17
|
-
* `collectionList` `@cogenta/theme-docs` reads as the left-hand sidebar
|
|
18
|
-
* (`section`/`order`, plain fields — neither is a valid
|
|
19
|
-
* `collectionList.sort.field`, so the theme groups and re-sorts the
|
|
20
|
-
* already-fetched slice itself; see the theme's own `render-block.ts`).
|
|
21
|
-
* Everything after that first block is ordinary prose.
|
|
22
|
-
*/
|
|
23
|
-
export const docPage = defineCollection({
|
|
24
|
-
name: 'doc_page',
|
|
25
|
-
labels: { singular: 'Doc page', plural: 'Doc pages' },
|
|
26
|
-
routing: { pattern: '/docs/:slug' },
|
|
27
|
-
fields: {
|
|
28
|
-
title: f.text({ required: true, max: 200 }),
|
|
29
|
-
slug: f.slug({ from: 'title', unique: true }),
|
|
30
|
-
section: f.text({ required: true, max: 80 }),
|
|
31
|
-
order: f.number({ required: true, integer: true, min: 0 }),
|
|
32
|
-
body: f.blocks({ required: true }),
|
|
33
|
-
...SEO_FIELDS,
|
|
34
|
-
},
|
|
35
|
-
indexes: [['slug'], ['section']],
|
|
36
|
-
permissions: {
|
|
37
|
-
read: ['public'],
|
|
38
|
-
create: ['editor', 'admin'],
|
|
39
|
-
update: ['editor', 'admin'],
|
|
40
|
-
delete: ['admin'],
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
export const page = definePageCollection('/:slug');
|
|
44
|
-
export const DOCUMENTATION_COLLECTIONS = [docPage, page];
|
|
45
|
-
validateCollectionSet(DOCUMENTATION_COLLECTIONS);
|
|
46
|
-
const BLOCK_VERSION = '1.0.0';
|
|
47
|
-
// --------------------------------------------------------------------------
|
|
48
|
-
// Rich-text helpers. Contract A's rich-text schema (`@cogenta/schema`,
|
|
49
|
-
// frozen) has no fenced "code block" node and no table — the closed
|
|
50
|
-
// vocabulary is `block` (styles `normal`/`h2`/`h3`/`h4`/`blockquote`, plus
|
|
51
|
-
// list items), `media` and `hr`. `codeBlock` below produces the one shape
|
|
52
|
-
// `@cogenta/theme-docs`'s `prose.ts` recognises and promotes to a real
|
|
53
|
-
// `<pre><code>` — a paragraph whose only span carries the `code` mark.
|
|
54
|
-
// Where the brief asks for "a table", a definition-style bullet list
|
|
55
|
-
// (`term — description`) is the honest equivalent this schema can express;
|
|
56
|
-
// see the CLI/config reference pages below.
|
|
57
|
-
// --------------------------------------------------------------------------
|
|
58
|
-
function heading(key, level, text) {
|
|
59
|
-
return {
|
|
60
|
-
_key: key,
|
|
61
|
-
_type: 'block',
|
|
62
|
-
style: level,
|
|
63
|
-
children: [{ _key: `${key}-span`, _type: 'span', text, marks: [] }],
|
|
64
|
-
markDefs: [],
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
function paragraph(key, text) {
|
|
68
|
-
return {
|
|
69
|
-
_key: key,
|
|
70
|
-
_type: 'block',
|
|
71
|
-
style: 'normal',
|
|
72
|
-
children: [{ _key: `${key}-span`, _type: 'span', text, marks: [] }],
|
|
73
|
-
markDefs: [],
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
function codeBlock(key, code) {
|
|
77
|
-
return {
|
|
78
|
-
_key: key,
|
|
79
|
-
_type: 'block',
|
|
80
|
-
style: 'normal',
|
|
81
|
-
children: [{ _key: `${key}-span`, _type: 'span', text: code, marks: ['code'] }],
|
|
82
|
-
markDefs: [],
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
function bulletList(keyPrefix, items) {
|
|
86
|
-
return items.map((text, index) => ({
|
|
87
|
-
_key: `${keyPrefix}-${index}`,
|
|
88
|
-
_type: 'block',
|
|
89
|
-
style: 'normal',
|
|
90
|
-
listItem: 'bullet',
|
|
91
|
-
level: 1,
|
|
92
|
-
children: [{ _key: `${keyPrefix}-${index}-span`, _type: 'span', text, marks: [] }],
|
|
93
|
-
markDefs: [],
|
|
94
|
-
}));
|
|
95
|
-
}
|
|
96
|
-
function proseBlock(key, body) {
|
|
97
|
-
return { _key: key, _type: 'prose', _version: BLOCK_VERSION, body };
|
|
98
|
-
}
|
|
99
|
-
/** The sidebar `collectionList`, identical on every doc page — `@cogenta/theme-docs` detects it by being the page's own first block, on the `doc_page` collection. */
|
|
100
|
-
function sidebarBlock(key) {
|
|
101
|
-
return {
|
|
102
|
-
_key: key,
|
|
103
|
-
_type: 'collectionList',
|
|
104
|
-
_version: BLOCK_VERSION,
|
|
105
|
-
collection: 'doc_page',
|
|
106
|
-
sort: { field: 'createdAt', direction: 'asc' },
|
|
107
|
-
limit: 100,
|
|
108
|
-
layout: 'list',
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Ten real, technical doc pages across three sections — the exact shape the
|
|
113
|
-
* brief asks for: headings, code blocks, lists, and (where a real table
|
|
114
|
-
* would go) a definition-style list, credible enough to read as an actual
|
|
115
|
-
* getting-started guide rather than placeholder copy.
|
|
116
|
-
*/
|
|
117
|
-
export const DOCUMENTATION_DEMO_DOC_PAGES = [
|
|
118
|
-
{
|
|
119
|
-
title: 'Introduction',
|
|
120
|
-
slug: 'introduction',
|
|
121
|
-
section: 'Getting started',
|
|
122
|
-
order: 1,
|
|
123
|
-
body: [
|
|
124
|
-
paragraph('intro-p1', 'Cogenta is an agentic, open-source CMS: a runtime for content, a runtime for agents, and the wiring between them, in one project. Most content management systems bolt an "AI assistant" onto an otherwise ordinary editing screen. Cogenta starts from the other direction — the multi-agent runtime is part of the core, not a plugin, so a site can read its own traffic, propose a fix, and apply it once you say yes.'),
|
|
125
|
-
heading('intro-h1', 'h2', "What's in the box"),
|
|
126
|
-
...bulletList('intro-list', [
|
|
127
|
-
'A schema-driven content model — collections, fields, permissions, versioning, drafts and a real trash can, not a soft flag.',
|
|
128
|
-
'A theme layer with zero client JavaScript by default — every page you are reading right now is plain HTML and CSS, except for the one small script that remembers whether you prefer light or dark mode.',
|
|
129
|
-
'A multi-agent runtime that can read, propose and — with your explicit consent — apply changes to the site: rewriting a broken redirect, drafting release notes, or flagging a page that has drifted out of date.',
|
|
130
|
-
'A REST and GraphQL API generated from the same schema an editor sees in the admin — no second definition to keep in sync.',
|
|
131
|
-
]),
|
|
132
|
-
paragraph('intro-p2', 'This site is itself a demo, scaffolded by create-cogenta from the "documentation" blueprint. Every page below is real, published content in a real database — edit it like any other entry, delete it, or add ten more sections next to it.'),
|
|
133
|
-
heading('intro-h2', 'h2', 'How this documentation is organised'),
|
|
134
|
-
paragraph('intro-p3', 'Three sections, left to right in the sidebar: "Getting started" gets a new site running end to end, "Guides" covers the decisions you make once a site exists — deployment, content modelling, theming, plugins — and "Reference" is the material you come back to and skim rather than read start to finish: every CLI command, every configuration key, every HTTP endpoint.'),
|
|
135
|
-
paragraph('intro-p4', 'If you only read one more page, make it "Content model" — nearly everything else in Cogenta, from permissions to the theme layer to the agent runtime, is built on top of the same collection-and-field vocabulary it describes.'),
|
|
136
|
-
],
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
title: 'Installation',
|
|
140
|
-
slug: 'installation',
|
|
141
|
-
section: 'Getting started',
|
|
142
|
-
order: 2,
|
|
143
|
-
body: [
|
|
144
|
-
paragraph('install-p1', 'A new site starts from one command:'),
|
|
145
|
-
codeBlock('install-code1', 'npm create cogenta my-site\ncd my-site\nnpm run dev'),
|
|
146
|
-
paragraph('install-p1b', 'The installer asks a short series of questions — site name, default language, database, and (optionally) a starting template — then writes a runnable project. Answer with defaults throughout and you still get a working site: every question has one.'),
|
|
147
|
-
heading('install-h1', 'h2', 'Requirements'),
|
|
148
|
-
...bulletList('install-req', [
|
|
149
|
-
'Node.js — the current LTS or newer',
|
|
150
|
-
'A database — SQLite (default, zero setup), PostgreSQL, or MySQL/MariaDB',
|
|
151
|
-
'No other service is required to start — no Redis, no queue, no object storage; Cogenta degrades to a file-backed implementation of each until you configure the real thing',
|
|
152
|
-
]),
|
|
153
|
-
heading('install-h2', 'h2', 'What gets created'),
|
|
154
|
-
paragraph('install-p2', 'The installer writes a schema file (cogenta.schema.mjs), a starting skin, a .env with a freshly generated signing key, and — if you chose a template — demo content you can delete at any time. Nothing is published on your behalf: demo entries seeded by a template start as drafts unless the template says otherwise.'),
|
|
155
|
-
heading('install-h3', 'h2', 'Starting from a document instead'),
|
|
156
|
-
paragraph('install-p3', 'The installer can also read a real brief — a product spec, a set of notes, a PDF — and propose a content model and a page plan from it. Nothing is written to disk until you accept each proposed piece individually; declining all of them leaves you with exactly the site the ordinary wizard would have produced.'),
|
|
157
|
-
heading('install-h4', 'h2', 'Troubleshooting a first run'),
|
|
158
|
-
...bulletList('install-trouble', [
|
|
159
|
-
'SCHEMA_INVALID on first start — the schema file failed to load; run cogenta doctor to see which collection or field it rejected and why',
|
|
160
|
-
'COGENTA_AUTH_SIGNING_KEY is not set — the .env file was not loaded; confirm it sits next to cogenta.config.mjs',
|
|
161
|
-
'A blank homepage — most blueprints publish their landing page under the slug "home"; confirm at least one page entry with that slug is published',
|
|
162
|
-
]),
|
|
163
|
-
],
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
title: 'Configuration',
|
|
167
|
-
slug: 'configuration',
|
|
168
|
-
section: 'Getting started',
|
|
169
|
-
order: 3,
|
|
170
|
-
body: [
|
|
171
|
-
paragraph('config-p1', 'A site is configured by cogenta.config.mjs at the project root, loaded once at startup. There is deliberately no second place to configure a running site — no database table of settings that can drift from what is checked into version control alongside the code that depends on it.'),
|
|
172
|
-
codeBlock('config-code1', "export default {\n site: { name: 'My site', url: 'https://example.com' },\n database: { driver: 'sqlite' },\n}"),
|
|
173
|
-
heading('config-h1', 'h2', 'Commonly changed options'),
|
|
174
|
-
...bulletList('config-list', [
|
|
175
|
-
'site.name and site.url — used across SEO tags, the sitemap, and Open Graph metadata',
|
|
176
|
-
'database.driver — sqlite, postgres, or mysql',
|
|
177
|
-
'security.pageMaxAge — the public cache lifetime for a rendered page, in seconds',
|
|
178
|
-
'security.cors — disabled by default; an explicit allow-list turns it on for a headless front end on another origin',
|
|
179
|
-
'security.hstsMaxAge — off by default on purpose: a bad value here can lock visitors out of your site over plain HTTP for up to a year',
|
|
180
|
-
]),
|
|
181
|
-
heading('config-h2', 'h2', 'A fuller example'),
|
|
182
|
-
codeBlock('config-code2', "export default {\n site: { name: 'My site', url: 'https://example.com' },\n database: { driver: 'postgres', url: process.env.DATABASE_URL },\n storage: { driver: 'auto', path: './.cogenta/media' },\n security: {\n pageMaxAge: 300,\n cors: { origins: ['https://app.example.com'] },\n },\n}"),
|
|
183
|
-
heading('config-h3', 'h2', 'Config file versus environment variables'),
|
|
184
|
-
paragraph('config-p2', 'Every secret — a database password, an LLM provider key, the signing key itself — is read from the environment, never written into cogenta.config.mjs. Everything else that describes the shape of the site (its name, its cache lifetime, which optional features are on) belongs in the config file, where it is reviewable in a diff like any other code change.'),
|
|
185
|
-
],
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
title: 'Deploying to production',
|
|
189
|
-
slug: 'deploying-to-production',
|
|
190
|
-
section: 'Guides',
|
|
191
|
-
order: 1,
|
|
192
|
-
body: [
|
|
193
|
-
paragraph('deploy-p1', 'A production deploy is the same site, run with a real database and a signing key that never changes between restarts. There is no separate "build for production" artifact to keep in sync with the project — cogenta serve is the one code path that renders every page, in development and in production alike.'),
|
|
194
|
-
heading('deploy-h1', 'h2', 'Steps'),
|
|
195
|
-
...bulletList('deploy-list', [
|
|
196
|
-
'Set COGENTA_AUTH_SIGNING_KEY to a stable, secret value — generate one with openssl rand -base64 32 and store it in your host’s secret manager, never in a committed file',
|
|
197
|
-
'Point database.url at your production database',
|
|
198
|
-
'Run cogenta migrate once, before the first request — an unapplied migration is a startup error, not a silent gap',
|
|
199
|
-
'Start the server with cogenta serve',
|
|
200
|
-
'Put a process manager or your platform’s own supervisor in front of it, so a crash restarts the process rather than taking the site down until someone notices',
|
|
201
|
-
]),
|
|
202
|
-
codeBlock('deploy-code1', 'cogenta migrate\ncogenta serve --port 3000'),
|
|
203
|
-
heading('deploy-h2', 'h2', 'Environment variables'),
|
|
204
|
-
paragraph('deploy-p2', 'Every secret is read from the environment, never written to a config file that could end up in version control. At minimum, a production deploy needs COGENTA_AUTH_SIGNING_KEY and, for anything but SQLite, DATABASE_URL — an LLM provider key is optional and only needed if you plan to run an agent.'),
|
|
205
|
-
heading('deploy-h3', 'h2', 'Zero-downtime restarts'),
|
|
206
|
-
paragraph('deploy-p3', 'cogenta serve refuses new connections and waits for in-flight requests to finish before exiting on SIGTERM, which is what lets a rolling restart behind a load balancer avoid dropping a request mid-flight. It never runs a schema migration on its own — cogenta migrate is always a separate, explicit step, so a deploy that skips it fails loudly instead of starting against a database it does not recognise.'),
|
|
207
|
-
heading('deploy-h4', 'h2', 'Health checks'),
|
|
208
|
-
paragraph('deploy-p4', 'GET /api/health returns 200 once the database connection is live and the schema has loaded — point your platform’s liveness probe at it rather than at the homepage, which also depends on content actually being published.'),
|
|
209
|
-
],
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
title: 'Content model',
|
|
213
|
-
slug: 'content-model',
|
|
214
|
-
section: 'Guides',
|
|
215
|
-
order: 2,
|
|
216
|
-
body: [
|
|
217
|
-
paragraph('model-p1', 'A collection is a TypeScript declaration: a name, a set of fields, and who may read, create, update, delete and publish it. Every REST route, every GraphQL type, every admin screen, and every permission check in Cogenta is generated from this one declaration — there is no second schema to keep in sync by hand.'),
|
|
218
|
-
codeBlock('model-code1', "export const article = defineCollection({\n name: 'article',\n fields: {\n title: f.text({ required: true }),\n body: f.richText(),\n },\n})"),
|
|
219
|
-
heading('model-h1', 'h2', 'Field kinds'),
|
|
220
|
-
...bulletList('model-list', [
|
|
221
|
-
'text, richText, number, boolean, date — the ordinary scalar fields',
|
|
222
|
-
'media — a reference into the media library, with alt text tracked alongside it',
|
|
223
|
-
'relation — a typed link to another collection’s entry, with an explicit rule for what happens on delete (restrict, by default)',
|
|
224
|
-
'taxonomy — a link to a classified term in a hierarchy your site owns, such as a category or a tag tree',
|
|
225
|
-
'blocks — a page composed from the shared block vocabulary (hero, prose, feature grid, and so on) — this is what every landing page and this very doc page uses for its body',
|
|
226
|
-
]),
|
|
227
|
-
heading('model-h2', 'h2', 'Permissions, per action'),
|
|
228
|
-
paragraph('model-p2', 'A collection names, separately, who may read, create, update, delete and publish it — five independent gates, not one "can edit" flag. A press-kit collection might be public to read but restricted to admin to write; a draft-only internal note might be closed to everyone but editors in both directions.'),
|
|
229
|
-
codeBlock('model-code2', "permissions: {\n read: ['public'],\n create: ['editor', 'admin'],\n update: ['editor', 'admin'],\n delete: ['admin'],\n}"),
|
|
230
|
-
heading('model-h3', 'h2', 'Versioning, drafts and trash'),
|
|
231
|
-
paragraph('model-p3', 'Every write to a published entry keeps its previous version — the History tab in the admin can compare and restore any of them. Deleting an entry moves it to the trash rather than destroying it outright; it is recoverable until it is purged, which is a distinct, deliberate action.'),
|
|
232
|
-
],
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
title: 'Themes',
|
|
236
|
-
slug: 'themes',
|
|
237
|
-
section: 'Guides',
|
|
238
|
-
order: 3,
|
|
239
|
-
body: [
|
|
240
|
-
paragraph('themes-p1', 'A theme is an installable package that renders every block in the shared vocabulary, plus its own header, footer and article layout. A theme never touches the database or a secret directly — it receives a RenderContext and a small, permission-scoped client, and nothing else. The block data it renders is always sanitised, structured content; a theme can shape it however it likes but cannot smuggle raw HTML into a block.'),
|
|
241
|
-
heading('themes-h1', 'h2', 'Built in'),
|
|
242
|
-
...bulletList('themes-list', [
|
|
243
|
-
'canonical — the reference implementation every other theme is checked against',
|
|
244
|
-
'blog, magazine, portfolio — editorial and creative sites',
|
|
245
|
-
'docs — this site, built for a sidebar table of contents, code blocks, and deep nesting',
|
|
246
|
-
'saas, association, restaurant, entreprise, store — the rest of the catalogue, one per common site type',
|
|
247
|
-
]),
|
|
248
|
-
paragraph('themes-p2', 'Switch themes from the admin’s Appearance screen — the change applies to the next request, no restart required, because the active theme’s name is stored in the database and resolved on every request rather than imported once at boot.'),
|
|
249
|
-
heading('themes-h2', 'h2', 'Customising without writing a theme'),
|
|
250
|
-
paragraph('themes-p3', 'Most day-to-day customisation is a colour palette (a "skin"), not a new theme: accent colour, surface colour, radii and a handful of other tokens, generated from a couple of brand colours and previewed live before you apply it. Writing an entirely new theme is a bigger commitment — a real npm package with its own tests — reserved for a genuinely different layout, not a different colour scheme.'),
|
|
251
|
-
heading('themes-h3', 'h2', 'Light, dark, and letting the visitor choose'),
|
|
252
|
-
paragraph('themes-p4', 'Every built-in theme ships a complete dark palette, not an inverted one — dedicated colour and elevation decisions for low light, matching the light palette’s structure token for token. The small sun or moon control in the header (try it — it is in the corner of this very page) cycles between following the visitor’s own system setting, forcing light, and forcing dark, and remembers the choice across a visit without ever setting a cookie.'),
|
|
253
|
-
],
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
title: 'Plugins',
|
|
257
|
-
slug: 'plugins',
|
|
258
|
-
section: 'Guides',
|
|
259
|
-
order: 4,
|
|
260
|
-
body: [
|
|
261
|
-
paragraph('plugins-p1', 'A plugin declares a manifest — the capabilities it needs, nothing implicit — and runs isolated from the rest of the site. A plugin that never asks for http.fetch cannot reach the network no matter what its code tries; a capability a manifest never names is absent, not merely refused at the last moment.'),
|
|
262
|
-
codeBlock('plugins-code1', "export default definePlugin({\n name: 'example-plugin',\n capabilities: ['content.read', 'http.fetch'],\n})"),
|
|
263
|
-
heading('plugins-h1', 'h2', 'What a capability grants'),
|
|
264
|
-
...bulletList('plugins-list', [
|
|
265
|
-
'content.read — read-only access to published content',
|
|
266
|
-
'http.fetch — outbound HTTP, to a reviewed allow-list, never an open socket',
|
|
267
|
-
'storage.read / storage.write — a private, per-plugin key-value store other plugins cannot see',
|
|
268
|
-
]),
|
|
269
|
-
heading('plugins-h2', 'h2', 'Where a plugin actually runs'),
|
|
270
|
-
paragraph('plugins-p2', 'Plugin code runs in an isolated worker thread inside a further-restricted execution context, not in the same process space as the rest of the site. A plugin that hangs, leaks memory, or is simply malicious cannot see the database, the file system, or another plugin’s data — only the SDK functions its granted capabilities actually construct for it.'),
|
|
271
|
-
heading('plugins-h3', 'h2', 'Installing and reviewing one'),
|
|
272
|
-
paragraph('plugins-p3', 'Every plugin from the registry is signed; an unsigned or tampered package is refused before its code ever runs. The Plugins screen in the admin lists exactly what a plugin is asking for in plain language — "read your published content", not a capability identifier — and any admin can revisit that grant and revoke it later without uninstalling the plugin outright.'),
|
|
273
|
-
],
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
title: 'CLI reference',
|
|
277
|
-
slug: 'cli-reference',
|
|
278
|
-
section: 'Reference',
|
|
279
|
-
order: 1,
|
|
280
|
-
body: [
|
|
281
|
-
paragraph('cli-p1', 'Every subcommand of the cogenta binary.'),
|
|
282
|
-
heading('cli-h1', 'h2', 'Commands'),
|
|
283
|
-
...bulletList('cli-list', [
|
|
284
|
-
'cogenta dev — starts the server with the schema editor enabled',
|
|
285
|
-
'cogenta serve — starts the server in read-only-schema production mode',
|
|
286
|
-
'cogenta migrate — applies pending database migrations',
|
|
287
|
-
'cogenta doctor — checks the environment for common misconfiguration',
|
|
288
|
-
'cogenta users create — creates the first admin account',
|
|
289
|
-
'cogenta import wordpress — imports content from a WordPress WXR export',
|
|
290
|
-
'cogenta generate types — writes TypeScript types generated from your schema',
|
|
291
|
-
'cogenta skin list / validate / apply / generate — manage colour palettes from the command line',
|
|
292
|
-
'cogenta channels — runs the Telegram/Slack/Discord bridge as its own process, separate from serve',
|
|
293
|
-
'cogenta mcp — starts a Model Context Protocol server exposing this site’s content to an external agent',
|
|
294
|
-
]),
|
|
295
|
-
codeBlock('cli-code1', 'cogenta doctor\ncogenta users create --email admin@example.com'),
|
|
296
|
-
heading('cli-h2', 'h2', 'Global flags'),
|
|
297
|
-
...bulletList('cli-flags', [
|
|
298
|
-
'--config <path> — use a config file other than cogenta.config.mjs',
|
|
299
|
-
'--port <n> — override the port cogenta serve/dev listens on',
|
|
300
|
-
'--json — machine-readable output, where a command supports it (cogenta doctor, for one)',
|
|
301
|
-
]),
|
|
302
|
-
heading('cli-h3', 'h2', 'dev versus serve'),
|
|
303
|
-
paragraph('cli-p2', 'cogenta dev is the only command that ever writes cogenta.schema.* — from the visual schema editor, or by applying an AI-proposed site plan. cogenta serve treats the schema as read-only, by design: a production site should never have its content model changed by an unattended process.'),
|
|
304
|
-
],
|
|
305
|
-
},
|
|
306
|
-
{
|
|
307
|
-
title: 'Configuration reference',
|
|
308
|
-
slug: 'configuration-reference',
|
|
309
|
-
section: 'Reference',
|
|
310
|
-
order: 2,
|
|
311
|
-
body: [
|
|
312
|
-
paragraph('confref-p1', 'Every key cogenta.config.mjs accepts, grouped by section.'),
|
|
313
|
-
heading('confref-h1', 'h2', 'site'),
|
|
314
|
-
...bulletList('confref-site', [
|
|
315
|
-
'name — the site’s display name',
|
|
316
|
-
'url — the canonical public URL, used for SEO tags',
|
|
317
|
-
]),
|
|
318
|
-
heading('confref-h2', 'h2', 'database'),
|
|
319
|
-
...bulletList('confref-db', [
|
|
320
|
-
'driver — sqlite, postgres, or mysql',
|
|
321
|
-
'url — a connection string, for postgres/mysql',
|
|
322
|
-
'poolSize — the maximum number of pooled connections (default 5)',
|
|
323
|
-
]),
|
|
324
|
-
heading('confref-h3', 'h2', 'security'),
|
|
325
|
-
...bulletList('confref-security', [
|
|
326
|
-
'pageMaxAge — the public cache lifetime, in seconds',
|
|
327
|
-
'cors — disabled by default; an explicit allow-list to enable it',
|
|
328
|
-
'csp — a verbatim Content-Security-Policy header value',
|
|
329
|
-
'hstsMaxAge — zero by default, and never sent over plain HTTP; set only once every subdomain genuinely serves HTTPS',
|
|
330
|
-
]),
|
|
331
|
-
heading('confref-h4', 'h2', 'storage, cache and queue'),
|
|
332
|
-
paragraph('confref-p2', 'Each of these has a driver key defaulting to "auto": Cogenta picks the best available implementation (S3-compatible storage, Redis, a real queue) when one is configured, and falls back to a file- or database-backed implementation that needs no external service otherwise. A site never fails to start for lacking infrastructure it was never given.'),
|
|
333
|
-
heading('confref-h5', 'h2', 'embeddings and vector'),
|
|
334
|
-
...bulletList('confref-ai', [
|
|
335
|
-
'embeddings.provider — "local" by default, a zero-dependency hash-based embedder that needs no API key',
|
|
336
|
-
'vector.driver — "auto"; falls back to an in-memory or file-backed cosine index without pgvector',
|
|
337
|
-
]),
|
|
338
|
-
],
|
|
339
|
-
},
|
|
340
|
-
{
|
|
341
|
-
title: 'HTTP API',
|
|
342
|
-
slug: 'http-api',
|
|
343
|
-
section: 'Reference',
|
|
344
|
-
order: 3,
|
|
345
|
-
body: [
|
|
346
|
-
paragraph('api-p1', 'Every collection is exposed as REST under /api/content, permission-checked against the same rules the admin obeys — a viewer role gets exactly the same 403 from the API that it would get clicking the same action in the admin UI.'),
|
|
347
|
-
heading('api-h1', 'h2', 'Content endpoints'),
|
|
348
|
-
...bulletList('api-list', [
|
|
349
|
-
'GET /api/content/:collection — list published entries',
|
|
350
|
-
'GET /api/content/:collection/:id — read one entry',
|
|
351
|
-
'POST /api/content/:collection — create an entry (requires a session)',
|
|
352
|
-
'PATCH /api/content/:collection/:id — update an entry',
|
|
353
|
-
'DELETE /api/content/:collection/:id — move an entry to the trash (recoverable)',
|
|
354
|
-
'GET /api/search?q= — full-text search across public collections',
|
|
355
|
-
]),
|
|
356
|
-
codeBlock('api-code1', 'curl https://example.com/api/content/doc_page?limit=10'),
|
|
357
|
-
heading('api-h2', 'h2', 'Site-level endpoints'),
|
|
358
|
-
...bulletList('api-site', [
|
|
359
|
-
'GET /sitemap.xml — generated from published, indexable entries',
|
|
360
|
-
'GET /robots.txt — generated from the same rules the sitemap uses',
|
|
361
|
-
'/graphql — a GraphQL endpoint generated from the same schema as the REST routes',
|
|
362
|
-
]),
|
|
363
|
-
heading('api-h3', 'h2', 'Authentication'),
|
|
364
|
-
paragraph('api-p2', 'A write to any endpoint above requires a session cookie or a bearer token belonging to a signed-in user; anonymous requests only ever see what the public role is granted to read. There is no separate "API key" that bypasses the permission model a human editor is held to.'),
|
|
365
|
-
],
|
|
366
|
-
},
|
|
367
|
-
];
|
|
368
|
-
/**
|
|
369
|
-
* `home` — the six-block composition the brief fixes exactly, in order:
|
|
370
|
-
* hero (title/subtitle/actions, a small decorative `coverArt` panel) →
|
|
371
|
-
* featureGrid "Start here" (six cards, each linking a real seeded doc page)
|
|
372
|
-
* → collectionList "All guides" on `doc_page` (the theme groups it by
|
|
373
|
-
* section) → prose "Quick install" (with a real code block) → faq → cta
|
|
374
|
-
* "Contribute on GitHub".
|
|
375
|
-
*
|
|
376
|
-
* A function of `media` (`SeedContext.media`), not a static const: the
|
|
377
|
-
* hero's `media` field needs the id `seedDemoMedia` only knows at scaffold
|
|
378
|
-
* time.
|
|
379
|
-
*/
|
|
380
|
-
export function buildDocumentationDemoPages(media) {
|
|
381
|
-
return [
|
|
382
|
-
{
|
|
383
|
-
title: 'Documentation',
|
|
384
|
-
slug: 'home',
|
|
385
|
-
blocks: [
|
|
386
|
-
{
|
|
387
|
-
_key: 'demo-home-hero',
|
|
388
|
-
_type: 'hero',
|
|
389
|
-
_version: BLOCK_VERSION,
|
|
390
|
-
eyebrow: 'Documentation',
|
|
391
|
-
title: 'Documentation',
|
|
392
|
-
subtitle: 'Guides, reference and real examples, kept in sync with every release.',
|
|
393
|
-
...(media.hero === undefined ? {} : { media: media.hero }),
|
|
394
|
-
actions: [
|
|
395
|
-
{ label: 'Get started', target: { href: '/docs/introduction' }, emphasis: 'primary' },
|
|
396
|
-
{ label: 'API reference', target: { href: '/docs/cli-reference' } },
|
|
397
|
-
],
|
|
398
|
-
},
|
|
399
|
-
{
|
|
400
|
-
_key: 'demo-home-start',
|
|
401
|
-
_type: 'featureGrid',
|
|
402
|
-
_version: BLOCK_VERSION,
|
|
403
|
-
title: 'Start here',
|
|
404
|
-
items: [
|
|
405
|
-
{
|
|
406
|
-
_key: 'start-1',
|
|
407
|
-
icon: 'download',
|
|
408
|
-
title: 'Install',
|
|
409
|
-
text: 'One command, three supported databases.',
|
|
410
|
-
link: { href: '/docs/installation' },
|
|
411
|
-
},
|
|
412
|
-
{
|
|
413
|
-
_key: 'start-2',
|
|
414
|
-
icon: 'settings',
|
|
415
|
-
title: 'Configure',
|
|
416
|
-
text: 'Every option, with its default.',
|
|
417
|
-
link: { href: '/docs/configuration' },
|
|
418
|
-
},
|
|
419
|
-
{
|
|
420
|
-
_key: 'start-3',
|
|
421
|
-
icon: 'rocket',
|
|
422
|
-
title: 'Deploy',
|
|
423
|
-
text: 'From a first request to a production release.',
|
|
424
|
-
link: { href: '/docs/deploying-to-production' },
|
|
425
|
-
},
|
|
426
|
-
{
|
|
427
|
-
_key: 'start-4',
|
|
428
|
-
icon: 'layers',
|
|
429
|
-
title: 'Content model',
|
|
430
|
-
text: 'Collections, fields and permissions.',
|
|
431
|
-
link: { href: '/docs/content-model' },
|
|
432
|
-
},
|
|
433
|
-
{
|
|
434
|
-
_key: 'start-5',
|
|
435
|
-
icon: 'image',
|
|
436
|
-
title: 'Themes',
|
|
437
|
-
text: 'Ten built-in themes, switchable with no restart.',
|
|
438
|
-
link: { href: '/docs/themes' },
|
|
439
|
-
},
|
|
440
|
-
{
|
|
441
|
-
_key: 'start-6',
|
|
442
|
-
icon: 'code',
|
|
443
|
-
title: 'Plugins',
|
|
444
|
-
text: 'Capability-scoped, isolated at runtime.',
|
|
445
|
-
link: { href: '/docs/plugins' },
|
|
446
|
-
},
|
|
447
|
-
],
|
|
448
|
-
},
|
|
449
|
-
{
|
|
450
|
-
_key: 'demo-home-guides',
|
|
451
|
-
_type: 'collectionList',
|
|
452
|
-
_version: BLOCK_VERSION,
|
|
453
|
-
title: 'All guides',
|
|
454
|
-
collection: 'doc_page',
|
|
455
|
-
sort: { field: 'createdAt', direction: 'asc' },
|
|
456
|
-
limit: 100,
|
|
457
|
-
layout: 'list',
|
|
458
|
-
},
|
|
459
|
-
proseBlock('demo-home-install', [
|
|
460
|
-
heading('demo-install-h', 'h2', 'Quick install'),
|
|
461
|
-
paragraph('demo-install-p', 'The whole of getting started, in one command:'),
|
|
462
|
-
codeBlock('demo-install-code', 'npm create cogenta my-docs\ncd my-docs\nnpm run dev'),
|
|
463
|
-
]),
|
|
464
|
-
{
|
|
465
|
-
_key: 'demo-home-faq',
|
|
466
|
-
_type: 'faq',
|
|
467
|
-
_version: BLOCK_VERSION,
|
|
468
|
-
title: 'Common questions',
|
|
469
|
-
items: [
|
|
470
|
-
{
|
|
471
|
-
_key: 'demo-home-faq-1',
|
|
472
|
-
question: 'Which version do these docs describe?',
|
|
473
|
-
answer: richTextParagraph('demo-home-faq-1-a', 'The one currently released. Older versions stay online at their own URLs rather than being rewritten in place.'),
|
|
474
|
-
},
|
|
475
|
-
{
|
|
476
|
-
_key: 'demo-home-faq-2',
|
|
477
|
-
question: 'Can I edit these pages?',
|
|
478
|
-
answer: richTextParagraph('demo-home-faq-2-a', 'Yes — every doc page below is a normal, editable entry, seeded once by the installer and owned by you from then on.'),
|
|
479
|
-
},
|
|
480
|
-
{
|
|
481
|
-
_key: 'demo-home-faq-3',
|
|
482
|
-
question: 'Do the code examples actually run?',
|
|
483
|
-
answer: richTextParagraph('demo-home-faq-3-a', 'They describe the real commands and files this project ships — they are not generated placeholder text.'),
|
|
484
|
-
},
|
|
485
|
-
{
|
|
486
|
-
_key: 'demo-home-faq-4',
|
|
487
|
-
question: 'Something here is wrong. What do I do?',
|
|
488
|
-
answer: richTextParagraph('demo-home-faq-4-a', 'Open a pull request against the docs source — see "Contribute on GitHub" below.'),
|
|
489
|
-
},
|
|
490
|
-
],
|
|
491
|
-
},
|
|
492
|
-
{
|
|
493
|
-
_key: 'demo-home-cta',
|
|
494
|
-
_type: 'cta',
|
|
495
|
-
_version: BLOCK_VERSION,
|
|
496
|
-
title: 'Contribute on GitHub',
|
|
497
|
-
text: 'Found a gap, a broken link, or an outdated example? Open a pull request.',
|
|
498
|
-
actions: [
|
|
499
|
-
{
|
|
500
|
-
label: 'Open GitHub',
|
|
501
|
-
target: { href: 'https://github.com/cogenta-cms/cogenta' },
|
|
502
|
-
emphasis: 'primary',
|
|
503
|
-
},
|
|
504
|
-
],
|
|
505
|
-
},
|
|
506
|
-
],
|
|
507
|
-
},
|
|
508
|
-
];
|
|
509
|
-
}
|
|
510
|
-
/**
|
|
511
|
-
* `documentation`'s own starting skin (`starting-skins.js`), asserted
|
|
512
|
-
* present with a real check — same pattern `store.ts`'s `storePalette()`
|
|
513
|
-
* uses.
|
|
514
|
-
*/
|
|
515
|
-
function documentationPalette() {
|
|
516
|
-
const skin = STARTING_SKINS.documentation;
|
|
517
|
-
if (skin === undefined) {
|
|
518
|
-
throw new CogentaError({
|
|
519
|
-
code: 'BLUEPRINT_REGISTRY_CORRUPT',
|
|
520
|
-
message: 'STARTING_SKINS.documentation is missing.',
|
|
521
|
-
hint: 'The "documentation" entry must stay declared in starting-skins.ts for this blueprint to render its demo art.',
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
return skin.color;
|
|
525
|
-
}
|
|
526
|
-
/**
|
|
527
|
-
* A small decorative panel for the hero (`coverArt`, not `heroArt`: the
|
|
528
|
-
* brief asks for "a small coverArt used as decorative right-side panel",
|
|
529
|
-
* not a full-bleed backdrop), plus two more for the "Content model" and
|
|
530
|
-
* "Themes" doc pages (L26 D2/D3) — the two guides dense enough in prose
|
|
531
|
-
* that the user's "some pages read as too bare" complaint applied to them
|
|
532
|
-
* specifically. This blueprint has no bundled photography (a docs site is
|
|
533
|
-
* diagram-led, not photo-led, and there is no Replicate key any more to
|
|
534
|
-
* generate new photos) — every one of these three is the same zero-
|
|
535
|
-
* dependency procedural generator, at a different seed so no two repeat.
|
|
536
|
-
*/
|
|
537
|
-
export const DOCUMENTATION_MEDIA_SPECS = [
|
|
538
|
-
{
|
|
539
|
-
name: 'hero',
|
|
540
|
-
spec: coverArt(documentationPalette(), 5),
|
|
541
|
-
alt: 'Abstract geometric composition, decorative',
|
|
542
|
-
},
|
|
543
|
-
{
|
|
544
|
-
name: 'docsContentModel',
|
|
545
|
-
spec: coverArt(documentationPalette(), 8),
|
|
546
|
-
alt: 'Abstract diagram-style illustration, decorative',
|
|
547
|
-
},
|
|
548
|
-
{
|
|
549
|
-
name: 'docsThemes',
|
|
550
|
-
spec: coverArt(documentationPalette(), 11),
|
|
551
|
-
alt: 'Abstract diagram-style illustration, decorative',
|
|
552
|
-
},
|
|
553
|
-
];
|
|
554
|
-
/**
|
|
555
|
-
* The two doc pages illustrated with the extra `docsContentModel`/
|
|
556
|
-
* `docsThemes` panels above, keyed by slug — a `mediaFigure` block appended
|
|
557
|
-
* after the page's own prose, never in place of it. `f.blocks()` already
|
|
558
|
-
* carries the shared vocabulary, so this needs no schema change: `doc_page`
|
|
559
|
-
* keeps its five declared fields exactly as they were.
|
|
560
|
-
*/
|
|
561
|
-
const DOC_PAGE_ILLUSTRATIONS = {
|
|
562
|
-
'content-model': {
|
|
563
|
-
media: 'docsContentModel',
|
|
564
|
-
caption: 'A collection: fields, permissions, and a version history, all declared in one place.',
|
|
565
|
-
},
|
|
566
|
-
themes: {
|
|
567
|
-
media: 'docsThemes',
|
|
568
|
-
caption: 'One content model, rendered by any of the ten built-in themes.',
|
|
569
|
-
},
|
|
570
|
-
};
|
|
571
|
-
/** Header/footer navigation and the header call-to-action button (L25 D4). */
|
|
572
|
-
export const DOCUMENTATION_MENUS = {
|
|
573
|
-
header: [
|
|
574
|
-
{ label: 'Docs' },
|
|
575
|
-
{ label: 'Guides', url: '/docs/deploying-to-production' },
|
|
576
|
-
{ label: 'Reference', url: '/docs/cli-reference' },
|
|
577
|
-
// No blog collection exists in this blueprint (contract B is frozen and
|
|
578
|
-
// a blog needs its own content model, out of scope for a docs site) —
|
|
579
|
-
// the release notes on GitHub are the honest stand-in a real docs site
|
|
580
|
-
// links to when it has none of its own.
|
|
581
|
-
{ label: 'Blog', url: 'https://github.com/cogenta-cms/cogenta/releases', openInNewTab: true },
|
|
582
|
-
],
|
|
583
|
-
footer: [
|
|
584
|
-
{ label: 'Docs' },
|
|
585
|
-
{
|
|
586
|
-
label: 'Community',
|
|
587
|
-
url: 'https://github.com/cogenta-cms/cogenta/discussions',
|
|
588
|
-
openInNewTab: true,
|
|
589
|
-
},
|
|
590
|
-
{ label: 'GitHub', url: 'https://github.com/cogenta-cms/cogenta', openInNewTab: true },
|
|
591
|
-
],
|
|
592
|
-
headerAction: {
|
|
593
|
-
label: 'GitHub',
|
|
594
|
-
url: 'https://github.com/cogenta-cms/cogenta',
|
|
595
|
-
openInNewTab: true,
|
|
596
|
-
},
|
|
597
|
-
};
|
|
598
|
-
export const DOCUMENTATION_SITE_SETTINGS = {
|
|
599
|
-
'general.tagline': 'Documentation that stays honest about what is actually built.',
|
|
600
|
-
'general.socialLinks': [
|
|
601
|
-
{ label: 'GitHub', url: 'https://github.com/cogenta-cms/cogenta' },
|
|
602
|
-
{ label: 'X', url: 'https://x.com/cogenta' },
|
|
603
|
-
{ label: 'Discord', url: 'https://discord.gg/cogenta' },
|
|
604
|
-
],
|
|
605
|
-
'general.footerNote': 'A demo documentation site, scaffolded by create-cogenta.',
|
|
606
|
-
};
|
|
607
|
-
export const DOCUMENTATION_RECOMMENDED_AGENTS = [
|
|
608
|
-
{
|
|
609
|
-
name: 'contentAgent',
|
|
610
|
-
package: '@cogenta/agents-builtin',
|
|
611
|
-
reason: 'Flags terminology drift across doc pages, where consistent wording matters most.',
|
|
612
|
-
},
|
|
613
|
-
{
|
|
614
|
-
name: 'seoAgent',
|
|
615
|
-
package: '@cogenta/agents-builtin',
|
|
616
|
-
reason: 'Audits internal linking between doc pages so readers can navigate without the sidebar.',
|
|
617
|
-
},
|
|
618
|
-
];
|
|
619
|
-
/**
|
|
620
|
-
* Inserts the `documentation` blueprint's demo content through the real
|
|
621
|
-
* `ContentStore` — never mocked (house rule). Every doc page's body starts
|
|
622
|
-
* with the same sidebar `collectionList`, and every entry — doc pages and
|
|
623
|
-
* the home page alike — is seeded **published**: this is project-authored
|
|
624
|
-
* demo content, not model output (contrast L19, where generated content
|
|
625
|
-
* stays a draft).
|
|
626
|
-
*/
|
|
627
|
-
async function seedDocumentationDemoContent(ctx) {
|
|
628
|
-
const { db, defaultLocale, adminId, media } = ctx;
|
|
629
|
-
const docPageStore = createContentStore({ db, collection: docPage, defaultLocale });
|
|
630
|
-
const pageStore = createContentStore({ db, collection: page, defaultLocale });
|
|
631
|
-
for (const demo of DOCUMENTATION_DEMO_DOC_PAGES) {
|
|
632
|
-
const illustration = DOC_PAGE_ILLUSTRATIONS[demo.slug];
|
|
633
|
-
const mediaId = illustration === undefined ? undefined : media[illustration.media];
|
|
634
|
-
const body = [
|
|
635
|
-
sidebarBlock(`sidebar-${demo.slug}`),
|
|
636
|
-
proseBlock(`content-${demo.slug}`, demo.body),
|
|
637
|
-
// `mediaFigure.media` is required — with no matching media seeded
|
|
638
|
-
// (should `seedDemoMedia` ever be skipped upstream), the block is
|
|
639
|
-
// omitted rather than emitted invalid.
|
|
640
|
-
...(illustration === undefined || mediaId === undefined
|
|
641
|
-
? []
|
|
642
|
-
: [
|
|
643
|
-
{
|
|
644
|
-
_key: `figure-${demo.slug}`,
|
|
645
|
-
_type: 'mediaFigure',
|
|
646
|
-
_version: BLOCK_VERSION,
|
|
647
|
-
media: mediaId,
|
|
648
|
-
caption: illustration.caption,
|
|
649
|
-
align: 'wide',
|
|
650
|
-
},
|
|
651
|
-
]),
|
|
652
|
-
];
|
|
653
|
-
await docPageStore.create({
|
|
654
|
-
status: 'published',
|
|
655
|
-
createdBy: adminId,
|
|
656
|
-
values: { title: demo.title, slug: demo.slug, section: demo.section, order: demo.order },
|
|
657
|
-
blocks: { body: body.map(toBlockZoneEntry) },
|
|
658
|
-
});
|
|
659
|
-
}
|
|
660
|
-
for (const demo of buildDocumentationDemoPages(media)) {
|
|
661
|
-
await pageStore.create({
|
|
662
|
-
status: 'published',
|
|
663
|
-
createdBy: adminId,
|
|
664
|
-
values: { title: demo.title, slug: demo.slug },
|
|
665
|
-
blocks: { blocks: demo.blocks.map(toBlockZoneEntry) },
|
|
666
|
-
});
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
export const documentationContentPack = {
|
|
670
|
-
collections: DOCUMENTATION_COLLECTIONS,
|
|
671
|
-
recommendedAgents: DOCUMENTATION_RECOMMENDED_AGENTS,
|
|
672
|
-
seedDemoContent: seedDocumentationDemoContent,
|
|
673
|
-
defaultTheme: '@cogenta/theme-docs',
|
|
674
|
-
menus: DOCUMENTATION_MENUS,
|
|
675
|
-
siteSettings: DOCUMENTATION_SITE_SETTINGS,
|
|
676
|
-
mediaSpecs: DOCUMENTATION_MEDIA_SPECS,
|
|
677
|
-
};
|
|
678
|
-
//# sourceMappingURL=documentation.js.map
|