rendering.py 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. from typing import List
  2. from nicegui import ui
  3. from ..header import add_head_html, add_header
  4. from ..style import section_heading, subheading
  5. from .content import DocumentationPage
  6. from .custom_restructured_text import CustomRestructuredText as custom_restructured_text
  7. from .demo import demo
  8. from .reference import generate_class_doc
  9. from .tree import nodes
  10. def render_page(documentation: DocumentationPage, *, with_menu: bool = True) -> None:
  11. """Render the documentation."""
  12. # menu
  13. if with_menu:
  14. with ui.left_drawer() \
  15. .classes('column no-wrap gap-1 bg-[#eee] dark:bg-[#1b1b1b] mt-[-20px] px-8 py-20') \
  16. .style('height: calc(100% + 20px) !important') as menu:
  17. tree = ui.tree(nodes, label_key='title').classes('w-full').props('accordion no-connectors')
  18. tree.add_slot('default-header', '''
  19. <a :href="'/documentation/' + props.node.id" onclick="event.stopPropagation()">{{ props.node.title }}</a>
  20. ''')
  21. tree.expand(_ancestor_nodes(documentation.name))
  22. ui.run_javascript(f'''
  23. Array.from(getHtmlElement({tree.id}).getElementsByTagName("a"))
  24. .find(el => el.innerText.trim() === "{(documentation.parts[0].title or '').replace('*', '')}")
  25. .scrollIntoView({{block: "center"}});
  26. ''')
  27. else:
  28. menu = None
  29. # header
  30. add_head_html()
  31. add_header(menu)
  32. ui.add_css('html {scroll-behavior: auto}')
  33. title = (documentation.title or '').replace('*', '')
  34. ui.page_title('NiceGUI' if not title else title if title.split()[0] == 'NiceGUI' else f'{title} | NiceGUI')
  35. # content
  36. def render_content():
  37. section_heading(documentation.subtitle or '', documentation.heading)
  38. for part in documentation.parts:
  39. if part.title:
  40. if part.link_target:
  41. ui.link_target(part.link_target)
  42. subheading(part.title, link=part.link, major=part.reference is not None)
  43. if part.description:
  44. if part.description_format == 'rst':
  45. element = custom_restructured_text(part.description.replace(':param ', ':'))
  46. else:
  47. element = ui.markdown(part.description)
  48. element.classes('bold-links arrow-links')
  49. if ':param' in part.description:
  50. element.classes('rst-param-tables')
  51. if part.ui:
  52. part.ui()
  53. if part.demo:
  54. demo(part.demo.function, lazy=part.demo.lazy, tab=part.demo.tab)
  55. if part.reference:
  56. generate_class_doc(part.reference, part.title)
  57. if part.link:
  58. ui.markdown(f'See [more...]({part.link})').classes('bold-links arrow-links')
  59. with ui.column().classes('w-full p-8 lg:p-16 max-w-[1250px] mx-auto'):
  60. if documentation.extra_column:
  61. with ui.grid().classes('grid-cols-[2fr_1fr] max-[600px]:grid-cols-[1fr] gap-x-8 gap-y-16'):
  62. with ui.column().classes('w-full'):
  63. render_content()
  64. with ui.column():
  65. documentation.extra_column()
  66. else:
  67. render_content()
  68. def _ancestor_nodes(node_id: str) -> List[str]:
  69. parent = next((node for node in nodes if any(child['id'] == node_id for child in node.get('children', []))), None)
  70. return [node_id] + (_ancestor_nodes(parent['id']) if parent else [])