uniweb 0.8.14 → 0.8.16
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 +42 -12
- package/package.json +19 -6
- package/partials/agents.md +16 -13
- package/partials/components-docs.hbs +2 -2
- package/partials/config-reference.hbs +1 -1
- package/src/commands/add.js +21 -10
- package/src/commands/build.js +29 -41
- package/src/commands/deploy.js +272 -0
- package/src/commands/doctor.js +2 -2
- package/src/commands/handoff.js +254 -0
- package/src/commands/invite.js +326 -0
- package/src/commands/login.js +87 -0
- package/src/commands/publish.js +300 -0
- package/src/commands/template.js +230 -0
- package/src/index.js +265 -28
- package/src/utils/auth.js +150 -0
- package/src/utils/registry.js +361 -0
- package/src/utils/update-check.js +105 -0
- package/src/versions.js +1 -1
package/README.md
CHANGED
|
@@ -36,10 +36,10 @@ Edit files in `site/pages/` and `foundation/src/sections/` to see changes instan
|
|
|
36
36
|
| **Store** | E-commerce with product grid |
|
|
37
37
|
| **Extensions** | Multi-foundation with visual effects extension |
|
|
38
38
|
|
|
39
|
-
Use `--blank` for an empty workspace (no packages) — grow with `uniweb add`.
|
|
40
|
-
|
|
41
39
|
**See them live:** [View all template demos](https://uniweb.github.io/templates/)
|
|
42
40
|
|
|
41
|
+
Use `--blank` for an empty workspace (no packages) — grow with `uniweb add`.
|
|
42
|
+
|
|
43
43
|
Or skip the interactive prompt:
|
|
44
44
|
|
|
45
45
|
```bash
|
|
@@ -164,13 +164,43 @@ export default function Hero({ content, params }) {
|
|
|
164
164
|
|
|
165
165
|
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.
|
|
166
166
|
|
|
167
|
+
### Composition
|
|
168
|
+
|
|
169
|
+
Sections aren't limited to flat content. Content authors can embed interactive React components using markdown image syntax:
|
|
170
|
+
|
|
171
|
+
```markdown
|
|
172
|
+
---
|
|
173
|
+
type: SplitContent
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
# See it in action
|
|
177
|
+
|
|
178
|
+
The architecture handles the hard parts so you can focus on what matters.
|
|
179
|
+
|
|
180
|
+
{period=30d}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
`@PerformanceChart` is a full React component — a ThreeJS animation, an interactive diagram, a live data visualization — placed by the content author, rendered in the component's visual slot via `<Visual>`. It looks like an image reference, but it can be anything.
|
|
184
|
+
|
|
185
|
+
Authors can also compose layouts from reusable section types using child sections:
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
pages/home/
|
|
189
|
+
├── highlights.md # type: Grid, columns: 3
|
|
190
|
+
├── @stats.md # type: StatCard
|
|
191
|
+
├── @testimonial.md # type: Testimonial
|
|
192
|
+
└── @demo.md # type: SplitContent (with an embedded @LiveDemo inset)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
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.
|
|
196
|
+
|
|
167
197
|
## Next Steps
|
|
168
198
|
|
|
169
199
|
After creating your project:
|
|
170
200
|
|
|
171
201
|
1. **Explore the structure** — Browse `site/pages/` to see how content is organized. Each page folder contains `page.yml` (metadata) and `.md` files (sections).
|
|
172
202
|
|
|
173
|
-
2. **Generate component docs** — Run `
|
|
203
|
+
2. **Generate component docs** — Run `uniweb docs` to create `COMPONENTS.md` with all available components, their parameters, and presets.
|
|
174
204
|
|
|
175
205
|
3. **Learn the configuration** — Run `uniweb docs site` or `uniweb docs page` for quick reference on configuration options.
|
|
176
206
|
|
|
@@ -237,31 +267,31 @@ Start simple. Add what you need, when you need it:
|
|
|
237
267
|
cd my-site
|
|
238
268
|
|
|
239
269
|
# Add a co-located foundation + site pair
|
|
240
|
-
|
|
270
|
+
uniweb add project blog
|
|
241
271
|
|
|
242
272
|
# Add a second foundation at root
|
|
243
|
-
|
|
273
|
+
uniweb add foundation ui
|
|
244
274
|
|
|
245
275
|
# Add a site wired to a specific foundation
|
|
246
|
-
|
|
276
|
+
uniweb add site docs --foundation ui
|
|
247
277
|
|
|
248
278
|
# Add an extension (auto-wired to the only site)
|
|
249
|
-
|
|
279
|
+
uniweb add extension effects
|
|
250
280
|
|
|
251
281
|
# Scaffold + apply content from an official template
|
|
252
|
-
|
|
282
|
+
uniweb add project marketing --from marketing
|
|
253
283
|
```
|
|
254
284
|
|
|
255
285
|
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.
|
|
256
286
|
|
|
257
|
-
>
|
|
287
|
+
> **Install the CLI globally** with `npm i -g uniweb` for the best experience. You can also use `npx uniweb` or `pnpm uniweb` without a global install.
|
|
258
288
|
|
|
259
289
|
**Or start blank and build up:**
|
|
260
290
|
|
|
261
291
|
```bash
|
|
262
292
|
pnpm create uniweb acme --blank
|
|
263
293
|
cd acme
|
|
264
|
-
|
|
294
|
+
uniweb add project main
|
|
265
295
|
pnpm install
|
|
266
296
|
pnpm dev
|
|
267
297
|
```
|
|
@@ -386,7 +416,7 @@ packages:
|
|
|
386
416
|
|
|
387
417
|
**How is this different from MDX?**
|
|
388
418
|
|
|
389
|
-
MDX blends markdown and JSX—content authors write code. Uniweb keeps them separate: content stays in markdown, components stay in React.
|
|
419
|
+
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.
|
|
390
420
|
|
|
391
421
|
**How is this different from Astro?**
|
|
392
422
|
|
|
@@ -420,4 +450,4 @@ Yes — documentation is a natural fit. Content stays in markdown (easy to versi
|
|
|
420
450
|
|
|
421
451
|
## License
|
|
422
452
|
|
|
423
|
-
Apache 2.0
|
|
453
|
+
Apache 2.0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uniweb",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.16",
|
|
4
4
|
"description": "Create structured Vite + React sites with content/code separation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,11 +41,24 @@
|
|
|
41
41
|
"js-yaml": "^4.1.0",
|
|
42
42
|
"prompts": "^2.4.2",
|
|
43
43
|
"tar": "^7.0.0",
|
|
44
|
-
"@uniweb/
|
|
45
|
-
"@uniweb/content-reader": "1.1.4",
|
|
46
|
-
"@uniweb/kit": "0.7.10",
|
|
47
|
-
"@uniweb/runtime": "0.6.10",
|
|
44
|
+
"@uniweb/runtime": "0.6.11",
|
|
48
45
|
"@uniweb/core": "0.5.10",
|
|
49
|
-
"@uniweb/
|
|
46
|
+
"@uniweb/kit": "0.7.11"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"@uniweb/build": "0.8.15",
|
|
50
|
+
"@uniweb/semantic-parser": "1.1.6",
|
|
51
|
+
"@uniweb/content-reader": "1.1.4"
|
|
52
|
+
},
|
|
53
|
+
"peerDependenciesMeta": {
|
|
54
|
+
"@uniweb/build": {
|
|
55
|
+
"optional": true
|
|
56
|
+
},
|
|
57
|
+
"@uniweb/content-reader": {
|
|
58
|
+
"optional": true
|
|
59
|
+
},
|
|
60
|
+
"@uniweb/semantic-parser": {
|
|
61
|
+
"optional": true
|
|
62
|
+
}
|
|
50
63
|
}
|
|
51
64
|
}
|
package/partials/agents.md
CHANGED
|
@@ -83,7 +83,7 @@ Use `--template <n>` for an official template (`none`, `starter`, `marketing`, `
|
|
|
83
83
|
### Adding a co-located project
|
|
84
84
|
|
|
85
85
|
```bash
|
|
86
|
-
|
|
86
|
+
uniweb add project docs
|
|
87
87
|
pnpm install
|
|
88
88
|
```
|
|
89
89
|
|
|
@@ -92,10 +92,10 @@ This creates `docs/foundation/` + `docs/site/` with package names `docs-foundati
|
|
|
92
92
|
### Adding individual packages
|
|
93
93
|
|
|
94
94
|
```bash
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
uniweb add foundation # First foundation → ./foundation/
|
|
96
|
+
uniweb add foundation ui # Named → ./ui/
|
|
97
|
+
uniweb add site # First site → ./site/
|
|
98
|
+
uniweb add site blog # Named → ./blog/
|
|
99
99
|
```
|
|
100
100
|
|
|
101
101
|
The name is both the directory name and the package name. Use `--project <n>` to co-locate under a project directory (e.g., `--project docs` → `docs/foundation/`).
|
|
@@ -103,8 +103,8 @@ The name is both the directory name and the package name. Use `--project <n>` to
|
|
|
103
103
|
### Adding section types
|
|
104
104
|
|
|
105
105
|
```bash
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
uniweb add section Hero
|
|
107
|
+
uniweb add section Hero --foundation ui # When multiple foundations exist
|
|
108
108
|
```
|
|
109
109
|
|
|
110
110
|
Creates `src/sections/Hero/index.jsx` and `meta.js` with a minimal CCA-proper starter. The dev server picks it up automatically — no build or install needed.
|
|
@@ -340,9 +340,9 @@ Check out [this](/a) link. ← inline → stays in paragraphs as <a> tag
|
|
|
340
340
|
This is [less important]{muted} context.
|
|
341
341
|
```
|
|
342
342
|
|
|
343
|
-
`accent` (colored + bold) and `muted` (subtle) adapt to context automatically. Components receive HTML strings with spans applied: `<span accent="true">faster</span>`.
|
|
343
|
+
`accent` (link-colored + bold), `callout` (accent-colored + bold), and `muted` (subtle) are built-in defaults that adapt to context automatically. Components receive HTML strings with spans applied: `<span accent="true">faster</span>`.
|
|
344
344
|
|
|
345
|
-
Sites can define additional named styles in `theme.yml`'s `inline:` section.
|
|
345
|
+
Sites can override these or define additional named styles in `theme.yml`'s `inline:` section.
|
|
346
346
|
|
|
347
347
|
### Fenced Code in Content
|
|
348
348
|
|
|
@@ -676,6 +676,9 @@ inline:
|
|
|
676
676
|
accent:
|
|
677
677
|
color: var(--link)
|
|
678
678
|
font-weight: '600'
|
|
679
|
+
callout:
|
|
680
|
+
color: var(--accent)
|
|
681
|
+
font-weight: '600'
|
|
679
682
|
|
|
680
683
|
vars:
|
|
681
684
|
header-height: 5rem
|
|
@@ -1282,9 +1285,9 @@ Semantic tokens come from `theme-tokens.css` (populated from `theme.yml`). Use `
|
|
|
1282
1285
|
|
|
1283
1286
|
**Content not appearing as expected?**
|
|
1284
1287
|
```bash
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
+
uniweb inspect pages/home/hero.md # Single section
|
|
1289
|
+
uniweb inspect pages/home/ # Whole page
|
|
1290
|
+
uniweb inspect pages/home/hero.md --raw # ProseMirror AST
|
|
1288
1291
|
```
|
|
1289
1292
|
|
|
1290
1293
|
## Learning from Official Templates
|
|
@@ -1292,7 +1295,7 @@ pnpm uniweb inspect pages/home/hero.md --raw # ProseMirror AST
|
|
|
1292
1295
|
When you're unsure how to implement a pattern — data fetching, i18n, layouts, insets, theming — install an official template as a reference project in your workspace:
|
|
1293
1296
|
|
|
1294
1297
|
```bash
|
|
1295
|
-
|
|
1298
|
+
uniweb add project marketing --from marketing
|
|
1296
1299
|
pnpm install
|
|
1297
1300
|
```
|
|
1298
1301
|
|
|
@@ -4,10 +4,10 @@ Generate up-to-date documentation for all foundation components:
|
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
# From foundation directory
|
|
7
|
-
|
|
7
|
+
uniweb docs
|
|
8
8
|
|
|
9
9
|
# Or from site directory (auto-detects linked foundation)
|
|
10
|
-
cd site &&
|
|
10
|
+
cd site && uniweb docs
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
This creates `COMPONENTS.md` with details on each component's parameters, presets, and content elements. The documentation is generated from component `meta.js` files, so it's always current.
|
package/src/commands/add.js
CHANGED
|
@@ -121,7 +121,7 @@ export async function add(rawArgs) {
|
|
|
121
121
|
error(`Missing subcommand.\n`)
|
|
122
122
|
log(formatOptions([
|
|
123
123
|
{ label: 'project', description: 'Co-located foundation + site pair' },
|
|
124
|
-
{ label: 'foundation', description: 'Component
|
|
124
|
+
{ label: 'foundation', description: 'Component system for content authors' },
|
|
125
125
|
{ label: 'site', description: 'Content site' },
|
|
126
126
|
{ label: 'extension', description: 'Additional component package' },
|
|
127
127
|
{ label: 'section', description: 'Section type in a foundation' },
|
|
@@ -137,7 +137,7 @@ export async function add(rawArgs) {
|
|
|
137
137
|
message: 'What would you like to add?',
|
|
138
138
|
choices: [
|
|
139
139
|
{ title: 'Project', value: 'project', description: 'Co-located foundation + site pair' },
|
|
140
|
-
{ title: 'Foundation', value: 'foundation', description: 'Component
|
|
140
|
+
{ title: 'Foundation', value: 'foundation', description: 'Component system for content authors' },
|
|
141
141
|
{ title: 'Site', value: 'site', description: 'Content site' },
|
|
142
142
|
{ title: 'Extension', value: 'extension', description: 'Additional component package' },
|
|
143
143
|
{ title: 'Section', value: 'section', description: 'Section type in a foundation' },
|
|
@@ -352,7 +352,7 @@ async function addSite(rootDir, projectName, opts, pm = 'pnpm') {
|
|
|
352
352
|
}, {
|
|
353
353
|
onProgress: (msg) => info(` ${msg}`),
|
|
354
354
|
})
|
|
355
|
-
log(` ${colors.yellow}⚠ No foundation wired. Add one later with:
|
|
355
|
+
log(` ${colors.yellow}⚠ No foundation wired. Add one later with: uniweb add foundation${colors.reset}`)
|
|
356
356
|
}
|
|
357
357
|
|
|
358
358
|
// Apply template content if --from specified
|
|
@@ -594,7 +594,8 @@ async function addProject(rootDir, projectName, opts, pm = 'pnpm') {
|
|
|
594
594
|
* - --project: {project}/foundation (co-located)
|
|
595
595
|
* - Existing co-located glob: follow pattern
|
|
596
596
|
* - Existing segregated glob: follow pattern
|
|
597
|
-
* -
|
|
597
|
+
* - Named (e.g., "marketing"): segregated at foundations/{name}
|
|
598
|
+
* - Unnamed: root-level 'foundation'
|
|
598
599
|
* - Already have one: error in non-interactive, ask in interactive
|
|
599
600
|
*/
|
|
600
601
|
async function resolveFoundationTarget(rootDir, name, opts) {
|
|
@@ -619,8 +620,13 @@ async function resolveFoundationTarget(rootDir, name, opts) {
|
|
|
619
620
|
return `foundations/${name || 'foundation'}`
|
|
620
621
|
}
|
|
621
622
|
|
|
622
|
-
//
|
|
623
|
-
|
|
623
|
+
// Named foundation → segregated layout (foundations/{name})
|
|
624
|
+
if (name) {
|
|
625
|
+
return `foundations/${name}`
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// Unnamed → root-level 'foundation'
|
|
629
|
+
const dirName = 'foundation'
|
|
624
630
|
|
|
625
631
|
// Check if target already exists
|
|
626
632
|
if (!existsSync(join(rootDir, dirName))) {
|
|
@@ -667,8 +673,13 @@ async function resolveSiteTarget(rootDir, name, opts) {
|
|
|
667
673
|
return `sites/${name || 'site'}`
|
|
668
674
|
}
|
|
669
675
|
|
|
670
|
-
//
|
|
671
|
-
|
|
676
|
+
// Named site → segregated layout (sites/{name})
|
|
677
|
+
if (name) {
|
|
678
|
+
return `sites/${name}`
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// Unnamed → root-level 'site'
|
|
682
|
+
const dirName = 'site'
|
|
672
683
|
|
|
673
684
|
// Check if target already exists
|
|
674
685
|
if (!existsSync(join(rootDir, dirName))) {
|
|
@@ -1050,9 +1061,9 @@ ${colors.bright}Examples:${colors.reset}
|
|
|
1050
1061
|
uniweb add project docs # Create docs/foundation/ + docs/site/
|
|
1051
1062
|
uniweb add project docs --from academic # Co-located pair + academic content
|
|
1052
1063
|
uniweb add foundation # Create ./foundation/ at root
|
|
1053
|
-
uniweb add foundation ui # Create ./ui/
|
|
1064
|
+
uniweb add foundation ui # Create ./foundations/ui/
|
|
1054
1065
|
uniweb add site # Create ./site/ at root
|
|
1055
|
-
uniweb add site blog --foundation marketing # Create ./blog/ wired to marketing
|
|
1066
|
+
uniweb add site blog --foundation marketing # Create ./sites/blog/ wired to marketing
|
|
1056
1067
|
uniweb add extension effects --site site # Create ./extensions/effects/
|
|
1057
1068
|
uniweb add section Hero # Create Hero section type
|
|
1058
1069
|
uniweb add section Hero --foundation ui # Target specific foundation
|
package/src/commands/build.js
CHANGED
|
@@ -18,9 +18,7 @@ import { writeFile, mkdir } from 'node:fs/promises'
|
|
|
18
18
|
// Import build utilities from @uniweb/build
|
|
19
19
|
import {
|
|
20
20
|
generateEntryPoint,
|
|
21
|
-
buildSchema,
|
|
22
21
|
discoverComponents,
|
|
23
|
-
processAllPreviews,
|
|
24
22
|
} from '@uniweb/build'
|
|
25
23
|
import { readSiteConfig } from '@uniweb/build/site'
|
|
26
24
|
import { readWorkspaceConfig, resolveGlob } from '../utils/config.js'
|
|
@@ -130,7 +128,6 @@ function runCommand(command, args, cwd) {
|
|
|
130
128
|
*/
|
|
131
129
|
async function buildFoundation(projectDir, options = {}) {
|
|
132
130
|
const srcDir = join(projectDir, 'src')
|
|
133
|
-
const distDir = join(projectDir, 'dist')
|
|
134
131
|
|
|
135
132
|
info('Building foundation...')
|
|
136
133
|
|
|
@@ -163,50 +160,19 @@ async function buildFoundation(projectDir, options = {}) {
|
|
|
163
160
|
// For now, just run the standard vite build
|
|
164
161
|
await runCommand('npx', ['vite', 'build'], projectDir)
|
|
165
162
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
// 4. Generate schema.json
|
|
169
|
-
log('')
|
|
170
|
-
info('Generating schema.json...')
|
|
171
|
-
let schema = await buildSchema(srcDir)
|
|
172
|
-
|
|
173
|
-
await mkdir(distDir, { recursive: true })
|
|
163
|
+
// Vite's foundation plugin generates dist/meta/schema.json
|
|
164
|
+
// and processes preview images during the build.
|
|
174
165
|
|
|
175
|
-
|
|
176
|
-
log('')
|
|
177
|
-
info('Processing preview images...')
|
|
178
|
-
const isProduction = process.env.NODE_ENV === 'production' || !process.env.NODE_ENV
|
|
179
|
-
const { schema: updatedSchema, totalImages } = await processAllPreviews(
|
|
180
|
-
srcDir,
|
|
181
|
-
distDir,
|
|
182
|
-
schema,
|
|
183
|
-
isProduction
|
|
184
|
-
)
|
|
185
|
-
schema = updatedSchema
|
|
186
|
-
|
|
187
|
-
if (totalImages > 0) {
|
|
188
|
-
success(`Processed ${totalImages} preview image${totalImages > 1 ? 's' : ''} (converted to webp)`)
|
|
189
|
-
} else {
|
|
190
|
-
log(` ${colors.dim}No preview images found${colors.reset}`)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// 6. Write schema.json
|
|
194
|
-
const schemaPath = join(distDir, 'schema.json')
|
|
195
|
-
await writeFile(schemaPath, JSON.stringify(schema, null, 2), 'utf-8')
|
|
196
|
-
|
|
197
|
-
success(`Generated schema.json with ${componentNames.length} components`)
|
|
166
|
+
success('Vite build complete')
|
|
198
167
|
|
|
199
168
|
// Summary
|
|
200
169
|
log('')
|
|
201
170
|
log(`${colors.green}${colors.bright}Build complete!${colors.reset}`)
|
|
171
|
+
|
|
202
172
|
log('')
|
|
203
|
-
log(`
|
|
204
|
-
log(` ${colors.
|
|
205
|
-
log(` ${colors.
|
|
206
|
-
log(` ${colors.dim}dist/schema.json${colors.reset} - Component schemas`)
|
|
207
|
-
if (totalImages > 0) {
|
|
208
|
-
log(` ${colors.dim}dist/assets/[component]/${colors.reset} - Preview images`)
|
|
209
|
-
}
|
|
173
|
+
log(`${colors.bright}Share with clients:${colors.reset}`)
|
|
174
|
+
log(` ${colors.bright}uniweb publish${colors.reset} Register your foundation (one-time setup)`)
|
|
175
|
+
log(` ${colors.bright}uniweb handoff <email>${colors.reset} Hand off a site to a client`)
|
|
210
176
|
}
|
|
211
177
|
|
|
212
178
|
/**
|
|
@@ -489,6 +455,8 @@ async function buildSite(projectDir, options = {}) {
|
|
|
489
455
|
process.exit(1)
|
|
490
456
|
}
|
|
491
457
|
}
|
|
458
|
+
|
|
459
|
+
showNextSteps(false, true)
|
|
492
460
|
}
|
|
493
461
|
|
|
494
462
|
/**
|
|
@@ -625,6 +593,26 @@ async function buildWorkspace(workspaceDir, options = {}) {
|
|
|
625
593
|
log(`${colors.green}${colors.bright}Workspace build complete!${colors.reset}`)
|
|
626
594
|
log('')
|
|
627
595
|
log(`Built ${parts.join(', ')}`)
|
|
596
|
+
|
|
597
|
+
showNextSteps(foundations.length > 0, sites.length > 0)
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Show next-step hints after workspace build
|
|
602
|
+
*/
|
|
603
|
+
function showNextSteps(hasFoundations, hasSites) {
|
|
604
|
+
if (hasFoundations) {
|
|
605
|
+
log('')
|
|
606
|
+
log(`${colors.bright}Share with clients:${colors.reset}`)
|
|
607
|
+
log(` ${colors.bright}uniweb publish${colors.reset} Register your foundation (one-time setup)`)
|
|
608
|
+
log(` ${colors.bright}uniweb handoff <email>${colors.reset} Hand off a site to a client`)
|
|
609
|
+
}
|
|
610
|
+
if (hasSites) {
|
|
611
|
+
log('')
|
|
612
|
+
log(`${colors.bright}Deploy:${colors.reset}`)
|
|
613
|
+
log(` ${colors.bright}uniweb deploy${colors.reset} Uniweb hosting`)
|
|
614
|
+
log(` Or upload ${colors.cyan}dist/${colors.reset} to any static host`)
|
|
615
|
+
}
|
|
628
616
|
}
|
|
629
617
|
|
|
630
618
|
/**
|