plugins/content-management-system/skills/navigation-architecture/SKILL.md
Use when designing menu systems, breadcrumbs, mega-menus, or navigation APIs. Covers menu hierarchies, dynamic vs static navigation, mobile navigation patterns, and navigation endpoint design for headless CMS.
npx skillsauth add melodic-software/claude-code-plugins navigation-architectureInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Guidance for designing menu systems, breadcrumbs, and navigation APIs for headless CMS architectures.
Main site navigation, typically in header.
public class Menu
{
public Guid Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Slug { get; set; } = string.Empty;
public MenuLocation Location { get; set; }
public List<MenuItem> Items { get; set; } = new();
}
public class MenuItem
{
public Guid Id { get; set; }
public string Label { get; set; } = string.Empty;
// Link target (one of these)
public Guid? PageId { get; set; }
public string? ExternalUrl { get; set; }
public string? Anchor { get; set; }
// Computed URL
public string Url { get; set; } = string.Empty;
// Hierarchy
public Guid? ParentId { get; set; }
public List<MenuItem> Children { get; set; } = new();
public int Order { get; set; }
// Display options
public bool OpenInNewTab { get; set; }
public string? Icon { get; set; }
public string? CssClass { get; set; }
}
public enum MenuLocation
{
Primary,
Secondary,
Footer,
Sidebar,
Utility,
Mobile
}
Complex navigation with multiple columns and featured content.
public class MegaMenuItem : MenuItem
{
// Mega menu specific
public bool IsMegaMenu { get; set; }
public int Columns { get; set; } = 4;
// Featured content
public Guid? FeaturedContentId { get; set; }
public string? FeaturedImageUrl { get; set; }
public string? Description { get; set; }
// Column groups
public List<MenuColumn> MenuColumns { get; set; } = new();
}
public class MenuColumn
{
public string? Heading { get; set; }
public List<MenuItem> Items { get; set; } = new();
}
public class FooterMenu
{
public List<FooterSection> Sections { get; set; } = new();
public List<MenuItem> LegalLinks { get; set; } = new();
public List<SocialLink> SocialLinks { get; set; } = new();
}
public class FooterSection
{
public string Heading { get; set; } = string.Empty;
public List<MenuItem> Links { get; set; } = new();
}
public class SocialLink
{
public string Platform { get; set; } = string.Empty;
public string Url { get; set; } = string.Empty;
public string? Icon { get; set; }
}
public class BreadcrumbService
{
public async Task<List<Breadcrumb>> GetBreadcrumbsAsync(Page page)
{
var breadcrumbs = new List<Breadcrumb>
{
new Breadcrumb { Label = "Home", Url = "/" }
};
// Walk up the page hierarchy
var ancestors = await GetAncestorsAsync(page);
foreach (var ancestor in ancestors)
{
breadcrumbs.Add(new Breadcrumb
{
Label = ancestor.Title,
Url = ancestor.Path
});
}
// Current page (no link)
breadcrumbs.Add(new Breadcrumb
{
Label = page.Title,
Url = null,
IsCurrent = true
});
return breadcrumbs;
}
}
public class Breadcrumb
{
public string Label { get; set; } = string.Empty;
public string? Url { get; set; }
public bool IsCurrent { get; set; }
}
public class BreadcrumbSchemaGenerator
{
public string GenerateJsonLd(List<Breadcrumb> breadcrumbs, string baseUrl)
{
var items = breadcrumbs.Select((b, i) => new
{
@type = "ListItem",
position = i + 1,
name = b.Label,
item = b.Url != null ? $"{baseUrl}{b.Url}" : null
}).ToList();
var schema = new
{
@context = "https://schema.org",
@type = "BreadcrumbList",
itemListElement = items
};
return JsonSerializer.Serialize(schema);
}
}
public class DynamicMenuService
{
public async Task<Menu> GenerateFromPagesAsync(
int maxDepth = 2,
bool publishedOnly = true)
{
var pages = await _pageRepository.GetPublishedPagesAsync();
var rootPages = pages
.Where(p => p.ParentId == null && p.ShowInNavigation)
.OrderBy(p => p.Order);
var menu = new Menu
{
Name = "Main Navigation",
Slug = "main",
Location = MenuLocation.Primary
};
foreach (var page in rootPages)
{
var item = await BuildMenuItemAsync(page, pages, 1, maxDepth);
menu.Items.Add(item);
}
return menu;
}
private async Task<MenuItem> BuildMenuItemAsync(
Page page,
IEnumerable<Page> allPages,
int currentDepth,
int maxDepth)
{
var item = new MenuItem
{
Id = page.Id,
Label = page.NavigationTitle ?? page.Title,
PageId = page.Id,
Url = page.Path,
Order = page.Order
};
if (currentDepth < maxDepth)
{
var children = allPages
.Where(p => p.ParentId == page.Id && p.ShowInNavigation)
.OrderBy(p => p.Order);
foreach (var child in children)
{
var childItem = await BuildMenuItemAsync(
child, allPages, currentDepth + 1, maxDepth);
item.Children.Add(childItem);
}
}
return item;
}
}
public class StaticMenuService
{
public async Task<Menu> GetMenuAsync(string slug)
{
var menu = await _menuRepository.GetBySlugAsync(slug);
if (menu == null) return null!;
// Resolve page URLs for page-linked items
foreach (var item in menu.Items.SelectMany(FlattenItems))
{
if (item.PageId.HasValue)
{
var page = await _pageRepository.GetAsync(item.PageId.Value);
item.Url = page?.Path ?? "#";
}
}
return menu;
}
private IEnumerable<MenuItem> FlattenItems(MenuItem item)
{
yield return item;
foreach (var child in item.Children.SelectMany(FlattenItems))
{
yield return child;
}
}
}
GET /api/menus # List all menus
GET /api/menus/{slug} # Get menu by slug
GET /api/menus/location/{location} # Get menu by location
GET /api/breadcrumbs?path=/about # Get breadcrumbs for path
{
"data": {
"id": "menu-123",
"name": "Main Navigation",
"slug": "main",
"location": "Primary",
"items": [
{
"id": "item-1",
"label": "Products",
"url": "/products",
"children": [
{
"id": "item-2",
"label": "Software",
"url": "/products/software",
"children": []
},
{
"id": "item-3",
"label": "Hardware",
"url": "/products/hardware",
"children": []
}
]
},
{
"id": "item-4",
"label": "About",
"url": "/about",
"children": []
},
{
"id": "item-5",
"label": "Contact",
"url": "/contact",
"children": []
}
]
}
}
{
"data": [
{ "label": "Home", "url": "/" },
{ "label": "Products", "url": "/products" },
{ "label": "Software", "url": "/products/software" },
{ "label": "Enterprise Suite", "url": null, "isCurrent": true }
],
"jsonLd": "<script type=\"application/ld+json\">...</script>"
}
public class MobileMenuConfig
{
public bool UseHamburger { get; set; } = true;
public HamburgerStyle Style { get; set; } = HamburgerStyle.SlideIn;
public int MaxVisibleItems { get; set; } = 5;
public bool ShowSearch { get; set; } = true;
}
public enum HamburgerStyle
{
SlideIn, // Slides from side
Overlay, // Full screen overlay
Dropdown // Drops down from header
}
| Breakpoint | Navigation Style | | ---------- | ---------------- | | Desktop (>1024px) | Full horizontal menu with dropdowns | | Tablet (768-1024px) | Condensed menu, mega-menu collapses | | Mobile (<768px) | Hamburger menu, accordion submenus |
DO:
- Limit primary nav to 5-7 items
- Use clear, action-oriented labels
- Keep hierarchy shallow (2-3 levels max)
- Highlight current page/section
- Make menus keyboard-accessible
DON'T:
- Create deep nested menus
- Use vague labels like "More" or "Misc"
- Hide important pages in submenus
- Forget mobile users
// Cache menus - they change infrequently
public class CachedMenuService
{
private readonly IMemoryCache _cache;
private readonly TimeSpan _cacheDuration = TimeSpan.FromMinutes(30);
public async Task<Menu> GetMenuAsync(string slug)
{
var cacheKey = $"menu:{slug}";
if (!_cache.TryGetValue(cacheKey, out Menu? menu))
{
menu = await _menuRepository.GetBySlugAsync(slug);
_cache.Set(cacheKey, menu, _cacheDuration);
}
return menu!;
}
}
page-structure-design - Page hierarchy for navigationurl-routing-patterns - URL structure for menu linksheadless-api-design - Navigation API endpointsdevelopment
Search Milan Jovanovic's .NET blog for Clean Architecture, DDD, CQRS, EF Core, and ASP.NET Core patterns. Use for finding applicable patterns, code examples, and architecture guidance. Invoke when working with .NET projects that could benefit from proven architectural patterns.
tools
Install and configure Data API Builder (DAB) for production SQL Server MCP access with RBAC
tools
Manage MssqlMcp servers - status, rebuild, and upstream updates
tools
Developer environment setup guides for Windows, macOS, Linux, and WSL. Use when setting up development machines, installing tools, configuring environments, or following platform-specific setup guides. Covers package management, shell/terminal, code editors, AI tooling, containerization, databases, and more.