1use crate::Route;
2use crate::RouterState;
3use gpui::prelude::*;
4use gpui::{App, Empty, SharedString, Window};
5use matchit::Router as MatchitRouter;
6use smallvec::SmallVec;
7
8#[derive(IntoElement)]
10pub struct Routes {
11 basename: SharedString,
12 routes: SmallVec<[Route; 1]>,
13}
14
15impl Default for Routes {
16 fn default() -> Self {
17 Self::new()
18 }
19}
20
21impl Routes {
22 pub fn new() -> Self {
23 Self {
24 basename: SharedString::from("/"),
25 routes: SmallVec::new(),
26 }
27 }
28
29 pub fn basename(mut self, basename: impl Into<SharedString>) -> Self {
31 self.basename = basename.into();
32 self
33 }
34
35 pub fn child(mut self, child: Route) -> Self {
37 self.routes.push(child);
38 self
39 }
40
41 pub fn children(mut self, children: impl IntoIterator<Item = Route>) -> Self {
43 for child in children.into_iter() {
44 self = self.child(child);
45 }
46 self
47 }
48
49 #[cfg(test)]
50 pub fn routes(&self) -> &SmallVec<[Route; 1]> {
51 &self.routes
52 }
53}
54
55impl RenderOnce for Routes {
56 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
57 if cfg!(debug_assertions) && !cx.has_global::<RouterState>() {
58 panic!("RouterState not initialized");
59 }
60
61 let mut route_map = MatchitRouter::new();
62 for route in self.routes.iter() {
63 route_map.merge(route.build_route_map(&self.basename)).unwrap();
64 }
65
66 let pathname = cx.global::<RouterState>().location.pathname.clone();
67 let matched = route_map.at(&pathname);
68
69 if let Ok(matched) = matched {
70 for (key, value) in matched.params.iter() {
71 cx.global_mut::<RouterState>()
72 .params
73 .insert(key.to_owned().into(), value.to_owned().into());
74 }
75 let route = self
76 .routes
77 .into_iter()
78 .find(|route| route.in_pattern(&self.basename, &pathname));
79 if let Some(route) = route {
80 return route.basename(self.basename).into_any_element();
81 }
82 }
83
84 Empty {}.into_any_element()
85 }
86}