docs nav: promote Devices and Administration out of User Guide
Follows the developer/api → API Reference carve-out: placement-only, no file paths or URLs change. placeDoc routes user/devices/* to a new top-level "Devices" section (icon: device) and user/admin-* to a new top-level "Administration" section (icon: shield); User Guide keeps its direct guides with no groups. Sidebar order: Getting Started, User Guide, Devices, Administration, API Reference, Developer, Operations, Contributing. Verified live: on kobo-setup the Devices section opens with the three device guides; on admin-guide Administration opens with both admin guides; on user/dashboard User Guide opens as before. Tests (TestPlaceDoc, TestBuildNavigation) updated to pin the new placement.
This commit is contained in:
1 parent
fb95b6d400
commit
27f42bf703
2 files changed
+28
-24
No files matched your search
@@ -20,6 +20,8 @@ var sectionOrder = []struct {
|
|||||||
}{
|
}{
|
||||||
{Title: "Getting Started", Icon: "book-open"},
|
{Title: "Getting Started", Icon: "book-open"},
|
||||||
{Title: "User Guide", Icon: "book"},
|
{Title: "User Guide", Icon: "book"},
|
||||||
|
{Title: "Devices", Icon: "device"},
|
||||||
|
{Title: "Administration", Icon: "shield"},
|
||||||
{Title: "API Reference", Icon: "list"},
|
{Title: "API Reference", Icon: "list"},
|
||||||
{Title: "Developer", Icon: "gear"},
|
{Title: "Developer", Icon: "gear"},
|
||||||
{Title: "Operations", Icon: "database"},
|
{Title: "Operations", Icon: "database"},
|
||||||
@@ -90,18 +92,20 @@ func placeDoc(docPath string) navPlacement {
|
|||||||
case strings.HasPrefix(docPath, "user/"):
|
case strings.HasPrefix(docPath, "user/"):
|
||||||
rest := strings.TrimPrefix(docPath, "user/")
|
rest := strings.TrimPrefix(docPath, "user/")
|
||||||
if dir, _, ok := strings.Cut(rest, "/"); ok {
|
if dir, _, ok := strings.Cut(rest, "/"); ok {
|
||||||
// Subdirectories become subcategories: device setup gets its
|
// Device setup guides get their own top-level section (the
|
||||||
// own group, the admin-facing guides another.
|
// directory stays where it is — placement is nav-only, same
|
||||||
|
// carve-out as developer/api → API Reference).
|
||||||
if dir == "devices" {
|
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}
|
return navPlacement{section: "User Guide", group: titleCase(dir), pin: pin}
|
||||||
}
|
}
|
||||||
if rest == "user-guide.md" {
|
if rest == "user-guide.md" {
|
||||||
return navPlacement{section: "User Guide", pin: -50}
|
return navPlacement{section: "User Guide", pin: -50}
|
||||||
}
|
}
|
||||||
|
// Admin-facing guides are their own top-level section too.
|
||||||
if strings.HasPrefix(rest, "admin-") {
|
if strings.HasPrefix(rest, "admin-") {
|
||||||
return navPlacement{section: "User Guide", group: "Administration"}
|
return navPlacement{section: "Administration"}
|
||||||
}
|
}
|
||||||
return navPlacement{section: "User Guide"}
|
return navPlacement{section: "User Guide"}
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"bookhoard/templates"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPlaceDoc(t *testing.T) {
|
func TestPlaceDoc(t *testing.T) {
|
||||||
@@ -18,8 +16,8 @@ func TestPlaceDoc(t *testing.T) {
|
|||||||
{"index.md", "Getting Started", "", true},
|
{"index.md", "Getting Started", "", true},
|
||||||
{"user/user-guide.md", "User Guide", "", true},
|
{"user/user-guide.md", "User Guide", "", true},
|
||||||
{"user/dashboard.md", "User Guide", "", false},
|
{"user/dashboard.md", "User Guide", "", false},
|
||||||
{"user/admin-guide.md", "User Guide", "Administration", false},
|
{"user/admin-guide.md", "Administration", "", false},
|
||||||
{"user/devices/kobo-setup.md", "User Guide", "Devices", false},
|
{"user/devices/kobo-setup.md", "Devices", "", false},
|
||||||
{"developer/api/api-reference.md", "API Reference", "", true},
|
{"developer/api/api-reference.md", "API Reference", "", true},
|
||||||
{"developer/api/dashboard.md", "API Reference", "", false},
|
{"developer/api/dashboard.md", "API Reference", "", false},
|
||||||
{"developer/api/authentication/login.md", "API Reference", "Authentication", false},
|
{"developer/api/authentication/login.md", "API Reference", "Authentication", false},
|
||||||
@@ -119,7 +117,7 @@ func TestBuildNavigation(t *testing.T) {
|
|||||||
t.Fatal("no sections built")
|
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 {
|
for i, want := range wantOrder {
|
||||||
if nav.Sections[i].Title != want {
|
if nav.Sections[i].Title != want {
|
||||||
t.Fatalf("section %d = %q, want %q", i, 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)
|
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]
|
userGuide := nav.Sections[1]
|
||||||
if userGuide.Collapsed {
|
if !userGuide.Collapsed {
|
||||||
t.Error("User Guide should be expanded: it contains the current page")
|
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" {
|
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)
|
t.Errorf("User Guide direct items = %+v, want User Guide pinned first", userGuide.Items)
|
||||||
}
|
}
|
||||||
var devices *templates.NavGroup
|
|
||||||
for i := range userGuide.Groups {
|
// Devices: own top-level section, expanded, no groups.
|
||||||
if userGuide.Groups[i].Title == "Devices" {
|
devices := nav.Sections[2]
|
||||||
devices = &userGuide.Groups[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if devices == nil {
|
|
||||||
t.Fatal("User Guide has no Devices group")
|
|
||||||
}
|
|
||||||
if devices.Collapsed {
|
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" {
|
if len(devices.Items) != 2 || devices.Items[0].Title != "Kobo Setup" {
|
||||||
t.Errorf("Devices items = %+v, want Kobo Setup + KOReader Setup", devices.Items)
|
t.Errorf("Devices items = %+v, want Kobo Setup + KOReader Setup", devices.Items)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Everything else starts collapsed.
|
// Everything else starts collapsed.
|
||||||
for _, s := range nav.Sections[2:] {
|
for _, s := range nav.Sections[3:] {
|
||||||
if !s.Collapsed {
|
if !s.Collapsed {
|
||||||
t.Errorf("section %q should be collapsed (current page is elsewhere)", s.Title)
|
t.Errorf("section %q should be collapsed (current page is elsewhere)", s.Title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// API Reference: subdirectory groups with the index page as Overview.
|
// API Reference: subdirectory groups with the index page as Overview.
|
||||||
api := nav.Sections[2]
|
api := nav.Sections[4]
|
||||||
if len(api.Groups) != 2 {
|
if len(api.Groups) != 2 {
|
||||||
t.Fatalf("API Reference groups = %d, want 2 (Authentication, Saved Filters)", len(api.Groups))
|
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.
|
// 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" {
|
if len(dev.Groups) != 1 || dev.Groups[0].Title != "Reference" {
|
||||||
t.Errorf("Developer groups = %+v, want Reference", dev.Groups)
|
t.Errorf("Developer groups = %+v, want Reference", dev.Groups)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user