Skip to content

poc drilldown multigroup #23078

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions content/manuals/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ params:
- AI
- Products
- Platform
- Desktop
notoc: true
open-source:
- title: Docker Build
Expand Down
5 changes: 4 additions & 1 deletion content/manuals/ai/mcp-catalog-and-toolkit/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ title: Docker MCP Catalog and Toolkit
linkTitle: MCP Catalog and Toolkit
params:
sidebar:
group: AI
group:
- AI
- Products
- Desktop
badge:
color: blue
text: Beta
Expand Down
4 changes: 3 additions & 1 deletion content/manuals/desktop/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ keywords: how to use docker desktop, what is docker desktop used for, what does
desktop do, using docker desktop
params:
sidebar:
group: Products
group:
- Products
- Desktop
grid:
- title: Install Docker Desktop
description: |
Expand Down
11 changes: 7 additions & 4 deletions layouts/_default/baseof.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,13 @@
Back
</button>
<!-- Actual Sidebar Content -->
{{ block "left" . }}
{{ partial "sidebar/mainnav.html" . }}
{{ partial "sidebar/sections.html" . }}
{{ end }}
{{ block "left" . }}
{{ partial "sidebar/mainnav.html" . }}
{{/* only skip sections.html when we're on exactly /manuals/ */}}
{{ if ne .RelPermalink "/manuals/" }}
{{ partial "sidebar/sections.html" . }}
{{ end }}
{{ end }}
</div>
</div>

Expand Down
112 changes: 59 additions & 53 deletions layouts/partials/sidebar/sections.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,46 @@
- Dynamically applies current page highlighting and expanded states.
- Handles external links via `Params.sidebar.goto` in `renderSingle`.
- Requires `Params.sitemap` and `Params.sidebar` for filtering and behavior.
*/
-}}
*/ -}}
<!-- section tree -->
<nav class="navbar-font flex flex-col">
<div class="block py-4 text-gray-200 md:hidden dark:text-gray-200">
This section
</div>
<ul>
{{ template "renderChildren" .FirstSection }}
{{- $first := .FirstSection }}
{{- if eq $first.Title "Manuals" }}
{{- if eq page $first }}
{{/* 1) On /manuals/ → list all manuals, grouped by Params.sidebar.groups (multi-group supported) */}}
{{- $sections := $first.Sections }}
{{- /* Manuals without any group */}}
{{- $ungrouped := where $sections "Params.sidebar.group" "==" nil }}
{{- range $ungrouped }}
{{ template "renderSingle" . }}
{{- end }}
{{- /* Then each declared group, allowing multiple groups per manual */}}
{{- range $group := $first.Params.sidebar.groups }}
<div class="navbar-group">
<li class="navbar-group-font-title">{{ $group }}</li>
{{- range $sections }}
{{- if in .Params.sidebar.group $group }}
{{ template "renderSingle" . }}
{{- end }}
{{- end }}
</div>
{{- end }}
{{- else }}
{{/* 2) Under a specific manual → render that manual’s full collapsible tree */}}
{{- range $first.Sections }}
{{- if or (eq page .) (page.IsDescendant .) }}
{{ template "renderList" . }}
{{- end }}
{{- end }}
{{- end }}
{{- else }}
{{/* 3) Everywhere else → normal recursive nav of FirstSection */}}
{{ template "renderChildren" $first }}
{{- end }}
</ul>
</nav>

Expand All @@ -30,50 +61,40 @@
{{- template "renderSingle" . }}
{{- end }}
{{- end }}
{{- range .Params.sidebar.groups }}
<!-- Main titles -->
{{- /* grouping, allowing multiple groups per page */}}
{{- range $group := .Params.sidebar.groups }}
<div class="navbar-group">
<li class="navbar-group-font-title">
{{ . }}
</li>
{{- range where $pages "Params.sidebar.group" . }}
{{- if .IsSection }}
{{- template "renderList" . }}
{{- else }}
{{- template "renderSingle" . }}
<li class="navbar-group-font-title">{{ $group }}</li>
{{- range $pages }}
{{- if in .Params.sidebar.group $group }}
{{- if .IsSection }}
{{- template "renderList" . }}
{{- else }}
{{- template "renderSingle" . }}
{{- end }}
{{- end }}
{{- end }}
</div>
{{- end }}

{{ end }}

