From bfb4b53da330601bea4506b9be5229e5212632dc Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sun, 21 Jun 2026 11:00:18 -0500 Subject: [PATCH] feat: add folder-based tree sidebar to org wiki (#680) Replace flat page list with hierarchical folder tree in org wiki sidebar. _Sidebar.md takes precedence when present; otherwise auto-generates collapsible folder menus up to 2 levels deep. --- routers/web/org/wiki.go | 98 +++++++++++++++++++++++++++--------- templates/org/wiki/view.tmpl | 49 +++++++++++++----- 2 files changed, 110 insertions(+), 37 deletions(-) diff --git a/routers/web/org/wiki.go b/routers/web/org/wiki.go index dc76d34747..e6d76f08c3 100644 --- a/routers/web/org/wiki.go +++ b/routers/web/org/wiki.go @@ -29,6 +29,14 @@ type OrgWikiPage struct { SubURL string } +// OrgWikiTreeNode represents a node in the org wiki folder tree for sidebar navigation. +type OrgWikiTreeNode struct { + Name string + SubURL string + IsDir bool + Children []*OrgWikiTreeNode +} + // Wiki renders the org wiki tab. func Wiki(ctx *context.Context) { org := ctx.Org.Organization @@ -71,31 +79,9 @@ func Wiki(ctx *context.Context) { } ctx.Data["WikiRepoLink"] = wikiRepo.Link() - // Build page list from repo root. - entries, err := commit.ListEntries() - if err != nil { - ctx.ServerError("ListEntries", err) - return - } - pages := make([]OrgWikiPage, 0, len(entries)) - for _, entry := range entries { - if !entry.IsRegular() { - continue - } - name := entry.Name() - if !isMarkdownFile(name) { - continue - } - displayName := strings.TrimSuffix(name, path.Ext(name)) - if strings.EqualFold(displayName, "_sidebar") || strings.EqualFold(displayName, "_footer") { - continue - } - pages = append(pages, OrgWikiPage{ - Name: displayName, - SubURL: displayName, - }) - } - ctx.Data["Pages"] = pages + // Build folder tree for sidebar navigation. + wikiTree := buildOrgWikiTree(commit) + ctx.Data["WikiTree"] = wikiTree // Determine which page to render. pageName := ctx.PathParamRaw("*") @@ -157,6 +143,68 @@ func Wiki(ctx *context.Context) { ctx.HTML(http.StatusOK, tplOrgWiki) } +// buildOrgWikiTree builds a hierarchical folder tree from the org wiki git repo. +// Shows up to 2 levels deep (folders and their immediate children). +func buildOrgWikiTree(commit *git.Commit) []*OrgWikiTreeNode { + if commit == nil { + return nil + } + entries, err := commit.ListEntries() + if err != nil { + return nil + } + + var topLevel []*OrgWikiTreeNode + + for _, entry := range entries { + name := entry.Name() + if entry.IsDir() { + node := &OrgWikiTreeNode{ + Name: name, + SubURL: name, + IsDir: true, + } + // List children of this directory (1 level deep). + subTree := entry.Tree() + if subTree != nil { + children, _ := subTree.ListEntries() + for _, child := range children { + childName := child.Name() + if child.IsDir() { + node.Children = append(node.Children, &OrgWikiTreeNode{ + Name: childName, + SubURL: name + "/" + childName, + IsDir: true, + }) + } else if isMarkdownFile(childName) { + displayName := strings.TrimSuffix(childName, path.Ext(childName)) + if strings.EqualFold(displayName, "_sidebar") || strings.EqualFold(displayName, "_footer") { + continue + } + node.Children = append(node.Children, &OrgWikiTreeNode{ + Name: displayName, + SubURL: name + "/" + displayName, + IsDir: false, + }) + } + } + } + topLevel = append(topLevel, node) + } else if isMarkdownFile(name) { + displayName := strings.TrimSuffix(name, path.Ext(name)) + if strings.EqualFold(displayName, "_sidebar") || strings.EqualFold(displayName, "_footer") { + continue + } + topLevel = append(topLevel, &OrgWikiTreeNode{ + Name: displayName, + SubURL: displayName, + IsDir: false, + }) + } + } + return topLevel +} + // findOrgWikiCommit locates the profile repo's wiki and returns its HEAD commit. // The org wiki lives in the .wiki.git sidecar of the profile repo (e.g. .mokogitea.wiki.git). // Tries fallback repo names (.profile, .github) if the primary doesn't exist. diff --git a/templates/org/wiki/view.tmpl b/templates/org/wiki/view.tmpl index d55bdbed9c..de4020fb3f 100644 --- a/templates/org/wiki/view.tmpl +++ b/templates/org/wiki/view.tmpl @@ -11,7 +11,7 @@ This organization doesn't have a wiki yet.

- Enable the wiki on the .profile (public) or .profile-private (members-only) + Enable the wiki on the .mokogitea (public) or .mokogitea-private (members-only) repository to get started.

@@ -47,34 +47,59 @@

The page "{{.CurrentPage}}" does not exist in this wiki.

- {{if .Pages}} + {{if .WikiTree}}

Available pages:

{{end}} {{else}}
-
+
{{.WikiContent}}
- {{if or .WikiSidebarHTML .Pages}} + {{if or .WikiSidebarHTML .WikiTree}}