diff --git a/web/build.sh b/web/build.sh index e882219..0806f63 100755 --- a/web/build.sh +++ b/web/build.sh @@ -242,29 +242,35 @@ for spec in "${REMOTE_PAGES[@]}"; do done if [[ "$CHECK_ONLY" == false ]]; then - # Apply menu order if defined — reorder PAGE_ENTRIES and filter nav visibility - mapfile -t MENU_ORDER < <(yq '(.menu // [])[]' "$MANIFEST") + # Build navigation.json from menu: section. + # Convert full manifest to JSON once (single yq call) then jq handles all logic. + # Menu items: string → page lookup, object → pass-through (separator/section). + manifest_json=$(yq -o json '.' "$MANIFEST") + menu_json=$(echo "$manifest_json" | jq -c '.menu // []') + menu_len=$(echo "$menu_json" | jq 'length') - if [[ ${#MENU_ORDER[@]} -gt 0 ]]; then - ORDERED="[]" - for route in "${MENU_ORDER[@]}"; do - [[ -z "$route" ]] && continue - entry="$(echo "$PAGE_ENTRIES" | jq --arg r "$route" '.[] | select(.route == $r)')" - [[ -z "$entry" ]] && warn "menu: route '${route}' not found in pages, skipping" - [[ -n "$entry" ]] && ORDERED="$(echo "$ORDERED" | jq --argjson e "$entry" '. + [$e]')" - done - NAV_ENTRIES="$ORDERED" + if [[ "$menu_len" -gt 0 ]]; then + NAV_ENTRIES=$(jq -n \ + --argjson menu "$menu_json" \ + --argjson pages "$PAGE_ENTRIES" \ + '[ $menu[] | + if type == "string" + then (. as $r | $pages[] | select(.route == $r) | + { label, href: ("#/" + .route), icon }) + else . + end + ]') else - NAV_ENTRIES="$PAGE_ENTRIES" + # No menu defined — use all pages in discovery order + NAV_ENTRIES=$(echo "$PAGE_ENTRIES" | \ + jq '[.[] | { label, href: ("#/" + .route), icon }]') fi # pages.json — full list (all pages, original discovery order) echo "$PAGE_ENTRIES" | jq '.' > "${WEB_DIR}/pages.json" - # navigation.json — ordered + filtered by menu: - echo "$NAV_ENTRIES" | \ - jq '[.[] | {label: .label, href: ("#/" + .route), icon: .icon}]' \ - > "${WEB_DIR}/navigation.json" + # navigation.json — write NAV_ENTRIES as-is (already correctly shaped) + echo "$NAV_ENTRIES" | jq '.' > "${WEB_DIR}/navigation.json" log "wrote pages.json ($(echo "$PAGE_ENTRIES" | jq 'length') pages) + navigation.json ($(echo "$NAV_ENTRIES" | jq 'length') in menu)" fi diff --git a/web/components.yml b/web/components.yml index 7b80ec3..b39eb90 100644 --- a/web/components.yml +++ b/web/components.yml @@ -52,7 +52,10 @@ remote_pages: [] # A page not listed here is accessible via /#/route but hidden from the nav. menu: - dashboard + - type: section + label: Réseau - vpcs - subnets + - type: separator - vms diff --git a/web/components/side-nav/side-nav.css b/web/components/side-nav/side-nav.css index 6e371c1..2cae64a 100644 --- a/web/components/side-nav/side-nav.css +++ b/web/components/side-nav/side-nav.css @@ -16,13 +16,14 @@ display: flex; align-items: center; gap: 10px; - padding: 11px 12px; + padding: 5px 12px; + margin: 2px; border-radius: 6px; text-decoration: none; color: #a6adc8; font-size: 14px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; - min-height: 44px; + min-height: 25px; transition: background 0.1s, color 0.1s; } @@ -38,3 +39,18 @@ } .item:hover .icon { color: #cdd6f4; } + +.section-header { + font-size: 10px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.1em; + color: #45475a; + padding: 14px 12px 4px; +} + +.separator { + height: 1px; + background: #313244; + margin: 6px 4px; +} diff --git a/web/components/side-nav/side-nav.js b/web/components/side-nav/side-nav.js index 3c7f7db..9e85870 100644 --- a/web/components/side-nav/side-nav.js +++ b/web/components/side-nav/side-nav.js @@ -76,6 +76,14 @@ class SideNav extends HTMLElement { const current = this.#currentHref() const links = this.#items.map(item => { + if (item.type === 'separator') { + return `
` + } + if (item.type === 'section') { + return `