Files
tsuki/docs/customization.md
T
tiennm99 10a71228ea docs: v0.3.0 sync — CHANGELOG, accessibility statement, plan close-out
- README: add a11y badge linking to docs/accessibility.md.
- CHANGELOG: full v0.3.0 entry under Unreleased (Added/Changed/Fixed/
  Deferred-to-v0.3.1). Documents per-kind CSS bundles, Tier A
  features, Lighthouse-relevant polish, contrast-token visual diff,
  tap-target sizing decisions, and Hugo CI matrix.
- docs/accessibility.md: new — WCAG 2.2 AA conformance summary,
  Lighthouse measurement instructions, projected baseline (TBD entries
  to fill after first production deploy), known limitations.
- docs/customization.md: cover-image override snippet (v0.4.0 native
  pipeline promise); document breadcrumbs/prev-next/lang-switcher opt-ins.
- plans/260510-0144-tsuki-v0.3.0/: mark all phases completed; note
  narrow-TOC <details> deferral to v0.3.1; record audit-pass scope
  additions integrated into Phases 2–6.
- plans/reports/: add researcher-260515-tsuki-vs-stack-papermod-feature
  -gap.md (verdict: feature parity on must-haves; Tier A gaps shipped
  this round) + code-reviewer-260515-lighthouse-80-baseline-audit.md
  (projected ≥80 on all 4 categories; ≥95 a11y achievable with
  shipped fixes).
2026-05-15 18:56:12 +07:00

