diff --git a/.gitignore b/.gitignore
index 817eebf7ae..d9c77c7453 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,8 +42,8 @@ bld/
# Visual Studio 2015/2017 cache/options directory
.vs/
-# Uncomment if you have tasks that create the project's static files in wwwroot
-#wwwroot/
+# Pagefind.Net.Frontend auto-extraction output (disabled via PagefindFrontendDisableExtract)
+wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
diff --git a/Directory.Build.props b/Directory.Build.props
index 3f89a0761e..1e2d4f14b3 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -23,6 +23,7 @@
enable
enable
true
+ true
diff --git a/Directory.Packages.props b/Directory.Packages.props
index be5918099a..0d0a5b39db 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -45,6 +45,8 @@
+
+
diff --git a/docs/_docset.yml b/docs/_docset.yml
index c9a4ff76c3..33dfda75e4 100644
--- a/docs/_docset.yml
+++ b/docs/_docset.yml
@@ -40,7 +40,6 @@ subs:
features:
primary-nav: false
- static-search: true
# Temporarily disabled: the pr-272388 preview registry artifact is gone and there is no
# working `main` registry to fall back to yet. Re-enable once a registry URL resolves.
diff --git a/docs/configure/content-set/index.md b/docs/configure/content-set/index.md
index 7cc9411eac..a1e7e933ce 100644
--- a/docs/configure/content-set/index.md
+++ b/docs/configure/content-set/index.md
@@ -13,22 +13,17 @@ A content set in `docs-builder` is equivalent to an AsciiDoc book. At this level
| **Content source files** --> A whole bunch of markup files as well as any other assets used in the docs (for example, images, videos, and diagrams). | **Markup**: AsciiDoc files **Assets**: Images, videos, and diagrams | **Markup**: MD files **Assets**: Images, videos, and diagrams |
| **Information architecture** --> A way to specify the order in which these text-based files should appear in the information architecture of the book. | `index.asciidoc` file (this can be spread across several AsciiDoc files, but generally starts with the index file specified in the `conf.yaml` file)) | `docset.yml` and/or `toc.yml` file(s) |
-## Enable static search
+## Static search
-Isolated builds can include a Pagefind index that runs entirely in the browser. Enable it in `docset.yml`:
+Isolated builds and `docs-builder serve` automatically include a [Pagefind](https://pagefind.app) search index that runs entirely in the browser. No configuration is needed — the `pagefind` exporter is included by default.
-```yaml
-features:
- static-search: true
-```
-
-The generated site needs to be served over HTTP, such as from S3 and CloudFront or a local static server:
+To use it with a static build, serve the output over HTTP:
```sh
python3 -m http.server --directory .artifacts/docs/html
```
-Static search does not require a search API, but it does not work in the on-demand `docs-builder serve` mode or when pages are opened directly with `file://`.
+Static search does not require a search API. It does not work when pages are opened directly with `file://`.
## Learn more
diff --git a/src/Elastic.Documentation.Configuration/Builder/ConfigurationFile.cs b/src/Elastic.Documentation.Configuration/Builder/ConfigurationFile.cs
index aaa9c84006..34db8d3ea0 100644
--- a/src/Elastic.Documentation.Configuration/Builder/ConfigurationFile.cs
+++ b/src/Elastic.Documentation.Configuration/Builder/ConfigurationFile.cs
@@ -313,8 +313,6 @@ public ConfigurationFile(DocumentationSetFile docSetFile, IDocumentationSetConte
_features["primary-nav"] = docSetFile.Features.PrimaryNav.Value;
if (docSetFile.Features.DisableGithubEditLink.HasValue)
_features["disable-github-edit-link"] = docSetFile.Features.DisableGithubEditLink.Value;
- if (docSetFile.Features.StaticSearch.HasValue)
- _features["static-search"] = docSetFile.Features.StaticSearch.Value;
// primary-nav requires the Elastic global navigation which is not available for white-label builds
if (Branding is not null && docSetFile.Features.PrimaryNav is true)
diff --git a/src/Elastic.Documentation.Configuration/Builder/FeatureFlags.cs b/src/Elastic.Documentation.Configuration/Builder/FeatureFlags.cs
index 917143312d..00ecf4fc53 100644
--- a/src/Elastic.Documentation.Configuration/Builder/FeatureFlags.cs
+++ b/src/Elastic.Documentation.Configuration/Builder/FeatureFlags.cs
@@ -38,12 +38,6 @@ public bool WebsiteSearchEnabled
set => _featureFlags["website-search"] = value;
}
- public bool StaticSearchEnabled
- {
- get => IsEnabled("static-search");
- set => _featureFlags["static-search"] = value;
- }
-
public string? WebsiteSearchScriptUrl { get; set; }
public bool AirGappedEnabled
diff --git a/src/Elastic.Documentation.Configuration/Toc/DocumentationSetFile.cs b/src/Elastic.Documentation.Configuration/Toc/DocumentationSetFile.cs
index 41e00716df..5ea875eb28 100644
--- a/src/Elastic.Documentation.Configuration/Toc/DocumentationSetFile.cs
+++ b/src/Elastic.Documentation.Configuration/Toc/DocumentationSetFile.cs
@@ -756,8 +756,6 @@ public class DocumentationSetFeatures
public bool? PrimaryNav { get; set; }
[YamlMember(Alias = "disable-github-edit-link", ApplyNamingConventions = false)]
public bool? DisableGithubEditLink { get; set; }
- [YamlMember(Alias = "static-search", ApplyNamingConventions = false)]
- public bool? StaticSearch { get; set; }
}
[YamlSerializable]
diff --git a/src/Elastic.Documentation.Site/Assets/config.ts b/src/Elastic.Documentation.Site/Assets/config.ts
index e9fc45392f..1ac157be94 100644
--- a/src/Elastic.Documentation.Site/Assets/config.ts
+++ b/src/Elastic.Documentation.Site/Assets/config.ts
@@ -11,7 +11,6 @@ export interface DocsConfig {
rootPath: string // '/docs' for assembler, '' for codex and isolated
apiBasePath: string // '/docs/_api' for assembler, '/api' for codex
airGapped: boolean
- staticSearch: boolean
}
declare global {
@@ -27,7 +26,6 @@ const DEFAULT_CONFIG: DocsConfig = {
rootPath: '',
apiBasePath: '/docs/_api',
airGapped: false,
- staticSearch: false,
}
export const config: DocsConfig = window.__DOCS_CONFIG__ ?? DEFAULT_CONFIG
diff --git a/src/Elastic.Documentation.Site/Assets/markdown/mermaid.css b/src/Elastic.Documentation.Site/Assets/markdown/mermaid.css
index 068f647869..8dd77c0106 100644
--- a/src/Elastic.Documentation.Site/Assets/markdown/mermaid.css
+++ b/src/Elastic.Documentation.Site/Assets/markdown/mermaid.css
@@ -26,7 +26,7 @@
transition: transform 0.1s ease-out;
}
-.mermaid-rendered svg {
+.mermaid-rendered img {
height: auto;
max-width: 100%;
}
diff --git a/src/Elastic.Documentation.Site/Assets/mermaid.ts b/src/Elastic.Documentation.Site/Assets/mermaid.ts
index 2ec993a2f1..976afc73a5 100644
--- a/src/Elastic.Documentation.Site/Assets/mermaid.ts
+++ b/src/Elastic.Documentation.Site/Assets/mermaid.ts
@@ -61,7 +61,7 @@ function setupControls(
container: HTMLElement,
viewport: HTMLElement,
rendered: HTMLElement,
- svgContent: string
+ imgSrc: string
): void {
const state: DiagramState = {
zoom: 1,
@@ -131,7 +131,7 @@ function setupControls(
// Fullscreen handler
fullscreenBtn.addEventListener('click', () => {
- openFullscreenModal(svgContent)
+ openFullscreenModal(imgSrc)
})
// Pan with mouse drag
@@ -200,7 +200,7 @@ function calculateFitScale(
/**
* Open fullscreen modal with the diagram
*/
-function openFullscreenModal(svgContent: string): void {
+function openFullscreenModal(imgSrc: string): void {
// Create modal elements
const modal = document.createElement('div')
modal.className = 'mermaid-modal'
@@ -219,7 +219,10 @@ function openFullscreenModal(svgContent: string): void {
const rendered = document.createElement('div')
rendered.className = 'mermaid-rendered'
- rendered.innerHTML = svgContent
+ const modalImg = document.createElement('img')
+ modalImg.src = imgSrc
+ modalImg.alt = 'Mermaid diagram'
+ rendered.appendChild(modalImg)
viewport.appendChild(rendered)
modalContent.appendChild(closeBtn)
@@ -365,14 +368,14 @@ function openFullscreenModal(svgContent: string): void {
// Calculate and apply initial zoom to fit diagram in viewport
requestAnimationFrame(() => {
- const svg = rendered.querySelector('svg')
- if (svg) {
- const svgRect = svg.getBoundingClientRect()
+ const img = rendered.querySelector('img')
+ if (img) {
+ const imgRect = img.getBoundingClientRect()
const viewportRect = viewport.getBoundingClientRect()
initialZoom = calculateFitScale(
- svgRect.width,
- svgRect.height,
+ imgRect.width,
+ imgRect.height,
viewportRect.width,
viewportRect.height
)
@@ -405,7 +408,8 @@ export function initMermaid() {
if (!viewport || !rendered) continue
- const svgContent = rendered.innerHTML
- setupControls(el, viewport, rendered, svgContent)
+ const img = rendered.querySelector('img')
+ const imgSrc = img?.src ?? ''
+ setupControls(el, viewport, rendered, imgSrc)
}
}
diff --git a/src/Elastic.Documentation.Site/Assets/web-components/Header/Header.tsx b/src/Elastic.Documentation.Site/Assets/web-components/Header/Header.tsx
index 73840df870..8ce881f011 100644
--- a/src/Elastic.Documentation.Site/Assets/web-components/Header/Header.tsx
+++ b/src/Elastic.Documentation.Site/Assets/web-components/Header/Header.tsx
@@ -18,7 +18,7 @@ import { useRef } from 'react'
interface Props {
title: string
- logoHref: string
+ logoHref?: string
githubRepository?: string
githubLink?: string
gitBranch: string
@@ -33,6 +33,8 @@ interface Props {
* component does not have to infer branding state from other optional props.
*/
branded?: boolean
+ /** When true the git remote belongs to the `elastic` GitHub organization. Controls whether the Elastic logo is shown as default. */
+ elasticOrg?: boolean
/** Custom header background CSS colour. Only used when branded=true; defaults to #000000. */
headerBg?: string
/** Custom icon image URL. When set (and branded=true), renders an
instead of the title text. */
@@ -49,6 +51,7 @@ export const Header = ({
githubRef,
airGapped = false,
branded = false,
+ elasticOrg = false,
headerBg,
iconSrc,
}: Props) => {
@@ -56,65 +59,65 @@ export const Header = ({
const containerRef = useRef(null)
useHtmxContainer(containerRef)
- const logoSection = branded ? (
- iconSrc ? (
- // Branded with icon — plain , no HTMX (no containerRef)
-
+
-
-
- {title}
-
+ />
+ {title}
+ >
+ ) : (
+ <>{title}>
+ )
+
+ const brandedStyles = iconSrc
+ ? css`
+ display: inline-flex;
+ align-items: center;
+ gap: ${euiTheme.size.s};
+ color: var(--color-white);
+ text-decoration: none;
+ padding: ${euiTheme.size.s};
+ `
+ : css`
+ display: inline-flex;
+ align-items: center;
+ color: var(--color-white);
+ text-decoration: none;
+ padding: ${euiTheme.size.s};
+ font-weight: ${euiTheme.font.weight.bold};
+ `
+
+ const plainStyles = css`
+ display: inline-flex;
+ align-items: center;
+ padding: ${euiTheme.size.s};
+ font-weight: ${euiTheme.font.weight.bold};
+ color: ${euiTheme.colors.textInk};
+ text-decoration: none;
+ border-radius: ${euiTheme.border.radius.small};
+ &:hover {
+ background: rgba(0, 0, 0, 0.06);
+ }
+ `
+
+ const logoSection = branded ? (
+ logoHref ? (
+
+ {brandedIconContent}
) : (
- // Branded without icon — title text only, no HTMX
-
- {title}
-
+ {brandedIconContent}
)
- ) : (
- // Default: Elastic-branded logo (light-mode styling)
+ ) : elasticOrg ? (
+ ) : (
+
+ {logoHref ? (
+
+ {title}
+
+ ) : (
+ {title}
+ )}
+
)
const headerCss =
@@ -166,7 +179,7 @@ export const Header = ({
{
items: [logoSection],
},
- ...(config.staticSearch
+ ...(config.buildType === 'isolated'
? [
{
items: [
@@ -257,6 +270,7 @@ customElements.define(
githubRef: 'string',
airGapped: 'boolean',
branded: 'boolean',
+ elasticOrg: 'boolean',
headerBg: 'string',
iconSrc: 'string',
},
diff --git a/src/Elastic.Documentation.Site/Assets/web-components/ModalSearch/pagefind.ts b/src/Elastic.Documentation.Site/Assets/web-components/ModalSearch/pagefind.ts
index a356630611..46883c3563 100644
--- a/src/Elastic.Documentation.Site/Assets/web-components/ModalSearch/pagefind.ts
+++ b/src/Elastic.Documentation.Site/Assets/web-components/ModalSearch/pagefind.ts
@@ -52,11 +52,11 @@ const rootPath = config.rootPath.replace(/\/$/, '')
const loadPagefind = () => {
pagefindPromise ??= (async () => {
try {
- const moduleUrl = `${rootPath}/pagefind/pagefind.js`
+ const moduleUrl = `${rootPath}/_static/pagefind/pagefind.js`
const pagefind = (await import(moduleUrl)) as PagefindApi
await pagefind.options({
baseUrl: rootPath || '/',
- basePath: `${rootPath}/pagefind/`,
+ basePath: `${rootPath}/_static/pagefind/`,
})
await pagefind.init()
return pagefind
diff --git a/src/Elastic.Documentation.Site/Assets/web-components/ModalSearch/useModalSearchQuery.ts b/src/Elastic.Documentation.Site/Assets/web-components/ModalSearch/useModalSearchQuery.ts
index 6cb6c1397d..1ca23e633b 100644
--- a/src/Elastic.Documentation.Site/Assets/web-components/ModalSearch/useModalSearchQuery.ts
+++ b/src/Elastic.Documentation.Site/Assets/web-components/ModalSearch/useModalSearchQuery.ts
@@ -87,7 +87,7 @@ export const useModalSearchQuery = () => {
trimmedSearchTerm.length >= 1 &&
!isCooldownActive &&
!awaitingNewInput &&
- (config.buildType !== 'isolated' || config.staticSearch)
+ true
const query = useQuery({
queryKey: [
diff --git a/src/Elastic.Documentation.Site/Elastic.Documentation.Site.csproj b/src/Elastic.Documentation.Site/Elastic.Documentation.Site.csproj
index 1316622364..5a9d1c2ae4 100644
--- a/src/Elastic.Documentation.Site/Elastic.Documentation.Site.csproj
+++ b/src/Elastic.Documentation.Site/Elastic.Documentation.Site.csproj
@@ -86,21 +86,6 @@
-
-
-
-
-
-
-
-