Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,12 @@ Docs are versioned per Cozystack minor release. Each version is an independent c
**Version registration (`hugo.yaml`)**
- `params.latest_version_id` — id of the current/default version
- `params.versions[]` — ordered list consumed by the version switcher (`layouts/partials/version-switcher.html`). Newest goes first, `order` highest. **When adding a new version, update both fields.**
- `params.versions_visible` — how many of the newest non-hidden versions (ranked by `order`, minimum 1) stay in the switcher, the `/docs/` table and the `/docs/` sidebar tree; the rest are grouped under "Older versions". `hack/register_version.sh` needs no change: a new release pushes the oldest visible version into the group on its own. The split lives in `layouts/partials/docs-versions.html`.
- `hidden: true` on a version entry hides it from the dropdown selector. Combined with the content mount exclusion pattern (`- '! docs/<id>/**'`), the whole version is also excluded from production builds. Used for the `next` trunk; the dev server and Netlify deploy previews still render it at `/docs/next/`.

**Where to add changes**
- Docs for an upcoming (unreleased) feature → edit `content/en/docs/next/`. These materialize as `v<next-release>/` when `make release-next RELEASE_TAG=vX.Y.Z` runs
- Bug fix or addition to the current release → edit only `content/en/docs/<latest_version_id>/` (currently `v1.2`)
- Bug fix or addition to the current release → edit only `content/en/docs/<latest_version_id>/` (the `params.latest_version_id` value in `hugo.yaml`)
- Content that also applies to older supported versions → copy the change into each relevant `v*/` directory (no automatic backport)
- Cross-version/landing content → `content/en/docs/_index.md`
- Blog posts are version-independent → `content/en/blog/`
Expand Down
11 changes: 6 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Use this decision table before you start editing:
| Your change is… | Edit here |
|---------------------------------------------------------------------|-------------------------------------------------|
| A doc for a **feature that ships in a future release** | `content/en/docs/next/` |
| A **bug fix** or addition **for the current release** | `content/en/docs/<latest_version_id>/` (`v1.2`) |
| A **bug fix** or addition **for the current release** | `content/en/docs/<latest_version_id>/` |
| A fix that also applies to an **older supported version** | Copy the change into each relevant `vX.Y/` |
| Cross-version content (the landing page, overview) | `content/en/docs/_index.md` |
| A **blog post** | `content/en/blog/` |
Expand Down Expand Up @@ -237,6 +237,7 @@ If you need to understand or change the versioning machinery itself:
- `hugo.yaml` — site-wide config; `params.versions[]` is the list of
registered versions (including `next` with `hidden: true`), and
`params.latest_version_id` is the current stable.
- `params.versions_visible` (in `hugo.yaml`) — how many of the newest released versions, ranked by `order` (minimum 1), stay in the version switcher, the `/docs/` table and the `/docs/` sidebar tree; the rest are grouped under "Older versions".
- `config/production/hugo.yaml` — production-only overrides; excludes
`docs/next/**` from GitHub Pages builds. Netlify deploy previews set
`HUGO_ENV=preview` so they skip this override.
Expand All @@ -250,10 +251,10 @@ If you need to understand or change the versioning machinery itself:
cozystack/cozystack.
- `hack/download_openapi.sh` — fetches `openapi.json` per version at build
time (v1.1+; v0 and v1.0 ship their `api.json` in-tree).
- `layouts/docs/docs-landing.html` — the `/docs/` landing template; builds the
version table from `params.versions[]`, filtering out hidden entries.
- `layouts/partials/version-switcher.html` — top-navbar version dropdown;
filters out hidden entries.
- `layouts/partials/docs-versions.html` — splits `params.versions[]` into the newest `params.versions_visible` released versions and the older rest, skipping hidden entries; shared by the three consumers below.
- `layouts/docs/docs-landing.html` — the `/docs/` landing template; builds the version table from that split, with the older versions in a collapsed block.
- `layouts/partials/version-switcher.html` — sidebar version dropdown; lists the recent versions and puts the older ones under an "Older versions" disclosure that is open when the current page belongs to one.
- `layouts/partials/sidebar-tree.html` — on `/docs/` it leaves out the roots of older versions.
- `layouts/404.html` — client-side fallback redirect for `/docs/v1/…` short
paths.

30 changes: 30 additions & 0 deletions assets/scss/blocks/_nav.scss
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,36 @@ nav.navbar {
}
}
}

// "Older versions" group: native <details>, no JS.
&__older {
summary {
cursor: pointer;
list-style: none;

&::-webkit-details-marker {
display: none;
}

// Same caret as .dropdown-toggle, flipped when the group is open.
&::after {
content: "";
float: right;
margin-top: 0.5em;
border-top: 0.3em solid;
border-right: 0.3em solid transparent;
border-left: 0.3em solid transparent;
}
}

&[open] > summary::after {
transform: rotate(180deg);
}

ul .dropdown-item {
padding-left: 1.75rem;
}
}
}

