From a25f12875abb9aa4c2b0399514b7824cde03ae40 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Fri, 17 Jul 2026 15:10:09 +0200 Subject: [PATCH 01/55] Rework API reference Endpoint to use standard code blocks The Endpoint component now delegates request and response code to the site's standard Tabs and CodeBlock components instead of re-rendering code passed as props. This restores syntax highlighting, native copy/wrap/Ask AI buttons, and status tabs consistent with the rest of the site. Only the first REST endpoint is migrated so far. --- docusaurus/docs/cms/api/rest.md | 108 ++++----- .../src/components/ApiReference/CodePanel.jsx | 69 ------ .../ApiReference/CopyCodeButton.jsx | 44 ---- .../src/components/ApiReference/Endpoint.jsx | 107 +++------ .../components/ApiReference/ResponsePanel.jsx | 100 -------- .../src/components/ApiReference/Responses.jsx | 65 +++++ .../ApiReference/api-reference.module.scss | 223 ++++++++++++------ .../src/components/ApiReference/index.js | 3 +- docusaurus/src/theme/MDXComponents.js | 3 + 9 files changed, 309 insertions(+), 413 deletions(-) delete mode 100644 docusaurus/src/components/ApiReference/CodePanel.jsx delete mode 100644 docusaurus/src/components/ApiReference/CopyCodeButton.jsx delete mode 100644 docusaurus/src/components/ApiReference/ResponsePanel.jsx create mode 100644 docusaurus/src/components/ApiReference/Responses.jsx diff --git a/docusaurus/docs/cms/api/rest.md b/docusaurus/docs/cms/api/rest.md index e2f67be0a0..f04023c5e7 100644 --- a/docusaurus/docs/cms/api/rest.md +++ b/docusaurus/docs/cms/api/rest.md @@ -152,18 +152,21 @@ You can pass an optional header while you're migrating to Strapi 5 (see the [rel { name: 'locale', type: 'string', required: false, description: 'Locale of the documents to fetch. See locale.' }, { name: 'status', type: 'string', required: false, description: 'published or draft. See status.' }, { name: 'publicationFilter', type: 'string', required: false, description: 'Query documents by the relationship between their draft and published versions. See publicationFilter.' }, - ]} - codePath="/api/restaurants" - codePathHighlights={['restaurants']} - codeTabs={[ - { - label: 'cURL', - code: `curl 'http://localhost:1337/api/restaurants' \\ - -H 'Authorization: Bearer '`, - }, - { - label: 'JavaScript', - code: `const response = await fetch( + ]}> + + + + +```bash +curl 'http://localhost:1337/api/restaurants' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const response = await fetch( 'http://localhost:1337/api/restaurants', { headers: { @@ -171,49 +174,48 @@ You can pass an optional header while you're migrating to Strapi 5 (see the [rel }, } ); -const data = await response.json();`, - }, - ]} - responses={[ +const data = await response.json(); +``` + + + + + + + +```json +{ + "data": [ { - status: 200, - statusText: 'OK', - time: '23ms', - body: JSON.stringify({ - data: [ - { - id: 2, - documentId: "hgv1vny5cebq2l3czil1rpb3", - Name: "BMK Paris Bamako", - Description: null, - createdAt: "2024-03-06T13:42:05.098Z", - updatedAt: "2024-03-06T13:42:05.098Z", - publishedAt: "2024-03-06T13:42:05.103Z", - locale: "en" - }, - { - id: 4, - documentId: "znrlzntu9ei5onjvwfaalu2v", - Name: "Biscotte Restaurant", - Description: [ - { - type: "paragraph", - children: [{ type: "text", text: "Welcome to Biscotte restaurant! Restaurant Biscotte offers a cuisine based on fresh, quality products, often local, organic when possible, and always produced by passionate producers." }] - } - ], - createdAt: "2024-03-06T13:43:30.172Z", - updatedAt: "2024-03-06T13:43:30.172Z", - publishedAt: "2024-03-06T13:43:30.175Z", - locale: "en" - } - ], - meta: { - pagination: { page: 1, pageSize: 25, pageCount: 1, total: 2 } - } - }, null, 2), + "id": 2, + "documentId": "hgv1vny5cebq2l3czil1rpb3", + "Name": "BMK Paris Bamako", + "Description": null, + "createdAt": "2024-03-06T13:42:05.098Z", + "updatedAt": "2024-03-06T13:42:05.098Z", + "publishedAt": "2024-03-06T13:42:05.103Z", + "locale": "en" }, - ]} -/> + { + "id": 4, + "documentId": "znrlzntu9ei5onjvwfaalu2v", + "Name": "Biscotte Restaurant", + "createdAt": "2024-03-06T13:43:30.172Z", + "updatedAt": "2024-03-06T13:43:30.172Z", + "publishedAt": "2024-03-06T13:43:30.175Z", + "locale": "en" + } + ], + "meta": { + "pagination": { "page": 1, "pageSize": 25, "pageCount": 1, "total": 2 } + } +} +``` + + + + + ### Get a document {#get} diff --git a/docusaurus/src/components/ApiReference/CodePanel.jsx b/docusaurus/src/components/ApiReference/CodePanel.jsx deleted file mode 100644 index 62ef38200f..0000000000 --- a/docusaurus/src/components/ApiReference/CodePanel.jsx +++ /dev/null @@ -1,69 +0,0 @@ -import React, { useState } from 'react'; -import CopyCodeButton from './CopyCodeButton'; -import styles from './api-reference.module.scss'; -import clsx from 'clsx'; - -/** - * CodePanel with language tabs and URL bar. - * - * Usage: - * - */ -export default function CodePanel({ kind = 'http', method = 'GET', path, pathHighlights = [], tabs = [] }) { - const [activeTab, setActiveTab] = useState(0); - const methodKey = method.toUpperCase() === 'DELETE' ? 'del' : method.toLowerCase(); - const displayMethod = method.toUpperCase() === 'DELETE' ? 'DEL' : method.toUpperCase(); - const isJs = kind === 'js'; - - // Highlight path params - const renderPath = (p) => { - if (!p) return null; - let result = p; - pathHighlights.forEach(h => { - result = result.replace(h, `${h}`); - }); - // Also highlight :param patterns - result = result.replace(/:(\w+)/g, `:$1`); - return ; - }; - - return ( -
- {tabs.length > 1 && ( -
- {tabs.map((tab, i) => ( - setActiveTab(i)} - > - {tab.label} - - ))} -
- )} - {path && !isJs && ( -
- - {displayMethod} - - {renderPath(path)} -
- )} -
- -
-          {tabs[activeTab]?.code || ''}
-        
-
-
- ); -} diff --git a/docusaurus/src/components/ApiReference/CopyCodeButton.jsx b/docusaurus/src/components/ApiReference/CopyCodeButton.jsx deleted file mode 100644 index 50571bdaf8..0000000000 --- a/docusaurus/src/components/ApiReference/CopyCodeButton.jsx +++ /dev/null @@ -1,44 +0,0 @@ -import React, { useState, useCallback } from 'react'; -import styles from './api-reference.module.scss'; -import clsx from 'clsx'; - -/** - * Self-contained copy button for the API reference code/response panels. - * - * The Docusaurus @theme/CodeBlock/CopyButton only renders correctly inside a - * real (it depends on that component's CSS modules for sizing and - * icons). Used standalone it collapses to a 0x0 element. This button owns its - * own markup and styles, so it works anywhere. - */ -export default function CopyCodeButton({ code = '' }) { - const [copied, setCopied] = useState(false); - - const onCopy = useCallback(() => { - if (!code) return; - navigator.clipboard.writeText(code).then(() => { - setCopied(true); - setTimeout(() => setCopied(false), 2000); - }); - }, [code]); - - return ( - - ); -} diff --git a/docusaurus/src/components/ApiReference/Endpoint.jsx b/docusaurus/src/components/ApiReference/Endpoint.jsx index 36301ab44e..b72820775d 100644 --- a/docusaurus/src/components/ApiReference/Endpoint.jsx +++ b/docusaurus/src/components/ApiReference/Endpoint.jsx @@ -3,38 +3,37 @@ import useBrokenLinks from '@docusaurus/useBrokenLinks'; import styles from './api-reference.module.scss'; import MethodPill from './MethodPill'; import ParamTable from './ParamTable'; -import CodePanel from './CodePanel'; -import ResponsePanel from './ResponsePanel'; /** - * Full 2-column endpoint block matching the V3 mockup. + * 2-column endpoint block. * - * Usage (HTTP / REST): - * + * The component only owns what's specific to an API endpoint — the method pill, + * the URL, the description, and the parameter table. The actual code (request + * examples and responses) is passed as CHILDREN and rendered by the site's + * standard Tabs + CodeBlock components, exactly like every other code block on + * the site. This is why syntax highlighting and the copy / wrap / Ask AI + * buttons are identical here: they *are* the standard code blocks. * - * Usage (JS API — Document Service, etc.): pass kind="js". This hides the HTTP - * method pill and the URL bar, renders `path` as the JS method signature, and - * labels the result "Returns" instead of an HTTP status. A JS call has no HTTP - * verb and no HTTP status, so the http chrome is suppressed. - * + * Authoring (see docs for full example): + * + * + * + * + * ```bash + * curl … + * ``` + * + * + * + * + * + * ```json + * { … } + * ``` + * + * + * */ export default function Endpoint({ id, @@ -45,25 +44,19 @@ export default function Endpoint({ description, params = [], paramTitle = 'Parameters', - codeTabs = [], - codePath, - codePathHighlights = [], - responses = [], - collapsibleResponse = false, isLast = false, children, }) { useBrokenLinks().collectAnchor(id); - const hasColumns = (params.length > 0 || children) && (codeTabs.length > 0 || responses.length > 0); const isJs = kind === 'js'; + const hasParams = params.length > 0; return (
- {/* Header: full-width, above the 2-column grid */}
{isJs ? ( @@ -71,53 +64,23 @@ export default function Endpoint({ ) : ( <> - - {path} - + {path} )}
+ {title &&

{title}

} {description &&

{description}

}
- {/* 2-column grid: params left, code right */} - {hasColumns ? ( + {hasParams ? (
- {params.length > 0 && } - {children} -
-
- {codeTabs.length > 0 && ( - - )} - {responses.length > 0 && } +
+
{children}
) : ( - /* Fallback: no params, just code below the header */ - <> - {(codeTabs.length > 0 || responses.length > 0) && ( -
- {codeTabs.length > 0 && ( - - )} - {responses.length > 0 && } -
- )} - {children &&
{children}
} - +
{children}
)}
); diff --git a/docusaurus/src/components/ApiReference/ResponsePanel.jsx b/docusaurus/src/components/ApiReference/ResponsePanel.jsx deleted file mode 100644 index 445f1c2901..0000000000 --- a/docusaurus/src/components/ApiReference/ResponsePanel.jsx +++ /dev/null @@ -1,100 +0,0 @@ -import React, { useState } from 'react'; -import CopyCodeButton from './CopyCodeButton'; -import styles from './api-reference.module.scss'; -import clsx from 'clsx'; - -/** - * ResponsePanel with status tabs and animated dot. - * - * Usage: - * - */ -const COLLAPSE_LINE_THRESHOLD = 10; - -export default function ResponsePanel({ kind = 'http', responses = [], collapsible = false }) { - const [activeIdx, setActiveIdx] = useState(0); - const [expanded, setExpanded] = useState(false); - if (!responses.length) return null; - - const isJs = kind === 'js'; - const active = responses[activeIdx]; - const isOk = active.status < 400; - - // Opt-in: collapse long response bodies behind a "Show more" toggle. - const lineCount = active.body ? String(active.body).split('\n').length : 0; - const isCollapsible = collapsible && lineCount > COLLAPSE_LINE_THRESHOLD; - const collapsed = isCollapsible && !expanded; - - const getTabStyle = (status) => { - if (status < 300) return 'response-tab--2xx'; - if (status < 400) return 'response-tab--3xx'; - if (status < 500) return 'response-tab--4xx'; - return 'response-tab--5xx'; - }; - - return ( -
- {!isJs && responses.length > 1 && ( -
- {responses.map((r, i) => ( - setActiveIdx(i)} - > - {r.status} - - ))} -
- )} - -
- {isJs ? ( - - Returns - - ) : ( - <> - - - {active.status} {active.statusText} - - {active.time && {active.time}} - - )} -
- -
-
- -
-            {active.body}
-          
- {collapsed && - {isCollapsible && ( - - )} -
-
- ); -} diff --git a/docusaurus/src/components/ApiReference/Responses.jsx b/docusaurus/src/components/ApiReference/Responses.jsx new file mode 100644 index 0000000000..ab262cabb9 --- /dev/null +++ b/docusaurus/src/components/ApiReference/Responses.jsx @@ -0,0 +1,65 @@ +import React, { Children, isValidElement } from 'react'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import clsx from 'clsx'; +import styles from './api-reference.module.scss'; + +/** + * Response block(s) for an endpoint. + * + * renders the site's standard (one tab per status), so the + * status switcher looks and behaves like every other tab set on the site — and + * the code inside each tab is a standard CodeBlock (identical highlighting and + * copy / wrap / Ask AI buttons). Inside each tab, a colored pulsing dot + label + * (e.g. "200 OK") heads the response, then the code. + * + * wraps one status' code fence. + */ + +function dotClass(status) { + return status < 400 ? styles['responseDot--ok'] : styles['responseDot--err']; +} +function labelClass(status) { + return status < 400 ? styles['responseStatus--ok'] : styles['responseStatus--err']; +} + +export function ResponseTab({ status, statusText = '', children }) { + const s = Number(status); + return ( + <> +
+ + + {s} {statusText} + +
+ {children} + + ); +} + +export default function Responses({ children }) { + const items = Children.toArray(children).filter( + (c) => isValidElement(c) && c.type === ResponseTab, + ); + + // Single response: no tabs needed, just render it. + if (items.length <= 1) { + return
{items}
; + } + + return ( +
+ + {items.map((item, i) => { + const status = Number(item.props.status); + return ( + + {item} + + ); + })} + +
+ ); +} diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss index 6fa52de42a..fe2fe6ee14 100644 --- a/docusaurus/src/components/ApiReference/api-reference.module.scss +++ b/docusaurus/src/components/ApiReference/api-reference.module.scss @@ -412,26 +412,37 @@ &__tabs { display: flex; + align-items: center; border-bottom: 1px solid var(--strapi-border); - padding: 0 4px; + padding: 0 8px 0 4px; background: var(--strapi-surface-2); } &__tab { + appearance: none; + background: transparent; + border: none; + // These tabs are now real )} - {langLabel && ( - {langLabel} - )}
); From d47bdb12caefef64dece66c93ec4415cc88b2db6 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Fri, 17 Jul 2026 16:02:40 +0200 Subject: [PATCH 07/55] Align terminal title-bar action buttons The copy/wrap button group in terminal code blocks was oversized and overflowed the title bar. Size it to match the Ask AI button and align it on the same row, inside the bar. --- docusaurus/src/scss/code-block.scss | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index a5afc17cc3..3d2ae75594 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -384,19 +384,36 @@ pre.prism-code { [class*="buttonGroup"] { position: absolute !important; - top: 9px; - right: 16px; + // The group is anchored to the whole wrapper, so a percentage top would + // center it over the entire block. Use a fixed offset that lands it inside + // the ~50px title bar, vertically aligned with the Ask AI button. + top: 12px; + right: 20px; z-index: 3; display: flex; - gap: 6px; + align-items: center; + gap: 4px; opacity: 1; .clean-btn { background: var(--code-title-bar-lang-bg) !important; position: static !important; top: auto !important; + // Match the Ask AI button's compact size so both align on one row. + display: inline-flex; + align-items: center; + justify-content: center; + width: auto; + height: 26px; + min-height: 0; + padding: 4px 6px; border-radius: var(--strapi-radius-xs); + svg { + width: 15px; + height: 15px; + } + svg, i::before, span { color: var(--code-title-bar-lang-color) !important; opacity: 1 !important; From 0e1cc59e4353aa58568621b21cad411debc5b183 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Fri, 17 Jul 2026 16:11:45 +0200 Subject: [PATCH 08/55] Fix terminal title-bar button alignment Align the copy/wrap button group to the title bar's right padding and reserve space so the Ask AI button sits just left of it, on the same row, without overflowing the bar. --- docusaurus/src/scss/code-block.scss | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index 3d2ae75594..296dc92f30 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -326,10 +326,12 @@ pre.prism-code { border-color: var(--strapi-border-accent); } - // Leave room in the title bar so the wrap/copy button group (positioned into - // it below) doesn't overlap the "Ask AI" button. + // The title bar's content box is inset ~20px from the wrapper edge. Reserve + // room on the right of the actions row (Ask AI) for the absolutely-positioned + // copy/wrap group, which is anchored to the wrapper at right:20px (see below), + // so Ask AI stops just before it with a small gap. .code-title-bar__actions { - margin-right: 76px; + margin-right: 44px; } // The inner .theme-code-block should not have its own border @@ -388,6 +390,8 @@ pre.prism-code { // center it over the entire block. Use a fixed offset that lands it inside // the ~50px title bar, vertically aligned with the Ask AI button. top: 12px; + // 20px = the wrapper→title-bar content inset, so the button's right edge + // aligns with the bar's inner right padding. right: 20px; z-index: 3; display: flex; From 313e753ec4bbc6136ed4a2d0406cff9347e8199d Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Fri, 17 Jul 2026 16:23:19 +0200 Subject: [PATCH 09/55] Match terminal action buttons to standard code block style Style the copy/wrap buttons in terminal code blocks as the same white pill with a neutral border used on regular code blocks, sized and positioned to align with the Ask AI button in both light and dark. --- docusaurus/src/scss/code-block.scss | 39 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index 296dc92f30..24f553e008 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -329,9 +329,10 @@ pre.prism-code { // The title bar's content box is inset ~20px from the wrapper edge. Reserve // room on the right of the actions row (Ask AI) for the absolutely-positioned // copy/wrap group, which is anchored to the wrapper at right:20px (see below), - // so Ask AI stops just before it with a small gap. + // so Ask AI stops just before it with a small gap. Width fits up to two pill + // buttons (wrap + copy) plus gaps. .code-title-bar__actions { - margin-right: 44px; + margin-right: 96px; } // The inner .theme-code-block should not have its own border @@ -387,39 +388,37 @@ pre.prism-code { [class*="buttonGroup"] { position: absolute !important; // The group is anchored to the whole wrapper, so a percentage top would - // center it over the entire block. Use a fixed offset that lands it inside - // the ~50px title bar, vertically aligned with the Ask AI button. - top: 12px; - // 20px = the wrapper→title-bar content inset, so the button's right edge + // center it over the entire block. Use a fixed offset that lands the ~34px + // pill buttons inside the ~50px title bar, aligned with the Ask AI button. + top: 8px; + // 20px = the wrapper→title-bar content inset, so the group's right edge // aligns with the bar's inner right padding. right: 20px; z-index: 3; display: flex; align-items: center; - gap: 4px; + gap: 8px; opacity: 1; + // Match the regular (non-terminal) code block buttons exactly: white pill + // with a neutral border, so terminal blocks are visually identical to the + // rest of the site. Only reset positioning + restore the pill chrome; leave + // the icon color to the default so it inverts correctly in dark mode. .clean-btn { - background: var(--code-title-bar-lang-bg) !important; position: static !important; top: auto !important; - // Match the Ask AI button's compact size so both align on one row. display: inline-flex; align-items: center; justify-content: center; - width: auto; - height: 26px; - min-height: 0; - padding: 4px 6px; - border-radius: var(--strapi-radius-xs); - - svg { - width: 15px; - height: 15px; - } + padding: 6.4px; + background: var(--strapi-neutral-0) !important; + border: 1px solid var(--strapi-neutral-200) !important; + border-radius: var(--strapi-radius-md) !important; svg, i::before, span { - color: var(--code-title-bar-lang-color) !important; + // Theme-aware icon color so it stays legible in dark mode (a legacy + // rule forces black, which vanishes on the dark pill). + color: var(--strapi-fg-1) !important; opacity: 1 !important; } } From d19138199ae6a95310167265052c3778f0893eae Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Mon, 20 Jul 2026 11:49:07 +0200 Subject: [PATCH 10/55] Group terminal action buttons in the title bar Move the native copy/wrap button group into the title bar's actions row via the CodeBlockWrapper effect, so Ask AI, wrap, and copy sit in one flex row and align naturally without brittle absolute positioning. Style all three as the same white pill used on regular code blocks. --- docusaurus/src/scss/code-block.scss | 65 ++++++++++--------------- docusaurus/src/theme/CodeBlock/index.js | 20 ++++++++ 2 files changed, 45 insertions(+), 40 deletions(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index 24f553e008..38e6de1f75 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -255,33 +255,33 @@ pre.prism-code { } } - // AI button inside the title bar + // AI button inside the title bar — same white pill as the copy/wrap buttons + // and the Ask AI button on regular code blocks, so all actions match. .ai-button { - padding: 4px 8px; - display: flex; + display: inline-flex; align-items: center; - gap: 4px; + gap: 6px; + height: 34px; + padding: 0 10px; font-size: 11px; font-weight: 600; - border-radius: var(--strapi-radius-xs); + border-radius: var(--strapi-radius-md) !important; cursor: pointer; transition: all var(--strapi-duration-fast) var(--strapi-ease); - min-height: auto; - opacity: 0.6; - background: transparent; + background: var(--strapi-neutral-0) !important; + border: 1px solid var(--strapi-neutral-200) !important; &:hover { - opacity: 1; - background: var(--code-title-bar-lang-bg); + border-color: var(--strapi-border-accent) !important; } i { font-size: 12px; - color: var(--code-title-bar-lang-color); + color: var(--strapi-primary-500); } span { - color: var(--code-title-bar-lang-color); + color: var(--strapi-fg-1); } } } @@ -326,13 +326,13 @@ pre.prism-code { border-color: var(--strapi-border-accent); } - // The title bar's content box is inset ~20px from the wrapper edge. Reserve - // room on the right of the actions row (Ask AI) for the absolutely-positioned - // copy/wrap group, which is anchored to the wrapper at right:20px (see below), - // so Ask AI stops just before it with a small gap. Width fits up to two pill - // buttons (wrap + copy) plus gaps. + // Ask AI + the relocated copy/wrap group share this one flex row, so they + // align naturally with no absolute positioning (the buttons are moved into + // here by CodeBlockWrapper's relocateButtons effect). .code-title-bar__actions { - margin-right: 96px; + display: flex; + align-items: center; + gap: 8px; } // The inner .theme-code-block should not have its own border @@ -376,25 +376,10 @@ pre.prism-code { } } - // Docusaurus copy/wrap buttons: pull them up into the title bar (top-right), - // next to the Ask AI button, instead of floating over the code. Anchor the - // absolute group to the wrapper (not the inner code content) by neutralizing - // the code container's positioning context. - [class*="codeBlockContent"], - [class*="codeBlockContainer"] { - position: static !important; - } - + // The copy/wrap button group is moved into .code-title-bar__actions (see + // CodeBlockWrapper). It flows inline there — no absolute positioning. [class*="buttonGroup"] { - position: absolute !important; - // The group is anchored to the whole wrapper, so a percentage top would - // center it over the entire block. Use a fixed offset that lands the ~34px - // pill buttons inside the ~50px title bar, aligned with the Ask AI button. - top: 8px; - // 20px = the wrapper→title-bar content inset, so the group's right edge - // aligns with the bar's inner right padding. - right: 20px; - z-index: 3; + position: static !important; display: flex; align-items: center; gap: 8px; @@ -402,22 +387,22 @@ pre.prism-code { // Match the regular (non-terminal) code block buttons exactly: white pill // with a neutral border, so terminal blocks are visually identical to the - // rest of the site. Only reset positioning + restore the pill chrome; leave - // the icon color to the default so it inverts correctly in dark mode. + // rest of the site. Leave the icon color to the default so it inverts + // correctly in dark mode. .clean-btn { position: static !important; top: auto !important; display: inline-flex; align-items: center; justify-content: center; + width: 34px; + height: 34px; padding: 6.4px; background: var(--strapi-neutral-0) !important; border: 1px solid var(--strapi-neutral-200) !important; border-radius: var(--strapi-radius-md) !important; svg, i::before, span { - // Theme-aware icon color so it stays legible in dark mode (a legacy - // rule forces black, which vanishes on the dark pill). color: var(--strapi-fg-1) !important; opacity: 1 !important; } diff --git a/docusaurus/src/theme/CodeBlock/index.js b/docusaurus/src/theme/CodeBlock/index.js index bc7bb59f49..cb68422675 100644 --- a/docusaurus/src/theme/CodeBlock/index.js +++ b/docusaurus/src/theme/CodeBlock/index.js @@ -136,8 +136,28 @@ export default function CodeBlockWrapper(props) { // Inject a real DOM cursor element into terminal blocks // (CSS ::after pseudo-elements get their background overridden by parent rules) const terminalRef = useRef(null); + + // Terminal blocks render their own title bar (with the Ask AI button) as a + // sibling of the Docusaurus code block, while the native copy/wrap buttons + // live deep inside the code block. Rather than align the two across separate + // DOM subtrees with brittle absolute positioning, physically MOVE the native + // button group into the title bar's actions container so Ask AI + wrap + copy + // sit in one flex row and align naturally. + const relocateButtons = useCallback((wrapper) => { + if (!wrapper) return; + const move = () => { + const actions = wrapper.querySelector('.code-title-bar__actions'); + const group = wrapper.querySelector('[class*="buttonGroup"]'); + if (!actions || !group) return; + if (group.parentElement === actions) return; // already moved + actions.appendChild(group); + }; + requestAnimationFrame(() => requestAnimationFrame(move)); + }, []); + const injectCursor = useCallback((node) => { terminalRef.current = node; + if (node) relocateButtons(node); if (!node) return; // Find the last token line and append a real cursor span From a97336c2ebc129fb4cb82fe5dd1d8fdef8885458 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Mon, 20 Jul 2026 11:54:24 +0200 Subject: [PATCH 11/55] Reveal terminal action buttons on hover only Hide the Ask AI / wrap / copy buttons in terminal code blocks at rest and reveal them on hover or focus of the block, matching the behavior of regular code blocks. --- docusaurus/src/scss/code-block.scss | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index 38e6de1f75..0065758f68 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -328,11 +328,19 @@ pre.prism-code { // Ask AI + the relocated copy/wrap group share this one flex row, so they // align naturally with no absolute positioning (the buttons are moved into - // here by CodeBlockWrapper's relocateButtons effect). + // here by CodeBlockWrapper's relocateButtons effect). Hidden at rest, shown + // on hover/focus of the block — same behavior as regular code blocks. .code-title-bar__actions { display: flex; align-items: center; gap: 8px; + opacity: 0; + transition: opacity var(--strapi-duration-fast) var(--strapi-ease); + } + + &:hover .code-title-bar__actions, + &:focus-within .code-title-bar__actions { + opacity: 1; } // The inner .theme-code-block should not have its own border @@ -383,7 +391,8 @@ pre.prism-code { display: flex; align-items: center; gap: 8px; - opacity: 1; + // Visibility is controlled by the parent .code-title-bar__actions + // (hidden at rest, shown on hover), so don't force opacity here. // Match the regular (non-terminal) code block buttons exactly: white pill // with a neutral border, so terminal blocks are visually identical to the From 3e0eeff2f2dff46dabd936b6e4a453e8d5911395 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Mon, 20 Jul 2026 12:03:40 +0200 Subject: [PATCH 12/55] Revert "Reveal terminal action buttons on hover only" This reverts commit a97336c2ebc129fb4cb82fe5dd1d8fdef8885458. --- docusaurus/src/scss/code-block.scss | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index 0065758f68..38e6de1f75 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -328,19 +328,11 @@ pre.prism-code { // Ask AI + the relocated copy/wrap group share this one flex row, so they // align naturally with no absolute positioning (the buttons are moved into - // here by CodeBlockWrapper's relocateButtons effect). Hidden at rest, shown - // on hover/focus of the block — same behavior as regular code blocks. + // here by CodeBlockWrapper's relocateButtons effect). .code-title-bar__actions { display: flex; align-items: center; gap: 8px; - opacity: 0; - transition: opacity var(--strapi-duration-fast) var(--strapi-ease); - } - - &:hover .code-title-bar__actions, - &:focus-within .code-title-bar__actions { - opacity: 1; } // The inner .theme-code-block should not have its own border @@ -391,8 +383,7 @@ pre.prism-code { display: flex; align-items: center; gap: 8px; - // Visibility is controlled by the parent .code-title-bar__actions - // (hidden at rest, shown on hover), so don't force opacity here. + opacity: 1; // Match the regular (non-terminal) code block buttons exactly: white pill // with a neutral border, so terminal blocks are visually identical to the From 7907d729a832f495a3c94da9daa2b17880ebd192 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Mon, 20 Jul 2026 12:08:18 +0200 Subject: [PATCH 13/55] Reveal terminal action buttons on hover, keep them opaque Fade the whole title-bar actions row in on block hover/focus while forcing the individual buttons to full opacity, so the copy button no longer disappears (the legacy .clean-btn opacity:0.6 was making it vanish at rest and fight the reveal). --- docusaurus/src/scss/code-block.scss | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index 38e6de1f75..b3d4816099 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -268,6 +268,8 @@ pre.prism-code { border-radius: var(--strapi-radius-md) !important; cursor: pointer; transition: all var(--strapi-duration-fast) var(--strapi-ease); + // Stays opaque; the actions row handles the hover fade. + opacity: 1 !important; background: var(--strapi-neutral-0) !important; border: 1px solid var(--strapi-neutral-200) !important; @@ -328,11 +330,19 @@ pre.prism-code { // Ask AI + the relocated copy/wrap group share this one flex row, so they // align naturally with no absolute positioning (the buttons are moved into - // here by CodeBlockWrapper's relocateButtons effect). + // here by CodeBlockWrapper's relocateButtons effect). Hidden at rest, shown + // when the whole block is hovered/focused — same as regular code blocks. .code-title-bar__actions { display: flex; align-items: center; gap: 8px; + opacity: 0; + transition: opacity var(--strapi-duration-fast) var(--strapi-ease); + } + + &:hover .code-title-bar__actions, + &:focus-within .code-title-bar__actions { + opacity: 1; } // The inner .theme-code-block should not have its own border @@ -398,6 +408,9 @@ pre.prism-code { width: 34px; height: 34px; padding: 6.4px; + // The button itself stays fully opaque; the whole actions row is what + // fades in/out on hover. Overrides the legacy .clean-btn opacity:0.6. + opacity: 1 !important; background: var(--strapi-neutral-0) !important; border: 1px solid var(--strapi-neutral-200) !important; border-radius: var(--strapi-radius-md) !important; From 3277b4c2803f03040687fa80a5e9dd6a9324f66b Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Mon, 20 Jul 2026 12:21:13 +0200 Subject: [PATCH 14/55] Fix code block action button hover and rest states On hover the Ask AI button now only darkens its label and icon (no background/border change) on both terminal and regular code blocks. The terminal copy/wrap icons are dimmed at rest (opacity 0.6) and go full opacity on hover, matching the reference buttons instead of showing solid black at rest. --- docusaurus/src/scss/code-block.scss | 38 ++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index b3d4816099..d9d95de1eb 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -273,10 +273,6 @@ pre.prism-code { background: var(--strapi-neutral-0) !important; border: 1px solid var(--strapi-neutral-200) !important; - &:hover { - border-color: var(--strapi-border-accent) !important; - } - i { font-size: 12px; color: var(--strapi-primary-500); @@ -285,6 +281,21 @@ pre.prism-code { span { color: var(--strapi-fg-1); } + + // On hover only darken the label + icon; keep background and border as-is. + // The button also carries the `clean-btn` class, whose legacy :hover would + // otherwise tint the background grey — override it explicitly. + &:hover { + background: var(--strapi-neutral-0) !important; + + i { + color: var(--strapi-primary-700) !important; + } + + span { + color: var(--strapi-neutral-800) !important; + } + } } } @@ -415,8 +426,18 @@ pre.prism-code { border: 1px solid var(--strapi-neutral-200) !important; border-radius: var(--strapi-radius-md) !important; + // Match the reference copy/wrap buttons: the icon is dimmed at rest + // (opacity 0.6) and goes full opacity on hover — this is what makes it + // look grey rather than solid black. !important beats the legacy + // opacity:1 rules on .clean-btn icons. svg, i::before, span { color: var(--strapi-fg-1) !important; + opacity: 0.6 !important; + } + + &:hover svg, + &:hover i::before, + &:hover span { opacity: 1 !important; } } @@ -618,11 +639,16 @@ pre.prism-code { font-weight: 600; } + // On hover only darken the label + icon; keep the background unchanged. + // !important overrides the more specific .theme-code-block .clean-btn color + // rules (these buttons also carry the clean-btn class). &:hover { - background: var(--strapi-primary-100); + i { + color: var(--strapi-primary-700) !important; + } span { - color: var(--strapi-primary-600); + color: var(--strapi-neutral-800) !important; } } } From 72f1093f4a840f6734a86e725e00041cf92cbdd7 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Mon, 20 Jul 2026 12:28:18 +0200 Subject: [PATCH 15/55] Dim terminal Ask AI button icon and label at rest The Ask AI button in terminal blocks now dims its icon and label to opacity 0.6 at rest (matching the copy/wrap icons) and brings them to full opacity on hover, so it is no longer over-emphasized in dark mode. --- docusaurus/src/scss/code-block.scss | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index d9d95de1eb..4f4ebd1952 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -273,27 +273,34 @@ pre.prism-code { background: var(--strapi-neutral-0) !important; border: 1px solid var(--strapi-neutral-200) !important; + // Dimmed at rest (like the copy/wrap icons), full opacity on hover. + // !important beats the legacy .clean-btn opacity:1 rules (this button also + // carries the clean-btn class). i { font-size: 12px; color: var(--strapi-primary-500); + opacity: 0.6 !important; } span { color: var(--strapi-fg-1); + opacity: 0.6 !important; } - // On hover only darken the label + icon; keep background and border as-is. - // The button also carries the `clean-btn` class, whose legacy :hover would - // otherwise tint the background grey — override it explicitly. + // On hover only darken the label + icon and bring them to full opacity; + // keep background and border as-is. The button also carries the `clean-btn` + // class, whose legacy :hover would otherwise tint the background grey. &:hover { background: var(--strapi-neutral-0) !important; i { color: var(--strapi-primary-700) !important; + opacity: 1 !important; } span { color: var(--strapi-neutral-800) !important; + opacity: 1 !important; } } } From 1afb8f5d87c8a2997bbcba843bc915fd48081aa8 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:26:30 +0200 Subject: [PATCH 16/55] Migrate REST status and populate-select pages to standard code blocks Convert the Endpoint blocks on the REST status and populate-select pages to the new authoring format (Tabs + fenced code + Responses). --- .../docs/cms/api/rest/populate-select.md | 266 ++++++++++-------- docusaurus/docs/cms/api/rest/status.md | 112 ++++---- 2 files changed, 209 insertions(+), 169 deletions(-) diff --git a/docusaurus/docs/cms/api/rest/populate-select.md b/docusaurus/docs/cms/api/rest/populate-select.md index b948349d2c..89be62c3c6 100644 --- a/docusaurus/docs/cms/api/rest/populate-select.md +++ b/docusaurus/docs/cms/api/rest/populate-select.md @@ -54,17 +54,21 @@ Field selection does not work on relational, media, component, or dynamic zone f id="field-selection-example" method="GET" path="/api/restaurants?fields[0]=name&fields[1]=description" - codePath="/api/restaurants?fields[0]=name&fields[1]=description" title="Return only name and description fields" - description="Use the fields parameter to select only specific fields in the response." - codeTabs={[ - { - label: 'URL', - code: `GET /api/restaurants?fields[0]=name&fields[1]=description`, - }, - { - label: 'JavaScript', - code: `const qs = require('qs'); + description="Use the fields parameter to select only specific fields in the response."> + + + + +```bash +GET /api/restaurants?fields[0]=name&fields[1]=description +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify( { fields: ['name', 'description'], @@ -74,44 +78,50 @@ const query = qs.stringify( } ); -await request(\`/api/users?\${query}\`);`, - }, - ]} - responses={[ +await request(`/api/users?${query}`); +``` + + + + + + + +```json +{ + "data": [ { - status: 200, - statusText: 'OK', - body: JSON.stringify({ - data: [ - { - id: 4, - Name: "Pizzeria Arrivederci", - Description: [ - { - type: "paragraph", - children: [ - { - type: "text", - text: "Specialized in pizza, we invite you to rediscover our classics, such as 4 Formaggi or Calzone, and our original creations such as Do Luigi or Nduja." - } - ] - } - ], - documentId: "lr5wju2og49bf820kj9kz8c3" - } - ], - meta: { - pagination: { - page: 1, - pageSize: 25, - pageCount: 1, - total: 4 - } + "id": 4, + "Name": "Pizzeria Arrivederci", + "Description": [ + { + "type": "paragraph", + "children": [ + { + "type": "text", + "text": "Specialized in pizza, we invite you to rediscover our classics, such as 4 Formaggi or Calzone, and our original creations such as Do Luigi or Nduja." + } + ] } - }, null, 2), - }, - ]} -/> + ], + "documentId": "lr5wju2og49bf820kj9kz8c3" + } + ], + "meta": { + "pagination": { + "page": 1, + "pageSize": 25, + "pageCount": 1, + "total": 4 + } + } +} +``` + + + + +
## Population @@ -163,17 +173,21 @@ Top-level pagination parameters (e.g., `pagination[page]` and `pagination[pageSi + + + + +```bash +GET /api/articles?fields[0]=title&fields[1]=slug&populate[headerImage][fields][0]=name&populate[headerImage][fields][1]=url +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify( { fields: ['title', 'slug'], @@ -188,33 +202,39 @@ const query = qs.stringify( } ); -await request(\`/api/articles?\${query}\`);`, - }, - ]} - responses={[ +await request(`/api/articles?${query}`); +``` + + + + + + + +```json +{ + "data": [ { - status: 200, - statusText: 'OK', - body: JSON.stringify({ - data: [ - { - id: 1, - documentId: "h90lgohlzfpjf3bvan72mzll", - title: "Test Article", - slug: "test-article", - headerImage: { - id: 1, - documentId: "cf07g1dbusqr8mzmlbqvlegx", - name: "17520.jpg", - url: "/uploads/17520_73c601c014.jpg" - } - } - ], - meta: {} - }, null, 2), - }, - ]} -/> + "id": 1, + "documentId": "h90lgohlzfpjf3bvan72mzll", + "title": "Test Article", + "slug": "test-article", + "headerImage": { + "id": 1, + "documentId": "cf07g1dbusqr8mzmlbqvlegx", + "name": "17520.jpg", + "url": "/uploads/17520_73c601c014.jpg" + } + } + ], + "meta": {} +} +``` + + + + + #### Populate with filtering @@ -223,17 +243,21 @@ await request(\`/api/articles?\${query}\`);`, + + + + +```bash +GET /api/articles?populate[categories][sort][0]=name%3Aasc&populate[categories][filters][name][$eq]=Cars +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify( { populate: { @@ -252,35 +276,41 @@ const query = qs.stringify( } ); -await request(\`/api/articles?\${query}\`);`, - }, - ]} - responses={[ +await request(`/api/articles?${query}`); +``` + + + + + + + +```json +{ + "data": [ { - status: 200, - statusText: 'OK', - body: JSON.stringify({ - data: [ + "id": 1, + "documentId": "a1b2c3d4e5d6f7g8h9i0jkl", + "title": "Test Article", + "categories": { + "data": [ { - id: 1, - documentId: "a1b2c3d4e5d6f7g8h9i0jkl", - title: "Test Article", - categories: { - data: [ - { - id: 2, - documentId: "jKd8djla9ndalk98hflj3", - name: "Cars" - } - ] - } + "id": 2, + "documentId": "jKd8djla9ndalk98hflj3", + "name": "Cars" } - ], - meta: {} - }, null, 2), - }, - ]} -/> + ] + } + } + ], + "meta": {} +} +``` + + + + + :::note For many-to-many and other join-table relations, an explicit `sort` within a `populate` object overrides the default connect order. Omit `sort` to preserve the connect order (the order in which entries were associated). diff --git a/docusaurus/docs/cms/api/rest/status.md b/docusaurus/docs/cms/api/rest/status.md index ec3e1a7793..0ef80ea627 100644 --- a/docusaurus/docs/cms/api/rest/status.md +++ b/docusaurus/docs/cms/api/rest/status.md @@ -55,63 +55,73 @@ To select documents by how their draft and published versions relate (never-publ id="get-draft-versions" method="GET" path="/api/articles?status=draft" - codePath="/api/articles?status=draft" title="Get draft versions of restaurants" - description="Returns draft versions of documents by passing the status=draft query parameter." - codeTabs={[ - { - label: 'cURL', - code: `curl 'http://localhost:1337/api/articles?status=draft' \\ - -H 'Authorization: Bearer '`, - }, - { - label: 'JavaScript', - code: `const qs = require('qs'); + description="Returns draft versions of documents by passing the status=draft query parameter."> + + + + +```bash +curl 'http://localhost:1337/api/articles?status=draft' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ status: 'draft', }, { encodeValuesOnly: true, // prettify URL }); -await request(\`/api/articles?\${query}\`);`, - }, - ]} - responses={[ +await request(`/api/articles?${query}`); +``` + + + + + + + +```json +{ + "data": [ { - status: 200, - statusText: 'OK', - body: JSON.stringify({ - data: [ - { - id: 5, - documentId: "znrlzntu9ei5onjvwfaalu2v", - Name: "Biscotte Restaurant", - Description: [ - { - type: "paragraph", - children: [ - { - type: "text", - text: "This is the draft version." - } - ] - } - ], - createdAt: "2024-03-06T13:43:30.172Z", - updatedAt: "2024-03-06T21:38:46.353Z", - publishedAt: null, - locale: "en" - } - ], - meta: { - pagination: { - page: 1, - pageSize: 25, - pageCount: 1, - total: 4 - } + "id": 5, + "documentId": "znrlzntu9ei5onjvwfaalu2v", + "Name": "Biscotte Restaurant", + "Description": [ + { + "type": "paragraph", + "children": [ + { + "type": "text", + "text": "This is the draft version." + } + ] } - }, null, 2), - }, - ]} -/> + ], + "createdAt": "2024-03-06T13:43:30.172Z", + "updatedAt": "2024-03-06T21:38:46.353Z", + "publishedAt": null, + "locale": "en" + } + ], + "meta": { + "pagination": { + "page": 1, + "pageSize": 25, + "pageCount": 1, + "total": 4 + } + } +} +``` + + + + +
From cea6b5d12ccbb57e22742d679939406e4ff482ad Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:32:03 +0200 Subject: [PATCH 17/55] Migrate REST filters and sort-pagination pages to standard code blocks Convert the Endpoint blocks on the REST filters and sort-and-pagination pages to the new authoring format (Tabs + fenced code + Responses). --- docusaurus/docs/cms/api/rest/filters.md | 217 +++++++++++------- .../docs/cms/api/rest/sort-pagination.md | 216 ++++++++++------- 2 files changed, 256 insertions(+), 177 deletions(-) diff --git a/docusaurus/docs/cms/api/rest/filters.md b/docusaurus/docs/cms/api/rest/filters.md index 7ec5847760..22bf630cc2 100644 --- a/docusaurus/docs/cms/api/rest/filters.md +++ b/docusaurus/docs/cms/api/rest/filters.md @@ -90,17 +90,21 @@ By default, the filters can only be used from `find` endpoints generated by the id="find-users-eq" method="GET" path="/api/users?filters[username][$eq]=John" - codePath="/api/users?filters[username][$eq]=John" title="Find users having 'John' as first name" - description="Use the $eq filter operator to find an exact match." - codeTabs={[ - { - label: 'cURL', - code: `GET /api/users?filters[username][$eq]=John`, - }, - { - label: 'JavaScript', - code: `const qs = require('qs'); + description="Use the $eq filter operator to find an exact match."> + + + + +```bash +GET /api/users?filters[username][$eq]=John +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ filters: { username: { @@ -111,14 +115,17 @@ const query = qs.stringify({ encodeValuesOnly: true, // prettify URL }); -await request(\`/api/users?\${query}\`);`, - }, - ]} - responses={[ - { - status: 200, - statusText: 'OK', - body: `{ +await request(`/api/users?${query}`); +``` + + + + + + + +```json +{ "data": [ { "id": 1, @@ -140,10 +147,13 @@ await request(\`/api/users?\${query}\`);`, "total": 1 } } -}`, - }, - ]} -/> +} +``` + + + + + ## Example: Find multiple restaurants with ids 3, 6,8 @@ -151,17 +161,21 @@ await request(\`/api/users?\${query}\`);`, id="find-restaurants-in" method="GET" path="/api/restaurants?filters[id][$in][0]=3&filters[id][$in][1]=6&filters[id][$in][2]=8" - codePath="/api/restaurants?filters[id][$in][0]=3&filters[id][$in][1]=6&filters[id][$in][2]=8" title="Find multiple restaurants with ids 3, 6, 8" - description="Use the $in filter operator with an array of values to find multiple exact values." - codeTabs={[ - { - label: 'cURL', - code: `GET /api/restaurants?filters[id][$in][0]=3&filters[id][$in][1]=6&filters[id][$in][2]=8`, - }, - { - label: 'JavaScript', - code: `const qs = require('qs'); + description="Use the $in filter operator with an array of values to find multiple exact values."> + + + + +```bash +GET /api/restaurants?filters[id][$in][0]=3&filters[id][$in][1]=6&filters[id][$in][2]=8 +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ filters: { id: { @@ -172,14 +186,17 @@ const query = qs.stringify({ encodeValuesOnly: true, // prettify URL }); -await request(\`/api/restaurants?\${query}\`);`, - }, - ]} - responses={[ - { - status: 200, - statusText: 'OK', - body: `{ +await request(`/api/restaurants?${query}`); +``` + + + + + + + +```json +{ "data": [ { "id": 3, @@ -198,27 +215,34 @@ await request(\`/api/restaurants?\${query}\`);`, } ], "meta": {} -}`, - }, - ]} -/> +} +``` + + + + + ## Complex filtering + + + + +```bash +GET /api/books?filters[$and][0][$or][0][date][$eq]=2020-01-01&filters[$and][0][$or][1][date][$eq]=2020-01-02&filters[$and][1][author][name][$eq]=Kai%20doe +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ filters: { $and: [ @@ -249,14 +273,17 @@ const query = qs.stringify({ encodeValuesOnly: true, // prettify URL }); -await request(\`/api/books?\${query}\`);`, - }, - ]} - responses={[ - { - status: 200, - statusText: 'OK', - body: `{ +await request(`/api/books?${query}`); +``` + + + + + + + +```json +{ "data": [ { "id": 1, @@ -272,10 +299,13 @@ await request(\`/api/books?\${query}\`);`, } ], "meta": {} -}`, - }, - ]} -/> +} +``` + + + + + :::note The response above only contains a book's own attributes. The `author` relation traversed by the `$and` filter is not returned unless requested through the [`populate` parameter](/cms/api/rest/populate-select#population), for example by adding `&populate=author` to the request. @@ -297,17 +327,21 @@ Querying your API with deep filters may cause performance issues. If one of you + + + + +```bash +GET /api/restaurants?filters[chef][restaurants][stars][$eq]=5 +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ filters: { chef: { @@ -322,14 +356,17 @@ const query = qs.stringify({ encodeValuesOnly: true, // prettify URL }); -await request(\`/api/restaurants?\${query}\`);`, - }, - ]} - responses={[ - { - status: 200, - statusText: 'OK', - body: `{ +await request(`/api/restaurants?${query}`); +``` + + + + + + + +```json +{ "data": [ { "id": 1, @@ -345,11 +382,13 @@ await request(\`/api/restaurants?\${query}\`);`, } ], "meta": {} -}`, - }, - ]} - isLast -/> +} +``` + + + + + :::note The response above mirrors the default REST output, which excludes the relations traversed by the filter. Add a [`populate` parameter](/cms/api/rest/populate-select#population) such as `&populate[chef][populate][restaurants]=true` to also return the `chef.restaurants` relation referenced in the filter. diff --git a/docusaurus/docs/cms/api/rest/sort-pagination.md b/docusaurus/docs/cms/api/rest/sort-pagination.md index d9eceaa638..4cc0ee1c99 100644 --- a/docusaurus/docs/cms/api/rest/sort-pagination.md +++ b/docusaurus/docs/cms/api/rest/sort-pagination.md @@ -58,31 +58,38 @@ You can sort by multiple fields by passing fields in a `sort` array. id="sort-using-2-fields" method="GET" path="/api/restaurants?sort[0]=Description&sort[1]=Name" - codePath="/api/restaurants?sort[0]=Description&sort[1]=Name" title="Sort using 2 fields" - description="Sort results by Description and Name fields." - codeTabs={[ - { - label: "REST", - code: `GET /api/restaurants?sort[0]=Description&sort[1]=Name` - }, - { - label: "JavaScript", - code: `const qs = require('qs'); + description="Sort results by Description and Name fields."> + + + + +```bash +GET /api/restaurants?sort[0]=Description&sort[1]=Name +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ sort: ['Description', 'Name'], }, { encodeValuesOnly: true, // prettify URL }); -await request(\`/api/restaurants?\${query}\`);` - } - ]} - responses={[ - { - status: 200, - statusText: "OK", - body: `{ +await request(`/api/restaurants?${query}`); +``` + + + + + + + +```json +{ "data": [ { "id": 9, @@ -123,10 +130,13 @@ await request(\`/api/restaurants?\${query}\`);` "meta": { // … } -}` - } - ]} -/> +} +``` + + + + + ### Example: Sort using 2 fields and set the order @@ -136,31 +146,38 @@ Using the `sort` parameter and defining `:asc` or `:desc` on sorted fields, you id="sort-using-2-fields-and-set-the-order" method="GET" path="/api/restaurants?sort[0]=Description:asc&sort[1]=Name:desc" - codePath="/api/restaurants?sort[0]=Description:asc&sort[1]=Name:desc" title="Sort using 2 fields and set the order" - description="Sort results by Description ascending and Name descending." - codeTabs={[ - { - label: "REST", - code: `GET /api/restaurants?sort[0]=Description:asc&sort[1]=Name:desc` - }, - { - label: "JavaScript", - code: `const qs = require('qs'); + description="Sort results by Description ascending and Name descending."> + + + + +```bash +GET /api/restaurants?sort[0]=Description:asc&sort[1]=Name:desc +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ sort: ['Description:asc', 'Name:desc'], }, { encodeValuesOnly: true, // prettify URL }); -await request(\`/api/restaurants?\${query}\`);` - } - ]} - responses={[ - { - status: 200, - statusText: "OK", - body: `{ +await request(`/api/restaurants?${query}`); +``` + + + + + + + +```json +{ "data": [ { "id": 8, @@ -201,10 +218,13 @@ await request(\`/api/restaurants?\${query}\`);` "meta": { // … } -}` - } - ]} -/> +} +``` + + + + + ## Pagination @@ -230,17 +250,21 @@ To paginate results by page, use the following parameters: + + + + +```bash +GET /api/articles?pagination[page]=1&pagination[pageSize]=10 +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ pagination: { page: 1, @@ -250,14 +274,17 @@ const query = qs.stringify({ encodeValuesOnly: true, // prettify URL }); -await request(\`/api/articles?\${query}\`);` - } - ]} - responses={[ - { - status: 200, - statusText: "OK", - body: `{ +await request(`/api/articles?${query}`); +``` + + + + + + + +```json +{ "data": [ // ... ], @@ -269,10 +296,13 @@ await request(\`/api/articles?\${query}\`);` "total": 48 } } -}` - } - ]} -/> +} +``` + + + + + ### Pagination by offset @@ -291,17 +321,21 @@ The default and maximum values for `pagination[limit]` can be [configured in the + + + + +```bash +GET /api/articles?pagination[start]=0&pagination[limit]=10 +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ pagination: { start: 0, @@ -311,14 +345,17 @@ const query = qs.stringify({ encodeValuesOnly: true, // prettify URL }); -await request(\`/api/articles?\${query}\`);` - } - ]} - responses={[ - { - status: 200, - statusText: "OK", - body: `{ +await request(`/api/articles?${query}`); +``` + + + + + + + +```json +{ "data": [ // ... ], @@ -329,7 +366,10 @@ await request(\`/api/articles?\${query}\`);` "total": 42 } } -}` - } - ]} -/> +} +``` + + + + + From 3db3c356c3551e4642b91d997063c3222dd4a538 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:43:04 +0200 Subject: [PATCH 18/55] Migrate REST locale and publicationFilter pages to standard code blocks Convert the Endpoint blocks on the REST locale and publicationFilter pages to the new authoring format (fenced code + Responses). --- docusaurus/docs/cms/api/rest/locale.md | 526 +++++++-------- .../docs/cms/api/rest/publication-filter.md | 616 +++++++++++------- 2 files changed, 635 insertions(+), 507 deletions(-) diff --git a/docusaurus/docs/cms/api/rest/locale.md b/docusaurus/docs/cms/api/rest/locale.md index 4db4189937..468a51a134 100644 --- a/docusaurus/docs/cms/api/rest/locale.md +++ b/docusaurus/docs/cms/api/rest/locale.md @@ -75,52 +75,54 @@ The following table lists the new possible use cases added by i18n to the REST A method="GET" path="/api/restaurants?locale=fr" title="Get all documents in a specific locale" - description="Returns all documents for a given locale." - codeTabs={[ - { - label: 'Request', - code: `GET http://localhost:1337/api/restaurants?locale=fr`, - }, - ]} - responses={[ + description="Returns all documents for a given locale."> + +```bash +GET http://localhost:1337/api/restaurants?locale=fr +``` + + + + +```json +{ + "data": [ { - status: 200, - statusText: 'OK', - body: JSON.stringify({ - data: [ - { - id: 5, - documentId: "h90lgohlzfpjf3bvan72mzll", - Title: "Meilleures pizzas", - Body: [ - { - type: "paragraph", - children: [ - { - type: "text", - text: "On déguste les meilleures pizzas de la ville à la Pizzeria Arrivederci." - } - ] - } - ], - createdAt: "2024-03-06T22:08:59.643Z", - updatedAt: "2024-03-06T22:10:21.127Z", - publishedAt: "2024-03-06T22:10:21.130Z", - locale: "fr" - } - ], - meta: { - pagination: { - page: 1, - pageSize: 25, - pageCount: 1, - total: 1 - } + "id": 5, + "documentId": "h90lgohlzfpjf3bvan72mzll", + "Title": "Meilleures pizzas", + "Body": [ + { + "type": "paragraph", + "children": [ + { + "type": "text", + "text": "On déguste les meilleures pizzas de la ville à la Pizzeria Arrivederci." + } + ] } - }, null, 2), - }, - ]} -/> + ], + "createdAt": "2024-03-06T22:08:59.643Z", + "updatedAt": "2024-03-06T22:10:21.127Z", + "publishedAt": "2024-03-06T22:10:21.130Z", + "locale": "fr" + } + ], + "meta": { + "pagination": { + "page": 1, + "pageSize": 25, + "pageCount": 1, + "total": 1 + } + } +} +``` + + + + + ### `GET` Get a document in a specific locale {#rest-get} @@ -140,49 +142,51 @@ To get a specific document in a collection type in a given locale, add the `loca method="GET" path="/api/restaurants/:documentId?locale=fr" title="Get a document in a specific locale (collection type)" - description="Returns a specific document in a collection type for a given locale." - codeTabs={[ - { - label: 'Request', - code: `GET /api/restaurants/lr5wju2og49bf820kj9kz8c3?locale=fr`, - }, - ]} - responses={[ + description="Returns a specific document in a collection type for a given locale."> + +```bash +GET /api/restaurants/lr5wju2og49bf820kj9kz8c3?locale=fr +``` + + + + +```json +{ + "data": [ { - status: 200, - statusText: 'OK', - body: JSON.stringify({ - data: [ - { - id: 22, - documentId: "lr5wju2og49bf820kj9kz8c3", - Name: "Biscotte Restaurant", - Description: [ - { - type: "paragraph", - children: [ - { - type: "text", - text: "Bienvenue au restaurant Biscotte! Le Restaurant Biscotte propose une cuisine à base de produits frais et de qualité, souvent locaux, biologiques lorsque cela est possible, et toujours produits par des producteurs passionnés." - } - ] - } - ], - locale: "fr" - } - ], - meta: { - pagination: { - page: 1, - pageSize: 25, - pageCount: 1, - total: 3 - } + "id": 22, + "documentId": "lr5wju2og49bf820kj9kz8c3", + "Name": "Biscotte Restaurant", + "Description": [ + { + "type": "paragraph", + "children": [ + { + "type": "text", + "text": "Bienvenue au restaurant Biscotte! Le Restaurant Biscotte propose une cuisine à base de produits frais et de qualité, souvent locaux, biologiques lorsque cela est possible, et toujours produits par des producteurs passionnés." + } + ] } - }, null, 2), - }, - ]} -/> + ], + "locale": "fr" + } + ], + "meta": { + "pagination": { + "page": 1, + "pageSize": 25, + "pageCount": 1, + "total": 3 + } + } +} +``` + + + + + #### Single types {#get-one-single-type} @@ -193,33 +197,35 @@ To get a specific single type document in a given locale, add the `locale` param method="GET" path="/api/homepage?locale=fr" title="Get a document in a specific locale (single type)" - description="Returns a specific single type document for a given locale." - codeTabs={[ - { - label: 'Request', - code: `GET /api/homepage?locale=fr`, - }, - ]} - responses={[ - { - status: 200, - statusText: 'OK', - body: JSON.stringify({ - data: { - id: 10, - documentId: "ukbpbnu8kbutpn98rsanyi50", - Title: "Page d'accueil", - Body: null, - createdAt: "2024-03-07T13:28:26.349Z", - updatedAt: "2024-03-07T13:28:26.349Z", - publishedAt: "2024-03-07T13:28:26.353Z", - locale: "fr" - }, - meta: {} - }, null, 2), - }, - ]} -/> + description="Returns a specific single type document for a given locale."> + +```bash +GET /api/homepage?locale=fr +``` + + + + +```json +{ + "data": { + "id": 10, + "documentId": "ukbpbnu8kbutpn98rsanyi50", + "Title": "Page d'accueil", + "Body": null, + "createdAt": "2024-03-07T13:28:26.349Z", + "updatedAt": "2024-03-07T13:28:26.349Z", + "publishedAt": "2024-03-07T13:28:26.353Z", + "locale": "fr" + }, + "meta": {} +} +``` + + + + + ### `POST` Create a new localized document for a collection type {#rest-create} @@ -239,39 +245,41 @@ If no locale has been passed in the request body, the document is created using method="POST" path="/api/restaurants" title="Create a document for the default locale" - description="Creates a new document using the default locale." - codeTabs={[ - { - label: 'Request', - code: `POST http://localhost:1337/api/restaurants + description="Creates a new document using the default locale."> + +```bash +POST http://localhost:1337/api/restaurants { "data": { "Name": "Oplato" } -}`, - }, - ]} - responses={[ - { - status: 200, - statusText: 'OK', - body: JSON.stringify({ - data: { - id: 13, - documentId: "jae8klabhuucbkgfe2xxc5dj", - Name: "Oplato", - Description: null, - createdAt: "2024-03-06T22:19:54.646Z", - updatedAt: "2024-03-06T22:19:54.646Z", - publishedAt: "2024-03-06T22:19:54.649Z", - locale: "en" - }, - meta: {} - }, null, 2), - }, - ]} -/> +} +``` + + + + +```json +{ + "data": { + "id": 13, + "documentId": "jae8klabhuucbkgfe2xxc5dj", + "Name": "Oplato", + "Description": null, + "createdAt": "2024-03-06T22:19:54.646Z", + "updatedAt": "2024-03-06T22:19:54.646Z", + "publishedAt": "2024-03-06T22:19:54.649Z", + "locale": "en" + }, + "meta": {} +} +``` + + + + + #### For a specific locale {#rest-create-specific-locale} @@ -282,39 +290,41 @@ To create a localized entry for a locale different from the default one, add the method="POST" path="/api/restaurants?locale=fr" title="Create a document for a specific locale" - description="Creates a new document for a specified locale." - codeTabs={[ - { - label: 'Request', - code: `POST http://localhost:1337/api/restaurants?locale=fr + description="Creates a new document for a specified locale."> + +```bash +POST http://localhost:1337/api/restaurants?locale=fr { "data": { "Name": "She's Cake" } -}`, - }, - ]} - responses={[ - { - status: 200, - statusText: 'OK', - body: JSON.stringify({ - data: { - id: 15, - documentId: "ldcmn698iams5nuaehj69j5o", - Name: "She's Cake", - Description: null, - createdAt: "2024-03-06T22:21:18.373Z", - updatedAt: "2024-03-06T22:21:18.373Z", - publishedAt: "2024-03-06T22:21:18.378Z", - locale: "fr" - }, - meta: {} - }, null, 2), - }, - ]} -/> +} +``` + + + + +```json +{ + "data": { + "id": 15, + "documentId": "ldcmn698iams5nuaehj69j5o", + "Name": "She's Cake", + "Description": null, + "createdAt": "2024-03-06T22:21:18.373Z", + "updatedAt": "2024-03-06T22:21:18.373Z", + "publishedAt": "2024-03-06T22:21:18.378Z", + "locale": "fr" + }, + "meta": {} +} +``` + + + + + ### `PUT` Create a new, or update an existing, locale version for an existing document {#rest-update} @@ -351,39 +361,41 @@ To create a new locale for an existing document in a collection type, add the `l method="PUT" path="/api/restaurants/:documentId?locale=fr" title="Create or update a locale version (collection type)" - description="Creates a French locale for an existing restaurant, or updates it if it already exists." - codeTabs={[ - { - label: 'Request', - code: `PUT http://localhost:1337/api/restaurants/lr5wju2og49bf820kj9kz8c3?locale=fr + description="Creates a French locale for an existing restaurant, or updates it if it already exists."> + +```bash +PUT http://localhost:1337/api/restaurants/lr5wju2og49bf820kj9kz8c3?locale=fr { "data": { "Name": "She's Cake in French" } -}`, - }, - ]} - responses={[ - { - status: 200, - statusText: 'OK', - body: JSON.stringify({ - data: { - id: 19, - documentId: "lr5wju2og49bf820kj9kz8c3", - Name: "She's Cake in French", - Description: null, - createdAt: "2024-03-07T12:13:09.551Z", - updatedAt: "2024-03-07T12:13:09.551Z", - publishedAt: "2024-03-07T12:13:09.554Z", - locale: "fr" - }, - meta: {} - }, null, 2), - }, - ]} -/> +} +``` + + + + +```json +{ + "data": { + "id": 19, + "documentId": "lr5wju2og49bf820kj9kz8c3", + "Name": "She's Cake in French", + "Description": null, + "createdAt": "2024-03-07T12:13:09.551Z", + "updatedAt": "2024-03-07T12:13:09.551Z", + "publishedAt": "2024-03-07T12:13:09.554Z", + "locale": "fr" + }, + "meta": {} +} +``` + + + + + #### In a single type {#rest-put-single-type} @@ -394,39 +406,41 @@ To create a new locale for an existing single type document, add the `locale` pa method="PUT" path="/api/homepage?locale=fr" title="Create or update a locale version (single type)" - description="Creates a French locale for an existing Homepage single type, or updates it if it already exists." - codeTabs={[ - { - label: 'Request', - code: `PUT http://localhost:1337/api/homepage?locale=fr + description="Creates a French locale for an existing Homepage single type, or updates it if it already exists."> + +```bash +PUT http://localhost:1337/api/homepage?locale=fr { "data": { "Title": "Page d'accueil" } -}`, - }, - ]} - responses={[ - { - status: 200, - statusText: 'OK', - body: JSON.stringify({ - data: { - id: 10, - documentId: "ukbpbnu8kbutpn98rsanyi50", - Title: "Page d'accueil", - Body: null, - createdAt: "2024-03-07T13:28:26.349Z", - updatedAt: "2024-03-07T13:28:26.349Z", - publishedAt: "2024-03-07T13:28:26.353Z", - locale: "fr" - }, - meta: {} - }, null, 2), - }, - ]} -/> +} +``` + + + + +```json +{ + "data": { + "id": 10, + "documentId": "ukbpbnu8kbutpn98rsanyi50", + "Title": "Page d'accueil", + "Body": null, + "createdAt": "2024-03-07T13:28:26.349Z", + "updatedAt": "2024-03-07T13:28:26.349Z", + "publishedAt": "2024-03-07T13:28:26.353Z", + "locale": "fr" + }, + "meta": {} +} +``` + + + + +
@@ -445,21 +459,23 @@ To delete only a specific locale version of a document in a collection type, add method="DELETE" path="/api/restaurants/:documentId?locale=fr" title="Delete a locale version (collection type)" - description="Deletes a specific locale version of a document in a collection type." - codeTabs={[ - { - label: 'Request', - code: `DELETE /api/restaurants/abcdefghijklmno456?locale=fr`, - }, - ]} - responses={[ - { - status: 204, - statusText: 'No Content', - body: '', - }, - ]} -/> + description="Deletes a specific locale version of a document in a collection type."> + +```bash +DELETE /api/restaurants/abcdefghijklmno456?locale=fr +``` + + + + +```json + +``` + + + + + #### In a single type {#rest-delete-single-type} @@ -470,18 +486,20 @@ To delete only a specific locale version of a single type document, add the `loc method="DELETE" path="/api/homepage?locale=fr" title="Delete a locale version (single type)" - description="Deletes a specific locale version of a single type document." - codeTabs={[ - { - label: 'Request', - code: `DELETE /api/homepage?locale=fr`, - }, - ]} - responses={[ - { - status: 204, - statusText: 'No Content', - body: '', - }, - ]} -/> + description="Deletes a specific locale version of a single type document."> + +```bash +DELETE /api/homepage?locale=fr +``` + + + + +```json + +``` + + + + + diff --git a/docusaurus/docs/cms/api/rest/publication-filter.md b/docusaurus/docs/cms/api/rest/publication-filter.md index b4e9506fa6..c9bdc8860b 100644 --- a/docusaurus/docs/cms/api/rest/publication-filter.md +++ b/docusaurus/docs/cms/api/rest/publication-filter.md @@ -90,18 +90,22 @@ This parameter combination works only on a given locale; to find these documents '` - }, - { - label: "JavaScript", - code: `const qs = require('qs'); + description="Return the drafts that have never been published for their locale."> + + + + +```bash +curl 'http://localhost:1337/api/restaurants?status=draft&publicationFilter=never-published' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ status: 'draft', publicationFilter: 'never-published', @@ -109,14 +113,17 @@ const query = qs.stringify({ encodeValuesOnly: true, // prettify URL }); -await request(\`/api/restaurants?\${query}\`);` - } - ]} - responses={[ - { - status: 200, - statusText: "OK", - body: `{ +await request(`/api/restaurants?${query}`); +``` + + + + + + + +```json +{ "data": [ { "documentId": "a1b2c3d4e5f6g7h8i9j0klm", @@ -133,10 +140,13 @@ await request(\`/api/restaurants?\${query}\`);` "total": 1 } } -}` - } - ]} -/> +} +``` + + + + + ### Find drafts never published in any locale {#never-published-document} @@ -147,18 +157,22 @@ A document counts as published as soon as one of its locales is published: the d '` - }, - { - label: "JavaScript", - code: `const qs = require('qs'); + description="Return the drafts of documents never published in any locale."> + + + + +```bash +curl 'http://localhost:1337/api/restaurants?status=draft&publicationFilter=never-published-document' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ status: 'draft', publicationFilter: 'never-published-document', @@ -166,14 +180,17 @@ const query = qs.stringify({ encodeValuesOnly: true, // prettify URL }); -await request(\`/api/restaurants?\${query}\`);` - } - ]} - responses={[ - { - status: 200, - statusText: "OK", - body: `{ +await request(`/api/restaurants?${query}`); +``` + + + + + + + +```json +{ "data": [ { "documentId": "d41r46wac4xix5vpba7561at", @@ -190,10 +207,13 @@ await request(\`/api/restaurants?\${query}\`);` "total": 1 } } -}` - } - ]} -/> +} +``` + + + + + ### Find modified documents {#modified} @@ -204,18 +224,22 @@ For instance, with `status=draft`, the query returns the draft versions: '` - }, - { - label: "JavaScript", - code: `const qs = require('qs'); + description="Return the draft versions of documents with unpublished changes."> + + + + +```bash +curl 'http://localhost:1337/api/restaurants?status=draft&publicationFilter=modified' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ status: 'draft', publicationFilter: 'modified', @@ -223,14 +247,17 @@ const query = qs.stringify({ encodeValuesOnly: true, // prettify URL }); -await request(\`/api/restaurants?\${query}\`);` - } - ]} - responses={[ - { - status: 200, - statusText: "OK", - body: `{ +await request(`/api/restaurants?${query}`); +``` + + + + + + + +```json +{ "data": [ { "documentId": "a1b2c3d4e5f6g7h8i9j0klm", @@ -247,10 +274,13 @@ await request(\`/api/restaurants?\${query}\`);` "total": 1 } } -}` - } - ]} -/> +} +``` + + + + +
With `status=published` (the REST default), the same query returns the currently live version of those documents instead: @@ -258,32 +288,39 @@ With `status=published` (the REST default), the same query returns the currently '` - }, - { - label: "JavaScript", - code: `const qs = require('qs'); + description="Return the currently live versions of documents with unpublished changes."> + + + + +```bash +curl 'http://localhost:1337/api/restaurants?publicationFilter=modified' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ publicationFilter: 'modified', }, { encodeValuesOnly: true, // prettify URL }); -await request(\`/api/restaurants?\${query}\`);` - } - ]} - responses={[ - { - status: 200, - statusText: "OK", - body: `{ +await request(`/api/restaurants?${query}`); +``` + + + + + + + +```json +{ "data": [ { "documentId": "a1b2c3d4e5f6g7h8i9j0klm", @@ -300,10 +337,13 @@ await request(\`/api/restaurants?\${query}\`);` "total": 1 } } -}` - } - ]} -/> +} +``` + + + + + ### Find unmodified documents {#unmodified} @@ -314,18 +354,22 @@ For instance, with `status=draft`, the query returns the draft versions: '` - }, - { - label: "JavaScript", - code: `const qs = require('qs'); + description="Return the draft versions of documents unchanged since their last publication."> + + + + +```bash +curl 'http://localhost:1337/api/restaurants?status=draft&publicationFilter=unmodified' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ status: 'draft', publicationFilter: 'unmodified', @@ -333,14 +377,17 @@ const query = qs.stringify({ encodeValuesOnly: true, // prettify URL }); -await request(\`/api/restaurants?\${query}\`);` - } - ]} - responses={[ - { - status: 200, - statusText: "OK", - body: `{ +await request(`/api/restaurants?${query}`); +``` + + + + + + + +```json +{ "data": [ { "documentId": "a1b2c3d4e5f6g7h8i9j0klm", @@ -357,10 +404,13 @@ await request(\`/api/restaurants?\${query}\`);` "total": 1 } } -}` - } - ]} -/> +} +``` + + + + +
With `status=published` (the REST default), the same query returns the currently live version of those documents instead: @@ -368,32 +418,39 @@ With `status=published` (the REST default), the same query returns the currently '` - }, - { - label: "JavaScript", - code: `const qs = require('qs'); + description="Return the currently live versions of documents unchanged since their last publication."> + + + + +```bash +curl 'http://localhost:1337/api/restaurants?publicationFilter=unmodified' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ publicationFilter: 'unmodified', }, { encodeValuesOnly: true, // prettify URL }); -await request(\`/api/restaurants?\${query}\`);` - } - ]} - responses={[ - { - status: 200, - statusText: "OK", - body: `{ +await request(`/api/restaurants?${query}`); +``` + + + + + + + +```json +{ "data": [ { "documentId": "a1b2c3d4e5f6g7h8i9j0klm", @@ -410,10 +467,13 @@ await request(\`/api/restaurants?\${query}\`);` "total": 1 } } -}` - } - ]} -/> +} +``` + + + + + ### Find documents with a published version {#has-published-version} @@ -424,18 +484,22 @@ For instance, with `status=draft`, the query returns the draft versions: '` - }, - { - label: "JavaScript", - code: `const qs = require('qs'); + description="Return the draft versions of documents that also have a published version for the same locale."> + + + + +```bash +curl 'http://localhost:1337/api/restaurants?status=draft&publicationFilter=has-published-version' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ status: 'draft', publicationFilter: 'has-published-version', @@ -443,14 +507,17 @@ const query = qs.stringify({ encodeValuesOnly: true, // prettify URL }); -await request(\`/api/restaurants?\${query}\`);` - } - ]} - responses={[ - { - status: 200, - statusText: "OK", - body: `{ +await request(`/api/restaurants?${query}`); +``` + + + + + + + +```json +{ "data": [ { "documentId": "a1b2c3d4e5f6g7h8i9j0klm", @@ -467,10 +534,13 @@ await request(\`/api/restaurants?\${query}\`);` "total": 1 } } -}` - } - ]} -/> +} +``` + + + + +
With `status=published` (the REST default), the same query returns the currently live version of those documents instead: @@ -478,32 +548,39 @@ With `status=published` (the REST default), the same query returns the currently '` - }, - { - label: "JavaScript", - code: `const qs = require('qs'); + description="Return the currently live versions of documents that also have a published version for the same locale."> + + + + +```bash +curl 'http://localhost:1337/api/restaurants?publicationFilter=has-published-version' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ publicationFilter: 'has-published-version', }, { encodeValuesOnly: true, // prettify URL }); -await request(\`/api/restaurants?\${query}\`);` - } - ]} - responses={[ - { - status: 200, - statusText: "OK", - body: `{ +await request(`/api/restaurants?${query}`); +``` + + + + + + + +```json +{ "data": [ { "documentId": "a1b2c3d4e5f6g7h8i9j0klm", @@ -520,10 +597,13 @@ await request(\`/api/restaurants?\${query}\`);` "total": 1 } } -}` - } - ]} -/> +} +``` + + + + + ### Find documents with a published version in at least one locale {#has-published-version-document} @@ -532,18 +612,22 @@ await request(\`/api/restaurants?\${query}\`);` '` - }, - { - label: "JavaScript", - code: `const qs = require('qs'); + description="Return the draft versions of documents published in at least one locale."> + + + + +```bash +curl 'http://localhost:1337/api/restaurants?status=draft&publicationFilter=has-published-version-document' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ status: 'draft', publicationFilter: 'has-published-version-document', @@ -551,14 +635,17 @@ const query = qs.stringify({ encodeValuesOnly: true, // prettify URL }); -await request(\`/api/restaurants?\${query}\`);` - } - ]} - responses={[ - { - status: 200, - statusText: "OK", - body: `{ +await request(`/api/restaurants?${query}`); +``` + + + + + + + +```json +{ "data": [ { "documentId": "a1b2c3d4e5f6g7h8i9j0klm", @@ -575,10 +662,13 @@ await request(\`/api/restaurants?\${query}\`);` "total": 1 } } -}` - } - ]} -/> +} +``` + + + + + ## Diagnostic values {#diagnostics} @@ -592,32 +682,39 @@ The `published-without-draft` and `published-with-draft` values are meant for da '` - }, - { - label: "JavaScript", - code: `const qs = require('qs'); + description="Return published documents with no matching draft version for the same locale."> + + + + +```bash +curl 'http://localhost:1337/api/restaurants?publicationFilter=published-without-draft' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ publicationFilter: 'published-without-draft', }, { encodeValuesOnly: true, // prettify URL }); -await request(\`/api/restaurants?\${query}\`);` - } - ]} - responses={[ - { - status: 200, - statusText: "OK", - body: `{ +await request(`/api/restaurants?${query}`); +``` + + + + + + + +```json +{ "data": [ { "documentId": "j0klm1n2o3p4q5r6s7t8u9v", @@ -634,42 +731,52 @@ await request(\`/api/restaurants?\${query}\`);` "total": 1 } } -}` - } - ]} -/> +} +``` + + + + + `publicationFilter=published-with-draft` selects published documents that also have a draft, which is every published document in a healthy database: '` - }, - { - label: "JavaScript", - code: `const qs = require('qs'); + description="Return published documents that also have a matching draft version for the same locale."> + + + + +```bash +curl 'http://localhost:1337/api/restaurants?publicationFilter=published-with-draft' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const qs = require('qs'); const query = qs.stringify({ publicationFilter: 'published-with-draft', }, { encodeValuesOnly: true, // prettify URL }); -await request(\`/api/restaurants?\${query}\`);` - } - ]} - responses={[ - { - status: 200, - statusText: "OK", - body: `{ +await request(`/api/restaurants?${query}`); +``` + + + + + + + +```json +{ "data": [ { "documentId": "a1b2c3d4e5f6g7h8i9j0klm", @@ -686,10 +793,13 @@ await request(\`/api/restaurants?\${query}\`);` "total": 1 } } -}` - } - ]} -/> +} +``` + + + + + From b64bc6bd4882b4d1df99b29746bf029201bfce56 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:44:42 +0200 Subject: [PATCH 19/55] Migrate REST understanding-populate guide to standard code blocks Convert the active Endpoint blocks on the understanding populate guide to the new authoring format (fenced code + Responses). Commented-out blocks are left untouched. --- .../api/rest/guides/understanding-populate.md | 333 +++++++++--------- 1 file changed, 171 insertions(+), 162 deletions(-) diff --git a/docusaurus/docs/cms/api/rest/guides/understanding-populate.md b/docusaurus/docs/cms/api/rest/guides/understanding-populate.md index 0792aa1229..268a964c06 100644 --- a/docusaurus/docs/cms/api/rest/guides/understanding-populate.md +++ b/docusaurus/docs/cms/api/rest/guides/understanding-populate.md @@ -85,23 +85,21 @@ The following example is the full response for all 4 entries from the `articles` Notice how the response only includes the `title`, `slug`, `createdAt`, `updatedAt`, `publishedAt`, and `locale` fields, and the field content of the article as handled by the CKEditor plugin (`ckeditor_content`, truncated for brevity): + +```bash +GET /api/articles +``` + + + + +```json +{ "data": [ { "id": 1, @@ -156,10 +154,13 @@ Notice how the response only includes the `title`, `slug`, `createdAt`, `updated "total": 4 } } -}` - } - ]} -/> +} +``` + + + + + ### Example: With `populate=*` @@ -180,23 +181,21 @@ To populate deeply nested components, see the [populate components](#populate-co
+ +```bash +GET /api/articles?populate=* +``` + + + + +```json +{ "data": [ { "id": 1, @@ -338,10 +337,13 @@ To populate deeply nested components, see the [populate components](#populate-co "total": 4 } } -}` - } - ]} -/> +} +``` + + + + + ## Populate specific relations and fields @@ -429,23 +431,21 @@ Notice that the response does not include any media fields, relations, component
+ +```bash +GET /api/articles +``` + + + + +```json +{ "data": [ { "id": 1, @@ -500,10 +500,13 @@ Notice that the response does not include any media fields, relations, component "total": 4 } } -}` - } - ]} -/> +} +``` + + + + + #### Example: With `populate[0]=category` @@ -514,23 +517,21 @@ The following example is the full response for all 4 entries from the `articles` Notice that the response now includes additional data with the `category` field for each article (see highlighted lines): + +```bash +GET /api/articles?populate[0]=category +``` + + + + +```json +{ "data": [ { "id": 1, @@ -624,10 +625,13 @@ Notice that the response now includes additional data with the `category` field "total": 4 } } -}` - } - ]} -/> +} +``` + + + + + ### Populate several levels deep for specific relations @@ -670,23 +674,21 @@ Let's compare and explain the responses returned with `populate[0]=category` (1 When we only populate 1 level deep, asking for the categories associated to articles, we can get the following example response (highlighted lines show the `category` relations field): + +```bash +GET /api/articles?populate[0]=category +``` + + + + +```json +{ "data": [ { "id": 1, @@ -780,10 +782,13 @@ When we only populate 1 level deep, asking for the categories associated to arti "total": 4 } } -}` - } - ]} -/> +} +``` + + + + + #### Example: With 2-level deep population @@ -792,23 +797,21 @@ When we populate 2 levels deep, asking for the categories associated to articles Notice that we now have the `restaurants` relation field included with the response inside the `category` relation (see highlighted lines): + +```bash +GET /api/articles?populate[category][populate][0]=restaurants +``` + + + + +```json +{ "data": [ { "id": 1, @@ -886,10 +889,13 @@ Notice that we now have the `restaurants` relation field included with the respo "total": 4 } } -}` - } - ]} -/> +} +``` + + + + + ### Populate components @@ -933,23 +939,21 @@ When we only populate the `seo` component, we go only 1 level deep, and we can g Notice there's no mention of the `metaSocial` component nested within the `seo` component: + +```bash +GET /api/articles?populate[0]=seo +``` + + + + +```json +{ "data": [ { "id": 1, @@ -994,10 +998,13 @@ Notice there's no mention of the `metaSocial` component nested within the `seo` "total": 4 } } -}` - } - ]} -/> +} +``` + + + + + #### Example: 1st level and 2nd level component @@ -1006,23 +1013,21 @@ When we populate 2 levels deep, asking both for the `seo` component and the `met Notice that we now have the `metaSocial` component-related data included with the response (see highlighted lines): + +```bash +GET /api/articles?populate[0]=seo&populate[1]=seo.metaSocial +``` + + + + +```json +{ "data": [ { "id": 1, @@ -1076,10 +1081,13 @@ Notice that we now have the `metaSocial` component-related data included with th "total": 4 } } -}` - } - ]} -/> +} +``` + + + + + ### Populate dynamic zones @@ -1363,23 +1371,21 @@ In the following example response, highlighted lines show that: - But because we have only asked to populate everything for the `CtaCommandLine` component and have not defined anything for the `faq` component, no data from the `faq` component is returned. + +```bash +GET /api/articles?populate[blocks][on][blocks.related-articles][populate][articles][populate][0]=image&populate[blocks][on][blocks.cta-command-line][populate]=* +``` + + + + +```json +{ "data": [ { "id": 1, @@ -1483,10 +1489,13 @@ In the following example response, highlighted lines show that: "total": 4 } } -}` - } - ]} -/> +} +``` + + + + + :::tip Avoid over-populating in production Using `populate=*` or deep population plugins can create unpredictable, costly database queries. In production, always populate explicitly and limit depth to 2-3 levels. Consider using route-level middlewares to centralize population logic. See on the Strapi blog. From 2bf7d702cadc8cb530bed5ac9c86668ee5c2cd11 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Mon, 20 Jul 2026 17:52:25 +0200 Subject: [PATCH 20/55] Restore collapsible long responses using ExpandableContent Add a collapsible prop to ResponseTab that wraps its content in the existing ExpandableContent component (Show more / Show less), and mark the long responses on the understanding-populate guide as collapsible, restoring the behavior lost when the Endpoint component was reworked. --- .../cms/api/rest/guides/understanding-populate.md | 14 +++++++------- .../src/components/ApiReference/Responses.jsx | 9 +++++++-- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/docusaurus/docs/cms/api/rest/guides/understanding-populate.md b/docusaurus/docs/cms/api/rest/guides/understanding-populate.md index 268a964c06..ba3749370a 100644 --- a/docusaurus/docs/cms/api/rest/guides/understanding-populate.md +++ b/docusaurus/docs/cms/api/rest/guides/understanding-populate.md @@ -192,7 +192,7 @@ GET /api/articles?populate=* ``` - + ```json { @@ -528,7 +528,7 @@ GET /api/articles?populate[0]=category ``` - + ```json { @@ -685,7 +685,7 @@ GET /api/articles?populate[0]=category ``` - + ```json { @@ -808,7 +808,7 @@ GET /api/articles?populate[category][populate][0]=restaurants ``` - + ```json { @@ -950,7 +950,7 @@ GET /api/articles?populate[0]=seo ``` - + ```json { @@ -1024,7 +1024,7 @@ GET /api/articles?populate[0]=seo&populate[1]=seo.metaSocial ``` - + ```json { @@ -1382,7 +1382,7 @@ GET /api/articles?populate[blocks][on][blocks.related-articles][populate][articl ``` - + ```json { diff --git a/docusaurus/src/components/ApiReference/Responses.jsx b/docusaurus/src/components/ApiReference/Responses.jsx index ab262cabb9..bf118f88b6 100644 --- a/docusaurus/src/components/ApiReference/Responses.jsx +++ b/docusaurus/src/components/ApiReference/Responses.jsx @@ -2,6 +2,7 @@ import React, { Children, isValidElement } from 'react'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import clsx from 'clsx'; +import ExpandableContent from '../ExpandableContent'; import styles from './api-reference.module.scss'; /** @@ -23,7 +24,7 @@ function labelClass(status) { return status < 400 ? styles['responseStatus--ok'] : styles['responseStatus--err']; } -export function ResponseTab({ status, statusText = '', children }) { +export function ResponseTab({ status, statusText = '', collapsible = false, children }) { const s = Number(status); return ( <> @@ -33,7 +34,11 @@ export function ResponseTab({ status, statusText = '', children }) { {s} {statusText}
- {children} + {collapsible ? ( + {children} + ) : ( + children + )} ); } From 35358b5bb6263b68e607aa878b20f5b8031dfe1b Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:06:40 +0200 Subject: [PATCH 21/55] Align terminal Ask AI button color and nudge param descriptions Give the terminal Ask AI button the same icon/label color and rest opacity as the copy/wrap buttons so all three match before hover. Add a 6px top padding to parameter descriptions so they line up with the required/optional badge on the same row. --- .../ApiReference/api-reference.module.scss | 3 ++ docusaurus/src/scss/code-block.scss | 28 ++++++------------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss index 2023d183f7..d35cf8dfd4 100644 --- a/docusaurus/src/components/ApiReference/api-reference.module.scss +++ b/docusaurus/src/components/ApiReference/api-reference.module.scss @@ -382,6 +382,9 @@ font-size: 13px; line-height: 1.5; color: var(--strapi-fg-3); + // Nudge down to visually align the description text with the + // required/optional badge on the same row. + padding-top: 6px; code { font-family: var(--strapi-font-family-mono); diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index 4f4ebd1952..9767d99a3a 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -273,33 +273,23 @@ pre.prism-code { background: var(--strapi-neutral-0) !important; border: 1px solid var(--strapi-neutral-200) !important; - // Dimmed at rest (like the copy/wrap icons), full opacity on hover. - // !important beats the legacy .clean-btn opacity:1 rules (this button also - // carries the clean-btn class). - i { - font-size: 12px; - color: var(--strapi-primary-500); + // Same color + opacity as the copy/wrap buttons (which use --strapi-fg-1 + // at 0.6 opacity), so all three action buttons match at rest. !important + // beats the legacy .clean-btn rules (this button also carries clean-btn). + i, span { + color: var(--strapi-fg-1) !important; opacity: 0.6 !important; } - span { - color: var(--strapi-fg-1); - opacity: 0.6 !important; + i { + font-size: 12px; } - // On hover only darken the label + icon and bring them to full opacity; - // keep background and border as-is. The button also carries the `clean-btn` - // class, whose legacy :hover would otherwise tint the background grey. + // On hover: full opacity, matching the copy/wrap icons. &:hover { background: var(--strapi-neutral-0) !important; - i { - color: var(--strapi-primary-700) !important; - opacity: 1 !important; - } - - span { - color: var(--strapi-neutral-800) !important; + i, span { opacity: 1 !important; } } From bf6173dea5a01e3a4577d10ef1cc11bc402320dc Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:07:58 +0200 Subject: [PATCH 22/55] Remove top margin above parameter types Drop the 2px top margin on parameter type labels so the type sits directly under the parameter name in REST API parameter tables. --- docusaurus/src/components/ApiReference/api-reference.module.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss index d35cf8dfd4..b1923e4d96 100644 --- a/docusaurus/src/components/ApiReference/api-reference.module.scss +++ b/docusaurus/src/components/ApiReference/api-reference.module.scss @@ -356,7 +356,6 @@ font-family: var(--strapi-font-family-mono); font-size: 11px; color: var(--strapi-fg-4); - margin-top: 2px; } &__badge { From 38a5d1f93e5aef92b2ff966fe765d227b993d8f0 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Mon, 20 Jul 2026 18:20:45 +0200 Subject: [PATCH 23/55] Remove blinking cursor from terminal code blocks Stop injecting the end-of-line blinking cursor in terminal code blocks; the wrapper ref now only relocates the action buttons into the title bar. --- docusaurus/src/theme/CodeBlock/index.js | 35 +++---------------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/docusaurus/src/theme/CodeBlock/index.js b/docusaurus/src/theme/CodeBlock/index.js index cb68422675..b4bb56d5e2 100644 --- a/docusaurus/src/theme/CodeBlock/index.js +++ b/docusaurus/src/theme/CodeBlock/index.js @@ -155,41 +155,12 @@ export default function CodeBlockWrapper(props) { requestAnimationFrame(() => requestAnimationFrame(move)); }, []); + // Ref callback for the terminal wrapper. Only relocates the action buttons + // into the title bar; the blinking end-of-line cursor was removed. const injectCursor = useCallback((node) => { terminalRef.current = node; if (node) relocateButtons(node); - if (!node) return; - - // Find the last token line and append a real cursor span - const injectCursorElement = () => { - // Remove any previously injected cursor - const existing = node.querySelector('.terminal-cursor'); - if (existing) existing.remove(); - - const codeEl = node.querySelector('code'); - if (!codeEl) return; - - const lastLine = codeEl.querySelector('.token-line:last-child'); - if (!lastLine) return; - - const cursor = document.createElement('span'); - cursor.className = 'terminal-cursor'; - - // Insert before the trailing
so the cursor stays on the same line - const lastBr = lastLine.querySelector('br:last-child'); - if (lastBr) { - lastLine.insertBefore(cursor, lastBr); - lastBr.remove(); - } else { - lastLine.appendChild(cursor); - } - }; - - // Run after Docusaurus finishes rendering the code block - requestAnimationFrame(() => { - requestAnimationFrame(injectCursorElement); - }); - }, []); + }, [relocateButtons]); // Terminal blocks: macOS-style wrapper with title bar + blinking cursor if (isTerminal) { From a18b12ff90820e44367ff47ccdd5f531b36c8450 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 10:53:07 +0200 Subject: [PATCH 24/55] Use real cURL commands in REST API request examples Replace raw URL/HTTP request snippets (GET /api/..., POST http://...) under the cURL tabs with real curl commands including the Authorization header, and -X/-H/-d for POST/PUT/DELETE, matching the main REST reference page. --- docusaurus/docs/cms/api/rest/filters.md | 20 +++-- docusaurus/docs/cms/api/rest/locale.md | 81 +++++++++++-------- .../docs/cms/api/rest/populate-select.md | 15 ++-- .../docs/cms/api/rest/sort-pagination.md | 20 +++-- 4 files changed, 81 insertions(+), 55 deletions(-) diff --git a/docusaurus/docs/cms/api/rest/filters.md b/docusaurus/docs/cms/api/rest/filters.md index 22bf630cc2..bd25a57928 100644 --- a/docusaurus/docs/cms/api/rest/filters.md +++ b/docusaurus/docs/cms/api/rest/filters.md @@ -94,10 +94,11 @@ By default, the filters can only be used from `find` endpoints generated by the description="Use the $eq filter operator to find an exact match."> - + ```bash -GET /api/users?filters[username][$eq]=John +curl 'http://localhost:1337/api/users?filters[username][$eq]=John' \ + -H 'Authorization: Bearer ' ``` @@ -165,10 +166,11 @@ await request(`/api/users?${query}`); description="Use the $in filter operator with an array of values to find multiple exact values."> - + ```bash -GET /api/restaurants?filters[id][$in][0]=3&filters[id][$in][1]=6&filters[id][$in][2]=8 +curl 'http://localhost:1337/api/restaurants?filters[id][$in][0]=3&filters[id][$in][1]=6&filters[id][$in][2]=8' \ + -H 'Authorization: Bearer ' ``` @@ -232,10 +234,11 @@ await request(`/api/restaurants?${query}`); description="Combine $and and $or operators for complex filtering."> - + ```bash -GET /api/books?filters[$and][0][$or][0][date][$eq]=2020-01-01&filters[$and][0][$or][1][date][$eq]=2020-01-02&filters[$and][1][author][name][$eq]=Kai%20doe +curl 'http://localhost:1337/api/books?filters[$and][0][$or][0][date][$eq]=2020-01-01&filters[$and][0][$or][1][date][$eq]=2020-01-02&filters[$and][1][author][name][$eq]=Kai%20doe' \ + -H 'Authorization: Bearer ' ``` @@ -331,10 +334,11 @@ Querying your API with deep filters may cause performance issues. If one of you description="Use deep filtering to filter on a relation's fields."> - + ```bash -GET /api/restaurants?filters[chef][restaurants][stars][$eq]=5 +curl 'http://localhost:1337/api/restaurants?filters[chef][restaurants][stars][$eq]=5' \ + -H 'Authorization: Bearer ' ``` diff --git a/docusaurus/docs/cms/api/rest/locale.md b/docusaurus/docs/cms/api/rest/locale.md index 468a51a134..5b66b74e62 100644 --- a/docusaurus/docs/cms/api/rest/locale.md +++ b/docusaurus/docs/cms/api/rest/locale.md @@ -78,7 +78,8 @@ The following table lists the new possible use cases added by i18n to the REST A description="Returns all documents for a given locale."> ```bash -GET http://localhost:1337/api/restaurants?locale=fr +curl 'http://localhost:1337/api/restaurants?locale=fr' \ + -H 'Authorization: Bearer ' ``` @@ -145,7 +146,8 @@ To get a specific document in a collection type in a given locale, add the `loca description="Returns a specific document in a collection type for a given locale."> ```bash -GET /api/restaurants/lr5wju2og49bf820kj9kz8c3?locale=fr +curl 'http://localhost:1337/api/restaurants/lr5wju2og49bf820kj9kz8c3?locale=fr' \ + -H 'Authorization: Bearer ' ``` @@ -200,7 +202,8 @@ To get a specific single type document in a given locale, add the `locale` param description="Returns a specific single type document for a given locale."> ```bash -GET /api/homepage?locale=fr +curl 'http://localhost:1337/api/homepage?locale=fr' \ + -H 'Authorization: Bearer ' ``` @@ -248,13 +251,15 @@ If no locale has been passed in the request body, the document is created using description="Creates a new document using the default locale."> ```bash -POST http://localhost:1337/api/restaurants - -{ - "data": { - "Name": "Oplato" - } -} +curl -X POST \ + 'http://localhost:1337/api/restaurants' \ + -H 'Authorization: Bearer ' \ + -H 'Content-Type: application/json' \ + -d '{ + "data": { + "Name": "Oplato" + } + }' ``` @@ -293,13 +298,15 @@ To create a localized entry for a locale different from the default one, add the description="Creates a new document for a specified locale."> ```bash -POST http://localhost:1337/api/restaurants?locale=fr - -{ - "data": { - "Name": "She's Cake" - } -} +curl -X POST \ + 'http://localhost:1337/api/restaurants?locale=fr' \ + -H 'Authorization: Bearer ' \ + -H 'Content-Type: application/json' \ + -d '{ + "data": { + "Name": "She'\''s Cake" + } + }' ``` @@ -364,13 +371,15 @@ To create a new locale for an existing document in a collection type, add the `l description="Creates a French locale for an existing restaurant, or updates it if it already exists."> ```bash -PUT http://localhost:1337/api/restaurants/lr5wju2og49bf820kj9kz8c3?locale=fr - -{ - "data": { - "Name": "She's Cake in French" - } -} +curl -X PUT \ + 'http://localhost:1337/api/restaurants/lr5wju2og49bf820kj9kz8c3?locale=fr' \ + -H 'Authorization: Bearer ' \ + -H 'Content-Type: application/json' \ + -d '{ + "data": { + "Name": "She'\''s Cake in French" + } + }' ``` @@ -409,13 +418,15 @@ To create a new locale for an existing single type document, add the `locale` pa description="Creates a French locale for an existing Homepage single type, or updates it if it already exists."> ```bash -PUT http://localhost:1337/api/homepage?locale=fr - -{ - "data": { - "Title": "Page d'accueil" - } -} +curl -X PUT \ + 'http://localhost:1337/api/homepage?locale=fr' \ + -H 'Authorization: Bearer ' \ + -H 'Content-Type: application/json' \ + -d '{ + "data": { + "Title": "Page d'\''accueil" + } + }' ``` @@ -462,7 +473,9 @@ To delete only a specific locale version of a document in a collection type, add description="Deletes a specific locale version of a document in a collection type."> ```bash -DELETE /api/restaurants/abcdefghijklmno456?locale=fr +curl -X DELETE \ + 'http://localhost:1337/api/restaurants/abcdefghijklmno456?locale=fr' \ + -H 'Authorization: Bearer ' ``` @@ -489,7 +502,9 @@ To delete only a specific locale version of a single type document, add the `loc description="Deletes a specific locale version of a single type document."> ```bash -DELETE /api/homepage?locale=fr +curl -X DELETE \ + 'http://localhost:1337/api/homepage?locale=fr' \ + -H 'Authorization: Bearer ' ``` diff --git a/docusaurus/docs/cms/api/rest/populate-select.md b/docusaurus/docs/cms/api/rest/populate-select.md index 89be62c3c6..a754c15b0f 100644 --- a/docusaurus/docs/cms/api/rest/populate-select.md +++ b/docusaurus/docs/cms/api/rest/populate-select.md @@ -58,10 +58,11 @@ Field selection does not work on relational, media, component, or dynamic zone f description="Use the fields parameter to select only specific fields in the response."> - + ```bash -GET /api/restaurants?fields[0]=name&fields[1]=description +curl 'http://localhost:1337/api/restaurants?fields[0]=name&fields[1]=description' \ + -H 'Authorization: Bearer ' ``` @@ -177,10 +178,11 @@ Top-level pagination parameters (e.g., `pagination[page]` and `pagination[pageSi description="Combine fields and populate parameters to select specific fields on both the main entry and its relations."> - + ```bash -GET /api/articles?fields[0]=title&fields[1]=slug&populate[headerImage][fields][0]=name&populate[headerImage][fields][1]=url +curl 'http://localhost:1337/api/articles?fields[0]=title&fields[1]=slug&populate[headerImage][fields][0]=name&populate[headerImage][fields][1]=url' \ + -H 'Authorization: Bearer ' ``` @@ -247,10 +249,11 @@ await request(`/api/articles?${query}`); description="Combine populate with sort and filter parameters to refine which related entries are returned."> - + ```bash -GET /api/articles?populate[categories][sort][0]=name%3Aasc&populate[categories][filters][name][$eq]=Cars +curl 'http://localhost:1337/api/articles?populate[categories][sort][0]=name%3Aasc&populate[categories][filters][name][$eq]=Cars' \ + -H 'Authorization: Bearer ' ``` diff --git a/docusaurus/docs/cms/api/rest/sort-pagination.md b/docusaurus/docs/cms/api/rest/sort-pagination.md index 4cc0ee1c99..2e51a6b42f 100644 --- a/docusaurus/docs/cms/api/rest/sort-pagination.md +++ b/docusaurus/docs/cms/api/rest/sort-pagination.md @@ -62,10 +62,11 @@ You can sort by multiple fields by passing fields in a `sort` array. description="Sort results by Description and Name fields."> - + ```bash -GET /api/restaurants?sort[0]=Description&sort[1]=Name +curl 'http://localhost:1337/api/restaurants?sort[0]=Description&sort[1]=Name' \ + -H 'Authorization: Bearer ' ``` @@ -150,10 +151,11 @@ Using the `sort` parameter and defining `:asc` or `:desc` on sorted fields, you description="Sort results by Description ascending and Name descending."> - + ```bash -GET /api/restaurants?sort[0]=Description:asc&sort[1]=Name:desc +curl 'http://localhost:1337/api/restaurants?sort[0]=Description:asc&sort[1]=Name:desc' \ + -H 'Authorization: Bearer ' ``` @@ -254,10 +256,11 @@ To paginate results by page, use the following parameters: description="Return only 10 entries on page 1."> - + ```bash -GET /api/articles?pagination[page]=1&pagination[pageSize]=10 +curl 'http://localhost:1337/api/articles?pagination[page]=1&pagination[pageSize]=10' \ + -H 'Authorization: Bearer ' ``` @@ -325,10 +328,11 @@ The default and maximum values for `pagination[limit]` can be [configured in the description="Return only the first 10 entries using offset."> - + ```bash -GET /api/articles?pagination[start]=0&pagination[limit]=10 +curl 'http://localhost:1337/api/articles?pagination[start]=0&pagination[limit]=10' \ + -H 'Authorization: Bearer ' ``` From 24a43f37a2fc22bc63b58d0adb86f62dd71e664c Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 11:25:39 +0200 Subject: [PATCH 25/55] Remove empty gap above code in terminal blocks on mobile On mobile, code blocks add a 48px top padding to clear the always-visible floating action buttons. Terminal blocks keep their buttons in the title bar, so that padding left a large empty gap above the code. Reset it to 0 for terminal blocks while leaving regular code blocks unchanged. --- docusaurus/src/scss/code-block.scss | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index 9767d99a3a..973c57765d 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -722,6 +722,18 @@ pre.prism-code { padding-top: 48px; } } + } + + // Terminal blocks keep their action buttons in the title bar even on mobile, + // so the 48px top padding (meant to clear floating buttons) just leaves a big + // empty gap above the code. Remove it here. + .code-block-enhanced .theme-code-block { + &[class*="codeBlockContainer"], + [class*="codeBlockContainer"] { + [class*="codeBlockContent"] { + padding-top: 0; + } + } // Reset button position on mobile (don't put them in title bar) &:has([class*="codeBlockTitle"]) { From 44961101e93304c25d5768a66bfeaf5f66b9d74f Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 11:33:03 +0200 Subject: [PATCH 26/55] Add cURL and JavaScript tabs to understanding-populate examples Replace the single terminal-style request in each understanding-populate example with two tabs (cURL and JavaScript), consistent with the main REST reference page. The JavaScript tab uses fetch with the request URL directly. --- .../api/rest/guides/understanding-populate.md | 216 +++++++++++++++++- 1 file changed, 207 insertions(+), 9 deletions(-) diff --git a/docusaurus/docs/cms/api/rest/guides/understanding-populate.md b/docusaurus/docs/cms/api/rest/guides/understanding-populate.md index ba3749370a..07716c63d9 100644 --- a/docusaurus/docs/cms/api/rest/guides/understanding-populate.md +++ b/docusaurus/docs/cms/api/rest/guides/understanding-populate.md @@ -91,10 +91,32 @@ Notice how the response only includes the `title`, `slug`, `createdAt`, `updated title="Without populate" description="Returns only default attributes, without any media fields, relations, components, or dynamic zones."> + + + ```bash -GET /api/articles +curl 'http://localhost:1337/api/articles' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const response = await fetch( + 'http://localhost:1337/api/articles', + { + headers: { + Authorization: 'Bearer ', + }, + } +); +const data = await response.json(); ``` + + + @@ -187,10 +209,32 @@ To populate deeply nested components, see the [populate components](#populate-co title="With populate=*" description="Returns all media fields, first-level relations, components, and dynamic zones."> + + + ```bash -GET /api/articles?populate=* +curl 'http://localhost:1337/api/articles?populate=*' \ + -H 'Authorization: Bearer ' ``` + + + +```js +const response = await fetch( + 'http://localhost:1337/api/articles?populate=*', + { + headers: { + Authorization: 'Bearer ', + }, + } +); +const data = await response.json(); +``` + + + + @@ -437,10 +481,32 @@ Notice that the response does not include any media fields, relations, component title="Without populate" description="Returns only default attributes for all articles."> + + + ```bash -GET /api/articles +curl 'http://localhost:1337/api/articles' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const response = await fetch( + 'http://localhost:1337/api/articles', + { + headers: { + Authorization: 'Bearer ', + }, + } +); +const data = await response.json(); ``` + + + @@ -523,10 +589,32 @@ Notice that the response now includes additional data with the `category` field title="With populate[0]=category" description="Returns articles with their related category data populated."> + + + ```bash -GET /api/articles?populate[0]=category +curl 'http://localhost:1337/api/articles?populate[0]=category' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const response = await fetch( + 'http://localhost:1337/api/articles?populate[0]=category', + { + headers: { + Authorization: 'Bearer ', + }, + } +); +const data = await response.json(); ``` + + + @@ -680,10 +768,32 @@ When we only populate 1 level deep, asking for the categories associated to arti title="With 1-level deep population" description="Populates the category relation 1 level deep."> + + + ```bash -GET /api/articles?populate[0]=category +curl 'http://localhost:1337/api/articles?populate[0]=category' \ + -H 'Authorization: Bearer ' ``` + + + +```js +const response = await fetch( + 'http://localhost:1337/api/articles?populate[0]=category', + { + headers: { + Authorization: 'Bearer ', + }, + } +); +const data = await response.json(); +``` + + + + @@ -803,10 +913,32 @@ Notice that we now have the `restaurants` relation field included with the respo title="With 2-level deep population" description="Populates the category relation and the nested restaurants relation 2 levels deep."> + + + ```bash -GET /api/articles?populate[category][populate][0]=restaurants +curl 'http://localhost:1337/api/articles?populate[category][populate][0]=restaurants' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const response = await fetch( + 'http://localhost:1337/api/articles?populate[category][populate][0]=restaurants', + { + headers: { + Authorization: 'Bearer ', + }, + } +); +const data = await response.json(); ``` + + + @@ -945,10 +1077,32 @@ Notice there's no mention of the `metaSocial` component nested within the `seo` title="Only 1st level component" description="Populates only the seo component, 1 level deep."> + + + ```bash -GET /api/articles?populate[0]=seo +curl 'http://localhost:1337/api/articles?populate[0]=seo' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const response = await fetch( + 'http://localhost:1337/api/articles?populate[0]=seo', + { + headers: { + Authorization: 'Bearer ', + }, + } +); +const data = await response.json(); ``` + + + @@ -1019,10 +1173,32 @@ Notice that we now have the `metaSocial` component-related data included with th title="1st level and 2nd level component" description="Populates the seo component and the nested metaSocial component."> + + + ```bash -GET /api/articles?populate[0]=seo&populate[1]=seo.metaSocial +curl 'http://localhost:1337/api/articles?populate[0]=seo&populate[1]=seo.metaSocial' \ + -H 'Authorization: Bearer ' +``` + + + + +```js +const response = await fetch( + 'http://localhost:1337/api/articles?populate[0]=seo&populate[1]=seo.metaSocial', + { + headers: { + Authorization: 'Bearer ', + }, + } +); +const data = await response.json(); ``` + + + @@ -1377,10 +1553,32 @@ In the following example response, highlighted lines show that: title="Detailed population strategy for dynamic zones" description="Populates the blocks dynamic zone using a detailed per-component population strategy."> + + + ```bash -GET /api/articles?populate[blocks][on][blocks.related-articles][populate][articles][populate][0]=image&populate[blocks][on][blocks.cta-command-line][populate]=* +curl 'http://localhost:1337/api/articles?populate[blocks][on][blocks.related-articles][populate][articles][populate][0]=image&populate[blocks][on][blocks.cta-command-line][populate]=*' \ + -H 'Authorization: Bearer ' ``` + + + +```js +const response = await fetch( + 'http://localhost:1337/api/articles?populate[blocks][on][blocks.related-articles][populate][articles][populate][0]=image&populate[blocks][on][blocks.cta-command-line][populate]=*', + { + headers: { + Authorization: 'Bearer ', + }, + } +); +const data = await response.json(); +``` + + + + From 41cee798ac0f1b1041fe17330ee8ccccdebdf6a0 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 11:43:33 +0200 Subject: [PATCH 27/55] Align terminal code with the title bar left edge Terminal code blocks indented the code far to the right (line-number padding it never uses). Remove the code's left padding and the lines container's left padding so the code lines up with the title-bar traffic-light dots. --- docusaurus/src/scss/code-block.scss | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index 973c57765d..ce5cd16338 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -382,7 +382,11 @@ pre.prism-code { background-color: transparent !important; code { - padding: 16px 24px; + // Align the code's left edge with the title-bar content (traffic-light + // dots) instead of the deep default indent. The wrapper's .language-* + // container already provides the left margin, so the code itself only + // needs vertical padding + a small right pad for the scrollbar. + padding: 16px 24px 16px 0; background: transparent !important; background-color: transparent !important; @@ -391,6 +395,12 @@ pre.prism-code { background-color: var(--strapi-primary-500) !important; } } + + // Remove the default 24px left padding on the lines container (meant to + // make room for line numbers, which terminal blocks don't show). + [class*="codeBlockLines"] { + padding-left: 0 !important; + } } } From 79e21192d32fc2bc08bf0fa5f00d9ef97459469c Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 12:02:33 +0200 Subject: [PATCH 28/55] Fix action button position and code block spacing in tabs For titleless non-terminal code blocks, lift the copy/wrap/Ask AI button group into the empty space above the code (top:-32px) instead of overlapping the first lines. Remove the extra bottom margin on code blocks inside tab panels (both terminal and regular) so the vertical space above and below the code is balanced. --- docusaurus/src/scss/code-block.scss | 7 +++++++ docusaurus/src/scss/tabs.scss | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index ce5cd16338..a0ae68b294 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -472,6 +472,13 @@ pre.prism-code { padding: 0; } } + + // No title bar to host the action buttons, so lift the button group up + // into the empty space above the code instead of letting it overlap the + // first lines. (Titled blocks are handled separately further down.) + [class*="buttonGroup"] { + top: -32px; + } } svg { diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss index 317452d169..28540de4f9 100644 --- a/docusaurus/src/scss/tabs.scss +++ b/docusaurus/src/scss/tabs.scss @@ -124,6 +124,9 @@ // Remove borders from code blocks inside tabs [class*="codeBlockContainer"]:not(:has([class*="codeBlockTitle"])) { border: none !important; + // Drop the default bottom margin: it left more empty space below the + // code than above it, unbalancing the block inside the tab panel. + margin-bottom: 0 !important; } [class*="codeBlockContainer"]:has([class*="codeBlockTitle"]) { @@ -146,7 +149,7 @@ } .theme-code-block { - margin: 0 20px 20px !important; + margin: 0 20px !important; border: 1px solid var(--custom-code-block-border-color) !important; border-top: none !important; border-radius: 0 0 var(--strapi-radius-md) var(--strapi-radius-md) !important; From 3d92ccfc28509790ff93e42a670f5c38fca43261 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 12:19:15 +0200 Subject: [PATCH 29/55] Scope lifted action buttons to titleless code blocks inside tabs The top:-32px lift for the action button group must apply only to titleless code blocks inside a tab panel (the request examples). Response blocks live outside any tab, so they keep the default top position with buttons in the block's top-right corner. Scoping the rule to tab panels fixes the response block regression without affecting other code block types. --- docusaurus/src/scss/code-block.scss | 7 ------- docusaurus/src/scss/tabs.scss | 8 ++++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index a0ae68b294..ce5cd16338 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -472,13 +472,6 @@ pre.prism-code { padding: 0; } } - - // No title bar to host the action buttons, so lift the button group up - // into the empty space above the code instead of letting it overlap the - // first lines. (Titled blocks are handled separately further down.) - [class*="buttonGroup"] { - top: -32px; - } } svg { diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss index 28540de4f9..e5451996eb 100644 --- a/docusaurus/src/scss/tabs.scss +++ b/docusaurus/src/scss/tabs.scss @@ -127,6 +127,14 @@ // Drop the default bottom margin: it left more empty space below the // code than above it, unbalancing the block inside the tab panel. margin-bottom: 0 !important; + + // A titleless code block inside a tab panel has no bar to host the + // action buttons, so lift the button group up into the empty space + // above the code instead of overlapping the first lines. Scoped to tab + // panels only, so response blocks (outside any tab) keep top:0. + [class*="buttonGroup"] { + top: -32px; + } } [class*="codeBlockContainer"]:has([class*="codeBlockTitle"]) { From 114b4bdce37cc8275726f2770c5b8693738df3b3 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 12:36:00 +0200 Subject: [PATCH 30/55] Align terminal window and code, dedupe copy button Inset the terminal window so its left border lines up with the response block's opening brace, and indent the terminal code so its first character sits under the title bar's first traffic-light dot. Also remove the duplicate copy button that React re-inserted into the code area after the button group was relocated to the title bar (a MutationObserver now drops stray groups). --- docusaurus/src/scss/code-block.scss | 12 +++++------- docusaurus/src/scss/tabs.scss | 14 +++++++++++--- docusaurus/src/theme/CodeBlock/index.js | 24 ++++++++++++++++++++---- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index ce5cd16338..54d5af34a1 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -382,10 +382,8 @@ pre.prism-code { background-color: transparent !important; code { - // Align the code's left edge with the title-bar content (traffic-light - // dots) instead of the deep default indent. The wrapper's .language-* - // container already provides the left margin, so the code itself only - // needs vertical padding + a small right pad for the scrollbar. + // Left inset is handled on the lines container below (18px); keep the + // code's own left padding at 0 to avoid stacking. padding: 16px 24px 16px 0; background: transparent !important; background-color: transparent !important; @@ -396,10 +394,10 @@ pre.prism-code { } } - // Remove the default 24px left padding on the lines container (meant to - // make room for line numbers, which terminal blocks don't show). + // The default lines-container padding (for line numbers) is replaced by + // an 18px inset so the code lines up under the title bar's first dot. [class*="codeBlockLines"] { - padding-left: 0 !important; + padding-left: 18px !important; } } } diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss index e5451996eb..494425331a 100644 --- a/docusaurus/src/scss/tabs.scss +++ b/docusaurus/src/scss/tabs.scss @@ -63,6 +63,7 @@ padding: 16px 20px; } + // Remove border for nested tabs container [role="tabpanel"] .tabs-container { border: none; @@ -127,6 +128,9 @@ // Drop the default bottom margin: it left more empty space below the // code than above it, unbalancing the block inside the tab panel. margin-bottom: 0 !important; + // Drop the container's own left padding; the tab panel's left padding + // provides the code's left inset, lining it up with the response code. + padding-left: 0 !important; // A titleless code block inside a tab panel has no bar to host the // action buttons, so lift the button group up into the empty space @@ -137,11 +141,15 @@ } } + [class*="codeBlockContainer"]:has([class*="codeBlockTitle"]) { margin: 22px 20px; } - // Enhanced terminal blocks inside tabs: remove double border, add spacing + // Enhanced terminal blocks inside tabs: remove double border, add spacing. + // The tab panel adds 20px left padding; the terminal window (title bar + + // code) is inset another 4px via its margin so its left border sits at + // 24px from the code column — lined up with the response block's `{`. .code-block-enhanced { border: none !important; border-radius: 0 !important; @@ -150,14 +158,14 @@ .code-title-bar { border-radius: 0; - margin: 0 20px; + margin: 0 4px; border: 1px solid var(--custom-code-block-border-color); border-bottom: 1px solid var(--code-title-bar-border); border-radius: var(--strapi-radius-md) var(--strapi-radius-md) 0 0; } .theme-code-block { - margin: 0 20px !important; + margin: 0 4px !important; border: 1px solid var(--custom-code-block-border-color) !important; border-top: none !important; border-radius: 0 0 var(--strapi-radius-md) var(--strapi-radius-md) !important; diff --git a/docusaurus/src/theme/CodeBlock/index.js b/docusaurus/src/theme/CodeBlock/index.js index b4bb56d5e2..7c781b7f60 100644 --- a/docusaurus/src/theme/CodeBlock/index.js +++ b/docusaurus/src/theme/CodeBlock/index.js @@ -147,12 +147,28 @@ export default function CodeBlockWrapper(props) { if (!wrapper) return; const move = () => { const actions = wrapper.querySelector('.code-title-bar__actions'); - const group = wrapper.querySelector('[class*="buttonGroup"]'); - if (!actions || !group) return; - if (group.parentElement === actions) return; // already moved - actions.appendChild(group); + if (!actions) return; + // Move the native copy/wrap group into the title bar. React can re-render + // its own group inside the code block afterwards, so also remove any + // stray groups left outside the title bar to avoid a duplicate button. + const groups = wrapper.querySelectorAll('[class*="buttonGroup"]'); + let kept = actions.querySelector('[class*="buttonGroup"]'); + groups.forEach((group) => { + if (group.closest('.code-title-bar__actions')) return; // already in the bar + if (!kept) { + actions.appendChild(group); // move the first one into the bar + kept = group; + } else { + group.remove(); // drop duplicates left in the code area + } + }); }; + // Run now and keep watching: React may re-insert a group after our move. requestAnimationFrame(() => requestAnimationFrame(move)); + const observer = new MutationObserver(move); + observer.observe(wrapper, { childList: true, subtree: true }); + // Stop observing shortly after mount once the DOM has settled. + setTimeout(() => observer.disconnect(), 2000); }, []); // Ref callback for the terminal wrapper. Only relocates the action buttons From 9a1d755101d580aa9aa2ae821777c1314988f499 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 12:43:11 +0200 Subject: [PATCH 31/55] Align endpoint tab pills and unify request/response border color In API endpoint blocks: align the tab pills' left edge with the terminal window (24px) via the first pill's margin, give the tab bar a 12px vertical padding (half the horizontal inset) so the active pill isn't cramped against the top border, and match the request tabs container border color to the response block's border. --- docusaurus/src/scss/tabs.scss | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss index 494425331a..c0912429e7 100644 --- a/docusaurus/src/scss/tabs.scss +++ b/docusaurus/src/scss/tabs.scss @@ -48,6 +48,12 @@ border-radius: var(--strapi-radius-md, 10px); border: solid 1px var(--strapi-neutral-150); overflow: hidden; // Prevents children from overflowing the border-radius + + // In API endpoint blocks, match the response block's border color so the + // request (tabs) and response outer borders look identical. + .api-endpoint-block & { + border-color: var(--strapi-border-strong); + } .margin-top--md { margin-top: 24px !important; @@ -91,6 +97,17 @@ } } + // In API endpoint blocks, align the tab pills with the terminal window's + // left edge (24px) and give the tab bar a vertical padding of half that + // (12px) so the active pill isn't cramped against the block's top border. + .api-endpoint-block & { + padding: 12px 0; + + [role="tab"]:nth-child(1) { + margin-left: 24px !important; + } + } + // Active tab styles [aria-selected="true"] { border-bottom: none; From a8eaa6decb9746a61867e19d7d9d6f667066e7d4 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 14:42:39 +0200 Subject: [PATCH 32/55] Harmonize code block spacing, radius, borders and Ask AI icon Match the tab bar's bottom gap to the top gap above the pills; use the admonition corner radius (4px) on request/response/terminal blocks; drop the extra top padding above titleless request code inside tabs; make the request tabs border match the response border in both light and dark; and use the filled sparkle icon for the Ask AI button, matching the navbar. --- docusaurus/src/scss/code-block.scss | 16 ++++++++++++++ docusaurus/src/scss/tabs.scss | 29 ++++++++++++++++++++----- docusaurus/src/theme/CodeBlock/index.js | 4 ++-- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index 54d5af34a1..898df0ea52 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -859,3 +859,19 @@ pre.prism-code { } } } + +/* ────────────────────────────────────────────────────── + API endpoint code blocks: match the admonition corner radius + ────────────────────────────────────────────────────── */ +// The request (tabs), response, and terminal blocks used a 10px radius while +// admonitions use 4px. Align them to the admonition radius (--strapi-radius-xs) +// so all boxed content on the page shares the same corners. Scoped to endpoints. +.api-endpoint-block { + .tabs-container, + [class*="responses"] [class*="codeBlockContainer"], + .code-block-enhanced { + border-radius: var(--strapi-radius-xs) !important; + } + // The terminal window's inner corners (title bar top / code block bottom) + // are set to --strapi-radius-xs directly in tabs.scss. +} diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss index c0912429e7..eda650aa18 100644 --- a/docusaurus/src/scss/tabs.scss +++ b/docusaurus/src/scss/tabs.scss @@ -50,9 +50,12 @@ overflow: hidden; // Prevents children from overflowing the border-radius // In API endpoint blocks, match the response block's border color so the - // request (tabs) and response outer borders look identical. + // request (tabs) and response outer borders look identical in both light + // and dark. The response uses --custom-code-block-border-color, so reuse + // that exact variable here rather than --strapi-border-strong (which + // resolves to a different value in dark mode). .api-endpoint-block & { - border-color: var(--strapi-border-strong); + border-color: var(--custom-code-block-border-color); } .margin-top--md { @@ -69,6 +72,13 @@ padding: 16px 20px; } + // In API endpoint blocks, use a 21px top padding so the gap between the + // tab bar's bottom border and the terminal window matches the gap above + // the active tab pill (harmonized vertical spacing). + .api-endpoint-block & [role="tabpanel"] { + padding-top: 21px; + } + // Remove border for nested tabs container [role="tabpanel"] .tabs-container { @@ -148,6 +158,9 @@ // Drop the container's own left padding; the tab panel's left padding // provides the code's left inset, lining it up with the response code. padding-left: 0 !important; + // Drop the container's top padding too: the tab panel already provides + // the space above the code, so the extra 24px just pushed it down. + padding-top: 0 !important; // A titleless code block inside a tab panel has no bar to host the // action buttons, so lift the button group up into the empty space @@ -178,14 +191,14 @@ margin: 0 4px; border: 1px solid var(--custom-code-block-border-color); border-bottom: 1px solid var(--code-title-bar-border); - border-radius: var(--strapi-radius-md) var(--strapi-radius-md) 0 0; + border-radius: var(--strapi-radius-xs) var(--strapi-radius-xs) 0 0; } .theme-code-block { margin: 0 4px !important; border: 1px solid var(--custom-code-block-border-color) !important; border-top: none !important; - border-radius: 0 0 var(--strapi-radius-md) var(--strapi-radius-md) !important; + border-radius: 0 0 var(--strapi-radius-xs) var(--strapi-radius-xs) !important; } } } @@ -241,7 +254,13 @@ details { :root body { --tabs-active-bg: rgba(73, 69, 255, 0.2); // Slightly different background in dark mode } - + + // Match the response block's dark-mode border (which uses --strapi-neutral-200) + // so the request (tabs) and response outer borders stay identical in dark too. + .api-endpoint-block .tabs-container { + border-color: var(--strapi-neutral-200); + } + .tabs__item:not(.tabs__item--active) { color: var(--strapi-neutral-400); } diff --git a/docusaurus/src/theme/CodeBlock/index.js b/docusaurus/src/theme/CodeBlock/index.js index 7c781b7f60..2efc434253 100644 --- a/docusaurus/src/theme/CodeBlock/index.js +++ b/docusaurus/src/theme/CodeBlock/index.js @@ -69,7 +69,7 @@ function useInjectAIButton(ref, language, codeContent, showAI) { btn.className = 'clean-btn ai-button-injected'; btn.title = 'Ask AI to explain this code'; btn.setAttribute('aria-label', 'Ask AI to explain this code example'); - btn.innerHTML = 'Ask AI'; + btn.innerHTML = 'Ask AI'; btn.addEventListener('click', () => handleAskAI(language, codeContent)); container.prepend(btn); @@ -104,7 +104,7 @@ function TerminalTitleBar({ language, title, showAI, codeContent }) { aria-label="Ask AI to explain this code example" onClick={() => handleAskAI(language, codeContent)} > - + Ask AI )} From 6cf162b220be89430455f80452c82960228561e5 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 14:52:22 +0200 Subject: [PATCH 33/55] Apply terminal radius and code alignment to all terminal blocks Move the 4px corner radius onto .code-block-enhanced itself and raise the specificity of the container padding reset so standalone terminal blocks (outside API endpoints, e.g. the quick-start guide) get the same 4px corners and left-aligned code (under the first title-bar dot) as those inside endpoints. --- docusaurus/src/scss/code-block.scss | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index 898df0ea52..dda3ea62b7 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -323,10 +323,11 @@ pre.prism-code { ────────────────────────────────────────────────────── */ .code-block-enhanced { - // The wrapper provides the border, radius, and background + // The wrapper provides the border, radius, and background. Use the same + // corner radius as admonitions (--strapi-radius-xs) for all terminal blocks. position: relative; border: solid 1px var(--custom-code-block-border-color); - border-radius: var(--strapi-radius-md); + border-radius: var(--strapi-radius-xs); overflow: hidden; transition: border-color var(--strapi-duration-fast) var(--strapi-ease); margin-bottom: var(--ifm-leading); @@ -366,10 +367,15 @@ pre.prism-code { } // Code block container inside enhanced wrapper - // All backgrounds are transparent — the wrapper controls the bg + // All backgrounds are transparent — the wrapper controls the bg. + // The :not(:has(codeBlockTitle)) variants raise specificity to beat the + // generic `.theme-code-block[codeBlockContainer]:not(:has(title)) { padding:24px }` + // rule, so terminal code isn't pushed in by that 24px padding. .theme-code-block, .theme-code-block[class*="codeBlockContainer"], - .theme-code-block [class*="codeBlockContainer"] { + .theme-code-block[class*="codeBlockContainer"]:not(:has([class*="codeBlockTitle"])), + .theme-code-block [class*="codeBlockContainer"], + .theme-code-block [class*="codeBlockContainer"]:not(:has([class*="codeBlockTitle"])) { padding: 0 !important; box-shadow: none !important; background: transparent !important; From 56c03c717a99fb008aca500995ce7c1bd1b0f23e Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:00:20 +0200 Subject: [PATCH 34/55] Align response block header and code with the active status pill, and remove terminal-in-tab top gap --- docusaurus/src/scss/tabs.scss | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss index eda650aa18..c991df9bce 100644 --- a/docusaurus/src/scss/tabs.scss +++ b/docusaurus/src/scss/tabs.scss @@ -73,12 +73,28 @@ } // In API endpoint blocks, use a 21px top padding so the gap between the - // tab bar's bottom border and the terminal window matches the gap above - // the active tab pill (harmonized vertical spacing). + // tab bar's bottom border and the code matches the gap above the active + // tab pill (harmonized vertical spacing). .api-endpoint-block & [role="tabpanel"] { padding-top: 21px; } + // Exception: when the tab panel holds a terminal block, drop the top + // padding to 0 — the terminal's own title bar already provides the spacing, + // so the 21px just left an empty gap between the tab bar and the window. + .api-endpoint-block & [role="tabpanel"]:has(.code-block-enhanced) { + padding-top: 0; + } + + // Response blocks (200/404 status tabs): the active status pill sits at + // 24px (nth-child margin-left), but the panel's default 20px left padding + // left the status header (● 200 OK) and the JSON's opening `{` 4px to the + // left of the pill. Bump the response panel's left padding to 24px so the + // dot, the label, and the code all line up with the active pill's left edge. + .api-endpoint-block [class*="responses"] & [role="tabpanel"] { + padding-left: 24px; + } + // Remove border for nested tabs container [role="tabpanel"] .tabs-container { From d40f798dd3ab2b74ca47de8af535d7e6c14bd94b Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:03:45 +0200 Subject: [PATCH 35/55] Preserve bottom padding of framed last children (admonitions, code) in details blocks --- docusaurus/src/scss/details.scss | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docusaurus/src/scss/details.scss b/docusaurus/src/scss/details.scss index 7987c35c54..7ccc09a235 100644 --- a/docusaurus/src/scss/details.scss +++ b/docusaurus/src/scss/details.scss @@ -81,10 +81,18 @@ details.alert { } > *:last-child { - padding-bottom: 0 !important; margin-bottom: 0 !important; } + // Strip the bottom padding of a plain (unframed) last child so its text does + // not add space on top of the block's own bottom padding. Framed blocks + // (admonitions, code blocks, tab containers) are excluded: their internal + // padding is part of their box, and zeroing it collapses their content + // against their own border. + > *:last-child:not(.theme-admonition):not([class*="admonition"]):not([class*="codeBlock"]):not(.tabs-container):not(.code-block-enhanced) { + padding-bottom: 0 !important; + } + // Only neutralize the top spacing of the first inner element, NOT the // content wrapper itself: the wrapper keeps its padding-top so the content // is separated from the summary (and its bottom border when open). From 70ef80cae22676241794fc23dab0e660276e4031 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:12:00 +0200 Subject: [PATCH 36/55] Align in-tab code with the tab label text and drop the button group below the tab bar --- docusaurus/src/scss/tabs.scss | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss index c991df9bce..4ddaf4aac3 100644 --- a/docusaurus/src/scss/tabs.scss +++ b/docusaurus/src/scss/tabs.scss @@ -171,19 +171,23 @@ // Drop the default bottom margin: it left more empty space below the // code than above it, unbalancing the block inside the tab panel. margin-bottom: 0 !important; - // Drop the container's own left padding; the tab panel's left padding - // provides the code's left inset, lining it up with the response code. - padding-left: 0 !important; + // Inset the code so its first character lines up with the left edge of + // the tab labels' TEXT (the "cURL" word), not the tab button box. The + // panel already provides 20px; add 18px so the code starts at ~38px, + // matching the tab label (button left 24px + its 14px inner padding). + padding-left: 18px !important; // Drop the container's top padding too: the tab panel already provides // the space above the code, so the extra 24px just pushed it down. padding-top: 0 !important; // A titleless code block inside a tab panel has no bar to host the - // action buttons, so lift the button group up into the empty space - // above the code instead of overlapping the first lines. Scoped to tab - // panels only, so response blocks (outside any tab) keep top:0. + // action buttons. Sit the button group just below the tab bar's bottom + // border (in the gap above the code) rather than straddling that border. + // The group is ~33px tall and the gap is ~23px, so it necessarily + // overlaps something: we let it overlap the code's right margin (bottom) + // instead of the tab bar (top), which reads much cleaner. [class*="buttonGroup"] { - top: -32px; + top: -17px; } } From b3322e3cd05c250e31faeaeb8e283d51b91aa62f Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:14:47 +0200 Subject: [PATCH 37/55] Align response header and code with the status pill label text --- docusaurus/src/scss/tabs.scss | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss index 4ddaf4aac3..fdfe08ae03 100644 --- a/docusaurus/src/scss/tabs.scss +++ b/docusaurus/src/scss/tabs.scss @@ -86,13 +86,19 @@ padding-top: 0; } - // Response blocks (200/404 status tabs): the active status pill sits at - // 24px (nth-child margin-left), but the panel's default 20px left padding - // left the status header (● 200 OK) and the JSON's opening `{` 4px to the - // left of the pill. Bump the response panel's left padding to 24px so the - // dot, the label, and the code all line up with the active pill's left edge. + // Response blocks (200/404 status tabs): align the status header + // (● 200 OK) and the JSON code with the left edge of the active status + // pill's TEXT — the "200" label, not the pill box. The pill box sits at + // 24px and its inner padding is 14px, so the label starts at ~38px. Give + // the panel a 38px left padding so the header (a direct child) lines up + // with the label; the code container's own padding is neutralized below so + // it inherits the same 38px inset. .api-endpoint-block [class*="responses"] & [role="tabpanel"] { - padding-left: 24px; + padding-left: 38px; + + [class*="codeBlockContainer"]:not(:has([class*="codeBlockTitle"])) { + padding-left: 0 !important; + } } From d2a6668ba5d97f1e51a2dae684c0f3fa400a0adb Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:18:19 +0200 Subject: [PATCH 38/55] Match Ask AI button icon and label to the copy/wrap buttons (neutral color, shared opacity) --- docusaurus/src/scss/code-block.scss | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index dda3ea62b7..0c48fba33b 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -639,29 +639,19 @@ pre.prism-code { border: none; transition: all 0.2s ease; + // Match the copy/wrap buttons exactly: same neutral icon+label color and the + // same 0.6→1 opacity fade (applied by the shared .clean-btn rules below). + // This button also carries .clean-btn, so we only need to size the icon here + // and NOT recolor it — a colored (purple) icon made Ask AI stand out from the + // neutral copy/wrap icons sitting right next to it on hover. i { font-size: 13px; - color: var(--strapi-primary-500); } span { - color: var(--strapi-neutral-600); font-size: 11px; font-weight: 600; } - - // On hover only darken the label + icon; keep the background unchanged. - // !important overrides the more specific .theme-code-block .clean-btn color - // rules (these buttons also carry the clean-btn class). - &:hover { - i { - color: var(--strapi-primary-700) !important; - } - - span { - color: var(--strapi-neutral-800) !important; - } - } } // Desktop: Button opacity behavior From 81ba8dc84dab5434c6d41bfad82ee44a86f0f33c Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:22:04 +0200 Subject: [PATCH 39/55] Fix terminal block rendering when it is a direct child of a details/StepDetails block --- docusaurus/src/scss/details.scss | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docusaurus/src/scss/details.scss b/docusaurus/src/scss/details.scss index 7ccc09a235..87dcf611f0 100644 --- a/docusaurus/src/scss/details.scss +++ b/docusaurus/src/scss/details.scss @@ -80,6 +80,15 @@ details.alert { padding: var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal); } + // A terminal code block (.code-block-enhanced) sitting as a direct child of a + // details/alert must keep its own zero padding: the rule above would push its + // title bar and code 20px inward, which detaches them from the terminal frame + // and draws a full-width divider line (the bug seen in Quick Start Step 2). + // Inside a TabItem the wrapper already has padding:0, so this restores parity. + > .code-block-enhanced { + padding: 0; + } + > *:last-child { margin-bottom: 0 !important; } From a2c1977419d7931a693828926b515f569f1facee Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:25:41 +0200 Subject: [PATCH 40/55] Balance top and bottom spacing of code-only tabs in API endpoint blocks --- docusaurus/src/scss/tabs.scss | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss index fdfe08ae03..d546383839 100644 --- a/docusaurus/src/scss/tabs.scss +++ b/docusaurus/src/scss/tabs.scss @@ -72,11 +72,13 @@ padding: 16px 20px; } - // In API endpoint blocks, use a 21px top padding so the gap between the - // tab bar's bottom border and the code matches the gap above the active - // tab pill (harmonized vertical spacing). + // In API endpoint blocks, use a symmetric 21px top and bottom padding: the + // top matches the gap above the active tab pill, and the bottom matches the + // top so the code sits evenly between the tab bar and the block's bottom + // border (the container's own 24px bottom padding is zeroed out below). .api-endpoint-block & [role="tabpanel"] { padding-top: 21px; + padding-bottom: 21px; } // Exception: when the tab panel holds a terminal block, drop the top @@ -182,9 +184,12 @@ // panel already provides 20px; add 18px so the code starts at ~38px, // matching the tab label (button left 24px + its 14px inner padding). padding-left: 18px !important; - // Drop the container's top padding too: the tab panel already provides - // the space above the code, so the extra 24px just pushed it down. + // Drop the container's top AND bottom padding: the tab panel provides + // the space above and below the code. Without this the container's own + // 24px bottom padding stacked on the panel's bottom padding, leaving far + // more empty space below the code than above it. padding-top: 0 !important; + padding-bottom: 0 !important; // A titleless code block inside a tab panel has no bar to host the // action buttons. Sit the button group just below the tab bar's bottom From 4fc954ba20108f5d991329c3a8f232d37469444a Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:27:28 +0200 Subject: [PATCH 41/55] Align terminal code with the first title-bar dot in endpoint request tabs --- docusaurus/src/scss/tabs.scss | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss index d546383839..ec1059012e 100644 --- a/docusaurus/src/scss/tabs.scss +++ b/docusaurus/src/scss/tabs.scss @@ -217,6 +217,13 @@ margin: 0 !important; background: transparent !important; + // Undo the 18px left inset applied to titleless code containers above: + // a terminal aligns its code under the first title-bar dot via its own + // inner padding, so the extra 18px pushed the command too far right. + [class*="codeBlockContainer"]:not(:has([class*="codeBlockTitle"])) { + padding-left: 0 !important; + } + .code-title-bar { border-radius: 0; margin: 0 4px; From c4aa189efe421f7249b1804aa73a0b59e3ea5630 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:29:54 +0200 Subject: [PATCH 42/55] Align the status header with the code for single-status responses --- .../components/ApiReference/api-reference.module.scss | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss index b1923e4d96..5b4544af39 100644 --- a/docusaurus/src/components/ApiReference/api-reference.module.scss +++ b/docusaurus/src/components/ApiReference/api-reference.module.scss @@ -732,6 +732,15 @@ font-size: 11px; } +// Single-status responses (no 200/404 tabs) render the header as a direct child +// of .responses, flush at 0px while the JSON code sits at 24px. Inset the header +// so the pulsing dot + "200 OK" line up with the code's opening `{`. In the +// multi-status case the header lives inside a tab panel (not a direct child), +// so this rule does not touch it — that alignment is handled in tabs.scss. +.responses > .responseHeader { + padding-left: 24px; +} + .responseDot { width: 6px; height: 6px; From 6c94203d7dc52878590b8b0fbf757f367b88091c Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:33:38 +0200 Subject: [PATCH 43/55] Keep terminal title bar padding when the terminal is a direct child of details --- docusaurus/src/scss/details.scss | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docusaurus/src/scss/details.scss b/docusaurus/src/scss/details.scss index 87dcf611f0..07e94a703b 100644 --- a/docusaurus/src/scss/details.scss +++ b/docusaurus/src/scss/details.scss @@ -105,7 +105,10 @@ details.alert { // Only neutralize the top spacing of the first inner element, NOT the // content wrapper itself: the wrapper keeps its padding-top so the content // is separated from the summary (and its bottom border when open). - > div > *:first-child { + // Exclude a terminal's title bar (.code-title-bar): it is the first child of + // the .code-block-enhanced wrapper and needs its own 10px top padding to keep + // the dots, "terminal" label, and copy button vertically centered. + > div > *:first-child:not(.code-title-bar) { padding-top: 0 !important; margin-top: 0 !important; } From 9d1257e4a2d2e7c0177d6543b22dae16840d0675 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:37:11 +0200 Subject: [PATCH 44/55] Color the terminal Ask AI sparkle glyph to match the copy/wrap icons --- docusaurus/src/scss/code-block.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index 0c48fba33b..240428dbe1 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -276,11 +276,19 @@ pre.prism-code { // Same color + opacity as the copy/wrap buttons (which use --strapi-fg-1 // at 0.6 opacity), so all three action buttons match at rest. !important // beats the legacy .clean-btn rules (this button also carries clean-btn). + // The sparkle is a Phosphor fill glyph rendered via ::before, which does + // not inherit the 's color (it defaults to neutral-600, a purple-grey), + // so color the ::before explicitly to match the neutral copy/wrap icons. i, span { color: var(--strapi-fg-1) !important; opacity: 0.6 !important; } + i, + i::before { + color: var(--strapi-fg-1) !important; + } + i { font-size: 12px; } From 3c5b336736414063dd8448b70c1b192a2757c993 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:40:58 +0200 Subject: [PATCH 45/55] Raise terminal copy/wrap icon opacity so thin stroke icons don't look washed out --- docusaurus/src/scss/code-block.scss | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index 240428dbe1..8cdb959357 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -445,13 +445,14 @@ pre.prism-code { border: 1px solid var(--strapi-neutral-200) !important; border-radius: var(--strapi-radius-md) !important; - // Match the reference copy/wrap buttons: the icon is dimmed at rest - // (opacity 0.6) and goes full opacity on hover — this is what makes it - // look grey rather than solid black. !important beats the legacy + // Dim the icon at rest so it reads grey rather than solid black, going + // full opacity on hover. Copy/wrap are thin stroke SVGs, which look washed + // out next to Ask AI's filled glyph at the same opacity, so use 0.75 (not + // 0.6) to match their perceived weight. !important beats the legacy // opacity:1 rules on .clean-btn icons. svg, i::before, span { color: var(--strapi-fg-1) !important; - opacity: 0.6 !important; + opacity: 0.75 !important; } &:hover svg, From 976034f1072bfeaf6a98e6d904e35adb2bbfc332 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:02:44 +0200 Subject: [PATCH 46/55] Fix terminal copy button: restore click in details, remove ghost check/copy icon --- docusaurus/src/scss/code-block.scss | 43 ++++++++++++++++--------- docusaurus/src/theme/CodeBlock/index.js | 29 +++++++++-------- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index 8cdb959357..c4f635eb37 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -249,9 +249,14 @@ pre.prism-code { background: var(--code-title-bar-lang-bg) !important; } - svg, i::before, span { + // Do not force opacity here: the more specific rules inside + // .code-block-enhanced handle the rest/hover dimming. Forcing opacity:1 on + // every svg also lit up the copy button's stacked success (check) icon, + // which Docusaurus keeps at opacity 0 until a copy succeeds — leaving a + // ghost icon behind the visible one. Only set color, and never touch the + // success icon's opacity. + svg:not([class*="copyButtonSuccessIcon"]), i::before, span { color: var(--code-title-bar-lang-color) !important; - opacity: 1 !important; } } @@ -438,26 +443,29 @@ pre.prism-code { width: 34px; height: 34px; padding: 6.4px; - // The button itself stays fully opaque; the whole actions row is what - // fades in/out on hover. Overrides the legacy .clean-btn opacity:0.6. - opacity: 1 !important; background: var(--strapi-neutral-0) !important; border: 1px solid var(--strapi-neutral-200) !important; border-radius: var(--strapi-radius-md) !important; - // Dim the icon at rest so it reads grey rather than solid black, going - // full opacity on hover. Copy/wrap are thin stroke SVGs, which look washed - // out next to Ask AI's filled glyph at the same opacity, so use 0.75 (not - // 0.6) to match their perceived weight. !important beats the legacy - // opacity:1 rules on .clean-btn icons. + // Dim the whole BUTTON at rest so its icon reads grey rather than solid + // black, going full opacity on hover. Copy/wrap are thin stroke SVGs that + // look washed out next to Ask AI's filled glyph at the same opacity, so + // use 0.75 (not 0.6) to match their perceived weight. + // + // Dimming the button (not its icons) is deliberate: the copy button + // stacks two SVGs (copy icon + success check) and toggles which is visible + // by flipping their individual opacities. Touching the icon opacities here + // would override that toggle and leave the hidden icon bleeding through as + // a ghost. Dimming the button lets Docusaurus's 0/1 toggle work untouched. + opacity: 0.75 !important; + transition: opacity 0.2s ease; + + // Color the icons so they invert correctly in dark mode. svg, i::before, span { color: var(--strapi-fg-1) !important; - opacity: 0.75 !important; } - &:hover svg, - &:hover i::before, - &:hover span { + &:hover { opacity: 1 !important; } } @@ -678,7 +686,10 @@ pre.prism-code { .clean-btn { opacity: 1 !important; - svg, + // Exclude the copy button's success (check) icon: Docusaurus keeps it at + // opacity 0 until a copy succeeds, so forcing an opacity here would make + // the check bleed through as a ghost behind the copy icon. + svg:not([class*="copyButtonSuccessIcon"]), i::before, span { opacity: 0.6; @@ -689,7 +700,7 @@ pre.prism-code { } .clean-btn:hover { - svg, + svg:not([class*="copyButtonSuccessIcon"]), i::before, span { opacity: 1 !important; diff --git a/docusaurus/src/theme/CodeBlock/index.js b/docusaurus/src/theme/CodeBlock/index.js index 2efc434253..a1b2de1922 100644 --- a/docusaurus/src/theme/CodeBlock/index.js +++ b/docusaurus/src/theme/CodeBlock/index.js @@ -148,20 +148,23 @@ export default function CodeBlockWrapper(props) { const move = () => { const actions = wrapper.querySelector('.code-title-bar__actions'); if (!actions) return; - // Move the native copy/wrap group into the title bar. React can re-render - // its own group inside the code block afterwards, so also remove any - // stray groups left outside the title bar to avoid a duplicate button. - const groups = wrapper.querySelectorAll('[class*="buttonGroup"]'); - let kept = actions.querySelector('[class*="buttonGroup"]'); - groups.forEach((group) => { - if (group.closest('.code-title-bar__actions')) return; // already in the bar - if (!kept) { - actions.appendChild(group); // move the first one into the bar - kept = group; - } else { - group.remove(); // drop duplicates left in the code area - } + // Relocate the native copy/wrap group into the title bar. React may + // re-render a FRESH group inside the code block after we move one; that + // fresh group is the live one (its click handlers are wired), while the + // one we moved earlier becomes a detached, dead clone. So whenever a group + // appears outside the bar, treat it as the live one: drop whatever stale + // group we previously parked in the bar and move the fresh one in. This + // keeps the working button (and fixes copy being dead inside StepDetails). + const groups = Array.from(wrapper.querySelectorAll('[class*="buttonGroup"]')); + const outside = groups.filter((g) => !g.closest('.code-title-bar__actions')); + if (outside.length === 0) return; // nothing new to relocate + // The last one in document order is the most recently rendered (live) one. + const live = outside[outside.length - 1]; + // Remove any other groups (stale relocated one in the bar + extra dupes). + groups.forEach((g) => { + if (g !== live) g.remove(); }); + actions.appendChild(live); }; // Run now and keep watching: React may re-insert a group after our move. requestAnimationFrame(() => requestAnimationFrame(move)); From b52fb2dbcfb31cdf7293e194cd5d6297f3f44d70 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:05:09 +0200 Subject: [PATCH 47/55] Keep the method pill compact and top-aligned next to long wrapping URLs --- .../components/ApiReference/api-reference.module.scss | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss index 5b4544af39..4840ce7c83 100644 --- a/docusaurus/src/components/ApiReference/api-reference.module.scss +++ b/docusaurus/src/components/ApiReference/api-reference.module.scss @@ -197,7 +197,10 @@ &__methodRow { display: flex; - align-items: center; + // Top-align so the method pill stays next to the FIRST line of a long URL + // that wraps onto several lines, instead of being vertically centered + // against the whole wrapped block. + align-items: flex-start; gap: 12px; margin-bottom: 20px; } @@ -274,6 +277,10 @@ letter-spacing: 0.02em; position: relative; overflow: hidden; + // Keep the pill a fixed, compact size next to long URLs: never shrink in the + // flex row and never let the verb ("GET") wrap onto a second line ("GE"/"T"). + flex-shrink: 0; + white-space: nowrap; &::after { content: ''; From 3de1576694bc6213ad0d39047a45f4249bdbb139 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:09:03 +0200 Subject: [PATCH 48/55] Dim only the terminal action icons, not the button border, matching Ask AI --- docusaurus/src/scss/code-block.scss | 35 ++++++++++++++++++----------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index c4f635eb37..2987e8aa73 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -447,26 +447,35 @@ pre.prism-code { border: 1px solid var(--strapi-neutral-200) !important; border-radius: var(--strapi-radius-md) !important; - // Dim the whole BUTTON at rest so its icon reads grey rather than solid - // black, going full opacity on hover. Copy/wrap are thin stroke SVGs that - // look washed out next to Ask AI's filled glyph at the same opacity, so - // use 0.75 (not 0.6) to match their perceived weight. - // - // Dimming the button (not its icons) is deliberate: the copy button - // stacks two SVGs (copy icon + success check) and toggles which is visible - // by flipping their individual opacities. Touching the icon opacities here - // would override that toggle and leave the hidden icon bleeding through as - // a ghost. Dimming the button lets Docusaurus's 0/1 toggle work untouched. - opacity: 0.75 !important; - transition: opacity 0.2s ease; + // The button (and its border) stays fully opaque; only the ICON is dimmed + // to 0.6 at rest and goes to 1 when the button itself is hovered — the + // exact treatment of the Ask AI button, so all three match in light/dark. + opacity: 1 !important; // Color the icons so they invert correctly in dark mode. svg, i::before, span { color: var(--strapi-fg-1) !important; } + // Dim the ICON only (never the border). The copy button stacks two SVGs + // (copy icon + success check) inside a [class*="copyButtonIcons"] wrapper + // and toggles which is visible via each svg's own opacity, so dim the + // WRAPPER (0.6 × the inner 1/0 toggle preserves the toggle, no ghost) + // rather than the raw svgs. The wrap button has a plain svg, and Ask AI a + // glyph in i::before; dim those too. + [class*="copyButtonIcons"], + > svg, + i::before { + opacity: 0.6 !important; + transition: opacity 0.2s ease; + } + &:hover { - opacity: 1 !important; + [class*="copyButtonIcons"], + > svg, + i::before { + opacity: 1 !important; + } } } } From 69ee6fcc0d5f582c6324fec05dff087fc1d06a2e Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:12:26 +0200 Subject: [PATCH 49/55] Nudge the copy icon opacity up to match the perceived weight of the other action icons --- docusaurus/src/scss/code-block.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss index 2987e8aa73..a31e1f7a00 100644 --- a/docusaurus/src/scss/code-block.scss +++ b/docusaurus/src/scss/code-block.scss @@ -470,6 +470,14 @@ pre.prism-code { transition: opacity 0.2s ease; } + // The copy glyph is two thin overlapping outlined rectangles: far fewer + // inked pixels than Ask AI's solid star or the wrap button's thick bars, + // so at the same 0.6 opacity it READS lighter. Nudge just the copy icon + // up to ~0.78 so its perceived weight matches the other two. + [class*="copyButtonIcons"] { + opacity: 0.78 !important; + } + &:hover { [class*="copyButtonIcons"], > svg, From 232f96674d34534d0eb23afcfda0b5b5485a744e Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:18:05 +0200 Subject: [PATCH 50/55] Lower the button group in code-only request tabs by 10px --- docusaurus/src/scss/tabs.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss index ec1059012e..dc0c30d1a7 100644 --- a/docusaurus/src/scss/tabs.scss +++ b/docusaurus/src/scss/tabs.scss @@ -198,7 +198,7 @@ // overlaps something: we let it overlap the code's right margin (bottom) // instead of the tab bar (top), which reads much cleaner. [class*="buttonGroup"] { - top: -17px; + top: -7px; } } From 797449327937cd7850aa3a4c04bf5da50495ab5f Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:25:16 +0200 Subject: [PATCH 51/55] Lower the button group in code-only request tabs by 16px --- docusaurus/src/scss/tabs.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss index dc0c30d1a7..ba8005dceb 100644 --- a/docusaurus/src/scss/tabs.scss +++ b/docusaurus/src/scss/tabs.scss @@ -198,7 +198,7 @@ // overlaps something: we let it overlap the code's right margin (bottom) // instead of the tab bar (top), which reads much cleaner. [class*="buttonGroup"] { - top: -7px; + top: 9px; } } From 892901d32d6be38acfdc039edd658c5c1637d364 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:27:16 +0200 Subject: [PATCH 52/55] Lower the endpoint URL by 12px to align it with the method pill --- docusaurus/src/components/ApiReference/api-reference.module.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss index 4840ce7c83..b996e6dce5 100644 --- a/docusaurus/src/components/ApiReference/api-reference.module.scss +++ b/docusaurus/src/components/ApiReference/api-reference.module.scss @@ -209,6 +209,7 @@ font-family: var(--strapi-font-family-mono); font-size: 14px; color: var(--strapi-fg-2); + padding-top: 12px; } // JS API signature (Document Service etc.): shown instead of a method pill + From 648e5a511c61ece2663162c3f32a3deca55938a3 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:28:55 +0200 Subject: [PATCH 53/55] Reduce endpoint URL top padding to 6px so it centers with the method pill --- .../src/components/ApiReference/api-reference.module.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss index b996e6dce5..419d1bbfc0 100644 --- a/docusaurus/src/components/ApiReference/api-reference.module.scss +++ b/docusaurus/src/components/ApiReference/api-reference.module.scss @@ -209,7 +209,7 @@ font-family: var(--strapi-font-family-mono); font-size: 14px; color: var(--strapi-fg-2); - padding-top: 12px; + padding-top: 6px; } // JS API signature (Document Service etc.): shown instead of a method pill + From 84cc2a47b20eb69e48e67d918bbd5141db2479e4 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:29:59 +0200 Subject: [PATCH 54/55] Fine-tune previous padding --- .../src/components/ApiReference/api-reference.module.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss index 419d1bbfc0..96308b7954 100644 --- a/docusaurus/src/components/ApiReference/api-reference.module.scss +++ b/docusaurus/src/components/ApiReference/api-reference.module.scss @@ -209,7 +209,7 @@ font-family: var(--strapi-font-family-mono); font-size: 14px; color: var(--strapi-fg-2); - padding-top: 6px; + padding-top: 2px; } // JS API signature (Document Service etc.): shown instead of a method pill + From 492c176f896e0237ea9b19528731e8e7fea74e28 Mon Sep 17 00:00:00 2001 From: Pierre Wizla <4233866+pwizla@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:30:07 +0200 Subject: [PATCH 55/55] Delete unwanted linebreak --- docusaurus/docs/cms/quick-start.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docusaurus/docs/cms/quick-start.md b/docusaurus/docs/cms/quick-start.md index a021617f3f..acac1f7128 100644 --- a/docusaurus/docs/cms/quick-start.md +++ b/docusaurus/docs/cms/quick-start.md @@ -166,7 +166,6 @@ sources={{ /> Once Strapi has restarted, "Restaurant" is listed under _Content Manager > Collection types_ in the navigation. Wow, you have just created your very first content-type! It was so cool, let's create another one right now, just for pleasure. -