From 2c52460397ffd1033b7e0e4a439f30cffcc5ddb4 Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 14:25:37 +0800 Subject: [PATCH 01/27] feat: add Release top-level menu entry in en and zh Co-Authored-By: Claude Opus 4.7 (1M context) --- config/_default/menus/menus.en.toml | 5 +++++ config/_default/menus/menus.zh.toml | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/config/_default/menus/menus.en.toml b/config/_default/menus/menus.en.toml index 18ab81940..56e19e3b8 100644 --- a/config/_default/menus/menus.en.toml +++ b/config/_default/menus/menus.en.toml @@ -30,6 +30,11 @@ url = "/blog/" weight = 30 +[[main]] + name = "Release" + url = "/release/" + weight = 25 + [[social]] name = "GitHub" pre = "" diff --git a/config/_default/menus/menus.zh.toml b/config/_default/menus/menus.zh.toml index 2182572a3..567538511 100644 --- a/config/_default/menus/menus.zh.toml +++ b/config/_default/menus/menus.zh.toml @@ -21,6 +21,11 @@ url = "/blog/" weight = 20 +[[main]] + name = "发布" + url = "/release/" + weight = 15 + [[social]] name = "GitHub" pre = "" From 5751ee84b1f6901011ddae5cbe0ec343ea7f035a Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 14:38:56 +0800 Subject: [PATCH 02/27] feat: add Release section landing _index.md for en and zh --- content/en/release/_index.md | 9 +++++++++ content/zh/release/_index.md | 9 +++++++++ 2 files changed, 18 insertions(+) create mode 100644 content/en/release/_index.md create mode 100644 content/zh/release/_index.md diff --git a/content/en/release/_index.md b/content/en/release/_index.md new file mode 100644 index 000000000..72e785662 --- /dev/null +++ b/content/en/release/_index.md @@ -0,0 +1,9 @@ +--- +title: "Release" +description: "Release notes and reports for Tableau." +date: 2026-06-11T00:00:00+08:00 +lastmod: 2026-06-11T00:00:00+08:00 +draft: false +images: [] +weight: 9999 +--- diff --git a/content/zh/release/_index.md b/content/zh/release/_index.md new file mode 100644 index 000000000..1e006dce2 --- /dev/null +++ b/content/zh/release/_index.md @@ -0,0 +1,9 @@ +--- +title: "发布" +description: "Tableau 发布说明与报告。" +date: 2026-06-11T00:00:00+08:00 +lastmod: 2026-06-11T00:00:00+08:00 +draft: false +images: [] +weight: 9999 +--- From b9ad799a6abc9a973e7d32be611ad98e1d112c0c Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 14:47:37 +0800 Subject: [PATCH 03/27] feat: pin release section permalink to /release/:slug/ --- config/_default/config.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/_default/config.toml b/config/_default/config.toml index c5ebee4f0..0623a491e 100644 --- a/config/_default/config.toml +++ b/config/_default/config.toml @@ -67,6 +67,7 @@ rel = "sitemap" [permalinks] blog = "/blog/:title/" + release = "/release/:slug/" # docs = "/docs/1.0/:sections[1:]/:title/" [minify.tdewolff.html] From e737e03904f915cf6b3f7e89e122e5d3acf54345 Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 15:20:38 +0800 Subject: [PATCH 04/27] feat: add release sidebar partial --- layouts/partials/release/sidebar.html | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 layouts/partials/release/sidebar.html diff --git a/layouts/partials/release/sidebar.html b/layouts/partials/release/sidebar.html new file mode 100644 index 000000000..7e128598a --- /dev/null +++ b/layouts/partials/release/sidebar.html @@ -0,0 +1,23 @@ +{{/* + Release sidebar: flat list of all pages in the "release" section for the + current language, sorted by `weight` ascending. The current page is + highlighted. HTML-stub releases (front-matter `iframe` is set) display a + small "HTML" badge as a visual cue. +*/}} + From b0b3052c038beb2589f562489fc2cdadd611a641 Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 15:20:45 +0800 Subject: [PATCH 05/27] feat: add release single-page layout with iframe and markdown branches --- layouts/release/single.html | 49 +++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 layouts/release/single.html diff --git a/layouts/release/single.html b/layouts/release/single.html new file mode 100644 index 000000000..f319a4419 --- /dev/null +++ b/layouts/release/single.html @@ -0,0 +1,49 @@ +{{ define "main" }} +
+
+ {{ partial "release/sidebar.html" . }} +
+ {{ if .Params.iframe -}} +
+ {{ if .Site.Params.options.breadCrumb -}} + + {{ end }} +

{{ .Title }}

+ {{ with .Params.lead }}

{{ . | safeHTML }}

{{ end }} + {{ with .Content }}
{{ . }}
{{ end }} +
+ +
+
+ {{ else -}} +
+ {{ if .Site.Params.options.breadCrumb -}} + + {{ end }} +

{{ .Title }}

+ {{ with .Params.lead }}

{{ . | safeHTML }}

{{ end }} + {{ if ne .Params.toc false -}} + + {{ end -}} + {{ .Content }} +
+ {{ end -}} +
+{{ end }} From ed41ba199a6132c01edc83c9e8baa70aef7b8e41 Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 15:20:52 +0800 Subject: [PATCH 06/27] feat: add release section list layout --- layouts/release/list.html | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 layouts/release/list.html diff --git a/layouts/release/list.html b/layouts/release/list.html new file mode 100644 index 000000000..d650e69c4 --- /dev/null +++ b/layouts/release/list.html @@ -0,0 +1,23 @@ +{{ define "main" }} +
+
+ {{ partial "release/sidebar.html" . }} +
+
+

{{ .Title }}

+ {{ with .Params.lead }}

{{ . | safeHTML }}

{{ end }} + {{ .Content }} +
    + {{ $currentLang := .Site.Language.Lang }} + {{ $releasePages := where (where site.RegularPages "Section" "release") "Lang" $currentLang }} + {{ range $releasePages.ByWeight }} +
  • + {{ .Title }} + {{ if .Params.iframe }}HTML{{ end }} + {{ with .Params.description }}
    {{ . }}
    {{ end }} +
  • + {{ end }} +
