@uniweb/core 0.7.13 → 0.7.14
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 +3 -3
- package/src/page.js +14 -15
- package/src/seo.js +28 -0
- package/src/website.js +9 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/core",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.14",
|
|
4
4
|
"description": "Core classes for the Uniweb platform - Uniweb, Website, Page, Block",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"vitest": "^4.1.7"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@uniweb/
|
|
34
|
-
"@uniweb/
|
|
33
|
+
"@uniweb/theming": "0.1.4",
|
|
34
|
+
"@uniweb/semantic-parser": "1.1.17"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"test": "vitest run"
|
package/src/page.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import Block from './block.js'
|
|
9
9
|
import ObservableState from './observable-state.js'
|
|
10
|
+
import { normalizeSeo } from './seo.js'
|
|
10
11
|
|
|
11
12
|
// Normalize a page's nav-visibility into a deduped hideIn array (the layout-area
|
|
12
13
|
// names the page is suppressed from). Reads the canonical hideIn (array, or a single
|
|
@@ -63,16 +64,8 @@ export default class Page {
|
|
|
63
64
|
params: pageData.layout?.params || {},
|
|
64
65
|
}
|
|
65
66
|
|
|
66
|
-
// SEO configuration
|
|
67
|
-
this.seo =
|
|
68
|
-
noindex: pageData.seo?.noindex || false,
|
|
69
|
-
image: pageData.seo?.image || null,
|
|
70
|
-
ogTitle: pageData.seo?.ogTitle || null,
|
|
71
|
-
ogDescription: pageData.seo?.ogDescription || null,
|
|
72
|
-
canonical: pageData.seo?.canonical || null,
|
|
73
|
-
changefreq: pageData.seo?.changefreq || null,
|
|
74
|
-
priority: pageData.seo?.priority || null,
|
|
75
|
-
}
|
|
67
|
+
// SEO configuration (canonical shape — shared with the site level via normalizeSeo)
|
|
68
|
+
this.seo = normalizeSeo(pageData.seo)
|
|
76
69
|
|
|
77
70
|
// Parent page (set by Website.buildPageHierarchy())
|
|
78
71
|
this.parent = null
|
|
@@ -159,16 +152,22 @@ export default class Page {
|
|
|
159
152
|
*/
|
|
160
153
|
getHeadMeta() {
|
|
161
154
|
const resolvedTitle = this.getTitle()
|
|
155
|
+
// Site-level seo provides the defaults; a page overrides any field it sets.
|
|
156
|
+
// (Website.seo / Website.keywords are the normalized site-root values.)
|
|
157
|
+
const site = this.website?.seo || {}
|
|
158
|
+
const siteKeywords = this.website?.keywords || null
|
|
162
159
|
return {
|
|
163
160
|
title: resolvedTitle,
|
|
164
161
|
description: this.description,
|
|
165
|
-
keywords: this.keywords,
|
|
162
|
+
keywords: this.keywords || siteKeywords,
|
|
166
163
|
canonical: this.seo.canonical,
|
|
167
|
-
robots: this.seo.noindex ? 'noindex, nofollow' : null,
|
|
164
|
+
robots: this.seo.noindex || site.noindex ? 'noindex, nofollow' : null,
|
|
168
165
|
og: {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
166
|
+
// Page content wins; site-level seo only fills gaps. Image is the
|
|
167
|
+
// exception authors most want cascaded (the shared social card).
|
|
168
|
+
title: this.seo.ogTitle || resolvedTitle || site.ogTitle,
|
|
169
|
+
description: this.seo.ogDescription || this.description || site.ogDescription,
|
|
170
|
+
image: this.seo.image || site.image,
|
|
172
171
|
url: this.route,
|
|
173
172
|
},
|
|
174
173
|
}
|
package/src/seo.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical SEO / social-card shape.
|
|
3
|
+
*
|
|
4
|
+
* Shared by Website (site-level defaults) and Page (per-page), so the same
|
|
5
|
+
* concept has the same shape at every level. Site `seo` cascades as the
|
|
6
|
+
* default; a page overrides any field it sets (see Page.getHeadMeta).
|
|
7
|
+
*
|
|
8
|
+
* Field names are camelCase to match the framework's authored convention
|
|
9
|
+
* (`defaultLanguage`, etc.). `changefreq`/`priority` are sitemap hints — only
|
|
10
|
+
* meaningful per-page, but carried uniformly so the shape never drifts.
|
|
11
|
+
*
|
|
12
|
+
* @param {Object} [raw] - raw `seo:` block from site.yml / page.yml
|
|
13
|
+
* @returns {{ noindex: boolean, image: string|null, ogTitle: string|null,
|
|
14
|
+
* ogDescription: string|null, canonical: string|null, changefreq: string|null,
|
|
15
|
+
* priority: (string|number)|null }}
|
|
16
|
+
*/
|
|
17
|
+
export function normalizeSeo(raw) {
|
|
18
|
+
const seo = raw || {}
|
|
19
|
+
return {
|
|
20
|
+
noindex: seo.noindex || false,
|
|
21
|
+
image: seo.image || null,
|
|
22
|
+
ogTitle: seo.ogTitle || null,
|
|
23
|
+
ogDescription: seo.ogDescription || null,
|
|
24
|
+
canonical: seo.canonical || null,
|
|
25
|
+
changefreq: seo.changefreq || null,
|
|
26
|
+
priority: seo.priority || null,
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/website.js
CHANGED
|
@@ -9,6 +9,7 @@ import DataStore from './datastore.js'
|
|
|
9
9
|
import EntityStore from './entity-store.js'
|
|
10
10
|
import FetcherDispatcher from './fetcher-dispatcher.js'
|
|
11
11
|
import ObservableState from './observable-state.js'
|
|
12
|
+
import { normalizeSeo } from './seo.js'
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Website — orchestration root for a single site instance.
|
|
@@ -73,6 +74,8 @@ export default class Website {
|
|
|
73
74
|
this.pageRoutes = []
|
|
74
75
|
this.themeData = {}
|
|
75
76
|
this.config = {}
|
|
77
|
+
this.seo = {} // site-level SEO/social defaults (normalized; cascade to pages)
|
|
78
|
+
this.keywords = null // site-level default keywords (localized list or null)
|
|
76
79
|
this.siteDefaultLocale = 'en'
|
|
77
80
|
this.defaultLocale = 'en'
|
|
78
81
|
this.activeLocale = 'en'
|
|
@@ -153,6 +156,12 @@ export default class Website {
|
|
|
153
156
|
this.themeData = theme
|
|
154
157
|
this.config = config
|
|
155
158
|
|
|
159
|
+
// Site-level SEO/social metadata — defaults that cascade to every page's
|
|
160
|
+
// effective head meta (Page.getHeadMeta). `config.seo` / `config.keywords`
|
|
161
|
+
// ride the raw site.yml spread; normalize seo to the canonical shape here.
|
|
162
|
+
this.seo = normalizeSeo(config.seo)
|
|
163
|
+
this.keywords = config.keywords || null
|
|
164
|
+
|
|
156
165
|
this.siteDefaultLocale = config.defaultLanguage || 'en'
|
|
157
166
|
this.defaultLocale = config.domainLocale || this.siteDefaultLocale
|
|
158
167
|
this.activeLocale = config.activeLocale || this.defaultLocale
|