Skip to content

Commit b0ed7f7

Browse files
committed
more updates
1 parent 9ef2ae8 commit b0ed7f7

File tree

2 files changed

+177
-185
lines changed

2 files changed

+177
-185
lines changed

pcweb/components/docpage/navbar/typesense.py

Lines changed: 51 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -47,34 +47,6 @@
4747
"Blogs": ["Blog"]
4848
}
4949

50-
SECTION_DISPLAY_NAMES = {
51-
'getting_started': 'Getting Started',
52-
'library': 'Components',
53-
'api-reference': 'API Reference',
54-
'hosting': 'Hosting',
55-
'events': 'Events',
56-
'styling': 'Styling',
57-
'state': 'State',
58-
'vars': 'Variables',
59-
'database': 'Database',
60-
'authentication': 'Authentication',
61-
'custom-components': 'Custom Components',
62-
'wrapping-react': 'Wrapping React',
63-
'ai_builder': 'AI Builder',
64-
'recipes': 'Recipes',
65-
'advanced_onboarding': 'Advanced',
66-
'enterprise': 'Enterprise',
67-
'utility_methods': 'Utilities',
68-
'client_storage': 'Client Storage',
69-
'components': 'Components',
70-
'pages': 'Pages',
71-
'assets': 'Assets',
72-
'api-routes': 'API Routes',
73-
'ui': 'UI',
74-
'state_structure': 'State Structure',
75-
'Blog': 'Blog'
76-
}
77-
7850
DEFAULT_SUGGESTIONS = [
7951
{"title": "Getting Started with Reflex", "url": "/docs/getting-started/introduction"},
8052
{"title": "Components Overview", "url": "/docs/library"},
@@ -84,6 +56,15 @@
8456
{"title": "Deployment Guide", "url": "/docs/hosting/deploy-quick-start"},
8557
]
8658

59+
# Precompiled regex patterns for component highlighting fixes
60+
PATTERN_PARTIAL_WORD = re.compile(r'<mark>([^<]*?)</mark>([a-zA-Z0-9_]*)')
61+
PATTERN_COMPONENT_NAME = re.compile(r'((?:rx|reflex)\.)<mark>([^<]*?)</mark>')
62+
PATTERN_NAMESPACE = re.compile(r'<mark>(rx|reflex)</mark>\.([a-zA-Z0-9_]+)')
63+
PATTERN_CHAINED = re.compile(r'<mark>((?:rx|reflex)\.[a-zA-Z0-9_]+)</mark>\.([a-zA-Z0-9_]+)')
64+
65+
# Styling for highlights
66+
HIGHLIGHT_STYLE = '<span style="background-color: var(--violet-3); color: var(--violet-11); padding: 2px 4px; border-radius: 3px;">'
67+
8768

8869
class TypesenseSearchState(rx.State):
8970
"""Enhanced state management for the Typesense search component."""
@@ -232,94 +213,57 @@ async def _perform_regular_search(self, query: str) -> dict:
232213
return client.collections['docs'].documents.search(search_parameters)
233214

234215
def _format_search_results(self, result: dict) -> list[dict]:
235-
"""Format search results for display with enhanced component info."""
236-
formatted_results = []
237-
238-
for hit in result['hits']:
239-
doc = hit['document']
240-
241-
# Extract component information
242-
components = doc.get('components', [])
243-
component_info = None
244-
if components:
245-
component_info = f"Components: {', '.join(components)}"
246-
247-
formatted_result = {
248-
'title': doc['title'],
249-
'content': self._get_highlighted_content(hit),
250-
'url': doc['url'],
251-
'path': doc['path'],
252-
'section': doc.get('section', ''),
253-
'subsection': doc.get('subsection', ''),
254-
'breadcrumb': self._create_breadcrumb(doc),
255-
'components': components,
256-
'component_info': component_info,
257-
'score': hit.get('text_match', 0) # Include relevance score
258-
}
259-
260-
formatted_results.append(formatted_result)
261-
262-
return formatted_results
216+
"""Format search results for display with enhanced component info."""
217+
formatted_results = []
218+
219+
for hit in result['hits']:
220+
doc = hit['document']
221+
components = doc.get('components', [])
222+
component_info = None
223+
if components:
224+
component_info = f"Components: {', '.join(components)}"
225+
formatted_result = {
226+
'title': doc['title'],
227+
'content': self._get_highlighted_content(hit),
228+
'url': doc['url'],
229+
'path': doc['path'],
230+
'section': doc.get('section', ''),
231+
'subsection': doc.get('subsection', ''),
232+
'breadcrumb': doc.get('breadcrumb', ''),
233+
'components': components,
234+
'component_info': component_info,
235+
'score': hit.get('text_match', 0)
236+
}
237+
formatted_results.append(formatted_result)
238+
239+
return formatted_results
263240

264241
def _get_highlighted_content(self, hit: dict) -> str:
265242
"""Get highlighted content snippet with component-aware highlighting."""
266243
highlights = hit.get('highlights', [])
267244

