mirror of
https://github.com/imfing/hextra.git
synced 2025-08-23 17:06:39 -04:00
feat(tabs): implement synchronized tabs switching (#700)
* Sync tabs across groups * feat(tabs): add optional synchronization * Move tabs sync setting under page params * fix: spacing between title and site title (#704) * docs: document configure opengraph image (#706) * [Docs] document using og:image * Make example title page match others * clarify wording * chore: update tailwind css to latest version 4.1.8 (#703) * fix: wrong SRI hash for katex.css (#702) * Correct URL given in 'dev.toml' * stylesheet 'katex.css': fix SRI hash * fix(build): run npm update to fix postcss complaint * feat(tags): improve usability of tags (#698) * feat(tags): improve usability of tags * Tags can be shown also at docs * Documented tag-related config flags * Added example tags to the site * Made rendered tags active * Move tags listing to ToC * Hide tags section on no tags * feat(math): add optional MathJax support (#707) * feat: add MathJax option * docs: move math engine note * refactor: update LaTeX documentation and improve MathJax integration - Adjusted LaTeX documentation for clarity and formatting. - Enhanced MathJax configuration in the templates to support both KaTeX and MathJax rendering. - Removed deprecated comments and streamlined the script loading process for MathJax. - Updated the passthrough extension settings in the Hugo configuration for better compatibility with LaTeX math expressions. * docs: simplify LaTeX documentation and clarify configuration steps - Updated LaTeX documentation to reflect that KaTeX is enabled by default, removing the need for manual activation. - Added examples for using LaTeX math expressions and clarified the configuration for the passthrough extension in Hugo. - Enhanced MathJax section to emphasize its use as an alternative rendering engine. * fix(tabs): add null check for panels container and update example items * fix(tabs): improve tab group key handling and add validation for items parameter * refactor(tabs): comment out sync option in configuration and adjust tab formatting in documentation --------- Co-authored-by: hobobandy <30026704+hobobandy@users.noreply.github.com> Co-authored-by: Matt Dodson <47385188+MattDodsonEnglish@users.noreply.github.com> Co-authored-by: Andreas Deininger <adeininger@urbanonline.de> Co-authored-by: yuri <1969yuri1969@gmail.com>
This commit is contained in:
@@ -1,20 +1,51 @@
|
|||||||
document.querySelectorAll('.hextra-tabs-toggle').forEach(function (button) {
|
(function () {
|
||||||
|
function updateGroup(container, index) {
|
||||||
|
const tabs = Array.from(container.querySelectorAll('.hextra-tabs-toggle'));
|
||||||
|
tabs.forEach((tab, i) => {
|
||||||
|
tab.dataset.state = i === index ? 'selected' : '';
|
||||||
|
if (i === index) {
|
||||||
|
tab.setAttribute('aria-selected', 'true');
|
||||||
|
tab.tabIndex = 0;
|
||||||
|
} else {
|
||||||
|
tab.removeAttribute('aria-selected');
|
||||||
|
tab.removeAttribute('tabindex');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const panelsContainer = container.parentElement.nextElementSibling;
|
||||||
|
if (!panelsContainer) return;
|
||||||
|
Array.from(panelsContainer.children).forEach((panel, i) => {
|
||||||
|
panel.dataset.state = i === index ? 'selected' : '';
|
||||||
|
if (i === index) {
|
||||||
|
panel.tabIndex = 0;
|
||||||
|
} else {
|
||||||
|
panel.removeAttribute('tabindex');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const groups = document.querySelectorAll('[data-tab-group]');
|
||||||
|
|
||||||
|
groups.forEach((group) => {
|
||||||
|
const key = encodeURIComponent(group.dataset.tabGroup);
|
||||||
|
const saved = localStorage.getItem('hextra-tab-' + key);
|
||||||
|
if (saved !== null) {
|
||||||
|
updateGroup(group, parseInt(saved, 10));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.hextra-tabs-toggle').forEach((button) => {
|
||||||
button.addEventListener('click', function (e) {
|
button.addEventListener('click', function (e) {
|
||||||
// set parent tabs to unselected
|
const container = e.target.parentElement;
|
||||||
const tabs = Array.from(e.target.parentElement.querySelectorAll('.hextra-tabs-toggle'));
|
const index = Array.from(container.querySelectorAll('.hextra-tabs-toggle')).indexOf(
|
||||||
tabs.map(tab => tab.dataset.state = '');
|
e.target
|
||||||
|
);
|
||||||
// set current tab to selected
|
const key = encodeURIComponent(container.dataset.tabGroup);
|
||||||
e.target.dataset.state = 'selected';
|
document
|
||||||
|
.querySelectorAll('[data-tab-group="' + container.dataset.tabGroup + '"]')
|
||||||
// set all panels to unselected
|
.forEach((grp) => updateGroup(grp, index));
|
||||||
const panelsContainer = e.target.parentElement.parentElement.nextElementSibling;
|
if (key) {
|
||||||
Array.from(panelsContainer.children).forEach(function (panel) {
|
localStorage.setItem('hextra-tab-' + key, index.toString());
|
||||||
panel.dataset.state = '';
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const panelId = e.target.getAttribute('aria-controls');
|
|
||||||
const panel = panelsContainer.querySelector(`#${panelId}`);
|
|
||||||
panel.dataset.state = 'selected';
|
|
||||||
});
|
});
|
||||||
});
|
})();
|
||||||
|
@@ -5,11 +5,11 @@ next: /docs/guide/deploy-site
|
|||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
{{< tabs items="JSON,YAML,TOML" >}}
|
{{< tabs items="macOS,Linux,Windows" >}}
|
||||||
|
|
||||||
{{< tab >}}**JSON**: JavaScript Object Notation (JSON) is a standard text-based format for representing structured data based on JavaScript object syntax.{{< /tab >}}
|
{{< tab >}}**macOS**: A desktop operating system by Apple.{{< /tab >}}
|
||||||
{{< tab >}}**YAML**: YAML is a human-readable data serialization language.{{< /tab >}}
|
{{< tab >}}**Linux**: An open-source operating system.{{< /tab >}}
|
||||||
{{< tab >}}**TOML**: TOML aims to be a minimal configuration file format that's easy to read due to obvious semantics.{{< /tab >}}
|
{{< tab >}}**Windows**: A desktop operating system by Microsoft.{{< /tab >}}
|
||||||
|
|
||||||
{{< /tabs >}}
|
{{< /tabs >}}
|
||||||
|
|
||||||
@@ -91,3 +91,35 @@ Markdown syntax including code block is also supported:
|
|||||||
{{< /tab >}}
|
{{< /tab >}}
|
||||||
|
|
||||||
{{< /tabs >}}
|
{{< /tabs >}}
|
||||||
|
|
||||||
|
|
||||||
|
### Sync Tabs
|
||||||
|
|
||||||
|
Tabs with the same list of `items` can be synchronized. When enabled, selecting a tab updates all other tabs with the same `items` and remembers the selection across pages.
|
||||||
|
|
||||||
|
Enable globally in your `hugo.yaml` under the `page` section:
|
||||||
|
|
||||||
|
```yaml {filename="hugo.yaml"}
|
||||||
|
params:
|
||||||
|
page:
|
||||||
|
tabs:
|
||||||
|
sync: true
|
||||||
|
```
|
||||||
|
|
||||||
|
With this enabled the following two tab blocks will always display the same selected item:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
{{</* tabs items="A,B" */>}}
|
||||||
|
|
||||||
|
{{</* tab */>}}A content{{</* /tab */>}}
|
||||||
|
{{</* tab */>}}B content{{</* /tab */>}}
|
||||||
|
|
||||||
|
{{</* /tabs */>}}
|
||||||
|
|
||||||
|
{{</* tabs items="A,B" */>}}
|
||||||
|
|
||||||
|
{{</* tab */>}}Second A content{{</* /tab */>}}
|
||||||
|
{{</* tab */>}}Second B content{{</* /tab */>}}
|
||||||
|
|
||||||
|
{{</* /tabs */>}}
|
||||||
|
```
|
||||||
|
@@ -132,10 +132,6 @@ params:
|
|||||||
# link: /
|
# link: /
|
||||||
width: wide
|
width: wide
|
||||||
|
|
||||||
page:
|
|
||||||
# full (100%), wide (90rem), normal (80rem)
|
|
||||||
width: normal
|
|
||||||
|
|
||||||
theme:
|
theme:
|
||||||
# light | dark | system
|
# light | dark | system
|
||||||
default: system
|
default: system
|
||||||
@@ -187,6 +183,12 @@ params:
|
|||||||
# hover | always
|
# hover | always
|
||||||
display: hover
|
display: hover
|
||||||
|
|
||||||
|
page:
|
||||||
|
# full (100%), wide (90rem), normal (80rem)
|
||||||
|
width: normal
|
||||||
|
# tabs:
|
||||||
|
# sync: true
|
||||||
|
|
||||||
comments:
|
comments:
|
||||||
enable: false
|
enable: false
|
||||||
type: giscus
|
type: giscus
|
||||||
|
@@ -1,12 +1,24 @@
|
|||||||
{{- $items := split (.Get "items") "," -}}
|
{{- $items := split (.Get "items") "," -}}
|
||||||
{{- $defaultIndex := int ((.Get "defaultIndex") | default "0") -}}
|
{{- $defaultIndex := int ((.Get "defaultIndex") | default "0") -}}
|
||||||
|
|
||||||
|
{{- $enableSync := site.Params.page.tabs.sync | default false -}}
|
||||||
|
|
||||||
|
{{- if not (.Get "items") -}}
|
||||||
|
{{ errorf "tabs shortcode: 'items' parameter is required" }}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
{{- if not $items -}}
|
{{- if not $items -}}
|
||||||
{{ errorf "no items provided" }}
|
{{ errorf "tabs shortcode: 'items' parameter cannot be empty" }}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- range $items -}}
|
||||||
|
{{- if eq (trim . " ") "" -}}
|
||||||
|
{{ errorf "tabs shortcode: empty item found in 'items' parameter" }}
|
||||||
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
<div class="hextra-scrollbar hx:overflow-x-auto hx:overflow-y-hidden hx:overscroll-x-contain">
|
<div class="hextra-scrollbar hx:overflow-x-auto hx:overflow-y-hidden hx:overscroll-x-contain">
|
||||||
<div class="hx:mt-4 hx:flex hx:w-max hx:min-w-full hx:border-b hx:border-gray-200 hx:pb-px hx:dark:border-neutral-800">
|
<div class="hx:mt-4 hx:flex hx:w-max hx:min-w-full hx:border-b hx:border-gray-200 hx:pb-px hx:dark:border-neutral-800"{{ if $enableSync }} data-tab-group="{{ delimit $items `,` }}"{{ end }}>
|
||||||
{{- range $i, $item := $items -}}
|
{{- range $i, $item := $items -}}
|
||||||
<button
|
<button
|
||||||
class="hextra-tabs-toggle hx:cursor-pointer hx:data-[state=selected]:border-primary-500 hx:data-[state=selected]:text-primary-600 hx:data-[state=selected]:dark:border-primary-500 hx:data-[state=selected]:dark:text-primary-600 hx:mr-2 hx:rounded-t hx:p-2 hx:font-medium hx:leading-5 hx:transition-colors hx:-mb-0.5 hx:select-none hx:border-b-2 hx:border-transparent hx:text-gray-600 hx:hover:border-gray-200 hx:hover:text-black hx:dark:text-gray-200 hx:dark:hover:border-neutral-800 hx:dark:hover:text-white"
|
class="hextra-tabs-toggle hx:cursor-pointer hx:data-[state=selected]:border-primary-500 hx:data-[state=selected]:text-primary-600 hx:data-[state=selected]:dark:border-primary-500 hx:data-[state=selected]:dark:text-primary-600 hx:mr-2 hx:rounded-t hx:p-2 hx:font-medium hx:leading-5 hx:transition-colors hx:-mb-0.5 hx:select-none hx:border-b-2 hx:border-transparent hx:text-gray-600 hx:hover:border-gray-200 hx:hover:text-black hx:dark:text-gray-200 hx:dark:hover:border-neutral-800 hx:dark:hover:text-white"
|
||||||
|
Reference in New Issue
Block a user