@typeroll/mcp-server 0.45.29 → 0.45.30
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/dist/bundled-content.js +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/skills/tr-responsive.md +8 -0
package/dist/bundled-content.js
CHANGED
|
@@ -20,7 +20,7 @@ export const BUNDLED_SKILLS = {
|
|
|
20
20
|
"tr-new-site": "---\nname: tr-new-site\ndescription: Use when the user wants to create a new Typeroll site from scratch, set up the initial design, or bootstrap a blank site with working header/footer, brand colors, and a homepage. Also triggers on \"start a new site\", \"set up a site for\", or \"build a website for [company]\".\n---\n\n# Bootstrap a new Typeroll site\n\n> **The buffer model (draft writes).** Every content write in this recipe\n> (pages, blocks and partials) lands in an unsaved per-doc\n> DRAFT — deploys and plain previews only see SAVED content. For recipe-style\n> build work, pass `save: true` on write calls (the work is pre-approved by\n> the task itself), or run `commit_working_copy` per doc before any\n> `trigger_deploy`. Preview your drafts with `include_working_copy: true`.\n\n\nStart here when the site already exists as a database record (created via\nthe portal UI or API) but has no design, no header/footer, and no pages.\nThe goal is to go from blank to a working 4-page site with correct brand\nidentity in a single session.\n\n**Pages are built in block mode** — the platform default. Blocks give\nstructured, per-field editing, native full-bleed sections, responsive\nbreakpoints, and templates. HTML mode is the secondary path for\nhand-crafted one-offs and migrated content (section at the end).\n\n## Workspace and context\n\nAn optional agent-neutral workspace stores the brief, decisions and QA. It does\nnot create a Site or replace CMS content. See the public Agent workspace guide.\nFor compact MCP: search_tools, describe_tool, then the appropriate read/write/admin\nwrapper. Load only the relevant guide section and recipe. Discover site apps with\nread_app_documentation when needed; do not bundle private app guides locally.\n\nNo Site yet? Use hosted MCP with an Organization key and create_site, or create it\nin the portal. Read back its ID before editing. Use one explicit Site/Version for\nrelated operations. Larger changes to an existing site should use a branch.\n\nBefore importing content or a media library, require get_import_readiness to pass.\nPublishing accounts may remain unconfigured while authoring new drafts and previews.\n\n## Preconditions\n\n- `@typeroll/mcp-server` configured with a valid `TYPEROLL_API_KEY`.\n- The site exists (confirm with `get_site`).\n- You have the customer brief: company name, industry, 2–3 key brand colors,\n tone of voice, and a list of initial pages.\n\n## Recipe\n\n### 1. Audit current state\n\n```\nget_site\nget_site_capabilities # template_capabilities_version — what this deployment supports\nread_site_settings # see what (if anything) is already configured\nlist_pages # don't overwrite pages that already exist\nlist_partials # check if header/footer already have content\nlist_block_types # the per-site block palette — NEVER assume, always list\n```\n\n**Do not choose a content mode or file a platform gap before these calls\nreturn.** For every required visual/behavioral element, map it to an existing\nblock or composition first. If the summary suggests a match, use\n`read_block_type` to inspect the exact schema. Only call something “missing”\nafter checking capabilities, the complete palette, and custom block types.\n\nCommon requirements that are easy to misclassify:\n\n| Requirement | Existing Typeroll primitive |\n|---|---|\n| Full-bleed hero flush below the header | `core/section` + `core/hero`; block-mode sections already own the full width and have no page-shell padding |\n| Responsive icon/card grid | `core/grid` + `core/icon_box`, or `core/feature_grid`; set responsive fields with `set_block_responsive` |\n| Custom cards backed by Pages | `core/repeater` / `core/page_list` with a site-authored `item_compatible` block type as `item_block` |\n| Grouped Page listing | `core/repeater` with `group_by`; array-valued fields place an item in every matching group |\n| Breadcrumbs in a page template | `template/page_breadcrumbs`; page and item routes supply a server-rendered trail |\n| Shared article typography | Set `font_size`, `line_height` and `paragraph_spacing` on `template_content_slot`; blank values retain block defaults (Core 0.2.2+) |\n| Generated heading index | `core/table_of_contents`; choose heading levels; links always come from the current Page headings |\n| Previous/next Page links | `template/page_navigation`; defaults to content type sort order and can bind explicit neighbor fields |\n| Download CTA that disappears without a file | `template/show_if` around a context-bound `core/button`; a dedicated download block is only editor convenience |\n| Sticky/custom header and multi-column footer | Block-mode header/footer partials plus layout blocks, or one reusable custom block type |\n| Cookie notice | `settings.cookie_consent`, not a page block |\n| Consent copy owned by an installed Extension | `list_extension_installations` → `read_extension_installation` → `update_extension_installation_config`, using exact manifest schema keys; the update queues a production deploy by default |\n| One-off HTML + JavaScript embed | `core/embed`; reusable widgets use a custom block type with `script` |\n| CTA/button variants | `core/cta` and `core/button`, styled from site tokens or a narrowly scoped class |\n| Two-column image/text | `core/media_card`, `core/feature_row`, or `core/columns` |\n| Figures, captions and tables | `core/prose` / richtext; the sanitizer preserves these semantic tags |\n| Full-width block page without a content shell | Native block mode; top-level `core/section` is unconstrained |\n| Brand colors and typography | Site `colors`/`fonts` tokens consumed by core blocks |\n\nReal gaps should say what was checked and why the nearest primitive is not\nenough. “I did not see a dedicated block name” is not evidence by itself.\n\n### 2. Brand + settings\n\nOne `update_site_settings` call with every field you know:\n\n```json\n{\n \"site_name\": \"Acme Studio\",\n \"tagline\": \"Short, punchy tagline\",\n \"language\": \"sv\",\n \"trailing_slash\": \"always\",\n \"colors\": {\n \"primary\": \"#1a1a2e\",\n \"secondary\": \"#16213e\",\n \"accent\": \"#e94560\",\n \"background\": \"#f5f5f5\",\n \"surface\": \"#ffffff\",\n \"text\": \"#1a1a2e\",\n \"text_light\": \"#6b7280\"\n },\n \"fonts\": { \"heading\": \"Playfair Display\", \"body\": \"Inter\", \"size_base\": 16 },\n \"contact\": { \"email\": \"hej@acme.se\", \"phone\": \"+46 8 123 456\" },\n \"social\": { \"instagram\": \"https://instagram.com/acme\" }\n}\n```\n\nRead it back with `read_site_settings`. Google Fonts names are\ncase-sensitive display names (\"Plus Jakarta Sans\", not \"plus jakarta\").\n\n**Site icons are part of brand setup** — upload favicon (32–64px), a\n180×180 apple touch icon, and a 192×192 app icon; set `favicon`,\n`apple_touch_icon`, and `icon_192`. No icon assets? Derive a proposal (see\n`tr-brand`). Also set `settings.logo` to the uploaded brand mark — it feeds\nOG/schema even if the header uses a different lockup.\n\nSet `iframe_allowed_hosts` when customer content embeds a provider outside\nthe built-in YouTube/Vimeo/Google Maps/Calendly set. Values are exact domain\nhostnames, never URLs or wildcards. Read the setting back before deciding that\nan iframe cannot be represented.\n\n### 3. Header + footer partials\n\n**Start from the native preset — don't hand-roll navigation.** Read\n`tr-header-footer` and use its `template/site_logo` + `core/navigation`\ncomposition. The server-rendered landmark, current-page state, no-JS links,\nmobile disclosure, focus treatment, and responsive behavior are Core\ncontracts rather than tenant CSS/JavaScript.\n\nStage the complete tree with `update_partial partial_id=\"header\"\npatch={blocks:[...]} save=true`, then call `set_partial_mode partial_id=\"header\"\nto=\"blocks\"`. Repeat for the footer and read both partials back. The inactive\nHTML representation is retained for rollback; changing `content_mode` through\nordinary PATCH/PUT is rejected intentionally.\n\nUse HTML mode only when preserving legacy authored markup that cannot yet be\nrepresented natively. Partials receive the same `{{site.*}}` render context as\npage blocks. Keep the first section and header backgrounds intentional; do not\nadd a decorative border merely to compensate for mismatched spacing.\n\n### 4. Homepage — block tree\n\n`create_page` with the whole tree in one call. Omit block `id`s — the\nplatform assigns them (`blk_…`); you read them back for later\n`update_block` calls.\n\n```\ncreate_page title=\"Start\" slug=\"\" status=\"draft\" content_mode=\"blocks\" blocks=[...]\n```\n\nA proven landing-page skeleton (every top-level block is a `core/section`\n— sections are **natively full-bleed**: the background runs edge-to-edge,\ncontent is constrained by the section's own inner container via the\n`width` field. NEVER use 100vw negative-margin hacks. Anchor ids and\ncustom classes via `style_overrides` are safe on sections from\ntemplate_capabilities_version ≥ 0.15.3; on 0.14.x–0.15.2 they wrap the\nsection in a div and silently break full-bleed — there, put the anchor\non a block *inside* the section instead):\n\n```json\n[\n { \"type\": \"core/section\", \"data\": { \"background\": \"#ffffff\", \"padding_y\": \"lg\" }, \"children\": [\n { \"type\": \"core/media_card\", \"data\": {\n \"image\": \"MEDIA_URL\", \"image_alt\": \"…\", \"image_side\": \"right\",\n \"heading\": \"Huvudrubriken\", \"heading_level\": \"h2\",\n \"text\": \"<p>Ingress …</p>\",\n \"button_label\": \"Kontakta oss\", \"button_url\": \"/#kontakt\"\n } }\n ] },\n { \"type\": \"core/section\", \"data\": { \"padding_y\": \"lg\" }, \"children\": [\n { \"type\": \"core/heading\", \"data\": { \"text\": \"Så funkar det\", \"level\": \"h2\", \"align\": \"center\" } },\n { \"type\": \"core/grid\", \"data\": { \"cols\": { \"mobile\": 1, \"tablet\": 2, \"desktop\": 3 }, \"gap\": \"lg\" }, \"children\": [\n { \"type\": \"core/step_card\", \"data\": { \"number\": \"1\", \"title\": \"…\", \"text\": \"<p>…</p>\" } },\n { \"type\": \"core/step_card\", \"data\": { \"number\": \"2\", \"title\": \"…\", \"text\": \"<p>…</p>\" } },\n { \"type\": \"core/step_card\", \"data\": { \"number\": \"3\", \"title\": \"…\", \"text\": \"<p>…</p>\" } }\n ] }\n ] },\n { \"type\": \"core/cta\", \"data\": {\n \"heading\": \"Redo att börja?\",\n \"primary_label\": \"Kontakta oss\", \"primary_url\": \"/kontakt\"\n } }\n]\n```\n\nBlock-palette guidance (verify against `list_block_types` — the source of\ntruth):\n\n- **Hero:** `core/media_card` inside a white section (image beside copy),\n or `core/hero` (eyebrow/heading/subheading + `primary_*`/`secondary_*`\n buttons — rendered server-side; `layout: split-right` puts the image\n beside the text). For a plain text hero: section + heading + prose +\n button.\n- **Alternating image+text rows (\"zig-zag\" feature/step lists):**\n `core/feature_row` (template_capabilities_version ≥ 0.29.0) — balanced\n halves that hug the center gutter so wide screens never open dead air,\n natural-aspect image, `image_side: left|right` per row, mobile stack\n order as a field. Prefer it over hand-building `core/columns` with an\n unbalanced ratio + width-capped text (the classic dead-air trap). Use\n `core/media_card` instead when you want a *boxed card* with a\n filled/cropped image.\n- **`core/heading`** decouples `level` (h1–h6, semantics) from `size`\n (visual) — exactly one `level: h1` per page.\n- **Images:** `core/image` with an uploaded media URL. The build pipeline\n emits responsive output from prepared media. Upload through a signed direct\n grant, finalize it, and use returned IDs/URLs. Follow media preparation status;\n do not routinely regenerate unchanged images or use legacy maintenance tools. Use the\n `radius` field for rounded corners.\n- **Repeaters/listings:** `core/page_list`, `gallery`,\n `feature_grid` etc. — alias blocks over `core/repeater`. Use these for\n Pages of a content type instead of hand-writing listing markup. The base\n repeater also supports `group_by`, group ordering/headings, multi-valued\n membership, filters, custom `item_block`, and `item_overrides`.\n- **Long-form navigation:** `core/table_of_contents` builds an anchor list\n from page headings. Page templates use\n `template/page_navigation` for deterministic previous/next links.\n- **Forms:** `create_form`, then place `core/form` with its `form_id`.\n HTML-mode pages use `<x-form id=\"…\" />`; both paths render the same signed\n shell and runtime. See `tr-forms`.\n- **`core/html`** is the escape hatch for the genuinely unique thing —\n not a default. If you reach for it more than once or twice per page,\n note why (that's block-library feedback).\n\nSlot containers (`core/columns`, `core/tabs`): populate them either by\npassing the whole tree inline (`block={ type: 'core/columns', slots:\n[[…],[…]] }`) or incrementally with `add_block parent_id=<columns-id>\nslot_index=0|1`. Requires template_capabilities_version ≥ 0.15.2 — on\nolder sites use `core/grid` (children flow into columns) instead.\n\nPartial last rows (template_capabilities_version ≥ 0.16.5): when N equal\ncards don't divide by the grid's column count (5 cards, 3 cols), set\n`last_row: 'center'` on the `core/grid` — the orphan row auto-centers.\nNEVER invent a \"wide\" variant of one peer card to fill the hole, and\ndon't hand-roll 6-column CSS tricks; both distort content to patch\nlayout. On older sites, pick a column count that divides N.\n\nIcons (template_capabilities_version ≥ 0.16.0): `type: 'icon'` fields on\n`core/icon`, `core/icon_box`, and `core/step_card` render inline SVG when\nthe value is a name from `get_site_capabilities → core_icon_names` (a\ncurated Lucide subset — `check`, `star`, `shield-check`, `mail`,\n`arrow-right`, `truck`, `chart-line`, …). Any other value (emoji, plain\ntext) renders as text, so emoji stand-ins keep working. Icons inherit\nsize from font-size and color from `currentColor`/the block's color\nfield. On older sites icons don't render — use emoji or CSS markers.\n\nEditor schemas (template_capabilities_version ≥ 0.39.0): labelled enum\noptions, newline-edited string lists, nested object/repeating-array fields,\nand internal-page pickers for URL fields are first-class. Do not flatten an\nExtension's `props_schema` merely to make it editable.\n\nFor an Extension placed in an HTML header or footer, require\n`supports_extension_html_partial_directive: true`. The broader\n`supports_extension_html_directive` flag covers HTML page bodies and is not\nproof that an older static build expands partial directives.\n\nFor a cross-page Extension flow, require both\n`supports_extension_site_navigation` and `supports_extension_storage`. Use\n`context.site.navigate(\"/path/\")` and installation-scoped\n`context.storage.session` rather than direct root-path navigation, Web Storage,\nor personal data in query parameters. This keeps navigation inside the current\npreview and preserves state without exposing it through URLs or referrers.\n\nKnown limitations (honest list — don't fight them):\n\n- **`core/tabs` label icons don't render** (the tab strip is built\n client-side without the icon pipeline). Text labels only.\n\nTheming: block primitives render neutral. Brand color/typography comes\nfrom settings (step 2). For page-specific polish (e.g. a colored card\ntreatment), a single `core/html` block with a small `<style>` scoped to\n`[data-bid]`/section selectors is acceptable — keep it minimal and note\nit in your log.\n\n### 5. Inner pages\n\nSame pattern: `create_page` with `content_mode: \"blocks\"` and a section\ntree. Standard set: Om oss, Tjänster, Kontakt — or what the brief says.\nDefault new pages to `status: \"draft\"`; publish after review.\n\n### 5b. If the legacy site is still live, scrape canonical content\n\nFor pages with canonical text (privacy policy, terms, about), `WebFetch`\nthe live page and carry the text verbatim — don't rewrite legal copy\nfrom memory. Convert to prose blocks (or one `core/html` for complex\nlegacy markup).\n\n### 6. Preview + iterate\n\n```\nget_preview_link # signed URL for browser review\nget_page_preview page_id=\"home\" # rendered HTML for structural checks\n```\n\n**Self-review the visuals before you call it done — appearance AND\nreadability, not just structure.** Screenshot the deployed/preview site at\ndesktop (~1440px) and mobile (~390px) and look: logo FULLY VISIBLE (not clipped by\na header's overflow:hidden) + legible + brand-compliant against its actual\nbackground — screenshot the header IN CONTEXT, not the logo element in isolation\n(an element shot hides layout clipping); a light wordmark must not sit bare on a\nlight surface. Text contrast everywhere, no horizontal scroll or mid-word\nbreaks, every image rendered, mobile layout actually collapsed. \"No overflow +\ncopy present\" is not a design review — never report a build as done/perfect off\nstructural metrics alone.\n\nShare the preview link. Iterate on feedback with `update_block` /\n`add_block` / `move_block` — that's the point of block mode: surgical\nedits, not full-page rewrites.\n\n### 7. Deploy\n\nWhen the user approves, verify read_publishing_readiness and save the intended\nVersion before deploying. A published CMS status is not a live deployment.\n```\ntrigger_deploy\nget_deploy_status job_id=<id>\n```\n\n## Secondary path: HTML mode\n\nFor migrated legacy pages or a hand-crafted one-off, `content_mode:\n\"html\"` still works. Rules that apply there (and only there):\n\n- Wrap the body in a page-scope `<article class=\"my-page\">` and prefix\n selectors with it — the `.page-content` shell sets width/padding at\n normal specificity.\n- HTML-mode bodies are container-constrained; full-bleed requires the\n negative-margin escape (`margin-left: calc(50% - 50vw); width: 100vw`)\n — never combine with `overflow-x: clip` on a wrapper.\n- `set_page_mode` flips a page between modes;\n `convert_page_to_blocks` does a heuristic HTML→blocks conversion.\n\n## Pitfalls\n\n- **Don't create pages that already exist** — `list_pages` first; use\n `update_page` if the slug is taken.\n- **`update_page` takes a `patch` object**, not flat fields.\n- **Don't hardcode block field names from memory** — schemas are\n per-site (`list_block_types`/`read_block_type`).\n- **One `level: h1` per page** (core/heading) — SEO + screen readers.\n- **Don't simplify data during import** — preserve Swedish characters in\n labels (`affärsutveckling`, not the ASCII-folded slug), keep titles\n verbatim; slugs are derived for URLs only.\n- **Minimal JS.** Inline `<script>` in page content is stripped by the\n sanitizer. One-off interactivity uses `core/embed`; reusable interactivity\n uses a block-type `script`; site-wide code belongs in `scripts_body_end`.\n",
|
|
21
21
|
"tr-page-template": "---\nname: tr-page-template\ndescription: Create or edit a reusable Page template for articles, checklists, products, directory entries or other Pages that share a layout.\n---\n\n# Share a layout across Pages\n\nRead capabilities, available block types, content types and Page templates first.\nUse a site version for substantial design changes. The Page owns its body blocks;\nthe template owns the shared layout around that body. The content type selects a\ndefault template, and an individual Page can override it.\n\n1. `create_page_template name=\"article-layout\" label=\"Article\" starter=\"article\" status=\"published\"`.\n Alternatively supply `blocks` instead of `starter`. Presets include article,\n blog, checklist, team, events, products, profile, landing and custom.\n2. `update_content_type name=\"articles\" patch={template:\"article-layout\"}`.\n For a single-page override, `update_page page_id=... patch={template:\"article-layout\"} save=true`.\n3. Read and edit the template through `read_page_template` or block tools with\n `target: { kind: \"template\", id: \"article-layout\" }`. Template edits save\n immediately; content-type and template changes are isolated by `version`.\n4. Keep a `template_content_slot` where the Page's body belongs. Its `max_width`\n can be full, narrow, normal or wide. Use native columns/containers for layout.\n5. Metadata blocks include `template/page_title`, `template/page_date`,\n `template/page_featured_image`, `template/page_breadcrumbs` and\n `template/page_navigation`. The outline block reads the rendered body headings.\n6. Use `{{page.title}}` or `{{page.custom_field}}` in template bindings.\n A repeater's children use `{{item.title}}` for the current listed Page.\n Custom fields can be typed objects, arrays or Page references; preserve those\n structures instead of storing hand-generated list HTML.\n7. Preview several Pages using the template: long title, short body, missing\n optional image, populated reference list. Inspect desktop and mobile output.\n Verify the authorized static build as well as the live database preview.\n\nPrefer native image, table, list, heading and content blocks. A rare specialized\nwidget can use a reviewed HTML/embed block. Reusable custom behavior belongs in\none custom block type rather than repeated HTML bodies. Existing HTML-mode pages\nmay share fragments through partials and `<x-include>`, but use block templates\nfor new content families.\n\nHeader/footer partials are global and remain separate from content types. Keep\nsite-level design tokens in settings and shared layout changes in the template.\nPage body edits stay specific to that Page. Read the template before mutation;\nnever replace it with a starter merely because an import is being retried.\n\n\nContent types also own `sort_field`/`sort_dir` and optional `allowed_templates`.\nTypes define content; templates define presentation. Multiple compatible Page\ntemplates can be allowed, with `template` selecting the default. Null/absent\n`allowed_templates` is unrestricted, `[]` allows none, and a configured default\nmust be in an explicit allowed list. Page overrides must be allowed; null/empty\n`Page.template` restores inheritance. Page template changes use Save/Discard.\n\nListings inherit type sorting unless explicitly overridden. `Page.sort_order`\nis the manual numeric order; null clears it. Missing sort values come last and\nIDs break ties. Explicit ID lists keep their order. Typed `list_pages` queries\ninherit type sorting and accept `sort_by`/`sort_order`; unfiltered API lists\ndefault to stable IDs. See the public Content types guide for editor steps.\n\n## Structured fields without empty labels\n\nCheck `supports_page_field_list` before adding `core/field_list`. Configure\n`data.fields` as `{ field, label? }` rows, optional `title` and `layout`\n(`stack` or `two-column`). It omits empty rows and an entirely empty section,\nrespects `rendered: false`, uses select display labels and links Page references.\nZero is displayed. From Core 0.2.14, boolean rows hide false/unset by default; set `boolean_display: \"yes-no\"` to show both set values with `true_label` / `false_label` (defaults Yes/No). Stored false remains real data. Optional row `html` has only `{{label}}` and\n`{{value}}` slots; row `css` contains declarations, and `css_class` supports\nshared selectors. Values stay in Page.fields; never duplicate them into rich text.\nRead the current block schema and content type, and verify preview before publishing.\n\nFor checkbox lists, `item_html` decorates each selected option with the same\nlabel/value slots (for example a check icon). `item_links: [{ value, url }]`\nlinks only chosen stored options to listing URLs, retaining their schema labels.\nStyle list items via the row css_class and normal block Custom CSS.\n\n## Heading and field-list defaults (Core 0.2.13)\n\nA template H1 owns the Page title. Do not send body `core/heading` blocks with\n`level: \"h1\"` when the selected/default template supplies one. Use H2. Creation,\nPage writes and Save reject duplicates with a corrective error. Existing duplicate\nheadings render as H2 without mutating storage. A Page without a template H1 can\nkeep one body H1. The layout itself does not inject an additional title.\n`core/field_list` defaults to a 0.7rem row gap, weight-600 labels and values that\nwrap long URLs. Empty rows and entirely empty groups stay hidden.\n\n### Native precision (Core 0.2.25 candidate)\n\nRead current block schemas before relying on new controls. Heading/Page title\nsupport responsive `font_size_px`, unitless `line_height` and `color`. Sections\nseparate full-width background from `max_width_px`, `padding_x` and\n`content_gap_px`; Containers add `max_width_px`, `gap_px`, `padding_x_px` and\n`padding_y_px`. Two columns add `gap_px` and `right_width_px`. Use numeric values\nor `{mobile, tablet, laptop, desktop, wide}` overrides, not CSS strings.\nBreadcrumbs have `padding_before_px`, `padding_after_px`, `divider`; TOC has\n`padding_px`, `radius_px`, `border`, `shadow`, `link_color: neutral` and\n`list_style: chevron`. Keep TOC generated from headings. Icon box adds native\ncard dimensions and `whole_card_link`; map real Page URLs rather than freezing\ncustomer routes in HTML. Site logo accepts `height_px`. The `system` font family\nuses the device stack without a webfont request. Preserve complete images and\nvalidate actual mobile/desktop output, including scrolled outlines.\n\nColumns `stack_below` accepts the select strings `\"721\"` (default), `\"768\"`,\n`\"1024\"`, `\"1280\"`. A direct-slot TOC follows the selected stacked boundary: its\n`mobile_display: \"hidden\"` releases the otherwise empty slot; `\"visible\"` keeps\nit in flow. Use `\"1024\"` for full article width below laptop when justified by\nthe source comparison. Do not merely hide the TOC with `hidden_on` while leaving\na reserved two-column track, or duplicate body content for tablet/desktop.\n\nFor a sticky site header, use an outer semantic Container (`tag: \"header\"`,\n`sticky: true`, optional responsive `sticky_top_px`, 0–240) outside main. Keep\nits background opaque and its containing block tall enough; do not create a\nshort header wrapper or clip it with ancestor overflow. Sticky is opt-in.\nContainer `padding_top_px`/`padding_bottom_px` override `padding_y_px` per side\nand accept responsive maps. Grid/Repeater and repeater aliases expose responsive\n`gap_px` (0–240). Use these fields for exact source spacing rather than empty\nspacers or corrective CSS. TOC active-section feedback includes document scroll\npadding; remove obsolete duplicated tenant header offsets during migration.\n\n\n## Qualified composition starters (Core 0.2.32 / MCP 0.45.26 and later)\n\nCheck `supports_composition_starters` and `supports_default_presentation_contract`.\nUse `get_composition_starter` to read one editable `header`, `footer`, `archive`\nor Page-template starter without changing CMS data. An archive also requires\n`content_type`; optional `title` names its heading. Replace sample navigation,\nmap the Profile's empty field_list to real public fields, and save through the\nnormal version-aware tools. `create_page_template` accepts the same Page starter\nnames as Templates → New template. Starters are copies, never live links that\nreplace an existing design after an upgrade.\n\nSections own background/gutters, Containers default to no padding, and article\nflow owns heading rhythm. Inspect Appearance before Advanced settings. Reset\nrestores block defaults; don't mirror styles into canonical fields. Formatted\nheadings have typed responsive typography. Container `overflow: \"clip\"` and\nmenu `panel_padding: \"none\"` are deliberate opt-ins. Default PDF text links are\nunderlined theme links. Missing template image/date/excerpt/author emits no node.\n\nFor an existing Container whose padding was omitted, review the new zero-padding\noutput; explicitly set the former `md` values if they should remain (horizontal\n2rem, vertical 4rem). Never bulk-replace existing templates. Read\nhttps://typeroll.com/docs/tools/blocks/ for the full default/migration contract.\n\n\n## Native surface controls (Core 0.2.33 / MCP 0.45.27)\n\nCheck `supports_surface_feedback_and_gradients`. Section/Container\n`background_gradient: { from: \"#f8fbff\", to: \"#e8f4fc\", angle: 135 }` adds\nan opt-in two-stop gradient; remove the object to return to the solid/image\nbackground. Use real colors or simple theme variables, never CSS declarations.\nPost Card `hover_background`, `hover_border_color`, `hover_color` and outlined\nPDF `download_hover_background`/`download_hover_color` control pointer, pressed\nand keyboard feedback. Repeater/page_list item_overrides use the same schema.\nKeep focus visible and check contrasting color pairs; don't move the card.\nNavigation Links `density: \"compact-desktop\"` gives footer links a 24px minimum\non desktop with fine pointers; mobile/touch retains 44px. For dense taxonomy\nfooters use `direction: \"column\"`, `font_size_px: 14.4`, `line_height: 1.1`,\n`gap_px: 4` and `padding_y_px: 0`. Primary menus keep comfortable defaults. Verify both narrow and\nwide views and publish the intended version after saving; no automatic migration.\n\n\n## Publication fidelity (Core 0.2.34)\n\nStatic Repeater rows and aliases export the selected item block’s declared public\nfields, explicit card mappings and grouping labels. Use `title`/`href` for static\nPost Cards and `item_overrides` for common appearance; never place private data\nin public fields. `rendered: false` still excludes the field. `breadcrumb_label`\nis preserved separately from the Page title. Older public artifacts need a new\ndeployment; do not rewrite the saved rows to compensate. Native Heading and Page\nTitle wrap long words without shrinking authored type. Firestore history adds no\nextra Page nesting; an actual storage depth limit returns structured HTTP 422\n`storage_document_too_deep` with the offending field path.\n",
|
|
22
22
|
"tr-redesign-branch": "---\nname: tr-redesign-branch\ndescription: Use when the user asks to redesign, modernize, or restructure a Typeroll site (or a section of it). Forces branch-isolated work so the live site stays untouched until the redesign is approved.\n---\n\n# Redesign a site without breaking the live one\n\n> **The buffer model (draft writes).** Every content write in this recipe\n> (pages, blocks and partials) lands in an unsaved per-doc\n> DRAFT — deploys and plain previews only see SAVED content. For recipe-style\n> build work, pass `save: true` on write calls (the work is pre-approved by\n> the task itself), or run `commit_working_copy` per doc before any\n> `trigger_deploy`. Preview your drafts with `include_working_copy: true`.\n\n\nSite-wide changes are exactly where copy-on-write branches earn their\nkeep. This skill enforces the discipline: every redesign happens on a\nbranch, preview-checked end-to-end, merged only after user sign-off.\n\n**Copy comes from the LIVE page, not a local draft.** A redesign changes\nthe design, not the words. Read the existing copy from the live page\n(`read_page`/`batch_read_pages`) and carry it over verbatim. Local\n`sources/*.md` files are drafts — use them only if the user explicitly\nsays \"apply the copy in `<file>`\". Don't invent new headlines, drop\nsections, or \"restore\" text from an old draft; a draft that had drifted\nfrom the live page once sent a whole redesign off the approved wording.\nWhen you must change a word, change it on the live page too and keep the\ndraft file in sync.\n\n**Restraint beats decoration.** Default to clean, purposeful design. Don't reach\nfor decorative motifs (suns, blobs, glows, mascots, confetti) to look \"graphic\" —\nunless a motif *means something for this brand/page*, it reads as random, and it's\nusually the exact thing that clips, seams, and crops. These fragile patterns broke\na real build — avoid them:\n- **A shape divider (wave/curve) between two sections** → don't hand-roll it in\n `core/html`; a separate stacked shape seams against the next section (a Chrome\n sub-pixel hairline). Use `core/section`'s **`divider_top` / `divider_bottom`**\n (`wave | curve | tilt`) — the platform paints it in the section's own colour and\n overlaps the neighbour by 1px, so it's seam-free by construction. Put the divider\n on the section whose colour should rise/dip into the neighbour.\n- **A glow/decoration inside an `overflow:hidden` box** → clipped to a hard edge.\n Put it in a non-clipped layer, or size it to fade out before the box edge.\n- **`object-fit:cover` on a portrait inside a circle/frame** → crops heads and\n faces. Use `contain`, reframe the source art, or size the frame to the art.\n- **A gradient \"fade\" at a section join** → reads as the design being cut off.\n Make transitions deliberate (a clean shape or a solid edge), never a fade.\nThese are invisible in a small full-page thumbnail and only show at real size in\nthe actual browser — see the review gate in step 6.\n\n## Recipe\n\n### 1. Discover (always)\n\n```\nget_site\nread_site_settings\nread_partial partial_id=\"header\"\nread_partial partial_id=\"footer\"\nlist_pages limit=20\nbatch_read_pages page_ids=[<top 3-5 pages>] # see actual conventions\nlist_partials # what free blocks exist\nlist_content_types # any data we need to consider\n```\n\nWrite the user a short read-back: *\"This is a 12-page agency site\nusing CSS variables, primary color #1e40af, Inter heading + Source\nSans body. Existing pages are content-dense, single-column. Main nav\nhas 5 items including a CTA. I'd suggest...\"*\n\nConfirm direction before touching anything.\n\n### 2. Create a branch\n\n```\ncreate_branch name=\"<descriptive name>\"\n```\n\nSave the response's `id` — pass it as `version=<id>` on every\nsubsequent call. Branches default `robots_blocked: true` so a\nhalf-finished redesign won't be indexed.\n\n### 2b. Write the design spec (REQUIRED — before you build)\n\nEvery redesign branch MUST carry a written design spec. Without it the\ndesign choices live only in the agent's head, so a later \"just tweak the\nillustration style / palette\" means re-deriving everything by hand (this\ngap cost a real project a full reverse-engineering pass). Write it BEFORE\nbuilding so it guides the work, and keep it in sync as the design evolves.\n\nSave it as a markdown doc with the project (e.g. `design-spec.md`, or\n`prompts/design-system.md`) — or, if there's no local working dir, as an\nunlisted page on the branch. It must capture:\n\n- **Palette** — every role + hex (background, surface, primary, accent,\n text, borders), and where the variant *diverges* from the brand and why.\n- **Typography** — fonts + weights/sizes per role.\n- **Illustration / imagery style** — the exact image-gen prompt prefix\n (tone, palette, formspråk, framing rules), so the imagery can be\n regenerated or restyled on its own without touching layout. State the\n business/concept constraints the imagery must respect (a wrong-concept\n image is worse than none).\n- **Section structure** — the page's sections in order + each one's\n treatment (band colour, layout).\n- **Rationale** — one line per major choice: *why* this direction.\n\nWhen the user later says \"adjust just the illustrations\" or \"change the\npalette\", you edit the spec first, then apply — the spec is the source of\ntruth for the design intent.\n\n### 3. Iterate on the branch\n\nFor each redesign step:\n\na. Make the change with `?version=<branch-id>`. Updates here don't\n touch main:\n\n ```\n update_partial partial_id=\"header\" patch={...} version=\"<branch>\"\n update_page page_id=home patch={...} version=\"<branch>\"\n ```\n\nb. Preview after every meaningful change:\n\n ```\n get_preview_link page_id=home version=\"<branch>\"\n ```\n\n Send the URL to the user. The preview navigates the whole branch\n from one mint.\n\nc. Iterate on feedback. Common rounds: headline tightening, color\n tweaks, swapping hero images.\n\n### 4. Site-wide changes through partials, not pages\n\nIf the redesign touches every page (e.g. new global header, new\nfooter, new CTA bar) — edit a partial, not 23 pages. Before editing a\nshared block, check the blast radius:\n\n```\nfind_pages_using_block partial_id=\"header\" version=\"<branch>\"\n```\n\nThis returns every page that would show the change. Communicate that\nto the user before the save.\n\n### 5. Bulk content cleanups via dry-run first\n\nIf the redesign requires content rewrites (e.g. \"remove every mention\nof the old company name\"), use the bulk tool with dry-run:\n\n```\nsearch_pages contains=\"OldCo\" version=\"<branch>\"\nbulk_replace_text pattern=\"OldCo\" replacement=\"NewCo\" dry_run=true version=\"<branch>\"\n# Show the user the sample_diffs\nbulk_replace_text pattern=\"OldCo\" replacement=\"NewCo\" dry_run=false version=\"<branch>\"\n```\n\n### 6. Approval round\n\n**Self-review is a multi-DIMENSION pass, not a glance — and most of it you\nMEASURE, not eyeball.** Structural checks (copy present, images return 200) are\nNOT a design review; never report \"approved\" off them. Don't just list the bugs\nyou happened to notice — walk every dimension below on the DB-live preview\n(a reused `get_preview_link`; browser tool + DOM reads), fix what you find,\nreload, re-check. No re-deploy between fixes — the preview renders from the DB.\n\n**Use `tr-design-review` (`read_skill tr-design-review`) for the HOW** — it has\nthe per-dimension measurement snippets (overflow ladder, computed contrast, touch\ntargets, the anti-lazy-load broken-image check) and the scorecard + verdict\nformat. The dimension summary below is the \"what\"; that skill is the runnable\nroutine. In particular: scroll-and-settle to trigger lazy images BEFORE any\nfull-page screenshot, or you'll report blank boxes that aren't real.\n\n1. **Responsive** — screenshot across a width ladder (mobile / tablet / laptop /\n desktop / wide ≈390 / 768 / 1024 / 1440 / 1920px) AND sweep the page's own\n `@media` breakpoints (read the page-scoped `<style>`; resize a few px below +\n above each). At EVERY width: `document.documentElement.scrollWidth <=\n clientWidth` (no horizontal scroll), grids flip cleanly, nothing squished /\n orphaned / overlapping, no mid-word breaks. Two sizes is not enough — bugs hide\n in between. Also check a short/landscape viewport and 200% browser zoom.\n2. **Visual & brand** — logo FULLY VISIBLE (not clipped by a header\n `overflow:hidden` + overlap margin) and brand-compliant; screenshot the header\n IN CONTEXT, never the logo element in isolation (that hides clipping).\n Decoration robust at real size in the real browser: no hairline seam at a\n divider (use `core/section` `divider_top`/`divider_bottom` — don't hand-roll a\n band), no glow clipped to a hard edge, no `object-fit:cover` cropping faces, no\n gradient fade-cutoff. Typography: body line-length ~45–75ch, consistent scale,\n no awkward widows on headings. Palette adherence (no off-brand colours);\n consistent spacing / alignment / radius / shadow.\n3. **Accessibility — MEASURE, don't eyeball** — compute actual contrast ratios\n (WCAG AA: body ≥4.5:1, large/UI ≥3:1) and fix failures by deepening the\n offending colour token; meaningful `alt` on every image; exactly one `<h1>` +\n no skipped heading levels; visible `:focus-visible` on every interactive\n element; every input has an associated `<label>`; touch targets ≥44px on\n mobile; semantic landmarks (header/nav/main/footer) + nav `aria-label`; honour\n `prefers-reduced-motion`.\n4. **Functional** — the form actually works (POST action correct, hidden token\n non-empty, honeypot present + hidden; a long name/email doesn't break layout);\n every link + in-page anchor resolves (each `#anchor` has a matching `id`; no\n `href=\"#\"`/`\"\"`); ZERO console errors/warnings; interactions (menu toggle,\n hover/focus/active) work.\n5. **Content** — no unrendered `{{…}}` tokens in the DOM; no placeholder/lorem;\n copy still matches the source of truth (the live page) verbatim.\n6. **Findable (SEO/meta)** — `<title>` + meta description present + sensible;\n `og:title`/`og:description`/`og:image`; canonical; favicon + apple-touch-icon;\n `<html lang>`; `noindex` correct (branches must be noindex).\n7. **Fast (performance)** — images at sane sizes (not a 2048px file shown at\n 380px without a responsive variant), modern format (avif/webp), `width`/`height`\n or aspect-ratio set (no layout shift), below-fold lazy / above-fold eager.\n8. **Cross-browser** — the same CSS renders differently per engine (the divider\n seam was Chrome-only; WebKit/Firefox have their own). Re-check in another engine\n if you can; if only Chromium is available, statically flag risky props\n (`backdrop-filter` without fallback, `-webkit-`-only masks, `100vh` on mobile →\n prefer `100svh`, `sticky` inside `overflow`).\n\nFix what you find and re-check before involving the user. \"Looks structurally\nfine\" ≠ \"looks good\", and \"looks good in Chrome at 1440\" ≠ \"works for everyone,\neverywhere\" — never report a design as approved/perfect off a glance or a partial\npass.\n\nThen give the user the **DB-live preview link** to review — and use the SAME\nlink for your own verification:\n\n- **While iterating (default):** a reused `get_preview_link` (mint once,\n reuse — defaults to a 24h TTL). It renders from the database with NO build, so every\n edit shows on reload, and one link navigates the whole branch (internal\n links keep the token). The token URL is stable across edits — re-mint only\n when the 24h lapses, never per edit. Do NOT deploy just to let the user (or\n yourself) see a change.\n- **When they want the COMPILED static site** (a permanent bookmark, a\n stakeholder link to the built output, or a final pre-merge check): deploy\n the branch once (`trigger_deploy version=\"<branch>\"`) and share the stable\n alias `https://<branch>.<project>.pages.dev` (the `<project>` is the part\n after the hash in the returned `deploy_url`). Branch deploys are\n `robots_blocked`, so it won't be indexed. The immutable per-deploy\n `<hash>.pages.dev` is for your own one-off checks (a new hash each deploy).\n\nDefault: review/iterate on the reused DB-live preview; deploy only for the\ncompiled output or merge. Wait for an explicit \"looks good, ship it.\"\n\n### 7. Merge + deploy\n\n```\nmerge_branch version_id=\"<branch>\" # branch's diffs land on main\ntrigger_deploy\nget_deploy_status job_id=<id> # poll until succeeded\n```\n\nOptionally, after a successful deploy:\n\n```\ndelete_branch version_id=\"<branch>\" # tidy up\n```\n\n(You can also leave the branch around as a record of the redesign;\ndisk cost is tiny.)\n\n## Pitfalls\n\n- **Forgetting `version=` on writes.** Every call you make on the\n branch must include `version=<branch-id>`. A missing one writes\n straight to main — silent and bad.\n- **Skipping discovery.** \"Modernize\" without first reading the site\n produces a confidently-out-of-place result. Always sample existing\n pages.\n- **Deploying to preview.** Don't `trigger_deploy` after every edit just to\n see the change — that builds static pages and the URL is only as fresh as\n the last build. Iterate on a reused DB-live `get_preview_link` (renders from\n the DB, reflects edits on reload); deploy only for the compiled static\n output or merge (steps 6–7).\n- **Auto-merge.** Don't `merge_branch` without explicit user sign-off.\n Once merged, the only undo is another branch + reverse edits.\n- **Header rewrites that drop the brand block.** Even when the\n redesign is dramatic, preserve the brand mark + the nav skeleton\n unless the user said to redo them.\n\n## When to NOT use a branch\n\nTiny edits — \"fix the typo on the About page\" — don't need a branch.\nThe in-portal chat handles those directly on main. This skill is for\nwork where:\n\n- The user might want to walk away mid-redesign and come back later\n- Multiple changes need to ship together\n- The site is high-traffic and \"broken for an hour\" is unacceptable\n- Stakeholder review across multiple pages is expected\n\nIf none of those apply, edit main directly and move on.\n",
|
|
23
|
-
"tr-responsive": "---\nname: tr-responsive\ndescription: Use when a layout must behave differently at different screen sizes — different grid columns per breakpoint, an icon-box that's icon-on-top on mobile but icon-left on tablet, hiding a block on small screens, fluid type. Triggers on \"responsive\", \"mobile/tablet/desktop layout\", \"stack on mobile\", \"X columns on desktop and Y on mobile\", \"olika på mobil/surfplatta\", \"responsivt\".\n---\n\n# Make a Typeroll block layout responsive\n\nTyperoll has a built-in five-breakpoint system. You almost never hand-write\nmedia queries — you set per-breakpoint values on responsive fields and the\nrenderer compiles the `@media` rules per block instance.\n\n## The five breakpoints (mobile-first)\n\n`mobile (<640) · tablet (≥640) · laptop (≥1024) · desktop (≥1280) · wide (≥1536)`\n\nA responsive field takes either a scalar (applies everywhere) or a sparse\nobject `{ mobile?, tablet?, laptop?, desktop?, wide? }`. Missing breakpoints\ninherit from the next smaller one. So you only set the breakpoints that change.\n\n## Setting per-breakpoint values\n\nUse `set_block_responsive` (or pass the object form directly in `add_block` /\n`update_block` data). `read_block_type <id>` tells you which fields are\n`responsive`.\n\nThe breakpoint object belongs on the responsive field inside `block.data`,\nfor example `data.cols`. Do not add a top-level `block.responsive` object: it\nis not a rendered field, and page, partial and Page-template writes\nreject it instead of silently storing an inert value.\n\n```\n# 4 columns on desktop, 2 on tablet, 1 on mobile:\nset_block_responsive target={kind:page,id:home} block_id=<grid-id>\n field=cols value={ mobile: 1, tablet: 2, desktop: 4 }\n\n# icon-box: icon on top on phones, beside the text on tablet+:\nset_block_responsive ... block_id=<iconbox-id>\n field=layout value={ mobile: \"icon-top\", tablet: \"icon-left\" }\n```\n\nPass a scalar to collapse a field back to one value everywhere, except the\nlisting defaults below.\n\n### Listing grids and content gutters (Core 0.2.13)\n\n`core/repeater` and aliases such as `core/page_list` use one grid column below\n768px even when scalar `cols` is larger. Set `mobile_cols: 2` only when multiple\nmobile columns are intentional. An explicit responsive `cols.mobile` is honored;\n`mobile_cols` takes precedence. Above this threshold `cols` works normally.\nMasonry is opt-in and also uses the explicit mobile count. Other blocks retain\nthe five breakpoints above.\n\nContent gutters default to 1.25rem below 768px and 1.75rem at/above 768px.\nFull-bleed section backgrounds keep their padded inner content. Customize\n`--content-gutter` in site CSS if needed. Rebuild published sites after upgrading\nCore to apply these shared preview/static defaults.\n\n### Worked example — the classic feature grid\n\n\"4 cards/row with icon-on-top on desktop, 2/row with icon-left on a landscape\niPad, 1/row icon-on-top on a phone\":\n\n1. `core/grid` containing `core/icon_box` cards (or a `core/repeater` with\n `item_block: core/icon_box` for a Page-driven list).\n2. On the grid: `cols = { mobile: 1, tablet: 2, desktop: 4 }`.\n3. On each icon_box (or the repeater's item defaults):\n `layout = { mobile: \"icon-top\", tablet: \"icon-left\", desktop: \"icon-top\" }`.\n\nNo media queries authored — the build emits per-instance `@media` blocks and\nthe editor preview honours them. Flip the device toggle in the editor header\n(Mobil / Mobil-liggande / iPad / iPad-liggande / Desktop) to author and verify\neach breakpoint.\n\n## Hiding a block at some sizes\n\n`Block.hidden_on: Breakpoint[]` is universal — no per-block opt-in. E.g.\n`hidden_on: [\"mobile\"]` drops the block below 640px. Use it instead of building\na \"mobile-only\" duplicate.\n\n## Authoring a CUSTOM block type that's responsive\n\nTwo halves, BOTH required (`create_block_type` / `update_block_type`):\n\n1. Mark the field `responsive: true`.\n2. Expose it on the **outermost** template element as a CSS variable:\n `style=\"--{field}:{{field}}\"`, then read `var(--{field})` in the block CSS.\n\nIf the field's value is directly usable CSS (e.g. `direction: row|column` →\n`flex-direction: var(--direction)`), you're done.\n\nIf it's a friendly **token** that maps to CSS (e.g. `layout: icon-left` →\n`flex-direction: row`), add a `responsive_css` map on the field — otherwise the\nper-breakpoint overrides silently do nothing (a `[style*=\"--field:token\"]`\nselector can't see a `@media` override):\n\n```\n{ name: \"layout\", type: \"select\", options: [\"icon-top\",\"icon-left\"],\n default: \"icon-top\", responsive: true,\n responsive_css: { \"icon-top\": \"--dir: column;\", \"icon-left\": \"--dir: row;\" } }\n```\n\nThen the block CSS reads `flex-direction: var(--dir, column)`.\n\n## Fluid type — usually automatic\n\n`core/heading` and prose already use `clamp()` to scale smoothly between mobile\nand desktop. `core/heading` separates semantic `level` (h1–h6, for SEO) from\nvisual `size` (sm–3xl/auto) — \"h1 but only as big as an h3\" is one field, no\nbreakpoints needed.\n\n## Gotchas\n\n- Setting a value only at `desktop` leaves smaller screens on the field\n *default*, not on your value — set `mobile` too if you want a non-default\n baseline (mobile-first).\n- The editor preview width is approximate on a narrow panel, but the breakpoint\n you're editing is exact. Trust the deployed site / a wider window for `wide`.\n- **Never paper over horizontal overflow with `html,body{overflow-x:hidden}`.**\n Setting `overflow-x:hidden` on `html` forces `overflow-y` to compute as `auto`\n (CSS spec), turning `<html>` into a fixed-height nested scroller — the page\n then won't scroll normally (`window.scrollY` sticks at 0) and renders blank\n below the fold. Instead, find the element that overflows (a fixed width, a\n `transform:rotate` card poking out, a decorative `::before`/`::after`, a grid\n that didn't collapse) and fix THAT element's width / clip it with\n `overflow:hidden` on its own section. Verify with\n `document.documentElement.scrollWidth === clientWidth` at 360–390px.\n- `core/grid` `stack_at` and responsive `data.cols` both compile overrides\n that beat the inline mobile baseline. Verify the computed column count at\n the actual breakpoint; no page CSS workaround should be necessary.\n- Background design reference: `docs/responsive-blocks.md` in the platform repo.\n\n\n## Core 0.2.14 native defaults\n\nUse section/hero as top-level background carriers; their inner content owns the\n20px phone / 28px tablet gutters. Do not add another gutter to main. Section\npadding auto is 48/64/80px at phone/768/1280; heading auto is H1 28/32/36 and\nH2 22/24/24 at a 16px root. Use shared --type-h1…h4, --section-padding,\n--block-gap, --card-padding and --grid-gap tokens for theme overrides.\nNavigation collapses through 1023px and becomes inline at 1024px.\nImages preserve the complete subject with intrinsic height and contain; request\ncover and a ratio explicitly only when cropping is intended. Breadcrumb spacing\nuses --breadcrumbs-before / --breadcrumbs-after. Custom field-list item_html\nreplaces native bullets; core/list marker none supports custom icons.\nPreview and static CSS order is defaults → blocks/instances → site → Page;\nspecificity, inline CSS and !important still apply. Compare without temporary\ncorrective CSS before removing any existing site rules.\n\n\n## Site-specific responsive widths (Core 0.2.28)\n\nThe five names stay the same, but their widths can be set in **Site settings →\nTypography → Responsive block widths**, or through `update_site_settings`:\n\n```json\n{\"responsive_breakpoints\":{\"tablet\":576,\"laptop\":769,\"desktop\":1024,\"wide\":1280}}\n```\n\nSend all four increasing integer widths (320–2560px); `null` restores\n640/1024/1280/1536px. Values are versioned with the site's settings. Responsive\nblock fields, repeater item overrides and `hidden_on` use these widths in the\neditor preview and static output. Reload an open editor after changing them.\nRepublish to update live pages; changing widths invalidates rendered-page caches.\n\nThis does not change explicit menu `collapse_below`, grid `stack_at`, listing\nmobile defaults or theme typography thresholds. Set the menu threshold separately\nwhen it must match, and use explicit responsive `cols` for exact listing columns.\nCheck one pixel below and at each threshold, including fractional widths for\nvisibility. Do not hide layout overflow to make a test pass.\n\n## Independent components (candidate capability 0.48.0)\n\nNot available in Core 0.2.31. Read capabilities and the live block registry first.\nEvery core block accepts `data.responsive_breakpoints` with all four increasing\nintegers (320–2560); null restores Site widths. It affects only that block's\nresponsive fields/visibility, not children. Listing grid and item cards are\nindependent: put card widths in `item_overrides.responsive_breakpoints`.\n\nA checklist card can use widths `{tablet:577,laptop:769,desktop:1041,wide:1440}`,\n`layout:{mobile:\"column\",desktop:\"row\"}`, `image_width_percent:40`,\n`image_sizing:{mobile:\"fixed\",desktop:\"stretch\"}`, `image_height_px:200`, and\nexplicit `image_fit:\"cover\"`. Intrinsic ignores pixel height; auto preserves it.\nUse stretch only for row layouts. Border, x/y panel padding, background and\n`title_font` are native fields. `action_label` no longer removes the title link;\n`title_link:false` opts out. Secondary actions prevent whole-card overlays.\n\nPDF styling is independent: `download_width:{mobile:\"full\",desktop:\"fill\"}`,\n`download_size_px:13`, `download_weight:\"700\"`, `download_color`,\n`download_border_width_px`, `download_radius_px`, `download_padding_x_px` and\n`download_padding_y_px`. `actions_align:\"center\"` centers the action row.\n`download_behavior:\"download\"` emits HTML download; cross-origin file hosts may\nstill cause browser navigation. Default is navigate, no proxy.\n\nColumns expose `left_width_px:150` and `stack_below_px:481` (stack through480).\nSet one fixed side; left wins if both set. Custom stacking overrides the preset.\nContainer `radius_px` and `shadow` (none/subtle/header) style a composed group.\nMenus use matching SVG symbols; `close_size_px` overrides the close symbol size\nwithout shrinking the44px hit area. Compare exact threshold boundaries in real\npreview and static output before deleting corrective CSS.\n\n## Native image framing and body heading scales (Core 0.2.35+)\n\nUse `core/image.scale_percent` (100–200, responsive) for deliberate horizontal\nframing; 100 retains the uncropped original. `focal_x`/`focal_y` are percentage\npositions; Image `fit`/`aspect_ratio` and Post Card `image_fit`/`image_aspect` are\nresponsive. Keep intrinsic dimensions and original SVG/alt. A mobile 120% centered\nimage uses scale_percent={mobile:120,tablet:100}, focal_x=50 and local\nresponsive_breakpoints={tablet:577,laptop:769,desktop:1024,wide:1280}.\n\nSet `h1_size_px`…`h6_size_px` on `template_content_slot`, not every Page heading.\nThese responsive values inherit through nested containers; explicit font_size_px\non a heading wins. `heading_before_px`/`heading_after_px` control article-rhythm\nspacing. The slot's local breakpoint map controls its scale. Breadcrumbs flow as\ninline ordered-list items, including long current titles. Do not shorten customer\nheadings to compensate for a layout issue. Read the deployed block schema first.\n",
|
|
23
|
+
"tr-responsive": "---\nname: tr-responsive\ndescription: Use when a layout must behave differently at different screen sizes — different grid columns per breakpoint, an icon-box that's icon-on-top on mobile but icon-left on tablet, hiding a block on small screens, fluid type. Triggers on \"responsive\", \"mobile/tablet/desktop layout\", \"stack on mobile\", \"X columns on desktop and Y on mobile\", \"olika på mobil/surfplatta\", \"responsivt\".\n---\n\n# Make a Typeroll block layout responsive\n\nTyperoll has a built-in five-breakpoint system. You almost never hand-write\nmedia queries — you set per-breakpoint values on responsive fields and the\nrenderer compiles the `@media` rules per block instance.\n\n## The five breakpoints (mobile-first)\n\n`mobile (<640) · tablet (≥640) · laptop (≥1024) · desktop (≥1280) · wide (≥1536)`\n\nA responsive field takes either a scalar (applies everywhere) or a sparse\nobject `{ mobile?, tablet?, laptop?, desktop?, wide? }`. Missing breakpoints\ninherit from the next smaller one. So you only set the breakpoints that change.\n\n## Setting per-breakpoint values\n\nUse `set_block_responsive` (or pass the object form directly in `add_block` /\n`update_block` data). `read_block_type <id>` tells you which fields are\n`responsive`.\n\nThe breakpoint object belongs on the responsive field inside `block.data`,\nfor example `data.cols`. Do not add a top-level `block.responsive` object: it\nis not a rendered field, and page, partial and Page-template writes\nreject it instead of silently storing an inert value.\n\n```\n# 4 columns on desktop, 2 on tablet, 1 on mobile:\nset_block_responsive target={kind:page,id:home} block_id=<grid-id>\n field=cols value={ mobile: 1, tablet: 2, desktop: 4 }\n\n# icon-box: icon on top on phones, beside the text on tablet+:\nset_block_responsive ... block_id=<iconbox-id>\n field=layout value={ mobile: \"icon-top\", tablet: \"icon-left\" }\n```\n\nPass a scalar to collapse a field back to one value everywhere, except the\nlisting defaults below.\n\n### Listing grids and content gutters (Core 0.2.13)\n\n`core/repeater` and aliases such as `core/page_list` use one grid column below\n768px even when scalar `cols` is larger. Set `mobile_cols: 2` only when multiple\nmobile columns are intentional. An explicit responsive `cols.mobile` is honored;\n`mobile_cols` takes precedence. Above this threshold `cols` works normally.\nMasonry is opt-in and also uses the explicit mobile count. Other blocks retain\nthe five breakpoints above.\n\nContent gutters default to 1.25rem below 768px and 1.75rem at/above 768px.\nFull-bleed section backgrounds keep their padded inner content. Customize\n`--content-gutter` in site CSS if needed. Rebuild published sites after upgrading\nCore to apply these shared preview/static defaults.\n\n### Worked example — the classic feature grid\n\n\"4 cards/row with icon-on-top on desktop, 2/row with icon-left on a landscape\niPad, 1/row icon-on-top on a phone\":\n\n1. `core/grid` containing `core/icon_box` cards (or a `core/repeater` with\n `item_block: core/icon_box` for a Page-driven list).\n2. On the grid: `cols = { mobile: 1, tablet: 2, desktop: 4 }`.\n3. On each icon_box (or the repeater's item defaults):\n `layout = { mobile: \"icon-top\", tablet: \"icon-left\", desktop: \"icon-top\" }`.\n\nNo media queries authored — the build emits per-instance `@media` blocks and\nthe editor preview honours them. Flip the device toggle in the editor header\n(Mobil / Mobil-liggande / iPad / iPad-liggande / Desktop) to author and verify\neach breakpoint.\n\n## Hiding a block at some sizes\n\n`Block.hidden_on: Breakpoint[]` is universal — no per-block opt-in. E.g.\n`hidden_on: [\"mobile\"]` drops the block below 640px. Use it instead of building\na \"mobile-only\" duplicate.\n\n## Authoring a CUSTOM block type that's responsive\n\nTwo halves, BOTH required (`create_block_type` / `update_block_type`):\n\n1. Mark the field `responsive: true`.\n2. Expose it on the **outermost** template element as a CSS variable:\n `style=\"--{field}:{{field}}\"`, then read `var(--{field})` in the block CSS.\n\nIf the field's value is directly usable CSS (e.g. `direction: row|column` →\n`flex-direction: var(--direction)`), you're done.\n\nIf it's a friendly **token** that maps to CSS (e.g. `layout: icon-left` →\n`flex-direction: row`), add a `responsive_css` map on the field — otherwise the\nper-breakpoint overrides silently do nothing (a `[style*=\"--field:token\"]`\nselector can't see a `@media` override):\n\n```\n{ name: \"layout\", type: \"select\", options: [\"icon-top\",\"icon-left\"],\n default: \"icon-top\", responsive: true,\n responsive_css: { \"icon-top\": \"--dir: column;\", \"icon-left\": \"--dir: row;\" } }\n```\n\nThen the block CSS reads `flex-direction: var(--dir, column)`.\n\n## Fluid type — usually automatic\n\n`core/heading` and prose already use `clamp()` to scale smoothly between mobile\nand desktop. `core/heading` separates semantic `level` (h1–h6, for SEO) from\nvisual `size` (sm–3xl/auto) — \"h1 but only as big as an h3\" is one field, no\nbreakpoints needed.\n\n## Gotchas\n\n- Setting a value only at `desktop` leaves smaller screens on the field\n *default*, not on your value — set `mobile` too if you want a non-default\n baseline (mobile-first).\n- The editor preview width is approximate on a narrow panel, but the breakpoint\n you're editing is exact. Trust the deployed site / a wider window for `wide`.\n- **Never paper over horizontal overflow with `html,body{overflow-x:hidden}`.**\n Setting `overflow-x:hidden` on `html` forces `overflow-y` to compute as `auto`\n (CSS spec), turning `<html>` into a fixed-height nested scroller — the page\n then won't scroll normally (`window.scrollY` sticks at 0) and renders blank\n below the fold. Instead, find the element that overflows (a fixed width, a\n `transform:rotate` card poking out, a decorative `::before`/`::after`, a grid\n that didn't collapse) and fix THAT element's width / clip it with\n `overflow:hidden` on its own section. Verify with\n `document.documentElement.scrollWidth === clientWidth` at 360–390px.\n- `core/grid` `stack_at` and responsive `data.cols` both compile overrides\n that beat the inline mobile baseline. Verify the computed column count at\n the actual breakpoint; no page CSS workaround should be necessary.\n- Background design reference: `docs/responsive-blocks.md` in the platform repo.\n\n\n## Core 0.2.14 native defaults\n\nUse section/hero as top-level background carriers; their inner content owns the\n20px phone / 28px tablet gutters. Do not add another gutter to main. Section\npadding auto is 48/64/80px at phone/768/1280; heading auto is H1 28/32/36 and\nH2 22/24/24 at a 16px root. Use shared --type-h1…h4, --section-padding,\n--block-gap, --card-padding and --grid-gap tokens for theme overrides.\nNavigation collapses through 1023px and becomes inline at 1024px.\nImages preserve the complete subject with intrinsic height and contain; request\ncover and a ratio explicitly only when cropping is intended. Breadcrumb spacing\nuses --breadcrumbs-before / --breadcrumbs-after. Custom field-list item_html\nreplaces native bullets; core/list marker none supports custom icons.\nPreview and static CSS order is defaults → blocks/instances → site → Page;\nspecificity, inline CSS and !important still apply. Compare without temporary\ncorrective CSS before removing any existing site rules.\n\n\n## Site-specific responsive widths (Core 0.2.28)\n\nThe five names stay the same, but their widths can be set in **Site settings →\nTypography → Responsive block widths**, or through `update_site_settings`:\n\n```json\n{\"responsive_breakpoints\":{\"tablet\":576,\"laptop\":769,\"desktop\":1024,\"wide\":1280}}\n```\n\nSend all four increasing integer widths (320–2560px); `null` restores\n640/1024/1280/1536px. Values are versioned with the site's settings. Responsive\nblock fields, repeater item overrides and `hidden_on` use these widths in the\neditor preview and static output. Reload an open editor after changing them.\nRepublish to update live pages; changing widths invalidates rendered-page caches.\n\nThis does not change explicit menu `collapse_below`, grid `stack_at`, listing\nmobile defaults or theme typography thresholds. Set the menu threshold separately\nwhen it must match, and use explicit responsive `cols` for exact listing columns.\nCheck one pixel below and at each threshold, including fractional widths for\nvisibility. Do not hide layout overflow to make a test pass.\n\n## Independent components (candidate capability 0.48.0)\n\nNot available in Core 0.2.31. Read capabilities and the live block registry first.\nEvery core block accepts `data.responsive_breakpoints` with all four increasing\nintegers (320–2560); null restores Site widths. It affects only that block's\nresponsive fields/visibility, not children. Listing grid and item cards are\nindependent: put card widths in `item_overrides.responsive_breakpoints`.\n\nA checklist card can use widths `{tablet:577,laptop:769,desktop:1041,wide:1440}`,\n`layout:{mobile:\"column\",desktop:\"row\"}`, `image_width_percent:40`,\n`image_sizing:{mobile:\"fixed\",desktop:\"stretch\"}`, `image_height_px:200`, and\nexplicit `image_fit:\"cover\"`. Intrinsic ignores pixel height; auto preserves it.\nUse stretch only for row layouts. Border, x/y panel padding, background and\n`title_font` are native fields. `action_label` no longer removes the title link;\n`title_link:false` opts out. Secondary actions prevent whole-card overlays.\n\nPDF styling is independent: `download_width:{mobile:\"full\",desktop:\"fill\"}`,\n`download_size_px:13`, `download_weight:\"700\"`, `download_color`,\n`download_border_width_px`, `download_radius_px`, `download_padding_x_px` and\n`download_padding_y_px`. `actions_align:\"center\"` centers the action row.\n`download_behavior:\"download\"` emits HTML download; cross-origin file hosts may\nstill cause browser navigation. Default is navigate, no proxy.\n\nColumns expose `left_width_px:150` and `stack_below_px:481` (stack through480).\nSet one fixed side; left wins if both set. Custom stacking overrides the preset.\nContainer `radius_px` and `shadow` (none/subtle/header) style a composed group.\nMenus use matching SVG symbols; `close_size_px` overrides the close symbol size\nwithout shrinking the44px hit area. Compare exact threshold boundaries in real\npreview and static output before deleting corrective CSS.\n\n## Native image framing and body heading scales (Core 0.2.35+)\n\nUse `core/image.scale_percent` (100–200, responsive) for deliberate horizontal\nframing; 100 retains the uncropped original. `focal_x`/`focal_y` are percentage\npositions; Image `fit`/`aspect_ratio` and Post Card `image_fit`/`image_aspect` are\nresponsive. Keep intrinsic dimensions and original SVG/alt. A mobile 120% centered\nimage uses scale_percent={mobile:120,tablet:100}, focal_x=50 and local\nresponsive_breakpoints={tablet:577,laptop:769,desktop:1024,wide:1280}.\n\nSet `h1_size_px`…`h6_size_px` on `template_content_slot`, not every Page heading.\nThese responsive values inherit through nested containers; explicit font_size_px\non a heading wins. `heading_before_px`/`heading_after_px` control article-rhythm\nspacing. The slot's local breakpoint map controls its scale. Breadcrumbs flow as\ninline ordered-list items, including long current titles. Do not shorten customer\nheadings to compensate for a layout issue. Read the deployed block schema first.\n\n## Native text links (Core 0.2.36+)\n\nInline links in native rich-text surfaces (including lists, tables and image\ncaptions) are underlined and keyboard-focusable by default. Use native fields;\ndo not add customer CSS patches just to restore recognizable text links. Card\ntitles, image wrappers, buttons and navigation retain their own styles. Republish\nexisting sites to adopt the updated renderer.\n",
|
|
24
24
|
"tr-seo": "---\nname: tr-seo\ndescription: Use when the user asks to improve SEO, fix meta tags, add structured data, check page titles, or audit the site's search visibility. Triggers on \"SEO\", \"meta descriptions\", \"Google ranking\", \"structured data\", \"JSON-LD\", \"sitemap\", \"sökoptimering\", or \"hjälp mig synas på Google\".\n---\n\n# SEO audit and improvements for a Typeroll site\n\n> **The buffer model (draft writes).** Every content write in this recipe\n> (pages, blocks and partials) lands in an unsaved per-doc\n> DRAFT — deploys and plain previews only see SAVED content. For recipe-style\n> build work, pass `save: true` on write calls (the work is pre-approved by\n> the task itself), or run `commit_working_copy` per doc before any\n> `trigger_deploy`. Preview your drafts with `include_working_copy: true`.\n\n\n## What Typeroll handles automatically\n\n- `<html lang>` from site `language` setting (per-page override via `language` field)\n- `<title>` = `page.seo_title || page.title + settings.default_seo_suffix`\n- `<meta name=\"description\">` from `page.seo_description`\n- `<meta name=\"robots\">` from `page.noindex`\n- `<meta property=\"og:*\">` Open Graph tags from seo_title, seo_description, og_image\n- `<link rel=\"canonical\">` from `page.canonical_url` (falls back to the page's own URL)\n- Article schema from `kind: \"article\"` + `author` + `date_published`\n- Page schema from `kind: \"page\"` (default)\n- `robots.txt` from `settings.robots_txt`\n- Sanitized HTML that preserves semantic structure\n\n## Recipe\n\n### 1. Audit current state\n\n```\nlist_pages status=\"all\"\nread_site_settings\n```\n\nFor each page, check:\n- Is `seo_title` set? (if not, Google uses `title` + suffix — often fine)\n- Is `seo_description` set? (150–160 chars, unique per page, includes keywords)\n- Is `og_image` set for the homepage and key landing pages?\n- Does the page have exactly one `<h1>`?\n\n### 2. Fix missing meta descriptions\n\n```\nbatch_update_pages updates=[\n {page_id: \"home\", patch: {seo_description: \"Acme designar rum...\"}},\n {page_id: \"om-oss\", patch: {seo_description: \"Vi är ett...\"}},\n {page_id: \"tjanster\", patch: {seo_description: \"Våra tjänster...\"}}\n]\n```\n\nGuidelines:\n- 150–160 characters\n- Include the most important keyword naturally\n- Make it a compelling reason to click, not a summary of the page's nav\n\n### 3. Fix page titles\n\nSEO title = what Google shows in search results.\n\nIf `settings.default_seo_suffix` is set (e.g. \" — Acme Studio\"), every\npage whose `seo_title` is empty will show `title + suffix`. That's usually\nfine for inner pages; set an explicit `seo_title` only when you want\nsomething different.\n\n```\nupdate_site_settings {\"default_seo_suffix\": \" — Acme Studio\"}\n\n# Set the canonical URL style once per site. Existing sites default to `always`.\nupdate_site_settings {\"trailing_slash\": \"always\"}\n\n# A page that must keep its exact campaign/title text can opt out.\nupdate_page {\"page_id\": \"campaign\", \"patch\": {\"append_seo_suffix\": false}, \"save\": true}\n\nupdate_page page_id=\"home\" patch={\n \"seo_title\": \"Acme Studio — Inredningsdesign i Stockholm\"\n}\n```\n\n### 4. Add Open Graph images\n\nSet `og_image` on pages that get shared on social media. If the site has\na branded hero image, upload it:\n\n```\nupload_media_from_url url=\"https://...\" alt=\"Acme Studio — Inredningsdesign\"\n# → returns cdn_url\n\nbatch_update_pages updates=[\n {page_id: \"home\", patch: {og_image: \"<cdn_url>\"}},\n {page_id: \"om-oss\", patch: {og_image: \"<cdn_url>\"}}\n]\n```\n\nOG image dimensions: 1200×630px ideal. The platform doesn't resize —\nuse a correctly-sized source image.\n\n### 5. Add structured data (JSON-LD)\n\nTyperoll auto-generates Article and Page schema, but you can override or\nextend with custom JSON-LD per page. Example: LocalBusiness on the homepage.\n\n```\nupdate_page page_id=\"home\" patch={\n \"json_ld\": \"{\\\"@context\\\":\\\"https://schema.org\\\",\\\"@type\\\":\\\"LocalBusiness\\\",\\\"name\\\":\\\"Acme Studio\\\",\\\"url\\\":\\\"https://acme.se\\\",\\\"telephone\\\":\\\"+46812345\\\",\\\"address\\\":{\\\"@type\\\":\\\"PostalAddress\\\",\\\"streetAddress\\\":\\\"Drottninggatan 1\\\",\\\"addressLocality\\\":\\\"Stockholm\\\",\\\"postalCode\\\":\\\"111 51\\\",\\\"addressCountry\\\":\\\"SE\\\"}}\"\n}\n```\n\n**Important:** JSON-LD goes in the `json_ld` field as a JSON *string*\n(not a nested object). The renderer injects it inside\n`<script type=\"application/ld+json\">`.\n\nCommon schemas worth adding:\n- Homepage: `LocalBusiness` or `Organization`\n- About: `AboutPage`\n- Contact: `ContactPage`\n- Blog articles: auto-generated from `kind:\"article\"` + `author`\n- Events: `Event` with `startDate`, `location`\n- Products: `Product` with `offers`\n\n### 6. robots.txt\n\nThe default robots.txt allows all crawlers. Update if needed:\n\n```\nupdate_site_settings {\n \"robots_txt\": \"User-agent: *\\nAllow: /\\nSitemap: https://acme.se/sitemap.xml\"\n}\n```\n\nTyperoll doesn't generate a sitemap automatically in phase 1. If the\ncustomer needs one, create a `/sitemap` page with HTML that lists all\npublished pages, or write a static `sitemap.xml` as a page with\n`slug: \"sitemap.xml\"` and HTML-encoded XML (not recommended for large sites).\n\n### 7. Canonical URLs\n\nSet `canonical_url` when a page has a duplicate (e.g. the same content\naccessible via two slugs after a migration):\n\n```\nupdate_page page_id=\"tjansterna\" patch={\n \"canonical_url\": \"https://acme.se/tjanster\",\n \"noindex\": true\n}\n```\n\n### 8. Language settings\n\n```\nupdate_site_settings {\"language\": \"sv\"}\n```\n\nPer-page override for multilingual content:\n```\nupdate_page page_id=\"about-en\" patch={\"language\": \"en\"}\n```\n\n### 9. Heading audit\n\nUse `search_pages` to find structural problems:\n\n```\nsearch_pages contains=\"<h1\" # pages that have at least one H1\n```\n\nThen `read_page` on pages that seem to have none or multiple. Fix via\n`update_page patch={html_content: \"<corrected HTML>\"}`.\n\n### 10. Deploy\n\n```\ntrigger_deploy\nget_deploy_status job_id=<id>\n```\n\n## Pitfalls\n\n- **Don't stuff keywords.** Write descriptions for humans. Google ignores\n `<meta name=\"keywords\">` (not a field in Typeroll anyway).\n- **JSON-LD is a string, not a nested field.** Pass the entire schema as\n a JSON-encoded string in `json_ld`. The server escapes `</script` before\n injection.\n- **OG images need absolute URLs.** The `cdn.typeroll.com` URLs are always\n absolute — use those.\n- **`canonical_url` + `noindex` together.** If you noindex a page AND set\n canonical, the canonical is redundant (noindexed pages don't pass equity).\n Use one or the other.\n- **Default suffix on homepage looks odd.** \"Acme Studio — Acme Studio\"\n happens when title=\"Acme Studio\" and suffix=\" — Acme Studio\". Set an\n explicit `seo_title` for the homepage.\n"
|
|
25
25
|
};
|
|
26
26
|
export const BUNDLED_DOCS = {
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
package/skills/tr-responsive.md
CHANGED
|
@@ -213,3 +213,11 @@ on a heading wins. `heading_before_px`/`heading_after_px` control article-rhythm
|
|
|
213
213
|
spacing. The slot's local breakpoint map controls its scale. Breadcrumbs flow as
|
|
214
214
|
inline ordered-list items, including long current titles. Do not shorten customer
|
|
215
215
|
headings to compensate for a layout issue. Read the deployed block schema first.
|
|
216
|
+
|
|
217
|
+
## Native text links (Core 0.2.36+)
|
|
218
|
+
|
|
219
|
+
Inline links in native rich-text surfaces (including lists, tables and image
|
|
220
|
+
captions) are underlined and keyboard-focusable by default. Use native fields;
|
|
221
|
+
do not add customer CSS patches just to restore recognizable text links. Card
|
|
222
|
+
titles, image wrappers, buttons and navigation retain their own styles. Republish
|
|
223
|
+
existing sites to adopt the updated renderer.
|