nodality 1.0.166 → 1.0.168
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/bin/nodality.js +312 -0
- package/layout/animator.js +1 -1
- package/layout/audio.js +1 -1
- package/layout/audionew.js +1 -1
- package/layout/base-2.js +1 -1
- package/layout/base.js +1 -1
- package/layout/beta-desktop-bar.js +1 -1
- package/layout/beta-mobile-bar.js +1 -1
- package/layout/box.js +1 -1
- package/layout/button.js +1 -1
- package/layout/cards.js +1 -1
- package/layout/center.js +1 -1
- package/layout/checkbox.js +1 -1
- package/layout/circle.js +1 -1
- package/layout/clean-row.js +1 -1
- package/layout/code.js +1 -1
- package/layout/container.js +1 -1
- package/layout/custom.js +1 -1
- package/layout/div-image.js +1 -1
- package/layout/dropdown-2025.js +1 -1
- package/layout/dropdown.js +1 -1
- package/layout/empty-element.js +1 -1
- package/layout/external-stylesheet.js +1 -1
- package/layout/flex-card.js +1 -1
- package/layout/flex-grid.js +1 -1
- package/layout/flex-row.js +1 -1
- package/layout/footer.js +1 -1
- package/layout/form-components/custom.js +1 -1
- package/layout/form-components/data-list.js +1 -1
- package/layout/form-components/floating-input.js +1 -1
- package/layout/form-components/form-all.js +1 -1
- package/layout/form-components/form.js +1 -1
- package/layout/form-components/image-picker.js +1 -1
- package/layout/form-components/picker.js +1 -1
- package/layout/form-components/radio.js +1 -1
- package/layout/form-components/radiogroup.js +1 -1
- package/layout/form-components/range.js +1 -1
- package/layout/free.js +1 -1
- package/layout/grid-new.js +1 -1
- package/layout/grid-switcher.js +1 -1
- package/layout/grid.js +1 -1
- package/layout/group.js +1 -1
- package/layout/header.js +1 -1
- package/layout/horizontal-scroller.js +1 -1
- package/layout/image-old.js +1 -1
- package/layout/image.js +1 -1
- package/layout/index.js +1 -1
- package/layout/label.js +1 -1
- package/layout/link.js +1 -1
- package/layout/list-OLD.js +1 -1
- package/layout/list.js +1 -1
- package/layout/meta-adder.js +1 -1
- package/layout/modal-2025.js +1 -1
- package/layout/modernwrap.js +1 -1
- package/layout/multiswitcher.js +1 -1
- package/layout/multiswitcherBeta.js +1 -1
- package/layout/nav-bar.js +1 -1
- package/layout/nav-factor/custom-div.js +1 -1
- package/layout/navBar-OLD.js +1 -1
- package/layout/new-flat-adder.js +1 -1
- package/layout/new-nav-bar.js +1 -1
- package/layout/offset-container.js +1 -1
- package/layout/polygon.js +1 -1
- package/layout/prerender-site.js +16 -2
- package/layout/prerender.js +15 -5
- package/layout/progress.js +1 -1
- package/layout/row.js +1 -1
- package/layout/saved-new-nav-bar.js +1 -1
- package/layout/scroll-video.js +1 -1
- package/layout/side-bar.js +1 -1
- package/layout/side-nav-bar.js +1 -1
- package/layout/simple-bar.js +1 -1
- package/layout/slider-2025.js +1 -1
- package/layout/spacer.js +1 -1
- package/layout/stack.js +1 -1
- package/layout/styler.js +1 -1
- package/layout/svg.js +1 -1
- package/layout/switcher.js +1 -1
- package/layout/table.js +1 -1
- package/layout/text-field.js +1 -1
- package/layout/text.js +1 -1
- package/layout/ulist.js +1 -1
- package/layout/video.js +1 -1
- package/layout/without-new.js +1 -1
- package/layout/wrap.js +1 -1
- package/layout/zoom-card.js +1 -1
- package/lib/card-getter.js +1 -1
- package/lib/data.js +48 -0
- package/lib/designer.js +1 -1
- package/lib/element-mapper.js +1 -1
- package/lib/keyframe-animation.js +1 -1
- package/lib/link-getter.js +1 -1
- package/lib/scroll-video.js +1 -1
- package/lib/seo.js +198 -0
- package/lib/stacker.js +1 -1
- package/lib/theme.js +1 -1
- package/lib/transform-anim.js +1 -1
- package/package.json +4 -2
package/lib/seo.js
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* nodality v1.0.168
|
|
3
|
+
* (c) 2026 Filip Vabrousek
|
|
4
|
+
* License: MIT
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
let configuredOrigin = "";
|
|
8
|
+
|
|
9
|
+
export function setSeoOrigin(origin) {
|
|
10
|
+
configuredOrigin = String(origin ?? "").replace(/\/+$/, "");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function resolveOrigin() {
|
|
14
|
+
if (configuredOrigin) return configuredOrigin;
|
|
15
|
+
if (typeof window !== "undefined" && window.location?.origin) {
|
|
16
|
+
return window.location.origin;
|
|
17
|
+
}
|
|
18
|
+
return "";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function upsert(selector, build) {
|
|
22
|
+
if (typeof document === "undefined") return;
|
|
23
|
+
// Drop the previously-managed tag (if any) and write a fresh one.
|
|
24
|
+
// Safer than in-place mutation because the static template may have
|
|
25
|
+
// shipped its own <title> or <meta charset>; we own only the
|
|
26
|
+
// `data-seo="1"` set.
|
|
27
|
+
document.head.querySelectorAll(selector).forEach((el) => el.remove());
|
|
28
|
+
const el = build();
|
|
29
|
+
if (el) document.head.appendChild(el);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function metaTag(nameAttr, name, content) {
|
|
33
|
+
if (content == null || content === "") return null;
|
|
34
|
+
const m = document.createElement("meta");
|
|
35
|
+
m.setAttribute(nameAttr, name);
|
|
36
|
+
m.setAttribute("content", String(content));
|
|
37
|
+
m.setAttribute("data-seo", "1");
|
|
38
|
+
return m;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param {object} opts
|
|
43
|
+
* @param {string} [opts.path] — page path relative to origin ("/" or "/blog/foo")
|
|
44
|
+
* @param {string} [opts.title] — used for OG / Twitter title (NOT <title>)
|
|
45
|
+
* @param {string} [opts.description] — meta description + OG / Twitter description
|
|
46
|
+
* @param {string} [opts.image] — hero image (absolute, or origin-relative starting with "/")
|
|
47
|
+
* @param {string} [opts.ogType] — defaults to "website"; products use "product", articles "article"
|
|
48
|
+
* @param {string} [opts.siteName] — defaults to ""; appears in OG site_name
|
|
49
|
+
* @param {object} [opts.jsonLd] — optional schema.org payload (object or @graph wrapper)
|
|
50
|
+
*/
|
|
51
|
+
export function applySeoMeta(opts) {
|
|
52
|
+
if (typeof document === "undefined") return;
|
|
53
|
+
|
|
54
|
+
const origin = resolveOrigin();
|
|
55
|
+
const canonicalUrl = opts.path
|
|
56
|
+
? (origin ? new URL(opts.path, origin).toString() : opts.path)
|
|
57
|
+
: origin || "";
|
|
58
|
+
|
|
59
|
+
let absoluteImage = null;
|
|
60
|
+
if (opts.image) {
|
|
61
|
+
absoluteImage = /^https?:/i.test(opts.image)
|
|
62
|
+
? opts.image
|
|
63
|
+
: (origin ? new URL(opts.image, origin).toString() : opts.image);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
upsert('meta[name="description"][data-seo]', () =>
|
|
67
|
+
metaTag("name", "description", opts.description));
|
|
68
|
+
|
|
69
|
+
upsert('link[rel="canonical"][data-seo]', () => {
|
|
70
|
+
if (!canonicalUrl) return null;
|
|
71
|
+
const l = document.createElement("link");
|
|
72
|
+
l.setAttribute("rel", "canonical");
|
|
73
|
+
l.setAttribute("href", canonicalUrl);
|
|
74
|
+
l.setAttribute("data-seo", "1");
|
|
75
|
+
return l;
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Open Graph — Facebook, WhatsApp, iMessage, LinkedIn, Slack.
|
|
79
|
+
upsert('meta[property="og:type"][data-seo]', () =>
|
|
80
|
+
metaTag("property", "og:type", opts.ogType ?? "website"));
|
|
81
|
+
upsert('meta[property="og:title"][data-seo]', () =>
|
|
82
|
+
metaTag("property", "og:title", opts.title));
|
|
83
|
+
upsert('meta[property="og:description"][data-seo]', () =>
|
|
84
|
+
metaTag("property", "og:description", opts.description));
|
|
85
|
+
upsert('meta[property="og:url"][data-seo]', () =>
|
|
86
|
+
metaTag("property", "og:url", canonicalUrl));
|
|
87
|
+
upsert('meta[property="og:image"][data-seo]', () =>
|
|
88
|
+
metaTag("property", "og:image", absoluteImage));
|
|
89
|
+
upsert('meta[property="og:site_name"][data-seo]', () =>
|
|
90
|
+
metaTag("property", "og:site_name", opts.siteName));
|
|
91
|
+
|
|
92
|
+
// Twitter / X — prefers its own tags, falls back to OG.
|
|
93
|
+
upsert('meta[name="twitter:card"][data-seo]', () =>
|
|
94
|
+
metaTag("name", "twitter:card", absoluteImage ? "summary_large_image" : "summary"));
|
|
95
|
+
upsert('meta[name="twitter:title"][data-seo]', () =>
|
|
96
|
+
metaTag("name", "twitter:title", opts.title));
|
|
97
|
+
upsert('meta[name="twitter:description"][data-seo]', () =>
|
|
98
|
+
metaTag("name", "twitter:description", opts.description));
|
|
99
|
+
upsert('meta[name="twitter:image"][data-seo]', () =>
|
|
100
|
+
metaTag("name", "twitter:image", absoluteImage));
|
|
101
|
+
|
|
102
|
+
upsert('script[type="application/ld+json"][data-seo]', () => {
|
|
103
|
+
if (!opts.jsonLd) return null;
|
|
104
|
+
const s = document.createElement("script");
|
|
105
|
+
s.setAttribute("type", "application/ld+json");
|
|
106
|
+
s.setAttribute("data-seo", "1");
|
|
107
|
+
s.textContent = JSON.stringify(opts.jsonLd);
|
|
108
|
+
return s;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ─── JSON-LD builders ──────────────────────────────────────────────
|
|
113
|
+
//
|
|
114
|
+
// Each builder returns a plain object the caller can pass to
|
|
115
|
+
// `applySeoMeta({ jsonLd: ... })`. For pages that need to declare more
|
|
116
|
+
// than one type, wrap them in @graph:
|
|
117
|
+
//
|
|
118
|
+
// applySeoMeta({ jsonLd: { "@context": "https://schema.org",
|
|
119
|
+
// "@graph": [websiteJsonLd({ name, url }), organizationJsonLd({...}) ] } });
|
|
120
|
+
|
|
121
|
+
export function websiteJsonLd({ name, url, inLanguage } = {}) {
|
|
122
|
+
return {
|
|
123
|
+
"@context": "https://schema.org",
|
|
124
|
+
"@type": "WebSite",
|
|
125
|
+
name,
|
|
126
|
+
url,
|
|
127
|
+
...(inLanguage ? { inLanguage } : {}),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function organizationJsonLd({ name, url, logo, sameAs } = {}) {
|
|
132
|
+
return {
|
|
133
|
+
"@context": "https://schema.org",
|
|
134
|
+
"@type": "Organization",
|
|
135
|
+
name,
|
|
136
|
+
url,
|
|
137
|
+
...(logo ? { logo } : {}),
|
|
138
|
+
...(sameAs ? { sameAs } : {}),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Product schema. `priceCurrency` defaults to USD; pass your own
|
|
144
|
+
* (e.g. "EUR", "CZK") if you ship internationally. `price` is the
|
|
145
|
+
* numeric value as a string (schema.org spec) — pass undefined to
|
|
146
|
+
* omit the offer block entirely.
|
|
147
|
+
*/
|
|
148
|
+
export function productJsonLd({ name, description, image, brand, category, sku, url, price, priceCurrency = "USD", availability = "https://schema.org/InStock" } = {}) {
|
|
149
|
+
const ld = {
|
|
150
|
+
"@context": "https://schema.org",
|
|
151
|
+
"@type": "Product",
|
|
152
|
+
name,
|
|
153
|
+
...(description ? { description } : {}),
|
|
154
|
+
...(image ? { image: Array.isArray(image) ? image : [image] } : {}),
|
|
155
|
+
...(brand ? { brand: typeof brand === "string" ? { "@type": "Brand", name: brand } : brand } : {}),
|
|
156
|
+
...(category ? { category } : {}),
|
|
157
|
+
...(sku ? { sku } : {}),
|
|
158
|
+
};
|
|
159
|
+
if (price != null) {
|
|
160
|
+
ld.offers = {
|
|
161
|
+
"@type": "Offer",
|
|
162
|
+
...(url ? { url } : {}),
|
|
163
|
+
priceCurrency,
|
|
164
|
+
price: String(price),
|
|
165
|
+
availability,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
return ld;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function articleJsonLd({ headline, description, image, author, datePublished, dateModified, publisher, url } = {}) {
|
|
172
|
+
return {
|
|
173
|
+
"@context": "https://schema.org",
|
|
174
|
+
"@type": "Article",
|
|
175
|
+
headline,
|
|
176
|
+
...(description ? { description } : {}),
|
|
177
|
+
...(image ? { image: Array.isArray(image) ? image : [image] } : {}),
|
|
178
|
+
...(author ? { author: typeof author === "string" ? { "@type": "Person", name: author } : author } : {}),
|
|
179
|
+
...(datePublished ? { datePublished } : {}),
|
|
180
|
+
...(dateModified ? { dateModified } : {}),
|
|
181
|
+
...(publisher ? { publisher: typeof publisher === "string" ? { "@type": "Organization", name: publisher } : publisher } : {}),
|
|
182
|
+
...(url ? { mainEntityOfPage: url } : {}),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** items: [{ name, url }, ...] in breadcrumb order (root → leaf). */
|
|
187
|
+
export function breadcrumbJsonLd(items = []) {
|
|
188
|
+
return {
|
|
189
|
+
"@context": "https://schema.org",
|
|
190
|
+
"@type": "BreadcrumbList",
|
|
191
|
+
itemListElement: items.map((it, i) => ({
|
|
192
|
+
"@type": "ListItem",
|
|
193
|
+
position: i + 1,
|
|
194
|
+
name: it.name,
|
|
195
|
+
item: it.url,
|
|
196
|
+
})),
|
|
197
|
+
};
|
|
198
|
+
}
|
package/lib/stacker.js
CHANGED
package/lib/theme.js
CHANGED
package/lib/transform-anim.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodality",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.168",
|
|
4
4
|
"description": "A lightweight library for declarative UI elements.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
@@ -19,7 +19,9 @@
|
|
|
19
19
|
"import": "./dist/index.esm.js"
|
|
20
20
|
},
|
|
21
21
|
"./ssg": "./layout/prerender.js",
|
|
22
|
-
"./ssg-site": "./layout/prerender-site.js"
|
|
22
|
+
"./ssg-site": "./layout/prerender-site.js",
|
|
23
|
+
"./seo": "./lib/seo.js",
|
|
24
|
+
"./data": "./lib/data.js"
|
|
23
25
|
},
|
|
24
26
|
"publishConfig": {
|
|
25
27
|
"access": "public",
|