uniweb 0.8.7 → 0.8.8
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/package.json +5 -5
- package/partials/agents.md +110 -12
- package/partials/ai-assistance.hbs +5 -3
- package/partials/learn-more.hbs +3 -2
- package/starter/foundation/src/sections/Section/index.jsx +13 -39
- package/starter/foundation/src/sections/Section/meta.js +2 -17
- package/starter/site/pages/home/1-welcome.md.hbs +1 -1
- package/templates/site/theme.yml +3 -3
- package/templates/workspace/README.md.hbs +12 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uniweb",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.8",
|
|
4
4
|
"description": "Create structured Vite + React sites with content/code separation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"js-yaml": "^4.1.0",
|
|
42
42
|
"prompts": "^2.4.2",
|
|
43
43
|
"tar": "^7.0.0",
|
|
44
|
-
"@uniweb/build": "0.8.
|
|
45
|
-
"@uniweb/
|
|
46
|
-
"@uniweb/
|
|
47
|
-
"@uniweb/
|
|
44
|
+
"@uniweb/build": "0.8.7",
|
|
45
|
+
"@uniweb/kit": "0.7.5",
|
|
46
|
+
"@uniweb/core": "0.5.6",
|
|
47
|
+
"@uniweb/runtime": "0.6.6"
|
|
48
48
|
}
|
|
49
49
|
}
|
package/partials/agents.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# AGENTS.md
|
|
2
2
|
|
|
3
|
+
> A comprehensive guide to building with Uniweb — for developers and AI assistants alike.
|
|
4
|
+
|
|
3
5
|
Uniweb is a Component Content Architecture (CCA). Content lives in markdown, code lives in React components, and a runtime connects them. The runtime handles section wrapping, background rendering, context theming, and token resolution — components receive pre-parsed content and render it with semantic tokens. Understanding what the runtime does (and therefore what components should *not* do) is the key to working effectively in this architecture.
|
|
4
6
|
|
|
5
7
|
## Documentation
|
|
@@ -135,9 +137,9 @@ The semantic parser extracts markdown into a flat, guaranteed structure. No null
|
|
|
135
137
|
|
|
136
138
|
```js
|
|
137
139
|
content = {
|
|
138
|
-
title: '', // Main heading
|
|
140
|
+
title: '', // Main heading (string or string[] for multi-line)
|
|
139
141
|
pretitle: '', // Heading before main title (auto-detected)
|
|
140
|
-
subtitle: '', // Heading after title
|
|
142
|
+
subtitle: '', // Heading after title (string or string[] for multi-line)
|
|
141
143
|
subtitle2: '', // Third-level heading
|
|
142
144
|
paragraphs: [], // Text blocks
|
|
143
145
|
links: [], // { href, label, role } — standalone links become buttons
|
|
@@ -194,6 +196,55 @@ Enterprise-grade security. │ content.items[1].paragraphs[0] = "Enterprise
|
|
|
194
196
|
|
|
195
197
|
Headings before the main title become `pretitle`. Headings after the main title at a lower importance become `subtitle`. Headings that appear after body content (paragraphs, links, images) start the `items` array.
|
|
196
198
|
|
|
199
|
+
### Multi-Line Headings
|
|
200
|
+
|
|
201
|
+
Consecutive headings at the same level merge into a title array — a single heading split across visual lines:
|
|
202
|
+
|
|
203
|
+
```markdown
|
|
204
|
+
# Build the future │ content.title = ["Build the future", "with confidence"]
|
|
205
|
+
# with confidence │
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Kit's `<H1>`, `<H2>`, etc. render arrays as a single tag with line breaks. This is how you create dramatic multi-line hero headlines.
|
|
209
|
+
|
|
210
|
+
**Works with accent styling:**
|
|
211
|
+
|
|
212
|
+
```markdown
|
|
213
|
+
# Build the future │ content.title = [
|
|
214
|
+
# [with confidence]{accent} │ "Build the future",
|
|
215
|
+
│ "<span accent=\"true\">with confidence</span>"
|
|
216
|
+
│ ]
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Works at any heading slot** — title, subtitle, items:
|
|
220
|
+
|
|
221
|
+
```markdown
|
|
222
|
+
### Our Mission │ content.pretitle = "Our Mission"
|
|
223
|
+
# Build the future │ content.title = ["Build the future",
|
|
224
|
+
# with confidence │ "with confidence"]
|
|
225
|
+
## The platform for │ content.subtitle = ["The platform for",
|
|
226
|
+
## modern teams │ "modern teams"]
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**Rule:** Same-level continuation only applies before going deeper. Once a subtitle level is reached, same-level headings start new items instead of merging:
|
|
230
|
+
|
|
231
|
+
```markdown
|
|
232
|
+
# Features │ title = "Features"
|
|
233
|
+
│
|
|
234
|
+
We built this for you. │ paragraph
|
|
235
|
+
│
|
|
236
|
+
### Fast │ items[0].title = "Fast"
|
|
237
|
+
### Secure │ items[1].title = "Secure" ← new item, not merged
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Use `---` to force separate items when same-level headings would otherwise merge:
|
|
241
|
+
|
|
242
|
+
```markdown
|
|
243
|
+
# Line one │ title = "Line one"
|
|
244
|
+
--- │ ← divider forces split
|
|
245
|
+
# Line two │ items[0].title = "Line two"
|
|
246
|
+
```
|
|
247
|
+
|
|
197
248
|
**Lists** contain bullet or ordered list items. Each list item is an object with the same content shape — not a plain string:
|
|
198
249
|
|
|
199
250
|
```markdown
|
|
@@ -280,6 +331,49 @@ Links mixed with non-link text stay as inline `<a>` tags within `content.paragra
|
|
|
280
331
|
Check out [this](/a) and [that](/b). ← inline links in paragraph text, NOT in content.links[]
|
|
281
332
|
```
|
|
282
333
|
|
|
334
|
+
### Inline Text Styling
|
|
335
|
+
|
|
336
|
+
Style specific words or phrases using bracketed spans with boolean attributes:
|
|
337
|
+
|
|
338
|
+
```markdown
|
|
339
|
+
# Build [faster]{accent} with structure
|
|
340
|
+
|
|
341
|
+
This is [less important]{muted} context.
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
The framework provides two defaults: `accent` (colored + bold) and `muted` (subtle). These adapt to context automatically — in dark sections, `accent` resolves to a lighter shade.
|
|
345
|
+
|
|
346
|
+
**What you write → what components receive:**
|
|
347
|
+
|
|
348
|
+
| Markdown | HTML in content string |
|
|
349
|
+
|----------|----------------------|
|
|
350
|
+
| `[text]{accent}` | `<span accent="true">text</span>` |
|
|
351
|
+
| `[text]{muted}` | `<span muted="true">text</span>` |
|
|
352
|
+
| `[text]{color=red}` | `<span style="color: red">text</span>` |
|
|
353
|
+
|
|
354
|
+
CSS is generated from `theme.yml`'s `inline:` section using attribute selectors (`span[accent] { ... }`). Sites can define additional named styles:
|
|
355
|
+
|
|
356
|
+
```yaml
|
|
357
|
+
inline:
|
|
358
|
+
accent:
|
|
359
|
+
color: var(--link)
|
|
360
|
+
font-weight: '600'
|
|
361
|
+
callout:
|
|
362
|
+
color: var(--accent-600)
|
|
363
|
+
font-style: italic
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**Common pattern — accented multi-line hero heading:**
|
|
367
|
+
|
|
368
|
+
```markdown
|
|
369
|
+
# Build the future
|
|
370
|
+
# [with confidence]{accent}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
This produces `content.title = ["Build the future", "<span accent=\"true\">with confidence</span>"]` — an array rendered as a single `<h1>` with visual line breaks. See [Multi-Line Headings](#multi-line-headings) for details.
|
|
374
|
+
|
|
375
|
+
Components receive HTML strings with the spans already applied. Kit's `<H1>`, `<P>`, etc. render them correctly via `dangerouslySetInnerHTML`.
|
|
376
|
+
|
|
283
377
|
### Structured Data
|
|
284
378
|
|
|
285
379
|
Tagged code blocks pass structured data via `content.data`:
|
|
@@ -621,7 +715,7 @@ fonts:
|
|
|
621
715
|
body: "'Inter', system-ui, sans-serif"
|
|
622
716
|
|
|
623
717
|
inline:
|
|
624
|
-
|
|
718
|
+
accent: # For [text]{accent} in markdown
|
|
625
719
|
color: var(--link)
|
|
626
720
|
font-weight: '600'
|
|
627
721
|
|
|
@@ -834,7 +928,7 @@ export default {
|
|
|
834
928
|
title: 'Feature Grid',
|
|
835
929
|
description: 'Grid of feature cards with icons',
|
|
836
930
|
category: 'marketing',
|
|
837
|
-
// hidden: true, //
|
|
931
|
+
// hidden: true, // Exclude from export (internal/helper component)
|
|
838
932
|
// background: 'self', // Component renders its own background
|
|
839
933
|
// inset: true, // Available for @ComponentName references in markdown
|
|
840
934
|
// visuals: 1, // Expects 1 visual (image, video, or inset)
|
|
@@ -872,11 +966,13 @@ Content fields (`title`, `pretitle`, `paragraphs[]`, list item text) are **HTML
|
|
|
872
966
|
**Rendering text** (`@uniweb/kit`):
|
|
873
967
|
|
|
874
968
|
```jsx
|
|
875
|
-
import { H2, P, Span } from '@uniweb/kit'
|
|
969
|
+
import { H1, H2, P, Span } from '@uniweb/kit'
|
|
876
970
|
|
|
877
|
-
<
|
|
878
|
-
<
|
|
879
|
-
<
|
|
971
|
+
<H1 text={content.title} className="text-heading text-5xl font-bold" />
|
|
972
|
+
// string → single <h1>, array → single <h1> with line breaks (multi-line headings)
|
|
973
|
+
<H2 text={content.subtitle} className="text-heading text-3xl font-bold" />
|
|
974
|
+
<P text={content.paragraphs} className="text-body" />
|
|
975
|
+
// array → each string becomes its own <p>
|
|
880
976
|
<Span text={listItem.paragraphs[0]} className="text-subtle" />
|
|
881
977
|
```
|
|
882
978
|
|
|
@@ -956,7 +1052,8 @@ Only folders with `meta.js` in `sections/` (or `components/` for older foundatio
|
|
|
956
1052
|
### Website and Page APIs
|
|
957
1053
|
|
|
958
1054
|
```jsx
|
|
959
|
-
const { website } = useWebsite()
|
|
1055
|
+
const { website } = useWebsite() // or block.website
|
|
1056
|
+
const page = website.activePage // or block.page
|
|
960
1057
|
|
|
961
1058
|
// Navigation
|
|
962
1059
|
const pages = website.getPageHierarchy({ for: 'header' }) // or 'footer'
|
|
@@ -1019,17 +1116,18 @@ function SplitContent({ content, block }) {
|
|
|
1019
1116
|
|
|
1020
1117
|
**SSG and hooks:** Inset components that use React hooks (useState, useEffect) will trigger prerender warnings during `pnpm build`. This is expected — the SSG pipeline cannot render hooks due to dual React instances in the build. The warnings are informational; the page renders correctly client-side. If you see `"Skipped SSG for /..."` or `"Invalid hook call"`, this is the cause.
|
|
1021
1118
|
|
|
1022
|
-
Inset components declare `inset: true` in meta.js
|
|
1119
|
+
Inset components declare `inset: true` in meta.js:
|
|
1023
1120
|
|
|
1024
1121
|
```js
|
|
1025
1122
|
// sections/insets/NetworkDiagram/meta.js
|
|
1026
1123
|
export default {
|
|
1027
1124
|
inset: true,
|
|
1028
|
-
hidden: true,
|
|
1029
1125
|
params: { variant: { type: 'select', options: ['full', 'compact'], default: 'full' } },
|
|
1030
1126
|
}
|
|
1031
1127
|
```
|
|
1032
1128
|
|
|
1129
|
+
Whether an inset appears in a section palette is a concern of the parent component (via `children` and `insets` in its meta.js), not a property of the inset itself. Don't use `hidden: true` on insets — `hidden` means "don't export this component at all" (internal helpers, not-yet-ready components).
|
|
1130
|
+
|
|
1033
1131
|
### Dispatcher Pattern
|
|
1034
1132
|
|
|
1035
1133
|
One section type with a `variant` param replaces multiple near-duplicates. Instead of `HeroLeft`, `HeroCentered`, `HeroSplit` — one `Hero` with `variant: left | centered | split`:
|
|
@@ -1208,7 +1306,7 @@ Semantic color tokens (`text-heading`, `bg-section`, `bg-primary`, etc.) come fr
|
|
|
1208
1306
|
|
|
1209
1307
|
**"Could not load foundation"** — Check `site/package.json` has `"foundation": "file:../foundation"` (or `"default": "file:../../foundations/default"` for multi-site).
|
|
1210
1308
|
|
|
1211
|
-
**Component not appearing** — Verify `meta.js` exists
|
|
1309
|
+
**Component not appearing** — Verify `meta.js` exists. Check for `hidden: true` (means component is excluded from export — only use for internal helpers). Rebuild: `cd foundation && pnpm build`.
|
|
1212
1310
|
|
|
1213
1311
|
**Styles not applying** — Verify `@source` in `styles.css` includes your component paths. Check custom colors match `@theme` definitions.
|
|
1214
1312
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
##
|
|
1
|
+
## Developer Guide
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[AGENTS.md](./AGENTS.md) is a comprehensive guide to building with Uniweb — content authoring, component development, theming, configuration, and the kit API. Despite the name, it's written for developers and AI assistants alike. Read it to get productive fast.
|
|
4
4
|
|
|
5
|
-
###
|
|
5
|
+
### AI Prompts
|
|
6
|
+
|
|
7
|
+
AI coding assistants (Claude Code, Cursor, Copilot, etc.) read AGENTS.md automatically. Some prompts to try:
|
|
6
8
|
|
|
7
9
|
**Converting an existing design:**
|
|
8
10
|
```
|
package/partials/learn-more.hbs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
## Learn More
|
|
2
2
|
|
|
3
|
-
- [
|
|
4
|
-
- [
|
|
3
|
+
- [AGENTS.md](./AGENTS.md) — comprehensive guide to building with Uniweb
|
|
4
|
+
- [Uniweb Documentation](https://github.com/uniweb/docs) — full reference docs
|
|
5
|
+
- [Uniweb CLI](https://github.com/uniweb/cli) — project scaffolding and build tools
|
|
5
6
|
- [Tailwind CSS v4](https://tailwindcss.com)
|
|
@@ -1,37 +1,25 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
1
|
import { H1, H2, P, Link, cn } from '@uniweb/kit'
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* Section Component
|
|
6
5
|
*
|
|
7
6
|
* A versatile content section that handles headings, text, and links.
|
|
8
|
-
*
|
|
7
|
+
* Uses semantic tokens so it adapts to any theme context automatically.
|
|
9
8
|
*/
|
|
10
|
-
function Section({ content, params }) {
|
|
11
|
-
// Content fields: title, pretitle, subtitle, paragraphs, links, imgs, items
|
|
9
|
+
export default function Section({ content, params }) {
|
|
12
10
|
const { title, pretitle, subtitle, paragraphs = [], links = [], imgs = [] } = content || {}
|
|
13
11
|
|
|
14
12
|
const {
|
|
15
|
-
theme = 'light',
|
|
16
13
|
align = 'center',
|
|
17
14
|
width = 'default',
|
|
18
15
|
} = params || {}
|
|
19
16
|
|
|
20
|
-
// Theme styles
|
|
21
|
-
const themes = {
|
|
22
|
-
light: 'bg-white text-gray-900',
|
|
23
|
-
dark: 'bg-gray-900 text-white',
|
|
24
|
-
primary: 'bg-primary text-white',
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Alignment styles
|
|
28
17
|
const alignments = {
|
|
29
18
|
left: 'text-left',
|
|
30
19
|
center: 'text-center',
|
|
31
20
|
right: 'text-right',
|
|
32
21
|
}
|
|
33
22
|
|
|
34
|
-
// Width styles
|
|
35
23
|
const widths = {
|
|
36
24
|
narrow: 'max-w-2xl',
|
|
37
25
|
default: 'max-w-4xl',
|
|
@@ -40,58 +28,47 @@ function Section({ content, params }) {
|
|
|
40
28
|
}
|
|
41
29
|
|
|
42
30
|
return (
|
|
43
|
-
<
|
|
44
|
-
<div className={cn('mx-auto', widths[width]
|
|
45
|
-
{/* Pretitle / Eyebrow */}
|
|
31
|
+
<div className={cn('py-16 px-6', alignments[align])}>
|
|
32
|
+
<div className={cn('mx-auto', widths[width])}>
|
|
46
33
|
{pretitle && (
|
|
47
|
-
<p className="text-sm font-medium text-
|
|
34
|
+
<p className="text-sm font-medium text-link mb-4 uppercase tracking-wide">
|
|
48
35
|
{pretitle}
|
|
49
36
|
</p>
|
|
50
37
|
)}
|
|
51
38
|
|
|
52
|
-
{/* Title */}
|
|
53
39
|
{title && (
|
|
54
40
|
<H1
|
|
55
41
|
text={title}
|
|
56
|
-
className="text-3xl sm:text-4xl font-bold mb-4"
|
|
42
|
+
className="text-heading text-3xl sm:text-4xl font-bold mb-4"
|
|
57
43
|
/>
|
|
58
44
|
)}
|
|
59
45
|
|
|
60
|
-
{/* Subtitle */}
|
|
61
46
|
{subtitle && (
|
|
62
47
|
<H2
|
|
63
48
|
text={subtitle}
|
|
64
|
-
className=
|
|
65
|
-
'text-xl mb-6',
|
|
66
|
-
theme === 'light' ? 'text-gray-600' : 'text-gray-300'
|
|
67
|
-
)}
|
|
49
|
+
className="text-body text-xl mb-6"
|
|
68
50
|
/>
|
|
69
51
|
)}
|
|
70
52
|
|
|
71
|
-
{/* Paragraphs */}
|
|
72
53
|
{paragraphs.map((para, index) => (
|
|
73
54
|
<P
|
|
74
55
|
key={index}
|
|
75
56
|
text={para}
|
|
76
|
-
className=
|
|
77
|
-
'text-lg mb-4 leading-relaxed',
|
|
78
|
-
theme === 'light' ? 'text-gray-700' : 'text-gray-300'
|
|
79
|
-
)}
|
|
57
|
+
className="text-body text-lg mb-4 leading-relaxed"
|
|
80
58
|
/>
|
|
81
59
|
))}
|
|
82
60
|
|
|
83
|
-
{/* Links */}
|
|
84
61
|
{links.length > 0 && (
|
|
85
|
-
<div className={cn('mt-8 flex gap-4 flex-wrap',
|
|
62
|
+
<div className={cn('mt-8 flex gap-4 flex-wrap', align === 'center' && 'justify-center')}>
|
|
86
63
|
{links.map((link, index) => (
|
|
87
64
|
<Link
|
|
88
65
|
key={index}
|
|
89
|
-
|
|
66
|
+
to={link.href}
|
|
90
67
|
className={cn(
|
|
91
68
|
'inline-flex items-center px-6 py-3 font-medium rounded-lg transition-colors',
|
|
92
69
|
index === 0
|
|
93
|
-
? 'bg-primary
|
|
94
|
-
: '
|
|
70
|
+
? 'bg-primary text-primary-foreground hover:bg-primary-hover'
|
|
71
|
+
: 'bg-secondary text-secondary-foreground hover:bg-secondary-hover'
|
|
95
72
|
)}
|
|
96
73
|
>
|
|
97
74
|
{link.label}
|
|
@@ -100,7 +77,6 @@ function Section({ content, params }) {
|
|
|
100
77
|
</div>
|
|
101
78
|
)}
|
|
102
79
|
|
|
103
|
-
{/* Images */}
|
|
104
80
|
{imgs.length > 0 && (
|
|
105
81
|
<div className="mt-8">
|
|
106
82
|
{imgs.map((img, index) => (
|
|
@@ -114,8 +90,6 @@ function Section({ content, params }) {
|
|
|
114
90
|
</div>
|
|
115
91
|
)}
|
|
116
92
|
</div>
|
|
117
|
-
</
|
|
93
|
+
</div>
|
|
118
94
|
)
|
|
119
95
|
}
|
|
120
|
-
|
|
121
|
-
export default Section
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Section Component Metadata (v2)
|
|
3
|
-
*
|
|
4
|
-
* A versatile content section for headings, text, and links.
|
|
5
|
-
*/
|
|
6
1
|
export default {
|
|
7
2
|
title: 'Section',
|
|
8
3
|
description: 'A versatile content section for headings, text, and links',
|
|
@@ -19,12 +14,6 @@ export default {
|
|
|
19
14
|
},
|
|
20
15
|
|
|
21
16
|
params: {
|
|
22
|
-
theme: {
|
|
23
|
-
type: 'select',
|
|
24
|
-
label: 'Theme',
|
|
25
|
-
options: ['light', 'dark', 'primary'],
|
|
26
|
-
default: 'light',
|
|
27
|
-
},
|
|
28
17
|
align: {
|
|
29
18
|
type: 'select',
|
|
30
19
|
label: 'Alignment',
|
|
@@ -47,15 +36,11 @@ export default {
|
|
|
47
36
|
presets: {
|
|
48
37
|
default: {
|
|
49
38
|
label: 'Centered',
|
|
50
|
-
params: {
|
|
51
|
-
},
|
|
52
|
-
dark: {
|
|
53
|
-
label: 'Dark Theme',
|
|
54
|
-
params: { theme: 'dark', align: 'center' },
|
|
39
|
+
params: { align: 'center' },
|
|
55
40
|
},
|
|
56
41
|
left: {
|
|
57
42
|
label: 'Left Aligned',
|
|
58
|
-
params: {
|
|
43
|
+
params: { align: 'left' },
|
|
59
44
|
},
|
|
60
45
|
},
|
|
61
46
|
}
|
|
@@ -8,7 +8,7 @@ align: center
|
|
|
8
8
|
|
|
9
9
|
## Your Uniweb project is ready
|
|
10
10
|
|
|
11
|
-
This is a minimal starting point for your Uniweb project. Edit the content in `site/pages/` and
|
|
11
|
+
This is a minimal starting point for your Uniweb project. Edit the content in `site/pages/` and build section types in `foundation/src/sections/`.
|
|
12
12
|
|
|
13
13
|
[About](/about)
|
|
14
14
|
[Documentation](https://github.com/uniweb)
|
package/templates/site/theme.yml
CHANGED
|
@@ -64,12 +64,12 @@ colors:
|
|
|
64
64
|
# heading: white
|
|
65
65
|
|
|
66
66
|
# ─── Inline Text Styles ───────────────────────────────────────────────────────
|
|
67
|
-
# Named styles for inline text in markdown: [text]{
|
|
67
|
+
# Named styles for inline text in markdown: [text]{accent}
|
|
68
68
|
# Each name maps to CSS properties.
|
|
69
|
-
# Defaults:
|
|
69
|
+
# Defaults: accent (colored + bold), muted (subtle).
|
|
70
70
|
|
|
71
71
|
# inline:
|
|
72
|
-
#
|
|
72
|
+
# accent:
|
|
73
73
|
# color: 'var(--link)'
|
|
74
74
|
# font-weight: '600'
|
|
75
75
|
# muted:
|
|
@@ -10,7 +10,7 @@ A website built with [Uniweb](https://github.com/uniweb/cli) — a component web
|
|
|
10
10
|
{{projectName}}/
|
|
11
11
|
├── foundation/ # React component library
|
|
12
12
|
│ ├── src/
|
|
13
|
-
│ │ ├──
|
|
13
|
+
│ │ ├── sections/ # Section types (selectable by content authors)
|
|
14
14
|
│ │ └── styles.css # Tailwind CSS v4 theme
|
|
15
15
|
│ └── vite.config.js # defineFoundationConfig()
|
|
16
16
|
│
|
|
@@ -22,7 +22,7 @@ A website built with [Uniweb](https://github.com/uniweb/cli) — a component web
|
|
|
22
22
|
│ ├── site.yml # Site configuration
|
|
23
23
|
│ └── vite.config.js # defineSiteConfig()
|
|
24
24
|
│
|
|
25
|
-
└── AGENTS.md #
|
|
25
|
+
└── AGENTS.md # Developer guide (human + AI)
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
## Content Authoring
|
|
@@ -46,27 +46,25 @@ Your content here.
|
|
|
46
46
|
|
|
47
47
|
## Component Development
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Section types live in `foundation/src/sections/`. Each is a folder with an `index.jsx` and a `meta.js`:
|
|
50
50
|
|
|
51
51
|
```jsx
|
|
52
|
-
// foundation/src/
|
|
53
|
-
import { H1, P
|
|
52
|
+
// foundation/src/sections/Hero/index.jsx
|
|
53
|
+
import { H1, P } from '@uniweb/kit'
|
|
54
54
|
|
|
55
|
-
export function Hero({ content
|
|
56
|
-
const { title } = content
|
|
57
|
-
const { theme = 'light' } = params
|
|
55
|
+
export default function Hero({ content }) {
|
|
56
|
+
const { title, paragraphs = [] } = content || {}
|
|
58
57
|
|
|
59
58
|
return (
|
|
60
|
-
<
|
|
61
|
-
<H1 text={title} />
|
|
62
|
-
|
|
59
|
+
<div className="max-w-4xl mx-auto px-6">
|
|
60
|
+
<H1 text={title} className="text-heading text-4xl font-bold" />
|
|
61
|
+
<P text={paragraphs} className="text-body mt-4" />
|
|
62
|
+
</div>
|
|
63
63
|
)
|
|
64
64
|
}
|
|
65
|
-
|
|
66
|
-
export default Hero
|
|
67
65
|
```
|
|
68
66
|
|
|
69
|
-
|
|
67
|
+
Components receive parsed content from markdown. Classes like `text-heading` and `text-body` are semantic tokens — the site controls their actual colors through theming, so the same component adapts to any context automatically.
|
|
70
68
|
|
|
71
69
|
{{> components-docs}}
|
|
72
70
|
|