{{/* Recursive template for sidebar items */}}
{{ define "renderList" }}
{{ $isCurrent := eq page . }}
{{ $expanded := or $isCurrent (page.IsDescendant .) }}
<li class="" x-data="{ expanded: {{ $expanded }} }">
<div
class="{{ if $isCurrent }}
navbar-entry-background-current
{{ end }} flex w-full items-center justify-between rounded-sm"
>
<li x-data="{ expanded: {{ $expanded }} }">
<div class="{{ if $isCurrent }}navbar-entry-background-current{{ end }}
flex w-full items-center justify-between rounded-sm">
<div class="navbar-entry-margin w-full truncate">
{{- if .Permalink }}
{{/* If the link is not empty, use it */}}
<!-- Sections that have children and linking to a page -->
<a
{{ if $isCurrent }}
aria-current="page" id="sidebar-current-page"
{{ end }}
{{ if $isCurrent }}aria-current="page" id="sidebar-current-page"{{ end }}
class="hover:text-blue block select-none hover:dark:text-blue-400"
href="{{ .Permalink }}"
>
{{ template "renderTitle" . }}
</a>
{{- else }}
{{/* Otherwise, just expand the section */}}
<!-- Sections that have children and do not link to a page -->
<button
@click="expanded = !expanded"
class="hover:text-blue w-full text-left select-none hover:dark:text-blue-400"
Expand All @@ -82,29 +103,20 @@
</button>
{{- end }}
</div>
<!-- Expand group button -->
<button
@click="expanded = !expanded"
class="rounded-sm hover:bg-gray-200 hover:dark:bg-gray-800"
>
<span
:class="{ 'hidden' : expanded }"
class="icon-svg {{ if $expanded }}hidden{{ end }}"
>
<button @click="expanded = !expanded"
class="rounded-sm hover:bg-gray-200 hover:dark:bg-gray-800">
<span :class="{ 'hidden': expanded }"
class="icon-svg {{ if $expanded }}hidden{{ end }}">
{{ partialCached "icon" "arrow_drop_down" "arrow_drop_down" }}
</span>
<span
:class="{ 'hidden' : !expanded }"
class="icon-svg {{ if not $expanded }}hidden{{ end }}"
>
<span :class="{ 'hidden': !expanded }"
class="icon-svg {{ if not $expanded }}hidden{{ end }}">
{{ partialCached "icon" "arrow_drop_up" "arrow_drop_up" }}
</span>
</button>
</div>
<ul
:class="{ 'hidden' : !expanded }"
class="{{ if not $expanded }}hidden{{ end }} ml-3"
>
<ul :class="{ 'hidden': !expanded }"
class="{{ if not $expanded }}hidden{{ end }} ml-3">
{{ template "renderChildren" . }}
</ul>
</li>
Expand All @@ -123,15 +135,9 @@
</li>
{{- else }}
{{ $isCurrent := eq page . }}
<li
class="navbar-entry-margin hover:text-blue {{ if $isCurrent }}
navbar-entry-background-current
{{ end }} rounded-sm hover:dark:text-blue-400"
>
<li class="navbar-entry-margin hover:text-blue {{ if $isCurrent }}navbar-entry-background-current{{ end }} rounded-sm hover:dark:text-blue-400">
<a
{{ if $isCurrent }}
aria-current="page" id="sidebar-current-page"
{{ end }}
{{ if $isCurrent }}aria-current="page" id="sidebar-current-page"{{ end }}
class="block w-full truncate"
href="{{ .Permalink }}"
title="{{ .LinkTitle }}"
Expand All @@ -146,7 +152,7 @@
{{ .LinkTitle }}
{{- with .Params.sidebar.badge }}
<span>
{{- partial "components/badge.html" (dict "color" .color "content" .text) }}
{{ partial "components/badge.html" (dict "color" .color "content" .text) }}
</span>
{{- end }}
{{ end }}
163 changes: 163 additions & 0 deletions layouts/section/manuals.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
{{ define "left" }}
{{ if eq .RelPermalink "/manuals/" }}
{{ partial "sidebar/mainnav.html" . }}

{{ $section := .Site.GetPage "section" "manuals" }}

{{/* Create group-to-count map */}}
{{ $groupCounts := dict }}

{{/* Count all manuals (no dupes) */}}
{{ $seen := slice }}
{{ $allCount := 0 }}
{{ range $p := $section.Pages }}
{{ if not (in $seen $p.Permalink) }}
{{ $seen = $seen | append $p.Permalink }}
{{ $allCount = add $allCount 1 }}
{{ end }}
{{ end }}
{{ $groupCounts = merge $groupCounts (dict "All" $allCount) }}

