@typeroll/mcp-server 0.42.2 → 0.43.1
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/AGENTS.md +26 -5
- package/README.md +14 -7
- package/dist/bundled-content.js +9 -9
- package/dist/tools/collections.js +6 -1
- package/dist/tools/domain.js +21 -16
- package/dist/tools/migration.js +49 -2
- package/dist/tools/pages.js +2 -3
- package/dist/tools/partials.js +17 -2
- package/dist/tools/settings.js +8 -0
- package/dist/tools/sites.js +8 -0
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/skills/tr-blog.md +36 -70
- package/skills/tr-collection-template.md +40 -3
- package/skills/tr-header-footer.md +109 -173
- package/skills/tr-migrate-multisite.md +12 -7
- package/skills/tr-migrate-wp.md +20 -11
- package/skills/tr-new-site.md +19 -37
- package/skills/tr-responsive.md +8 -5
|
@@ -1,182 +1,118 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: tr-header-footer
|
|
3
|
-
description:
|
|
3
|
+
description: Build accessible native header and footer partials with the site logo, semantic navigation, responsive disclosure, and optional native cookie consent.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
6
|
+
# Native header and footer compositions
|
|
7
|
+
|
|
8
|
+
Use block-mode partials for new work. Core 0.1.8 / capability contract 0.43.0
|
|
9
|
+
ships `template/site_logo`, `core/navigation`, layout primitives, and a
|
|
10
|
+
revision-safe partial mode operation. HTML partials remain supported for
|
|
11
|
+
legacy markup, but generic navigation and responsive layout no longer require
|
|
12
|
+
tenant HTML, CSS, or JavaScript.
|
|
13
|
+
|
|
14
|
+
## Preconditions
|
|
15
|
+
|
|
16
|
+
1. Read `get_site_capabilities`, `read_site_settings`, `list_partials`, and
|
|
17
|
+
`list_block_types`.
|
|
18
|
+
2. Require `supports_native_navigation`, `supports_partial_mode_switching`,
|
|
19
|
+
`supports_responsive_data_fields`, and
|
|
20
|
+
`supports_versioned_block_type_inheritance`.
|
|
21
|
+
3. Read the existing header/footer before replacing anything. Work in a branch
|
|
22
|
+
for redesigns and preview at desktop, 390 px, keyboard-only, and 200% zoom.
|
|
23
|
+
|
|
24
|
+
## Header tree
|
|
25
|
+
|
|
26
|
+
Stage this tree with `update_partial partial_id="header" patch={blocks:[...]}
|
|
27
|
+
save=true`, then call `set_partial_mode partial_id="header" to="blocks"` and
|
|
28
|
+
read it back. Localize both accessible labels and every link label.
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
[
|
|
32
|
+
{
|
|
33
|
+
"type": "core/section",
|
|
34
|
+
"data": { "width": "wide", "padding_y": "sm" },
|
|
35
|
+
"children": [{
|
|
36
|
+
"type": "core/container",
|
|
37
|
+
"data": {
|
|
38
|
+
"direction": { "mobile": "column", "tablet": "row" },
|
|
39
|
+
"align_main": "space-between",
|
|
40
|
+
"align_cross": "center",
|
|
41
|
+
"gap": "md",
|
|
42
|
+
"width": "wide",
|
|
43
|
+
"padding_y": "none",
|
|
44
|
+
"padding_x": "none"
|
|
45
|
+
},
|
|
46
|
+
"children": [
|
|
47
|
+
{ "type": "template/site_logo", "data": { "height": "md", "link_to_home": true } },
|
|
48
|
+
{
|
|
49
|
+
"type": "core/navigation",
|
|
50
|
+
"data": {
|
|
51
|
+
"aria_label": "Main navigation",
|
|
52
|
+
"menu_label": "Menu",
|
|
53
|
+
"links": [
|
|
54
|
+
{ "label": "Home", "href": "/" },
|
|
55
|
+
{ "label": "About", "href": "/about/" },
|
|
56
|
+
{ "label": "Contact", "href": "/contact/" }
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}]
|
|
62
|
+
}
|
|
63
|
+
]
|
|
54
64
|
```
|
|
55
65
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
<style>
|
|
81
|
-
.tr-hdr--nav{background:var(--color-surface,#fff);border-bottom:1px solid rgba(0,0,0,.06)}
|
|
82
|
-
.tr-hdr-inner{max-width:1160px;margin:0 auto;padding:.9rem 1.5rem;display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap}
|
|
83
|
-
.tr-hdr-logo{line-height:0}
|
|
84
|
-
.tr-hdr-logo img{height:clamp(36px,4.6vw,50px);width:auto;display:block}
|
|
85
|
-
.tr-hdr-nav{display:flex;align-items:center;gap:clamp(1rem,2.4vw,2rem);font-family:var(--font-heading),sans-serif;font-weight:600}
|
|
86
|
-
.tr-hdr-nav a{color:var(--color-text,#1a1a1a);text-decoration:none}
|
|
87
|
-
.tr-hdr-nav a:hover{color:var(--color-primary,#1F4FB8)}
|
|
88
|
-
.tr-hdr-cta{background:var(--color-primary,#1F4FB8);color:var(--color-primary-fg,#fff);padding:.6rem 1.2rem;border-radius:999px}
|
|
89
|
-
.tr-hdr-cta:hover{filter:brightness(1.05);color:var(--color-primary-fg,#fff)}
|
|
90
|
-
.tr-nav-toggle{display:none}
|
|
91
|
-
.tr-nav-burger{display:none;flex-direction:column;gap:5px;cursor:pointer;padding:.4rem}
|
|
92
|
-
.tr-nav-burger span{width:24px;height:2px;background:var(--color-text,#1a1a1a);border-radius:2px}
|
|
93
|
-
@media(max-width:760px){
|
|
94
|
-
.tr-nav-burger{display:flex}
|
|
95
|
-
.tr-hdr-nav{flex-basis:100%;flex-direction:column;align-items:stretch;gap:.2rem;max-height:0;overflow:hidden;transition:max-height .25s ease}
|
|
96
|
-
.tr-hdr-nav a{padding:.7rem .2rem}
|
|
97
|
-
.tr-nav-toggle:checked ~ .tr-hdr-nav{max-height:60vh}
|
|
66
|
+
`core/navigation` emits a real `nav` and list in initial HTML, marks the
|
|
67
|
+
matching page with `aria-current="page"`, and progressively enhances to a
|
|
68
|
+
button-controlled mobile menu. Verify Tab and Shift-Tab order, Enter/Space,
|
|
69
|
+
Escape returning focus to the disclosure, visible focus, long translated
|
|
70
|
+
labels, and no horizontal overflow. Without JavaScript the links remain
|
|
71
|
+
visible and usable.
|
|
72
|
+
|
|
73
|
+
## Footer tree and consent
|
|
74
|
+
|
|
75
|
+
Use the same tree for `footer`, normally with `padding_y: "lg"`, a small site
|
|
76
|
+
logo, localized footer navigation, and optional contact/prose blocks. The
|
|
77
|
+
footer navigation gets its own accessible label; it is not the main
|
|
78
|
+
navigation landmark.
|
|
79
|
+
|
|
80
|
+
Cookie consent is a site feature, not a footer widget. Configure it separately:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"cookie_consent": {
|
|
85
|
+
"enabled": true,
|
|
86
|
+
"text": "We use optional cookies. <a href=\"/privacy/\">Privacy policy</a>",
|
|
87
|
+
"privacy_policy_url": "/privacy/",
|
|
88
|
+
"reload_after_consent": false
|
|
89
|
+
}
|
|
98
90
|
}
|
|
99
|
-
</style>
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
**Why it's robust:** the mobile menu is a pure-CSS checkbox toggle — no JS to break,
|
|
103
|
-
no library. The `overflow:hidden` is ONLY on the collapsing nav list (never on the
|
|
104
|
-
header or the logo), so the logo is always fully visible. Links use site colour
|
|
105
|
-
variables so it matches the brand automatically. The header wraps (`flex-wrap`) so
|
|
106
|
-
nothing overflows the viewport on narrow screens.
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
## Footer A — Centered minimal
|
|
111
|
-
|
|
112
|
-
```html
|
|
113
|
-
<footer class="tr-ftr tr-ftr--center">
|
|
114
|
-
<div class="tr-ftr-inner">
|
|
115
|
-
<div class="tr-ftr-brand">{{SITE_NAME}}</div>
|
|
116
|
-
<p class="tr-ftr-tag">{{TAGLINE}}</p>
|
|
117
|
-
<p class="tr-ftr-contact"><a href="mailto:{{EMAIL}}">{{EMAIL}}</a></p>
|
|
118
|
-
<p class="tr-ftr-copy">© {{YEAR}} {{SITE_NAME}}</p>
|
|
119
|
-
</div>
|
|
120
|
-
</footer>
|
|
121
|
-
<style>
|
|
122
|
-
.tr-ftr--center{background:var(--color-primary,#163C8C);color:rgba(255,255,255,.78)}
|
|
123
|
-
.tr-ftr--center .tr-ftr-inner{max-width:1120px;margin:0 auto;padding:2.6rem 1.5rem;text-align:center;display:grid;gap:.45rem}
|
|
124
|
-
.tr-ftr-brand{font-family:var(--font-heading),sans-serif;font-weight:800;font-size:1.35rem;color:#fff}
|
|
125
|
-
.tr-ftr-tag{margin:0;font-size:1rem;color:rgba(255,255,255,.85)}
|
|
126
|
-
.tr-ftr-contact{margin:.15rem 0 0}
|
|
127
|
-
.tr-ftr-contact a{color:#fff;text-decoration:none;font-weight:600}
|
|
128
|
-
.tr-ftr-contact a:hover{text-decoration:underline}
|
|
129
|
-
.tr-ftr-copy{margin:.8rem 0 0;font-size:.85rem;color:rgba(255,255,255,.55)}
|
|
130
|
-
</style>
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
## Footer B — Three columns (brand · links · contact)
|
|
134
|
-
|
|
135
|
-
```html
|
|
136
|
-
<footer class="tr-ftr tr-ftr--cols">
|
|
137
|
-
<div class="tr-ftr-grid">
|
|
138
|
-
<div class="tr-ftr-col">
|
|
139
|
-
<div class="tr-ftr-brand">{{SITE_NAME}}</div>
|
|
140
|
-
<p class="tr-ftr-tag">{{TAGLINE}}</p>
|
|
141
|
-
</div>
|
|
142
|
-
<nav class="tr-ftr-col" aria-label="Sidfot">
|
|
143
|
-
<a href="/">Start</a>
|
|
144
|
-
<a href="#">Sidan ett</a>
|
|
145
|
-
<a href="#">Sidan två</a>
|
|
146
|
-
</nav>
|
|
147
|
-
<div class="tr-ftr-col">
|
|
148
|
-
<p class="tr-ftr-contact"><a href="mailto:{{EMAIL}}">{{EMAIL}}</a></p>
|
|
149
|
-
</div>
|
|
150
|
-
</div>
|
|
151
|
-
<p class="tr-ftr-copy">© {{YEAR}} {{SITE_NAME}}</p>
|
|
152
|
-
</footer>
|
|
153
|
-
<style>
|
|
154
|
-
.tr-ftr--cols{background:var(--color-primary,#163C8C);color:rgba(255,255,255,.78)}
|
|
155
|
-
.tr-ftr--cols .tr-ftr-grid{max-width:1120px;margin:0 auto;padding:3rem 1.5rem 1.4rem;display:grid;grid-template-columns:1.4fr 1fr 1fr;gap:2rem}
|
|
156
|
-
.tr-ftr--cols .tr-ftr-brand{font-family:var(--font-heading),sans-serif;font-weight:800;font-size:1.35rem;color:#fff;margin-bottom:.4rem}
|
|
157
|
-
.tr-ftr--cols .tr-ftr-tag{margin:0;color:rgba(255,255,255,.8);max-width:34ch}
|
|
158
|
-
.tr-ftr--cols .tr-ftr-col{display:grid;gap:.5rem;align-content:start}
|
|
159
|
-
.tr-ftr--cols nav a{color:rgba(255,255,255,.85);text-decoration:none}
|
|
160
|
-
.tr-ftr--cols nav a:hover{color:#fff;text-decoration:underline}
|
|
161
|
-
.tr-ftr-contact a{color:#fff;text-decoration:none;font-weight:600}
|
|
162
|
-
.tr-ftr--cols .tr-ftr-copy{max-width:1120px;margin:0 auto;padding:0 1.5rem 2.4rem;font-size:.85rem;color:rgba(255,255,255,.55)}
|
|
163
|
-
@media(max-width:680px){.tr-ftr--cols .tr-ftr-grid{grid-template-columns:1fr;gap:1.4rem}}
|
|
164
|
-
</style>
|
|
165
91
|
```
|
|
166
92
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
93
|
+
Use `update_site_settings`, then read settings back. `scripts_necessary` and
|
|
94
|
+
`scripts_optional` execute in visitors' browsers and must be reviewed like
|
|
95
|
+
other API-key-authorized script surfaces. Verify accept/necessary/reject,
|
|
96
|
+
optional-script gating, and keyboard focus in preview and the actual build.
|
|
97
|
+
The signed hosted preview runs at an opaque origin. Consent choices therefore
|
|
98
|
+
use in-memory state for the current preview document; they are intentionally
|
|
99
|
+
not persisted as portal cookies across a reload or page navigation. Accepting
|
|
100
|
+
all must still activate optional scripts immediately, which is enough to test
|
|
101
|
+
the gate without weakening the preview sandbox.
|
|
102
|
+
|
|
103
|
+
## Version and dependency rules
|
|
104
|
+
|
|
105
|
+
Child versions inherit installed, custom, and third-party block types from
|
|
106
|
+
their base chain. If preview reports a missing type, stop and inspect
|
|
107
|
+
`list_block_types` for that exact version; do not duplicate an Extension or
|
|
108
|
+
installation. A type missing after capability 0.43.0 is a dependency error to
|
|
109
|
+
report, not a reason to let the block silently disappear.
|
|
110
|
+
|
|
111
|
+
## Final checks
|
|
112
|
+
|
|
113
|
+
- Header and footer landmarks exist exactly once around their content.
|
|
114
|
+
- Logo is fully visible, keeps its aspect ratio, has useful alt text, and links home.
|
|
115
|
+
- Current-page state and localized navigation labels are correct.
|
|
116
|
+
- Mobile disclosure is keyboard accessible and does not trap focus.
|
|
117
|
+
- No tenant CSS is required for spacing, focus, wrapping, or the narrow layout.
|
|
118
|
+
- Preview and a hosted static build match before promotion.
|
|
@@ -311,31 +311,36 @@ blocker. Redirect builds cover both source spellings and send internal targets
|
|
|
311
311
|
to the site's configured trailing-slash style.
|
|
312
312
|
|
|
313
313
|
Note what the check does NOT catch: it verifies that a URL *resolves*, not
|
|
314
|
-
that the page at the other end is the right content.
|
|
315
|
-
|
|
314
|
+
that the page at the other end is the right content. Review content and SEO
|
|
315
|
+
parity, then record the exact dataset and result with
|
|
316
|
+
`record_migration_seo_acceptance`.
|
|
316
317
|
|
|
317
318
|
Iterate until `missing` and `broken_redirect` are both zero **on every site**.
|
|
318
319
|
Then, per site:
|
|
319
320
|
|
|
320
|
-
1. `add_domain`
|
|
321
|
-
2.
|
|
322
|
-
3. `poll_domain` until verified
|
|
321
|
+
1. `add_domain` with the intended apex/www canonical; leave `auto_deploy` on
|
|
322
|
+
2. Wait for that canonical/sitemap deploy to succeed, then point DNS
|
|
323
|
+
3. `poll_domain` until verified — there is no separate activation step
|
|
323
324
|
4. Re-run `verify_migration_urls target_origin="https://example.de"` against
|
|
324
325
|
the real domain, to confirm the cutover kept what the pre-check proved
|
|
325
326
|
5. Submit the new sitemap in Search Console; keep the old property open for
|
|
326
327
|
a few weeks and watch the 404 report
|
|
328
|
+
6. Rerun the complete, unfiltered URL check and SEO review, then require
|
|
329
|
+
`get_migration_launch_report` to return `launch_ready: true`
|
|
327
330
|
|
|
328
331
|
## Definition of done (per site)
|
|
329
332
|
|
|
330
333
|
- [ ] `get_migration_readiness source_url=<this market's old site>` → `ready: true`, warnings reviewed
|
|
331
334
|
- [ ] `list_migration_urls status="unhandled"` → 0
|
|
332
|
-
- [ ] `verify_migration_urls` → 0 `missing`, 0 `broken_redirect`
|
|
335
|
+
- [ ] Complete `verify_migration_urls` → 0 `missing`, 0 `broken_redirect`, 0 `error`, 0 untested variants
|
|
336
|
+
- [ ] `record_migration_seo_acceptance` is accepted for the latest deploy
|
|
337
|
+
- [ ] `get_migration_launch_report` → `launch_ready: true`
|
|
333
338
|
- [ ] hreflang cluster written on both/all sides, absolute, final domains
|
|
334
339
|
- [ ] `language` set on the site; `<html lang>` correct in the deployed HTML
|
|
335
340
|
- [ ] Internal links rewritten (no lingering absolute links to the old domain)
|
|
336
341
|
- [ ] Forms rebuilt, recipient address correct for THIS market, test submission sent and received
|
|
337
342
|
- [ ] Media uploaded to this site's own library (no cross-site `cdn_url`), alt text in this market's language
|
|
338
|
-
- [ ] Domain
|
|
343
|
+
- [ ] Domain declared, canonical deploy succeeded, DNS verified; sitemap submitted
|
|
339
344
|
|
|
340
345
|
## Pitfalls specific to this job
|
|
341
346
|
|
package/skills/tr-migrate-wp.md
CHANGED
|
@@ -26,6 +26,14 @@ agency) reviews each step in their terminal.
|
|
|
26
26
|
get_migration_readiness source_url="https://oldsite.com"
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
When the migration includes reusable page/item layouts, include each proposed
|
|
30
|
+
block composition and its collection fields in this same call. A
|
|
31
|
+
`waiting_for_native_support` result means leave that template intact and do
|
|
32
|
+
not replace the gap with generic custom blocks, raw HTML, or corrective site
|
|
33
|
+
CSS. Independent content and SEO work may continue. Rerun the review after the
|
|
34
|
+
required Core version is deployed, then verify preview and a fresh hosted
|
|
35
|
+
build.
|
|
36
|
+
|
|
29
37
|
Pass `source_url` — that adds the checks on the site you're migrating FROM.
|
|
30
38
|
An old host that answers 403/429 to server-side requests is a **blocker**: the
|
|
31
39
|
import would produce empty pages, or pages containing the host's block page,
|
|
@@ -110,26 +118,25 @@ c. Migrate referenced images:
|
|
|
110
118
|
text (existing WP `alt` attribute or `aria-label`; fall back to
|
|
111
119
|
filename only as a last resort).
|
|
112
120
|
|
|
113
|
-
d. Reconstruct in the target's design
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
page has exactly one `<h1>`. If you're confident, batch these
|
|
118
|
-
through `bulk_replace_text` with `dry_run: true` first.
|
|
121
|
+
d. Reconstruct in the target's design with native blocks first. Read the
|
|
122
|
+
available block types and map headings, prose, images, buttons and layout
|
|
123
|
+
into their typed fields. Use HTML mode only for source-specific markup that
|
|
124
|
+
has no native representation and has passed the composition preflight.
|
|
119
125
|
|
|
120
126
|
e. Write the page as a draft:
|
|
121
127
|
|
|
122
128
|
```
|
|
123
|
-
create_page title="..." slug="<
|
|
124
|
-
|
|
129
|
+
create_page title="..." slug="<last-path-segment>"
|
|
130
|
+
path="/<preserved-wordpress/path/>"
|
|
131
|
+
blocks=[<native block tree>]
|
|
125
132
|
status="draft" kind="article" author="..."
|
|
126
133
|
seo_title="..." seo_description="..."
|
|
127
134
|
```
|
|
128
135
|
|
|
129
136
|
**Preserve the source URL.** WP post URLs like
|
|
130
|
-
`/2024/01/foo-bar/`
|
|
131
|
-
|
|
132
|
-
|
|
137
|
+
`/2024/01/foo-bar/` uses `slug: "foo-bar"` and
|
|
138
|
+
`path: "/2024/01/foo-bar/"`. Slug is one segment; `path` preserves the
|
|
139
|
+
complete nested URL.
|
|
133
140
|
|
|
134
141
|
### 4. Redirects
|
|
135
142
|
|
|
@@ -183,6 +190,8 @@ import_gsc_performance property="https://old.example.com/" months=6
|
|
|
183
190
|
# Or paste a Search Console Pages CSV via csv="..." and source_origin.
|
|
184
191
|
check_internal_links # database preflight before deploy
|
|
185
192
|
verify_migration_urls # after trigger_deploy; compact exceptions by default
|
|
193
|
+
record_migration_seo_acceptance # after reviewing this exact deployment
|
|
194
|
+
get_migration_launch_report # final fail-closed launch gate
|
|
186
195
|
```
|
|
187
196
|
|
|
188
197
|
The inventory merges slash-equivalent URLs into one work item but preserves
|
package/skills/tr-new-site.md
CHANGED
|
@@ -57,9 +57,9 @@ Common requirements that are easy to misclassify:
|
|
|
57
57
|
| Responsive icon/card grid | `core/grid` + `core/icon_box`, or `core/feature_grid`; set responsive fields with `set_block_responsive` |
|
|
58
58
|
| Custom cards backed by a collection | `core/repeater` / `core/collection_list` with a site-authored `item_compatible` block type as `item_block` |
|
|
59
59
|
| Grouped collection listing | `core/repeater` with `group_by`; array-valued fields place an item in every matching group |
|
|
60
|
-
| Breadcrumbs in a page template | `template/page_breadcrumbs
|
|
61
|
-
| Generated heading index | `core/table_of_contents`; choose
|
|
62
|
-
| Previous/next collection item links | `template/item_navigation
|
|
60
|
+
| Breadcrumbs in a page template | `template/page_breadcrumbs`; page and item routes supply a server-rendered trail |
|
|
61
|
+
| Generated heading index | `core/table_of_contents`; choose heading levels and set `source_field` for collection content |
|
|
62
|
+
| Previous/next collection item links | `template/item_navigation`; defaults to collection order and can bind explicit neighbor fields |
|
|
63
63
|
| Download CTA that disappears without a file | `template/show_if` around a context-bound `core/button`; a dedicated download block is only editor convenience |
|
|
64
64
|
| Sticky/custom header and multi-column footer | Block-mode header/footer partials plus layout blocks, or one reusable custom block type |
|
|
65
65
|
| Cookie notice | `settings.cookie_consent`, not a page block |
|
|
@@ -115,40 +115,22 @@ an iframe cannot be represented.
|
|
|
115
115
|
|
|
116
116
|
### 3. Header + footer partials
|
|
117
117
|
|
|
118
|
-
**Start from
|
|
119
|
-
tr-header-footer`
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
```html
|
|
131
|
-
<header class="site-header">
|
|
132
|
-
<div class="header-inner">
|
|
133
|
-
<a class="header-logo" href="/"><img src="LOGO_MEDIA_URL" alt="Acme Studio" height="40" /></a>
|
|
134
|
-
<nav class="header-nav">
|
|
135
|
-
<a href="/om-oss">Om oss</a>
|
|
136
|
-
<a href="/kontakt">Kontakt</a>
|
|
137
|
-
</nav>
|
|
138
|
-
</div>
|
|
139
|
-
</header>
|
|
140
|
-
<style>
|
|
141
|
-
.site-header{background:var(--color-background);padding:1rem 2rem}
|
|
142
|
-
.header-inner{max-width:1080px;margin:0 auto;display:flex;align-items:center;justify-content:space-between}
|
|
143
|
-
.header-nav{display:flex;gap:2rem}
|
|
144
|
-
.header-nav a{color:var(--color-text);text-decoration:none}
|
|
145
|
-
</style>
|
|
146
|
-
```
|
|
118
|
+
**Start from the native preset — don't hand-roll navigation.** Read
|
|
119
|
+
`tr-header-footer` and use its `template/site_logo` + `core/navigation`
|
|
120
|
+
composition. The server-rendered landmark, current-page state, no-JS links,
|
|
121
|
+
mobile disclosure, focus treatment, and responsive behavior are Core
|
|
122
|
+
contracts rather than tenant CSS/JavaScript.
|
|
123
|
+
|
|
124
|
+
Stage the complete tree with `update_partial partial_id="header"
|
|
125
|
+
patch={blocks:[...]} save=true`, then call `set_partial_mode partial_id="header"
|
|
126
|
+
to="blocks"`. Repeat for the footer and read both partials back. The inactive
|
|
127
|
+
HTML representation is retained for rollback; changing `content_mode` through
|
|
128
|
+
ordinary PATCH/PUT is rejected intentionally.
|
|
147
129
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
130
|
+
Use HTML mode only when preserving legacy authored markup that cannot yet be
|
|
131
|
+
represented natively. Partials receive the same `{{site.*}}` render context as
|
|
132
|
+
page blocks. Keep the first section and header backgrounds intentional; do not
|
|
133
|
+
add a decorative border merely to compensate for mismatched spacing.
|
|
152
134
|
|
|
153
135
|
### 4. Homepage — block tree
|
|
154
136
|
|
|
@@ -181,7 +163,7 @@ on a block *inside* the section instead):
|
|
|
181
163
|
] },
|
|
182
164
|
{ "type": "core/section", "data": { "padding_y": "lg" }, "children": [
|
|
183
165
|
{ "type": "core/heading", "data": { "text": "Så funkar det", "level": "h2", "align": "center" } },
|
|
184
|
-
{ "type": "core/grid", "data": { "cols": 3, "gap": "lg" }, "children": [
|
|
166
|
+
{ "type": "core/grid", "data": { "cols": { "mobile": 1, "tablet": 2, "desktop": 3 }, "gap": "lg" }, "children": [
|
|
185
167
|
{ "type": "core/step_card", "data": { "number": "1", "title": "…", "text": "<p>…</p>" } },
|
|
186
168
|
{ "type": "core/step_card", "data": { "number": "2", "title": "…", "text": "<p>…</p>" } },
|
|
187
169
|
{ "type": "core/step_card", "data": { "number": "3", "title": "…", "text": "<p>…</p>" } }
|
package/skills/tr-responsive.md
CHANGED
|
@@ -23,6 +23,11 @@ Use `set_block_responsive` (or pass the object form directly in `add_block` /
|
|
|
23
23
|
`update_block` data). `read_block_type <id>` tells you which fields are
|
|
24
24
|
`responsive`.
|
|
25
25
|
|
|
26
|
+
The breakpoint object belongs on the responsive field inside `block.data`,
|
|
27
|
+
for example `data.cols`. Do not add a top-level `block.responsive` object: it
|
|
28
|
+
is not a rendered field, and page, partial and collection-template writes
|
|
29
|
+
reject it instead of silently storing an inert value.
|
|
30
|
+
|
|
26
31
|
```
|
|
27
32
|
# 4 columns on desktop, 2 on tablet, 1 on mobile:
|
|
28
33
|
set_block_responsive target={kind:page,id:home} block_id=<grid-id>
|
|
@@ -104,9 +109,7 @@ breakpoints needed.
|
|
|
104
109
|
that didn't collapse) and fix THAT element's width / clip it with
|
|
105
110
|
`overflow:hidden` on its own section. Verify with
|
|
106
111
|
`document.documentElement.scrollWidth === clientWidth` at 360–390px.
|
|
107
|
-
-
|
|
108
|
-
the
|
|
109
|
-
the
|
|
110
|
-
wraps a letter per line. Workaround until fixed: in page-scoped CSS override the
|
|
111
|
-
real property, e.g. `@media(max-width:640px){.my-section [data-block="grid"]{grid-template-columns:1fr!important}}`.
|
|
112
|
+
- `core/grid` `stack_at` and responsive `data.cols` both compile overrides
|
|
113
|
+
that beat the inline mobile baseline. Verify the computed column count at
|
|
114
|
+
the actual breakpoint; no page CSS workaround should be necessary.
|
|
112
115
|
- Background design reference: `docs/responsive-blocks.md` in the platform repo.
|