// Fixed-header offset.
Expand Down
3 changes: 3 additions & 0 deletions hugo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,9 @@ params:
version_menu: "Versions"
version_menu_pagelinks: true
latest_version_id: "v1.6"
# How many of the newest released versions stay in the version switcher and the
# /docs/ table; the rest go under "Older versions". Ranked by `order`; minimum 1.
versions_visible: 2
versions:
- version: "v1.6"
url: "/docs/v1.6/"
Expand Down
3 changes: 3 additions & 0 deletions i18n/de.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,6 @@ other = 'Einen Fehler entdeckt? <a href="{{ .IssueURL }}">Eröffnen Sie ein Issu

[translation_see_original]
other = 'Siehe das <a href="{{ .Link }}">englische Original</a>.'

[docs_older_versions]
other = "Ältere Versionen"
3 changes: 3 additions & 0 deletions i18n/en.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,6 @@ other = 'Spotted a mistake? <a href="{{ .IssueURL }}">Open an issue</a>.'

[translation_see_original]
other = 'See the <a href="{{ .Link }}">English original</a>.'

[docs_older_versions]
other = "Older versions"
3 changes: 3 additions & 0 deletions i18n/es.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,6 @@ other = "Caso de uso anterior"

[home_use_cases_next]
other = "Caso de uso siguiente"

[docs_older_versions]
other = "Versiones anteriores"
3 changes: 3 additions & 0 deletions i18n/hi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,6 @@ other = 'कोई त्रुटि मिली? <a href="{{ .IssueURL }}">Is

[translation_see_original]
other = '<a href="{{ .Link }}">अंग्रेज़ी मूल</a> देखें।'

[docs_older_versions]
other = "पुराने संस्करण"
3 changes: 3 additions & 0 deletions i18n/pt-br.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,6 @@ other = "Caso de uso anterior"

[home_use_cases_next]
other = "Próximo caso de uso"

[docs_older_versions]
other = "Versões anteriores"
3 changes: 3 additions & 0 deletions i18n/ru.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,6 @@ other = 'Нашли ошибку? <a href="{{ .IssueURL }}">Создайте iss

[translation_see_original]
other = 'Смотрите <a href="{{ .Link }}">английский оригинал</a>.'

[docs_older_versions]
other = "Старые версии"
3 changes: 3 additions & 0 deletions i18n/zh-cn.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,6 @@ other = '发现错误?<a href="{{ .IssueURL }}">提交 issue</a>。'

[translation_see_original]
other = '请参阅<a href="{{ .Link }}">英文原文</a>。'

[docs_older_versions]
other = "更早的版本"
57 changes: 34 additions & 23 deletions layouts/docs/docs-landing.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,40 @@ <h1>{{ .Title }}</h1>

{{ .Content }}

{{- $groups := partial "docs-versions.html" . -}}
<h3>{{ T "docs_landing_available_versions" }}</h3>
<table class="table">
<thead>
<tr>
<th>{{ T "docs_landing_col_version" }}</th>
<th>{{ T "docs_landing_col_status" }}</th>
</tr>
</thead>
<tbody>
{{- range .Site.Params.versions -}}
{{- if not .hidden -}}
{{- $isLatest := eq .id $latestID -}}
{{- $status := T "docs_landing_status_previous" -}}
{{- if $isLatest -}}
{{- $status = T "docs_landing_status_latest" -}}
{{- end -}}
<tr>
<td><a href="{{ .url }}">{{ .version }}</a></td>
<td>{{ $status }}</td>
</tr>
{{- end -}}
{{- end -}}
</tbody>
</table>
{{ template "versions-table" (dict "versions" $groups.recent "latestID" $latestID) }}
{{- with $groups.older }}
<details id="older-versions" class="mb-3">
<summary class="h5">{{ T "docs_older_versions" }} ({{ len . }})</summary>
{{ template "versions-table" (dict "versions" . "latestID" $latestID) }}
</details>
<script>
(function () {
var d = document.getElementById('older-versions');
if (d && location.hash === '#older-versions') d.open = true;
})();
</script>
{{- end }}
</div>
{{ end }}

