diff --git a/antora-ui-camel/src/css/header.css b/antora-ui-camel/src/css/header.css index ae4fa531972..8b265ec82da 100644 --- a/antora-ui-camel/src/css/header.css +++ b/antora-ui-camel/src/css/header.css @@ -380,6 +380,10 @@ html:not([data-scroll='0']) .navbar { .result_summary { color: var(--color-jet-50); padding-top: 0.3rem; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 3; + overflow: hidden; } #search_results div.footer-search { diff --git a/antora-ui-camel/src/js/vendor/algoliasearch.bundle.js b/antora-ui-camel/src/js/vendor/algoliasearch.bundle.js index eb436617b41..a4b692ab8df 100644 --- a/antora-ui-camel/src/js/vendor/algoliasearch.bundle.js +++ b/antora-ui-camel/src/js/vendor/algoliasearch.bundle.js @@ -3,6 +3,9 @@ const algoliasearch = require('algoliasearch/lite') + const MAX_SNIPPET_LENGTH = 200 + const RESULTS_LIMIT = 10 + // Sub-projects to exclude from main search - users can browse these directly const EXCLUDED_SUBPROJECTS = [ '/camel-k/', @@ -21,6 +24,60 @@ }) } + function truncateHighlightedHtml (html, maxChars) { + if (!html || maxChars <= 0) return '' + + const template = document.createElement('template') + template.innerHTML = html + + let remaining = maxChars + let truncated = false + + const TEXT_NODE = 3 + const ELEMENT_NODE = 1 + + function cloneUntilLimit (node) { + if (remaining <= 0) return null + + if (node.nodeType === TEXT_NODE) { + const text = node.nodeValue || '' + if (text.length <= remaining) { + remaining -= text.length + return document.createTextNode(text) + } + truncated = true + const slice = text.slice(0, remaining) + remaining = 0 + return document.createTextNode(slice) + } + + if (node.nodeType === ELEMENT_NODE) { + const el = node + const cloned = el.cloneNode(false) + for (const child of Array.from(el.childNodes)) { + if (remaining <= 0) break + const childClone = cloneUntilLimit(child) + if (childClone) cloned.appendChild(childClone) + } + return cloned + } + + return null + } + + const outFragment = document.createDocumentFragment() + for (const child of Array.from(template.content.childNodes)) { + if (remaining <= 0) break + const childClone = cloneUntilLimit(child) + if (childClone) outFragment.appendChild(childClone) + } + if (truncated) outFragment.appendChild(document.createTextNode('…')) + + const container = document.createElement('div') + container.appendChild(outFragment) + return container.innerHTML + } + window.addEventListener('load', () => { const client = algoliasearch('V62SL4FFIW', '1b7e52df4759e32dd49adedb286997f6') const index = client.initIndex('apache_camel') @@ -70,7 +127,7 @@ // Filter out sub-project results to focus on camel-core documentation const filteredHits = results.hits.filter(function (hit) { return !isSubProjectUrl(hit.url) - }).slice(0, 5) + }).slice(0, RESULTS_LIMIT) const data = filteredHits.reduce((data, hit) => { const section = hit.hierarchy.lvl0 const sectionKey = `${section}-${hit.version || ''}` @@ -86,7 +143,7 @@ .slice(1) .filter((lvl) => lvl !== null) .join(' / '), - snippet: hit._highlightResult.content.value, + snippet: truncateHighlightedHtml(hit._highlightResult.content.value, MAX_SNIPPET_LENGTH), }) return data