@typeroll/mcp-server 0.42.2 → 0.43.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.
@@ -1,182 +1,113 @@
1
1
  ---
2
2
  name: tr-header-footer
3
- description: Vetted, robust header and footer presets to drop into the header/footer partials. Use when building or restyling a site's site-wide header or footer start from a preset and restyle it instead of hand-rolling layout + overflow (the usual source of clipped logos and broken mobile menus).
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
- # Header & footer presets
7
-
8
- > **The buffer model (draft writes).** Every content write in this recipe
9
- > (pages, blocks, partials, collection items) lands in an unsaved per-doc
10
- > DRAFT deploys and plain previews only see SAVED content. For recipe-style
11
- > build work, pass `save: true` on write calls (the work is pre-approved by
12
- > the task itself), or run `commit_working_copy` per doc before any
13
- > `trigger_deploy`. Preview your drafts with `include_working_copy: true`.
14
-
15
-
16
- Headers and footers are the two partials every page shows, and hand-rolling them
17
- is where logos get clipped and mobile menus break. **Start from a preset below,
18
- fill the placeholders, restyle with the site's colours — don't build the layout
19
- from scratch.** Each preset is deliberately robust; the "why" notes call out the
20
- traps it avoids.
21
-
22
- ## How to use
23
-
24
- 1. `read_site_settings` — grab `logo`, `site_name`, `tagline`, `contact.email`,
25
- and the colour palette.
26
- 2. `read_partial partial_id="header"` (and `footer`) — see what's already there;
27
- don't blow away a working one without reason.
28
- 3. Pick a preset, replace every `{{PLACEHOLDER}}`, adjust colours to the palette
29
- (the presets already read `--color-*` / `--font-heading` with fallbacks).
30
- 4. `update_partial partial_id="header" patch={ html_content: "…" } version="…"`.
31
- 5. **Preview and self-review in context** (see `tr-redesign-branch` step 6):
32
- the logo must be FULLY VISIBLE (not clipped), legible against its background,
33
- and the mobile layout must work at 390px. Screenshot the header region in
34
- context never the logo element in isolation (that hides clipping).
35
-
36
- Placeholders: `{{SITE_NAME}}`, `{{LOGO_URL}}`, `{{TAGLINE}}`, `{{EMAIL}}`, `{{YEAR}}`.
37
-
38
- ---
39
-
40
- ## Header A — Centered logo (minimal; landing pages)
41
-
42
- ```html
43
- <header class="tr-hdr tr-hdr--center">
44
- <a class="tr-hdr-logo" href="/" aria-label="{{SITE_NAME}} — till startsidan">
45
- <img src="{{LOGO_URL}}" alt="{{SITE_NAME}}" />
46
- </a>
47
- </header>
48
- <style>
49
- .tr-hdr--center{background:var(--color-surface,#fff);display:flex;justify-content:center;padding:clamp(1rem,2.5vw,1.6rem) 1.5rem}
50
- .tr-hdr-logo{display:inline-block;line-height:0;transition:transform .15s ease}
51
- .tr-hdr-logo:hover{transform:translateY(-1px)}
52
- .tr-hdr-logo img{height:clamp(40px,6vw,58px);width:auto;display:block}
53
- </style>
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
- **Why it's robust:** no `overflow:hidden` anywhere near the logo (the #1 cause of a
57
- clipped wordmark); the logo sizes by `height` with `width:auto` so it never
58
- distorts and never gets cropped; symmetric padding so it can't collide with the
59
- section below. If you want a tinted header, set a solid `background` — don't add a
60
- glow that has to be clipped.
61
-
62
- ## Header B — Logo left + links right (no-JS responsive menu)
63
-
64
- ```html
65
- <header class="tr-hdr tr-hdr--nav">
66
- <div class="tr-hdr-inner">
67
- <a class="tr-hdr-logo" href="/" aria-label="{{SITE_NAME}} till startsidan">
68
- <img src="{{LOGO_URL}}" alt="{{SITE_NAME}}" />
69
- </a>
70
- <input type="checkbox" id="tr-nav-toggle" class="tr-nav-toggle" aria-hidden="true" />
71
- <label for="tr-nav-toggle" class="tr-nav-burger" aria-label="Meny"><span></span><span></span><span></span></label>
72
- <nav class="tr-hdr-nav" aria-label="Huvudmeny">
73
- <a href="/">Start</a>
74
- <a href="#">Sidan ett</a>
75
- <a href="#">Sidan två</a>
76
- <a class="tr-hdr-cta" href="#kontakt">Kontakta oss</a>
77
- </nav>
78
- </div>
79
- </header>
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
91
  ```
132
92
 
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
- ```
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.
166
97
 
167
- **Why these footers are robust:** the columns collapse to one at 680px (no
168
- horizontal scroll); all colours come from `--color-*` with fallbacks; the contact
169
- is a real `mailto:` link; nothing relies on fixed heights. Swap `--color-primary`
170
- for a custom dark if the brand's primary is too light for white text.
98
+ ## Version and dependency rules
171
99
 
172
- ---
100
+ Child versions inherit installed, custom, and third-party block types from
101
+ their base chain. If preview reports a missing type, stop and inspect
102
+ `list_block_types` for that exact version; do not duplicate an Extension or
103
+ installation. A type missing after capability 0.43.0 is a dependency error to
104
+ report, not a reason to let the block silently disappear.
173
105
 
174
- ## Restyling notes
106
+ ## Final checks
175
107
 
176
- - The logo always comes from `read_site_settings logo`. If it's `null`, set it
177
- first (upload + `update_site_settings`) don't hard-code a path.
178
- - For a **shaped transition** from the header/footer into the page, don't build a
179
- wave band by hand that belongs to the adjacent `core/section` via its
180
- `divider_top` / `divider_bottom` (see `tr-redesign-branch`).
181
- - Keep the brand mark + a way home. Even a dramatic redesign keeps the logo
182
- linking to `/`.
108
+ - Header and footer landmarks exist exactly once around their content.
109
+ - Logo is fully visible, keeps its aspect ratio, has useful alt text, and links home.
110
+ - Current-page state and localized navigation labels are correct.
111
+ - Mobile disclosure is keyboard accessible and does not trap focus.
112
+ - No tenant CSS is required for spacing, focus, wrapping, or the narrow layout.
113
+ - Preview and a hosted static build match before promotion.
@@ -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,
@@ -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` (verify that the relevant route supplies a breadcrumb trail) |
61
- | Generated heading index | `core/table_of_contents`; choose `h2`, `h2-h3`, or `h2-h4` |
62
- | Previous/next collection item links | `template/item_navigation` in the collection's block template; ordering follows `sort_field` / `sort_dir` |
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 a vetted preset — don't hand-roll the layout.** `read_skill
119
- tr-header-footer` has robust header + footer presets (centered logo, logo+nav
120
- with a no-JS mobile menu, centered + 3-column footers) that avoid the usual
121
- traps: clipped logos (no `overflow:hidden` near the logo), distorted logos
122
- (`height` + `width:auto`), and broken mobile menus. Fill the placeholders and
123
- restyle to the palette.
124
-
125
- Partials can use either mode. Use HTML for a compact hand-authored nav, or
126
- block mode when editors need per-field control or an installed Extension must
127
- be placed there. Partials receive the same `{{site.*}}` render context as page
128
- blocks, so literal brand data is optional rather than required:
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
- `replace_partial partial_id="header" html_content="..."` same pattern
149
- for the footer. Design notes: **no border-bottom on the header if the
150
- first page section should meet it seamlessly** let background color
151
- changes do the separating. Anchor links in nav (`/#section`) are fine.
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>" } }