268245
def fix_component_highlighting(text):
269246
"""Fix incomplete word and component highlighting patterns."""
270-
import re
271-
272-
# Fix 1: Complete partial words (e.g., Form -> Forms)
273-
text = re.sub(r'<mark>([^<]*?)</mark>([a-zA-Z0-9_]*)', r'<mark>\1\2</mark>', text)
274-
275-
# Fix 2: Handle component patterns where only component name is highlighted
276-
# rx.<mark>form</mark> -> <mark>rx.form</mark>
277-
text = re.sub(r'((?:rx|reflex)\.)<mark>([^<]*?)</mark>', r'<mark>\1\2</mark>', text)
278-
279-
# Fix 3: Handle reverse case where namespace is highlighted
280-
# <mark>rx</mark>.form -> <mark>rx.form</mark>
281-
text = re.sub(r'<mark>(rx|reflex)</mark>\.([a-zA-Z0-9_]+)', r'<mark>\1.\2</mark>', text)
282-
283-
# Fix 4: Handle chained components/methods
284-
# <mark>rx.component</mark>.method -> <mark>rx.component.method</mark>
285-
text = re.sub(r'<mark>((?:rx|reflex)\.[a-zA-Z0-9_]+)</mark>\.([a-zA-Z0-9_]+)', r'<mark>\1.\2</mark>', text)
286-
247+
text = PATTERN_PARTIAL_WORD.sub(r'<mark>\1\2</mark>', text)
248+
text = PATTERN_COMPONENT_NAME.sub(r'<mark>\1\2</mark>', text)
249+
text = PATTERN_NAMESPACE.sub(r'<mark>\1.\2</mark>', text)
250+
text = PATTERN_CHAINED.sub(r'<mark>\1.\2</mark>', text)
287251
return text
288252

289-
if highlights:
290-
# Prioritize component field highlights
291-
for highlight in highlights:
292-
if highlight.get('field') == 'components':
293-
values = highlight.get('values', [])
294-
if values:
295-
# Apply highlighting fix to component values too
296-
fixed_values = [fix_component_highlighting(value) for value in values]
297-
highlighted_components = ', '.join(fixed_values)
298-
return f"<span style='font-weight: 600;'>Components:</span> {highlighted_components}"
299-
300-
# Then look for content highlights
301-
for highlight in highlights:
302-
if highlight.get('field') == 'content':
303-
content = highlight.get('snippet') or highlight.get('value')
304-
if content and '<mark>' in content:
305-
# Apply comprehensive highlighting fix
306-
content = fix_component_highlighting(content)
307-
content = content.replace(
308-
'<mark>', '<span style="background-color: var(--violet-3); color: var(--violet-11); padding: 2px 4px; border-radius: 3px;">'
309-
).replace('</mark>', '</span>')
310-
return content
311-
312-
# Finally, title highlights
313-
for highlight in highlights:
314-
if highlight.get('field') == 'title':
315-
content = highlight.get('snippet') or highlight.get('value')
316-
if content and '<mark>' in content:
317-
# Apply comprehensive highlighting fix
318-
content = fix_component_highlighting(content)
319-
content = content.replace(
320-
'<mark>', '<span style="background-color: var(--violet-3); color: var(--violet-11); padding: 2px 4px; border-radius: 3px;">'
321-
).replace('</mark>', '</span>')
322-
return content
253+
for highlight in highlights:
254+
field = highlight.get('field')
255+
if field == 'components':
256+
values = highlight.get('values', [])
257+
if values:
258+
fixed_values = [fix_component_highlighting(value) for value in values]
259+
highlighted_components = ', '.join(fixed_values)
260+
styled = f"<span style='font-weight: 600;'>Components:</span> {highlighted_components}"
261+
return styled.replace('<mark>', HIGHLIGHT_STYLE).replace('</mark>', '</span>')
262+
elif field in ['content', 'title']:
263+
content = highlight.get('snippet') or highlight.get('value', '')
264+
if content and '<mark>' in content:
265+
content = fix_component_highlighting(content)
266+
return content.replace('<mark>', HIGHLIGHT_STYLE).replace('</mark>', '</span>')
323267

324268
# Fallback to truncated plain content
325269
return self._truncate_content(hit['document']['content'])
@@ -330,32 +274,6 @@ def _truncate_content(self, content: str, max_length: int = 150) -> str:
330274
return content
331275
return content[:max_length] + '...'
332276

333-
def _create_breadcrumb(self, document: dict) -> str:
334-
"""Create a breadcrumb string from document metadata."""
335-
parts = []
336-
337-
# Add section
338-
section = document.get('section', '')
339-
if section:
340-
section_display = SECTION_DISPLAY_NAMES.get(
341-
section,
342-
section.replace('-', ' ').replace('_', ' ').title()
343-
)
344-
parts.append(section_display)
345-
346-
# Add subsection
347-
subsection = document.get('subsection', '')
348-
if subsection:
349-
subsection_display = subsection.replace('-', ' ').replace('_', ' ').title()
350-
parts.append(subsection_display)
351-
352-
# Add title if different from last part
353-
title = document.get('title', '')
354-
if title and (not parts or title.lower() != parts[-1].lower()):
355-
parts.append(title)
356-
357-
return ' › '.join(parts)
358-
359277
def hide_results(self):
360278
"""Hide search results."""
361279
self.show_results = False

0 commit comments

Comments
 (0)