Merge pull request #2713 from ZhenShuo2021/feat/tabs

 Feat(tabs): add icon, group, and default options
This commit is contained in:
Nuno C.
2026-01-12 00:52:30 +00:00
committed by GitHub
6 changed files with 292 additions and 12 deletions

View File

@@ -178,6 +178,53 @@
],
"description": "Output a set of up to three different colors. Blowfish swatches Shortcode. Documentation: https://blowfish.page/docs/shortcodes/#swatches ",
},
"Tabs - Basic": {
"prefix": "tabs",
"body": [
"{{< tabs >}}",
"",
" {{< tab label=\"${1:Tab 1}\" >}}",
" $2",
" {{< /tab >}}",
"",
" {{< tab label=\"${3:Tab 2}\" >}}",
" $4",
" {{< /tab >}}",
"",
"{{< /tabs >}}"
],
"description": "Insert Hugo tabs shortcode"
},
"Tabs - Full Options": {
"prefix": "tabsfull",
"body": [
"{{< tabs group=\"${1:group-name}\" default=\"${2:Default Tab}\" >}}",
"",
" {{< tab label=\"${3:Tab 1}\" icon=\"${4:code}\" >}}",
" $5",
" {{< /tab >}}",
"",
" {{< tab label=\"${2:Default Tab}\" icon=\"${6:sun}\" >}}",
" $7",
" {{< /tab >}}",
"",
" {{< tab label=\"${8:Tab 3}\" icon=\"${9:moon}\" >}}",
" $0",
" {{< /tab >}}",
"",
"{{< /tabs >}}"
],
"description": "Insert Hugo tabs with group, default, and icons"
},
"Tab": {
"prefix": "tab",
"body": [
"{{< tab label=\"${1:Tab Label}\" >}}",
"$2",
"{{< /tab >}}"
],
"description": "Insert Hugo tab item"
},
"timeline": {
"prefix": ["BFS-timeline", "HSC-timeline", "timeline"],
"body": [

View File

@@ -5,7 +5,25 @@ function initTabs() {
const container = button.closest(".tab__container");
const tabIndex = parseInt(button.dataset.tabIndex);
activateTab(container, tabIndex);
const tabLabel = button.dataset.tabLabel;
const group = container.dataset.tabGroup;
if (group) {
const allGroupContainers = document.querySelectorAll(`.tab__container[data-tab-group="${group}"]`);
allGroupContainers.forEach((groupContainer) => {
const targetButton = Array.from(groupContainer.querySelectorAll(".tab__button")).find(
(btn) => btn.dataset.tabLabel === tabLabel,
);
if (targetButton) {
const targetIndex = parseInt(targetButton.dataset.tabIndex);
activateTab(groupContainer, targetIndex);
}
});
} else {
activateTab(container, tabIndex);
}
};
document.addEventListener("click", tabClickHandler);

View File

@@ -753,7 +753,14 @@ You can see some additional Mermaid examples on the [diagrams and flowcharts sam
The `tabs` shortcode is commonly used to present different variants of a particular step. For example, it can be used to show how to install VS Code on different platforms.
**Example**
| Parameter | Description |
| --------- | -------------------------------------------------------- |
| `group` | **Optional.** Group name for synchronized tab switching. All tabs with the same group name will switch together. |
| `default` | **Optional.** Label of the tab to be active by default. If not set, the first tab will be active. |
| `label` | **Required.** The text label displayed on the tab button. |
| `icon` | **Optional.** Icon name to display before the label. |
**Example 1: Basic Usage**
`````md
{{</* tabs */>}}
@@ -815,6 +822,94 @@ The `tabs` shortcode is commonly used to present different variants of a particu
{{< /tabs >}}
**Example 2: With Group, Default, and Icon**
`````md
{{</* tabs group="lang" default="Python" */>}}
{{</* tab label="JavaScript" icon="code" */>}}
```javascript
console.log("Hello");
```
{{</* /tab */>}}
{{</* tab label="Python" icon="sun" */>}}
```python
print("Hello")
```
{{</* /tab */>}}
{{</* tab label="Go" icon="moon" */>}}
```go
fmt.Println("Hello")
```
{{</* /tab */>}}
{{</* /tabs */>}}
{{</* tabs group="lang" default="Python" */>}}
{{</* tab label="JavaScript" icon="code" */>}}
```javascript
const add = (a, b) => a + b;
```
{{</* /tab */>}}
{{</* tab label="Python" icon="sun" */>}}
```python
def add(a, b): return a + b
```
{{</* /tab */>}}
{{</* tab label="Go" icon="moon" */>}}
```go
func add(a, b int) int { return a + b }
```
{{</* /tab */>}}
{{</* /tabs */>}}
`````
**Output**
{{< tabs group="lang" default="Python" >}}
{{< tab label="JavaScript" icon="code" >}}
```javascript
console.log("Hello");
```
{{< /tab >}}
{{< tab label="Python" icon="sun" >}}
```python
print("Hello")
```
{{< /tab >}}
{{< tab label="Go" icon="moon" >}}
```go
fmt.Println("Hello")
```
{{< /tab >}}
{{< /tabs >}}
{{< tabs group="lang" default="Python" >}}
{{< tab label="JavaScript" icon="code" >}}
```javascript
const add = (a, b) => a + b;
```
{{< /tab >}}
{{< tab label="Python" icon="sun" >}}
```python
def add(a, b): return a + b
```
{{< /tab >}}
{{< tab label="Go" icon="moon" >}}
```go
func add(a, b int) int { return a + b }
```
{{< /tab >}}
{{< /tabs >}}
In this example, both tab groups share the same `group="lang"` parameter, so clicking any tab will synchronize both groups. The `default="Python"` parameter makes Python the initially active tab, and `icon="code"` adds an icon before each label.
<br/><br/><br/>
## Timeline

View File

@@ -763,7 +763,14 @@ B-->C[Profit]
`tabs` 简码常用于呈现某个步骤的不同变体。例如,可用于展示在不同平台上安装 VS Code 的方式。
**示例**
| 参数 | 描述 |
| --------- | --------------------------------------- |
| `group` | **可选。** 用于同步切换标签页的组名。具有相同组名的所有标签页将一起切换。 |
| `default` | **可选。** 默认激活的标签页的标签。如果未设置,默认激活第一个标签页。 |
| `label` | **必填。** 显示在标签按钮上的文本标签。 |
| `icon` | **可选。** 在标签前显示的图标名称。 |
**示例 1基本用法**
````md
{{</* tabs */>}}
@@ -825,6 +832,94 @@ B-->C[Profit]
{{< /tabs >}}
**示例 2使用 Group、Default 和 Icon**
`````md
{{</* tabs group="lang" default="Python" */>}}
{{</* tab label="JavaScript" icon="code" */>}}
```javascript
console.log("Hello");
```
{{</* /tab */>}}
{{</* tab label="Python" icon="sun" */>}}
```python
print("Hello")
```
{{</* /tab */>}}
{{</* tab label="Go" icon="moon" */>}}
```go
fmt.Println("Hello")
```
{{</* /tab */>}}
{{</* /tabs */>}}
{{</* tabs group="lang" default="Python" */>}}
{{</* tab label="JavaScript" icon="code" */>}}
```javascript
const add = (a, b) => a + b;
```
{{</* /tab */>}}
{{</* tab label="Python" icon="sun" */>}}
```python
def add(a, b): return a + b
```
{{</* /tab */>}}
{{</* tab label="Go" icon="moon" */>}}
```go
func add(a, b int) int { return a + b }
```
{{</* /tab */>}}
{{</* /tabs */>}}
`````
**Output**
{{< tabs group="lang" default="Python" >}}
{{< tab label="JavaScript" icon="code" >}}
```javascript
console.log("Hello");
```
{{< /tab >}}
{{< tab label="Python" icon="sun" >}}
```python
print("Hello")
```
{{< /tab >}}
{{< tab label="Go" icon="moon" >}}
```go
fmt.Println("Hello")
```
{{< /tab >}}
{{< /tabs >}}
{{< tabs group="lang" default="Python" >}}
{{< tab label="JavaScript" icon="code" >}}
```javascript
const add = (a, b) => a + b;
```
{{< /tab >}}
{{< tab label="Python" icon="sun" >}}
```python
def add(a, b): return a + b
```
{{< /tab >}}
{{< tab label="Go" icon="moon" >}}
```go
func add(a, b int) int { return a + b }
```
{{< /tab >}}
{{< /tabs >}}
在这个示例中,两个标签组都使用了相同的 `group="lang"` 参数,因此点击任意一个标签时,两个标签组都会同步切换。`default="Python"` 参数用于指定 Python 为初始激活的标签,而 `icon="code"` 会在每个标签标题前添加一个图标。
<br/><br/><br/>
## 时间线

View File

@@ -1,7 +1,8 @@
{{- $label := .Get "label" -}}
{{- $icon := .Get "icon" -}}
{{- $index := .Parent.Store.Get "tab-index" | default 0 -}}
{{- $content := .InnerDeindent | strings.TrimSpace | .Page.RenderString -}}
{{- $tabs := .Parent.Store.Get "tabs" | default slice -}}
{{- .Parent.Store.Set "tabs" ($tabs | append (dict "label" $label "content" $content)) -}}
{{- .Parent.Store.Set "tabs" ($tabs | append (dict "label" $label "icon" $icon "content" $content)) -}}
{{- .Parent.Store.Set "tab-index" (add 1 $index) -}}

View File

@@ -1,26 +1,50 @@
{{- .Store.Set "tab-index" 0 -}}
{{- $noop := .Inner -}}
{{- $group := .Get "group" -}}
{{- $default := .Get "default" -}}
<div class="tab__container w-full">
<div
class="tab__container w-full"
{{ with $group }}data-tab-group="{{ . }}"{{ end }}
{{ with $default }}data-default-tab="{{ . }}"{{ end }}>
<div class="tab__nav" role="tablist">
<div class="flex gap-1 overflow-x-auto">
<div class="flex flex-wrap gap-1">
{{- range $nTabs, $_ := .Store.Get "tabs" -}}
{{- $isActive := false -}}
{{- if $default -}}
{{- $isActive = eq $default (index . "label") -}}
{{- else -}}
{{- $isActive = eq $nTabs 0 -}}
{{- end -}}
<button
class="tab__button px-3 py-2 text-sm font-semibold border-b-2 border-transparent rounded-t-md hover:bg-neutral-200 dark:hover:bg-neutral-700 {{ if eq $nTabs 0 }}
class="tab__button px-3 py-2 text-sm font-semibold border-b-2 border-transparent rounded-t-md hover:bg-neutral-200 dark:hover:bg-neutral-700 {{ if $isActive -}}
tab--active
{{ end }}"
{{- end }}"
role="tab"
aria-selected="{{ cond (eq $nTabs 0) "true" "false" }}"
data-tab-index="{{ $nTabs }}">
{{ index . "label" }}
aria-selected="{{ cond $isActive `true` `false` }}"
data-tab-index="{{ $nTabs }}"
data-tab-label="{{ index . "label" }}">
<span class="flex items-center gap-1">
{{ with index . "icon" }}
{{ partial "icon.html" . }}
{{ end }}
{{ index . "label" }}
</span>
</button>
{{- end -}}
</div>
</div>
<div class="tab__content mt-4">
{{- range $nTabs, $_ := .Store.Get "tabs" -}}
<div class="tab__panel {{ if eq $nTabs 0 }}tab--active{{ end }}" data-tab-index="{{ $nTabs }}">
{{- $isActive := false -}}
{{- if $default -}}
{{- $isActive = eq $default (index . "label") -}}
{{- else -}}
{{- $isActive = eq $nTabs 0 -}}
{{- end -}}
<div class="tab__panel {{ if $isActive }}tab--active{{ end }}" data-tab-index="{{ $nTabs }}">
{{ index . "content" }}
</div>
{{- end -}}