From c0e3327692d7935f01c1b422778e940191106b6f Mon Sep 17 00:00:00 2001 From: Jan Calanog Date: Thu, 13 Feb 2025 01:31:18 +0100 Subject: [PATCH 1/4] Add ToC sidebar + some fixes and refactoring --- .github/workflows/preview-build.yml | 3 +- docs/contribute/index.md | 19 +-- docs/contribute/locally.md | 55 ++----- docs/docset.yml | 1 - .../_snippets/content-patterns-list.md | 2 +- docs/versions/content-patterns.md | 54 ++----- src/Elastic.Markdown/Assets/main.ts | 3 + src/Elastic.Markdown/Assets/markdown/list.css | 25 ++++ .../Assets/markdown/typography.css | 11 +- src/Elastic.Markdown/Assets/pages-nav.ts | 11 +- src/Elastic.Markdown/Assets/styles.css | 76 +++++++--- src/Elastic.Markdown/Assets/toc-nav.ts | 138 ++++++++++++++++++ src/Elastic.Markdown/Elastic.Markdown.csproj | 8 +- src/Elastic.Markdown/IO/MarkdownFile.cs | 6 +- .../Slices/Layout/_Breadcrumbs.cshtml | 9 +- .../Slices/Layout/_Footer.cshtml | 25 ++-- .../Slices/Layout/_Header.cshtml | 2 +- .../Slices/Layout/_PagesNav.cshtml | 4 +- .../Slices/Layout/_TableOfContents.cshtml | 79 +++++++--- .../Slices/Layout/_TocTree.cshtml | 1 + .../Slices/Layout/_TocTreeNav.cshtml | 19 +-- src/Elastic.Markdown/Slices/_Layout.cshtml | 45 ++++-- src/Elastic.Markdown/Slices/_ViewModels.cs | 2 + 23 files changed, 410 insertions(+), 188 deletions(-) create mode 100644 src/Elastic.Markdown/Assets/markdown/list.css create mode 100644 src/Elastic.Markdown/Assets/toc-nav.ts diff --git a/.github/workflows/preview-build.yml b/.github/workflows/preview-build.yml index 091dea0b9..471fdebfb 100644 --- a/.github/workflows/preview-build.yml +++ b/.github/workflows/preview-build.yml @@ -53,6 +53,7 @@ jobs: if: github.event_name == 'push' || steps.check-files.outputs.any_changed == 'true' uses: actions/checkout@v4 with: + repository: '${{ github.event.pull_request.head.repo.full_name || github.repository }}' ref: ${{ github.event.pull_request.head.sha || github.ref }} persist-credentials: false @@ -147,7 +148,7 @@ jobs: --paths "${PATH_PREFIX}" "${PATH_PREFIX}/*" - name: Update Link Index - if: github.event_name == 'push' && github.ref == 'refs/heads/main' && steps.s3-upload.outcome == 'success' + if: steps.s3-upload.outcome == 'success' uses: elastic/docs-builder/actions/update-link-index@main - name: Update deployment status diff --git a/docs/contribute/index.md b/docs/contribute/index.md index 0af35e1c1..e5a29a5a8 100644 --- a/docs/contribute/index.md +++ b/docs/contribute/index.md @@ -10,29 +10,20 @@ Whether you're a technical writer or you've only edited Elastic docs once or twi ## Contribute to the docs [#contribute] -The version of the docs you want to contribute to determines the tool and syntax you must use to update the docs. - -### Contribute to Elastic Stack version 8.x docs and earlier - -To contribute to earlier versions of the Elastic Stack, you must work with our [legacy documentation build system](https://github.com/elastic/docs). This system uses AsciiDoc as it's authoring format. - -* For **simple bugfixes and enhancements** --> [Contribute on the web](on-the-web.md) -* For **complex or multi-page updates** --> See the [legacy documentation build guide](https://github.com/elastic/docs?tab=readme-ov-file#building-documentation) - -### Contribute to Elastic Stack version 9.0 docs and later - -* For **simple bugfixes and enhancements** --> [contribute on the web](on-the-web.md) -* For **complex or multi-page updates** --> [Contribute locally](locally.md) +* Simple bugs and enhancements --> [Contribute on the web](on-the-web.md) +* Complex or multi-page updates --> [Contribute locally](locally.md) +* Test migrated content --> [Migration guide](../migration/guide/index.md) ## Report a bug * It's a **documentation** problem --> [Open a docs issue](https://github.com/elastic/docs-content/issues/new?template=internal-request.yaml) *or* [Fix it myself](locally.md) * It's a **build tool (docs-builder)** problem --> [Open a bug report](https://github.com/elastic/docs-builder/issues/new?template=bug-report.yaml) +* It's a **migration tooling** problem --> [Open a bug report](https://github.com/elastic/docs-builder/issues/new?template=bug-report.yaml) ## Request an enhancement * Make the **documentation** better --> [Open a docs issue](https://github.com/elastic/docs-content/issues/new?template=internal-request.yaml) -* Make our **build tool (docs-builder)** better --> [Start a docs-builder discussion](https://github.com/elastic/docs-builder/discussions) +* Make our **build tool (docs-builder)** better --> [Open a docs-builder issue](https://github.com/elastic/docs-builder/issues/new?template=enhancement.yaml) ## Work on docs-builder diff --git a/docs/contribute/locally.md b/docs/contribute/locally.md index 08eb9c0f2..7818afbe7 100644 --- a/docs/contribute/locally.md +++ b/docs/contribute/locally.md @@ -1,31 +1,13 @@ # Contribute locally Follow these steps to contribute to Elastic docs. - -* [Prerequisites](#prerequisites) * [Step 1: Install `docs-builder`](#step-one) -* [Step 2: Clone a content repository](#step-two) +* [Step 2: Clone the `docs-content` repository](#step-two) * [Step 3: Serve the Documentation](#step-three) -* [Step 4: Write docs!](#step-four) -* [Step 5: Push your changes](#step-five) - -## Prerequisites - -To write and push updates to Elastic documentation, you need the following: - -1. **A code editor**: we recommend [Visual Studio Code](https://code.visualstudio.com/download) -1. **Git installed on your machine**: learn how [here](https://github.com/git-guides/install-git) -1. **A GitHub account**: sign up [here](https://github.com/) +* [Step 4: Open a PR](#step-three) ## Step 1: Install `docs-builder` [#step-one] -There are two different ways to install and run `docs-builder`: - -1. Download, extract, and run the binary (recommended) -1. Clone the repository and build the binary from source - -This guide uses option one. If you'd like to clone the repository and build from source, learn how in the [project readme](https://github.com/elastic/docs-builder?tab=readme-ov-file#docs-builder). - ::::{tab-set} :::{tab-item} macOS @@ -45,7 +27,7 @@ This guide uses option one. If you'd like to clone the repository and build from ``` 3. **Run the Binary:** - Use the `serve` command to start serving the documentation at http://localhost:3000. The path to the `docset.yml` file that you want to build can be specified with `-p`: + Use the `serve` command to start serving the documentation at http://localhost:3000. The path to the docset.yml file that you want to build can be specified with `-p`: ```sh ./docs-builder serve -p ./path/to/docs ``` @@ -69,7 +51,7 @@ This guide uses option one. If you'd like to clone the repository and build from ``` 3. **Run the Binary:** - Use the `serve` command to start serving the documentation at http://localhost:3000. The path to the `docset.yml` file that you want to build can be specified with `-p`: + Use the `serve` command to start serving the documentation at http://localhost:3000. The path to the docset.yml file that you want to build can be specified with `-p`: ```sh .\docs-builder serve -p ./path/to/docs ``` @@ -93,7 +75,7 @@ This guide uses option one. If you'd like to clone the repository and build from ``` 3. **Run the Binary:** - Use the `serve` command to start serving the documentation at http://localhost:3000. The path to the `docset.yml` file that you want to build can be specified with `-p`: + Use the `serve` command to start serving the documentation at http://localhost:3000. The path to the docset.yml file that you want to build can be specified with `-p`: ```sh ./docs-builder serve -p ./path/to/docs ``` @@ -102,28 +84,22 @@ This guide uses option one. If you'd like to clone the repository and build from :::: -## Clone a content repository [#step-two] - -:::{tip} -Documentation lives in many repositories across Elastic. If you're unsure which repository to clone, you can use the "Edit this page" link on any documentation page to determine where the source file lives. -::: +## Clone the `docs-content` Repository [#step-two] -In this guide, we'll clone the [`docs-content`](https://github.com/elastic/docs-content) repository. The `docs-content` repository is the home for narrative documentation at Elastic. Clone this repo to a directory of your choice: +Clone the `docs-content` repository to a directory of your choice: ```sh git clone https://github.com/elastic/docs-content.git ``` ## Serve the Documentation [#step-three] -1. **Navigate to the `docs-builder` clone location:** +1. **Navigate to the cloned repository:** ```sh cd docs-content ``` -1. **Run the Binary:** - Run the binary with the `serve` command to build and serve the content set to http://localhost:3000. Specify the path to the `docset.yml` file that you want to build with `-p`. - - For example, if `docs-builder` and `docs-content` are in the same top-level directory, you would run: +2. **Run the Binary:** + Use the `serve` command to start serving the documentation at http://localhost:3000. The path to the `docset.yml` file that you want to build can be specified with `-p`: ```sh # macOS/Linux ./docs-builder serve -p ./migration-test @@ -134,16 +110,9 @@ git clone https://github.com/elastic/docs-content.git Now you should be able to view the documentation locally by navigating to http://localhost:3000. -## Step 4: Write docs [#step-four] - -We write docs in markdown. See our [syntax](../syntax/index.md) guide for the flavor of markdown that we support and all of our custom directives that enable you to add a little extra pizazz to your docs. - -## Step 5: Push your changes [#step-five] - -After you've made your changes locally, +## Step 4: Open a PR [#step-four] -* [Push your commits](https://docs.github.com/en/get-started/using-git/pushing-commits-to-a-remote-repository) -* [Open a Pull Request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) +Open a PR. Good luck. ## Step 5: View on elastic.co/docs diff --git a/docs/docset.yml b/docs/docset.yml index 74139c204..52eb412e5 100644 --- a/docs/docset.yml +++ b/docs/docset.yml @@ -21,7 +21,6 @@ external_hosts: - github.io - github.com - elastic.dev - - visualstudio.com exclude: - '_*.md' subs: diff --git a/docs/versions/_snippets/content-patterns-list.md b/docs/versions/_snippets/content-patterns-list.md index 4157477bb..3a01f0841 100644 --- a/docs/versions/_snippets/content-patterns-list.md +++ b/docs/versions/_snippets/content-patterns-list.md @@ -4,7 +4,7 @@ | [Section/heading-level `applies` tags](/versions/content-patterns.md#sectionheading-level-applies-tags) | Provide signals about a section’s scope so a user can choose to read or skip it as needed. | | [Tabs](/versions/content-patterns.md#tabs) | Provide two sets of procedures when one or more steps in a process differs between contexts or versions. | | [Callouts](/versions/content-patterns.md#callouts) | Draw attention to happy differences and basic clarifications. | -| [Prose](/versions/content-patterns.md#prose) | - Identify features in a list of features that are exclusive to a specific context, or that were introduced in a specific version
- List differing requirements, limits, and other simple, mirrored facts
- Provide clarifying or secondary information
- Explain differences with a "why" (e.g. comparative overviews) | +| [Prose](/versions/content-patterns.md#prose) | Provide clarifying or secondary information, explain differences with a "why". | | [Sibling pages](/versions/content-patterns.md#sibling-pages) | When the information is too complex to be addressed with only the other content patterns. See specific examples in the sibling pages section. | % | [List item suffixes](/versions/content-patterns.md#list-item-suffixes) | Identify features in a **list of features** that are exclusive to a specific context, or that were introduced in a specific version. | diff --git a/docs/versions/content-patterns.md b/docs/versions/content-patterns.md index a0bbb08cd..a7462321f 100644 --- a/docs/versions/content-patterns.md +++ b/docs/versions/content-patterns.md @@ -208,12 +208,12 @@ If there’s a terminology change or other minor change (especially where x equa ## Prose -**Use cases:** -* When features in a list of features are exclusive to a specific context, or were introduced in a specific version -* Requirements, limits, other simple, mirrored facts +**Use case**: Clarifying or secondary information, differences with a "why" + +**When to use:** * Cases where the information isn’t wildly important, but nice to know, or to add basic terminology change info to overviews * Comparative overviews -* Differences that are small enough or not significant enough to warrant an admonition or tabs or separate sections with front matter +* Differences that are small enough or not significant enough to warrant an admonition or tabs or separate sections with frontmatter. In some cases, you might want to add a paragraph specific to one version or another in prose to clarify behavior or terminology. @@ -223,44 +223,12 @@ In cases where there are significant differences between contexts, close explana ### Examples +* In {{stack}} 9.1.0 and earlier, **Spaces** were referred to as **Places**. ::::{tab-set} -:group: five-six-four-one-three - -:::{tab-item} Unique features -:sync: five - -* Each space has its own saved objects. -* Users can only access the spaces that they have been granted access to. This access is based on user roles, and a given role can have different permissions per space. -* In {{stack}} 9.0.0+, each space has its own navigation. - -::: - -:::{tab-item} Unique reqs / limits -:sync: six - -* In serverless, use `Admin` or equivalent -* In {{stack}} 9.0.0+, use `kibana_admin` or equivalent - -OR - -The maximum number of spaces that you can have differs by [what do we call this]: - -* In serverless, you can have a maximum of 100 spaces. -* In {{stack}} 9.0.0+, the maximum is controlled by the `xpack.spaces.maxSpaces` setting. Default is 1000. -::: +:group: one-two-three -:::{tab-item} Nice-to-know -:sync: four - -In {{stack}} 9.1.0 and earlier, **Spaces** were referred to as **Places**. - -OR - -If you're managing a {{stack}} v9 deployment, then you can also assign roles and define permissions for a space from the **Permissions** tab of the space settings. -::: - -:::{tab-item} Comparative overviews +:::{tab-item} One :sync: one The way that TLS certificates are managed depends on your deployment type: @@ -272,7 +240,12 @@ In {{eck}}, you can manage certificates for the HTTP layer. Certificates for the In {{ece}}, you can use one or more proxy certificates to secure the HTTP layer. These certificates are managed at the ECE installation level. Transport-level encryption is managed by ECE and certificates can’t be changed. ::: -:::{tab-item} Comparative overviews II +:::{tab-item} Two +:sync: two +If you're managing a {{stack}} v9 deployment, then you can also assign roles and define permissions for a space from the **Permissions** tab of the space settings. +::: + +:::{tab-item} Three :sync: three **Managed security in Elastic Cloud** @@ -291,7 +264,6 @@ You can augment Elastic Cloud security features in the following ways: ::: :::: - ## Sibling pages **Use case:** diff --git a/src/Elastic.Markdown/Assets/main.ts b/src/Elastic.Markdown/Assets/main.ts index 97b9d92b8..45b3f2846 100644 --- a/src/Elastic.Markdown/Assets/main.ts +++ b/src/Elastic.Markdown/Assets/main.ts @@ -1,5 +1,8 @@ import {initNav} from "./pages-nav"; +import {initTocNav} from "./toc-nav"; + import {initHighlight} from "./hljs"; initNav(); +initTocNav(); initHighlight(); diff --git a/src/Elastic.Markdown/Assets/markdown/list.css b/src/Elastic.Markdown/Assets/markdown/list.css new file mode 100644 index 000000000..1d9e79e0e --- /dev/null +++ b/src/Elastic.Markdown/Assets/markdown/list.css @@ -0,0 +1,25 @@ +#elastic-docs-v3 { + ol,ul { + font-family: "Inter", sans-serif; + @apply text-base text-body mb-6; + line-height: 1.5em; + letter-spacing: 0; + margin-left: 1.5em; + } + + ol { + list-style-type: decimal; + } + + ul { + list-style-type: disc; + } + + li { + margin-bottom: calc(var(--spacing) * 3); + + p { + margin-bottom: 0; + } + } +} diff --git a/src/Elastic.Markdown/Assets/markdown/typography.css b/src/Elastic.Markdown/Assets/markdown/typography.css index 0fc01be64..920a5fe55 100644 --- a/src/Elastic.Markdown/Assets/markdown/typography.css +++ b/src/Elastic.Markdown/Assets/markdown/typography.css @@ -1,34 +1,35 @@ #elastic-docs-v3 { + h1 { font-family: "Mier B", "Inter", sans-serif; - @apply text-4xl text-ink font-bold mb-6; + @apply text-4xl text-black mb-6 mt-4; line-height: 1.2em; letter-spacing: -0.04em; } h2 { font-family: "Mier B", "Inter", sans-serif; - @apply text-2xl text-ink mb-6; + @apply text-2xl text-black mb-6 mt-4; line-height: 1.2em; letter-spacing: -0.02em; } h3 { font-family: "Mier B", "Inter", sans-serif; - @apply text-xl text-ink font-bold mb-6; + @apply text-xl text-black font-bold mb-6 mt-4; line-height: 1.2em; letter-spacing: -0.02em; } p { font-family: "Inter", sans-serif; - @apply text-base text-body mb-6; + @apply text-base text-ink text-body mb-6; line-height: 1.5em; letter-spacing: 0; } a { font-family: "Inter", sans-serif; - @apply text-blue-elastic hover:underline underline-offset-4; + @apply text-blue-elastic underline hover:text-blue-800; } } diff --git a/src/Elastic.Markdown/Assets/pages-nav.ts b/src/Elastic.Markdown/Assets/pages-nav.ts index 96f763bbc..efef84b43 100644 --- a/src/Elastic.Markdown/Assets/pages-nav.ts +++ b/src/Elastic.Markdown/Assets/pages-nav.ts @@ -1,8 +1,8 @@ -import {$, $$} from "select-dom/strict"; +import {$, $$} from "select-dom"; type NavExpandState = { [key: string]: boolean }; const PAGE_NAV_EXPAND_STATE_KEY = 'pagesNavState'; -const navState = JSON.parse(sessionStorage.getItem(PAGE_NAV_EXPAND_STATE_KEY)) as NavExpandState +const navState = JSON.parse(sessionStorage.getItem(PAGE_NAV_EXPAND_STATE_KEY) ?? "{}") as NavExpandState // Initialize the nav state from the session storage // Return a function to keep the nav state in the session storage that should be called before the page is unloaded @@ -14,7 +14,9 @@ function keepNavState(nav: HTMLElement): () => void { if ('shouldExpand' in input.dataset && input.dataset['shouldExpand'] === 'true') { input.checked = true; } else { - input.checked = navState[key]; + if (key in navState) { + input.checked = navState[key]; + } } }); } @@ -68,6 +70,9 @@ function isElementInViewport(el: HTMLElement): boolean { export function initNav() { const pagesNav = $('#pages-nav'); + if (!pagesNav) { + return; + } const keepNavStateCallback = keepNavState(pagesNav); const keepNavPositionCallback = keepNavPosition(pagesNav); scrollCurrentNaviItemIntoView(pagesNav, 100); diff --git a/src/Elastic.Markdown/Assets/styles.css b/src/Elastic.Markdown/Assets/styles.css index a663b8466..bf677292a 100644 --- a/src/Elastic.Markdown/Assets/styles.css +++ b/src/Elastic.Markdown/Assets/styles.css @@ -3,6 +3,7 @@ @import "./theme.css"; @import "highlight.js/styles/atom-one-dark.css"; @import "./markdown/typography.css"; +@import "./markdown/list.css"; #default-search::-webkit-search-cancel-button { padding-right: calc(var(--spacing) * 2); @@ -15,25 +16,6 @@ background-repeat: no-repeat; } -#pages-nav { - &::-webkit-scrollbar-track { - background-color: transparent; - } - &:hover::-webkit-scrollbar-thumb { - background-color: var(--color-gray-light); - } - &::-webkit-scrollbar { - width: calc(var(--spacing) * 2); - height: calc(var(--spacing) * 2); - } - &::-webkit-scrollbar-thumb { - border-radius: var(--spacing); - } - - scrollbar-gutter: stable; -} - - #pages-nav li.current { position: relative; &::before { @@ -46,3 +28,59 @@ background-color: var(--color-gray-200); } } + +#toc-nav a.current { + color: var(--color-blue-elastic); + &:hover { + color: var(--color-blue-elastic); + } +} + +@layer components { + .link { + font-family: "Mier B", "Inter", sans-serif; + @apply + text-blue-elastic + text-nowrap + font-semibold + hover:text-blue-800 + inline-flex + justify-center + items-center; + + .link-arrow { + @apply + shrink-0 + size-7 + ml-2 + transition-transform + ease-out; + } + + &:hover{ + svg { + @apply translate-x-2; + } + } + } + + .sidebar { + .sidebar-nav { + @apply sticky top-22 z-30 overflow-y-auto; + max-height: calc(100vh - var(--spacing) * 22); + } + + .sidebar-link { + @apply + text-ink-light + hover:text-black + text-sm + leading-[1.2em] + tracking-[-0.02em]; + } + } +} + +* { + scroll-margin-top: calc(var(--spacing) * 26); +} diff --git a/src/Elastic.Markdown/Assets/toc-nav.ts b/src/Elastic.Markdown/Assets/toc-nav.ts new file mode 100644 index 000000000..21d1ad5cc --- /dev/null +++ b/src/Elastic.Markdown/Assets/toc-nav.ts @@ -0,0 +1,138 @@ +import { $$, $ } from 'select-dom'; + +interface TocElements { + headings: Element[]; + tocLinks: HTMLAnchorElement[]; + tocContainer: HTMLUListElement | null; + progressIndicator: HTMLDivElement; +} + +// 34 is the height of the header + some padding +// 4 is the base spacing unit +const HEADING_OFFSET = 34 * 4; + +function initializeTocElements(): TocElements { + const headings = $$('h2, h3'); + const tocLinks = $$('#toc-nav li>a') as HTMLAnchorElement[]; + const tocContainer = $('#toc-nav ul') as HTMLUListElement; + const progressIndicator = $('.toc-progress-indicator', tocContainer) as HTMLDivElement; + return { headings, tocLinks, tocContainer,progressIndicator }; +} + +// Find the current TOC links based on visible headings +// It can return multiple links because headings in a tab can have the same position +function findCurrentTocLinks(elements: TocElements): HTMLAnchorElement[] { + let currentTocLinks: HTMLAnchorElement[] = []; + let currentTop: number | null = null; + for (const heading of elements.headings) { + const rect = heading.getBoundingClientRect(); + if (rect.top <= HEADING_OFFSET) { + if (currentTop !== null && Math.abs(rect.top - currentTop) > 1) { + currentTocLinks = []; + } + currentTop = rect.top; + const foundLink = elements.tocLinks.find(link => + link.getAttribute('href') === `#${heading.closest('section')?.id}` + ); + if (foundLink) { + currentTocLinks.push(foundLink); + } + } + } + return currentTocLinks; +} + +// Get visible headings in viewport +function getVisibleHeadings(elements: TocElements) { + return elements.headings.filter(heading => { + const rect = heading.getBoundingClientRect(); + return rect.top - HEADING_OFFSET + 64 >= 0 && rect.top <= window.innerHeight; + }); +} + +// If the user has scrolled to the bottom of the page, +// and there are still multiple headings visible, we need to +// handle the progress indicator differently. +// In this case it sets the indicator for all visible headings. +function handleBottomScroll(elements: TocElements) { + const visibleHeadings = getVisibleHeadings(elements); + if (visibleHeadings.length === 0) return; + const firstHeading = visibleHeadings[0]; + const lastHeading = visibleHeadings[visibleHeadings.length - 1]; + const firstLink = elements.tocLinks.find(link => + link.getAttribute('href') === `#${firstHeading.parentElement?.id}` + )?.closest('li'); + const lastLink = elements.tocLinks.find(link => + link.getAttribute('href') === `#${lastHeading.parentElement?.id}` + )?.closest('li'); + if (firstLink && lastLink && elements.tocContainer) { + const tocRect = elements.tocContainer.getBoundingClientRect(); + const firstRect = firstLink.getBoundingClientRect(); + const lastRect = lastLink.getBoundingClientRect(); + updateProgressIndicatorPosition( + elements.progressIndicator, + firstRect.top - tocRect.top, + (lastRect.top + lastRect.height) - firstRect.top + ); + } +} + +function updateProgressIndicatorPosition( + indicator: HTMLDivElement, + top: number, + height: number +) { + indicator.style.top = `${top}px`; + indicator.style.height = `${height}px`; +} + +function updateIndicator(elements: TocElements) { + if (!elements.tocContainer) return; + + const isAtBottom = window.innerHeight + window.scrollY >= document.documentElement.scrollHeight - 10; + const currentTocLinks = findCurrentTocLinks(elements); + + if (isAtBottom) { + handleBottomScroll(elements); + } else if (currentTocLinks.length > 0) { + const tocRect = elements.tocContainer.getBoundingClientRect(); + const linkElements = currentTocLinks + .map(link => link.closest('li')) + .filter((li): li is HTMLLIElement => li !== null); + if (linkElements.length === 0) return; + const firstLinkRect = linkElements[0].getBoundingClientRect(); + const lastLinkRect = linkElements[linkElements.length - 1].getBoundingClientRect(); + updateProgressIndicatorPosition( + elements.progressIndicator, + firstLinkRect.top - tocRect.top, + (lastLinkRect.top + lastLinkRect.height) - firstLinkRect.top + ); + } +} + +function setupSmoothScrolling(elements: TocElements) { + elements.tocLinks.forEach(link => { + link.addEventListener('click', (e) => { + const href = link.getAttribute('href'); + if (href?.charAt(0) === '#') { + e.preventDefault(); + const target = $(href.replace('.', '\\.')); + if (target) { + target.scrollIntoView({ behavior: 'smooth' }); + history.pushState(null, '', href); + } + } + }); + }); +} + +export function initTocNav() { + const elements = initializeTocElements(); + elements.progressIndicator.style.height = '0'; + elements.progressIndicator.style.top = '0'; + const update = () => updateIndicator(elements) + update(); + window.addEventListener('scroll', update); + window.addEventListener('resize', update); + setupSmoothScrolling(elements); +} diff --git a/src/Elastic.Markdown/Elastic.Markdown.csproj b/src/Elastic.Markdown/Elastic.Markdown.csproj index 15b337c15..d4a8701ca 100644 --- a/src/Elastic.Markdown/Elastic.Markdown.csproj +++ b/src/Elastic.Markdown/Elastic.Markdown.csproj @@ -40,10 +40,10 @@ - - - - + + + + diff --git a/src/Elastic.Markdown/IO/MarkdownFile.cs b/src/Elastic.Markdown/IO/MarkdownFile.cs index c141126a9..f7f14afe7 100644 --- a/src/Elastic.Markdown/IO/MarkdownFile.cs +++ b/src/Elastic.Markdown/IO/MarkdownFile.cs @@ -149,14 +149,14 @@ private void ReadDocumentInstructions(MarkdownDocument document) var contents = document .Descendants() - .Where(block => block is { Level: >= 2 }) - .Select(h => (h.GetData("header") as string, h.GetData("anchor") as string)) + .Where(block => block is { Level: 2 or 3 }) + .Select(h => (h.GetData("header") as string, h.GetData("anchor") as string, h.Level)) .Select(h => { var header = h.Item1!.StripMarkdown(); if (header.AsSpan().ReplaceSubstitutions(subs, out var replacement)) header = replacement; - return new PageTocItem { Heading = header!, Slug = (h.Item2 ?? header).Slugify() }; + return new PageTocItem { Heading = header!, Slug = (h.Item2 ?? header).Slugify(), Level = h.Level }; }) .ToList(); diff --git a/src/Elastic.Markdown/Slices/Layout/_Breadcrumbs.cshtml b/src/Elastic.Markdown/Slices/Layout/_Breadcrumbs.cshtml index 1fd63a0d9..790c0baca 100644 --- a/src/Elastic.Markdown/Slices/Layout/_Breadcrumbs.cshtml +++ b/src/Elastic.Markdown/Slices/Layout/_Breadcrumbs.cshtml @@ -1,5 +1,5 @@ @inherits RazorSlice -
    +
    1. Elastic @@ -16,4 +16,11 @@
    2. } +
    3. + / + + @Model.CurrentDocument.NavigationTitle + + +
    diff --git a/src/Elastic.Markdown/Slices/Layout/_Footer.cshtml b/src/Elastic.Markdown/Slices/Layout/_Footer.cshtml index 1d55b038c..80999f6d0 100644 --- a/src/Elastic.Markdown/Slices/Layout/_Footer.cshtml +++ b/src/Elastic.Markdown/Slices/Layout/_Footer.cshtml @@ -1,12 +1,19 @@ - + +} diff --git a/src/Elastic.Markdown/Slices/Layout/_Header.cshtml b/src/Elastic.Markdown/Slices/Layout/_Header.cshtml index 739db0d21..08c58a81a 100644 --- a/src/Elastic.Markdown/Slices/Layout/_Header.cshtml +++ b/src/Elastic.Markdown/Slices/Layout/_Header.cshtml @@ -1,5 +1,5 @@ @inherits RazorSlice -
    +
    diff --git a/src/Elastic.Markdown/Slices/Layout/_PagesNav.cshtml b/src/Elastic.Markdown/Slices/Layout/_PagesNav.cshtml index 5edb1853b..e0e9455a2 100644 --- a/src/Elastic.Markdown/Slices/Layout/_PagesNav.cshtml +++ b/src/Elastic.Markdown/Slices/Layout/_PagesNav.cshtml @@ -1,6 +1,6 @@ @inherits RazorSlice - + +} diff --git a/src/Elastic.Markdown/Slices/Layout/_TocTree.cshtml b/src/Elastic.Markdown/Slices/Layout/_TocTree.cshtml index 6751687bd..23016b5e8 100644 --- a/src/Elastic.Markdown/Slices/Layout/_TocTree.cshtml +++ b/src/Elastic.Markdown/Slices/Layout/_TocTree.cshtml @@ -3,6 +3,7 @@ @if (Model.IsRedesign) {
    +
    Elastic Docs
    -@(await RenderPartialAsync<_Footer>()) +@(await RenderPartialAsync(_Footer.Create(Model))) @(await RenderPartialAsync(_Scripts.Create(Model))) @await RenderSectionAsync("scripts") diff --git a/src/Elastic.Markdown/Slices/_ViewModels.cs b/src/Elastic.Markdown/Slices/_ViewModels.cs index 65d74724a..c636008b1 100644 --- a/src/Elastic.Markdown/Slices/_ViewModels.cs +++ b/src/Elastic.Markdown/Slices/_ViewModels.cs @@ -73,6 +73,8 @@ public class PageTocItem { public required string Heading { get; init; } public required string Slug { get; init; } + + public required int Level { get; init; } } From 904a9b0850c2c8d884f6d66bb3473d0f89f7dc7b Mon Sep 17 00:00:00 2001 From: Jan Calanog Date: Thu, 13 Feb 2025 01:43:58 +0100 Subject: [PATCH 2/4] revert --- docs/contribute/index.md | 19 +++++-- docs/contribute/locally.md | 55 +++++++++++++++---- docs/docset.yml | 1 + .../_snippets/content-patterns-list.md | 2 +- docs/versions/content-patterns.md | 54 +++++++++++++----- 5 files changed, 100 insertions(+), 31 deletions(-) diff --git a/docs/contribute/index.md b/docs/contribute/index.md index e5a29a5a8..0af35e1c1 100644 --- a/docs/contribute/index.md +++ b/docs/contribute/index.md @@ -10,20 +10,29 @@ Whether you're a technical writer or you've only edited Elastic docs once or twi ## Contribute to the docs [#contribute] -* Simple bugs and enhancements --> [Contribute on the web](on-the-web.md) -* Complex or multi-page updates --> [Contribute locally](locally.md) -* Test migrated content --> [Migration guide](../migration/guide/index.md) +The version of the docs you want to contribute to determines the tool and syntax you must use to update the docs. + +### Contribute to Elastic Stack version 8.x docs and earlier + +To contribute to earlier versions of the Elastic Stack, you must work with our [legacy documentation build system](https://github.com/elastic/docs). This system uses AsciiDoc as it's authoring format. + +* For **simple bugfixes and enhancements** --> [Contribute on the web](on-the-web.md) +* For **complex or multi-page updates** --> See the [legacy documentation build guide](https://github.com/elastic/docs?tab=readme-ov-file#building-documentation) + +### Contribute to Elastic Stack version 9.0 docs and later + +* For **simple bugfixes and enhancements** --> [contribute on the web](on-the-web.md) +* For **complex or multi-page updates** --> [Contribute locally](locally.md) ## Report a bug * It's a **documentation** problem --> [Open a docs issue](https://github.com/elastic/docs-content/issues/new?template=internal-request.yaml) *or* [Fix it myself](locally.md) * It's a **build tool (docs-builder)** problem --> [Open a bug report](https://github.com/elastic/docs-builder/issues/new?template=bug-report.yaml) -* It's a **migration tooling** problem --> [Open a bug report](https://github.com/elastic/docs-builder/issues/new?template=bug-report.yaml) ## Request an enhancement * Make the **documentation** better --> [Open a docs issue](https://github.com/elastic/docs-content/issues/new?template=internal-request.yaml) -* Make our **build tool (docs-builder)** better --> [Open a docs-builder issue](https://github.com/elastic/docs-builder/issues/new?template=enhancement.yaml) +* Make our **build tool (docs-builder)** better --> [Start a docs-builder discussion](https://github.com/elastic/docs-builder/discussions) ## Work on docs-builder diff --git a/docs/contribute/locally.md b/docs/contribute/locally.md index 7818afbe7..08eb9c0f2 100644 --- a/docs/contribute/locally.md +++ b/docs/contribute/locally.md @@ -1,13 +1,31 @@ # Contribute locally Follow these steps to contribute to Elastic docs. + +* [Prerequisites](#prerequisites) * [Step 1: Install `docs-builder`](#step-one) -* [Step 2: Clone the `docs-content` repository](#step-two) +* [Step 2: Clone a content repository](#step-two) * [Step 3: Serve the Documentation](#step-three) -* [Step 4: Open a PR](#step-three) +* [Step 4: Write docs!](#step-four) +* [Step 5: Push your changes](#step-five) + +## Prerequisites + +To write and push updates to Elastic documentation, you need the following: + +1. **A code editor**: we recommend [Visual Studio Code](https://code.visualstudio.com/download) +1. **Git installed on your machine**: learn how [here](https://github.com/git-guides/install-git) +1. **A GitHub account**: sign up [here](https://github.com/) ## Step 1: Install `docs-builder` [#step-one] +There are two different ways to install and run `docs-builder`: + +1. Download, extract, and run the binary (recommended) +1. Clone the repository and build the binary from source + +This guide uses option one. If you'd like to clone the repository and build from source, learn how in the [project readme](https://github.com/elastic/docs-builder?tab=readme-ov-file#docs-builder). + ::::{tab-set} :::{tab-item} macOS @@ -27,7 +45,7 @@ Follow these steps to contribute to Elastic docs. ``` 3. **Run the Binary:** - Use the `serve` command to start serving the documentation at http://localhost:3000. The path to the docset.yml file that you want to build can be specified with `-p`: + Use the `serve` command to start serving the documentation at http://localhost:3000. The path to the `docset.yml` file that you want to build can be specified with `-p`: ```sh ./docs-builder serve -p ./path/to/docs ``` @@ -51,7 +69,7 @@ Follow these steps to contribute to Elastic docs. ``` 3. **Run the Binary:** - Use the `serve` command to start serving the documentation at http://localhost:3000. The path to the docset.yml file that you want to build can be specified with `-p`: + Use the `serve` command to start serving the documentation at http://localhost:3000. The path to the `docset.yml` file that you want to build can be specified with `-p`: ```sh .\docs-builder serve -p ./path/to/docs ``` @@ -75,7 +93,7 @@ Follow these steps to contribute to Elastic docs. ``` 3. **Run the Binary:** - Use the `serve` command to start serving the documentation at http://localhost:3000. The path to the docset.yml file that you want to build can be specified with `-p`: + Use the `serve` command to start serving the documentation at http://localhost:3000. The path to the `docset.yml` file that you want to build can be specified with `-p`: ```sh ./docs-builder serve -p ./path/to/docs ``` @@ -84,22 +102,28 @@ Follow these steps to contribute to Elastic docs. :::: -## Clone the `docs-content` Repository [#step-two] +## Clone a content repository [#step-two] + +:::{tip} +Documentation lives in many repositories across Elastic. If you're unsure which repository to clone, you can use the "Edit this page" link on any documentation page to determine where the source file lives. +::: -Clone the `docs-content` repository to a directory of your choice: +In this guide, we'll clone the [`docs-content`](https://github.com/elastic/docs-content) repository. The `docs-content` repository is the home for narrative documentation at Elastic. Clone this repo to a directory of your choice: ```sh git clone https://github.com/elastic/docs-content.git ``` ## Serve the Documentation [#step-three] -1. **Navigate to the cloned repository:** +1. **Navigate to the `docs-builder` clone location:** ```sh cd docs-content ``` -2. **Run the Binary:** - Use the `serve` command to start serving the documentation at http://localhost:3000. The path to the `docset.yml` file that you want to build can be specified with `-p`: +1. **Run the Binary:** + Run the binary with the `serve` command to build and serve the content set to http://localhost:3000. Specify the path to the `docset.yml` file that you want to build with `-p`. + + For example, if `docs-builder` and `docs-content` are in the same top-level directory, you would run: ```sh # macOS/Linux ./docs-builder serve -p ./migration-test @@ -110,9 +134,16 @@ git clone https://github.com/elastic/docs-content.git Now you should be able to view the documentation locally by navigating to http://localhost:3000. -## Step 4: Open a PR [#step-four] +## Step 4: Write docs [#step-four] + +We write docs in markdown. See our [syntax](../syntax/index.md) guide for the flavor of markdown that we support and all of our custom directives that enable you to add a little extra pizazz to your docs. + +## Step 5: Push your changes [#step-five] + +After you've made your changes locally, -Open a PR. Good luck. +* [Push your commits](https://docs.github.com/en/get-started/using-git/pushing-commits-to-a-remote-repository) +* [Open a Pull Request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) ## Step 5: View on elastic.co/docs diff --git a/docs/docset.yml b/docs/docset.yml index 52eb412e5..74139c204 100644 --- a/docs/docset.yml +++ b/docs/docset.yml @@ -21,6 +21,7 @@ external_hosts: - github.io - github.com - elastic.dev + - visualstudio.com exclude: - '_*.md' subs: diff --git a/docs/versions/_snippets/content-patterns-list.md b/docs/versions/_snippets/content-patterns-list.md index 3a01f0841..4157477bb 100644 --- a/docs/versions/_snippets/content-patterns-list.md +++ b/docs/versions/_snippets/content-patterns-list.md @@ -4,7 +4,7 @@ | [Section/heading-level `applies` tags](/versions/content-patterns.md#sectionheading-level-applies-tags) | Provide signals about a section’s scope so a user can choose to read or skip it as needed. | | [Tabs](/versions/content-patterns.md#tabs) | Provide two sets of procedures when one or more steps in a process differs between contexts or versions. | | [Callouts](/versions/content-patterns.md#callouts) | Draw attention to happy differences and basic clarifications. | -| [Prose](/versions/content-patterns.md#prose) | Provide clarifying or secondary information, explain differences with a "why". | +| [Prose](/versions/content-patterns.md#prose) | - Identify features in a list of features that are exclusive to a specific context, or that were introduced in a specific version
    - List differing requirements, limits, and other simple, mirrored facts
    - Provide clarifying or secondary information
    - Explain differences with a "why" (e.g. comparative overviews) | | [Sibling pages](/versions/content-patterns.md#sibling-pages) | When the information is too complex to be addressed with only the other content patterns. See specific examples in the sibling pages section. | % | [List item suffixes](/versions/content-patterns.md#list-item-suffixes) | Identify features in a **list of features** that are exclusive to a specific context, or that were introduced in a specific version. | diff --git a/docs/versions/content-patterns.md b/docs/versions/content-patterns.md index a7462321f..a0bbb08cd 100644 --- a/docs/versions/content-patterns.md +++ b/docs/versions/content-patterns.md @@ -208,12 +208,12 @@ If there’s a terminology change or other minor change (especially where x equa ## Prose -**Use case**: Clarifying or secondary information, differences with a "why" - -**When to use:** +**Use cases:** +* When features in a list of features are exclusive to a specific context, or were introduced in a specific version +* Requirements, limits, other simple, mirrored facts * Cases where the information isn’t wildly important, but nice to know, or to add basic terminology change info to overviews * Comparative overviews -* Differences that are small enough or not significant enough to warrant an admonition or tabs or separate sections with frontmatter. +* Differences that are small enough or not significant enough to warrant an admonition or tabs or separate sections with front matter In some cases, you might want to add a paragraph specific to one version or another in prose to clarify behavior or terminology. @@ -223,12 +223,44 @@ In cases where there are significant differences between contexts, close explana ### Examples -* In {{stack}} 9.1.0 and earlier, **Spaces** were referred to as **Places**. ::::{tab-set} -:group: one-two-three +:group: five-six-four-one-three + +:::{tab-item} Unique features +:sync: five + +* Each space has its own saved objects. +* Users can only access the spaces that they have been granted access to. This access is based on user roles, and a given role can have different permissions per space. +* In {{stack}} 9.0.0+, each space has its own navigation. + +::: + +:::{tab-item} Unique reqs / limits +:sync: six + +* In serverless, use `Admin` or equivalent +* In {{stack}} 9.0.0+, use `kibana_admin` or equivalent + +OR + +The maximum number of spaces that you can have differs by [what do we call this]: + +* In serverless, you can have a maximum of 100 spaces. +* In {{stack}} 9.0.0+, the maximum is controlled by the `xpack.spaces.maxSpaces` setting. Default is 1000. +::: -:::{tab-item} One +:::{tab-item} Nice-to-know +:sync: four + +In {{stack}} 9.1.0 and earlier, **Spaces** were referred to as **Places**. + +OR + +If you're managing a {{stack}} v9 deployment, then you can also assign roles and define permissions for a space from the **Permissions** tab of the space settings. +::: + +:::{tab-item} Comparative overviews :sync: one The way that TLS certificates are managed depends on your deployment type: @@ -240,12 +272,7 @@ In {{eck}}, you can manage certificates for the HTTP layer. Certificates for the In {{ece}}, you can use one or more proxy certificates to secure the HTTP layer. These certificates are managed at the ECE installation level. Transport-level encryption is managed by ECE and certificates can’t be changed. ::: -:::{tab-item} Two -:sync: two -If you're managing a {{stack}} v9 deployment, then you can also assign roles and define permissions for a space from the **Permissions** tab of the space settings. -::: - -:::{tab-item} Three +:::{tab-item} Comparative overviews II :sync: three **Managed security in Elastic Cloud** @@ -264,6 +291,7 @@ You can augment Elastic Cloud security features in the following ways: ::: :::: + ## Sibling pages **Use case:** From 429d71e02d197c16edc48c4c27d42e4378f266f1 Mon Sep 17 00:00:00 2001 From: Jan Calanog Date: Thu, 13 Feb 2025 01:46:21 +0100 Subject: [PATCH 3/4] Remove extra newline --- .github/workflows/preview-build.yml | 3 +-- src/Elastic.Markdown/Slices/_ViewModels.cs | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/preview-build.yml b/.github/workflows/preview-build.yml index 471fdebfb..091dea0b9 100644 --- a/.github/workflows/preview-build.yml +++ b/.github/workflows/preview-build.yml @@ -53,7 +53,6 @@ jobs: if: github.event_name == 'push' || steps.check-files.outputs.any_changed == 'true' uses: actions/checkout@v4 with: - repository: '${{ github.event.pull_request.head.repo.full_name || github.repository }}' ref: ${{ github.event.pull_request.head.sha || github.ref }} persist-credentials: false @@ -148,7 +147,7 @@ jobs: --paths "${PATH_PREFIX}" "${PATH_PREFIX}/*" - name: Update Link Index - if: steps.s3-upload.outcome == 'success' + if: github.event_name == 'push' && github.ref == 'refs/heads/main' && steps.s3-upload.outcome == 'success' uses: elastic/docs-builder/actions/update-link-index@main - name: Update deployment status diff --git a/src/Elastic.Markdown/Slices/_ViewModels.cs b/src/Elastic.Markdown/Slices/_ViewModels.cs index c636008b1..99d14929b 100644 --- a/src/Elastic.Markdown/Slices/_ViewModels.cs +++ b/src/Elastic.Markdown/Slices/_ViewModels.cs @@ -73,7 +73,6 @@ public class PageTocItem { public required string Heading { get; init; } public required string Slug { get; init; } - public required int Level { get; init; } } From d28139d70af203b6cc99bf70617e31618163edd5 Mon Sep 17 00:00:00 2001 From: Jan Calanog Date: Thu, 13 Feb 2025 02:21:23 +0100 Subject: [PATCH 4/4] Fix test --- src/Elastic.Markdown/IO/MarkdownFile.cs | 2 +- src/Elastic.Markdown/Slices/Index.cshtml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Elastic.Markdown/IO/MarkdownFile.cs b/src/Elastic.Markdown/IO/MarkdownFile.cs index f7f14afe7..a3dcd45ef 100644 --- a/src/Elastic.Markdown/IO/MarkdownFile.cs +++ b/src/Elastic.Markdown/IO/MarkdownFile.cs @@ -149,7 +149,7 @@ private void ReadDocumentInstructions(MarkdownDocument document) var contents = document .Descendants() - .Where(block => block is { Level: 2 or 3 }) + .Where(block => block is { Level: >= 2 }) .Select(h => (h.GetData("header") as string, h.GetData("anchor") as string, h.Level)) .Select(h => { diff --git a/src/Elastic.Markdown/Slices/Index.cshtml b/src/Elastic.Markdown/Slices/Index.cshtml index 3abb070d1..14cd141e3 100644 --- a/src/Elastic.Markdown/Slices/Index.cshtml +++ b/src/Elastic.Markdown/Slices/Index.cshtml @@ -5,7 +5,7 @@ public LayoutViewModel LayoutModel => new() { Title = $"Elastic Documentation: {Model.Title}", - PageTocItems = Model.PageTocItems, + PageTocItems = Model.PageTocItems.Where(i => i is { Level: 2 or 3 }).ToList(), Tree = Model.Tree, CurrentDocument = Model.CurrentDocument, Previous = Model.PreviousDocument,