Show the documentation hierarchy in the sidebar (#4732)
This PR shows the documentation hierarchy in the sidebar.
- Completes
https://github.com/orgs/zauberzeug/projects/6/views/1?pane=issue&itemId=82941340
- Mentioned in https://github.com/zauberzeug/nicegui/discussions/2976
<img width="1280" alt="{A8984628-61CD-40C3-BEEF-7B7834085616}"
src="https://github.com/user-attachments/assets/f9389386-5517-4b3a-a23a-301d830ff45e"
/>
<img width="1280" alt="{40313142-2528-40CD-92E5-75E6773CBDE0}"
src="https://github.com/user-attachments/assets/45a44731-728b-4ad4-8363-7fa062dc2eeb"
/>
---
_If, in the unlucky case that you have found some deficiencies in the
tree generation code, here is an old copy of the code with a lot of
debugging prints:_
<details>
<summary> Ugly code ahead! </summary>
```py
@ui.page('/debug_documentation')
def _debug_documentation_page() -> None:
def display_dict_pretty(d: dict) -> None:
for k, v in d.items():
ui.label(f'{k}: {v}').classes('text-xs font-mono')
ui.label('Debug documentation')
all_registry_keys = [k for k in documentation.registry.keys()]
single_key_empty = {k: v for k, v in documentation.registry.items() if k == ''}
no_back_link = {k: v for k, v in documentation.registry.items() if k != '' and v.back_link is None}
rest = {k: v for k, v in documentation.registry.items() if k != '' and v.back_link is not None}
"""ui.label('Single key empty:').classes('font-bold')
display_dict_pretty(single_key_empty)
for k, v in documentation.content.overview.tiles:
ui.label(k.__name__.rpartition(".")[2]).classes('text-xs font-mono')
ui.label('No back link:').classes('font-bold')
display_dict_pretty(no_back_link)
ui.label('Rest:').classes('font-bold')
display_dict_pretty(rest)"""
all_registry_keys.remove('')
# First build the adjacency list
adjacency_list: List[tuple[str, str, str]] = []
for k, v in documentation.content.overview.tiles:
adjacency_list.append(('', k.__name__.rpartition(
".")[2], documentation.registry[k.__name__.rpartition(".")[2]].title))
all_registry_keys.remove(k.__name__.rpartition(".")[2])
"""for k, v in rest.items():
adjacency_list.append((v.back_link, k))"""
i = 0
while i < len(adjacency_list):
if i > 1000000:
break # no way
_, v, _ = adjacency_list[i]
if '#' in v:
i += 1
continue
registry_entry = documentation.registry.get(v)
if registry_entry and registry_entry.parts:
for part in registry_entry.parts:
if part.link:
adjacency_list.append((v, part.link, part.title))
all_registry_keys.remove(part.link)
elif part.link_target:
adjacency_list.append((v, f'{v}#{part.link_target}', part.title))
i += 1
"""ui.label('Adjacency list:').classes('font-bold')
for k, v, t in adjacency_list:
ui.label(f'{k} -> {v} ({t})').classes('text-xs font-mono')
ui.label('Length of adjacency list:').classes('font-bold')
ui.label(str(len(adjacency_list))).classes('text-xs font-mono')
ui.label('Number of remaining entries:').classes('font-bold')
ui.label(str(len(all_registry_keys))).classes('text-xs font-mono')
ui.label('Remaining entries:').classes('font-bold')
for k in all_registry_keys:
ui.label(k).classes('text-xs font-mono')"""
def add_to_tree(tree, parent_id, child_id, title):
for node in tree:
if node['id'] == parent_id:
node['children'].append({'id': child_id, 'children': [], 'title': title})
return True
# Recursively search in the children
if add_to_tree(node['children'], parent_id, child_id, title):
return True
return False
adjacency_list = [(k, v, t.replace("*", "")) for k, v, t in adjacency_list]
# Build the tree from adjacency list
tree_format_list = []
for k, v, t in adjacency_list:
if k == '':
tree_format_list.append({'id': v, 'children': [], 'title': t})
else:
# Try to add the child to the correct parent in the tree
if not add_to_tree(tree_format_list, k, v, t):
# If the parent is not found, create a new top-level node
tree_format_list.append({'id': k, 'children': [{'id': v, 'children': [], 'title': t}]})
ui.tree(tree_format_list, label_key='title',).props('accordion=true').classes('w-full').add_slot('default-header', '''
<span :props="props">
<a :href="'/documentation/' + props.node.id" target="_blank" onclick="event.stopPropagation()">{{ props.node.title }}</a>
</span>
''')
```
</details>
---------
Co-authored-by: Falko Schindler <falko@zauberzeug.com>