diff --git a/internal/docs/navigation.go b/internal/docs/navigation.go index 299ea528..640f33ed 100644 --- a/internal/docs/navigation.go +++ b/internal/docs/navigation.go @@ -20,6 +20,8 @@ var sectionOrder = []struct { }{ {Title: "Getting Started", Icon: "book-open"}, {Title: "User Guide", Icon: "book"}, + {Title: "Devices", Icon: "device"}, + {Title: "Administration", Icon: "shield"}, {Title: "API Reference", Icon: "list"}, {Title: "Developer", Icon: "gear"}, {Title: "Operations", Icon: "database"}, @@ -90,18 +92,20 @@ func placeDoc(docPath string) navPlacement { case strings.HasPrefix(docPath, "user/"): rest := strings.TrimPrefix(docPath, "user/") if dir, _, ok := strings.Cut(rest, "/"); ok { - // Subdirectories become subcategories: device setup gets its - // own group, the admin-facing guides another. + // Device setup guides get their own top-level section (the + // directory stays where it is — placement is nav-only, same + // carve-out as developer/api → API Reference). if dir == "devices" { - return navPlacement{section: "User Guide", group: "Devices", pin: pin} + return navPlacement{section: "Devices", pin: pin} } return navPlacement{section: "User Guide", group: titleCase(dir), pin: pin} } if rest == "user-guide.md" { return navPlacement{section: "User Guide", pin: -50} } + // Admin-facing guides are their own top-level section too. if strings.HasPrefix(rest, "admin-") { - return navPlacement{section: "User Guide", group: "Administration"} + return navPlacement{section: "Administration"} } return navPlacement{section: "User Guide"} diff --git a/internal/docs/navigation_test.go b/internal/docs/navigation_test.go index 6583db83..09aacc96 100644 --- a/internal/docs/navigation_test.go +++ b/internal/docs/navigation_test.go @@ -4,8 +4,6 @@ import ( "os" "path/filepath" "testing" - - "bookhoard/templates" ) func TestPlaceDoc(t *testing.T) { @@ -18,8 +16,8 @@ func TestPlaceDoc(t *testing.T) { {"index.md", "Getting Started", "", true}, {"user/user-guide.md", "User Guide", "", true}, {"user/dashboard.md", "User Guide", "", false}, - {"user/admin-guide.md", "User Guide", "Administration", false}, - {"user/devices/kobo-setup.md", "User Guide", "Devices", false}, + {"user/admin-guide.md", "Administration", "", false}, + {"user/devices/kobo-setup.md", "Devices", "", false}, {"developer/api/api-reference.md", "API Reference", "", true}, {"developer/api/dashboard.md", "API Reference", "", false}, {"developer/api/authentication/login.md", "API Reference", "Authentication", false}, @@ -119,7 +117,7 @@ func TestBuildNavigation(t *testing.T) { t.Fatal("no sections built") } - wantOrder := []string{"Getting Started", "User Guide", "API Reference", "Developer", "Operations", "Contributing"} + wantOrder := []string{"Getting Started", "User Guide", "Devices", "Administration", "API Reference", "Developer", "Operations", "Contributing"} for i, want := range wantOrder { if nav.Sections[i].Title != want { t.Fatalf("section %d = %q, want %q", i, nav.Sections[i].Title, want) @@ -134,38 +132,40 @@ func TestBuildNavigation(t *testing.T) { t.Errorf("Getting Started items = %+v, want single Overview → /docs", getting.Items) } + // User Guide no longer contains the current page (device guides are + // their own section now): collapsed, no groups. userGuide := nav.Sections[1] - if userGuide.Collapsed { - t.Error("User Guide should be expanded: it contains the current page") + if !userGuide.Collapsed { + t.Error("User Guide should be collapsed: it no longer contains the current page") + } + if len(userGuide.Groups) != 0 { + t.Errorf("User Guide groups = %+v, want none (Devices + Administration carved out)", userGuide.Groups) } if len(userGuide.Items) != 2 || userGuide.Items[0].Title != "User Guide" { t.Errorf("User Guide direct items = %+v, want User Guide pinned first", userGuide.Items) } - var devices *templates.NavGroup - for i := range userGuide.Groups { - if userGuide.Groups[i].Title == "Devices" { - devices = &userGuide.Groups[i] - } - } - if devices == nil { - t.Fatal("User Guide has no Devices group") - } + + // Devices: own top-level section, expanded, no groups. + devices := nav.Sections[2] if devices.Collapsed { - t.Error("Devices group should be expanded: it contains the current page") + t.Error("Devices section should be expanded: it contains the current page") + } + if len(devices.Groups) != 0 { + t.Errorf("Devices groups = %+v, want none", devices.Groups) } if len(devices.Items) != 2 || devices.Items[0].Title != "Kobo Setup" { t.Errorf("Devices items = %+v, want Kobo Setup + KOReader Setup", devices.Items) } // Everything else starts collapsed. - for _, s := range nav.Sections[2:] { + for _, s := range nav.Sections[3:] { if !s.Collapsed { t.Errorf("section %q should be collapsed (current page is elsewhere)", s.Title) } } // API Reference: subdirectory groups with the index page as Overview. - api := nav.Sections[2] + api := nav.Sections[4] if len(api.Groups) != 2 { t.Fatalf("API Reference groups = %d, want 2 (Authentication, Saved Filters)", len(api.Groups)) } @@ -181,7 +181,7 @@ func TestBuildNavigation(t *testing.T) { } // Stray root files land in Developer → Reference. - dev := nav.Sections[3] + dev := nav.Sections[5] if len(dev.Groups) != 1 || dev.Groups[0].Title != "Reference" { t.Errorf("Developer groups = %+v, want Reference", dev.Groups) }