Files
tiennm99 60c14917fb fix(ci): unbreak smoke + htmltest steps post v0.3.0
Three independent CI failures from run 25916500415:

1. Smoke test [linkToSection aria-label] fail on Hugo 0.146 leg.
   The assertion pinned to $post selected via `find ... | head -1`,
   which on 0.146 picked `doc-sach-quan-sat/index.html` — a post with
   zero h2/h3/h4 headings, so zero heading-anchor markup. Rewrite the
   check to scan all built post HTML (same pattern already in use for
   render-link rel). Now reports 13 matches on the demo build.

2. htmltest URLSwap silently never matched. The prior
   `^/tsuki/: /` config (added in d30f50f) used a regex anchor that
   doesn't match htmltest's substring evaluation against minified
   `href=/tsuki/...` attributes. Switch to the unanchored
   `"/tsuki/": /` form. CI has been failing on this since v0.2.0
   despite the "fix" commit; this is the real fix.

3. head.html referenced `/favicon.ico` and `/favicon.svg` but neither
   asset existed in exampleSite/static/. Add a minimal SVG favicon,
   drop the legacy .ico reference (modern browsers fall back to a
   site-rooted /favicon.ico by convention; sites needing one can
   override head.html). Switch the SVG link to `relURL` so the
   `/tsuki/` baseURL prefix is honoured under GitHub Pages subpath
   deploy.

Local validation: all 32 smoke checks green; favicon resolves to
`/tsuki/favicon.svg` and ships in the build artifact.
2026-05-15 20:18:26 +07:00

103 lines
4.2 KiB
HTML

{{- $title := cond .IsHome site.Title (printf "%s · %s" .Title site.Title) -}}
{{- $description := .Description | default .Summary | default site.Params.description | default site.Title | plainify -}}
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="generator" content="tsuki">
<meta name="theme-color" content="#fbfaf7" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#14151a" media="(prefers-color-scheme: dark)">
<title>{{ $title }}</title>
<meta name="description" content="{{ $description }}">
<link rel="canonical" href="{{ .Permalink }}">
{{/* Theme flash prevention — must run before <body> */}}
<script>
(function () {
try {
var stored = localStorage.getItem('tsuki-theme');
if (stored === 'dark' || stored === 'light') {
document.documentElement.setAttribute('data-theme', stored);
}
} catch (e) {}
})();
</script>
{{/* SEO: OpenGraph + Twitter Cards + JSON-LD Article */}}
{{ partial "head/seo.html" . }}
{{/* RSS autodiscovery */}}
{{- with .OutputFormats.Get "RSS" }}
<link rel="alternate" type="application/rss+xml" title="{{ site.Title }}" href="{{ .Permalink }}">
{{- end }}
{{/* hreflang alternates — emit only on multilingual sites */}}
{{- if hugo.IsMultilingual }}
{{- range .AllTranslations }}
<link rel="alternate" hreflang="{{ .Language.Lang }}" href="{{ .Permalink }}">
{{- end }}
{{- with site.Home }}<link rel="alternate" hreflang="x-default" href="{{ .Permalink }}">{{- end }}
{{- end }}
{{/* Pagination prev/next for SEO — only on paginated kinds with >1 page */}}
{{- if or (eq .Kind "section") (eq .Kind "taxonomy") (eq .Kind "term") }}
{{- with .Paginator }}
{{- if gt .TotalPages 1 }}
{{- if .HasPrev }}<link rel="prev" href="{{ .Prev.URL }}">{{ end }}
{{- if .HasNext }}<link rel="next" href="{{ .Next.URL }}">{{ end }}
{{- end }}
{{- end }}
{{- end }}
{{/* Favicon — SVG only; sites can override head.html to add an .ico fallback */}}
<link rel="icon" href="{{ "favicon.svg" | relURL }}" type="image/svg+xml">
{{/* Speculation Rules — Chromium prefetch hints; gated, off by default */}}
{{- $prefetch := site.Params.prefetch -}}
{{- if and $prefetch $prefetch.enable }}
<script type="speculationrules">
{{- with $prefetch.rules -}}{{ . | safeJS }}{{- else -}}
{"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":"/search/*"}}]},"eagerness":"moderate"}]}
{{- end -}}
</script>
{{- end }}
{{/* Preconnect to Giscus on comment-enabled posts to shave third-party DNS+TLS handshake */}}
{{- $giscusCfg := site.Params.comments.giscus -}}
{{- if and (eq .Kind "page") $giscusCfg $giscusCfg.enable $giscusCfg.repo $giscusCfg.repoId $giscusCfg.categoryId (ne .Params.comments false) }}
<link rel="preconnect" href="https://giscus.app" crossorigin>
{{- end }}
{{/* Theme CSS — per-page-kind bundles. Core loads everywhere; kind-specific bundles add only when needed. */}}
{{- $coreFiles := slice
(resources.Get "css/tokens.css")
(resources.Get "css/reset.css")
(resources.Get "css/typography.css")
(resources.Get "css/layout.css")
(resources.Get "css/components.css")
(resources.Get "css/view-transitions.css")
-}}
{{- $core := $coreFiles | resources.Concat "css/tsuki.core.css" | minify | fingerprint -}}
<link rel="stylesheet" href="{{ $core.RelPermalink }}" integrity="{{ $core.Data.Integrity }}" crossorigin="anonymous">
{{- if .IsHome }}
{{- $home := resources.Get "css/home.css" | minify | fingerprint -}}
<link rel="stylesheet" href="{{ $home.RelPermalink }}" integrity="{{ $home.Data.Integrity }}" crossorigin="anonymous">
{{- end }}
{{- if eq .Kind "page" }}
{{- $singleFiles := slice
(resources.Get "css/toc.css")
(resources.Get "css/callouts.css")
(resources.Get "css/comments.css")
(resources.Get "css/single-extras.css")
-}}
{{- $single := $singleFiles | resources.Concat "css/tsuki.single.css" | minify | fingerprint -}}
<link rel="stylesheet" href="{{ $single.RelPermalink }}" integrity="{{ $single.Data.Integrity }}" crossorigin="anonymous">
{{- end }}
{{- if eq .Section "archives" }}
{{- $archive := resources.Get "css/archive.css" | minify | fingerprint -}}
<link rel="stylesheet" href="{{ $archive.RelPermalink }}" integrity="{{ $archive.Data.Integrity }}" crossorigin="anonymous">
{{- end }}