uniweb 0.8.28 → 0.8.30
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 +86 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uniweb",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.30",
|
|
4
4
|
"description": "Create structured Vite + React sites with content/code separation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
"js-yaml": "^4.1.0",
|
|
42
42
|
"prompts": "^2.4.2",
|
|
43
43
|
"tar": "^7.0.0",
|
|
44
|
-
"@uniweb/core": "0.5.
|
|
45
|
-
"@uniweb/
|
|
46
|
-
"@uniweb/
|
|
44
|
+
"@uniweb/core": "0.5.18",
|
|
45
|
+
"@uniweb/runtime": "0.6.25",
|
|
46
|
+
"@uniweb/kit": "0.7.19"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"@uniweb/build": "0.8.
|
|
49
|
+
"@uniweb/build": "0.8.29",
|
|
50
50
|
"@uniweb/content-reader": "1.1.4",
|
|
51
51
|
"@uniweb/semantic-parser": "1.1.8"
|
|
52
52
|
},
|
package/partials/agents.md
CHANGED
|
@@ -61,9 +61,11 @@ project/
|
|
|
61
61
|
└── pnpm-workspace.yaml
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
- **Foundation** (developer): React components. Those in `src/sections` and `src/layouts` are *section types* — selectable by content authors via `type:` in frontmatter, or used for site-level layout areas (header, footer, panel). Most have
|
|
64
|
+
- **Foundation** (developer): React components. Those in `src/sections` and `src/layouts` are *section types* — selectable by content authors via `type:` in frontmatter, or used for site-level layout areas (header, footer, panel). Most have a `meta.js` with metadata in them. Everything in `src/components` (or elsewhere) is ordinary React — the developer's workbench for helper components that section types import and compose internally.
|
|
65
65
|
- **Site** (content author): Markdown content + configuration. Each section file references a section type. Authors work here without touching foundation code. It may also contain collections of structured content and/or references to external data sources.
|
|
66
66
|
|
|
67
|
+
**The composition boundary:** Authors compose pages from finished section types — choosing types, writing content, setting params. Developers compose section types from building blocks — importing helpers from `src/components/`, using libraries, writing JSX. These are two different levels of composition. The section type is the boundary between them. Don't expose building-block composition to authors; build complete, self-contained section types that handle their own internal structure.
|
|
68
|
+
|
|
67
69
|
> Multi-site projects use sub-folders with site/foundation pairs in them, or segregate foundations and sites into separate folders (`foundations/`, `sites/`).
|
|
68
70
|
|
|
69
71
|
## Project Setup
|
|
@@ -553,7 +555,6 @@ description: Learn about our company
|
|
|
553
555
|
id: about # Stable identity (for page: links, survives moves)
|
|
554
556
|
order: 2 # Navigation sort position
|
|
555
557
|
pages: [team, history, ...] # Child page order (... = rest). Without ... = strict (hides unlisted)
|
|
556
|
-
index: getting-started # Which child page is the index
|
|
557
558
|
redirect: academic # Redirect to child page (relative or absolute path, or URL)
|
|
558
559
|
```
|
|
559
560
|
|
|
@@ -564,6 +565,10 @@ pages: [home, about, ...] # Order pages (... = rest, first = homepage)
|
|
|
564
565
|
pages: [home, about] # Strict: only listed pages in nav
|
|
565
566
|
```
|
|
566
567
|
|
|
568
|
+
**Route mapping:** Folder structure maps 1:1 to routes. Every folder keeps its natural route — `pages:` controls **order only**, not which child "becomes" the parent. The only exception is the site root: `index:` (or first in `pages:`) in site.yml sets the homepage at `/`.
|
|
569
|
+
|
|
570
|
+
**Content-less containers:** Folders with `page.yml` but no markdown are structural groups. They appear in `getPageHierarchy()` with `hasContent: false` and their own title/label. When visited directly, the runtime auto-redirects to the first descendant with content. This supports hierarchical navigation (courses → modules → lessons) at any depth.
|
|
571
|
+
|
|
567
572
|
### Lists as Navigation Menus
|
|
568
573
|
|
|
569
574
|
Markdown lists model nav, menus, and grouped links. Each list item is a full content object with `paragraphs`, `links`, `icons`, and nested `lists`.
|
|
@@ -708,7 +713,7 @@ inline:
|
|
|
708
713
|
font-weight: '600'
|
|
709
714
|
|
|
710
715
|
vars:
|
|
711
|
-
|
|
716
|
+
radius: 0.75rem
|
|
712
717
|
```
|
|
713
718
|
|
|
714
719
|
Each color generates 11 OKLCH shades (50–950). `neutral` uses a named preset rather than hex. Shade 500 = your exact input color. Context override keys match token names: `section:` not `bg:`, `primary:` not `btn-primary-bg:`.
|
|
@@ -734,19 +739,35 @@ contexts:
|
|
|
734
739
|
|
|
735
740
|
### Foundation variables
|
|
736
741
|
|
|
737
|
-
|
|
742
|
+
Most customization is handled by component params. Both section components and layout components declare their own params in `meta.js` — layouts are full components with params, not just structural wrappers. A header height, for example, is typically a layout param, not a foundation var.
|
|
743
|
+
|
|
744
|
+
Foundation-level CSS variables are for values that must stay consistent **across** multiple components — shared radii, spacing scales, or additional font roles beyond the three the theming system already provides (body, heading, mono). Don't reach for foundation vars when a component or layout param would do.
|
|
745
|
+
|
|
746
|
+
If you need them, declare vars in two places:
|
|
747
|
+
|
|
748
|
+
**`foundation.js`** — metadata for the editor and schema:
|
|
738
749
|
|
|
739
750
|
```js
|
|
740
751
|
export const vars = {
|
|
741
|
-
'
|
|
742
|
-
'
|
|
752
|
+
'radius': { default: '0.5rem', description: 'Default border radius for cards and buttons' },
|
|
753
|
+
'radius-lg': { default: '1rem', description: 'Large border radius' },
|
|
743
754
|
'section-padding-y': { default: 'clamp(4rem, 6vw, 7rem)', description: 'Vertical section padding' },
|
|
744
755
|
}
|
|
745
756
|
```
|
|
746
757
|
|
|
747
|
-
|
|
758
|
+
**`styles.css`** — the actual CSS that ships with the foundation:
|
|
748
759
|
|
|
749
|
-
|
|
760
|
+
```css
|
|
761
|
+
@theme inline {
|
|
762
|
+
--radius: 0.5rem;
|
|
763
|
+
--radius-lg: 1rem;
|
|
764
|
+
--section-padding-y: clamp(4rem, 6vw, 7rem);
|
|
765
|
+
}
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
The `styles.css` declaration ensures defaults are present in the foundation's CSS output and enables Tailwind shorthand (`rounded-(--radius)` instead of `rounded-[var(--radius)]`). The `foundation.js` declaration provides descriptions and types for the visual editor. Sites override values in `theme.yml` under `vars:` — the site's theme CSS takes priority over the foundation defaults.
|
|
769
|
+
|
|
770
|
+
**Common mistake:** Using foundation vars for values that belong to a specific component. A header height is a layout param, not a foundation var — the layout component owns it. A sidebar width is a layout param too. Foundation vars are for values that multiple unrelated components share — radii, spacing, shadows.
|
|
750
771
|
|
|
751
772
|
### Design richness beyond tokens
|
|
752
773
|
|
|
@@ -1083,6 +1104,33 @@ export default function Hero({ content, block, params }) {
|
|
|
1083
1104
|
|
|
1084
1105
|
This is the system-building pattern at its clearest: **section types are the public interface** to your content system (author-friendly names, documented in `meta.js`). **Helper components are the implementation** (developer-friendly APIs, ordinary React props). The section type is the thin translation layer that connects the two worlds.
|
|
1085
1106
|
|
|
1107
|
+
### Section components are composites
|
|
1108
|
+
|
|
1109
|
+
A section component is rarely a single flat render. It imports helper components from `src/components/` to build a complex UI while presenting a single `type:` to the content author. The `src/components/` directory is the developer's workbench — ordinary React components with ordinary props, not selectable by authors, not auto-discovered.
|
|
1110
|
+
|
|
1111
|
+
```jsx
|
|
1112
|
+
// src/sections/Lesson/index.jsx
|
|
1113
|
+
import LessonHeader from '../../components/LessonHeader'
|
|
1114
|
+
import LessonContent from '../../components/LessonContent'
|
|
1115
|
+
import LessonNav from '../../components/LessonNav'
|
|
1116
|
+
|
|
1117
|
+
export default function Lesson({ content, params, block }) {
|
|
1118
|
+
return (
|
|
1119
|
+
<>
|
|
1120
|
+
<LessonHeader block={block} />
|
|
1121
|
+
<LessonContent content={content} params={params} />
|
|
1122
|
+
<LessonNav block={block} />
|
|
1123
|
+
</>
|
|
1124
|
+
)
|
|
1125
|
+
}
|
|
1126
|
+
```
|
|
1127
|
+
|
|
1128
|
+
The content author writes `type: Lesson` in one markdown file. The section component handles the structural chrome — a header derived from the page hierarchy, the rendered content, a prev/next footer. The three helpers live in `src/components/` and receive whatever props make sense for their job.
|
|
1129
|
+
|
|
1130
|
+
**When to reach for this pattern:** When a page type has consistent structural elements (header bars, navigation footers, contextual sidebars) that the content author shouldn't need to add as separate sections. If the author would have to add the same boilerplate sections to every page of a certain type, the section component should compose them internally.
|
|
1131
|
+
|
|
1132
|
+
**Common mistake:** Solving structural repetition at the layout level. If only some page types need a content header (lessons do, the homepage doesn't), it's a section concern, not a layout concern. The layout owns the page-wide chrome (header area, sidebar area). The section owns its own internal structure.
|
|
1133
|
+
|
|
1086
1134
|
### Foundation Organization
|
|
1087
1135
|
|
|
1088
1136
|
```
|
|
@@ -1111,9 +1159,26 @@ foundation/src/
|
|
|
1111
1159
|
const { website } = useWebsite()
|
|
1112
1160
|
const page = website.activePage
|
|
1113
1161
|
|
|
1114
|
-
// Navigation
|
|
1115
|
-
|
|
1116
|
-
//
|
|
1162
|
+
// Navigation — getPageHierarchy(options)
|
|
1163
|
+
// Returns [{ id, route, navigableRoute, translatedRoute, title, label, description, hasContent, version, children }]
|
|
1164
|
+
//
|
|
1165
|
+
// Options:
|
|
1166
|
+
// for: 'header' | 'footer' — filter by nav type (respects hideInHeader/hideInFooter)
|
|
1167
|
+
// nested: true (default) — nested hierarchy with children; false = flat list
|
|
1168
|
+
// includeHidden: false — include hidden pages
|
|
1169
|
+
// filter: (page) => bool — custom filter function
|
|
1170
|
+
// sort: (a, b) => number — custom sort function
|
|
1171
|
+
//
|
|
1172
|
+
// Convenience methods:
|
|
1173
|
+
// website.getHeaderPages() — same as getPageHierarchy({ for: 'header' })
|
|
1174
|
+
// website.getFooterPages() — same as getPageHierarchy({ for: 'footer' })
|
|
1175
|
+
// website.getAllPages() — flat list: getPageHierarchy({ nested: false })
|
|
1176
|
+
//
|
|
1177
|
+
// Common patterns:
|
|
1178
|
+
website.getPageHierarchy({ for: 'header' }) // Header nav (excludes hideInHeader pages)
|
|
1179
|
+
website.getPageHierarchy() // Full nested hierarchy (no nav filtering)
|
|
1180
|
+
website.getPageHierarchy({ nested: false }) // Flat list of all visible pages
|
|
1181
|
+
website.getPageHierarchy({ nested: false, includeHidden: true }) // Everything including hidden
|
|
1117
1182
|
|
|
1118
1183
|
// Core properties
|
|
1119
1184
|
website.name // Site name from site.yml
|
|
@@ -1132,9 +1197,17 @@ const { isActive, isActiveOrAncestor } = useActiveRoute()
|
|
|
1132
1197
|
const { scheme, toggle, canToggle } = useAppearance()
|
|
1133
1198
|
|
|
1134
1199
|
// Page properties
|
|
1135
|
-
page.title, page.label, page.route
|
|
1200
|
+
page.title, page.label, page.route, page.description
|
|
1136
1201
|
page.isHidden(), page.showInHeader(), page.showInFooter()
|
|
1137
|
-
page.
|
|
1202
|
+
page.hasContent() // True if page has its own content (not just a folder)
|
|
1203
|
+
page.hasChildren(), page.children // Direct child Page instances
|
|
1204
|
+
page.parent // Parent Page instance (null for root pages)
|
|
1205
|
+
page.getNavigableRoute() // First descendant route with content (for linking)
|
|
1206
|
+
|
|
1207
|
+
// Hierarchical navigation — content-less containers are group nodes:
|
|
1208
|
+
// { route: '/courses/intro', title: 'Introduction', hasContent: false,
|
|
1209
|
+
// navigableRoute: '/courses/intro/lesson-1', children: [...] }
|
|
1210
|
+
// Use navigableRoute for links, title for display, hasContent to style differently.
|
|
1138
1211
|
```
|
|
1139
1212
|
|
|
1140
1213
|
### Cross-Block Communication
|