+
+
+{{ end }} From a2b59e30a77294638c27326d88c98e146002be0f Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 15:20:58 +0800 Subject: [PATCH 07/27] feat: add release section SCSS --- assets/scss/app.scss | 1 + assets/scss/components/_release.scss | 44 ++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 assets/scss/components/_release.scss diff --git a/assets/scss/app.scss b/assets/scss/app.scss index 4984649ae..b00719090 100644 --- a/assets/scss/app.scss +++ b/assets/scss/app.scss @@ -28,6 +28,7 @@ @import "components/forms"; @import "components/images"; @import "components/mermaid"; +@import "components/release"; @import "components/search"; @import "components/tables"; @import "components/sheet"; diff --git a/assets/scss/components/_release.scss b/assets/scss/components/_release.scss new file mode 100644 index 000000000..fc0693618 --- /dev/null +++ b/assets/scss/components/_release.scss @@ -0,0 +1,44 @@ +/* Release section */ + +/* Iframe pane: fill the available content column height. */ +.release-iframe-wrap { + position: relative; + width: 100%; + /* Approximate offset: site header (~64px) + breadcrumb/title block (~120px). */ + height: calc(100vh - 200px); + min-height: 480px; + margin-top: 1rem; + border: 1px solid var(--bs-border-color, #dee2e6); + border-radius: 0.25rem; + overflow: hidden; + background: #fff; +} + +.release-iframe-wrap iframe { + width: 100%; + height: 100%; + border: 0; + display: block; +} + +/* Active sidebar item: subtle highlight using the existing docs-sidebar look. */ +.release-sidebar-item.active > a { + font-weight: 600; + color: var(--bs-primary, #0d6efd); +} + +/* HTML badge in sidebar and list. */ +.release-html-badge { + font-size: 0.65rem; + padding: 0.15rem 0.4rem; + background: var(--bs-secondary-bg, #e9ecef); + color: var(--bs-secondary-color, #495057); + border-radius: 0.25rem; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +/* Optional caption block above an iframe (when stub body is non-empty). */ +.release-prelude { + margin-bottom: 1rem; +} From 7c0a8015fe653913bda808df92a5e50640256c82 Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 15:21:09 +0800 Subject: [PATCH 08/27] feat: add v0.1.0 sample markdown release in en and zh --- content/en/release/v0-1-0.md | 20 ++++++++++++++++++++ content/zh/release/v0-1-0.md | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 content/en/release/v0-1-0.md create mode 100644 content/zh/release/v0-1-0.md diff --git a/content/en/release/v0-1-0.md b/content/en/release/v0-1-0.md new file mode 100644 index 000000000..843b10738 --- /dev/null +++ b/content/en/release/v0-1-0.md @@ -0,0 +1,20 @@ +--- +title: "v0.1.0" +description: "Release notes for v0.1.0." +lead: "Highlights of the v0.1.0 release." +date: 2024-09-24T14:00:00+08:00 +lastmod: 2024-09-24T14:00:00+08:00 +draft: false +images: [] +weight: 9000 +toc: true +--- + +## Highlights + +- Initial public release. +- Excel / CSV / XML / YAML → JSON / Text / Bin conversion. + +## Changelog + +See the [GitHub release](https://github.com/tableauio/tableau/releases/tag/v0.1.0) for the full changelog. diff --git a/content/zh/release/v0-1-0.md b/content/zh/release/v0-1-0.md new file mode 100644 index 000000000..607eb5bd9 --- /dev/null +++ b/content/zh/release/v0-1-0.md @@ -0,0 +1,20 @@ +--- +title: "v0.1.0" +description: "v0.1.0 发布说明。" +lead: "v0.1.0 主要更新内容。" +date: 2024-09-24T14:00:00+08:00 +lastmod: 2024-09-24T14:00:00+08:00 +draft: false +images: [] +weight: 9000 +toc: true +--- + +## 主要更新 + +- 首个公开版本。 +- 支持 Excel / CSV / XML / YAML → JSON / Text / Bin 转换。 + +## 更新记录 + +完整更新记录请参阅 [GitHub release](https://github.com/tableauio/tableau/releases/tag/v0.1.0)。 From 95b72898b048b5d3c2bd6d7db6bb12e93510b117 Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 15:21:16 +0800 Subject: [PATCH 09/27] feat: add v0.2.0 sample HTML-stub release with iframe artifact --- content/en/release/v0-2-0.md | 12 ++++++++++++ content/zh/release/v0-2-0.md | 12 ++++++++++++ static/release/v0-2-0.html | 26 ++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 content/en/release/v0-2-0.md create mode 100644 content/zh/release/v0-2-0.md create mode 100644 static/release/v0-2-0.html diff --git a/content/en/release/v0-2-0.md b/content/en/release/v0-2-0.md new file mode 100644 index 000000000..bd953a8bb --- /dev/null +++ b/content/en/release/v0-2-0.md @@ -0,0 +1,12 @@ +--- +title: "v0.2.0" +description: "v0.2.0 generated report." +lead: "Auto-generated benchmark / changelog report." +date: 2024-12-01T14:00:00+08:00 +lastmod: 2024-12-01T14:00:00+08:00 +draft: false +images: [] +weight: 8000 +toc: false +iframe: "/release/v0-2-0.html" +--- diff --git a/content/zh/release/v0-2-0.md b/content/zh/release/v0-2-0.md new file mode 100644 index 000000000..41c6aec1b --- /dev/null +++ b/content/zh/release/v0-2-0.md @@ -0,0 +1,12 @@ +--- +title: "v0.2.0" +description: "v0.2.0 自动生成报告。" +lead: "自动生成的基准测试 / 更新报告。" +date: 2024-12-01T14:00:00+08:00 +lastmod: 2024-12-01T14:00:00+08:00 +draft: false +images: [] +weight: 8000 +toc: false +iframe: "/release/v0-2-0.html" +--- diff --git a/static/release/v0-2-0.html b/static/release/v0-2-0.html new file mode 100644 index 000000000..dba4ba32c --- /dev/null +++ b/static/release/v0-2-0.html @@ -0,0 +1,26 @@ + + + + + Tableau v0.2.0 Report + + + +

Tableau v0.2.0 Report

+

This is a sample standalone HTML artifact embedded via iframe in the + Release section. Replace this with your actual generated report.

+ + + + + + +
MetricBeforeAfter
Conversion speed1.0×1.4×
Memory usage240 MB180 MB
+ + From aad47844559729ef9cc8598332d51566f5fc3fa6 Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 15:26:32 +0800 Subject: [PATCH 10/27] fix: revert release permalink rule (use filename slug not :slug from title) --- config/_default/config.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/config/_default/config.toml b/config/_default/config.toml index 0623a491e..c5ebee4f0 100644 --- a/config/_default/config.toml +++ b/config/_default/config.toml @@ -67,7 +67,6 @@ rel = "sitemap" [permalinks] blog = "/blog/:title/" - release = "/release/:slug/" # docs = "/docs/1.0/:sections[1:]/:title/" [minify.tdewolff.html] From c109784f47abaf0d2f476d8cfe4e22b183de84ac Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 15:31:10 +0800 Subject: [PATCH 11/27] fix: place Release as the last item in the main top nav --- config/_default/menus/menus.en.toml | 2 +- config/_default/menus/menus.zh.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/_default/menus/menus.en.toml b/config/_default/menus/menus.en.toml index 56e19e3b8..d0a29eb62 100644 --- a/config/_default/menus/menus.en.toml +++ b/config/_default/menus/menus.en.toml @@ -33,7 +33,7 @@ [[main]] name = "Release" url = "/release/" - weight = 25 + weight = 40 [[social]] name = "GitHub" diff --git a/config/_default/menus/menus.zh.toml b/config/_default/menus/menus.zh.toml index 567538511..5edcd88b2 100644 --- a/config/_default/menus/menus.zh.toml +++ b/config/_default/menus/menus.zh.toml @@ -24,7 +24,7 @@ [[main]] name = "发布" url = "/release/" - weight = 15 + weight = 30 [[social]] name = "GitHub" From 0995fc2afdd82712944999aec8152bc0abab44f4 Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 15:35:55 +0800 Subject: [PATCH 12/27] feat: add v0.16.0 release report (HTML stub + artifact) --- content/en/release/v0-16-0.md | 12 + content/zh/release/v0-16-0.md | 12 + static/release/v0-16-0.html | 1175 +++++++++++++++++++++++++++++++++ 3 files changed, 1199 insertions(+) create mode 100644 content/en/release/v0-16-0.md create mode 100644 content/zh/release/v0-16-0.md create mode 100644 static/release/v0-16-0.html diff --git a/content/en/release/v0-16-0.md b/content/en/release/v0-16-0.md new file mode 100644 index 000000000..42f0508d4 --- /dev/null +++ b/content/en/release/v0-16-0.md @@ -0,0 +1,12 @@ +--- +title: "v0.16.0" +description: "v0.16.0 release report." +lead: "Auto-generated v0.16.0 release report." +date: 2025-06-11T00:00:00+08:00 +lastmod: 2025-06-11T00:00:00+08:00 +draft: false +images: [] +weight: 1600 +toc: false +iframe: "/release/v0-16-0.html" +--- diff --git a/content/zh/release/v0-16-0.md b/content/zh/release/v0-16-0.md new file mode 100644 index 000000000..5b6890602 --- /dev/null +++ b/content/zh/release/v0-16-0.md @@ -0,0 +1,12 @@ +--- +title: "v0.16.0" +description: "v0.16.0 发布报告。" +lead: "v0.16.0 自动生成的发布报告。" +date: 2025-06-11T00:00:00+08:00 +lastmod: 2025-06-11T00:00:00+08:00 +draft: false +images: [] +weight: 1600 +toc: false +iframe: "/release/v0-16-0.html" +--- diff --git a/static/release/v0-16-0.html b/static/release/v0-16-0.html new file mode 100644 index 000000000..b3ea42395 --- /dev/null +++ b/static/release/v0-16-0.html @@ -0,0 +1,1175 @@ + + + + + + Tableau v0.16.0 — Release Notes + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ABCDEFG
1IDNameLevelHPAttackTypeValidate
2map<uint32,Hero>stringint32int32int32enum<HeroType>string|{validate:...
3Hero IDHero nameHero levelMax HPBase attackHero classCEL rule
41Arthur50500120warrior
52Merlin4538090mage
63Lancelot55620150knight
74Guinevere48420110rogue
85Galahad60700180paladin
+
+ + + + +
v0.16.0
+ +
+ + +
+ Tableau + Tableau + | + v0.16.0 + | +
+ + Released May 29, 2026 +
+
+ + +
Release Notes
+ + +
v0.16.0
+ + +

+ CEL validation via protovalidate, Buf toolchain support, structured error collection, + PreserveFieldNumbers, and more. +

+ + +
+
✦ 7 Features
+
⬡ 9 Bug Fixes
+
⚠ 2 Breaking
+
↯ 1 Deprecated
+ | + Go · Protobuf · Config Generation +
+
+ + +
+
+ Scroll +
+
+ + + +
+
+ +
+ 01 +

New Features

+
+
+ +
+ + +
+
+ 📦 + 01 / 07 +
+

Protobuf Editions Support

+

Generator now supports protobuf editions alongside proto2/proto3, with properly quoted file option values. A key step toward future-proofing generated proto files.

+
+ New + Breaking +
+
+ + +
+
+ 🔖 + 02 / 07 +
+

PreserveFieldNumbers

+

New option to maintain field tag number compatibility across regenerations — critical for wire format stability. Works on both regular fields and union structs.

+
+ New Option +
+
+ + +
+
+ + 03 / 07 +
+

CEL Validation via protovalidate

+

Integrated buf's protovalidate framework — declare CEL validation rules directly in spreadsheet field/worksheet properties, compiled into generated proto files.

+
+ New +
+
+ + +
+
+ 🔧 + 04 / 07 +
+

Buf Toolchain Migration

+

Switched to Buf for protobuf generation, linting, and BSR publishing. CI no longer requires manual protoc install steps.

+
+ Tooling + New +
+
+ + +
+
+ 🔗 + 05 / 07 +
+

Union Field Improvements

+

Field numbers preserved on union structs. Fixed column ordering — definition order index (i+1) used as column suffix, ensuring stable Field1, Field2….

+
+ Enhanced +
+
+ + +
+
+ 📊 + 06 / 07 +
+

Per-Messager Output Formats

+

Configure different output formats (json, txtpb, binpb) for individual messagers in confgen — fine-grained control beyond the global default.

+
+ New +
+
+ + +
+
+
+
+ 🏗️ + 07 / 07 · Largest Change +
+

Structured Error Collection System

+

+ The biggest architectural change in v0.16.0 (#387 — 6,595 insertions, 119 files). + Previously tableau stopped on the first parse error. Now a hierarchical + Collector tree + accumulates multiple errors concurrently — global → book → sheet → message — each level + with its own cap. You see all errors in one run. +

+
+ New + Architectural · 119 files +
+
+ +
+
Error Collector Hierarchy
+
+
+ Generator + max 20 +
+
+ └─ Book + max 10 / book +
+
+ └─ Sheet + max 5 / sheet +
+
+ └─ Message + max 3 / row +
+
+ confgen: 20 → 10 → 5 → 3 (4 levels)
+ protogen: 10 → 5 → 3 (3 levels)
+ Join() assembles the full error tree +
+
+
+
+
+ +
+
+
+ + + +
+
+
+ 02 +

Bug Fixes

+
+
+ +
+
+ git log — 9 patches since v0.15.0 +
+
+
+ bc70718 + protogen +
Wrap bookName and sheetName correctly when parsing special sheet mode
+
+
+ 05396e8 + protogen +
Add correct cell positioners for struct and union type sheet parsing
+
+
+ 0f3049f + protogen +
Skip TYPE_INVALID=0 in union when enum value 0 is user-specified
+
+
+ 7e3e4bc + union +
Fix incell list field properties in union message field parsing; simplify parser logic
+
+
+ b80914b + fieldprop +
Check presence correctly for incell struct / list / map / union fields
+
+
+ c0f520c + protogen +
Use fullpath when removing all protos except imports in outdir (fixes Windows)
+
+
+ 69e0296 + refer +
Skip ignored rows in refer check to avoid false-positive validation errors
+
+
+ 508d6c4 + protogen +
Use strings.LastIndex to correctly trim first field name from predefined struct names
+
+
+ 1da426f + log +
Only output log to console after log.Init is called
+
+
+
+
+
+ + + +
+
+
+ 03 +

Breaking Changes

+
+
+
+
+
⚠ Breaking 1 / 2
+

Protobuf Editions: go_package Must Be Quoted

+

File option values like go_package now require explicit double-quote wrapping in YAML config.

+
+
# config.yaml — fileOptions migration
+
+ - go_package: github.com/org/protoconf + + go_package: '"github.com/org/protoconf"' + # ↑ outer single + inner double +
+
+
+
+
⚠ Breaking 2 / 2
+

Consistent protoFiles Parsing Refactor

+

protoFiles parsing unified across all code paths. Workflows relying on previous parser behavior may be affected. Re-run proto generation and verify output.

+
+
# Commit: c27cf3c — action required
+
+ // Affects: protogen + confgen pipelines + // Also: CleanSlashPath for Windows paths + // Also: Go 1.25 support via sonic upgrade + // Action: re-generate + verify output +
+
+
+
+
+
+ + + +
+
+
+ 04 +

Deprecated & Refactored

+
+
+ +
+
🚫
+
+

Field Option cross — Deprecated

+

The field option cross is deprecated as of this release. Existing sheets continue to work but the option will be removed in a future version.

+
+
+
+
+
Refactor
+

JSON Parser: sonic → fastjson

+

Replaced bytedance/sonic with valyala/fastjson for cross-platform compatibility.

+
+
+
Refactor
+

i18n Template Quoting

+

Use template quote function instead of manual strconv.Quote at all call sites across the codebase.

+
+
+
Refactor
+

IsSamePath with Absolute Paths

+

Improved xfs.IsSamePath to resolve absolute paths, fixing subtle mismatches on Windows and symlinked directories.

+
+
+
Improvement
+

Validate Violation Error Messages

+

Richer, more actionable error messages for field, message, list, and map violations — easier to trace issues to source cells.

+
+
+
+
+ + + +
+
+
+ 05 +

Dependency Updates

+
+
+
+
buf (toolchain) NEW
+
valyala/fastjson NEW
+
golangci-lint-action 8 → 9
+
codecov-action 5 → 6
+
actions/checkout 5 → 6
+
antchfx/xpath ↑
+
bufbuild/protocompile ↑
+
spf13/cobra ↑
+
go.uber.org/zap ↑
+
xuri/excelize ↑
+
+
+
+ + + +
+
+ +
+ 06 +

Spreadsheet Examples

+
+
+

+ Tableau converts Excel/CSV spreadsheets into protobuf configs. Sheets use a 3-row header convention: + Row 1 = field names  ·  + Row 2 = field types + props  ·  + Row 3 = notes. Examples use real test-data from the repository. +

+ + +
+
✦ New Feature
+

CEL Validation via protovalidate

+

+ Add validate: / + validate_complex: / + validate_message: + props directly in the field-type cell (Row 2). Worksheet-level rules go in the + @TABLEAU metasheet. +

+ +
+
+
📄 ValidateFieldLevel — field-level validation props in Row 2
+
+ + + + + + + + + + + + + +
ABC
1IDNameScore
2map<uint32, Item>|{validate:"uint32:{gt:0}" validate_complex:"map:{min_pairs:1}"}string|{validate:"string:{min_len:1 max_len:20}"}int32|{validate:"int32:{gt:0 lte:100}"}
3Item IDItem NameItem Score
41sword80
52shield95
+
+
+
+
📋 Validate#@TABLEAU — worksheet-level CEL expressions
+
+ + + + + + + +
A (Sheet)B (Mode)C (Validate)
2ValidateWorksheetLevelcel_expression:"this.item_map.size() > 0"
3ValidateStructTypeMODE_STRUCT_TYPEcel_expression:"this.begin > this.end ? 'begin must be before end' : ''"
4ValidateUnionTypeMODE_UNION_TYPEcel_expression:"this.type != 0"
+
+
+
+
+
▸ generated proto — field-level buf.validate annotations
+
+ // Validation rules compiled from spreadsheet props + message Item { +   uint32 id = 1 [(tableau.field) = {name:"ID"}, (buf.validate.field).uint32 = {gt: 0}]; +   string name = 2 [(tableau.field) = {name:"Name"}, (buf.validate.field).string = {min_len: 1, max_len: 20}]; +   int32 score = 3 [(tableau.field) = {name:"Score"}, (buf.validate.field).int32 = {gt: 0, lte: 100}]; + } +
+
+
+ + +
+
✦ New Option
+

PreserveFieldNumbers — Safe Schema Evolution

+

+ Adding a column mid-sheet silently shifts field tag numbers — breaking binary-serialized data. + Enable preserveFieldNumbers: true + to lock existing fields to their original numbers. New fields get max+1. +

+
+
+
📄 HeroConf — v1 (original)
+
+ + + + + + + + +
ABC
1IDNameLevel
2map<uint32, Hero>stringint32
3Hero IDHero nameHero level
41Arthur50
+
+
+
+
📄 HeroConf — v2 (HP inserted between Name and Level)
+
+ + + + + + + + +
ABCD
1IDNameHPLevel
2map<uint32, Hero>stringint32int32
3Hero IDHero nameHero HPHero level
41Arthur50050
+
+
+
+
+
+
✗ Without PreserveFieldNumbers
+
+ // Fields re-numbered in sheet order
+ uint32 id = 1; // ✓ unchanged
+ string name = 2; // ✓ unchanged
+ int32 hp = 3; // ← took level's old #
+ int32 level = 4; // ⚠ SHIFTED 3→4!
+ // binary data CORRUPTED +
+
+
+
✓ With preserveFieldNumbers: true
+
+ // Existing numbers locked; new = max+1
+ uint32 id = 1; // ✓ preserved
+ string name = 2; // ✓ preserved
+ int32 hp = 4; // ✓ new = max+1
+ int32 level = 3; // ✓ preserved!
+ // wire format safe ✓ +
+
+
+
+
▸ tableauc config.yaml
+
+ proto: + output: + preserveFieldNumbers: true # enable preservation +
+
+
+ 💡 On first run, tableau reads existing generated .proto files in outdir to learn current field numbers — keep them before regenerating. +
+
+ + +
+
⬡ Bug Fix
+

Union Field Ordering — Column Lookup Fixed

+

+ The bug was in the confgen parser: when reading a union member's + value fields, it used fd.Number() + (the protobuf tag number) to construct the column name to look up. If a union member struct + has non-sequential field tag numbers, the parser searched for the wrong columns and silently + produced zero values. The fix uses i+1 + (definition order) instead — matching how column names are always generated. +

+ + +
+
▸ Proto — Pvp union member struct with non-sequential field tag numbers
+
+ // (tableau.oneof) = {field: "Field"} → column prefix is "Field" + message Pvp { + int32 type = 1; // definition index i=0 → column suffix = 0+1 = 1 → TargetField1 + int32 health = 4; // definition index i=1 → column suffix = 1+1 = 2 → TargetField2 (tag ≠ position!) + int64 damage = 3; // definition index i=2 → column suffix = 2+1 = 3 → TargetField3 (tag ≠ position!) + } +
+
+ + +
+
📄 TaskConf — column names are always sequential (TargetField1, TargetField2, TargetField3)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ABCDE
1IDTargetTypeTargetField1TargetField2TargetField3
2map<int32, Task>{union.Target}enum<union.Target.Type>unionunionunion
3Task IDTarget typeTarget field 1Target field 2Target field 3
41PVP10200500
52PVE35
+
+
+ + +
+
+
✗ Before fix — parser used fd.Number() as column suffix
+
+ // Parsing PVP row, iterating Pvp fields:
+ Pvp.type (tag=1) → looked for TargetField1 → found, type=10 ✓
+ Pvp.health (tag=4) → looked for TargetField4 → NOT FOUND → health=0
+ Pvp.damage (tag=3) → looked for TargetField3 → found BUT reads wrong slot
+
+ // Result: health silently zeroed, damage wrong +
+
+
+
✓ After fix — parser uses i+1 (definition order)
+
+ // Parsing PVP row, iterating Pvp fields:
+ Pvp.type (i=0, i+1=1) → looked for TargetField1 → found, type=10 ✓
+ Pvp.health (i=1, i+1=2) → looked for TargetField2 → found, health=200 ✓
+ Pvp.damage (i=2, i+1=3) → looked for TargetField3 → found, damage=500 ✓
+
+ // Result: all fields correctly parsed ✓ +
+
+
+ + +
+
▸ internal/confgen/document_parser.go — the one-line fix
+
+ // Inside parseUnionMessage(), iterating fields of a union member struct: + - valNodeName := unionDesc.ValueFieldName() + strconv.Itoa(int(fd.Number())) + + valNodeName := unionDesc.ValueFieldName() + strconv.Itoa(i+1) + // fd.Number() = proto tag (can be any int) → wrong column when non-sequential + // i+1 = definition order (always 1,2,3…) → always matches sheet columns +
+
+
+ + +
+
✦ New Feature
+

Per-Messager Output Formats

+

+ Override output formats per messager. Supported formats: json, + txtpb (text protobuf), + binpb (binary protobuf). + Useful when some messagers need compact binary for runtime performance while others stay in human-readable JSON or text protobuf. +

+
+
+
📄 ItemConf — runtime-critical, needs binary
+
+ + + + + + + + +
ABC
1IDNamePrice
2map<uint32, Item>stringint32
3Item IDItem nameItem price
41Sword100
+
+
+
+
📄 LevelConf — needs text protobuf for inspection
+
+ + + + + + + + +
ABC
1LevelExpMaxHP
2map<int32, LevelData>int64int32
3Level numExp neededMax HP
410100
+
+
+
+
+
▸ tableauc config.yaml — messagerFormats (NEW in v0.16.0)
+
+ conf: + output: + formats: [json] # default for all + messagerFormats: # per-messager overrides + ItemConf: [json, binpb] # json for debug + binpb for runtime perf + LevelConf: [json, txtpb] # json + txtpb for human-readable inspection +
+
+
+ + +
+
⚠ Breaking Change
+

Protobuf Editions: go_package Must Be Quoted

+

+ With editions support, string file options must be explicitly double-quoted in YAML config. +

+
+
+
✗ v0.15.x config (now broken)
+
+ # tableauc config.yaml
+ proto:
output:
fileOptions:
+ go_package: github.com/org/protoconf

+ # Generated proto (wrong):
+ option go_package = github.com/org/protoconf;
+ # ↑ missing quotes → parse error +
+
+
+
✓ v0.16.0 migration
+
+ # tableauc config.yaml
+ proto:
output:
fileOptions:
+ go_package: '"github.com/org/protoconf"'
+ # outer single + inner double quotes

+ # Generated proto (correct):
+ option go_package = "github.com/org/protoconf"; +
+
+
+
+ + +
+
↯ Deprecated
+

Field Option cross — Deprecated

+

+ cross was used on a horizontal union list field to specify how many value-field columns each list element spans. + cross:3 means every element in the list occupies exactly 3 consecutive value-field columns. + The option is deprecated as of v0.16.0 — existing sheets still work but it will be removed in a future version. +

+ + +
+
🏗️ Architectural
+

Structured Error Collector — See All Errors, Not Just the First

+

+ The new xerrors.Collector tree collects multiple parse errors concurrently + across the full pipeline. Each level has its own cap — parsing stops only when a level's budget is exhausted, not on the very first error. +

+ +
+
+
📄 Collector#ItemConf.csv — two invalid cells in the same row
+
+ + + + + + + + + + + +
ABC
1IDNumPrice
2uint32int32int32
3Item's IDItem's numItem's price
41xyzbad_price
+
+
+
+
📄 Collector#ShopConf.csv — errors across two rows
+
+ + + + + + + + + +
AB
1ShopIDPrice
2uint32int32
3Shop's IDGoods's price
41bad_price
5bad_id200
+
+
+
+ +
+
+
✗ Old behavior (v0.15.x) — stops at first error
+
+ $ tableauc gen ...

+ error[E2012]: invalid syntax of numerical value
+ Workbook: Collector#*.csv
+ Worksheet: ItemConf
+ DataCellPos: B4
+ DataCell: xyz
+ Reason: "xyz" cannot be parsed to int32

+ // ← STOPS. Fix xyz, run again,
+ // discover bad_price, fix it, run again…
+ // painful iteration cycle. +
+
+
+
✓ New behavior (v0.16.0) — all errors at once
+
+ $ tableauc gen ...

+ [1] error[E2012]: invalid syntax…
+ Workbook: Collector#*.csv
...

+ [2] error[E2012]: invalid syntax…
+ Workbook: Collector#*.csv
...

+ [3] error[E2012]: invalid syntax…
+ Workbook: Collector#*.csv
...

+ // Fix ALL 3 issues in one pass ✓ +
+
+
+ +
+
▸ confgen 4-level collector hierarchy (protogen uses 3 levels: 10→5→3, no message level)
+
+ // Each level has its own cap; Collect(err) increments self + ALL ancestors + gen.collector = NewCollector(20) // global: all workbooks + bookCollector = gen.collector.NewChild(10) // per workbook + sheetCollector = bookCollector.NewChild(5) // per sheet + messageCollector = sheetCollector.NewChild(3) // per row/message +   + // Concurrent workbooks via Group (cancels ctx when full): + group = gen.collector.NewGroup(ctx) + group.Go(func(ctx) { return gen.convertTable(fd) }) // one goroutine per workbook + err = group.Wait() // returns joined error tree or nil +
+
+
+ 💡 Cap behavior with overflow (confgen): A sheet with 12 bad rows reports only the first 5 errors per sheet (up to 3 per row). Parsing skips remaining rows once the sheet cap is reached. The global cap of 20 prevents runaway output across all concurrent workbooks. +
+
+ +
+
+ + + + + + + + + + From 7dfd4fd3314862295262c1ba202bdf76ae699d2b Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 15:48:05 +0800 Subject: [PATCH 13/27] fix(release): full-width iframe layout, drop sidebar, add fullscreen + open-in-tab actions --- assets/scss/components/_release.scss | 71 +++++++++++++-- layouts/release/single.html | 129 +++++++++++++++++++-------- 2 files changed, 156 insertions(+), 44 deletions(-) diff --git a/assets/scss/components/_release.scss b/assets/scss/components/_release.scss index fc0693618..340384dda 100644 --- a/assets/scss/components/_release.scss +++ b/assets/scss/components/_release.scss @@ -1,13 +1,57 @@ /* Release section */ -/* Iframe pane: fill the available content column height. */ +/* Full-width iframe page: break out of the parent `.container-xxl` so reports + span the entire viewport width regardless of the global fullWidth setting. + `100vw` minus its own offset keeps it left-aligned without horizontal scroll. */ +.release-iframe-page { + width: 100vw; + position: relative; + left: 50%; + right: 50%; + margin-left: -50vw; + margin-right: -50vw; + padding: 0 1rem; + box-sizing: border-box; +} + +.release-iframe-header { + padding: 0.5rem 0.25rem; + margin-bottom: 0.5rem; + border-bottom: 1px solid var(--bs-border-color, #dee2e6); +} + +.release-iframe-header .breadcrumb { + background: transparent; + padding: 0; +} + +.release-iframe-actions .release-iframe-action { + color: var(--bs-secondary-color, #495057); + padding: 0.25rem 0.5rem; + border-radius: 0.25rem; + text-decoration: none; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.release-iframe-actions .release-iframe-action:hover, +.release-iframe-actions .release-iframe-action:focus { + color: var(--bs-primary, #0d6efd); + background: var(--bs-secondary-bg, rgba(13, 110, 253, 0.08)); +} + +.release-iframe-lead { + margin: 0 0 0.5rem; +} + +/* Iframe wrap: tall, edge-to-edge inside the page. */ .release-iframe-wrap { position: relative; width: 100%; - /* Approximate offset: site header (~64px) + breadcrumb/title block (~120px). */ - height: calc(100vh - 200px); - min-height: 480px; - margin-top: 1rem; + height: calc(100vh - 160px); + min-height: 520px; + margin-top: 0.5rem; border: 1px solid var(--bs-border-color, #dee2e6); border-radius: 0.25rem; overflow: hidden; @@ -21,6 +65,23 @@ display: block; } +/* Browser native fullscreen: occupy whole screen with no padding. */ +.release-iframe-wrap:fullscreen, +.release-iframe-wrap:-webkit-full-screen { + width: 100vw; + height: 100vh; + border: 0; + border-radius: 0; + margin: 0; + background: #fff; +} + +.release-iframe-wrap:fullscreen iframe, +.release-iframe-wrap:-webkit-full-screen iframe { + width: 100vw; + height: 100vh; +} + /* Active sidebar item: subtle highlight using the existing docs-sidebar look. */ .release-sidebar-item.active > a { font-weight: 600; diff --git a/layouts/release/single.html b/layouts/release/single.html index f319a4419..b6c2406d5 100644 --- a/layouts/release/single.html +++ b/layouts/release/single.html @@ -1,22 +1,52 @@ {{ define "main" }} -
-
- {{ partial "release/sidebar.html" . }} -
- {{ if .Params.iframe -}} -
- {{ if .Site.Params.options.breadCrumb -}} - - {{ end }} -

{{ .Title }}

- {{ with .Params.lead }}

{{ . | safeHTML }}

{{ end }} + {{ if .Params.iframe -}} + {{/* Full-width iframe layout — no sidebar, content fills viewport. */}} +
+
+ {{ if .Site.Params.options.breadCrumb -}} + + {{ else -}} +

{{ .Title }}

+ {{ end -}} +
+ + + + +
+
+ {{ with .Params.lead }}

{{ . | safeHTML }}

{{ end }} {{ with .Content }}
{{ . }}
{{ end }} -
+
-
- {{ else -}} -
- {{ if .Site.Params.options.breadCrumb -}} - - {{ end }} -

{{ .Title }}

- {{ with .Params.lead }}

{{ . | safeHTML }}

{{ end }} - {{ if ne .Params.toc false -}} - - {{ end -}} - {{ .Content }} -
- {{ end -}} -
+ + + {{ else -}} + {{/* Markdown release: docs-style two-pane layout with sidebar + TOC. */}} +
+
+ {{ partial "release/sidebar.html" . }} +
+
+ {{ if .Site.Params.options.breadCrumb -}} + + {{ end }} +

{{ .Title }}

+ {{ with .Params.lead }}

{{ . | safeHTML }}

{{ end }} + {{ if ne .Params.toc false -}} + + {{ end -}} + {{ .Content }} +
+
+ {{ end -}} {{ end }} From c9048eea67fe668cbc31fbc3b9c8f94c904981a9 Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 16:22:44 +0800 Subject: [PATCH 14/27] fix(dev): enable poll watcher + force-sync static for live reload of release/static dirs --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 928030245..6062c25a9 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "init": "shx rm -rf .git && git init -b main", "create": "exec-bin node_modules/.bin/hugo/hugo new", "prestart": "npm run clean", - "start": "exec-bin node_modules/.bin/hugo/hugo server --bind=0.0.0.0 --disableFastRender", + "start": "exec-bin node_modules/.bin/hugo/hugo server --bind=0.0.0.0 --disableFastRender --poll 700ms --forceSyncStatic --navigateToChanged", "prebuild": "npm run clean", "build": "exec-bin node_modules/.bin/hugo/hugo --gc --minify", "build:preview": "npm run build -D -F", From 8f4c9ad43c8057f70f3df1e71051613b4849d198 Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 17:06:20 +0800 Subject: [PATCH 15/27] refactor(release): blog-style card list, drop sidebar from list and markdown pages, remove sample v0.2.0 --- content/en/release/v0-16-0.md | 1 - content/en/release/v0-2-0.md | 12 ------ content/zh/release/v0-2-0.md | 12 ------ layouts/partials/release/sidebar.html | 23 ------------ layouts/release/list.html | 35 ++++++++++-------- layouts/release/single.html | 53 +++++++++++++++------------ static/release/v0-2-0.html | 26 ------------- 7 files changed, 49 insertions(+), 113 deletions(-) delete mode 100644 content/en/release/v0-2-0.md delete mode 100644 content/zh/release/v0-2-0.md delete mode 100644 layouts/partials/release/sidebar.html delete mode 100644 static/release/v0-2-0.html diff --git a/content/en/release/v0-16-0.md b/content/en/release/v0-16-0.md index 42f0508d4..a9e224afe 100644 --- a/content/en/release/v0-16-0.md +++ b/content/en/release/v0-16-0.md @@ -1,7 +1,6 @@ --- title: "v0.16.0" description: "v0.16.0 release report." -lead: "Auto-generated v0.16.0 release report." date: 2025-06-11T00:00:00+08:00 lastmod: 2025-06-11T00:00:00+08:00 draft: false diff --git a/content/en/release/v0-2-0.md b/content/en/release/v0-2-0.md deleted file mode 100644 index bd953a8bb..000000000 --- a/content/en/release/v0-2-0.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: "v0.2.0" -description: "v0.2.0 generated report." -lead: "Auto-generated benchmark / changelog report." -date: 2024-12-01T14:00:00+08:00 -lastmod: 2024-12-01T14:00:00+08:00 -draft: false -images: [] -weight: 8000 -toc: false -iframe: "/release/v0-2-0.html" ---- diff --git a/content/zh/release/v0-2-0.md b/content/zh/release/v0-2-0.md deleted file mode 100644 index 41c6aec1b..000000000 --- a/content/zh/release/v0-2-0.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: "v0.2.0" -description: "v0.2.0 自动生成报告。" -lead: "自动生成的基准测试 / 更新报告。" -date: 2024-12-01T14:00:00+08:00 -lastmod: 2024-12-01T14:00:00+08:00 -draft: false -images: [] -weight: 8000 -toc: false -iframe: "/release/v0-2-0.html" ---- diff --git a/layouts/partials/release/sidebar.html b/layouts/partials/release/sidebar.html deleted file mode 100644 index 7e128598a..000000000 --- a/layouts/partials/release/sidebar.html +++ /dev/null @@ -1,23 +0,0 @@ -{{/* - Release sidebar: flat list of all pages in the "release" section for the - current language, sorted by `weight` ascending. The current page is - highlighted. HTML-stub releases (front-matter `iframe` is set) display a - small "HTML" badge as a visual cue. -*/}} - diff --git a/layouts/release/list.html b/layouts/release/list.html index d650e69c4..bb01b38b4 100644 --- a/layouts/release/list.html +++ b/layouts/release/list.html @@ -1,23 +1,26 @@ {{ define "main" }} -
-
- {{ partial "release/sidebar.html" . }} -
-
-

{{ .Title }}

- {{ with .Params.lead }}

{{ . | safeHTML }}

{{ end }} - {{ .Content }} -
    +
    +
    +
    +

    {{ .Title }}

    +
    {{ .Content }}
    +
    {{ $currentLang := .Site.Language.Lang }} {{ $releasePages := where (where site.RegularPages "Section" "release") "Lang" $currentLang }} {{ range $releasePages.ByWeight }} -
  • - {{ .Title }} - {{ if .Params.iframe }}HTML{{ end }} - {{ with .Params.description }}
    {{ . }}
    {{ end }} -
  • +
    +
    +

    + {{ .Title }} + {{ if .Params.iframe }}HTML{{ end }} +

    + {{ with .Params.lead }}

    {{ . | safeHTML }}

    {{ end }} +

    {{ .Date.Format "January 2, 2006" }}

    +
    +
    {{ end }} -
-
+
+ + {{ end }} diff --git a/layouts/release/single.html b/layouts/release/single.html index b6c2406d5..f7e7bda85 100644 --- a/layouts/release/single.html +++ b/layouts/release/single.html @@ -1,6 +1,6 @@ {{ define "main" }} {{ if .Params.iframe -}} - {{/* Full-width iframe layout — no sidebar, content fills viewport. */}} + {{/* Full-width iframe layout — content fills viewport, no sidebar. */}}
{{ if .Site.Params.options.breadCrumb -}} @@ -72,29 +72,36 @@

{{ .Title }}

})(); {{ else -}} - {{/* Markdown release: docs-style two-pane layout with sidebar + TOC. */}} -
-
- {{ partial "release/sidebar.html" . }} -
-
- {{ if .Site.Params.options.breadCrumb -}} - - {{ end }} -

{{ .Title }}

- {{ with .Params.lead }}

{{ . | safeHTML }}

{{ end }} - {{ if ne .Params.toc false -}} - - {{ end -}} - {{ .Content }} + {{/* Markdown release: blog-style centered article with optional right TOC. */}} +
+
+
+ {{ if .Site.Params.options.breadCrumb -}} + + {{ end }} +
+

{{ .Title }}

+

{{ .Date.Format "January 2, 2006" }}

+
+ {{ with .Params.lead }}

{{ . | safeHTML }}

{{ end }} + {{ if ne .Params.toc false -}} + + {{ end -}} + {{ .Content }} +
+ {{ if ne .Params.toc false -}} + + {{ end -}}
{{ end -}} {{ end }} diff --git a/static/release/v0-2-0.html b/static/release/v0-2-0.html deleted file mode 100644 index dba4ba32c..000000000 --- a/static/release/v0-2-0.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - Tableau v0.2.0 Report - - - -

Tableau v0.2.0 Report

-

This is a sample standalone HTML artifact embedded via iframe in the - Release section. Replace this with your actual generated report.

- - - - - - -
MetricBeforeAfter
Conversion speed1.0×1.4×
Memory usage240 MB180 MB
- - From 200beef819095dbf5412e160bccdbe21865a06c6 Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 17:13:11 +0800 Subject: [PATCH 16/27] refactor(release): match blog card styling exactly (same partial, same selectors, same shape) --- assets/scss/layouts/_posts.scss | 12 ++++++++---- layouts/partials/main/blog-meta.html | 2 +- layouts/release/list.html | 16 ++++++++-------- layouts/release/single.html | 2 +- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/assets/scss/layouts/_posts.scss b/assets/scss/layouts/_posts.scss index da2766052..70bcd3eba 100644 --- a/assets/scss/layouts/_posts.scss +++ b/assets/scss/layouts/_posts.scss @@ -1,6 +1,7 @@ .home .card, .contributors.list .card, -.blog.list .card { +.blog.list .card, +.release.list .card { margin-top: 2rem; margin-bottom: 2rem; transition: transform 0.3s; @@ -8,17 +9,20 @@ .home .card:hover, .contributors.list .card:hover, -.blog.list .card:hover { +.blog.list .card:hover, +.release.list .card:hover { transform: scale(1.025); } .home .card-body, .contributors.list .card-body, -.blog.list .card-body { +.blog.list .card-body, +.release.list .card-body { padding: 0 2rem 1rem; } -.blog-header { +.blog-header, +.release-header { text-align: center; margin-bottom: 2rem; } diff --git a/layouts/partials/main/blog-meta.html b/layouts/partials/main/blog-meta.html index a9eb43877..e4da75322 100644 --- a/layouts/partials/main/blog-meta.html +++ b/layouts/partials/main/blog-meta.html @@ -1 +1 @@ -

Posted {{ .PublishDate.Format "January 2, 2006" }} by {{ if .Params.contributors -}}{{ range $index, $contributor := .Params.contributors }}{{ if gt $index 0 }} and {{ end }}{{ . }}{{ end -}}{{ end -}} ‐ {{ .ReadingTime -}} min read

\ No newline at end of file +

Posted {{ .PublishDate.Format "January 2, 2006" }}{{ if .Params.contributors }} by {{ range $index, $contributor := .Params.contributors }}{{ if gt $index 0 }} and {{ end }}{{ . }}{{ end }}{{ end }} ‐ {{ .ReadingTime -}} min read

diff --git a/layouts/release/list.html b/layouts/release/list.html index bb01b38b4..bb75b9cb5 100644 --- a/layouts/release/list.html +++ b/layouts/release/list.html @@ -7,18 +7,18 @@

{{ .Title }}

{{ $currentLang := .Site.Language.Lang }} {{ $releasePages := where (where site.RegularPages "Section" "release") "Lang" $currentLang }} - {{ range $releasePages.ByWeight }} + {{ $paginator := .Paginate $releasePages.ByWeight -}} + {{ range $paginator.Pages -}}
-

- {{ .Title }} - {{ if .Params.iframe }}HTML{{ end }} -

- {{ with .Params.lead }}

{{ . | safeHTML }}

{{ end }} -

{{ .Date.Format "January 2, 2006" }}

+

{{ .Params.title }}{{ if .Params.iframe }} HTML{{ end }}

+

{{ .Params.lead | safeHTML }}

+ {{ partial "main/blog-meta.html" . -}}
- {{ end }} + {{ end -}} + {{ $.Scratch.Set "paginator" true }} + {{ template "_internal/pagination.html" . }}
diff --git a/layouts/release/single.html b/layouts/release/single.html index f7e7bda85..d6706b9c3 100644 --- a/layouts/release/single.html +++ b/layouts/release/single.html @@ -86,7 +86,7 @@

{{ .Title }}

{{ end }}

{{ .Title }}

-

{{ .Date.Format "January 2, 2006" }}

+ {{ partial "main/blog-meta.html" . }}
{{ with .Params.lead }}

{{ . | safeHTML }}

{{ end }} {{ if ne .Params.toc false -}} From 4ecbe276755200432921840dcba602b1756ed87b Mon Sep 17 00:00:00 2001 From: wenchy Date: Thu, 11 Jun 2026 17:23:27 +0800 Subject: [PATCH 17/27] fix(release): align breadcrumb with action icons; hide lead on iframe pages --- assets/scss/components/_release.scss | 14 ++++++++++++++ layouts/release/single.html | 1 - 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/assets/scss/components/_release.scss b/assets/scss/components/_release.scss index 340384dda..8a085a091 100644 --- a/assets/scss/components/_release.scss +++ b/assets/scss/components/_release.scss @@ -18,11 +18,24 @@ padding: 0.5rem 0.25rem; margin-bottom: 0.5rem; border-bottom: 1px solid var(--bs-border-color, #dee2e6); + min-height: 2.5rem; + line-height: 1.5; } .release-iframe-header .breadcrumb { background: transparent; padding: 0; + margin: 0; + display: flex; + align-items: center; + flex-wrap: wrap; + line-height: 1.5; +} + +.release-iframe-header nav[aria-label="breadcrumb"] { + margin: 0; + display: flex; + align-items: center; } .release-iframe-actions .release-iframe-action { @@ -33,6 +46,7 @@ display: inline-flex; align-items: center; justify-content: center; + line-height: 1; } .release-iframe-actions .release-iframe-action:hover, diff --git a/layouts/release/single.html b/layouts/release/single.html index d6706b9c3..623c1cf67 100644 --- a/layouts/release/single.html +++ b/layouts/release/single.html @@ -44,7 +44,6 @@

{{ .Title }}

- {{ with .Params.lead }}

{{ . | safeHTML }}

{{ end }} {{ with .Content }}
{{ . }}
{{ end }}