{{ define "versions-table" }}
<table class="table">
<thead>
<tr>
<th>{{ T "docs_landing_col_version" }}</th>
<th>{{ T "docs_landing_col_status" }}</th>
</tr>
</thead>
<tbody>
{{- $latestID := .latestID -}}
{{- range .versions }}
<tr>
<td><a href="{{ .url }}">{{ .version }}</a></td>
<td>{{ if eq .id $latestID }}{{ T "docs_landing_status_latest" }}{{ else }}{{ T "docs_landing_status_previous" }}{{ end }}</td>
</tr>
{{- end }}
</tbody>
</table>
{{ end }}
19 changes: 19 additions & 0 deletions layouts/partials/docs-versions.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{{- /* Splits params.versions into the newest `versions_visible` released entries
and the rest. `hidden` entries (the `next` trunk) are in neither group.
Ranking uses `order`, which hack/register_version.sh assigns on release,
so a new release pushes the oldest visible version into "older" on its own.
Returns dict "recent" "older" (both slices of version entries, newest first). */ -}}
{{- $released := slice -}}
{{- range site.Params.versions -}}
{{- if not .hidden -}}
{{- $released = $released | append . -}}
{{- end -}}
{{- end -}}
{{- $sorted := sort $released "order" "desc" -}}
{{- /* `default 2` would turn an explicit 0 into 2; isset keeps it and max clamps it to 1. */ -}}
{{- $n := 2 -}}
{{- if isset site.Params "versions_visible" -}}
{{- $n = int site.Params.versions_visible -}}
{{- end -}}
{{- $n = int (math.Max 1 $n) -}}
{{- return dict "recent" (first $n $sorted) "older" (after $n $sorted) -}}
17 changes: 14 additions & 3 deletions layouts/partials/sidebar-tree.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,21 @@
{{- end -}}
{{- end -}}
{{- end -}}
{{- $hideRoots := slice -}}
{{- /* Never prune the version the page belongs to. .Path is the content path, so
this holds even when the prefix match above misses (subpath baseURL,
defaultContentLanguageInSubdir) and the tree is rooted at /docs/. */ -}}
{{- range (partial "docs-versions.html" .).older -}}
{{- $root := strings.TrimRight "/" .url -}}
{{- if not (or (eq $.Page.Path $root) (hasPrefix $.Page.Path (printf "%s/" $root))) -}}
{{- $hideRoots = $hideRoots | append $root -}}
{{- end -}}
{{- end -}}
{{ $ulNr := 0 -}}
{{ $ulShow := cond (isset .Site.Params.ui "ul_show") .Site.Params.ui.ul_show 1 -}}
{{ $sidebarMenuTruncate := cond (isset .Site.Params.ui "sidebar_menu_truncate") .Site.Params.ui.sidebar_menu_truncate 50 -}}
<ul class="td-sidebar-nav__section pr-md-3 ul-{{ $ulNr }}">
{{ template "section-tree-nav-section" (dict "page" . "section" $navRoot "shouldDelayActive" $shouldDelayActive "sidebarMenuTruncate" $sidebarMenuTruncate "ulNr" $ulNr "ulShow" (add $ulShow 1)) }}
{{ template "section-tree-nav-section" (dict "page" . "section" $navRoot "shouldDelayActive" $shouldDelayActive "sidebarMenuTruncate" $sidebarMenuTruncate "ulNr" $ulNr "ulShow" (add $ulShow 1) "hideRoots" $hideRoots) }}
</ul>
</nav>
</div>
Expand All @@ -51,6 +61,7 @@
{{ $treeRoot := cond (eq .ulNr 0) true false -}}
{{ $ulNr := .ulNr -}}
{{ $ulShow := .ulShow -}}
{{ $hideRoots := .hideRoots -}}
{{ $active := and (not $shouldDelayActive) (eq $s $p) -}}
{{ $activePath := and (not $shouldDelayActive) (or (eq $p $s) ($p.IsDescendant $s)) -}}
{{ $show := cond (or (lt $ulNr $ulShow) $activePath (and (not $shouldDelayActive) (eq $s.Parent $p.Parent)) (and (not $shouldDelayActive) (eq $s.Parent $p)) (not $p.Site.Params.ui.sidebar_menu_compact) (and (not $shouldDelayActive) ($p.IsDescendant $s.Parent))) true false -}}
Expand All @@ -71,8 +82,8 @@
{{- $ulNr := add $ulNr 1 }}
<ul class="ul-{{ $ulNr }}{{ if (gt $ulNr 1)}} foldable{{end}}">
{{ range $pages -}}
{{ if (not (and (eq $s $p.Site.Home) (eq .Params.toc_root true))) -}}
{{ template "section-tree-nav-section" (dict "page" $p "section" . "shouldDelayActive" $shouldDelayActive "sidebarMenuTruncate" $sidebarMenuTruncate "ulNr" $ulNr "ulShow" $ulShow) }}
{{ if and (not (and (eq $s $p.Site.Home) (eq .Params.toc_root true))) (not (in $hideRoots .Path)) -}}
{{ template "section-tree-nav-section" (dict "page" $p "section" . "shouldDelayActive" $shouldDelayActive "sidebarMenuTruncate" $sidebarMenuTruncate "ulNr" $ulNr "ulShow" $ulShow "hideRoots" $hideRoots) }}
{{- end }}
{{- end }}
</ul>
Expand Down
29 changes: 29 additions & 0 deletions layouts/partials/version-switcher-item.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{{- /* One dropdown entry. Context: dict "v" <version entry> "logicalPath"
(current page path without the language base) "currentID" "currentUrl".
Each target is the most specific page that is actually built, so no link
404s. The pipeline translates only the latest version, so most localized
pages and version roots never exist. Staying on the same topic matters more
than staying in the language, so the order is: English version root (always
built), localized version root, the same page in English, the same page
localized. site.GetPage resolves in the current-language site;
hugo.Sites.Default is the English site. */ -}}
{{- $v := .v -}}
{{- $targetPath := $v.url -}}
{{- with site.GetPage (strings.TrimRight "/" $v.url) -}}
{{- $targetPath = .RelPermalink -}}
{{- end -}}
{{- if .currentUrl -}}
{{- $subPath := strings.TrimPrefix .currentUrl .logicalPath -}}
{{- $trimmed := strings.TrimRight "/" (printf "%s%s" $v.url $subPath) -}}
{{- with hugo.Sites.Default.GetPage $trimmed -}}
{{- $targetPath = .RelPermalink -}}
{{- end -}}
{{- with site.GetPage $trimmed -}}
{{- $targetPath = .RelPermalink -}}
{{- end -}}
{{- end -}}
<li>
<a href="{{ $targetPath }}" class="dropdown-item{{ if eq $v.id .currentID }} active{{ end }}">
{{- $v.version -}}
</a>
</li>
45 changes: 17 additions & 28 deletions layouts/partials/version-switcher.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

