Skip to content

feat: Add profile selector dropdown to tools menu#410

Open
DennisOSRM wants to merge 25 commits intogh-pagesfrom
profile-selector
Open

feat: Add profile selector dropdown to tools menu#410
DennisOSRM wants to merge 25 commits intogh-pagesfrom
profile-selector

Conversation

@DennisOSRM
Copy link
Copy Markdown
Contributor

@DennisOSRM DennisOSRM commented Apr 11, 2026

Description

Implements a routing profile selector allowing users to switch between three routing profiles (Car, Bike, Foot) with auto re-routing and URL persistence.

Features

  • Profile dropdown selector appears in bottom-left tools menu between language selector and build timestamp
  • Three default profiles: Car, Bike, Foot
  • Automatic route recalculation when profile changes
  • Profile preference persisted in localStorage
  • Profile selection encoded in shareable URLs
  • Translatable profile labels using existing i18n system
  • CSS styling matches language selector appearance

Technical Details

  • Uses monkey-patching approach to extend leaflet-routing-machine (no fork needed)
  • Different OSRM services host different routing profiles
  • Profile parameter persisted in URL for shareable links with localStorage backup

Testing

✅ All 88 tests passing
✅ Linting passes
✅ Build successful

Visual Proof

mode selector

Implement a routing profile selector allowing users to switch between:
- Car (fastest) - Uses https://router.project-osrm.org/route/v1
- Bike - Uses https://routing.openstreetmap.de/routed-bike/route/v1
- Foot - Uses https://routing.openstreetmap.de/routed-foot/route/v1

The selector appears in the bottom-left tools menu between the language
selector and build timestamp. Profile selection automatically triggers
re-routing with the new profile's routing engine.

Features:
- Profile dropdown UI with three default profiles
- Auto re-routing when profile changes
- Profile preference persisted in localStorage
- Profile selection encoded in shareable URLs for link persistence
- Translatable profile labels using existing i18n system
- CSS styling matching language selector appearance

Implementation uses monkey-patching approach to extend leaflet-routing-machine,
avoiding the need for a fork while keeping dependencies stable.

Comprehensive test coverage:
- Profile selector UI rendering and translation
- Profile change event handling
- Router endpoint switching
- Re-routing on profile change
- localStorage persistence
- 88 total tests, all passing

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 11, 2026 14:52

This comment was marked as outdated.

DennisOSRM and others added 24 commits April 12, 2026 12:22
- Remove extra wrapper div around profile select for consistency with language selector
- Add vertical-align: middle and line-height properties to both selectors
- Ensure font-size matches at 13px for consistent text rendering
- Profile and language selectors now have identical alignment and spacing

This fixes the visual misalignment issue where profile selector text appeared
lower than language selector text in the bottom tools menu.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace 'Build: timestamp' text with a circular info icon (i)
- Build timestamp now displays on hover as a tooltip
- Icon styling uses white border circle with centered text
- Hover effect adds subtle background color for better UX

This provides a cleaner, more compact UI in the tools menu while
preserving access to build timestamp information via tooltip.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace plain 'i' with Unicode character U+24D8 (ⓘ) for a more
professional appearance.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Unicode character U+24D8 (ⓘ) already includes the circle,
so the CSS border styling is redundant.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Convert version container to inline-block with vertical-align: middle
- Reduce padding from 12px 8px to 0px 4px to match other menu items
- Remove margin-top to align with language and profile selectors
- Add margin-left: auto to push version info to the right side

All menu items (icons, language, profile, info icon) now have consistent
vertical alignment in the tools menu.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Change icon from flex to inline-block display
- Use text-align: center with line-height: 24px for proper vertical centering
- Add explicit height and line-height to version container
- Ensure vertical-align: middle on icon for proper baseline alignment

This fixes the misalignment of the Unicode circled info icon (ⓘ)
with other menu items.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reorder creation of profile and language selectors so that profile
selector appears before language selector in the tools menu.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reorder creation so profile selector appears before language selector
in the tools menu (left to right).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add left and right borders to profile and language selectors
- Use semi-transparent white (rgba(255, 255, 255, 0.2)) for subtle separator
- Increase padding from 3px to 6px to accommodate borders
- Creates visual separation between selector groups and other menu items

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When language is changed, state.reload() is called which reloads the page.
The profile was not being preserved in state.options, causing it to reset
to the default (car) profile on reload.

Now we update state.options.profile whenever the profile is changed, so
the correct profile is restored after a language change.

Fixes: Switching language no longer triggers re-request with wrong profile.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move profile initialization logic to run BEFORE the router and lrmControl
are created. This ensures that when lrmControl sets initial waypoints from
the URL and calculates the route, it uses the correct serviceUrl for the
selected profile.

Previously, the router was created with the default (car) serviceUrl, and
the profile was set afterwards. This caused routes to be calculated with
the wrong profile when switching languages (which triggers a page reload).

Now the router is initialized with the correct serviceUrl and profile
from the start, so language changes preserve the selected profile.

Fixes: Language switch no longer re-requests route with wrong profile.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove page reload triggered by language change. Instead:
- Update URL with new language parameter
- Update tools localization and profile selector labels in place
- Avoid unnecessary route recalculation

This eliminates the unwanted re-route request when users switch languages
while keeping the UI updated and the URL synchronized.

Fixes: Language switch no longer triggers unnecessary re-route.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update the ItineraryBuilder with the new language and re-render the
current route directions when the user changes the language.

This ensures that all direction text is translated to the selected
language without requiring a page reload.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use setAlternatives() to rebuild the itinerary with the new language
instead of trying to call non-existent _updateSummary() method.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ensure the language dropdown displays the newly selected language
by updating _localizationSelect.value in updateLocalization().

Previously, selecting a language would fire the event but the
dropdown would not visually update to show the new selection,
making it appear as if nothing happened.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update both options.itineraryBuilder and _itinerary._itineraryBuilder
when language changes, then call setAlternatives() to rebuild the
itinerary with the new language.

The itinerary uses _itineraryBuilder internally to create the
instruction containers and steps, so both references need to be
updated for the new language to take effect.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove debug logging and simplify the language change logic.
Add error handling for itinerary re-rendering and consolidate
conditional checks for cleaner code.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Revert to the simpler original implementation without trying to
manually update the language selector dropdown or store references.
Keep focus on the core functionality: updating options, URL,
localization, and itinerary re-rendering.

This resolves the issue where language selection had no effect.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
lrmControl extends L.Routing.Itinerary directly, so _itineraryBuilder,
_routes and setAlternatives are properties of lrmControl itself — not
of a nested _itinerary object. The previous code guarded on
this._lrm._itinerary (always undefined) so the re-render block was
silently skipped every time.

The _convertRoute monkey-patch in index.js already stores the raw OSRM
v5 step object in instr.text, so creating a fresh ItineraryBuilder for
the selected language and calling setAlternatives() re-compiles every
instruction in the new language without issuing a new route request.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@DennisOSRM
Copy link
Copy Markdown
Contributor Author

state of the UI as of 2e9436a:

profileselection

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants