Skip to content

feat(community): add a Community page and link it from the main menu - #637

Merged
Timur Tukaev (tym83) merged 2 commits into
mainfrom
feat/community-page
Aug 10, 2026
Merged

feat(community): add a Community page and link it from the main menu#637
Timur Tukaev (tym83) merged 2 commits into
mainfrom
feat/community-page

Conversation

@tym83

@tym83 Timur Tukaev (tym83) commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

cozystack.io/community returned 404, and nothing on the site pointed at the
community meeting, its recordings, or the contributor path. From the website
alone a visitor could not learn that public community calls happen at all —
they have been running every two weeks since April 2024.

What

  • content/en/community.md — chat channels, the community meeting (schedule,
    Zoom link, calendar, link to the archive), contributor entry points, the
    governance documents, and the four YouTube playlists.
  • hugo.yaml — a Community entry in the main menu at weight 30, so it lands
    between Blog and OSS Health.
  • content/en/.gitignore — dropped the community.md line.

Why the .gitignore change

That file has been ignoring community.md, contributing.md, governance.md
and security.md under an # Imported comment, but nothing in the tree imports
them: no hack/ script, Makefile target or workflow references any of those
names. The rule only prevented the page from being committed. Only the
community.md line is removed — the other three are left alone in case they
belong to a plan I am not aware of.

Preview

Verified locally: the page renders, the menu entry appears in the expected
position, and the ref to the Developer Guide resolves.

Note for whoever builds locally — hugo newer than the pinned 0.160.1 fails on
this repo before reaching any of these changes, with
access denied: "text/html" is not whitelisted in policy "security.allowContent"
on content/<lang>/_index.html. That reproduces on a clean main too, so it is
unrelated to this PR, but it does mean the pinned version is now effectively
mandatory rather than advisory.

Localisation

Only the English page is added; the translation pipeline owns the other locales.

Summary by CodeRabbit

  • New Features
    • Added a public Community page with communication channels, meeting details, contribution resources, governance information, and video playlists.
    • Added the Community page to the main site navigation for easier access.

@netlify

netlify Bot commented Aug 3, 2026

Copy link
Copy Markdown

Deploy Preview for cozystack ready!

Name Link
🔨 Latest commit 5a4783d
🔍 Latest deploy log https://app.netlify.com/projects/cozystack/deploys/6a79dc4dcfb5e800089a532a
😎 Deploy Preview https://deploy-preview-637--cozystack.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Added an English Community page with communication channels, meeting details, contribution resources, governance references, and video links. Added the page to the main navigation and removed it from the imported-content ignore list.

Changes

Community page

Layer / File(s) Summary
Publish Community page
content/en/community.md, hugo.yaml
The new page documents community channels, meetings, contribution resources, governance references, and media links. The main navigation links to /community/ with weight 30.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Suggested reviewers: kvaps

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main changes: adding a Community page and linking it from the main menu.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/community-page

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

cozystack.io had no community page: /community/ returned 404, and nothing on
the site pointed at the community meeting, its two years of recordings, or the
contributor path. A visitor could not find out that public calls happen at all.

The page collects the chat channels, the meeting (schedule, joining link,
calendar, archive), the contributor entry points, the governance documents and
the video playlists. It links to cozystack/community, which now holds the
meeting archive and the onboarding guide.

content/en/.gitignore has been ignoring community.md under an "# Imported"
comment, but no import mechanism exists anywhere in the tree — no hack script,
Makefile target or workflow references it. The rule only prevented the page
from being added, so drop that one line and keep the rest untouched.

Signed-off-by: Timur Tukaev <timur.tukaev@aenix.io>

Signed-off-by: tym83 <6355522@gmail.com>
@IvanHunters

Copy link
Copy Markdown
Contributor

The core justification checks out: content/en/.gitignore ignores those four files under # Imported, and nothing in the tree actually imports them (every hack/ script, the Makefile and the workflows only write into content/en/docs/ and static/; the only hits for those names elsewhere are external links to the cozystack repo). Dropping the community.md line is safe. The {{% ref "/docs/v1.6/development" %}} target exists and type: "page" has a layout.

Two small things:

  1. weight: 30 on the Community menu entry collides with Blog, which is also weight: 30 (content/en/blog/_index.md:6). "Between Blog and OSS Health" only holds via Hugo's alphabetical tie-break, so give it a distinct weight (e.g. 32). Note also that Blog's menu entry is front-matter-defined and English-only, while this hugo.yaml entry appears on every locale, where Community's neighbour will be GitHub rather than Blog.
  2. The "hugo newer than 0.160.1 fails ... the pinned version is now effectively mandatory" note in the description is stale after the rebase: main pins 0.164.0 (netlify.toml:6, .github/workflows/hugo.yaml:35) and the landing pages are markdown. Worth dropping so it does not mislead.

Signed-off-by: tym83 <6355522@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@content/en/community.md`:
- Around line 25-27: Update the Community meeting section in the community
content to expose the meetings anchor expected by the homepage, either by adding
a hidden meetings anchor before the heading or by changing the homepage link to
target the generated community-meeting ID; keep the existing section heading and
link behavior consistent.

In `@hugo.yaml`:
- Around line 325-327: Update the Community menu entry in the Hugo menu
configuration so it remains English-only when no translated community page
exists, avoiding locale-prefixed URLs generated through relLangURL on
non-English sites. Use the project’s translation-aware menu expression or
English fallback handling while preserving the existing Community label and
weight.
- Around line 325-327: Update the Community menu entry’s weight in hugo.yaml to
an unused value that preserves its intended ordering relative to the other menu
entries, avoiding the duplicate weight used by Blog.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c1f93fca-89b3-4d59-8fd7-32802bc372b5

📥 Commits

Reviewing files that changed from the base of the PR and between 5594a23 and 5a4783d.

📒 Files selected for processing (3)
  • content/en/.gitignore
  • content/en/community.md
  • hugo.yaml
💤 Files with no reviewable changes (1)
  • content/en/.gitignore

Comment thread content/en/community.md
Comment on lines +25 to +27
## Community meeting

The community meeting runs **every second Thursday at 18:00 CET** and is open to everyone. Releases, design proposals and open questions are discussed there, and new attendees are invited to introduce themselves at the start.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== locate relevant files ==="
git ls-files | rg '(^|/)content/en/community\.md$|layouts/shortcodes/home/calendar\.html$|^config|archetypes|themes' | sed -n '1,120p'

echo
echo "=== community.md excerpt ==="
if [ -f content/en/community.md ]; then
  nl -ba content/en/community.md | sed -n '1,70p'
fi

echo
echo "=== calendar.html excerpt ==="
if [ -f layouts/shortcodes/home/calendar.html ]; then
  nl -ba layouts/shortcodes/home/calendar.html | sed -n '1,90p'
fi

echo
echo "=== search for /community/#meetings and heading id variants ==="
rg -n 'community/#meetings|id=["'\'']meetings|/community/|community meeting|<a |anchor|slug|title:' layout layouts content -S || true

Repository: cozystack/website

Length of output: 346


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== community.md excerpt ==="
if [ -f content/en/community.md ]; then
  awk '{printf "%5d\t%s\n", NR, $0}' content/en/community.md | sed -n '51,75l'
fi

echo
echo "=== calendar.html excerpt ==="
if [ -f layouts/shortcodes/home/calendar.html ]; then
  awk '{printf "%5d\t%s\n", NR, $0}' layouts/shortcodes/home/calendar.html | sed -n '25,40l'
fi

echo
echo "=== search for homepage calendar anchor and community page anchors/headings ==="
rg -n 'community/#meetings|href=.*community|id=["'\'']meetings|community meeting|<h[1-6]id|id=' layouts content -S || true

Repository: cozystack/website

Length of output: 50373


🌐 Web query:

Hugo Goldmark anchors heading IDs replace spaces with hyphens lowercase

💡 Result:

Hugo, which uses the Goldmark Markdown parser by default, automatically generates heading IDs by converting heading text into a "slug" [1]. This process typically involves lowercasing the text, stripping punctuation, and replacing spaces with hyphens [1][2][3]. In Goldmark, the exact behavior of this ID generation is controlled by the parser.autoIDType configuration setting [4][5]. The default behavior matches GitHub's slugification algorithm [1][6][5]. Key configuration details: The autoHeadingID setting must be true (which is the default) to enable automatic ID generation [4][7][6]. The autoIDType setting determines the strategy used [4][5]. The available options include: github: The default, which produces GitHub-compatible ID attributes [4][6][5]. github-ascii: Similar to github, but drops any non-ASCII characters after accent normalization [5]. blackfriday: Mimics the behavior of the older Blackfriday renderer [5]. Since version 0.60.0, Goldmark has been the default parser in Hugo [8][1]. While earlier versions (using Blackfriday) handled punctuation and spaces differently, the current Goldmark-based system focuses on GitHub compatibility, where spaces are replaced by hyphens and most punctuation is stripped [8][1][2]. If you encounter issues with trailing dashes or unexpected formatting, it is often due to trailing spaces or specific punctuation in the source heading text, which Hugo's developers have addressed in various updates to ensure cleaner slug generation [9].

Citations:


Define the meetings anchor used by the homepage.

layouts/shortcodes/home/calendar.html links to /community/#meetings, but content/en/community.md uses ## Community meeting, which generates community-meeting. Add a hidden meetings anchor before the heading or update the link to the generated heading ID.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@content/en/community.md` around lines 25 - 27, Update the Community meeting
section in the community content to expose the meetings anchor expected by the
homepage, either by adding a hidden meetings anchor before the heading or by
changing the homepage link to target the generated community-meeting ID; keep
the existing section heading and link behavior consistent.

