| Crates.io | gpui-navigator |
| lib.rs | gpui-navigator |
| version | 0.1.2 |
| created_at | 2026-01-19 00:09:54.487722+00 |
| updated_at | 2026-01-19 01:13:49.663634+00 |
| description | Navigator for GPUI with transitions, nested routing, guards, and middleware |
| homepage | https://github.com/vanyastaff/gpui-navigator |
| repository | https://github.com/vanyastaff/gpui-navigator |
| max_upload_size | |
| id | 2053356 |
| size | 526,820 |
A declarative navigation library for GPUI with smooth transitions, nested routing, and beautiful default error pages.
RouterOutletUnlike other GPUI routers:
[dependencies]
gpui-navigator = "0.1"
gpui = "0.2"
use gpui::prelude::*;
use gpui::*;
use gpui_navigator::*;
fn main() {
Application::new().run(|cx: &mut App| {
// Initialize router
init_router(cx, |router| {
// Define routes with closures
router.add_route(
Route::new("/", |_, _| home_page().into_any_element())
.transition(Transition::fade(300))
);
router.add_route(
Route::new("/about", |_, _| about_page().into_any_element())
.transition(Transition::slide_left(400))
);
});
// Open window with RouterOutlet
cx.open_window(WindowOptions::default(), |_, cx| {
cx.new(|cx| AppView::new(cx))
}).unwrap();
});
}
fn home_page() -> impl IntoElement {
div().child("Home Page")
}
fn about_page() -> impl IntoElement {
div().child("About Page")
}
struct AppView {
outlet: Entity<RouterOutlet>,
}
impl AppView {
fn new(cx: &mut Context<'_, Self>) -> Self {
Self {
outlet: cx.new(|_| RouterOutlet::new()),
}
}
}
impl Render for AppView {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
div()
.flex()
.flex_col()
.size_full()
.child(self.outlet.clone())
}
}
use gpui_navigator::Navigator;
// Push new route
Navigator::push(cx, "/about");
// Replace current route
Navigator::replace(cx, "/login");
// Go back
Navigator::pop(cx);
// Go forward
Navigator::forward(cx);
// Get current path
let path = Navigator::current_path(cx);
// Check if can go back
if Navigator::can_pop(cx) {
Navigator::pop(cx);
}
Create clickable navigation links with automatic active state:
use gpui_navigator::*;
fn navbar(cx: &mut Context<'_, AppView>) -> impl IntoElement {
div()
.flex()
.gap_4()
// Basic link
.child(
RouterLink::new("/".to_string())
.child(div().child("Home"))
.build(cx)
)
// Link with active styling
.child(
RouterLink::new("/about".to_string())
.child(div().px_4().py_2().child("About"))
.active_class(|div| {
div.bg(rgb(0x2196f3))
.text_color(white())
})
.build(cx)
)
}
RouterLink features:
Add smooth animations between pages:
use gpui_navigator::*;
// Fade transition
Route::new("/fade", |_, _| page().into_any_element())
.transition(Transition::fade(300))
// Slide transitions
Route::new("/slide-left", |_, _| page().into_any_element())
.transition(Transition::slide_left(400))
Route::new("/slide-right", |_, _| page().into_any_element())
.transition(Transition::slide_right(400))
Route::new("/slide-up", |_, _| page().into_any_element())
.transition(Transition::slide_up(400))
Route::new("/slide-down", |_, _| page().into_any_element())
.transition(Transition::slide_down(400))
// No transition
Route::new("/instant", |_, _| page().into_any_element())
.transition(Transition::None)
Dual Animation System: GPUI Navigator uses the new route's transition for both exit and enter animations, creating smooth, professional transitions.
Extract dynamic values from URLs:
use gpui_navigator::*;
// Define route with parameter
router.add_route(
Route::new("/users/:id", |_, params| {
user_page(params).into_any_element()
})
);
fn user_page(params: &RouteParams) -> impl IntoElement {
let user_id = params.get("id").unwrap_or(&"unknown".to_string());
div().child(format!("User: {}", user_id))
}
// Navigate with parameter
Navigator::push(cx, "/users/123");
Create layouts with child routes:
use gpui_navigator::*;
router.add_route(
Route::new("/dashboard", |_, _| dashboard_layout().into_any_element())
.children(vec![
Route::new("overview", |_, _| overview_page().into_any_element()).into(),
Route::new("settings", |_, _| settings_page().into_any_element()).into(),
])
);
fn dashboard_layout() -> impl IntoElement {
div()
.flex()
.flex_col()
.child("Dashboard Header")
.child(RouterOutlet::new()) // Child routes render here
}
Access nested routes:
/dashboard - Shows dashboard layout/dashboard/overview - Shows overview inside layout/dashboard/settings - Shows settings inside layoutGPUI Navigator includes beautiful, pre-styled error pages:
These work automatically - no configuration needed!
Override defaults if desired:
use gpui_navigator::*;
let default_pages = DefaultPages::new()
.with_not_found(|| {
div()
.child("Custom 404")
.child("Page not found")
.into_any_element()
});
Navigate by name instead of hardcoded paths:
// Define named route
router.add_route(
Route::new("/users/:id", |_, params| user_page(params).into_any_element())
.name("user-profile")
);
// Navigate by name
let mut params = RouteParams::new();
params.set("id".to_string(), "123".to_string());
Navigator::push_named(cx, "user-profile", ¶ms);
Enable advanced features in Cargo.toml:
[dependencies]
gpui-navigator = { version = "0.1", features = ["guard", "middleware", "cache"] }
Protect routes with authentication:
#[cfg(feature = "guard")]
use gpui_navigator::*;
fn is_logged_in(cx: &App) -> bool {
// Check auth state
true
}
Route::new("/profile", |_, _| profile_page().into_any_element())
.guard(AuthGuard::new(is_logged_in, "/login"))
Add hooks before/after navigation:
#[cfg(feature = "middleware")]
use gpui_navigator::*;
struct LoggingMiddleware;
impl RouteMiddleware for LoggingMiddleware {
// Implement before_navigation and after_navigation
}
Route::new("/", |_, _| home().into_any_element())
.middleware(LoggingMiddleware)
Run the included examples:
# Transition animations demo
cargo run --example transition_demo
# RouterLink and error handling demo
cargo run --example error_demo
| Function/Type | Description |
|---|---|
init_router(cx, |router| {...}) |
Initialize the router with routes |
Route::new(path, handler) |
Create a new route |
.transition(Transition::fade(ms)) |
Add transition animation |
.name("route-name") |
Name the route for reference |
.children(vec![...]) |
Add child routes |
Navigator::push(cx, path) |
Navigate to path |
Navigator::pop(cx) |
Go back |
RouterOutlet::new() |
Render current/child routes |
RouterLink::new(path) |
Create navigation link |
RouteParams::get("key") |
Get route parameter |
GPUI Navigator is built with a clean, modular architecture:
Rust 1.75 or later.
Licensed under either of:
at your option.
Contributions welcome! Please:
cargo test