mirror of
https://github.com/tiennm99/tsuki.git
synced 2026-09-02 16:20:55 +00:00
refactor: consolidate TOC gate, inline single-call SEO partial, prune unused i18n
- Extract duplicated TOC predicate to _partials/toc-enabled.html (single.html + footer.html were both computing the same 6-line gate). - Inline _partials/head/og-image.html into head/seo.html — single caller, the fallback chain is the contract; the partial wasn't earning its override surface. - Drop 6 unused i18n keys: postedOn, tags, categories, archive, noResults, copyright. None referenced by any template (verified via grep). Also removed an accidental duplicate of the callout title block; vi.yml reorganized into thematic groups. Behavior unchanged. Smoke (11 checks) + Hugo build clean. CSS bundle unchanged at 3962 B gz.
This commit is contained in:
@@ -4,6 +4,15 @@ All notable changes to tsuki will be documented here. Format follows [Keep a Cha
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- **TOC gate consolidated** to `_partials/toc-enabled.html` — single source for the `params.toc.{enable,minWordCount}` + per-page `toc: false` predicate, called from `single.html` (TOC partial) and `_partials/footer.html` (toc-active.js loader). Was duplicated 6-line logic in two sites; now one partial. No behavior change.
|
||||
- **`_partials/head/og-image.html` inlined into `head/seo.html`** — single-call partial removed; the OG image fallback chain (`cover.image` → `image` → `params.og.fallbackImage` → `data/profile.yaml: avatar`) is now expressed once at the top of `seo.html`. Override surface unchanged: replace `head/seo.html` to customize.
|
||||
|
||||
### Removed
|
||||
|
||||
- **Six unused i18n keys** — `postedOn`, `tags`, `categories`, `archive`, `noResults`, `copyright` were defined in `vi.yml` but never referenced by any template. Dropped along with one accidental duplicate of the callout title block. `vi.yml` reorganized into thematic groups (search/feeds/UI/callouts).
|
||||
|
||||
### Added
|
||||
|
||||
- **CI smoke tests** (`scripts/smoke-tests.sh`) run after Hugo build — assert JSON-LD on post / not on home, OG/Twitter image emit, skip-link + `<main id="main">`, render-link rel marker, reading-time byline, related-posts aside, CSS budget. 11 checks, fails the workflow on regression. Local-runnable: `./scripts/smoke-tests.sh`.
|
||||
|
||||
+56
-74
@@ -4,45 +4,54 @@
|
||||
- id: wordCount
|
||||
translation: "{{ .Count }} từ"
|
||||
|
||||
- id: calloutNote
|
||||
translation: "Ghi chú"
|
||||
|
||||
- id: calloutTip
|
||||
translation: "Mẹo"
|
||||
|
||||
- id: calloutImportant
|
||||
translation: "Quan trọng"
|
||||
|
||||
- id: calloutWarning
|
||||
translation: "Cảnh báo"
|
||||
|
||||
- id: calloutCaution
|
||||
translation: "Thận trọng"
|
||||
|
||||
- id: postedOn
|
||||
translation: "Đăng vào"
|
||||
|
||||
- id: updatedOn
|
||||
translation: "Cập nhật"
|
||||
|
||||
- id: tags
|
||||
translation: "Thẻ"
|
||||
|
||||
- id: categories
|
||||
translation: "Chuyên mục"
|
||||
|
||||
- id: archive
|
||||
translation: "Lưu trữ"
|
||||
|
||||
- id: search
|
||||
translation: "Tìm kiếm"
|
||||
|
||||
- id: searchPlaceholder
|
||||
translation: "Tìm bài viết..."
|
||||
|
||||
- id: searchNoScript
|
||||
translation: "Tìm kiếm yêu cầu JavaScript."
|
||||
|
||||
- id: searchDisabled
|
||||
translation: "Tìm kiếm hiện không khả dụng trên trang này."
|
||||
|
||||
- id: clearSearch
|
||||
translation: "Xoá"
|
||||
|
||||
- id: loadMore
|
||||
translation: "Xem thêm"
|
||||
|
||||
- id: filters
|
||||
translation: "Bộ lọc"
|
||||
|
||||
- id: zeroResults
|
||||
translation: "Không có kết quả cho [SEARCH_TERM]"
|
||||
|
||||
- id: oneResult
|
||||
translation: "[COUNT] kết quả cho [SEARCH_TERM]"
|
||||
|
||||
- id: manyResults
|
||||
translation: "[COUNT] kết quả cho [SEARCH_TERM]"
|
||||
|
||||
- id: searching
|
||||
translation: "Đang tìm [SEARCH_TERM]..."
|
||||
|
||||
- id: searchSuggestion
|
||||
translation: "Không có kết quả cho [SEARCH_TERM]. Thử các từ khoá: [DIFFERENT_TERMS]."
|
||||
|
||||
- id: altSearch
|
||||
translation: "Không có kết quả cho [SEARCH_TERM]. Đang hiển thị kết quả cho [DIFFERENT_TERM]."
|
||||
|
||||
- id: recentPosts
|
||||
translation: "Bài viết gần đây"
|
||||
|
||||
- id: relatedPosts
|
||||
translation: "Bài viết liên quan"
|
||||
|
||||
- id: featuredProjects
|
||||
translation: "Dự án nổi bật"
|
||||
|
||||
@@ -64,47 +73,20 @@
|
||||
- id: archiveEmpty
|
||||
translation: "Chưa có bài viết."
|
||||
|
||||
- id: toggleTheme
|
||||
translation: "Đổi giao diện"
|
||||
|
||||
- id: poweredBy
|
||||
translation: "Chạy bằng"
|
||||
|
||||
- id: noResults
|
||||
translation: "Không có kết quả."
|
||||
|
||||
- id: searchNoScript
|
||||
translation: "Tìm kiếm yêu cầu JavaScript."
|
||||
|
||||
- id: clearSearch
|
||||
translation: "Xoá"
|
||||
|
||||
- id: loadMore
|
||||
translation: "Xem thêm"
|
||||
|
||||
- id: filters
|
||||
translation: "Bộ lọc"
|
||||
|
||||
- id: zeroResults
|
||||
translation: "Không có kết quả cho [SEARCH_TERM]"
|
||||
|
||||
- id: manyResults
|
||||
translation: "[COUNT] kết quả cho [SEARCH_TERM]"
|
||||
|
||||
- id: oneResult
|
||||
translation: "[COUNT] kết quả cho [SEARCH_TERM]"
|
||||
|
||||
- id: searching
|
||||
translation: "Đang tìm [SEARCH_TERM]..."
|
||||
|
||||
- id: copyright
|
||||
translation: "© {{ .Year }} {{ .Author }}"
|
||||
- id: month
|
||||
translation: "Tháng {{ .Number }}"
|
||||
|
||||
- id: comments
|
||||
translation: "Bình luận"
|
||||
|
||||
- id: month
|
||||
translation: "Tháng {{ .Number }}"
|
||||
- id: toggleTheme
|
||||
translation: "Đổi giao diện"
|
||||
|
||||
- id: skipToContent
|
||||
translation: "Đến nội dung chính"
|
||||
|
||||
- id: poweredBy
|
||||
translation: "Chạy bằng"
|
||||
|
||||
- id: pageNotFound
|
||||
translation: "Trang không tồn tại."
|
||||
@@ -112,17 +94,17 @@
|
||||
- id: backHome
|
||||
translation: "Về trang chủ"
|
||||
|
||||
- id: searchSuggestion
|
||||
translation: "Không có kết quả cho [SEARCH_TERM]. Thử các từ khoá: [DIFFERENT_TERMS]."
|
||||
- id: calloutNote
|
||||
translation: "Ghi chú"
|
||||
|
||||
- id: altSearch
|
||||
translation: "Không có kết quả cho [SEARCH_TERM]. Đang hiển thị kết quả cho [DIFFERENT_TERM]."
|
||||
- id: calloutTip
|
||||
translation: "Mẹo"
|
||||
|
||||
- id: searchDisabled
|
||||
translation: "Tìm kiếm hiện không khả dụng trên trang này."
|
||||
- id: calloutImportant
|
||||
translation: "Quan trọng"
|
||||
|
||||
- id: skipToContent
|
||||
translation: "Đến nội dung chính"
|
||||
- id: calloutWarning
|
||||
translation: "Cảnh báo"
|
||||
|
||||
- id: relatedPosts
|
||||
translation: "Bài viết liên quan"
|
||||
- id: calloutCaution
|
||||
translation: "Thận trọng"
|
||||
|
||||
@@ -16,10 +16,7 @@
|
||||
-}}
|
||||
{{- $js := $jsFiles | resources.Concat "js/tsuki.bundle.js" | js.Build (dict "minify" true) | fingerprint -}}
|
||||
<script type="module" src="{{ $js.RelPermalink }}" integrity="{{ $js.Data.Integrity }}" crossorigin="anonymous"></script>
|
||||
{{- $tocCfg := site.Params.toc | default dict -}}
|
||||
{{- $tocEnabled := $tocCfg.enable | default true -}}
|
||||
{{- $tocMin := $tocCfg.minWordCount | default 400 -}}
|
||||
{{- if and (eq .Kind "page") $tocEnabled (gt .WordCount $tocMin) (ne .Params.toc false) }}
|
||||
{{- if partial "toc-enabled.html" . }}
|
||||
{{- $tocJs := resources.Get "js/toc-active.js" | js.Build (dict "minify" true) | fingerprint -}}
|
||||
<script type="module" src="{{ $tocJs.RelPermalink }}" integrity="{{ $tocJs.Data.Integrity }}" crossorigin="anonymous"></script>
|
||||
{{- end }}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
{{- /*
|
||||
Resolves the OG/Twitter image URL for the current page.
|
||||
Order: per-post `cover.image` → per-post `image` (legacy) → `params.og.fallbackImage` → `data/profile.yaml: avatar`.
|
||||
Returns the bare site-relative path; caller applies `absURL`.
|
||||
*/ -}}
|
||||
{{- $img := "" -}}
|
||||
{{- with .Params.cover -}}{{- $img = .image -}}{{- end -}}
|
||||
{{- if not $img -}}{{- $img = .Params.image -}}{{- end -}}
|
||||
{{- if not $img -}}{{- $img = site.Params.og.fallbackImage -}}{{- end -}}
|
||||
{{- if not $img -}}{{- with site.Data.profile -}}{{- $img = .avatar -}}{{- end -}}{{- end -}}
|
||||
{{- $img -}}
|
||||
@@ -7,7 +7,12 @@
|
||||
{{- $rawDesc := .Description | default .Summary | default site.Params.description -}}
|
||||
{{- $desc := "" -}}
|
||||
{{- with $rawDesc -}}{{- $desc = . | plainify | truncate 200 -}}{{- end -}}
|
||||
{{- $img := partial "head/og-image.html" . -}}
|
||||
{{- /* OG/Twitter image: per-post `cover.image` → per-post `image` → site `og.fallbackImage` → `data/profile.yaml: avatar`. */ -}}
|
||||
{{- $img := "" -}}
|
||||
{{- with .Params.cover -}}{{- $img = .image -}}{{- end -}}
|
||||
{{- if not $img -}}{{- $img = .Params.image -}}{{- end -}}
|
||||
{{- if not $img -}}{{- $img = site.Params.og.fallbackImage -}}{{- end -}}
|
||||
{{- if not $img -}}{{- with site.Data.profile -}}{{- $img = .avatar -}}{{- end -}}{{- end -}}
|
||||
|
||||
{{- /* OG locale: map common Hugo lang codes to OpenGraph IETF-with-region. */ -}}
|
||||
{{- $ogLocale := site.Params.og.locale | default (index (dict "vi" "vi_VN" "en" "en_US" "ja" "ja_JP" "zh" "zh_CN" "ko" "ko_KR" "fr" "fr_FR" "de" "de_DE") site.Language.Lang) | default site.LanguageCode -}}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{{- /*
|
||||
Single source of truth for whether to render the TOC for the current page.
|
||||
Returns the literal string "true" when enabled, empty otherwise.
|
||||
Callers: `single.html` (TOC partial), `footer.html` (toc-active.js loader).
|
||||
Site config: `params.toc.enable` (default true), `params.toc.minWordCount` (default 400).
|
||||
Per-page override: frontmatter `toc: false` always wins.
|
||||
*/ -}}
|
||||
{{- $cfg := site.Params.toc | default dict -}}
|
||||
{{- $enabled := $cfg.enable | default true -}}
|
||||
{{- $min := $cfg.minWordCount | default 400 -}}
|
||||
{{- if and $enabled (eq .Kind "page") (gt .WordCount $min) (ne .Params.toc false) -}}
|
||||
true
|
||||
{{- end -}}
|
||||
+1
-4
@@ -25,10 +25,7 @@
|
||||
</footer>
|
||||
</article>
|
||||
|
||||
{{- $tocCfg := site.Params.toc | default dict -}}
|
||||
{{- $tocEnabled := $tocCfg.enable | default true -}}
|
||||
{{- $tocMin := $tocCfg.minWordCount | default 400 -}}
|
||||
{{- if and $tocEnabled (gt .WordCount $tocMin) (ne .Params.toc false) }}
|
||||
{{- if partial "toc-enabled.html" . }}
|
||||
{{ partial "toc.html" . }}
|
||||
{{- end }}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user