sidebar.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. """Sidebar component for the app."""
  2. from code import styles
  3. from code.state import State
  4. import reflex as rx
  5. def sidebar_header() -> rx.Component:
  6. """Sidebar header.
  7. Returns:
  8. The sidebar header component.
  9. """
  10. return rx.hstack(
  11. # The logo.
  12. rx.image(
  13. src="/icon.svg",
  14. height="2em",
  15. ),
  16. rx.spacer(),
  17. # Link to Reflex GitHub repo.
  18. rx.link(
  19. rx.center(
  20. rx.image(
  21. src="/github.svg",
  22. height="3em",
  23. padding="0.5em",
  24. ),
  25. box_shadow=styles.box_shadow,
  26. bg="transparent",
  27. border_radius=styles.border_radius,
  28. _hover={
  29. "bg": styles.accent_color,
  30. },
  31. ),
  32. href="https://github.com/reflex-dev/reflex",
  33. ),
  34. width="100%",
  35. border_bottom=styles.border,
  36. padding="1em",
  37. )
  38. def sidebar_footer() -> rx.Component:
  39. """Sidebar footer.
  40. Returns:
  41. The sidebar footer component.
  42. """
  43. return rx.hstack(
  44. rx.link(
  45. rx.center(
  46. rx.image(
  47. src="/paneleft.svg",
  48. height="2em",
  49. padding="0.5em",
  50. ),
  51. bg="transparent",
  52. border_radius=styles.border_radius,
  53. **styles.hover_accent_bg,
  54. ),
  55. on_click=State.toggle_sidebar_displayed,
  56. transform=rx.cond(~State.sidebar_displayed, "rotate(180deg)", ""),
  57. transition="transform 0.5s, left 0.5s",
  58. position="relative",
  59. left=rx.cond(State.sidebar_displayed, "0px", "20.5em"),
  60. **styles.overlapping_button_style,
  61. ),
  62. rx.spacer(),
  63. rx.link(
  64. rx.text(
  65. "Docs",
  66. ),
  67. href="https://reflex.dev/docs/getting-started/introduction/",
  68. ),
  69. rx.link(
  70. rx.text(
  71. "Blog",
  72. ),
  73. href="https://reflex.dev/blog/",
  74. ),
  75. width="100%",
  76. border_top=styles.border,
  77. padding="1em",
  78. )
  79. def sidebar_item(text: str, icon: str, url: str) -> rx.Component:
  80. """Sidebar item.
  81. Args:
  82. text: The text of the item.
  83. icon: The icon of the item.
  84. url: The URL of the item.
  85. Returns:
  86. rx.Component: The sidebar item component.
  87. """
  88. # Whether the item is active.
  89. active = (State.router.page.path == f"/{text.lower()}") | (
  90. (State.router.page.path == "/") & text == "Home"
  91. )
  92. return rx.link(
  93. rx.hstack(
  94. rx.image(
  95. src=icon,
  96. height="2.5em",
  97. padding="0.5em",
  98. ),
  99. rx.text(
  100. text,
  101. ),
  102. bg=rx.cond(
  103. active,
  104. styles.accent_color,
  105. "transparent",
  106. ),
  107. color=rx.cond(
  108. active,
  109. styles.accent_text_color,
  110. styles.text_color,
  111. ),
  112. border_radius=styles.border_radius,
  113. box_shadow=styles.box_shadow,
  114. width="100%",
  115. padding_x="1em",
  116. ),
  117. href=url,
  118. width="100%",
  119. )
  120. def sidebar() -> rx.Component:
  121. """The sidebar.
  122. Returns:
  123. The sidebar component.
  124. """
  125. # Get all the decorated pages and add them to the sidebar.
  126. from reflex.page import get_decorated_pages
  127. return rx.box(
  128. rx.vstack(
  129. sidebar_header(),
  130. rx.vstack(
  131. *[
  132. sidebar_item(
  133. text=page.get("title", page["route"].strip("/").capitalize()),
  134. icon=page.get("image", "/github.svg"),
  135. url=page["route"],
  136. )
  137. for page in get_decorated_pages()
  138. ],
  139. width="100%",
  140. overflow_y="auto",
  141. align_items="flex-start",
  142. padding="1em",
  143. ),
  144. rx.spacer(),
  145. sidebar_footer(),
  146. height="100dvh",
  147. ),
  148. min_width=styles.sidebar_width,
  149. height="100%",
  150. position="sticky",
  151. top="0px",
  152. border_right=styles.border,
  153. )