Skip to content

docs: add AI Catalog header button and reorder theme selector - #399

Merged
aaitor merged 2 commits into
mainfrom
aaitor/catalog_link
Sep 14, 2026
Merged

aaitor merged 2 commits into
mainfrom
aaitor/catalog_link

Conversation

@aaitor

@aaitor aaitor commented Sep 14, 2026

Copy link
Copy Markdown
Member

Adds a direct AI Catalog header button linking to https://nevermined.app/catalog/, with the Nevermined ribbon shimmer from the supplied button studio artifact. App becomes a plain link, with the theme selector positioned to its left: theme selector → App → AI Catalog.

The ribbon animates teal to lime on hover and keyboard focus, uses light/dark theme colors, and respects reduced-motion preferences.

Validation: Mintlify build validation passed (with an existing React import diagnostic in snippets/hero-banner.jsx). Browser checks confirmed header order, Catalog destination and styling, hover animation, reduced-motion behavior, and a clickable theme selector. git diff --check passed.

Copilot AI lite review requested due to automatic review settings September 14, 2026 11:44
@aaitor
aaitor requested a review from a team as a code owner September 14, 2026 11:44
@aaitor
aaitor enabled auto-merge (squash) September 14, 2026 11:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

Changes are small, consistent with the PR description, and the updated navbar config + CSS appear valid and self-contained.

Pull request overview

This PR updates the Mintlify header configuration and styling to introduce an AI Catalog primary CTA button (with custom “ribbon shimmer” styling) while demoting App to a standard navbar link and reordering the theme selector to appear before those links.

Changes:

  • Updated docs.json navbar config: App moved to navbar.links, AI Catalog set as navbar.primary.
  • Added custom.css rules to (a) reposition the theme selector relative to the CTA area and (b) fully restyle/animate the AI Catalog button (including dark mode + reduced-motion behavior).
File summaries
File Description
docs.json Reconfigures navbar items so AI Catalog becomes the primary button and App becomes a plain link.
custom.css Adds header layout reordering plus AI Catalog button ribbon/shimmer styling with dark-mode and reduced-motion handling.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@r-marques

Copy link
Copy Markdown
Member

👀 Reviewing

@r-marques r-marques left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Automated PR review — 🟡 Mergeable with nits

