style.py 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import re
  2. from typing import List, Optional
  3. from nicegui import context, ui
  4. from .examples import Example
  5. SPECIAL_CHARACTERS = re.compile('[^(a-z)(A-Z)(0-9)-]')
  6. def link_target(name: str, offset: str = '0') -> ui.link_target:
  7. """Create a link target that can be linked to with a hash."""
  8. target = ui.link_target(name).style(f'position: absolute; top: {offset}; left: 0')
  9. assert target.parent_slot is not None
  10. target.parent_slot.parent.classes('relative')
  11. return target
  12. def section_heading(subtitle_: str, title_: str) -> None:
  13. """Render a section heading with a subtitle."""
  14. ui.label(subtitle_).classes('md:text-lg font-bold')
  15. ui.markdown(title_).classes('text-3xl md:text-5xl font-medium mt-[-12px] fancy-em')
  16. def heading(title_: str) -> ui.markdown:
  17. """Render a heading."""
  18. return ui.markdown(title_).classes('text-2xl md:text-3xl xl:text-4xl font-medium text-white')
  19. def title(content: str) -> ui.markdown:
  20. """Render a title."""
  21. return ui.markdown(content).classes('text-4xl sm:text-5xl md:text-6xl font-medium fancy-em')
  22. def subtitle(content: str) -> ui.markdown:
  23. """Render a subtitle."""
  24. return ui.markdown(content).classes('text-xl sm:text-2xl md:text-3xl leading-7')
  25. def example_link(example: Example) -> None:
  26. """Render a link to an example."""
  27. with ui.link(target=example.url) \
  28. .classes('bg-[#5898d420] p-4 self-stretch rounded flex flex-col gap-2') \
  29. .style('box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1)'):
  30. ui.label(example.title).classes(replace='font-bold')
  31. ui.markdown(example.description).classes(replace='bold-links arrow-links')
  32. def features(icon: str, title_: str, items: List[str]) -> None:
  33. """Render a list of features."""
  34. with ui.column().classes('gap-1'):
  35. ui.icon(icon).classes('max-sm:hidden text-3xl md:text-5xl mb-3 text-primary opacity-80')
  36. ui.label(title_).classes('font-bold mb-3')
  37. for item in items:
  38. ui.markdown(f'- {item}').classes('bold-links arrow-links')
  39. def side_menu() -> ui.left_drawer:
  40. """Render the side menu."""
  41. return ui.left_drawer() \
  42. .classes('column no-wrap gap-1 bg-[#eee] dark:bg-[#1b1b1b] mt-[-20px] px-8 py-20') \
  43. .style('height: calc(100% + 20px) !important')
  44. def subheading(text: str, *, link: Optional[str] = None, major: bool = False) -> None:
  45. """Render a subheading with an anchor that can be linked to with a hash."""
  46. name = create_anchor_name(text)
  47. ui.html(f'<div id="{name}"></div>').style('position: relative; top: -90px')
  48. with ui.row().classes('gap-2 items-center relative'):
  49. classes = 'text-3xl' if major else 'text-2xl'
  50. if link:
  51. ui.link(text, link).classes(classes)
  52. else:
  53. ui.label(text).classes(classes)
  54. with ui.link(target=f'#{name}').classes('absolute').style('transform: translateX(-150%)'):
  55. ui.icon('link', size='sm').classes('opacity-10 hover:opacity-80')
  56. drawers = [element for element in context.get_client().elements.values() if isinstance(element, ui.left_drawer)]
  57. if drawers:
  58. menu = drawers[0]
  59. with menu:
  60. async def click():
  61. if await ui.run_javascript('!!document.querySelector("div.q-drawer__backdrop")', timeout=5.0):
  62. menu.hide()
  63. ui.open(f'#{name}')
  64. ui.link(text, target=f'#{name}').props('data-close-overlay').on('click', click, []) \
  65. .classes('font-bold mt-4' if major else '')
  66. def create_anchor_name(text: str) -> str:
  67. """Create an anchor name that can be linked to with a hash."""
  68. return SPECIAL_CHARACTERS.sub('_', text).lower()