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} - + /> + {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 @@ - - - - - - - -