Skip to content

Commit f289b0d

Browse files
committed
Replace hash-based tab routing with path-based routing
Use leptos_router with /balance and /transactions paths instead of #balance and #transactions hash fragments. The server now falls back to the shell HTML for any unmatched route so deep links and refreshes work, and the client router redirects / to /balance.
1 parent 270ff1d commit f289b0d

3 files changed

Lines changed: 27 additions & 73 deletions

File tree

src/app.rs

Lines changed: 23 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,33 @@
1-
use leptos::ev;
21
use leptos::prelude::*;
2+
use leptos_router::components::{FlatRoutes, Redirect, Route, Router, A};
3+
use leptos_router::path;
34

45
use crate::{BalanceEntry, TransactionEntry};
56

6-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7-
enum Tab {
8-
Balance,
9-
Transactions,
10-
}
11-
12-
fn tab_from_hash() -> Tab {
13-
match location_hash().as_deref() {
14-
Some("transactions") => Tab::Transactions,
15-
_ => Tab::Balance,
16-
}
17-
}
18-
19-
fn tab_hash(tab: Tab) -> &'static str {
20-
match tab {
21-
Tab::Balance => "balance",
22-
Tab::Transactions => "transactions",
23-
}
24-
}
25-
26-
fn write_hash(tab: Tab) {
27-
if !is_server() {
28-
let _ = window().location().set_hash(tab_hash(tab));
29-
}
30-
}
31-
327
#[component]
338
pub fn App() -> impl IntoView {
34-
let tab = RwSignal::new(tab_from_hash());
35-
36-
// Sync browser back/forward and manual hash edits into the signal.
37-
if !is_server() {
38-
let handle = window_event_listener(ev::hashchange, move |_| {
39-
let new_tab = tab_from_hash();
40-
if tab.get_untracked() != new_tab {
41-
tab.set(new_tab);
42-
}
43-
});
44-
on_cleanup(move || handle.remove());
45-
}
46-
47-
let is_balance = move || tab.get() == Tab::Balance;
48-
let is_transactions = move || tab.get() == Tab::Transactions;
49-
509
view! {
51-
<nav>
52-
<h1>"Transity"</h1>
53-
<div class="tabs">
54-
<button
55-
class="tab"
56-
class:active=is_balance
57-
on:click=move |_| {
58-
tab.set(Tab::Balance);
59-
write_hash(Tab::Balance);
60-
}
61-
>"Balance"</button>
62-
<button
63-
class="tab"
64-
class:active=is_transactions
65-
on:click=move |_| {
66-
tab.set(Tab::Transactions);
67-
write_hash(Tab::Transactions);
68-
}
69-
>"Transactions"</button>
70-
</div>
71-
</nav>
72-
<main>
73-
{move || match tab.get() {
74-
Tab::Balance => view! { <BalancePage /> }.into_any(),
75-
Tab::Transactions => view! { <TransactionsPage /> }.into_any(),
76-
}}
77-
</main>
10+
<Router>
11+
<nav>
12+
<h1>"Transity"</h1>
13+
<div class="tabs">
14+
<A href="/balance" attr:class="tab">"Balance"</A>
15+
<A href="/transactions" attr:class="tab">"Transactions"</A>
16+
</div>
17+
</nav>
18+
<main>
19+
<FlatRoutes fallback=|| view! {
20+
<p class="error">"Page not found."</p>
21+
}>
22+
<Route
23+
path=path!("")
24+
view=|| view! { <Redirect path="/balance" /> }
25+
/>
26+
<Route path=path!("/balance") view=BalancePage />
27+
<Route path=path!("/transactions") view=TransactionsPage />
28+
</FlatRoutes>
29+
</main>
30+
</Router>
7831
}
7932
}
8033

src/server.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ pub async fn start(ledger: Ledger, port: u16) -> anyhow::Result<()> {
6868
let addr = SocketAddr::from(([127, 0, 0, 1], port));
6969

7070
let app = Router::new()
71-
.route("/", axum::routing::get(serve_shell))
7271
.route("/pkg/transity.js", axum::routing::get(serve_js))
7372
.route("/pkg/transity.css", axum::routing::get(serve_css))
7473
.route("/pkg/transity.wasm", axum::routing::get(serve_wasm))
@@ -86,7 +85,8 @@ pub async fn start(ledger: Ledger, port: u16) -> anyhow::Result<()> {
8685
)
8786
}
8887
}),
89-
);
88+
)
89+
.fallback(serve_shell);
9090

9191
eprintln!("Serving on http://{}", addr);
9292
let listener = tokio::net::TcpListener::bind(&addr).await?;

style/main.css

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,15 @@ nav h1 {
8383
border-bottom: 2px solid transparent;
8484
border-radius: 0;
8585
margin-bottom: -1px;
86+
text-decoration: none;
8687
transition: color 0.1s ease, border-color 0.1s ease;
8788
}
8889

8990
.tab:hover {
9091
color: var(--color-text);
9192
}
9293

93-
.tab.active {
94+
.tab[aria-current="page"] {
9495
color: var(--color-text);
9596
border-bottom-color: var(--color-leaf-account);
9697
}

0 commit comments

Comments
 (0)