{{/* Count per group */}}
{{ range $group := $section.Params.sidebar.groups }}
{{ $count := 0 }}
{{ range $p := $section.Pages }}
{{ $pageGroups := slice }}
{{ if reflect.IsSlice $p.Params.sidebar.group }}
{{ $pageGroups = $p.Params.sidebar.group }}
{{ else if $p.Params.sidebar.group }}
{{ $pageGroups = slice $p.Params.sidebar.group }}
{{ end }}
{{ if in $pageGroups $group }}
{{ $count = add $count 1 }}
{{ end }}
{{ end }}
{{ $groupCounts = merge $groupCounts (dict $group $count) }}
{{ end }}

<nav
class="navbar-font flex flex-col gap-4 p-4 text-sm"
x-data="{
selected: '',
select(group) {
this.selected = group;
const url = new URL(window.location.href);
url.searchParams.set('group', group);
window.history.replaceState({}, '', url);
this.$dispatch('group-selected', { group });
},
init() {
const url = new URL(window.location.href);
const group = url.searchParams.get('group') || 'All';
this.selected = group;
this.$nextTick(() => {
this.$dispatch('group-selected', { group: this.selected });
});
}
}"
>
<p class="font-semibold">Product category</p>
<ul class="space-y-2">
{{ $groups := slice "All" | append $section.Params.sidebar.groups }}
{{ range $group := $groups }}
<li>
<button
@click="select('{{ $group }}')"
:class="{ 'font-bold': selected === '{{ $group }}' }"
class="hover:underline text-left w-full"
>
{{ $group }} ({{ index $groupCounts $group }})
</button>
</li>
{{ end }}
</ul>
</nav>
{{ else }}
{{ partial "sidebar/mainnav.html" . }}
{{ partial "sidebar/sections.html" . }}
{{ end }}
{{ end }}


{{ define "main" }}
{{ if eq .RelPermalink "/manuals/" }}
<article
class="prose max-w-none"
x-data="{
manuals: [],
all: JSON.parse(document.getElementById('manuals-data').textContent),
init() {
const url = new URL(window.location.href);
const group = url.searchParams.get('group') || 'All';
this.manuals = this.all[group] || [];
}
}"
@group-selected.window="manuals = all[$event.detail.group] || []"
>
<h1>{{ .Title }}</h1>

<template x-if="manuals.length === 0">
<p>Select a group from the left to view its manuals.</p>
</template>

<template x-if="manuals.length > 0">
<section>
<ul class="list-disc ml-6">
<template x-for="item in manuals" :key="item.url">
<li>
<a class="hover:underline" :href="item.url" x-text="item.title"></a>
</li>
</template>
</ul>
</section>
</template>

<script type="application/json" id="manuals-data">
{
{{- $section := .Site.GetPage "section" "manuals" }}
"All": [
{{- $seen := slice }}
{{- $innerFirst := true }}
{{- range $p := $section.Pages }}
{{- if not (in $seen $p.Permalink) }}
{{- if not $innerFirst }},{{ end }}
{
"title": "{{ $p.LinkTitle | htmlEscape }}",
"url": "{{ $p.Permalink }}"
}
{{- $seen = $seen | append $p.Permalink }}
{{- $innerFirst = false }}
{{- end }}
{{- end }}
],
{{- $first := true }}
{{- range $group := $section.Params.sidebar.groups }}
{{- if not $first }},{{ end }}
"{{ $group }}": [
{{- $inner := true }}
{{- range $p := $section.Pages }}
{{- $pageGroups := slice }}
{{- if reflect.IsSlice $p.Params.sidebar.group }}
{{- $pageGroups = $p.Params.sidebar.group }}
{{- else if $p.Params.sidebar.group }}
{{- $pageGroups = slice $p.Params.sidebar.group }}
{{- end }}
{{- if in $pageGroups $group }}
{{- if not $inner }},{{ end }}
{
"title": "{{ $p.LinkTitle | htmlEscape }}",
"url": "{{ $p.Permalink }}"
}
{{- $inner = false }}
{{- end }}
{{- end }}
]
{{- $first = false }}
{{- end }}
}
</script>
</article>
{{ else }}
{{ partial "content-default.html" . }}
{{ end }}
{{ end }}