template.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. """Common templates used between pages in the app."""
  2. from __future__ import annotations
  3. from boppersbizza import styles
  4. from boppersbizza.components.sidebar import sidebar
  5. from typing import Callable
  6. import reflex as rx
  7. # Meta tags for the app.
  8. default_meta = [
  9. {
  10. "name": "viewport",
  11. "content": "width=device-width, shrink-to-fit=no, initial-scale=1",
  12. },
  13. ]
  14. def menu_item_link(text, href):
  15. return rx.menu.item(
  16. rx.link(
  17. text,
  18. href=href,
  19. width="100%",
  20. color="inherit",
  21. ),
  22. _hover={
  23. "color": styles.accent_color,
  24. "background_color": styles.accent_text_color,
  25. },
  26. )
  27. def menu_button() -> rx.Component:
  28. """The menu button on the top right of the page.
  29. Returns:
  30. The menu button component.
  31. """
  32. from reflex.page import get_decorated_pages
  33. return rx.box(
  34. rx.menu.root(
  35. rx.menu.trigger(
  36. rx.icon(
  37. "menu",
  38. size=36,
  39. color=styles.accent_text_color,
  40. ),
  41. background_color=styles.accent_color,
  42. ),
  43. rx.menu.content(
  44. *[
  45. menu_item_link(page["title"], page["route"])
  46. for page in get_decorated_pages()
  47. ],
  48. rx.menu.separator(),
  49. menu_item_link("About", "https://github.com/reflex-dev"),
  50. menu_item_link("Contact", "mailto:founders@=reflex.dev"),
  51. ),
  52. ),
  53. position="fixed",
  54. right="1.5em",
  55. top="1.5em",
  56. z_index="500",
  57. )
  58. class ThemeState(rx.State):
  59. """The state for the theme of the app."""
  60. accent_color: str = "crimson"
  61. def template(
  62. route: str | None = None,
  63. title: str | None = None,
  64. image: str | None = None,
  65. description: str | None = None,
  66. meta: str | None = None,
  67. script_tags: list[rx.Component] | None = None,
  68. on_load: rx.event.EventHandler | list[rx.event.EventHandler] | None = None,
  69. ) -> Callable[[Callable[[], rx.Component]], rx.Component]:
  70. """The template for each page of the app.
  71. Args:
  72. route: The route to reach the page.
  73. title: The title of the page.
  74. image: The favicon of the page.
  75. description: The description of the page.
  76. meta: Additionnal meta to add to the page.
  77. on_load: The event handler(s) called when the page load.
  78. script_tags: Scripts to attach to the page.
  79. Returns:
  80. The template with the page content.
  81. """
  82. def decorator(page_content: Callable[[], rx.Component]) -> rx.Component:
  83. """The template for each page of the app.
  84. Args:
  85. page_content: The content of the page.
  86. Returns:
  87. The template with the page content.
  88. """
  89. # Get the meta tags for the page.
  90. all_meta = [*default_meta, *(meta or [])]
  91. def templated_page():
  92. return rx.hstack(
  93. sidebar(),
  94. rx.box(
  95. rx.box(
  96. page_content(),
  97. **styles.template_content_style,
  98. ),
  99. **styles.template_page_style,
  100. ),
  101. menu_button(),
  102. align="start",
  103. transition="left 0.5s, width 0.5s",
  104. position="relative",
  105. )
  106. @rx.page(
  107. route=route,
  108. title=title,
  109. image=image,
  110. description=description,
  111. meta=all_meta,
  112. script_tags=script_tags,
  113. on_load=on_load,
  114. )
  115. def theme_wrap():
  116. return rx.theme(
  117. templated_page(),
  118. accent_color=ThemeState.accent_color,
  119. )
  120. return theme_wrap
  121. return decorator