Gitfed
bastien-mrq/gitfed/ Commits/ e800460

Show recent changelog entries on the homepage

The landing page now previews the latest 3 CHANGELOG.md version sections (rendered Markdown, reusing the same renderer as /changelog), with a link to the full changelog.

bastien-mrq 2026-07-29 08:46 commit e800460b8039aa2a57be93b8528eed58262d36f1 parent 751c99d5482953cd1757d600bdf7e14d56be5259
4 files changed +52 −3
M cmd/gitfed-web/handlers_landing.go +44 −3
M cmd/gitfed-web/render.go +4 −0
M internal/i18n/strings_en.go +2 −0
M internal/i18n/strings_fr.go +2 −0
cmd/gitfed-web/handlers_landing.go
diff --git a/cmd/gitfed-web/handlers_landing.go b/cmd/gitfed-web/handlers_landing.go index a4a1a85..d8ce72f 100644 --- a/cmd/gitfed-web/handlers_landing.go +++ b/cmd/gitfed-web/handlers_landing.go @@ -4,7 +4,9 @@ import ( "bytes" "html/template" "net/http" + "strings" + "gitfed" "gitfed/internal/i18n" ) @@ -68,6 +70,13 @@ var landingTpl = newTpl("landing", ` </div> </div> +<div class="changelog-preview"> + <div class="gf-page-head"><h2>{{t .Lang "landing.changelog_h"}}</h2><a class="see-all" href="/changelog">{{t .Lang "landing.changelog_link"}} {{icon "arrow"}}</a></div> + <div class="gf-card"> + <div class="gf-readme-body markdown-body">{{.ChangelogHTML}}</div> + </div> +</div> + <div class="cta-band"> <h2>{{t .Lang "landing.cta_band_h"}}</h2> <p>{{t .Lang "landing.cta_band_p"}}</p> @@ -82,14 +91,46 @@ var landingTpl = newTpl("landing", ` </div> `) +// recentChangelogEntriesCount caps the landing page's "recent updates" +// preview — the full history stays one click away at /changelog. +const recentChangelogEntriesCount = 3 + +// recentChangelogEntries returns the Markdown source of the first n "## " +// version sections from CHANGELOG.md (it lists newest first), dropping the +// leading "# Changelog" title. +func recentChangelogEntries(n int) string { + var out []string + sections := 0 + for _, l := range strings.Split(gitfed.Changelog, "\n") { + if strings.HasPrefix(l, "## ") { + sections++ + if sections > n { + break + } + } + if sections == 0 { + continue + } + out = append(out, l) + } + return strings.Join(out, "\n") +} + func (s *server) handleLanding(w http.ResponseWriter, r *http.Request) { lang := s.lang(r) _, loggedIn := s.currentSession(r) + changelogHTML, err := renderMarkdown(recentChangelogEntries(recentChangelogEntriesCount)) + if err != nil { + s.serverError(w, r, err) + return + } + var buf bytes.Buffer _ = landingTpl.Execute(&buf, struct { - Lang string - LoggedIn bool - }{string(lang), loggedIn}) + Lang string + LoggedIn bool + ChangelogHTML template.HTML + }{string(lang), loggedIn, changelogHTML}) s.render(w, r, i18n.T(lang, "landing.title"), "home", template.HTML(buf.String())) }
cmd/gitfed-web/render.go
diff --git a/cmd/gitfed-web/render.go b/cmd/gitfed-web/render.go index 6691b99..eb8b2e2 100644 --- a/cmd/gitfed-web/render.go +++ b/cmd/gitfed-web/render.go @@ -299,6 +299,10 @@ const shellHeadSrc = `<!doctype html> .fed-diagram { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 1.4rem; } .fed-diagram svg { width: 100%; height: auto; display: block; } + .changelog-preview { margin: 2.8rem 0; } + .changelog-preview .gf-page-head { margin-bottom: 1rem; } + .changelog-preview .see-all { color: var(--accent); text-decoration: none; font-size: 0.88rem; font-weight: 600; display: inline-flex; align-items: center; gap: 0.35rem; flex-shrink: 0; } + .cta-band { text-align: center; padding: 2.4rem 1.4rem; margin: 2.6rem 0 1rem; background: var(--surface); border: 1px solid var(--border); border-radius: 14px; } .cta-band h2 { font-size: 1.25rem; margin: 0 0 0.5rem; } .cta-band p { color: var(--text-dim); font-size: 0.9rem; margin: 0 0 1.2rem; }
internal/i18n/strings_en.go
diff --git a/internal/i18n/strings_en.go b/internal/i18n/strings_en.go index bb9deba..4c3faeb 100644 --- a/internal/i18n/strings_en.go +++ b/internal/i18n/strings_en.go @@ -62,6 +62,8 @@ var en = map[string]string{ "landing.cta_band_h": "Ready to take back control of your code?", "landing.cta_band_p": "Gitfed is open-source and self-hosted — one Go binary, one embedded database, no external dependencies.", "landing.cta_band_dashboard": "Go to your repos", + "landing.changelog_h": "Recent updates", + "landing.changelog_link": "Full changelog", // ---------- security ---------- "security.title": "Security",
internal/i18n/strings_fr.go
diff --git a/internal/i18n/strings_fr.go b/internal/i18n/strings_fr.go index a21f68c..6c1256c 100644 --- a/internal/i18n/strings_fr.go +++ b/internal/i18n/strings_fr.go @@ -62,6 +62,8 @@ var fr = map[string]string{ "landing.cta_band_h": "Envie de reprendre la main sur votre code ?", "landing.cta_band_p": "Gitfed est open-source et auto-hébergé — un binaire Go, une base embarquée, aucune dépendance externe.", "landing.cta_band_dashboard": "Aller à mes dépôts", + "landing.changelog_h": "Dernières mises à jour", + "landing.changelog_link": "Changelog complet", // ---------- security ---------- "security.title": "Sécurité",