Comment thread hugo.yaml
Comment on lines +325 to +327
- name: Community
url: /community/
weight: 30

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

fd -t f 'community\.md$' content
rg -n 'url: /community/|relLangURL' hugo.yaml layouts/partials/navbar.html

Repository: cozystack/website

Length of output: 582


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== hugo.yaml language/menu/version config =="
sed -n '1,80p' hugo.yaml
sed -n '300,340p' hugo.yaml

echo
echo "== layouts/partials/navbar.html relevant section =="
sed -n '40,75p' layouts/partials/navbar.html

echo
echo "== content tree summary =="
find content -maxdir 3 -type f | sort | sed 's#^./##' | head -120

echo
echo "== site configuration references =="
rg -n 'DefaultContentLanguage|languages:|baseURL|params:|paramsVersions|Community|community' hugo.yaml config.toml config.yaml config/_default 2>/dev/null || true

echo
echo "== community page front matter =="
sed -n '1,160p' content/en/community.md

Repository: cozystack/website

Length of output: 5839


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== content tree summary =="
find content -maxdepth 3 -type f | sort | sed 's#^./##' | head -200

echo
echo "== i18n translation keys =="
find i18n -maxdepth 3 -type f -print | sort
for f in $(find i18n -maxdepth 3 -type f -print | sort); do
  echo "--- $f"
  sed -n '1,80p' "$f"
done

echo
echo "== all content/community references =="
rg -n '^---$|content/community|community\.md|community|Community' content i18n hugo.yaml -S

Repository: cozystack/website

Length of output: 50374


🌐 Web query:

HUGO documentation relLangURL menu item URL no corresponding page translated content

💡 Result:

In Hugo, using relLangURL on menu item URLs can lead to broken links or incorrect language prefixes when the target page does not exist in the current language [1][2]. Hugo functions like relLangURL or absLangURL are designed to prepend the language prefix to a path regardless of whether a translated version of that specific page exists [3][1]. To handle menu links that should only point to translated content or fall back gracefully, consider the following best practices: 1. Use pageRef: If you define your menu entries in your site configuration, use pageRef instead of url [1]. Page references automatically resolve to the correct, language-relative path based on the available content, avoiding the manual need for relLangURL [1]. 2. Conditional Template Logic: If you must manage these links manually or use custom logic, you can check for the page's existence before rendering the link [1][2]. For instance, you can use.Site.GetPage to verify if the page exists for the current language context [1][2]. Example logic for templates: {{ with.Page }} {{.RelPermalink }} {{ else }} {{.URL | relLangURL }} {{ end }} By leveraging the.Page object associated with the menu entry (if available), you ensure that Hugo provides the specific URL for that page in the current language context, rather than blindly prepending a language prefix to a static string [1]. Avoid applying relLangURL to URLs that already contain language-specific paths or are derived from existing page objects, as this often leads to double-prefixing or incorrect routing [1][4].

Citations:


Keep the Community menu link limited to English.

content/en/community.md is the only source page, and layouts/partials/navbar.html renders the community menu item through .URL | relLangURL. This can add locale prefixes on non-English sites when no translated community.md exists. Use a translation-aware menu expression for this link, keep it English-only until translations exist, or add English fallback handling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@hugo.yaml` around lines 325 - 327, Update the Community menu entry in the
Hugo menu configuration so it remains English-only when no translated community
page exists, avoiding locale-prefixed URLs generated through relLangURL on
non-English sites. Use the project’s translation-aware menu expression or
English fallback handling while preserving the existing Community label and
weight.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== hugo.yaml relevant sections =="
python3 - <<'PY'
from pathlib import Path
p=Path('hugo.yaml')
text=p.read_text()
for i,line in enumerate(text.splitlines(),1):
    if 'menu:' in line or (300 <= i <= 340):
        print(f"{i:4}: {line}")
PY

echo
echo "== locate navbar and search Community/Blog menu entries =="
rg -n "Community|Blog|relLangURL|i18n|languages|sectionName|weight:" hugo.yaml layouts .github 2>/dev/null | head -200

echo
echo "== git diff stat and summary for hugo.yaml =="
git diff --stat -- hugo.yaml || true
git diff --unified=80 -- hugo.yaml || true

Repository: cozystack/website

Length of output: 4307


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Hugo-related config files =="
git ls-files | rg '(^|/)(hugo\.toml|hugo\.yaml|hugo\.toml\.base\.yaml|hugo\.base\.yaml|hugo\.toml\.example|hugo\.example\.yaml)$|(^|/)hugo\.config.*' || true

echo
echo "== Search all git-tracked config for Blog menu ==
rg -n "name:\s*Blog|identifier:\s*blog|/blog|weight: 30|Community" . --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' | head -200

Repository: cozystack/website

Length of output: 314


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Search all git-tracked config for Blog menu =="
rg -n "name:\s*Blog|identifier:\s*blog|/blog|weight: 30|Community" . --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' | head -250

echo
echo "== Hugo config file sizes =="
wc -l hugo.yaml config/production/hugo.yaml .github/workflows/hugo.yaml 2>/dev/null || true

echo
echo "== hugo.yaml menu/head sections summary =="
python3 - <<'PY'
from pathlib import Path
for p in ['hugo.yaml','config/production/hugo.yaml','.github/workflows/hugo.yaml']:
    pp=Path(p)
    print(f"\n--- {p} exists={pp.exists()} ---")
    if not pp.exists(): continue
    for i,line in enumerate(pp.read_text().splitlines(),1):
        if 1 <= i <= 180 or 'menu:' in line or 'sectionName' in line or i>250:
            if ('sectionName' in line or 'url:' in line or 'name:' in line or 'weight:' in line or i<10 or i>280) in line:
                print(f"{i:4}: {line}")
PY

echo
echo "== Static files matching community/blog =="
git ls-files | rg '(^|/)(content/i18n|content|archetypes)/.*\.(md|json|toml|yaml)$|(^|/)layouts/partials/navbar\.html$' | xargs -r rg -n "Community|Blog|sectionName|/community|/blog|url:|weight:" 2>/dev/null | head -250

Repository: cozystack/website

Length of output: 41857


🌐 Web query:

Hugo menu entry duplicate weights tie-breaker order

💡 Result:

In Hugo, when menu entries share the same weight, the default sorting mechanism uses a specific tie-breaker sequence [1][2]. The menu entries are sorted by weight, then by name, and finally by identifier [1][2]. The precise logic implemented in Hugo's core is as follows [2]: 1. Weight: Entries are sorted by their defined weight value (ascending) [1][2]. 2. Name: If the weights are equal, entries are sorted by their Name (alphabetically) [1][2]. 3. Identifier: If both the weights and names are equal, entries are sorted by their Identifier (alphabetically) [1][2]. This order is standard for the default.ByWeight method [1]. If you need to avoid specific conflicts or force a particular order, ensure that your menu entries have unique identifiers assigned, as the identifier acts as the final tie-breaker [1][3][4]. Using an identifier is also required when multiple entries share the same name [1][3][5].

Citations:


🌐 Web query:

GitHub gohugoio/hugo menu.go byWeight Weight Name Identifier sort logic

💡 Result:

In Hugo, the default sort logic for menu entries—implemented in navigation/menu.go—prioritizes weight, then name, and finally the identifier [1][2][3]. The sorting is handled by the defaultMenuEntrySort function, which dictates the order in which menu entries appear when using the ByWeight method [1]. The logic is defined as follows: 1. Weight: Hugo first compares the Weight of two entries [1][4]. - If one entry has a Weight of 0 and the other does not, the entry with the non-zero Weight is prioritized (meaning it floats to the top if it is a lower positive integer, while 0-weighted items are treated as heavier/lower priority in this specific comparison logic) [1]. - If both have the same Weight, the sort proceeds to the next criteria [1]. 2. Name: If the Weights are equal, the entries are compared by their Name property using string comparison [1][4]. 3. Identifier: If both the Weight and Name are identical, the entries are finally sorted by their Identifier [1][2]. This stable sort ensures a predictable menu structure [1][4]. The Identifier is used as a fallback tie-breaker when Name is not sufficient to distinguish entries, which is particularly relevant when multiple menu items share the same display name [2][5].

Citations:


Use a unique menu weight for Community.

Community uses weight 30, which is also used by the Blog section front matter. Hugo falls back on the entry name when weights match, so menu position is not fixed by this config. Assign an unused weight that matches the intended order.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@hugo.yaml` around lines 325 - 327, Update the Community menu entry’s weight
in hugo.yaml to an unused value that preserves its intended ordering relative to
the other menu entries, avoiding the duplicate weight used by Blog.

@tym83
Timur Tukaev (tym83) merged commit 1e21c76 into main Aug 10, 2026
6 of 7 checks passed
@tym83
Timur Tukaev (tym83) deleted the feat/community-page branch August 10, 2026 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants