Skip to content

Commit 7cb71c6

Browse files
mnoconclaudeadriendupuis
committed
AFDocs: Improve docs accessibility for agents (#3297)
* AFDocs: Improve docs accessibility for agents * Fix * TEMP: Probe RTD markdown converter element handling Temporary markers on the product_catalog page to determine which wrappers the RTD/Cloudflare HTML->Markdown converter strips. Will be removed once the experiment concludes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * TEMP: Round 2 converter probes with link-rich content Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * AFDocs: Keep sidebar nav out of agent-facing Markdown output HTML->Markdown converters used by AI agents (e.g. the one behind Read the Docs' 'Accept: text/markdown' content negotiation) skip <nav>/<header>/<footer> elements, but only until the first closing tag - nested <nav> elements make them leak most of the sidebar into the converted Markdown (~170 lines of nav noise per page). Restructure the sidebar so each skippable region is a single <nav> with no nested nav/header/footer inside: - main.html: the main_nav wrapper div becomes the one <nav> landmark - nav.html / nav-item.html: inner md-nav elements become <div>s - toc.html: inner group <nav>s become <div>s; the outer wrapper stays <nav> standalone but renders as <div> when embedded in the sidebar Styling and behavior are unchanged: all CSS targets classes and Material's JS targets data-md-component attributes. Also removes the temporary converter probe markup. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * AFDocs: Render llms.txt description as blockquote summary The llms.txt spec expects the summary right after the H1 title to be a blockquote. mkdocs-llmstxt emits markdown_description verbatim, so prefix it with '> ' to produce the expected structure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Update theme/main.html Co-authored-by: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com>
1 parent 62410db commit 7cb71c6

9 files changed

Lines changed: 51 additions & 23 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/vendor/
22
**/.DS_Store
3-
__pycache__/*
3+
**/__pycache__/*
44
/site/
55
**/.idea/
66
.php-cs-fixer.cache

docs/js/custom.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,6 @@ $(document).ready(function() {
1212
if (branchNameRegexp !== null && branchNameRegexp.hasOwnProperty(1) && branchNameRegexp[1].length) {
1313
branchName = branchNameRegexp[1];
1414
}
15-
16-
// Show warning box for versions that have reached End Of Life
17-
if (eolVersions.includes(branchName)) {
18-
const warningBox = document.querySelector('#eol-warning-box');
19-
20-
warningBox.hidden = false;
21-
}
22-
2315
if (!/^\d+\.\d+$/.test(branchName) && branchName !== 'latest') {
2416
branchName = 'master';
2517
}

hooks/eol_status.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import os
2+
3+
4+
def on_config(config, **kwargs):
5+
"""Determine at build time whether this build is for an End-Of-Life version.
6+
7+
Each version is built by RTD as its own separate build (one per branch/tag),
8+
with READTHEDOCS_VERSION_NAME set to the version slug (matching the
9+
``extra.eol_versions`` entries, e.g. "2.5", "3.3"). Computing this here
10+
lets the theme render the EOL warning only where it's actually true,
11+
instead of always emitting it in the HTML and hiding it via JS/CSS
12+
(which is present in the served page whether the visible warning applies
13+
or not).
14+
"""
15+
current_version = os.environ.get("READTHEDOCS_VERSION_NAME", "")
16+
eol_versions = config["extra"].get("eol_versions") or []
17+
config["extra"]["current_version_is_eol"] = current_version in eol_versions
18+
19+
return config

mkdocs.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ INHERIT: plugins.yml
33
site_name: Developer Documentation
44
repo_url: https://github.com/ibexa/documentation-developer
55
site_url: https://doc.ibexa.co/en/latest/
6-
copyright: "Copyright 1999-2024 Ibexa AS and others"
6+
copyright: "Copyright 1999-2026 Ibexa AS and others"
7+
hooks:
8+
- hooks/eol_status.py
79
validation:
810
omitted_files: warn
911
absolute_links: relative_to_docs
@@ -949,7 +951,7 @@ nav:
949951
theme:
950952
name: material
951953
features:
952-
- content.code.annotate
954+
- content.code.annotate
953955
- content.code.copy
954956
- navigation.tracking
955957
- navigation.top

theme/main.html

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
{% endblock %}
1717
{% block site_nav %}
1818
{% if nav %}
19-
<div class="main_nav">
19+
{# The single <nav> landmark wrapping the whole sidebar. Keep it the only <nav> in this
20+
subtree: nested <nav> tags break the HTML->Markdown converters used by AI agents
21+
(e.g. behind RTD's "Accept: text/markdown"), leaking nav items into the output. #}
22+
<nav class="main_nav" aria-label="Site navigation">
2023
<div class="main_nav_content">
2124
<div class="site-header" id="site-name">
2225
{% set site_url = config.site_url | default(nav.homepage.url, true) | url %}
@@ -33,7 +36,7 @@
3336
</div>
3437
</div>
3538
</div>
36-
</div>
39+
</nav>
3740
{% endif %}
3841
{% if page.toc %}
3942
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
@@ -74,7 +77,9 @@
7477
{% endif %}
7578
</div>
7679
{% endif %}
77-
{% include "partials/eol_warning.html" %}
80+
{% if config.extra.current_version_is_eol %}
81+
{% include "partials/eol_warning.html" %}
82+
{% endif %}
7883
{{ page.content }}
7984
{% include "partials/tags.html" %}
8085
</div>

theme/partials/eol_warning.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<div id="eol-warning-box" class="admonition caution" hidden>
1+
<div id="eol-warning-box" class="admonition caution">
22
<div class="admonition-title">
33
This documentation is for a version that has reached its <a href="https://support.ibexa.co/Public/service-life">End Of Life</a>. Such versions are no longer supported and don't receive security updates. Consider <a href="https://doc.ibexa.co/en/latest/update_and_migration/update_ibexa_dxp/">updating to a newer version</a>.
44
</div>

theme/partials/nav-item.html

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
<label class="md-nav__link level-{{ level }}" for="{{ path }}">
1010
{{ nav_item.title }} <span class="pill pill--new" hidden>New</span>
1111
</label>
12-
<nav class="md-nav" aria-label="{{ nav_item.title }}" data-md-level="{{ level }}">
12+
{# div instead of nav: nested <nav> tags break HTML->Markdown converters, see nav.html #}
13+
<div class="md-nav" aria-label="{{ nav_item.title }}" data-md-level="{{ level }}">
1314
<label class="md-nav__link-title md-nav__link level-{{ level }}" for="{{ path }}">
1415
{{ nav_item.title }}
1516
</label>
@@ -21,7 +22,7 @@
2122
{% include "partials/nav-item.html" %}
2223
{% endfor %}
2324
</ul>
24-
</nav>
25+
</div>
2526
</li>
2627
{% elif nav_item == page %}
2728
<li class="{{ class }}">
@@ -40,6 +41,9 @@
4041
{% if nav_item.meta.month_change %}<span class="pill pill--new">New</span>{% endif %}
4142
</a>
4243
{% if toc | first is defined %}
44+
{# toc_inside_nav: render the TOC with a <div> wrapper because it sits inside the
45+
sidebar <nav> here; a nested <nav> would break HTML->Markdown converters, see nav.html #}
46+
{% set toc_inside_nav = true %}
4347
{% include "partials/toc.html" %}
4448
{% endif %}
4549
</li>

theme/partials/nav.html

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
<nav class="md-nav md-nav--primary" data-md-level="0">
1+
{# div instead of nav: the whole sidebar is wrapped in a single <nav> in main.html.
2+
Nested <nav> tags break the HTML->Markdown converters used by AI agents (e.g. the one
3+
behind RTD's "Accept: text/markdown"), which skip <nav> only until the first closing tag. #}
4+
<div class="md-nav md-nav--primary" data-md-level="0">
25
<ul class="md-nav__list" data-md-scrollfix>
36
{% for nav_item in nav %}
47
{% set path = "nav-" + loop.index | string %}
58
{% set level = 1 %}
69
{% include "partials/nav-item.html" %}
710
{% endfor %}
811
</ul>
9-
</nav>
12+
</div>

theme/partials/toc.html

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
{% import "partials/language.html" as lang with context %}
2-
<nav class="md-nav md-nav--secondary" aria-label="{{ lang.t('toc.title') }}">
2+
{# toc_wrapper_tag: <nav> when standalone; <div> when embedded inside the sidebar <nav>
3+
(toc_inside_nav set by nav-item.html) — nested <nav> tags break HTML->Markdown converters #}
4+
{% set toc_wrapper_tag = 'div' if toc_inside_nav else 'nav' %}
5+
<{{ toc_wrapper_tag }} class="md-nav md-nav--secondary" aria-label="{{ lang.t('toc.title') }}">
36
{% set toc = page.toc %}
47
{% if toc | first is defined and "\x3ch1 id=" in page.content %}
58
{% set toc = (toc | first).children %}
@@ -18,7 +21,7 @@
1821
{{ toc_item.title }}
1922
</a>
2023
{% if toc_item.children %}
21-
<nav class="md-nav">
24+
<div class="md-nav">
2225
<ul class="md-nav__list">
2326
{% for toc_item in toc_item.children %}
2427
<li class="md-nav__item level-2">
@@ -28,10 +31,10 @@
2831
</li>
2932
{% endfor %}
3033
</ul>
31-
</nav>
34+
</div>
3235
{% endif %}
3336
</li>
3437
{% endfor %}
3538
</ul>
3639
{% endif %}
37-
</nav>
40+
</{{ toc_wrapper_tag }}>

0 commit comments

Comments
 (0)