Adds an AI Catalog primary CTA (navbar.primaryhttps://nevermined.app/catalog/), demotes App to navbar.links[], and appends ~85 lines to custom.css that (a) move Mintlify's theme selector in front of the nav links with order: on #navbar div:has(> nav #topbar-cta-button) > nav and (b) restyle the CTA with a two-stroke Nevermined-mark "ribbon" drawn on ::before/::after masks. The core change is right: docs.json offers no lever for the toggle's position (only appearance.strict to hide it), so CSS is the only way; the selectors match the live production DOM; the reduced-motion, colour and mask work all check out. Three should-fix items, none blocking: the margin compensation at custom.css:340-347 was written against Tailwind v3 space-x semantics while the served bundle is v4 (:where(.space-x-4>:not(:last-child)){margin-inline-end:1rem}), so > div { margin-inline: 0 } is a no-op and the CTA lands 1rem short of the header's right edge; the comment at custom.css:348 links a personal share artifact that says "Expires in 20d 21h" and custom.css is inlined into every page's HTML; and the :focus-visible rule at custom.css:404 is dead — it loses to the !important global ring at lines 250-256 (and should stay lost: #12a89e on white is 2.95:1).

What I reviewed

  • Diff range origin/main...HEAD — 2 files (custom.css, docs.json), +93/−2, head 7780019e.
  • Panel: code-reviewer, comment-analyzer (read-only; both delivered). Not security-sensitive.
  • jq . docs.json valid; the docs.json diff is an 8-line text edit (no reflow); git diff --check clean.
  • mintlify broken-links (CLI 4.2.629): success, no broken links. mintlify validate exits 1 on one warning — the pre-existing react import in snippets/hero-banner.jsx, identical on main and unrelated to this PR. mintlify build does not exist in this CLI (prints help, exit 0), so "build validation" ≙ validate.
  • Mintlify Deployment check: skipped"No eligible deployments found for changes" — the same on every recent PR here (#394, #395, #397), so there is no preview URL to check.
  • Live DOM (https://nevermined.ai/docs/): nav[aria-label=Main] > ul > li#topbar-cta-button > a > (span.absolute + div > span + svg), sibling div > button#theme-preference-menu-trigger — the selectors match. #navbar, #topbar-cta-button, #mobile-nav are documented Mintlify CSS hooks; the structural div:has(> nav …) > nav, > div, span.absolute chain is scraped, which Mintlify documents as "subject to change".
  • Live compiled CSS: .space-x-4 is the Tailwind v4 shape (end-margin on every non-last DOM child) — basis for the margin finding.
  • Link target: https://nevermined.app/catalog/ → 200; /catalog (no slash) 301s to it, so the trailing slash is canonical. Same prod host as the existing App link.
  • https://share.onorca.dev/a/y4Pbp441fhCj → an Orca Artifacts share of button-studio.html, page reads "Expires in 20d 21h" (fetched 2026-09-14).
  • Mintlify bundle: #mobile-nav is the left navigation drawer; the phone-width App/AI Catalog links render in a portalled "Mobile menu" dialog outside both #navbar and #mobile-nav, so that selector arm matches nothing today.
  • No visual render was done (no preview deployment; the mechanics were verified against the live DOM + bundle instead).

Verdict: 🟡 Mergeable with nits — 0 blockers, 3 should-fix, 4 nits.

🧭 Inline comments (11)

Each is posted on its line in Files changed.

  • 🟡 SHOULD FIX — Margin compensation targets Tailwind v3 space-x; the served bundle is v4, so > div { margin-inline: 0 } is a no-op and the CTA sits 1rem short of the right edge — custom.css:347
  • 🟡 SHOULD FIX — This share link expires in ~3 weeks and custom.css is inlined into every public page — replace it with a durable reference — custom.css:349
  • 🟡 SHOULD FIX — Dead rule: the global focus ring at lines 250-256 is !important and wins — delete this rather than promoting it — custom.css:407
  • 💡 NIT — Href-keyed selector couples byte-for-byte to docs.json navbar.primary.href; and the #mobile-nav arm matches nothing on this theme — custom.css:351
  • 💡 NIT — Comment states the effect, not the why, and the block breaks the file's banner convention — custom.css:339
  • 💡 NIT — "Replace" → these rules hide; say what is hidden and what reappears if the scraped class changes — custom.css:377
  • 💡 NIT — A few generator no-ops against the live markup (harmless) — custom.css:367
  • NICE — Reduced motion is genuinely honoured — custom.css:418
  • NICE — Per-pseudo --catalog-ribbon resolves correctly; box matches the viewBox ratio — custom.css:390
  • NICE — Palette and theme handling check out — custom.css:372
  • NICE — Minimal, valid edit; trailing slash is the canonical form; host matches precedent — docs.json:750

Comment thread custom.css
Comment on lines +340 to +347
#navbar div:has(> nav #topbar-cta-button) > nav {
order: 1;
margin-inline-start: 1rem;
}

#navbar div:has(> nav #topbar-cta-button) > div {
margin-inline: 0;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 SHOULD FIX — Margin compensation targets Tailwind v3 space-x; the served bundle is v4, so > div { margin-inline: 0 } is a no-op and the CTA sits 1rem short of the right edge

The parent container is flex … justify-end space-x-4. In the CSS Mintlify actually serves (/docs/_next/static/chunks/c9c6061f3cdd5c21.css) that utility is the Tailwind v4 shape:

:where(.space-x-4 > :not(:last-child)) { margin-inline-end: 1rem; }

i.e. an END margin on every child except the DOM-last one — not v3's margin-left on every child except the first. :last-child is DOM order, which order: does not change, so after this rule:

  • nav (DOM-first) keeps margin-inline-end: 1rem and gains margin-inline-start: 1rem. Once it is visually last, that end margin becomes a trailing 16px gap: the AI Catalog button's right edge sits 1rem inside the header's right edge, where the theme toggle used to sit flush.
  • the theme div is DOM-last and never had a margin, so > div { margin-inline: 0 } (lines 345-347) changes nothing.

Suggested fix — put the whole compensation on the nav and drop the > div rule:

#navbar div:has(> nav #topbar-cta-button) > nav {
  order: 1;
  margin-inline: 1rem 0; /* Tailwind v4 space-x puts its 1rem on this (DOM-first) child's END; move it to the start now that the nav is visually last */
}

Worth a comment either way — as written a maintainer cannot tell which space-x shape the two margins are compensating, or that the > div rule is dead.

🤖 pr-review-toolkit · code-reviewer · high

Comment thread custom.css Outdated
Comment on lines +348 to +349

/* AI Catalog ribbon shimmer: https://share.onorca.dev/a/y4Pbp441fhCj.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 SHOULD FIX — This share link expires in ~3 weeks and custom.css is inlined into every public page — replace it with a durable reference

https://share.onorca.dev/a/y4Pbp441fhCj is an Orca Artifacts share of a local button-studio.html; the page itself reads "Expires in 20d 21h" (fetched 2026-09-14). Mintlify inlines custom.css verbatim into every page's HTML (<style data-custom-css-path="custom.css"> — the #2789 / #2801 refs above are visible in the live page source today), so from early October every docs page will carry a dead link to a personal tool's domain.

The file's house style is a GitHub reference (nevermined-io/nvm-monorepo#2789, #2801). Suggest citing nevermined-io/docs#399 and putting what the share showed into words, which also fixes the second half of this comment losing its antecedent once the link dies. Concretely, the non-obvious facts a maintainer needs are: the two masks are the first two <path>s of logo/light.svg (the two strokes of the Nevermined mark, coordinates shifted ~0.01 — a logo refresh will not know to touch these data URIs otherwise); ::before carries the left stroke and ::after the right so the second can pulse .12s later; and nvm-catalog-shimmer is a fill-colour pulse (accent ↔ lime), not a moving highlight.

🤖 pr-review-toolkit · comment-analyzer · high

Comment thread custom.css Outdated
Comment on lines +404 to +407
outline: 2px solid var(--catalog-accent);
outline-offset: 3px;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 SHOULD FIX — Dead rule: the global focus ring at lines 250-256 is !important and wins — delete this rather than promoting it

Lines 250-256 declare outline: 2px solid #0f766e !important; outline-offset: 2px !important on every a:focus-visible (and #5eead4 in dark). An !important declaration beats a normal one regardless of specificity, so neither outline nor outline-offset here ever applies: the computed ring on the focused CTA is the global #0f766e / #5eead4 at 2px, not var(--catalog-accent) at 3px.

Delete the rule rather than adding !important: the ring sits outside the button on the navbar background, and #12a89e on the white navbar is 2.95:1 — below WCAG 1.4.11's 3:1 non-text minimum — whereas the global ring it currently loses to is 5.47:1 light / 13.1:1 dark (the file's own numbers at line 245). The hover/focus animation at lines 409-418 is unaffected — nothing !important touches animation, so keyboard focus still triggers the shimmer.

🤖 pr-review-toolkit · code-reviewer · high

Comment thread custom.css Outdated

/* AI Catalog ribbon shimmer: https://share.onorca.dev/a/y4Pbp441fhCj.
Separate masks preserve the staggered animation without custom scripts. */
:is(#navbar, #mobile-nav) a[href="https://nevermined.app/catalog/"] {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 NIT — Href-keyed selector couples byte-for-byte to docs.json navbar.primary.href; and the #mobile-nav arm matches nothing on this theme

Two coupling notes, neither a bug today.

(a) Mintlify renders navbar.primary.href verbatim (live: href="https://nevermined.app"), so this selector must byte-match docs.json:750 — trailing slash included. Drop the slash there, or add a UTM, and the button silently reverts to Mintlify's default pill while the id-keyed theme-order rules above keep working: a half-applied state nobody is told about, and JSON cannot carry a comment pointing back here. Either key the desktop half on the documented hook the reorder rule already relies on — #topbar-cta-button > a — which has no href coupling, or add a one-line comment naming docs.json → navbar.primary.href as the string that must stay in sync.

(b) #mobile-nav is Mintlify's left navigation drawer (DrawerPopup side="left" id="mobile-nav" aria-label="Navigation" — it renders the sidebar). On the mint theme the phone-width App / AI Catalog links render inside a portalled "Mobile menu" dialog (nav[aria-label="Mobile menu"], no id) that is outside both #navbar and #mobile-nav, so that arm of :is(#navbar, #mobile-nav) matches no CTA today and the small-screen link keeps Mintlify's list style — which is fine, but the selector suggests coverage it does not have. Either drop the arm or say the mobile menu deliberately stays unstyled.

🤖 pr-review-toolkit · code-reviewer · high

Comment thread custom.css Outdated
mask-image: radial-gradient(120% 140% at 0 0, #000 0%, transparent 55%);
}

/* Place the theme selector before the App / AI Catalog navigation. */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 NIT — Comment states the effect, not the why, and the block breaks the file's banner convention

Three things the next maintainer needs that the comment does not say:

  1. Why order: at all — Mintlify hard-codes the theme menu after nav[aria-label=Main] and docs.json exposes no way to order them (only appearance.strict to hide the toggle), so CSS is the only lever.
  2. What silently breaks#navbar and #topbar-cta-button are documented Mintlify hooks, but the div > nav > ul > li#topbar-cta-button chain between them is scraped from the DOM, which Mintlify documents as "subject to change". When it stops matching, the toggle moves back to the right of the CTA with no error.
  3. Tab orderorder: changes the visual order (theme → App → AI Catalog) but not the DOM/tab order (App → AI Catalog → theme), so keyboard focus travels right across the links and then jumps back left to the toggle. Inherent to the CSS-only approach, but given the focus-ring block at line 240 targets keyboard users explicitly, a one-line acknowledgement of the WCAG 2.4.3 trade-off is worth having.

House style: every other block in this file opens with a /* ===== Section ===== */ banner carrying the rationale and an issue ref (nvm-monorepo#2789, #2801); appended as three one-liners directly under the "Corner engraving hatch" subsection, this reads as part of the Ledger-background section to anyone scanning banners. A Header — theme toggle order + AI Catalog CTA banner with the originating PR would fix that.

🤖 pr-review-toolkit · comment-analyzer · high

Comment thread custom.css Outdated
Comment on lines +358 to +367
border: 0;
border-radius: 12px;
background: #0d3f48;
color: #fff;
font-size: 15px;
font-weight: 600;
line-height: 1;
text-decoration: none;
white-space: nowrap;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 NIT — A few generator no-ops against the live markup (harmless)

Against the served page these declarations change nothing: border: 0 (preflight already sets border: 0 solid on *), text-decoration: none (preflight a { text-decoration: inherit }, computed is already none), white-space: nowrap (inherited from li.whitespace-nowrap), and color: #fff (the visible text is a <span class="text-white"> child, so the anchor's colour never paints). Harmless and arguably defensive against Mintlify class changes — position: relative / align-items: center are the ones worth keeping for that reason — but if the block is being touched for the items above, trimming these keeps it honest. line-height: 1 does not interact with the pseudo-element centring: top: 50% is measured on the 41px padding box (13 + 15 + 13), which centres the 17px ribbon exactly.

🤖 pr-review-toolkit · code-reviewer · medium

Comment thread custom.css
Comment on lines +408 to +418
@media (prefers-reduced-motion: no-preference) {
:is(#navbar, #mobile-nav) a[href="https://nevermined.app/catalog/"]:is(:hover, :focus-visible)::before,
:is(#navbar, #mobile-nav) a[href="https://nevermined.app/catalog/"]:is(:hover, :focus-visible)::after {
animation: nvm-catalog-shimmer .8s ease-in-out infinite;
}

:is(#navbar, #mobile-nav) a[href="https://nevermined.app/catalog/"]:is(:hover, :focus-visible)::after {
animation-delay: .12s;
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ NICE — Reduced motion is genuinely honoured

The animation lives only inside @media (prefers-reduced-motion: no-preference), so under reduce no animation is ever applied — nothing to un-set, and the @keyframes outside the query is inert without a reference. Opt-in is the right shape here (an opt-out reduce block would have to remember every animation it cancels). Hover and :focus-visible both start the shimmer, with the .12s stagger on ::after.

🤖 pr-review-toolkit · code-reviewer · high

Comment thread custom.css Outdated
Comment on lines +380 to +390
:is(#navbar, #mobile-nav) a[href="https://nevermined.app/catalog/"]::before,
:is(#navbar, #mobile-nav) a[href="https://nevermined.app/catalog/"]::after {
content: "";
position: absolute;
left: 22px;
top: 50%;
transform: translateY(-50%);
width: 24px;
height: 17px;
background-color: var(--catalog-accent);
mask: var(--catalog-ribbon) center / contain no-repeat;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ NICE — Per-pseudo --catalog-ribbon resolves correctly; box matches the viewBox ratio

Declaring --catalog-ribbon on the ::before / ::after rules (396, 400) and consuming it in this shared mask: works as intended — custom properties substitute at computed-value time on the pseudo-element itself, independent of rule order — so each pseudo gets its own half-ribbon. The 24×17 box matches the 31.06×22 viewBox aspect ratio (1.412 vs 1.412), so contain neither letterboxes nor crops. -webkit-mask alongside mask covers Safari.

🤖 pr-review-toolkit · code-reviewer · high

Comment thread custom.css Outdated
Comment on lines +369 to +372
:is(.dark, [data-theme="dark"]) :is(#navbar, #mobile-nav) a[href="https://nevermined.app/catalog/"] {
--catalog-accent: #4ac6bf;
--catalog-lime: #bcdc4a;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ NICE — Palette and theme handling check out

White on #0d3f48 is 11.5:1. Ribbon accents on the button: #12a89e 3.9:1 / #8fbf1f 5.3:1 (light), #4ac6bf 5.6:1 / #bcdc4a 7.4:1 (dark) — all above the 3:1 non-text floor. Keeping #0d3f48 as the background in dark mode is not a regression: docs.json sets colors.dark: "#0d3f48", so today's bg-primary-dark App button already paints exactly that on the dark navbar, and the new tokens reuse the ledger/hero palette already in this file. :is(.dark, [data-theme="dark"]) is functionally identical to the file's .dark X, [data-theme="dark"] X convention (same specificity, both arms match); only the spelling differs.

🤖 pr-review-toolkit · code-reviewer · high

Comment thread docs.json
Comment on lines +741 to +750
"links": [
{
"label": "App",
"href": "https://nevermined.app"
}
],
"primary": {
"type": "button",
"label": "App",
"href": "https://nevermined.app"
"label": "AI Catalog",
"href": "https://nevermined.app/catalog/"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ NICE — Minimal, valid edit; trailing slash is the canonical form; host matches precedent

Eight-line text edit, no reflow, jq valid. https://nevermined.app/catalog/ answers 200 directly, while /catalog without the slash 301s to it — so the slash saves a redirect hop on every click. Hardcoding the production host is consistent with the existing App link (https://nevermined.app) — the docs site has one production deployment, so there is no staging variant to parameterise for. The :is(#navbar, #mobile-nav) guard in custom.css keeps the page-body links to nevermined.app untouched. Note for the CSS side: the exact string here is what custom.css:351 matches on (see that comment).

🤖 pr-review-toolkit · code-reviewer · high

@r-marques
r-marques disabled auto-merge September 14, 2026 12:22

@r-marques r-marques left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Approved with comments — no blockers; 3 should-fix, 4 nit(s) left inline. Auto-merge was disabled so these can be looked at first.

Inline review: #399 (review)

@aaitor

aaitor commented Sep 14, 2026

Copy link
Copy Markdown
Member Author

Addressed the review in 894b8b8:

  • Reset both nav margins so Tailwind v4 leaves no trailing gap; retained and documented the theme-wrapper reset for the older Tailwind v3 local preview.
  • Replaced the expiring artifact reference with this PR and documented the two logo strokes and staggered color pulse.
  • Removed the ineffective focus override, preserving the global accessible focus ring.
  • Switched styling to the desktop CTA hook, narrowed the chevron selector, removed redundant declarations, and documented the DOM dependency and visual/tab-order distinction.

Browser verification passed against the local preview and the production page with the proposed CSS and header links applied in a temporary browser session: theme → App → AI Catalog, zero trailing gap, ribbon masks, keyboard-focus shimmer/global outline, and no animation under reduced motion. No production content was changed by that check. git diff --check passed.

@aaitor
aaitor merged commit f93f916 into main Sep 14, 2026
@aaitor
aaitor deleted the aaitor/catalog_link branch September 14, 2026 12:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants