github.com/kyleu/dbaudit@v0.0.2-0.20240321155047-ff2f2c940496/app/controller/cmenu/docs.go (about) 1 // Package cmenu - Content managed by Project Forge, see [projectforge.md] for details. 2 package cmenu 3 4 import ( 5 "cmp" 6 "io/fs" 7 "path" 8 "slices" 9 "strings" 10 11 "github.com/samber/lo" 12 13 "github.com/kyleu/dbaudit/app/lib/menu" 14 "github.com/kyleu/dbaudit/app/util" 15 "github.com/kyleu/dbaudit/doc" 16 ) 17 18 var docMenuCached *menu.Item 19 20 func docMenu(logger util.Logger) *menu.Item { 21 if docMenuCached == nil { 22 docMenuCached = docMenuCreate(logger) 23 } 24 return docMenuCached 25 } 26 27 func docMenuCreate(logger util.Logger) *menu.Item { 28 var paths []string 29 err := fs.WalkDir(doc.FS, ".", func(path string, _ fs.DirEntry, err error) error { 30 paths = append(paths, path) 31 return err 32 }) 33 if err != nil { 34 logger.Errorf("unable to build documentation menu: %+v", err) 35 } 36 slices.Sort(paths) 37 38 ret := &menu.Item{Key: "docs", Title: "Documentation", Icon: "folder"} 39 for _, p := range paths { 40 if p == "." || strings.HasPrefix(p, "module/") || !strings.HasSuffix(p, util.ExtMarkdown) { 41 continue 42 } 43 split := util.StringSplitAndTrim(p, "/") 44 p = strings.TrimSuffix(p, util.ExtMarkdown) 45 mi := ret 46 lo.ForEach(split, func(comp string, idx int) { 47 name := strings.TrimSuffix(comp, util.ExtMarkdown) 48 addFolder := func() { 49 i := &menu.Item{Key: name, Title: util.StringToCamel(name), Icon: "folder"} 50 mi.Children = append(mi.Children, i) 51 slices.SortFunc(mi.Children, func(l *menu.Item, r *menu.Item) int { 52 return cmp.Compare(l.Title, r.Title) 53 }) 54 mi = i 55 } 56 if idx == len(split)-1 { 57 if strings.HasSuffix(comp, util.ExtMarkdown) { 58 mi.Children = append(mi.Children, addChild(p, name)) 59 } else { 60 addFolder() 61 } 62 } else { 63 if kid := mi.Children.Get(comp); kid == nil { 64 addFolder() 65 } else { 66 mi = kid 67 } 68 } 69 }) 70 } 71 slices.SortFunc(ret.Children, func(l *menu.Item, r *menu.Item) int { 72 return cmp.Compare(l.Title, r.Title) 73 }) 74 75 return ret 76 } 77 78 func addChild(p string, name string) *menu.Item { 79 r := "/" + path.Join("docs", p) 80 title := util.StringToCamel(name) 81 b, err := doc.FS.ReadFile(p + util.ExtMarkdown) 82 if err != nil { 83 panic(err) 84 } 85 86 lines := util.StringSplitLines(string(b)) 87 for _, line := range lines { 88 if strings.HasPrefix(line, "#") { 89 for strings.HasPrefix(line, "#") { 90 line = line[1:] 91 } 92 title = strings.TrimSpace(line) 93 break 94 } 95 } 96 97 return &menu.Item{Key: name, Title: title, Icon: "file", Route: r} 98 }