Mobile Navigation
Loquent replaces the desktop sidebar with a native-feeling navigation stack on mobile: a persistent bottom tab bar, a WhatsApp-style nav header on detail routes, direction-aware page transitions, and hardware back-button support. Desktop UI is completely unaffected.
Bottom Tab Bar
Section titled “Bottom Tab Bar”MobileTabBar renders a fixed bottom bar on root-level routes (lists, dashboards). It hides automatically on detail views.
File: src/mods/mobile/components/mobile_tab_bar.rs
| Tab | Icon | Destination |
|---|---|---|
| Home | Home | Workspace |
| Messages | MessageSquare | Messaging |
| Calls | Phone | Calls |
| Tasks | CheckSquare | Tasks |
| More | MoreHorizontal | Opens MoreSheet |
The active tab shows a bg-primary/15 pill behind the icon with an animated scale transition. Each tab enforces the 44px touch-target floor (min-h-11 min-w-11).
Visibility
Section titled “Visibility”The tab bar renders only when is_root_route(&route) returns true. Root routes include list views (Workspace, Messaging, Calls, Tasks, Contacts, Settings, Admin). Detail and create routes hide the tab bar.
When the keyboard opens, the JS bridge adds .kb-open to <html>, which hides the tab bar via CSS:
html.kb-open .mobile-tab-bar { display: none;}Glass Surface
Section titled “Glass Surface”The bar uses a frosted-glass effect: bg-background/35 backdrop-blur-2xl backdrop-saturate-150, pinned at z-30 with pb-safe for notch clearance.
MoreSheet
Section titled “MoreSheet”The “More” tab opens a bottom drawer with permission-gated links to secondary destinations: Dashboard, Insights, Contacts, Reports, AI tools (Agents, Knowledge, Analyzers), Sales (Offers, Products), Automation (Plan Templates, Plans, Widgets), Settings, and Admin.
Mobile Nav Header
Section titled “Mobile Nav Header”MobileNavHeader replaces the desktop back button on detail routes with a WhatsApp-style header: left chevron, optional avatar, title/subtitle, and right actions.
File: src/shared/components/mobile_nav_header_component.rs
pub struct MobileNavHeaderProps { pub title: String, pub subtitle: Option<String>, pub back_to: Option<NavigationTarget>, pub leading: Option<Element>, // e.g. avatar pub right_action: Option<Element>, // e.g. edit/call buttons}MobileNavHeader { title: contact_name, subtitle: last_seen_text, back_to: Route::ContactListView { query: ContactFilterQuery::default() }, leading: rsx! { Avatar { src: contact.avatar_url, size: 32 } }, right_action: rsx! { button { class: "min-h-11 min-w-11", Phone { size: 20 } } },}When back_to is None, the chevron calls nav.go_back(). When set, it navigates to the specified route. ViewContainer auto-injects the mobile header when back_button is present.
Page Transitions
Section titled “Page Transitions”MobilePageTransition wraps Outlet and animates route changes based on navigation direction — slide from right on push, slide from left on pop, cross-fade on peer swap.
File: src/mods/mobile/components/mobile_page_transition.rs
How Direction Is Determined
Section titled “How Direction Is Determined”The use_mobile_nav hook (wired in AppLayout) compares route_depth of the previous and current routes:
| Depth change | Direction | Animation |
|---|---|---|
| Increases | Push | Slide from right (320ms) |
| Decreases | Pop | Slide from left (280ms) |
| Same | Fade | Cross-fade (200ms) |
| Initial | None | No animation |
All animations use cubic-bezier(0.32, 0.72, 0, 1) and respect prefers-reduced-motion: reduce.
NavDirection Enum
Section titled “NavDirection Enum”#[derive(Debug, Clone, Copy, PartialEq, Eq)]pub enum NavDirection { None, Push, Pop, Fade,}Route Meta Utilities
Section titled “Route Meta Utilities”route_meta.rs classifies routes for tab bar visibility, active tab highlighting, and transition direction.
File: src/mods/mobile/utils/route_meta.rs
Functions
Section titled “Functions”| Function | Returns | Purpose |
|---|---|---|
is_root_route(&route) | bool | Whether the bottom tab bar shows |
active_tab(&route) | MobileTab | Which tab to highlight |
route_depth(&route) | u8 | Depth for transition direction (0 = root, 1 = detail, 2 = sub-section) |
MobileTab Enum
Section titled “MobileTab Enum”#[derive(Debug, Clone, Copy, PartialEq, Eq)]pub enum MobileTab { Home, Messages, Calls, Tasks, More,}Back Button Handling
Section titled “Back Button Handling”Android Hardware Back
Section titled “Android Hardware Back”use_capacitor_back_button listens for the Android hardware back button and calls nav.go_back() on non-root routes. On root routes, the listener is inactive — the user navigates via the tab bar.
File: src/shared/capacitor/back_button.rs
use_capacitor_back_button(|| { let r = router().current::<Route>(); !is_root_route(&r)});Native WKWebView handles swipe-back gestures — no custom code needed.
AppLayout Wiring
Section titled “AppLayout Wiring”All mobile navigation components are wired in AppLayout:
use_capacitor_back_button(|| !is_root_route(&router().current::<Route>()));use_mobile_nav(); // Provides MobileNavContext
// Main content areamain { class: "flex-1 overflow-y-auto bg-background pb-mobile-tab md:pb-0 pl-safe pr-safe", MobilePageTransition {} // Wraps Outlet}
MobileTabBar {}The pb-mobile-tab utility adds bottom padding equal to the tab bar height plus safe area:
@utility pb-mobile-tab { padding-bottom: calc(2.75rem + env(safe-area-inset-bottom, 0px));}On desktop (md:pb-0), this padding is removed.
Key Files
Section titled “Key Files”| File | Purpose |
|---|---|
src/mods/mobile/mod.rs | Module root, constants, exports |
src/mods/mobile/components/mobile_tab_bar.rs | Bottom tab navigation |
src/mods/mobile/components/more_sheet.rs | Overflow destinations drawer |
src/mods/mobile/components/mobile_page_transition.rs | Direction-aware route animation |
src/mods/mobile/hooks/use_mobile_nav.rs | Navigation direction tracker |
src/mods/mobile/utils/route_meta.rs | Route depth, tab mapping, root detection |
src/shared/components/mobile_nav_header_component.rs | WhatsApp-style detail header |
src/shared/capacitor/back_button.rs | Android hardware back handler |
src/shared/layouts/app_layout.rs | Wires tab bar, transitions, back button |