<div class="version-switcher dropdown">
<button class="version-switcher__toggle dropdown-toggle" type="button"
id="versionSwitcherButton" data-bs-toggle="dropdown"
id="versionSwitcherButton" data-bs-toggle="dropdown" data-bs-auto-close="outside"
aria-expanded="false" aria-haspopup="true">
{{- if $currentVersionLabel -}}
{{ $currentVersionLabel }}
Expand All @@ -34,36 +34,25 @@
{{- end -}}
</button>
<ul class="version-switcher__menu dropdown-menu" aria-labelledby="versionSwitcherButton">
{{- range .Site.Params.versions }}
{{- if not .hidden }}
{{- /* Each target is the most specific page that is actually built, so no
link 404s. The pipeline translates only the latest version, so most
localized pages and version roots never exist. Staying on the same
topic matters more than staying in the language, so the order is:
English version root (always built), localized version root, the same
page in English, the same page localized. site.GetPage resolves in the
current-language site; hugo.Sites.Default is the English site. */ -}}
{{- $targetPath := .url -}}
{{- with site.GetPage (strings.TrimRight "/" .url) -}}
{{- $targetPath = .RelPermalink -}}
{{- end -}}
{{- if $currentVersionUrl -}}
{{- $subPath := strings.TrimPrefix $currentVersionUrl $logicalPath -}}
{{- $trimmed := strings.TrimRight "/" (printf "%s%s" .url $subPath) -}}
{{- with hugo.Sites.Default.GetPage $trimmed -}}
{{- $targetPath = .RelPermalink -}}
{{- end -}}
{{- with site.GetPage $trimmed -}}
{{- $targetPath = .RelPermalink -}}
{{- end -}}
{{- end -}}
{{- $groups := partial "docs-versions.html" . -}}
{{- $currentIsOlder := false -}}
{{- range $groups.older }}{{ if eq .id $currentVersionID }}{{ $currentIsOlder = true }}{{ end }}{{ end }}
{{- range $groups.recent }}
{{ partial "version-switcher-item.html" (dict "v" . "logicalPath" $logicalPath "currentID" $currentVersionID "currentUrl" $currentVersionUrl) }}
{{- end }}
{{- with $groups.older }}
<li><hr class="dropdown-divider"></li>
<li>
<a href="{{ $targetPath }}" class="dropdown-item{{ if eq .id $currentVersionID }} active{{ end }}">
{{- .version -}}
</a>
<details class="version-switcher__older"{{ if $currentIsOlder }} open{{ end }}>
<summary class="dropdown-item">{{ T "docs_older_versions" }}</summary>
<ul class="list-unstyled mb-0">
{{- range . }}
{{ partial "version-switcher-item.html" (dict "v" . "logicalPath" $logicalPath "currentID" $currentVersionID "currentUrl" $currentVersionUrl) }}
{{- end }}
</ul>
</details>
</li>
{{- end }}
{{- end }}
</ul>
</div>
{{- else if .Site.Params.versions -}}
Expand Down
Loading