226 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Customization
Hugo's lookup order means **anything in your site overrides the theme**. No fork required.
## Override layouts and partials
Drop a file with the same path under your site's `layouts/` to replace the theme version.
```
your-site/
└── layouts/
├── _partials/
│ └── footer.html # overrides themes/tsuki/layouts/_partials/footer.html
└── single.html # overrides themes/tsuki/layouts/single.html
```
To extend rather than replace, copy the theme partial into your site, then modify. Common overrides:
- `_partials/footer.html` — add license, build info, web ring links
- `_partials/home/hero.html` — restructure the homepage hero
- `_partials/comments.html` — swap Giscus for a different provider
## Override design tokens
Tokens are CSS custom properties on `:root` and `:where([data-theme="dark"])`. Override them in a custom stylesheet without editing the theme.
```css
/* your-site/assets/css/custom.css */
:root {
--tsuki-accent: #cc7a3b; /* warmer accent */
--tsuki-font-sans: "Public Sans", system-ui, sans-serif;
--tsuki-content-width: 48rem; /* wider posts */
}
:where([data-theme="dark"]) {
--tsuki-accent: #f0a070;
}
```
Append it to the bundle by overriding `_partials/head.html`. Copy the theme version, add your file:
```go-html-template
{{- $cssFiles := slice
(resources.Get "css/tokens.css")
(resources.Get "css/reset.css")
...
(resources.Get "css/view-transitions.css")
(resources.Get "css/custom.css") {{/* your override, last in cascade */}}
-}}
```
## Add custom icons
Drop SVGs into `assets/icons/<name>.svg`, then reference by name:
```yaml
# data/profile.yaml
links:
- icon: bluesky
label: Bluesky
url: https://bsky.app/profile/...
```
Use `currentColor` for fill/stroke so icons inherit text color in light and dark modes:
```svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<path d="..."/>
</svg>
```
## Self-host fonts
The theme stack is `"Inter", "Be Vietnam Pro", system-ui, ...`. The first two fall back to system fonts when missing. To self-host:
1. Subset Be Vietnam Pro + Inter to `vietnamese,latin` ranges.
2. Drop the woff2 files into `static/fonts/`.
3. Add `@font-face` declarations in `assets/css/custom.css` (see "Override design tokens" above).
```css
@font-face {
font-family: "Inter";
src: url("/fonts/Inter-VariableFont_slnt,wght.woff2") format("woff2-variations");
font-weight: 100 900;
font-display: swap;
}
@font-face {
font-family: "Be Vietnam Pro";
src: url("/fonts/BeVietnamPro-Regular.woff2") format("woff2");
font-weight: 400;
font-display: swap;
}
```
## Override colors per-page
Set CSS variables inline via a frontmatter `style` you wire up yourself, or use the `body_class` block from `baseof.html`:
```html
<!-- layouts/section/work.html -->
{{ define "body_class" }}list section-work{{ end }}
```
Then style `body.section-work { --tsuki-accent: #...; }` in your custom CSS.
## Callouts (admonitions)
Use Hugo's native Markdown alert syntax (Hugo 0.140+) — no shortcode needed:
```markdown
> [!note]
> Useful side information.
> [!tip]
> Reader-friendly hint.
> [!important]
> Hard requirement.
> [!warning]
> Heads-up about a pitfall.
> [!caution]
> Risk of breakage.
```
Titles localize via `i18n/vi.yml` keys `calloutNote`, `calloutTip`, `calloutImportant`, `calloutWarning`, `calloutCaution`. Override per-callout with `> [!note] Custom title`.
Plain `> blockquote` still renders as the regular muted blockquote — only `[!type]` triggers callout styling.
**Override callout colors** in your custom CSS — each callout type exposes the `--tsuki-callout` and `--tsuki-callout-bg` tokens through its modifier class:
```css
/* your-site/assets/css/custom.css */
.callout-note { --tsuki-callout: #ff5d8f; --tsuki-callout-bg: #ff5d8f1f; }
```
## Show word count
Reading time is shown on every post by default. Add word count under it with:
```yaml
params:
showWordCount: true # default false
```
The byline reads `5 phút đọc · 1024 từ` (translated via the `wordCount` i18n key).
## Accessibility & SEO defaults
The theme includes accessibility features that require no configuration:
- **Skip-link** — first focusable element on every page; jumps to `<main id="main">` (WCAG 2.1 M3)
- **Focus rings** — visible outline via `--tsuki-accent` on `:focus-visible` for keyboard navigation
- **Lastmod byline** — shows "Cập nhật {date}" when modified date is ≥24h newer than publish date
- **Lazy-load images** — all in-content images get `loading="lazy" decoding="async"` via render hook
- **External link security** — all Markdown links to `http://` / `https://` / `//` get `rel="noopener noreferrer"` automatically
All of these are transparent — no override hooks needed unless you want to customize the markup.
## Disable features
Every interactive feature has a kill switch:
```yaml
params:
search:
enable: false # removes search button + /search/ route
comments:
giscus:
enable: false # comments partial becomes a no-op
```
Per-post:
```yaml
toc: false
comments: false
```
## Cover images
`cover.image` is currently used for OG / Twitter card metadata only — the theme does **not** render a hero cover above the post title by default. This avoids LCP regressions on themes with un-optimised consumer-supplied images.
To render a cover, override `layouts/single.html` in your site:
```hugo
{{ define "main" }}
{{ partial "breadcrumbs.html" . }}
<article class="post">
<header class="post-header">
{{- with .Params.cover.image }}
{{- /* Use Hugo image processing for a responsive, hashed asset */ -}}
{{- $img := resources.Get . | images.Resize "1200x" -}}
<img class="post-cover"
src="{{ $img.RelPermalink }}"
width="{{ $img.Width }}" height="{{ $img.Height }}"
alt="" fetchpriority="high" decoding="async">
{{- end }}
<h1 class="post-title">{{ .Title }}</h1>
{{ partial "meta.html" . }}
</header>
<div class="post-content" data-pagefind-body>{{ .Content }}</div>
</article>
{{ partial "prev-next.html" . }}
{{ partial "related-posts.html" . }}
{{ partial "comments.html" . }}
{{ end }}
```
A built-in cover pipeline with `srcset`/AVIF is planned for **v0.4.0**.
## Breadcrumbs, prev/next, language switcher
These ship in v0.3.0 as opt-in features.
```yaml
params:
breadcrumbs:
enable: true # Home Section Page trail + BreadcrumbList JSON-LD
prevNextNav:
enable: true # in-section prev/next post nav below content
```
The language switcher partial auto-emits when `hugo.IsMultilingual` is true; no config flag needed.