@uniweb/runtime 0.6.23 → 0.6.25
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 +4 -4
- package/src/components/PageRenderer.jsx +41 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/runtime",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.25",
|
|
4
4
|
"description": "Minimal runtime for loading Uniweb foundations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -35,13 +35,13 @@
|
|
|
35
35
|
"node": ">=20.19"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@uniweb/
|
|
39
|
-
"@uniweb/
|
|
38
|
+
"@uniweb/core": "0.5.18",
|
|
39
|
+
"@uniweb/theming": "0.1.3"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@vitejs/plugin-react": "^4.5.2",
|
|
43
43
|
"vite": "^7.3.1",
|
|
44
|
-
"@uniweb/build": "0.8.
|
|
44
|
+
"@uniweb/build": "0.8.28"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -122,40 +122,47 @@ export default function PageRenderer() {
|
|
|
122
122
|
let page = website?.getPage(location.pathname)
|
|
123
123
|
if (page && website) website.setActivePage(location.pathname)
|
|
124
124
|
|
|
125
|
-
//
|
|
126
|
-
const redirectTarget = page?.redirect
|
|
127
|
-
useEffect(() => {
|
|
128
|
-
if (!redirectTarget) return
|
|
129
|
-
if (redirectTarget.startsWith('http')) {
|
|
130
|
-
window.location.replace(redirectTarget)
|
|
131
|
-
} else {
|
|
132
|
-
navigate(redirectTarget, { replace: true })
|
|
133
|
-
}
|
|
134
|
-
}, [redirectTarget, navigate])
|
|
125
|
+
// ─── Compute navigation targets (before hooks, no early returns) ───
|
|
135
126
|
|
|
136
|
-
|
|
127
|
+
// Explicit redirect: in page.yml
|
|
128
|
+
const redirectTarget = page?.redirect || null
|
|
137
129
|
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
130
|
+
// Auto-redirect for content-less pages (structural containers).
|
|
131
|
+
// Folders with page.yml but no markdown keep their route in the hierarchy;
|
|
132
|
+
// when visited directly, redirect to the first descendant with content.
|
|
133
|
+
const autoRedirectRoute = page && !page.redirect && !page.hasContent()
|
|
134
|
+
? page.getNavigableRoute()
|
|
135
|
+
: null
|
|
136
|
+
const shouldAutoRedirect = !!(autoRedirectRoute && autoRedirectRoute !== page?.route)
|
|
145
137
|
|
|
146
138
|
// If no page found, try the 404 page (do NOT fall back to activePage/homepage)
|
|
147
|
-
const isNotFound = !page
|
|
139
|
+
const isNotFound = !page && !redirectTarget
|
|
148
140
|
if (isNotFound) {
|
|
149
141
|
page = website?.getNotFoundPage?.() || null
|
|
150
142
|
}
|
|
151
143
|
|
|
152
|
-
//
|
|
144
|
+
// Head metadata — compute for all cases (redirect pages get a fallback)
|
|
153
145
|
const headMeta = page?.getHeadMeta?.() || {
|
|
154
146
|
title: isNotFound ? 'Page Not Found' : (page?.title || 'Website'),
|
|
155
147
|
description: page?.description || ''
|
|
156
148
|
}
|
|
157
149
|
|
|
158
|
-
//
|
|
150
|
+
// ─── All hooks called unconditionally (React rules of hooks) ───
|
|
151
|
+
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (!redirectTarget) return
|
|
154
|
+
if (redirectTarget.startsWith('http')) {
|
|
155
|
+
window.location.replace(redirectTarget)
|
|
156
|
+
} else {
|
|
157
|
+
navigate(redirectTarget, { replace: true })
|
|
158
|
+
}
|
|
159
|
+
}, [redirectTarget, navigate])
|
|
160
|
+
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
if (!shouldAutoRedirect) return
|
|
163
|
+
navigate(autoRedirectRoute, { replace: true })
|
|
164
|
+
}, [shouldAutoRedirect, autoRedirectRoute, navigate])
|
|
165
|
+
|
|
159
166
|
useHeadMeta(headMeta, { siteName })
|
|
160
167
|
|
|
161
168
|
// For dynamic pages created before collection data was available (hard reload),
|
|
@@ -168,6 +175,19 @@ export default function PageRenderer() {
|
|
|
168
175
|
return website.dataStore.onUpdate(forceUpdate)
|
|
169
176
|
}, [isDynamicPending, website])
|
|
170
177
|
|
|
178
|
+
// ─── Early returns (after all hooks) ───
|
|
179
|
+
|
|
180
|
+
if (redirectTarget) return null
|
|
181
|
+
if (shouldAutoRedirect) return null
|
|
182
|
+
|
|
183
|
+
// Rewrite pages are served by an external site — the host handles routing.
|
|
184
|
+
// In SPA mode this shouldn't be reached (host proxies before JS loads),
|
|
185
|
+
// but if it is (e.g., dev mode), do a full page reload to let the host handle it.
|
|
186
|
+
if (page?.rewrite) {
|
|
187
|
+
window.location.reload()
|
|
188
|
+
return null
|
|
189
|
+
}
|
|
190
|
+
|
|
171
191
|
if (!page) {
|
|
172
192
|
// No page and no 404 page defined - show shared fallback + dev debug info
|
|
173
193
|
const requestedPath = location.pathname
|