From 20044af981df3f07be1a264e83fe687f3650dcc5 Mon Sep 17 00:00:00 2001
From: ZhenShuo Leo <98386542+ZhenShuo2021@users.noreply.github.com>
Date: Sat, 29 Nov 2025 11:58:40 +0800
Subject: [PATCH] feat: add tabs
---
assets/css/compiled/main.css | 34 ++++++++
assets/css/components/tabs.css | 9 +++
assets/css/main.css | 1 +
assets/js/shortcodes/tabs.js | 41 ++++++++++
.../content/docs/shortcodes/index.it.md | 80 +++++++++++++++++++
.../content/docs/shortcodes/index.ja.md | 80 +++++++++++++++++++
exampleSite/content/docs/shortcodes/index.md | 80 +++++++++++++++++++
.../content/docs/shortcodes/index.zh-cn.md | 80 +++++++++++++++++++
layouts/partials/vendor.html | 8 ++
layouts/shortcodes/tab.html | 5 ++
layouts/shortcodes/tabs.html | 23 ++++++
11 files changed, 441 insertions(+)
create mode 100644 assets/css/components/tabs.css
create mode 100644 assets/js/shortcodes/tabs.js
create mode 100644 layouts/shortcodes/tab.html
create mode 100644 layouts/shortcodes/tabs.html
diff --git a/assets/css/compiled/main.css b/assets/css/compiled/main.css
index 4a5b2722..a540fc2a 100644
--- a/assets/css/compiled/main.css
+++ b/assets/css/compiled/main.css
@@ -1372,6 +1372,9 @@
.justify-center {
justify-content: center;
}
+ .gap-1 {
+ gap: calc(var(--spacing) * 1);
+ }
.gap-4 {
gap: calc(var(--spacing) * 4);
}
@@ -1496,6 +1499,10 @@
border-top-left-radius: var(--radius-lg);
border-top-right-radius: var(--radius-lg);
}
+ .rounded-t-md {
+ border-top-left-radius: var(--radius-md);
+ border-top-right-radius: var(--radius-md);
+ }
.rounded-b-lg {
border-bottom-right-radius: var(--radius-lg);
border-bottom-left-radius: var(--radius-lg);
@@ -2412,6 +2419,13 @@
}
}
}
+ .hover\:bg-neutral-200 {
+ &:hover {
+ @media (hover: hover) {
+ background-color: rgba(var(--color-neutral-200), 1);
+ }
+ }
+ }
.hover\:bg-primary-100 {
&:hover {
@media (hover: hover) {
@@ -3226,6 +3240,15 @@
}
}
}
+ .dark\:hover\:bg-neutral-700 {
+ &:is(.dark *) {
+ &:hover {
+ @media (hover: hover) {
+ background-color: rgba(var(--color-neutral-700), 1);
+ }
+ }
+ }
+ }
.dark\:hover\:bg-primary-400 {
&:is(.dark *) {
&:hover {
@@ -3448,6 +3471,17 @@
text-decoration-line: underline;
}
}
+@layer utilities {
+ .tab__button.tab--active {
+ border-bottom: 2px solid rgb(var(--color-primary-500));
+ }
+ .tab__panel {
+ display: none;
+ }
+ .tab__panel.tab--active {
+ display: block;
+ }
+}
#zen-mode-button {
cursor: pointer;
}
diff --git a/assets/css/components/tabs.css b/assets/css/components/tabs.css
new file mode 100644
index 00000000..7bc7548d
--- /dev/null
+++ b/assets/css/components/tabs.css
@@ -0,0 +1,9 @@
+.tab__button.tab--active {
+ border-bottom: 2px solid rgb(var(--color-primary-500));
+}
+.tab__panel {
+ display: none;
+}
+.tab__panel.tab--active {
+ display: block;
+}
diff --git a/assets/css/main.css b/assets/css/main.css
index c270f924..4f8325a3 100644
--- a/assets/css/main.css
+++ b/assets/css/main.css
@@ -4,6 +4,7 @@
@import "tailwindcss";
@import "./components/chroma.css" layer(utilities);
+@import "./components/tabs.css" layer(utilities);
@import "./components/zen-mode.css";
@import "./components/a11y.css";
diff --git a/assets/js/shortcodes/tabs.js b/assets/js/shortcodes/tabs.js
new file mode 100644
index 00000000..121c1c6c
--- /dev/null
+++ b/assets/js/shortcodes/tabs.js
@@ -0,0 +1,41 @@
+function initTabs() {
+ tabClickHandler = (event) => {
+ const button = event.target.closest(".tab__button");
+ if (!button) return;
+
+ const container = button.closest(".tab__container");
+ const tabIndex = parseInt(button.dataset.tabIndex);
+ activateTab(container, tabIndex);
+ };
+
+ document.addEventListener("click", tabClickHandler);
+}
+
+function activateTab(container, activeIndex) {
+ const buttons = container.querySelectorAll(".tab__button");
+ const panels = container.querySelectorAll(".tab__panel");
+
+ buttons.forEach((btn, index) => {
+ if (index === activeIndex) {
+ btn.classList.add("tab--active");
+ btn.setAttribute("aria-selected", "true");
+ } else {
+ btn.classList.remove("tab--active");
+ btn.setAttribute("aria-selected", "false");
+ }
+ });
+
+ panels.forEach((panel, index) => {
+ if (index === activeIndex) {
+ panel.classList.add("tab--active");
+ } else {
+ panel.classList.remove("tab--active");
+ }
+ });
+}
+
+if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', initTabs);
+} else {
+ initTabs();
+}
diff --git a/exampleSite/content/docs/shortcodes/index.it.md b/exampleSite/content/docs/shortcodes/index.it.md
index 3034d038..8ab3f6b2 100644
--- a/exampleSite/content/docs/shortcodes/index.it.md
+++ b/exampleSite/content/docs/shortcodes/index.it.md
@@ -714,6 +714,86 @@ You can see some additional Mermaid examples on the [diagrams and flowcharts sam
+## Tabs
+
+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**
+
+`````md
+{{* tabs labels="Windows;;macOS;;Linux" */>}}
+
+{{* tab */>}}
+
+Install using Chocolatey:
+
+```pwsh
+choco install vscode.install
+```
+
+or install using WinGet
+
+```pwsh
+winget install -e --id Microsoft.VisualStudioCode
+```
+
+{{* /tab */>}}
+
+{{* tab */>}}
+
+```bash
+brew install --cask visual-studio-code
+```
+
+{{* /tab */>}}
+
+{{* tab */>}}
+
+See [documentation](https://code.visualstudio.com/docs/setup/linux#_install-vs-code-on-linux).
+
+{{* /tab */>}}
+
+{{* /tabs */>}}
+`````
+
+**Output**
+
+{{< tabs labels="Windows;;macOS;;Linux" >}}
+
+{{< tab >}}
+
+Install using Chocolatey:
+
+```pwsh
+choco install vscode.install
+```
+
+or install using WinGet
+
+```pwsh
+winget install -e --id Microsoft.VisualStudioCode
+```
+
+{{< /tab >}}
+
+{{< tab >}}
+
+```bash
+brew install --cask visual-studio-code
+```
+
+{{< /tab >}}
+
+{{< tab >}}
+
+See [documentation](https://code.visualstudio.com/docs/setup/linux#_install-vs-code-on-linux).
+
+{{< /tab >}}
+
+{{< /tabs >}}
+
+
+
## Timeline
The `timeline` creates a visual timeline that can be used in different use-cases, e.g. professional experience, a project's achievements, etc. The `timeline` shortcode relies on the `timelineItem` sub-shortcode to define each item within the main timeline. Each item can have the following properties.
diff --git a/exampleSite/content/docs/shortcodes/index.ja.md b/exampleSite/content/docs/shortcodes/index.ja.md
index 221770f9..a38e24df 100644
--- a/exampleSite/content/docs/shortcodes/index.ja.md
+++ b/exampleSite/content/docs/shortcodes/index.ja.md
@@ -711,6 +711,86 @@ B-->C[利益]
+## Tabs
+
+`tabs` ショートコードは、特定の手順における異なるバリアントを提示する際によく使用される。例えば、VS Code を各種プラットフォームにインストールする方法を示す場合などに利用できる。
+
+**例**
+
+````md
+{{* tabs labels="Windows;;macOS;;Linux" */>}}
+
+{{* tab */>}}
+
+Chocolatey を使用してインストール:
+
+```pwsh
+choco install vscode.install
+```
+
+または WinGet を使用してインストール
+
+```pwsh
+winget install -e --id Microsoft.VisualStudioCode
+```
+
+{{* /tab */>}}
+
+{{* tab */>}}
+
+```bash
+brew install --cask visual-studio-code
+```
+
+{{* /tab */>}}
+
+{{* tab */>}}
+
+[ドキュメント](https://code.visualstudio.com/docs/setup/linux#_install-vs-code-on-linux)を参照。
+
+{{* /tab */>}}
+
+{{* /tabs */>}}
+````
+
+**出力**
+
+{{< tabs labels="Windows;;macOS;;Linux" >}}
+
+{{< tab >}}
+
+Chocolatey を使用してインストール:
+
+```pwsh
+choco install vscode.install
+```
+
+または WinGet を使用してインストール
+
+```pwsh
+winget install -e --id Microsoft.VisualStudioCode
+```
+
+{{< /tab >}}
+
+{{< tab >}}
+
+```bash
+brew install --cask visual-studio-code
+```
+
+{{< /tab >}}
+
+{{< tab >}}
+
+[ドキュメント](https://code.visualstudio.com/docs/setup/linux#_install-vs-code-on-linux)を参照。
+
+{{< /tab >}}
+
+{{< /tabs >}}
+
+
+
## タイムライン
`timeline` は、さまざまなユースケース (例: 職務経歴、プロジェクトの成果など) で使用できる視覚的なタイムラインを作成します。`timeline` ショートコードは、メインタイムライン内の各アイテムを定義するために `timelineItem` サブショートコードに依存しています。各アイテムには、次のプロパティを設定できます。
diff --git a/exampleSite/content/docs/shortcodes/index.md b/exampleSite/content/docs/shortcodes/index.md
index 0b72c969..a1add5f7 100644
--- a/exampleSite/content/docs/shortcodes/index.md
+++ b/exampleSite/content/docs/shortcodes/index.md
@@ -720,6 +720,86 @@ You can see some additional Mermaid examples on the [diagrams and flowcharts sam
+## Tabs
+
+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**
+
+`````md
+{{* tabs labels="Windows;;macOS;;Linux" */>}}
+
+{{* tab */>}}
+
+Install using Chocolatey:
+
+```pwsh
+choco install vscode.install
+```
+
+or install using WinGet
+
+```pwsh
+winget install -e --id Microsoft.VisualStudioCode
+```
+
+{{* /tab */>}}
+
+{{* tab */>}}
+
+```bash
+brew install --cask visual-studio-code
+```
+
+{{* /tab */>}}
+
+{{* tab */>}}
+
+See [documentation](https://code.visualstudio.com/docs/setup/linux#_install-vs-code-on-linux).
+
+{{* /tab */>}}
+
+{{* /tabs */>}}
+`````
+
+**Output**
+
+{{< tabs labels="Windows;;macOS;;Linux" >}}
+
+{{< tab >}}
+
+Install using Chocolatey:
+
+```pwsh
+choco install vscode.install
+```
+
+or install using WinGet
+
+```pwsh
+winget install -e --id Microsoft.VisualStudioCode
+```
+
+{{< /tab >}}
+
+{{< tab >}}
+
+```bash
+brew install --cask visual-studio-code
+```
+
+{{< /tab >}}
+
+{{< tab >}}
+
+See [documentation](https://code.visualstudio.com/docs/setup/linux#_install-vs-code-on-linux).
+
+{{< /tab >}}
+
+{{< /tabs >}}
+
+
+
## Timeline
The `timeline` creates a visual timeline that can be used in different use-cases, e.g. professional experience, a project's achievements, etc. The `timeline` shortcode relies on the `timelineItem` sub-shortcode to define each item within the main timeline. Each item can have the following properties.
diff --git a/exampleSite/content/docs/shortcodes/index.zh-cn.md b/exampleSite/content/docs/shortcodes/index.zh-cn.md
index 17ccc2a3..b5eb1548 100644
--- a/exampleSite/content/docs/shortcodes/index.zh-cn.md
+++ b/exampleSite/content/docs/shortcodes/index.zh-cn.md
@@ -724,6 +724,86 @@ B-->C[Profit]
+## Tabs
+
+`tabs` 简码常用于呈现某个步骤的不同变体。例如,可用于展示在不同平台上安装 VS Code 的方式。
+
+**示例**
+
+````md
+{{* tabs labels="Windows;;macOS;;Linux" */>}}
+
+{{* tab */>}}
+
+使用 Chocolatey 安装:
+
+```pwsh
+choco install vscode.install
+```
+
+或使用 WinGet 安装
+
+```pwsh
+winget install -e --id Microsoft.VisualStudioCode
+```
+
+{{* /tab */>}}
+
+{{* tab */>}}
+
+```bash
+brew install --cask visual-studio-code
+```
+
+{{* /tab */>}}
+
+{{* tab */>}}
+
+参见[文档](https://code.visualstudio.com/docs/setup/linux#_install-vs-code-on-linux)。
+
+{{* /tab */>}}
+
+{{* /tabs */>}}
+````
+
+**输出**
+
+{{< tabs labels="Windows;;macOS;;Linux" >}}
+
+{{< tab >}}
+
+使用 Chocolatey 安装:
+
+```pwsh
+choco install vscode.install
+```
+
+或使用 WinGet 安装
+
+```pwsh
+winget install -e --id Microsoft.VisualStudioCode
+```
+
+{{< /tab >}}
+
+{{< tab >}}
+
+```bash
+brew install --cask visual-studio-code
+```
+
+{{< /tab >}}
+
+{{< tab >}}
+
+参见[文档](https://code.visualstudio.com/docs/setup/linux#_install-vs-code-on-linux)。
+
+{{< /tab >}}
+
+{{< /tabs >}}
+
+
+
## 时间线
`timeline` 创建了一个可视化时间线,用于展示专业经验、项目成就等。 `timeline` 简码依赖于 `timelineItem` 子简码来定义主时间线中的每个项目。每个项目可以具有以下属性。
diff --git a/layouts/partials/vendor.html b/layouts/partials/vendor.html
index 31872d08..66b6a9c0 100644
--- a/layouts/partials/vendor.html
+++ b/layouts/partials/vendor.html
@@ -145,3 +145,11 @@
}}
{{ end }}
+
+{{/* tabs */}}
+{{ if .Page.HasShortcode "tabs" }}
+ {{ $tabJS := resources.Get "js/shortcodes/tabs.js" }}
+ {{ with $tabJS | minify | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
+
+ {{ end }}
+{{ end }}
diff --git a/layouts/shortcodes/tab.html b/layouts/shortcodes/tab.html
new file mode 100644
index 00000000..05061c0c
--- /dev/null
+++ b/layouts/shortcodes/tab.html
@@ -0,0 +1,5 @@
+{{- $index := .Parent.Scratch.Get "tab-index" | default 0 -}}
+{{- .Parent.Scratch.Set "tab-index" (add 1 $index) -}}
+