uniweb 1.20.3 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +145 -113
- package/package.json +5 -5
- package/partials/agents.md +19 -8
- package/partials/start.md +126 -0
- package/src/backend/app-changes.js +153 -0
- package/src/backend/client.js +3 -3
- package/src/backend/foundation-bring-along.js +1 -1
- package/src/backend/payment-handoff.js +25 -2
- package/src/commands/clone.js +2 -0
- package/src/commands/doctor.js +41 -10
- package/src/commands/pull.js +17 -2
- package/src/commands/register.js +15 -15
- package/src/commands/start.js +60 -0
- package/src/commands/status.js +712 -254
- package/src/commands/update.js +1 -23
- package/src/index.js +80 -2
- package/src/utils/code-upload.js +27 -27
- package/src/utils/flag-guard.js +17 -2
- package/src/utils/git.js +91 -1
- package/src/utils/registry-auth.js +15 -5
- package/src/utils/scaffold.js +4 -0
- package/src/utils/status-next.js +47 -0
- package/src/utils/update-check.js +8 -6
- package/src/utils/workspace.js +26 -0
- package/starter/foundation/sections/Section/index.jsx +6 -6
- package/starter/site/pages/home/1-welcome.md.hbs +1 -1
- package/templates/site/site.yml.hbs +4 -5
- package/templates/workspace/README.md.hbs +132 -50
- package/partials/adding-pages.hbs +0 -77
- package/partials/ai-assistance.hbs +0 -28
- package/partials/components-docs.hbs +0 -13
- package/partials/config-reference.hbs +0 -66
- package/partials/deployment.hbs +0 -13
- package/partials/learn-more.hbs +0 -6
- package/partials/quick-start.hbs +0 -8
- package/partials/search-docs.hbs +0 -110
package/README.md
CHANGED
|
@@ -1,68 +1,68 @@
|
|
|
1
1
|
# uniweb
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The CLI for [Uniweb](https://uniweb.io): an open-source React framework and a connected visual authoring platform.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Developers define the vocabulary. Authors compose with it. Uniweb keeps both sides in sync.**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Developers build real React components, schemas and content structures in a normal codebase. Those definitions become the vocabulary authors use in the Uniweb app to create pages, manage content and work with structured data. Your project and the authors' workspace are two interfaces to the same website, and the CLI keeps them in sync, so both sides keep working.
|
|
8
8
|
|
|
9
|
-
```
|
|
10
|
-
|
|
9
|
+
```text
|
|
10
|
+
Traditional: developer builds → hands off → CMS users edit
|
|
11
|
+
|
|
12
|
+
Uniweb: developer project ⇄ Uniweb ⇄ author workspace
|
|
13
|
+
↑ ↑
|
|
14
|
+
└──── both keep working ───┘
|
|
11
15
|
```
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
## Quick Start
|
|
14
18
|
|
|
15
19
|
```bash
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
pnpm
|
|
20
|
+
npx uniweb@latest create my-site
|
|
21
|
+
cd my-site
|
|
22
|
+
pnpm install # or npm install
|
|
23
|
+
pnpm dev # or npm run dev — prints the address it serves the site at
|
|
19
24
|
```
|
|
20
25
|
|
|
21
|
-
Edit
|
|
22
|
-
|
|
23
|
-
> **pnpm ready** — `pnpm create uniweb` works out of the box. Projects include both `pnpm-workspace.yaml` and npm workspaces.
|
|
26
|
+
At a terminal, `create` asks which template to start from (`npm create uniweb` does the same). Edit the pages in `site/pages/` and the section types in `src/sections/`, and the page updates as you save.
|
|
24
27
|
|
|
25
|
-
|
|
28
|
+
Start with a normal project, and connect the authoring app when you want it:
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
| **Marketing** | Landing page, features, pricing, testimonials |
|
|
32
|
-
| **Docs** | Documentation with sidebar and search |
|
|
33
|
-
| **Academic** | Research site with publications and team |
|
|
34
|
-
| **International** | Multilingual site with i18n and blog |
|
|
35
|
-
| **Dynamic** | Live API data fetching with loading states |
|
|
36
|
-
| **Store** | E-commerce with product grid |
|
|
37
|
-
| **Extensions** | Multi-foundation with visual effects extension |
|
|
30
|
+
```bash
|
|
31
|
+
pnpm uniweb login # sign in to your Uniweb account
|
|
32
|
+
pnpm uniweb sync # the first sync brings the site and its foundation into the app
|
|
33
|
+
```
|
|
38
34
|
|
|
39
|
-
**
|
|
35
|
+
> **pnpm ready** — `pnpm create uniweb` works out of the box. Projects include both `pnpm-workspace.yaml` and npm workspaces.
|
|
40
36
|
|
|
41
|
-
|
|
37
|
+
### With an AI agent
|
|
42
38
|
|
|
43
|
-
|
|
39
|
+
Building a site with an AI coding agent? Ask it to run `npx uniweb@latest start` first. It prints a short guide written for the agent: how to create the project, where its manual is (`AGENTS.md`), how to run it, and how to bring the site into the Uniweb app. The agent runs every command; you only use your browser, to sign in and to pay when the site goes live.
|
|
44
40
|
|
|
45
|
-
|
|
46
|
-
pnpm create uniweb my-site --template docs
|
|
47
|
-
```
|
|
41
|
+
## Two Interfaces to One Website
|
|
48
42
|
|
|
49
|
-
|
|
43
|
+
| Developers | Authors |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| React components | Visual components |
|
|
46
|
+
| Schemas and configuration | Forms and structured records |
|
|
47
|
+
| Vite and local development | Live visual editing |
|
|
48
|
+
| Files and Git | Content and composition |
|
|
49
|
+
| `push` · `pull` · `sync` · `publish` | Changes appear live |
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
pnpm create uniweb . --template docs
|
|
53
|
-
```
|
|
51
|
+
**For developers, it's a normal project.** Section types are React components, content is markdown in the repository, Vite builds it, and git holds the history. You keep your editor, terminal and deployment workflow.
|
|
54
52
|
|
|
55
|
-
|
|
53
|
+
**For authors, it's the Uniweb app.** Your section types become their building blocks: they compose pages from them, set the options each one declares in its `meta.js`, and manage records through your schemas, with live previews. They never see JSX, markdown, YAML or git, and you never build an editing UI. You build the components; Uniweb builds the authoring experience.
|
|
56
54
|
|
|
57
|
-
|
|
55
|
+
### The CLI is the bridge
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
57
|
+
| Command | What it does |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| `uniweb push` | Sends your section types, schemas and content to the app: a draft, not live |
|
|
60
|
+
| `uniweb pull` | Brings authors' edits into your files, as a git merge |
|
|
61
|
+
| `uniweb sync` | Takes your teammates' commits and the authors' edits, then pushes yours |
|
|
62
|
+
| `uniweb publish` | Pushes, then takes the site live on Uniweb hosting (paid) |
|
|
63
|
+
| `uniweb clone <site-uuid>` | Starts a local project from a site made in the app (`uniweb site list` shows its uuid) |
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
Edits to different sections combine. When the same section changed on both sides, `pull` stops at a git conflict for you to settle, and a push stops rather than overwrite what an author changed (only `--force` goes past it), so neither edit is lost. Like git, a push sends what you have committed; `--commit` commits the site's content first.
|
|
66
66
|
|
|
67
67
|
## What You Get
|
|
68
68
|
|
|
@@ -71,7 +71,7 @@ Every project starts as a workspace with two packages:
|
|
|
71
71
|
- **`site/`** — Content, pages, entry point (package name: `site`)
|
|
72
72
|
- **`src/`** — React components, the site's source code (package name: `src`)
|
|
73
73
|
|
|
74
|
-
A site is pure content. A foundation is the site's source code — that's why it lives in `src/`. Content
|
|
74
|
+
A site is pure content. A foundation is the site's source code — that's why it lives in `src/`. Content lives in markdown and component code in React, so neither can break the other. As your project grows, use `uniweb add` to add more foundations, sites, and extensions.
|
|
75
75
|
|
|
76
76
|
```
|
|
77
77
|
my-project/
|
|
@@ -79,25 +79,26 @@ my-project/
|
|
|
79
79
|
│ ├── pages/ # File-based routing
|
|
80
80
|
│ │ └── home/
|
|
81
81
|
│ │ ├── page.yml # Page metadata
|
|
82
|
-
│ │ └──
|
|
83
|
-
│ ├──
|
|
82
|
+
│ │ └── 1-welcome.md # A section
|
|
83
|
+
│ ├── site.yml # Site configuration
|
|
84
|
+
│ ├── theme.yml # Colors, fonts, appearance
|
|
84
85
|
│ ├── entry.js # Entry point (~6 lines)
|
|
85
|
-
│ ├── vite.config.js #
|
|
86
|
+
│ ├── vite.config.js # One-line config
|
|
86
87
|
│ └── public/ # Static assets
|
|
87
88
|
│
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
89
|
+
├── src/ # Foundation package (the site's source)
|
|
90
|
+
│ ├── sections/ # Section types (addressable from markdown)
|
|
91
|
+
│ │ ├── Hero.jsx # Bare file → section type (no meta.js needed)
|
|
92
|
+
│ │ └── Features/
|
|
93
|
+
│ │ ├── index.jsx
|
|
94
|
+
│ │ └── meta.js # Content interface (params, presets)
|
|
95
|
+
│ ├── components/ # Regular React components
|
|
96
|
+
│ ├── main.js # Foundation declarations (name, theme variables, default layout)
|
|
97
|
+
│ ├── styles.css # Tailwind v4 + CSS tokens
|
|
98
|
+
│ ├── package.json # name: "src"
|
|
99
|
+
│ └── vite.config.js # 3-line config
|
|
100
|
+
│
|
|
101
|
+
└── AGENTS.md # The project's manual, for developers and AI agents
|
|
101
102
|
```
|
|
102
103
|
|
|
103
104
|
**Pages are folders.** Create `pages/about/` with markdown files inside → visit `/about`. That's the whole routing model.
|
|
@@ -119,7 +120,7 @@ Build something great.
|
|
|
119
120
|
[Get Started](#)
|
|
120
121
|
```
|
|
121
122
|
|
|
122
|
-
Frontmatter
|
|
123
|
+
Frontmatter names the section type and its configuration — `theme: dark` sets the section's color context. The body contains the actual content—headings, paragraphs, links, images—which gets semantically parsed into structured data your component receives.
|
|
123
124
|
|
|
124
125
|
### Beyond Markdown
|
|
125
126
|
|
|
@@ -145,32 +146,34 @@ function TeamCard({ content }) {
|
|
|
145
146
|
}
|
|
146
147
|
```
|
|
147
148
|
|
|
148
|
-
Natural content stays in markdown; structured data goes in tagged blocks (YAML or JSON).
|
|
149
|
+
Natural content stays in markdown; structured data goes in tagged blocks (YAML or JSON). Content that many pages share — people, publications, events — can live as records instead, typed by your foundation's schemas, which is what authors then manage as forms in the app.
|
|
149
150
|
|
|
150
151
|
### Components as React
|
|
151
152
|
|
|
152
153
|
```jsx
|
|
153
|
-
|
|
154
|
+
import { H1, P, Link } from '@uniweb/kit'
|
|
155
|
+
|
|
156
|
+
export default function Hero({ content }) {
|
|
154
157
|
const { title, paragraphs, links } = content
|
|
155
158
|
|
|
156
159
|
return (
|
|
157
|
-
<
|
|
158
|
-
<
|
|
159
|
-
<
|
|
160
|
+
<div className="py-20 text-center">
|
|
161
|
+
<H1 text={title} className="text-4xl font-bold text-heading" />
|
|
162
|
+
<P text={paragraphs[0]} className="mt-4 text-xl text-body" />
|
|
160
163
|
{links[0] && (
|
|
161
|
-
<
|
|
162
|
-
|
|
163
|
-
className="mt-8 px-6 py-3
|
|
164
|
+
<Link
|
|
165
|
+
to={links[0].href}
|
|
166
|
+
className="mt-8 inline-block rounded bg-primary px-6 py-3 text-primary-foreground"
|
|
164
167
|
>
|
|
165
168
|
{links[0].label}
|
|
166
|
-
</
|
|
169
|
+
</Link>
|
|
167
170
|
)}
|
|
168
|
-
</
|
|
171
|
+
</div>
|
|
169
172
|
)
|
|
170
173
|
}
|
|
171
174
|
```
|
|
172
175
|
|
|
173
|
-
Standard React. Standard Tailwind. The `{ content, params }` interface is only for _section types_ — components that content creators select in markdown frontmatter. Everything else uses regular React props.
|
|
176
|
+
Standard React. Standard Tailwind. Classes like `text-heading` and `bg-primary` are theme tokens, so one component adapts to light and dark sections and to every site's colors; the runtime wraps each section in its `<section>` and paints its background. The `{ content, params }` interface is only for _section types_ — components that content creators select in markdown frontmatter. Everything else uses regular React props.
|
|
174
177
|
|
|
175
178
|
### Composition
|
|
176
179
|
|
|
@@ -194,13 +197,48 @@ Authors can also compose layouts from reusable section types using child section
|
|
|
194
197
|
|
|
195
198
|
```
|
|
196
199
|
pages/home/
|
|
197
|
-
├──
|
|
200
|
+
├── page.yml # nest: { highlights: [stats, testimonial, demo] }
|
|
201
|
+
├── highlights.md # type: Grid
|
|
198
202
|
├── @stats.md # type: StatCard
|
|
199
203
|
├── @testimonial.md # type: Testimonial
|
|
200
204
|
└── @demo.md # type: SplitContent (with an embedded @LiveDemo inset)
|
|
201
205
|
```
|
|
202
206
|
|
|
203
|
-
Three different section types, arranged in a grid, one with an interactive component inside it — all authored in markdown. The developer builds reusable pieces; the content author composes them. See the [Component Patterns guide](https://github.com/uniweb/docs/blob/main/development/component-patterns.md) for the full composition model.
|
|
207
|
+
Three different section types, arranged in a grid, one with an interactive component inside it — all authored in markdown. An `@` file is a child section, and `nest:` in `page.yml` says whose. The developer builds reusable pieces; the content author composes them. See the [Component Patterns guide](https://github.com/uniweb/docs/blob/main/development/component-patterns.md) for the full composition model.
|
|
208
|
+
|
|
209
|
+
## Templates
|
|
210
|
+
|
|
211
|
+
| Template | Description |
|
|
212
|
+
| --- | --- |
|
|
213
|
+
| **Starter** | Foundation + site + sample content (default) |
|
|
214
|
+
| **None** | Foundation + site with no content |
|
|
215
|
+
| **Blank** (`--blank`) | An empty workspace — grow it with `uniweb add` |
|
|
216
|
+
|
|
217
|
+
**Official templates** — marketing sites, documentation, blogs, academic sites and more — each come with a working foundation and sample content. `uniweb template list` shows the ones your CLI scaffolds, and you can [see them live](https://uniweb.github.io/templates/).
|
|
218
|
+
|
|
219
|
+
**Two starting points.** Either let the CLI create a new directory:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
pnpm create uniweb my-site --template docs
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
…or scaffold inside an existing directory (e.g., a freshly-cloned GitHub repo):
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
pnpm create uniweb . --template docs
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Local Scripts
|
|
232
|
+
|
|
233
|
+
Run these from the **project root**:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
pnpm dev # Start development server
|
|
237
|
+
pnpm build # Build foundation + site for production
|
|
238
|
+
pnpm preview # Preview the production build
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
The `build` command outputs to `site/dist/`. With pre-rendering enabled (the default for official templates), you get static HTML files ready to deploy anywhere.
|
|
204
242
|
|
|
205
243
|
## Next Steps
|
|
206
244
|
|
|
@@ -212,17 +250,17 @@ After creating your project:
|
|
|
212
250
|
|
|
213
251
|
3. **Learn the configuration** — Run `uniweb docs site` or `uniweb docs page` for quick reference on configuration options.
|
|
214
252
|
|
|
215
|
-
4. **Create a section type** —
|
|
253
|
+
4. **Create a section type** — `uniweb add section Banner` scaffolds one, or add a file to `src/sections/` (e.g., `Banner.jsx`): the dev server picks it up. Bare files at the root are discovered automatically — no `meta.js` needed. Add `meta.js` when you want to declare params or presets. See the [Component Metadata Reference](https://github.com/uniweb/docs/blob/main/reference/component-metadata.md) for the full schema.
|
|
216
254
|
|
|
217
|
-
|
|
255
|
+
`meta.js` declares what content and parameters a section type accepts. The runtime fills each param from its default there, and hands every section the full content shape, so your components need no defensive null checks.
|
|
218
256
|
|
|
219
257
|
### Your First Content Change
|
|
220
258
|
|
|
221
|
-
Open `site/pages/home/
|
|
259
|
+
Open a section of the home page (in the starter, `site/pages/home/1-welcome.md`) and edit the headline:
|
|
222
260
|
|
|
223
261
|
```markdown
|
|
224
262
|
---
|
|
225
|
-
type:
|
|
263
|
+
type: Section
|
|
226
264
|
---
|
|
227
265
|
|
|
228
266
|
# Your New Headline Here
|
|
@@ -236,10 +274,10 @@ Save and see the change instantly in your browser.
|
|
|
236
274
|
|
|
237
275
|
### Your First Component Change
|
|
238
276
|
|
|
239
|
-
Open `src/sections/
|
|
277
|
+
Open the section type that renders it (in the starter, `src/sections/Section/index.jsx`). The component receives parsed content:
|
|
240
278
|
|
|
241
279
|
```jsx
|
|
242
|
-
export default function
|
|
280
|
+
export default function Section({ content, params }) {
|
|
243
281
|
const { title, paragraphs, links, images, items } = content
|
|
244
282
|
// Edit the JSX below...
|
|
245
283
|
}
|
|
@@ -249,7 +287,7 @@ The parser extracts semantic elements from markdown—`title` from the first hea
|
|
|
249
287
|
|
|
250
288
|
## Foundations Are Portable
|
|
251
289
|
|
|
252
|
-
The `src/` folder (your project's foundation) ships with your project as a convenience, but
|
|
290
|
+
The `src/` folder (your project's foundation) ships with your project as a convenience, but sites reference a foundation by configuration, not by folder proximity.
|
|
253
291
|
|
|
254
292
|
**Two ways to use a foundation:**
|
|
255
293
|
|
|
@@ -258,7 +296,7 @@ The `src/` folder (your project's foundation) ships with your project as a conve
|
|
|
258
296
|
| **Local folder** | Foundation lives in your workspace | Developing site and components together |
|
|
259
297
|
| **Runtime link** | Foundation loads from a URL | Independent release cycles, platform-managed sites |
|
|
260
298
|
|
|
261
|
-
|
|
299
|
+
Develop a foundation locally, then register it for other sites to use. A site can also name a registered foundation instead of a local one — a project made by `uniweb clone` does — and `uniweb dev` runs it, while Uniweb hosting builds and serves it. The site doesn't care where its components come from.
|
|
262
300
|
|
|
263
301
|
**This enables two development patterns:**
|
|
264
302
|
|
|
@@ -282,10 +320,10 @@ cd my-workspace
|
|
|
282
320
|
uniweb add project blog
|
|
283
321
|
|
|
284
322
|
# Add a second foundation at root
|
|
285
|
-
uniweb add foundation
|
|
323
|
+
uniweb add foundation doc-kit
|
|
286
324
|
|
|
287
325
|
# Add a site wired to a specific foundation
|
|
288
|
-
uniweb add site docs --foundation
|
|
326
|
+
uniweb add site docs --foundation doc-kit
|
|
289
327
|
|
|
290
328
|
# Add an extension (auto-wired to the only site)
|
|
291
329
|
uniweb add extension effects
|
|
@@ -300,18 +338,13 @@ pnpm dev # or npm run dev
|
|
|
300
338
|
|
|
301
339
|
The workspace grows organically. `add` handles placement, wires dependencies, updates workspace globs, and generates root scripts. The name you provide becomes both the directory name and the package name. Use `--path` to override default placement, or `--project` for explicit co-located layouts.
|
|
302
340
|
|
|
303
|
-
##
|
|
304
|
-
|
|
305
|
-
A Uniweb project produces two artifacts — a **site** (content) and a **foundation** (code). **Who manages the content** decides what you ship:
|
|
341
|
+
## Other Ways to Ship
|
|
306
342
|
|
|
307
|
-
|
|
308
|
-
- If someone else manages the content, you ship only the foundation. Content authors compose sites in the Uniweb apps; there's no site to deploy from your repo.
|
|
343
|
+
A Uniweb project produces two artifacts — a **site** (content) and a **foundation** (code). Connected to the app, both sides edit one site, as above. The framework also works on its own, and **who manages the content** decides what you ship.
|
|
309
344
|
|
|
310
|
-
###
|
|
345
|
+
### You manage the content, in files
|
|
311
346
|
|
|
312
|
-
You (or your dev team) write the markdown. Deploy site + foundation together.
|
|
313
|
-
|
|
314
|
-
The shortest path to a live site is free, on GitHub Pages, with a custom domain:
|
|
347
|
+
You (or your dev team) write the markdown. Deploy site + foundation together. The shortest path to a live site is free, on GitHub Pages, with a custom domain:
|
|
315
348
|
|
|
316
349
|
```bash
|
|
317
350
|
uniweb create . # from within a freshly-cloned GitHub repo
|
|
@@ -325,7 +358,7 @@ uniweb add ci --host=github-pages
|
|
|
325
358
|
|
|
326
359
|
**When to choose Uniweb hosting instead** (paid): when you need dynamic-page prerender at the edge (for collections fetched at runtime, not just at build time), foundation/runtime version propagation without redeploying every site, or edge SSR. If your site's content lives in markdown and updates ship via git, free CI is the right call.
|
|
327
360
|
|
|
328
|
-
###
|
|
361
|
+
### Your clients manage the content, in the app
|
|
329
362
|
|
|
330
363
|
You're building a foundation for clients, content authors, or any team that won't write markdown. The foundation is your product; the repo's `site/` is a test harness for the code (run `pnpm dev` to preview your components against sample content). You don't deploy a site — you register a foundation:
|
|
331
364
|
|
|
@@ -338,10 +371,6 @@ Real sites built on your foundation are managed in the **Uniweb app** — a visu
|
|
|
338
371
|
|
|
339
372
|
This is the best path when site content has a life independent of the foundation's release cycle — agencies, design studios, multi-client teams, or any project where content authors aren't the same people as the developers.
|
|
340
373
|
|
|
341
|
-
### Hybrid
|
|
342
|
-
|
|
343
|
-
Markdown in a git repo and content in the Uniweb apps can share the same site. `uniweb push` sends local content to the backend, `uniweb pull` brings the backend's content back — in a git repository by merging it into your branch, like `git pull`, so edits made on both surfaces at once are combined and only a genuine overlap is a conflict to settle — and `uniweb clone` bootstraps a local project from a site that already lives in the backend. Authors edit visually, devs edit in their IDE, both surfaces work on the same content. Review flows and branch isolation across the two are still evolving.
|
|
344
|
-
|
|
345
374
|
### Commands at a glance
|
|
346
375
|
|
|
347
376
|
| Command | What it does |
|
|
@@ -349,22 +378,20 @@ Markdown in a git repo and content in the Uniweb apps can share the same site. `
|
|
|
349
378
|
| `uniweb deploy` | Ask where the site should go, then do it. Remembers the answer in `deploy.yml`. |
|
|
350
379
|
| `uniweb add ci --host=<adapter>` | Scaffold a CI workflow (+ PR previews) so every push deploys. `github-pages`, `cloudflare-pages`, `netlify`, `vercel`. |
|
|
351
380
|
| `uniweb add ci --target foundation` | Publish foundations at permanent versioned GitHub Pages URLs — the free alternative to the catalog. |
|
|
352
|
-
| `uniweb publish` | Go live on Uniweb hosting (paid) —
|
|
381
|
+
| `uniweb publish` | Go live on Uniweb hosting (paid) — brings the site's foundation along, pushes the content, and serves the site dynamically. The canonical verb for Uniweb hosting. |
|
|
353
382
|
| `uniweb deploy --host=<adapter>` | Ship to a third-party static host in one step — builds `dist/`, uploads, invalidates. Drives that host's own CLI. |
|
|
354
383
|
| `uniweb export` | Produce a self-contained `dist/` for any static host. You upload it yourself. `--host=<adapter>` adds host-specific helper files. |
|
|
355
|
-
| `uniweb register --scope @org` | Register a foundation to the registry
|
|
384
|
+
| `uniweb register --scope @org` | Register a foundation to the registry, for sites managed in the app. |
|
|
356
385
|
| `uniweb build` | Inspect a build locally. For shipping, use `publish` (Uniweb hosting) or `deploy`/`export` (static hosts). |
|
|
357
386
|
| `uniweb update` | Align this project with the CLI you're running: bump `@uniweb/*` deps in every `package.json` to the CLI's matrix (then install), and refresh `AGENTS.md`. Pins to *this* CLI's matrix — run `npx uniweb@latest update` to align to the latest release. Updating the CLI itself is your package manager's job (`npm i -g uniweb@latest`). |
|
|
358
387
|
|
|
359
388
|
`--host=<adapter>` is the same option across `deploy`, `export`, and `add ci`. Built-in adapters: `github-pages`, `cloudflare-pages`, `netlify`, `vercel`, `s3-cloudfront`, and `generic-static` (an artifact shape for `export`, not a deploy target). Each adapter implements only the operations it supports, and the CLI never offers one it can't perform: `add ci` lists only hosts that can scaffold a workflow, and `deploy`'s picker lists only destinations with a working deploy hook.
|
|
360
389
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
Both paths use the same framework. The difference is who edits content, where it lives, and what gets deployed. For the deeper menu — standalone vs cataloged foundations, S3+CloudFront, manual exports, per-host recipes, foundation propagation — see → **[Deploying](https://github.com/uniweb/docs/blob/main/development/deploying.md)**.
|
|
390
|
+
For the deeper menu — standalone vs cataloged foundations, S3+CloudFront, manual exports, per-host recipes, foundation propagation — see → **[Deploying](https://github.com/uniweb/docs/blob/main/development/deploying.md)**.
|
|
364
391
|
|
|
365
392
|
---
|
|
366
393
|
|
|
367
|
-
## Keeping a Project
|
|
394
|
+
## Keeping a Project Current
|
|
368
395
|
|
|
369
396
|
Uniweb projects pin to specific `@uniweb/*` versions in their `package.json` files and ship an `AGENTS.md` stamped with the CLI version that wrote it. As the framework releases, both can drift from what the CLI you're running expects.
|
|
370
397
|
|
|
@@ -395,7 +422,7 @@ yarn global add uniweb@latest # yarn
|
|
|
395
422
|
|
|
396
423
|
## Documentation
|
|
397
424
|
|
|
398
|
-
Full documentation is
|
|
425
|
+
Full documentation is at **[uniweb.io/docs](https://uniweb.io/docs)**, written in the public [uniweb/docs](https://github.com/uniweb/docs) repository:
|
|
399
426
|
|
|
400
427
|
| Section | Topics |
|
|
401
428
|
| ------- | ------ |
|
|
@@ -404,6 +431,8 @@ Full documentation is available at **[github.com/uniweb/docs](https://github.com
|
|
|
404
431
|
| [Development](https://github.com/uniweb/docs/tree/main/development) | Building foundations, component patterns, data fetching, layouts |
|
|
405
432
|
| [Reference](https://github.com/uniweb/docs/tree/main/reference) | Configuration files, kit API, CLI commands, deployment |
|
|
406
433
|
|
|
434
|
+
For AI agents, the documentation's index is [uniweb.io/llms.txt](https://uniweb.io/llms.txt).
|
|
435
|
+
|
|
407
436
|
### Quick Reference
|
|
408
437
|
|
|
409
438
|
| Topic | Guide |
|
|
@@ -443,7 +472,6 @@ import { defineFoundationConfig } from '@uniweb/build'
|
|
|
443
472
|
|
|
444
473
|
export default defineFoundationConfig({
|
|
445
474
|
// All options are optional - entry is auto-generated
|
|
446
|
-
fileName: 'foundation', // Output file name
|
|
447
475
|
externals: [], // Additional packages to externalize
|
|
448
476
|
includeDefaultExternals: true, // Include react, @uniweb/core, etc.
|
|
449
477
|
tailwind: true, // Enable Tailwind CSS v4 Vite plugin
|
|
@@ -495,21 +523,25 @@ packages:
|
|
|
495
523
|
|
|
496
524
|
## FAQ
|
|
497
525
|
|
|
498
|
-
**
|
|
526
|
+
**Do I need the Uniweb app?**
|
|
499
527
|
|
|
500
|
-
|
|
528
|
+
No. The framework works on its own: content in markdown, built and deployed like any Vite project, to any static host. Connect the app when people who don't write code need to edit the site — or when you'd rather not build an editing interface for them.
|
|
529
|
+
|
|
530
|
+
**Is the app a CMS?**
|
|
501
531
|
|
|
502
|
-
|
|
532
|
+
It's where authors work: they compose pages from your section types and manage records through your schemas, with live previews. There's no admin interface or editing UI for you to build, and a site's content isn't locked in it: `uniweb clone` or `uniweb pull` brings it into a project as files in git, kept in sync both ways.
|
|
503
533
|
|
|
504
|
-
|
|
534
|
+
**How is this different from MDX?**
|
|
535
|
+
|
|
536
|
+
MDX blends markdown and JSX—content authors write code. Uniweb keeps them separate: content stays in markdown, components stay in React. Authors can still embed interactive components (via `` syntax), but they never see JSX. Component updates don't require content changes, and content changes can't break components.
|
|
505
537
|
|
|
506
|
-
**
|
|
538
|
+
**How is this different from Astro and other site frameworks?**
|
|
507
539
|
|
|
508
|
-
|
|
540
|
+
They build sites from code and content files, and so does Uniweb. Uniweb adds the other interface: a visual authoring app, kept in sync with your project, where your components are the authors' building blocks. The foundation model also makes components portable across sites, with any deployment — static, SSR, or platform-managed.
|
|
509
541
|
|
|
510
542
|
**Can I use an existing component library?**
|
|
511
543
|
|
|
512
|
-
Yes. Foundations are standard React. Import any library into your foundation components. The `{ content, params }` interface only applies to section types (components
|
|
544
|
+
Yes. Foundations are standard React. Import any library into your foundation components. The `{ content, params }` interface only applies to section types (the components authors pick from markdown) — everything else uses regular React props.
|
|
513
545
|
|
|
514
546
|
**Is this SEO-friendly?**
|
|
515
547
|
|
|
@@ -531,4 +563,4 @@ Yes — documentation is a natural fit. Content stays in markdown (easy to versi
|
|
|
531
563
|
|
|
532
564
|
## License
|
|
533
565
|
|
|
534
|
-
Apache 2.0
|
|
566
|
+
Apache 2.0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uniweb",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.0",
|
|
4
4
|
"description": "Create structured Vite + React sites with content/code separation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,15 +41,15 @@
|
|
|
41
41
|
"js-yaml": "^4.3.2",
|
|
42
42
|
"prompts": "^2.4.2",
|
|
43
43
|
"tar": "^7.5.21",
|
|
44
|
+
"@uniweb/content-writer": "~1.3.1",
|
|
44
45
|
"@uniweb/core": "~1.4.7",
|
|
45
46
|
"@uniweb/schemas": "~1.6.5",
|
|
46
|
-
"@uniweb/semantic-parser": "~1.13.0"
|
|
47
|
-
"@uniweb/content-writer": "~1.3.1"
|
|
47
|
+
"@uniweb/semantic-parser": "~1.13.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"@uniweb/build": "~1.10.2",
|
|
51
|
-
"@uniweb/
|
|
52
|
-
"@uniweb/
|
|
51
|
+
"@uniweb/content-reader": "~1.5.7",
|
|
52
|
+
"@uniweb/semantic-parser": "~1.13.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependenciesMeta": {
|
|
55
55
|
"@uniweb/build": {
|
package/partials/agents.md
CHANGED
|
@@ -33,15 +33,18 @@ You're building a *system* of section types, not individual pages. That's what m
|
|
|
33
33
|
| Existing project, component task (new section type, restyle) | **Part 2**, then Part 4 |
|
|
34
34
|
| Porting a design from React / Next / a generated site | **Part 1**, then Part 5 → *Migrating* |
|
|
35
35
|
|
|
36
|
-
###
|
|
36
|
+
### Four commands that replace guessing
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
|
+
uniweb status # what changed in the app, in git and in Uniweb — and what to run
|
|
39
40
|
uniweb inspect <path> # print the parsed content shape of a section or page
|
|
40
41
|
uniweb <command> --help # exact flags, always current — no side effects
|
|
41
42
|
uniweb doctor # diagnose project configuration (--fix to repair)
|
|
42
43
|
```
|
|
43
44
|
|
|
44
|
-
`uniweb inspect` is the important one. Every parse rule in Part 3 is faster to *confirm* than to re-derive, and re-deriving from memory is where agents go wrong. Don't predict the shape — print it.
|
|
45
|
+
`uniweb inspect` is the important one for content. Every parse rule in Part 3 is faster to *confirm* than to re-derive, and re-deriving from memory is where agents go wrong. Don't predict the shape — print it.
|
|
46
|
+
|
|
47
|
+
`uniweb status` is the one for a project other people edit. A site in the Uniweb app can change there at any time, teammates push to git, and Uniweb releases often. Run it when you begin, before you push, and after a command refuses: it changes nothing, and ends with the commands to run, in order (`--json` for a script).
|
|
45
48
|
|
|
46
49
|
### The four silent failures
|
|
47
50
|
|
|
@@ -59,7 +62,7 @@ This guide covers what you can't derive by reading code. Everything else is in t
|
|
|
59
62
|
**Start at the index.** One address, and it's the only documentation URL worth memorizing:
|
|
60
63
|
|
|
61
64
|
```
|
|
62
|
-
https://
|
|
65
|
+
https://uniweb.io/llms.txt
|
|
63
66
|
```
|
|
64
67
|
|
|
65
68
|
It lists every documentation page with a one-line description and a fetchable link. Go there whenever your question isn't answered in this file — and *especially* when you don't know whether a feature exists at all. That's where guessing does the most damage: **a 404 on a path you invented tells you your guess was wrong, not that the feature is missing.** Concluding "the framework doesn't support X" from a failed fetch is a mistake worth actively guarding against; the index answers the existence question directly.
|
|
@@ -76,7 +79,7 @@ Same content, greppable, and one network operation instead of many. `grep -ri "q
|
|
|
76
79
|
|
|
77
80
|
Documentation paths in this guide are given bare — `development/creating-components.md` — so they resolve three ways: as a key in the index, as a file in a clone, or at `https://raw.githubusercontent.com/uniweb/docs/main/{path}`.
|
|
78
81
|
|
|
79
|
-
> **Don't confuse the two doc sites.** `
|
|
82
|
+
> **Don't confuse the two doc sites.** `uniweb.io/docs` is the **developer** documentation — this is the one you want. `docs.uniweb.app` is the *author-facing* app documentation, written for non-technical people using the visual editor; it won't answer framework questions.
|
|
80
83
|
|
|
81
84
|
**The table below saves you the round trip** for the tasks that come up most:
|
|
82
85
|
|
|
@@ -189,6 +192,8 @@ The rest of this guide explains how Uniweb works. This part is what to do *first
|
|
|
189
192
|
|
|
190
193
|
### 1. Orient — what kind of workspace is this?
|
|
191
194
|
|
|
195
|
+
**Run `uniweb status` first.** It says whether the site changed in the app since this copy last synced, whether git or Uniweb has something newer, and what to run about each — before you edit something someone else just changed.
|
|
196
|
+
|
|
192
197
|
**There is no single layout. Read `pnpm-workspace.yaml` first** — its `packages:` globs name the shape in one glance:
|
|
193
198
|
|
|
194
199
|
| Globs | Layout | What it implies |
|
|
@@ -2818,7 +2823,8 @@ uniweb publish # Ship to Uniweb hosting, foundation included
|
|
|
2818
2823
|
uniweb add ci --target foundation # Publish a foundation for free at permanent versioned URLs
|
|
2819
2824
|
# (GitHub Pages → foundations/<name>/<version>/entry.js)
|
|
2820
2825
|
|
|
2821
|
-
uniweb
|
|
2826
|
+
uniweb status # What changed in the app, in git and in Uniweb — and what to run
|
|
2827
|
+
uniweb push / pull / clone # Git-style content sync with the Uniweb backend
|
|
2822
2828
|
uniweb refresh / sync # Catch up (git + backend, never pushes) / catch up, then push
|
|
2823
2829
|
uniweb login --org @acme # The workspace you work in — new sites are created there (see below)
|
|
2824
2830
|
uniweb register [--scope @scope] # Register a foundation + its data schemas to the registry
|
|
@@ -2830,7 +2836,7 @@ uniweb rename <foundation|site|extension> <old> <new> # Rename across the whol
|
|
|
2830
2836
|
uniweb i18n extract / init / sync / status / audit # Translation workflow (build first)
|
|
2831
2837
|
uniweb i18n init-freeform / update-hash / move / rename / prune --freeform
|
|
2832
2838
|
|
|
2833
|
-
uniweb -v #
|
|
2839
|
+
uniweb -v # CLI version — only a global install also says whether a newer one exists
|
|
2834
2840
|
uniweb doctor # Diagnose project configuration (--fix to auto-repair)
|
|
2835
2841
|
uniweb validate # Check file-based data against declared schemas (fails on a violation; --lax)
|
|
2836
2842
|
npx uniweb@latest update # Align @uniweb/* deps + AGENTS.md (--dry-run, --yes)
|
|
@@ -2896,6 +2902,8 @@ Foundations have their own free path too: `uniweb add ci --target foundation` pu
|
|
|
2896
2902
|
- **Git is the reviewed, durable record** — you `pull` content back, read it with `git diff`, and commit.
|
|
2897
2903
|
- **Authors never push or pull.** For them, content simply updates, whether the change came from another author or from a developer's CLI.
|
|
2898
2904
|
|
|
2905
|
+
**Working on a site others edit — run `uniweb status` when you begin, before you push, and after any refusal.** It reads the backend without taking anything: what changed there since this copy last synced, file by file; what you hold that it lacks; whether the site is live; who has it open in the app right now, and on which file. Then it lists the commands to run, in an order that works from the top — `uniweb pull` before the push it would otherwise refuse. Three habits go with it: take what changed (`pull`, or `refresh`) before you edit; never `--force` past a refusal; and when someone has a page open in the app, tell the person before you change that page. A step marked *ask the person first* — going live, which may cost money — is theirs to decide.
|
|
2906
|
+
|
|
2899
2907
|
**Nobody's work is overwritten without asking.** `uniweb push` is refused if the site changed on the backend since your last pull — usually an author editing in the app — and reports what changed; nothing is written. Edits to different sections never collide. **In a git repository `uniweb pull` merges, like `git pull`:** it commits the backend's content (*"The site's content on …"*) and merges that commit into your branch, against the last state of the site your history shares with the backend. Your work, committed or not, and a teammate's arriving through git are kept; a file the backend never had is never deleted; changes to different parts of a file combine silently; and only a genuine overlap leaves conflict markers and a non-zero exit — so `uniweb pull && uniweb push` never ships markers. Settle a conflict as in any merge, then `git commit`; where your uncommitted changes overlap what the pull brought, the markers are theirs — settle them and `git add` each file, then `git stash drop` (git keeps them in the stash too). A push or publish is refused while a file under the site is in conflict. **In a git repository a push sends what you have committed:** with the site's content not committed it is refused before anything is sent, naming the files — commit them, or run `uniweb push --commit -m "…"` (it commits the site's content only, and leaves anything else staged as it is); `publish` and `sync` take `--commit` too. That commit is where the next pull merges from, which is how the pull tells your changes from the backend's. What the push writes back into the files — the ids the backend assigned — it commits itself, as `uniweb`. When the backend has nothing new, a pull says so and lists the files where yours hold changes it lacks. `uniweb refresh` runs `git pull` first, then the same pull. A push is also refused when your branch does not hold what this copy last took from the backend — after `git merge --abort`, or in a fresh clone that has not pulled — so pull, then push. Outside git — which includes a folder the repository around it ignores, such as a scratch directory — `uniweb pull` takes the backend's version over your files, asking first. `--force` is the deliberate overwrite (on `push` it replaces the backend's changes, on `pull` it discards yours); don't use it to get past a refusal. `uniweb sync` is `refresh` then `push`; neither publishes.
|
|
2900
2908
|
|
|
2901
2909
|
**`sync.json` says which site this is, on each backend.** The first push to a backend records what that backend assigned — the site's id and owner, the ids of its records and uploaded files — in `sync.json` beside `site.yml`. In a git repository the push commits it; never edit it. **To make a new site from a copy of a project, run `uniweb forget --all` in the copy before its first push** — the copy carries the original's `sync.json`, so otherwise its push updates the original's site. When two projects in one workspace hold the same site, a push or publish from either is refused until that is done. `uniweb forget --server <url>` removes just one backend's records, such as a scratch server's. A record file's `$uuid` is its own id and stays in both cases. **`push`, `pull` and `publish` go to the backend you are logged in to** — the last `uniweb login --server <url>` — and never to one you are not logged in to. A bare `uniweb login` logs in to https://uniweb.app; for any other backend, name it — logging in is how you switch, and the backend commands take no `--server` of their own. When the project has no site on that backend but has one elsewhere, a push says so before creating a new one.
|
|
@@ -2942,12 +2950,15 @@ Either side can publish. Nothing about this changes how you build: the same foun
|
|
|
2942
2950
|
### Staying current
|
|
2943
2951
|
|
|
2944
2952
|
```bash
|
|
2945
|
-
uniweb
|
|
2953
|
+
uniweb status # among its checks: whether a newer Uniweb is out than this project runs
|
|
2954
|
+
uniweb -v # CLI version — only a global install also says whether a newer one exists
|
|
2946
2955
|
uniweb doctor # report drift in this project, changing nothing
|
|
2947
2956
|
npx uniweb@latest update --dry-run # preview exactly what update would change
|
|
2948
2957
|
npx uniweb@latest update # apply: align @uniweb/* deps AND refresh AGENTS.md
|
|
2949
2958
|
```
|
|
2950
2959
|
|
|
2960
|
+
When `status` names a newer release, take it: `npx uniweb@latest update`, then build and look at the pages. Releases rarely ask anything of a project.
|
|
2961
|
+
|
|
2951
2962
|
**`npx uniweb@latest update` is the command for bringing a project up to date.** It aligns the project's `@uniweb/*` dependencies *and* this AGENTS.md to the version matrix of the CLI that runs it. Deps and documentation move together — that's the whole point of the verb.
|
|
2952
2963
|
|
|
2953
2964
|
**What the version numbers mean.** A patch brings fixes and features; a minor version is where Uniweb puts breaking changes — `update` lists each package that crosses one, so build and check the project before shipping — and a major is kept for something really big. Dependencies are written as tilde ranges (`~1.0.1`), so `pnpm install` and `pnpm update` never cross a minor on their own. The move from 0.x to 1.0.1 asks nothing of a project that was on the latest 0.x versions — 1.0.1 carried every package's 0.x line over — though `update` marks each package `major · BREAKING`.
|
|
@@ -3134,7 +3145,7 @@ Loud failures:
|
|
|
3134
3145
|
|
|
3135
3146
|
## Documentation index
|
|
3136
3147
|
|
|
3137
|
-
**Index of every page: https://
|
|
3148
|
+
**Index of every page: https://uniweb.io/llms.txt** — start there when you don't know which page you need.
|
|
3138
3149
|
|
|
3139
3150
|
Source repo (public, cloneable): **https://github.com/uniweb/docs** · any page as raw markdown at `https://raw.githubusercontent.com/uniweb/docs/main/{section}/{page}.md`. See *Documentation* in Part 0 for when to fetch versus clone.
|
|
3140
3151
|
|