@bytesbrains/weblocks 0.3.0 → 0.5.0
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/AGENT.md +10 -3
- package/CATALOG.md +40 -3
- package/CHANGELOG.md +48 -0
- package/README.md +28 -3
- package/catalog.json +214 -8
- package/lib/blocks/brandIcons.d.ts +5 -0
- package/lib/blocks/brandIcons.js +18 -0
- package/lib/blocks/copyright.d.ts +2 -0
- package/lib/blocks/copyright.js +48 -0
- package/lib/blocks/gallery.js +2 -1
- package/lib/blocks/legal.d.ts +2 -0
- package/lib/blocks/legal.js +100 -0
- package/lib/blocks/socialLinks.js +71 -21
- package/lib/blocks/videoGallery.d.ts +2 -0
- package/lib/blocks/videoGallery.js +110 -0
- package/lib/blocks/videoUtil.d.ts +14 -0
- package/lib/blocks/videoUtil.js +30 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/islands/carousel.d.ts +1 -0
- package/lib/islands/carousel.js +122 -0
- package/lib/islands/lightbox.d.ts +1 -0
- package/lib/islands/lightbox.js +139 -0
- package/lib/islands/video.d.ts +1 -0
- package/lib/islands/video.js +48 -0
- package/lib/markdown.d.ts +2 -0
- package/lib/markdown.js +90 -0
- package/lib/registry.js +6 -3
- package/lib/render.d.ts +6 -0
- package/lib/render.js +2 -1
- package/package.json +5 -3
package/AGENT.md
CHANGED
|
@@ -46,18 +46,25 @@ its exact config schema:
|
|
|
46
46
|
- `catalogPrompt()` — a compact text menu for a system prompt.
|
|
47
47
|
- `CATALOG.md` — the same, human-readable.
|
|
48
48
|
|
|
49
|
-
The
|
|
49
|
+
The 42 block types, by group:
|
|
50
50
|
|
|
51
51
|
- **Chrome/app-shell:** `nav`, `app-shell`, `sidebar`, `announcement-bar`, `footer`
|
|
52
52
|
- **Heroes:** `hero`, `hero-app`
|
|
53
53
|
- **Content:** `features`, `about`, `rich-text`, `split`, `steps`, `stats`,
|
|
54
54
|
`services-catalogue`, `pricing`, `logos`, `team`
|
|
55
|
-
- **Media:** `gallery`, `carousel`, `video`, `map`
|
|
55
|
+
- **Media:** `gallery`, `carousel`, `video`, `video-gallery`, `map`
|
|
56
56
|
- **Location:** `directions` (deep links to open the visitor’s map app)
|
|
57
57
|
- **Structured:** `timeline`, `tabs`, `accordion`, `testimonials`, `faq`
|
|
58
58
|
- **Collections:** `blog-list`, `blog-post`, `feed`
|
|
59
59
|
- **Dynamic (powered):** `contact-form`, `newsletter`, `search`, `auth`
|
|
60
|
-
- **Conversion/rhythm:** `cta`, `social-links`, `contact-details`, `divider`, `spacer`
|
|
60
|
+
- **Conversion/rhythm:** `cta`, `social-links`, `contact-details`, `divider`, `spacer`, `copyright`
|
|
61
|
+
- **Legal:** `legal` (terms/privacy links that open safe-Markdown dialogs; content is Markdown, never raw HTML)
|
|
62
|
+
|
|
63
|
+
Interactivity is safe to enable: `gallery` with `lightbox: true`, `carousel` with
|
|
64
|
+
`autoplay: true`, `tabs`/`accordion`, etc. work out of the box — CSS-only where
|
|
65
|
+
possible, and the host serves small shipped islands (`gallery` lightbox,
|
|
66
|
+
`carousel` controls) for the rest. You just set the typed config; you never write
|
|
67
|
+
the JavaScript.
|
|
61
68
|
|
|
62
69
|
## Composing a manifest
|
|
63
70
|
|
package/CATALOG.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# @bytesbrains/weblocks — Block Catalog (v0.
|
|
1
|
+
# @bytesbrains/weblocks — Block Catalog (v0.5.0)
|
|
2
2
|
|
|
3
3
|
The AI composes a `SiteManifest` (`{ meta, design, blocks[] }`) using **only** the block types below, then the engine validates + renders it to static HTML. This file is generated from the code (`npm run emit:catalog`) — do not edit by hand.
|
|
4
4
|
|
|
5
|
-
**Block types:** `app-shell` · `nav` · `announcement-bar` · `sidebar` · `hero` · `hero-app` · `features` · `about` · `rich-text` · `split` · `steps` · `stats` · `services-catalogue` · `pricing` · `logos` · `team` · `gallery` · `carousel` · `video` · `map` · `timeline` · `tabs` · `accordion` · `testimonials` · `faq` · `blog-list` · `blog-post` · `feed` · `contact-form` · `newsletter` · `search` · `auth` · `cta` · `social-links` · `contact-details` · `directions` · `divider` · `spacer` · `footer`
|
|
5
|
+
**Block types:** `app-shell` · `nav` · `announcement-bar` · `sidebar` · `hero` · `hero-app` · `features` · `about` · `rich-text` · `split` · `steps` · `stats` · `services-catalogue` · `pricing` · `logos` · `team` · `gallery` · `carousel` · `video` · `video-gallery` · `map` · `timeline` · `tabs` · `accordion` · `testimonials` · `faq` · `blog-list` · `blog-post` · `feed` · `contact-form` · `newsletter` · `search` · `auth` · `cta` · `social-links` · `contact-details` · `directions` · `legal` · `divider` · `spacer` · `copyright` · `footer`
|
|
6
6
|
|
|
7
7
|
## `app-shell`
|
|
8
8
|
|
|
@@ -203,6 +203,17 @@ A responsive embedded video from YouTube or Vimeo (by id or URL) or a self-hoste
|
|
|
203
203
|
| `poster` | string | | |
|
|
204
204
|
| `caption` | string | | |
|
|
205
205
|
|
|
206
|
+
## `video-gallery`
|
|
207
|
+
|
|
208
|
+
A grid or carousel of click-to-play video cards (YouTube/Vimeo/file); each loads its player inline on click (a lightweight facade — no heavy iframes up front).
|
|
209
|
+
|
|
210
|
+
| field | type | required | notes |
|
|
211
|
+
|---|---|---|---|
|
|
212
|
+
| `title` | string | | |
|
|
213
|
+
| `layout` | undefined (grid\|carousel) | | |
|
|
214
|
+
| `columns` | integer (2\|3\|4) | | |
|
|
215
|
+
| `items` | array | | |
|
|
216
|
+
|
|
206
217
|
## `map`
|
|
207
218
|
|
|
208
219
|
An embedded location map for a place or address query, with configurable zoom and height and a link to the full map.
|
|
@@ -352,11 +363,14 @@ A full-width call-to-action band: a headline, optional subheading, and one butto
|
|
|
352
363
|
|
|
353
364
|
## `social-links`
|
|
354
365
|
|
|
355
|
-
A
|
|
366
|
+
A row or grid of links to social/contact profiles; each link picks a built-in brand icon by platform (or a custom emoji), shown labeled or icon-only.
|
|
356
367
|
|
|
357
368
|
| field | type | required | notes |
|
|
358
369
|
|---|---|---|---|
|
|
359
370
|
| `title` | string | | |
|
|
371
|
+
| `layout` | undefined (row\|grid) | | |
|
|
372
|
+
| `variant` | undefined (labeled\|icon) | | |
|
|
373
|
+
| `align` | undefined (start\|center\|end) | | |
|
|
360
374
|
| `links` | array | | |
|
|
361
375
|
|
|
362
376
|
## `contact-details`
|
|
@@ -386,6 +400,17 @@ A location card with deep links that open the visitor’s map app (Google/Apple
|
|
|
386
400
|
| `directionsLabel` | string | | |
|
|
387
401
|
| `appleMaps` | boolean | | |
|
|
388
402
|
|
|
403
|
+
## `legal`
|
|
404
|
+
|
|
405
|
+
Policy links (terms, privacy, cookies, …) that open as scrollable, dismissible dialogs; each body is safe Markdown (never raw HTML). No JavaScript.
|
|
406
|
+
|
|
407
|
+
| field | type | required | notes |
|
|
408
|
+
|---|---|---|---|
|
|
409
|
+
| `title` | string | | |
|
|
410
|
+
| `align` | undefined (start\|center\|end) | | |
|
|
411
|
+
| `separator` | string | | |
|
|
412
|
+
| `documents` | array | | |
|
|
413
|
+
|
|
389
414
|
## `divider`
|
|
390
415
|
|
|
391
416
|
A visual section break rendered as a thin line, a dotted rule, or a gradient bar.
|
|
@@ -402,6 +427,18 @@ Deliberate vertical whitespace between sections, in one of four sizes (sm, md, l
|
|
|
402
427
|
|---|---|---|---|
|
|
403
428
|
| `size` | undefined (sm\|md\|lg\|xl) | | |
|
|
404
429
|
|
|
430
|
+
## `copyright`
|
|
431
|
+
|
|
432
|
+
A small copyright bar (© year holder + rights text) for the bottom of a page; the year auto-fills to the current year when left blank.
|
|
433
|
+
|
|
434
|
+
| field | type | required | notes |
|
|
435
|
+
|---|---|---|---|
|
|
436
|
+
| `holder` | string | | |
|
|
437
|
+
| `year` | string | | |
|
|
438
|
+
| `text` | string | | |
|
|
439
|
+
| `showSymbol` | boolean | | |
|
|
440
|
+
| `align` | undefined (start\|center\|end) | | |
|
|
441
|
+
|
|
405
442
|
## `footer`
|
|
406
443
|
|
|
407
444
|
Page footer: brand, tagline, a row of links, and a copyright line. Place last.
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,54 @@ follows [semantic versioning](https://semver.org): the **block catalog** and the
|
|
|
5
5
|
**`SiteManifest` shape** are the public contract — additive block/field changes
|
|
6
6
|
are minor, breaking changes to either are major.
|
|
7
7
|
|
|
8
|
+
## 0.5.0 — 2026-07-16
|
|
9
|
+
|
|
10
|
+
More media & footer blocks, brand icons, and shipped interactivity. Additive and
|
|
11
|
+
**non-breaking** — every `0.4.0` manifest still validates and renders identically.
|
|
12
|
+
Catalog 40 → 42.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- **`video-gallery` block** — a grid or carousel of **click-to-play video cards**
|
|
16
|
+
(YouTube / Vimeo / self-hosted). Each card is a lightweight *facade* (thumbnail
|
|
17
|
+
+ play button); the new **`video.js` island** loads the real player inline on
|
|
18
|
+
click, so no heavy iframes load up front. YouTube thumbnails auto-derive from
|
|
19
|
+
the id; no-JS clicks open the platform.
|
|
20
|
+
- **`copyright` block** — a small "© year holder · rights" bar for the bottom of
|
|
21
|
+
a page (a standalone alternative to the `footer` copyright line). The year
|
|
22
|
+
auto-fills to the current year when blank; configurable holder, note, symbol,
|
|
23
|
+
and alignment.
|
|
24
|
+
- **`social-links` — built-in brand icons & layouts.** Each link takes a typed
|
|
25
|
+
`platform` (x/twitter, instagram, facebook, linkedin, youtube, github, tiktok,
|
|
26
|
+
whatsapp, telegram, discord, mastodon, rss, email, website, phone) that supplies
|
|
27
|
+
a monochrome brand icon (simple-icons, CC0; themed via `currentColor`) and a
|
|
28
|
+
default label — `custom` still takes your own emoji/glyph. New `layout`
|
|
29
|
+
(row/grid), `variant` (labeled/icon-only), and `align` options. Non-breaking.
|
|
30
|
+
- **Shipped interactive islands** — the engine now ships the client scripts for
|
|
31
|
+
its interactive blocks (previously host-provided), as zero-dependency browser
|
|
32
|
+
modules under the `./islands/*.js` subpath export:
|
|
33
|
+
- `lightbox.js` — `gallery` click-to-zoom: prev/next, keyboard, swipe, Esc,
|
|
34
|
+
caption, scroll-lock, focus restore.
|
|
35
|
+
- `carousel.js` — `carousel` arrows, dot indicators, keyboard nav, and optional
|
|
36
|
+
autoplay (honours `prefers-reduced-motion`, pauses on hover/focus).
|
|
37
|
+
- `renderSite(manifest, { islandBase })` to configure where island scripts are
|
|
38
|
+
served (default `/_island`).
|
|
39
|
+
- Islands are built by a separate `tsconfig.islands.json` (DOM lib); the engine's
|
|
40
|
+
Node code stays DOM-free. `gallery` now marks `data-wl-lightbox` when its
|
|
41
|
+
lightbox is enabled.
|
|
42
|
+
|
|
43
|
+
## 0.4.0 — 2026-07-16
|
|
44
|
+
|
|
45
|
+
Additive and non-breaking — every `0.3.0` manifest still validates and renders
|
|
46
|
+
identically. Catalog 39 → 40.
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
- **`legal` block** — policy links (Terms, Privacy, Cookies, …) that open as
|
|
50
|
+
**scrollable, dismissible dialogs** (pure CSS `:target`, no JavaScript). Each
|
|
51
|
+
document's body is authored in a **safe Markdown subset** (headings, lists,
|
|
52
|
+
links, emphasis, quotes, rules) — rich formatting, but **never raw HTML** (any
|
|
53
|
+
literal HTML is escaped, not executed). Exports `renderMarkdown`. Catalog now
|
|
54
|
+
40 blocks.
|
|
55
|
+
|
|
8
56
|
## 0.3.0 — 2026-07-16
|
|
9
57
|
|
|
10
58
|
Additive and non-breaking — every `0.2.0` manifest still validates and renders
|
package/README.md
CHANGED
|
@@ -139,19 +139,20 @@ import catalogJson from '@bytesbrains/weblocks/catalog.json' with { type: 'json'
|
|
|
139
139
|
|
|
140
140
|
## Block catalog
|
|
141
141
|
|
|
142
|
-
**
|
|
142
|
+
**42 typed blocks.** Full field reference in [`CATALOG.md`](./CATALOG.md).
|
|
143
143
|
|
|
144
144
|
| Group | Blocks |
|
|
145
145
|
|---|---|
|
|
146
146
|
| Chrome / app-shell | `nav` · `app-shell` · `sidebar` · `announcement-bar` · `footer` |
|
|
147
147
|
| Heroes | `hero` · `hero-app` |
|
|
148
148
|
| Content | `features` · `about` · `rich-text` · `split` · `steps` · `stats` · `services-catalogue` · `pricing` · `logos` · `team` |
|
|
149
|
-
| Media | `gallery` · `carousel` · `video` · `map` |
|
|
149
|
+
| Media | `gallery` · `carousel` · `video` · `video-gallery` · `map` |
|
|
150
150
|
| Location | `directions` (deep links to the visitor’s map app) |
|
|
151
151
|
| Structured | `timeline` · `tabs` · `accordion` · `testimonials` · `faq` |
|
|
152
152
|
| Collections | `blog-list` · `blog-post` · `feed` |
|
|
153
153
|
| Dynamic (powered) | `contact-form` · `newsletter` · `search` · `auth` |
|
|
154
|
-
| Conversion / rhythm | `cta` · `social-links` · `contact-details` · `divider` · `spacer` |
|
|
154
|
+
| Conversion / rhythm | `cta` · `social-links` · `contact-details` · `divider` · `spacer` · `copyright` |
|
|
155
|
+
| Legal | `legal` (terms/privacy links → safe-Markdown dialogs) |
|
|
155
156
|
|
|
156
157
|
`rich-text` and `blog-post` carry **typed** content nodes (headings, paragraphs,
|
|
157
158
|
quotes, lists) — a safe freeform-content escape hatch that is never raw HTML.
|
|
@@ -233,6 +234,30 @@ for (const [file, body] of Object.entries(emitPwa(manifest) ?? {})) writeFileSyn
|
|
|
233
234
|
// → manifest.webmanifest + sw.js
|
|
234
235
|
```
|
|
235
236
|
|
|
237
|
+
## Interactivity (islands)
|
|
238
|
+
|
|
239
|
+
Pages are static-first: JavaScript ships only for the interactive blocks that need
|
|
240
|
+
it, and only when their behaviour is on. `renderSite` emits a marker for each —
|
|
241
|
+
`<script type="module" src="/_island/<name>.js">` — and the engine **ships the
|
|
242
|
+
island scripts** (zero-dependency, ~6 KB each) under a subpath:
|
|
243
|
+
|
|
244
|
+
| Block | Island | Behaviour |
|
|
245
|
+
|---|---|---|
|
|
246
|
+
| `gallery` (`lightbox: true`) | `lightbox.js` | click-to-zoom, prev/next, keyboard, swipe, Esc |
|
|
247
|
+
| `carousel` | `carousel.js` | arrows, dots, keyboard, optional autoplay |
|
|
248
|
+
| `video-gallery` | `video.js` | click-to-play cards (load the real player inline on press) |
|
|
249
|
+
|
|
250
|
+
Serve them at the island URL. Copy from the package's `./islands/*.js` export, e.g.:
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
import lightbox from '@bytesbrains/weblocks/islands/lightbox.js?url'; // bundler
|
|
254
|
+
// or, for a static host, copy node_modules/@bytesbrains/weblocks/lib/islands/*.js
|
|
255
|
+
// to /_island/ (change the base with renderSite(m, { islandBase: '/assets/js' }))
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Blocks whose behaviour is off (e.g. `tabs`, `accordion` — CSS-only) ship no JS at
|
|
259
|
+
all.
|
|
260
|
+
|
|
236
261
|
## API reference
|
|
237
262
|
|
|
238
263
|
All exports are named; types are shipped (`lib/index.d.ts`).
|
package/catalog.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"package": "@bytesbrains/weblocks",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.0",
|
|
5
5
|
"description": "Block catalog for @bytesbrains/weblocks. Send this to the model as its API reference; it composes a SiteManifest ({ meta, design, blocks[] }) using ONLY these block types. The engine then validates and renders it.",
|
|
6
6
|
"blockTypes": [
|
|
7
7
|
"app-shell",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"gallery",
|
|
24
24
|
"carousel",
|
|
25
25
|
"video",
|
|
26
|
+
"video-gallery",
|
|
26
27
|
"map",
|
|
27
28
|
"timeline",
|
|
28
29
|
"tabs",
|
|
@@ -40,8 +41,10 @@
|
|
|
40
41
|
"social-links",
|
|
41
42
|
"contact-details",
|
|
42
43
|
"directions",
|
|
44
|
+
"legal",
|
|
43
45
|
"divider",
|
|
44
46
|
"spacer",
|
|
47
|
+
"copyright",
|
|
45
48
|
"footer"
|
|
46
49
|
],
|
|
47
50
|
"blocks": [
|
|
@@ -1029,6 +1032,73 @@
|
|
|
1029
1032
|
"additionalProperties": false
|
|
1030
1033
|
}
|
|
1031
1034
|
},
|
|
1035
|
+
{
|
|
1036
|
+
"type": "video-gallery",
|
|
1037
|
+
"description": "A grid or carousel of click-to-play video cards (YouTube/Vimeo/file); each loads its player inline on click (a lightweight facade — no heavy iframes up front).",
|
|
1038
|
+
"schema": {
|
|
1039
|
+
"type": "object",
|
|
1040
|
+
"properties": {
|
|
1041
|
+
"title": {
|
|
1042
|
+
"type": "string",
|
|
1043
|
+
"maxLength": 120,
|
|
1044
|
+
"default": ""
|
|
1045
|
+
},
|
|
1046
|
+
"layout": {
|
|
1047
|
+
"enum": [
|
|
1048
|
+
"grid",
|
|
1049
|
+
"carousel"
|
|
1050
|
+
],
|
|
1051
|
+
"default": "grid"
|
|
1052
|
+
},
|
|
1053
|
+
"columns": {
|
|
1054
|
+
"type": "integer",
|
|
1055
|
+
"enum": [
|
|
1056
|
+
2,
|
|
1057
|
+
3,
|
|
1058
|
+
4
|
|
1059
|
+
],
|
|
1060
|
+
"default": 3
|
|
1061
|
+
},
|
|
1062
|
+
"items": {
|
|
1063
|
+
"type": "array",
|
|
1064
|
+
"items": {
|
|
1065
|
+
"type": "object",
|
|
1066
|
+
"properties": {
|
|
1067
|
+
"provider": {
|
|
1068
|
+
"enum": [
|
|
1069
|
+
"youtube",
|
|
1070
|
+
"vimeo",
|
|
1071
|
+
"file"
|
|
1072
|
+
],
|
|
1073
|
+
"default": "youtube"
|
|
1074
|
+
},
|
|
1075
|
+
"src": {
|
|
1076
|
+
"type": "string",
|
|
1077
|
+
"maxLength": 500,
|
|
1078
|
+
"default": ""
|
|
1079
|
+
},
|
|
1080
|
+
"title": {
|
|
1081
|
+
"type": "string",
|
|
1082
|
+
"maxLength": 160,
|
|
1083
|
+
"default": ""
|
|
1084
|
+
},
|
|
1085
|
+
"poster": {
|
|
1086
|
+
"type": "string",
|
|
1087
|
+
"maxLength": 500,
|
|
1088
|
+
"default": ""
|
|
1089
|
+
}
|
|
1090
|
+
},
|
|
1091
|
+
"required": [
|
|
1092
|
+
"src"
|
|
1093
|
+
],
|
|
1094
|
+
"additionalProperties": false
|
|
1095
|
+
},
|
|
1096
|
+
"maxItems": 24
|
|
1097
|
+
}
|
|
1098
|
+
},
|
|
1099
|
+
"additionalProperties": false
|
|
1100
|
+
}
|
|
1101
|
+
},
|
|
1032
1102
|
{
|
|
1033
1103
|
"type": "map",
|
|
1034
1104
|
"description": "An embedded location map for a place or address query, with configurable zoom and height and a link to the full map.",
|
|
@@ -1736,7 +1806,7 @@
|
|
|
1736
1806
|
},
|
|
1737
1807
|
{
|
|
1738
1808
|
"type": "social-links",
|
|
1739
|
-
"description": "A
|
|
1809
|
+
"description": "A row or grid of links to social/contact profiles; each link picks a built-in brand icon by platform (or a custom emoji), shown labeled or icon-only.",
|
|
1740
1810
|
"schema": {
|
|
1741
1811
|
"type": "object",
|
|
1742
1812
|
"properties": {
|
|
@@ -1745,21 +1815,65 @@
|
|
|
1745
1815
|
"maxLength": 120,
|
|
1746
1816
|
"default": ""
|
|
1747
1817
|
},
|
|
1818
|
+
"layout": {
|
|
1819
|
+
"enum": [
|
|
1820
|
+
"row",
|
|
1821
|
+
"grid"
|
|
1822
|
+
],
|
|
1823
|
+
"default": "row"
|
|
1824
|
+
},
|
|
1825
|
+
"variant": {
|
|
1826
|
+
"enum": [
|
|
1827
|
+
"labeled",
|
|
1828
|
+
"icon"
|
|
1829
|
+
],
|
|
1830
|
+
"default": "labeled"
|
|
1831
|
+
},
|
|
1832
|
+
"align": {
|
|
1833
|
+
"enum": [
|
|
1834
|
+
"start",
|
|
1835
|
+
"center",
|
|
1836
|
+
"end"
|
|
1837
|
+
],
|
|
1838
|
+
"default": "center"
|
|
1839
|
+
},
|
|
1748
1840
|
"links": {
|
|
1749
1841
|
"type": "array",
|
|
1750
1842
|
"items": {
|
|
1751
1843
|
"type": "object",
|
|
1752
1844
|
"properties": {
|
|
1753
|
-
"
|
|
1754
|
-
"
|
|
1755
|
-
|
|
1756
|
-
|
|
1845
|
+
"platform": {
|
|
1846
|
+
"enum": [
|
|
1847
|
+
"x",
|
|
1848
|
+
"twitter",
|
|
1849
|
+
"instagram",
|
|
1850
|
+
"facebook",
|
|
1851
|
+
"linkedin",
|
|
1852
|
+
"youtube",
|
|
1853
|
+
"github",
|
|
1854
|
+
"tiktok",
|
|
1855
|
+
"whatsapp",
|
|
1856
|
+
"telegram",
|
|
1857
|
+
"discord",
|
|
1858
|
+
"mastodon",
|
|
1859
|
+
"rss",
|
|
1860
|
+
"email",
|
|
1861
|
+
"website",
|
|
1862
|
+
"phone",
|
|
1863
|
+
"custom"
|
|
1864
|
+
],
|
|
1865
|
+
"default": "custom"
|
|
1757
1866
|
},
|
|
1758
1867
|
"href": {
|
|
1759
1868
|
"type": "string",
|
|
1760
1869
|
"maxLength": 500,
|
|
1761
1870
|
"default": ""
|
|
1762
1871
|
},
|
|
1872
|
+
"label": {
|
|
1873
|
+
"type": "string",
|
|
1874
|
+
"maxLength": 60,
|
|
1875
|
+
"default": ""
|
|
1876
|
+
},
|
|
1763
1877
|
"icon": {
|
|
1764
1878
|
"type": "string",
|
|
1765
1879
|
"maxLength": 8,
|
|
@@ -1767,12 +1881,11 @@
|
|
|
1767
1881
|
}
|
|
1768
1882
|
},
|
|
1769
1883
|
"required": [
|
|
1770
|
-
"label",
|
|
1771
1884
|
"href"
|
|
1772
1885
|
],
|
|
1773
1886
|
"additionalProperties": false
|
|
1774
1887
|
},
|
|
1775
|
-
"maxItems":
|
|
1888
|
+
"maxItems": 20
|
|
1776
1889
|
}
|
|
1777
1890
|
},
|
|
1778
1891
|
"additionalProperties": false
|
|
@@ -1862,6 +1975,62 @@
|
|
|
1862
1975
|
"additionalProperties": false
|
|
1863
1976
|
}
|
|
1864
1977
|
},
|
|
1978
|
+
{
|
|
1979
|
+
"type": "legal",
|
|
1980
|
+
"description": "Policy links (terms, privacy, cookies, …) that open as scrollable, dismissible dialogs; each body is safe Markdown (never raw HTML). No JavaScript.",
|
|
1981
|
+
"schema": {
|
|
1982
|
+
"type": "object",
|
|
1983
|
+
"properties": {
|
|
1984
|
+
"title": {
|
|
1985
|
+
"type": "string",
|
|
1986
|
+
"maxLength": 120,
|
|
1987
|
+
"default": ""
|
|
1988
|
+
},
|
|
1989
|
+
"align": {
|
|
1990
|
+
"enum": [
|
|
1991
|
+
"start",
|
|
1992
|
+
"center",
|
|
1993
|
+
"end"
|
|
1994
|
+
],
|
|
1995
|
+
"default": "center"
|
|
1996
|
+
},
|
|
1997
|
+
"separator": {
|
|
1998
|
+
"type": "string",
|
|
1999
|
+
"maxLength": 4,
|
|
2000
|
+
"default": "·"
|
|
2001
|
+
},
|
|
2002
|
+
"documents": {
|
|
2003
|
+
"type": "array",
|
|
2004
|
+
"items": {
|
|
2005
|
+
"type": "object",
|
|
2006
|
+
"properties": {
|
|
2007
|
+
"label": {
|
|
2008
|
+
"type": "string",
|
|
2009
|
+
"maxLength": 60,
|
|
2010
|
+
"default": ""
|
|
2011
|
+
},
|
|
2012
|
+
"title": {
|
|
2013
|
+
"type": "string",
|
|
2014
|
+
"maxLength": 120,
|
|
2015
|
+
"default": ""
|
|
2016
|
+
},
|
|
2017
|
+
"content": {
|
|
2018
|
+
"type": "string",
|
|
2019
|
+
"maxLength": 40000,
|
|
2020
|
+
"default": ""
|
|
2021
|
+
}
|
|
2022
|
+
},
|
|
2023
|
+
"required": [
|
|
2024
|
+
"label"
|
|
2025
|
+
],
|
|
2026
|
+
"additionalProperties": false
|
|
2027
|
+
},
|
|
2028
|
+
"maxItems": 8
|
|
2029
|
+
}
|
|
2030
|
+
},
|
|
2031
|
+
"additionalProperties": false
|
|
2032
|
+
}
|
|
2033
|
+
},
|
|
1865
2034
|
{
|
|
1866
2035
|
"type": "divider",
|
|
1867
2036
|
"description": "A visual section break rendered as a thin line, a dotted rule, or a gradient bar.",
|
|
@@ -1899,6 +2068,43 @@
|
|
|
1899
2068
|
"additionalProperties": false
|
|
1900
2069
|
}
|
|
1901
2070
|
},
|
|
2071
|
+
{
|
|
2072
|
+
"type": "copyright",
|
|
2073
|
+
"description": "A small copyright bar (© year holder + rights text) for the bottom of a page; the year auto-fills to the current year when left blank.",
|
|
2074
|
+
"schema": {
|
|
2075
|
+
"type": "object",
|
|
2076
|
+
"properties": {
|
|
2077
|
+
"holder": {
|
|
2078
|
+
"type": "string",
|
|
2079
|
+
"maxLength": 120,
|
|
2080
|
+
"default": ""
|
|
2081
|
+
},
|
|
2082
|
+
"year": {
|
|
2083
|
+
"type": "string",
|
|
2084
|
+
"maxLength": 24,
|
|
2085
|
+
"default": ""
|
|
2086
|
+
},
|
|
2087
|
+
"text": {
|
|
2088
|
+
"type": "string",
|
|
2089
|
+
"maxLength": 160,
|
|
2090
|
+
"default": "All rights reserved."
|
|
2091
|
+
},
|
|
2092
|
+
"showSymbol": {
|
|
2093
|
+
"type": "boolean",
|
|
2094
|
+
"default": true
|
|
2095
|
+
},
|
|
2096
|
+
"align": {
|
|
2097
|
+
"enum": [
|
|
2098
|
+
"start",
|
|
2099
|
+
"center",
|
|
2100
|
+
"end"
|
|
2101
|
+
],
|
|
2102
|
+
"default": "center"
|
|
2103
|
+
}
|
|
2104
|
+
},
|
|
2105
|
+
"additionalProperties": false
|
|
2106
|
+
}
|
|
2107
|
+
},
|
|
1902
2108
|
{
|
|
1903
2109
|
"type": "footer",
|
|
1904
2110
|
"description": "Page footer: brand, tagline, a row of links, and a copyright line. Place last.",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Brand icon path data (24×24 viewBox, fill=currentColor). Sourced from
|
|
3
|
+
* simple-icons (CC0 / public domain). Generated from source — do not edit by hand.
|
|
4
|
+
*/
|
|
5
|
+
export const BRAND_ICON_PATHS = {
|
|
6
|
+
discord: "M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z",
|
|
7
|
+
facebook: "M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z",
|
|
8
|
+
github: "M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12",
|
|
9
|
+
instagram: "M7.0301.084c-1.2768.0602-2.1487.264-2.911.5634-.7888.3075-1.4575.72-2.1228 1.3877-.6652.6677-1.075 1.3368-1.3802 2.127-.2954.7638-.4956 1.6365-.552 2.914-.0564 1.2775-.0689 1.6882-.0626 4.947.0062 3.2586.0206 3.6671.0825 4.9473.061 1.2765.264 2.1482.5635 2.9107.308.7889.72 1.4573 1.388 2.1228.6679.6655 1.3365 1.0743 2.1285 1.38.7632.295 1.6361.4961 2.9134.552 1.2773.056 1.6884.069 4.9462.0627 3.2578-.0062 3.668-.0207 4.9478-.0814 1.28-.0607 2.147-.2652 2.9098-.5633.7889-.3086 1.4578-.72 2.1228-1.3881.665-.6682 1.0745-1.3378 1.3795-2.1284.2957-.7632.4966-1.636.552-2.9124.056-1.2809.0692-1.6898.063-4.948-.0063-3.2583-.021-3.6668-.0817-4.9465-.0607-1.2797-.264-2.1487-.5633-2.9117-.3084-.7889-.72-1.4568-1.3876-2.1228C21.2982 1.33 20.628.9208 19.8378.6165 19.074.321 18.2017.1197 16.9244.0645 15.6471.0093 15.236-.005 11.977.0014 8.718.0076 8.31.0215 7.0301.0839m.1402 21.6932c-1.17-.0509-1.8053-.2453-2.2287-.408-.5606-.216-.96-.4771-1.3819-.895-.422-.4178-.6811-.8186-.9-1.378-.1644-.4234-.3624-1.058-.4171-2.228-.0595-1.2645-.072-1.6442-.079-4.848-.007-3.2037.0053-3.583.0607-4.848.05-1.169.2456-1.805.408-2.2282.216-.5613.4762-.96.895-1.3816.4188-.4217.8184-.6814 1.3783-.9003.423-.1651 1.0575-.3614 2.227-.4171 1.2655-.06 1.6447-.072 4.848-.079 3.2033-.007 3.5835.005 4.8495.0608 1.169.0508 1.8053.2445 2.228.408.5608.216.96.4754 1.3816.895.4217.4194.6816.8176.9005 1.3787.1653.4217.3617 1.056.4169 2.2263.0602 1.2655.0739 1.645.0796 4.848.0058 3.203-.0055 3.5834-.061 4.848-.051 1.17-.245 1.8055-.408 2.2294-.216.5604-.4763.96-.8954 1.3814-.419.4215-.8181.6811-1.3783.9-.4224.1649-1.0577.3617-2.2262.4174-1.2656.0595-1.6448.072-4.8493.079-3.2045.007-3.5825-.006-4.848-.0608M16.953 5.5864A1.44 1.44 0 1 0 18.39 4.144a1.44 1.44 0 0 0-1.437 1.4424M5.8385 12.012c.0067 3.4032 2.7706 6.1557 6.173 6.1493 3.4026-.0065 6.157-2.7701 6.1506-6.1733-.0065-3.4032-2.771-6.1565-6.174-6.1498-3.403.0067-6.156 2.771-6.1496 6.1738M8 12.0077a4 4 0 1 1 4.008 3.9921A3.9996 3.9996 0 0 1 8 12.0077",
|
|
10
|
+
linkedin: "M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z",
|
|
11
|
+
mastodon: "M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z",
|
|
12
|
+
rss: "M19.199 24C19.199 13.467 10.533 4.8 0 4.8V0c13.165 0 24 10.835 24 24h-4.801zM3.291 17.415c1.814 0 3.293 1.479 3.293 3.295 0 1.813-1.485 3.29-3.301 3.29C1.47 24 0 22.526 0 20.71s1.475-3.294 3.291-3.295zM15.909 24h-4.665c0-6.169-5.075-11.245-11.244-11.245V8.09c8.727 0 15.909 7.184 15.909 15.91z",
|
|
13
|
+
telegram: "M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z",
|
|
14
|
+
tiktok: "M12.525.02c1.31-.02 2.61-.01 3.91-.02.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.05-2.89-.35-4.2-.97-.57-.26-1.1-.59-1.62-.93-.01 2.92.01 5.84-.02 8.75-.08 1.4-.54 2.79-1.35 3.94-1.31 1.92-3.58 3.17-5.91 3.21-1.43.08-2.86-.31-4.08-1.03-2.02-1.19-3.44-3.37-3.65-5.71-.02-.5-.03-1-.01-1.49.18-1.9 1.12-3.72 2.58-4.96 1.66-1.44 3.98-2.13 6.15-1.72.02 1.48-.04 2.96-.04 4.44-.99-.32-2.15-.23-3.02.37-.63.41-1.11 1.04-1.36 1.75-.21.51-.15 1.07-.14 1.61.24 1.64 1.82 3.02 3.5 2.87 1.12-.01 2.19-.66 2.77-1.61.19-.33.4-.67.41-1.06.1-1.79.06-3.57.07-5.36.01-4.03-.01-8.05.02-12.07z",
|
|
15
|
+
whatsapp: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z",
|
|
16
|
+
x: "M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z",
|
|
17
|
+
youtube: "M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z",
|
|
18
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `copyright` — a small "© year holder · rights" bar for the very bottom of a
|
|
3
|
+
* page. A standalone alternative to the `footer` block's copyright line: pair it
|
|
4
|
+
* with `legal` and `social-links` for a lightweight footer, or use it under the
|
|
5
|
+
* full `footer`. The year auto-fills to the current year when left blank (or give
|
|
6
|
+
* an explicit year / range like "2020–2026"). Static brick.
|
|
7
|
+
*/
|
|
8
|
+
import { escapeHtml } from '../schema.js';
|
|
9
|
+
const schema = {
|
|
10
|
+
holder: { kind: 'string', default: '', max: 120 }, // e.g. "Acme Inc."
|
|
11
|
+
year: { kind: 'string', default: '', max: 24 }, // blank → current year
|
|
12
|
+
text: { kind: 'string', default: 'All rights reserved.', max: 160 }, // trailing note
|
|
13
|
+
showSymbol: { kind: 'boolean', default: true }, // the © symbol
|
|
14
|
+
align: { kind: 'enum', values: ['start', 'center', 'end'], default: 'center' },
|
|
15
|
+
};
|
|
16
|
+
const css = `
|
|
17
|
+
.blk-copyright{padding:var(--space) var(--space);background:var(--bg);color:var(--muted);border-top:1px solid color-mix(in srgb,var(--text) 10%,transparent)}
|
|
18
|
+
.blk-copyright .wrap{max-width:1080px;margin:0 auto;font-size:var(--fs-base)}
|
|
19
|
+
.blk-copyright.align-center .wrap{text-align:center}
|
|
20
|
+
.blk-copyright.align-end .wrap{text-align:right}
|
|
21
|
+
.blk-copyright p{margin:0}
|
|
22
|
+
`.trim();
|
|
23
|
+
function render(config) {
|
|
24
|
+
const holder = config.holder;
|
|
25
|
+
const yearIn = String(config.year ?? '').trim();
|
|
26
|
+
const year = yearIn || String(new Date().getFullYear()); // blank → current year
|
|
27
|
+
const text = config.text;
|
|
28
|
+
const symbol = config.showSymbol !== false;
|
|
29
|
+
const align = ['start', 'center', 'end'].includes(config.align) ? config.align : 'center';
|
|
30
|
+
let line = `${symbol ? '© ' : ''}${escapeHtml(year)}`;
|
|
31
|
+
if (holder)
|
|
32
|
+
line += ` ${escapeHtml(holder)}`;
|
|
33
|
+
// Add the note, but don't double punctuation when the holder ends in "." (Inc./Co./Ltd.).
|
|
34
|
+
if (text)
|
|
35
|
+
line += `${/[.!?]$/.test(line) ? ' ' : '. '}${escapeHtml(text)}`;
|
|
36
|
+
return `<footer class="blk-copyright align-${align}" aria-label="Copyright">
|
|
37
|
+
<div class="wrap">
|
|
38
|
+
<p>${line}</p>
|
|
39
|
+
</div>
|
|
40
|
+
</footer>`;
|
|
41
|
+
}
|
|
42
|
+
export const copyright = {
|
|
43
|
+
type: 'copyright',
|
|
44
|
+
description: 'A small copyright bar (© year holder + rights text) for the bottom of a page; the year auto-fills to the current year when left blank.',
|
|
45
|
+
schema,
|
|
46
|
+
css,
|
|
47
|
+
render,
|
|
48
|
+
};
|
package/lib/blocks/gallery.js
CHANGED
|
@@ -44,8 +44,9 @@ function figure(it) {
|
|
|
44
44
|
function render(config) {
|
|
45
45
|
const columns = Number.isInteger(config.columns) ? config.columns : 3;
|
|
46
46
|
const gap = GAP_REM[config.gap] ?? GAP_REM.md;
|
|
47
|
+
const lightbox = config.lightbox === true; // flag for the `lightbox` island
|
|
47
48
|
const items = (config.items ?? []).map(figure).filter(Boolean);
|
|
48
|
-
return `<section class="blk-gallery" aria-label="Gallery">
|
|
49
|
+
return `<section class="blk-gallery" aria-label="Gallery"${lightbox ? ' data-wl-lightbox="true"' : ''}>
|
|
49
50
|
<div class="wrap">
|
|
50
51
|
<div class="grid" style="--cols:${columns};--gap:${gap}">
|
|
51
52
|
${items.join('\n ')}
|