Skip to content

Commit c32970e

Browse files
cscheidclaude
andcommitted
Convert tabsets to headings with content in llms-txt output
Tabsets were rendered as a bullet list of empty links followed by disconnected content. Add handle_tabset() to the Lua filter that extracts tab titles from the nav BulletList and pairs them with their tab-pane contents, outputting each as a heading + content. Co-Authored-By: Claude Opus 4.6 <[email protected]>
1 parent 43ef7e1 commit c32970e

2 files changed

Lines changed: 68 additions & 3 deletions

File tree

src/resources/filters/llms/llms.lua

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,53 @@ local function clean_element(el)
7171
end
7272
end
7373

74+
local function handle_tabset(div)
75+
local titles = {}
76+
local panes = {}
77+
78+
-- Extract tab titles from the nav BulletList (first one in the div)
79+
-- and tab pane contents from the tab-content Div
80+
for _, block in ipairs(div.content) do
81+
if block.t == "BulletList" and #titles == 0 then
82+
for _, item in ipairs(block.content) do
83+
for _, inner_block in ipairs(item) do
84+
if inner_block.t == "Plain" or inner_block.t == "Para" then
85+
for _, inline in ipairs(inner_block.content) do
86+
if inline.t == "Link" then
87+
table.insert(titles, inline.content)
88+
break
89+
end
90+
end
91+
end
92+
end
93+
end
94+
elseif block.t == "Div" and block.classes:includes("tab-content") then
95+
for _, inner in ipairs(block.content) do
96+
if inner.t == "Div" and inner.classes:includes("tab-pane") then
97+
table.insert(panes, inner.content)
98+
end
99+
end
100+
end
101+
end
102+
103+
-- Build output: heading + content for each tab
104+
local result = pandoc.Blocks({})
105+
for i = 1, math.max(#titles, #panes) do
106+
if titles[i] then
107+
result:insert(pandoc.Header(2, titles[i]))
108+
end
109+
if panes[i] then
110+
result:extend(panes[i])
111+
end
112+
end
113+
114+
if #result > 0 then
115+
return result
116+
end
117+
-- Fallback: return content as-is
118+
return div.content
119+
end
120+
74121
local function handle_callout(div)
75122
local kind = "NOTE" -- NOTE, TIP, IMPORTANT, WARNING, CAUTION
76123
div.classes:map(function(cls)
@@ -176,6 +223,10 @@ end
176223

177224
function Div(div)
178225

226+
if div.classes:includes("panel-tabset") then
227+
return handle_tabset(div)
228+
end
229+
179230
if div.classes:includes("callout") then
180231
return handle_callout(div)
181232
end

tests/docs/smoke-all/website/llms-txt/about.qmd

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ _quarto:
66
ensureLlmsMdExists: true
77
ensureLlmsMdRegexMatches:
88
# First array: patterns that MUST match
9-
- ["^# About", "> \\*\\*NOTE:\\*\\*", "> \\*\\*WARNING:\\*\\*", "This is a note", "``` python", "def hello", "\\| Feature", "\\|[-]+\\|", "\\[home page\\]\\(.*\\.llms\\.md\\)", "\\[test site intro\\]\\(index\\.llms\\.md#test-content\\)"]
10-
# Second array: patterns that must NOT match (no .html links, no breadcrumbs)
11-
- ["\\.html\\)", "\\.html#", "\\[Info\\]"]
9+
- ["^# About", "> \\*\\*NOTE:\\*\\*", "> \\*\\*WARNING:\\*\\*", "This is a note", "``` python", "def hello", "\\| Feature", "\\|[-]+\\|", "\\[home page\\]\\(.*\\.llms\\.md\\)", "\\[test site intro\\]\\(index\\.llms\\.md#test-content\\)", "## Alpha Tab", "Alpha content here", "## Beta Tab", "Beta content here"]
10+
# Second array: patterns that must NOT match (no .html links, no breadcrumbs, no empty tab links)
11+
- ["\\.html\\)", "\\.html#", "\\[Info\\]", "\\[Alpha Tab\\]\\(\\)", "\\[Beta Tab\\]\\(\\)"]
1212
---
1313

1414
About this test site.
@@ -39,6 +39,20 @@ def hello():
3939
| Code | Working |
4040
| Tables | Working |
4141

42+
## Tabset Example
43+
44+
::: {.panel-tabset}
45+
46+
## Alpha Tab
47+
48+
Alpha content here.
49+
50+
## Beta Tab
51+
52+
Beta content here.
53+
54+
:::
55+
4256
## Link Example
4357

4458
Go back to the [home page](index.qmd).

0 commit comments

Comments
 (0)