diff --git a/.vscode/blowfish.code-snippets b/.vscode/blowfish.code-snippets
index 265bdc87..abd80369 100644
--- a/.vscode/blowfish.code-snippets
+++ b/.vscode/blowfish.code-snippets
@@ -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": [
diff --git a/assets/js/shortcodes/tabs.js b/assets/js/shortcodes/tabs.js
index a08c4601..6a64c57e 100644
--- a/assets/js/shortcodes/tabs.js
+++ b/assets/js/shortcodes/tabs.js
@@ -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);
diff --git a/exampleSite/content/docs/shortcodes/index.md b/exampleSite/content/docs/shortcodes/index.md
index 97593cb6..7fd16773 100644
--- a/exampleSite/content/docs/shortcodes/index.md
+++ b/exampleSite/content/docs/shortcodes/index.md
@@ -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.
+
## Timeline
diff --git a/exampleSite/content/docs/shortcodes/index.zh-cn.md b/exampleSite/content/docs/shortcodes/index.zh-cn.md
index 622c99bf..c3f599f1 100644
--- a/exampleSite/content/docs/shortcodes/index.zh-cn.md
+++ b/exampleSite/content/docs/shortcodes/index.zh-cn.md
@@ -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"` 会在每个标签标题前添加一个图标。
+
## 时间线
diff --git a/layouts/shortcodes/tab.html b/layouts/shortcodes/tab.html
index 338ccc52..f2b96f2a 100644
--- a/layouts/shortcodes/tab.html
+++ b/layouts/shortcodes/tab.html
@@ -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) -}}
diff --git a/layouts/shortcodes/tabs.html b/layouts/shortcodes/tabs.html
index 07fe2695..d093855a 100644
--- a/layouts/shortcodes/tabs.html
+++ b/layouts/shortcodes/tabs.html
@@ -1,26 +1,50 @@
{{- .Store.Set "tab-index" 0 -}}
{{- $noop := .Inner -}}
+{{- $group := .Get "group" -}}
+{{- $default := .Get "default" -}}
-