from nicegui import __version__, background_tasks, events, ui from .documentation import CustomRestructuredText as custom_restructured_text from .documentation.search import search_index class Search: def __init__(self) -> None: ui.add_head_html(r''' ''') with ui.dialog() as self.dialog, ui.card().tight().classes('w-[800px] h-[600px]'): with ui.row().classes('w-full items-center px-4'): ui.icon('search', size='2em') ui.input(placeholder='Search documentation', on_change=self.handle_input) \ .classes('flex-grow').props('borderless autofocus') ui.button('ESC', on_click=self.dialog.close) \ .props('padding="2px 8px" outline size=sm color=grey-5').classes('shadow') ui.separator() self.results = ui.element('q-list').classes('w-full').props('separator') ui.keyboard(self.handle_keypress) def create_button(self) -> ui.button: return ui.button(on_click=self.dialog.open, icon='search').props('flat color=white') \ .tooltip('Press Ctrl+K or / to search the documentation') def handle_keypress(self, e: events.KeyEventArguments) -> None: if not e.action.keydown: return if e.key == '/': self.dialog.open() if e.key == 'k' and (e.modifiers.ctrl or e.modifiers.meta): self.dialog.open() def handle_input(self, e: events.ValueChangeEventArguments) -> None: async def handle_input() -> None: with self.results: indices = await ui.run_javascript(f''' const isMobile = window.innerWidth < 610; const limit = isMobile ? 25 : 100; return window.fuse.search("{e.value}", {{ limit }}).map(result => result.refIndex); ''', timeout=6) self.results.clear() with ui.list().props('bordered separator'): for index in indices: if not 0 <= index < len(search_index): continue result_item = search_index[index] if not result_item['content']: continue with ui.item().props('clickable'): with ui.item_section(): with ui.link(target=result_item['url']): ui.item_label(result_item['title']) with ui.item_label().props('caption'): intro = result_item['content'].split(':param')[0] if result_item['format'] == 'md': element = ui.markdown(intro) else: element = custom_restructured_text(intro) element.classes('text-grey line-clamp-1') background_tasks.create_lazy(handle_input(), name='handle_search_input') def open_url(self, url: str) -> None: ui.run_javascript(f''' const url = "{url}" if (url.startsWith("http")) window.open(url, "_blank"); else window.location.href = url; ''') self.dialog.close()