@@ -274,11 +274,54 @@ def link_pill(text: str, href: str) -> rx.Component:
274274 )
275275
276276
277+ def _build_url_to_filepath_mapping ():
278+ """Build dynamic mapping from browser URLs to filesystem paths.
279+
280+ Uses the same logic as the routing system to convert file paths to browser URLs,
281+ then creates the reverse mapping for URL-to-filepath conversion.
282+ """
283+ import flexdown
284+ import reflex as rx
285+
286+ url_to_filepath = {}
287+
288+ flexdown_docs = [
289+ str (doc ).replace ("\\ " , "/" ) for doc in flexdown .utils .get_flexdown_files ("docs/" )
290+ ]
291+
292+ for doc_path in flexdown_docs :
293+ browser_url = rx .utils .format .to_kebab_case (f"/{ doc_path .replace ('.md' , '/' )} " )
294+
295+ if browser_url .endswith ("/index/" ):
296+ folder_url = browser_url [:- 7 ] + "/"
297+ index_url = browser_url [:- 1 ] # Remove trailing slash but keep /index
298+
299+ folder_key = folder_url .strip ("/" )
300+ index_key = index_url .strip ("/" )
301+
302+ if folder_key .startswith ("docs/" ):
303+ folder_key = folder_key [5 :]
304+ if index_key .startswith ("docs/" ):
305+ index_key = index_key [5 :]
306+
307+ url_to_filepath [folder_key ] = doc_path
308+ url_to_filepath [index_key ] = doc_path
309+ else :
310+ url_key = browser_url .strip ("/" )
311+ if url_key .startswith ("docs/" ):
312+ url_key = url_key [5 :]
313+
314+ url_to_filepath [url_key ] = doc_path
315+
316+ return url_to_filepath
317+
318+ _URL_TO_FILEPATH_MAP = _build_url_to_filepath_mapping ()
319+
277320def convert_url_path_to_github_path (url_path ) -> str :
278321 """Convert a URL path to the corresponding GitHub filesystem path.
279322
280- Preserves the exact file structure as it exists in the docs/ folder,
281- handling mixed naming conventions (some folders use hyphens, others underscores) .
323+ Uses dynamic mapping built from the actual docs folder structure ,
324+ eliminating hardcoded path conversions while preserving exact file paths .
282325
283326 Args:
284327 url_path: URL path like "/docs/getting-started/introduction/" (can be str or rx.Var[str])
@@ -292,175 +335,31 @@ def convert_url_path_to_github_path(url_path) -> str:
292335 path_no_slashes = string_replace_operation (url_path , r"^/+|/+$" , "" )
293336 path_clean = string_replace_operation (path_no_slashes , r"/+" , "/" )
294337
295- path_converted = string_replace_operation (path_clean , "getting-started" , "getting_started" )
296- path_converted = string_replace_operation (path_converted , "client-storage" , "client_storage" )
297- path_converted = string_replace_operation (path_converted , "utility-methods" , "utility_methods" )
298- path_converted = string_replace_operation (path_converted , "advanced-onboarding" , "advanced_onboarding" )
299- path_converted = string_replace_operation (path_converted , "state-structure" , "state_structure" )
300- path_converted = string_replace_operation (path_converted , "ai-builder" , "ai_builder" )
301-
302- path_converted = string_replace_operation (path_converted , "chatapp-tutorial" , "chatapp_tutorial" )
303- path_converted = string_replace_operation (path_converted , "dashboard-tutorial" , "dashboard_tutorial" )
304-
305- path_converted = string_replace_operation (path_converted , "login-form" , "login_form" )
306- path_converted = string_replace_operation (path_converted , "signup-form" , "signup_form" )
307- path_converted = string_replace_operation (path_converted , "multi-column-row" , "multi_column_row" )
308- path_converted = string_replace_operation (path_converted , "top-banner" , "top_banner" )
309- path_converted = string_replace_operation (path_converted , "dark-mode-toggle" , "dark_mode_toggle" )
310- path_converted = string_replace_operation (path_converted , "pricing-cards" , "pricing_cards" )
311- path_converted = string_replace_operation (path_converted , "speed-dial" , "speed_dial" )
312-
313- path_converted = string_replace_operation (path_converted , "deploy-app" , "deploy_app" )
314- path_converted = string_replace_operation (path_converted , "download-app" , "download_app" )
315- path_converted = string_replace_operation (path_converted , "environment-variables" , "environment_variables" )
316- path_converted = string_replace_operation (path_converted , "image-as-prompt" , "image_as_prompt" )
317- path_converted = string_replace_operation (path_converted , "installing-external-packages" , "installing_external_packages" )
318- path_converted = string_replace_operation (path_converted , "frequently-asked-questions" , "frequently_asked_questions" )
319- path_converted = string_replace_operation (path_converted , "what-is-reflex-build" , "what_is_reflex_build" )
320- path_converted = string_replace_operation (path_converted , "breaking-up-complex-prompts" , "breaking_up_complex_prompts" )
321- path_converted = string_replace_operation (path_converted , "fixing-errors" , "fixing_errors" )
338+ path_without_docs = string_replace_operation (path_clean , "^docs/" , "" )
322339
323- path_converted = string_replace_operation (path_converted , "enterprise/ag-grid" , "enterprise/ag_grid" )
324- path_converted = string_replace_operation (path_converted , "ag-chart" , "ag_chart" )
340+ result_path = path_without_docs
341+ for browser_url , file_path in _URL_TO_FILEPATH_MAP .items ():
342+ if browser_url != file_path .replace ('.md' , '' ):
343+ result_path = string_replace_operation (result_path , browser_url , file_path .replace ('.md' , '' ))
325344
326- path_converted = string_replace_operation (path_converted , "page-load-events" , "page_load_events" )
327- path_converted = string_replace_operation (path_converted , "background-events" , "background_events" )
328- path_converted = string_replace_operation (path_converted , "yield-events" , "yield_events" )
329- path_converted = string_replace_operation (path_converted , "event-arguments" , "event_arguments" )
330- path_converted = string_replace_operation (path_converted , "event-actions" , "event_actions" )
331- path_converted = string_replace_operation (path_converted , "chaining-events" , "chaining_events" )
332- path_converted = string_replace_operation (path_converted , "special-events" , "special_events" )
333- path_converted = string_replace_operation (path_converted , "decentralized-event-handlers" , "decentralized_event_handlers" )
334- path_converted = string_replace_operation (path_converted , "events-overview" , "events_overview" )
335- path_converted = string_replace_operation (path_converted , "authentication-overview" , "authentication_overview" )
336- path_converted = string_replace_operation (path_converted , "dynamic-routing" , "dynamic_routing" )
337- path_converted = string_replace_operation (path_converted , "code-structure" , "code_structure" )
338- path_converted = string_replace_operation (path_converted , "component-state" , "component_state" )
339-
340- path_converted = string_replace_operation (path_converted , "segmented-control" , "segmented_control" )
341- path_converted = string_replace_operation (path_converted , "auto-scroll" , "auto_scroll" )
342- path_converted = string_replace_operation (path_converted , "code-block" , "code_block" )
343- path_converted = string_replace_operation (path_converted , "data-list" , "data_list" )
344- path_converted = string_replace_operation (path_converted , "scroll-area" , "scroll_area" )
345- path_converted = string_replace_operation (path_converted , "html-embed" , "html_embed" )
346- path_converted = string_replace_operation (path_converted , "aspect-ratio" , "aspect_ratio" )
347- path_converted = string_replace_operation (path_converted , "data-table" , "data_table" )
348- path_converted = string_replace_operation (path_converted , "data-editor" , "data_editor" )
349- path_converted = string_replace_operation (path_converted , "hover-card" , "hover_card" )
350- path_converted = string_replace_operation (path_converted , "alert-dialog" , "alert_dialog" )
351- path_converted = string_replace_operation (path_converted , "context-menu" , "context_menu" )
352- path_converted = string_replace_operation (path_converted , "dropdown-menu" , "dropdown_menu" )
353- path_converted = string_replace_operation (path_converted , "radio-group" , "radio_group" )
354- path_converted = string_replace_operation (path_converted , "text-area" , "text_area" )
355-
356- path_converted = string_replace_operation (path_converted , "custom-vars" , "custom_vars" )
357- path_converted = string_replace_operation (path_converted , "computed-vars" , "computed_vars" )
358- path_converted = string_replace_operation (path_converted , "base-vars" , "base_vars" )
359-
360- path_converted = string_replace_operation (path_converted , "config-file" , "config_file" )
361-
362- path_converted = string_replace_operation (path_converted , "upload-and-download-files" , "upload_and_download_files" )
363- path_converted = string_replace_operation (path_converted , "rendering-iterables" , "rendering_iterables" )
364- path_converted = string_replace_operation (path_converted , "html-to-reflex" , "html_to_reflex" )
365- path_converted = string_replace_operation (path_converted , "conditional-rendering" , "conditional_rendering" )
366- path_converted = string_replace_operation (path_converted , "other-methods" , "other_methods" )
367- path_converted = string_replace_operation (path_converted , "lifespan-tasks" , "lifespan_tasks" )
368- path_converted = string_replace_operation (path_converted , "exception-handlers" , "exception_handlers" )
369- path_converted = string_replace_operation (path_converted , "router-attributes" , "router_attributes" )
370- path_converted = string_replace_operation (path_converted , "event-triggers" , "event_triggers" )
371- path_converted = string_replace_operation (path_converted , "browser-storage" , "browser_storage" )
372- path_converted = string_replace_operation (path_converted , "var-system" , "var_system" )
373- path_converted = string_replace_operation (path_converted , "browser-javascript" , "browser_javascript" )
374-
375- return f"{ path_converted } .md"
345+ final_path = result_path
346+ if not result_path ._js_expr .endswith (".md" ):
347+ final_path = result_path + ".md"
348+ return final_path
376349 else :
377350 path = str (url_path ).strip ("/" )
378351 while "//" in path :
379352 path = path .replace ("//" , "/" )
380353
381- path = path .replace ("getting-started" , "getting_started" )
382- path = path .replace ("client-storage" , "client_storage" )
383- path = path .replace ("utility-methods" , "utility_methods" )
384- path = path .replace ("advanced-onboarding" , "advanced_onboarding" )
385- path = path .replace ("state-structure" , "state_structure" )
386- path = path .replace ("ai-builder" , "ai_builder" )
387-
388- path = path .replace ("chatapp-tutorial" , "chatapp_tutorial" )
389- path = path .replace ("dashboard-tutorial" , "dashboard_tutorial" )
390-
391- path = path .replace ("login-form" , "login_form" )
392- path = path .replace ("signup-form" , "signup_form" )
393- path = path .replace ("multi-column-row" , "multi_column_row" )
394- path = path .replace ("top-banner" , "top_banner" )
395- path = path .replace ("dark-mode-toggle" , "dark_mode_toggle" )
396- path = path .replace ("pricing-cards" , "pricing_cards" )
397- path = path .replace ("speed-dial" , "speed_dial" )
398-
399- path = path .replace ("deploy-app" , "deploy_app" )
400- path = path .replace ("download-app" , "download_app" )
401- path = path .replace ("environment-variables" , "environment_variables" )
402- path = path .replace ("image-as-prompt" , "image_as_prompt" )
403- path = path .replace ("installing-external-packages" , "installing_external_packages" )
404- path = path .replace ("frequently-asked-questions" , "frequently_asked_questions" )
405- path = path .replace ("what-is-reflex-build" , "what_is_reflex_build" )
406- path = path .replace ("breaking-up-complex-prompts" , "breaking_up_complex_prompts" )
407- path = path .replace ("fixing-errors" , "fixing_errors" )
408-
409- path = path .replace ("enterprise/ag-grid" , "enterprise/ag_grid" )
410- path = path .replace ("ag-chart" , "ag_chart" )
411-
412- path = path .replace ("page-load-events" , "page_load_events" )
413- path = path .replace ("background-events" , "background_events" )
414- path = path .replace ("yield-events" , "yield_events" )
415- path = path .replace ("event-arguments" , "event_arguments" )
416- path = path .replace ("event-actions" , "event_actions" )
417- path = path .replace ("chaining-events" , "chaining_events" )
418- path = path .replace ("special-events" , "special_events" )
419- path = path .replace ("decentralized-event-handlers" , "decentralized_event_handlers" )
420- path = path .replace ("events-overview" , "events_overview" )
421- path = path .replace ("authentication-overview" , "authentication_overview" )
422- path = path .replace ("dynamic-routing" , "dynamic_routing" )
423- path = path .replace ("code-structure" , "code_structure" )
424- path = path .replace ("component-state" , "component_state" )
425-
426- path = path .replace ("segmented-control" , "segmented_control" )
427- path = path .replace ("auto-scroll" , "auto_scroll" )
428- path = path .replace ("code-block" , "code_block" )
429- path = path .replace ("data-list" , "data_list" )
430- path = path .replace ("scroll-area" , "scroll_area" )
431- path = path .replace ("html-embed" , "html_embed" )
432- path = path .replace ("aspect-ratio" , "aspect_ratio" )
433- path = path .replace ("data-table" , "data_table" )
434- path = path .replace ("data-editor" , "data_editor" )
435- path = path .replace ("hover-card" , "hover_card" )
436- path = path .replace ("alert-dialog" , "alert_dialog" )
437- path = path .replace ("context-menu" , "context_menu" )
438- path = path .replace ("dropdown-menu" , "dropdown_menu" )
439- path = path .replace ("radio-group" , "radio_group" )
440- path = path .replace ("text-area" , "text_area" )
441-
442- path = path .replace ("custom-vars" , "custom_vars" )
443- path = path .replace ("computed-vars" , "computed_vars" )
444- path = path .replace ("base-vars" , "base_vars" )
445-
446- path = path .replace ("config-file" , "config_file" )
354+ if path .startswith ("docs/" ):
355+ path = path [5 :]
447356
448- path = path .replace ("upload-and-download-files" , "upload_and_download_files" )
449- path = path .replace ("rendering-iterables" , "rendering_iterables" )
450- path = path .replace ("html-to-reflex" , "html_to_reflex" )
451- path = path .replace ("conditional-rendering" , "conditional_rendering" )
452- path = path .replace ("other-methods" , "other_methods" )
453- path = path .replace ("lifespan-tasks" , "lifespan_tasks" )
454- path = path .replace ("exception-handlers" , "exception_handlers" )
455- path = path .replace ("router-attributes" , "router_attributes" )
456- path = path .replace ("event-triggers" , "event_triggers" )
457- path = path .replace ("browser-storage" , "browser_storage" )
458- path = path .replace ("var-system" , "var_system" )
459- path = path .replace ("browser-javascript" , "browser_javascript" )
357+ if path in _URL_TO_FILEPATH_MAP :
358+ return _URL_TO_FILEPATH_MAP [path ]
460359
461360 if not path .endswith (".md" ):
462361 path += ".md"
463- return path
362+ return f"docs/ { path } "
464363
465364
466365@rx .memo
0 commit comments