Compare commits

..

5 Commits

Author SHA1 Message Date
Xin
d0cdd29ee5 fix(navbar): search wrapper class not prefixed (#756)
* fix(navbar): search wrapper class not prefixed

* fix(css): update Tailwind CSS properties layer for improved compatibility
2025-08-15 14:33:09 +08:00
Xin
91cc6b53d8 fix(toc): enhance hash navigation handling and adjust observer sensitivity (#754) 2025-08-15 10:33:49 +08:00
Ludovic Fernandez
2033d50005 docs: add documentation on all shortcodes (#753) 2025-08-15 09:09:58 +08:00
Ludovic Fernandez
80ada64da0 fix: search colors (#752) 2025-08-15 08:57:18 +08:00
Xin
776c758825 chore(build): update MAIN_VERSION to v0.10.0 in build script 2025-08-15 00:07:57 +08:00
27 changed files with 260 additions and 20 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,5 @@
nav { nav {
.search-wrapper { .hextra-search-wrapper {
@apply hx:hidden hx:md:inline-block; @apply hx:hidden hx:md:inline-block;
} }
} }

View File

@@ -392,7 +392,7 @@ document.addEventListener("DOMContentLoaded", function () {
function highlightMatches(text, query) { function highlightMatches(text, query) {
const escapedQuery = query.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&'); const escapedQuery = query.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');
const regex = new RegExp(escapedQuery, 'gi'); const regex = new RegExp(escapedQuery, 'gi');
return text.replace(regex, (match) => `<span class="match">${match}</span>`); return text.replace(regex, (match) => `<span class="hextra-search-match">${match}</span>`);
} }
// Create a DOM element from the HTML string. // Create a DOM element from the HTML string.
@@ -405,11 +405,11 @@ document.addEventListener("DOMContentLoaded", function () {
function handleMouseMove(e) { function handleMouseMove(e) {
const target = e.target.closest('a'); const target = e.target.closest('a');
if (target) { if (target) {
const active = resultsElement.querySelector('a.active'); const active = resultsElement.querySelector('a.hextra-search-active');
if (active) { if (active) {
active.classList.remove('active'); active.classList.remove('hextra-search-active');
} }
target.classList.add('active'); target.classList.add('hextra-search-active');
} }
} }

View File

@@ -20,10 +20,14 @@ document.addEventListener("DOMContentLoaded", function () {
if (headings.length === 0) return; if (headings.length === 0) return;
let currentActiveLink = null; let currentActiveLink = null;
let isHashNavigation = false;
// Create intersection observer // Create intersection observer
const observer = new IntersectionObserver( const observer = new IntersectionObserver(
(entries) => { (entries) => {
// Skip observer updates during hash navigation
if (isHashNavigation) return;
const visibleHeadings = entries.filter((entry) => entry.isIntersecting).map((entry) => entry.target); const visibleHeadings = entries.filter((entry) => entry.isIntersecting).map((entry) => entry.target);
if (visibleHeadings.length === 0) return; if (visibleHeadings.length === 0) return;
@@ -50,7 +54,7 @@ document.addEventListener("DOMContentLoaded", function () {
} }
}, },
{ {
rootMargin: "-20px 0px -80% 0px", // Adjust sensitivity rootMargin: "-20px 0px -60% 0px", // Adjust sensitivity
threshold: [0, 0.1, 0.5, 1], threshold: [0, 0.1, 0.5, 1],
} }
); );
@@ -58,11 +62,31 @@ document.addEventListener("DOMContentLoaded", function () {
// Observe all headings // Observe all headings
headings.forEach((heading) => observer.observe(heading)); headings.forEach((heading) => observer.observe(heading));
// Handle edge case: if no headings are visible on initial load // Handle direct navigation to page with hash
setTimeout(() => { function handleHashNavigation() {
if (!currentActiveLink && tocLinks.length > 0) { const hash = window.location.hash;
tocLinks[0].classList.add("hextra-toc-active"); if (hash) {
currentActiveLink = tocLinks[0]; const targetLink = toc.querySelector(`a[href="${hash}"]`);
if (targetLink) {
// Disable observer temporarily during hash navigation
isHashNavigation = true;
if (currentActiveLink) {
currentActiveLink.classList.remove("hextra-toc-active");
}
targetLink.classList.add("hextra-toc-active");
currentActiveLink = targetLink;
// Re-enable observer after scroll settles
setTimeout(() => { isHashNavigation = false; }, 500);
return;
}
} }
}, 100); }
// Handle hash changes navigation
window.addEventListener("hashchange", handleHashNavigation);
// Handle initial load
setTimeout(handleHashNavigation, 100);
}); });

View File

@@ -8,7 +8,7 @@ echo "Using base URL: $BASE_URL"
# Version configuration - modify these arrays to specify versions to build # Version configuration - modify these arrays to specify versions to build
# Format: "ref:display_name" (ref can be tag, branch, or commit hash, display name is what will appear in URL) # Format: "ref:display_name" (ref can be tag, branch, or commit hash, display name is what will appear in URL)
MAIN_VERSION="v0.9.6:latest" MAIN_VERSION="v0.10.0:latest"
VERSIONS=( VERSIONS=(
"main:latest" # latest version always builds from main "main:latest" # latest version always builds from main
"v0.9.6:v0.9" "v0.9.6:v0.9"

View File

@@ -1,3 +1,19 @@
{{- /*
A shortcode to create a badge.
@param {string} content The content of the badge.
@param {string} type The type of the badge.
@param {string} class The class of the badge.
@param {string} link The link of the badge.
@param {string} icon The icon of the badge.
or
@param {string} 0 The content of the badge.
@example {{< badge content="info" type="info" >}}
*/ -}}
{{- if .IsNamedParams -}} {{- if .IsNamedParams -}}
{{- $content := .Get "content" -}} {{- $content := .Get "content" -}}
{{- $type := .Get "type" | default "" -}} {{- $type := .Get "type" | default "" -}}

View File

@@ -1,3 +1,14 @@
{{- /*
A shortcode to create a callout.
@param {string} type The type of the callout (default, info, warning, error).
@param {string} content The content of the callout.
@param {string} emoji The emoji of the callout (related to type or can be a custom emoji).
@param {string} icon The icon of the callout.
@example {{< callout type="info" >}}Content{{< /callout >}}
*/ -}}
{{- $calloutEmojiDict := dict "info" "" "warning" "⚠️" "error" "🚫" -}} {{- $calloutEmojiDict := dict "info" "" "warning" "⚠️" "error" "🚫" -}}
{{- $type := .Get "type" | default "default" -}} {{- $type := .Get "type" | default "default" -}}
{{/* If emoji is not set, use the emoji from dict */}} {{/* If emoji is not set, use the emoji from dict */}}

View File

@@ -1,3 +1,20 @@
{{- /*
A shortcode to create a card.
@param {string} link The link to the card.
@param {string} title The title of the card.
@param {string} icon The icon of the card.
@param {string} subtitle The subtitle of the card.
@param {string} tag The tag of the card.
@param {string} tagType The type of the tag.
@param {string} image The image of the card.
@param {string} method The method to process the image.
@param {string} options The options to process the image.
@param {string} imageStyle The style of the image.
@example {{< card link="/" title="Image Card" }}
*/ -}}
{{- $context := . -}} {{- $context := . -}}
{{- $link := .Get "link" -}} {{- $link := .Get "link" -}}
{{- $title := .Get "title" -}} {{- $title := .Get "title" -}}

View File

@@ -1,3 +1,11 @@
{{- /*
A shortcode for creating cards.
@param {string} cols The number of columns.
@example {{< cards cols="3" >}}{{< /cards >}}
*/ -}}
{{- $cols := .Get "cols" | default 3 -}} {{- $cols := .Get "cols" | default 3 -}}
{{- partial "shortcodes/cards" (dict "cols" $cols "content" .Inner) -}} {{- partial "shortcodes/cards" (dict "cols" $cols "content" .Inner) -}}

View File

@@ -1,3 +1,12 @@
{{- /*
A built-in component to display a collapsible content.
@param {string} title The title of the details.
@param {string} closed Whether the details are closed or not (default: false).
@example {{% details title="Details" %}}Content{{% /details %}}
*/ -}}
{{- $title := .Get "title" | default "" -}} {{- $title := .Get "title" | default "" -}}
{{- $closed := eq (.Get "closed") "true" | default false -}} {{- $closed := eq (.Get "closed") "true" | default false -}}

View File

@@ -1,3 +1,9 @@
{{- /*
A file tree container.
@example {{< filetree/container >}}{{< /filetree/container >}}
*/ -}}
<div class="hextra-filetree hx:mt-6 hx:select-none hx:text-sm hx:text-gray-800 hx:dark:text-gray-300 not-prose"> <div class="hextra-filetree hx:mt-6 hx:select-none hx:text-sm hx:text-gray-800 hx:dark:text-gray-300 not-prose">
<div class="hx:inline-block hx:rounded-lg hx:px-4 hx:py-2 hx:border hx:border-gray-200 hx:dark:border-neutral-800"> <div class="hx:inline-block hx:rounded-lg hx:px-4 hx:py-2 hx:border hx:border-gray-200 hx:dark:border-neutral-800">
{{- .InnerDeindent -}} {{- .InnerDeindent -}}

View File

@@ -1,5 +1,12 @@
{{- $name := .Get "name" -}} {{- /*
A file in a file tree.
@param {string} name The name of the file.
@example {{< filetree/file name="_index.md" >}}
*/ -}}
{{- $name := .Get "name" -}}
<li class="hx:flex hx:list-none"> <li class="hx:flex hx:list-none">
<span class="hx:inline-flex hx:cursor-default hx:items-center hx:py-1"> <span class="hx:inline-flex hx:cursor-default hx:items-center hx:py-1">

View File

@@ -1,3 +1,12 @@
{{- /*
A folder in a file tree.
@param {string} name The name of the folder.
@param {string} state The state of the folder.
@example {{< filetree/folder name="docs" state="closed" >}}
*/ -}}
{{- $name := .Get "name" -}} {{- $name := .Get "name" -}}
{{- $state := .Get "state" | default "open" }} {{- $state := .Get "state" | default "open" }}

View File

@@ -1,3 +1,18 @@
{{- /*
A shortcode for displaying a feature card.
@param {string} title The title of the card.
@param {string} subtitle The subtitle of the card.
@param {string} class The class of the card.
@param {string} image The image of the card.
@param {string} imageClass The class of the image.
@param {string} style The style of the card.
@param {string} icon The icon of the card.
@param {string} link The link of the card.
@example {{< hextra/feature-card title="Feature Card" subtitle="This is a feature card." >}}
*/ -}}
{{- $title := .Get "title" -}} {{- $title := .Get "title" -}}
{{- $subtitle := .Get "subtitle" -}} {{- $subtitle := .Get "subtitle" -}}
{{- $class := .Get "class" -}} {{- $class := .Get "class" -}}

View File

@@ -1,3 +1,12 @@
{{- /*
A shortcode for displaying a feature grid.
@param {string} cols The number of columns.
@param {string} style The style of the grid.
@example {{< hextra/feature-grid cols="3" >}}{{< /hextra/feature-grid >}}
*/ -}}
{{- $cols := .Get "cols" | default 3 -}} {{- $cols := .Get "cols" | default 3 -}}
{{- $style := .Get "style" | default "" -}} {{- $style := .Get "style" | default "" -}}

View File

@@ -1,10 +1,19 @@
{{- /*
A shortcode for rendering a badge with a link.
@param {string} link The link of the badge.
@param {string} class The class of the badge.
@param {string} style The style of the badge.
@example {{< hextra/hero-badge >}}{{< /hextra/hero-badge >}}
*/ -}}
{{- $link := .Get "link" -}} {{- $link := .Get "link" -}}
{{- $external := hasPrefix $link "http" -}} {{- $external := hasPrefix $link "http" -}}
{{- $href := cond (hasPrefix $link "/") ($link | relURL) $link -}} {{- $href := cond (hasPrefix $link "/") ($link | relURL) $link -}}
{{- $class := .Get "class" }} {{- $class := .Get "class" }}
{{- $style := .Get "style" -}} {{- $style := .Get "style" -}}
<a <a
{{ if $link }}href="{{ $href }}"{{ end }} {{ if $link }}href="{{ $href }}"{{ end }}
class="{{ $class }} not-prose hx:inline-flex hx:items-center hx:rounded-full hx:gap-2 hx:px-3 hx:py-1 hx:text-xs hx:text-gray-600 hx:dark:text-gray-400 hx:bg-gray-100 hx:dark:bg-neutral-800 hx:border-gray-200 hx:dark:border-neutral-800 hx:border hx:hover:border-gray-400 hx:dark:hover:text-gray-50 hx:dark:hover:border-gray-600 hx:transition-all hx:ease-in hx:duration-200" class="{{ $class }} not-prose hx:inline-flex hx:items-center hx:rounded-full hx:gap-2 hx:px-3 hx:py-1 hx:text-xs hx:text-gray-600 hx:dark:text-gray-400 hx:bg-gray-100 hx:dark:bg-neutral-800 hx:border-gray-200 hx:dark:border-neutral-800 hx:border hx:hover:border-gray-400 hx:dark:hover:text-gray-50 hx:dark:hover:border-gray-600 hx:transition-all hx:ease-in hx:duration-200"

View File

@@ -1,3 +1,13 @@
{{- /*
A shortcode for rendering a button with a link.
@param {string} link The link of the button.
@param {string} text The text of the button.
@param {string} style The style of the button.
@example {{< hextra/hero-button text="Get Started" link="docs" >}}
*/ -}}
{{- $link := .Get "link" -}} {{- $link := .Get "link" -}}
{{- $text := .Get "text" -}} {{- $text := .Get "text" -}}
{{- $style := .Get "style" -}} {{- $style := .Get "style" -}}

View File

@@ -1,3 +1,21 @@
{{- /*
A simple hero container with an image on the left side.
@param {string} class The class of the container.
@param {string} cols The number of columns (default: 2).
@param {string} image The image of the container.
@param {bool} imageCard Whether to display the image as a card (default: false).
@param {string} imageClass The class of the image.
@param {string} imageLink The link of the image.
@param {string} imageStyle The style of the image.
@param {string} imageTitle The title of the image.
@param {int} imageWidth The width of the image (default: 350).
@param {int} imageHeight The height of the image (default: 350).
@param {string} style The style of the container.
@example {{< hextra/hero-container image="image.png" imageLink="https://example.com" imageTitle="Example Image" >}}
*/ -}}
{{- $class := .Get "class" -}} {{- $class := .Get "class" -}}
{{- $cols := .Get "cols" | default 2 -}} {{- $cols := .Get "cols" | default 2 -}}
{{- $image := .Get "image" -}} {{- $image := .Get "image" -}}

View File

@@ -1,5 +1,12 @@
{{- $style := .Get "style" -}} {{- /*
A shortcode for displaying a hero headline.
@param {string} style The style of the headline.
@example {{< hextra/hero-headline >}}{{< /hextra/hero-headline >}}
*/ -}}
{{- $style := .Get "style" -}}
<h1 <h1
class="not-prose hx:text-4xl hx:font-bold hx:leading-none hx:tracking-tighter hx:md:text-5xl hx:py-2 hx:bg-clip-text hx:text-transparent hx:bg-gradient-to-r hx:from-gray-900 hx:to-gray-600 hx:dark:from-gray-100 hx:dark:to-gray-400" class="not-prose hx:text-4xl hx:font-bold hx:leading-none hx:tracking-tighter hx:md:text-5xl hx:py-2 hx:bg-clip-text hx:text-transparent hx:bg-gradient-to-r hx:from-gray-900 hx:to-gray-600 hx:dark:from-gray-100 hx:dark:to-gray-400"

View File

@@ -1,3 +1,13 @@
{{- /*
A simple hero section with a heading and optional style.
@param {string} heading The heading level (default: h2).
@param {string} style The style of the heading.
@param {string} content The content of the heading.
@example {{< hextra/hero-section heading="h3" >}}{{< /hextra/hero-section >}}>
*/ -}}
{{- $style := .Get "style" -}} {{- $style := .Get "style" -}}
{{- $heading := int (strings.TrimPrefix "h" (.Get "heading" | default "h2")) -}} {{- $heading := int (strings.TrimPrefix "h" (.Get "heading" | default "h2")) -}}
{{- $size := cond (ge $heading 4) "xl" (cond (eq $heading 3) "2xl" "4xl") -}} {{- $size := cond (ge $heading 4) "xl" (cond (eq $heading 3) "2xl" "4xl") -}}

View File

@@ -1,5 +1,12 @@
{{- $style := .Get "style" -}} {{- /*
A shortcode for displaying a hero subtitle.
@param {string} style The style of the subtitle.
@example {{< hextra/hero-subtitle >}}{{< /hextra/hero-subtitle >}}
*/ -}}
{{- $style := .Get "style" -}}
<p <p
class="not-prose hx:text-xl hx:text-gray-600 hx:dark:text-gray-400 hx:sm:text-xl" class="not-prose hx:text-xl hx:text-gray-600 hx:dark:text-gray-400 hx:sm:text-xl"

View File

@@ -1,3 +1,17 @@
{{- /*
Create an icon.
@param {string} name The name of the icon.
@param {string} attributes The attributes of the icon.
or
@param {string} 0 The name of the icon.
@example {{< icon name="github" >}}
@example {{< icon "github" >}}
*/ -}}
{{- $name := .Get "name" | default (.Get 0) -}} {{- $name := .Get "name" | default (.Get 0) -}}
{{- $icon := index site.Data.icons $name -}} {{- $icon := index site.Data.icons $name -}}
{{- $attributes := .Get "attributes" | default "height=1em"}} {{- $attributes := .Get "attributes" | default "height=1em"}}

View File

@@ -1,4 +1,11 @@
{{/* Render Jupyter Notebook */}} {{- /*
Render Jupyter Notebook
@param {string} 0 The path of the Jupyter Notebook.
@example {{% jupyter "notebook.ipynb" %}}
*/ -}}
{{- $path := .Get 0 -}} {{- $path := .Get 0 -}}
{{- $data := "" -}} {{- $data := "" -}}
{{- $page := .Page -}} {{- $page := .Page -}}

View File

@@ -1,4 +1,10 @@
{{/* Shortcode to include a PDF file in a page. */}} {{- /*
Shortcode to include a PDF file in a page.
@param {string} 0 The path to the PDF file.
@example {{< pdf "path/to/file.pdf" >}}
*/ -}}
{{- $path := .Get 0 -}} {{- $path := .Get 0 -}}
{{- $url := partial "utils/file-path" (dict "page" .Page "path" $path) -}} {{- $url := partial "utils/file-path" (dict "page" .Page "path" $path) -}}

View File

@@ -1,3 +1,9 @@
{{- /*
A shortcode for creating a step list.
@example {{% steps %}}{{% /steps %}}
*/ -}}
<div class="hextra-steps hx:ml-4 hx:mb-12 hx:ltr:border-l hx:rtl:border-r hx:border-gray-200 hx:ltr:pl-6 hx:rtl:pr-6 hx:dark:border-neutral-800 [counter-reset:step]"> <div class="hextra-steps hx:ml-4 hx:mb-12 hx:ltr:border-l hx:rtl:border-r hx:border-gray-200 hx:ltr:pl-6 hx:rtl:pr-6 hx:dark:border-neutral-800 [counter-reset:step]">
{{- .Inner -}} {{- .Inner -}}
</div> </div>

View File

@@ -1,3 +1,9 @@
{{- /*
Create a tab.
@example {{< tab >}}content{{< /tab >}}
*/ -}}
{{- $defaultIndex := int ((.Parent.Get "defaultIndex") | default "0") -}} {{- $defaultIndex := int ((.Parent.Get "defaultIndex") | default "0") -}}
<div <div

View File

@@ -1,3 +1,12 @@
{{- /*
Create a tabbed interface with the given items.
@param {string} items The items to display in the tabs.
@param {string} defaultIndex The index of the default tab.
@example {{< tabs items="JSON,YAML,TOML" >}}{{< /tabs >}}
*/ -}}
{{- $items := split (.Get "items") "," -}} {{- $items := split (.Get "items") "," -}}
{{- $defaultIndex := int ((.Get "defaultIndex") | default "0") -}} {{- $defaultIndex := int ((.Get "defaultIndex") | default "0") -}}